gimp/plug-ins/map-object/map-object-preview.c

395 lines
10 KiB
C
Raw Normal View History

/*************************************************/
/* Compute a preview image and preview wireframe */
/*************************************************/
#include "config.h"
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include "map-object-main.h"
#include "map-object-ui.h"
#include "map-object-image.h"
#include "map-object-apply.h"
#include "map-object-shade.h"
#include "map-object-preview.h"
typedef struct
{
gint x, y, w, h;
cairo_surface_t *image;
} BackBuffer;
gdouble mat[3][4];
gint lightx, lighty;
static BackBuffer backbuf = { 0, 0, 0, 0, NULL };
/* Protos */
/* ====== */
static void compute_preview (gint x,
gint y,
gint w,
gint h,
gint pw,
gint ph);
static void draw_light_marker (gint xpos,
gint ypos);
static void clear_light_marker (void);
/**************************************************************/
/* Computes a preview of the rectangle starting at (x,y) with */
/* dimensions (w,h), placing the result in preview_RGB_data. */
/**************************************************************/
static void
compute_preview (gint x,
gint y,
gint w,
gint h,
gint pw,
gint ph)
{
gdouble xpostab[PREVIEW_WIDTH];
gdouble ypostab[PREVIEW_HEIGHT];
gdouble realw;
gdouble realh;
GimpVector3 p1, p2;
GimpRGB color;
GimpRGB lightcheck, darkcheck;
gint xcnt, ycnt, f1, f2;
guchar r, g, b;
glong index = 0;
init_compute ();
p1 = int_to_pos (x, y);
p2 = int_to_pos (x + w, y + h);
/* First, compute the linear mapping (x,y,x+w,y+h) to (0,0,pw,ph) */
/* ============================================================== */
realw = (p2.x - p1.x);
realh = (p2.y - p1.y);
for (xcnt = 0; xcnt < pw; xcnt++)
xpostab[xcnt] = p1.x + realw * ((gdouble) xcnt / (gdouble) pw);
for (ycnt = 0; ycnt < ph; ycnt++)
ypostab[ycnt] = p1.y + realh * ((gdouble) ycnt / (gdouble) ph);
/* Compute preview using the offset tables */
/* ======================================= */
if (mapvals.transparent_background == TRUE)
{
plug-ins/libgck/gck/gck.h removed the GckRGB color type and all it's 2001-01-01 Michael Natterer <mitch@gimp.org> * plug-ins/libgck/gck/gck.h * plug-ins/libgck/gck/gckcolor.c: removed the GckRGB color type and all it's functions. * libgimp/Makefile.am * libgimp/gimpcolor.[ch]: new files containing the new GimpRGB color type and assorted functions. * libgimp/gimpcolorspace.[ch]: colorspace conversion routines for the new GimpRGB type. Also taken from LibGCK. * libgimp/gimp.h * libgimp/gimptypes.h: #include "gimpcolor.h". It's ugly to include it in both files but unavoidable to follow our new "*.c" file include policy. This will go away as libgimp will be chopped up into pieces anyway. * app/apptypes.h * app/asupsample.[ch] * app/blend.c * app/color_transfer.h * app/gradient_header.h: removed "color_t" and use GimpRGB instead. * plug-ins/Lighting/lighting_apply.c * plug-ins/Lighting/lighting_image.c * plug-ins/Lighting/lighting_image.h * plug-ins/Lighting/lighting_main.c * plug-ins/Lighting/lighting_main.h * plug-ins/Lighting/lighting_preview.c * plug-ins/Lighting/lighting_shade.c * plug-ins/Lighting/lighting_shade.h * plug-ins/MapObject/mapobject_apply.c * plug-ins/MapObject/mapobject_image.c * plug-ins/MapObject/mapobject_image.h * plug-ins/MapObject/mapobject_main.c * plug-ins/MapObject/mapobject_main.h * plug-ins/MapObject/mapobject_preview.c * plug-ins/MapObject/mapobject_shade.c * plug-ins/MapObject/mapobject_shade.h * modules/colorsel_triangle.c: s/GckRGB/GimpRGB/g * plug-ins/gdyntext/gdyntextcompat.h: check also for GIMP's minor version when deciding if to add a missing PDB wrapper. (All this compat cruft including libgimp/gimpcompat.h should go away ASAP)
2001-01-02 02:35:09 +08:00
gimp_rgba_set (&background, 0.0, 0.0, 0.0, 0.0);
}
else
{
tools/pdbgen/Makefile.am tools/pdbgen/groups.pl removed the "Palette" pdb 2004-09-22 Michael Natterer <mitch@gimp.org> * tools/pdbgen/Makefile.am * tools/pdbgen/groups.pl * tools/pdbgen/pdb/palette.pdb: removed the "Palette" pdb group... * tools/pdbgen/pdb/context.pdb: and added its functions to the "Context" namespace instead. * app/pdb/Makefile.am * app/pdb/palette_cmds.c: removed. * app/pdb/procedural_db.c: added them to the pdb_compat hash table. * libgimp/Makefile.am * libgimp/gimppalette_pdb.[ch]: removed. * libgimp/gimppalette.[ch]: new files holding compat functions which call gimp_context_*() functions. * libgimp/gimp.h * libgimp/gimpui.c: changed accordingly. * app/pdb/context_cmds.c * app/pdb/internal_procs.c * libgimp/gimp_pdb.h * libgimp/gimpcontext_pdb.[ch]: regenerated. * plug-ins/MapObject/mapobject_image.c * plug-ins/MapObject/mapobject_preview.c * plug-ins/common/apply_lens.c * plug-ins/common/blinds.c * plug-ins/common/borderaverage.c * plug-ins/common/checkerboard.c * plug-ins/common/colortoalpha.c * plug-ins/common/cubism.c * plug-ins/common/exchange.c * plug-ins/common/film.c * plug-ins/common/gif.c * plug-ins/common/grid.c * plug-ins/common/mapcolor.c * plug-ins/common/mblur.c * plug-ins/common/mng.c * plug-ins/common/mosaic.c * plug-ins/common/papertile.c * plug-ins/common/png.c * plug-ins/common/polar.c * plug-ins/common/semiflatten.c * plug-ins/common/sinus.c * plug-ins/common/sparkle.c * plug-ins/common/vpropagate.c * plug-ins/common/warp.c * plug-ins/common/whirlpinch.c * plug-ins/gfig/gfig-style.c * plug-ins/gfli/gfli.c * plug-ins/ifscompose/ifscompose.c * plug-ins/maze/handy.c * plug-ins/pagecurl/pagecurl.c * plug-ins/pygimp/gimpmodule.c * plug-ins/script-fu/scripts/*.scm: changed accordingly.
2004-09-23 02:43:09 +08:00
gimp_context_get_background (&background);
gimp_rgb_set_alpha (&background, 1.0);
}
gimp_rgba_set (&lightcheck,
GIMP_CHECK_LIGHT, GIMP_CHECK_LIGHT, GIMP_CHECK_LIGHT, 1.0);
gimp_rgba_set (&darkcheck,
GIMP_CHECK_DARK, GIMP_CHECK_DARK, GIMP_CHECK_DARK, 1.0);
gimp_vector3_set (&p2, -1.0, -1.0, 0.0);
cairo_surface_flush (preview_surface);
for (ycnt = 0; ycnt < ph; ycnt++)
{
index = ycnt * preview_rgb_stride;
for (xcnt = 0; xcnt < pw; xcnt++)
{
p1.x = xpostab[xcnt];
p1.y = ypostab[ycnt];
p2 = p1;
color = (* get_ray_color) (&p1);
if (color.a < 1.0)
{
f1 = ((xcnt % 32) < 16);
f2 = ((ycnt % 32) < 16);
f1 = f1 ^ f2;
if (f1)
{
if (color.a == 0.0)
color = lightcheck;
else
gimp_rgb_composite (&color, &lightcheck,
GIMP_RGB_COMPOSITE_BEHIND);
}
else
{
if (color.a == 0.0)
color = darkcheck;
else
gimp_rgb_composite (&color, &darkcheck,
GIMP_RGB_COMPOSITE_BEHIND);
}
}
gimp_rgb_get_uchar (&color, &r, &g, &b);
GIMP_CAIRO_RGB24_SET_PIXEL((preview_rgb_data + index), r, g, b);
index += 4;
}
}
cairo_surface_mark_dirty (preview_surface);
}
/*************************************************/
/* Check if the given position is within the */
/* light marker. Return TRUE if so, FALSE if not */
/*************************************************/
gint
check_light_hit (gint xpos,
gint ypos)
{
gdouble dx, dy, r;
if (mapvals.lightsource.type == POINT_LIGHT)
{
dx = (gdouble) lightx - xpos;
dy = (gdouble) lighty - ypos;
r = sqrt (dx * dx + dy * dy) + 0.5;
if ((gint) r > 7)
return FALSE;
else
return TRUE;
}
return FALSE;
}
/****************************************/
/* Draw a marker to show light position */
/****************************************/
static void
draw_light_marker (gint xpos,
gint ypos)
{
GdkColor color;
cairo_t *cr, *cr_p;
gint pw, ph, startx, starty;
if (mapvals.lightsource.type != POINT_LIGHT)
return;
pw = PREVIEW_WIDTH * mapvals.zoom;
ph = PREVIEW_HEIGHT * mapvals.zoom;
startx = (PREVIEW_WIDTH - pw) / 2;
starty = (PREVIEW_HEIGHT - ph) / 2;
cr = gdk_cairo_create (gtk_widget_get_window (previewarea));
cairo_set_line_width (cr, 1.0);
color.red = 0x0;
color.green = 0x4000;
color.blue = 0xFFFF;
gdk_cairo_set_source_color (cr, &color);
lightx = xpos;
lighty = ypos;
/* Save background */
/* =============== */
backbuf.x = lightx - 7;
backbuf.y = lighty - 7;
backbuf.w = 14;
backbuf.h = 14;
/* X doesn't like images that's outside a window, make sure */
/* we get the backbuffer image from within the boundaries */
/* ======================================================== */
if (backbuf.x < startx)
backbuf.x = startx;
else if ((backbuf.x + backbuf.w) > startx + pw)
backbuf.w = MAX(startx + pw - backbuf.x, 0);
if (backbuf.y < starty)
backbuf.y = starty;
else if ((backbuf.y + backbuf.h) > starty + ph)
backbuf.h = MAX(starty + ph - backbuf.y, 0);
if (backbuf.image)
cairo_surface_destroy (backbuf.image);
backbuf.image = cairo_surface_create_similar (preview_surface,
CAIRO_CONTENT_COLOR,
PREVIEW_WIDTH, PREVIEW_HEIGHT);
cr_p = cairo_create (backbuf.image);
cairo_rectangle (cr_p, backbuf.x, backbuf.y, backbuf.w, backbuf.h);
cairo_clip (cr_p);
cairo_set_source_surface (cr_p, preview_surface, startx, starty);
cairo_paint (cr_p);
cairo_destroy (cr_p);
cairo_arc (cr, lightx, lighty, 7, 0, 2 * M_PI);
cairo_fill (cr);
cairo_destroy (cr);
}
static void
clear_light_marker (void)
{
/* Restore background if it has been saved */
/* ======================================= */
gint pw, ph, startx, starty;
if (backbuf.image != NULL)
{
cairo_t *cr;
cr = gdk_cairo_create (gtk_widget_get_window (previewarea));
cairo_rectangle (cr, backbuf.x, backbuf.y, backbuf.w, backbuf.h);
cairo_clip (cr);
cairo_set_source_surface (cr, backbuf.image, 0.0, 0.0);
cairo_paint (cr);
cairo_destroy (cr);
cairo_surface_destroy (backbuf.image);
backbuf.image = NULL;
}
pw = PREVIEW_WIDTH * mapvals.zoom;
ph = PREVIEW_HEIGHT * mapvals.zoom;
if (pw != PREVIEW_WIDTH || ph != PREVIEW_HEIGHT)
{
startx = (PREVIEW_WIDTH - pw) / 2;
starty = (PREVIEW_HEIGHT - ph) / 2;
gdk_window_clear_area (gtk_widget_get_window (previewarea),
0, 0, startx, PREVIEW_HEIGHT);
gdk_window_clear_area (gtk_widget_get_window (previewarea),
startx, 0, pw, starty);
gdk_window_clear_area (gtk_widget_get_window (previewarea),
pw + startx, 0, startx, PREVIEW_HEIGHT);
gdk_window_clear_area (gtk_widget_get_window (previewarea),
startx, ph + starty, pw, starty);
}
}
static void
draw_lights (gint startx,
gint starty,
gint pw,
gint ph)
{
gdouble dxpos, dypos;
gint xpos, ypos;
clear_light_marker ();
gimp_vector_3d_to_2d (startx, starty, pw, ph,
&dxpos, &dypos, &mapvals.viewpoint,
&mapvals.lightsource.position);
xpos = RINT (dxpos);
ypos = RINT (dypos);
if (xpos >= 0 && xpos <= PREVIEW_WIDTH &&
ypos >= 0 && ypos <= PREVIEW_HEIGHT)
draw_light_marker (xpos, ypos);
}
/*************************************************/
/* Update light position given new screen coords */
/*************************************************/
void
update_light (gint xpos,
gint ypos)
{
gint startx, starty, pw, ph;
pw = PREVIEW_WIDTH * mapvals.zoom;
ph = PREVIEW_HEIGHT * mapvals.zoom;
startx = (PREVIEW_WIDTH - pw) / 2;
starty = (PREVIEW_HEIGHT - ph) / 2;
gimp_vector_2d_to_3d (startx, starty, pw, ph, xpos, ypos,
&mapvals.viewpoint, &mapvals.lightsource.position);
draw_lights (startx, starty, pw, ph);
}
/******************************************************************/
/* Draw preview image. if DoCompute is TRUE then recompute image. */
/******************************************************************/
void
compute_preview_image (void)
{
GdkDisplay *display = gtk_widget_get_display (previewarea);
GdkCursor *cursor;
gint startx, starty, pw, ph;
pw = PREVIEW_WIDTH * mapvals.zoom;
ph = PREVIEW_HEIGHT * mapvals.zoom;
startx = (PREVIEW_WIDTH - pw) / 2;
starty = (PREVIEW_HEIGHT - ph) / 2;
cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
gdk_window_set_cursor (gtk_widget_get_window (previewarea), cursor);
gdk_cursor_unref (cursor);
compute_preview (0, 0, width - 1, height - 1, pw, ph);
cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
gdk_window_set_cursor(gtk_widget_get_window (previewarea), cursor);
gdk_cursor_unref (cursor);
clear_light_marker ();
}
gboolean
preview_expose (GtkWidget *widget,
GdkEventExpose *eevent)
{
gint startx, starty, pw, ph;
GdkColor color;
cairo_t *cr;
cr = gdk_cairo_create (eevent->window);
color.red = 0xFFFF;
color.green = 0xFFFF;
color.blue = 0xFFFF;
gdk_cairo_set_source_color (cr, &color);
pw = PREVIEW_WIDTH * mapvals.zoom;
ph = PREVIEW_HEIGHT * mapvals.zoom;
startx = (PREVIEW_WIDTH - pw) / 2;
starty = (PREVIEW_HEIGHT - ph) / 2;
cairo_set_source_surface (cr, preview_surface, startx, starty);
cairo_rectangle (cr, startx, starty, pw, ph);
cairo_clip (cr);
cairo_paint (cr);
draw_lights (startx, starty, pw, ph);
cairo_destroy (cr);
return FALSE;
}