2c831c0877c38870e8b92da250b079ee056b4645
[blender.git] / source / blender / editors / space_view3d / view3d_draw.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup spview3d
22  */
23
24 #include <math.h>
25
26 #include "BLI_listbase.h"
27 #include "BLI_math.h"
28 #include "BLI_rect.h"
29 #include "BLI_string.h"
30 #include "BLI_threads.h"
31 #include "BLI_jitter_2d.h"
32
33 #include "BKE_camera.h"
34 #include "BKE_collection.h"
35 #include "BKE_context.h"
36 #include "BKE_global.h"
37 #include "BKE_key.h"
38 #include "BKE_main.h"
39 #include "BKE_scene.h"
40 #include "BKE_object.h"
41 #include "BKE_paint.h"
42 #include "BKE_unit.h"
43
44 #include "BLF_api.h"
45
46 #include "BLT_translation.h"
47
48 #include "DNA_armature_types.h"
49 #include "DNA_brush_types.h"
50 #include "DNA_camera_types.h"
51 #include "DNA_key_types.h"
52 #include "DNA_mesh_types.h"
53 #include "DNA_object_types.h"
54 #include "DNA_view3d_types.h"
55 #include "DNA_windowmanager_types.h"
56
57 #include "DRW_engine.h"
58
59 #include "ED_armature.h"
60 #include "ED_keyframing.h"
61 #include "ED_gpencil.h"
62 #include "ED_screen.h"
63 #include "ED_transform.h"
64
65 #include "DEG_depsgraph_query.h"
66
67 #include "GPU_batch.h"
68 #include "GPU_batch_presets.h"
69 #include "GPU_draw.h"
70 #include "GPU_matrix.h"
71 #include "GPU_immediate.h"
72 #include "GPU_immediate_util.h"
73 #include "GPU_material.h"
74 #include "GPU_viewport.h"
75 #include "GPU_state.h"
76 #include "GPU_framebuffer.h"
77
78 #include "MEM_guardedalloc.h"
79
80 #include "UI_interface.h"
81 #include "UI_resources.h"
82
83 #include "RE_engine.h"
84
85 #include "WM_api.h"
86 #include "WM_types.h"
87
88 #include "RNA_access.h"
89
90 #include "IMB_imbuf.h"
91 #include "IMB_imbuf_types.h"
92
93 #include "view3d_intern.h" /* own include */
94
95 /* -------------------------------------------------------------------- */
96 /** \name General Functions
97  * \{ */
98
99 /**
100  * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
101  */
102 void ED_view3d_update_viewmat(Depsgraph *depsgraph,
103                               Scene *scene,
104                               View3D *v3d,
105                               ARegion *ar,
106                               float viewmat[4][4],
107                               float winmat[4][4],
108                               const rcti *rect)
109 {
110   RegionView3D *rv3d = ar->regiondata;
111
112   /* setup window matrices */
113   if (winmat) {
114     copy_m4_m4(rv3d->winmat, winmat);
115   }
116   else {
117     view3d_winmatrix_set(depsgraph, ar, v3d, rect);
118   }
119
120   /* setup view matrix */
121   if (viewmat) {
122     copy_m4_m4(rv3d->viewmat, viewmat);
123   }
124   else {
125     float rect_scale[2];
126     if (rect) {
127       rect_scale[0] = (float)BLI_rcti_size_x(rect) / (float)ar->winx;
128       rect_scale[1] = (float)BLI_rcti_size_y(rect) / (float)ar->winy;
129     }
130     /* note: calls BKE_object_where_is_calc for camera... */
131     view3d_viewmatrix_set(depsgraph, scene, v3d, rv3d, rect ? rect_scale : NULL);
132   }
133   /* update utility matrices */
134   mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
135   invert_m4_m4(rv3d->persinv, rv3d->persmat);
136   invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
137
138   /* calculate GLSL view dependent values */
139
140   /* store window coordinates scaling/offset */
141   if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
142     rctf cameraborder;
143     ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &cameraborder, false);
144     rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder);
145     rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder);
146
147     rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx;
148     rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy;
149   }
150   else {
151     rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f;
152     rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f;
153   }
154
155   /* calculate pixelsize factor once, is used for lights and obcenters */
156   {
157     /* note:  '1.0f / len_v3(v1)'  replaced  'len_v3(rv3d->viewmat[0])'
158      * because of float point precision problems at large values [#23908] */
159     float v1[3], v2[3];
160     float len_px, len_sc;
161
162     v1[0] = rv3d->persmat[0][0];
163     v1[1] = rv3d->persmat[1][0];
164     v1[2] = rv3d->persmat[2][0];
165
166     v2[0] = rv3d->persmat[0][1];
167     v2[1] = rv3d->persmat[1][1];
168     v2[2] = rv3d->persmat[2][1];
169
170     len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
171     len_sc = (float)MAX2(ar->winx, ar->winy);
172
173     rv3d->pixsize = len_px / len_sc;
174   }
175 }
176
177 static void view3d_main_region_setup_view(Depsgraph *depsgraph,
178                                           Scene *scene,
179                                           View3D *v3d,
180                                           ARegion *ar,
181                                           float viewmat[4][4],
182                                           float winmat[4][4],
183                                           const rcti *rect)
184 {
185   RegionView3D *rv3d = ar->regiondata;
186
187   ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, viewmat, winmat, rect);
188
189   /* set for opengl */
190   GPU_matrix_projection_set(rv3d->winmat);
191   GPU_matrix_set(rv3d->viewmat);
192 }
193
194 static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d)
195 {
196   if ((scene->r.scemode & R_MULTIVIEW) == 0) {
197     return false;
198   }
199
200   if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) {
201     return false;
202   }
203
204   switch (v3d->stereo3d_camera) {
205     case STEREO_MONO_ID:
206       return false;
207       break;
208     case STEREO_3D_ID:
209       /* win will be NULL when calling this from the selection or draw loop. */
210       if ((win == NULL) || (WM_stereo3d_enabled(win, true) == false)) {
211         return false;
212       }
213       if (((scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) != 0) &&
214           !BKE_scene_multiview_is_stereo3d(&scene->r)) {
215         return false;
216       }
217       break;
218     /* We always need the stereo calculation for left and right cameras. */
219     case STEREO_LEFT_ID:
220     case STEREO_RIGHT_ID:
221     default:
222       break;
223   }
224   return true;
225 }
226
227 /* setup the view and win matrices for the multiview cameras
228  *
229  * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called
230  * we have no winmatrix (i.e., projection matrix) defined at that time.
231  * Since the camera and the camera shift are needed for the winmat calculation
232  * we do a small hack to replace it temporarily so we don't need to change the
233  * view3d)main_region_setup_view() code to account for that.
234  */
235 static void view3d_stereo3d_setup(
236     Depsgraph *depsgraph, Scene *scene, View3D *v3d, ARegion *ar, const rcti *rect)
237 {
238   bool is_left;
239   const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
240   const char *viewname;
241
242   /* show only left or right camera */
243   if (v3d->stereo3d_camera != STEREO_3D_ID) {
244     v3d->multiview_eye = v3d->stereo3d_camera;
245   }
246
247   is_left = v3d->multiview_eye == STEREO_LEFT_ID;
248   viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID];
249
250   /* update the viewport matrices with the new camera */
251   if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
252     Camera *data, *data_eval;
253     float viewmat[4][4];
254     float shiftx;
255
256     data = (Camera *)v3d->camera->data;
257     data_eval = (Camera *)DEG_get_evaluated_id(depsgraph, &data->id);
258
259     shiftx = data_eval->shiftx;
260
261     BLI_thread_lock(LOCK_VIEW3D);
262     data_eval->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname);
263
264     BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
265     view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, NULL, rect);
266
267     data_eval->shiftx = shiftx;
268     BLI_thread_unlock(LOCK_VIEW3D);
269   }
270   else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
271     float viewmat[4][4];
272     Object *view_ob = v3d->camera;
273     Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
274
275     BLI_thread_lock(LOCK_VIEW3D);
276     v3d->camera = camera;
277
278     BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
279     view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, NULL, rect);
280
281     v3d->camera = view_ob;
282     BLI_thread_unlock(LOCK_VIEW3D);
283   }
284 }
285
286 /**
287  * Set the correct matrices
288  */
289 void ED_view3d_draw_setup_view(wmWindow *win,
290                                Depsgraph *depsgraph,
291                                Scene *scene,
292                                ARegion *ar,
293                                View3D *v3d,
294                                float viewmat[4][4],
295                                float winmat[4][4],
296                                const rcti *rect)
297 {
298   RegionView3D *rv3d = ar->regiondata;
299
300   /* Setup the view matrix. */
301   if (view3d_stereo3d_active(win, scene, v3d, rv3d)) {
302     view3d_stereo3d_setup(depsgraph, scene, v3d, ar, rect);
303   }
304   else {
305     view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, rect);
306   }
307 }
308
309 /** \} */
310
311 /* -------------------------------------------------------------------- */
312 /** \name Draw View Border
313  * \{ */
314
315 static void view3d_camera_border(const Scene *scene,
316                                  struct Depsgraph *depsgraph,
317                                  const ARegion *ar,
318                                  const View3D *v3d,
319                                  const RegionView3D *rv3d,
320                                  rctf *r_viewborder,
321                                  const bool no_shift,
322                                  const bool no_zoom)
323 {
324   CameraParams params;
325   rctf rect_view, rect_camera;
326   Object *camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
327
328   /* get viewport viewplane */
329   BKE_camera_params_init(&params);
330   BKE_camera_params_from_view3d(&params, depsgraph, v3d, rv3d);
331   if (no_zoom) {
332     params.zoom = 1.0f;
333   }
334   BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, 1.0f, 1.0f);
335   rect_view = params.viewplane;
336
337   /* get camera viewplane */
338   BKE_camera_params_init(&params);
339   /* fallback for non camera objects */
340   params.clip_start = v3d->clip_start;
341   params.clip_end = v3d->clip_end;
342   BKE_camera_params_from_object(&params, camera_eval);
343   if (no_shift) {
344     params.shiftx = 0.0f;
345     params.shifty = 0.0f;
346   }
347   BKE_camera_params_compute_viewplane(
348       &params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp);
349   rect_camera = params.viewplane;
350
351   /* get camera border within viewport */
352   r_viewborder->xmin = ((rect_camera.xmin - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) *
353                        ar->winx;
354   r_viewborder->xmax = ((rect_camera.xmax - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) *
355                        ar->winx;
356   r_viewborder->ymin = ((rect_camera.ymin - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) *
357                        ar->winy;
358   r_viewborder->ymax = ((rect_camera.ymax - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) *
359                        ar->winy;
360 }
361
362 void ED_view3d_calc_camera_border_size(const Scene *scene,
363                                        Depsgraph *depsgraph,
364                                        const ARegion *ar,
365                                        const View3D *v3d,
366                                        const RegionView3D *rv3d,
367                                        float r_size[2])
368 {
369   rctf viewborder;
370
371   view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, true, true);
372   r_size[0] = BLI_rctf_size_x(&viewborder);
373   r_size[1] = BLI_rctf_size_y(&viewborder);
374 }
375
376 void ED_view3d_calc_camera_border(const Scene *scene,
377                                   Depsgraph *depsgraph,
378                                   const ARegion *ar,
379                                   const View3D *v3d,
380                                   const RegionView3D *rv3d,
381                                   rctf *r_viewborder,
382                                   const bool no_shift)
383 {
384   view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, r_viewborder, no_shift, false);
385 }
386
387 static void drawviewborder_grid3(uint shdr_pos, float x1, float x2, float y1, float y2, float fac)
388 {
389   float x3, y3, x4, y4;
390
391   x3 = x1 + fac * (x2 - x1);
392   y3 = y1 + fac * (y2 - y1);
393   x4 = x1 + (1.0f - fac) * (x2 - x1);
394   y4 = y1 + (1.0f - fac) * (y2 - y1);
395
396   immBegin(GPU_PRIM_LINES, 8);
397
398   immVertex2f(shdr_pos, x1, y3);
399   immVertex2f(shdr_pos, x2, y3);
400
401   immVertex2f(shdr_pos, x1, y4);
402   immVertex2f(shdr_pos, x2, y4);
403
404   immVertex2f(shdr_pos, x3, y1);
405   immVertex2f(shdr_pos, x3, y2);
406
407   immVertex2f(shdr_pos, x4, y1);
408   immVertex2f(shdr_pos, x4, y2);
409
410   immEnd();
411 }
412
413 /* harmonious triangle */
414 static void drawviewborder_triangle(
415     uint shdr_pos, float x1, float x2, float y1, float y2, const char golden, const char dir)
416 {
417   float ofs;
418   float w = x2 - x1;
419   float h = y2 - y1;
420
421   immBegin(GPU_PRIM_LINES, 6);
422
423   if (w > h) {
424     if (golden) {
425       ofs = w * (1.0f - (1.0f / 1.61803399f));
426     }
427     else {
428       ofs = h * (h / w);
429     }
430     if (dir == 'B') {
431       SWAP(float, y1, y2);
432     }
433
434     immVertex2f(shdr_pos, x1, y1);
435     immVertex2f(shdr_pos, x2, y2);
436
437     immVertex2f(shdr_pos, x2, y1);
438     immVertex2f(shdr_pos, x1 + (w - ofs), y2);
439
440     immVertex2f(shdr_pos, x1, y2);
441     immVertex2f(shdr_pos, x1 + ofs, y1);
442   }
443   else {
444     if (golden) {
445       ofs = h * (1.0f - (1.0f / 1.61803399f));
446     }
447     else {
448       ofs = w * (w / h);
449     }
450     if (dir == 'B') {
451       SWAP(float, x1, x2);
452     }
453
454     immVertex2f(shdr_pos, x1, y1);
455     immVertex2f(shdr_pos, x2, y2);
456
457     immVertex2f(shdr_pos, x2, y1);
458     immVertex2f(shdr_pos, x1, y1 + ofs);
459
460     immVertex2f(shdr_pos, x1, y2);
461     immVertex2f(shdr_pos, x2, y1 + (h - ofs));
462   }
463
464   immEnd();
465 }
466
467 static void drawviewborder(Scene *scene, Depsgraph *depsgraph, ARegion *ar, View3D *v3d)
468 {
469   float x1, x2, y1, y2;
470   float x1i, x2i, y1i, y2i;
471
472   rctf viewborder;
473   Camera *ca = NULL;
474   RegionView3D *rv3d = ar->regiondata;
475
476   if (v3d->camera == NULL) {
477     return;
478   }
479   if (v3d->camera->type == OB_CAMERA) {
480     ca = v3d->camera->data;
481   }
482
483   ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false);
484   /* the offsets */
485   x1 = viewborder.xmin;
486   y1 = viewborder.ymin;
487   x2 = viewborder.xmax;
488   y2 = viewborder.ymax;
489
490   GPU_line_width(1.0f);
491
492   /* apply offsets so the real 3D camera shows through */
493
494   /* note: quite un-scientific but without this bit extra
495    * 0.0001 on the lower left the 2D border sometimes
496    * obscures the 3D camera border */
497   /* note: with VIEW3D_CAMERA_BORDER_HACK defined this error isn't noticeable
498    * but keep it here in case we need to remove the workaround */
499   x1i = (int)(x1 - 1.0001f);
500   y1i = (int)(y1 - 1.0001f);
501   x2i = (int)(x2 + (1.0f - 0.0001f));
502   y2i = (int)(y2 + (1.0f - 0.0001f));
503
504   uint shdr_pos = GPU_vertformat_attr_add(
505       immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
506
507   /* First, solid lines. */
508   {
509     immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
510
511     /* passepartout, specified in camera edit buttons */
512     if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) {
513       const float winx = (ar->winx + 1);
514       const float winy = (ar->winy + 1);
515
516       float alpha = 1.0f;
517
518       if (ca->passepartalpha != 1.0f) {
519         GPU_blend_set_func_separate(
520             GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
521         GPU_blend(true);
522         alpha = ca->passepartalpha;
523       }
524
525       immUniformColor4f(0.0f, 0.0f, 0.0f, alpha);
526
527       if (x1i > 0.0f) {
528         immRectf(shdr_pos, 0.0f, winy, x1i, 0.0f);
529       }
530       if (x2i < winx) {
531         immRectf(shdr_pos, x2i, winy, winx, 0.0f);
532       }
533       if (y2i < winy) {
534         immRectf(shdr_pos, x1i, winy, x2i, y2i);
535       }
536       if (y2i > 0.0f) {
537         immRectf(shdr_pos, x1i, y1i, x2i, 0.0f);
538       }
539
540       GPU_blend(false);
541     }
542
543     immUniformThemeColor(TH_BACK);
544     imm_draw_box_wire_2d(shdr_pos, x1i, y1i, x2i, y2i);
545
546 #ifdef VIEW3D_CAMERA_BORDER_HACK
547     if (view3d_camera_border_hack_test == true) {
548       immUniformColor3ubv(view3d_camera_border_hack_col);
549       imm_draw_box_wire_2d(shdr_pos, x1i + 1, y1i + 1, x2i - 1, y2i - 1);
550       view3d_camera_border_hack_test = false;
551     }
552 #endif
553
554     immUnbindProgram();
555   }
556
557   /* When overlays are disabled, only show camera outline & passepartout. */
558   if (v3d->flag2 & V3D_HIDE_OVERLAYS) {
559     return;
560   }
561
562   /* And now, the dashed lines! */
563   immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
564
565   {
566     float viewport_size[4];
567     GPU_viewport_size_get_f(viewport_size);
568     immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
569
570     immUniform1i("colors_len", 0); /* "simple" mode */
571     immUniform1f("dash_width", 6.0f);
572     immUniform1f("dash_factor", 0.5f);
573
574     /* outer line not to confuse with object selection */
575     if (v3d->flag2 & V3D_LOCK_CAMERA) {
576       immUniformThemeColor(TH_REDALERT);
577       imm_draw_box_wire_2d(shdr_pos, x1i - 1, y1i - 1, x2i + 1, y2i + 1);
578     }
579
580     immUniformThemeColor(TH_VIEW_OVERLAY);
581     imm_draw_box_wire_2d(shdr_pos, x1i, y1i, x2i, y2i);
582   }
583
584   /* Render Border. */
585   if (scene->r.mode & R_BORDER) {
586     float x3, y3, x4, y4;
587
588     x3 = floorf(x1 + (scene->r.border.xmin * (x2 - x1))) - 1;
589     y3 = floorf(y1 + (scene->r.border.ymin * (y2 - y1))) - 1;
590     x4 = floorf(x1 + (scene->r.border.xmax * (x2 - x1))) + (U.pixelsize - 1);
591     y4 = floorf(y1 + (scene->r.border.ymax * (y2 - y1))) + (U.pixelsize - 1);
592
593     immUniformColor3f(1.0f, 0.25f, 0.25f);
594     imm_draw_box_wire_2d(shdr_pos, x3, y3, x4, y4);
595   }
596
597   /* safety border */
598   if (ca) {
599     immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f);
600
601     if (ca->dtx & CAM_DTX_CENTER) {
602       float x3, y3;
603
604       x3 = x1 + 0.5f * (x2 - x1);
605       y3 = y1 + 0.5f * (y2 - y1);
606
607       immBegin(GPU_PRIM_LINES, 4);
608
609       immVertex2f(shdr_pos, x1, y3);
610       immVertex2f(shdr_pos, x2, y3);
611
612       immVertex2f(shdr_pos, x3, y1);
613       immVertex2f(shdr_pos, x3, y2);
614
615       immEnd();
616     }
617
618     if (ca->dtx & CAM_DTX_CENTER_DIAG) {
619       immBegin(GPU_PRIM_LINES, 4);
620
621       immVertex2f(shdr_pos, x1, y1);
622       immVertex2f(shdr_pos, x2, y2);
623
624       immVertex2f(shdr_pos, x1, y2);
625       immVertex2f(shdr_pos, x2, y1);
626
627       immEnd();
628     }
629
630     if (ca->dtx & CAM_DTX_THIRDS) {
631       drawviewborder_grid3(shdr_pos, x1, x2, y1, y2, 1.0f / 3.0f);
632     }
633
634     if (ca->dtx & CAM_DTX_GOLDEN) {
635       drawviewborder_grid3(shdr_pos, x1, x2, y1, y2, 1.0f - (1.0f / 1.61803399f));
636     }
637
638     if (ca->dtx & CAM_DTX_GOLDEN_TRI_A) {
639       drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 0, 'A');
640     }
641
642     if (ca->dtx & CAM_DTX_GOLDEN_TRI_B) {
643       drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 0, 'B');
644     }
645
646     if (ca->dtx & CAM_DTX_HARMONY_TRI_A) {
647       drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 1, 'A');
648     }
649
650     if (ca->dtx & CAM_DTX_HARMONY_TRI_B) {
651       drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 1, 'B');
652     }
653
654     if (ca->flag & CAM_SHOW_SAFE_MARGINS) {
655       UI_draw_safe_areas(
656           shdr_pos, x1, x2, y1, y2, scene->safe_areas.title, scene->safe_areas.action);
657
658       if (ca->flag & CAM_SHOW_SAFE_CENTER) {
659         UI_draw_safe_areas(shdr_pos,
660                            x1,
661                            x2,
662                            y1,
663                            y2,
664                            scene->safe_areas.title_center,
665                            scene->safe_areas.action_center);
666       }
667     }
668
669     if (ca->flag & CAM_SHOWSENSOR) {
670       /* determine sensor fit, and get sensor x/y, for auto fit we
671        * assume and square sensor and only use sensor_x */
672       float sizex = scene->r.xsch * scene->r.xasp;
673       float sizey = scene->r.ysch * scene->r.yasp;
674       int sensor_fit = BKE_camera_sensor_fit(ca->sensor_fit, sizex, sizey);
675       float sensor_x = ca->sensor_x;
676       float sensor_y = (ca->sensor_fit == CAMERA_SENSOR_FIT_AUTO) ? ca->sensor_x : ca->sensor_y;
677
678       /* determine sensor plane */
679       rctf rect;
680
681       if (sensor_fit == CAMERA_SENSOR_FIT_HOR) {
682         float sensor_scale = (x2i - x1i) / sensor_x;
683         float sensor_height = sensor_scale * sensor_y;
684
685         rect.xmin = x1i;
686         rect.xmax = x2i;
687         rect.ymin = (y1i + y2i) * 0.5f - sensor_height * 0.5f;
688         rect.ymax = rect.ymin + sensor_height;
689       }
690       else {
691         float sensor_scale = (y2i - y1i) / sensor_y;
692         float sensor_width = sensor_scale * sensor_x;
693
694         rect.xmin = (x1i + x2i) * 0.5f - sensor_width * 0.5f;
695         rect.xmax = rect.xmin + sensor_width;
696         rect.ymin = y1i;
697         rect.ymax = y2i;
698       }
699
700       /* draw */
701       immUniformThemeColorShade(TH_VIEW_OVERLAY, 100);
702
703       /* TODO Was using UI_draw_roundbox_4fv(false, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f, color).
704        * We'll probably need a new imm_draw_line_roundbox_dashed dor that - though in practice the
705        * 2.0f round corner effect was nearly not visible anyway... */
706       imm_draw_box_wire_2d(shdr_pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
707     }
708   }
709
710   immUnbindProgram();
711   /* end dashed lines */
712
713   /* camera name - draw in highlighted text color */
714   if (ca && ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) && (ca->flag & CAM_SHOWNAME)) {
715     UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
716     BLF_draw_default(x1i,
717                      y1i - (0.7f * U.widget_unit),
718                      0.0f,
719                      v3d->camera->id.name + 2,
720                      sizeof(v3d->camera->id.name) - 2);
721   }
722 }
723
724 static void drawrenderborder(ARegion *ar, View3D *v3d)
725 {
726   /* use the same program for everything */
727   uint shdr_pos = GPU_vertformat_attr_add(
728       immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
729
730   GPU_line_width(1.0f);
731
732   immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
733
734   float viewport_size[4];
735   GPU_viewport_size_get_f(viewport_size);
736   immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
737
738   immUniform1i("colors_len", 0); /* "simple" mode */
739   immUniform4f("color", 1.0f, 0.25f, 0.25f, 1.0f);
740   immUniform1f("dash_width", 6.0f);
741   immUniform1f("dash_factor", 0.5f);
742
743   imm_draw_box_wire_2d(shdr_pos,
744                        v3d->render_border.xmin * ar->winx,
745                        v3d->render_border.ymin * ar->winy,
746                        v3d->render_border.xmax * ar->winx,
747                        v3d->render_border.ymax * ar->winy);
748
749   immUnbindProgram();
750 }
751
752 void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, bool alphaoverride)
753 {
754   struct bThemeState theme_state;
755   Scene *scene = DEG_get_evaluated_scene(depsgraph);
756   RegionView3D *rv3d = ar->regiondata;
757
758   short flag = v3d->flag;
759   float glalphaclip = U.glalphaclip;
760   int obcenter_dia = U.obcenter_dia;
761   /* temp set drawtype to solid */
762   /* Setting these temporarily is not nice */
763   v3d->flag &= ~V3D_SELECT_OUTLINE;
764
765   /* not that nice but means we wont zoom into billboards */
766   U.glalphaclip = alphaoverride ? 0.5f : glalphaclip;
767
768   U.obcenter_dia = 0;
769
770   /* Tools may request depth outside of regular drawing code. */
771   UI_Theme_Store(&theme_state);
772   UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
773
774   ED_view3d_draw_setup_view(NULL, depsgraph, scene, ar, v3d, NULL, NULL, NULL);
775
776   GPU_clear(GPU_DEPTH_BIT);
777
778   if (rv3d->rflag & RV3D_CLIPPING) {
779     ED_view3d_clipping_set(rv3d);
780   }
781   /* get surface depth without bias */
782   rv3d->rflag |= RV3D_ZOFFSET_DISABLED;
783
784   GPU_depth_test(true);
785
786   GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
787   DRW_draw_depth_loop(depsgraph, ar, v3d, viewport);
788
789   if (rv3d->rflag & RV3D_CLIPPING) {
790     ED_view3d_clipping_disable();
791   }
792   rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED;
793
794   /* Reset default for UI */
795   GPU_depth_test(false);
796
797   U.glalphaclip = glalphaclip;
798   v3d->flag = flag;
799   U.obcenter_dia = obcenter_dia;
800
801   UI_Theme_Restore(&theme_state);
802 }
803
804 /* ******************** other elements ***************** */
805
806 /** could move this elsewhere, but tied into #ED_view3d_grid_scale */
807 float ED_scene_grid_scale(Scene *scene, const char **grid_unit)
808 {
809   /* apply units */
810   if (scene->unit.system) {
811     const void *usys;
812     int len;
813
814     bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
815
816     if (usys) {
817       int i = bUnit_GetBaseUnit(usys);
818       if (grid_unit) {
819         *grid_unit = bUnit_GetNameDisplay(usys, i);
820       }
821       return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length;
822     }
823   }
824
825   return 1.0f;
826 }
827
828 float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit)
829 {
830   return v3d->grid * ED_scene_grid_scale(scene, grid_unit);
831 }
832
833 /* Simulates the grid scale that is actually viewed.
834  * The actual code is seen in `object_grid_frag.glsl` (see `grid_res`).
835  * Currently the simulation is only done when RV3D_VIEW_IS_AXIS. */
836 float ED_view3d_grid_view_scale(Scene *scene,
837                                 View3D *v3d,
838                                 RegionView3D *rv3d,
839                                 const char **grid_unit)
840 {
841   float grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit);
842   if (!rv3d->is_persp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
843     /* Decrease the distance between grid snap points depending on zoom. */
844     float grid_subdiv = v3d->gridsubdiv;
845     if (grid_subdiv > 1) {
846       /* Allow 3 more subdivisions (see OBJECT_engine_init). */
847       grid_scale /= powf(grid_subdiv, 3);
848
849       /* `3.0` was a value obtained by trial and error in order to get
850        * a nice snap distance.*/
851       float grid_res = 3.0 * (rv3d->dist / v3d->lens);
852       float lvl = (logf(grid_res / grid_scale) / logf(grid_subdiv));
853
854       CLAMP_MIN(lvl, 0.0f);
855
856       grid_scale *= pow(grid_subdiv, (int)lvl);
857     }
858   }
859
860   return grid_scale;
861 }
862
863 static void draw_view_axis(RegionView3D *rv3d, const rcti *rect)
864 {
865   const float k = U.rvisize * U.pixelsize; /* axis size */
866   /* axis alpha offset (rvibright has range 0-10) */
867   const int bright = -20 * (10 - U.rvibright);
868
869   /* Axis center in screen coordinates.
870    *
871    * - Unit size offset so small text doesn't draw outside the screen
872    * - Extra X offset because of the panel expander.
873    */
874   const float startx = rect->xmax - (k + UI_UNIT_X * 1.5);
875   const float starty = rect->ymax - (k + UI_UNIT_Y);
876
877   float axis_pos[3][2];
878   uchar axis_col[3][4];
879
880   int axis_order[3] = {0, 1, 2};
881   axis_sort_v3(rv3d->viewinv[2], axis_order);
882
883   for (int axis_i = 0; axis_i < 3; axis_i++) {
884     int i = axis_order[axis_i];
885
886     /* get position of each axis tip on screen */
887     float vec[3] = {0.0f};
888     vec[i] = 1.0f;
889     mul_qt_v3(rv3d->viewquat, vec);
890     axis_pos[i][0] = startx + vec[0] * k;
891     axis_pos[i][1] = starty + vec[1] * k;
892
893     /* get color of each axis */
894     UI_GetThemeColorShade3ubv(TH_AXIS_X + i, bright, axis_col[i]); /* rgb */
895     axis_col[i][3] = 255 * hypotf(vec[0], vec[1]);                 /* alpha */
896   }
897
898   /* draw axis lines */
899   GPU_line_width(2.0f);
900   GPU_line_smooth(true);
901   GPU_blend(true);
902   GPU_blend_set_func_separate(
903       GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
904
905   GPUVertFormat *format = immVertexFormat();
906   uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
907   uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
908
909   immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
910   immBegin(GPU_PRIM_LINES, 6);
911
912   for (int axis_i = 0; axis_i < 3; axis_i++) {
913     int i = axis_order[axis_i];
914
915     immAttr4ubv(col, axis_col[i]);
916     immVertex2f(pos, startx, starty);
917     immAttr4ubv(col, axis_col[i]);
918     immVertex2fv(pos, axis_pos[i]);
919   }
920
921   immEnd();
922   immUnbindProgram();
923   GPU_line_smooth(false);
924
925   /* draw axis names */
926   for (int axis_i = 0; axis_i < 3; axis_i++) {
927     int i = axis_order[axis_i];
928
929     const char axis_text[2] = {'x' + i, '\0'};
930     BLF_color4ubv(BLF_default(), axis_col[i]);
931     BLF_draw_default_ascii(axis_pos[i][0] + 2, axis_pos[i][1] + 2, 0.0f, axis_text, 1);
932   }
933 }
934
935 #ifdef WITH_INPUT_NDOF
936 /* draw center and axis of rotation for ongoing 3D mouse navigation */
937 static void draw_rotation_guide(const RegionView3D *rv3d)
938 {
939   float o[3];   /* center of rotation */
940   float end[3]; /* endpoints for drawing */
941
942   GLubyte color[4] = {0, 108, 255, 255}; /* bright blue so it matches device LEDs */
943
944   negate_v3_v3(o, rv3d->ofs);
945
946   GPU_blend(true);
947   GPU_blend_set_func_separate(
948       GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
949   glDepthMask(GL_FALSE); /* don't overwrite zbuf */
950
951   GPUVertFormat *format = immVertexFormat();
952   uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
953   uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
954
955   immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
956
957   if (rv3d->rot_angle != 0.0f) {
958     /* -- draw rotation axis -- */
959     float scaled_axis[3];
960     const float scale = rv3d->dist;
961     mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale);
962
963     immBegin(GPU_PRIM_LINE_STRIP, 3);
964     color[3] = 0; /* more transparent toward the ends */
965     immAttr4ubv(col, color);
966     add_v3_v3v3(end, o, scaled_axis);
967     immVertex3fv(pos, end);
968
969 #  if 0
970     color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */
971     /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */
972 #  endif
973
974     color[3] = 127; /* more opaque toward the center */
975     immAttr4ubv(col, color);
976     immVertex3fv(pos, o);
977
978     color[3] = 0;
979     immAttr4ubv(col, color);
980     sub_v3_v3v3(end, o, scaled_axis);
981     immVertex3fv(pos, end);
982     immEnd();
983
984     /* -- draw ring around rotation center -- */
985     {
986 #  define ROT_AXIS_DETAIL 13
987
988       const float s = 0.05f * scale;
989       const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL);
990
991       float q[4]; /* rotate ring so it's perpendicular to axis */
992       const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f;
993       if (!upright) {
994         const float up[3] = {0.0f, 0.0f, 1.0f};
995         float vis_angle, vis_axis[3];
996
997         cross_v3_v3v3(vis_axis, up, rv3d->rot_axis);
998         vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis));
999         axis_angle_to_quat(q, vis_axis, vis_angle);
1000       }
1001
1002       immBegin(GPU_PRIM_LINE_LOOP, ROT_AXIS_DETAIL);
1003       color[3] = 63; /* somewhat faint */
1004       immAttr4ubv(col, color);
1005       float angle = 0.0f;
1006       for (int i = 0; i < ROT_AXIS_DETAIL; ++i, angle += step) {
1007         float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f};
1008
1009         if (!upright) {
1010           mul_qt_v3(q, p);
1011         }
1012
1013         add_v3_v3(p, o);
1014         immVertex3fv(pos, p);
1015       }
1016       immEnd();
1017
1018 #  undef ROT_AXIS_DETAIL
1019     }
1020
1021     color[3] = 255; /* solid dot */
1022   }
1023   else {
1024     color[3] = 127; /* see-through dot */
1025   }
1026
1027   immUnbindProgram();
1028
1029   /* -- draw rotation center -- */
1030   immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
1031   GPU_point_size(5.0f);
1032   immBegin(GPU_PRIM_POINTS, 1);
1033   immAttr4ubv(col, color);
1034   immVertex3fv(pos, o);
1035   immEnd();
1036   immUnbindProgram();
1037
1038 #  if 0
1039   /* find screen coordinates for rotation center, then draw pretty icon */
1040   mul_m4_v3(rv3d->persinv, rot_center);
1041   UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN);
1042   /* ^^ just playing around, does not work */
1043 #  endif
1044
1045   GPU_blend(false);
1046   glDepthMask(GL_TRUE);
1047 }
1048 #endif /* WITH_INPUT_NDOF */
1049
1050 /**
1051  * Render and camera border
1052  */
1053 static void view3d_draw_border(const bContext *C, ARegion *ar)
1054 {
1055   Scene *scene = CTX_data_scene(C);
1056   Depsgraph *depsgraph = CTX_data_depsgraph(C);
1057   RegionView3D *rv3d = ar->regiondata;
1058   View3D *v3d = CTX_wm_view3d(C);
1059
1060   if (rv3d->persp == RV3D_CAMOB) {
1061     drawviewborder(scene, depsgraph, ar, v3d);
1062   }
1063   else if (v3d->flag2 & V3D_RENDER_BORDER) {
1064     drawrenderborder(ar, v3d);
1065   }
1066 }
1067
1068 /** \} */
1069
1070 /* -------------------------------------------------------------------- */
1071 /** \name Draw Text & Info
1072  * \{ */
1073
1074 /**
1075  * Draw Info
1076  */
1077 static void view3d_draw_grease_pencil(const bContext *UNUSED(C))
1078 {
1079   /* TODO viewport */
1080 }
1081
1082 /**
1083  * Viewport Name
1084  */
1085 static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d)
1086 {
1087   const char *name = NULL;
1088
1089   switch (rv3d->view) {
1090     case RV3D_VIEW_FRONT:
1091       if (rv3d->persp == RV3D_ORTHO) {
1092         name = IFACE_("Front Orthographic");
1093       }
1094       else {
1095         name = IFACE_("Front Perspective");
1096       }
1097       break;
1098     case RV3D_VIEW_BACK:
1099       if (rv3d->persp == RV3D_ORTHO) {
1100         name = IFACE_("Back Orthographic");
1101       }
1102       else {
1103         name = IFACE_("Back Perspective");
1104       }
1105       break;
1106     case RV3D_VIEW_TOP:
1107       if (rv3d->persp == RV3D_ORTHO) {
1108         name = IFACE_("Top Orthographic");
1109       }
1110       else {
1111         name = IFACE_("Top Perspective");
1112       }
1113       break;
1114     case RV3D_VIEW_BOTTOM:
1115       if (rv3d->persp == RV3D_ORTHO) {
1116         name = IFACE_("Bottom Orthographic");
1117       }
1118       else {
1119         name = IFACE_("Bottom Perspective");
1120       }
1121       break;
1122     case RV3D_VIEW_RIGHT:
1123       if (rv3d->persp == RV3D_ORTHO) {
1124         name = IFACE_("Right Orthographic");
1125       }
1126       else {
1127         name = IFACE_("Right Perspective");
1128       }
1129       break;
1130     case RV3D_VIEW_LEFT:
1131       if (rv3d->persp == RV3D_ORTHO) {
1132         name = IFACE_("Left Orthographic");
1133       }
1134       else {
1135         name = IFACE_("Left Perspective");
1136       }
1137       break;
1138
1139     default:
1140       if (rv3d->persp == RV3D_CAMOB) {
1141         if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) {
1142           Camera *cam;
1143           cam = v3d->camera->data;
1144           if (cam->type == CAM_PERSP) {
1145             name = IFACE_("Camera Perspective");
1146           }
1147           else if (cam->type == CAM_ORTHO) {
1148             name = IFACE_("Camera Orthographic");
1149           }
1150           else {
1151             BLI_assert(cam->type == CAM_PANO);
1152             name = IFACE_("Camera Panoramic");
1153           }
1154         }
1155         else {
1156           name = IFACE_("Object as Camera");
1157         }
1158       }
1159       else {
1160         name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Orthographic") :
1161                                              IFACE_("User Perspective");
1162       }
1163   }
1164
1165   return name;
1166 }
1167
1168 static void draw_viewport_name(ARegion *ar, View3D *v3d, int xoffset, int *yoffset)
1169 {
1170   RegionView3D *rv3d = ar->regiondata;
1171   const char *name = view3d_get_name(v3d, rv3d);
1172   const int font_id = BLF_default();
1173
1174   /* increase size for unicode languages (Chinese in utf-8...) */
1175 #ifdef WITH_INTERNATIONAL
1176   char tmpstr[96];
1177 #else
1178   char tmpstr[32];
1179 #endif
1180
1181   BLF_enable(font_id, BLF_SHADOW);
1182   BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
1183   BLF_shadow_offset(font_id, 1, -1);
1184
1185   if (v3d->localvd) {
1186     BLI_snprintf(tmpstr, sizeof(tmpstr), IFACE_("%s (Local)"), name);
1187     name = tmpstr;
1188   }
1189
1190   UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
1191
1192   *yoffset -= U.widget_unit;
1193
1194 #ifdef WITH_INTERNATIONAL
1195   BLF_draw_default(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr));
1196 #else
1197   BLF_draw_default_ascii(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr));
1198 #endif
1199
1200   BLF_disable(font_id, BLF_SHADOW);
1201 }
1202
1203 /**
1204  * draw info beside axes in bottom left-corner:
1205  * framenum, collection, object name, bone name (if available), marker name (if available)
1206  */
1207
1208 static void draw_selected_name(
1209     Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset)
1210 {
1211   const int cfra = CFRA;
1212   const char *msg_pin = " (Pinned)";
1213   const char *msg_sep = " : ";
1214
1215   const int font_id = BLF_default();
1216
1217   char info[300];
1218   char *s = info;
1219
1220   s += sprintf(s, "(%d)", cfra);
1221
1222   if ((ob == NULL) || (ob->mode == OB_MODE_OBJECT)) {
1223     LayerCollection *layer_collection = view_layer->active_collection;
1224     s += sprintf(s,
1225                  " %s%s",
1226                  BKE_collection_ui_name_get(layer_collection->collection),
1227                  (ob == NULL) ? "" : " |");
1228   }
1229
1230   /*
1231    * info can contain:
1232    * - a frame (7 + 2)
1233    * - a collection name (MAX_NAME + 3)
1234    * - 3 object names (MAX_NAME)
1235    * - 2 BREAD_CRUMB_SEPARATORs (6)
1236    * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room!
1237    * - a marker name (MAX_NAME + 3)
1238    */
1239
1240   /* get name of marker on current frame (if available) */
1241   const char *markern = BKE_scene_find_marker_name(scene, cfra);
1242
1243   /* check if there is an object */
1244   if (ob) {
1245     *s++ = ' ';
1246     s += BLI_strcpy_rlen(s, ob->id.name + 2);
1247
1248     /* name(s) to display depends on type of object */
1249     if (ob->type == OB_ARMATURE) {
1250       bArmature *arm = ob->data;
1251
1252       /* show name of active bone too (if possible) */
1253       if (arm->edbo) {
1254         if (arm->act_edbone) {
1255           s += BLI_strcpy_rlen(s, msg_sep);
1256           s += BLI_strcpy_rlen(s, arm->act_edbone->name);
1257         }
1258       }
1259       else if (ob->mode & OB_MODE_POSE) {
1260         if (arm->act_bone) {
1261
1262           if (arm->act_bone->layer & arm->layer) {
1263             s += BLI_strcpy_rlen(s, msg_sep);
1264             s += BLI_strcpy_rlen(s, arm->act_bone->name);
1265           }
1266         }
1267       }
1268     }
1269     else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) {
1270       /* try to display active bone and active shapekey too (if they exist) */
1271
1272       if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) {
1273         Object *armobj = BKE_object_pose_armature_get(ob);
1274         if (armobj && armobj->mode & OB_MODE_POSE) {
1275           bArmature *arm = armobj->data;
1276           if (arm->act_bone) {
1277             if (arm->act_bone->layer & arm->layer) {
1278               s += BLI_strcpy_rlen(s, msg_sep);
1279               s += BLI_strcpy_rlen(s, arm->act_bone->name);
1280             }
1281           }
1282         }
1283       }
1284
1285       Key *key = BKE_key_from_object(ob);
1286       if (key) {
1287         KeyBlock *kb = BLI_findlink(&key->block, ob->shapenr - 1);
1288         if (kb) {
1289           s += BLI_strcpy_rlen(s, msg_sep);
1290           s += BLI_strcpy_rlen(s, kb->name);
1291           if (ob->shapeflag & OB_SHAPE_LOCK) {
1292             s += BLI_strcpy_rlen(s, IFACE_(msg_pin));
1293           }
1294         }
1295       }
1296     }
1297
1298     /* color depends on whether there is a keyframe */
1299     if (id_frame_has_keyframe(
1300             (ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) {
1301       UI_FontThemeColor(font_id, TH_TIME_KEYFRAME);
1302     }
1303     else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) {
1304       UI_FontThemeColor(font_id, TH_TIME_GP_KEYFRAME);
1305     }
1306     else {
1307       UI_FontThemeColor(font_id, TH_TEXT_HI);
1308     }
1309   }
1310   else {
1311     /* no object */
1312     if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra)) {
1313       UI_FontThemeColor(font_id, TH_TIME_GP_KEYFRAME);
1314     }
1315     else {
1316       UI_FontThemeColor(font_id, TH_TEXT_HI);
1317     }
1318   }
1319
1320   if (markern) {
1321     s += sprintf(s, " <%s>", markern);
1322   }
1323
1324   BLF_enable(font_id, BLF_SHADOW);
1325   BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
1326   BLF_shadow_offset(font_id, 1, -1);
1327
1328   *yoffset -= U.widget_unit;
1329   BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info));
1330
1331   BLF_disable(font_id, BLF_SHADOW);
1332 }
1333
1334 /**
1335  * Information drawn on top of the solid plates and composed data
1336  */
1337 void view3d_draw_region_info(const bContext *C, ARegion *ar)
1338 {
1339   RegionView3D *rv3d = ar->regiondata;
1340   View3D *v3d = CTX_wm_view3d(C);
1341   Scene *scene = CTX_data_scene(C);
1342   wmWindowManager *wm = CTX_wm_manager(C);
1343
1344 #ifdef WITH_INPUT_NDOF
1345   if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((rv3d->viewlock & RV3D_LOCKED) == 0) &&
1346       (rv3d->persp != RV3D_CAMOB)) {
1347     /* TODO: draw something else (but not this) during fly mode */
1348     draw_rotation_guide(rv3d);
1349   }
1350 #endif
1351
1352   /* correct projection matrix */
1353   ED_region_pixelspace(ar);
1354
1355   /* local coordinate visible rect inside region, to accommodate overlapping ui */
1356   rcti rect;
1357   ED_region_visible_rect(ar, &rect);
1358
1359   view3d_draw_border(C, ar);
1360   view3d_draw_grease_pencil(C);
1361
1362   BLF_batch_draw_begin();
1363
1364   if ((U.uiflag & USER_SHOW_GIZMO_AXIS) ||
1365       /* No need to display gizmo and this info. */
1366       (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_NAVIGATE))) {
1367     /* pass */
1368   }
1369   else {
1370     draw_view_axis(rv3d, &rect);
1371   }
1372
1373   int xoffset = rect.xmin + U.widget_unit;
1374   int yoffset = rect.ymax;
1375
1376   if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
1377     if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
1378       ED_scene_draw_fps(scene, xoffset, &yoffset);
1379     }
1380     else if (U.uiflag & USER_SHOW_VIEWPORTNAME) {
1381       draw_viewport_name(ar, v3d, xoffset, &yoffset);
1382     }
1383
1384     if (U.uiflag & USER_DRAWVIEWINFO) {
1385       ViewLayer *view_layer = CTX_data_view_layer(C);
1386       Object *ob = OBACT(view_layer);
1387       draw_selected_name(scene, view_layer, ob, xoffset, &yoffset);
1388     }
1389
1390 #if 0 /* TODO */
1391     if (grid_unit) { /* draw below the viewport name */
1392       char numstr[32] = "";
1393
1394       UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
1395       if (v3d->grid != 1.0f) {
1396         BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid);
1397       }
1398
1399       *yoffset -= U.widget_unit;
1400       BLF_draw_default_ascii(xoffset, *yoffset, numstr[0] ? numstr : grid_unit, sizeof(numstr));
1401     }
1402 #endif
1403   }
1404
1405   if ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
1406     DRW_draw_region_engine_info(xoffset, yoffset);
1407   }
1408
1409   BLF_batch_draw_end();
1410 }
1411
1412 /** \} */
1413
1414 /* -------------------------------------------------------------------- */
1415 /** \name Draw Viewport Contents
1416  * \{ */
1417
1418 static void view3d_draw_view(const bContext *C, ARegion *ar)
1419 {
1420   ED_view3d_draw_setup_view(CTX_wm_window(C),
1421                             CTX_data_depsgraph(C),
1422                             CTX_data_scene(C),
1423                             ar,
1424                             CTX_wm_view3d(C),
1425                             NULL,
1426                             NULL,
1427                             NULL);
1428
1429   /* Only 100% compliant on new spec goes below */
1430   DRW_draw_view(C);
1431 }
1432
1433 RenderEngineType *ED_view3d_engine_type(Scene *scene, int drawtype)
1434 {
1435   /*
1436    * Temporary viewport draw modes until we have a proper system.
1437    * all modes are done in the draw manager, except
1438    * cycles material as it is an external render engine.
1439    */
1440   if (strcmp(scene->r.engine, RE_engine_id_CYCLES) == 0 && drawtype == OB_MATERIAL) {
1441     return RE_engines_find(RE_engine_id_BLENDER_EEVEE);
1442   }
1443   return RE_engines_find(scene->r.engine);
1444 }
1445
1446 void view3d_main_region_draw(const bContext *C, ARegion *ar)
1447 {
1448   Main *bmain = CTX_data_main(C);
1449   View3D *v3d = CTX_wm_view3d(C);
1450
1451   view3d_draw_view(C, ar);
1452
1453   GPU_free_images_old(bmain);
1454   GPU_pass_cache_garbage_collect();
1455
1456   /* XXX This is in order to draw UI batches with the DRW
1457    * olg context since we now use it for drawing the entire area */
1458   gpu_batch_presets_reset();
1459
1460   /* No depth test for drawing action zones afterwards. */
1461   GPU_depth_test(false);
1462
1463   v3d->flag |= V3D_INVALID_BACKBUF;
1464 }
1465
1466 /** \} */
1467
1468 /* -------------------------------------------------------------------- */
1469 /** \name Offscreen Drawing
1470  * \{ */
1471
1472 static void view3d_stereo3d_setup_offscreen(Depsgraph *depsgraph,
1473                                             Scene *scene,
1474                                             View3D *v3d,
1475                                             ARegion *ar,
1476                                             float winmat[4][4],
1477                                             const char *viewname)
1478 {
1479   /* update the viewport matrices with the new camera */
1480   if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
1481     float viewmat[4][4];
1482     const bool is_left = STREQ(viewname, STEREO_LEFT_NAME);
1483
1484     BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
1485     view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL);
1486   }
1487   else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
1488     float viewmat[4][4];
1489     Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
1490
1491     BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
1492     view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL);
1493   }
1494 }
1495
1496 void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
1497                               Scene *scene,
1498                               int drawtype,
1499                               View3D *v3d,
1500                               ARegion *ar,
1501                               int winx,
1502                               int winy,
1503                               float viewmat[4][4],
1504                               float winmat[4][4],
1505                               bool do_sky,
1506                               bool UNUSED(is_persp),
1507                               const char *viewname,
1508                               GPUFXSettings *UNUSED(fx_settings),
1509                               const bool do_color_management,
1510                               GPUOffScreen *ofs,
1511                               GPUViewport *viewport)
1512 {
1513   RegionView3D *rv3d = ar->regiondata;
1514   RenderEngineType *engine_type = ED_view3d_engine_type(scene, drawtype);
1515
1516   /* set temporary new size */
1517   int bwinx = ar->winx;
1518   int bwiny = ar->winy;
1519   rcti brect = ar->winrct;
1520
1521   ar->winx = winx;
1522   ar->winy = winy;
1523   ar->winrct.xmin = 0;
1524   ar->winrct.ymin = 0;
1525   ar->winrct.xmax = winx;
1526   ar->winrct.ymax = winy;
1527
1528   struct bThemeState theme_state;
1529   UI_Theme_Store(&theme_state);
1530   UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
1531
1532   /* set flags */
1533   G.f |= G_FLAG_RENDER_VIEWPORT;
1534
1535   {
1536     /* free images which can have changed on frame-change
1537      * warning! can be slow so only free animated images - campbell */
1538     GPU_free_images_anim(G.main); /* XXX :((( */
1539   }
1540
1541   GPU_matrix_push_projection();
1542   GPU_matrix_identity_set();
1543   GPU_matrix_push();
1544   GPU_matrix_identity_set();
1545
1546   if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) &&
1547       rv3d->persp == RV3D_CAMOB && v3d->camera) {
1548     view3d_stereo3d_setup_offscreen(depsgraph, scene, v3d, ar, winmat, viewname);
1549   }
1550   else {
1551     view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL);
1552   }
1553
1554   /* main drawing call */
1555   DRW_draw_render_loop_offscreen(
1556       depsgraph, engine_type, ar, v3d, do_sky, do_color_management, ofs, viewport);
1557
1558   /* restore size */
1559   ar->winx = bwinx;
1560   ar->winy = bwiny;
1561   ar->winrct = brect;
1562
1563   GPU_matrix_pop_projection();
1564   GPU_matrix_pop();
1565
1566   UI_Theme_Restore(&theme_state);
1567
1568   G.f &= ~G_FLAG_RENDER_VIEWPORT;
1569 }
1570
1571 /**
1572  * Utility func for ED_view3d_draw_offscreen
1573  *
1574  * \param ofs: Optional off-screen buffer, can be NULL.
1575  * (avoids re-creating when doing multiple GL renders).
1576  */
1577 ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
1578                                       Scene *scene,
1579                                       int drawtype,
1580                                       View3D *v3d,
1581                                       ARegion *ar,
1582                                       int sizex,
1583                                       int sizey,
1584                                       uint flag,
1585                                       uint draw_flags,
1586                                       int alpha_mode,
1587                                       int samples,
1588                                       const char *viewname,
1589                                       /* output vars */
1590                                       GPUOffScreen *ofs,
1591                                       char err_out[256])
1592 {
1593   RegionView3D *rv3d = ar->regiondata;
1594   const bool draw_sky = (alpha_mode == R_ADDSKY);
1595   const bool use_full_sample = (draw_flags & V3D_OFSDRAW_USE_FULL_SAMPLE);
1596
1597   /* view state */
1598   GPUFXSettings fx_settings = v3d->fx_settings;
1599   bool is_ortho = false;
1600   float winmat[4][4];
1601
1602   if (ofs && ((GPU_offscreen_width(ofs) != sizex) || (GPU_offscreen_height(ofs) != sizey))) {
1603     /* sizes differ, can't reuse */
1604     ofs = NULL;
1605   }
1606
1607   GPUFrameBuffer *old_fb = GPU_framebuffer_active_get();
1608
1609   if (old_fb) {
1610     GPU_framebuffer_restore();
1611   }
1612
1613   const bool own_ofs = (ofs == NULL);
1614   DRW_opengl_context_enable();
1615
1616   if (own_ofs) {
1617     /* bind */
1618     ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, true, false, err_out);
1619     if (ofs == NULL) {
1620       DRW_opengl_context_disable();
1621       return NULL;
1622     }
1623   }
1624
1625   GPU_offscreen_bind(ofs, true);
1626
1627   /* read in pixels & stamp */
1628   ImBuf *ibuf = IMB_allocImBuf(sizex, sizey, 32, flag);
1629
1630   /* render 3d view */
1631   if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
1632     CameraParams params;
1633     Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
1634     const Object *camera_eval = DEG_get_evaluated_object(depsgraph, camera);
1635
1636     BKE_camera_params_init(&params);
1637     /* fallback for non camera objects */
1638     params.clip_start = v3d->clip_start;
1639     params.clip_end = v3d->clip_end;
1640     BKE_camera_params_from_object(&params, camera_eval);
1641     BKE_camera_multiview_params(&scene->r, &params, camera_eval, viewname);
1642     BKE_camera_params_compute_viewplane(&params, sizex, sizey, scene->r.xasp, scene->r.yasp);
1643     BKE_camera_params_compute_matrix(&params);
1644
1645     BKE_camera_to_gpu_dof(camera, &fx_settings);
1646
1647     is_ortho = params.is_ortho;
1648     copy_m4_m4(winmat, params.winmat);
1649   }
1650   else {
1651     rctf viewplane;
1652     float clip_start, clipend;
1653
1654     is_ortho = ED_view3d_viewplane_get(
1655         depsgraph, v3d, rv3d, sizex, sizey, &viewplane, &clip_start, &clipend, NULL);
1656     if (is_ortho) {
1657       orthographic_m4(winmat,
1658                       viewplane.xmin,
1659                       viewplane.xmax,
1660                       viewplane.ymin,
1661                       viewplane.ymax,
1662                       -clipend,
1663                       clipend);
1664     }
1665     else {
1666       perspective_m4(winmat,
1667                      viewplane.xmin,
1668                      viewplane.xmax,
1669                      viewplane.ymin,
1670                      viewplane.ymax,
1671                      clip_start,
1672                      clipend);
1673     }
1674   }
1675
1676   if ((samples && use_full_sample) == 0) {
1677     const bool do_color_management = (ibuf->rect_float == NULL);
1678     /* Single-pass render, common case */
1679     ED_view3d_draw_offscreen(depsgraph,
1680                              scene,
1681                              drawtype,
1682                              v3d,
1683                              ar,
1684                              sizex,
1685                              sizey,
1686                              NULL,
1687                              winmat,
1688                              draw_sky,
1689                              !is_ortho,
1690                              viewname,
1691                              &fx_settings,
1692                              do_color_management,
1693                              ofs,
1694                              NULL);
1695
1696     if (ibuf->rect_float) {
1697       GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float);
1698     }
1699     else if (ibuf->rect) {
1700       GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect);
1701     }
1702   }
1703   else {
1704     /* Multi-pass render, use accumulation buffer & jitter for 'full' oversampling.
1705      * Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */
1706     static float jit_ofs[32][2];
1707     float winmat_jitter[4][4];
1708     float *rect_temp = (ibuf->rect_float) ?
1709                            ibuf->rect_float :
1710                            MEM_mallocN(sizex * sizey * sizeof(float[4]), "rect_temp");
1711     float *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(float[4]), "accum_buffer");
1712     GPUViewport *viewport = GPU_viewport_create_from_offscreen(ofs);
1713
1714     BLI_jitter_init(jit_ofs, samples);
1715
1716     /* first sample buffer, also initializes 'rv3d->persmat' */
1717     ED_view3d_draw_offscreen(depsgraph,
1718                              scene,
1719                              drawtype,
1720                              v3d,
1721                              ar,
1722                              sizex,
1723                              sizey,
1724                              NULL,
1725                              winmat,
1726                              draw_sky,
1727                              !is_ortho,
1728                              viewname,
1729                              &fx_settings,
1730                              false,
1731                              ofs,
1732                              viewport);
1733     GPU_offscreen_read_pixels(ofs, GL_FLOAT, accum_buffer);
1734
1735     /* skip the first sample */
1736     for (int j = 1; j < samples; j++) {
1737       copy_m4_m4(winmat_jitter, winmat);
1738       window_translate_m4(winmat_jitter,
1739                           rv3d->persmat,
1740                           (jit_ofs[j][0] * 2.0f) / sizex,
1741                           (jit_ofs[j][1] * 2.0f) / sizey);
1742
1743       ED_view3d_draw_offscreen(depsgraph,
1744                                scene,
1745                                drawtype,
1746                                v3d,
1747                                ar,
1748                                sizex,
1749                                sizey,
1750                                NULL,
1751                                winmat_jitter,
1752                                draw_sky,
1753                                !is_ortho,
1754                                viewname,
1755                                &fx_settings,
1756                                false,
1757                                ofs,
1758                                viewport);
1759       GPU_offscreen_read_pixels(ofs, GL_FLOAT, rect_temp);
1760
1761       uint i = sizex * sizey * 4;
1762       while (i--) {
1763         accum_buffer[i] += rect_temp[i];
1764       }
1765     }
1766
1767     {
1768       /* don't free data owned by 'ofs' */
1769       GPU_viewport_clear_from_offscreen(viewport);
1770       GPU_viewport_free(viewport);
1771     }
1772
1773     if (ibuf->rect_float == NULL) {
1774       MEM_freeN(rect_temp);
1775     }
1776
1777     if (ibuf->rect_float) {
1778       float *rect_float = ibuf->rect_float;
1779       uint i = sizex * sizey * 4;
1780       while (i--) {
1781         rect_float[i] = accum_buffer[i] / samples;
1782       }
1783     }
1784     else {
1785       uchar *rect_ub = (uchar *)ibuf->rect;
1786       uint i = sizex * sizey * 4;
1787       while (i--) {
1788         rect_ub[i] = (uchar)(255.0f * accum_buffer[i] / samples);
1789       }
1790     }
1791
1792     MEM_freeN(accum_buffer);
1793   }
1794
1795   /* unbind */
1796   GPU_offscreen_unbind(ofs, true);
1797
1798   if (own_ofs) {
1799     GPU_offscreen_free(ofs);
1800   }
1801
1802   DRW_opengl_context_disable();
1803
1804   if (old_fb) {
1805     GPU_framebuffer_bind(old_fb);
1806   }
1807
1808   if (ibuf->rect_float && ibuf->rect) {
1809     IMB_rect_from_float(ibuf);
1810   }
1811
1812   return ibuf;
1813 }
1814
1815 /**
1816  * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf)
1817  *
1818  * \param ofs: Optional off-screen buffer can be NULL.
1819  * (avoids re-creating when doing multiple GL renders).
1820  *
1821  * \note used by the sequencer
1822  */
1823 ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
1824                                              Scene *scene,
1825                                              int drawtype,
1826                                              Object *camera,
1827                                              int width,
1828                                              int height,
1829                                              uint flag,
1830                                              uint draw_flags,
1831                                              int alpha_mode,
1832                                              int samples,
1833                                              const char *viewname,
1834                                              GPUOffScreen *ofs,
1835                                              char err_out[256])
1836 {
1837   View3D v3d = {NULL};
1838   ARegion ar = {NULL};
1839   RegionView3D rv3d = {{{0}}};
1840
1841   /* connect data */
1842   v3d.regionbase.first = v3d.regionbase.last = &ar;
1843   ar.regiondata = &rv3d;
1844   ar.regiontype = RGN_TYPE_WINDOW;
1845
1846   v3d.camera = camera;
1847   v3d.shading.type = drawtype;
1848   v3d.flag2 = V3D_HIDE_OVERLAYS;
1849
1850   if (draw_flags & V3D_OFSDRAW_USE_GPENCIL) {
1851     v3d.flag2 |= V3D_SHOW_ANNOTATION;
1852   }
1853
1854   v3d.shading.background_type = V3D_SHADING_BACKGROUND_WORLD;
1855
1856   if (draw_flags & V3D_OFSDRAW_USE_CAMERA_DOF) {
1857     if (camera->type == OB_CAMERA) {
1858       v3d.fx_settings.dof = &((Camera *)camera->data)->gpu_dof;
1859       v3d.fx_settings.fx_flag |= GPU_FX_FLAG_DOF;
1860     }
1861   }
1862
1863   rv3d.persp = RV3D_CAMOB;
1864
1865   copy_m4_m4(rv3d.viewinv, v3d.camera->obmat);
1866   normalize_m4(rv3d.viewinv);
1867   invert_m4_m4(rv3d.viewmat, rv3d.viewinv);
1868
1869   {
1870     CameraParams params;
1871     const Object *view_camera_eval = DEG_get_evaluated_object(
1872         depsgraph, BKE_camera_multiview_render(scene, v3d.camera, viewname));
1873
1874     BKE_camera_params_init(&params);
1875     BKE_camera_params_from_object(&params, view_camera_eval);
1876     BKE_camera_multiview_params(&scene->r, &params, view_camera_eval, viewname);
1877     BKE_camera_params_compute_viewplane(&params, width, height, scene->r.xasp, scene->r.yasp);
1878     BKE_camera_params_compute_matrix(&params);
1879
1880     copy_m4_m4(rv3d.winmat, params.winmat);
1881     v3d.clip_start = params.clip_start;
1882     v3d.clip_end = params.clip_end;
1883     v3d.lens = params.lens;
1884   }
1885
1886   mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat);
1887   invert_m4_m4(rv3d.persinv, rv3d.viewinv);
1888
1889   return ED_view3d_draw_offscreen_imbuf(depsgraph,
1890                                         scene,
1891                                         drawtype,
1892                                         &v3d,
1893                                         &ar,
1894                                         width,
1895                                         height,
1896                                         flag,
1897                                         draw_flags,
1898                                         alpha_mode,
1899                                         samples,
1900                                         viewname,
1901                                         ofs,
1902                                         err_out);
1903 }
1904
1905 /** \} */
1906
1907 /* -------------------------------------------------------------------- */
1908 /** \name Viewport Clipping
1909  * \{ */
1910
1911 static bool view3d_clipping_test(const float co[3], const float clip[6][4])
1912 {
1913   if (plane_point_side_v3(clip[0], co) > 0.0f) {
1914     if (plane_point_side_v3(clip[1], co) > 0.0f) {
1915       if (plane_point_side_v3(clip[2], co) > 0.0f) {
1916         if (plane_point_side_v3(clip[3], co) > 0.0f) {
1917           return false;
1918         }
1919       }
1920     }
1921   }
1922
1923   return true;
1924 }
1925
1926 /* for 'local' ED_view3d_clipping_local must run first
1927  * then all comparisons can be done in localspace */
1928 bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
1929 {
1930   return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
1931 }
1932
1933 /** \} */