return;
}
+ if (g_ascii_strcasecmp(".jps", il->fd->extension) == 0)
+ {
+ g_object_set_data(G_OBJECT(pb), "stereo_sbs", GINT_TO_POINTER(1));
+ }
+
if (il->pixbuf) g_object_unref(il->pixbuf);
il->pixbuf = pb;
if (vertical)
{
- zoom = (gdouble)pr->window_height / height;
+ zoom = (gdouble)pr->viewport_height / height;
}
else
{
- zoom = (gdouble)pr->window_width / width;
+ zoom = (gdouble)pr->viewport_width / width;
}
if (zoom < 1.0)
pr->norm_center_x = 0.5;
pr->norm_center_y = 0.5;
- pr->renderer = (void *)renderer_tiles_new(pr);
+ pr->stereo_mode = PR_STEREO_HORIZ;
+
+ pr->renderer = (void *)renderer_tiles_new(pr, pr->stereo_mode);
+
+ pr->renderer2 = (pr->stereo_mode && (PR_STEREO_HORIZ || PR_STEREO_VERT)) ?
+ (void *)renderer_tiles_new(pr, pr->stereo_mode | PR_STEREO_RIGHT) : NULL;
gtk_widget_set_double_buffered(box, FALSE);
g_signal_connect_after(G_OBJECT(box), "size_allocate",
pr = PIXBUF_RENDERER(object);
pr->renderer->free(pr->renderer);
+ if (pr->renderer2) pr->renderer->free(pr->renderer2);
if (pr->pixbuf) g_object_unref(pr->pixbuf);
gint pixbuf_renderer_overlay_add(PixbufRenderer *pr, GdkPixbuf *pixbuf, gint x, gint y,
OverlayRendererFlags flags)
{
+ /* let's assume both renderers returns the same value */
+ if (pr->renderer2) pr->renderer2->overlay_add(pr->renderer2, pixbuf, x, y, flags);
return pr->renderer->overlay_add(pr->renderer, pixbuf, x, y, flags);
}
void pixbuf_renderer_overlay_set(PixbufRenderer *pr, gint id, GdkPixbuf *pixbuf, gint x, gint y)
{
pr->renderer->overlay_set(pr->renderer, id, pixbuf, x, y);
+ if (pr->renderer2) pr->renderer2->overlay_set(pr->renderer2, id, pixbuf, x, y);
}
gboolean pixbuf_renderer_overlay_get(PixbufRenderer *pr, gint id, GdkPixbuf **pixbuf, gint *x, gint *y)
{
+ if (pr->renderer2) pr->renderer2->overlay_get(pr->renderer2, id, pixbuf, x, y);
return pr->renderer->overlay_get(pr->renderer, id, pixbuf, x, y);
}
void pixbuf_renderer_overlay_remove(PixbufRenderer *pr, gint id)
{
pr->renderer->overlay_set(pr->renderer, id, NULL, 0, 0);
+ if (pr->renderer2) pr->renderer2->overlay_set(pr->renderer2, id, NULL, 0, 0);
}
/*
static void pr_border_clear(PixbufRenderer *pr)
{
- pr->renderer->border_draw(pr->renderer, 0, 0, pr->window_width, pr->window_height);
+ pr->renderer->border_draw(pr->renderer, 0, 0, pr->viewport_width, pr->viewport_height);
+ if (pr->renderer2) pr->renderer2->border_draw(pr->renderer2, 0, 0, pr->viewport_width, pr->viewport_height);
}
void pixbuf_renderer_set_color(PixbufRenderer *pr, GdkColor *color)
{
pr->renderer->queue_clear(pr->renderer);
pr->renderer->queue(pr->renderer, 0, 0, pr->width, pr->height, TRUE, TILE_RENDER_ALL, new_data, FALSE);
+ if (pr->renderer2) {
+ pr->renderer2->queue_clear(pr->renderer2);
+ pr->renderer2->queue(pr->renderer2, 0, 0, pr->width, pr->height, TRUE, TILE_RENDER_ALL, new_data, FALSE);
+ }
}
/*
pr->renderer->invalidate_region(pr->renderer, st->x * pr->scale, st->y * pr->scale,
pr->source_tile_width * pr->scale, pr->source_tile_height * pr->scale);
-
+ if (pr->renderer2) pr->renderer2->invalidate_region(pr->renderer2, st->x * pr->scale, st->y * pr->scale,
+ pr->source_tile_width * pr->scale, pr->source_tile_height * pr->scale);
return st;
}
{
pr->renderer->invalidate_region(pr->renderer, rx * pr->scale, ry * pr->scale,
rw * pr->scale, rh * pr->scale);
+ if (pr->renderer2) pr->renderer2->invalidate_region(pr->renderer2, rx * pr->scale, ry * pr->scale,
+ rw * pr->scale, rh * pr->scale);
}
g_object_unref(pixbuf);
}
* of the "broken image" icon.
*/
- if (pr->width > pr->window_width)
+ if (pr->width > pr->viewport_width)
{
src_x = pr->x_scroll + pr->vis_width / 2;
pr->norm_center_x = (gdouble)src_x / pr->width;
}
- if (pr->height > pr->window_height)
+ if (pr->height > pr->viewport_height)
{
src_y = pr->y_scroll + pr->vis_height / 2;
pr->norm_center_y = (gdouble)src_y / pr->height;
old_vw = pr->vis_width;
old_vh = pr->vis_height;
- if (pr->width < pr->window_width)
+ if (pr->width < pr->viewport_width)
{
pr->vis_width = pr->width;
- pr->x_offset = (pr->window_width - pr->width) / 2;
+ pr->x_offset = (pr->viewport_width - pr->width) / 2;
}
else
{
- pr->vis_width = pr->window_width;
+ pr->vis_width = pr->viewport_width;
pr->x_offset = 0;
}
- if (pr->height < pr->window_height)
+ if (pr->height < pr->viewport_height)
{
pr->vis_height = pr->height;
- pr->y_offset = (pr->window_height - pr->height) / 2;
+ pr->y_offset = (pr->viewport_height - pr->height) / 2;
}
else
{
- pr->vis_height = pr->window_height;
+ pr->vis_height = pr->viewport_height;
pr->y_offset = 0;
}
}
else
{
- max_w = pr->window_width;
- max_h = pr->window_height;
+ max_w = pr->viewport_width;
+ max_h = pr->viewport_height;
}
if ((pr->zoom_expand && !sizeable) || w > max_w || h > max_h)
if (invalidate || invalid)
{
pr->renderer->invalidate_all(pr->renderer);
+ if (pr->renderer2) pr->renderer2->invalidate_all(pr->renderer2);
if (!lazy) pr_redraw(pr, TRUE);
}
if (redrawn) *redrawn = (invalidate || invalid);
if (lazy)
{
pr->renderer->queue_clear(pr->renderer);
+ if (pr->renderer2) pr->renderer2->queue_clear(pr->renderer2);
}
else
{
{
gboolean zoom_changed = FALSE;
- if (pr->window_width == new_width && pr->window_height == new_height) return;
+ gint new_viewport_width = (pr->stereo_mode & PR_STEREO_HORIZ) ? new_width / 2 : new_width;
+ gint new_viewport_height = (pr->stereo_mode & PR_STEREO_VERT) ? new_height / 2 : new_height;
+
+ if (pr->window_width == new_width && pr->window_height == new_height &&
+ pr->viewport_width == new_viewport_width && pr->viewport_height == new_viewport_height) return;
pr->window_width = new_width;
pr->window_height = new_height;
+ pr->viewport_width = new_viewport_width;
+ pr->viewport_height = new_viewport_height;
if (pr->zoom == 0.0)
{
pr_size_clamp(pr);
pr_scroll_clamp(pr);
- pr->renderer->overlay_update_sizes(pr->renderer);
+ pr->renderer->update_sizes(pr->renderer);
+ if (pr->renderer2) pr->renderer2->update_sizes(pr->renderer2);
/* ensure scroller remains visible */
if (pr->scroller_overlay != -1)
{
gint x, y;
- pr->renderer->border_draw(pr->renderer, area->x, area->y, area->width, area->height);
x = MAX(0, (gint)area->x - pr->x_offset + pr->x_scroll);
y = MAX(0, (gint)area->y - pr->y_offset + pr->y_scroll);
+ pr->renderer->border_draw(pr->renderer, area->x, area->y, area->width, area->height);
pr->renderer->queue(pr->renderer,
x, y,
MIN((gint)area->width, pr->width - x),
MIN((gint)area->height, pr->height - y),
FALSE, TILE_RENDER_ALL, FALSE, FALSE);
+ if (pr->renderer2)
+ {
+ pr->renderer2->border_draw(pr->renderer2, area->x, area->y, area->width, area->height);
+ pr->renderer2->queue(pr->renderer2,
+ x, y,
+ MIN((gint)area->width, pr->width - x),
+ MIN((gint)area->height, pr->height - y),
+ FALSE, TILE_RENDER_ALL, FALSE, FALSE);
+ }
}
/*
y_off = pr->y_scroll - old_y;
pr->renderer->scroll(pr->renderer, x_off, y_off);
+ if (pr->renderer2) pr->renderer2->scroll(pr->renderer2, x_off, y_off);
}
void pixbuf_renderer_scroll_to_point(PixbufRenderer *pr, gint x, gint y,
*/
static void pr_pixbuf_size_sync(PixbufRenderer *pr)
{
+ pr->stereo_pixbuf_off = 0;
if (!pr->pixbuf) return;
switch (pr->orientation)
{
case EXIF_ORIENTATION_LEFT_BOTTOM:
pr->image_width = gdk_pixbuf_get_height(pr->pixbuf);
pr->image_height = gdk_pixbuf_get_width(pr->pixbuf);
+ if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(pr->pixbuf), "stereo_sbs")))
+ {
+ pr->image_height /= 2;
+ pr->stereo_pixbuf_off = pr->image_height;
+ }
+
break;
default:
pr->image_width = gdk_pixbuf_get_width(pr->pixbuf);
pr->image_height = gdk_pixbuf_get_height(pr->pixbuf);
+ if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(pr->pixbuf), "stereo_sbs")))
+ {
+ pr->image_width /= 2;
+ pr->stereo_pixbuf_off = pr->image_width;
+ }
}
}
#endif
{
gdk_window_clear(box->window);
- pr->renderer->overlay_draw(pr->renderer, 0, 0, pr->window_width, pr->window_height);
+ pr->renderer->overlay_draw(pr->renderer, 0, 0, pr->viewport_width, pr->viewport_height);
+ if (pr->renderer2) pr->renderer2->overlay_draw(pr->renderer2, 0, 0, pr->viewport_width, pr->viewport_height);
}
pr_update_signal(pr);
y2 = (gint)ceil((gdouble)(y + height) * pr->scale);
pr->renderer->queue(pr->renderer, x1, y1, x2 - x1, y2 - y1, FALSE, TILE_RENDER_AREA, TRUE, TRUE);
+ if (pr->renderer2) pr->renderer2->queue(pr->renderer2, x1, y1, x2 - x1, y2 - y1, FALSE, TILE_RENDER_AREA, TRUE, TRUE);
}
void pixbuf_renderer_zoom_adjust(PixbufRenderer *pr, gdouble increment)
/* OVL_HIDE_ON_SCROLL = 1 << 1*/ /* hide temporarily when scrolling (not yet implemented) */
} OverlayRendererFlags;
+typedef enum {
+ PR_STEREO_NONE = 0, /* do nothing */
+ PR_STEREO_DUAL = 1 << 0, /* independent stereo buffers, for example nvidia opengl */
+ PR_STEREO_HORIZ = 1 << 2, /* side by side */
+ PR_STEREO_VERT = 1 << 3, /* above below */
+ /* flags for renderer: */
+ PR_STEREO_RIGHT = 1 << 4, /* above below */
+ PR_STEREO_ANAGLYPH = 1 << 5 /* anaglyph */
+
+} PixbufRendererStereoMode;
+
struct _RendererFuncs
{
void (*queue)(void *renderer, gint x, gint y, gint w, gint h,
void (*invalidate_all)(void *renderer);
void (*invalidate_region)(void *renderer, gint x, gint y, gint w, gint h);
void (*scroll)(void *renderer, gint x_off, gint y_off);
+ void (*update_sizes)(void *renderer);
gint (*overlay_add)(void *renderer, GdkPixbuf *pixbuf, gint x, gint y, OverlayRendererFlags flags);
void (*overlay_set)(void *renderer, gint id, GdkPixbuf *pixbuf, gint x, gint y);
gboolean (*overlay_get)(void *renderer, gint id, GdkPixbuf **pixbuf, gint *x, gint *y);
- void (*overlay_update_sizes)(void *renderer);
void (*overlay_draw)(void *renderer, gint x, gint y, gint w, gint h);
void (*free)(void *renderer);
gint image_width; /* image actual dimensions (pixels) */
gint image_height;
+ gint stereo_pixbuf_off; /* offset of the right part of the stereo image in pixbuf */
GdkPixbuf *pixbuf;
gint orientation;
+ gint stereo_mode;
+
RendererFuncs *renderer;
+ RendererFuncs *renderer2;
};
struct _PixbufRendererClass
guint draw_idle_id; /* event source id */
GdkPixbuf *spare_tile;
-
+
+ gint stereo_mode;
+ gint stereo_off_x;
+ gint stereo_off_y;
};
{
if (pr_clip_region(x, y, w, h,
0, 0,
- pr->window_width, pr->window_height,
+ pr->viewport_width, pr->viewport_height,
&rx, &ry, &rw, &rh))
{
- gdk_window_clear_area(box->window, rx, ry, rw, rh);
+ gdk_window_clear_area(box->window, rx + rt->stereo_off_x, ry + rt->stereo_off_y, rw, rh);
rt_overlay_draw(rt, rx, ry, rw, rh, NULL);
}
return;
}
- if (pr->vis_width < pr->window_width)
+ if (pr->vis_width < pr->viewport_width)
{
if (pr->x_offset > 0 &&
pr_clip_region(x, y, w, h,
0, 0,
- pr->x_offset, pr->window_height,
+ pr->x_offset, pr->viewport_height,
&rx, &ry, &rw, &rh))
{
- gdk_window_clear_area(box->window, rx, ry, rw, rh);
+ gdk_window_clear_area(box->window, rx + rt->stereo_off_x, ry + rt->stereo_off_y, rw, rh);
rt_overlay_draw(rt, rx, ry, rw, rh, NULL);
}
- if (pr->window_width - pr->vis_width - pr->x_offset > 0 &&
+ if (pr->viewport_width - pr->vis_width - pr->x_offset > 0 &&
pr_clip_region(x, y, w, h,
pr->x_offset + pr->vis_width, 0,
- pr->window_width - pr->vis_width - pr->x_offset, pr->window_height,
+ pr->viewport_width - pr->vis_width - pr->x_offset, pr->viewport_height,
&rx, &ry, &rw, &rh))
{
- gdk_window_clear_area(box->window, rx, ry, rw, rh);
+ gdk_window_clear_area(box->window, rx + rt->stereo_off_x, ry + rt->stereo_off_y, rw, rh);
rt_overlay_draw(rt, rx, ry, rw, rh, NULL);
}
}
- if (pr->vis_height < pr->window_height)
+ if (pr->vis_height < pr->viewport_height)
{
if (pr->y_offset > 0 &&
pr_clip_region(x, y, w, h,
pr->vis_width, pr->y_offset,
&rx, &ry, &rw, &rh))
{
- gdk_window_clear_area(box->window, rx, ry, rw, rh);
+ gdk_window_clear_area(box->window, rx + rt->stereo_off_x, ry + rt->stereo_off_y, rw, rh);
rt_overlay_draw(rt, rx, ry, rw, rh, NULL);
}
- if (pr->window_height - pr->vis_height - pr->y_offset > 0 &&
+ if (pr->viewport_height - pr->vis_height - pr->y_offset > 0 &&
pr_clip_region(x, y, w, h,
pr->x_offset, pr->y_offset + pr->vis_height,
- pr->vis_width, pr->window_height - pr->vis_height - pr->y_offset,
+ pr->vis_width, pr->viewport_height - pr->vis_height - pr->y_offset,
&rx, &ry, &rw, &rh))
{
- gdk_window_clear_area(box->window, rx, ry, rw, rh);
+ gdk_window_clear_area(box->window, rx + rt->stereo_off_x, ry + rt->stereo_off_y, rw, rh);
rt_overlay_draw(rt, rx, ry, rw, rh, NULL);
}
}
static void rt_border_clear(RendererTiles *rt)
{
PixbufRenderer *pr = rt->pr;
- rt_border_draw(rt, 0, 0, pr->window_width, pr->window_height);
+ rt_border_draw(rt, 0, 0, pr->viewport_width, pr->viewport_height);
}
if (od->flags & OVL_RELATIVE)
{
- if (px < 0) px = pr->window_width - pw + px;
- if (py < 0) py = pr->window_height - ph + py;
+ if (px < 0) px = pr->viewport_width - pw + px;
+ if (py < 0) py = pr->viewport_height - ph + py;
}
if (x) *x = px;
GtkWidget *box;
gboolean has_alpha;
gboolean draw = FALSE;
+ gint stereo_pixbuf_off;
if (it->render_todo == TILE_RENDER_NONE && it->pixmap && !new_data) return;
rt_tile_prepare(rt, it);
has_alpha = (pr->pixbuf && gdk_pixbuf_get_has_alpha(pr->pixbuf));
+ stereo_pixbuf_off = (rt->stereo_mode & PR_STEREO_RIGHT) ? pr->stereo_pixbuf_off : 0;
box = GTK_WIDGET(pr);
/* FIXME checker colors for alpha should be configurable,
w, h,
&pb_x, &pb_y,
&pb_w, &pb_h);
+ src_x += stereo_pixbuf_off;
if (has_alpha)
{
box->style->fg_gc[GTK_WIDGET_STATE(box)],
#endif
pr->pixbuf,
- it->x + x, it->y + y,
+ it->x + x + stereo_pixbuf_off, it->y + y,
x, y,
w, h,
pr->dither_quality, it->x + x, it->y + y);
w, h,
&pb_x, &pb_y,
&pb_w, &pb_h);
+
switch (pr->orientation)
{
gdouble tmp;
/* nothing to do */
break;
}
-
+ src_x += stereo_pixbuf_off * scale_x;
+
/* HACK: The pixbuf scalers get kinda buggy(crash) with extremely
* small sizes for anything but GDK_INTERP_NEAREST
*/
x, y,
x, y,
w, h,
- pr->dither_quality, it->x + x, it->y + y);
+ pr->dither_quality, it->x + x + rt->stereo_off_x, it->y + y + rt->stereo_off_y);
}
#if 0
gdk_draw_drawable(box->window, box->style->fg_gc[GTK_WIDGET_STATE(box)],
#endif
it->pixmap, x, y,
- pr->x_offset + (it->x - pr->x_scroll) + x, pr->y_offset + (it->y - pr->y_scroll) + y, w, h);
+ pr->x_offset + (it->x - pr->x_scroll) + x + rt->stereo_off_x, pr->y_offset + (it->y - pr->y_scroll) + y + rt->stereo_off_y, w, h);
if (rt->overlay_list)
{
gdk_gc_set_exposures(gc, TRUE);
gdk_draw_drawable(box->window, gc,
box->window,
- x2 + pr->x_offset, y2 + pr->y_offset,
- x1 + pr->x_offset, y1 + pr->y_offset, w, h);
+ x2 + pr->x_offset + rt->stereo_off_x, y2 + pr->y_offset + rt->stereo_off_y,
+ x1 + pr->x_offset + rt->stereo_off_x, y1 + pr->y_offset + rt->stereo_off_y, w, h);
g_object_unref(gc);
rt_overlay_queue_all(rt, x2, y2, x1, y1);
rt_overlay_draw((RendererTiles *)renderer, x, y, w, h, NULL);
}
+static void renderer_update_sizes(void *renderer)
+{
+ RendererTiles *rt = (RendererTiles *)renderer;
+
+ rt_overlay_update_sizes(rt);
+
+ rt->stereo_off_x = 0;
+ rt->stereo_off_x = 0;
+
+ if (rt->stereo_mode & PR_STEREO_RIGHT)
+ {
+ if (rt->stereo_mode & PR_STEREO_HORIZ)
+ {
+ rt->stereo_off_x = rt->pr->viewport_width;
+ }
+ else if (rt->stereo_mode & PR_STEREO_VERT)
+ {
+ rt->stereo_off_y = rt->pr->viewport_height;
+ }
+ }
+}
+
static void renderer_free(void *renderer)
{
RendererTiles *rt = (RendererTiles *)renderer;
g_free(rt);
}
-RendererFuncs *renderer_tiles_new(PixbufRenderer *pr)
+RendererFuncs *renderer_tiles_new(PixbufRenderer *pr, gint stereo_mode)
{
RendererTiles *rt = g_new0(RendererTiles, 1);
rt->f.invalidate_all = renderer_invalidate_all;
rt->f.invalidate_region = renderer_invalidate_region;
rt->f.scroll = rt_scroll;
+ rt->f.update_sizes = renderer_update_sizes;
rt->f.overlay_add = renderer_tiles_overlay_add;
rt->f.overlay_set = renderer_tiles_overlay_set;
rt->f.overlay_get = renderer_tiles_overlay_get;
- rt->f.overlay_update_sizes = rt_overlay_update_sizes;
rt->f.overlay_draw = renderer_overlay_draw;
rt->tile_width = PR_TILE_SIZE;
rt->tile_cache_max = PR_CACHE_SIZE_DEFAULT;
rt->draw_idle_id = 0;
+
+ rt->stereo_mode = stereo_mode;
+ rt->stereo_off_x = 0;
+ rt->stereo_off_y = 0;
g_signal_connect(G_OBJECT(pr), "hierarchy-changed",
G_CALLBACK(rt_hierarchy_changed_cb), rt);
#include <pixbuf-renderer.h>
-RendererFuncs *renderer_tiles_new(PixbufRenderer *pr);
+RendererFuncs *renderer_tiles_new(PixbufRenderer *pr, gint stereo_flags);
#endif
/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */