Cleanup: remove unused G_FLAG_BACKBUFSEL
[blender.git] / source / blender / editors / space_view3d / view3d_draw_legacy.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 <string.h>
25 #include <stdio.h>
26 #include <math.h>
27
28 #include "DNA_armature_types.h"
29 #include "DNA_camera_types.h"
30 #include "DNA_collection_types.h"
31 #include "DNA_customdata_types.h"
32 #include "DNA_object_types.h"
33 #include "DNA_mesh_types.h"
34 #include "DNA_key_types.h"
35 #include "DNA_light_types.h"
36 #include "DNA_scene_types.h"
37 #include "DNA_world_types.h"
38 #include "DNA_brush_types.h"
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BLI_blenlib.h"
43 #include "BLI_math.h"
44 #include "BLI_utildefines.h"
45 #include "BLI_endian_switch.h"
46 #include "BLI_threads.h"
47
48 #include "BKE_anim.h"
49 #include "BKE_camera.h"
50 #include "BKE_context.h"
51 #include "BKE_customdata.h"
52 #include "BKE_image.h"
53 #include "BKE_key.h"
54 #include "BKE_layer.h"
55 #include "BKE_object.h"
56 #include "BKE_global.h"
57 #include "BKE_paint.h"
58 #include "BKE_scene.h"
59 #include "BKE_unit.h"
60 #include "BKE_movieclip.h"
61
62 #include "DEG_depsgraph.h"
63 #include "DEG_depsgraph_query.h"
64
65 #include "IMB_imbuf_types.h"
66 #include "IMB_imbuf.h"
67 #include "IMB_colormanagement.h"
68
69 #include "BIF_glutil.h"
70
71 #include "WM_api.h"
72 #include "WM_types.h"
73
74 #include "BLF_api.h"
75 #include "BLT_translation.h"
76
77 #include "ED_armature.h"
78 #include "ED_keyframing.h"
79 #include "ED_gpencil.h"
80 #include "ED_mesh.h"
81 #include "ED_screen.h"
82 #include "ED_space_api.h"
83 #include "ED_screen_types.h"
84 #include "ED_transform.h"
85 #include "ED_view3d.h"
86
87 #include "UI_interface.h"
88 #include "UI_interface_icons.h"
89 #include "UI_resources.h"
90
91 #include "GPU_draw.h"
92 #include "GPU_framebuffer.h"
93 #include "GPU_material.h"
94 #include "GPU_extensions.h"
95 #include "GPU_immediate.h"
96 #include "GPU_immediate_util.h"
97 #include "GPU_select.h"
98 #include "GPU_matrix.h"
99 #include "GPU_state.h"
100 #include "GPU_viewport.h"
101
102 #include "RE_engine.h"
103
104 #include "DRW_engine.h"
105
106 #include "view3d_intern.h" /* own include */
107
108 /* ********* custom clipping *********** */
109
110 /* Legacy 2.7x, now use shaders that use clip distance instead.
111  * Remove once clipping is working properly. */
112 #define USE_CLIP_PLANES
113
114 void ED_view3d_clipping_set(RegionView3D *rv3d)
115 {
116 #ifdef USE_CLIP_PLANES
117   double plane[4];
118   const uint tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6;
119
120   for (unsigned a = 0; a < tot; a++) {
121     copy_v4db_v4fl(plane, rv3d->clip[a]);
122     glClipPlane(GL_CLIP_PLANE0 + a, plane);
123     glEnable(GL_CLIP_PLANE0 + a);
124     glEnable(GL_CLIP_DISTANCE0 + a);
125   }
126 #else
127   for (unsigned a = 0; a < 6; a++) {
128     glEnable(GL_CLIP_DISTANCE0 + a);
129   }
130 #endif
131 }
132
133 /* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */
134 void ED_view3d_clipping_disable(void)
135 {
136   for (unsigned a = 0; a < 6; a++) {
137 #ifdef USE_CLIP_PLANES
138     glDisable(GL_CLIP_PLANE0 + a);
139 #endif
140     glDisable(GL_CLIP_DISTANCE0 + a);
141   }
142 }
143 void ED_view3d_clipping_enable(void)
144 {
145   for (unsigned a = 0; a < 6; a++) {
146 #ifdef USE_CLIP_PLANES
147     glEnable(GL_CLIP_PLANE0 + a);
148 #endif
149     glEnable(GL_CLIP_DISTANCE0 + a);
150   }
151 }
152
153 /* *********************** backdraw for selection *************** */
154
155 static void validate_object_select_id(struct Depsgraph *depsgraph,
156                                       Scene *scene,
157                                       ARegion *ar,
158                                       View3D *v3d,
159                                       Object *obact,
160                                       Object *obedit,
161                                       short select_mode)
162 {
163   RegionView3D *rv3d = ar->regiondata;
164   Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
165   Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
166
167   BLI_assert(ar->regiontype == RGN_TYPE_WINDOW);
168
169   if (obact_eval && (obact_eval->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
170                      BKE_paint_select_face_test(obact_eval))) {
171     /* do nothing */
172   }
173   /* texture paint mode sampling */
174   else if (obact_eval && (obact_eval->mode & OB_MODE_TEXTURE_PAINT) &&
175            (v3d->shading.type > OB_WIRE)) {
176     /* do nothing */
177   }
178   else if ((obact_eval && (obact_eval->mode & OB_MODE_PARTICLE_EDIT)) && !XRAY_ENABLED(v3d)) {
179     /* do nothing */
180   }
181   else {
182     v3d->flag &= ~V3D_INVALID_BACKBUF;
183     return;
184   }
185
186   if (!(v3d->flag & V3D_INVALID_BACKBUF)) {
187     return;
188   }
189
190   if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) {
191     DRW_framebuffer_select_id_setup(ar, true);
192     DRW_draw_select_id_object(scene_eval,
193                               rv3d,
194                               obact_eval,
195                               select_mode,
196                               false,
197                               1,
198                               &bm_vertoffs,
199                               &bm_wireoffs,
200                               &bm_solidoffs);
201
202     DRW_framebuffer_select_id_release(ar);
203   }
204
205   /* TODO: Create a flag in `DRW_manager` because the drawing is no longer
206    *       made on the backbuffer in this case. */
207   v3d->flag &= ~V3D_INVALID_BACKBUF;
208 }
209
210 /* TODO: Creating, attaching texture, and destroying a framebuffer is quite slow.
211  *       Calling this function should be avoided during interactive drawing. */
212 static void view3d_opengl_read_Z_pixels(GPUViewport *viewport, rcti *rect, void *data)
213 {
214   DefaultTextureList *dtxl = (DefaultTextureList *)GPU_viewport_texture_list_get(viewport);
215
216   GPUFrameBuffer *tmp_fb = GPU_framebuffer_create();
217   GPU_framebuffer_texture_attach(tmp_fb, dtxl->depth, 0, 0);
218   GPU_framebuffer_bind(tmp_fb);
219
220   glReadPixels(rect->xmin,
221                rect->ymin,
222                BLI_rcti_size_x(rect),
223                BLI_rcti_size_y(rect),
224                GL_DEPTH_COMPONENT,
225                GL_FLOAT,
226                data);
227
228   GPU_framebuffer_restore();
229   GPU_framebuffer_free(tmp_fb);
230 }
231
232 void ED_view3d_select_id_validate_with_select_mode(ViewContext *vc, short select_mode)
233 {
234   /* TODO: Create a flag in `DRW_manager` because the drawing is no longer
235    *       made on the backbuffer in this case. */
236   if (vc->v3d->flag & V3D_INVALID_BACKBUF) {
237     validate_object_select_id(
238         vc->depsgraph, vc->scene, vc->ar, vc->v3d, vc->obact, vc->obedit, select_mode);
239   }
240 }
241
242 void ED_view3d_select_id_validate(ViewContext *vc)
243 {
244   ED_view3d_select_id_validate_with_select_mode(vc, -1);
245 }
246
247 void ED_view3d_backbuf_depth_validate(ViewContext *vc)
248 {
249   if (vc->v3d->flag & V3D_INVALID_BACKBUF) {
250     ARegion *ar = vc->ar;
251     Object *obact_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
252
253     if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) {
254       GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
255       DRW_draw_depth_object(vc->ar, viewport, obact_eval);
256     }
257
258     vc->v3d->flag &= ~V3D_INVALID_BACKBUF;
259   }
260 }
261
262 uint *ED_view3d_select_id_read_rect(const rcti *clip, uint *r_buf_len)
263 {
264   uint width = BLI_rcti_size_x(clip);
265   uint height = BLI_rcti_size_y(clip);
266   uint buf_len = width * height;
267   uint *buf = MEM_mallocN(buf_len * sizeof(*buf), __func__);
268
269   DRW_framebuffer_select_id_read(clip, buf);
270
271   if (r_buf_len) {
272     *r_buf_len = buf_len;
273   }
274
275   return buf;
276 }
277
278 /**
279  * allow for small values [0.5 - 2.5],
280  * and large values, FLT_MAX by clamping by the area size
281  */
282 int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist)
283 {
284   return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx));
285 }
286
287 /* samples a single pixel (copied from vpaint) */
288 uint ED_view3d_select_id_sample(ViewContext *vc, int x, int y)
289 {
290   if (x >= vc->ar->winx || y >= vc->ar->winy) {
291     return 0;
292   }
293
294   uint buf_len;
295   uint *buf = ED_view3d_select_id_read(x, y, x, y, &buf_len);
296   BLI_assert(0 != buf_len);
297   uint ret = buf[0];
298   MEM_freeN(buf);
299
300   return ret;
301 }
302
303 /* reads full rect, converts indices */
304 uint *ED_view3d_select_id_read(int xmin, int ymin, int xmax, int ymax, uint *r_buf_len)
305 {
306   if (UNLIKELY((xmin > xmax) || (ymin > ymax))) {
307     return NULL;
308   }
309
310   const rcti rect = {
311       .xmin = xmin,
312       .xmax = xmax + 1,
313       .ymin = ymin,
314       .ymax = ymax + 1,
315   };
316
317   uint buf_len;
318   uint *buf = ED_view3d_select_id_read_rect(&rect, &buf_len);
319
320   if (r_buf_len) {
321     *r_buf_len = buf_len;
322   }
323
324   return buf;
325 }
326
327 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
328 uint ED_view3d_select_id_read_nearest(struct ViewContext *UNUSED(vc),
329                                       const int mval[2],
330                                       const uint id_min,
331                                       const uint id_max,
332                                       uint *r_dist)
333 {
334   /* Create region around mouse cursor. This must be square and have an odd
335    * width, the spiraling algorithm does not work with arbitrary rectangles. */
336   rcti rect;
337   BLI_rcti_init_pt_radius(&rect, mval, *r_dist);
338   rect.xmax += 1;
339   rect.ymax += 1;
340
341   int width = BLI_rcti_size_x(&rect);
342   int height = width;
343   BLI_assert(width == height);
344
345   /* Read from selection framebuffer. */
346   uint *buf = MEM_mallocN(width * height * sizeof(*buf), __func__);
347   DRW_framebuffer_select_id_read(&rect, buf);
348
349   /* Spiral, starting from center of buffer. */
350   int spiral_offset = height * (int)(width / 2) + (height / 2);
351   int spiral_direction = 0;
352
353   uint index = 0;
354
355   for (int nr = 1; nr <= height; nr++) {
356     for (int a = 0; a < 2; a++) {
357       for (int b = 0; b < nr; b++) {
358         /* Find hit within the specified range. */
359         uint hit_id = buf[spiral_offset];
360
361         if (hit_id && hit_id >= id_min && hit_id < id_max) {
362           /* Get x/y from spiral offset. */
363           int hit_x = spiral_offset % width;
364           int hit_y = spiral_offset / width;
365
366           int center_x = width / 2;
367           int center_y = height / 2;
368
369           /* Manhatten distance in keeping with other screen-based selection. */
370           *r_dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y));
371
372           /* Indices start at 1 here. */
373           index = (hit_id - id_min) + 1;
374           goto exit;
375         }
376
377         /* Next spiral step. */
378         if (spiral_direction == 0) {
379           spiral_offset += 1; /* right */
380         }
381         else if (spiral_direction == 1) {
382           spiral_offset -= width; /* down */
383         }
384         else if (spiral_direction == 2) {
385           spiral_offset -= 1; /* left */
386         }
387         else {
388           spiral_offset += width; /* up */
389         }
390
391         /* Stop if we are outside the buffer. */
392         if (spiral_offset < 0 || spiral_offset >= width * height) {
393           goto exit;
394         }
395       }
396
397       spiral_direction = (spiral_direction + 1) % 4;
398     }
399   }
400
401 exit:
402   MEM_freeN(buf);
403   return index;
404 }
405
406 /* ************************************************************* */
407
408 static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
409 {
410   if (BKE_image_is_stereo(ima)) {
411     iuser->flag |= IMA_SHOW_STEREO;
412
413     if ((scene->r.scemode & R_MULTIVIEW) == 0) {
414       iuser->multiview_eye = STEREO_LEFT_ID;
415     }
416     else if (v3d->stereo3d_camera != STEREO_3D_ID) {
417       /* show only left or right camera */
418       iuser->multiview_eye = v3d->stereo3d_camera;
419     }
420
421     BKE_image_multiview_index(ima, iuser);
422   }
423   else {
424     iuser->flag &= ~IMA_SHOW_STEREO;
425   }
426 }
427
428 static void view3d_draw_bgpic(Scene *scene,
429                               Depsgraph *depsgraph,
430                               ARegion *ar,
431                               View3D *v3d,
432                               const bool do_foreground,
433                               const bool do_camera_frame)
434 {
435   RegionView3D *rv3d = ar->regiondata;
436   int fg_flag = do_foreground ? CAM_BGIMG_FLAG_FOREGROUND : 0;
437   if (v3d->camera == NULL || v3d->camera->type != OB_CAMERA) {
438     return;
439   }
440   Camera *cam = v3d->camera->data;
441
442   for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
443     if ((bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != fg_flag) {
444       continue;
445     }
446
447     {
448       float image_aspect[2];
449       float x1, y1, x2, y2, centx, centy;
450
451       void *lock;
452
453       Image *ima = NULL;
454
455       /* disable individual images */
456       if ((bgpic->flag & CAM_BGIMG_FLAG_DISABLED)) {
457         continue;
458       }
459
460       ImBuf *ibuf = NULL;
461       ImBuf *freeibuf = NULL;
462       ImBuf *releaseibuf = NULL;
463       if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
464         ima = bgpic->ima;
465         if (ima == NULL) {
466           continue;
467         }
468
469         ImageUser iuser = bgpic->iuser;
470         iuser.scene = scene; /* Needed for render results. */
471         BKE_image_user_frame_calc(&iuser, (int)DEG_get_ctime(depsgraph));
472         if (ima->source == IMA_SRC_SEQUENCE && !(iuser.flag & IMA_USER_FRAME_IN_RANGE)) {
473           ibuf = NULL; /* frame is out of range, dont show */
474         }
475         else {
476           view3d_stereo_bgpic_setup(scene, v3d, ima, &iuser);
477           ibuf = BKE_image_acquire_ibuf(ima, &iuser, &lock);
478           releaseibuf = ibuf;
479         }
480
481         image_aspect[0] = ima->aspx;
482         image_aspect[1] = ima->aspy;
483       }
484       else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
485         /* TODO: skip drawing when out of frame range (as image sequences do above) */
486         MovieClip *clip = NULL;
487
488         if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) {
489           if (scene->camera) {
490             clip = BKE_object_movieclip_get(scene, scene->camera, true);
491           }
492         }
493         else {
494           clip = bgpic->clip;
495         }
496
497         if (clip == NULL) {
498           continue;
499         }
500
501         BKE_movieclip_user_set_frame(&bgpic->cuser, (int)DEG_get_ctime(depsgraph));
502         ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser);
503
504         image_aspect[0] = clip->aspx;
505         image_aspect[1] = clip->aspy;
506
507         /* working with ibuf from image and clip has got different workflow now.
508          * ibuf acquired from clip is referenced by cache system and should
509          * be dereferenced after usage. */
510         freeibuf = ibuf;
511       }
512       else {
513         /* perhaps when loading future files... */
514         BLI_assert(0);
515         copy_v2_fl(image_aspect, 1.0f);
516       }
517
518       if (ibuf == NULL) {
519         continue;
520       }
521
522       if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) {
523         /* invalid image format */
524         if (freeibuf) {
525           IMB_freeImBuf(freeibuf);
526         }
527         if (releaseibuf) {
528           BKE_image_release_ibuf(ima, releaseibuf, lock);
529         }
530
531         continue;
532       }
533
534       if (ibuf->rect == NULL) {
535         IMB_rect_from_float(ibuf);
536       }
537
538       BLI_assert(rv3d->persp == RV3D_CAMOB);
539       {
540         if (do_camera_frame) {
541           rctf vb;
542           ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false);
543           x1 = vb.xmin;
544           y1 = vb.ymin;
545           x2 = vb.xmax;
546           y2 = vb.ymax;
547         }
548         else {
549           x1 = ar->winrct.xmin;
550           y1 = ar->winrct.ymin;
551           x2 = ar->winrct.xmax;
552           y2 = ar->winrct.ymax;
553         }
554
555         /* apply offset last - camera offset is different to offset in blender units */
556         /* so this has some sane way of working - this matches camera's shift _exactly_ */
557         {
558           const float max_dim = max_ff(x2 - x1, y2 - y1);
559           const float xof_scale = bgpic->offset[0] * max_dim;
560           const float yof_scale = bgpic->offset[1] * max_dim;
561
562           x1 += xof_scale;
563           y1 += yof_scale;
564           x2 += xof_scale;
565           y2 += yof_scale;
566         }
567
568         centx = (x1 + x2) * 0.5f;
569         centy = (y1 + y2) * 0.5f;
570
571         /* aspect correction */
572         if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
573           /* apply aspect from clip */
574           const float w_src = ibuf->x * image_aspect[0];
575           const float h_src = ibuf->y * image_aspect[1];
576
577           /* destination aspect is already applied from the camera frame */
578           const float w_dst = x1 - x2;
579           const float h_dst = y1 - y2;
580
581           const float asp_src = w_src / h_src;
582           const float asp_dst = w_dst / h_dst;
583
584           if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
585             if ((asp_src > asp_dst) == ((bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) != 0)) {
586               /* fit X */
587               const float div = asp_src / asp_dst;
588               x1 = ((x1 - centx) * div) + centx;
589               x2 = ((x2 - centx) * div) + centx;
590             }
591             else {
592               /* fit Y */
593               const float div = asp_dst / asp_src;
594               y1 = ((y1 - centy) * div) + centy;
595               y2 = ((y2 - centy) * div) + centy;
596             }
597           }
598         }
599       }
600
601       /* complete clip? */
602       rctf clip_rect;
603       BLI_rctf_init(&clip_rect, x1, x2, y1, y2);
604       if (bgpic->rotation) {
605         BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation);
606       }
607
608       if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx ||
609           clip_rect.ymin > ar->winy) {
610         if (freeibuf) {
611           IMB_freeImBuf(freeibuf);
612         }
613         if (releaseibuf) {
614           BKE_image_release_ibuf(ima, releaseibuf, lock);
615         }
616
617         continue;
618       }
619
620       float zoomx = (x2 - x1) / ibuf->x;
621       float zoomy = (y2 - y1) / ibuf->y;
622
623       /* For some reason; zoom-levels down refuses to use GL_ALPHA_SCALE. */
624       if (zoomx < 1.0f || zoomy < 1.0f) {
625         float tzoom = min_ff(zoomx, zoomy);
626         int mip = 0;
627
628         if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) {
629           IMB_remakemipmap(ibuf, 0);
630           ibuf->userflags &= ~IB_MIPMAP_INVALID;
631         }
632         else if (ibuf->mipmap[0] == NULL) {
633           IMB_makemipmap(ibuf, 0);
634         }
635
636         while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) {
637           tzoom *= 2.0f;
638           zoomx *= 2.0f;
639           zoomy *= 2.0f;
640           mip++;
641         }
642         if (mip > 0) {
643           ibuf = ibuf->mipmap[mip - 1];
644         }
645       }
646
647       GPU_depth_test(!do_foreground);
648       glDepthMask(GL_FALSE);
649
650       GPU_blend(true);
651       GPU_blend_set_func_separate(
652           GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
653
654       GPU_matrix_push_projection();
655       GPU_matrix_push();
656       ED_region_pixelspace(ar);
657
658       GPU_matrix_translate_2f(centx, centy);
659       GPU_matrix_scale_1f(bgpic->scale);
660       GPU_matrix_rotate_2d(RAD2DEGF(-bgpic->rotation));
661
662       if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) {
663         zoomx *= -1.0f;
664         x1 = x2;
665       }
666       if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) {
667         zoomy *= -1.0f;
668         y1 = y2;
669       }
670
671       float col[4] = {1.0f, 1.0f, 1.0f, bgpic->alpha};
672       IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
673       immDrawPixelsTex(&state,
674                        x1 - centx,
675                        y1 - centy,
676                        ibuf->x,
677                        ibuf->y,
678                        GL_RGBA,
679                        GL_UNSIGNED_BYTE,
680                        GL_LINEAR,
681                        ibuf->rect,
682                        zoomx,
683                        zoomy,
684                        col);
685
686       GPU_matrix_pop_projection();
687       GPU_matrix_pop();
688
689       GPU_blend(false);
690
691       glDepthMask(GL_TRUE);
692       GPU_depth_test(true);
693
694       if (freeibuf) {
695         IMB_freeImBuf(freeibuf);
696       }
697       if (releaseibuf) {
698         BKE_image_release_ibuf(ima, releaseibuf, lock);
699       }
700     }
701   }
702 }
703
704 void ED_view3d_draw_bgpic_test(Scene *scene,
705                                Depsgraph *depsgraph,
706                                ARegion *ar,
707                                View3D *v3d,
708                                const bool do_foreground,
709                                const bool do_camera_frame)
710 {
711   RegionView3D *rv3d = ar->regiondata;
712
713   if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) {
714     Camera *cam = v3d->camera->data;
715     if ((cam->flag & CAM_SHOW_BG_IMAGE) == 0) {
716       return;
717     }
718   }
719   else {
720     return;
721   }
722
723   /* disabled - mango request, since footage /w only render is quite useful
724    * and this option is easy to disable all background images at once */
725 #if 0
726   if (v3d->flag2 & V3D_HIDE_OVERLAYS) {
727     return;
728   }
729 #endif
730
731   if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) {
732     if (rv3d->persp == RV3D_CAMOB) {
733       view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame);
734     }
735   }
736   else {
737     view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame);
738   }
739 }
740
741 /* *********************** */
742
743 void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect)
744 {
745   /* clamp rect by region */
746   rcti r = {
747       .xmin = 0,
748       .xmax = ar->winx - 1,
749       .ymin = 0,
750       .ymax = ar->winy - 1,
751   };
752
753   /* Constrain rect to depth bounds */
754   BLI_rcti_isect(&r, rect, rect);
755
756   /* assign values to compare with the ViewDepths */
757   int x = rect->xmin;
758   int y = rect->ymin;
759
760   int w = BLI_rcti_size_x(rect);
761   int h = BLI_rcti_size_y(rect);
762
763   if (w <= 0 || h <= 0) {
764     if (d->depths) {
765       MEM_freeN(d->depths);
766     }
767     d->depths = NULL;
768
769     d->damaged = false;
770   }
771   else if (d->w != w || d->h != h || d->x != x || d->y != y || d->depths == NULL) {
772     d->x = x;
773     d->y = y;
774     d->w = w;
775     d->h = h;
776
777     if (d->depths) {
778       MEM_freeN(d->depths);
779     }
780
781     d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset");
782
783     d->damaged = true;
784   }
785
786   if (d->damaged) {
787     GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
788     view3d_opengl_read_Z_pixels(viewport, rect, d->depths);
789     glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
790     d->damaged = false;
791   }
792 }
793
794 /* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */
795 void ED_view3d_depth_update(ARegion *ar)
796 {
797   RegionView3D *rv3d = ar->regiondata;
798
799   /* Create storage for, and, if necessary, copy depth buffer */
800   if (!rv3d->depths) {
801     rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths");
802   }
803   if (rv3d->depths) {
804     ViewDepths *d = rv3d->depths;
805     if (d->w != ar->winx || d->h != ar->winy || !d->depths) {
806       d->w = ar->winx;
807       d->h = ar->winy;
808       if (d->depths) {
809         MEM_freeN(d->depths);
810       }
811       d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths");
812       d->damaged = true;
813     }
814
815     if (d->damaged) {
816       GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
817       rcti r = {
818           .xmin = 0,
819           .xmax = d->w,
820           .ymin = 0,
821           .ymax = d->h,
822       };
823       view3d_opengl_read_Z_pixels(viewport, &r, d->depths);
824       glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
825       d->damaged = false;
826     }
827   }
828 }
829
830 /* utility function to find the closest Z value, use for autodepth */
831 float view3d_depth_near(ViewDepths *d)
832 {
833   /* convert to float for comparisons */
834   const float near = (float)d->depth_range[0];
835   const float far_real = (float)d->depth_range[1];
836   float far = far_real;
837
838   const float *depths = d->depths;
839   float depth = FLT_MAX;
840   int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */
841
842   /* far is both the starting 'far' value
843    * and the closest value found. */
844   while (i--) {
845     depth = *depths++;
846     if ((depth < far) && (depth > near)) {
847       far = depth;
848     }
849   }
850
851   return far == far_real ? FLT_MAX : far;
852 }
853
854 void ED_view3d_draw_depth_gpencil(Depsgraph *depsgraph, Scene *scene, ARegion *ar, View3D *v3d)
855 {
856   /* Setup view matrix. */
857   ED_view3d_draw_setup_view(NULL, depsgraph, scene, ar, v3d, NULL, NULL, NULL);
858
859   GPU_clear(GPU_DEPTH_BIT);
860
861   GPU_depth_test(true);
862
863   GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
864   DRW_draw_depth_loop_gpencil(depsgraph, ar, v3d, viewport);
865
866   GPU_depth_test(false);
867 }
868
869 /* *********************** customdata **************** */
870
871 void ED_view3d_datamask(const bContext *C,
872                         const Scene *UNUSED(scene),
873                         const View3D *v3d,
874                         CustomData_MeshMasks *r_cddata_masks)
875 {
876   const int drawtype = view3d_effective_drawtype(v3d);
877
878   if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL)) {
879     r_cddata_masks->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
880
881     if (drawtype == OB_MATERIAL) {
882       r_cddata_masks->vmask |= CD_MASK_ORCO;
883     }
884   }
885
886   if ((CTX_data_mode_enum(C) == CTX_MODE_EDIT_MESH) &&
887       (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_WEIGHT)) {
888     r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
889   }
890 }
891
892 /* goes over all modes and view3d settings */
893 void ED_view3d_screen_datamask(const bContext *C,
894                                const Scene *scene,
895                                const bScreen *screen,
896                                CustomData_MeshMasks *r_cddata_masks)
897 {
898   CustomData_MeshMasks_update(r_cddata_masks, &CD_MASK_BAREMESH);
899
900   /* check if we need tfaces & mcols due to view mode */
901   for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
902     if (sa->spacetype == SPACE_VIEW3D) {
903       ED_view3d_datamask(C, scene, sa->spacedata.first, r_cddata_masks);
904     }
905   }
906 }
907
908 /**
909  * Store values from #RegionView3D, set when drawing.
910  * This is needed when we draw with to a viewport using a different matrix
911  * (offscreen drawing for example).
912  *
913  * Values set by #ED_view3d_update_viewmat should be handled here.
914  */
915 struct RV3DMatrixStore {
916   float winmat[4][4];
917   float viewmat[4][4];
918   float viewinv[4][4];
919   float persmat[4][4];
920   float persinv[4][4];
921   float viewcamtexcofac[4];
922   float pixsize;
923 };
924
925 struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d)
926 {
927   struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__);
928   copy_m4_m4(rv3dmat->winmat, rv3d->winmat);
929   copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat);
930   copy_m4_m4(rv3dmat->persmat, rv3d->persmat);
931   copy_m4_m4(rv3dmat->persinv, rv3d->persinv);
932   copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv);
933   copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac);
934   rv3dmat->pixsize = rv3d->pixsize;
935   return (void *)rv3dmat;
936 }
937
938 void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat_pt)
939 {
940   struct RV3DMatrixStore *rv3dmat = rv3dmat_pt;
941   copy_m4_m4(rv3d->winmat, rv3dmat->winmat);
942   copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat);
943   copy_m4_m4(rv3d->persmat, rv3dmat->persmat);
944   copy_m4_m4(rv3d->persinv, rv3dmat->persinv);
945   copy_m4_m4(rv3d->viewinv, rv3dmat->viewinv);
946   copy_v4_v4(rv3d->viewcamtexcofac, rv3dmat->viewcamtexcofac);
947   rv3d->pixsize = rv3dmat->pixsize;
948 }
949
950 /**
951  * \note The info that this uses is updated in #ED_refresh_viewport_fps,
952  * which currently gets called during #SCREEN_OT_animation_step.
953  */
954 void ED_scene_draw_fps(Scene *scene, int xoffset, int *yoffset)
955 {
956   ScreenFrameRateInfo *fpsi = scene->fps_info;
957   char printable[16];
958
959   if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime) {
960     return;
961   }
962
963   printable[0] = '\0';
964
965 #if 0
966   /* this is too simple, better do an average */
967   fps = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime))
968 #else
969   fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 /
970                                                           (fpsi->lredrawtime - fpsi->redrawtime));
971
972   float fps = 0.0f;
973   int tot = 0;
974   for (int i = 0; i < REDRAW_FRAME_AVERAGE; i++) {
975     if (fpsi->redrawtimes_fps[i]) {
976       fps += fpsi->redrawtimes_fps[i];
977       tot++;
978     }
979   }
980   if (tot) {
981     fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE;
982
983     // fpsi->redrawtime_index++;
984     // if (fpsi->redrawtime >= REDRAW_FRAME_AVERAGE) {
985     //  fpsi->redrawtime = 0;
986     //}
987
988     fps = fps / tot;
989   }
990 #endif
991
992   const int font_id = BLF_default();
993
994   /* is this more than half a frame behind? */
995   if (fps + 0.5f < (float)(FPS)) {
996     UI_FontThemeColor(font_id, TH_REDALERT);
997     BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps);
998   }
999   else {
1000     UI_FontThemeColor(font_id, TH_TEXT_HI);
1001     BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f));
1002   }
1003
1004   BLF_enable(font_id, BLF_SHADOW);
1005   BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
1006   BLF_shadow_offset(font_id, 1, -1);
1007
1008   *yoffset -= U.widget_unit;
1009
1010 #ifdef WITH_INTERNATIONAL
1011   BLF_draw_default(xoffset, *yoffset, 0.0f, printable, sizeof(printable));
1012 #else
1013   BLF_draw_default_ascii(xoffset, *yoffset, 0.0f, printable, sizeof(printable));
1014 #endif
1015
1016   BLF_disable(font_id, BLF_SHADOW);
1017 }
1018
1019 static bool view3d_main_region_do_render_draw(const Scene *scene)
1020 {
1021   RenderEngineType *type = RE_engines_find(scene->r.engine);
1022   return (type && type->view_update && type->view_draw);
1023 }
1024
1025 bool ED_view3d_calc_render_border(
1026     const Scene *scene, Depsgraph *depsgraph, View3D *v3d, ARegion *ar, rcti *rect)
1027 {
1028   RegionView3D *rv3d = ar->regiondata;
1029   bool use_border;
1030
1031   /* test if there is a 3d view rendering */
1032   if (v3d->shading.type != OB_RENDER || !view3d_main_region_do_render_draw(scene)) {
1033     return false;
1034   }
1035
1036   /* test if there is a border render */
1037   if (rv3d->persp == RV3D_CAMOB) {
1038     use_border = (scene->r.mode & R_BORDER) != 0;
1039   }
1040   else {
1041     use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0;
1042   }
1043
1044   if (!use_border) {
1045     return false;
1046   }
1047
1048   /* compute border */
1049   if (rv3d->persp == RV3D_CAMOB) {
1050     rctf viewborder;
1051     ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false);
1052
1053     rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder);
1054     rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder);
1055     rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder);
1056     rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder);
1057   }
1058   else {
1059     rect->xmin = v3d->render_border.xmin * ar->winx;
1060     rect->xmax = v3d->render_border.xmax * ar->winx;
1061     rect->ymin = v3d->render_border.ymin * ar->winy;
1062     rect->ymax = v3d->render_border.ymax * ar->winy;
1063   }
1064
1065   BLI_rcti_translate(rect, ar->winrct.xmin, ar->winrct.ymin);
1066   BLI_rcti_isect(&ar->winrct, rect, rect);
1067
1068   return true;
1069 }