Commit afb3f5c1 authored by Philip Lafleur's avatar Philip Lafleur Committed by Philip Lafleur
Browse files

Fixed incorrect logic that caused perfect-but-slow pointer tracking to be

2004-06-12  Philip Lafleur  <plafleur@cvs.gnome.org>

	* app/display/gimpdisplayshell-callbacks.c: Fixed incorrect logic that
	caused perfect-but-slow pointer tracking to be used in tools that
	don't request exact mode.

	* app/display/Makefile.am:
	* app/display/gimpdisplayshell-appearance.[ch]:
	* app/display/gimpdisplayshell-callbacks.c:
	* app/display/gimpdisplayshell.[ch]:
	* app/display/gimpdisplayshell-preview.[ch]: added
	* app/tools/gimpperspectivetool.c:
	* app/tools/gimprotatetool.c:
	* app/tools/gimpscaletool.c:
	* app/tools/gimpsheartool.c:
	* app/tools/gimptransformoptions.[ch]:
	* app/tools/gimptransformtool.[ch]: Implemented live transformation
	previews, available through tool options. Fixes bug #108172.
parent c28d70ce
2004-06-12 Philip Lafleur <plafleur@cvs.gnome.org>
* app/display/gimpdisplayshell-callbacks.c: Fixed incorrect logic that
caused perfect-but-slow pointer tracking to be used in tools that
don't request exact mode.
* app/display/Makefile.am:
* app/display/gimpdisplayshell-appearance.[ch]:
* app/display/gimpdisplayshell-callbacks.c:
* app/display/gimpdisplayshell.[ch]:
* app/display/gimpdisplayshell-preview.[ch]: added
* app/tools/gimpperspectivetool.c:
* app/tools/gimprotatetool.c:
* app/tools/gimpscaletool.c:
* app/tools/gimpsheartool.c:
* app/tools/gimptransformoptions.[ch]:
* app/tools/gimptransformtool.[ch]: Implemented live transformation
previews, available through tool options. Fixes bug #108172.
2004-06-13 Sven Neumann <sven@gimp.org>
* app/core/gimpdrawable-blend.c (gradient_render_pixel): inline
......
......@@ -48,6 +48,8 @@ libappdisplay_a_sources = \
gimpdisplayshell-filter-dialog.h \
gimpdisplayshell-layer-select.c \
gimpdisplayshell-layer-select.h \
gimpdisplayshell-preview.c \
gimpdisplayshell-preview.h \
gimpdisplayshell-render.c \
gimpdisplayshell-render.h \
gimpdisplayshell-scale.c \
......
......@@ -319,6 +319,23 @@ gimp_display_shell_get_show_layer (GimpDisplayShell *shell)
return GET_OPTIONS (shell)->show_layer_boundary;
}
void
gimp_display_shell_set_show_transform (GimpDisplayShell *shell,
gboolean show)
{
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
shell->show_transform_preview = show;
}
gboolean
gimp_display_shell_get_show_transform (GimpDisplayShell *shell)
{
g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
return shell->show_transform_preview;
}
void
gimp_display_shell_set_show_grid (GimpDisplayShell *shell,
gboolean show)
......
......@@ -48,6 +48,10 @@ void gimp_display_shell_set_show_layer (GimpDisplayShell *shell,
gboolean show);
gboolean gimp_display_shell_get_show_layer (GimpDisplayShell *shell);
void gimp_display_shell_set_show_transform (GimpDisplayShell *shell,
gboolean show);
gboolean gimp_display_shell_get_show_transform (GimpDisplayShell *shell);
void gimp_display_shell_set_show_grid (GimpDisplayShell *shell,
gboolean show);
gboolean gimp_display_shell_get_show_grid (GimpDisplayShell *shell);
......
......@@ -61,6 +61,7 @@
#include "gimpdisplayshell-cursor.h"
#include "gimpdisplayshell-draw.h"
#include "gimpdisplayshell-layer-select.h"
#include "gimpdisplayshell-preview.h"
#include "gimpdisplayshell-render.h"
#include "gimpdisplayshell-scale.h"
#include "gimpdisplayshell-scroll.h"
......@@ -394,6 +395,9 @@ gimp_display_shell_canvas_expose (GtkWidget *widget,
g_free (rects);
/* draw the transform tool preview */
gimp_display_shell_preview_transform (shell);
/* draw the guides */
gimp_display_shell_draw_guides (shell);
......@@ -674,7 +678,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
event_mask = (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK);
if (active_tool &&
(! GIMP_DISPLAY_CONFIG (gimp->config)->perfect_mouse &&
(! GIMP_DISPLAY_CONFIG (gimp->config)->perfect_mouse ||
(gimp_tool_control_motion_mode (active_tool->control) !=
GIMP_MOTION_MODE_EXACT)))
{
......
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "display-types.h"
#include "tools/tools-types.h"
#include "core/gimpimage.h"
#include "core/gimpdrawable.h"
#include "base/tile-manager.h"
#include "tools/gimptransformtool.h"
#include "tools/tool_manager.h"
#include "gimpdisplay.h"
#include "gimpdisplayshell.h"
#include "gimpdisplayshell-appearance.h"
#include "gimpdisplayshell-preview.h"
#include "gimpdisplayshell-transform.h"
/* local function prototypes */
static void gimp_display_shell_draw_quad (GimpDrawable *texture,
GdkDrawable *dest,
gint *x,
gint *y,
gfloat *u,
gfloat *v);
static void gimp_display_shell_draw_quad_row (GimpDrawable *texture,
GdkDrawable *dest,
GdkPixbuf *row,
gint x1,
gfloat u1,
gfloat v1,
gint x2,
gfloat u2,
gfloat v2,
gint y);
static void gimp_display_shell_trace_quad_edge (gint *dest,
gint x1,
gint y1,
gint x2,
gint y2);
/* public functions */
void
gimp_display_shell_preview_transform (GimpDisplayShell *shell)
{
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
if (gimp_display_shell_get_show_transform (shell))
{
GimpTool *tool;
GimpTransformTool *tr_tool;
gdouble z1, z2, z3, z4;
tool = tool_manager_get_active (shell->gdisp->gimage->gimp);
if (! GIMP_IS_TRANSFORM_TOOL (tool))
return;
tr_tool = GIMP_TRANSFORM_TOOL (tool);
if (! tr_tool->use_grid)
return;
z1 = ((tr_tool->tx2 - tr_tool->tx1) * (tr_tool->ty4 - tr_tool->ty1) -
(tr_tool->tx4 - tr_tool->tx1) * (tr_tool->ty2 - tr_tool->ty1));
z2 = ((tr_tool->tx4 - tr_tool->tx1) * (tr_tool->ty3 - tr_tool->ty1) -
(tr_tool->tx3 - tr_tool->tx1) * (tr_tool->ty4 - tr_tool->ty1));
z3 = ((tr_tool->tx4 - tr_tool->tx2) * (tr_tool->ty3 - tr_tool->ty2) -
(tr_tool->tx3 - tr_tool->tx2) * (tr_tool->ty4 - tr_tool->ty2));
z4 = ((tr_tool->tx3 - tr_tool->tx2) * (tr_tool->ty1 - tr_tool->ty2) -
(tr_tool->tx1 - tr_tool->tx2) * (tr_tool->ty3 - tr_tool->ty2));
/* only draw convex polygons */
if ((z1 * z2 > 0) && (z3 * z4 > 0))
{
gdouble dx [4];
gdouble dy [4];
gint x [4];
gint y [4];
gfloat u [4] = {0, 1, 0, 1};
gfloat v [4] = {0, 0, 1, 1};
gint i;
gimp_display_shell_transform_xy_f (shell, tr_tool->tx1, tr_tool->ty1,
dx + 0, dy + 0, FALSE);
gimp_display_shell_transform_xy_f (shell, tr_tool->tx2, tr_tool->ty2,
dx + 1, dy + 1, FALSE);
gimp_display_shell_transform_xy_f (shell, tr_tool->tx3, tr_tool->ty3,
dx + 2, dy + 2, FALSE);
gimp_display_shell_transform_xy_f (shell, tr_tool->tx4, tr_tool->ty4,
dx + 3, dy + 3, FALSE);
for (i = 0; i < 4; i++)
{
x [i] = (gint) dx [i];
y [i] = (gint) dy [i];
}
gimp_display_shell_draw_quad (tool->drawable,
GDK_DRAWABLE (GTK_WIDGET (shell->canvas)->window),
x, y, u, v);
}
}
}
/* private functions */
static void
gimp_display_shell_draw_quad (GimpDrawable *texture,
GdkDrawable *dest,
gint *x,
gint *y,
gfloat *u, /* texture coords */
gfloat *v) /* 0.0 ... 1.0 */
{
GdkPixbuf *row;
gint dwidth, dheight; /* clip boundary */
gint j, k;
gint ry;
gint *l_edge, *r_edge; /* arrays holding x-coords of edge pixels */
gint *left, *right;
gfloat dul, dvl, dur, dvr; /* left and right texture coord deltas */
gfloat u_l, v_l, u_r, v_r; /* left and right texture coord pairs */
if (! GIMP_IS_DRAWABLE (texture) ||
! GDK_IS_DRAWABLE (dest))
return;
g_return_if_fail (x != NULL && y != NULL && u != NULL && v != NULL);
left = right = NULL;
dul = dvl = dur = dvr = 0;
u_l = v_l = u_r = v_r = 0;
gdk_drawable_get_size (dest, &dwidth, &dheight);
/* is the preview in the window? */
{
gboolean in_window_x, in_window_y;
in_window_x = in_window_y = FALSE;
for (j = 0; j < 4; j++)
{
if (x [j] >= 0)
in_window_x = TRUE;
if (y [j] >= 0)
in_window_y = TRUE;
}
if (! (in_window_x && in_window_y))
return;
in_window_x = in_window_y = FALSE;
for (j = 0; j < 4; j++)
{
if (x [j] < dwidth)
in_window_x = TRUE;
if (y [j] < dheight)
in_window_y = TRUE;
}
if (! (in_window_x && in_window_y))
return;
}
row = gdk_pixbuf_new (GDK_COLORSPACE_RGB, gimp_drawable_has_alpha (texture),
8, dwidth, 1);
if (row == NULL) return;
/* scale texture coords to fit the source drawable */
for (j = 0; j < 4; j++)
{
u [j] *= tile_manager_width (texture->tiles);
v [j] *= tile_manager_height (texture->tiles);
}
/* sort vertices in order of y-coordinate */
for (j = 0; j < 4; j++)
for (k = j + 1; k < 4; k++)
if (y [k] < y [j])
{
gint tmp;
gfloat ftmp;
tmp = y [k]; y [k] = y [j]; y [j] = tmp;
tmp = x [k]; x [k] = x [j]; x [j] = tmp;
ftmp = u [k]; u [k] = u [j]; u [j] = ftmp;
ftmp = v [k]; v [k] = v [j]; v [j] = ftmp;
}
if (y [3] == y [0])
return;
l_edge = g_malloc ((y [3] - y [0]) * sizeof (gint));
r_edge = g_malloc ((y [3] - y [0]) * sizeof (gint));
/* draw the quad */
#define QUAD_TRACE_L_EDGE(a, b) \
if (y [a] != y [b]) \
{ \
gimp_display_shell_trace_quad_edge (l_edge, \
x [a], y [a], \
x [b], y [b]); \
left = l_edge; \
dul = (u [b] - u [a]) / (y [b] - y [a]); \
dvl = (v [b] - v [a]) / (y [b] - y [a]); \
u_l = u [a]; \
v_l = v [a]; \
}
#define QUAD_TRACE_R_EDGE(a, b) \
if (y [a] != y [b]) \
{ \
gimp_display_shell_trace_quad_edge (r_edge, \
x [a], y [a], \
x [b], y [b]); \
right = r_edge; \
dur = (u [b] - u [a]) / (y [b] - y [a]); \
dvr = (v [b] - v [a]) / (y [b] - y [a]); \
u_r = u [a]; \
v_r = v [a]; \
}
#define QUAD_DRAW_SECTION(a, b) \
if (y [a] != y [b]) \
for (ry = y [a]; ry < y [b]; ry++) \
{ \
if (ry >= 0 && ry < dheight) \
gimp_display_shell_draw_quad_row (texture, dest, row, \
*left, u_l, v_l, \
*right, u_r, v_r, \
ry); \
left ++; \
right ++; \
u_l += dul; \
v_l += dvl; \
u_r += dur; \
v_r += dvr; \
} \
if (((x [0] > x [1]) && (x [3] > x [2])) ||
((x [0] < x [1]) && (x [3] < x [2])))
{
/*
* v0
* |--__
* _____ |....--_ v1 ____
* | |
* | |
* _____ |.....__| ______
* |__--- v2
* v3
*/
QUAD_TRACE_L_EDGE (0, 3);
QUAD_TRACE_R_EDGE (0, 1);
QUAD_DRAW_SECTION (0, 1); /* top section */
QUAD_TRACE_R_EDGE (1, 2);
QUAD_DRAW_SECTION (1, 2); /* middle section */
QUAD_TRACE_R_EDGE (2, 3);
QUAD_DRAW_SECTION (2, 3); /* bottom section */
}
else
{
/*
* v0
* /-___
* -------- /.....-- v1 ---
* / /
* ___ v2 /__...../________
* ---_/
* v3
*/
QUAD_TRACE_L_EDGE (0, 2);
QUAD_TRACE_R_EDGE (0, 1);
QUAD_DRAW_SECTION (0, 1); /* top section */
QUAD_TRACE_R_EDGE (1, 3);
QUAD_DRAW_SECTION (1, 2); /* middle section */
QUAD_TRACE_L_EDGE (2, 3);
QUAD_DRAW_SECTION (2, 3); /* bottom section */
}
#undef QUAD_TRACE_L_EDGE
#undef QUAD_TRACE_R_EDGE
#undef QUAD_DRAW_SECTION
g_object_unref (row);
g_free (l_edge);
g_free (r_edge);
}
static void
gimp_display_shell_draw_quad_row (GimpDrawable *texture,
GdkDrawable *dest,
GdkPixbuf *row,
gint x1,
gfloat u1,
gfloat v1,
gint x2,
gfloat u2,
gfloat v2,
gint y)
{
TileManager *tiles;
guchar *pptr;
gchar bytes;
gfloat u, v;
gfloat du, dv;
gint dx;
guchar pixel [4];
guchar *cmap;
gint offset;
if (! (x2 - x1))
return;
g_return_if_fail (GIMP_IS_DRAWABLE (texture));
g_return_if_fail (GDK_IS_DRAWABLE (dest));
g_return_if_fail (GDK_IS_PIXBUF (row));
g_return_if_fail (gdk_pixbuf_get_bits_per_sample (row) == 8);
g_return_if_fail (gdk_pixbuf_get_colorspace (row) == GDK_COLORSPACE_RGB);
g_return_if_fail (gdk_pixbuf_get_has_alpha (row) ==
gimp_drawable_has_alpha (texture));
bytes = gdk_pixbuf_get_n_channels (row);
pptr = gdk_pixbuf_get_pixels (row);
tiles = gimp_drawable_data (texture);
if (x1 > x2)
{
gint tmp;
gfloat ftmp;
tmp = x2; x2 = x1; x1 = tmp;
ftmp = u2; u2 = u1; u1 = ftmp;
ftmp = v2; v2 = v1; v1 = ftmp;
}
u = u1;
v = v1;
du = (u2 - u1) / (x2 - x1);
dv = (v2 - v1) / (x2 - x1);
/* don't calculate unseen pixels */
if (x1 < 0)
{
u += du * (0 - x1);
v += dv * (0 - x1);
x1 = 0;
}
else if (x1 > gdk_pixbuf_get_width (row))
return;
if (x2 < 0)
return;
else if (x2 > gdk_pixbuf_get_width (row))
x2 = gdk_pixbuf_get_width (row);
dx = x2 - x1;
switch (gimp_drawable_type (texture))
{
case GIMP_INDEXED_IMAGE:
cmap = gimp_drawable_cmap (texture);
while (dx --)
{
read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
offset = pixel [0] + pixel [0] + pixel [0];
*pptr++ = cmap [offset];
*pptr++ = cmap [offset + 1];
*pptr++ = cmap [offset + 2];
u += du;
v += dv;
}
break;
case GIMP_INDEXEDA_IMAGE:
cmap = gimp_drawable_cmap (texture);
while (dx --)
{
read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
offset = pixel [0] + pixel [0] + pixel [0];
*pptr++ = cmap [offset];
*pptr++ = cmap [offset + 1];
*pptr++ = cmap [offset + 2];
*pptr++ = pixel [1];
u += du;
v += dv;
}
break;
case GIMP_GRAY_IMAGE:
while (dx --)
{
read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
*pptr++ = pixel [0];
*pptr++ = pixel [0];
*pptr++ = pixel [0];
u += du;
v += dv;
}
break;
case GIMP_GRAYA_IMAGE:
while (dx --)
{
read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
*pptr++ = pixel [0];
*pptr++ = pixel [0];
*pptr++ = pixel [0];
*pptr++ = pixel [1];
u += du;
v += dv;
}
break;
case GIMP_RGB_IMAGE:
case GIMP_RGBA_IMAGE:
while (dx --)
{
read_pixel_data_1 (tiles, (gint) u, (gint) v, pptr);
pptr += bytes;
u += du;
v += dv;
}
break;
default:
return;
}
gdk_draw_pixbuf (dest, NULL, row, 0, 0, x1, y, x2 - x1, 1,
GDK_RGB_DITHER_NONE, 0, 0);
}
static void
gimp_display_shell_trace_quad_edge (gint *dest,
gint x1,
gint y1,
gint x2,
gint y2)
{
const gint dy = y2 - y1;
gint dx;
gchar xdir;
gint errorterm;
gint b;
gint *dptr;
if (dy == 0)
return;
g_return_if_fail (dest != NULL);
b = 0;
errorterm = 0;
dptr = dest;
if (x2 < x1)
{
dx = x1 - x2;
xdir = -1;
}
else