Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_view3d / view3d_draw_legacy.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_view3d/view3d_draw_legacy.c
28  *  \ingroup spview3d
29  */
30
31 #include <string.h>
32 #include <stdio.h>
33 #include <math.h>
34
35 #include "DNA_armature_types.h"
36 #include "DNA_camera_types.h"
37 #include "DNA_collection_types.h"
38 #include "DNA_customdata_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_key_types.h"
42 #include "DNA_lamp_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_world_types.h"
45 #include "DNA_brush_types.h"
46
47 #include "MEM_guardedalloc.h"
48
49 #include "BLI_blenlib.h"
50 #include "BLI_math.h"
51 #include "BLI_jitter_2d.h"
52 #include "BLI_utildefines.h"
53 #include "BLI_endian_switch.h"
54 #include "BLI_threads.h"
55
56 #include "BKE_anim.h"
57 #include "BKE_camera.h"
58 #include "BKE_context.h"
59 #include "BKE_customdata.h"
60 #include "BKE_image.h"
61 #include "BKE_key.h"
62 #include "BKE_layer.h"
63 #include "BKE_main.h"
64 #include "BKE_object.h"
65 #include "BKE_global.h"
66 #include "BKE_paint.h"
67 #include "BKE_scene.h"
68 #include "BKE_screen.h"
69 #include "BKE_unit.h"
70 #include "BKE_movieclip.h"
71
72 #include "DEG_depsgraph.h"
73 #include "DEG_depsgraph_query.h"
74
75 #include "IMB_imbuf_types.h"
76 #include "IMB_imbuf.h"
77 #include "IMB_colormanagement.h"
78
79 #include "BIF_glutil.h"
80
81 #include "WM_api.h"
82 #include "WM_types.h"
83
84 #include "BLF_api.h"
85 #include "BLT_translation.h"
86
87 #include "ED_armature.h"
88 #include "ED_keyframing.h"
89 #include "ED_gpencil.h"
90 #include "ED_screen.h"
91 #include "ED_space_api.h"
92 #include "ED_screen_types.h"
93 #include "ED_transform.h"
94
95 #include "UI_interface.h"
96 #include "UI_interface_icons.h"
97 #include "UI_resources.h"
98
99 #include "GPU_draw.h"
100 #include "GPU_framebuffer.h"
101 #include "GPU_material.h"
102 #include "GPU_extensions.h"
103 #include "GPU_immediate.h"
104 #include "GPU_immediate_util.h"
105 #include "GPU_select.h"
106 #include "GPU_matrix.h"
107 #include "GPU_state.h"
108
109 #include "RE_engine.h"
110
111 #include "DRW_engine.h"
112
113 #include "view3d_intern.h"  /* own include */
114
115 /* ********* custom clipping *********** */
116
117 void ED_view3d_clipping_set(RegionView3D *rv3d)
118 {
119         double plane[4];
120         const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6;
121
122         for (unsigned a = 0; a < tot; a++) {
123                 copy_v4db_v4fl(plane, rv3d->clip[a]);
124                 glClipPlane(GL_CLIP_PLANE0 + a, plane);
125                 glEnable(GL_CLIP_PLANE0 + a);
126         }
127 }
128
129 /* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */
130 void ED_view3d_clipping_disable(void)
131 {
132         for (unsigned a = 0; a < 6; a++) {
133                 glDisable(GL_CLIP_PLANE0 + a);
134         }
135 }
136 void ED_view3d_clipping_enable(void)
137 {
138         for (unsigned a = 0; a < 6; a++) {
139                 glEnable(GL_CLIP_PLANE0 + a);
140         }
141 }
142
143 static bool view3d_clipping_test(const float co[3], const float clip[6][4])
144 {
145         if (plane_point_side_v3(clip[0], co) > 0.0f)
146                 if (plane_point_side_v3(clip[1], co) > 0.0f)
147                         if (plane_point_side_v3(clip[2], co) > 0.0f)
148                                 if (plane_point_side_v3(clip[3], co) > 0.0f)
149                                         return false;
150
151         return true;
152 }
153
154 /* for 'local' ED_view3d_clipping_local must run first
155  * then all comparisons can be done in localspace */
156 bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local)
157 {
158         return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
159 }
160
161 /* *********************** backdraw for selection *************** */
162
163 static void backdrawview3d(
164         struct Depsgraph *depsgraph, Scene *scene,
165         ARegion *ar, View3D *v3d,
166         Object *obact, Object *obedit,
167         short select_mode)
168 {
169         RegionView3D *rv3d = ar->regiondata;
170         Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
171         Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
172
173         BLI_assert(ar->regiontype == RGN_TYPE_WINDOW);
174
175         if (obact_eval && (obact_eval->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
176                      BKE_paint_select_face_test(obact_eval)))
177         {
178                 /* do nothing */
179         }
180         /* texture paint mode sampling */
181         else if (obact_eval && (obact_eval->mode & OB_MODE_TEXTURE_PAINT) &&
182                  (v3d->shading.type > OB_WIRE))
183         {
184                 /* do nothing */
185         }
186         else if ((obact_eval && (obact_eval->mode & OB_MODE_PARTICLE_EDIT)) &&
187                  V3D_IS_ZBUF(v3d))
188         {
189                 /* do nothing */
190         }
191         else if ((obedit && (obedit->mode & OB_MODE_EDIT)) &&
192                  V3D_IS_ZBUF(v3d))
193         {
194                 /* do nothing */
195         }
196         else {
197                 v3d->flag &= ~V3D_INVALID_BACKBUF;
198                 return;
199         }
200
201         if (!(v3d->flag & V3D_INVALID_BACKBUF))
202                 return;
203
204 #if 0
205         if (test) {
206                 if (qtest()) {
207                         addafterqueue(ar->win, BACKBUFDRAW, 1);
208                         return;
209                 }
210         }
211 #endif
212
213 #if 0 /* v3d->zbuf deprecated */
214         if (v3d->shading.type > OB_WIRE) v3d->zbuf = true;
215 #endif
216
217         /* dithering and AA break color coding, so disable */
218         glDisable(GL_DITHER);
219
220         if (false) {
221                 /* for multisample we use an offscreen FBO. multisample drawing can fail
222                  * with color coded selection drawing, and reading back depths from such
223                  * a buffer can also cause a few seconds freeze on OS X / NVidia.
224                  *
225                  * NOTE: code is no longer used now, but offscreen drawing is likely
226                  * what we will always want to do for the new viewport. */
227                 int w = BLI_rcti_size_x(&ar->winrct);
228                 int h = BLI_rcti_size_y(&ar->winrct);
229                 char error[256];
230
231                 if (rv3d->gpuoffscreen) {
232                         if (GPU_offscreen_width(rv3d->gpuoffscreen)  != w ||
233                             GPU_offscreen_height(rv3d->gpuoffscreen) != h)
234                         {
235                                 GPU_offscreen_free(rv3d->gpuoffscreen);
236                                 rv3d->gpuoffscreen = NULL;
237                         }
238                 }
239
240                 if (!rv3d->gpuoffscreen) {
241                         rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, true, false, error);
242
243                         if (!rv3d->gpuoffscreen)
244                                 fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error);
245                 }
246         }
247
248         if (rv3d->gpuoffscreen)
249                 GPU_offscreen_bind(rv3d->gpuoffscreen, true);
250         else
251                 GPU_scissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
252
253         GPU_clear_color(0.0, 0.0, 0.0, 0.0);
254         GPU_depth_test(true);
255         GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT);
256
257         if (rv3d->rflag & RV3D_CLIPPING)
258                 ED_view3d_clipping_set(rv3d);
259
260         G.f |= G_BACKBUFSEL;
261
262         if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) {
263                 draw_object_backbufsel(depsgraph, scene_eval, v3d, rv3d, obact_eval, select_mode);
264         }
265
266         if (rv3d->gpuoffscreen)
267                 GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
268
269         v3d->flag &= ~V3D_INVALID_BACKBUF;
270
271         G.f &= ~G_BACKBUFSEL;
272         GPU_depth_test(false);
273         glEnable(GL_DITHER);
274
275         if (rv3d->rflag & RV3D_CLIPPING)
276                 ED_view3d_clipping_disable();
277 }
278
279 void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
280 {
281         RegionView3D *rv3d = ar->regiondata;
282
283         if (rv3d->gpuoffscreen) {
284                 GPU_offscreen_bind(rv3d->gpuoffscreen, true);
285                 glReadBuffer(GL_COLOR_ATTACHMENT0);
286                 glReadPixels(x, y, w, h, format, type, data);
287                 GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
288         }
289         else {
290                 glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
291         }
292 }
293
294 /* XXX depth reading exception, for code not using gpu offscreen */
295 static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
296 {
297         glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
298 }
299
300 void ED_view3d_backbuf_validate_with_select_mode(ViewContext *vc, short select_mode)
301 {
302         if (vc->v3d->flag & V3D_INVALID_BACKBUF) {
303                 backdrawview3d(vc->depsgraph, vc->scene, vc->ar, vc->v3d, vc->obact, vc->obedit, select_mode);
304         }
305 }
306
307 void ED_view3d_backbuf_validate(ViewContext *vc)
308 {
309         ED_view3d_backbuf_validate_with_select_mode(vc, -1);
310 }
311
312 /**
313  * allow for small values [0.5 - 2.5],
314  * and large values, FLT_MAX by clamping by the area size
315  */
316 int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist)
317 {
318         return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx));
319 }
320
321 /* samples a single pixel (copied from vpaint) */
322 unsigned int ED_view3d_backbuf_sample(
323         ViewContext *vc, int x, int y)
324 {
325         if (x >= vc->ar->winx || y >= vc->ar->winy) {
326                 return 0;
327         }
328
329         ED_view3d_backbuf_validate(vc);
330
331         unsigned int col;
332         view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
333         glReadBuffer(GL_BACK);
334
335         if (ENDIAN_ORDER == B_ENDIAN) {
336                 BLI_endian_switch_uint32(&col);
337         }
338
339         return GPU_select_to_index(col);
340 }
341
342 /* reads full rect, converts indices */
343 ImBuf *ED_view3d_backbuf_read(
344         ViewContext *vc, int xmin, int ymin, int xmax, int ymax)
345 {
346         /* clip */
347         const rcti clip = {
348             max_ii(xmin, 0), min_ii(xmax, vc->ar->winx - 1),
349             max_ii(ymin, 0), min_ii(ymax, vc->ar->winy - 1)};
350         const int size_clip[2] = {
351             BLI_rcti_size_x(&clip) + 1,
352             BLI_rcti_size_y(&clip) + 1};
353
354         if (UNLIKELY((clip.xmin > clip.xmax) ||
355                      (clip.ymin > clip.ymax)))
356         {
357                 return NULL;
358         }
359
360         ImBuf *ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect);
361
362         ED_view3d_backbuf_validate(vc);
363
364         view3d_opengl_read_pixels(vc->ar, clip.xmin, clip.ymin, size_clip[0], size_clip[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf_clip->rect);
365
366         glReadBuffer(GL_BACK);
367
368         if (ENDIAN_ORDER == B_ENDIAN) {
369                 IMB_convert_rgba_to_abgr(ibuf_clip);
370         }
371
372         GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
373
374         if ((clip.xmin == xmin) &&
375             (clip.xmax == xmax) &&
376             (clip.ymin == ymin) &&
377             (clip.ymax == ymax))
378         {
379                 return ibuf_clip;
380         }
381         else {
382                 /* put clipped result into a non-clipped buffer */
383                 const int size[2] = {
384                     (xmax - xmin + 1),
385                     (ymax - ymin + 1)};
386
387                 ImBuf *ibuf_full = IMB_allocImBuf(size[0], size[1], 32, IB_rect);
388
389                 IMB_rectcpy(
390                         ibuf_full, ibuf_clip,
391                         clip.xmin - xmin, clip.ymin - ymin,
392                         0, 0,
393                         size_clip[0], size_clip[1]);
394                 IMB_freeImBuf(ibuf_clip);
395                 return ibuf_full;
396         }
397 }
398
399 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
400 unsigned int ED_view3d_backbuf_sample_rect(
401         ViewContext *vc, const int mval[2], int size,
402         unsigned int min, unsigned int max, float *r_dist)
403 {
404         int dirvec[4][2];
405
406         const int amount = (size - 1) / 2;
407
408         const int minx = mval[0] - (amount + 1);
409         const int miny = mval[1] - (amount + 1);
410         ImBuf *buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1);
411         if (!buf) return 0;
412
413         unsigned index = 0;
414         int rc = 0;
415
416         dirvec[0][0] = 1; dirvec[0][1] = 0;
417         dirvec[1][0] = 0; dirvec[1][1] = -size;
418         dirvec[2][0] = -1; dirvec[2][1] = 0;
419         dirvec[3][0] = 0; dirvec[3][1] = size;
420
421         const unsigned *bufmin = buf->rect;
422         const unsigned *tbuf = buf->rect;
423         const unsigned *bufmax = buf->rect + size * size;
424         tbuf += amount * size + amount;
425
426         for (int nr = 1; nr <= size; nr++) {
427                 for (int a = 0; a < 2; a++) {
428                         for (int b = 0; b < nr; b++) {
429                                 if (*tbuf && *tbuf >= min && *tbuf < max) {
430                                         /* we got a hit */
431
432                                         /* get x,y pixel coords from the offset
433                                          * (manhatten distance in keeping with other screen-based selection) */
434                                         *r_dist = (float)(
435                                                 abs(((int)(tbuf - buf->rect) % size) - (size / 2)) +
436                                                 abs(((int)(tbuf - buf->rect) / size) - (size / 2)));
437
438                                         /* indices start at 1 here */
439                                         index = (*tbuf - min) + 1;
440                                         goto exit;
441                                 }
442
443                                 tbuf += (dirvec[rc][0] + dirvec[rc][1]);
444
445                                 if (tbuf < bufmin || tbuf >= bufmax) {
446                                         goto exit;
447                                 }
448                         }
449                         rc++;
450                         rc &= 3;
451                 }
452         }
453
454 exit:
455         IMB_freeImBuf(buf);
456         return index;
457 }
458
459
460 /* ************************************************************* */
461
462 static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
463 {
464         if (BKE_image_is_stereo(ima)) {
465                 iuser->flag |= IMA_SHOW_STEREO;
466
467                 if ((scene->r.scemode & R_MULTIVIEW) == 0) {
468                         iuser->multiview_eye = STEREO_LEFT_ID;
469                 }
470                 else if (v3d->stereo3d_camera != STEREO_3D_ID) {
471                         /* show only left or right camera */
472                         iuser->multiview_eye = v3d->stereo3d_camera;
473                 }
474
475                 BKE_image_multiview_index(ima, iuser);
476         }
477         else {
478                 iuser->flag &= ~IMA_SHOW_STEREO;
479         }
480 }
481
482 static void view3d_draw_bgpic(Scene *scene, Depsgraph *depsgraph,
483                               ARegion *ar, View3D *v3d,
484                               const bool do_foreground, const bool do_camera_frame)
485 {
486         RegionView3D *rv3d = ar->regiondata;
487         int fg_flag = do_foreground ? CAM_BGIMG_FLAG_FOREGROUND : 0;
488         if (v3d->camera == NULL || v3d->camera->type != OB_CAMERA) {
489                 return;
490         }
491         Camera *cam = v3d->camera->data;
492
493         for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
494                 bgpic->iuser.scene = scene;  /* Needed for render results. */
495
496                 if ((bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != fg_flag)
497                         continue;
498
499                 {
500                         float image_aspect[2];
501                         float x1, y1, x2, y2, centx, centy;
502
503                         void *lock;
504
505                         Image *ima = NULL;
506
507                         /* disable individual images */
508                         if ((bgpic->flag & CAM_BGIMG_FLAG_DISABLED))
509                                 continue;
510
511                         ImBuf *ibuf = NULL;
512                         ImBuf *freeibuf = NULL;
513                         ImBuf *releaseibuf = NULL;
514                         if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
515                                 ima = bgpic->ima;
516                                 if (ima == NULL)
517                                         continue;
518                                 BKE_image_user_frame_calc(&bgpic->iuser, (int)DEG_get_ctime(depsgraph));
519                                 if (ima->source == IMA_SRC_SEQUENCE && !(bgpic->iuser.flag & IMA_USER_FRAME_IN_RANGE)) {
520                                         ibuf = NULL; /* frame is out of range, dont show */
521                                 }
522                                 else {
523                                         view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser);
524                                         ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock);
525                                         releaseibuf = ibuf;
526                                 }
527
528                                 image_aspect[0] = ima->aspx;
529                                 image_aspect[1] = ima->aspy;
530                         }
531                         else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
532                                 /* TODO: skip drawing when out of frame range (as image sequences do above) */
533                                 MovieClip *clip = NULL;
534
535                                 if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) {
536                                         if (scene->camera)
537                                                 clip = BKE_object_movieclip_get(scene, scene->camera, true);
538                                 }
539                                 else {
540                                         clip = bgpic->clip;
541                                 }
542
543                                 if (clip == NULL)
544                                         continue;
545
546                                 BKE_movieclip_user_set_frame(&bgpic->cuser, (int)DEG_get_ctime(depsgraph));
547                                 ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser);
548
549                                 image_aspect[0] = clip->aspx;
550                                 image_aspect[1] = clip->aspy;
551
552                                 /* working with ibuf from image and clip has got different workflow now.
553                                  * ibuf acquired from clip is referenced by cache system and should
554                                  * be dereferenced after usage. */
555                                 freeibuf = ibuf;
556                         }
557                         else {
558                                 /* perhaps when loading future files... */
559                                 BLI_assert(0);
560                                 copy_v2_fl(image_aspect, 1.0f);
561                         }
562
563                         if (ibuf == NULL)
564                                 continue;
565
566                         if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */
567                                 if (freeibuf)
568                                         IMB_freeImBuf(freeibuf);
569                                 if (releaseibuf)
570                                         BKE_image_release_ibuf(ima, releaseibuf, lock);
571
572                                 continue;
573                         }
574
575                         if (ibuf->rect == NULL)
576                                 IMB_rect_from_float(ibuf);
577
578                         BLI_assert(rv3d->persp == RV3D_CAMOB);
579                         {
580                                 if (do_camera_frame) {
581                                         rctf vb;
582                                         ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false);
583                                         x1 = vb.xmin;
584                                         y1 = vb.ymin;
585                                         x2 = vb.xmax;
586                                         y2 = vb.ymax;
587                                 }
588                                 else {
589                                         x1 = ar->winrct.xmin;
590                                         y1 = ar->winrct.ymin;
591                                         x2 = ar->winrct.xmax;
592                                         y2 = ar->winrct.ymax;
593                                 }
594
595                                 /* apply offset last - camera offset is different to offset in blender units */
596                                 /* so this has some sane way of working - this matches camera's shift _exactly_ */
597                                 {
598                                         const float max_dim = max_ff(x2 - x1, y2 - y1);
599                                         const float xof_scale = bgpic->offset[0] * max_dim;
600                                         const float yof_scale = bgpic->offset[1] * max_dim;
601
602                                         x1 += xof_scale;
603                                         y1 += yof_scale;
604                                         x2 += xof_scale;
605                                         y2 += yof_scale;
606                                 }
607
608                                 centx = (x1 + x2) * 0.5f;
609                                 centy = (y1 + y2) * 0.5f;
610
611                                 /* aspect correction */
612                                 if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
613                                         /* apply aspect from clip */
614                                         const float w_src = ibuf->x * image_aspect[0];
615                                         const float h_src = ibuf->y * image_aspect[1];
616
617                                         /* destination aspect is already applied from the camera frame */
618                                         const float w_dst = x1 - x2;
619                                         const float h_dst = y1 - y2;
620
621                                         const float asp_src = w_src / h_src;
622                                         const float asp_dst = w_dst / h_dst;
623
624                                         if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
625                                                 if ((asp_src > asp_dst) == ((bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) != 0)) {
626                                                         /* fit X */
627                                                         const float div = asp_src / asp_dst;
628                                                         x1 = ((x1 - centx) * div) + centx;
629                                                         x2 = ((x2 - centx) * div) + centx;
630                                                 }
631                                                 else {
632                                                         /* fit Y */
633                                                         const float div = asp_dst / asp_src;
634                                                         y1 = ((y1 - centy) * div) + centy;
635                                                         y2 = ((y2 - centy) * div) + centy;
636                                                 }
637                                         }
638                                 }
639                         }
640
641                         /* complete clip? */
642                         rctf clip_rect;
643                         BLI_rctf_init(&clip_rect, x1, x2, y1, y2);
644                         if (bgpic->rotation) {
645                                 BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation);
646                         }
647
648                         if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) {
649                                 if (freeibuf)
650                                         IMB_freeImBuf(freeibuf);
651                                 if (releaseibuf)
652                                         BKE_image_release_ibuf(ima, releaseibuf, lock);
653
654                                 continue;
655                         }
656
657                         float zoomx = (x2 - x1) / ibuf->x;
658                         float zoomy = (y2 - y1) / ibuf->y;
659
660                         /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */
661                         if (zoomx < 1.0f || zoomy < 1.0f) {
662                                 float tzoom = min_ff(zoomx, zoomy);
663                                 int mip = 0;
664
665                                 if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) {
666                                         IMB_remakemipmap(ibuf, 0);
667                                         ibuf->userflags &= ~IB_MIPMAP_INVALID;
668                                 }
669                                 else if (ibuf->mipmap[0] == NULL)
670                                         IMB_makemipmap(ibuf, 0);
671
672                                 while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) {
673                                         tzoom *= 2.0f;
674                                         zoomx *= 2.0f;
675                                         zoomy *= 2.0f;
676                                         mip++;
677                                 }
678                                 if (mip > 0)
679                                         ibuf = ibuf->mipmap[mip - 1];
680                         }
681
682                         GPU_depth_test(!do_foreground);
683                         glDepthMask(GL_FALSE);
684
685                         GPU_blend(true);
686                         GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
687
688                         GPU_matrix_push_projection();
689                         GPU_matrix_push();
690                         ED_region_pixelspace(ar);
691
692                         GPU_matrix_translate_2f(centx, centy);
693                         GPU_matrix_scale_1f(bgpic->scale);
694                         GPU_matrix_rotate_2d(RAD2DEGF(-bgpic->rotation));
695
696                         if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) {
697                                 zoomx *= -1.0f;
698                                 x1 = x2;
699                         }
700                         if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) {
701                                 zoomy *= -1.0f;
702                                 y1 = y2;
703                         }
704
705                         float col[4] = {1.0f, 1.0f, 1.0f, bgpic->alpha};
706                         IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
707                         immDrawPixelsTex(&state, x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect,
708                                          zoomx, zoomy, col);
709
710                         GPU_matrix_pop_projection();
711                         GPU_matrix_pop();
712
713                         GPU_blend(false);
714
715                         glDepthMask(GL_TRUE);
716                         GPU_depth_test(true);
717
718                         if (freeibuf)
719                                 IMB_freeImBuf(freeibuf);
720                         if (releaseibuf)
721                                 BKE_image_release_ibuf(ima, releaseibuf, lock);
722                 }
723         }
724 }
725
726 void ED_view3d_draw_bgpic_test(
727         Scene *scene, Depsgraph *depsgraph,
728         ARegion *ar, View3D *v3d,
729         const bool do_foreground, const bool do_camera_frame)
730 {
731         RegionView3D *rv3d = ar->regiondata;
732
733         if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) {
734                 Camera *cam = v3d->camera->data;
735                 if ((cam->flag & CAM_SHOW_BG_IMAGE) == 0) {
736                         return;
737                 }
738         }
739         else {
740                 return;
741         }
742
743         /* disabled - mango request, since footage /w only render is quite useful
744          * and this option is easy to disable all background images at once */
745 #if 0
746         if (v3d->flag2 & V3D_RENDER_OVERRIDE)
747                 return;
748 #endif
749
750         if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) {
751                 if (rv3d->persp == RV3D_CAMOB) {
752                         view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame);
753                 }
754         }
755         else {
756                 view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame);
757         }
758 }
759
760 /* *********************** */
761
762 /* XXX warning, not using gpu offscreen here */
763 void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect)
764 {
765         /* clamp rect by region */
766         rcti r = {
767                 .xmin = 0,
768                 .xmax = ar->winx - 1,
769                 .ymin = 0,
770                 .ymax = ar->winy - 1
771         };
772
773         /* Constrain rect to depth bounds */
774         BLI_rcti_isect(&r, rect, rect);
775
776         /* assign values to compare with the ViewDepths */
777         int x = rect->xmin;
778         int y = rect->ymin;
779
780         int w = BLI_rcti_size_x(rect);
781         int h = BLI_rcti_size_y(rect);
782
783         if (w <= 0 || h <= 0) {
784                 if (d->depths)
785                         MEM_freeN(d->depths);
786                 d->depths = NULL;
787
788                 d->damaged = false;
789         }
790         else if (d->w != w ||
791                  d->h != h ||
792                  d->x != x ||
793                  d->y != y ||
794                  d->depths == NULL
795                  )
796         {
797                 d->x = x;
798                 d->y = y;
799                 d->w = w;
800                 d->h = h;
801
802                 if (d->depths)
803                         MEM_freeN(d->depths);
804
805                 d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset");
806
807                 d->damaged = true;
808         }
809
810         if (d->damaged) {
811                 /* XXX using special function here, it doesn't use the gpu offscreen system */
812                 view3d_opengl_read_Z_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
813                 glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
814                 d->damaged = false;
815         }
816 }
817
818 /* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */
819 void ED_view3d_depth_update(ARegion *ar)
820 {
821         RegionView3D *rv3d = ar->regiondata;
822
823         /* Create storage for, and, if necessary, copy depth buffer */
824         if (!rv3d->depths) rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths");
825         if (rv3d->depths) {
826                 ViewDepths *d = rv3d->depths;
827                 if (d->w != ar->winx ||
828                     d->h != ar->winy ||
829                     !d->depths)
830                 {
831                         d->w = ar->winx;
832                         d->h = ar->winy;
833                         if (d->depths)
834                                 MEM_freeN(d->depths);
835                         d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths");
836                         d->damaged = true;
837                 }
838
839                 if (d->damaged) {
840                         view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
841                         glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
842
843                         d->damaged = false;
844                 }
845         }
846 }
847
848 /* utility function to find the closest Z value, use for autodepth */
849 float view3d_depth_near(ViewDepths *d)
850 {
851         /* convert to float for comparisons */
852         const float near = (float)d->depth_range[0];
853         const float far_real = (float)d->depth_range[1];
854         float far = far_real;
855
856         const float *depths = d->depths;
857         float depth = FLT_MAX;
858         int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */
859
860         /* far is both the starting 'far' value
861          * and the closest value found. */
862         while (i--) {
863                 depth = *depths++;
864                 if ((depth < far) && (depth > near)) {
865                         far = depth;
866                 }
867         }
868
869         return far == far_real ? FLT_MAX : far;
870 }
871
872 void ED_view3d_draw_depth_gpencil(
873         Depsgraph *depsgraph, Scene *scene, ARegion *ar, View3D *v3d)
874 {
875         ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
876
877         /* Setup view matrix. */
878         ED_view3d_draw_setup_view(NULL, depsgraph, scene, ar, v3d, NULL, NULL, NULL);
879
880         GPU_clear(GPU_DEPTH_BIT);
881
882         GPU_depth_test(true);
883
884         ED_gpencil_draw_view3d(NULL, scene, view_layer, depsgraph, v3d, ar, true);
885
886         GPU_depth_test(false);
887 }
888
889 /* *********************** customdata **************** */
890
891 CustomDataMask ED_view3d_datamask(const Scene *UNUSED(scene), const View3D *v3d)
892 {
893         CustomDataMask mask = 0;
894         const int drawtype = view3d_effective_drawtype(v3d);
895
896         if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) ||
897             ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX)))
898         {
899                 mask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
900
901                 if (drawtype == OB_MATERIAL)
902                         mask |= CD_MASK_ORCO;
903         }
904
905         return mask;
906 }
907
908 /* goes over all modes and view3d settings */
909 CustomDataMask ED_view3d_screen_datamask(const Scene *scene, const bScreen *screen)
910 {
911         CustomDataMask mask = CD_MASK_BAREMESH;
912
913         /* check if we need tfaces & mcols due to view mode */
914         for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
915                 if (sa->spacetype == SPACE_VIEW3D) {
916                         mask |= ED_view3d_datamask(scene, sa->spacedata.first);
917                 }
918         }
919
920         return mask;
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         printable[0] = '\0';
977
978 #if 0
979         /* this is too simple, better do an average */
980         fps = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime))
981 #else
982         fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime));
983
984         float fps = 0.0f;
985         int tot = 0;
986         for (int i = 0; i < REDRAW_FRAME_AVERAGE; i++) {
987                 if (fpsi->redrawtimes_fps[i]) {
988                         fps += fpsi->redrawtimes_fps[i];
989                         tot++;
990                 }
991         }
992         if (tot) {
993                 fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE;
994
995                 //fpsi->redrawtime_index++;
996                 //if (fpsi->redrawtime >= REDRAW_FRAME_AVERAGE)
997                 //      fpsi->redrawtime = 0;
998
999                 fps = fps / tot;
1000         }
1001 #endif
1002
1003         const int font_id = BLF_default();
1004
1005         /* is this more than half a frame behind? */
1006         if (fps + 0.5f < (float)(FPS)) {
1007                 UI_FontThemeColor(font_id, TH_REDALERT);
1008                 BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps);
1009         }
1010         else {
1011                 UI_FontThemeColor(font_id, TH_TEXT_HI);
1012                 BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f));
1013         }
1014
1015         BLF_enable(font_id, BLF_SHADOW);
1016         BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
1017         BLF_shadow_offset(font_id, 1, -1);
1018
1019         *yoffset -= U.widget_unit;
1020
1021 #ifdef WITH_INTERNATIONAL
1022         BLF_draw_default(xoffset, *yoffset, 0.0f, printable, sizeof(printable));
1023 #else
1024         BLF_draw_default_ascii(xoffset, *yoffset, 0.0f, printable, sizeof(printable));
1025 #endif
1026
1027         BLF_disable(font_id, BLF_SHADOW);
1028 }
1029
1030 static bool view3d_main_region_do_render_draw(const Scene *scene)
1031 {
1032         RenderEngineType *type = RE_engines_find(scene->r.engine);
1033         return (type && type->view_update && type->view_draw);
1034 }
1035
1036 bool ED_view3d_calc_render_border(const Scene *scene, Depsgraph *depsgraph, View3D *v3d, ARegion *ar, rcti *rect)
1037 {
1038         RegionView3D *rv3d = ar->regiondata;
1039         bool use_border;
1040
1041         /* test if there is a 3d view rendering */
1042         if (v3d->shading.type != OB_RENDER || !view3d_main_region_do_render_draw(scene))
1043                 return false;
1044
1045         /* test if there is a border render */
1046         if (rv3d->persp == RV3D_CAMOB)
1047                 use_border = (scene->r.mode & R_BORDER) != 0;
1048         else
1049                 use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0;
1050
1051         if (!use_border)
1052                 return false;
1053
1054         /* compute border */
1055         if (rv3d->persp == RV3D_CAMOB) {
1056                 rctf viewborder;
1057                 ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false);
1058
1059                 rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder);
1060                 rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder);
1061                 rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder);
1062                 rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder);
1063         }
1064         else {
1065                 rect->xmin = v3d->render_border.xmin * ar->winx;
1066                 rect->xmax = v3d->render_border.xmax * ar->winx;
1067                 rect->ymin = v3d->render_border.ymin * ar->winy;
1068                 rect->ymax = v3d->render_border.ymax * ar->winy;
1069         }
1070
1071         BLI_rcti_translate(rect, ar->winrct.xmin, ar->winrct.ymin);
1072         BLI_rcti_isect(&ar->winrct, rect, rect);
1073
1074         return true;
1075 }