2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2008 Blender Foundation.
19 * All rights reserved.
22 * Contributor(s): Blender Foundation
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/editors/space_view3d/view3d_draw.c
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_mesh_types.h"
41 #include "DNA_key_types.h"
42 #include "DNA_lamp_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_world_types.h"
45 #include "DNA_brush_types.h"
47 #include "MEM_guardedalloc.h"
49 #include "BLI_blenlib.h"
51 #include "BLI_jitter.h"
52 #include "BLI_utildefines.h"
53 #include "BLI_endian_switch.h"
54 #include "BLI_threads.h"
57 #include "BKE_camera.h"
58 #include "BKE_context.h"
59 #include "BKE_customdata.h"
60 #include "BKE_DerivedMesh.h"
61 #include "BKE_image.h"
64 #include "BKE_object.h"
65 #include "BKE_global.h"
66 #include "BKE_paint.h"
67 #include "BKE_scene.h"
68 #include "BKE_screen.h"
70 #include "BKE_movieclip.h"
72 #include "RE_engine.h"
74 #include "IMB_imbuf_types.h"
75 #include "IMB_imbuf.h"
76 #include "IMB_colormanagement.h"
79 #include "BIF_glutil.h"
84 #include "BLT_translation.h"
86 #include "ED_armature.h"
87 #include "ED_keyframing.h"
88 #include "ED_gpencil.h"
89 #include "ED_screen.h"
90 #include "ED_space_api.h"
91 #include "ED_screen_types.h"
92 #include "ED_transform.h"
94 #include "UI_interface.h"
95 #include "UI_interface_icons.h"
96 #include "UI_resources.h"
99 #include "GPU_framebuffer.h"
100 #include "GPU_material.h"
101 #include "GPU_compositing.h"
102 #include "GPU_extensions.h"
103 #include "GPU_select.h"
105 #include "view3d_intern.h" /* own include */
108 static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d);
109 static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar);
110 static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
111 float winmat[4][4], const char *viewname);
113 /* handy utility for drawing shapes in the viewport for arbitrary code.
114 * could add lines and points too */
115 // #define DEBUG_DRAW
117 static void bl_debug_draw(void);
118 /* add these locally when using these functions for testing */
119 extern void bl_debug_draw_quad_clear(void);
120 extern void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]);
121 extern void bl_debug_draw_edge_add(const float v0[3], const float v1[3]);
122 extern void bl_debug_color_set(const unsigned int col);
125 void circf(float x, float y, float rad)
127 GLUquadricObj *qobj = gluNewQuadric();
129 gluQuadricDrawStyle(qobj, GLU_FILL);
133 glTranslatef(x, y, 0.0);
135 gluDisk(qobj, 0.0, rad, 32, 1);
139 gluDeleteQuadric(qobj);
142 void circ(float x, float y, float rad)
144 GLUquadricObj *qobj = gluNewQuadric();
146 gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
150 glTranslatef(x, y, 0.0);
152 gluDisk(qobj, 0.0, rad, 32, 1);
156 gluDeleteQuadric(qobj);
160 /* ********* custom clipping *********** */
162 static void view3d_draw_clipping(RegionView3D *rv3d)
164 BoundBox *bb = rv3d->clipbb;
167 const unsigned int clipping_index[6][4] = {
176 /* fill in zero alpha for rendering & re-projection [#31530] */
177 unsigned char col[4];
178 UI_GetThemeColor4ubv(TH_V3D_CLIPPING_BORDER, col);
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);
190 void ED_view3d_clipping_set(RegionView3D *rv3d)
193 const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6;
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);
203 /* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */
204 void ED_view3d_clipping_disable(void)
208 for (a = 0; a < 6; a++) {
209 glDisable(GL_CLIP_PLANE0 + a);
212 void ED_view3d_clipping_enable(void)
216 for (a = 0; a < 6; a++) {
217 glEnable(GL_CLIP_PLANE0 + a);
221 static bool view3d_clipping_test(const float co[3], const float clip[6][4])
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)
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(const RegionView3D *rv3d, const float co[3], const bool is_local)
236 return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip);
239 /* ********* end custom clipping *********** */
242 static void drawgrid_draw(ARegion *ar, double wx, double wy, double x, double y, double dx)
251 verts[1][1] = (double)ar->winy;
254 verts[0][0] = verts[1][0] = x - dx * floor(x / dx);
255 glEnableClientState(GL_VERTEX_ARRAY);
256 glVertexPointer(2, GL_DOUBLE, 0, verts);
258 while (verts[0][0] < ar->winx) {
259 glDrawArrays(GL_LINES, 0, 2);
260 verts[0][0] = verts[1][0] = verts[0][0] + dx;
265 verts[1][0] = (double)ar->winx;
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;
274 glDisableClientState(GL_VERTEX_ARRAY);
277 #define GRID_MIN_PX_D 6.0
278 #define GRID_MIN_PX_F 6.0f
280 static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit)
282 /* extern short bgpicmode; */
283 RegionView3D *rv3d = ar->regiondata;
284 double wx, wy, x, y, fw, fx, fy, dx;
286 unsigned char col[3], col2[3];
288 fx = rv3d->persmat[3][0];
289 fy = rv3d->persmat[3][1];
290 fw = rv3d->persmat[3][3];
292 wx = (ar->winx / 2.0); /* because of rounding errors, grid at wrong location */
293 wy = (ar->winy / 2.0);
298 vec4[0] = vec4[1] = v3d->grid;
302 mul_m4_v4d(rv3d->persmat, vec4);
307 dx = fabs(x - (wx) * fx / fw);
308 if (dx == 0) dx = fabs(y - (wy) * fy / fw);
312 glDepthMask(GL_FALSE); /* disable write in zbuffer */
315 UI_ThemeColor(TH_GRID);
318 /* Use GRID_MIN_PX * 2 for units because very very small grid
319 * items are less useful when dealing with units */
325 bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len);
330 double scalar = bUnit_GetScaler(usys, i);
332 dx_scalar = dx * scalar / (double)unit->scale_length;
333 if (dx_scalar < (GRID_MIN_PX_D * 2.0))
336 /* Store the smallest drawn grid size units name so users know how big each grid cell is */
337 if (*grid_unit == NULL) {
338 *grid_unit = bUnit_GetNameDisplay(usys, i);
339 rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length);
341 blend_fac = 1.0f - ((GRID_MIN_PX_F * 2.0f) / (float)dx_scalar);
343 /* tweak to have the fade a bit nicer */
344 blend_fac = (blend_fac * blend_fac) * 2.0f;
345 CLAMP(blend_fac, 0.3f, 1.0f);
348 UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, blend_fac);
350 drawgrid_draw(ar, wx, wy, x, y, dx_scalar);
355 const double sublines = v3d->gridsubdiv;
356 const float sublines_fl = v3d->gridsubdiv;
358 if (dx < GRID_MIN_PX_D) {
359 rv3d->gridview *= sublines_fl;
362 if (dx < GRID_MIN_PX_D) {
363 rv3d->gridview *= sublines_fl;
366 if (dx < GRID_MIN_PX_D) {
367 rv3d->gridview *= sublines_fl;
369 if (dx < GRID_MIN_PX_D) {
373 UI_ThemeColor(TH_GRID);
374 drawgrid_draw(ar, wx, wy, x, y, dx);
377 else { /* start blending out */
378 UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
379 drawgrid_draw(ar, wx, wy, x, y, dx);
381 UI_ThemeColor(TH_GRID);
382 drawgrid_draw(ar, wx, wy, x, y, sublines * dx);
385 else { /* start blending out (GRID_MIN_PX < dx < (GRID_MIN_PX * 10)) */
386 UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
387 drawgrid_draw(ar, wx, wy, x, y, dx);
389 UI_ThemeColor(TH_GRID);
390 drawgrid_draw(ar, wx, wy, x, y, sublines * dx);
394 if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */
395 rv3d->gridview /= sublines_fl;
397 if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */
398 rv3d->gridview /= sublines_fl;
400 if (dx > (GRID_MIN_PX_D * 10.0)) {
401 UI_ThemeColor(TH_GRID);
402 drawgrid_draw(ar, wx, wy, x, y, dx);
405 UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
406 drawgrid_draw(ar, wx, wy, x, y, dx);
407 UI_ThemeColor(TH_GRID);
408 drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
412 UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
413 drawgrid_draw(ar, wx, wy, x, y, dx);
414 UI_ThemeColor(TH_GRID);
415 drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
419 UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0));
420 drawgrid_draw(ar, wx, wy, x, y, dx);
421 UI_ThemeColor(TH_GRID);
422 drawgrid_draw(ar, wx, wy, x, y, dx * sublines);
430 UI_GetThemeColor3ubv(TH_GRID, col);
435 /* horizontal line */
436 if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
437 UI_make_axis_color(col, col2, 'Y');
438 else UI_make_axis_color(col, col2, 'X');
441 fdrawline(0.0, y, (float)ar->winx, y);
444 if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
445 UI_make_axis_color(col, col2, 'Y');
446 else UI_make_axis_color(col, col2, 'Z');
449 fdrawline(x, 0.0, x, (float)ar->winy);
451 glDepthMask(GL_TRUE); /* enable write in zbuffer */
455 /** could move this elsewhere, but tied into #ED_view3d_grid_scale */
456 float ED_scene_grid_scale(Scene *scene, const char **grid_unit)
459 if (scene->unit.system) {
463 bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
466 int i = bUnit_GetBaseUnit(usys);
468 *grid_unit = bUnit_GetNameDisplay(usys, i);
469 return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length;
476 float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit)
478 return v3d->grid * ED_scene_grid_scale(scene, grid_unit);
481 static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth)
483 float grid, grid_scale;
484 unsigned char col_grid[3];
485 const int gridlines = v3d->gridlines / 2;
487 if (v3d->gridlines < 3) return;
489 /* use 'grid_scale' instead of 'v3d->grid' from now on */
490 grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit);
491 grid = gridlines * grid_scale;
494 glDepthMask(GL_FALSE);
496 UI_GetThemeColor3ubv(TH_GRID, col_grid);
500 /* draw the Y axis and/or grid lines */
501 if (v3d->gridflag & V3D_SHOW_FLOOR) {
502 const int sublines = v3d->gridsubdiv;
503 float vert[4][3] = {{0.0f}};
504 unsigned char col_bg[3];
505 unsigned char col_grid_emphasise[3], col_grid_light[3];
507 int prev_emphasise = -1;
509 UI_GetThemeColor3ubv(TH_BACK, col_bg);
511 /* emphasise division lines lighter instead of darker, if background is darker than grid */
512 UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10);
513 UI_GetColorPtrShade3ubv(col_grid, col_grid_emphasise,
514 (((col_grid[0] + col_grid[1] + col_grid[2]) + 30) >
515 (col_bg[0] + col_bg[1] + col_bg[2])) ? 20 : -10);
518 vert[0][0] = vert[2][1] = grid;
519 vert[1][0] = vert[3][1] = -grid;
521 glEnableClientState(GL_VERTEX_ARRAY);
522 glVertexPointer(3, GL_FLOAT, 0, vert);
524 for (a = -gridlines; a <= gridlines; a++) {
525 const float line = a * grid_scale;
526 const int is_emphasise = (a % sublines) == 0;
528 if (is_emphasise != prev_emphasise) {
529 glColor3ubv(is_emphasise ? col_grid_emphasise : col_grid_light);
530 prev_emphasise = is_emphasise;
533 /* set variable axis */
534 vert[0][1] = vert[1][1] = vert[2][0] = vert[3][0] = line;
536 glDrawArrays(GL_LINES, 0, 4);
539 glDisableClientState(GL_VERTEX_ARRAY);
542 /* draw the Z axis line */
543 /* check for the 'show Z axis' preference */
544 if (v3d->gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) {
547 for (axis = 0; axis < 3; axis++) {
548 if (v3d->gridflag & (V3D_SHOW_X << axis)) {
550 unsigned char tcol[3];
552 UI_make_axis_color(col_grid, tcol, 'X' + axis);
565 glDepthMask(GL_TRUE);
569 static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d)
573 /* we don't want the clipping for cursor */
574 if (ED_view3d_project_int_global(ar, ED_view3d_cursor3d_get(scene, v3d), co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
575 const float f5 = 0.25f * U.widget_unit;
576 const float f10 = 0.5f * U.widget_unit;
577 const float f20 = U.widget_unit;
582 circ((float)co[0], (float)co[1], f10);
585 circ((float)co[0], (float)co[1], f10);
588 UI_ThemeColor(TH_VIEW_OVERLAY);
589 sdrawline(co[0] - f20, co[1], co[0] - f5, co[1]);
590 sdrawline(co[0] + f5, co[1], co[0] + f20, co[1]);
591 sdrawline(co[0], co[1] - f20, co[0], co[1] - f5);
592 sdrawline(co[0], co[1] + f5, co[0], co[1] + f20);
596 /* Draw a live substitute of the view icon, which is always shown
597 * colors copied from transform_manipulator.c, we should keep these matching. */
598 static void draw_view_axis(RegionView3D *rv3d, rcti *rect)
600 const float k = U.rvisize * U.pixelsize; /* axis size */
601 const float toll = 0.5; /* used to see when view is quasi-orthogonal */
602 float startx = k + 1.0f; /* axis center in screen coordinates, x=y */
603 float starty = k + 1.0f;
604 float ydisp = 0.0; /* vertical displacement to allow obj info text */
605 int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */
609 int axis_order[3] = {0, 1, 2};
612 startx += rect->xmin;
613 starty += rect->ymin;
615 axis_sort_v3(rv3d->viewinv[2], axis_order);
617 /* thickness of lines is proportional to k */
621 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
623 for (axis_i = 0; axis_i < 3; axis_i++) {
624 int i = axis_order[axis_i];
625 const char axis_text[2] = {'x' + i, '\0'};
629 mul_qt_v3(rv3d->viewquat, vec);
633 UI_ThemeColorShadeAlpha(TH_AXIS_X + i, 0, bright);
635 glVertex2f(startx, starty + ydisp);
636 glVertex2f(startx + dx, starty + dy + ydisp);
639 if (fabsf(dx) > toll || fabsf(dy) > toll) {
640 BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, axis_text, 1);
642 /* BLF_draw_default disables blending */
650 #ifdef WITH_INPUT_NDOF
651 /* draw center and axis of rotation for ongoing 3D mouse navigation */
652 static void draw_rotation_guide(RegionView3D *rv3d)
654 float o[3]; /* center of rotation */
655 float end[3]; /* endpoints for drawing */
657 float color[4] = {0.0f, 0.4235f, 1.0f, 1.0f}; /* bright blue so it matches device LEDs */
659 negate_v3_v3(o, rv3d->ofs);
662 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
664 glEnable(GL_POINT_SMOOTH);
665 glDepthMask(0); /* don't overwrite zbuf */
667 if (rv3d->rot_angle != 0.0f) {
668 /* -- draw rotation axis -- */
669 float scaled_axis[3];
670 const float scale = rv3d->dist;
671 mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale);
674 glBegin(GL_LINE_STRIP);
675 color[3] = 0.0f; /* more transparent toward the ends */
677 add_v3_v3v3(end, o, scaled_axis);
681 color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */
682 /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */
685 color[3] = 0.5f; /* more opaque toward the center */
691 sub_v3_v3v3(end, o, scaled_axis);
695 /* -- draw ring around rotation center -- */
697 #define ROT_AXIS_DETAIL 13
699 const float s = 0.05f * scale;
700 const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL);
704 float q[4]; /* rotate ring so it's perpendicular to axis */
705 const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f;
707 const float up[3] = {0.0f, 0.0f, 1.0f};
708 float vis_angle, vis_axis[3];
710 cross_v3_v3v3(vis_axis, up, rv3d->rot_axis);
711 vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis));
712 axis_angle_to_quat(q, vis_axis, vis_angle);
715 color[3] = 0.25f; /* somewhat faint */
717 glBegin(GL_LINE_LOOP);
718 for (i = 0, angle = 0.0f; i < ROT_AXIS_DETAIL; ++i, angle += step) {
719 float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f};
730 #undef ROT_AXIS_DETAIL
733 color[3] = 1.0f; /* solid dot */
736 color[3] = 0.5f; /* see-through dot */
738 /* -- draw rotation center -- */
745 /* find screen coordinates for rotation center, then draw pretty icon */
746 mul_m4_v3(rv3d->persinv, rot_center);
747 UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN);
748 /* ^^ just playing around, does not work */
752 glDisable(GL_POINT_SMOOTH);
755 #endif /* WITH_INPUT_NDOF */
757 static void draw_view_icon(RegionView3D *rv3d, rcti *rect)
761 if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
762 icon = ICON_AXIS_TOP;
763 else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
764 icon = ICON_AXIS_FRONT;
765 else if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
766 icon = ICON_AXIS_SIDE;
770 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
772 UI_icon_draw(5.0 + rect->xmin, 5.0 + rect->ymin, icon);
777 static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d)
779 const char *name = NULL;
781 switch (rv3d->view) {
782 case RV3D_VIEW_FRONT:
783 if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Front Ortho");
784 else name = IFACE_("Front Persp");
787 if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Back Ortho");
788 else name = IFACE_("Back Persp");
791 if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Top Ortho");
792 else name = IFACE_("Top Persp");
794 case RV3D_VIEW_BOTTOM:
795 if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Bottom Ortho");
796 else name = IFACE_("Bottom Persp");
798 case RV3D_VIEW_RIGHT:
799 if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Right Ortho");
800 else name = IFACE_("Right Persp");
803 if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Left Ortho");
804 else name = IFACE_("Left Persp");
808 if (rv3d->persp == RV3D_CAMOB) {
809 if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) {
811 cam = v3d->camera->data;
812 if (cam->type == CAM_PERSP) {
813 name = IFACE_("Camera Persp");
815 else if (cam->type == CAM_ORTHO) {
816 name = IFACE_("Camera Ortho");
819 BLI_assert(cam->type == CAM_PANO);
820 name = IFACE_("Camera Pano");
824 name = IFACE_("Object as Camera");
828 name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Ortho") : IFACE_("User Persp");
836 static void draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect)
838 RegionView3D *rv3d = ar->regiondata;
839 const char *name = view3d_get_name(v3d, rv3d);
840 /* increase size for unicode languages (Chinese in utf-8...) */
841 #ifdef WITH_INTERNATIONAL
848 BLI_snprintf(tmpstr, sizeof(tmpstr), IFACE_("%s (Local)"), name);
852 UI_ThemeColor(TH_TEXT_HI);
853 #ifdef WITH_INTERNATIONAL
854 BLF_draw_default(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr));
856 BLF_draw_default_ascii(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr));
860 /* draw info beside axes in bottom left-corner:
861 * framenum, object name, bone name (if available), marker name (if available)
864 static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
866 const int cfra = CFRA;
867 const char *msg_pin = " (Pinned)";
868 const char *msg_sep = " : ";
873 short offset = 1.5f * UI_UNIT_X + rect->xmin;
875 s += sprintf(s, "(%d)", cfra);
880 * - 3 object names (MAX_NAME)
881 * - 2 BREAD_CRUMB_SEPARATORs (6)
882 * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room!
883 * - a marker name (MAX_NAME + 3)
886 /* get name of marker on current frame (if available) */
887 markern = BKE_scene_find_marker_name(scene, cfra);
889 /* check if there is an object */
892 s += BLI_strcpy_rlen(s, ob->id.name + 2);
894 /* name(s) to display depends on type of object */
895 if (ob->type == OB_ARMATURE) {
896 bArmature *arm = ob->data;
898 /* show name of active bone too (if possible) */
900 if (arm->act_edbone) {
901 s += BLI_strcpy_rlen(s, msg_sep);
902 s += BLI_strcpy_rlen(s, arm->act_edbone->name);
905 else if (ob->mode & OB_MODE_POSE) {
908 if (arm->act_bone->layer & arm->layer) {
909 s += BLI_strcpy_rlen(s, msg_sep);
910 s += BLI_strcpy_rlen(s, arm->act_bone->name);
915 else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) {
919 /* try to display active bone and active shapekey too (if they exist) */
921 if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) {
922 Object *armobj = BKE_object_pose_armature_get(ob);
923 if (armobj && armobj->mode & OB_MODE_POSE) {
924 bArmature *arm = armobj->data;
926 if (arm->act_bone->layer & arm->layer) {
927 s += BLI_strcpy_rlen(s, msg_sep);
928 s += BLI_strcpy_rlen(s, arm->act_bone->name);
934 key = BKE_key_from_object(ob);
936 kb = BLI_findlink(&key->block, ob->shapenr - 1);
938 s += BLI_strcpy_rlen(s, msg_sep);
939 s += BLI_strcpy_rlen(s, kb->name);
940 if (ob->shapeflag & OB_SHAPE_LOCK) {
941 s += BLI_strcpy_rlen(s, IFACE_(msg_pin));
947 /* color depends on whether there is a keyframe */
948 if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL))
949 UI_ThemeColor(TH_TIME_KEYFRAME);
950 else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra))
951 UI_ThemeColor(TH_TIME_GP_KEYFRAME);
953 UI_ThemeColor(TH_TEXT_HI);
957 if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra))
958 UI_ThemeColor(TH_TIME_GP_KEYFRAME);
960 UI_ThemeColor(TH_TEXT_HI);
964 s += sprintf(s, " <%s>", markern);
967 if (U.uiflag & USER_SHOW_ROTVIEWICON)
968 offset = U.widget_unit + (U.rvisize * 2) + rect->xmin;
970 BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info));
973 static void view3d_camera_border(
974 const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
975 rctf *r_viewborder, const bool no_shift, const bool no_zoom)
978 rctf rect_view, rect_camera;
980 /* get viewport viewplane */
981 BKE_camera_params_init(¶ms);
982 BKE_camera_params_from_view3d(¶ms, v3d, rv3d);
985 BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, 1.0f, 1.0f);
986 rect_view = params.viewplane;
988 /* get camera viewplane */
989 BKE_camera_params_init(¶ms);
990 /* fallback for non camera objects */
991 params.clipsta = v3d->near;
992 params.clipend = v3d->far;
993 BKE_camera_params_from_object(¶ms, v3d->camera);
995 params.shiftx = 0.0f;
996 params.shifty = 0.0f;
998 BKE_camera_params_compute_viewplane(¶ms, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp);
999 rect_camera = params.viewplane;
1001 /* get camera border within viewport */
1002 r_viewborder->xmin = ((rect_camera.xmin - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx;
1003 r_viewborder->xmax = ((rect_camera.xmax - rect_view.xmin) / BLI_rctf_size_x(&rect_view)) * ar->winx;
1004 r_viewborder->ymin = ((rect_camera.ymin - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy;
1005 r_viewborder->ymax = ((rect_camera.ymax - rect_view.ymin) / BLI_rctf_size_y(&rect_view)) * ar->winy;
1008 void ED_view3d_calc_camera_border_size(
1009 const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
1014 view3d_camera_border(scene, ar, v3d, rv3d, &viewborder, true, true);
1015 r_size[0] = BLI_rctf_size_x(&viewborder);
1016 r_size[1] = BLI_rctf_size_y(&viewborder);
1019 void ED_view3d_calc_camera_border(
1020 const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d,
1021 rctf *r_viewborder, const bool no_shift)
1023 view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false);
1026 static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float fac)
1028 float x3, y3, x4, y4;
1030 x3 = x1 + fac * (x2 - x1);
1031 y3 = y1 + fac * (y2 - y1);
1032 x4 = x1 + (1.0f - fac) * (x2 - x1);
1033 y4 = y1 + (1.0f - fac) * (y2 - y1);
1050 /* harmonious triangle */
1051 static void drawviewborder_triangle(float x1, float x2, float y1, float y2, const char golden, const char dir)
1060 ofs = w * (1.0f - (1.0f / 1.61803399f));
1065 if (dir == 'B') SWAP(float, y1, y2);
1071 glVertex2f(x1 + (w - ofs), y2);
1074 glVertex2f(x1 + ofs, y1);
1078 ofs = h * (1.0f - (1.0f / 1.61803399f));
1083 if (dir == 'B') SWAP(float, x1, x2);
1089 glVertex2f(x1, y1 + ofs);
1092 glVertex2f(x2, y1 + (h - ofs));
1097 static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
1099 float x1, x2, y1, y2;
1100 float x1i, x2i, y1i, y2i;
1104 RegionView3D *rv3d = ar->regiondata;
1106 if (v3d->camera == NULL)
1108 if (v3d->camera->type == OB_CAMERA)
1109 ca = v3d->camera->data;
1111 ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false);
1113 x1 = viewborder.xmin;
1114 y1 = viewborder.ymin;
1115 x2 = viewborder.xmax;
1116 y2 = viewborder.ymax;
1120 /* apply offsets so the real 3D camera shows through */
1122 /* note: quite un-scientific but without this bit extra
1123 * 0.0001 on the lower left the 2D border sometimes
1124 * obscures the 3D camera border */
1125 /* note: with VIEW3D_CAMERA_BORDER_HACK defined this error isn't noticeable
1126 * but keep it here in case we need to remove the workaround */
1127 x1i = (int)(x1 - 1.0001f);
1128 y1i = (int)(y1 - 1.0001f);
1129 x2i = (int)(x2 + (1.0f - 0.0001f));
1130 y2i = (int)(y2 + (1.0f - 0.0001f));
1132 /* passepartout, specified in camera edit buttons */
1133 if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) {
1134 const float winx = (ar->winx + 1);
1135 const float winy = (ar->winy + 1);
1137 if (ca->passepartalpha == 1.0f) {
1141 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1143 glColor4f(0, 0, 0, ca->passepartalpha);
1147 glRectf(0.0, winy, x1i, 0.0);
1149 glRectf(x2i, winy, winx, 0.0);
1151 glRectf(x1i, winy, x2i, y2i);
1153 glRectf(x1i, y1i, x2i, 0.0);
1155 glDisable(GL_BLEND);
1160 UI_ThemeColor(TH_BACK);
1162 fdrawbox(x1i, y1i, x2i, y2i);
1164 #ifdef VIEW3D_CAMERA_BORDER_HACK
1165 if (view3d_camera_border_hack_test == true) {
1166 glColor3ubv(view3d_camera_border_hack_col);
1167 fdrawbox(x1i + 1, y1i + 1, x2i - 1, y2i - 1);
1168 view3d_camera_border_hack_test = false;
1174 /* outer line not to confuse with object selecton */
1175 if (v3d->flag2 & V3D_LOCK_CAMERA) {
1176 UI_ThemeColor(TH_REDALERT);
1177 fdrawbox(x1i - 1, y1i - 1, x2i + 1, y2i + 1);
1180 UI_ThemeColor(TH_VIEW_OVERLAY);
1181 fdrawbox(x1i, y1i, x2i, y2i);
1184 if (scene->r.mode & R_BORDER) {
1185 float x3, y3, x4, y4;
1187 x3 = floorf(x1 + (scene->r.border.xmin * (x2 - x1))) - 1;
1188 y3 = floorf(y1 + (scene->r.border.ymin * (y2 - y1))) - 1;
1189 x4 = floorf(x1 + (scene->r.border.xmax * (x2 - x1))) + (U.pixelsize - 1);
1190 y4 = floorf(y1 + (scene->r.border.ymax * (y2 - y1))) + (U.pixelsize - 1);
1193 sdrawbox(x3, y3, x4, y4);
1198 if (ca->dtx & CAM_DTX_CENTER) {
1201 UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
1203 x3 = x1 + 0.5f * (x2 - x1);
1204 y3 = y1 + 0.5f * (y2 - y1);
1215 if (ca->dtx & CAM_DTX_CENTER_DIAG) {
1216 UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
1227 if (ca->dtx & CAM_DTX_THIRDS) {
1228 UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
1229 drawviewborder_grid3(x1, x2, y1, y2, 1.0f / 3.0f);
1232 if (ca->dtx & CAM_DTX_GOLDEN) {
1233 UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
1234 drawviewborder_grid3(x1, x2, y1, y2, 1.0f - (1.0f / 1.61803399f));
1237 if (ca->dtx & CAM_DTX_GOLDEN_TRI_A) {
1238 UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
1239 drawviewborder_triangle(x1, x2, y1, y2, 0, 'A');
1242 if (ca->dtx & CAM_DTX_GOLDEN_TRI_B) {
1243 UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
1244 drawviewborder_triangle(x1, x2, y1, y2, 0, 'B');
1247 if (ca->dtx & CAM_DTX_HARMONY_TRI_A) {
1248 UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
1249 drawviewborder_triangle(x1, x2, y1, y2, 1, 'A');
1252 if (ca->dtx & CAM_DTX_HARMONY_TRI_B) {
1253 UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
1254 drawviewborder_triangle(x1, x2, y1, y2, 1, 'B');
1257 if (ca->flag & CAM_SHOW_SAFE_MARGINS) {
1260 scene->safe_areas.title,
1261 scene->safe_areas.action);
1263 if (ca->flag & CAM_SHOW_SAFE_CENTER) {
1266 scene->safe_areas.title_center,
1267 scene->safe_areas.action_center);
1271 if (ca->flag & CAM_SHOWSENSOR) {
1272 /* determine sensor fit, and get sensor x/y, for auto fit we
1273 * assume and square sensor and only use sensor_x */
1274 float sizex = scene->r.xsch * scene->r.xasp;
1275 float sizey = scene->r.ysch * scene->r.yasp;
1276 int sensor_fit = BKE_camera_sensor_fit(ca->sensor_fit, sizex, sizey);
1277 float sensor_x = ca->sensor_x;
1278 float sensor_y = (ca->sensor_fit == CAMERA_SENSOR_FIT_AUTO) ? ca->sensor_x : ca->sensor_y;
1280 /* determine sensor plane */
1283 if (sensor_fit == CAMERA_SENSOR_FIT_HOR) {
1284 float sensor_scale = (x2i - x1i) / sensor_x;
1285 float sensor_height = sensor_scale * sensor_y;
1289 rect.ymin = (y1i + y2i) * 0.5f - sensor_height * 0.5f;
1290 rect.ymax = rect.ymin + sensor_height;
1293 float sensor_scale = (y2i - y1i) / sensor_y;
1294 float sensor_width = sensor_scale * sensor_x;
1296 rect.xmin = (x1i + x2i) * 0.5f - sensor_width * 0.5f;
1297 rect.xmax = rect.xmin + sensor_width;
1303 UI_ThemeColorShade(TH_VIEW_OVERLAY, 100);
1304 UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f);
1310 /* camera name - draw in highlighted text color */
1311 if (ca && (ca->flag & CAM_SHOWNAME)) {
1312 UI_ThemeColor(TH_TEXT_HI);
1314 x1i, y1i - (0.7f * U.widget_unit), 0.0f,
1315 v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2);
1319 /* *********************** backdraw for selection *************** */
1321 static void backdrawview3d(Scene *scene, wmWindow *win, ARegion *ar, View3D *v3d)
1323 RegionView3D *rv3d = ar->regiondata;
1324 struct Base *base = scene->basact;
1325 int multisample_enabled;
1327 BLI_assert(ar->regiontype == RGN_TYPE_WINDOW);
1329 if (base && (base->object->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) ||
1330 BKE_paint_select_face_test(base->object)))
1334 /* texture paint mode sampling */
1335 else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) &&
1336 (v3d->drawtype > OB_WIRE))
1340 else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) &&
1345 else if (scene->obedit &&
1351 v3d->flag &= ~V3D_INVALID_BACKBUF;
1355 if (!(v3d->flag & V3D_INVALID_BACKBUF))
1361 addafterqueue(ar->win, BACKBUFDRAW, 1);
1367 if (v3d->drawtype > OB_WIRE) v3d->zbuf = true;
1369 /* dithering and AA break color coding, so disable */
1370 glDisable(GL_DITHER);
1372 multisample_enabled = glIsEnabled(GL_MULTISAMPLE);
1373 if (multisample_enabled)
1374 glDisable(GL_MULTISAMPLE);
1376 if (win->multisamples != USER_MULTISAMPLE_NONE) {
1377 /* for multisample we use an offscreen FBO. multisample drawing can fail
1378 * with color coded selection drawing, and reading back depths from such
1379 * a buffer can also cause a few seconds freeze on OS X / NVidia. */
1380 int w = BLI_rcti_size_x(&ar->winrct);
1381 int h = BLI_rcti_size_y(&ar->winrct);
1384 if (rv3d->gpuoffscreen) {
1385 if (GPU_offscreen_width(rv3d->gpuoffscreen) != w ||
1386 GPU_offscreen_height(rv3d->gpuoffscreen) != h)
1388 GPU_offscreen_free(rv3d->gpuoffscreen);
1389 rv3d->gpuoffscreen = NULL;
1393 if (!rv3d->gpuoffscreen) {
1394 rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error);
1396 if (!rv3d->gpuoffscreen)
1397 fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error);
1401 if (rv3d->gpuoffscreen)
1402 GPU_offscreen_bind(rv3d->gpuoffscreen, true);
1404 glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
1406 glClearColor(0.0, 0.0, 0.0, 0.0);
1408 glEnable(GL_DEPTH_TEST);
1409 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1412 glClear(GL_COLOR_BUFFER_BIT);
1413 glDisable(GL_DEPTH_TEST);
1416 if (rv3d->rflag & RV3D_CLIPPING)
1417 ED_view3d_clipping_set(rv3d);
1419 G.f |= G_BACKBUFSEL;
1421 if (base && (base->lay & v3d->lay))
1422 draw_object_backbufsel(scene, v3d, rv3d, base->object);
1424 if (rv3d->gpuoffscreen)
1425 GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
1427 ar->swap = 0; /* mark invalid backbuf for wm draw */
1429 v3d->flag &= ~V3D_INVALID_BACKBUF;
1431 G.f &= ~G_BACKBUFSEL;
1433 glDisable(GL_DEPTH_TEST);
1434 glEnable(GL_DITHER);
1435 if (multisample_enabled)
1436 glEnable(GL_MULTISAMPLE);
1438 if (rv3d->rflag & RV3D_CLIPPING)
1439 ED_view3d_clipping_disable();
1442 void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
1444 RegionView3D *rv3d = ar->regiondata;
1446 if (rv3d->gpuoffscreen) {
1447 GPU_offscreen_bind(rv3d->gpuoffscreen, true);
1448 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
1449 glReadPixels(x, y, w, h, format, type, data);
1450 GPU_offscreen_unbind(rv3d->gpuoffscreen, true);
1453 glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
1457 /* XXX depth reading exception, for code not using gpu offscreen */
1458 static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
1461 glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
1464 void ED_view3d_backbuf_validate(ViewContext *vc)
1466 if (vc->v3d->flag & V3D_INVALID_BACKBUF)
1467 backdrawview3d(vc->scene, vc->win, vc->ar, vc->v3d);
1471 * allow for small values [0.5 - 2.5],
1472 * and large values, FLT_MAX by clamping by the area size
1474 int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist)
1476 return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx));
1479 /* samples a single pixel (copied from vpaint) */
1480 unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y)
1484 if (x >= vc->ar->winx || y >= vc->ar->winy) {
1488 ED_view3d_backbuf_validate(vc);
1490 view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
1491 glReadBuffer(GL_BACK);
1493 if (ENDIAN_ORDER == B_ENDIAN) {
1494 BLI_endian_switch_uint32(&col);
1497 return GPU_select_to_index(col);
1500 /* reads full rect, converts indices */
1501 ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int ymax)
1503 struct ImBuf *ibuf_clip;
1506 max_ii(xmin, 0), min_ii(xmax, vc->ar->winx - 1),
1507 max_ii(ymin, 0), min_ii(ymax, vc->ar->winy - 1)};
1508 const int size_clip[2] = {
1509 BLI_rcti_size_x(&clip) + 1,
1510 BLI_rcti_size_y(&clip) + 1};
1512 if (UNLIKELY((clip.xmin > clip.xmax) ||
1513 (clip.ymin > clip.ymax)))
1518 ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect);
1520 ED_view3d_backbuf_validate(vc);
1522 view3d_opengl_read_pixels(vc->ar, clip.xmin, clip.ymin, size_clip[0], size_clip[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf_clip->rect);
1524 glReadBuffer(GL_BACK);
1526 if (ENDIAN_ORDER == B_ENDIAN) {
1527 IMB_convert_rgba_to_abgr(ibuf_clip);
1530 GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]);
1532 if ((clip.xmin == xmin) &&
1533 (clip.xmax == xmax) &&
1534 (clip.ymin == ymin) &&
1535 (clip.ymax == ymax))
1540 /* put clipped result into a non-clipped buffer */
1541 struct ImBuf *ibuf_full;
1542 const int size[2] = {
1546 ibuf_full = IMB_allocImBuf(size[0], size[1], 32, IB_rect);
1549 ibuf_full, ibuf_clip,
1550 clip.xmin - xmin, clip.ymin - ymin,
1552 size_clip[0], size_clip[1]);
1553 IMB_freeImBuf(ibuf_clip);
1558 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
1559 unsigned int ED_view3d_backbuf_sample_rect(
1560 ViewContext *vc, const int mval[2], int size,
1561 unsigned int min, unsigned int max, float *r_dist)
1564 const unsigned int *bufmin, *bufmax, *tbuf;
1566 int a, b, rc, nr, amount, dirvec[4][2];
1567 unsigned int index = 0;
1569 amount = (size - 1) / 2;
1571 minx = mval[0] - (amount + 1);
1572 miny = mval[1] - (amount + 1);
1573 buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1);
1578 dirvec[0][0] = 1; dirvec[0][1] = 0;
1579 dirvec[1][0] = 0; dirvec[1][1] = -size;
1580 dirvec[2][0] = -1; dirvec[2][1] = 0;
1581 dirvec[3][0] = 0; dirvec[3][1] = size;
1585 bufmax = buf->rect + size * size;
1586 tbuf += amount * size + amount;
1588 for (nr = 1; nr <= size; nr++) {
1590 for (a = 0; a < 2; a++) {
1591 for (b = 0; b < nr; b++) {
1592 if (*tbuf && *tbuf >= min && *tbuf < max) {
1595 /* get x,y pixel coords from the offset
1596 * (manhatten distance in keeping with other screen-based selection) */
1598 abs(((int)(tbuf - buf->rect) % size) - (size / 2)) +
1599 abs(((int)(tbuf - buf->rect) / size) - (size / 2)));
1601 /* indices start at 1 here */
1602 index = (*tbuf - min) + 1;
1606 tbuf += (dirvec[rc][0] + dirvec[rc][1]);
1608 if (tbuf < bufmin || tbuf >= bufmax) {
1623 /* ************************************************************* */
1625 static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
1627 if (BKE_image_is_stereo(ima)) {
1628 iuser->flag |= IMA_SHOW_STEREO;
1630 if ((scene->r.scemode & R_MULTIVIEW) == 0) {
1631 iuser->multiview_eye = STEREO_LEFT_ID;
1633 else if (v3d->stereo3d_camera != STEREO_3D_ID) {
1634 /* show only left or right camera */
1635 iuser->multiview_eye = v3d->stereo3d_camera;
1638 BKE_image_multiview_index(ima, iuser);
1641 iuser->flag &= ~IMA_SHOW_STEREO;
1645 static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
1646 const bool do_foreground, const bool do_camera_frame)
1648 RegionView3D *rv3d = ar->regiondata;
1650 int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0;
1652 for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
1653 bgpic->iuser.scene = scene; /* Needed for render results. */
1655 if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag)
1658 if ((bgpic->view == 0) || /* zero for any */
1659 (bgpic->view & (1 << rv3d->view)) || /* check agaist flags */
1660 (rv3d->persp == RV3D_CAMOB && bgpic->view == (1 << RV3D_VIEW_CAMERA)))
1662 float image_aspect[2];
1663 float fac, asp, zoomx, zoomy;
1664 float x1, y1, x2, y2, centx, centy;
1666 ImBuf *ibuf = NULL, *freeibuf, *releaseibuf;
1671 MovieClip *clip = NULL;
1673 /* disable individual images */
1674 if ((bgpic->flag & V3D_BGPIC_DISABLED))
1679 if (bgpic->source == V3D_BGPIC_IMAGE) {
1683 BKE_image_user_frame_calc(&bgpic->iuser, CFRA, 0);
1684 if (ima->source == IMA_SRC_SEQUENCE && !(bgpic->iuser.flag & IMA_USER_FRAME_IN_RANGE)) {
1685 ibuf = NULL; /* frame is out of range, dont show */
1688 view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser);
1689 ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock);
1693 image_aspect[0] = ima->aspx;
1694 image_aspect[1] = ima->aspy;
1696 else if (bgpic->source == V3D_BGPIC_MOVIE) {
1697 /* TODO: skip drawing when out of frame range (as image sequences do above) */
1699 if (bgpic->flag & V3D_BGPIC_CAMERACLIP) {
1701 clip = BKE_object_movieclip_get(scene, scene->camera, true);
1710 BKE_movieclip_user_set_frame(&bgpic->cuser, CFRA);
1711 ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser);
1713 image_aspect[0] = clip->aspx;
1714 image_aspect[1] = clip->aspy;
1716 /* working with ibuf from image and clip has got different workflow now.
1717 * ibuf acquired from clip is referenced by cache system and should
1718 * be dereferenced after usage. */
1722 /* perhaps when loading future files... */
1724 copy_v2_fl(image_aspect, 1.0f);
1730 if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */
1732 IMB_freeImBuf(freeibuf);
1734 BKE_image_release_ibuf(ima, releaseibuf, lock);
1739 if (ibuf->rect == NULL)
1740 IMB_rect_from_float(ibuf);
1742 if (rv3d->persp == RV3D_CAMOB) {
1744 if (do_camera_frame) {
1746 ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false);
1753 x1 = ar->winrct.xmin;
1754 y1 = ar->winrct.ymin;
1755 x2 = ar->winrct.xmax;
1756 y2 = ar->winrct.ymax;
1759 /* apply offset last - camera offset is different to offset in blender units */
1760 /* so this has some sane way of working - this matches camera's shift _exactly_ */
1762 const float max_dim = max_ff(x2 - x1, y2 - y1);
1763 const float xof_scale = bgpic->xof * max_dim;
1764 const float yof_scale = bgpic->yof * max_dim;
1772 centx = (x1 + x2) / 2.0f;
1773 centy = (y1 + y2) / 2.0f;
1775 /* aspect correction */
1776 if (bgpic->flag & V3D_BGPIC_CAMERA_ASPECT) {
1777 /* apply aspect from clip */
1778 const float w_src = ibuf->x * image_aspect[0];
1779 const float h_src = ibuf->y * image_aspect[1];
1781 /* destination aspect is already applied from the camera frame */
1782 const float w_dst = x1 - x2;
1783 const float h_dst = y1 - y2;
1785 const float asp_src = w_src / h_src;
1786 const float asp_dst = w_dst / h_dst;
1788 if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
1789 if ((asp_src > asp_dst) == ((bgpic->flag & V3D_BGPIC_CAMERA_CROP) != 0)) {
1791 const float div = asp_src / asp_dst;
1792 x1 = ((x1 - centx) * div) + centx;
1793 x2 = ((x2 - centx) * div) + centx;
1797 const float div = asp_dst / asp_src;
1798 y1 = ((y1 - centy) * div) + centy;
1799 y2 = ((y2 - centy) * div) + centy;
1807 const float mval_f[2] = {1.0f, 0.0f};
1808 const float co_zero[3] = {0};
1811 /* calc window coord */
1812 zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL);
1813 ED_view3d_win_to_delta(ar, mval_f, tvec, zfac);
1814 fac = max_ff(fabsf(tvec[0]), max_ff(fabsf(tvec[1]), fabsf(tvec[2]))); /* largest abs axis */
1817 asp = (float)ibuf->y / (float)ibuf->x;
1820 ED_view3d_project_float_v2_m4(ar, tvec, sco, rv3d->persmat);
1822 x1 = sco[0] + fac * (bgpic->xof - bgpic->size);
1823 y1 = sco[1] + asp * fac * (bgpic->yof - bgpic->size);
1824 x2 = sco[0] + fac * (bgpic->xof + bgpic->size);
1825 y2 = sco[1] + asp * fac * (bgpic->yof + bgpic->size);
1827 centx = (x1 + x2) / 2.0f;
1828 centy = (y1 + y2) / 2.0f;
1831 /* complete clip? */
1832 BLI_rctf_init(&clip_rect, x1, x2, y1, y2);
1833 if (bgpic->rotation) {
1834 BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation);
1837 if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) {
1839 IMB_freeImBuf(freeibuf);
1841 BKE_image_release_ibuf(ima, releaseibuf, lock);
1846 zoomx = (x2 - x1) / ibuf->x;
1847 zoomy = (y2 - y1) / ibuf->y;
1849 /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */
1850 if (zoomx < 1.0f || zoomy < 1.0f) {
1851 float tzoom = min_ff(zoomx, zoomy);
1854 if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) {
1855 IMB_remakemipmap(ibuf, 0);
1856 ibuf->userflags &= ~IB_MIPMAP_INVALID;
1858 else if (ibuf->mipmap[0] == NULL)
1859 IMB_makemipmap(ibuf, 0);
1861 while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) {
1868 ibuf = ibuf->mipmap[mip - 1];
1871 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
1875 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1877 glMatrixMode(GL_PROJECTION);
1879 glMatrixMode(GL_MODELVIEW);
1881 ED_region_pixelspace(ar);
1883 glTranslatef(centx, centy, 0.0);
1884 glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f);
1886 if (bgpic->flag & V3D_BGPIC_FLIP_X) {
1890 if (bgpic->flag & V3D_BGPIC_FLIP_Y) {
1894 glPixelZoom(zoomx, zoomy);
1895 glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend);
1897 /* could not use glaDrawPixelsAuto because it could fallback to
1898 * glaDrawPixelsSafe in some cases, which will end up in missing
1899 * alpha transparency for the background image (sergey)
1901 glaDrawPixelsTex(x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect);
1903 glPixelZoom(1.0, 1.0);
1904 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
1906 glMatrixMode(GL_PROJECTION);
1908 glMatrixMode(GL_MODELVIEW);
1911 glDisable(GL_BLEND);
1914 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1917 IMB_freeImBuf(freeibuf);
1919 BKE_image_release_ibuf(ima, releaseibuf, lock);
1924 static void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d,
1925 const bool do_foreground, const bool do_camera_frame)
1927 RegionView3D *rv3d = ar->regiondata;
1929 if ((v3d->flag & V3D_DISPBGPICS) == 0)
1932 /* disabled - mango request, since footage /w only render is quite useful
1933 * and this option is easy to disable all background images at once */
1935 if (v3d->flag2 & V3D_RENDER_OVERRIDE)
1939 if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) {
1940 if (rv3d->persp == RV3D_CAMOB) {
1941 view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame);
1945 view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame);
1949 /* ****************** View3d afterdraw *************** */
1951 typedef struct View3DAfter {
1952 struct View3DAfter *next, *prev;
1957 /* temp storage of Objects that need to be drawn as last */
1958 void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag)
1960 View3DAfter *v3da = MEM_callocN(sizeof(View3DAfter), "View 3d after");
1961 BLI_assert((base->flag & OB_FROMDUPLI) == 0);
1962 BLI_addtail(lb, v3da);
1964 v3da->dflag = dflag;
1967 /* disables write in zbuffer and draws it over */
1968 static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d)
1972 glDepthMask(GL_FALSE);
1975 while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) {
1976 draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
1979 v3d->transp = false;
1981 glDepthMask(GL_TRUE);
1985 /* clears zbuffer and draws it over */
1986 static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear)
1990 if (*clear && v3d->zbuf) {
1991 glClear(GL_DEPTH_BUFFER_BIT);
1996 while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
1997 draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
2004 /* clears zbuffer and draws it over */
2005 static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const bool clear)
2009 if (clear && v3d->zbuf)
2010 glClear(GL_DEPTH_BUFFER_BIT);
2015 glDepthMask(GL_FALSE);
2017 while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) {
2018 draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
2022 v3d->transp = false;
2025 glDepthMask(GL_TRUE);
2028 /* clears zbuffer and draws it over,
2029 * note that in the select version we don't care about transparent flag as with regular drawing */
2030 static void view3d_draw_xray_select(Scene *scene, ARegion *ar, View3D *v3d, bool *clear)
2032 /* Not ideal, but we need to read from the previous depths before clearing
2033 * otherwise we could have a function to load the depths after drawing.
2035 * Clearing the depth buffer isn't all that common between drawing objects so accept this for now.
2037 if (U.gpu_select_pick_deph) {
2038 GPU_select_load_id(-1);
2042 if (*clear && v3d->zbuf) {
2043 glClear(GL_DEPTH_BUFFER_BIT);
2048 while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
2049 if (GPU_select_load_id(v3da->base->selcol)) {
2050 draw_object_select(scene, ar, v3d, v3da->base, v3da->dflag);
2057 /* *********************** */
2060 * In most cases call draw_dupli_objects,
2061 * draw_dupli_objects_color was added because when drawing set dupli's
2062 * we need to force the color
2066 int dupli_ob_sort(void *arg1, void *arg2)
2068 void *p1 = ((DupliObject *)arg1)->ob;
2069 void *p2 = ((DupliObject *)arg2)->ob;
2071 if (p1 < p2) val = -1;
2072 else if (p1 > p2) val = 1;
2078 static DupliObject *dupli_step(DupliObject *dob)
2080 while (dob && dob->no_draw)
2085 static void draw_dupli_objects_color(
2086 Scene *scene, ARegion *ar, View3D *v3d, Base *base,
2087 const short dflag, const int color)
2089 RegionView3D *rv3d = ar->regiondata;
2092 DupliObject *dob_prev = NULL, *dob, *dob_next = NULL;
2093 Base tbase = {NULL};
2094 BoundBox bb, *bb_tmp; /* use a copy because draw_object, calls clear_mesh_caches */
2095 GLuint displist = 0;
2096 unsigned char color_rgb[3];
2097 const short dflag_dupli = dflag | DRAW_CONSTCOLOR;
2099 bool use_displist = false; /* -1 is initialize */
2102 DupliApplyData *apply_data;
2104 if (base->object->restrictflag & OB_RESTRICT_VIEW) return;
2105 if ((base->object->restrictflag & OB_RESTRICT_RENDER) && (v3d->flag2 & V3D_RENDER_OVERRIDE)) return;
2107 if (dflag & DRAW_CONSTCOLOR) {
2108 BLI_assert(color == TH_UNDEFINED);
2111 UI_GetThemeColorBlend3ubv(color, TH_BACK, 0.5f, color_rgb);
2114 tbase.flag = OB_FROMDUPLI | base->flag;
2115 lb = object_duplilist(G.main->eval_ctx, scene, base->object);
2116 // BLI_listbase_sort(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */
2118 apply_data = duplilist_apply(base->object, scene, lb);
2120 dob = dupli_step(lb->first);
2121 if (dob) dob_next = dupli_step(dob->next);
2123 for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) {
2124 bool testbb = false;
2126 tbase.object = dob->ob;
2128 /* Make sure lod is updated from dupli's position */
2129 savedlod = dob->ob->currentlod;
2131 #ifdef WITH_GAMEENGINE
2132 if (rv3d->rflag & RV3D_IS_GAME_ENGINE) {
2133 BKE_object_lod_update(dob->ob, rv3d->viewinv[3]);
2137 /* extra service: draw the duplicator in drawtype of parent, minimum taken
2138 * to allow e.g. boundbox box objects in groups for LOD */
2139 dt = tbase.object->dt;
2140 tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
2142 /* inherit draw extra, but not if a boundbox under the assumption that this
2143 * is intended to speed up drawing, and drawing extra (especially wire) can
2144 * slow it down too much */
2145 dtx = tbase.object->dtx;
2146 if (tbase.object->dt != OB_BOUNDBOX)
2147 tbase.object->dtx = base->object->dtx;
2149 /* negative scale flag has to propagate */
2150 transflag = tbase.object->transflag;
2152 if (is_negative_m4(dob->mat))
2153 tbase.object->transflag |= OB_NEG_SCALE;
2155 tbase.object->transflag &= ~OB_NEG_SCALE;
2157 /* should move outside the loop but possible color is set in draw_object still */
2158 if ((dflag & DRAW_CONSTCOLOR) == 0) {
2159 glColor3ubv(color_rgb);
2162 /* generate displist, test for new object */
2163 if (dob_prev && dob_prev->ob != dob->ob) {
2164 if (use_displist == true)
2165 glDeleteLists(displist, 1);
2167 use_displist = false;
2170 if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) {
2171 bb = *bb_tmp; /* must make a copy */
2175 if (!testbb || ED_view3d_boundbox_clip_ex(rv3d, &bb, dob->mat)) {
2176 /* generate displist */
2177 if (use_displist == false) {
2179 /* note, since this was added, its checked (dob->type == OB_DUPLIGROUP)
2180 * however this is very slow, it was probably needed for the NLA
2181 * offset feature (used in group-duplicate.blend but no longer works in 2.5)
2182 * so for now it should be ok to - campbell */
2184 if ( /* if this is the last no need to make a displist */
2185 (dob_next == NULL || dob_next->ob != dob->ob) ||
2186 /* lamp drawing messes with matrices, could be handled smarter... but this works */
2187 (dob->ob->type == OB_LAMP) ||
2188 (dob->type == OB_DUPLIGROUP && dob->animated) ||
2190 draw_glsl_material(scene, dob->ob, v3d, dt) ||
2191 check_object_draw_texture(scene, v3d, dt) ||
2192 (v3d->flag2 & V3D_SOLID_MATCAP) != 0)
2194 // printf("draw_dupli_objects_color: skipping displist for %s\n", dob->ob->id.name + 2);
2195 use_displist = false;
2198 // printf("draw_dupli_objects_color: using displist for %s\n", dob->ob->id.name + 2);
2200 /* disable boundbox check for list creation */
2201 BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1);
2202 /* need this for next part of code */
2203 unit_m4(dob->ob->obmat); /* obmat gets restored */
2205 displist = glGenLists(1);
2206 glNewList(displist, GL_COMPILE);
2207 draw_object(scene, ar, v3d, &tbase, dflag_dupli);
2210 use_displist = true;
2211 BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0);
2217 glMultMatrixf(dob->mat);
2218 glCallList(displist);
2222 copy_m4_m4(dob->ob->obmat, dob->mat);
2223 GPU_begin_dupli_object(dob);
2224 draw_object(scene, ar, v3d, &tbase, dflag_dupli);
2225 GPU_end_dupli_object();
2229 tbase.object->dt = dt;
2230 tbase.object->dtx = dtx;
2231 tbase.object->transflag = transflag;
2232 tbase.object->currentlod = savedlod;
2236 duplilist_restore(lb, apply_data);
2237 duplilist_free_apply_data(apply_data);
2240 free_object_duplilist(lb);
2243 glDeleteLists(displist, 1);
2246 static void draw_dupli_objects(Scene *scene, ARegion *ar, View3D *v3d, Base *base)
2248 /* define the color here so draw_dupli_objects_color can be called
2249 * from the set loop */
2251 int color = (base->flag & SELECT) ? TH_SELECT : TH_WIRE;
2253 if (base->object->dup_group && base->object->dup_group->id.us < 1)
2254 color = TH_REDALERT;
2256 draw_dupli_objects_color(scene, ar, v3d, base, 0, color);
2259 /* XXX warning, not using gpu offscreen here */
2260 void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect)
2264 /* clamp rect by region */
2267 r.xmax = ar->winx - 1;
2269 r.ymax = ar->winy - 1;
2271 /* Constrain rect to depth bounds */
2272 BLI_rcti_isect(&r, rect, rect);
2274 /* assign values to compare with the ViewDepths */
2278 w = BLI_rcti_size_x(rect);
2279 h = BLI_rcti_size_y(rect);
2281 if (w <= 0 || h <= 0) {
2283 MEM_freeN(d->depths);
2288 else if (d->w != w ||
2301 MEM_freeN(d->depths);
2303 d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset");
2309 /* XXX using special function here, it doesn't use the gpu offscreen system */
2310 view3d_opengl_read_Z_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
2311 glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
2316 /* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */
2317 void ED_view3d_depth_update(ARegion *ar)
2319 RegionView3D *rv3d = ar->regiondata;
2321 /* Create storage for, and, if necessary, copy depth buffer */
2322 if (!rv3d->depths) rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths");
2324 ViewDepths *d = rv3d->depths;
2325 if (d->w != ar->winx ||
2332 MEM_freeN(d->depths);
2333 d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths");
2338 view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
2339 glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
2346 /* utility function to find the closest Z value, use for autodepth */
2347 float view3d_depth_near(ViewDepths *d)
2349 /* convert to float for comparisons */
2350 const float near = (float)d->depth_range[0];
2351 const float far_real = (float)d->depth_range[1];
2352 float far = far_real;
2354 const float *depths = d->depths;
2355 float depth = FLT_MAX;
2356 int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */
2358 /* far is both the starting 'far' value
2359 * and the closest value found. */
2362 if ((depth < far) && (depth > near)) {
2367 return far == far_real ? FLT_MAX : far;
2370 void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d)
2372 short zbuf = v3d->zbuf;
2373 RegionView3D *rv3d = ar->regiondata;
2375 /* Setup view matrix. */
2376 ED_view3d_draw_setup_view(NULL, scene, ar, v3d, rv3d->winmat, rv3d->viewmat);
2378 glClear(GL_DEPTH_BUFFER_BIT);
2381 glEnable(GL_DEPTH_TEST);
2383 if (v3d->flag2 & V3D_SHOW_GPENCIL) {
2384 ED_gpencil_draw_view3d(NULL, scene, v3d, ar, true);
2390 static void view3d_draw_depth_loop(Scene *scene, ARegion *ar, View3D *v3d)
2394 /* no need for color when drawing depth buffer */
2395 const short dflag_depth = DRAW_CONSTCOLOR;
2397 /* draw set first */
2400 for (SETLOOPER(scene->set, sce_iter, base)) {
2401 if (v3d->lay & base->lay) {
2402 draw_object(scene, ar, v3d, base, 0);
2403 if (base->object->transflag & OB_DUPLI) {
2404 draw_dupli_objects_color(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED);
2410 for (base = scene->base.first; base; base = base->next) {
2411 if (v3d->lay & base->lay) {
2413 if (base->object->transflag & OB_DUPLI) {
2414 draw_dupli_objects_color(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED);
2416 draw_object(scene, ar, v3d, base, dflag_depth);
2420 /* this isn't that nice, draw xray objects as if they are normal */
2421 if (v3d->afterdraw_transp.first ||
2422 v3d->afterdraw_xray.first ||
2423 v3d->afterdraw_xraytransp.first)
2430 /* transp materials can change the depth mask, see #21388 */
2431 glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
2434 if (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first) {
2435 glDepthFunc(GL_ALWAYS); /* always write into the depth bufer, overwriting front z values */
2436 for (v3da = v3d->afterdraw_xray.first; v3da; v3da = v3da->next) {
2437 draw_object(scene, ar, v3d, v3da->base, dflag_depth);
2439 glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */
2442 /* draw 3 passes, transp/xray/xraytransp */
2445 while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) {
2446 draw_object(scene, ar, v3d, v3da->base, dflag_depth);
2451 v3d->transp = false;
2452 while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
2453 draw_object(scene, ar, v3d, v3da->base, dflag_depth);
2459 while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) {
2460 draw_object(scene, ar, v3d, v3da->base, dflag_depth);
2466 v3d->transp = false;
2468 glDepthMask(mask_orig);
2472 void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride)
2474 RegionView3D *rv3d = ar->regiondata;
2475 short zbuf = v3d->zbuf;
2476 short flag = v3d->flag;
2477 float glalphaclip = U.glalphaclip;
2478 int obcenter_dia = U.obcenter_dia;
2479 /* temp set drawtype to solid */
2481 /* Setting these temporarily is not nice */
2482 v3d->flag &= ~V3D_SELECT_OUTLINE;
2483 U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */
2486 /* Setup view matrix. */
2487 ED_view3d_draw_setup_view(NULL, scene, ar, v3d, rv3d->viewmat, rv3d->winmat);
2489 glClear(GL_DEPTH_BUFFER_BIT);
2491 if (rv3d->rflag & RV3D_CLIPPING) {
2492 ED_view3d_clipping_set(rv3d);
2494 /* get surface depth without bias */
2495 rv3d->rflag |= RV3D_ZOFFSET_DISABLED;
2498 glEnable(GL_DEPTH_TEST);
2500 view3d_draw_depth_loop(scene, ar, v3d);
2502 if (rv3d->rflag & RV3D_CLIPPING) {
2503 ED_view3d_clipping_disable();
2505 rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED;
2508 if (!v3d->zbuf) glDisable(GL_DEPTH_TEST);
2510 U.glalphaclip = glalphaclip;
2512 U.obcenter_dia = obcenter_dia;
2515 void ED_view3d_draw_select_loop(
2516 ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar,
2517 bool use_obedit_skip, bool use_nearest)
2520 const short dflag = DRAW_PICKING | DRAW_CONSTCOLOR;
2522 if (vc->obedit && vc->obedit->type == OB_MBALL) {
2523 draw_object(scene, ar, v3d, BASACT, dflag);
2525 else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
2526 /* if not drawing sketch, draw bones */
2527 if (!BDR_drawSketchNames(vc)) {
2528 draw_object(scene, ar, v3d, BASACT, dflag);
2534 for (base = scene->base.first; base; base = base->next) {
2535 if (base->lay & v3d->lay) {
2537 if ((base->object->restrictflag & OB_RESTRICT_SELECT) ||
2538 (use_obedit_skip && (scene->obedit->data == base->object->data)))
2543 base->selcol = code;
2545 if (use_nearest && (base->object->dtx & OB_DRAWXRAY)) {
2546 ED_view3d_after_add(&v3d->afterdraw_xray, base, dflag);
2549 if (GPU_select_load_id(code)) {
2550 draw_object_select(scene, ar, v3d, base, dflag);
2559 bool xrayclear = true;
2560 if (v3d->afterdraw_xray.first) {
2561 view3d_draw_xray_select(scene, ar, v3d, &xrayclear);
2567 typedef struct View3DShadow {
2568 struct View3DShadow *next, *prev;
2572 static void gpu_render_lamp_update(Scene *scene, View3D *v3d,
2573 Object *ob, Object *par,
2574 float obmat[4][4], unsigned int lay,
2575 ListBase *shadows, SceneRenderLayer *srl)
2578 Lamp *la = (Lamp *)ob->data;
2579 View3DShadow *shadow;
2580 unsigned int layers;
2582 lamp = GPU_lamp_from_blender(scene, ob, par);
2585 GPU_lamp_update(lamp, lay, (ob->restrictflag & OB_RESTRICT_RENDER), obmat);
2586 GPU_lamp_update_colors(lamp, la->r, la->g, la->b, la->energy);
2588 layers = lay & v3d->lay;
2593 GPU_lamp_has_shadow_buffer(lamp) &&
2594 /* keep last, may do string lookup */
2595 GPU_lamp_override_visible(lamp, srl, NULL))
2597 shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow");
2598 shadow->lamp = lamp;
2599 BLI_addtail(shadows, shadow);
2604 static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d)
2607 View3DShadow *shadow;
2611 World *world = scene->world;
2612 SceneRenderLayer *srl = v3d->scenelock ? BLI_findlink(&scene->r.layers, scene->r.actlay) : NULL;
2614 BLI_listbase_clear(&shadows);
2616 /* update lamp transform and gather shadow lamps */
2617 for (SETLOOPER(scene, sce_iter, base)) {
2620 if (ob->type == OB_LAMP)
2621 gpu_render_lamp_update(scene, v3d, ob, NULL, ob->obmat, ob->lay, &shadows, srl);
2623 if (ob->transflag & OB_DUPLI) {
2625 ListBase *lb = object_duplilist(G.main->eval_ctx, scene, ob);
2627 for (dob = lb->first; dob; dob = dob->next)
2628 if (dob->ob->type == OB_LAMP)
2629 gpu_render_lamp_update(scene, v3d, dob->ob, ob, dob->mat, ob->lay, &shadows, srl);
2631 free_object_duplilist(lb);
2635 /* render shadows after updating all lamps, nested object_duplilist
2636 * don't work correct since it's replacing object matrices */
2637 for (shadow = shadows.first; shadow; shadow = shadow->next) {
2638 /* this needs to be done better .. */
2639 float viewmat[4][4], winmat[4][4];
2640 int drawtype, lay, winsize, flag2 = v3d->flag2;
2641 ARegion ar = {NULL};
2642 RegionView3D rv3d = {{{0}}};
2644 drawtype = v3d->drawtype;
2647 v3d->drawtype = OB_SOLID;
2648 v3d->lay &= GPU_lamp_shadow_layer(shadow->lamp);
2649 v3d->flag2 &= ~(V3D_SOLID_TEX | V3D_SHOW_SOLID_MATCAP);
2650 v3d->flag2 |= V3D_RENDER_OVERRIDE | V3D_RENDER_SHADOW;
2652 GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat);
2654 ar.regiondata = &rv3d;
2655 ar.regiontype = RGN_TYPE_WINDOW;
2656 rv3d.persp = RV3D_CAMOB;
2657 copy_m4_m4(rv3d.winmat, winmat);
2658 copy_m4_m4(rv3d.viewmat, viewmat);
2659 invert_m4_m4(rv3d.viewinv, rv3d.viewmat);
2660 mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat);
2661 invert_m4_m4(rv3d.persinv, rv3d.viewinv);
2663 /* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */
2664 ED_view3d_draw_offscreen(
2665 scene, v3d, &ar, winsize, winsize, viewmat, winmat,
2667 NULL, NULL, NULL, NULL);
2668 GPU_lamp_shadow_buffer_unbind(shadow->lamp);
2670 v3d->drawtype = drawtype;
2675 BLI_freelistN(&shadows);
2677 /* update world values */
2679 GPU_mist_update_enable(world->mode & WO_MIST);
2680 GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr);
2681 GPU_horizon_update_color(&world->horr);
2682 GPU_ambient_update_color(&world->ambr);
2683 GPU_zenith_update_color(&world->zenr);
2687 /* *********************** customdata **************** */
2689 CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d)
2691 CustomDataMask mask = 0;
2692 const int drawtype = view3d_effective_drawtype(v3d);
2694 if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) ||
2695 ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX)))
2697 mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
2699 if (BKE_scene_use_new_shading_nodes(scene)) {
2700 if (drawtype == OB_MATERIAL)
2701 mask |= CD_MASK_ORCO;
2704 if ((scene->gm.matmode == GAME_MAT_GLSL && drawtype == OB_TEXTURE) ||
2705 (drawtype == OB_MATERIAL))
2707 mask |= CD_MASK_ORCO;
2715 /* goes over all modes and view3d settings */
2716 CustomDataMask ED_view3d_screen_datamask(const bScreen *screen)
2718 const Scene *scene = screen->scene;
2719 CustomDataMask mask = CD_MASK_BAREMESH;
2722 /* check if we need tfaces & mcols due to view mode */
2723 for (sa = screen->areabase.first; sa; sa = sa->next) {
2724 if (sa->spacetype == SPACE_VIEW3D) {
2725 mask |= ED_view3d_datamask(scene, sa->spacedata.first);
2733 * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
2735 void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
2737 RegionView3D *rv3d = ar->regiondata;
2739 /* setup window matrices */
2741 copy_m4_m4(rv3d->winmat, winmat);
2743 view3d_winmatrix_set(ar, v3d, NULL);
2745 /* setup view matrix */
2747 copy_m4_m4(rv3d->viewmat, viewmat);
2749 view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */
2751 /* update utility matrices */
2752 mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
2753 invert_m4_m4(rv3d->persinv, rv3d->persmat);
2754 invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
2756 /* calculate GLSL view dependent values */
2758 /* store window coordinates scaling/offset */
2759 if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
2761 ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false);
2762 rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder);
2763 rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder);
2765 rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx;
2766 rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy;
2769 rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f;
2770 rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f;
2774 * Calculate pixel-size factor once, is used for lamps and object centers.
2775 * Used by #ED_view3d_pixel_size and typically not accessed directly.
2777 * \note #BKE_camera_params_compute_viewplane' also calculates a pixel-size value,
2778 * passed to #RE_SetPixelSize, in ortho mode this is compatible with this value,
2779 * but in perspective mode its offset by the near-clip.
2781 * 'RegionView3D.pixsize' is used for viewport drawing, not rendering.
2784 /* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])'
2785 * because of float point precision problems at large values [#23908] */
2787 float len_px, len_sc;
2789 v1[0] = rv3d->persmat[0][0];
2790 v1[1] = rv3d->persmat[1][0];
2791 v1[2] = rv3d->persmat[2][0];
2793 v2[0] = rv3d->persmat[0][1];
2794 v2[1] = rv3d->persmat[1][1];
2795 v2[2] = rv3d->persmat[2][1];
2797 len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
2798 len_sc = (float)MAX2(ar->winx, ar->winy);
2800 rv3d->pixsize = len_px / len_sc;
2805 * Shared by #ED_view3d_draw_offscreen and #view3d_main_region_draw_objects
2807 * \note \a C and \a grid_unit will be NULL when \a draw_offscreen is set.
2808 * \note Drawing lamps and opengl render uses this, so dont do grease pencil or view widgets here.
2810 static void view3d_draw_objects(
2812 Scene *scene, View3D *v3d, ARegion *ar,
2813 const char **grid_unit,
2814 const bool do_bgpic, const bool draw_offscreen, GPUFX *fx)
2816 RegionView3D *rv3d = ar->regiondata;
2818 const bool do_camera_frame = !draw_offscreen;
2819 const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0;
2820 const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO);
2821 /* only draw grids after in solid modes, else it hovers over mesh wires */
2822 const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE) && fx;
2823 bool do_composite_xray = false;
2824 bool xrayclear = true;
2826 if (!draw_offscreen) {
2827 ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
2830 if (rv3d->rflag & RV3D_CLIPPING)
2831 view3d_draw_clipping(rv3d);
2833 /* set zbuffer after we draw clipping region */
2834 if (v3d->drawtype > OB_WIRE) {
2841 /* special case (depth for wire color) */
2842 if (v3d->drawtype <= OB_WIRE) {
2843 if (scene->obedit && scene->obedit->type == OB_MESH) {
2844 Mesh *me = scene->obedit->data;
2845 if (me->drawflag & ME_DRAWEIGHT) {
2852 glEnable(GL_DEPTH_TEST);
2855 /* ortho grid goes first, does not write to depth buffer and doesn't need depth test so it will override
2856 * objects if done last */
2858 /* needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. */
2859 rv3d->gridview = ED_view3d_grid_scale(scene, v3d, grid_unit);
2862 ED_region_pixelspace(ar);
2863 *grid_unit = NULL; /* drawgrid need this to detect/affect smallest valid unit... */
2864 drawgrid(&scene->unit, ar, v3d, grid_unit);
2865 /* XXX make function? replaces persp(1) */
2866 glMatrixMode(GL_PROJECTION);
2867 glLoadMatrixf(rv3d->winmat);
2868 glMatrixMode(GL_MODELVIEW);
2869 glLoadMatrixf(rv3d->viewmat);
2871 else if (!draw_grids_after) {
2872 drawfloor(scene, v3d, grid_unit, true);
2876 /* important to do before clipping */
2878 view3d_draw_bgpic_test(scene, ar, v3d, false, do_camera_frame);
2881 if (rv3d->rflag & RV3D_CLIPPING) {
2882 ED_view3d_clipping_set(rv3d);
2885 /* draw set first */
2887 const short dflag = DRAW_CONSTCOLOR | DRAW_SCENESET;
2889 for (SETLOOPER(scene->set, sce_iter, base)) {
2890 if (v3d->lay & base->lay) {
2891 UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f);
2892 draw_object(scene, ar, v3d, base, dflag);
2894 if (base->object->transflag & OB_DUPLI) {
2895 draw_dupli_objects_color(scene, ar, v3d, base, dflag, TH_UNDEFINED);
2900 /* Transp and X-ray afterdraw stuff for sets is done later */
2904 if (draw_offscreen) {
2905 for (base = scene->base.first; base; base = base->next) {
2906 if (v3d->lay & base->lay) {
2908 if (base->object->transflag & OB_DUPLI)
2909 draw_dupli_objects(scene, ar, v3d, base);
2911 draw_object(scene, ar, v3d, base, 0);
2916 unsigned int lay_used = 0;
2918 /* then draw not selected and the duplis, but skip editmode object */
2919 for (base = scene->base.first; base; base = base->next) {
2920 lay_used |= base->lay;
2922 if (v3d->lay & base->lay) {
2925 if (base->object->transflag & OB_DUPLI) {
2926 draw_dupli_objects(scene, ar, v3d, base);
2928 if ((base->flag & SELECT) == 0) {
2929 if (base->object != scene->obedit)
2930 draw_object(scene, ar, v3d, base, 0);
2935 /* mask out localview */
2936 v3d->lay_used = lay_used & ((1 << 20) - 1);
2938 /* draw selected and editmode */
2939 for (base = scene->base.first; base; base = base->next) {
2940 if (v3d->lay & base->lay) {
2941 if (base->object == scene->obedit || (base->flag & SELECT)) {
2942 draw_object(scene, ar, v3d, base, 0);
2948 /* perspective floor goes last to use scene depth and avoid writing to depth buffer */
2949 if (draw_grids_after) {
2950 drawfloor(scene, v3d, grid_unit, false);
2953 /* must be before xray draw which clears the depth buffer */
2954 if (v3d->flag2 & V3D_SHOW_GPENCIL) {
2955 wmWindowManager *wm = (C != NULL) ? CTX_wm_manager(C) : NULL;
2957 /* must be before xray draw which clears the depth buffer */
2958 if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
2959 ED_gpencil_draw_view3d(wm, scene, v3d, ar, true);
2960 if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
2963 /* transp and X-ray afterdraw stuff */
2964 if (v3d->afterdraw_transp.first) view3d_draw_transp(scene, ar, v3d);
2966 /* always do that here to cleanup depth buffers if none needed */
2968 do_composite_xray = v3d->zbuf && (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first);
2969 GPU_fx_compositor_setup_XRay_pass(fx, do_composite_xray);
2972 if (v3d->afterdraw_xray.first) view3d_draw_xray(scene, ar, v3d, &xrayclear);
2973 if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(scene, ar, v3d, xrayclear);
2975 if (fx && do_composite_xray) {
2976 GPU_fx_compositor_XRay_resolve(fx);
2979 if (!draw_offscreen) {
2980 ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
2983 if (rv3d->rflag & RV3D_CLIPPING)
2984 ED_view3d_clipping_disable();
2986 /* important to do after clipping */
2988 view3d_draw_bgpic_test(scene, ar, v3d, true, do_camera_frame);
2991 if (!draw_offscreen) {
2992 BIF_draw_manipulator(C);
2998 glDisable(GL_DEPTH_TEST);
3001 if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
3002 GPU_free_images_old();
3006 static void view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
3008 RegionView3D *rv3d = ar->regiondata;
3010 ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat);
3012 /* set for opengl */
3013 glMatrixMode(GL_PROJECTION);
3014 glLoadMatrixf(rv3d->winmat);
3015 glMatrixMode(GL_MODELVIEW);
3016 glLoadMatrixf(rv3d->viewmat);
3020 * Store values from #RegionView3D, set when drawing.
3021 * This is needed when we draw with to a viewport using a different matrix (offscreen drawing for example).
3023 * Values set by #ED_view3d_update_viewmat should be handled here.
3025 struct RV3DMatrixStore {
3027 float viewmat[4][4];
3028 float viewinv[4][4];
3029 float persmat[4][4];
3030 float persinv[4][4];
3031 float viewcamtexcofac[4];
3035 struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d)
3037 struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__);
3038 copy_m4_m4(rv3dmat->winmat, rv3d->winmat);
3039 copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat);
3040 copy_m4_m4(rv3dmat->persmat, rv3d->persmat);
3041 copy_m4_m4(rv3dmat->persinv, rv3d->persinv);
3042 copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv);
3043 copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac);
3044 rv3dmat->pixsize = rv3d->pixsize;
3045 return (void *)rv3dmat;
3048 void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat)
3050 copy_m4_m4(rv3d->winmat, rv3dmat->winmat);
3051 copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat);