2011-11-07 12:55:18 +00:00
|
|
|
/*
|
|
|
|
* 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) 2011 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup spclip
|
2011-11-07 12:55:18 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stddef.h>
|
2013-03-20 17:03:20 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
# include <unistd.h>
|
|
|
|
#else
|
|
|
|
# include <io.h>
|
|
|
|
#endif
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-04-30 16:19:12 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
2012-06-04 16:42:58 +00:00
|
|
|
#include "DNA_mask_types.h"
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
#include "BLI_utildefines.h"
|
2013-03-20 17:03:20 +00:00
|
|
|
#include "BLI_fileops.h"
|
2011-11-07 12:55:18 +00:00
|
|
|
#include "BLI_math.h"
|
2012-08-20 23:06:17 +00:00
|
|
|
#include "BLI_rect.h"
|
2014-10-10 02:54:40 +06:00
|
|
|
#include "BLI_task.h"
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2018-11-07 18:00:24 +01:00
|
|
|
#include "BKE_context.h"
|
2013-03-20 17:03:20 +00:00
|
|
|
#include "BKE_global.h"
|
2018-11-07 18:00:24 +01:00
|
|
|
#include "BKE_library.h"
|
2013-01-24 21:57:13 +00:00
|
|
|
#include "BKE_main.h"
|
2015-06-11 22:46:42 +02:00
|
|
|
#include "BKE_mask.h"
|
2013-01-24 21:57:13 +00:00
|
|
|
#include "BKE_movieclip.h"
|
|
|
|
#include "BKE_tracking.h"
|
|
|
|
|
2012-04-30 16:19:12 +00:00
|
|
|
|
2013-03-29 16:02:27 +00:00
|
|
|
#include "IMB_colormanagement.h"
|
2011-11-07 12:55:18 +00:00
|
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
#include "IMB_imbuf.h"
|
|
|
|
|
|
|
|
#include "ED_screen.h"
|
|
|
|
#include "ED_clip.h"
|
2015-06-11 22:46:42 +02:00
|
|
|
#include "ED_mask.h"
|
2019-03-05 18:33:09 +11:00
|
|
|
#include "ED_select_utils.h"
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
#include "UI_view2d.h"
|
|
|
|
|
|
|
|
#include "clip_intern.h" // own include
|
|
|
|
|
2012-04-29 12:32:26 +00:00
|
|
|
/* ******** operactor poll functions ******** */
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
bool ED_space_clip_poll(bContext *C)
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
2012-03-25 23:19:21 +00:00
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (sc && sc->clip)
|
2014-04-01 11:34:00 +11:00
|
|
|
return true;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
return false;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
bool ED_space_clip_view_clip_poll(bContext *C)
|
2012-05-02 17:33:48 +00:00
|
|
|
{
|
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
|
|
|
2013-01-06 11:16:49 +00:00
|
|
|
if (sc) {
|
2012-05-02 17:33:48 +00:00
|
|
|
return sc->view == SC_VIEW_CLIP;
|
|
|
|
}
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
return false;
|
2012-05-02 17:33:48 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
bool ED_space_clip_tracking_poll(bContext *C)
|
2012-04-29 12:32:26 +00:00
|
|
|
{
|
2012-05-03 23:47:39 +00:00
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
2012-04-29 12:32:26 +00:00
|
|
|
|
|
|
|
if (sc && sc->clip)
|
2012-06-19 14:26:29 +00:00
|
|
|
return ED_space_clip_check_show_trackedit(sc);
|
2012-04-29 12:32:26 +00:00
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
return false;
|
2012-04-29 12:32:26 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
bool ED_space_clip_maskedit_poll(bContext *C)
|
2012-06-04 16:42:58 +00:00
|
|
|
{
|
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
|
|
|
|
|
|
if (sc && sc->clip) {
|
2012-06-19 14:26:29 +00:00
|
|
|
return ED_space_clip_check_show_maskedit(sc);
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
return false;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
bool ED_space_clip_maskedit_mask_poll(bContext *C)
|
2012-06-04 16:42:58 +00:00
|
|
|
{
|
2012-06-04 17:30:54 +00:00
|
|
|
if (ED_space_clip_maskedit_poll(C)) {
|
2012-06-04 16:42:58 +00:00
|
|
|
MovieClip *clip = CTX_data_edit_movieclip(C);
|
|
|
|
|
|
|
|
if (clip) {
|
2012-06-15 14:11:23 +00:00
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-07-24 20:33:55 +00:00
|
|
|
return sc->mask_info.mask != NULL;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
return false;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
/* ******** common editing functions ******** */
|
2012-04-29 12:32:26 +00:00
|
|
|
|
2012-07-26 22:47:05 +00:00
|
|
|
void ED_space_clip_get_size(SpaceClip *sc, int *width, int *height)
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
2012-07-25 19:36:59 +00:00
|
|
|
if (sc->clip) {
|
|
|
|
BKE_movieclip_get_size(sc->clip, &sc->user, width, height);
|
2012-03-24 06:38:07 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-07-25 19:36:59 +00:00
|
|
|
*width = *height = IMG_SIZE_FALLBACK;
|
2012-03-24 06:38:07 +00:00
|
|
|
}
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
|
2012-07-26 22:47:05 +00:00
|
|
|
void ED_space_clip_get_size_fl(SpaceClip *sc, float size[2])
|
2012-07-26 11:47:47 +00:00
|
|
|
{
|
|
|
|
int size_i[2];
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_size(sc, &size_i[0], &size_i[1]);
|
2012-07-26 11:47:47 +00:00
|
|
|
size[0] = size_i[0];
|
|
|
|
size[1] = size_i[1];
|
|
|
|
}
|
|
|
|
|
2012-07-26 22:47:05 +00:00
|
|
|
void ED_space_clip_get_zoom(SpaceClip *sc, ARegion *ar, float *zoomx, float *zoomy)
|
2012-06-04 16:42:58 +00:00
|
|
|
{
|
2012-06-20 10:28:51 +00:00
|
|
|
int width, height;
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_size(sc, &width, &height);
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-09-15 11:48:20 +00:00
|
|
|
*zoomx = (float)(BLI_rcti_size_x(&ar->winrct) + 1) / (BLI_rctf_size_x(&ar->v2d.cur) * width);
|
|
|
|
*zoomy = (float)(BLI_rcti_size_y(&ar->winrct) + 1) / (BLI_rctf_size_y(&ar->v2d.cur) * height);
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
void ED_space_clip_get_aspect(SpaceClip *sc, float *aspx, float *aspy)
|
2012-06-04 16:42:58 +00:00
|
|
|
{
|
2012-06-20 10:28:51 +00:00
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
if (clip)
|
2012-09-13 05:29:38 +00:00
|
|
|
BKE_movieclip_get_aspect(clip, aspx, aspy);
|
2012-06-20 10:28:51 +00:00
|
|
|
else
|
|
|
|
*aspx = *aspy = 1.0f;
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-06-04 20:11:09 +00:00
|
|
|
if (*aspx < *aspy) {
|
2012-06-15 14:11:23 +00:00
|
|
|
*aspy = *aspy / *aspx;
|
|
|
|
*aspx = 1.0f;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-06-15 14:11:23 +00:00
|
|
|
*aspx = *aspx / *aspy;
|
|
|
|
*aspy = 1.0f;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
void ED_space_clip_get_aspect_dimension_aware(SpaceClip *sc, float *aspx, float *aspy)
|
2012-06-04 16:42:58 +00:00
|
|
|
{
|
|
|
|
int w, h;
|
|
|
|
|
|
|
|
/* most of tools does not require aspect to be returned with dimensions correction
|
|
|
|
* due to they're invariant to this stuff, but some transformation tools like rotation
|
|
|
|
* should be aware of aspect correction caused by different resolution in different
|
|
|
|
* directions.
|
|
|
|
* mainly this is sued for transformation stuff
|
|
|
|
*/
|
|
|
|
|
2012-06-25 19:48:05 +00:00
|
|
|
if (!sc->clip) {
|
|
|
|
*aspx = 1.0f;
|
|
|
|
*aspy = 1.0f;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
ED_space_clip_get_aspect(sc, aspx, aspy);
|
|
|
|
BKE_movieclip_get_size(sc->clip, &sc->user, &w, &h);
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
*aspx *= (float) w;
|
|
|
|
*aspy *= (float) h;
|
2012-06-04 16:42:58 +00:00
|
|
|
|
2012-06-04 20:11:09 +00:00
|
|
|
if (*aspx < *aspy) {
|
2012-06-15 14:11:23 +00:00
|
|
|
*aspy = *aspy / *aspx;
|
|
|
|
*aspx = 1.0f;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-06-15 14:11:23 +00:00
|
|
|
*aspx = *aspx / *aspy;
|
|
|
|
*aspy = 1.0f;
|
2012-06-04 16:42:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
/* return current frame number in clip space */
|
|
|
|
int ED_space_clip_get_clip_frame_number(SpaceClip *sc)
|
|
|
|
{
|
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
|
|
|
|
2015-06-10 17:29:46 +02:00
|
|
|
/* Caller must ensure space does have a valid clip, otherwise it will crash, see T45017. */
|
|
|
|
return BKE_movieclip_remap_scene_to_clip_frame(clip, sc->user.framenr);
|
2012-06-20 10:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ImBuf *ED_space_clip_get_buffer(SpaceClip *sc)
|
|
|
|
{
|
|
|
|
if (sc->clip) {
|
|
|
|
ImBuf *ibuf;
|
|
|
|
|
|
|
|
ibuf = BKE_movieclip_get_postprocessed_ibuf(sc->clip, &sc->user, sc->postproc_flag);
|
|
|
|
|
|
|
|
if (ibuf && (ibuf->rect || ibuf->rect_float))
|
|
|
|
return ibuf;
|
|
|
|
|
|
|
|
if (ibuf)
|
|
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale, float *angle)
|
|
|
|
{
|
|
|
|
if (sc->clip) {
|
|
|
|
ImBuf *ibuf;
|
|
|
|
|
|
|
|
ibuf = BKE_movieclip_get_stable_ibuf(sc->clip, &sc->user, loc, scale, angle, sc->postproc_flag);
|
|
|
|
|
|
|
|
if (ibuf && (ibuf->rect || ibuf->rect_float))
|
|
|
|
return ibuf;
|
|
|
|
|
|
|
|
if (ibuf)
|
|
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-04-20 22:41:26 +02:00
|
|
|
/* Returns color in linear space, matching ED_space_image_color_sample(). */
|
|
|
|
bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *ar, int mval[2], float r_col[3])
|
2012-08-20 16:56:11 +00:00
|
|
|
{
|
|
|
|
ImBuf *ibuf;
|
|
|
|
float fx, fy, co[2];
|
2013-09-05 13:37:53 +00:00
|
|
|
bool ret = false;
|
2012-08-20 16:56:11 +00:00
|
|
|
|
|
|
|
ibuf = ED_space_clip_get_buffer(sc);
|
|
|
|
if (!ibuf) {
|
2013-09-05 13:37:53 +00:00
|
|
|
return false;
|
2012-08-20 16:56:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* map the mouse coords to the backdrop image space */
|
|
|
|
ED_clip_mouse_pos(sc, ar, mval, co);
|
|
|
|
|
|
|
|
fx = co[0];
|
|
|
|
fy = co[1];
|
|
|
|
|
|
|
|
if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
|
2014-04-27 00:22:49 +10:00
|
|
|
const float *fp;
|
2012-08-20 16:56:11 +00:00
|
|
|
unsigned char *cp;
|
|
|
|
int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
|
|
|
|
|
|
|
|
CLAMP(x, 0, ibuf->x - 1);
|
|
|
|
CLAMP(y, 0, ibuf->y - 1);
|
|
|
|
|
|
|
|
if (ibuf->rect_float) {
|
|
|
|
fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
|
2014-04-14 13:45:09 +06:00
|
|
|
copy_v3_v3(r_col, fp);
|
2013-09-05 13:37:53 +00:00
|
|
|
ret = true;
|
2012-08-20 16:56:11 +00:00
|
|
|
}
|
|
|
|
else if (ibuf->rect) {
|
|
|
|
cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
|
2014-04-14 17:56:04 +06:00
|
|
|
rgb_uchar_to_float(r_col, cp);
|
2014-04-14 13:45:09 +06:00
|
|
|
IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
|
2013-09-05 13:37:53 +00:00
|
|
|
ret = true;
|
2012-08-20 16:56:11 +00:00
|
|
|
}
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2014-04-14 13:45:09 +06:00
|
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
|
2012-08-20 16:56:11 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-07 12:55:18 +00:00
|
|
|
void ED_clip_update_frame(const Main *mainp, int cfra)
|
|
|
|
{
|
|
|
|
/* image window, compo node users */
|
Main Workspace Integration
This commit does the main integration of workspaces, which is a design we agreed on during the 2.8 UI workshop (see https://wiki.blender.org/index.php/Dev:2.8/UI/Workshop_Writeup)
Workspaces should generally be stable, I'm not aware of any remaining bugs (or I've forgotten them :) ). If you find any, let me know!
(Exception: mode switching button might get out of sync with actual mode in some cases, would consider that a limitation/ToDo. Needs to be resolved at some point.)
== Main Changes/Features
* Introduces the new Workspaces as data-blocks.
* Allow storing a number of custom workspaces as part of the user configuration. Needs further work to allow adding and deleting individual workspaces.
* Bundle a default workspace configuration with Blender (current screen-layouts converted to workspaces).
* Pressing button to add a workspace spawns a menu to select between "Duplicate Current" and the workspaces from the user configuration. If no workspaces are stored in the user configuration, the default workspaces are listed instead.
* Store screen-layouts (`bScreen`) per workspace.
* Store an active screen-layout per workspace. Changing the workspace will enable this layout.
* Store active mode in workspace. Changing the workspace will also enter the mode of the new workspace. (Note that we still store the active mode in the object, moving this completely to workspaces is a separate project.)
* Store an active render layer per workspace.
* Moved mode switch from 3D View header to Info Editor header.
* Store active scene in window (not directly workspace related, but overlaps quite a bit).
* Removed 'Use Global Scene' User Preference option.
* Compatibility with old files - a new workspace is created for every screen-layout of old files. Old Blender versions should be able to read files saved with workspace support as well.
* Default .blend only contains one workspace ("General").
* Support appending workspaces.
Opening files without UI and commandline rendering should work fine.
Note that the UI is temporary! We plan to introduce a new global topbar
that contains the workspace options and tabs for switching workspaces.
== Technical Notes
* Workspaces are data-blocks.
* Adding and removing `bScreen`s should be done through `ED_workspace_layout` API now.
* A workspace can be active in multiple windows at the same time.
* The mode menu (which is now in the Info Editor header) doesn't display "Grease Pencil Edit" mode anymore since its availability depends on the active editor. Will be fixed by making Grease Pencil an own object type (as planned).
* The button to change the active workspace object mode may get out of sync with the mode of the active object. Will either be resolved by moving mode out of object data, or we'll disable workspace modes again (there's a `#define USE_WORKSPACE_MODE` for that).
* Screen-layouts (`bScreen`) are IDs and thus stored in a main list-base. Had to add a wrapper `WorkSpaceLayout` so we can store them in a list-base within workspaces, too. On the long run we could completely replace `bScreen` by workspace structs.
* `WorkSpace` types use some special compiler trickery to allow marking structs and struct members as private. BKE_workspace API should be used for accessing those.
* Added scene operators `SCENE_OT_`. Was previously done through screen operators.
== BPY API Changes
* Removed `Screen.scene`, added `Window.scene`
* Removed `UserPreferencesView.use_global_scene`
* Added `Context.workspace`, `Window.workspace` and `BlendData.workspaces`
* Added `bpy.types.WorkSpace` containing `screens`, `object_mode` and `render_layer`
* Added Screen.layout_name for the layout name that'll be displayed in the UI (may differ from internal name)
== What's left?
* There are a few open design questions (T50521). We should find the needed answers and implement them.
* Allow adding and removing individual workspaces from workspace configuration (needs UI design).
* Get the override system ready and support overrides per workspace.
* Support custom UI setups as part of workspaces (hidden panels, hidden buttons, customizable toolbars, etc).
* Allow enabling add-ons per workspace.
* Support custom workspace keymaps.
* Remove special exception for workspaces in linking code (so they're always appended, never linked). Depends on a few things, so best to solve later.
* Get the topbar done.
* Workspaces need a proper icon, current one is just a placeholder :)
Reviewed By: campbellbarton, mont29
Tags: #user_interface, #bf_blender_2.8
Maniphest Tasks: T50521
Differential Revision: https://developer.blender.org/D2451
2017-06-01 19:56:58 +02:00
|
|
|
for (wmWindowManager *wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
|
|
|
|
for (wmWindow *win = wm->windows.first; win; win = win->next) {
|
|
|
|
bScreen *screen = WM_window_get_active_screen(win);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
Main Workspace Integration
This commit does the main integration of workspaces, which is a design we agreed on during the 2.8 UI workshop (see https://wiki.blender.org/index.php/Dev:2.8/UI/Workshop_Writeup)
Workspaces should generally be stable, I'm not aware of any remaining bugs (or I've forgotten them :) ). If you find any, let me know!
(Exception: mode switching button might get out of sync with actual mode in some cases, would consider that a limitation/ToDo. Needs to be resolved at some point.)
== Main Changes/Features
* Introduces the new Workspaces as data-blocks.
* Allow storing a number of custom workspaces as part of the user configuration. Needs further work to allow adding and deleting individual workspaces.
* Bundle a default workspace configuration with Blender (current screen-layouts converted to workspaces).
* Pressing button to add a workspace spawns a menu to select between "Duplicate Current" and the workspaces from the user configuration. If no workspaces are stored in the user configuration, the default workspaces are listed instead.
* Store screen-layouts (`bScreen`) per workspace.
* Store an active screen-layout per workspace. Changing the workspace will enable this layout.
* Store active mode in workspace. Changing the workspace will also enter the mode of the new workspace. (Note that we still store the active mode in the object, moving this completely to workspaces is a separate project.)
* Store an active render layer per workspace.
* Moved mode switch from 3D View header to Info Editor header.
* Store active scene in window (not directly workspace related, but overlaps quite a bit).
* Removed 'Use Global Scene' User Preference option.
* Compatibility with old files - a new workspace is created for every screen-layout of old files. Old Blender versions should be able to read files saved with workspace support as well.
* Default .blend only contains one workspace ("General").
* Support appending workspaces.
Opening files without UI and commandline rendering should work fine.
Note that the UI is temporary! We plan to introduce a new global topbar
that contains the workspace options and tabs for switching workspaces.
== Technical Notes
* Workspaces are data-blocks.
* Adding and removing `bScreen`s should be done through `ED_workspace_layout` API now.
* A workspace can be active in multiple windows at the same time.
* The mode menu (which is now in the Info Editor header) doesn't display "Grease Pencil Edit" mode anymore since its availability depends on the active editor. Will be fixed by making Grease Pencil an own object type (as planned).
* The button to change the active workspace object mode may get out of sync with the mode of the active object. Will either be resolved by moving mode out of object data, or we'll disable workspace modes again (there's a `#define USE_WORKSPACE_MODE` for that).
* Screen-layouts (`bScreen`) are IDs and thus stored in a main list-base. Had to add a wrapper `WorkSpaceLayout` so we can store them in a list-base within workspaces, too. On the long run we could completely replace `bScreen` by workspace structs.
* `WorkSpace` types use some special compiler trickery to allow marking structs and struct members as private. BKE_workspace API should be used for accessing those.
* Added scene operators `SCENE_OT_`. Was previously done through screen operators.
== BPY API Changes
* Removed `Screen.scene`, added `Window.scene`
* Removed `UserPreferencesView.use_global_scene`
* Added `Context.workspace`, `Window.workspace` and `BlendData.workspaces`
* Added `bpy.types.WorkSpace` containing `screens`, `object_mode` and `render_layer`
* Added Screen.layout_name for the layout name that'll be displayed in the UI (may differ from internal name)
== What's left?
* There are a few open design questions (T50521). We should find the needed answers and implement them.
* Allow adding and removing individual workspaces from workspace configuration (needs UI design).
* Get the override system ready and support overrides per workspace.
* Support custom UI setups as part of workspaces (hidden panels, hidden buttons, customizable toolbars, etc).
* Allow enabling add-ons per workspace.
* Support custom workspace keymaps.
* Remove special exception for workspaces in linking code (so they're always appended, never linked). Depends on a few things, so best to solve later.
* Get the topbar done.
* Workspaces need a proper icon, current one is just a placeholder :)
Reviewed By: campbellbarton, mont29
Tags: #user_interface, #bf_blender_2.8
Maniphest Tasks: T50521
Differential Revision: https://developer.blender.org/D2451
2017-06-01 19:56:58 +02:00
|
|
|
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
|
2012-03-25 23:19:21 +00:00
|
|
|
if (sa->spacetype == SPACE_CLIP) {
|
|
|
|
SpaceClip *sc = sa->spacedata.first;
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
sc->scopes.ok = false;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
BKE_movieclip_user_set_frame(&sc->user, cfra);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-11 22:46:42 +02:00
|
|
|
static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2])
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
2012-06-19 14:26:29 +00:00
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
2011-11-07 12:55:18 +00:00
|
|
|
MovieTrackingTrack *track;
|
2013-09-05 13:37:53 +00:00
|
|
|
int width, height;
|
|
|
|
bool ok = false;
|
2012-06-15 11:03:23 +00:00
|
|
|
ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
|
2012-06-20 10:42:41 +00:00
|
|
|
int framenr = ED_space_clip_get_clip_frame_number(sc);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
INIT_MINMAX2(min, max);
|
|
|
|
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_size(sc, &width, &height);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
track = tracksbase->first;
|
2012-03-24 06:38:07 +00:00
|
|
|
while (track) {
|
|
|
|
if (TRACK_VIEW_SELECTED(sc, track)) {
|
2012-06-20 10:42:41 +00:00
|
|
|
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (marker) {
|
2011-11-07 12:55:18 +00:00
|
|
|
float pos[3];
|
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
pos[0] = marker->pos[0] + track->offset[0];
|
|
|
|
pos[1] = marker->pos[1] + track->offset[1];
|
|
|
|
pos[2] = 0.0f;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2011-11-07 15:32:32 +00:00
|
|
|
/* undistortion happens for normalized coords */
|
2012-03-25 23:19:21 +00:00
|
|
|
if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
|
2011-11-07 15:32:32 +00:00
|
|
|
/* undistortion happens for normalized coords */
|
|
|
|
ED_clip_point_undistorted_pos(sc, pos, pos);
|
2012-03-25 23:19:21 +00:00
|
|
|
}
|
2011-11-07 15:32:32 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
pos[0] *= width;
|
|
|
|
pos[1] *= height;
|
2011-11-07 15:32:32 +00:00
|
|
|
|
2011-11-07 12:55:18 +00:00
|
|
|
mul_v3_m4v3(pos, sc->stabmat, pos);
|
|
|
|
|
2012-11-15 22:20:18 +00:00
|
|
|
minmax_v2v2_v2(min, max, pos);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
ok = true;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
track = track->next;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2015-06-11 22:46:42 +02:00
|
|
|
static bool selected_boundbox(const bContext *C, float min[2], float max[2])
|
|
|
|
{
|
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
|
|
if (sc->mode == SC_MODE_TRACKING) {
|
|
|
|
return selected_tracking_boundbox(sc, min, max);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (ED_mask_selected_minmax(C, min, max)) {
|
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
|
|
|
int width, height;
|
|
|
|
ED_space_clip_get_size(sc, &width, &height);
|
|
|
|
BKE_mask_coord_to_movieclip(clip, &sc->user, min, min);
|
|
|
|
BKE_mask_coord_to_movieclip(clip, &sc->user, max, max);
|
|
|
|
min[0] *= width;
|
|
|
|
min[1] *= height;
|
|
|
|
max[0] *= width;
|
|
|
|
max[1] *= height;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
bool ED_clip_view_selection(const bContext *C, ARegion *ar, bool fit)
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
2012-06-20 10:28:51 +00:00
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
2011-11-07 12:55:18 +00:00
|
|
|
int w, h, frame_width, frame_height;
|
|
|
|
float min[2], max[2];
|
|
|
|
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_size(sc, &frame_width, &frame_height);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-09-30 10:39:00 +00:00
|
|
|
if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL))
|
2013-09-05 13:37:53 +00:00
|
|
|
return false;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2015-06-11 22:46:42 +02:00
|
|
|
if (!selected_boundbox(C, min, max))
|
2013-09-05 13:37:53 +00:00
|
|
|
return false;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
/* center view */
|
2012-07-26 22:41:40 +00:00
|
|
|
clip_view_center_to_point(sc, (max[0] + min[0]) / (2 * frame_width),
|
|
|
|
(max[1] + min[1]) / (2 * frame_height));
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
w = max[0] - min[0];
|
|
|
|
h = max[1] - min[1];
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
/* set zoom to see all selection */
|
2012-03-25 23:19:21 +00:00
|
|
|
if (w > 0 && h > 0) {
|
2011-11-07 12:55:18 +00:00
|
|
|
int width, height;
|
|
|
|
float zoomx, zoomy, newzoom, aspx, aspy;
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
ED_space_clip_get_aspect(sc, &aspx, &aspy);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-09-15 11:48:20 +00:00
|
|
|
width = BLI_rcti_size_x(&ar->winrct) + 1;
|
|
|
|
height = BLI_rcti_size_y(&ar->winrct) + 1;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
zoomx = (float)width / w / aspx;
|
|
|
|
zoomy = (float)height / h / aspy;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-10-23 13:28:22 +00:00
|
|
|
newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy));
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-05-07 08:53:59 +00:00
|
|
|
if (fit || sc->zoom > newzoom)
|
2012-03-25 23:19:21 +00:00
|
|
|
sc->zoom = newzoom;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
return true;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
|
2019-03-05 18:33:09 +11:00
|
|
|
void ED_clip_select_all(SpaceClip *sc, int action, bool *r_has_selection)
|
|
|
|
{
|
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
|
|
|
const int framenr = ED_space_clip_get_clip_frame_number(sc);
|
|
|
|
MovieTracking *tracking = &clip->tracking;
|
|
|
|
MovieTrackingTrack *track = NULL; /* selected track */
|
|
|
|
MovieTrackingPlaneTrack *plane_track = NULL; /* selected plane track */
|
|
|
|
MovieTrackingMarker *marker;
|
|
|
|
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
|
|
|
|
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
|
|
|
|
bool has_selection = false;
|
|
|
|
|
|
|
|
if (action == SEL_TOGGLE) {
|
|
|
|
action = SEL_SELECT;
|
|
|
|
|
|
|
|
for (track = tracksbase->first; track; track = track->next) {
|
|
|
|
if (TRACK_VIEW_SELECTED(sc, track)) {
|
|
|
|
marker = BKE_tracking_marker_get(track, framenr);
|
|
|
|
|
|
|
|
if (MARKER_VISIBLE(sc, track, marker)) {
|
|
|
|
action = SEL_DESELECT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (plane_track = plane_tracks_base->first;
|
|
|
|
plane_track;
|
|
|
|
plane_track = plane_track->next)
|
|
|
|
{
|
|
|
|
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
|
|
|
|
action = SEL_DESELECT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (track = tracksbase->first; track; track = track->next) {
|
|
|
|
if ((track->flag & TRACK_HIDDEN) == 0) {
|
|
|
|
marker = BKE_tracking_marker_get(track, framenr);
|
|
|
|
|
|
|
|
if (MARKER_VISIBLE(sc, track, marker)) {
|
|
|
|
switch (action) {
|
|
|
|
case SEL_SELECT:
|
|
|
|
track->flag |= SELECT;
|
|
|
|
track->pat_flag |= SELECT;
|
|
|
|
track->search_flag |= SELECT;
|
|
|
|
break;
|
|
|
|
case SEL_DESELECT:
|
|
|
|
track->flag &= ~SELECT;
|
|
|
|
track->pat_flag &= ~SELECT;
|
|
|
|
track->search_flag &= ~SELECT;
|
|
|
|
break;
|
|
|
|
case SEL_INVERT:
|
|
|
|
track->flag ^= SELECT;
|
|
|
|
track->pat_flag ^= SELECT;
|
|
|
|
track->search_flag ^= SELECT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TRACK_VIEW_SELECTED(sc, track))
|
|
|
|
has_selection = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (plane_track = plane_tracks_base->first;
|
|
|
|
plane_track;
|
|
|
|
plane_track = plane_track->next)
|
|
|
|
{
|
|
|
|
if ((plane_track->flag & PLANE_TRACK_HIDDEN) == 0) {
|
|
|
|
switch (action) {
|
|
|
|
case SEL_SELECT:
|
|
|
|
plane_track->flag |= SELECT;
|
|
|
|
break;
|
|
|
|
case SEL_DESELECT:
|
|
|
|
plane_track->flag &= ~SELECT;
|
|
|
|
break;
|
|
|
|
case SEL_INVERT:
|
|
|
|
plane_track->flag ^= SELECT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (plane_track->flag & SELECT) {
|
|
|
|
has_selection = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r_has_selection) {
|
|
|
|
*r_has_selection = has_selection;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-11 20:50:57 +00:00
|
|
|
void ED_clip_point_undistorted_pos(SpaceClip *sc, const float co[2], float r_co[2])
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
2012-06-11 20:50:57 +00:00
|
|
|
copy_v2_v2(r_co, co);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
|
2012-06-19 14:26:29 +00:00
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
2012-03-25 23:19:21 +00:00
|
|
|
float aspy = 1.0f / clip->tracking.camera.pixel_aspect;
|
2011-11-07 12:55:18 +00:00
|
|
|
int width, height;
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
BKE_movieclip_get_size(sc->clip, &sc->user, &width, &height);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-06-11 20:50:57 +00:00
|
|
|
r_co[0] *= width;
|
|
|
|
r_co[1] *= height * aspy;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-06-15 11:03:23 +00:00
|
|
|
BKE_tracking_undistort_v2(&clip->tracking, r_co, r_co);
|
2012-03-25 23:19:21 +00:00
|
|
|
|
2012-06-11 20:50:57 +00:00
|
|
|
r_co[0] /= width;
|
|
|
|
r_co[1] /= height * aspy;
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-26 22:47:05 +00:00
|
|
|
void ED_clip_point_stable_pos(SpaceClip *sc, ARegion *ar, float x, float y, float *xr, float *yr)
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
|
|
|
int sx, sy, width, height;
|
2012-06-11 20:50:57 +00:00
|
|
|
float zoomx, zoomy, pos[3], imat[4][4];
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_zoom(sc, ar, &zoomx, &zoomy);
|
|
|
|
ED_space_clip_get_size(sc, &width, &height);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2014-04-21 16:47:16 +10:00
|
|
|
UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
pos[0] = (x - sx) / zoomx;
|
|
|
|
pos[1] = (y - sy) / zoomy;
|
2012-06-11 20:50:57 +00:00
|
|
|
pos[2] = 0.0f;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
|
|
|
invert_m4_m4(imat, sc->stabmat);
|
|
|
|
mul_v3_m4v3(pos, imat, pos);
|
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
*xr = pos[0] / width;
|
|
|
|
*yr = pos[1] / height;
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) {
|
2012-06-19 14:26:29 +00:00
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
2012-03-25 23:19:21 +00:00
|
|
|
MovieTracking *tracking = &clip->tracking;
|
|
|
|
float aspy = 1.0f / tracking->camera.pixel_aspect;
|
|
|
|
float tmp[2] = {*xr * width, *yr * height * aspy};
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-06-15 11:03:23 +00:00
|
|
|
BKE_tracking_distort_v2(tracking, tmp, tmp);
|
2011-11-07 12:55:18 +00:00
|
|
|
|
2012-03-25 23:19:21 +00:00
|
|
|
*xr = tmp[0] / width;
|
|
|
|
*yr = tmp[1] / (height * aspy);
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-14 12:04:00 +00:00
|
|
|
/**
|
2019-04-14 10:48:42 +02:00
|
|
|
* \brief the reverse of #ED_clip_point_stable_pos(), gets the marker region coords.
|
2012-05-14 12:50:36 +00:00
|
|
|
* better name here? view_to_track / track_to_view or so?
|
2012-05-14 12:04:00 +00:00
|
|
|
*/
|
2012-07-26 22:47:05 +00:00
|
|
|
void ED_clip_point_stable_pos__reverse(SpaceClip *sc, ARegion *ar, const float co[2], float r_co[2])
|
2012-05-14 12:04:00 +00:00
|
|
|
{
|
|
|
|
float zoomx, zoomy;
|
|
|
|
float pos[3];
|
|
|
|
int width, height;
|
|
|
|
int sx, sy;
|
|
|
|
|
2014-04-21 16:47:16 +10:00
|
|
|
UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &sx, &sy);
|
2012-07-26 22:41:40 +00:00
|
|
|
ED_space_clip_get_size(sc, &width, &height);
|
|
|
|
ED_space_clip_get_zoom(sc, ar, &zoomx, &zoomy);
|
2012-05-14 12:04:00 +00:00
|
|
|
|
|
|
|
ED_clip_point_undistorted_pos(sc, co, pos);
|
2012-06-11 20:50:57 +00:00
|
|
|
pos[2] = 0.0f;
|
2012-05-14 12:04:00 +00:00
|
|
|
|
|
|
|
/* untested */
|
|
|
|
mul_v3_m4v3(pos, sc->stabmat, pos);
|
|
|
|
|
2012-06-11 20:50:57 +00:00
|
|
|
r_co[0] = (pos[0] * width * zoomx) + (float)sx;
|
|
|
|
r_co[1] = (pos[1] * height * zoomy) + (float)sy;
|
2012-05-14 12:04:00 +00:00
|
|
|
}
|
|
|
|
|
2012-07-27 15:15:55 +00:00
|
|
|
/* takes event->mval */
|
|
|
|
void ED_clip_mouse_pos(SpaceClip *sc, ARegion *ar, const int mval[2], float co[2])
|
2011-11-07 12:55:18 +00:00
|
|
|
{
|
2012-07-27 15:15:55 +00:00
|
|
|
ED_clip_point_stable_pos(sc, ar, mval[0], mval[1], &co[0], &co[1]);
|
2011-11-07 12:55:18 +00:00
|
|
|
}
|
2012-04-29 12:32:26 +00:00
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
bool ED_space_clip_check_show_trackedit(SpaceClip *sc)
|
2012-06-20 10:28:51 +00:00
|
|
|
{
|
|
|
|
if (sc) {
|
2014-02-07 20:26:43 +06:00
|
|
|
return sc->mode == SC_MODE_TRACKING;
|
2012-06-20 10:28:51 +00:00
|
|
|
}
|
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
return false;
|
2012-06-20 10:28:51 +00:00
|
|
|
}
|
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
bool ED_space_clip_check_show_maskedit(SpaceClip *sc)
|
2012-06-20 10:28:51 +00:00
|
|
|
{
|
|
|
|
if (sc) {
|
|
|
|
return sc->mode == SC_MODE_MASKEDIT;
|
|
|
|
}
|
|
|
|
|
2013-09-05 13:37:53 +00:00
|
|
|
return false;
|
2012-06-20 10:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ******** clip editing functions ******** */
|
|
|
|
|
|
|
|
MovieClip *ED_space_clip_get_clip(SpaceClip *sc)
|
|
|
|
{
|
|
|
|
return sc->clip;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ED_space_clip_set_clip(bContext *C, bScreen *screen, SpaceClip *sc, MovieClip *clip)
|
|
|
|
{
|
|
|
|
MovieClip *old_clip;
|
2013-04-04 09:50:51 +00:00
|
|
|
bool old_clip_visible = false;
|
2012-06-20 10:28:51 +00:00
|
|
|
|
|
|
|
if (!screen && C)
|
|
|
|
screen = CTX_wm_screen(C);
|
|
|
|
|
|
|
|
old_clip = sc->clip;
|
|
|
|
sc->clip = clip;
|
|
|
|
|
2012-12-18 08:41:38 +00:00
|
|
|
id_us_ensure_real((ID *)sc->clip);
|
2012-06-20 10:28:51 +00:00
|
|
|
|
|
|
|
if (screen && sc->view == SC_VIEW_CLIP) {
|
|
|
|
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;
|
|
|
|
|
2013-04-04 09:50:51 +00:00
|
|
|
if (cur_sc != sc) {
|
|
|
|
if (cur_sc->view == SC_VIEW_CLIP) {
|
|
|
|
if (cur_sc->clip == old_clip)
|
|
|
|
old_clip_visible = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (cur_sc->clip == old_clip || cur_sc->clip == NULL) {
|
|
|
|
cur_sc->clip = clip;
|
|
|
|
}
|
2012-06-20 10:28:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-04 09:50:51 +00:00
|
|
|
/* If clip is no longer visible on screen, free memory used by it's cache */
|
|
|
|
if (old_clip && old_clip != clip && !old_clip_visible) {
|
|
|
|
BKE_movieclip_clear_cache(old_clip);
|
|
|
|
}
|
|
|
|
|
2012-06-20 10:28:51 +00:00
|
|
|
if (C)
|
|
|
|
WM_event_add_notifier(C, NC_MOVIECLIP | NA_SELECTED, sc->clip);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ******** masking editing functions ******** */
|
|
|
|
|
|
|
|
Mask *ED_space_clip_get_mask(SpaceClip *sc)
|
|
|
|
{
|
2012-07-24 20:33:55 +00:00
|
|
|
return sc->mask_info.mask;
|
2012-06-20 10:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ED_space_clip_set_mask(bContext *C, SpaceClip *sc, Mask *mask)
|
|
|
|
{
|
2012-07-24 20:33:55 +00:00
|
|
|
sc->mask_info.mask = mask;
|
2012-06-20 10:28:51 +00:00
|
|
|
|
2012-12-18 08:41:38 +00:00
|
|
|
id_us_ensure_real((ID *)sc->mask_info.mask);
|
2012-06-20 10:28:51 +00:00
|
|
|
|
|
|
|
if (C) {
|
|
|
|
WM_event_add_notifier(C, NC_MASK | NA_SELECTED, mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
/* ******** pre-fetching functions ******** */
|
|
|
|
|
|
|
|
typedef struct PrefetchJob {
|
|
|
|
MovieClip *clip;
|
2013-03-25 15:32:15 +00:00
|
|
|
int start_frame, current_frame, end_frame;
|
2013-03-20 17:03:20 +00:00
|
|
|
short render_size, render_flag;
|
|
|
|
} PrefetchJob;
|
|
|
|
|
|
|
|
typedef struct PrefetchQueue {
|
2013-03-25 15:32:15 +00:00
|
|
|
int initial_frame, current_frame, start_frame, end_frame;
|
2013-03-20 17:03:20 +00:00
|
|
|
short render_size, render_flag;
|
|
|
|
|
2014-01-01 23:23:12 +06:00
|
|
|
/* If true prefecthing goes forward in time,
|
2016-07-16 17:48:57 +10:00
|
|
|
* otherwise it goes backwards in time (starting from current frame).
|
2014-01-01 23:23:12 +06:00
|
|
|
*/
|
|
|
|
bool forward;
|
2013-03-25 15:32:15 +00:00
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
SpinLock spin;
|
|
|
|
|
|
|
|
short *stop;
|
|
|
|
short *do_update;
|
|
|
|
float *progress;
|
|
|
|
} PrefetchQueue;
|
|
|
|
|
|
|
|
/* check whether pre-fetching is allowed */
|
2013-04-04 09:50:38 +00:00
|
|
|
static bool check_prefetch_break(void)
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
2013-04-04 09:50:38 +00:00
|
|
|
return G.is_break;
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* read file for specified frame number to the memory */
|
2015-05-08 07:25:39 +10:00
|
|
|
static unsigned char *prefetch_read_file_to_memory(
|
|
|
|
MovieClip *clip, int current_frame, short render_size, short render_flag,
|
|
|
|
size_t *r_size)
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
|
|
|
MovieClipUser user = {0};
|
|
|
|
user.framenr = current_frame;
|
|
|
|
user.render_size = render_size;
|
|
|
|
user.render_flag = render_flag;
|
|
|
|
|
2019-02-21 10:52:03 +01:00
|
|
|
char name[FILE_MAX];
|
2013-03-20 17:03:20 +00:00
|
|
|
BKE_movieclip_filename_for_frame(clip, &user, name);
|
|
|
|
|
2019-02-21 10:52:03 +01:00
|
|
|
int file = BLI_open(name, O_BINARY | O_RDONLY, 0);
|
2014-04-22 16:40:17 +10:00
|
|
|
if (file == -1) {
|
2013-03-20 17:03:20 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-02-21 10:52:03 +01:00
|
|
|
const size_t size = BLI_file_descriptor_size(file);
|
2013-03-20 17:03:20 +00:00
|
|
|
if (size < 1) {
|
|
|
|
close(file);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-02-21 10:52:03 +01:00
|
|
|
unsigned char *mem = MEM_mallocN(size, "movieclip prefetch memory file");
|
|
|
|
if (mem == NULL) {
|
|
|
|
close(file);
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
if (read(file, mem, size) != size) {
|
|
|
|
close(file);
|
|
|
|
MEM_freeN(mem);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-05-08 07:25:39 +10:00
|
|
|
*r_size = size;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
close(file);
|
|
|
|
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find first uncached frame within prefetching frame range */
|
|
|
|
static int prefetch_find_uncached_frame(MovieClip *clip, int from_frame, int end_frame,
|
2013-03-25 15:32:15 +00:00
|
|
|
short render_size, short render_flag, short direction)
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
|
|
|
int current_frame;
|
2013-03-25 15:32:15 +00:00
|
|
|
MovieClipUser user = {0};
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
user.render_size = render_size;
|
|
|
|
user.render_flag = render_flag;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (direction > 0) {
|
|
|
|
for (current_frame = from_frame; current_frame <= end_frame; current_frame++) {
|
|
|
|
user.framenr = current_frame;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (!BKE_movieclip_has_cached_frame(clip, &user))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (current_frame = from_frame; current_frame >= end_frame; current_frame--) {
|
|
|
|
user.framenr = current_frame;
|
|
|
|
|
|
|
|
if (!BKE_movieclip_has_cached_frame(clip, &user))
|
|
|
|
break;
|
|
|
|
}
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return current_frame;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get memory buffer for first uncached frame within prefetch frame range */
|
2015-05-08 07:25:39 +10:00
|
|
|
static unsigned char *prefetch_thread_next_frame(
|
|
|
|
PrefetchQueue *queue, MovieClip *clip,
|
|
|
|
size_t *r_size, int *r_current_frame)
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
|
|
|
unsigned char *mem = NULL;
|
|
|
|
|
|
|
|
BLI_spin_lock(&queue->spin);
|
2013-04-04 09:50:38 +00:00
|
|
|
if (!*queue->stop && !check_prefetch_break() &&
|
2013-03-25 15:32:15 +00:00
|
|
|
IN_RANGE_INCL(queue->current_frame, queue->start_frame, queue->end_frame))
|
|
|
|
{
|
2013-03-20 17:03:20 +00:00
|
|
|
int current_frame;
|
|
|
|
|
2014-01-01 23:23:12 +06:00
|
|
|
if (queue->forward) {
|
2013-03-25 15:32:15 +00:00
|
|
|
current_frame = prefetch_find_uncached_frame(clip, queue->current_frame + 1, queue->end_frame,
|
|
|
|
queue->render_size, queue->render_flag, 1);
|
2013-10-12 14:47:04 +00:00
|
|
|
/* switch direction if read frames from current up to scene end frames */
|
2013-10-17 09:19:03 +00:00
|
|
|
if (current_frame > queue->end_frame) {
|
2013-10-12 14:47:04 +00:00
|
|
|
queue->current_frame = queue->initial_frame;
|
2014-01-01 23:23:12 +06:00
|
|
|
queue->forward = false;
|
2013-10-12 14:47:04 +00:00
|
|
|
}
|
2013-03-25 15:32:15 +00:00
|
|
|
}
|
2013-10-12 14:47:04 +00:00
|
|
|
|
2014-01-01 23:23:12 +06:00
|
|
|
if (!queue->forward) {
|
2013-03-25 15:32:15 +00:00
|
|
|
current_frame = prefetch_find_uncached_frame(clip, queue->current_frame - 1, queue->start_frame,
|
|
|
|
queue->render_size, queue->render_flag, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IN_RANGE_INCL(current_frame, queue->start_frame, queue->end_frame)) {
|
|
|
|
int frames_processed;
|
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
mem = prefetch_read_file_to_memory(clip, current_frame, queue->render_size,
|
2015-05-08 07:25:39 +10:00
|
|
|
queue->render_flag, r_size);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2015-05-08 07:25:39 +10:00
|
|
|
*r_current_frame = current_frame;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
queue->current_frame = current_frame;
|
|
|
|
|
2014-01-01 23:23:12 +06:00
|
|
|
if (queue->forward) {
|
2013-03-25 15:32:15 +00:00
|
|
|
frames_processed = queue->current_frame - queue->initial_frame;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
frames_processed = (queue->end_frame - queue->initial_frame) +
|
|
|
|
(queue->initial_frame - queue->current_frame);
|
|
|
|
}
|
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
*queue->do_update = 1;
|
2013-03-25 15:32:15 +00:00
|
|
|
*queue->progress = (float)frames_processed / (queue->end_frame - queue->start_frame);
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
BLI_spin_unlock(&queue->spin);
|
|
|
|
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
2015-12-21 13:00:06 +11:00
|
|
|
static void prefetch_task_func(TaskPool * __restrict pool, void *task_data, int UNUSED(threadid))
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
2014-10-10 02:54:40 +06:00
|
|
|
PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_userdata(pool);
|
|
|
|
MovieClip *clip = (MovieClip *)task_data;
|
2013-03-20 17:03:20 +00:00
|
|
|
unsigned char *mem;
|
|
|
|
size_t size;
|
|
|
|
int current_frame;
|
|
|
|
|
2014-10-10 02:54:40 +06:00
|
|
|
while ((mem = prefetch_thread_next_frame(queue, clip, &size, ¤t_frame))) {
|
2013-03-20 17:03:20 +00:00
|
|
|
ImBuf *ibuf;
|
|
|
|
MovieClipUser user = {0};
|
2019-02-05 16:50:57 +01:00
|
|
|
int flag = IB_rect | IB_multilayer | IB_alphamode_detect | IB_metadata;
|
2013-03-20 17:03:20 +00:00
|
|
|
int result;
|
2014-03-10 16:46:05 +06:00
|
|
|
char *colorspace_name = NULL;
|
2015-05-18 16:40:12 +05:00
|
|
|
const bool use_proxy = (clip->flag & MCLIP_USE_PROXY) &&
|
|
|
|
(queue->render_size != MCLIP_PROXY_RENDER_SIZE_FULL);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
user.framenr = current_frame;
|
2014-10-10 02:54:40 +06:00
|
|
|
user.render_size = queue->render_size;
|
|
|
|
user.render_flag = queue->render_flag;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2014-03-10 16:46:05 +06:00
|
|
|
/* Proxies are stored in the display space. */
|
2015-05-18 16:40:12 +05:00
|
|
|
if (!use_proxy) {
|
2014-03-10 16:46:05 +06:00
|
|
|
colorspace_name = clip->colorspace_settings.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
ibuf = IMB_ibImageFromMemory(mem, size, flag, colorspace_name, "prefetch frame");
|
2019-02-05 16:50:57 +01:00
|
|
|
if (ibuf == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
BKE_movieclip_convert_multilayer_ibuf(ibuf);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2014-10-10 02:54:40 +06:00
|
|
|
result = BKE_movieclip_put_frame_if_possible(clip, &user, ibuf);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
|
|
|
|
MEM_freeN(mem);
|
|
|
|
|
|
|
|
if (!result) {
|
|
|
|
/* no more space in the cache, stop reading frames */
|
2014-10-10 02:54:40 +06:00
|
|
|
*queue->stop = 1;
|
2013-03-20 17:03:20 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
static void start_prefetch_threads(MovieClip *clip, int start_frame, int current_frame, int end_frame,
|
|
|
|
short render_size, short render_flag, short *stop, short *do_update,
|
|
|
|
float *progress)
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
|
|
|
PrefetchQueue queue;
|
2014-10-10 02:54:40 +06:00
|
|
|
TaskScheduler *task_scheduler = BLI_task_scheduler_get();
|
|
|
|
TaskPool *task_pool;
|
|
|
|
int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
/* initialize queue */
|
|
|
|
BLI_spin_init(&queue.spin);
|
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
queue.current_frame = current_frame;
|
|
|
|
queue.initial_frame = current_frame;
|
2013-03-20 17:03:20 +00:00
|
|
|
queue.start_frame = start_frame;
|
|
|
|
queue.end_frame = end_frame;
|
|
|
|
queue.render_size = render_size;
|
|
|
|
queue.render_flag = render_flag;
|
2014-01-01 23:23:12 +06:00
|
|
|
queue.forward = 1;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
queue.stop = stop;
|
|
|
|
queue.do_update = do_update;
|
|
|
|
queue.progress = progress;
|
|
|
|
|
2014-10-10 02:54:40 +06:00
|
|
|
task_pool = BLI_task_pool_create(task_scheduler, &queue);
|
2013-03-20 17:03:20 +00:00
|
|
|
for (i = 0; i < tot_thread; i++) {
|
2014-10-10 02:54:40 +06:00
|
|
|
BLI_task_pool_push(task_pool,
|
|
|
|
prefetch_task_func,
|
|
|
|
clip,
|
|
|
|
false,
|
|
|
|
TASK_PRIORITY_LOW);
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
2014-10-10 02:54:40 +06:00
|
|
|
BLI_task_pool_work_and_wait(task_pool);
|
|
|
|
BLI_task_pool_free(task_pool);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2014-10-10 02:54:40 +06:00
|
|
|
BLI_spin_end(&queue.spin);
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
static bool prefetch_movie_frame(MovieClip *clip, int frame, short render_size,
|
|
|
|
short render_flag, short *stop)
|
2013-03-20 17:03:20 +00:00
|
|
|
{
|
2013-03-25 15:32:15 +00:00
|
|
|
MovieClipUser user = {0};
|
|
|
|
ImBuf *ibuf;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-04-04 09:50:38 +00:00
|
|
|
if (check_prefetch_break() || *stop)
|
2013-03-25 15:32:15 +00:00
|
|
|
return false;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
user.framenr = frame;
|
|
|
|
user.render_size = render_size;
|
|
|
|
user.render_flag = render_flag;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (!BKE_movieclip_has_cached_frame(clip, &user)) {
|
|
|
|
ibuf = BKE_movieclip_anim_ibuf_for_frame(clip, &user);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (ibuf) {
|
|
|
|
int result;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
result = BKE_movieclip_put_frame_if_possible(clip, &user, ibuf);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (!result) {
|
|
|
|
/* no more space in the cache, we could stop prefetching here */
|
2013-03-20 17:03:20 +00:00
|
|
|
*stop = 1;
|
|
|
|
}
|
2013-03-25 15:32:15 +00:00
|
|
|
|
|
|
|
IMB_freeImBuf(ibuf);
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
2013-03-25 15:32:15 +00:00
|
|
|
else {
|
|
|
|
/* error reading frame, fair enough stop attempting further reading */
|
|
|
|
*stop = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void do_prefetch_movie(MovieClip *clip, int start_frame, int current_frame, int end_frame,
|
|
|
|
short render_size, short render_flag, short *stop, short *do_update,
|
|
|
|
float *progress)
|
|
|
|
{
|
|
|
|
int frame;
|
|
|
|
int frames_processed = 0;
|
|
|
|
|
|
|
|
/* read frames starting from current frame up to scene end frame */
|
|
|
|
for (frame = current_frame; frame <= end_frame; frame++) {
|
|
|
|
if (!prefetch_movie_frame(clip, frame, render_size, render_flag, stop))
|
|
|
|
return;
|
|
|
|
|
|
|
|
frames_processed++;
|
|
|
|
|
|
|
|
*do_update = 1;
|
|
|
|
*progress = (float) frames_processed / (end_frame - start_frame);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* read frames starting from current frame up to scene start frame */
|
|
|
|
for (frame = current_frame; frame >= start_frame; frame--) {
|
|
|
|
if (!prefetch_movie_frame(clip, frame, render_size, render_flag, stop))
|
|
|
|
return;
|
|
|
|
|
|
|
|
frames_processed++;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
*do_update = 1;
|
2013-03-25 15:32:15 +00:00
|
|
|
*progress = (float) frames_processed / (end_frame - start_frame);
|
2013-03-20 17:03:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void prefetch_startjob(void *pjv, short *stop, short *do_update, float *progress)
|
|
|
|
{
|
|
|
|
PrefetchJob *pj = pjv;
|
|
|
|
|
|
|
|
if (pj->clip->source == MCLIP_SRC_SEQUENCE) {
|
|
|
|
/* read sequence files in multiple threads */
|
2013-03-25 15:32:15 +00:00
|
|
|
start_prefetch_threads(pj->clip, pj->start_frame, pj->current_frame, pj->end_frame,
|
2013-03-20 17:03:20 +00:00
|
|
|
pj->render_size, pj->render_flag,
|
|
|
|
stop, do_update, progress);
|
|
|
|
}
|
|
|
|
else if (pj->clip->source == MCLIP_SRC_MOVIE) {
|
|
|
|
/* read movie in a single thread */
|
2013-03-25 15:32:15 +00:00
|
|
|
do_prefetch_movie(pj->clip, pj->start_frame, pj->current_frame, pj->end_frame,
|
2013-03-20 17:03:20 +00:00
|
|
|
pj->render_size, pj->render_flag,
|
|
|
|
stop, do_update, progress);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_assert(!"Unknown movie clip source when prefetching frames");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void prefetch_freejob(void *pjv)
|
|
|
|
{
|
|
|
|
PrefetchJob *pj = pjv;
|
|
|
|
|
|
|
|
MEM_freeN(pj);
|
|
|
|
}
|
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
static int prefetch_get_start_frame(const bContext *C)
|
|
|
|
{
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
|
|
|
return SFRA;
|
|
|
|
}
|
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
static int prefetch_get_final_frame(const bContext *C)
|
|
|
|
{
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
|
|
|
int end_frame;
|
|
|
|
|
|
|
|
/* check whether all the frames from prefetch range are cached */
|
2013-03-21 07:47:38 +00:00
|
|
|
end_frame = EFRA;
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2019-03-04 15:22:14 +01:00
|
|
|
if (clip->len) {
|
|
|
|
end_frame = min_ii(end_frame, SFRA + clip->len - 1);
|
|
|
|
}
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
return end_frame;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns true if early out is possible */
|
|
|
|
static bool prefetch_check_early_out(const bContext *C)
|
|
|
|
{
|
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
|
|
MovieClip *clip = ED_space_clip_get_clip(sc);
|
|
|
|
int first_uncached_frame, end_frame;
|
|
|
|
int clip_len;
|
|
|
|
|
2014-03-20 12:39:02 +06:00
|
|
|
if (clip == NULL) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
clip_len = BKE_movieclip_get_duration(clip);
|
|
|
|
|
|
|
|
/* check whether all the frames from prefetch range are cached */
|
|
|
|
end_frame = prefetch_get_final_frame(C);
|
|
|
|
|
|
|
|
first_uncached_frame =
|
|
|
|
prefetch_find_uncached_frame(clip, sc->user.framenr, end_frame,
|
2013-03-25 15:32:15 +00:00
|
|
|
sc->user.render_size, sc->user.render_flag, 1);
|
2013-03-20 17:03:20 +00:00
|
|
|
|
2013-03-25 15:32:15 +00:00
|
|
|
if (first_uncached_frame > end_frame || first_uncached_frame == clip_len) {
|
|
|
|
int start_frame = prefetch_get_start_frame(C);
|
|
|
|
|
|
|
|
first_uncached_frame =
|
|
|
|
prefetch_find_uncached_frame(clip, sc->user.framenr, start_frame,
|
|
|
|
sc->user.render_size, sc->user.render_flag, -1);
|
|
|
|
|
|
|
|
if (first_uncached_frame < start_frame)
|
|
|
|
return true;
|
|
|
|
}
|
2013-03-20 17:03:20 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void clip_start_prefetch_job(const bContext *C)
|
|
|
|
{
|
|
|
|
wmJob *wm_job;
|
|
|
|
PrefetchJob *pj;
|
|
|
|
SpaceClip *sc = CTX_wm_space_clip(C);
|
|
|
|
|
|
|
|
if (prefetch_check_early_out(C))
|
|
|
|
return;
|
|
|
|
|
|
|
|
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_area(C), "Prefetching",
|
|
|
|
WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_PREFETCH);
|
|
|
|
|
|
|
|
/* create new job */
|
|
|
|
pj = MEM_callocN(sizeof(PrefetchJob), "prefetch job");
|
|
|
|
pj->clip = ED_space_clip_get_clip(sc);
|
2013-03-25 15:32:15 +00:00
|
|
|
pj->start_frame = prefetch_get_start_frame(C);
|
|
|
|
pj->current_frame = sc->user.framenr;
|
2013-03-20 17:03:20 +00:00
|
|
|
pj->end_frame = prefetch_get_final_frame(C);
|
|
|
|
pj->render_size = sc->user.render_size;
|
|
|
|
pj->render_flag = sc->user.render_flag;
|
|
|
|
|
|
|
|
WM_jobs_customdata_set(wm_job, pj, prefetch_freejob);
|
2013-04-04 09:50:38 +00:00
|
|
|
WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | ND_DISPLAY, 0);
|
2013-03-20 17:03:20 +00:00
|
|
|
WM_jobs_callbacks(wm_job, prefetch_startjob, NULL, NULL, NULL);
|
|
|
|
|
2014-03-20 15:52:00 +06:00
|
|
|
G.is_break = false;
|
2013-04-04 09:50:38 +00:00
|
|
|
|
2013-03-20 17:03:20 +00:00
|
|
|
/* and finally start the job */
|
|
|
|
WM_jobs_start(CTX_wm_manager(C), wm_job);
|
|
|
|
}
|