ccb53468ca9563294acb26b5f6f0dd86c2fa6ff8
[blender.git] / source / blender / editors / space_view3d / view3d_draw.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.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_customdata_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_group_types.h"
40 #include "DNA_key_types.h"
41 #include "DNA_lamp_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_world_types.h"
44
45 #include "MEM_guardedalloc.h"
46
47 #include "BLI_blenlib.h"
48 #include "BLI_math.h"
49 #include "BLI_utildefines.h"
50 #include "BLI_endian_switch.h"
51
52 #include "BKE_anim.h"
53 #include "BKE_camera.h"
54 #include "BKE_context.h"
55 #include "BKE_customdata.h"
56 #include "BKE_image.h"
57 #include "BKE_key.h"
58 #include "BKE_object.h"
59 #include "BKE_global.h"
60 #include "BKE_paint.h"
61 #include "BKE_scene.h"
62 #include "BKE_screen.h"
63 #include "BKE_unit.h"
64 #include "BKE_movieclip.h"
65
66 #include "RE_engine.h"
67 #include "RE_pipeline.h"  /* make_stars */
68
69 #include "IMB_imbuf_types.h"
70 #include "IMB_imbuf.h"
71 #include "IMB_colormanagement.h"
72
73 #include "BIF_gl.h"
74 #include "BIF_glutil.h"
75
76 #include "WM_api.h"
77
78 #include "BLF_api.h"
79 #include "BLF_translation.h"
80
81 #include "ED_armature.h"
82 #include "ED_keyframing.h"
83 #include "ED_gpencil.h"
84 #include "ED_screen.h"
85 #include "ED_space_api.h"
86 #include "ED_screen_types.h"
87 #include "ED_transform.h"
88
89 #include "UI_interface.h"
90 #include "UI_interface_icons.h"
91 #include "UI_resources.h"
92
93 #include "GPU_draw.h"
94 #include "GPU_material.h"
95 #include "GPU_extensions.h"
96
97 #include "view3d_intern.h"  /* own include */
98
99 /* handy utility for drawing shapes in the viewport for arbitrary code.
100  * could add lines and points too */
101 // #define DEBUG_DRAW
102 #ifdef DEBUG_DRAW
103 static void bl_debug_draw(void);
104 /* add these locally when using these functions for testing */
105 extern void bl_debug_draw_quad_clear(void);
106 extern void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]);
107 extern void bl_debug_draw_edge_add(const float v0[3], const float v1[3]);
108 #endif
109
110 static void star_stuff_init_func(void)
111 {
112         cpack(0xFFFFFF);
113         glPointSize(1.0);
114         glBegin(GL_POINTS);
115 }
116 static void star_stuff_vertex_func(float *i)
117 {
118         glVertex3fv(i);
119 }
120 static void star_stuff_term_func(void)
121 {
122         glEnd();
123 }
124
125 void circf(float x, float y, float rad)
126 {
127         GLUquadricObj *qobj = gluNewQuadric(); 
128         
129         gluQuadricDrawStyle(qobj, GLU_FILL); 
130         
131         glPushMatrix(); 
132         
133         glTranslatef(x, y, 0.0);
134         
135         gluDisk(qobj, 0.0,  rad, 32, 1);
136         
137         glPopMatrix(); 
138         
139         gluDeleteQuadric(qobj);
140 }
141
142 void circ(float x, float y, float rad)
143 {
144         GLUquadricObj *qobj = gluNewQuadric(); 
145         
146         gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); 
147         
148         glPushMatrix(); 
149         
150         glTranslatef(x, y, 0.0);
151         
152         gluDisk(qobj, 0.0,  rad, 32, 1);
153         
154         glPopMatrix(); 
155         
156         gluDeleteQuadric(qobj);
157 }
158
159
160 /* ********* custom clipping *********** */
161
162 static void view3d_draw_clipping(RegionView3D *rv3d)
163 {
164         BoundBox *bb = rv3d->clipbb;
165
166         if (bb) {
167                 static unsigned int clipping_index[6][4] = {
168                         {0, 1, 2, 3},
169                         {0, 4, 5, 1},
170                         {4, 7, 6, 5},
171                         {7, 3, 2, 6},
172                         {1, 5, 6, 2},
173                         {7, 4, 0, 3}
174                 };
175
176                 /* fill in zero alpha for rendering & re-projection [#31530] */
177                 unsigned char col[4];
178                 UI_GetThemeColorShade3ubv(TH_BACK, -8, col);
179                 col[3] = 0;
180                 glColor4ubv(col);
181
182                 glEnableClientState(GL_VERTEX_ARRAY);
183                 glVertexPointer(3, GL_FLOAT, 0, bb->vec);
184                 glDrawElements(GL_QUADS, sizeof(clipping_index) / sizeof(unsigned int), GL_UNSIGNED_INT, clipping_index);
185                 glDisableClientState(GL_VERTEX_ARRAY);
186
187         }
188 }
189
190 void ED_view3d_clipping_set(RegionView3D *rv3d)
191 {
192         double plane[4];
193         const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6;
194         unsigned int a;
195
196         for (a = 0; a < tot; a++) {
197                 copy_v4db_v4fl(plane, rv3d->clip[a]);
198                 glClipPlane(GL_CLIP_PLANE0 + a, plane);
199                 glEnable(GL_CLIP_PLANE0 + a);
200         }
201 }
202
203 /* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */
204 void ED_view3d_clipping_disable(void)
205 {
206         unsigned int a;
207
208         for (a = 0; a < 6; a++) {
209                 glDisable(GL_CLIP_PLANE0 + a);
210         }
211 }
212 void ED_view3d_clipping_enable(void)
213 {
214         unsigned int a;
215
216         for (a = 0; a < 6; a++) {
217                 glEnable(GL_CLIP_PLANE0 + a);
218         }
219 }
220
221 static bool view3d_clipping_test(const float co[3], float clip[6][4])
222 {
223         if (plane_point_side_v3(clip[0], co) > 0.0f)
224                 if (plane_point_side_v3(clip[1], co) > 0.0f)
225                         if (plane_point_side_v3(clip[2], co) > 0.0f)
226                                 if (plane_point_side_v3(clip[3], co) > 0.0f)
227                                         return false;
228
229         return true;
230 }
231
232 /* for 'local' ED_view3d_clipping_local must run first
233  * then all comparisons can be done in localspace */
234 bool ED_view3d_clipping_test(RegionView3D *rv3d, const float co[3], const bool is_local)
235 {
236         return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
237 }
238
239 /* ********* end custom clipping *********** */
240
241
242 static void drawgrid_draw(ARegion *ar, double wx, double wy, double x, double y, double dx)
243 {       
244         double verts[2][2];
245
246         x += (wx);
247         y += (wy);
248
249         /* set fixed 'Y' */
250         verts[0][1] = 0.0f;
251         verts[1][1] = (double)ar->winy;
252
253         /* iter over 'X' */
254         verts[0][0] = verts[1][0] = x - dx * floor(x / dx);
255         glEnableClientState(GL_VERTEX_ARRAY);
256         glVertexPointer(2, GL_DOUBLE, 0, verts);
257
258         while (verts[0][0] < ar->winx) {
259                 glDrawArrays(GL_LINES, 0, 2);
260                 verts[0][0] = verts[1][0] = verts[0][0] + dx;
261         }
262
263         /* set fixed 'X' */
264         verts[0][0] = 0.0f;
265         verts[1][0] = (double)ar->winx;
266
267         /* iter over 'Y' */
268         verts[0][1] = verts[1][1] = y - dx * floor(y / dx);
269         while (verts[0][1] < ar->winy) {
270                 glDrawArrays(GL_LINES, 0, 2);
271                 verts[0][1] = verts[1][1] = verts[0][1] + dx;
272         }
273
274         glDisableClientState(GL_VERTEX_ARRAY);
275 }
276
277 #define GRID_MIN_PX_D   6.0
278 #define GRID_MIN_PX_F 6.0f
279
280 static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit)
281 {
282         /* extern short bgpicmode; */
283         RegionView3D *rv3d = ar->regiondata;
284         double wx, wy, x, y, fw, fx, fy, dx;
285         double vec4[4];
286         unsigned char col[3], col2[3];
287
288         fx = rv3d->persmat[3][0];
289         fy = rv3d->persmat[3][1];
290         fw = rv3d->persmat[3][3];
291
292         wx = (ar->winx / 2.0); /* because of rounding errors, grid at wrong location */
293         wy = (ar->winy / 2.0);
294
295         x = (wx) * fx / fw;
296         y = (wy) * fy / fw;
297
298         vec4[0] = vec4[1] = v3d->grid;
299
300         vec4[2] = 0.0;
301         vec4[3] = 1.0;
302         mul_m4_v4d(rv3d->persmat, vec4);
303         fx = vec4[0];
304         fy = vec4[1];
305         fw = vec4[3];
306
307         dx = fabs(x - (wx) * fx / fw);
308         if (dx == 0) dx = fabs(y - (wy) * fy / fw);
309         
310         glDepthMask(0);     /* disable write in zbuffer */
311
312         /* check zoom out */
313         UI_ThemeColor(TH_GRID);
314         
315         if (unit->system) {
316                 /* Use GRID_MIN_PX * 2 for units because very very small grid
317                  * items are less useful when dealing with units */
318                 void *usys;
319                 int len, i;
320                 double dx_scalar;
321                 float blend_fac;
322
323                 bUnit_GetSystem(&usys, &len, unit->system, B_UNIT_LENGTH);
324
325                 if (usys) {
326                         i = len;
327                         while (i--) {
328                                 double scalar = bUnit_GetScaler(usys, i);
329
330                                 dx_scalar = dx * scalar / (double)unit->scale_length;
331                                 if (dx_scalar < (GRID_MIN_PX_D * 2.0))
332                                         continue;
333
334                                 /* Store the smallest drawn grid size units name so users know how big each grid cell is */
335                                 if (*grid_unit == NULL) {
336                                         *grid_unit = bUnit_GetNameDisplay(usys, i);
337                                         rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length);
338                                 }
339                                 blend_fac = 1.0f - ((GRID_MIN_PX_F * 2.0f) / (float)dx_scalar);
340
341                                 /* tweak to have the fade a bit nicer */
342                                 blend_fac = (blend_fac * blend_fac) * 2.0f;
343                                 CLAMP(blend_fac, 0.3f, 1.0f);
344
345
346                                 UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, blend_fac);
347
348                                 drawgrid_draw(ar, wx, wy, x, y, dx_scalar);
349                         }
350                 }
351         }
352         else {
353                 const double sublines    = v3d->gridsubdiv;
354                 const float  sublines_fl = v3d->gridsubdiv;
355
356                 if (dx < GRID_MIN_PX_D) {
357                         rv3d->gridview *= sublines_fl;
358                         dx *= sublines;
359
360                         if (dx < GRID_MIN_PX_D) {
361                                 rv3d->gridview *= sublines_fl;
362                                 dx *= sublines;
363
364                                 if (dx < GRID_MIN_PX_D) {
365                                         rv3d->gridview *= sublines_fl;
366                                         dx *= sublines;
367                                         if (dx < GRID_MIN_PX_D) {
368                                                 /* pass */
369                                         }
370                                         else {
371                                                 UI_ThemeColor(TH_GRID);
372                                                 drawgrid_draw(ar, wx, wy, x, y, dx);
373                                         }
374                                 }
375                                 else {  /* start blending out */
376                                         UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
377                                         drawgrid_draw(ar, wx, wy, x, y, dx);
378
379                                         UI_ThemeColor(TH_GRID);
380                                         drawgrid_draw(ar, wx, wy, x, y, sublines * dx);
381                                 }
382                         }
383                         else {  /* start blending out (GRID_MIN_PX < dx < (GRID_MIN_PX * 10)) */
384                                 UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
385                                 drawgrid_draw(ar, wx, wy, x, y, dx);
386
387                                 UI_ThemeColor(TH_GRID);
388                                 drawgrid_draw(ar, wx, wy, x, y, sublines * dx);
389                         }
390                 }
391                 else {
392                         if (dx > (GRID_MIN_PX_D * 10.0)) {  /* start blending in */
393                                 rv3d->gridview /= sublines_fl;
394                                 dx /= sublines;
395                                 if (dx > (GRID_MIN_PX_D * 10.0)) {  /* start blending in */
396                                         rv3d->gridview /= sublines_fl;
397                                         dx /= sublines;
398                                         if (dx > (GRID_MIN_PX_D * 10.0)) {
399                                                 UI_ThemeColor(TH_GRID);
400                                                 drawgrid_draw(ar, wx, wy, x, y, dx);
401                                         }
402                                         else {
403                                                 UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
404                                                 drawgrid_draw(ar, wx, wy, x, y, dx);
405                                                 UI_ThemeColor(TH_GRID);
406                                                 drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
407                                         }
408                                 }
409                                 else {
410                                         UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
411                                         drawgrid_draw(ar, wx, wy, x, y, dx);
412                                         UI_ThemeColor(TH_GRID);
413                                         drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
414                                 }
415                         }
416                         else {
417                                 UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
418                                 drawgrid_draw(ar, wx, wy, x, y, dx);
419                                 UI_ThemeColor(TH_GRID);
420                                 drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
421                         }
422                 }
423         }
424
425
426         x += (wx);
427         y += (wy);
428         UI_GetThemeColor3ubv(TH_GRID, col);
429
430         setlinestyle(0);
431         
432         /* center cross */
433         /* horizontal line */
434         if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
435                 UI_make_axis_color(col, col2, 'Y');
436         else UI_make_axis_color(col, col2, 'X');
437         glColor3ubv(col2);
438         
439         fdrawline(0.0,  y,  (float)ar->winx,  y); 
440         
441         /* vertical line */
442         if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
443                 UI_make_axis_color(col, col2, 'Y');
444         else UI_make_axis_color(col, col2, 'Z');
445         glColor3ubv(col2);
446
447         fdrawline(x, 0.0, x, (float)ar->winy); 
448
449         glDepthMask(1);  /* enable write in zbuffer */
450 }
451 #undef GRID_MIN_PX
452
453 /** could move this elsewhere, but tied into #ED_view3d_grid_scale */
454 float ED_scene_grid_scale(Scene *scene, const char **grid_unit)
455 {
456         /* apply units */
457         if (scene->unit.system) {
458                 void *usys;
459                 int len;
460
461                 bUnit_GetSystem(&usys, &len, scene->unit.system, B_UNIT_LENGTH);
462
463                 if (usys) {
464                         int i = bUnit_GetBaseUnit(usys);
465                         if (grid_unit)
466                                 *grid_unit = bUnit_GetNameDisplay(usys, i);
467                         return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length;
468                 }
469         }
470
471         return 1.0f;
472 }
473
474 float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit)
475 {
476         return v3d->grid * ED_scene_grid_scale(scene, grid_unit);
477 }
478
479 static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit)
480 {
481         float grid, grid_scale;
482         unsigned char col_grid[3];
483         const int gridlines = v3d->gridlines / 2;
484
485         if (v3d->gridlines < 3) return;
486         
487         /* use 'grid_scale' instead of 'v3d->grid' from now on */
488         grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit);
489         grid = gridlines * grid_scale;
490
491         if (v3d->zbuf && scene->obedit)
492                 glDepthMask(0);  /* for zbuffer-select */
493
494         UI_GetThemeColor3ubv(TH_GRID, col_grid);
495
496         /* draw the Y axis and/or grid lines */
497         if (v3d->gridflag & V3D_SHOW_FLOOR) {
498                 const int sublines = v3d->gridsubdiv;
499                 float vert[4][3] = {{0.0f}};
500                 unsigned char col_bg[3];
501                 unsigned char col_grid_emphasise[3], col_grid_light[3];
502                 int a;
503                 int prev_emphasise = -1;
504
505                 UI_GetThemeColor3ubv(TH_BACK, col_bg);
506
507                 /* emphasise division lines lighter instead of darker, if background is darker than grid */
508                 UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10);
509                 UI_GetColorPtrShade3ubv(col_grid, col_grid_emphasise,
510                                         (((col_grid[0] + col_grid[1] + col_grid[2]) + 30) >
511                                          (col_bg[0] + col_bg[1] + col_bg[2])) ? 20 : -10);
512
513                 /* set fixed axis */
514                 vert[0][0] = vert[2][1] = grid;
515                 vert[1][0] = vert[3][1] = -grid;
516
517                 glEnableClientState(GL_VERTEX_ARRAY);
518                 glVertexPointer(3, GL_FLOAT, 0, vert);
519
520                 for (a = -gridlines; a <= gridlines; a++) {
521                         const float line = a * grid_scale;
522                         const int is_emphasise = (a % sublines) == 0;
523
524                         if (is_emphasise != prev_emphasise) {
525                                 glColor3ubv(is_emphasise ? col_grid_emphasise : col_grid_light);
526                                 prev_emphasise = is_emphasise;
527                         }
528
529                         /* set variable axis */
530                         vert[0][1] = vert[1][1] = vert[2][0] = vert[3][0] = line;
531
532                         glDrawArrays(GL_LINES, 0, 4);
533                 }
534
535                 glDisableClientState(GL_VERTEX_ARRAY);
536         }
537         
538         /* draw the Z axis line */
539         /* check for the 'show Z axis' preference */
540         if (v3d->gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) {
541                 int axis;
542                 for (axis = 0; axis < 3; axis++) {
543                         if (v3d->gridflag & (V3D_SHOW_X << axis)) {
544                                 float vert[3];
545                                 unsigned char tcol[3];
546
547                                 UI_make_axis_color(col_grid, tcol, 'X' + axis);
548                                 glColor3ubv(tcol);
549
550                                 glBegin(GL_LINE_STRIP);
551                                 zero_v3(vert);
552                                 vert[axis] = grid;
553                                 glVertex3fv(vert);
554                                 vert[axis] = -grid;
555                                 glVertex3fv(vert);
556                                 glEnd();
557                         }
558                 }
559         }
560         
561         if (v3d->zbuf && scene->obedit) glDepthMask(1);
562 }
563
564
565 static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d)
566 {
567         int co[2];
568
569         /* we don't want the clipping for cursor */
570         if (ED_view3d_project_int_global(ar, give_cursor(scene, v3d), co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
571                 const float f5 = 0.25f * U.widget_unit;
572                 const float f10 = 0.5f * U.widget_unit;
573                 const float f20 = U.widget_unit;
574                 
575                 setlinestyle(0); 
576                 cpack(0xFF);
577                 circ((float)co[0], (float)co[1], f10);
578                 setlinestyle(4);
579                 cpack(0xFFFFFF);
580                 circ((float)co[0], (float)co[1], f10);
581                 setlinestyle(0);
582                 cpack(0x0);
583                 
584                 sdrawline(co[0] - f20, co[1], co[0] - f5, co[1]);
585                 sdrawline(co[0] + f5, co[1], co[0] + f20, co[1]);
586                 sdrawline(co[0], co[1] - f20, co[0], co[1] - f5);
587                 sdrawline(co[0], co[1] + f5, co[0], co[1] + f20);
588         }
589 }
590
591 /* Draw a live substitute of the view icon, which is always shown
592  * colors copied from transform_manipulator.c, we should keep these matching. */
593 static void draw_view_axis(RegionView3D *rv3d, rcti *rect)
594 {
595         const float k = U.rvisize * U.pixelsize;   /* axis size */
596         const float toll = 0.5;      /* used to see when view is quasi-orthogonal */
597         float startx = k + 1.0f; /* axis center in screen coordinates, x=y */
598         float starty = k + 1.0f;
599         float ydisp = 0.0;          /* vertical displacement to allow obj info text */
600         int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */
601         float vec[3];
602         float dx, dy;
603         
604         startx += rect->xmin;
605         starty += rect->ymin;
606         
607         /* thickness of lines is proportional to k */
608         glLineWidth(2);
609
610         glEnable(GL_BLEND);
611         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
612
613         /* X */
614         vec[0] = 1;
615         vec[1] = vec[2] = 0;
616         mul_qt_v3(rv3d->viewquat, vec);
617         dx = vec[0] * k;
618         dy = vec[1] * k;
619         
620         UI_ThemeColorShadeAlpha(TH_AXIS_X, 0, bright);
621         glBegin(GL_LINES);
622         glVertex2f(startx, starty + ydisp);
623         glVertex2f(startx + dx, starty + dy + ydisp);
624         glEnd();
625
626         if (fabsf(dx) > toll || fabsf(dy) > toll) {
627                 BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, "x", 1);
628         }
629         
630         /* BLF_draw_default disables blending */
631         glEnable(GL_BLEND);
632
633         /* Y */
634         vec[1] = 1;
635         vec[0] = vec[2] = 0;
636         mul_qt_v3(rv3d->viewquat, vec);
637         dx = vec[0] * k;
638         dy = vec[1] * k;
639         
640         UI_ThemeColorShadeAlpha(TH_AXIS_Y, 0, bright);
641         glBegin(GL_LINES);
642         glVertex2f(startx, starty + ydisp);
643         glVertex2f(startx + dx, starty + dy + ydisp);
644         glEnd();
645
646         if (fabsf(dx) > toll || fabsf(dy) > toll) {
647                 BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, "y", 1);
648         }
649
650         glEnable(GL_BLEND);
651         
652         /* Z */
653         vec[2] = 1;
654         vec[1] = vec[0] = 0;
655         mul_qt_v3(rv3d->viewquat, vec);
656         dx = vec[0] * k;
657         dy = vec[1] * k;
658
659         UI_ThemeColorShadeAlpha(TH_AXIS_Z, 0, bright);
660         glBegin(GL_LINES);
661         glVertex2f(startx, starty + ydisp);
662         glVertex2f(startx + dx, starty + dy + ydisp);
663         glEnd();
664
665         if (fabsf(dx) > toll || fabsf(dy) > toll) {
666                 BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, "z", 1);
667         }
668
669         /* restore line-width */
670         
671         glLineWidth(1.0);
672         glDisable(GL_BLEND);
673 }
674
675 /* draw center and axis of rotation for ongoing 3D mouse navigation */
676 static void draw_rotation_guide(RegionView3D *rv3d)
677 {
678         float o[3];    /* center of rotation */
679         float end[3];  /* endpoints for drawing */
680
681         float color[4] = {0.0f, 0.4235f, 1.0f, 1.0f};  /* bright blue so it matches device LEDs */
682
683         negate_v3_v3(o, rv3d->ofs);
684
685         glEnable(GL_BLEND);
686         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
687         glShadeModel(GL_SMOOTH);
688         glPointSize(5);
689         glEnable(GL_POINT_SMOOTH);
690         glDepthMask(0);  /* don't overwrite zbuf */
691
692         if (rv3d->rot_angle != 0.f) {
693                 /* -- draw rotation axis -- */
694                 float scaled_axis[3];
695                 const float scale = rv3d->dist;
696                 mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale);
697
698
699                 glBegin(GL_LINE_STRIP);
700                 color[3] = 0.f;  /* more transparent toward the ends */
701                 glColor4fv(color);
702                 add_v3_v3v3(end, o, scaled_axis);
703                 glVertex3fv(end);
704
705                 // color[3] = 0.2f + fabsf(rv3d->rot_angle);  /* modulate opacity with angle */
706                 // ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2
707
708                 color[3] = 0.5f;  /* more opaque toward the center */
709                 glColor4fv(color);
710                 glVertex3fv(o);
711
712                 color[3] = 0.f;
713                 glColor4fv(color);
714                 sub_v3_v3v3(end, o, scaled_axis);
715                 glVertex3fv(end);
716                 glEnd();
717                 
718                 /* -- draw ring around rotation center -- */
719                 {
720 #define     ROT_AXIS_DETAIL 13
721
722                         const float s = 0.05f * scale;
723                         const float step = 2.f * (float)(M_PI / ROT_AXIS_DETAIL);
724                         float angle;
725                         int i;
726
727                         float q[4];  /* rotate ring so it's perpendicular to axis */
728                         const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f;
729                         if (!upright) {
730                                 const float up[3] = {0.f, 0.f, 1.f};
731                                 float vis_angle, vis_axis[3];
732
733                                 cross_v3_v3v3(vis_axis, up, rv3d->rot_axis);
734                                 vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis));
735                                 axis_angle_to_quat(q, vis_axis, vis_angle);
736                         }
737
738                         color[3] = 0.25f;  /* somewhat faint */
739                         glColor4fv(color);
740                         glBegin(GL_LINE_LOOP);
741                         for (i = 0, angle = 0.f; i < ROT_AXIS_DETAIL; ++i, angle += step) {
742                                 float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f};
743
744                                 if (!upright) {
745                                         mul_qt_v3(q, p);
746                                 }
747
748                                 add_v3_v3(p, o);
749                                 glVertex3fv(p);
750                         }
751                         glEnd();
752
753 #undef      ROT_AXIS_DETAIL
754                 }
755
756                 color[3] = 1.0f;  /* solid dot */
757         }
758         else
759                 color[3] = 0.5f;  /* see-through dot */
760
761         /* -- draw rotation center -- */
762         glColor4fv(color);
763         glBegin(GL_POINTS);
764         glVertex3fv(o);
765         glEnd();
766
767         /* find screen coordinates for rotation center, then draw pretty icon */
768 #if 0
769         mul_m4_v3(rv3d->persinv, rot_center);
770         UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN);
771 #endif
772         /* ^^ just playing around, does not work */
773
774         glDisable(GL_BLEND);
775         glDisable(GL_POINT_SMOOTH);
776         glDepthMask(1);
777 }
778
779 static void draw_view_icon(RegionView3D *rv3d, rcti *rect)
780 {
781         BIFIconID icon;
782         
783         if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
784                 icon = ICON_AXIS_TOP;
785         else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
786                 icon = ICON_AXIS_FRONT;
787         else if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
788                 icon = ICON_AXIS_SIDE;
789         else return;
790         
791         glEnable(GL_BLEND);
792         glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA); 
793         
794         UI_icon_draw(5.0 + rect->xmin, 5.0 + rect->ymin, icon);
795         
796         glDisable(GL_BLEND);
797 }
798
799 static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d)
800 {
801         const char *name = NULL;
802         
803         switch (rv3d->view) {
804                 case RV3D_VIEW_FRONT:
805                         if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Front Ortho");
806                         else name = IFACE_("Front Persp");
807                         break;
808                 case RV3D_VIEW_BACK:
809                         if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Back Ortho");
810                         else name = IFACE_("Back Persp");
811                         break;
812                 case RV3D_VIEW_TOP:
813                         if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Top Ortho");
814                         else name = IFACE_("Top Persp");
815                         break;
816                 case RV3D_VIEW_BOTTOM:
817                         if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Bottom Ortho");
818                         else name = IFACE_("Bottom Persp");
819                         break;
820                 case RV3D_VIEW_RIGHT:
821                         if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Right Ortho");
822                         else name = IFACE_("Right Persp");
823                         break;
824                 case RV3D_VIEW_LEFT:
825                         if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Left Ortho");
826                         else name = IFACE_("Left Persp");
827                         break;
828                         
829                 default:
830                         if (rv3d->persp == RV3D_CAMOB) {
831                                 if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) {
832                                         Camera *cam;
833                                         cam = v3d->camera->data;
834                                         name = (cam->type != CAM_ORTHO) ? IFACE_("Camera Persp") : IFACE_("Camera Ortho");
835                                 }
836                                 else {
837                                         name = IFACE_("Object as Camera");
838                                 }
839                         }
840                         else {
841                                 name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Ortho") : IFACE_("User Persp");
842                         }
843                         break;
844         }
845         
846         return name;
847 }
848
849 static void draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect)
850 {
851         RegionView3D *rv3d = ar->regiondata;
852         const char *name = view3d_get_name(v3d, rv3d);
853         /* XXX 24 may be a bit small for unicode languages (Chinese in utf-8...) */
854 #ifdef WITH_INTERNATIONAL
855         char tmpstr[64];
856 #else
857         char tmpstr[24];
858 #endif
859
860         if (v3d->localvd) {
861                 BLI_snprintf(tmpstr, sizeof(tmpstr), IFACE_("%s (Local)"), name);
862                 name = tmpstr;
863         }
864
865         UI_ThemeColor(TH_TEXT_HI);
866 #ifdef WITH_INTERNATIONAL
867         BLF_draw_default(U.widget_unit + rect->xmin,  rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr));
868 #else
869         BLF_draw_default_ascii(U.widget_unit + rect->xmin,  rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr));
870 #endif
871 }
872
873 /* draw info beside axes in bottom left-corner: 
874  * framenum, object name, bone name (if available), marker name (if available)
875  */
876
877 static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
878 {
879         const int cfra = CFRA;
880         const char *msg_pin = " (Pinned)";
881         const char *msg_sep = " : ";
882
883         char info[300];
884         char *markern;
885         char *s = info;
886         short offset = 1.5f * UI_UNIT_X + rect->xmin;
887
888         s += sprintf(s, "(%d)", cfra);
889
890         /* 
891          * info can contain:
892          * - a frame (7 + 2)
893          * - 3 object names (MAX_NAME)
894          * - 2 BREAD_CRUMB_SEPARATORs (6)
895          * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room!
896          * - a marker name (MAX_NAME + 3)
897          */
898
899         /* get name of marker on current frame (if available) */
900         markern = BKE_scene_find_marker_name(scene, cfra);
901         
902         /* check if there is an object */
903         if (ob) {
904                 *s++ = ' ';
905                 s += BLI_strcpy_rlen(s, ob->id.name + 2);
906
907                 /* name(s) to display depends on type of object */
908                 if (ob->type == OB_ARMATURE) {
909                         bArmature *arm = ob->data;
910                         
911                         /* show name of active bone too (if possible) */
912                         if (arm->edbo) {
913                                 if (arm->act_edbone) {
914                                         s += BLI_strcpy_rlen(s, msg_sep);
915                                         s += BLI_strcpy_rlen(s, arm->act_edbone->name);
916                                 }
917                         }
918                         else if (ob->mode & OB_MODE_POSE) {
919                                 if (arm->act_bone) {
920
921                                         if (arm->act_bone->layer & arm->layer) {
922                                                 s += BLI_strcpy_rlen(s, msg_sep);
923                                                 s += BLI_strcpy_rlen(s, arm->act_bone->name);
924                                         }
925                                 }
926                         }
927                 }
928                 else if (ELEM3(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) {
929                         Key *key = NULL;
930                         KeyBlock *kb = NULL;
931
932                         /* try to display active bone and active shapekey too (if they exist) */
933
934                         if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) {
935                                 Object *armobj = BKE_object_pose_armature_get(ob);
936                                 if (armobj  && armobj->mode & OB_MODE_POSE) {
937                                         bArmature *arm = armobj->data;
938                                         if (arm->act_bone) {
939                                                 if (arm->act_bone->layer & arm->layer) {
940                                                         s += BLI_strcpy_rlen(s, msg_sep);
941                                                         s += BLI_strcpy_rlen(s, arm->act_bone->name);
942                                                 }
943                                         }
944                                 }
945                         }
946
947                         key = BKE_key_from_object(ob);
948                         if (key) {
949                                 kb = BLI_findlink(&key->block, ob->shapenr - 1);
950                                 if (kb) {
951                                         s += BLI_strcpy_rlen(s, msg_sep);
952                                         s += BLI_strcpy_rlen(s, kb->name);
953                                         if (ob->shapeflag & OB_SHAPE_LOCK) {
954                                                 s += BLI_strcpy_rlen(s, IFACE_(msg_pin));
955                                         }
956                                 }
957                         }
958                 }
959                 
960                 /* color depends on whether there is a keyframe */
961                 if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL))
962                         UI_ThemeColor(TH_VERTEX_SELECT);
963                 else
964                         UI_ThemeColor(TH_TEXT_HI);
965         }
966         else {
967                 /* no object */         
968                 /* color is always white */
969                 UI_ThemeColor(TH_TEXT_HI);
970         }
971
972         if (markern) {
973                 s += sprintf(s, " <%s>", markern);
974         }
975         
976         if (U.uiflag & USER_SHOW_ROTVIEWICON)
977                 offset = U.widget_unit + (U.rvisize * 2) + rect->xmin;
978
979         BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info));
980 }
981
982 static void view3d_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d,
983                                  rctf *r_viewborder, const bool no_shift, const bool no_zoom)
984 {
985         CameraParams params;
986         rctf rect_view, rect_camera;
987
988         /* get viewport viewplane */
989         BKE_camera_params_init(&params);
990         BKE_camera_params_from_view3d(&params, v3d, rv3d);
991         if (no_zoom)
992                 params.zoom = 1.0f;
993         BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, 1.0f, 1.0f);
994         rect_view = params.viewplane;
995
996         /* get camera viewplane */
997         BKE_camera_params_init(&params);
998         BKE_camera_params_from_object(&params, v3d->camera);
999         if (no_shift) {
1000                 params.shiftx = 0.0f;
1001                 params.shifty = 0.0f;
1002         }
1003         BKE_camera_params_compute_viewplane(&params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp);
1004         rect_camera = params.viewplane;
1005
1006         /* get camera border within viewport */
1007         r_viewborder->xmin = ((rect_camera.xmin - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx;
1008         r_viewborder->xmax = ((rect_camera.xmax - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx;
1009         r_viewborder->ymin = ((rect_camera.ymin - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy;
1010         r_viewborder->ymax = ((rect_camera.ymax - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy;
1011 }
1012
1013 void ED_view3d_calc_camera_border_size(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, float r_size[2])
1014 {
1015         rctf viewborder;
1016
1017         view3d_camera_border(scene, ar, v3d, rv3d, &viewborder, true, true);
1018         r_size[0] = BLI_rctf_size_x(&viewborder);
1019         r_size[1] = BLI_rctf_size_y(&viewborder);
1020 }
1021
1022 void ED_view3d_calc_camera_border(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d,
1023                                   rctf *r_viewborder, const bool no_shift)
1024 {
1025         view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false);
1026 }
1027
1028 static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float fac)
1029 {
1030         float x3, y3, x4, y4;
1031
1032         x3 = x1 + fac * (x2 - x1);
1033         y3 = y1 + fac * (y2 - y1);
1034         x4 = x1 + (1.0f - fac) * (x2 - x1);
1035         y4 = y1 + (1.0f - fac) * (y2 - y1);
1036
1037         glBegin(GL_LINES);
1038         glVertex2f(x1, y3);
1039         glVertex2f(x2, y3);
1040
1041         glVertex2f(x1, y4);
1042         glVertex2f(x2, y4);
1043
1044         glVertex2f(x3, y1);
1045         glVertex2f(x3, y2);
1046
1047         glVertex2f(x4, y1);
1048         glVertex2f(x4, y2);
1049         glEnd();
1050 }
1051
1052 /* harmonious triangle */
1053 static void drawviewborder_triangle(float x1, float x2, float y1, float y2, const char golden, const char dir)
1054 {
1055         float ofs;
1056         float w = x2 - x1;
1057         float h = y2 - y1;
1058
1059         glBegin(GL_LINES);
1060         if (w > h) {
1061                 if (golden) {
1062                         ofs = w * (1.0f - (1.0f / 1.61803399f));
1063                 }
1064                 else {
1065                         ofs = h * (h / w);
1066                 }
1067                 if (dir == 'B') SWAP(float, y1, y2);
1068
1069                 glVertex2f(x1, y1);
1070                 glVertex2f(x2, y2);
1071
1072                 glVertex2f(x2, y1);
1073                 glVertex2f(x1 + (w - ofs), y2);
1074
1075                 glVertex2f(x1, y2);
1076                 glVertex2f(x1 + ofs, y1);
1077         }
1078         else {
1079                 if (golden) {
1080                         ofs = h * (1.0f - (1.0f / 1.61803399f));
1081                 }
1082                 else {
1083                         ofs = w * (w / h);
1084                 }
1085                 if (dir == 'B') SWAP(float, x1, x2);
1086
1087                 glVertex2f(x1, y1);
1088                 glVertex2f(x2, y2);
1089
1090                 glVertex2f(x2, y1);
1091                 glVertex2f(x1, y1 + ofs);
1092
1093                 glVertex2f(x1, y2);
1094                 glVertex2f(x2, y1 + (h - ofs));
1095         }
1096         glEnd();
1097 }
1098
1099 static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
1100 {
1101         float hmargin, vmargin;
1102         float x1, x2, y1, y2;
1103         float x1i, x2i, y1i, y2i;
1104         float x3, y3, x4, y4;
1105         rctf viewborder;
1106         Camera *ca = NULL;
1107         RegionView3D *rv3d = (RegionView3D *)ar->regiondata;
1108         
1109         if (v3d->camera == NULL)
1110                 return;
1111         if (v3d->camera->type == OB_CAMERA)
1112                 ca = v3d->camera->data;
1113         
1114         ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false);
1115         /* the offsets */
1116         x1 = viewborder.xmin;
1117         y1 = viewborder.ymin;
1118         x2 = viewborder.xmax;
1119         y2 = viewborder.ymax;
1120         
1121         /* apply offsets so the real 3D camera shows through */
1122
1123         /* note: quite un-scientific but without this bit extra
1124          * 0.0001 on the lower left the 2D border sometimes
1125          * obscures the 3D camera border */
1126         /* note: with VIEW3D_CAMERA_BORDER_HACK defined this error isn't noticeable
1127          * but keep it here in case we need to remove the workaround */
1128         x1i = (int)(x1 - 1.0001f);
1129         y1i = (int)(y1 - 1.0001f);
1130         x2i = (int)(x2 + (1.0f - 0.0001f));
1131         y2i = (int)(y2 + (1.0f - 0.0001f));
1132         
1133         /* passepartout, specified in camera edit buttons */
1134         if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) {
1135                 if (ca->passepartalpha == 1.0f) {
1136                         glColor3f(0, 0, 0);
1137                 }
1138                 else {
1139                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1140                         glEnable(GL_BLEND);
1141                         glColor4f(0, 0, 0, ca->passepartalpha);
1142                 }
1143                 if (x1i > 0.0f)
1144                         glRectf(0.0, (float)ar->winy, x1i, 0.0);
1145                 if (x2i < (float)ar->winx)
1146                         glRectf(x2i, (float)ar->winy, (float)ar->winx, 0.0);
1147                 if (y2i < (float)ar->winy)
1148                         glRectf(x1i, (float)ar->winy, x2i, y2i);
1149                 if (y2i > 0.0f)
1150                         glRectf(x1i, y1i, x2i, 0.0);
1151                 
1152                 glDisable(GL_BLEND);
1153         }
1154
1155         /* edge */
1156         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1157
1158         setlinestyle(0);
1159
1160         UI_ThemeColor(TH_BACK);
1161                 
1162         glRectf(x1i, y1i, x2i, y2i);
1163
1164 #ifdef VIEW3D_CAMERA_BORDER_HACK
1165         if (view3d_camera_border_hack_test == true) {
1166                 glColor3ubv(view3d_camera_border_hack_col);
1167                 glRectf(x1i + 1, y1i + 1, x2i - 1, y2i - 1);
1168                 view3d_camera_border_hack_test = false;
1169         }
1170 #endif
1171
1172         setlinestyle(3);
1173
1174         /* outer line not to confuse with object selecton */
1175         if (v3d->flag2 & V3D_LOCK_CAMERA) {
1176                 UI_ThemeColor(TH_REDALERT);
1177                 glRectf(x1i - 1, y1i - 1, x2i + 1, y2i + 1);
1178         }
1179
1180         UI_ThemeColor(TH_WIRE);
1181         glRectf(x1i, y1i, x2i, y2i);
1182
1183         /* border */
1184         if (scene->r.mode & R_BORDER) {
1185                 cpack(0);
1186                 x3 = x1 + scene->r.border.xmin * (x2 - x1);
1187                 y3 = y1 + scene->r.border.ymin * (y2 - y1);
1188                 x4 = x1 + scene->r.border.xmax * (x2 - x1);
1189                 y4 = y1 + scene->r.border.ymax * (y2 - y1);
1190                 
1191                 cpack(0x4040FF);
1192                 glRecti(x3,  y3,  x4,  y4);
1193         }
1194
1195         /* safety border */
1196         if (ca) {
1197                 if (ca->dtx & CAM_DTX_CENTER) {
1198                         UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 0.25, 0);
1199
1200                         x3 = x1 + 0.5f * (x2 - x1);
1201                         y3 = y1 + 0.5f * (y2 - y1);
1202
1203                         glBegin(GL_LINES);
1204                         glVertex2f(x1, y3);
1205                         glVertex2f(x2, y3);
1206
1207                         glVertex2f(x3, y1);
1208                         glVertex2f(x3, y2);
1209                         glEnd();
1210                 }
1211
1212                 if (ca->dtx & CAM_DTX_CENTER_DIAG) {
1213                         UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 0.25, 0);
1214
1215                         glBegin(GL_LINES);
1216                         glVertex2f(x1, y1);
1217                         glVertex2f(x2, y2);
1218
1219                         glVertex2f(x1, y2);
1220                         glVertex2f(x2, y1);
1221                         glEnd();
1222                 }
1223
1224                 if (ca->dtx & CAM_DTX_THIRDS) {
1225                         UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 0.25, 0);
1226                         drawviewborder_grid3(x1, x2, y1, y2, 1.0f / 3.0f);
1227                 }
1228
1229                 if (ca->dtx & CAM_DTX_GOLDEN) {
1230                         UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 0.25, 0);
1231                         drawviewborder_grid3(x1, x2, y1, y2, 1.0f - (1.0f / 1.61803399f));
1232                 }
1233
1234                 if (ca->dtx & CAM_DTX_GOLDEN_TRI_A) {
1235                         UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 0.25, 0);
1236                         drawviewborder_triangle(x1, x2, y1, y2, 0, 'A');
1237                 }
1238
1239                 if (ca->dtx & CAM_DTX_GOLDEN_TRI_B) {
1240                         UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 0.25, 0);
1241                         drawviewborder_triangle(x1, x2, y1, y2, 0, 'B');
1242                 }
1243
1244                 if (ca->dtx & CAM_DTX_HARMONY_TRI_A) {
1245                         UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 0.25, 0);
1246                         drawviewborder_triangle(x1, x2, y1, y2, 1, 'A');
1247                 }
1248
1249                 if (ca->dtx & CAM_DTX_HARMONY_TRI_B) {
1250                         UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 0.25, 0);
1251                         drawviewborder_triangle(x1, x2, y1, y2, 1, 'B');
1252                 }
1253
1254                 if (ca->flag & CAM_SHOWTITLESAFE) {
1255                         UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 0.25, 0);
1256
1257                         hmargin = 0.1f  * (x2 - x1);
1258                         vmargin = 0.05f * (y2 - y1);
1259                         uiDrawBox(GL_LINE_LOOP, x1 + hmargin, y1 + vmargin, x2 - hmargin, y2 - vmargin, 2.0f);
1260
1261                         hmargin = 0.035f * (x2 - x1);
1262                         vmargin = 0.035f * (y2 - y1);
1263                         uiDrawBox(GL_LINE_LOOP, x1 + hmargin, y1 + vmargin, x2 - hmargin, y2 - vmargin, 2.0f);
1264                 }
1265                 if (ca && (ca->flag & CAM_SHOWSENSOR)) {
1266                         /* determine sensor fit, and get sensor x/y, for auto fit we
1267                          * assume and square sensor and only use sensor_x */
1268                         float sizex = scene->r.xsch * scene->r.xasp;
1269                         float sizey = scene->r.ysch * scene->r.yasp;
1270                         int sensor_fit = BKE_camera_sensor_fit(ca->sensor_fit, sizex, sizey);
1271                         float sensor_x = ca->sensor_x;
1272                         float sensor_y = (ca->sensor_fit == CAMERA_SENSOR_FIT_AUTO) ? ca->sensor_x : ca->sensor_y;
1273
1274                         /* determine sensor plane */
1275                         rctf rect;
1276
1277                         if (sensor_fit == CAMERA_SENSOR_FIT_HOR) {
1278                                 float sensor_scale = (x2i - x1i) / sensor_x;
1279                                 float sensor_height = sensor_scale * sensor_y;
1280
1281                                 rect.xmin = x1i;
1282                                 rect.xmax = x2i;
1283                                 rect.ymin = (y1i + y2i) * 0.5f - sensor_height * 0.5f;
1284                                 rect.ymax = rect.ymin + sensor_height;
1285                         }
1286                         else {
1287                                 float sensor_scale = (y2i - y1i) / sensor_y;
1288                                 float sensor_width = sensor_scale * sensor_x;
1289
1290                                 rect.xmin = (x1i + x2i) * 0.5f - sensor_width * 0.5f;
1291                                 rect.xmax = rect.xmin + sensor_width;
1292                                 rect.ymin = y1i;
1293                                 rect.ymax = y2i;
1294                         }
1295
1296                         /* draw */
1297                         UI_ThemeColorShade(TH_WIRE, 100);
1298                         uiDrawBox(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f);
1299                 }
1300         }
1301
1302         setlinestyle(0);
1303         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1304
1305         /* camera name - draw in highlighted text color */
1306         if (ca && (ca->flag & CAM_SHOWNAME)) {
1307                 UI_ThemeColor(TH_TEXT_HI);
1308                 BLF_draw_default(x1i, y1i - 15, 0.0f, v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2);
1309                 UI_ThemeColor(TH_WIRE);
1310         }
1311 }
1312
1313 /* *********************** backdraw for selection *************** */
1314
1315 static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
1316 {
1317         RegionView3D *rv3d = ar->regiondata;
1318         struct Base *base = scene->basact;
1319         int multisample_enabled;
1320
1321         BLI_assert(ar->regiontype == RGN_TYPE_WINDOW);
1322
1323         if (base && (base->object->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
1324                      paint_facesel_test(base->object)))
1325         {
1326                 /* do nothing */
1327         }
1328         else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) &&
1329                  v3d->drawtype > OB_WIRE && (v3d->flag & V3D_ZBUF_SELECT))
1330         {
1331                 /* do nothing */
1332         }
1333         else if (scene->obedit && v3d->drawtype > OB_WIRE &&
1334                  (v3d->flag & V3D_ZBUF_SELECT))
1335         {
1336                 /* do nothing */
1337         }
1338         else {
1339                 v3d->flag &= ~V3D_INVALID_BACKBUF;
1340                 return;
1341         }
1342
1343         if (!(v3d->flag & V3D_INVALID_BACKBUF) ) return;
1344
1345 #if 0
1346         if (test) {
1347                 if (qtest()) {
1348                         addafterqueue(ar->win, BACKBUFDRAW, 1);
1349                         return;
1350                 }
1351         }
1352 #endif
1353
1354         if (v3d->drawtype > OB_WIRE) v3d->zbuf = TRUE;
1355         
1356         /* dithering and AA break color coding, so disable */
1357         glDisable(GL_DITHER);
1358
1359         multisample_enabled = glIsEnabled(GL_MULTISAMPLE_ARB);
1360         if (multisample_enabled)
1361                 glDisable(GL_MULTISAMPLE_ARB);
1362
1363         if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) {
1364                 /* for multisample we use an offscreen FBO. multisample drawing can fail
1365                  * with color coded selection drawing, and reading back depths from such
1366                  * a buffer can also cause a few seconds freeze on OS X / NVidia. */
1367                 int w = BLI_rcti_size_x(&ar->winrct);
1368                 int h = BLI_rcti_size_y(&ar->winrct);
1369                 char error[256];
1370
1371                 if (rv3d->gpuoffscreen) {
1372                         if (GPU_offscreen_width(rv3d->gpuoffscreen)  != w ||
1373                             GPU_offscreen_height(rv3d->gpuoffscreen) != h)
1374                         {
1375                                 GPU_offscreen_free(rv3d->gpuoffscreen);
1376                                 rv3d->gpuoffscreen = NULL;
1377                         }
1378                 }
1379
1380                 if (!rv3d->gpuoffscreen) {
1381                         rv3d->gpuoffscreen = GPU_offscreen_create(w, h, error);
1382
1383                         if (!rv3d->gpuoffscreen)
1384                                 fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error);
1385                 }
1386         }
1387
1388         if (rv3d->gpuoffscreen)
1389                 GPU_offscreen_bind(rv3d->gpuoffscreen);
1390         else
1391                 glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
1392
1393         glClearColor(0.0, 0.0, 0.0, 0.0); 
1394         if (v3d->zbuf) {
1395                 glEnable(GL_DEPTH_TEST);
1396                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1397         }
1398         else {
1399                 glClear(GL_COLOR_BUFFER_BIT);
1400                 glDisable(GL_DEPTH_TEST);
1401         }
1402         
1403         if (rv3d->rflag & RV3D_CLIPPING)
1404                 ED_view3d_clipping_set(rv3d);
1405         
1406         G.f |= G_BACKBUFSEL;
1407         
1408         if (base && (base->lay & v3d->lay))
1409                 draw_object_backbufsel(scene, v3d, rv3d, base->object);
1410         
1411         if (rv3d->gpuoffscreen)
1412                 GPU_offscreen_unbind(rv3d->gpuoffscreen);
1413         else
1414                 ar->swap = 0; /* mark invalid backbuf for wm draw */
1415
1416         v3d->flag &= ~V3D_INVALID_BACKBUF;
1417
1418         G.f &= ~G_BACKBUFSEL;
1419         v3d->zbuf = FALSE;
1420         glDisable(GL_DEPTH_TEST);
1421         glEnable(GL_DITHER);
1422         if (multisample_enabled)
1423                 glEnable(GL_MULTISAMPLE_ARB);
1424
1425         if (rv3d->rflag & RV3D_CLIPPING)
1426                 ED_view3d_clipping_disable();
1427
1428         /* it is important to end a view in a transform compatible with buttons */
1429 //      persp(PERSP_WIN);  /* set ortho */
1430
1431 }
1432
1433 void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
1434 {
1435         RegionView3D *rv3d = ar->regiondata;
1436
1437         if (rv3d->gpuoffscreen) {
1438                 GPU_offscreen_bind(rv3d->gpuoffscreen);
1439                 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
1440                 glReadPixels(x, y, w, h, format, type, data);
1441                 GPU_offscreen_unbind(rv3d->gpuoffscreen);
1442         }
1443         else {
1444                 glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
1445         }
1446 }
1447
1448 /* XXX depth reading exception, for code not using gpu offscreen */
1449 static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
1450 {
1451
1452         glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
1453 }
1454
1455 void view3d_validate_backbuf(ViewContext *vc)
1456 {
1457         if (vc->v3d->flag & V3D_INVALID_BACKBUF)
1458                 backdrawview3d(vc->scene, vc->ar, vc->v3d);
1459 }
1460
1461 /* samples a single pixel (copied from vpaint) */
1462 unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
1463 {
1464         unsigned int col;
1465         
1466         if (x >= vc->ar->winx || y >= vc->ar->winy) {
1467                 return 0;
1468         }
1469
1470         view3d_validate_backbuf(vc);
1471
1472         view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
1473         glReadBuffer(GL_BACK);
1474         
1475         if (ENDIAN_ORDER == B_ENDIAN) {
1476                 BLI_endian_switch_uint32(&col);
1477         }
1478         
1479         return WM_framebuffer_to_index(col);
1480 }
1481
1482 /* reads full rect, converts indices */
1483 ImBuf *view3d_read_backbuf(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
1484 {
1485         unsigned int *dr, *rd;
1486         struct ImBuf *ibuf, *ibuf1;
1487         int a;
1488         short xminc, yminc, xmaxc, ymaxc, xs, ys;
1489         
1490         /* clip */
1491         if (xmin < 0) xminc = 0; else xminc = xmin;
1492         if (xmax >= vc->ar->winx) xmaxc = vc->ar->winx - 1; else xmaxc = xmax;
1493         if (xminc > xmaxc) return NULL;
1494
1495         if (ymin < 0) yminc = 0; else yminc = ymin;
1496         if (ymax >= vc->ar->winy) ymaxc = vc->ar->winy - 1; else ymaxc = ymax;
1497         if (yminc > ymaxc) return NULL;
1498         
1499         ibuf = IMB_allocImBuf((xmaxc - xminc + 1), (ymaxc - yminc + 1), 32, IB_rect);
1500
1501         view3d_validate_backbuf(vc);
1502
1503         view3d_opengl_read_pixels(vc->ar,
1504                      xminc, yminc,
1505                      (xmaxc - xminc + 1),
1506                      (ymaxc - yminc + 1),
1507                      GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
1508
1509         glReadBuffer(GL_BACK);
1510
1511         if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
1512
1513         a = (xmaxc - xminc + 1) * (ymaxc - yminc + 1);
1514         dr = ibuf->rect;
1515         while (a--) {
1516                 if (*dr) *dr = WM_framebuffer_to_index(*dr);
1517                 dr++;
1518         }
1519         
1520         /* put clipped result back, if needed */
1521         if (xminc == xmin && xmaxc == xmax && yminc == ymin && ymaxc == ymax)
1522                 return ibuf;
1523         
1524         ibuf1 = IMB_allocImBuf( (xmax - xmin + 1), (ymax - ymin + 1), 32, IB_rect);
1525         rd = ibuf->rect;
1526         dr = ibuf1->rect;
1527
1528         for (ys = ymin; ys <= ymax; ys++) {
1529                 for (xs = xmin; xs <= xmax; xs++, dr++) {
1530                         if (xs >= xminc && xs <= xmaxc && ys >= yminc && ys <= ymaxc) {
1531                                 *dr = *rd;
1532                                 rd++;
1533                         }
1534                 }
1535         }
1536         IMB_freeImBuf(ibuf);
1537         return ibuf1;
1538 }
1539
1540 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
1541 unsigned int view3d_sample_backbuf_rect(ViewContext *vc, const int mval[2], int size,
1542                                         unsigned int min, unsigned int max, float *r_dist, short strict,
1543                                         void *handle, bool (*indextest)(void *handle, unsigned int index))
1544 {
1545         struct ImBuf *buf;
1546         unsigned int *bufmin, *bufmax, *tbuf;
1547         int minx, miny;
1548         int a, b, rc, nr, amount, dirvec[4][2];
1549         int distance = 0;
1550         unsigned int index = 0;
1551         bool indexok = false;
1552
1553         amount = (size - 1) / 2;
1554
1555         minx = mval[0] - (amount + 1);
1556         miny = mval[1] - (amount + 1);
1557         buf = view3d_read_backbuf(vc, minx, miny, minx + size - 1, miny + size - 1);
1558         if (!buf) return 0;
1559
1560         rc = 0;
1561         
1562         dirvec[0][0] = 1; dirvec[0][1] = 0;
1563         dirvec[1][0] = 0; dirvec[1][1] = -size;
1564         dirvec[2][0] = -1; dirvec[2][1] = 0;
1565         dirvec[3][0] = 0; dirvec[3][1] = size;
1566         
1567         bufmin = buf->rect;
1568         tbuf = buf->rect;
1569         bufmax = buf->rect + size * size;
1570         tbuf += amount * size + amount;
1571         
1572         for (nr = 1; nr <= size; nr++) {
1573                 
1574                 for (a = 0; a < 2; a++) {
1575                         for (b = 0; b < nr; b++, distance++) {
1576                                 if (*tbuf && *tbuf >= min && *tbuf < max) {  /* we got a hit */
1577                                         if (strict) {
1578                                                 indexok =  indextest(handle, *tbuf - min + 1);
1579                                                 if (indexok) {
1580                                                         *r_dist = sqrtf((float)distance);
1581                                                         index = *tbuf - min + 1;
1582                                                         goto exit; 
1583                                                 }
1584                                         }
1585                                         else {
1586                                                 *r_dist = sqrtf((float)distance);  /* XXX, this distance is wrong - */
1587                                                 index = *tbuf - min + 1;  /* messy yah, but indices start at 1 */
1588                                                 goto exit;
1589                                         }
1590                                 }
1591                                 
1592                                 tbuf += (dirvec[rc][0] + dirvec[rc][1]);
1593                                 
1594                                 if (tbuf < bufmin || tbuf >= bufmax) {
1595                                         goto exit;
1596                                 }
1597                         }
1598                         rc++;
1599                         rc &= 3;
1600                 }
1601         }
1602
1603 exit:
1604         IMB_freeImBuf(buf);
1605         return index;
1606 }
1607
1608
1609 /* ************************************************************* */
1610
1611 static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
1612                               const bool do_foreground, const bool do_camera_frame)
1613 {
1614         RegionView3D *rv3d = ar->regiondata;
1615         BGpic *bgpic;
1616         int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0;
1617
1618         for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
1619
1620                 if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag)
1621                         continue;
1622
1623                 if ((bgpic->view == 0) || /* zero for any */
1624                     (bgpic->view & (1 << rv3d->view)) || /* check agaist flags */
1625                     (rv3d->persp == RV3D_CAMOB && bgpic->view == (1 << RV3D_VIEW_CAMERA)))
1626                 {
1627                         float image_aspect[2];
1628                         float fac, asp, zoomx, zoomy;
1629                         float x1, y1, x2, y2;
1630
1631                         ImBuf *ibuf = NULL, *freeibuf, *releaseibuf;
1632
1633                         Image *ima;
1634                         MovieClip *clip;
1635
1636                         /* disable individual images */
1637                         if ((bgpic->flag & V3D_BGPIC_DISABLED))
1638                                 continue;
1639
1640                         freeibuf = NULL;
1641                         releaseibuf = NULL;
1642                         if (bgpic->source == V3D_BGPIC_IMAGE) {
1643                                 ima = bgpic->ima;
1644                                 if (ima == NULL)
1645                                         continue;
1646                                 BKE_image_user_frame_calc(&bgpic->iuser, CFRA, 0);
1647                                 if (ima->source == IMA_SRC_SEQUENCE && !(bgpic->iuser.flag & IMA_USER_FRAME_IN_RANGE)) {
1648                                         ibuf = NULL; /* frame is out of range, dont show */
1649                                 }
1650                                 else {
1651                                         ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, NULL);
1652                                         releaseibuf = ibuf;
1653                                 }
1654
1655                                 image_aspect[0] = ima->aspx;
1656                                 image_aspect[1] = ima->aspx;
1657                         }
1658                         else if (bgpic->source == V3D_BGPIC_MOVIE) {
1659                                 clip = NULL;
1660
1661                                 /* TODO: skip drawing when out of frame range (as image sequences do above) */
1662
1663                                 if (bgpic->flag & V3D_BGPIC_CAMERACLIP) {
1664                                         if (scene->camera)
1665                                                 clip = BKE_object_movieclip_get(scene, scene->camera, 1);
1666                                 }
1667                                 else {
1668                                         clip = bgpic->clip;
1669                                 }
1670
1671                                 if (clip == NULL)
1672                                         continue;
1673
1674                                 BKE_movieclip_user_set_frame(&bgpic->cuser, CFRA);
1675                                 ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser);
1676
1677                                 image_aspect[0] = clip->aspx;
1678                                 image_aspect[1] = clip->aspy;
1679
1680                                 /* working with ibuf from image and clip has got different workflow now.
1681                                  * ibuf acquired from clip is referenced by cache system and should
1682                                  * be dereferenced after usage. */
1683                                 freeibuf = ibuf;
1684                         }
1685                         else {
1686                                 /* perhaps when loading future files... */
1687                                 BLI_assert(0);
1688                                 copy_v2_fl(image_aspect, 1.0f);
1689                         }
1690
1691                         if (ibuf == NULL)
1692                                 continue;
1693
1694                         if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */
1695                                 if (freeibuf)
1696                                         IMB_freeImBuf(freeibuf);
1697                                 if (releaseibuf)
1698                                         BKE_image_release_ibuf(ima, releaseibuf, NULL);
1699
1700                                 continue;
1701                         }
1702
1703                         if (ibuf->rect == NULL)
1704                                 IMB_rect_from_float(ibuf);
1705
1706                         if (rv3d->persp == RV3D_CAMOB) {
1707
1708                                 if (do_camera_frame) {
1709                                         rctf vb;
1710                                         ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false);
1711                                         x1 = vb.xmin;
1712                                         y1 = vb.ymin;
1713                                         x2 = vb.xmax;
1714                                         y2 = vb.ymax;
1715                                 }
1716                                 else {
1717                                         x1 = ar->winrct.xmin;
1718                                         y1 = ar->winrct.ymin;
1719                                         x2 = ar->winrct.xmax;
1720                                         y2 = ar->winrct.ymax;
1721                                 }
1722
1723                                 /* apply offset last - camera offset is different to offset in blender units */
1724                                 /* so this has some sane way of working - this matches camera's shift _exactly_ */
1725                                 {
1726                                         const float max_dim = max_ff(x2 - x1, y2 - y1);
1727                                         const float xof_scale = bgpic->xof * max_dim;
1728                                         const float yof_scale = bgpic->yof * max_dim;
1729
1730                                         x1 += xof_scale;
1731                                         y1 += yof_scale;
1732                                         x2 += xof_scale;
1733                                         y2 += yof_scale;
1734                                 }
1735
1736                                 /* aspect correction */
1737                                 if (bgpic->flag & V3D_BGPIC_CAMERA_ASPECT) {
1738                                         /* apply aspect from clip */
1739                                         const float w_src = ibuf->x * image_aspect[0];
1740                                         const float h_src = ibuf->y * image_aspect[1];
1741
1742                                         /* destination aspect is already applied from the camera frame */
1743                                         const float w_dst = x1 - x2;
1744                                         const float h_dst = y1 - y2;
1745
1746                                         const float asp_src = w_src / h_src;
1747                                         const float asp_dst = w_dst / h_dst;
1748
1749                                         if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
1750                                                 if ((asp_src > asp_dst) == ((bgpic->flag & V3D_BGPIC_CAMERA_CROP) != 0)) {
1751                                                         /* fit X */
1752                                                         const float div = asp_src / asp_dst;
1753                                                         const float cent = (x1 + x2) / 2.0f;
1754                                                         x1 = ((x1 - cent) * div) + cent;
1755                                                         x2 = ((x2 - cent) * div) + cent;
1756                                                 }
1757                                                 else {
1758                                                         /* fit Y */
1759                                                         const float div = asp_dst / asp_src;
1760                                                         const float cent = (y1 + y2) / 2.0f;
1761                                                         y1 = ((y1 - cent) * div) + cent;
1762                                                         y2 = ((y2 - cent) * div) + cent;
1763                                                 }
1764                                         }
1765                                 }
1766                         }
1767                         else {
1768                                 float tvec[3];
1769                                 float sco[2];
1770                                 const float mval_f[2] = {1.0f, 0.0f};
1771                                 const float co_zero[3] = {0};
1772                                 float zfac;
1773
1774                                 /* calc window coord */
1775                                 zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL);
1776                                 ED_view3d_win_to_delta(ar, mval_f, tvec, zfac);
1777                                 fac = max_ff(fabsf(tvec[0]), max_ff(fabsf(tvec[1]), fabsf(tvec[2]))); /* largest abs axis */
1778                                 fac = 1.0f / fac;
1779
1780                                 asp = (float)ibuf->y / (float)ibuf->x;
1781
1782                                 zero_v3(tvec);
1783                                 ED_view3d_project_float_v2_m4(ar, tvec, sco, rv3d->persmat);
1784
1785                                 x1 =  sco[0] + fac * (bgpic->xof - bgpic->size);
1786                                 y1 =  sco[1] + asp * fac * (bgpic->yof - bgpic->size);
1787                                 x2 =  sco[0] + fac * (bgpic->xof + bgpic->size);
1788                                 y2 =  sco[1] + asp * fac * (bgpic->yof + bgpic->size);
1789                         }
1790
1791                         /* complete clip? */
1792
1793                         if (x2 < 0 || y2 < 0 || x1 > ar->winx || y1 > ar->winy) {
1794                                 if (freeibuf)
1795                                         IMB_freeImBuf(freeibuf);
1796                                 if (releaseibuf)
1797                                         BKE_image_release_ibuf(ima, releaseibuf, NULL);
1798
1799                                 continue;
1800                         }
1801
1802                         zoomx = (x2 - x1) / ibuf->x;
1803                         zoomy = (y2 - y1) / ibuf->y;
1804
1805                         /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */
1806                         if (zoomx < 1.0f || zoomy < 1.0f) {
1807                                 float tzoom = min_ff(zoomx, zoomy);
1808                                 int mip = 0;
1809
1810                                 if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) {
1811                                         IMB_remakemipmap(ibuf, 0);
1812                                         ibuf->userflags &= ~IB_MIPMAP_INVALID;
1813                                 }
1814                                 else if (ibuf->mipmap[0] == NULL)
1815                                         IMB_makemipmap(ibuf, 0);
1816
1817                                 while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) {
1818                                         tzoom *= 2.0f;
1819                                         zoomx *= 2.0f;
1820                                         zoomy *= 2.0f;
1821                                         mip++;
1822                                 }
1823                                 if (mip > 0)
1824                                         ibuf = ibuf->mipmap[mip - 1];
1825                         }
1826
1827                         if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
1828                         glDepthMask(0);
1829
1830                         glEnable(GL_BLEND);
1831                         glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA);
1832
1833                         glMatrixMode(GL_PROJECTION);
1834                         glPushMatrix();
1835                         glMatrixMode(GL_MODELVIEW);
1836                         glPushMatrix();
1837                         ED_region_pixelspace(ar);
1838
1839                         glPixelZoom(zoomx, zoomy);
1840                         glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend);
1841
1842                         /* could not use glaDrawPixelsAuto because it could fallback to
1843                          * glaDrawPixelsSafe in some cases, which will end up in misssing
1844                          * alpha transparency for the background image (sergey)
1845                          */
1846                         glaDrawPixelsTex(x1, y1, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect);
1847
1848                         glPixelZoom(1.0, 1.0);
1849                         glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
1850
1851                         glMatrixMode(GL_PROJECTION);
1852                         glPopMatrix();
1853                         glMatrixMode(GL_MODELVIEW);
1854                         glPopMatrix();
1855
1856                         glDisable(GL_BLEND);
1857
1858                         glDepthMask(1);
1859                         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1860
1861                         if (freeibuf)
1862                                 IMB_freeImBuf(freeibuf);
1863                         if (releaseibuf)
1864                                 BKE_image_release_ibuf(ima, releaseibuf, NULL);
1865                 }
1866         }
1867 }
1868
1869 static void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d,
1870                                    const bool do_foreground, const bool do_camera_frame)
1871 {
1872         RegionView3D *rv3d = ar->regiondata;
1873
1874         if ((v3d->flag & V3D_DISPBGPICS) == 0)
1875                 return;
1876
1877         /* disabled - mango request, since footage /w only render is quite useful
1878          * and this option is easy to disable all background images at once */
1879 #if 0
1880         if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1881                 return;
1882 #endif
1883
1884         if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) {
1885                 if (rv3d->persp == RV3D_CAMOB) {
1886                         view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame);
1887                 }
1888         }
1889         else {
1890                 view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame);
1891         }
1892 }
1893
1894 /* ****************** View3d afterdraw *************** */
1895
1896 typedef struct View3DAfter {
1897         struct View3DAfter *next, *prev;
1898         struct Base *base;
1899         short dflag;
1900 } View3DAfter;
1901
1902 /* temp storage of Objects that need to be drawn as last */
1903 void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag)
1904 {
1905         View3DAfter *v3da = MEM_callocN(sizeof(View3DAfter), "View 3d after");
1906         BLI_assert((base->flag & OB_FROMDUPLI) == 0);
1907         BLI_addtail(lb, v3da);
1908         v3da->base = base;
1909         v3da->dflag = dflag;
1910 }
1911
1912 /* disables write in zbuffer and draws it over */
1913 static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d)
1914 {
1915         View3DAfter *v3da, *next;
1916         
1917         glDepthMask(0);
1918         v3d->transp = TRUE;
1919         
1920         for (v3da = v3d->afterdraw_transp.first; v3da; v3da = next) {
1921                 next = v3da->next;
1922                 draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
1923                 BLI_remlink(&v3d->afterdraw_transp, v3da);
1924                 MEM_freeN(v3da);
1925         }
1926         v3d->transp = FALSE;
1927         
1928         glDepthMask(1);
1929         
1930 }
1931
1932 /* clears zbuffer and draws it over */
1933 static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, int clear)
1934 {
1935         View3DAfter *v3da, *next;
1936
1937         if (clear && v3d->zbuf)
1938                 glClear(GL_DEPTH_BUFFER_BIT);
1939
1940         v3d->xray = TRUE;
1941         for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) {
1942                 next = v3da->next;
1943                 draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
1944                 BLI_remlink(&v3d->afterdraw_xray, v3da);
1945                 MEM_freeN(v3da);
1946         }
1947         v3d->xray = FALSE;
1948 }
1949
1950
1951 /* clears zbuffer and draws it over */
1952 static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, int clear)
1953 {
1954         View3DAfter *v3da, *next;
1955
1956         if (clear && v3d->zbuf)
1957                 glClear(GL_DEPTH_BUFFER_BIT);
1958
1959         v3d->xray = TRUE;
1960         v3d->transp = TRUE;
1961         
1962         for (v3da = v3d->afterdraw_xraytransp.first; v3da; v3da = next) {
1963                 next = v3da->next;
1964                 draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
1965                 BLI_remlink(&v3d->afterdraw_xraytransp, v3da);
1966                 MEM_freeN(v3da);
1967         }
1968
1969         v3d->transp = FALSE;
1970         v3d->xray = FALSE;
1971
1972 }
1973
1974 /* *********************** */
1975
1976 /*
1977  * In most cases call draw_dupli_objects,
1978  * draw_dupli_objects_color was added because when drawing set dupli's
1979  * we need to force the color
1980  */
1981
1982 #if 0
1983 int dupli_ob_sort(void *arg1, void *arg2)
1984 {
1985         void *p1 = ((DupliObject *)arg1)->ob;
1986         void *p2 = ((DupliObject *)arg2)->ob;
1987         int val = 0;
1988         if (p1 < p2) val = -1;
1989         else if (p1 > p2) val = 1;
1990         return val;
1991 }
1992 #endif
1993
1994
1995 static DupliObject *dupli_step(DupliObject *dob)
1996 {
1997         while (dob && dob->no_draw)
1998                 dob = dob->next;
1999         return dob;
2000 }
2001
2002 static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int color)
2003 {
2004         RegionView3D *rv3d = ar->regiondata;
2005         ListBase *lb;
2006         DupliObject *dob_prev = NULL, *dob, *dob_next = NULL;
2007         Base tbase = {NULL};
2008         BoundBox bb, *bb_tmp; /* use a copy because draw_object, calls clear_mesh_caches */
2009         GLuint displist = 0;
2010         short transflag, use_displist = -1;  /* -1 is initialize */
2011         char dt;
2012         short dtx;
2013         
2014         if (base->object->restrictflag & OB_RESTRICT_VIEW) return;
2015         
2016         tbase.flag = OB_FROMDUPLI | base->flag;
2017         lb = object_duplilist(scene, base->object, false);
2018         // BLI_sortlist(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */
2019
2020         dob = dupli_step(lb->first);
2021         if (dob) dob_next = dupli_step(dob->next);
2022
2023         for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) {
2024                 tbase.object = dob->ob;
2025
2026                 /* extra service: draw the duplicator in drawtype of parent, minimum taken
2027                  * to allow e.g. boundbox box objects in groups for LOD */
2028                 dt = tbase.object->dt;
2029                 tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
2030
2031                 /* inherit draw extra, but not if a boundbox under the assumption that this
2032                  * is intended to speed up drawing, and drawing extra (especially wire) can
2033                  * slow it down too much */
2034                 dtx = tbase.object->dtx;
2035                 if (tbase.object->dt != OB_BOUNDBOX)
2036                         tbase.object->dtx = base->object->dtx;
2037
2038                 /* negative scale flag has to propagate */
2039                 transflag = tbase.object->transflag;
2040                 if (base->object->transflag & OB_NEG_SCALE)
2041                         tbase.object->transflag ^= OB_NEG_SCALE;
2042
2043                 UI_ThemeColorBlend(color, TH_BACK, 0.5);
2044
2045                 /* generate displist, test for new object */
2046                 if (dob_prev && dob_prev->ob != dob->ob) {
2047                         if (use_displist == true)
2048                                 glDeleteLists(displist, 1);
2049
2050                         use_displist = -1;
2051                 }
2052
2053                 /* generate displist */
2054                 if (use_displist == -1) {
2055
2056                         /* note, since this was added, its checked (dob->type == OB_DUPLIGROUP)
2057                          * however this is very slow, it was probably needed for the NLA
2058                          * offset feature (used in group-duplicate.blend but no longer works in 2.5)
2059                          * so for now it should be ok to - campbell */
2060
2061                         if ( /* if this is the last no need  to make a displist */
2062                             (dob_next == NULL || dob_next->ob != dob->ob) ||
2063                             /* lamp drawing messes with matrices, could be handled smarter... but this works */
2064                             (dob->ob->type == OB_LAMP) ||
2065                             (dob->type == OB_DUPLIGROUP && dob->animated) ||
2066                             !(bb_tmp = BKE_object_boundbox_get(dob->ob)))
2067                         {
2068                                 // printf("draw_dupli_objects_color: skipping displist for %s\n", dob->ob->id.name + 2);
2069                                 use_displist = false;
2070                         }
2071                         else {
2072                                 // printf("draw_dupli_objects_color: using displist for %s\n", dob->ob->id.name + 2);
2073                                 bb = *bb_tmp; /* must make a copy  */
2074
2075                                 /* disable boundbox check for list creation */
2076                                 BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1);
2077                                 /* need this for next part of code */
2078                                 unit_m4(dob->ob->obmat);    /* obmat gets restored */
2079
2080                                 displist = glGenLists(1);
2081                                 glNewList(displist, GL_COMPILE);
2082                                 draw_object(scene, ar, v3d, &tbase, DRAW_CONSTCOLOR);
2083                                 glEndList();
2084
2085                                 use_displist = true;
2086                                 BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0);
2087                         }
2088                 }
2089                 if (use_displist) {
2090                         glMultMatrixf(dob->mat);
2091                         if (ED_view3d_boundbox_clip(rv3d, dob->mat, &bb))
2092                                 glCallList(displist);
2093                         glLoadMatrixf(rv3d->viewmat);
2094                 }
2095                 else {
2096                         copy_m4_m4(dob->ob->obmat, dob->mat);
2097                         draw_object(scene, ar, v3d, &tbase, DRAW_CONSTCOLOR);
2098                 }
2099
2100                 tbase.object->dt = dt;
2101                 tbase.object->dtx = dtx;
2102                 tbase.object->transflag = transflag;
2103         }
2104         
2105         /* Transp afterdraw disabled, afterdraw only stores base pointers, and duplis can be same obj */
2106         
2107         free_object_duplilist(lb);  /* does restore */
2108         
2109         if (use_displist)
2110                 glDeleteLists(displist, 1);
2111 }
2112
2113 static void draw_dupli_objects(Scene *scene, ARegion *ar, View3D *v3d, Base *base)
2114 {
2115         /* define the color here so draw_dupli_objects_color can be called
2116          * from the set loop */
2117         
2118         int color = (base->flag & SELECT) ? TH_SELECT : TH_WIRE;
2119         /* debug */
2120         if (base->object->dup_group && base->object->dup_group->id.us < 1)
2121                 color = TH_REDALERT;
2122         
2123         draw_dupli_objects_color(scene, ar, v3d, base, color);
2124 }
2125
2126 /* XXX warning, not using gpu offscreen here */
2127 void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect)
2128 {
2129         int x, y, w, h;
2130         rcti r;
2131         /* clamp rect by area */
2132
2133         r.xmin = 0;
2134         r.xmax = ar->winx - 1;
2135         r.ymin = 0;
2136         r.ymax = ar->winy - 1;
2137
2138         /* Constrain rect to depth bounds */
2139         BLI_rcti_isect(&r, rect, rect);
2140
2141         /* assign values to compare with the ViewDepths */
2142         x = rect->xmin;
2143         y = rect->ymin;
2144
2145         w = BLI_rcti_size_x(rect);
2146         h = BLI_rcti_size_y(rect);
2147
2148         if (w <= 0 || h <= 0) {
2149                 if (d->depths)
2150                         MEM_freeN(d->depths);
2151                 d->depths = NULL;
2152
2153                 d->damaged = false;
2154         }
2155         else if (d->w != w ||
2156                  d->h != h ||
2157                  d->x != x ||
2158                  d->y != y ||
2159                  d->depths == NULL
2160                  )
2161         {
2162                 d->x = x;
2163                 d->y = y;
2164                 d->w = w;
2165                 d->h = h;
2166
2167                 if (d->depths)
2168                         MEM_freeN(d->depths);
2169
2170                 d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset");
2171                 
2172                 d->damaged = true;
2173         }
2174
2175         if (d->damaged) {
2176                 /* XXX using special function here, it doesn't use the gpu offscreen system */
2177                 view3d_opengl_read_Z_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
2178                 glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
2179                 d->damaged = false;
2180         }
2181 }
2182
2183 /* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */
2184 void ED_view3d_depth_update(ARegion *ar)
2185 {
2186         RegionView3D *rv3d = ar->regiondata;
2187         
2188         /* Create storage for, and, if necessary, copy depth buffer */
2189         if (!rv3d->depths) rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths");
2190         if (rv3d->depths) {
2191                 ViewDepths *d = rv3d->depths;
2192                 if (d->w != ar->winx ||
2193                     d->h != ar->winy ||
2194                     !d->depths)
2195                 {
2196                         d->w = ar->winx;
2197                         d->h = ar->winy;
2198                         if (d->depths)
2199                                 MEM_freeN(d->depths);
2200                         d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths");
2201                         d->damaged = true;
2202                 }
2203                 
2204                 if (d->damaged) {
2205                         view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
2206                         glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
2207                         
2208                         d->damaged = false;
2209                 }
2210         }
2211 }
2212
2213 /* utility function to find the closest Z value, use for autodepth */
2214 float view3d_depth_near(ViewDepths *d)
2215 {
2216         /* convert to float for comparisons */
2217         const float near = (float)d->depth_range[0];
2218         const float far_real = (float)d->depth_range[1];
2219         float far = far_real;
2220
2221         const float *depths = d->depths;
2222         float depth = FLT_MAX;
2223         int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */
2224
2225         /* far is both the starting 'far' value
2226          * and the closest value found. */
2227         while (i--) {
2228                 depth = *depths++;
2229                 if ((depth < far) && (depth > near)) {
2230                         far = depth;
2231                 }
2232         }
2233
2234         return far == far_real ? FLT_MAX : far;
2235 }
2236
2237 void draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d)
2238 {
2239         short zbuf = v3d->zbuf;
2240         RegionView3D *rv3d = ar->regiondata;
2241
2242         setwinmatrixview3d(ar, v3d, NULL);
2243         setviewmatrixview3d(scene, v3d, rv3d);  /* note: calls BKE_object_where_is_calc for camera... */
2244
2245         mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
2246         invert_m4_m4(rv3d->persinv, rv3d->persmat);
2247         invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
2248
2249         glClear(GL_DEPTH_BUFFER_BIT);
2250
2251         glLoadMatrixf(rv3d->viewmat);
2252
2253         v3d->zbuf = TRUE;
2254         glEnable(GL_DEPTH_TEST);
2255
2256         if (v3d->flag2 & V3D_SHOW_GPENCIL) {
2257                 draw_gpencil_view3d(scene, v3d, ar, true);
2258         }
2259         
2260         v3d->zbuf = zbuf;
2261
2262 }
2263
2264 void draw_depth(Scene *scene, ARegion *ar, View3D *v3d, int (*func)(void *), bool alphaoverride)
2265 {
2266         RegionView3D *rv3d = ar->regiondata;
2267         Base *base;
2268         short zbuf = v3d->zbuf;
2269         short flag = v3d->flag;
2270         float glalphaclip = U.glalphaclip;
2271         int obcenter_dia = U.obcenter_dia;
2272         /* temp set drawtype to solid */
2273         
2274         /* Setting these temporarily is not nice */
2275         v3d->flag &= ~V3D_SELECT_OUTLINE;
2276         U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */
2277         U.obcenter_dia = 0;
2278         
2279         setwinmatrixview3d(ar, v3d, NULL);
2280         setviewmatrixview3d(scene, v3d, rv3d);  /* note: calls BKE_object_where_is_calc for camera... */
2281         
2282         mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
2283         invert_m4_m4(rv3d->persinv, rv3d->persmat);
2284         invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
2285         
2286         glClear(GL_DEPTH_BUFFER_BIT);
2287         
2288         glLoadMatrixf(rv3d->viewmat);
2289 //      persp(PERSP_STORE);  /* store correct view for persp(PERSP_VIEW) calls */
2290         
2291         if (rv3d->rflag & RV3D_CLIPPING) {
2292                 ED_view3d_clipping_set(rv3d);
2293         }
2294         
2295         v3d->zbuf = TRUE;
2296         glEnable(GL_DEPTH_TEST);
2297         
2298         /* draw set first */
2299         if (scene->set) {
2300                 Scene *sce_iter;
2301                 for (SETLOOPER(scene->set, sce_iter, base)) {
2302                         if (v3d->lay & base->lay) {
2303                                 if (func == NULL || func(base)) {
2304                                         draw_object(scene, ar, v3d, base, 0);
2305                                         if (base->object->transflag & OB_DUPLI) {
2306                                                 draw_dupli_objects_color(scene, ar, v3d, base, TH_WIRE);
2307                                         }
2308                                 }
2309                         }
2310                 }
2311         }
2312         
2313         for (base = scene->base.first; base; base = base->next) {
2314                 if (v3d->lay & base->lay) {
2315                         if (func == NULL || func(base)) {
2316                                 /* dupli drawing */
2317                                 if (base->object->transflag & OB_DUPLI) {
2318                                         draw_dupli_objects(scene, ar, v3d, base);
2319                                 }
2320                                 draw_object(scene, ar, v3d, base, 0);
2321                         }
2322                 }
2323         }
2324         
2325         /* this isn't that nice, draw xray objects as if they are normal */
2326         if (v3d->afterdraw_transp.first ||
2327             v3d->afterdraw_xray.first ||
2328             v3d->afterdraw_xraytransp.first)
2329         {
2330                 View3DAfter *v3da, *next;
2331                 int mask_orig;
2332
2333                 v3d->xray = TRUE;
2334                 
2335                 /* transp materials can change the depth mask, see #21388 */
2336                 glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
2337
2338
2339                 if (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first) {
2340                         glDepthFunc(GL_ALWAYS); /* always write into the depth bufer, overwriting front z values */
2341                         for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) {
2342                                 next = v3da->next;
2343                                 draw_object(scene, ar, v3d, v3da->base, 0);
2344                         }
2345                         glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */
2346                 }
2347
2348                 /* draw 3 passes, transp/xray/xraytransp */
2349                 v3d->xray = FALSE;
2350                 v3d->transp = TRUE;
2351                 for (v3da = v3d->afterdraw_transp.first; v3da; v3da = next) {
2352                         next = v3da->next;
2353                         draw_object(scene, ar, v3d, v3da->base, 0);
2354                         BLI_remlink(&v3d->afterdraw_transp, v3da);
2355                         MEM_freeN(v3da);
2356                 }
2357
2358                 v3d->xray = TRUE;
2359                 v3d->transp = FALSE;
2360                 for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) {
2361                         next = v3da->next;
2362                         draw_object(scene, ar, v3d, v3da->base, 0);
2363                         BLI_remlink(&v3d->afterdraw_xray, v3da);
2364                         MEM_freeN(v3da);
2365                 }
2366
2367                 v3d->xray = TRUE;
2368                 v3d->transp = TRUE;
2369                 for (v3da = v3d->afterdraw_xraytransp.first; v3da; v3da = next) {
2370                         next = v3da->next;
2371                         draw_object(scene, ar, v3d, v3da->base, 0);
2372                         BLI_remlink(&v3d->afterdraw_xraytransp, v3da);
2373                         MEM_freeN(v3da);
2374                 }
2375
2376                 
2377                 v3d->xray = FALSE;
2378                 v3d->transp = FALSE;
2379
2380                 glDepthMask(mask_orig);
2381         }
2382         
2383         if (rv3d->rflag & RV3D_CLIPPING)
2384                 ED_view3d_clipping_disable();
2385         
2386         v3d->zbuf = zbuf;
2387         if (!v3d->zbuf) glDisable(GL_DEPTH_TEST);
2388
2389         U.glalphaclip = glalphaclip;
2390         v3d->flag = flag;
2391         U.obcenter_dia = obcenter_dia;
2392 }
2393
2394 typedef struct View3DShadow {
2395         struct View3DShadow *next, *prev;
2396         GPULamp *lamp;
2397 } View3DShadow;
2398
2399 static void gpu_render_lamp_update(Scene *scene, View3D *v3d, Object *ob, Object *par,
2400                                    float obmat[4][4], ListBase *shadows)
2401 {
2402         GPULamp *lamp;
2403         Lamp *la = (Lamp *)ob->data;
2404         View3DShadow *shadow;
2405         
2406         lamp = GPU_lamp_from_blender(scene, ob, par);
2407         
2408         if (lamp) {
2409                 GPU_lamp_update(lamp, ob->lay, (ob->restrictflag & OB_RESTRICT_RENDER), obmat);
2410                 GPU_lamp_update_colors(lamp, la->r, la->g, la->b, la->energy);
2411                 
2412                 if ((ob->lay & v3d->lay) && GPU_lamp_has_shadow_buffer(lamp)) {
2413                         shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow");
2414                         shadow->lamp = lamp;
2415                         BLI_addtail(shadows, shadow);
2416                 }
2417         }
2418 }
2419
2420 static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
2421 {
2422         ListBase shadows;
2423         View3DShadow *shadow;
2424         Scene *sce_iter;
2425         Base *base;
2426         Object *ob;
2427         
2428         shadows.first = shadows.last = NULL;
2429         
2430         /* update lamp transform and gather shadow lamps */
2431         for (SETLOOPER(scene, sce_iter, base)) {
2432                 ob = base->object;
2433                 
2434                 if (ob->type == OB_LAMP)
2435                         gpu_render_lamp_update(scene, v3d, ob, NULL, ob->obmat, &shadows);
2436                 
2437                 if (ob->transflag & OB_DUPLI) {
2438                         DupliObject *dob;
2439                         ListBase *lb = object_duplilist(scene, ob, false);
2440                         
2441                         for (dob = lb->first; dob; dob = dob->next)
2442                                 if (dob->ob->type == OB_LAMP)
2443                                         gpu_render_lamp_update(scene, v3d, dob->ob, ob, dob->mat, &shadows);
2444                         
2445                         free_object_duplilist(lb);
2446                 }
2447         }
2448         
2449         /* render shadows after updating all lamps, nested object_duplilist
2450          * don't work correct since it's replacing object matrices */
2451         for (shadow = shadows.first; shadow; shadow = shadow->next) {
2452                 /* this needs to be done better .. */
2453                 float viewmat[4][4], winmat[4][4];
2454                 int drawtype, lay, winsize, flag2 = v3d->flag2;
2455                 ARegion ar = {NULL};
2456                 RegionView3D rv3d = {{{0}}};
2457                 
2458                 drawtype = v3d->drawtype;
2459                 lay = v3d->lay;
2460                 
2461                 v3d->drawtype = OB_SOLID;
2462                 v3d->lay &= GPU_lamp_shadow_layer(shadow->lamp);
2463                 v3d->flag2 &= ~V3D_SOLID_TEX;
2464                 v3d->flag2 |= V3D_RENDER_OVERRIDE | V3D_RENDER_SHADOW;
2465                 
2466                 GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat);
2467
2468                 ar.regiondata = &rv3d;
2469                 ar.regiontype = RGN_TYPE_WINDOW;
2470                 rv3d.persp = RV3D_CAMOB;
2471                 copy_m4_m4(rv3d.winmat, winmat);
2472                 copy_m4_m4(rv3d.viewmat, viewmat);
2473                 invert_m4_m4(rv3d.viewinv, rv3d.viewmat);
2474                 mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat);
2475                 invert_m4_m4(rv3d.persinv, rv3d.viewinv);
2476
2477                 /* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */
2478                 ED_view3d_draw_offscreen(scene, v3d, &ar, winsize, winsize, viewmat, winmat, false, false);
2479                 GPU_lamp_shadow_buffer_unbind(shadow->lamp);
2480                 
2481                 v3d->drawtype = drawtype;
2482                 v3d->lay = lay;
2483                 v3d->flag2 = flag2;
2484         }
2485         
2486         BLI_freelistN(&shadows);
2487 }
2488
2489 /* *********************** customdata **************** */
2490
2491 CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d)
2492 {
2493         CustomDataMask mask = 0;
2494
2495         if (ELEM(v3d->drawtype, OB_TEXTURE, OB_MATERIAL) ||
2496             ((v3d->drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX)))
2497         {
2498                 mask |= CD_MASK_MTFACE | CD_MASK_MCOL;
2499
2500                 if (BKE_scene_use_new_shading_nodes(scene)) {
2501                         if (v3d->drawtype == OB_MATERIAL)
2502                                 mask |= CD_MASK_ORCO;
2503                 }
2504                 else {
2505                         if (scene->gm.matmode == GAME_MAT_GLSL)
2506                                 mask |= CD_MASK_ORCO;
2507                 }
2508         }
2509
2510         return mask;
2511 }
2512
2513 /* goes over all modes and view3d settings */
2514 CustomDataMask ED_view3d_screen_datamask(bScreen *screen)
2515 {
2516         Scene *scene = screen->scene;
2517         CustomDataMask mask = CD_MASK_BAREMESH;
2518         ScrArea *sa;
2519         
2520         /* check if we need tfaces & mcols due to view mode */
2521         for (sa = screen->areabase.first; sa; sa = sa->next) {
2522                 if (sa->spacetype == SPACE_VIEW3D) {
2523                         mask |= ED_view3d_datamask(scene, (View3D *)sa->spacedata.first);
2524                 }
2525         }
2526
2527         return mask;
2528 }
2529
2530 void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
2531 {
2532         RegionView3D *rv3d = ar->regiondata;
2533
2534         /* setup window matrices */
2535         if (winmat)
2536                 copy_m4_m4(rv3d->winmat, winmat);
2537         else
2538                 setwinmatrixview3d(ar, v3d, NULL);
2539
2540         /* setup view matrix */
2541         if (viewmat)
2542                 copy_m4_m4(rv3d->viewmat, viewmat);
2543         else
2544                 setviewmatrixview3d(scene, v3d, rv3d);  /* note: calls BKE_object_where_is_calc for camera... */
2545
2546         /* update utilitity matrices */
2547         mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
2548         invert_m4_m4(rv3d->persinv, rv3d->persmat);
2549         invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
2550
2551         /* calculate pixelsize factor once, is used for lamps and obcenters */
2552         {
2553                 /* note:  '1.0f / len_v3(v1)'  replaced  'len_v3(rv3d->viewmat[0])'
2554                  * because of float point precision problems at large values [#23908] */
2555                 float v1[3], v2[3];
2556                 float len_px, len_sc;
2557
2558                 v1[0] = rv3d->persmat[0][0];
2559                 v1[1] = rv3d->persmat[1][0];
2560                 v1[2] = rv3d->persmat[2][0];
2561
2562                 v2[0] = rv3d->persmat[0][1];
2563                 v2[1] = rv3d->persmat[1][1];
2564                 v2[2] = rv3d->persmat[2][1];
2565
2566                 len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
2567                 len_sc = (float)MAX2(ar->winx, ar->winy);
2568
2569                 rv3d->pixsize = len_px / len_sc;
2570         }
2571 }
2572
2573 static void view3d_main_area_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
2574 {
2575         RegionView3D *rv3d = ar->regiondata;
2576
2577         ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat);
2578
2579         /* set for opengl */
2580         glMatrixMode(GL_PROJECTION);
2581         glLoadMatrixf(rv3d->winmat);
2582         glMatrixMode(GL_MODELVIEW);
2583         glLoadMatrixf(rv3d->viewmat);
2584 }
2585
2586 void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
2587 {
2588         /* shadow buffers, before we setup matrices */
2589         if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype))
2590                 gpu_update_lamps_shadows(scene, v3d);
2591 }
2592
2593 /* ED_view3d_draw_offscreen_init should be called before this to initialize
2594  * stuff like shadow buffers
2595  */
2596 void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy,
2597                               float viewmat[4][4], float winmat[4][4], bool do_bgpic, bool do_sky)
2598 {
2599         RegionView3D *rv3d = ar->regiondata;
2600         Base *base;
2601         int bwinx, bwiny;
2602         rcti brect;
2603
2604         glPushMatrix();
2605
2606         /* set temporary new size */
2607         bwinx = ar->winx;
2608         bwiny = ar->winy;
2609         brect = ar->winrct;
2610         
2611         ar->winx = winx;
2612         ar->winy = winy;
2613         ar->winrct.xmin = 0;
2614         ar->winrct.ymin = 0;
2615         ar->winrct.xmax = winx;
2616         ar->winrct.ymax = winy;
2617
2618         /* set theme */
2619         UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW);
2620         
2621         /* set flags */
2622         G.f |= G_RENDER_OGL;
2623
2624         /* free images which can have changed on frame-change
2625          * warning! can be slow so only free animated images - campbell */
2626         GPU_free_images_anim();
2627
2628         /* clear opengl buffers */
2629         if (do_sky) {
2630                 float sky_color[3];
2631
2632                 ED_view3d_offscreen_sky_color_get(scene, sky_color);
2633                 glClearColor(sky_color[0], sky_color[1], sky_color[2], 1.0f);
2634         }
2635         else {
2636                 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
2637         }
2638
2639         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2640
2641         /* setup view matrices */
2642         view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
2643
2644         if (rv3d->rflag & RV3D_CLIPPING)
2645                 view3d_draw_clipping(rv3d);
2646
2647         /* set zbuffer */
2648         if (v3d->drawtype > OB_WIRE) {
2649                 v3d->zbuf = TRUE;
2650                 glEnable(GL_DEPTH_TEST);
2651         }
2652         else
2653                 v3d->zbuf = FALSE;
2654
2655         /* important to do before clipping */
2656         if (do_bgpic) {
2657                 view3d_draw_bgpic_test(scene, ar, v3d, false, false);
2658         }
2659
2660         if (rv3d->rflag & RV3D_CLIPPING)
2661                 ED_view3d_clipping_set(rv3d);
2662
2663         /* draw set first */
2664         if (scene->set) {
2665                 Scene *sce_iter;
2666                 for (SETLOOPER(scene->set, sce_iter, base)) {
2667                         if (v3d->lay & base->lay) {
2668                                 UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f);
2669                                 draw_object(scene, ar, v3d, base, DRAW_CONSTCOLOR | DRAW_SCENESET);
2670                                 
2671                                 if (base->object->transflag & OB_DUPLI)
2672                                         draw_dupli_objects_color(scene, ar, v3d, base, TH_WIRE);
2673                         }
2674                 }
2675         }
2676         
2677         /* then draw not selected and the duplis, but skip editmode object */
2678         for (base = scene->base.first; base; base = base->next) {
2679                 if (v3d->lay & base->lay) {
2680                         /* dupli drawing */
2681                         if (base->object->transflag & OB_DUPLI)
2682                                 draw_dupli_objects(scene, ar, v3d, base);
2683
2684                         draw_object(scene, ar, v3d, base, 0);
2685                 }
2686         }
2687
2688         /* must be before xray draw which clears the depth buffer */
2689         if (v3d->flag2 & V3D_SHOW_GPENCIL) {
2690                 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
2691                 draw_gpencil_view3d(scene, v3d, ar, true);
2692                 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
2693         }
2694
2695         /* transp and X-ray afterdraw stuff */
2696         if (v3d->afterdraw_transp.first)     view3d_draw_transp(scene, ar, v3d);
2697         if (v3d->afterdraw_xray.first)       view3d_draw_xray(scene, ar, v3d, 1);       /* clears zbuffer if it is used! */
2698         if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, ar, v3d, 1);
2699
2700         if (rv3d->rflag & RV3D_CLIPPING)
2701                 ED_view3d_clipping_disable();
2702
2703         /* important to do after clipping */
2704         if (do_bgpic) {
2705                 view3d_draw_bgpic_test(scene, ar, v3d, true, false);
2706         }
2707
2708         /* cleanup */
2709         if (v3d->zbuf) {
2710                 v3d->zbuf = FALSE;
2711                 glDisable(GL_DEPTH_TEST);
2712         }
2713
2714         /* draw grease-pencil stuff */
2715         ED_region_pixelspace(ar);
2716
2717
2718         if (v3d->flag2 & V3D_SHOW_GPENCIL) {
2719                 /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */
2720                 draw_gpencil_view3d(scene, v3d, ar, false);
2721         }
2722
2723         /* freeing the images again here could be done after the operator runs, leaving for now */
2724         GPU_free_images_anim();
2725
2726         /* restore size */
2727         ar->winx = bwinx;
2728         ar->winy = bwiny;
2729         ar->winrct = brect;
2730
2731         glPopMatrix();
2732
2733         /* XXX, without this the sequencer flickers with opengl draw enabled, need to find out why - campbell */
2734         glColor4ub(255, 255, 255, 255);
2735
2736         G.f &= ~G_RENDER_OGL;
2737 }
2738
2739 /* get a color used for offscreen sky, returns color in sRGB space */
2740 void ED_view3d_offscreen_sky_color_get(Scene *scene, float sky_color[3])
2741 {
2742         if (scene->world)
2743                 linearrgb_to_srgb_v3_v3(sky_color, &scene->world->horr);
2744         else
2745                 UI_GetThemeColor3fv(TH_BACK, sky_color);
2746 }
2747
2748 /* utility func for ED_view3d_draw_offscreen */
2749 ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, unsigned int flag,
2750                                       bool draw_background, int alpha_mode, char err_out[256])
2751 {
2752         RegionView3D *rv3d = ar->regiondata;
2753         ImBuf *ibuf;
2754         GPUOffScreen *ofs;
2755         bool draw_sky = (alpha_mode == R_ADDSKY);
2756         
2757         /* state changes make normal drawing go weird otherwise */
2758         glPushAttrib(GL_LIGHTING_BIT);
2759
2760         /* bind */
2761         ofs = GPU_offscreen_create(sizex, sizey, err_out);
2762         if (ofs == NULL) {
2763                 glPopAttrib();
2764                 return NULL;
2765         }
2766
2767         ED_view3d_draw_offscreen_init(scene, v3d);
2768
2769         GPU_offscreen_bind(ofs);
2770
2771         /* render 3d view */
2772         if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
2773                 CameraParams params;
2774
2775                 BKE_camera_params_init(&params);
2776                 BKE_camera_params_from_object(&params, v3d->camera);
2777                 BKE_camera_params_compute_viewplane(&params, sizex, sizey, scene->r.xasp, scene->r.yasp);
2778                 BKE_camera_params_compute_matrix(&params);
2779
2780                 ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, params.winmat, draw_background, draw_sky);
2781         }
2782         else {
2783                 ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, NULL, draw_background, draw_sky);
2784         }
2785
2786         /* read in pixels & stamp */
2787         ibuf = IMB_allocImBuf(sizex, sizey, 32, flag);
2788
2789         if (ibuf->rect_float)
2790                 GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float);
2791         else if (ibuf->rect)
2792                 GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect);
2793
2794         /* unbind */
2795         GPU_offscreen_unbind(ofs);
2796         GPU_offscreen_free(ofs);
2797
2798         glPopAttrib();
2799         
2800         if (ibuf->rect_float && ibuf->rect)
2801                 IMB_rect_from_float(ibuf);
2802         
2803         return ibuf;
2804 }
2805
2806 /* creates own 3d views, used by the sequencer */
2807 ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int width, int height, unsigned int flag, int drawtype,
2808                                              bool use_solid_tex, bool draw_background, int alpha_mode, char err_out[256])
2809 {
2810         View3D v3d = {NULL};
2811         ARegion ar = {NULL};
2812         RegionView3D rv3d = {{{0}}};
2813
2814         /* connect data */
2815         v3d.regionbase.first = v3d.regionbase.last = &ar;
2816         ar.regiondata = &rv3d;
2817         ar.regiontype = RGN_TYPE_WINDOW;
2818
2819         v3d.camera = camera;
2820         v3d.lay = scene->lay;
2821         v3d.drawtype = drawtype;
2822         v3d.flag2 = V3D_RENDER_OVERRIDE;
2823
2824         if (use_solid_tex)
2825                 v3d.flag2 |= V3D_SOLID_TEX;
2826
2827         rv3d.persp = RV3D_CAMOB;
2828
2829         copy_m4_m4(rv3d.viewinv, v3d.camera->obmat);
2830         normalize_m4(rv3d.viewinv);
2831         invert_m4_m4(rv3d.viewmat, rv3d.viewinv);
2832
2833         {
2834                 CameraParams params;
2835
2836                 BKE_camera_params_init(&params);
2837                 BKE_camera_params_from_object(&params, v3d.camera);
2838                 BKE_camera_params_compute_viewplane(&params, width, height, scene->r.xasp, scene->r.yasp);
2839                 BKE_camera_params_compute_matrix(&params);
2840
2841                 copy_m4_m4(rv3d.winmat, params.winmat);
2842                 v3d.near = params.clipsta;
2843                 v3d.far = params.clipend;
2844                 v3d.lens = params.lens;
2845         }
2846
2847         mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat);
2848         invert_m4_m4(rv3d.persinv, rv3d.viewinv);
2849
2850         return ED_view3d_draw_offscreen_imbuf(scene, &v3d, &ar, width, height, flag,
2851                                               draw_background, alpha_mode, err_out);
2852
2853         // seq_view3d_cb(scene, cfra, render_size, seqrectx, seqrecty);
2854 }
2855
2856
2857 /* NOTE: the info that this uses is updated in ED_refresh_viewport_fps(), 
2858  * which currently gets called during SCREEN_OT_animation_step.
2859  */
2860 static void draw_viewport_fps(Scene *scene, rcti *rect)
2861 {
2862         ScreenFrameRateInfo *fpsi = scene->fps_info;
2863         float fps;
2864         char printable[16];
2865         int i, tot;
2866         
2867         if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime)
2868                 return;
2869         
2870         printable[0] = '\0';
2871         
2872 #if 0
2873         /* this is too simple, better do an average */
2874         fps = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime))
2875 #else
2876         fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime));
2877         
2878         for (i = 0, tot = 0, fps = 0.0f; i < REDRAW_FRAME_AVERAGE; i++) {
2879                 if (fpsi->redrawtimes_fps[i]) {
2880                         fps += fpsi->redrawtimes_fps[i];
2881                         tot++;
2882                 }
2883         }
2884         if (tot) {
2885                 fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE;
2886                 
2887                 //fpsi->redrawtime_index++;
2888                 //if (fpsi->redrawtime >= REDRAW_FRAME_AVERAGE)
2889                 //      fpsi->redrawtime = 0;
2890                 
2891                 fps = fps / tot;
2892         }
2893 #endif
2894
2895         /* is this more than half a frame behind? */
2896         if (fps + 0.5f < (float)(FPS)) {
2897                 UI_ThemeColor(TH_REDALERT);
2898                 BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps);
2899         }
2900         else {
2901                 UI_ThemeColor(TH_TEXT_HI);
2902                 BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f));
2903         }
2904
2905 #ifdef WITH_INTERNATIONAL
2906         BLF_draw_default(rect->xmin + U.widget_unit,  rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable));
2907 #else
2908         BLF_draw_default_ascii(rect->xmin + U.widget_unit,  rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable));
2909 #endif
2910 }
2911
2912 static void view3d_main_area_draw_objects(const bContext *C, ARegion *ar, const char **grid_unit);
2913
2914 static bool view3d_main_area_do_render_draw(Scene *scene)
2915 {
2916         RenderEngineType *type = RE_engines_find(scene->r.engine);
2917
2918         return (type && type->view_update && type->view_draw);
2919 }
2920
2921 bool ED_view3d_calc_render_border(Scene *scene, View3D *v3d, ARegion *ar, rcti *rect)
2922 {
2923         RegionView3D *rv3d = ar->regiondata;
2924         rctf viewborder;
2925         bool use_border;
2926
2927         /* test if there is a 3d view rendering */
2928         if (v3d->drawtype != OB_RENDER || !view3d_main_area_do_render_draw(scene))
2929                 return false;
2930
2931         /* test if there is a border render */
2932         if (rv3d->persp == RV3D_CAMOB)
2933                 use_border = (scene->r.mode & R_BORDER) != 0;
2934         else
2935                 use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0;
2936         
2937         if (!use_border)
2938                 return false;
2939
2940         /* compute border */
2941         if (rv3d->persp == RV3D_CAMOB) {
2942                 ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false);
2943
2944                 rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder);
2945                 rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder);
2946                 rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder);
2947                 rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder);
2948         }
2949         else {
2950                 rect->xmin = v3d->render_border.xmin * ar->winx;
2951                 rect->xmax = v3d->render_border.xmax * ar->winx;
2952                 rect->ymin = v3d->render_border.ymin * ar->winy;
2953                 rect->ymax = v3d->render_border.ymax * ar->winy;
2954         }
2955
2956         BLI_rcti_translate(rect, ar->winrct.xmin, ar->winrct.ymin);
2957         BLI_rcti_isect(&ar->winrct, rect, rect);
2958
2959         return true;
2960 }
2961
2962 static bool view3d_main_area_draw_engine(const bContext *C, ARegion *ar, bool clip_border, rcti *border_rect)
2963 {
2964         Scene *scene = CTX_data_scene(C);
2965         View3D *v3d = CTX_wm_view3d(C);
2966         RegionView3D *rv3d = CTX_wm_region_view3d(C);
2967         RenderEngineType *type;
2968         GLint scissor[4];
2969
2970         /* create render engine */
2971         if (!rv3d->render_engine) {
2972                 RenderEngine *engine;
2973
2974                 type = RE_engines_find(scene->r.engine);
2975
2976                 if (!(type->view_update && type->view_draw))
2977                         return false;
2978
2979                 engine = RE_engine_create_ex(type, true);
2980
2981                 engine->tile_x = scene->r.tilex;
2982                 engine->tile_y = scene->r.tiley;
2983
2984                 type->view_update(engine, C);
2985
2986                 rv3d->render_engine = engine;
2987         }
2988
2989         /* setup view matrices */
2990         view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL);
2991
2992         /* background draw */
2993         ED_region_pixelspace(ar);
2994
2995         if (clip_border) {
2996                 /* for border draw, we only need to clear a subset of the 3d view */
2997                 if (border_rect->xmax > border_rect->xmin && border_rect->ymax > border_rect->ymin) {
2998                         glGetIntegerv(GL_SCISSOR_BOX, scissor);
2999                         glScissor(border_rect->xmin, border_rect->ymin,
3000                                   BLI_rcti_size_x(border_rect), BLI_rcti_size_y(border_rect));
3001                 }
3002                 else {
3003                         return false;
3004                 }
3005         }
3006
3007         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
3008         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3009
3010         if (v3d->flag & V3D_DISPBGPICS)
3011                 view3d_draw_bgpic(scene, ar, v3d, false, true);
3012         else
3013                 fdrawcheckerboard(0, 0, ar->winx, ar->winy);
3014
3015         /* render result draw */
3016         type = rv3d->render_engine->type;
3017         type->view_draw(rv3d->render_engine, C);
3018
3019         if (v3d->flag & V3D_DISPBGPICS)
3020                 view3d_draw_bgpic(scene, ar, v3d, true, true);
3021
3022         if (clip_border) {
3023                 /* restore scissor as it was before */
3024                 glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
3025         }
3026
3027         return true;
3028 }
3029
3030 static void view3d_main_area_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border)
3031 {
3032         float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f};
3033
3034         if (!rv3d->render_engine || !rv3d->render_engine->text[0])
3035                 return;
3036         
3037         if (render_border) {
3038                 /* draw darkened background color. no alpha because border render does
3039                  * partial redraw and will not redraw the area behind this info bar */
3040                 float alpha = 1.0f - fill_color[3];
3041         
3042                 if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) {
3043                         Camera *ca = v3d->camera->data;
3044
3045                         if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT))
3046                                 alpha *= (1.0f - ca->passepartalpha);
3047                 }
3048
3049                 UI_GetThemeColor3fv(TH_HIGH_GRAD, fill_color);
3050                 mul_v3_fl(fill_color, alpha);
3051                 fill_color[3] = 1.0f;
3052         }
3053
3054         ED_region_info_draw(ar, rv3d->render_engine->text, 1, fill_color);
3055 }
3056
3057 /*
3058  * Function to clear the view
3059  */
3060 static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
3061 {
3062         /* clear background */
3063         if (scene->world && (v3d->flag2 & V3D_RENDER_OVERRIDE)) {  /* clear with solid color */
3064                 if (scene->world->skytype & WO_SKYBLEND) {  /* blend sky */
3065                         int x, y;
3066                         float col_hor[3];
3067                         float col_zen[3];
3068
3069 #define VIEWGRAD_RES_X 16
3070 #define VIEWGRAD_RES_Y 16
3071
3072                         GLubyte grid_col[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][4];
3073                         static float   grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3];
3074                         static GLushort indices[VIEWGRAD_RES_X - 1][VIEWGRAD_RES_X - 1][4];
3075                         static bool buf_calculated = false;
3076
3077                         IMB_colormanagement_pixel_to_display_space_v3(col_hor, &scene->world->horr, &scene->view_settings,
3078                                                                       &scene->display_settings);
3079                         IMB_colormanagement_pixel_to_display_space_v3(col_zen, &scene->world->zenr, &scene->view_settings,
3080                                                                       &scene->display_settings);
3081
3082                         glMatrixMode(GL_PROJECTION);
3083                         glPushMatrix();
3084                         glLoadIdentity();
3085                         glMatrixMode(GL_MODELVIEW);
3086                         glPushMatrix();
3087                         glLoadIdentity();
3088
3089                         glShadeModel(GL_SMOOTH);