Fix T59675: Motion path frame numbers at wrong positions
[blender.git] / source / blender / draw / intern / draw_anim_viz.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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.
8  *
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.
13  *
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.
17  *
18  * The Original Code is Copyright (C) 2009/2018 by the Blender Foundation.
19  *
20  * Contributor(s): Joshua Leung
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/draw/intern/draw_anim_viz.c
26  *  \ingroup draw
27  */
28
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33
34 #include "BLI_sys_types.h"
35
36 #include "DNA_anim_types.h"
37 #include "DNA_armature_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_screen_types.h"
40 #include "DNA_view3d_types.h"
41 #include "DNA_object_types.h"
42
43 #include "BLI_math.h"
44 #include "BLI_dlrbTree.h"
45
46 #include "BKE_animsys.h"
47 #include "BKE_action.h"
48
49 #include "ED_keyframes_draw.h"
50
51 #include "UI_resources.h"
52
53 #include "DEG_depsgraph_query.h"
54
55 #include "DRW_engine.h"
56 #include "DRW_render.h"
57
58 #include "GPU_shader.h"
59 #include "GPU_immediate.h"
60 #include "GPU_matrix.h"
61
62 #include "draw_common.h"
63 #include "draw_manager_text.h"
64
65 #include "draw_mode_engines.h"
66
67 extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
68
69 /* ********************************* Lists ************************************** */
70 /* All lists are per viewport specific datas.
71  * They are all free when viewport changes engines
72  * or is free itself.
73  */
74
75 /* XXX: How to show frame numbers, etc.?  Currently only doing the dots and lines */
76 typedef struct MPATH_PassList {
77         struct DRWPass *lines;
78         struct DRWPass *points;
79 } MPATH_PassList;
80
81 typedef struct MPATH_StorageList {
82         struct MPATH_PrivateData *g_data;
83 } MPATH_StorageList;
84
85 typedef struct MPATH_Data {
86         void *engine_type;
87         DRWViewportEmptyList *fbl;
88         DRWViewportEmptyList *txl;
89         MPATH_PassList *psl;
90         MPATH_StorageList *stl;
91 } MPATH_Data;
92
93 #if 0
94 static struct {
95         GPUShader *mpath_line_sh;
96         GPUShader *mpath_points_sh;
97 } e_data = {0};
98 #endif
99
100 /* *************************** Path Cache *********************************** */
101
102 /* Just convert the CPU cache to GPU cache. */
103 static GPUVertBuf *mpath_vbo_get(bMotionPath *mpath)
104 {
105         if (!mpath->points_vbo) {
106                 GPUVertFormat format = {0};
107                 /* Match structure of bMotionPathVert. */
108                 uint pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
109                 GPU_vertformat_attr_add(&format, "flag", GPU_COMP_I32, 1, GPU_FETCH_INT);
110                 mpath->points_vbo = GPU_vertbuf_create_with_format(&format);
111                 GPU_vertbuf_data_alloc(mpath->points_vbo, mpath->length);
112
113                 /* meh... a useless memcpy. */
114                 GPUVertBufRaw raw_data;
115                 GPU_vertbuf_attr_get_raw_data(mpath->points_vbo, pos, &raw_data);
116                 memcpy(GPU_vertbuf_raw_step(&raw_data), mpath->points, sizeof(bMotionPathVert) * mpath->length);
117         }
118         return mpath->points_vbo;
119 }
120
121 static GPUBatch *mpath_batch_line_get(bMotionPath *mpath)
122 {
123         if (!mpath->batch_line) {
124                 mpath->batch_line = GPU_batch_create(GPU_PRIM_LINE_STRIP, mpath_vbo_get(mpath), NULL);
125         }
126         return mpath->batch_line;
127 }
128
129 static GPUBatch *mpath_batch_points_get(bMotionPath *mpath)
130 {
131         if (!mpath->batch_points) {
132                 mpath->batch_points = GPU_batch_create(GPU_PRIM_POINTS, mpath_vbo_get(mpath), NULL);
133         }
134         return mpath->batch_points;
135 }
136
137 /* *************************** Draw Engine Entrypoints ************************** */
138
139 static void MPATH_engine_init(void *UNUSED(vedata))
140 {
141 }
142
143 static void MPATH_engine_free(void)
144 {
145 }
146
147 /* Here init all passes and shading groups
148  * Assume that all Passes are NULL */
149 static void MPATH_cache_init(void *vedata)
150 {
151         MPATH_PassList *psl = ((MPATH_Data *)vedata)->psl;
152
153         {
154                 DRWState state = DRW_STATE_WRITE_COLOR;
155                 psl->lines = DRW_pass_create("Motionpath Line Pass", state);
156         }
157
158         {
159                 DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_POINT;
160                 psl->points = DRW_pass_create("Motionpath Point Pass", state);
161         }
162 }
163
164 static void MPATH_cache_motion_path(MPATH_PassList *psl,
165                                     Object *ob, bPoseChannel *pchan,
166                                     bAnimVizSettings *avs, bMotionPath *mpath)
167 {
168         const DRWContextState *draw_ctx = DRW_context_state_get();
169         struct DRWTextStore *dt = DRW_text_cache_ensure();
170         int txt_flag = DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_ASCII;
171         int stepsize = avs->path_step;
172         int sfra, efra, sind, len;
173         int cfra = (int)DEG_get_ctime(draw_ctx->depsgraph);
174         bool sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT);
175         bool show_keyframes = (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) != 0;
176         bMotionPathVert *mpv, *mpv_start;
177
178         /* get frame ranges */
179         if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
180                 /* With "Around Current", we only choose frames from around
181                  * the current frame to draw.
182                  */
183                 sfra = cfra - avs->path_bc;
184                 efra = cfra + avs->path_ac + 1;
185         }
186         else {
187                 /* Use the current display range */
188                 sfra = avs->path_sf;
189                 efra = avs->path_ef;
190         }
191
192         /* no matter what, we can only show what is in the cache and no more
193          * - abort if whole range is past ends of path
194          * - otherwise clamp endpoints to extents of path
195          */
196         if (sfra < mpath->start_frame) {
197                 /* start clamp */
198                 sfra = mpath->start_frame;
199         }
200         if (efra > mpath->end_frame) {
201                 /* end clamp */
202                 efra = mpath->end_frame;
203         }
204
205         if ((sfra > mpath->end_frame) || (efra < mpath->start_frame)) {
206                 /* whole path is out of bounds */
207                 return;
208         }
209
210         len = efra - sfra;
211
212         if ((len <= 0) || (mpath->points == NULL)) {
213                 return;
214         }
215
216         sind = sfra - mpath->start_frame;
217         mpv_start = (mpath->points + sind);
218
219         bool use_custom_col = (mpath->flag & MOTIONPATH_FLAG_CUSTOM) != 0;
220
221         /* draw curve-line of path */
222         /* Draw lines only if line drawing option is enabled */
223         if (mpath->flag & MOTIONPATH_FLAG_LINES) {
224                 DRWShadingGroup *shgrp = DRW_shgroup_create(mpath_line_shader_get(), psl->lines);
225                 DRW_shgroup_uniform_int_copy(shgrp, "frameCurrent", cfra);
226                 DRW_shgroup_uniform_int_copy(shgrp, "frameStart", sfra);
227                 DRW_shgroup_uniform_int_copy(shgrp, "frameEnd", efra);
228                 DRW_shgroup_uniform_int_copy(shgrp, "cacheStart", mpath->start_frame);
229                 DRW_shgroup_uniform_int_copy(shgrp, "lineThickness", mpath->line_thickness);
230                 DRW_shgroup_uniform_bool_copy(shgrp, "selected", sel);
231                 DRW_shgroup_uniform_bool_copy(shgrp, "useCustomColor", use_custom_col);
232                 DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1);
233                 DRW_shgroup_uniform_block(shgrp, "globalsBlock", globals_ubo);
234                 if (use_custom_col) {
235                         DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
236                 }
237                 /* Only draw the required range. */
238                 DRW_shgroup_call_range_add(shgrp, mpath_batch_line_get(mpath), NULL, sind, len);
239         }
240
241         /* Draw points. */
242         DRWShadingGroup *shgrp = DRW_shgroup_create(mpath_points_shader_get(), psl->points);
243         DRW_shgroup_uniform_int_copy(shgrp, "frameCurrent", cfra);
244         DRW_shgroup_uniform_int_copy(shgrp, "cacheStart", mpath->start_frame);
245         DRW_shgroup_uniform_int_copy(shgrp, "pointSize", mpath->line_thickness);
246         DRW_shgroup_uniform_int_copy(shgrp, "stepSize", stepsize);
247         DRW_shgroup_uniform_bool_copy(shgrp, "selected", sel);
248         DRW_shgroup_uniform_bool_copy(shgrp, "showKeyFrames", show_keyframes);
249         DRW_shgroup_uniform_bool_copy(shgrp, "useCustomColor", use_custom_col);
250         DRW_shgroup_uniform_block(shgrp, "globalsBlock", globals_ubo);
251         if (use_custom_col) {
252                 DRW_shgroup_uniform_vec3(shgrp, "customColor", mpath->color, 1);
253         }
254         /* Only draw the required range. */
255         DRW_shgroup_call_range_add(shgrp, mpath_batch_points_get(mpath), NULL, sind, len);
256
257         /* Draw frame numbers at each framestep value */
258         bool show_kf_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
259         if ((avs->path_viewflag & (MOTIONPATH_VIEW_FNUMS)) || (show_kf_no && show_keyframes)) {
260                 int i;
261                 uchar col[4], col_kf[4];
262                 UI_GetThemeColor3ubv(TH_TEXT_HI, col);
263                 UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col_kf);
264                 col[3] = col_kf[3] = 255;
265
266                 for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) {
267                         int frame = sfra + i;
268                         char numstr[32];
269                         size_t numstr_len;
270                         bool is_keyframe = (mpv->flag & MOTIONPATH_VERT_KEY) != 0;
271
272                         if ((show_keyframes && show_kf_no && is_keyframe) ||
273                             ((avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) && (i == 0)))
274                         {
275                                 numstr_len = sprintf(numstr, " %d", frame);
276                                 DRW_text_cache_add(dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, (is_keyframe) ? col_kf : col);
277                         }
278                         else if (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) {
279                                 bMotionPathVert *mpvP = (mpv - stepsize);
280                                 bMotionPathVert *mpvN = (mpv + stepsize);
281                                 /* only draw framenum if several consecutive highlighted points don't occur on same point */
282                                 if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) {
283                                         numstr_len = sprintf(numstr, " %d", frame);
284                                         DRW_text_cache_add(dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, col);
285                                 }
286                         }
287                 }
288         }
289 }
290
291 /* Add geometry to shading groups. Execute for each objects */
292 static void MPATH_cache_populate(void *vedata, Object *ob)
293 {
294         MPATH_PassList *psl = ((MPATH_Data *)vedata)->psl;
295         const DRWContextState *draw_ctx = DRW_context_state_get();
296
297         if (draw_ctx->v3d->overlay.flag & V3D_OVERLAY_HIDE_MOTION_PATHS) {
298                 return;
299         }
300
301         if (ob->type == OB_ARMATURE) {
302                 if (DRW_pose_mode_armature(ob, draw_ctx->obact)) {
303                         for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
304                                 if (pchan->mpath) {
305                                         MPATH_cache_motion_path(psl, ob, pchan, &ob->pose->avs, pchan->mpath);
306                                 }
307                         }
308                 }
309         }
310         else {
311                 if (ob->mpath) {
312                         MPATH_cache_motion_path(psl, ob, NULL, &ob->avs, ob->mpath);
313                 }
314         }
315 }
316
317 /* Draw time! Control rendering pipeline from here */
318 static void MPATH_draw_scene(void *vedata)
319 {
320         MPATH_PassList *psl = ((MPATH_Data *)vedata)->psl;
321         DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
322         DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
323
324         if (DRW_pass_is_empty(psl->lines) &&
325             DRW_pass_is_empty(psl->points))
326         {
327                 /* Nothing to draw. */
328                 return;
329         }
330
331         MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
332
333         DRW_draw_pass(psl->lines);
334         DRW_draw_pass(psl->points);
335
336         MULTISAMPLE_SYNC_DISABLE_NO_DEPTH(dfbl, dtxl)
337 }
338
339 /* *************************** Draw Engine Defines ****************************** */
340
341 static const DrawEngineDataSize MPATH_data_size = DRW_VIEWPORT_DATA_SIZE(MPATH_Data);
342
343 DrawEngineType draw_engine_motion_path_type = {
344         NULL, NULL,
345         N_("MotionPath"),
346         &MPATH_data_size,
347         &MPATH_engine_init,
348         &MPATH_engine_free,
349         &MPATH_cache_init,
350         &MPATH_cache_populate,
351         NULL,
352         NULL,
353         &MPATH_draw_scene,
354         NULL,
355         NULL,
356 };