/* * ***** 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) 2011 Blender Foundation. * All rights reserved. * * * Contributor(s): Blender Foundation, * Sergey Sharybin * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/editors/space_clip/clip_draw.c * \ingroup spclip */ #include "DNA_gpencil_types.h" #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" /* SELECT */ #include "MEM_guardedalloc.h" #include "BKE_context.h" #include "BKE_movieclip.h" #include "BKE_tracking.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_string.h" #include "BLI_rect.h" #include "BLI_math_base.h" #include "ED_screen.h" #include "ED_clip.h" #include "ED_gpencil.h" #include "BIF_gl.h" #include "BIF_glutil.h" #include "WM_api.h" #include "WM_types.h" #include "UI_interface.h" #include "UI_resources.h" #include "UI_view2d.h" #include "RNA_access.h" #include "BLF_api.h" #include "clip_intern.h" // own include /*********************** main area drawing *************************/ void clip_draw_curfra_label(SpaceClip *sc, float x, float y) { uiStyle *style= UI_GetStyle(); int fontid= style->widget.uifont_id; char numstr[32]; float font_dims[2] = {0.0f, 0.0f}; /* frame number */ BLF_size(fontid, 11.0f, U.dpi); BLI_snprintf(numstr, sizeof(numstr), "%d", sc->user.framenr); BLF_width_and_height(fontid, numstr, &font_dims[0], &font_dims[1]); glRecti(x, y, x + font_dims[0] + 6.0f, y + font_dims[1] + 4.0f); UI_ThemeColor(TH_TEXT); BLF_position(fontid, x+2.0f, y+2.0f, 0.0f); BLF_draw(fontid, numstr, sizeof(numstr)); } static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Scene *scene) { float x; int *points, totseg, i, a; float sfra= SFRA, efra= EFRA, framelen= ar->winx/(efra-sfra+1); MovieTrackingTrack *act_track= BKE_tracking_active_track(&clip->tracking); MovieTrackingReconstruction *reconstruction= BKE_tracking_get_reconstruction(&clip->tracking); glEnable(GL_BLEND); /* cache background */ glColor4ub(128, 128, 255, 64); glRecti(0, 0, ar->winx, 8); /* cached segments -- could be usefu lto debug caching strategies */ BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points); if(totseg) { glColor4ub(128, 128, 255, 128); for(a= 0; awinx; x2= (points[a*2+1]-sfra+1)/(efra-sfra+1)*ar->winx; glRecti(x1, 0, x2, 8); } } /* track */ if(act_track) { MovieTrackingTrack *track= act_track; for(i= sfra, a= 0; i <= efra; i++) { int framenr; MovieTrackingMarker *marker; while(amarkersnr) { if(track->markers[a].framenr>=i) break; if(amarkersnr-1 && track->markers[a+1].framenr>i) break; a++; } if(amarkersnr) marker= &track->markers[a]; else marker= &track->markers[track->markersnr-1]; if((marker->flag&MARKER_DISABLED)==0) { framenr= marker->framenr; if(framenr!=i) glColor4ub(128, 128, 0, 96); else if((marker->flag&MARKER_TRACKED)==0) glColor4ub(255, 255, 0, 196); else glColor4ub(255, 255, 0, 96); glRecti((i-sfra)*framelen, 0, (i-sfra+1)*framelen, 4); } } } /* failed frames */ if(reconstruction->flag&TRACKING_RECONSTRUCTED) { int n= reconstruction->camnr; MovieReconstructedCamera *cameras= reconstruction->cameras; glColor4ub(255, 0, 0, 96); for(i= sfra, a= 0; i <= efra; i++) { int ok= 0; while(ai) { break; } a++; } if(!ok) glRecti((i-sfra)*framelen, 0, (i-sfra+1)*framelen, 8); } } glDisable(GL_BLEND); /* current frame */ x= (sc->user.framenr-sfra)/(efra-sfra+1)*ar->winx; UI_ThemeColor(TH_CFRAME); glRecti(x, 0, x+framelen, 8); clip_draw_curfra_label(sc, x, 8.0f); } static void draw_movieclip_notes(SpaceClip *sc, ARegion *ar) { MovieClip *clip= ED_space_clip(sc); MovieTracking *tracking= &clip->tracking; char str[256]= {0}; int block= 0; if(tracking->stats) { BLI_strncpy(str, tracking->stats->message, sizeof(str)); block= 1; } else { if(sc->flag&SC_LOCK_SELECTION) strcpy(str, "Locked"); } if(str[0]) ED_region_info_draw(ar, str, block, 0.6f); } static void draw_movieclip_buffer(SpaceClip *sc, ARegion *ar, ImBuf *ibuf, int width, int height, float zoomx, float zoomy) { int x, y; MovieClip *clip= ED_space_clip(sc); /* set zoom */ glPixelZoom(zoomx*width/ibuf->x, zoomy*height/ibuf->y); /* find window pixel coordinates of origin */ UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y); if(sc->flag&SC_MUTE_FOOTAGE) { glColor3f(0.0f, 0.0f, 0.0f); glRectf(x, y, x+zoomx*width, y+zoomy*height); } else { if(ibuf->rect_float && !ibuf->rect) { IMB_rect_from_float(ibuf); } if(ibuf->rect) glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); } /* draw boundary border for frame if stabilization is enabled */ if(sc->flag&SC_SHOW_STABLE && clip->tracking.stabilization.flag&TRACKING_2D_STABILIZATION) { glColor3f(0.0f, 0.0f, 0.0f); glLineStipple(3, 0xaaaa); glEnable(GL_LINE_STIPPLE); glEnable(GL_COLOR_LOGIC_OP); glLogicOp(GL_NOR); glPushMatrix(); glTranslatef(x, y, 0); glScalef(zoomx, zoomy, 0); glMultMatrixf(sc->stabmat); glBegin(GL_LINE_LOOP); glVertex2f(0.0f, 0.0f); glVertex2f(width, 0.0f); glVertex2f(width, height); glVertex2f(0.0f, height); glEnd(); glPopMatrix(); glDisable(GL_COLOR_LOGIC_OP); glDisable(GL_LINE_STIPPLE); } /* reset zoom */ glPixelZoom(1.0f, 1.0f); } static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track) { int count= sc->path_length; int i, a, b, curindex= -1; float path[102][2]; int tiny= sc->flag&SC_SHOW_TINY_MARKER, framenr; MovieTrackingMarker *marker; if(count==0) return; marker= BKE_tracking_get_marker(track, sc->user.framenr); if(marker->framenr!=sc->user.framenr || marker->flag&MARKER_DISABLED) return; framenr= marker->framenr; a= count; i= framenr-1; while(i>=framenr-count) { marker= BKE_tracking_get_marker(track, i); if(!marker || marker->flag&MARKER_DISABLED) break; if(marker->framenr==i) { add_v2_v2v2(path[--a], marker->pos, track->offset); ED_clip_point_undistorted_pos(sc, path[a], path[a]); if(marker->framenr==sc->user.framenr) curindex= a; } else break; i--; } b= count; i= framenr; while(i<=framenr+count) { marker= BKE_tracking_get_marker(track, i); if(!marker || marker->flag&MARKER_DISABLED) break; if(marker->framenr==i) { if(marker->framenr==sc->user.framenr) curindex= b; add_v2_v2v2(path[b++], marker->pos, track->offset); ED_clip_point_undistorted_pos(sc, path[b-1], path[b-1]); } else break; i++; } if(!tiny) { UI_ThemeColor(TH_MARKER_OUTLINE); if(TRACK_VIEW_SELECTED(sc, track)) { glPointSize(5.0f); glBegin(GL_POINTS); for(i= a; iflag&SC_SHOW_TINY_MARKER; int show_search= 0; float px[2]; UI_ThemeColor(TH_MARKER_OUTLINE); px[0]= 1.0f/width/sc->zoom; px[1]= 1.0f/height/sc->zoom; if((marker->flag&MARKER_DISABLED)==0) { float pos[2]; rctf r; BLI_init_rctf(&r, track->pat_min[0], track->pat_max[0], track->pat_min[1], track->pat_max[1]); add_v2_v2v2(pos, marker->pos, track->offset); ED_clip_point_undistorted_pos(sc, pos, pos); if(BLI_in_rctf(&r, pos[0]-marker_pos[0], pos[1]-marker_pos[1])) { if(tiny) glPointSize(3.0f); else glPointSize(4.0f); glBegin(GL_POINTS); glVertex2f(pos[0], pos[1]); glEnd(); glPointSize(1.0f); } else { if(!tiny) glLineWidth(3.0f); glBegin(GL_LINES); glVertex2f(pos[0] + px[0]*2, pos[1]); glVertex2f(pos[0] + px[0]*8, pos[1]); glVertex2f(pos[0] - px[0]*2, pos[1]); glVertex2f(pos[0] - px[0]*8, pos[1]); glVertex2f(pos[0], pos[1] - px[1]*2); glVertex2f(pos[0], pos[1] - px[1]*8); glVertex2f(pos[0], pos[1] + px[1]*2); glVertex2f(pos[0], pos[1] + px[1]*8); glEnd(); if(!tiny) glLineWidth(1.0f); } } /* pattern and search outline */ glPushMatrix(); glTranslatef(marker_pos[0], marker_pos[1], 0); if(!tiny) glLineWidth(3.0f); if(sc->flag&SC_SHOW_MARKER_PATTERN) { glBegin(GL_LINE_LOOP); glVertex2f(track->pat_min[0], track->pat_min[1]); glVertex2f(track->pat_max[0], track->pat_min[1]); glVertex2f(track->pat_max[0], track->pat_max[1]); glVertex2f(track->pat_min[0], track->pat_max[1]); glEnd(); } show_search= TRACK_VIEW_SELECTED(sc, track) && ((marker->flag&MARKER_DISABLED)==0 || (sc->flag&SC_SHOW_MARKER_PATTERN)==0); if(sc->flag&SC_SHOW_MARKER_SEARCH && show_search) { glBegin(GL_LINE_LOOP); glVertex2f(track->search_min[0], track->search_min[1]); glVertex2f(track->search_max[0], track->search_min[1]); glVertex2f(track->search_max[0], track->search_max[1]); glVertex2f(track->search_min[0], track->search_max[1]); glEnd(); } glPopMatrix(); if(!tiny) glLineWidth(1.0f); } static void track_colors(MovieTrackingTrack *track, int act, float col[3], float scol[3]) { if(track->flag&TRACK_CUSTOMCOLOR) { if(act) UI_GetThemeColor3fv(TH_ACT_MARKER, scol); else copy_v3_v3(scol, track->color); mul_v3_v3fl(col, track->color, 0.5f); } else { UI_GetThemeColor3fv(TH_MARKER, col); if(act) UI_GetThemeColor3fv(TH_ACT_MARKER, scol); else UI_GetThemeColor3fv(TH_SEL_MARKER, scol); } } static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker, float marker_pos[2], int width, int height, int act, int sel) { int tiny= sc->flag&SC_SHOW_TINY_MARKER; int show_search= 0; float col[3], scol[3], px[2]; track_colors(track, act, col, scol); px[0]= 1.0f/width/sc->zoom; px[1]= 1.0f/height/sc->zoom; /* marker position and offset position */ if((track->flag&SELECT)==sel && (marker->flag&MARKER_DISABLED)==0) { float pos[2]; rctf r; if(track->flag&TRACK_LOCKED) { if(act) UI_ThemeColor(TH_ACT_MARKER); else if(track->flag&SELECT) UI_ThemeColorShade(TH_LOCK_MARKER, 64); else UI_ThemeColor(TH_LOCK_MARKER); } else { if(track->flag&SELECT) glColor3fv(scol); else glColor3fv(col); } BLI_init_rctf(&r, track->pat_min[0], track->pat_max[0], track->pat_min[1], track->pat_max[1]); add_v2_v2v2(pos, marker->pos, track->offset); ED_clip_point_undistorted_pos(sc, pos, pos); if(BLI_in_rctf(&r, pos[0]-marker_pos[0], pos[1]-marker_pos[1])) { if(!tiny) glPointSize(2.0f); glBegin(GL_POINTS); glVertex2f(pos[0], pos[1]); glEnd(); if(!tiny) glPointSize(1.0f); } else { glBegin(GL_LINES); glVertex2f(pos[0] + px[0]*3, pos[1]); glVertex2f(pos[0] + px[0]*7, pos[1]); glVertex2f(pos[0] - px[0]*3, pos[1]); glVertex2f(pos[0] - px[0]*7, pos[1]); glVertex2f(pos[0], pos[1] - px[1]*3); glVertex2f(pos[0], pos[1] - px[1]*7); glVertex2f(pos[0], pos[1] + px[1]*3); glVertex2f(pos[0], pos[1] + px[1]*7); glEnd(); glColor3f(0.0f, 0.0f, 0.0f); glLineStipple(3, 0xaaaa); glEnable(GL_LINE_STIPPLE); glEnable(GL_COLOR_LOGIC_OP); glLogicOp(GL_NOR); glBegin(GL_LINES); glVertex2fv(pos); glVertex2fv(marker_pos); glEnd(); glDisable(GL_COLOR_LOGIC_OP); glDisable(GL_LINE_STIPPLE); } } /* pattern */ glPushMatrix(); glTranslatef(marker_pos[0], marker_pos[1], 0); if(tiny) { glLineStipple(3, 0xaaaa); glEnable(GL_LINE_STIPPLE); } if((track->pat_flag&SELECT)==sel && (sc->flag&SC_SHOW_MARKER_PATTERN)) { if(track->flag&TRACK_LOCKED) { if(act) UI_ThemeColor(TH_ACT_MARKER); else if(track->pat_flag&SELECT) UI_ThemeColorShade(TH_LOCK_MARKER, 64); else UI_ThemeColor(TH_LOCK_MARKER); } else if(marker->flag&MARKER_DISABLED) { if(act) UI_ThemeColor(TH_ACT_MARKER); else if(track->pat_flag&SELECT) UI_ThemeColorShade(TH_DIS_MARKER, 128); else UI_ThemeColor(TH_DIS_MARKER); } else { if(track->pat_flag&SELECT) glColor3fv(scol); else glColor3fv(col); } glBegin(GL_LINE_LOOP); glVertex2f(track->pat_min[0], track->pat_min[1]); glVertex2f(track->pat_max[0], track->pat_min[1]); glVertex2f(track->pat_max[0], track->pat_max[1]); glVertex2f(track->pat_min[0], track->pat_max[1]); glEnd(); } /* search */ show_search= TRACK_VIEW_SELECTED(sc, track) && ((marker->flag&MARKER_DISABLED)==0 || (sc->flag&SC_SHOW_MARKER_PATTERN)==0); if((track->search_flag&SELECT)==sel && (sc->flag&SC_SHOW_MARKER_SEARCH) && show_search) { if(track->flag&TRACK_LOCKED) { if(act) UI_ThemeColor(TH_ACT_MARKER); else if(track->search_flag&SELECT) UI_ThemeColorShade(TH_LOCK_MARKER, 64); else UI_ThemeColor(TH_LOCK_MARKER); } else if(marker->flag&MARKER_DISABLED) { if(act) UI_ThemeColor(TH_ACT_MARKER); else if(track->search_flag&SELECT) UI_ThemeColorShade(TH_DIS_MARKER, 128); else UI_ThemeColor(TH_DIS_MARKER); } else { if(track->search_flag&SELECT) glColor3fv(scol); else glColor3fv(col); } glBegin(GL_LINE_LOOP); glVertex2f(track->search_min[0], track->search_min[1]); glVertex2f(track->search_max[0], track->search_min[1]); glVertex2f(track->search_max[0], track->search_max[1]); glVertex2f(track->search_min[0], track->search_max[1]); glEnd(); } /* pyramid */ if(sel && TRACK_SELECTED(track) && (track->tracker==TRACKER_KLT) && (marker->flag&MARKER_DISABLED)==0) { if(track->flag&TRACK_LOCKED) { if(act) UI_ThemeColor(TH_ACT_MARKER); else if(track->pat_flag&SELECT) UI_ThemeColorShade(TH_LOCK_MARKER, 64); else UI_ThemeColor(TH_LOCK_MARKER); } else if(marker->flag&MARKER_DISABLED) { if(act) UI_ThemeColor(TH_ACT_MARKER); else if(track->pat_flag&SELECT) UI_ThemeColorShade(TH_DIS_MARKER, 128); else UI_ThemeColor(TH_DIS_MARKER); } else { if(track->pat_flag&SELECT) glColor3fv(scol); else glColor3fv(col); } { int i = 0; glPushMatrix(); glEnable(GL_LINE_STIPPLE); for (i = 1; i < track->pyramid_levels; ++i) { glScalef(2.0f, 2.0f, 1.0); } /* only draw a pattern for the coarsest level */ glBegin(GL_LINE_LOOP); glVertex2f(track->pat_min[0], track->pat_min[1]); glVertex2f(track->pat_max[0], track->pat_min[1]); glVertex2f(track->pat_max[0], track->pat_max[1]); glVertex2f(track->pat_min[0], track->pat_max[1]); glEnd(); glDisable(GL_LINE_STIPPLE); glPopMatrix(); } } if(tiny) glDisable(GL_LINE_STIPPLE); glPopMatrix(); } static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker, float marker_pos[2], int outline, int sel, int act, int width, int height) { float x, y, dx, dy, patdx, patdy, searchdx, searchdy, tdx, tdy; int tiny= sc->flag&SC_SHOW_TINY_MARKER; float col[3], scol[3], px[2]; if((tiny && outline) || (marker->flag&MARKER_DISABLED)) return; if(!TRACK_VIEW_SELECTED(sc, track) || track->flag&TRACK_LOCKED) return; track_colors(track, act, col, scol); if(outline) { glLineWidth(3.0f); UI_ThemeColor(TH_MARKER_OUTLINE); } glPushMatrix(); glTranslatef(marker_pos[0], marker_pos[1], 0); dx= 6.0f/width/sc->zoom; dy= 6.0f/height/sc->zoom; patdx= MIN2(dx*2.0f/3.0f, (track->pat_max[0]-track->pat_min[0])/6.0f); patdy= MIN2(dy*2.0f/3.0f, (track->pat_max[1]-track->pat_min[1])/6.0f); searchdx= MIN2(dx, (track->search_max[0]-track->search_min[0])/6.0f); searchdy= MIN2(dy, (track->search_max[1]-track->search_min[1])/6.0f); px[0]= 1.0f/sc->zoom/width/sc->scale; px[1]= 1.0f/sc->zoom/height/sc->scale; if((sc->flag&SC_SHOW_MARKER_SEARCH) && ((track->search_flag&SELECT)==sel || outline)) { if(!outline) { if(track->search_flag&SELECT) glColor3fv(scol); else glColor3fv(col); } /* search offset square */ x= track->search_min[0]; y= track->search_max[1]; tdx= searchdx; tdy= searchdy; if(outline) { tdx+= px[0]; tdy+= px[1]; } glBegin(GL_QUADS); glVertex3f(x-tdx, y+tdy, 0); glVertex3f(x+tdx, y+tdy, 0); glVertex3f(x+tdx, y-tdy, 0); glVertex3f(x-tdx, y-tdy, 0); glEnd(); /* search resizing triangle */ x= track->search_max[0]; y= track->search_min[1]; tdx= searchdx*2.0f; tdy= searchdy*2.0f; if(outline) { tdx+= px[0]; tdy+= px[1]; } glBegin(GL_TRIANGLES); glVertex3f(x, y, 0); glVertex3f(x-tdx, y, 0); glVertex3f(x, y+tdy, 0); glEnd(); } if((sc->flag&SC_SHOW_MARKER_PATTERN) && ((track->pat_flag&SELECT)==sel || outline)) { if(!outline) { if(track->pat_flag&SELECT) glColor3fv(scol); else glColor3fv(col); } /* pattern offset square */ x= track->pat_min[0]; y= track->pat_max[1]; tdx= patdx; tdy= patdy; if(outline) { tdx+= px[0]; tdy+= px[1]; } glBegin(GL_QUADS); glVertex3f(x-tdx, y+tdy, 0); glVertex3f(x+tdx, y+tdy, 0); glVertex3f(x+tdx, y-tdy, 0); glVertex3f(x-tdx, y-tdy, 0); glEnd(); /* pattern resizing triangle */ x= track->pat_max[0]; y= track->pat_min[1]; tdx= patdx*2.0f; tdy= patdy*2.0f; if(outline) { tdx+= px[0]; tdy+= px[1]; } glBegin(GL_TRIANGLES); glVertex3f(x, y, 0); glVertex3f(x-tdx, y, 0); glVertex3f(x, y+tdy, 0); glEnd(); } glPopMatrix(); if(outline) glLineWidth(1.0f); } static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker, float marker_pos[2], int act, int width, int height, float zoomx, float zoomy) { char str[128]= {0}, state[64]= {0}; float dx= 0.0f, dy= 0.0f, fontsize, pos[3]; uiStyle *style= U.uistyles.first; int fontid= style->widget.uifont_id; if(!TRACK_VIEW_SELECTED(sc, track)) return; BLF_size(fontid, 11.0f, U.dpi); fontsize= BLF_height_max(fontid); if(marker->flag&MARKER_DISABLED) { if(act) UI_ThemeColor(TH_ACT_MARKER); else UI_ThemeColorShade(TH_DIS_MARKER, 128); } else { if(act) UI_ThemeColor(TH_ACT_MARKER); else UI_ThemeColor(TH_SEL_MARKER); } if((sc->flag&SC_SHOW_MARKER_SEARCH) && ((marker->flag&MARKER_DISABLED)==0 || (sc->flag&SC_SHOW_MARKER_PATTERN)==0)) { dx= track->search_min[0]; dy= track->search_min[1]; } else if(sc->flag&SC_SHOW_MARKER_PATTERN) { dx= track->pat_min[0]; dy= track->pat_min[1]; } pos[0]= (marker_pos[0]+dx)*width; pos[1]= (marker_pos[1]+dy)*height; pos[2]= 0.0f; mul_m4_v3(sc->stabmat, pos); pos[0]= pos[0]*zoomx; pos[1]= pos[1]*zoomy - fontsize; if(marker->flag&MARKER_DISABLED) strcpy(state, "disabled"); else if(marker->framenr!=sc->user.framenr) strcpy(state, "estimated"); else if(marker->flag&MARKER_TRACKED) strcpy(state, "tracked"); else strcpy(state, "keyframed"); if(state[0]) BLI_snprintf(str, sizeof(str), "%s: %s", track->name, state); else BLI_snprintf(str, sizeof(str), "%s", track->name); BLF_position(fontid, pos[0], pos[1], 0.0f); BLF_draw(fontid, str, sizeof(str)); pos[1]-= fontsize; if(track->flag&TRACK_HAS_BUNDLE) { BLI_snprintf(str, sizeof(str), "Average error: %.3f", track->error); BLF_position(fontid, pos[0], pos[1], 0.0f); BLF_draw(fontid, str, sizeof(str)); pos[1]-= fontsize; } if(track->flag&TRACK_LOCKED) { BLF_position(fontid, pos[0], pos[1], 0.0f); BLF_draw(fontid, "locked", 6); } } static void view2d_to_region_float(View2D *v2d, float x, float y, float *regionx, float *regiony) { /* express given coordinates as proportional values */ x= -v2d->cur.xmin / (v2d->cur.xmax-v2d->cur.xmin); y= -v2d->cur.ymin / (v2d->cur.ymax-v2d->cur.ymin); /* convert proportional distances to screen coordinates */ *regionx= v2d->mask.xmin + x*(v2d->mask.xmax-v2d->mask.xmin); *regiony= v2d->mask.ymin + y*(v2d->mask.ymax-v2d->mask.ymin); } static void draw_tracking_tracks(SpaceClip *sc, ARegion *ar, MovieClip *clip, int width, int height, float zoomx, float zoomy) { float x, y; MovieTracking* tracking= &clip->tracking; ListBase *tracksbase= BKE_tracking_get_tracks(tracking); MovieTrackingTrack *track, *act_track; MovieTrackingMarker *marker; int framenr= sc->user.framenr; int undistort= sc->user.render_flag&MCLIP_PROXY_RENDER_UNDISTORT; float *marker_pos= NULL, *fp, *active_pos= NULL, cur_pos[2]; /* ** find window pixel coordinates of origin ** */ /* UI_view2d_to_region_no_clip return integer values, this could lead to 1px flickering when view is locked to selection during playbeck. to avoid this flickering, calclate base point in the same way as it happens in UI_view2d_to_region_no_clip, but do it in floats here */ view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); glPushMatrix(); glTranslatef(x, y, 0); glPushMatrix(); glScalef(zoomx, zoomy, 0); glMultMatrixf(sc->stabmat); glScalef(width, height, 0); act_track= BKE_tracking_active_track(tracking); if(sc->user.render_flag&MCLIP_PROXY_RENDER_UNDISTORT) { int count= 0; /* count */ track= tracksbase->first; while(track) { if((track->flag&TRACK_HIDDEN)==0) { marker= BKE_tracking_get_marker(track, framenr); if(MARKER_VISIBLE(sc, marker)) count++; } track= track->next; } /* undistort */ if(count) { marker_pos= MEM_callocN(2*sizeof(float)*count, "draw_tracking_tracks marker_pos"); track= tracksbase->first; fp= marker_pos; while(track) { if((track->flag&TRACK_HIDDEN)==0) { marker= BKE_tracking_get_marker(track, framenr); if(MARKER_VISIBLE(sc, marker)) { ED_clip_point_undistorted_pos(sc, marker->pos, fp); if(track==act_track) active_pos= fp; fp+= 2; } } track= track->next; } } } if(sc->flag&SC_SHOW_TRACK_PATH) { track= tracksbase->first; while(track) { if((track->flag&TRACK_HIDDEN)==0) draw_track_path(sc, clip, track); track= track->next; } } /* markers outline and non-selected areas */ track= tracksbase->first; fp= marker_pos; while(track) { if((track->flag&TRACK_HIDDEN)==0) { marker= BKE_tracking_get_marker(track, framenr); if(MARKER_VISIBLE(sc, marker)) { copy_v2_v2(cur_pos, fp ? fp : marker->pos); draw_marker_outline(sc, track, marker, cur_pos, width, height); draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 0); draw_marker_slide_zones(sc, track, marker, cur_pos, 1, 0, 0, width, height); draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 0, 0, width, height); if(fp) fp+= 2; } } track= track->next; } /* selected areas only, so selection wouldn't be overlapped by non-selected areas */ track= tracksbase->first; fp= marker_pos; while(track) { if((track->flag&TRACK_HIDDEN)==0) { int act= track==act_track; marker= BKE_tracking_get_marker(track, framenr); if(MARKER_VISIBLE(sc, marker)) { if(!act) { copy_v2_v2(cur_pos, fp ? fp : marker->pos); draw_marker_areas(sc, track, marker, cur_pos, width, height, 0, 1); draw_marker_slide_zones(sc, track, marker, cur_pos, 0, 1, 0, width, height); } if(fp) fp+= 2; } } track= track->next; } /* active marker would be displayed on top of everything else */ if(act_track) { if((act_track->flag&TRACK_HIDDEN)==0) { marker= BKE_tracking_get_marker(act_track, framenr); if(MARKER_VISIBLE(sc, marker)) { copy_v2_v2(cur_pos, active_pos ? active_pos : marker->pos); draw_marker_areas(sc, act_track, marker, cur_pos, width, height, 1, 1); draw_marker_slide_zones(sc, act_track, marker, cur_pos, 0, 1, 1, width, height); } } } if(sc->flag&SC_SHOW_BUNDLES) { MovieTrackingObject *object= BKE_tracking_active_object(tracking); float pos[4], vec[4], mat[4][4], aspy; glEnable(GL_POINT_SMOOTH); glPointSize(3.0f); aspy= 1.0f/clip->tracking.camera.pixel_aspect; BKE_tracking_projection_matrix(tracking, object, framenr, width, height, mat); track= tracksbase->first; while(track) { if((track->flag&TRACK_HIDDEN)==0 && track->flag&TRACK_HAS_BUNDLE) { marker= BKE_tracking_get_marker(track, framenr); if(MARKER_VISIBLE(sc, marker)) { float npos[2]; copy_v4_v4(vec, track->bundle_pos); vec[3]=1; mul_v4_m4v4(pos, mat, vec); pos[0]= (pos[0]/(pos[3]*2.0f)+0.5f)*width; pos[1]= (pos[1]/(pos[3]*2.0f)+0.5f)*height*aspy; BKE_tracking_apply_intrinsics(tracking, pos, npos); if(npos[0]>=0.0f && npos[1]>=0.0f && npos[0]<=width && npos[1]<=height*aspy) { vec[0]= (marker->pos[0]+track->offset[0])*width; vec[1]= (marker->pos[1]+track->offset[1])*height*aspy; sub_v2_v2(vec, npos); if(len_v2(vec)<3) glColor3f(0.0f, 1.0f, 0.0f); else glColor3f(1.0f, 0.0f, 0.0f); glBegin(GL_POINTS); if(undistort) glVertex3f(pos[0]/width, pos[1]/(height*aspy), 0); else glVertex3f(npos[0]/width, npos[1]/(height*aspy), 0); glEnd(); } } } track= track->next; } glPointSize(1.0f); glDisable(GL_POINT_SMOOTH); } glPopMatrix(); if(sc->flag&SC_SHOW_NAMES) { /* scaling should be cleared before drawing texts, otherwise font would also be scaled */ track= tracksbase->first; fp= marker_pos; while(track) { if((track->flag&TRACK_HIDDEN)==0) { marker= BKE_tracking_get_marker(track, framenr); if(MARKER_VISIBLE(sc, marker)) { int act= track==act_track; copy_v2_v2(cur_pos, fp ? fp : marker->pos); draw_marker_texts(sc, track, marker, cur_pos, act, width, height, zoomx, zoomy); if(fp) fp+= 2; } } track= track->next; } } glPopMatrix(); if(marker_pos) MEM_freeN(marker_pos); } static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip, int width, int height, float zoomx, float zoomy) { float x, y; const int n= 10; int i, j, a; float pos[2], tpos[2], grid[11][11][2]; MovieTracking *tracking= &clip->tracking; float aspy= 1.0f/tracking->camera.pixel_aspect; float dx= (float)width/n, dy= (float)height/n*aspy; if(sc->mode!=SC_MODE_DISTORTION) return; if(!tracking->camera.focal) return; if((sc->flag&SC_SHOW_GRID)==0 && (sc->flag&SC_MANUAL_CALIBRATION)==0) return; view2d_to_region_float(&ar->v2d, 0.0f, 0.0f, &x, &y); glPushMatrix(); glTranslatef(x, y, 0); glScalef(zoomx, zoomy, 0); glMultMatrixf(sc->stabmat); glScalef(width, height, 0); /* grid */ if(sc->flag&SC_SHOW_GRID) { float val[4][2], idx[4][2]; float min[2], max[2]; for(a=0; a<4; a++) { if(a<2) val[a][a%2]= FLT_MAX; else val[a][a%2]= -FLT_MAX; } zero_v2(pos); for(i= 0; i<=n; i++) { for(j= 0; j<=n; j++) { if(i==0 || j==0 || i==n || j==n) { BKE_tracking_apply_intrinsics(tracking, pos, tpos); for(a=0; a<4; a++) { int ok; if(a<2) ok= tpos[a%2] < val[a][a%2]; else ok= tpos[a%2] > val[a][a%2]; if(ok) { copy_v2_v2(val[a], tpos); idx[a][0]= j; idx[a][1]= i; } } } pos[0]+= dx; } pos[0]= 0.0f; pos[1]+= dy; } INIT_MINMAX2(min, max); for(a= 0; a<4; a++) { pos[0]= idx[a][0]*dx; pos[1]= idx[a][1]*dy; BKE_tracking_invert_intrinsics(tracking, pos, tpos); DO_MINMAX2(tpos, min, max); } copy_v2_v2(pos, min); dx= (max[0]-min[0])/n; dy= (max[1]-min[1])/n; for(i= 0; i<=n; i++) { for(j= 0; j<=n; j++) { BKE_tracking_apply_intrinsics(tracking, pos, grid[i][j]); grid[i][j][0]/= width; grid[i][j][1]/= height*aspy; pos[0]+= dx; } pos[0]= min[0]; pos[1]+= dy; } glColor3f(1.0f, 0.0f, 0.0f); for(i= 0; i<=n; i++) { glBegin(GL_LINE_STRIP); for(j= 0; j<=n; j++) { glVertex2fv(grid[i][j]); } glEnd(); } for(j= 0; j<=n; j++) { glBegin(GL_LINE_STRIP); for(i= 0; i<=n; i++) { glVertex2fv(grid[i][j]); } glEnd(); } } if(sc->flag&SC_MANUAL_CALIBRATION && clip->gpd) { bGPDlayer *layer= clip->gpd->layers.first; while(layer) { bGPDframe *frame= layer->frames.first; if(layer->flag & GP_LAYER_HIDE) { layer= layer->next; continue; } glColor4fv(layer->color); glLineWidth(layer->thickness); glPointSize((float)(layer->thickness + 2)); while(frame) { bGPDstroke *stroke= frame->strokes.first; while(stroke) { if(stroke->flag&GP_STROKE_2DSPACE) { if(stroke->totpoints>1) { glBegin(GL_LINE_STRIP); for(i= 0; itotpoints-1; i++) { float npos[2], dpos[2], len; int steps; pos[0]= stroke->points[i].x*width; pos[1]= stroke->points[i].y*height*aspy; npos[0]= stroke->points[i+1].x*width; npos[1]= stroke->points[i+1].y*height*aspy; len= len_v2v2(pos, npos); steps= ceil(len/5.0f); /* we want to distort only long straight lines */ if(stroke->totpoints==2) { BKE_tracking_invert_intrinsics(tracking, pos, pos); BKE_tracking_invert_intrinsics(tracking, npos, npos); } sub_v2_v2v2(dpos, npos, pos); mul_v2_fl(dpos, 1.0f/steps); for(j= 0; j<=steps; j++) { BKE_tracking_apply_intrinsics(tracking, pos, tpos); glVertex2f(tpos[0]/width, tpos[1]/(height*aspy)); add_v2_v2(pos, dpos); } } glEnd(); } else if(stroke->totpoints==1) { glBegin(GL_POINTS); glVertex2f(stroke->points[0].x, stroke->points[0].y); glEnd(); } } stroke= stroke->next; } frame= frame->next; } layer= layer->next; } glLineWidth(1.0f); glPointSize(1.0f); } glPopMatrix(); } void clip_draw_main(SpaceClip *sc, ARegion *ar, Scene *scene) { MovieClip *clip= ED_space_clip(sc); ImBuf *ibuf; int width, height; float zoomx, zoomy; /* if no clip, nothing to do */ if(!clip) return; ED_space_clip_size(sc, &width, &height); ED_space_clip_zoom(sc, ar, &zoomx, &zoomy); if(sc->flag&SC_SHOW_STABLE) { float smat[4][4], ismat[4][4]; ibuf= ED_space_clip_get_stable_buffer(sc, sc->loc, &sc->scale, &sc->angle); if(ibuf) { float loc[2]; float aspect= clip->tracking.camera.pixel_aspect; if(width != ibuf->x) mul_v2_v2fl(loc, sc->loc, (float)width / ibuf->x); else copy_v2_v2(loc, sc->loc); BKE_tracking_stabdata_to_mat4(width, height, aspect, loc, sc->scale, sc->angle, sc->stabmat); unit_m4(smat); smat[0][0]= 1.0f/width; smat[1][1]= 1.0f/height; invert_m4_m4(ismat, smat); mul_serie_m4(sc->unistabmat, smat, sc->stabmat, ismat, NULL, NULL, NULL, NULL, NULL); } } else { ibuf= ED_space_clip_get_buffer(sc); zero_v2(sc->loc); sc->scale= 1.0f; unit_m4(sc->stabmat); unit_m4(sc->unistabmat); } if(ibuf) { draw_movieclip_buffer(sc, ar, ibuf, width, height, zoomx, zoomy); IMB_freeImBuf(ibuf); draw_tracking_tracks(sc, ar, clip, width, height, zoomx, zoomy); draw_distortion(sc, ar, clip, width, height, zoomx, zoomy); } draw_movieclip_cache(sc, ar, clip, scene); draw_movieclip_notes(sc, ar); } /* draw grease pencil */ void clip_draw_grease_pencil(bContext *C, int onlyv2d) { SpaceClip *sc= CTX_wm_space_clip(C); MovieClip *clip= ED_space_clip(sc); ImBuf *ibuf; if(!clip) return; if(onlyv2d) { /* if manual calibration is used then grase pencil data is already drawed in draw_distortion */ if((sc->flag&SC_MANUAL_CALIBRATION)==0 || sc->mode!=SC_MODE_DISTORTION) { ibuf= ED_space_clip_get_buffer(sc); if(ibuf) { glPushMatrix(); glMultMatrixf(sc->unistabmat); draw_gpencil_2dimage(C, ibuf); IMB_freeImBuf(ibuf); glPopMatrix(); } } } else { draw_gpencil_view2d(C, 0); } }