about summary refs log tree commit diff
diff options
context:
space:
mode:
authorsternenseemann <0rpkxez4ksa01gb3typccl0i@systemli.org>2020-12-24 23:27:18 +0100
committersternenseemann <0rpkxez4ksa01gb3typccl0i@systemli.org>2020-12-24 23:27:18 +0100
commitab1ead3ed15b2fcadabc490dc268cfc75a42cc44 (patch)
tree436cf86701dfdb12f4e3af953da62cad7f2d7cdd
parentdfd64e48de81898e73d09455d92110fa5047e6e7 (diff)
feat(flipdot): add flipdot utils to libbuchstabensuppe
-rw-r--r--Makefile1
-rw-r--r--bs-renderflipdot.c42
-rw-r--r--default.o.do3
-rw-r--r--flipdot.c94
-rw-r--r--include/buchstabensuppe/flipdot.h84
-rw-r--r--libbuchstabensuppe.a.do2
6 files changed, 188 insertions, 38 deletions
diff --git a/Makefile b/Makefile
index c4b8027..ff5bb04 100644
--- a/Makefile
+++ b/Makefile
@@ -20,6 +20,7 @@ install:
 	install -Dm755 bs-renderflipdot.exe $(BINDIR)/bs-renderflipdot
 	install -Dm644 include/buchstabensuppe.h -t $(INCDIR)
 	install -Dm644 include/buchstabensuppe/bitmap.h -t $(INCDIR)/buchstabensuppe
+	install -Dm644 include/buchstabensuppe/flipdot.h -t $(INCDIR)/buchstabensuppe
 	install -Dm644 third_party/stb/stb_truetype.h -t $(INCDIR)
 	install -Dm644 libbuchstabensuppe.a -t $(LIBDIR)
 	install -Dm644 doc/man/bs-renderflipdot.1 -t $(MANDIR)/man1
diff --git a/bs-renderflipdot.c b/bs-renderflipdot.c
index 19a66ac..377b543 100644
--- a/bs-renderflipdot.c
+++ b/bs-renderflipdot.c
@@ -11,6 +11,7 @@
 #include <unistd.h>
 
 #include <buchstabensuppe.h>
+#include <buchstabensuppe/flipdot.h>
 
 #define DEFAULT_FONT_SIZE 16
 #define DEFAULT_FLIPDOT_WIDTH 80
@@ -67,26 +68,6 @@ void print_usage(const char *name) {
     DEFAULT_FLIPDOT_WIDTH, DEFAULT_FLIPDOT_HEIGHT);
 }
 
-bool scroll_next_view(bs_view_t *view, int flipdot_width) {
-  if(view->bs_view_offset_x >= view->bs_view_bitmap.bs_bitmap_width) {
-    view->bs_view_offset_x = -flipdot_width;
-    return true;
-  } else {
-    view->bs_view_offset_x++;
-    return false;
-  }
-}
-
-bool page_next_view(bs_view_t *view, int flipdot_width) {
-  if(view->bs_view_offset_x + view->bs_view_width
-      >= view->bs_view_bitmap.bs_bitmap_width) {
-    return true;
-  } else {
-    view->bs_view_offset_x += flipdot_width;
-  }
-  return false;
-}
-
 void ignore_signal(int signum) {
   (void) signum;
 }
@@ -138,11 +119,6 @@ bool render_flipdot(const char *host, const char *port, int family, const char *
       mode == RENDER_PAGE;
     bool finished = false;
 
-    // render first frame immediately
-
-    size_t bits_size;
-    uint8_t *bits = bs_view_bitarray(view, &bits_size, invert);
-
     if(multiple_frames) {
       // TODO use sigaction
       // TODO handle SIGINT and SIGTERM
@@ -152,31 +128,23 @@ bool render_flipdot(const char *host, const char *port, int family, const char *
     }
 
     while(!finished && !failure) {
-      if(bits == NULL) {
-        failure = true;
-        break;
-      }
-
-      failure = sendto(sockfd, bits, bits_size, 0,
-          addrs->ai_addr, addrs->ai_addrlen) != (ssize_t) bits_size;
+      failure = bs_flipdot_render(sockfd, addrs->ai_addr,
+        addrs->ai_addrlen, view, invert) != 0;
 
       if(multiple_frames) {
         // restore handler which is removed by sendto
         signal(SIGALRM, ignore_signal);
       }
 
-      free(bits);
-
       if(mode == RENDER_SCROLL) {
-        finished = scroll_next_view(&view, flipdot_width);
+        finished = bs_scroll_next_view(&view, 1, BS_DIMENSION_X);
       } else if(mode == RENDER_PAGE) {
-        finished = page_next_view(&view, flipdot_width);
+        finished = bs_page_next_view(&view, 1, BS_DIMENSION_X);
       }
 
       if(!multiple_frames) {
         finished = true;
       } else if(!finished) {
-        bits = bs_view_bitarray(view, &bits_size, invert);
         pause();
       }
     }
diff --git a/default.o.do b/default.o.do
index 88d23a1..044a571 100644
--- a/default.o.do
+++ b/default.o.do
@@ -23,6 +23,9 @@ case "$2" in
   bitmap)
     redo-ifchange util.h
     ;;
+  flipdot)
+    redo-ifchange include/buchstabensuppe/bitmap.h
+    ;;
   *)
 esac
 
diff --git a/flipdot.c b/flipdot.c
new file mode 100644
index 0000000..7a6d557
--- /dev/null
+++ b/flipdot.c
@@ -0,0 +1,94 @@
+#include <errno.h>
+#include <stdlib.h>
+
+#include <buchstabensuppe/flipdot.h>
+
+bool bs_scroll_next_view(bs_view_t *view, int step, enum bs_dimension dim) {
+  if(step == 0) {
+    return true;
+  }
+
+  int bitmap_len, len;
+  int *offset;
+
+  switch(dim) {
+    case BS_DIMENSION_Y:
+      bitmap_len = view->bs_view_bitmap.bs_bitmap_height;
+      offset = &(view->bs_view_offset_y);
+      len = view->bs_view_width;
+      break;
+    case BS_DIMENSION_X: /* is also default case */
+    default:
+      bitmap_len = view->bs_view_bitmap.bs_bitmap_width;
+      offset = &(view->bs_view_offset_x);
+      len = view->bs_view_height;
+      break;
+  }
+
+  if(step > 0 && *offset >= bitmap_len) {
+    *offset = -len;
+    return true;
+  } else if(step < 0 && *offset <= -len) {
+    *offset = bitmap_len;
+    return true;
+  } else {
+    *offset = *offset + step;
+  }
+
+  return false;
+}
+
+bool bs_page_next_view(bs_view_t *view, int dir, enum bs_dimension dim) {
+  if(dir == 0) {
+    return true;
+  }
+
+  int bitmap_len, len;
+  int *offset;
+
+  switch(dim) {
+    case BS_DIMENSION_Y:
+      bitmap_len = view->bs_view_bitmap.bs_bitmap_height;
+      offset = &(view->bs_view_offset_y);
+      len = view->bs_view_width;
+      break;
+    case BS_DIMENSION_X: /* is also default case */
+    default:
+      bitmap_len = view->bs_view_bitmap.bs_bitmap_width;
+      offset = &(view->bs_view_offset_x);
+      len = view->bs_view_height;
+      break;
+  }
+
+  if(dir > 0 && *offset + len >= bitmap_len) {
+    *offset = 0;
+    return true;
+  } else if(dir < 0 && *offset <= 0) {
+    *offset = bitmap_len - len;
+    return true;
+  } else {
+    *offset = *offset + dir * len;
+  }
+
+  return false;
+}
+
+int bs_flipdot_render(int sockfd, struct sockaddr *addr, socklen_t addrlen, bs_view_t view, unsigned char overflow_color) {
+  size_t bits_size;
+  uint8_t *bits = bs_view_bitarray(view, &bits_size, overflow_color);
+
+  if(bits == NULL) {
+    errno = ENOMEM;
+    return -1;
+  }
+
+  ssize_t sent = sendto(sockfd, bits, bits_size, 0, addr, addrlen);
+
+  free(bits);
+
+  if(sent != (ssize_t) bits_size) {
+    return -1;
+  }
+
+  return 0;
+}
diff --git a/include/buchstabensuppe/flipdot.h b/include/buchstabensuppe/flipdot.h
new file mode 100644
index 0000000..f74ae10
--- /dev/null
+++ b/include/buchstabensuppe/flipdot.h
@@ -0,0 +1,84 @@
+/*!
+ * @file buchstabensuppe/flipdot.h
+ *
+ * Facilities for rendering bitmaps onto flipdot displays
+ * and useful bitmap manipulation when targeting flipdot displays.
+ */
+#ifndef BUCHSTABENSUPPE_FLIPDOT_H
+#define BUCHSTABENSUPPE_FLIPDOT_H
+
+#include <stdbool.h>     /* bool     */
+#include <sys/socket.h>  /* sockaddr */
+
+#include <buchstabensuppe/bitmap.h>
+
+/*!
+ * @brief Render a bitmap view onto a flipdot display
+ *
+ * This function renders a view to a flipdot display compatible bitarray
+ * using bs_view_bitmap() and sends it to a display listening at the given
+ * address using a given socket.
+ *
+ * The viewed bitmap must be a binary bitmap for this to work properly.
+ * Zero is black, all values greater than zero are white.
+ *
+ * @param sockfd          file descriptor of a `SOCK_DGRAM` socket
+ * @param addr            address of the target flipdot display
+ * @param addrlen         length of the address structure
+ * @param view            bitmap view to render
+ * @param overflow_color  value area outside of the picture should get (either 0 or 1)
+ */
+int bs_flipdot_render(int sockfd, struct sockaddr *addr, socklen_t addrlen,
+  bs_view_t view, unsigned char overflow_color);
+
+/*!
+ * @brief Axis description
+ *
+ * Describes which direction to perform a movement in for
+ * bs_scroll_next_view() and bs_page_next_view().
+ */
+enum bs_dimension {
+  BS_DIMENSION_X,    //!< X Axis
+  BS_DIMENSION_Y,    //!< Y Axis
+};
+
+/*!
+ * @brief Calculates next view for a one dimensional scroll through a bitmap.
+ *
+ * Advance a bitmap view by `step` in a given dimension. Will return `true`
+ * as soon as the bitmap is out of view and wrap around, i. e. sets the offset
+ * to `-len`. This is intended to provide the view for the next frame to be
+ * rendered to a (flipdot) display.
+ *
+ * The given view is expected to be fully intialized and `bs_view_width` and
+ * `bs_view_height` to be equal to the dimensions of the target screen. Also
+ * the first view position must be set by the caller.
+ *
+ * @param view bitmap view to alter
+ * @param step step to advance by
+ * @param dim  dimension to advance in
+ *
+ * @return true if the bitmap has come out of view,
+ *         i. e. the scrolling motion is finished
+ */
+bool bs_scroll_next_view(bs_view_t *view, int step, enum bs_dimension dim);
+
+/*!
+ * @brief Calculates next view for one dimensional paging through a bitmap.
+ *
+ * This is similar to bs_scroll_next_view(), but the scroll step is the target
+ * display's width or height and the picture is never scrolled out of view.
+ *
+ * If the edge of the bitmap is in view, true is returned and the offset is
+ * set so the first page is in view.
+ *
+ * @param view bitmap view to alter
+ * @param step step to advance by
+ * @param dim  dimension to advance in
+ *
+ * @return true if another page would mean the bitmap would come out of view
+ *         i. e. all pages have been viewed
+ */
+bool bs_page_next_view(bs_view_t *view, int direction, enum bs_dimension dim);
+
+#endif
diff --git a/libbuchstabensuppe.a.do b/libbuchstabensuppe.a.do
index 6a54444..2e96ce9 100644
--- a/libbuchstabensuppe.a.do
+++ b/libbuchstabensuppe.a.do
@@ -1,7 +1,7 @@
 source ./build_config
 redo-ifchange ./build_config
 
-OBJS="third_party/stb_truetype.o bitmap.o buchstabensuppe.o"
+OBJS="third_party/stb_truetype.o bitmap.o buchstabensuppe.o flipdot.o"
 redo-ifchange $OBJS
 
 tmp_dir="$(mktemp -d)"