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