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