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