c1995249c26de422f945bedb64f5816c84372297
[blender-staging.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_jitter_2d.h"
27 #include "BLI_listbase.h"
28 #include "BLI_math.h"
29 #include "BLI_rect.h"
30 #include "BLI_string.h"
31 #include "BLI_string_utils.h"
32 #include "BLI_threads.h"
33
34 #include "BKE_camera.h"
35 #include "BKE_collection.h"
36 #include "BKE_context.h"
37 #include "BKE_customdata.h"
38 #include "BKE_global.h"
39 #include "BKE_key.h"
40 #include "BKE_layer.h"
41 #include "BKE_main.h"
42 #include "BKE_object.h"
43 #include "BKE_paint.h"
44 #include "BKE_scene.h"
45 #include "BKE_studiolight.h"
46 #include "BKE_unit.h"
47
48 #include "BLF_api.h"
49
50 #include "BLT_translation.h"
51
52 #include "DNA_armature_types.h"
53 #include "DNA_brush_types.h"
54 #include "DNA_camera_types.h"
55 #include "DNA_key_types.h"
56 #include "DNA_mesh_types.h"
57 #include "DNA_object_types.h"
58 #include "DNA_view3d_types.h"
59 #include "DNA_windowmanager_types.h"
60
61 #include "DRW_engine.h"
62 #include "DRW_select_buffer.h"
63
64 #include "ED_armature.h"
65 #include "ED_gpencil.h"
66 #include "ED_keyframing.h"
67 #include "ED_screen.h"
68 #include "ED_screen_types.h"
69 #include "ED_transform.h"
70 #include "ED_view3d_offscreen.h"
71
72 #include "DEG_depsgraph_query.h"
73
74 #include "GPU_batch.h"
75 #include "GPU_batch_presets.h"
76 #include "GPU_draw.h"
77 #include "GPU_framebuffer.h"
78 #include "GPU_immediate.h"
79 #include "GPU_immediate_util.h"
80 #include "GPU_material.h"
81 #include "GPU_matrix.h"
82 #include "GPU_state.h"
83 #include "GPU_viewport.h"
84
85 #include "MEM_guardedalloc.h"
86
87 #include "UI_interface.h"
88 #include "UI_resources.h"
89
90 #include "RE_engine.h"
91
92 #include "WM_api.h"
93 #include "WM_types.h"
94
95 #include "RNA_access.h"
96
97 #include "IMB_imbuf.h"
98 #include "IMB_imbuf_types.h"
99
100 #include "view3d_intern.h" /* own include */
101
102 #define M_GOLDEN_RATIO_CONJUGATE 0.618033988749895f
103
104 /* -------------------------------------------------------------------- */
105 /** \name General Functions
106  * \{ */
107
108 /**
109  * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
110  */
111 void ED_view3d_update_viewmat(Depsgraph *depsgraph,
112                               const Scene *scene,
113                               View3D *v3d,
114                               ARegion *region,
115                               float viewmat[4][4],
116                               float winmat[4][4],
117                               const rcti *rect,
118                               bool offscreen)
119 {
120   RegionView3D *rv3d = region->regiondata;
121
122   /* setup window matrices */
123   if (winmat) {
124     copy_m4_m4(rv3d->winmat, winmat);
125   }
126   else {
127     view3d_winmatrix_set(depsgraph, region, v3d, rect);
128   }
129
130   /* setup view matrix */
131   if (viewmat) {
132     copy_m4_m4(rv3d->viewmat, viewmat);
133   }
134   else {
135     float rect_scale[2];
136     if (rect) {
137       rect_scale[0] = (float)BLI_rcti_size_x(rect) / (float)region->winx;
138       rect_scale[1] = (float)BLI_rcti_size_y(rect) / (float)region->winy;
139     }
140     /* note: calls BKE_object_where_is_calc for camera... */
141     view3d_viewmatrix_set(depsgraph, scene, v3d, rv3d, rect ? rect_scale : NULL);
142   }
143   /* update utility matrices */
144   mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
145   invert_m4_m4(rv3d->persinv, rv3d->persmat);
146   invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
147
148   /* calculate GLSL view dependent values */
149
150   /* store window coordinates scaling/offset */
151   if (!offscreen && rv3d->persp == RV3D_CAMOB && v3d->camera) {
152     rctf cameraborder;
153     ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &cameraborder, false);
154     rv3d->viewcamtexcofac[0] = (float)region->winx / BLI_rctf_size_x(&cameraborder);
155     rv3d->viewcamtexcofac[1] = (float)region->winy / BLI_rctf_size_y(&cameraborder);
156
157     rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)region->winx;
158     rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)region->winy;
159   }
160   else {
161     rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f;
162     rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f;
163   }
164
165   /* calculate pixelsize factor once, is used for lights and obcenters */
166   {
167     /* note:  '1.0f / len_v3(v1)'  replaced  'len_v3(rv3d->viewmat[0])'
168      * because of float point precision problems at large values [#23908] */
169     float v1[3], v2[3];
170     float len_px, len_sc;
171
172     v1[0] = rv3d->persmat[0][0];
173     v1[1] = rv3d->persmat[1][0];
174     v1[2] = rv3d->persmat[2][0];
175
176     v2[0] = rv3d->persmat[0][1];
177     v2[1] = rv3d->persmat[1][1];
178     v2[2] = rv3d->persmat[2][1];
179
180     len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
181
182     if (rect) {
183       len_sc = (float)max_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect));
184     }
185     else {
186       len_sc = (float)MAX2(region->winx, region->winy);
187     }
188
189     rv3d->pixsize = len_px / len_sc;
190   }
191 }
192
193 static void view3d_main_region_setup_view(Depsgraph *depsgraph,
194                                           Scene *scene,
195                                           View3D *v3d,
196                                           ARegion *region,
197                                           float viewmat[4][4],
198                                           float winmat[4][4],
199                                           const rcti *rect)
200 {
201   RegionView3D *rv3d = region->regiondata;
202
203   ED_view3d_update_viewmat(depsgraph, scene, v3d, region, viewmat, winmat, rect, false);
204
205   /* set for opengl */
206   GPU_matrix_projection_set(rv3d->winmat);
207   GPU_matrix_set(rv3d->viewmat);
208 }
209
210 static void view3d_main_region_setup_offscreen(Depsgraph *depsgraph,
211                                                const Scene *scene,
212                                                View3D *v3d,
213                                                ARegion *region,
214                                                float viewmat[4][4],
215                                                float winmat[4][4])
216 {
217   RegionView3D *rv3d = region->regiondata;
218   ED_view3d_update_viewmat(depsgraph, scene, v3d, region, viewmat, winmat, NULL, true);
219
220   /* set for opengl */
221   GPU_matrix_projection_set(rv3d->winmat);
222   GPU_matrix_set(rv3d->viewmat);
223 }
224
225 static bool view3d_stereo3d_active(wmWindow *win,
226                                    const Scene *scene,
227                                    View3D *v3d,
228                                    RegionView3D *rv3d)
229 {
230   if ((scene->r.scemode & R_MULTIVIEW) == 0) {
231     return false;
232   }
233
234   if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) {
235     return false;
236   }
237
238   switch (v3d->stereo3d_camera) {
239     case STEREO_MONO_ID:
240       return false;
241       break;
242     case STEREO_3D_ID:
243       /* win will be NULL when calling this from the selection or draw loop. */
244       if ((win == NULL) || (WM_stereo3d_enabled(win, true) == false)) {
245         return false;
246       }
247       if (((scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) != 0) &&
248           !BKE_scene_multiview_is_stereo3d(&scene->r)) {
249         return false;
250       }
251       break;
252     /* We always need the stereo calculation for left and right cameras. */
253     case STEREO_LEFT_ID:
254     case STEREO_RIGHT_ID:
255     default:
256       break;
257   }
258   return true;
259 }
260
261 /* setup the view and win matrices for the multiview cameras
262  *
263  * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called
264  * we have no winmatrix (i.e., projection matrix) defined at that time.
265  * Since the camera and the camera shift are needed for the winmat calculation
266  * we do a small hack to replace it temporarily so we don't need to change the
267  * view3d)main_region_setup_view() code to account for that.
268  */
269 static void view3d_stereo3d_setup(
270     Depsgraph *depsgraph, Scene *scene, View3D *v3d, ARegion *region, const rcti *rect)
271 {
272   bool is_left;
273   const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
274   const char *viewname;
275
276   /* show only left or right camera */
277   if (v3d->stereo3d_camera != STEREO_3D_ID) {
278     v3d->multiview_eye = v3d->stereo3d_camera;
279   }
280
281   is_left = v3d->multiview_eye == STEREO_LEFT_ID;
282   viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID];
283
284   /* update the viewport matrices with the new camera */
285   if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
286     Camera *data, *data_eval;
287     float viewmat[4][4];
288     float shiftx;
289
290     data = (Camera *)v3d->camera->data;
291     data_eval = (Camera *)DEG_get_evaluated_id(depsgraph, &data->id);
292
293     shiftx = data_eval->shiftx;
294
295     BLI_thread_lock(LOCK_VIEW3D);
296     data_eval->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname);
297
298     BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
299     view3d_main_region_setup_view(depsgraph, scene, v3d, region, viewmat, NULL, rect);
300
301     data_eval->shiftx = shiftx;
302     BLI_thread_unlock(LOCK_VIEW3D);
303   }
304   else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
305     float viewmat[4][4];
306     Object *view_ob = v3d->camera;
307     Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
308
309     BLI_thread_lock(LOCK_VIEW3D);
310     v3d->camera = camera;
311
312     BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
313     view3d_main_region_setup_view(depsgraph, scene, v3d, region, viewmat, NULL, rect);
314
315     v3d->camera = view_ob;
316     BLI_thread_unlock(LOCK_VIEW3D);
317   }
318 }
319
320 #ifdef WITH_XR_OPENXR
321 static void view3d_xr_mirror_setup(const wmWindowManager *wm,
322                                    Depsgraph *depsgraph,
323                                    Scene *scene,
324                                    View3D *v3d,
325                                    ARegion *region,
326                                    const rcti *rect)
327 {
328   RegionView3D *rv3d = region->regiondata;
329   float viewmat[4][4];
330   const float lens_old = v3d->lens;
331
332   if (!WM_xr_session_state_viewer_pose_matrix_info_get(&wm->xr, viewmat, &v3d->lens)) {
333     /* Can't get info from XR session, use fallback values. */
334     copy_m4_m4(viewmat, rv3d->viewmat);
335     v3d->lens = lens_old;
336   }
337   view3d_main_region_setup_view(depsgraph, scene, v3d, region, viewmat, NULL, rect);
338
339   /* Reset overridden View3D data */
340   v3d->lens = lens_old;
341 }
342 #endif /* WITH_XR_OPENXR */
343
344 /**
345  * Set the correct matrices
346  */
347 void ED_view3d_draw_setup_view(const wmWindowManager *wm,
348                                wmWindow *win,
349                                Depsgraph *depsgraph,
350                                Scene *scene,
351                                ARegion *region,
352                                View3D *v3d,
353                                float viewmat[4][4],
354                                float winmat[4][4],
355                                const rcti *rect)
356 {
357   RegionView3D *rv3d = region->regiondata;
358
359 #ifdef WITH_XR_OPENXR
360   /* Setup the view matrix. */
361   if (ED_view3d_is_region_xr_mirror_active(wm, v3d, region)) {
362     view3d_xr_mirror_setup(wm, depsgraph, scene, v3d, region, rect);
363   }
364   else
365 #endif
366       if (view3d_stereo3d_active(win, scene, v3d, rv3d)) {
367     view3d_stereo3d_setup(depsgraph, scene, v3d, region, rect);
368   }
369   else {
370     view3d_main_region_setup_view(depsgraph, scene, v3d, region, viewmat, winmat, rect);
371   }
372
373 #ifndef WITH_XR_OPENXR
374   UNUSED_VARS(wm);
375 #endif
376 }
377
378 /** \} */
379
380 /* -------------------------------------------------------------------- */
381 /** \name Draw View Border
382  * \{ */
383
384 static void view3d_camera_border(const Scene *scene,
385                                  struct Depsgraph *depsgraph,
386                                  const ARegion *region,
387                                  const View3D *v3d,
388                                  const RegionView3D *rv3d,
389                                  rctf *r_viewborder,
390                                  const bool no_shift,
391                                  const bool no_zoom)
392 {
393   CameraParams params;
394   rctf rect_view, rect_camera;
395   Object *camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
396
397   /* get viewport viewplane */
398   BKE_camera_params_init(&params);
399   BKE_camera_params_from_view3d(&params, depsgraph, v3d, rv3d);
400   if (no_zoom) {
401     params.zoom = 1.0f;
402   }
403   BKE_camera_params_compute_viewplane(&params, region->winx, region->winy, 1.0f, 1.0f);
404   rect_view = params.viewplane;
405
406   /* get camera viewplane */
407   BKE_camera_params_init(&params);
408   /* fallback for non camera objects */
409   params.clip_start = v3d->clip_start;
410   params.clip_end = v3d->clip_end;
411   BKE_camera_params_from_object(&params, camera_eval);
412   if (no_shift) {
413     params.shiftx = 0.0f;
414     params.shifty = 0.0f;
415   }
416   BKE_camera_params_compute_viewplane(
417       &params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp);
418   rect_camera = params.viewplane;
419
420   /* get camera border within viewport */
421   r_viewborder->xmin = ((rect_camera.xmin - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) *
422                        region->winx;
423   r_viewborder->xmax = ((rect_camera.xmax - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) *
424                        region->winx;
425   r_viewborder->ymin = ((rect_camera.ymin - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) *
426                        region->winy;
427   r_viewborder->ymax = ((rect_camera.ymax - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) *
428                        region->winy;
429 }
430
431 void ED_view3d_calc_camera_border_size(const Scene *scene,
432                                        Depsgraph *depsgraph,
433                                        const ARegion *region,
434                                        const View3D *v3d,
435                                        const RegionView3D *rv3d,
436                                        float r_size[2])
437 {
438   rctf viewborder;
439
440   view3d_camera_border(scene, depsgraph, region, v3d, rv3d, &viewborder, true, true);
441   r_size[0] = BLI_rctf_size_x(&viewborder);
442   r_size[1] = BLI_rctf_size_y(&viewborder);
443 }
444
445 void ED_view3d_calc_camera_border(const Scene *scene,
446                                   Depsgraph *depsgraph,
447                                   const ARegion *region,
448                                   const View3D *v3d,
449                                   const RegionView3D *rv3d,
450                                   rctf *r_viewborder,
451                                   const bool no_shift)
452 {
453   view3d_camera_border(scene, depsgraph, region, v3d, rv3d, r_viewborder, no_shift, false);
454 }
455
456 static void drawviewborder_grid3(uint shdr_pos, float x1, float x2, float y1, float y2, float fac)
457 {
458   float x3, y3, x4, y4;
459
460   x3 = x1 + fac * (x2 - x1);
461   y3 = y1 + fac * (y2 - y1);
462   x4 = x1 + (1.0f - fac) * (x2 - x1);
463   y4 = y1 + (1.0f - fac) * (y2 - y1);
464
465   immBegin(GPU_PRIM_LINES, 8);
466
467   immVertex2f(shdr_pos, x1, y3);
468   immVertex2f(shdr_pos, x2, y3);
469
470   immVertex2f(shdr_pos, x1, y4);
471   immVertex2f(shdr_pos, x2, y4);
472
473   immVertex2f(shdr_pos, x3, y1);
474   immVertex2f(shdr_pos, x3, y2);
475
476   immVertex2f(shdr_pos, x4, y1);
477   immVertex2f(shdr_pos, x4, y2);
478
479   immEnd();
480 }
481
482 /* harmonious triangle */
483 static void drawviewborder_triangle(
484     uint shdr_pos, float x1, float x2, float y1, float y2, const char golden, const char dir)
485 {
486   float ofs;
487   float w = x2 - x1;
488   float h = y2 - y1;
489
490   immBegin(GPU_PRIM_LINES, 6);
491
492   if (w > h) {
493     if (golden) {
494       ofs = w * (1.0f - M_GOLDEN_RATIO_CONJUGATE);
495     }
496     else {
497       ofs = h * (h / w);
498     }
499     if (dir == 'B') {
500       SWAP(float, y1, y2);
501     }
502
503     immVertex2f(shdr_pos, x1, y1);
504     immVertex2f(shdr_pos, x2, y2);
505
506     immVertex2f(shdr_pos, x2, y1);
507     immVertex2f(shdr_pos, x1 + (w - ofs), y2);
508
509     immVertex2f(shdr_pos, x1, y2);
510     immVertex2f(shdr_pos, x1 + ofs, y1);
511   }
512   else {
513     if (golden) {
514       ofs = h * (1.0f - M_GOLDEN_RATIO_CONJUGATE);
515     }
516     else {
517       ofs = w * (w / h);
518     }
519     if (dir == 'B') {
520       SWAP(float, x1, x2);
521     }
522
523     immVertex2f(shdr_pos, x1, y1);
524     immVertex2f(shdr_pos, x2, y2);
525
526     immVertex2f(shdr_pos, x2, y1);
527     immVertex2f(shdr_pos, x1, y1 + ofs);
528
529     immVertex2f(shdr_pos, x1, y2);
530     immVertex2f(shdr_pos, x2, y1 + (h - ofs));
531   }
532
533   immEnd();
534 }
535
536 static void drawviewborder(Scene *scene, Depsgraph *depsgraph, ARegion *region, View3D *v3d)
537 {
538   float x1, x2, y1, y2;
539   float x1i, x2i, y1i, y2i;
540
541   rctf viewborder;
542   Camera *ca = NULL;
543   RegionView3D *rv3d = region->regiondata;
544
545   if (v3d->camera == NULL) {
546     return;
547   }
548   if (v3d->camera->type == OB_CAMERA) {
549     ca = v3d->camera->data;
550   }
551
552   ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &viewborder, false);
553   /* the offsets */
554   x1 = viewborder.xmin;
555   y1 = viewborder.ymin;
556   x2 = viewborder.xmax;
557   y2 = viewborder.ymax;
558
559   GPU_line_width(1.0f);
560
561   /* apply offsets so the real 3D camera shows through */
562
563   /* note: quite un-scientific but without this bit extra
564    * 0.0001 on the lower left the 2D border sometimes
565    * obscures the 3D camera border */
566   /* note: with VIEW3D_CAMERA_BORDER_HACK defined this error isn't noticeable
567    * but keep it here in case we need to remove the workaround */
568   x1i = (int)(x1 - 1.0001f);
569   y1i = (int)(y1 - 1.0001f);
570   x2i = (int)(x2 + (1.0f - 0.0001f));
571   y2i = (int)(y2 + (1.0f - 0.0001f));
572
573   uint shdr_pos = GPU_vertformat_attr_add(
574       immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
575
576   /* First, solid lines. */
577   {
578     immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
579
580     /* passepartout, specified in camera edit buttons */
581     if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) {
582       const float winx = (region->winx + 1);
583       const float winy = (region->winy + 1);
584
585       float alpha = 1.0f;
586
587       if (ca->passepartalpha != 1.0f) {
588         GPU_blend_set_func_separate(
589             GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
590         GPU_blend(true);
591         alpha = ca->passepartalpha;
592       }
593
594       immUniformColor4f(0.0f, 0.0f, 0.0f, alpha);
595
596       if (x1i > 0.0f) {
597         immRectf(shdr_pos, 0.0f, winy, x1i, 0.0f);
598       }
599       if (x2i < winx) {
600         immRectf(shdr_pos, x2i, winy, winx, 0.0f);
601       }
602       if (y2i < winy) {
603         immRectf(shdr_pos, x1i, winy, x2i, y2i);
604       }
605       if (y2i > 0.0f) {
606         immRectf(shdr_pos, x1i, y1i, x2i, 0.0f);
607       }
608
609       GPU_blend(false);
610     }
611
612     immUniformThemeColor3(TH_BACK);
613     imm_draw_box_wire_2d(shdr_pos, x1i, y1i, x2i, y2i);
614
615 #ifdef VIEW3D_CAMERA_BORDER_HACK
616     if (view3d_camera_border_hack_test == true) {
617       immUniformColor3ubv(view3d_camera_border_hack_col);
618       imm_draw_box_wire_2d(shdr_pos, x1i + 1, y1i + 1, x2i - 1, y2i - 1);
619       view3d_camera_border_hack_test = false;
620     }
621 #endif
622
623     immUnbindProgram();
624   }
625
626   /* When overlays are disabled, only show camera outline & passepartout. */
627   if (v3d->flag2 & V3D_HIDE_OVERLAYS) {
628     return;
629   }
630
631   /* And now, the dashed lines! */
632   immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
633
634   {
635     float viewport_size[4];
636     GPU_viewport_size_get_f(viewport_size);
637     immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
638
639     immUniform1i("colors_len", 0); /* "simple" mode */
640     immUniform1f("dash_width", 6.0f);
641     immUniform1f("dash_factor", 0.5f);
642
643     /* outer line not to confuse with object selection */
644     if (v3d->flag2 & V3D_LOCK_CAMERA) {
645       immUniformThemeColor(TH_REDALERT);
646       imm_draw_box_wire_2d(shdr_pos, x1i - 1, y1i - 1, x2i + 1, y2i + 1);
647     }
648
649     immUniformThemeColor3(TH_VIEW_OVERLAY);
650     imm_draw_box_wire_2d(shdr_pos, x1i, y1i, x2i, y2i);
651   }
652
653   /* Render Border. */
654   if (scene->r.mode & R_BORDER) {
655     float x3, y3, x4, y4;
656
657     x3 = floorf(x1 + (scene->r.border.xmin * (x2 - x1))) - 1;
658     y3 = floorf(y1 + (scene->r.border.ymin * (y2 - y1))) - 1;
659     x4 = floorf(x1 + (scene->r.border.xmax * (x2 - x1))) + (U.pixelsize - 1);
660     y4 = floorf(y1 + (scene->r.border.ymax * (y2 - y1))) + (U.pixelsize - 1);
661
662     immUniformColor3f(1.0f, 0.25f, 0.25f);
663     imm_draw_box_wire_2d(shdr_pos, x3, y3, x4, y4);
664   }
665
666   /* safety border */
667   if (ca) {
668     immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f);
669
670     if (ca->dtx & CAM_DTX_CENTER) {
671       float x3, y3;
672
673       x3 = x1 + 0.5f * (x2 - x1);
674       y3 = y1 + 0.5f * (y2 - y1);
675
676       immBegin(GPU_PRIM_LINES, 4);
677
678       immVertex2f(shdr_pos, x1, y3);
679       immVertex2f(shdr_pos, x2, y3);
680
681       immVertex2f(shdr_pos, x3, y1);
682       immVertex2f(shdr_pos, x3, y2);
683
684       immEnd();
685     }
686
687     if (ca->dtx & CAM_DTX_CENTER_DIAG) {
688       immBegin(GPU_PRIM_LINES, 4);
689
690       immVertex2f(shdr_pos, x1, y1);
691       immVertex2f(shdr_pos, x2, y2);
692
693       immVertex2f(shdr_pos, x1, y2);
694       immVertex2f(shdr_pos, x2, y1);
695
696       immEnd();
697     }
698
699     if (ca->dtx & CAM_DTX_THIRDS) {
700       drawviewborder_grid3(shdr_pos, x1, x2, y1, y2, 1.0f / 3.0f);
701     }
702
703     if (ca->dtx & CAM_DTX_GOLDEN) {
704       drawviewborder_grid3(shdr_pos, x1, x2, y1, y2, 1.0f - M_GOLDEN_RATIO_CONJUGATE);
705     }
706
707     if (ca->dtx & CAM_DTX_GOLDEN_TRI_A) {
708       drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 0, 'A');
709     }
710
711     if (ca->dtx & CAM_DTX_GOLDEN_TRI_B) {
712       drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 0, 'B');
713     }
714
715     if (ca->dtx & CAM_DTX_HARMONY_TRI_A) {
716       drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 1, 'A');
717     }
718
719     if (ca->dtx & CAM_DTX_HARMONY_TRI_B) {
720       drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 1, 'B');
721     }
722
723     if (ca->flag & CAM_SHOW_SAFE_MARGINS) {
724       UI_draw_safe_areas(
725           shdr_pos, x1, x2, y1, y2, scene->safe_areas.title, scene->safe_areas.action);
726
727       if (ca->flag & CAM_SHOW_SAFE_CENTER) {
728         UI_draw_safe_areas(shdr_pos,
729                            x1,
730                            x2,
731                            y1,
732                            y2,
733                            scene->safe_areas.title_center,
734                            scene->safe_areas.action_center);
735       }
736     }
737
738     if (ca->flag & CAM_SHOWSENSOR) {
739       /* determine sensor fit, and get sensor x/y, for auto fit we
740        * assume and square sensor and only use sensor_x */
741       float sizex = scene->r.xsch * scene->r.xasp;
742       float sizey = scene->r.ysch * scene->r.yasp;
743       int sensor_fit = BKE_camera_sensor_fit(ca->sensor_fit, sizex, sizey);
744       float sensor_x = ca->sensor_x;
745       float sensor_y = (ca->sensor_fit == CAMERA_SENSOR_FIT_AUTO) ? ca->sensor_x : ca->sensor_y;
746
747       /* determine sensor plane */
748       rctf rect;
749
750       if (sensor_fit == CAMERA_SENSOR_FIT_HOR) {
751         float sensor_scale = (x2i - x1i) / sensor_x;
752         float sensor_height = sensor_scale * sensor_y;
753
754         rect.xmin = x1i;
755         rect.xmax = x2i;
756         rect.ymin = (y1i + y2i) * 0.5f - sensor_height * 0.5f;
757         rect.ymax = rect.ymin + sensor_height;
758       }
759       else {
760         float sensor_scale = (y2i - y1i) / sensor_y;
761         float sensor_width = sensor_scale * sensor_x;
762
763         rect.xmin = (x1i + x2i) * 0.5f - sensor_width * 0.5f;
764         rect.xmax = rect.xmin + sensor_width;
765         rect.ymin = y1i;
766         rect.ymax = y2i;
767       }
768
769       /* draw */
770       immUniformThemeColorShade(TH_VIEW_OVERLAY, 100);
771
772       /* TODO Was using:
773        * UI_draw_roundbox_4fv(false, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f, color);
774        * We'll probably need a new imm_draw_line_roundbox_dashed dor that - though in practice the
775        * 2.0f round corner effect was nearly not visible anyway... */
776       imm_draw_box_wire_2d(shdr_pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
777     }
778   }
779
780   immUnbindProgram();
781   /* end dashed lines */
782
783   /* camera name - draw in highlighted text color */
784   if (ca && ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) && (ca->flag & CAM_SHOWNAME)) {
785     UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
786     BLF_draw_default(x1i,
787                      y1i - (0.7f * U.widget_unit),
788                      0.0f,
789                      v3d->camera->id.name + 2,
790                      sizeof(v3d->camera->id.name) - 2);
791   }
792 }
793
794 static void drawrenderborder(ARegion *region, View3D *v3d)
795 {
796   /* use the same program for everything */
797   uint shdr_pos = GPU_vertformat_attr_add(
798       immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
799
800   GPU_line_width(1.0f);
801
802   immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
803
804   float viewport_size[4];
805   GPU_viewport_size_get_f(viewport_size);
806   immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
807
808   immUniform1i("colors_len", 0); /* "simple" mode */
809   immUniform4f("color", 1.0f, 0.25f, 0.25f, 1.0f);
810   immUniform1f("dash_width", 6.0f);
811   immUniform1f("dash_factor", 0.5f);
812
813   imm_draw_box_wire_2d(shdr_pos,
814                        v3d->render_border.xmin * region->winx,
815                        v3d->render_border.ymin * region->winy,
816                        v3d->render_border.xmax * region->winx,
817                        v3d->render_border.ymax * region->winy);
818
819   immUnbindProgram();
820 }
821
822 void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *region, View3D *v3d, bool alphaoverride)
823 {
824   struct bThemeState theme_state;
825   Scene *scene = DEG_get_evaluated_scene(depsgraph);
826   RegionView3D *rv3d = region->regiondata;
827
828   short flag = v3d->flag;
829   float glalphaclip = U.glalphaclip;
830   /* temp set drawtype to solid */
831   /* Setting these temporarily is not nice */
832   v3d->flag &= ~V3D_SELECT_OUTLINE;
833
834   /* not that nice but means we wont zoom into billboards */
835   U.glalphaclip = alphaoverride ? 0.5f : glalphaclip;
836
837   /* Tools may request depth outside of regular drawing code. */
838   UI_Theme_Store(&theme_state);
839   UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
840
841   ED_view3d_draw_setup_view(
842       G_MAIN->wm.first, NULL, depsgraph, scene, region, v3d, NULL, NULL, NULL);
843
844   GPU_clear(GPU_DEPTH_BIT);
845
846   if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
847     ED_view3d_clipping_set(rv3d);
848   }
849   /* get surface depth without bias */
850   rv3d->rflag |= RV3D_ZOFFSET_DISABLED;
851
852   GPU_depth_test(true);
853
854   /* Needed in cases the view-port isn't already setup. */
855   WM_draw_region_viewport_ensure(region, SPACE_VIEW3D);
856   WM_draw_region_viewport_bind(region);
857
858   GPUViewport *viewport = WM_draw_region_get_viewport(region);
859   /* When Blender is starting, a click event can trigger a depth test while the viewport is not
860    * yet available. */
861   if (viewport != NULL) {
862     DRW_draw_depth_loop(depsgraph, region, v3d, viewport, false);
863   }
864
865   WM_draw_region_viewport_unbind(region);
866
867   if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
868     ED_view3d_clipping_disable();
869   }
870   rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED;
871
872   /* Reset default for UI */
873   GPU_depth_test(false);
874
875   U.glalphaclip = glalphaclip;
876   v3d->flag = flag;
877
878   UI_Theme_Restore(&theme_state);
879 }
880
881 /* ******************** other elements ***************** */
882
883 /** could move this elsewhere, but tied into #ED_view3d_grid_scale */
884 float ED_scene_grid_scale(const Scene *scene, const char **r_grid_unit)
885 {
886   /* apply units */
887   if (scene->unit.system) {
888     const void *usys;
889     int len;
890
891     bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
892
893     if (usys) {
894       int i = bUnit_GetBaseUnit(usys);
895       if (r_grid_unit) {
896         *r_grid_unit = bUnit_GetNameDisplay(usys, i);
897       }
898       return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length;
899     }
900   }
901
902   return 1.0f;
903 }
904
905 float ED_view3d_grid_scale(const Scene *scene, View3D *v3d, const char **r_grid_unit)
906 {
907   return v3d->grid * ED_scene_grid_scale(scene, r_grid_unit);
908 }
909
910 #define STEPS_LEN 8
911 void ED_view3d_grid_steps(const Scene *scene,
912                           View3D *v3d,
913                           RegionView3D *rv3d,
914                           float r_grid_steps[STEPS_LEN])
915 {
916   const void *usys;
917   int i, len;
918   bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
919   float grid_scale = v3d->grid;
920   BLI_assert(STEPS_LEN >= len);
921
922   if (usys) {
923     if (rv3d->view == RV3D_VIEW_USER) {
924       /* Skip steps */
925       len = bUnit_GetBaseUnit(usys) + 1;
926     }
927
928     grid_scale /= scene->unit.scale_length;
929
930     for (i = 0; i < len; i++) {
931       r_grid_steps[i] = (float)bUnit_GetScaler(usys, len - 1 - i) * grid_scale;
932     }
933     for (; i < STEPS_LEN; i++) {
934       /* Fill last slots */
935       r_grid_steps[i] = 10.0f * r_grid_steps[i - 1];
936     }
937   }
938   else {
939     if (rv3d->view != RV3D_VIEW_USER) {
940       /* Allow 3 more subdivisions. */
941       grid_scale /= powf(v3d->gridsubdiv, 3);
942     }
943     int subdiv = 1;
944     for (i = 0;; i++) {
945       r_grid_steps[i] = grid_scale * subdiv;
946
947       if (i == STEPS_LEN - 1) {
948         break;
949       }
950       subdiv *= v3d->gridsubdiv;
951     }
952   }
953 }
954
955 /* Simulates the grid scale that is actually viewed.
956  * The actual code is seen in `object_grid_frag.glsl` (see `grid_res`).
957  * Currently the simulation is only done when RV3D_VIEW_IS_AXIS. */
958 float ED_view3d_grid_view_scale(Scene *scene,
959                                 View3D *v3d,
960                                 RegionView3D *rv3d,
961                                 const char **r_grid_unit)
962 {
963   float grid_scale;
964   if (!rv3d->is_persp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
965     /* Decrease the distance between grid snap points depending on zoom. */
966     /* `0.38` was a value visually obtained in order to get a snap distance
967      * that matches previous versions Blender.*/
968     float min_dist = 0.38f * (rv3d->dist / v3d->lens);
969     float grid_steps[STEPS_LEN];
970     ED_view3d_grid_steps(scene, v3d, rv3d, grid_steps);
971     /* Skip last item, in case the 'mid_dist' is greater than the largest unit. */
972     int i;
973     for (i = 0; i < ARRAY_SIZE(grid_steps) - 1; i++) {
974       grid_scale = grid_steps[i];
975       if (grid_scale > min_dist) {
976         break;
977       }
978     }
979
980     if (r_grid_unit) {
981       const void *usys;
982       int len;
983       bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
984
985       if (usys) {
986         *r_grid_unit = bUnit_GetNameDisplay(usys, len - i - 1);
987       }
988     }
989   }
990   else {
991     grid_scale = ED_view3d_grid_scale(scene, v3d, r_grid_unit);
992   }
993
994   return grid_scale;
995 }
996
997 #undef STEPS_LEN
998
999 static void draw_view_axis(RegionView3D *rv3d, const rcti *rect)
1000 {
1001   const float k = U.rvisize * U.pixelsize; /* axis size */
1002   /* axis alpha offset (rvibright has range 0-10) */
1003   const int bright = -20 * (10 - U.rvibright);
1004
1005   /* Axis center in screen coordinates.
1006    *
1007    * - Unit size offset so small text doesn't draw outside the screen
1008    * - Extra X offset because of the panel expander.
1009    */
1010   const float startx = rect->xmax - (k + UI_UNIT_X * 1.5);
1011   const float starty = rect->ymax - (k + UI_UNIT_Y);
1012
1013   float axis_pos[3][2];
1014   uchar axis_col[3][4];
1015
1016   int axis_order[3] = {0, 1, 2};
1017   axis_sort_v3(rv3d->viewinv[2], axis_order);
1018
1019   for (int axis_i = 0; axis_i < 3; axis_i++) {
1020     int i = axis_order[axis_i];
1021
1022     /* get position of each axis tip on screen */
1023     float vec[3] = {0.0f};
1024     vec[i] = 1.0f;
1025     mul_qt_v3(rv3d->viewquat, vec);
1026     axis_pos[i][0] = startx + vec[0] * k;
1027     axis_pos[i][1] = starty + vec[1] * k;
1028
1029     /* get color of each axis */
1030     UI_GetThemeColorShade3ubv(TH_AXIS_X + i, bright, axis_col[i]); /* rgb */
1031     axis_col[i][3] = 255 * hypotf(vec[0], vec[1]);                 /* alpha */
1032   }
1033
1034   /* draw axis lines */
1035   GPU_line_width(2.0f);
1036   GPU_line_smooth(true);
1037   GPU_blend(true);
1038   GPU_blend_set_func_separate(
1039       GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1040
1041   GPUVertFormat *format = immVertexFormat();
1042   uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1043   uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
1044
1045   immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
1046   immBegin(GPU_PRIM_LINES, 6);
1047
1048   for (int axis_i = 0; axis_i < 3; axis_i++) {
1049     int i = axis_order[axis_i];
1050
1051     immAttr4ubv(col, axis_col[i]);
1052     immVertex2f(pos, startx, starty);
1053     immAttr4ubv(col, axis_col[i]);
1054     immVertex2fv(pos, axis_pos[i]);
1055   }
1056
1057   immEnd();
1058   immUnbindProgram();
1059   GPU_line_smooth(false);
1060
1061   /* draw axis names */
1062   for (int axis_i = 0; axis_i < 3; axis_i++) {
1063     int i = axis_order[axis_i];
1064
1065     const char axis_text[2] = {'x' + i, '\0'};
1066     BLF_color4ubv(BLF_default(), axis_col[i]);
1067     BLF_draw_default_ascii(axis_pos[i][0] + 2, axis_pos[i][1] + 2, 0.0f, axis_text, 1);
1068   }
1069 }
1070
1071 #ifdef WITH_INPUT_NDOF
1072 /* draw center and axis of rotation for ongoing 3D mouse navigation */
1073 static void draw_rotation_guide(const RegionView3D *rv3d)
1074 {
1075   float o[3];   /* center of rotation */
1076   float end[3]; /* endpoints for drawing */
1077
1078   GLubyte color[4] = {0, 108, 255, 255}; /* bright blue so it matches device LEDs */
1079
1080   negate_v3_v3(o, rv3d->ofs);
1081
1082   GPU_blend(true);
1083   GPU_blend_set_func_separate(
1084       GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1085   glDepthMask(GL_FALSE); /* don't overwrite zbuf */
1086
1087   GPUVertFormat *format = immVertexFormat();
1088   uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1089   uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
1090
1091   immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
1092
1093   if (rv3d->rot_angle != 0.0f) {
1094     /* -- draw rotation axis -- */
1095     float scaled_axis[3];
1096     const float scale = rv3d->dist;
1097     mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale);
1098
1099     immBegin(GPU_PRIM_LINE_STRIP, 3);
1100     color[3] = 0; /* more transparent toward the ends */
1101     immAttr4ubv(col, color);
1102     add_v3_v3v3(end, o, scaled_axis);
1103     immVertex3fv(pos, end);
1104
1105 #  if 0
1106     color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */
1107     /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */
1108 #  endif
1109
1110     color[3] = 127; /* more opaque toward the center */
1111     immAttr4ubv(col, color);
1112     immVertex3fv(pos, o);
1113
1114     color[3] = 0;
1115     immAttr4ubv(col, color);
1116     sub_v3_v3v3(end, o, scaled_axis);
1117     immVertex3fv(pos, end);
1118     immEnd();
1119
1120     /* -- draw ring around rotation center -- */
1121     {
1122 #  define ROT_AXIS_DETAIL 13
1123
1124       const float s = 0.05f * scale;
1125       const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL);
1126
1127       float q[4]; /* rotate ring so it's perpendicular to axis */
1128       const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f;
1129       if (!upright) {
1130         const float up[3] = {0.0f, 0.0f, 1.0f};
1131         float vis_angle, vis_axis[3];
1132
1133         cross_v3_v3v3(vis_axis, up, rv3d->rot_axis);
1134         vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis));
1135         axis_angle_to_quat(q, vis_axis, vis_angle);
1136       }
1137
1138       immBegin(GPU_PRIM_LINE_LOOP, ROT_AXIS_DETAIL);
1139       color[3] = 63; /* somewhat faint */
1140       immAttr4ubv(col, color);
1141       float angle = 0.0f;
1142       for (int i = 0; i < ROT_AXIS_DETAIL; i++, angle += step) {
1143         float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f};
1144
1145         if (!upright) {
1146           mul_qt_v3(q, p);
1147         }
1148
1149         add_v3_v3(p, o);
1150         immVertex3fv(pos, p);
1151       }
1152       immEnd();
1153
1154 #  undef ROT_AXIS_DETAIL
1155     }
1156
1157     color[3] = 255; /* solid dot */
1158   }
1159   else {
1160     color[3] = 127; /* see-through dot */
1161   }
1162
1163   immUnbindProgram();
1164
1165   /* -- draw rotation center -- */
1166   immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
1167   GPU_point_size(5.0f);
1168   immBegin(GPU_PRIM_POINTS, 1);
1169   immAttr4ubv(col, color);
1170   immVertex3fv(pos, o);
1171   immEnd();
1172   immUnbindProgram();
1173
1174   GPU_blend(false);
1175   glDepthMask(GL_TRUE);
1176 }
1177 #endif /* WITH_INPUT_NDOF */
1178
1179 /**
1180  * Render and camera border
1181  */
1182 static void view3d_draw_border(const bContext *C, ARegion *region)
1183 {
1184   Scene *scene = CTX_data_scene(C);
1185   Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C);
1186   RegionView3D *rv3d = region->regiondata;
1187   View3D *v3d = CTX_wm_view3d(C);
1188
1189   if (rv3d->persp == RV3D_CAMOB) {
1190     drawviewborder(scene, depsgraph, region, v3d);
1191   }
1192   else if (v3d->flag2 & V3D_RENDER_BORDER) {
1193     drawrenderborder(region, v3d);
1194   }
1195 }
1196
1197 /** \} */
1198
1199 /* -------------------------------------------------------------------- */
1200 /** \name Draw Text & Info
1201  * \{ */
1202
1203 /**
1204  * Draw Info
1205  */
1206 static void view3d_draw_grease_pencil(const bContext *UNUSED(C))
1207 {
1208   /* TODO viewport */
1209 }
1210
1211 /**
1212  * Viewport Name
1213  */
1214 static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d)
1215 {
1216   const char *name = NULL;
1217
1218   switch (rv3d->view) {
1219     case RV3D_VIEW_FRONT:
1220       if (rv3d->persp == RV3D_ORTHO) {
1221         name = IFACE_("Front Orthographic");
1222       }
1223       else {
1224         name = IFACE_("Front Perspective");
1225       }
1226       break;
1227     case RV3D_VIEW_BACK:
1228       if (rv3d->persp == RV3D_ORTHO) {
1229         name = IFACE_("Back Orthographic");
1230       }
1231       else {
1232         name = IFACE_("Back Perspective");
1233       }
1234       break;
1235     case RV3D_VIEW_TOP:
1236       if (rv3d->persp == RV3D_ORTHO) {
1237         name = IFACE_("Top Orthographic");
1238       }
1239       else {
1240         name = IFACE_("Top Perspective");
1241       }
1242       break;
1243     case RV3D_VIEW_BOTTOM:
1244       if (rv3d->persp == RV3D_ORTHO) {
1245         name = IFACE_("Bottom Orthographic");
1246       }
1247       else {
1248         name = IFACE_("Bottom Perspective");
1249       }
1250       break;
1251     case RV3D_VIEW_RIGHT:
1252       if (rv3d->persp == RV3D_ORTHO) {
1253         name = IFACE_("Right Orthographic");
1254       }
1255       else {
1256         name = IFACE_("Right Perspective");
1257       }
1258       break;
1259     case RV3D_VIEW_LEFT:
1260       if (rv3d->persp == RV3D_ORTHO) {
1261         name = IFACE_("Left Orthographic");
1262       }
1263       else {
1264         name = IFACE_("Left Perspective");
1265       }
1266       break;
1267
1268     default:
1269       if (rv3d->persp == RV3D_CAMOB) {
1270         if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) {
1271           Camera *cam;
1272           cam = v3d->camera->data;
1273           if (cam->type == CAM_PERSP) {
1274             name = IFACE_("Camera Perspective");
1275           }
1276           else if (cam->type == CAM_ORTHO) {
1277             name = IFACE_("Camera Orthographic");
1278           }
1279           else {
1280             BLI_assert(cam->type == CAM_PANO);
1281             name = IFACE_("Camera Panoramic");
1282           }
1283         }
1284         else {
1285           name = IFACE_("Object as Camera");
1286         }
1287       }
1288       else {
1289         name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Orthographic") :
1290                                              IFACE_("User Perspective");
1291       }
1292   }
1293
1294   return name;
1295 }
1296
1297 static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *yoffset)
1298 {
1299   RegionView3D *rv3d = region->regiondata;
1300   const char *name = view3d_get_name(v3d, rv3d);
1301   const char *name_array[3] = {name, NULL, NULL};
1302   int name_array_len = 1;
1303   const int font_id = BLF_default();
1304
1305   /* 6 is the maximum size of the axis roll text. */
1306   /* increase size for unicode languages (Chinese in utf-8...) */
1307 #ifdef WITH_INTERNATIONAL
1308   char tmpstr[96 + 6];
1309 #else
1310   char tmpstr[32 + 6];
1311 #endif
1312
1313   BLF_enable(font_id, BLF_SHADOW);
1314   BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
1315   BLF_shadow_offset(font_id, 1, -1);
1316
1317   if (RV3D_VIEW_IS_AXIS(rv3d->view) && (rv3d->view_axis_roll != RV3D_VIEW_AXIS_ROLL_0)) {
1318     const char *axis_roll;
1319     switch (rv3d->view_axis_roll) {
1320       case RV3D_VIEW_AXIS_ROLL_90:
1321         axis_roll = " 90\xC2\xB0";
1322         break;
1323       case RV3D_VIEW_AXIS_ROLL_180:
1324         axis_roll = " 180\xC2\xB0";
1325         break;
1326       default:
1327         axis_roll = " -90\xC2\xB0";
1328         break;
1329     }
1330     name_array[name_array_len++] = axis_roll;
1331   }
1332
1333   if (v3d->localvd) {
1334     name_array[name_array_len++] = IFACE_(" (Local)");
1335   }
1336
1337   if (name_array_len > 1) {
1338     BLI_string_join_array(tmpstr, sizeof(tmpstr), name_array, name_array_len);
1339     name = tmpstr;
1340   }
1341
1342   UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
1343
1344   *yoffset -= U.widget_unit;
1345
1346   BLF_draw_default(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr));
1347
1348   BLF_disable(font_id, BLF_SHADOW);
1349 }
1350
1351 /**
1352  * Draw info beside axes in bottom left-corner:
1353  * frame-number, collection, object name, bone name (if available), marker name (if available).
1354  */
1355
1356 static void draw_selected_name(
1357     Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset)
1358 {
1359   const int cfra = CFRA;
1360   const char *msg_pin = " (Pinned)";
1361   const char *msg_sep = " : ";
1362
1363   const int font_id = BLF_default();
1364
1365   char info[300];
1366   char *s = info;
1367
1368   s += sprintf(s, "(%d)", cfra);
1369
1370   if ((ob == NULL) || (ob->mode == OB_MODE_OBJECT)) {
1371     LayerCollection *layer_collection = view_layer->active_collection;
1372     s += sprintf(s,
1373                  " %s%s",
1374                  BKE_collection_ui_name_get(layer_collection->collection),
1375                  (ob == NULL) ? "" : " |");
1376   }
1377
1378   /*
1379    * info can contain:
1380    * - a frame (7 + 2)
1381    * - a collection name (MAX_NAME + 3)
1382    * - 3 object names (MAX_NAME)
1383    * - 2 BREAD_CRUMB_SEPARATORs (6)
1384    * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room!
1385    * - a marker name (MAX_NAME + 3)
1386    */
1387
1388   /* get name of marker on current frame (if available) */
1389   const char *markern = BKE_scene_find_marker_name(scene, cfra);
1390
1391   /* check if there is an object */
1392   if (ob) {
1393     *s++ = ' ';
1394     s += BLI_strcpy_rlen(s, ob->id.name + 2);
1395
1396     /* name(s) to display depends on type of object */
1397     if (ob->type == OB_ARMATURE) {
1398       bArmature *arm = ob->data;
1399
1400       /* show name of active bone too (if possible) */
1401       if (arm->edbo) {
1402         if (arm->act_edbone) {
1403           s += BLI_strcpy_rlen(s, msg_sep);
1404           s += BLI_strcpy_rlen(s, arm->act_edbone->name);
1405         }
1406       }
1407       else if (ob->mode & OB_MODE_POSE) {
1408         if (arm->act_bone) {
1409
1410           if (arm->act_bone->layer & arm->layer) {
1411             s += BLI_strcpy_rlen(s, msg_sep);
1412             s += BLI_strcpy_rlen(s, arm->act_bone->name);
1413           }
1414         }
1415       }
1416     }
1417     else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) {
1418       /* try to display active bone and active shapekey too (if they exist) */
1419
1420       if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) {
1421         Object *armobj = BKE_object_pose_armature_get(ob);
1422         if (armobj && armobj->mode & OB_MODE_POSE) {
1423           bArmature *arm = armobj->data;
1424           if (arm->act_bone) {
1425             if (arm->act_bone->layer & arm->layer) {
1426               s += BLI_strcpy_rlen(s, msg_sep);
1427               s += BLI_strcpy_rlen(s, arm->act_bone->name);
1428             }
1429           }
1430         }
1431       }
1432
1433       Key *key = BKE_key_from_object(ob);
1434       if (key) {
1435         KeyBlock *kb = BLI_findlink(&key->block, ob->shapenr - 1);
1436         if (kb) {
1437           s += BLI_strcpy_rlen(s, msg_sep);
1438           s += BLI_strcpy_rlen(s, kb->name);
1439           if (ob->shapeflag & OB_SHAPE_LOCK) {
1440             s += BLI_strcpy_rlen(s, IFACE_(msg_pin));
1441           }
1442         }
1443       }
1444     }
1445
1446     /* color depends on whether there is a keyframe */
1447     if (id_frame_has_keyframe(
1448             (ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) {
1449       UI_FontThemeColor(font_id, TH_TIME_KEYFRAME);
1450     }
1451     else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) {
1452       UI_FontThemeColor(font_id, TH_TIME_GP_KEYFRAME);
1453     }
1454     else {
1455       UI_FontThemeColor(font_id, TH_TEXT_HI);
1456     }
1457   }
1458   else {
1459     /* no object */
1460     if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra)) {
1461       UI_FontThemeColor(font_id, TH_TIME_GP_KEYFRAME);
1462     }
1463     else {
1464       UI_FontThemeColor(font_id, TH_TEXT_HI);
1465     }
1466   }
1467
1468   if (markern) {
1469     s += sprintf(s, " <%s>", markern);
1470   }
1471
1472   BLF_enable(font_id, BLF_SHADOW);
1473   BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
1474   BLF_shadow_offset(font_id, 1, -1);
1475
1476   *yoffset -= U.widget_unit;
1477   BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info));
1478
1479   BLF_disable(font_id, BLF_SHADOW);
1480 }
1481
1482 static void draw_grid_unit_name(
1483     Scene *scene, RegionView3D *rv3d, View3D *v3d, int xoffset, int *yoffset)
1484 {
1485   if (!rv3d->is_persp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
1486     const char *grid_unit = NULL;
1487     int font_id = BLF_default();
1488     ED_view3d_grid_view_scale(scene, v3d, rv3d, &grid_unit);
1489
1490     if (grid_unit) {
1491       char numstr[32] = "";
1492       UI_FontThemeColor(font_id, TH_TEXT_HI);
1493       if (v3d->grid != 1.0f) {
1494         BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid);
1495       }
1496
1497       *yoffset -= U.widget_unit;
1498       BLF_enable(font_id, BLF_SHADOW);
1499       BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
1500       BLF_shadow_offset(font_id, 1, -1);
1501       BLF_draw_default_ascii(
1502           xoffset, *yoffset, 0.0f, numstr[0] ? numstr : grid_unit, sizeof(numstr));
1503
1504       BLF_disable(font_id, BLF_SHADOW);
1505     }
1506   }
1507 }
1508
1509 /**
1510  * Information drawn on top of the solid plates and composed data
1511  */
1512 void view3d_draw_region_info(const bContext *C, ARegion *region)
1513 {
1514   RegionView3D *rv3d = region->regiondata;
1515   View3D *v3d = CTX_wm_view3d(C);
1516   Scene *scene = CTX_data_scene(C);
1517   wmWindowManager *wm = CTX_wm_manager(C);
1518
1519 #ifdef WITH_INPUT_NDOF
1520   if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) &&
1521       (rv3d->persp != RV3D_CAMOB)) {
1522     /* TODO: draw something else (but not this) during fly mode */
1523     draw_rotation_guide(rv3d);
1524   }
1525 #endif
1526
1527   /* correct projection matrix */
1528   ED_region_pixelspace(region);
1529
1530   /* local coordinate visible rect inside region, to accommodate overlapping ui */
1531   const rcti *rect = ED_region_visible_rect(region);
1532
1533   view3d_draw_border(C, region);
1534   view3d_draw_grease_pencil(C);
1535
1536   BLF_batch_draw_begin();
1537
1538   if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_NAVIGATE)) {
1539     /* pass */
1540   }
1541   else {
1542     switch ((eUserpref_MiniAxisType)U.mini_axis_type) {
1543       case USER_MINI_AXIS_TYPE_GIZMO:
1544         /* The gizmo handles it's own drawing. */
1545         break;
1546       case USER_MINI_AXIS_TYPE_MINIMAL:
1547         draw_view_axis(rv3d, rect);
1548       case USER_MINI_AXIS_TYPE_NONE:
1549         break;
1550     }
1551   }
1552
1553   int xoffset = rect->xmin + U.widget_unit;
1554   int yoffset = rect->ymax;
1555
1556   if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
1557     if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
1558       ED_scene_draw_fps(scene, xoffset, &yoffset);
1559     }
1560     else if (U.uiflag & USER_SHOW_VIEWPORTNAME) {
1561       draw_viewport_name(region, v3d, xoffset, &yoffset);
1562     }
1563
1564     if (U.uiflag & USER_DRAWVIEWINFO) {
1565       ViewLayer *view_layer = CTX_data_view_layer(C);
1566       Object *ob = OBACT(view_layer);
1567       draw_selected_name(scene, view_layer, ob, xoffset, &yoffset);
1568     }
1569
1570     if (v3d->gridflag & (V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) {
1571       /* draw below the viewport name */
1572       draw_grid_unit_name(scene, rv3d, v3d, xoffset, &yoffset);
1573     }
1574   }
1575
1576   if ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
1577     DRW_draw_region_engine_info(xoffset, yoffset);
1578   }
1579
1580   BLF_batch_draw_end();
1581 }
1582
1583 /** \} */
1584
1585 /* -------------------------------------------------------------------- */
1586 /** \name Draw Viewport Contents
1587  * \{ */
1588
1589 static void view3d_draw_view(const bContext *C, ARegion *region)
1590 {
1591   ED_view3d_draw_setup_view(CTX_wm_manager(C),
1592                             CTX_wm_window(C),
1593                             CTX_data_expect_evaluated_depsgraph(C),
1594                             CTX_data_scene(C),
1595                             region,
1596                             CTX_wm_view3d(C),
1597                             NULL,
1598                             NULL,
1599                             NULL);
1600
1601   /* Only 100% compliant on new spec goes below */
1602   DRW_draw_view(C);
1603 }
1604
1605 RenderEngineType *ED_view3d_engine_type(const Scene *scene, int drawtype)
1606 {
1607   /*
1608    * Temporary viewport draw modes until we have a proper system.
1609    * all modes are done in the draw manager, except external render
1610    * engines like Cycles.
1611    */
1612   RenderEngineType *type = RE_engines_find(scene->r.engine);
1613   if (drawtype == OB_MATERIAL && (type->flag & RE_USE_EEVEE_VIEWPORT)) {
1614     return RE_engines_find(RE_engine_id_BLENDER_EEVEE);
1615   }
1616   else {
1617     return type;
1618   }
1619 }
1620
1621 void view3d_main_region_draw(const bContext *C, ARegion *region)
1622 {
1623   Main *bmain = CTX_data_main(C);
1624   View3D *v3d = CTX_wm_view3d(C);
1625
1626   view3d_draw_view(C, region);
1627
1628   DRW_cache_free_old_batches(bmain);
1629   GPU_free_images_old(bmain);
1630   GPU_pass_cache_garbage_collect();
1631
1632   /* XXX This is in order to draw UI batches with the DRW
1633    * old context since we now use it for drawing the entire area. */
1634   gpu_batch_presets_reset();
1635
1636   /* No depth test for drawing action zones afterwards. */
1637   GPU_depth_test(false);
1638
1639   v3d->flag |= V3D_INVALID_BACKBUF;
1640 }
1641
1642 /** \} */
1643
1644 /* -------------------------------------------------------------------- */
1645 /** \name Offscreen Drawing
1646  * \{ */
1647
1648 static void view3d_stereo3d_setup_offscreen(Depsgraph *depsgraph,
1649                                             const Scene *scene,
1650                                             View3D *v3d,
1651                                             ARegion *region,
1652                                             float winmat[4][4],
1653                                             const char *viewname)
1654 {
1655   /* update the viewport matrices with the new camera */
1656   if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
1657     float viewmat[4][4];
1658     const bool is_left = STREQ(viewname, STEREO_LEFT_NAME);
1659
1660     BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
1661     view3d_main_region_setup_offscreen(depsgraph, scene, v3d, region, viewmat, winmat);
1662   }
1663   else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
1664     float viewmat[4][4];
1665     Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
1666
1667     BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
1668     view3d_main_region_setup_offscreen(depsgraph, scene, v3d, region, viewmat, winmat);
1669   }
1670 }
1671
1672 void ED_view3d_draw_offscreen(Depsgraph *depsgraph,
1673                               const Scene *scene,
1674                               eDrawType drawtype,
1675                               View3D *v3d,
1676                               ARegion *region,
1677                               int winx,
1678                               int winy,
1679                               float viewmat[4][4],
1680                               float winmat[4][4],
1681                               bool is_image_render,
1682                               bool do_sky,
1683                               bool UNUSED(is_persp),
1684                               const char *viewname,
1685                               const bool do_color_management,
1686                               GPUOffScreen *ofs,
1687                               GPUViewport *viewport)
1688 {
1689   RegionView3D *rv3d = region->regiondata;
1690   RenderEngineType *engine_type = ED_view3d_engine_type(scene, drawtype);
1691
1692   /* set temporary new size */
1693   int bwinx = region->winx;
1694   int bwiny = region->winy;
1695   rcti brect = region->winrct;
1696
1697   region->winx = winx;
1698   region->winy = winy;
1699   region->winrct.xmin = 0;
1700   region->winrct.ymin = 0;
1701   region->winrct.xmax = winx;
1702   region->winrct.ymax = winy;
1703
1704   struct bThemeState theme_state;
1705   UI_Theme_Store(&theme_state);
1706   UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
1707
1708   /* set flags */
1709   G.f |= G_FLAG_RENDER_VIEWPORT;
1710
1711   {
1712     /* free images which can have changed on frame-change
1713      * warning! can be slow so only free animated images - campbell */
1714     GPU_free_images_anim(G.main); /* XXX :((( */
1715   }
1716
1717   GPU_matrix_push_projection();
1718   GPU_matrix_identity_set();
1719   GPU_matrix_push();
1720   GPU_matrix_identity_set();
1721
1722   if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) &&
1723       rv3d->persp == RV3D_CAMOB && v3d->camera) {
1724     view3d_stereo3d_setup_offscreen(depsgraph, scene, v3d, region, winmat, viewname);
1725   }
1726   else {
1727     view3d_main_region_setup_offscreen(depsgraph, scene, v3d, region, viewmat, winmat);
1728   }
1729
1730   /* main drawing call */
1731   DRW_draw_render_loop_offscreen(depsgraph,
1732                                  engine_type,
1733                                  region,
1734                                  v3d,
1735                                  is_image_render,
1736                                  do_sky,
1737                                  do_color_management,
1738                                  ofs,
1739                                  viewport);
1740
1741   /* restore size */
1742   region->winx = bwinx;
1743   region->winy = bwiny;
1744   region->winrct = brect;
1745
1746   GPU_matrix_pop_projection();
1747   GPU_matrix_pop();
1748
1749   UI_Theme_Restore(&theme_state);
1750
1751   G.f &= ~G_FLAG_RENDER_VIEWPORT;
1752 }
1753
1754 /**
1755  * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen). Similar too
1756  * #ED_view_draw_offscreen_imbuf_simple, but takes view/projection matrices as arguments.
1757  */
1758 void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
1759                                      Scene *scene,
1760                                      View3DShading *shading_override,
1761                                      int drawtype,
1762                                      int winx,
1763                                      int winy,
1764                                      uint draw_flags,
1765                                      float viewmat[4][4],
1766                                      float winmat[4][4],
1767                                      float clip_start,
1768                                      float clip_end,
1769                                      bool is_image_render,
1770                                      bool do_sky,
1771                                      bool is_persp,
1772                                      const char *viewname,
1773                                      const bool do_color_management,
1774                                      GPUOffScreen *ofs,
1775                                      GPUViewport *viewport)
1776 {
1777   View3D v3d = {NULL};
1778   ARegion ar = {NULL};
1779   RegionView3D rv3d = {{{0}}};
1780
1781   v3d.regionbase.first = v3d.regionbase.last = &ar;
1782   ar.regiondata = &rv3d;
1783   ar.regiontype = RGN_TYPE_WINDOW;
1784
1785   View3DShading *source_shading_settings = &scene->display.shading;
1786   if (draw_flags & V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS && shading_override != NULL) {
1787     source_shading_settings = shading_override;
1788   }
1789   memcpy(&v3d.shading, source_shading_settings, sizeof(View3DShading));
1790   v3d.shading.type = drawtype;
1791
1792   if (shading_override) {
1793     /* Pass. */
1794   }
1795   else if (drawtype == OB_MATERIAL) {
1796     v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
1797   }
1798
1799   if (draw_flags & V3D_OFSDRAW_SHOW_ANNOTATION) {
1800     v3d.flag2 |= V3D_SHOW_ANNOTATION;
1801   }
1802   if (draw_flags & V3D_OFSDRAW_SHOW_GRIDFLOOR) {
1803     v3d.gridflag |= V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y;
1804     v3d.grid = 1.0f;
1805     v3d.gridlines = 16;
1806     v3d.gridsubdiv = 10;
1807
1808     /* Show grid, disable other overlays (set all available _HIDE_ flags). */
1809     v3d.overlay.flag |= V3D_OVERLAY_HIDE_CURSOR | V3D_OVERLAY_HIDE_TEXT |
1810                         V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES |
1811                         V3D_OVERLAY_HIDE_OBJECT_XTRAS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
1812     v3d.flag |= V3D_HIDE_HELPLINES;
1813   }
1814   else {
1815     v3d.flag2 = V3D_HIDE_OVERLAYS;
1816   }
1817
1818   rv3d.persp = RV3D_PERSP;
1819   v3d.clip_start = clip_start;
1820   v3d.clip_end = clip_end;
1821   /* Actually not used since we pass in the projection matrix. */
1822   v3d.lens = 0;
1823
1824   ED_view3d_draw_offscreen(depsgraph,
1825                            scene,
1826                            drawtype,
1827                            &v3d,
1828                            &ar,
1829                            winx,
1830                            winy,
1831                            viewmat,
1832                            winmat,
1833                            is_image_render,
1834                            do_sky,
1835                            is_persp,
1836                            viewname,
1837                            do_color_management,
1838                            ofs,
1839                            viewport);
1840 }
1841
1842 /**
1843  * Utility func for ED_view3d_draw_offscreen
1844  *
1845  * \param ofs: Optional off-screen buffer, can be NULL.
1846  * (avoids re-creating when doing multiple GL renders).
1847  */
1848 ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
1849                                       Scene *scene,
1850                                       eDrawType drawtype,
1851                                       View3D *v3d,
1852                                       ARegion *region,
1853                                       int sizex,
1854                                       int sizey,
1855                                       eImBufFlags imbuf_flag,
1856                                       int alpha_mode,
1857                                       const char *viewname,
1858                                       /* output vars */
1859                                       GPUOffScreen *ofs,
1860                                       char err_out[256])
1861 {
1862   RegionView3D *rv3d = region->regiondata;
1863   const bool draw_sky = (alpha_mode == R_ADDSKY);
1864
1865   /* view state */
1866   bool is_ortho = false;
1867   float winmat[4][4];
1868
1869   if (ofs && ((GPU_offscreen_width(ofs) != sizex) || (GPU_offscreen_height(ofs) != sizey))) {
1870     /* sizes differ, can't reuse */
1871     ofs = NULL;
1872   }
1873
1874   GPUFrameBuffer *old_fb = GPU_framebuffer_active_get();
1875
1876   if (old_fb) {
1877     GPU_framebuffer_restore();
1878   }
1879
1880   const bool own_ofs = (ofs == NULL);
1881   DRW_opengl_context_enable();
1882
1883   if (own_ofs) {
1884     /* bind */
1885     ofs = GPU_offscreen_create(sizex, sizey, 0, true, false, err_out);
1886     if (ofs == NULL) {
1887       DRW_opengl_context_disable();
1888       return NULL;
1889     }
1890   }
1891
1892   GPU_offscreen_bind(ofs, true);
1893
1894   /* read in pixels & stamp */
1895   ImBuf *ibuf = IMB_allocImBuf(sizex, sizey, 32, imbuf_flag);
1896
1897   /* render 3d view */
1898   if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
1899     CameraParams params;
1900     Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
1901     const Object *camera_eval = DEG_get_evaluated_object(depsgraph, camera);
1902
1903     BKE_camera_params_init(&params);
1904     /* fallback for non camera objects */
1905     params.clip_start = v3d->clip_start;
1906     params.clip_end = v3d->clip_end;
1907     BKE_camera_params_from_object(&params, camera_eval);
1908     BKE_camera_multiview_params(&scene->r, &params, camera_eval, viewname);
1909     BKE_camera_params_compute_viewplane(&params, sizex, sizey, scene->r.xasp, scene->r.yasp);
1910     BKE_camera_params_compute_matrix(&params);
1911
1912     is_ortho = params.is_ortho;
1913     copy_m4_m4(winmat, params.winmat);
1914   }
1915   else {
1916     rctf viewplane;
1917     float clip_start, clipend;
1918
1919     is_ortho = ED_view3d_viewplane_get(
1920         depsgraph, v3d, rv3d, sizex, sizey, &viewplane, &clip_start, &clipend, NULL);
1921     if (is_ortho) {
1922       orthographic_m4(winmat,
1923                       viewplane.xmin,
1924                       viewplane.xmax,
1925                       viewplane.ymin,
1926                       viewplane.ymax,
1927                       -clipend,
1928                       clipend);
1929     }
1930     else {
1931       perspective_m4(winmat,
1932                      viewplane.xmin,
1933                      viewplane.xmax,
1934                      viewplane.ymin,
1935                      viewplane.ymax,
1936                      clip_start,
1937                      clipend);
1938     }
1939   }
1940
1941   const bool do_color_management = (ibuf->rect_float == NULL);
1942   ED_view3d_draw_offscreen(depsgraph,
1943                            scene,
1944                            drawtype,
1945                            v3d,
1946                            region,
1947                            sizex,
1948                            sizey,
1949                            NULL,
1950                            winmat,
1951                            true,
1952                            draw_sky,
1953                            !is_ortho,
1954                            viewname,
1955                            do_color_management,
1956                            ofs,
1957                            NULL);
1958
1959   if (ibuf->rect_float) {
1960     GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float);
1961   }
1962   else if (ibuf->rect) {
1963     GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect);
1964   }
1965
1966   /* unbind */
1967   GPU_offscreen_unbind(ofs, true);
1968
1969   if (own_ofs) {
1970     GPU_offscreen_free(ofs);
1971   }
1972
1973   DRW_opengl_context_disable();
1974
1975   if (old_fb) {
1976     GPU_framebuffer_bind(old_fb);
1977   }
1978
1979   if (ibuf->rect_float && ibuf->rect) {
1980     IMB_rect_from_float(ibuf);
1981   }
1982
1983   return ibuf;
1984 }
1985
1986 /**
1987  * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf)
1988  *
1989  * \param ofs: Optional off-screen buffer can be NULL.
1990  * (avoids re-creating when doing multiple GL renders).
1991  *
1992  * \note used by the sequencer
1993  */
1994 ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph,
1995                                              Scene *scene,
1996                                              View3DShading *shading_override,
1997                                              eDrawType drawtype,
1998                                              Object *camera,
1999                                              int width,
2000                                              int height,
2001                                              eImBufFlags imbuf_flag,
2002                                              eV3DOffscreenDrawFlag draw_flags,
2003                                              int alpha_mode,
2004                                              const char *viewname,
2005                                              GPUOffScreen *ofs,
2006                                              char err_out[256])
2007 {
2008   View3D v3d = {NULL};
2009   ARegion region = {NULL};
2010   RegionView3D rv3d = {{{0}}};
2011
2012   /* connect data */
2013   v3d.regionbase.first = v3d.regionbase.last = &region;
2014   region.regiondata = &rv3d;
2015   region.regiontype = RGN_TYPE_WINDOW;
2016
2017   v3d.camera = camera;
2018   View3DShading *source_shading_settings = &scene->display.shading;
2019   if (draw_flags & V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS && shading_override != NULL) {
2020     source_shading_settings = shading_override;
2021   }
2022   memcpy(&v3d.shading, source_shading_settings, sizeof(View3DShading));
2023   v3d.shading.type = drawtype;
2024
2025   if (drawtype == OB_MATERIAL) {
2026     v3d.shading.flag = V3D_SHADING_SCENE_WORLD | V3D_SHADING_SCENE_LIGHTS;
2027     v3d.shading.render_pass = SCE_PASS_COMBINED;
2028   }
2029   else if (drawtype == OB_RENDER) {
2030     v3d.shading.flag = V3D_SHADING_SCENE_WORLD_RENDER | V3D_SHADING_SCENE_LIGHTS_RENDER;
2031     v3d.shading.render_pass = SCE_PASS_COMBINED;
2032   }
2033
2034   v3d.flag2 = V3D_HIDE_OVERLAYS;
2035
2036   if (draw_flags & V3D_OFSDRAW_SHOW_ANNOTATION) {
2037     v3d.flag2 |= V3D_SHOW_ANNOTATION;
2038   }
2039   if (draw_flags & V3D_OFSDRAW_SHOW_GRIDFLOOR) {
2040     v3d.gridflag |= V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y;
2041   }
2042
2043   v3d.shading.background_type = V3D_SHADING_BACKGROUND_WORLD;
2044
2045   rv3d.persp = RV3D_CAMOB;
2046
2047   copy_m4_m4(rv3d.viewinv, v3d.camera->obmat);
2048   normalize_m4(rv3d.viewinv);
2049   invert_m4_m4(rv3d.viewmat, rv3d.viewinv);
2050
2051   {
2052     CameraParams params;
2053     const Object *view_camera_eval = DEG_get_evaluated_object(
2054         depsgraph, BKE_camera_multiview_render(scene, v3d.camera, viewname));
2055
2056     BKE_camera_params_init(&params);
2057     BKE_camera_params_from_object(&params, view_camera_eval);
2058     BKE_camera_multiview_params(&scene->r, &params, view_camera_eval, viewname);
2059     BKE_camera_params_compute_viewplane(&params, width, height, scene->r.xasp, scene->r.yasp);
2060     BKE_camera_params_compute_matrix(&params);
2061
2062     copy_m4_m4(rv3d.winmat, params.winmat);
2063     v3d.clip_start = params.clip_start;
2064     v3d.clip_end = params.clip_end;
2065     v3d.lens = params.lens;
2066   }
2067
2068   mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat);
2069   invert_m4_m4(rv3d.persinv, rv3d.viewinv);
2070
2071   return ED_view3d_draw_offscreen_imbuf(depsgraph,
2072                                         scene,
2073                                         drawtype,
2074                                         &v3d,
2075                                         &region,
2076                                         width,
2077                                         height,
2078                                         imbuf_flag,
2079                                         alpha_mode,
2080                                         viewname,
2081                                         ofs,
2082                                         err_out);
2083 }
2084
2085 /** \} */
2086
2087 /* -------------------------------------------------------------------- */
2088 /** \name Viewport Clipping
2089  * \{ */
2090
2091 static bool view3d_clipping_test(const float co[3], const float clip[6][4])
2092 {
2093   if (plane_point_side_v3(clip[0], co) > 0.0f) {
2094     if (plane_point_side_v3(clip[1], co) > 0.0f) {
2095       if (plane_point_side_v3(clip[2], co) > 0.0f) {
2096         if (plane_point_side_v3(clip[3], co) > 0.0f) {
2097           return false;
2098         }
2099       }
2100     }
2101   }
2102
2103   return true;
2104 }
2105
2106 /* For 'local' ED_view3d_clipping_local must run first
2107  * then all comparisons can be done in localspace. */
2108 bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
2109 {
2110   return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
2111 }
2112
2113 void ED_view3d_clipping_set(RegionView3D *UNUSED(rv3d))
2114 {
2115   for (uint a = 0; a < 6; a++) {
2116     glEnable(GL_CLIP_DISTANCE0 + a);
2117   }
2118 }
2119
2120 /* Use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set. */
2121 void ED_view3d_clipping_disable(void)
2122 {
2123   for (uint a = 0; a < 6; a++) {
2124     glDisable(GL_CLIP_DISTANCE0 + a);
2125   }
2126 }
2127 void ED_view3d_clipping_enable(void)
2128 {
2129   for (uint a = 0; a < 6; a++) {
2130     glEnable(GL_CLIP_DISTANCE0 + a);
2131   }
2132 }
2133
2134 /* *********************** backdraw for selection *************** */
2135
2136 /**
2137  * \note Only use in object mode.
2138  */
2139 static void validate_object_select_id(struct Depsgraph *depsgraph,
2140                                       ViewLayer *view_layer,
2141                                       ARegion *region,
2142                                       View3D *v3d,
2143                                       Object *obact)
2144 {
2145   Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
2146
2147   BLI_assert(region->regiontype == RGN_TYPE_WINDOW);
2148   UNUSED_VARS_NDEBUG(region);
2149
2150   if (obact_eval && (obact_eval->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
2151                      BKE_paint_select_face_test(obact_eval))) {
2152     /* do nothing */
2153   }
2154   /* texture paint mode sampling */
2155   else if (obact_eval && (obact_eval->mode & OB_MODE_TEXTURE_PAINT) &&
2156            (v3d->shading.type > OB_WIRE)) {
2157     /* do nothing */
2158   }
2159   else if ((obact_eval && (obact_eval->mode & OB_MODE_PARTICLE_EDIT)) && !XRAY_ENABLED(v3d)) {
2160     /* do nothing */
2161   }
2162   else {
2163     v3d->flag &= ~V3D_INVALID_BACKBUF;
2164     return;
2165   }
2166
2167   if (!(v3d->flag & V3D_INVALID_BACKBUF)) {
2168     return;
2169   }
2170
2171   if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) {
2172     Base *base = BKE_view_layer_base_find(view_layer, obact);
2173     DRW_select_buffer_context_create(&base, 1, -1);
2174   }
2175
2176   /* TODO: Create a flag in `DRW_manager` because the drawing is no longer
2177    *       made on the backbuffer in this case. */
2178   v3d->flag &= ~V3D_INVALID_BACKBUF;
2179 }
2180
2181 /* TODO: Creating, attaching texture, and destroying a framebuffer is quite slow.
2182  *       Calling this function should be avoided during interactive drawing. */
2183 static void view3d_opengl_read_Z_pixels(GPUViewport *viewport, rcti *rect, void *data)
2184 {
2185   DefaultTextureList *dtxl = (DefaultTextureList *)GPU_viewport_texture_list_get(viewport);
2186
2187   GPUFrameBuffer *tmp_fb = GPU_framebuffer_create();
2188   GPU_framebuffer_texture_attach(tmp_fb, dtxl->depth, 0, 0);
2189   GPU_framebuffer_bind(tmp_fb);
2190
2191   glReadPixels(rect->xmin,
2192                rect->ymin,
2193                BLI_rcti_size_x(rect),
2194                BLI_rcti_size_y(rect),
2195                GL_DEPTH_COMPONENT,
2196                GL_FLOAT,
2197                data);
2198
2199   GPU_framebuffer_restore();
2200   GPU_framebuffer_free(tmp_fb);
2201 }
2202
2203 void ED_view3d_select_id_validate(ViewContext *vc)
2204 {
2205   /* TODO: Create a flag in `DRW_manager` because the drawing is no longer
2206    *       made on the backbuffer in this case. */
2207   if (vc->v3d->flag & V3D_INVALID_BACKBUF) {
2208     validate_object_select_id(vc->depsgraph, vc->view_layer, vc->region, vc->v3d, vc->obact);
2209   }
2210 }
2211
2212 void ED_view3d_backbuf_depth_validate(ViewContext *vc)
2213 {
2214   if (vc->v3d->flag & V3D_INVALID_BACKBUF) {
2215     ARegion *region = vc->region;
2216     Object *obact_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
2217
2218     if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) {
2219       GPUViewport *viewport = WM_draw_region_get_viewport(region);
2220       DRW_draw_depth_object(vc->region, vc->v3d, viewport, obact_eval);
2221     }
2222
2223     vc->v3d->flag &= ~V3D_INVALID_BACKBUF;
2224   }
2225 }
2226
2227 /**
2228  * allow for small values [0.5 - 2.5],
2229  * and large values, FLT_MAX by clamping by the area size
2230  */
2231 int ED_view3d_backbuf_sample_size_clamp(ARegion *region, const float dist)
2232 {
2233   return (int)min_ff(ceilf(dist), (float)max_ii(region->winx, region->winx));
2234 }
2235
2236 /* *********************** */
2237
2238 void view3d_update_depths_rect(ARegion *region, ViewDepths *d, rcti *rect)
2239 {
2240   /* clamp rect by region */
2241   rcti r = {
2242       .xmin = 0,
2243       .xmax = region->winx - 1,
2244       .ymin = 0,
2245       .ymax = region->winy - 1,
2246   };
2247
2248   /* Constrain rect to depth bounds */
2249   BLI_rcti_isect(&r, rect, rect);
2250
2251   /* assign values to compare with the ViewDepths */
2252   int x = rect->xmin;
2253   int y = rect->ymin;
2254
2255   int w = BLI_rcti_size_x(rect);
2256   int h = BLI_rcti_size_y(rect);
2257
2258   if (w <= 0 || h <= 0) {
2259     if (d->depths) {
2260       MEM_freeN(d->depths);
2261     }
2262     d->depths = NULL;
2263
2264     d->damaged = false;
2265   }
2266   else if (d->w != w || d->h != h || d->x != x || d->y != y || d->depths == NULL) {
2267     d->x = x;
2268     d->y = y;
2269     d->w = w;
2270     d->h = h;
2271
2272     if (d->depths) {
2273       MEM_freeN(d->depths);
2274     }
2275
2276     d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset");
2277
2278     d->damaged = true;
2279   }
2280
2281   if (d->damaged) {
2282     GPUViewport *viewport = WM_draw_region_get_viewport(region);
2283     view3d_opengl_read_Z_pixels(viewport, rect, d->depths);
2284     glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
2285     d->damaged = false;
2286   }
2287 }
2288
2289 /* Note, with nouveau drivers the glReadPixels() is very slow. [#24339]. */
2290 void ED_view3d_depth_update(ARegion *region)
2291 {
2292   RegionView3D *rv3d = region->regiondata;
2293
2294   /* Create storage for, and, if necessary, copy depth buffer. */
2295   if (!rv3d->depths) {
2296     rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths");
2297   }
2298   if (rv3d->depths) {
2299     ViewDepths *d = rv3d->depths;
2300     if (d->w != region->winx || d->h != region->winy || !d->depths) {
2301       d->w = region->winx;
2302       d->h = region->winy;
2303       if (d->depths) {
2304         MEM_freeN(d->depths);
2305       }
2306       d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths");
2307       d->damaged = true;
2308     }
2309
2310     if (d->damaged) {
2311       GPUViewport *viewport = WM_draw_region_get_viewport(region);
2312       rcti r = {
2313           .xmin = 0,
2314           .xmax = d->w,
2315           .ymin = 0,
2316           .ymax = d->h,
2317       };
2318       view3d_opengl_read_Z_pixels(viewport, &r, d->depths);
2319       glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
2320       d->damaged = false;
2321     }
2322   }
2323 }
2324
2325 /* Utility function to find the closest Z value, use for autodepth. */
2326 float view3d_depth_near(ViewDepths *d)
2327 {
2328   /* Convert to float for comparisons. */
2329   const float near = (float)d->depth_range[0];
2330   const float far_real = (float)d->depth_range[1];
2331   float far = far_real;
2332
2333   const float *depths = d->depths;
2334   float depth = FLT_MAX;
2335   int i = (int)d->w * (int)d->h; /* Cast to avoid short overflow. */
2336
2337   /* Far is both the starting 'far' value
2338    * and the closest value found. */
2339   while (i--) {
2340     depth = *depths++;
2341     if ((depth < far) && (depth > near)) {
2342       far = depth;
2343     }
2344   }
2345
2346   return far == far_real ? FLT_MAX : far;
2347 }
2348
2349 void ED_view3d_draw_depth_gpencil(Depsgraph *depsgraph, Scene *scene, ARegion *region, View3D *v3d)
2350 {
2351   /* Setup view matrix. */
2352   ED_view3d_draw_setup_view(NULL, NULL, depsgraph, scene, region, v3d, NULL, NULL, NULL);
2353
2354   GPU_clear(GPU_DEPTH_BIT);
2355
2356   GPU_depth_test(true);
2357
2358   GPUViewport *viewport = WM_draw_region_get_viewport(region);
2359   DRW_draw_depth_loop_gpencil(depsgraph, region, v3d, viewport);
2360
2361   GPU_depth_test(false);
2362 }
2363
2364 /* *********************** customdata **************** */
2365
2366 void ED_view3d_datamask(const bContext *C,
2367                         const Scene *UNUSED(scene),
2368                         const View3D *v3d,
2369                         CustomData_MeshMasks *r_cddata_masks)
2370 {
2371   if (ELEM(v3d->shading.type, OB_TEXTURE, OB_MATERIAL, OB_RENDER)) {
2372     r_cddata_masks->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
2373     r_cddata_masks->vmask |= CD_MASK_ORCO;
2374   }
2375   else if (v3d->shading.type == OB_SOLID) {
2376     if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) {
2377       r_cddata_masks->lmask |= CD_MASK_MLOOPUV;
2378     }
2379     if (v3d->shading.color_type == V3D_SHADING_VERTEX_COLOR) {
2380       r_cddata_masks->lmask |= CD_MASK_MLOOPCOL;
2381     }
2382   }
2383
2384   if ((CTX_data_mode_enum(C) == CTX_MODE_EDIT_MESH) &&
2385       (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_WEIGHT)) {
2386     r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
2387   }
2388 }
2389
2390 /* Goes over all modes and view3d settings. */
2391 void ED_view3d_screen_datamask(const bContext *C,
2392                                const Scene *scene,
2393                                const bScreen *screen,
2394                                CustomData_MeshMasks *r_cddata_masks)
2395 {
2396   CustomData_MeshMasks_update(r_cddata_masks, &CD_MASK_BAREMESH);
2397
2398   /* Check if we need tfaces & mcols due to view mode. */
2399   LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
2400     if (area->spacetype == SPACE_VIEW3D) {
2401       ED_view3d_datamask(C, scene, area->spacedata.first, r_cddata_masks);
2402     }
2403   }
2404 }
2405
2406 /**
2407  * Store values from #RegionView3D, set when drawing.
2408  * This is needed when we draw with to a viewport using a different matrix
2409  * (offscreen drawing for example).
2410  *
2411  * Values set by #ED_view3d_update_viewmat should be handled here.
2412  */
2413 struct RV3DMatrixStore {
2414   float winmat[4][4];
2415   float viewmat[4][4];
2416   float viewinv[4][4];
2417   float persmat[4][4];
2418   float persinv[4][4];
2419   float viewcamtexcofac[4];
2420   float pixsize;
2421 };
2422
2423 struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d)
2424 {
2425   struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__);
2426   copy_m4_m4(rv3dmat->winmat, rv3d->winmat);
2427   copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat);
2428   copy_m4_m4(rv3dmat->persmat, rv3d->persmat);
2429   copy_m4_m4(rv3dmat->persinv, rv3d->persinv);
2430   copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv);
2431   copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac);
2432   rv3dmat->pixsize = rv3d->pixsize;
2433   return (void *)rv3dmat;
2434 }
2435
2436 void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat_pt)
2437 {
2438   struct RV3DMatrixStore *rv3dmat = rv3dmat_pt;
2439   copy_m4_m4(rv3d->winmat, rv3dmat->winmat);
2440   copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat);
2441   copy_m4_m4(rv3d->persmat, rv3dmat->persmat);
2442   copy_m4_m4(rv3d->persinv, rv3dmat->persinv);
2443   copy_m4_m4(rv3d->viewinv, rv3dmat->viewinv);
2444   copy_v4_v4(rv3d->viewcamtexcofac, rv3dmat->viewcamtexcofac);
2445   rv3d->pixsize = rv3dmat->pixsize;
2446 }
2447
2448 /**
2449  * \note The info that this uses is updated in #ED_refresh_viewport_fps,
2450  * which currently gets called during #SCREEN_OT_animation_step.
2451  */
2452 void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset)
2453 {
2454   ScreenFrameRateInfo *fpsi = scene->fps_info;
2455   char printable[16];
2456
2457   if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime) {
2458     return;
2459   }
2460
2461   printable[0] = '\0';
2462
2463   /* Doing an average for a more robust calculation. */
2464   fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 /
2465                                                           (fpsi->lredrawtime - fpsi->redrawtime));
2466
2467   float fps = 0.0f;
2468   int tot = 0;
2469   for (int i = 0; i < REDRAW_FRAME_AVERAGE; i++) {
2470     if (fpsi->redrawtimes_fps[i]) {
2471       fps += fpsi->redrawtimes_fps[i];
2472       tot++;
2473     }
2474   }
2475   if (tot) {
2476     fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE;
2477     fps = fps / tot;
2478   }
2479
2480   const int font_id = BLF_default();
2481
2482   /* Is this more than half a frame behind? */
2483   if (fps + 0.5f < (float)(FPS)) {
2484     UI_FontThemeColor(font_id, TH_REDALERT);
2485     BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps);
2486   }
2487   else {
2488     UI_FontThemeColor(font_id, TH_TEXT_HI);
2489     BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f));
2490   }
2491
2492   BLF_enable(font_id, BLF_SHADOW);
2493   BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
2494   BLF_shadow_offset(font_id, 1, -1);
2495
2496   *yoffset -= U.widget_unit;
2497
2498 #ifdef WITH_INTERNATIONAL
2499   BLF_draw_default(xoffset, *yoffset, 0.0f, printable, sizeof(printable));
2500 #else
2501   BLF_draw_default_ascii(xoffset, *yoffset, 0.0f, printable, sizeof(printable));
2502 #endif
2503
2504   BLF_disable(font_id, BLF_SHADOW);
2505 }
2506
2507 static bool view3d_main_region_do_render_draw(const Scene *scene)
2508 {
2509   RenderEngineType *type = RE_engines_find(scene->r.engine);
2510   return (type && type->view_update && type->view_draw);
2511 }
2512
2513 bool ED_view3d_calc_render_border(
2514     const Scene *scene, Depsgraph *depsgraph, View3D *v3d, ARegion *region, rcti *rect)
2515 {
2516   RegionView3D *rv3d = region->regiondata;
2517   bool use_border;
2518
2519   /* Test if there is a 3d view rendering. */
2520   if (v3d->shading.type != OB_RENDER || !view3d_main_region_do_render_draw(scene)) {
2521     return false;
2522   }
2523
2524   /* Test if there is a border render. */
2525   if (rv3d->persp == RV3D_CAMOB) {
2526     use_border = (scene->r.mode & R_BORDER) != 0;
2527   }
2528   else {
2529     use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0;
2530   }
2531
2532   if (!use_border) {
2533     return false;
2534   }
2535
2536   /* Compute border. */
2537   if (rv3d->persp == RV3D_CAMOB) {
2538     rctf viewborder;
2539     ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &viewborder, false);
2540
2541     rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder);
2542     rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder);
2543     rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder);
2544     rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder);
2545   }
2546   else {
2547     rect->xmin = v3d->render_border.xmin * region->winx;
2548     rect->xmax = v3d->render_border.xmax * region->winx;
2549     rect->ymin = v3d->render_border.ymin * region->winy;
2550     rect->ymax = v3d->render_border.ymax * region->winy;
2551   }
2552
2553   BLI_rcti_translate(rect, region->winrct.xmin, region->winrct.ymin);
2554   BLI_rcti_isect(&region->winrct, rect, rect);
2555
2556   return true;
2557 }
2558
2559 /** \} */