aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Älgmyr <anton@algmyr.se>2020-03-11 00:35:28 +0100
committerHarry Jeffery <harry@exec64.co.uk>2020-06-12 01:00:10 +0100
commitf968eb420c8d30d45adc1f668c15c29f5b9ee87d (patch)
tree48e33cd4bc0613dd87d66151cbfaab5d7ff6a093
parenteb60fefc3b7e9b5367bca9d3b5e5d4e50f5b72a7 (diff)
downloadimv-f968eb420c8d30d45adc1f668c15c29f5b9ee87d.tar.gz
Add rotation and flipping commands.
Rotation can be done by any amount (not limited to multiples of 90). Commands allow flipping horizontally and vertically. The flips are done relative to the current rotation.
-rw-r--r--doc/imv.1.txt9
-rw-r--r--src/canvas.c22
-rw-r--r--src/canvas.h8
-rw-r--r--src/imv.c49
-rw-r--r--src/viewport.c36
-rw-r--r--src/viewport.h18
6 files changed, 133 insertions, 9 deletions
diff --git a/doc/imv.1.txt b/doc/imv.1.txt
index 0738882..14dd727 100644
--- a/doc/imv.1.txt
+++ b/doc/imv.1.txt
@@ -99,6 +99,15 @@ Commands can be entered by pressing *:*. imv supports the following commands:
'actual' resets the zoom to 100%, showing the image at its actual size.
Aliased to 'z'.
+*rotate* <amount>::
+ Rotate image clockwise by the given amount in degrees.
+
+*rotate_to* <angle>::
+ Rotate image clockwise to the given angle in degrees.
+
+*flip* <'horizontal'|'vertical'>::
+ Flip image horizontally/vertically (across vertical/horizontal axis).
+
*open* [-r] <paths ...>::
Add the given paths to the list of open images. If the '-r' option is
specified, do so recursively. Shell expansions may be used.
diff --git a/src/canvas.c b/src/canvas.c
index c185c06..a1044d5 100644
--- a/src/canvas.c
+++ b/src/canvas.c
@@ -8,9 +8,9 @@
#include <cairo/cairo.h>
#include <pango/pangocairo.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdbool.h>
#ifdef IMV_BACKEND_LIBRSVG
#include <librsvg/rsvg.h>
@@ -204,7 +204,9 @@ static int convert_pixelformat(enum imv_pixelformat fmt)
static void draw_bitmap(struct imv_canvas *canvas,
struct imv_bitmap *bitmap,
int bx, int by, double scale,
- enum upscaling_method upscaling_method, bool cache_invalidated)
+ double rotation, bool mirrored,
+ enum upscaling_method upscaling_method,
+ bool cache_invalidated)
{
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
@@ -249,6 +251,15 @@ static void draw_bitmap(struct imv_canvas *canvas,
const int top = by;
const int right = left + bitmap->width * scale;
const int bottom = top + bitmap->height * scale;
+ const int center_x = left + bitmap->width * scale / 2;
+ const int center_y = top + bitmap->height * scale / 2;
+
+ glTranslated(center_x, center_y, 0);
+ if (mirrored) {
+ glScaled(-1, 1, 1);
+ }
+ glRotated(-rotation, 0, 0, 1);
+ glTranslated(-center_x, -center_y, 0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -273,11 +284,14 @@ RsvgHandle *imv_image_get_svg(const struct imv_image *image);
void imv_canvas_draw_image(struct imv_canvas *canvas, struct imv_image *image,
int x, int y, double scale,
- enum upscaling_method upscaling_method, bool cache_invalidated)
+ double rotation, bool mirrored,
+ enum upscaling_method upscaling_method,
+ bool cache_invalidated)
{
struct imv_bitmap *bitmap = imv_image_get_bitmap(image);
if (bitmap) {
- draw_bitmap(canvas, bitmap, x, y, scale, upscaling_method, cache_invalidated);
+ draw_bitmap(canvas, bitmap, x, y, scale, rotation, mirrored,
+ upscaling_method, cache_invalidated);
return;
}
diff --git a/src/canvas.h b/src/canvas.h
index fc043e5..255c10c 100644
--- a/src/canvas.h
+++ b/src/canvas.h
@@ -1,8 +1,8 @@
-#include <stdbool.h>
-
#ifndef IMV_CANVAS_H
#define IMV_CANVAS_H
+#include <stdbool.h>
+
struct imv_canvas;
struct imv_image;
@@ -48,6 +48,8 @@ void imv_canvas_draw(struct imv_canvas *canvas);
/* Blit the given image to the current OpenGL framebuffer */
void imv_canvas_draw_image(struct imv_canvas *canvas, struct imv_image *image,
int x, int y, double scale,
- enum upscaling_method upscaling_method, bool cache_invalidated);
+ double rotation, bool mirrored,
+ enum upscaling_method upscaling_method,
+ bool cache_invalidated);
#endif
diff --git a/src/imv.c b/src/imv.c
index 5522223..313b253 100644
--- a/src/imv.c
+++ b/src/imv.c
@@ -179,6 +179,9 @@ static void command_next(struct list *args, const char *argstr, void *data);
static void command_prev(struct list *args, const char *argstr, void *data);
static void command_goto(struct list *args, const char *argstr, void *data);
static void command_zoom(struct list *args, const char *argstr, void *data);
+static void command_rotate(struct list *args, const char *argstr, void *data);
+static void command_rotate_to(struct list *args, const char *argstr, void *data);
+static void command_flip(struct list *args, const char *argstr, void *data);
static void command_open(struct list *args, const char *argstr, void *data);
static void command_close(struct list *args, const char *argstr, void *data);
static void command_fullscreen(struct list *args, const char *argstr, void *data);
@@ -497,6 +500,9 @@ struct imv *imv_create(void)
imv_command_register(imv->commands, "prev", &command_prev);
imv_command_register(imv->commands, "goto", &command_goto);
imv_command_register(imv->commands, "zoom", &command_zoom);
+ imv_command_register(imv->commands, "rotate", &command_rotate);
+ imv_command_register(imv->commands, "rotate_to", &command_rotate_to);
+ imv_command_register(imv->commands, "flip", &command_flip);
imv_command_register(imv->commands, "open", &command_open);
imv_command_register(imv->commands, "close", &command_close);
imv_command_register(imv->commands, "fullscreen", &command_fullscreen);
@@ -1183,10 +1189,15 @@ static void render_window(struct imv *imv)
/* draw our actual image */
if (imv->current_image) {
int x, y;
- double scale;
+ double scale, rotation;
+ bool mirrored;
imv_viewport_get_offset(imv->view, &x, &y);
imv_viewport_get_scale(imv->view, &scale);
- imv_canvas_draw_image(imv->canvas, imv->current_image, x, y, scale, imv->upscaling_method, imv->cache_invalidated);
+ imv_viewport_get_rotation(imv->view, &rotation);
+ imv_viewport_get_mirrored(imv->view, &mirrored);
+ imv_canvas_draw_image(imv->canvas, imv->current_image,
+ x, y, scale, rotation, mirrored,
+ imv->upscaling_method, imv->cache_invalidated);
}
imv_canvas_clear(imv->canvas);
@@ -1497,6 +1508,39 @@ static void command_zoom(struct list *args, const char *argstr, void *data)
}
}
+static void command_rotate(struct list *args, const char *argstr, void *data)
+{
+ (void)argstr;
+ struct imv *imv = data;
+ if (args->len == 2) {
+ double degrees = strtod(args->items[1], NULL);
+ imv_viewport_rotate(imv->view, degrees);
+ }
+}
+
+static void command_rotate_to(struct list *args, const char *argstr, void *data)
+{
+ (void)argstr;
+ struct imv *imv = data;
+ if (args->len == 2) {
+ double degrees = strtod(args->items[1], NULL);
+ imv_viewport_rotate_to(imv->view, degrees);
+ }
+}
+
+static void command_flip(struct list *args, const char *argstr, void *data)
+{
+ (void)argstr;
+ struct imv *imv = data;
+ if (args->len == 2) {
+ if (!strcmp(args->items[1], "vertical")) {
+ imv_viewport_flip_v(imv->view);
+ } else if (!strcmp(args->items[1], "horizontal")) {
+ imv_viewport_flip_h(imv->view);
+ }
+ }
+}
+
static void command_open(struct list *args, const char *argstr, void *data)
{
(void)argstr;
@@ -1584,6 +1628,7 @@ static void command_reset(struct list *args, const char *argstr, void *data)
(void)args;
(void)argstr;
struct imv *imv = data;
+ imv_viewport_rotate_to(imv->view, 0);
imv->need_rescale = true;
imv->need_redraw = true;
}
diff --git a/src/viewport.c b/src/viewport.c
index c894f26..7cfb7db 100644
--- a/src/viewport.c
+++ b/src/viewport.c
@@ -1,9 +1,12 @@
#include "viewport.h"
+#include <stdbool.h>
#include <stdlib.h>
struct imv_viewport {
double scale;
+ double rotation;
+ bool mirrored;
struct {
int width, height;
} window; /* window dimensions */
@@ -32,6 +35,8 @@ struct imv_viewport *imv_viewport_create(int window_width, int window_height,
view->buffer.width = buffer_width;
view->buffer.height = buffer_height;
view->scale = 1;
+ view->rotation = 0;
+ view->mirrored = false;
view->x = view->y = view->redraw = 0;
view->pan_factor_x = view->pan_factor_y = 0.5;
view->playing = 1;
@@ -84,6 +89,20 @@ void imv_viewport_get_scale(struct imv_viewport *view, double *scale)
}
}
+void imv_viewport_get_rotation(struct imv_viewport *view, double *rotation)
+{
+ if(rotation) {
+ *rotation = view->rotation;
+ }
+}
+
+void imv_viewport_get_mirrored(struct imv_viewport *view, bool *mirrored)
+{
+ if(mirrored) {
+ *mirrored = view->mirrored;
+ }
+}
+
void imv_viewport_set_default_pan_factor(struct imv_viewport *view, double pan_factor_x, double pan_factor_y)
{
view->pan_factor_x = pan_factor_x;
@@ -177,6 +196,23 @@ void imv_viewport_zoom(struct imv_viewport *view, const struct imv_image *image,
view->locked = 1;
}
+void imv_viewport_rotate(struct imv_viewport *view, double degrees) {
+ view->rotation += degrees;
+}
+
+void imv_viewport_rotate_to(struct imv_viewport *view, double degrees) {
+ view->rotation = degrees;
+}
+
+void imv_viewport_flip_h(struct imv_viewport *view) {
+ view->mirrored = !view->mirrored;
+}
+
+void imv_viewport_flip_v(struct imv_viewport *view) {
+ view->mirrored = !view->mirrored;
+ view->rotation = -(180.0 - view->rotation);
+}
+
void imv_viewport_center(struct imv_viewport *view, const struct imv_image *image)
{
const int image_width = imv_image_width(image);
diff --git a/src/viewport.h b/src/viewport.h
index 5e5bc24..417bf93 100644
--- a/src/viewport.h
+++ b/src/viewport.h
@@ -42,6 +42,12 @@ void imv_viewport_get_offset(struct imv_viewport *view, int *x, int *y);
/* Fetch viewport scale */
void imv_viewport_get_scale(struct imv_viewport *view, double *scale);
+/* Fetch viewport rotation */
+void imv_viewport_get_rotation(struct imv_viewport *view, double *rotation);
+
+/* Fetch viewport mirror status */
+void imv_viewport_get_mirrored(struct imv_viewport *view, bool *mirrored);
+
/* Set the default pan_factor factor for the x and y position */
void imv_viewport_set_default_pan_factor(struct imv_viewport *view, double pan_factor_x, double pan_factor_y);
@@ -55,6 +61,18 @@ void imv_viewport_move(struct imv_viewport *view, int x, int y,
void imv_viewport_zoom(struct imv_viewport *view, const struct imv_image *image,
enum imv_zoom_source, int mouse_x, int mouse_y, int amount);
+/* Rotate the view by the given number of degrees */
+void imv_viewport_rotate(struct imv_viewport *view, double degrees);
+
+/* Rotate the view to the given number of degrees */
+void imv_viewport_rotate_to(struct imv_viewport *view, double degrees);
+
+/* Flip horizontally (across vertical axis) */
+void imv_viewport_flip_h(struct imv_viewport *view);
+
+/* Flip vertically (across horizontal axis) */
+void imv_viewport_flip_v(struct imv_viewport *view);
+
/* Recenter the view to be in the middle of the image */
void imv_viewport_center(struct imv_viewport *view,
const struct imv_image *image);