aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore14
-rw-r--r--LICENSE15
-rw-r--r--Makefile72
-rw-r--r--config.mk8
-rw-r--r--libglitter.h95
-rw-r--r--libglitter_compose_double.c106
-rw-r--r--libglitter_compose_float.c4
-rw-r--r--mk/linux.mk6
-rw-r--r--mk/macos.mk6
-rw-r--r--mk/windows.mk6
10 files changed, 332 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a071ed4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+*\#*
+*~
+*.o
+*.a
+*.lo
+*.su
+*.so
+*.so.*
+*.dll
+*.dylib
+*.gch
+*.gcov
+*.gcno
+*.gcda
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0be2ccf
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+© 2023 Mattias Andrée <maandree@kth.se>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..14674d2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,72 @@
+.POSIX:
+
+CONFIGFILE = config.mk
+include $(CONFIGFILE)
+
+OS = linux
+# Linux: linux
+# Mac OS: macos
+# Windows: windows
+include mk/$(OS).mk
+
+
+LIB_MAJOR = 1
+LIB_MINOR = 0
+LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR)
+LIB_NAME = glitter
+
+
+OBJ =\
+ libglitter_compose_double.o\
+ libglitter_compose_float.o
+
+HDR =\
+ libglitter.h
+
+LOBJ = $(OBJ:.o=.lo)
+
+
+all: libglitter.a libglitter.$(LIBEXT)
+$(OBJ): $(HDR)
+$(LOBJ): $(HDR)
+libglitter_compose_float.o: libglitter_compose_double.c
+
+.c.o:
+ $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+
+.c.lo:
+ $(CC) -fPIC -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+
+libglitter.a: $(OBJ)
+ @rm -f -- $@
+ $(AR) rc $@ $(OBJ)
+ $(AR) ts $@ > /dev/null
+
+libglitter.$(LIBEXT): $(LOBJ)
+ $(CC) $(LIBFLAGS) -o $@ $(LOBJ) $(LDFLAGS)
+
+install: libglitter.a libglitter.$(LIBEXT)
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/lib"
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/include"
+ cp -- libglitter.a "$(DESTDIR)$(PREFIX)/lib/"
+ cp -- libglitter.$(LIBEXT) "$(DESTDIR)$(PREFIX)/lib/libglitter.$(LIBMINOREXT)"
+ $(FIX_INSTALL_NAME) "$(DESTDIR)$(PREFIX)/lib/libglitter.$(LIBMINOREXT)"
+ ln -sf -- libglitter.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/libglitter.$(LIBMAJOREXT)"
+ ln -sf -- libglitter.$(LIBMAJOREXT) "$(DESTDIR)$(PREFIX)/lib/libglitter.$(LIBEXT)"
+ cp -- libglitter.h "$(DESTDIR)$(PREFIX)/include/"
+
+uninstall:
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libglitter.a"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libglitter.$(LIBMAJOREXT)"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libglitter.$(LIBMINOREXT)"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libglitter.$(LIBEXT)"
+ -rm -f -- "$(DESTDIR)$(PREFIX)/include/libglitter.h"
+
+clean:
+ -rm -f -- *.o *.a *.lo *.su *.so *.so.* *.dll *.dylib
+ -rm -f -- *.gch *.gcov *.gcno *.gcda *.$(LIBEXT)
+
+.SUFFIXES:
+.SUFFIXES: .lo .o .c
+
+.PHONY: all install uninstall clean
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..9b16e1d
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,8 @@
+PREFIX = /usr
+MANPREFIX = $(PREFIX)/share/man
+
+CC = cc
+
+CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE
+CFLAGS = -std=c99 -Wall -g
+LDFLAGS =
diff --git a/libglitter.h b/libglitter.h
new file mode 100644
index 0000000..6fc227d
--- /dev/null
+++ b/libglitter.h
@@ -0,0 +1,95 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBGLITTER_H
+#define LIBGLITTER_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+
+/**
+ * Create one raster per monitor colour from a raster of
+ * subpixels (which may be further divided in the raster)
+ *
+ * @param outputs Array of output rasters, on for each subpixel colour;
+ * each raster must be initialised to have the value 0
+ * in each cell. The function may change the offset for
+ * each raster, as such, the given pointer shall not be
+ * used anywhere else during the execution of the function
+ * and the inner pointers shall be considered undefined
+ * after the execution of the function
+ * @param noutputs The number of output buffers
+ * @param input Input raster; cells are adjacent
+ * @param output_rowsize The number of cells in a row in each output raster
+ * @param output_cellsize The number of values stored in each output raster,
+ * between each cell, plus 1 (that is, the number of
+ * values per cell)
+ * @param input_rowsize The number of cells in a row in `input`
+ * @param width The horizontal number of pixels in the rasters
+ * @param height The vertical number of pixels in the rasters
+ * @param widthmul The horizontal number of cells per pixel in `input`
+ * @param heightmul The vertical number of cells per pixel in `input`
+ * @param cellmap Subpixel map of size `heightmul * widthmul` that
+ * maps a cell for a pixel in `input` to an output
+ * raster (the value of the cell is the output's index
+ * in `outputs`); this is row-major map, and each valid
+ * value must appear at least once
+ * @param ncellweights For each `i` in [0, `noutputs`), `ncellvalues[i]`
+ * shall have the value `1. / x`, where `x` is the
+ * number of times the value `i` occurs in `cellmap`
+ *
+ * The initialisation requirement on the buffers in `outputs`
+ * does not apply if `noutputs` is 3 and either `widthmul` or
+ * `heightmul` is 3 and the other one is 1; additionally, in
+ * this case `ncellweights` will not be used as it is preknown
+ * that all it's values are 1
+ */
+void libglitter_compose_double(double **, size_t, const double *restrict,
+ size_t, size_t, size_t, size_t, size_t, size_t, size_t,
+ const uint8_t *restrict, const double *restrict);
+
+/**
+ * Create one raster per monitor colour from a raster of
+ * subpixels (which may be further divided in the raster)
+ *
+ * @param outputs Array of output rasters, on for each subpixel colour;
+ * each raster must be initialised to have the value 0
+ * in each cell. The function may change the offset for
+ * each raster, as such, the given pointer shall not be
+ * used anywhere else during the execution of the function
+ * and the inner pointers shall be considered undefined
+ * after the execution of the function
+ * @param noutputs The number of output buffers
+ * @param input Input raster; cells are adjacent
+ * @param output_rowsize The number of cells in a row in each output raster
+ * @param output_cellsize The number of values stored in each output raster,
+ * between each cell, plus 1 (that is, the number of
+ * values per cell)
+ * @param input_rowsize The number of cells in a row in `input`
+ * @param width The horizontal number of pixels in the rasters
+ * @param height The vertical number of pixels in the rasters
+ * @param widthmul The horizontal number of cells per pixel in `input`
+ * @param heightmul The vertical number of cells per pixel in `input`
+ * @param cellmap Subpixel map of size `heightmul * widthmul` that
+ * maps a cell for a pixel in `input` to an output
+ * raster (the value of the cell is the output's index
+ * in `outputs`); this is row-major map, and each valid
+ * value must appear at least once
+ * @param ncellweights For each `i` in [0, `noutputs`), `ncellvalues[i]`
+ * shall have the value `1. / x`, where `x` is the
+ * number of times the value `i` occurs in `cellmap`
+ *
+ * The initialisation requirement on the buffers in `outputs`
+ * does not apply if `noutputs` is 3 and either `widthmul` or
+ * `heightmul` is 3 and the other one is 1; additionally, in
+ * this case `ncellweights` will not be used as it is preknown
+ * that all it's values are 1
+ */
+void libglitter_compose_float(float **, size_t, const float *restrict,
+ size_t, size_t, size_t, size_t, size_t, size_t, size_t,
+ const uint8_t *restrict, const float *restrict);
+
+/* TODO add integer versions */
+/* TODO add colour space conversion and saturation */
+
+
+#endif
diff --git a/libglitter_compose_double.c b/libglitter_compose_double.c
new file mode 100644
index 0000000..ba094f0
--- /dev/null
+++ b/libglitter_compose_double.c
@@ -0,0 +1,106 @@
+/* See LICENSE file for copyright and license details. */
+#include "libglitter.h"
+
+
+static void
+generic(double **outputs, size_t noutputs, const double *restrict input,
+ size_t output_rowsize, size_t output_cellsize, size_t input_rowsize,
+ size_t width, size_t height, size_t widthmul, size_t heightmul,
+ const uint8_t *restrict cellmap, const double *restrict ncellweights)
+{
+ size_t y, x, iy, ix, output_y, output_i, input_blanking;
+ uint8_t channel;
+ double value;
+
+ output_rowsize *= output_cellsize;
+ input_blanking = input_rowsize * heightmul - width * widthmul;
+
+ for (y = 0, output_y = 0; y < height; y++, output_y += output_rowsize) {
+ for (x = 0, output_i = output_y; x < width; x++, output_i += output_cellsize) {
+
+ for (iy = 0; iy < heightmul; iy++) {
+ for (ix = 0; ix < widthmul; ix++) {
+ channel = cellmap[iy * widthmul + ix];
+
+ value = input[iy * input_rowsize + ix];
+ value *= ncellweights[channel];
+
+ outputs[channel][output_i] += value;
+ }
+ }
+ input = &input[widthmul];
+ }
+ input = &input[input_blanking];
+ }
+}
+
+
+static void
+vstrips(double **outputs_, const double *restrict input, size_t output_rowsize, size_t output_cellsize,
+ size_t input_rowsize, size_t width, size_t height, const uint8_t *restrict cellmap)
+{
+ double *outputs[3];
+ size_t y, x, output_y, output_i, input_blanking;
+
+ outputs[0] = outputs_[cellmap[0]];
+ outputs[1] = outputs_[cellmap[1]];
+ outputs[2] = outputs_[cellmap[2]];
+
+ output_rowsize *= output_cellsize;
+ input_blanking = input_rowsize - width * 3;
+
+ for (y = 0, output_y = 0; y < height; y++, output_y += output_rowsize) {
+ for (x = 0, output_i = output_y; x < width; x++, output_i += output_cellsize) {
+
+ outputs[0][output_i] = input[0];
+ outputs[1][output_i] = input[1];
+ outputs[2][output_i] = input[2];
+ input = &input[3];
+ }
+ input = &input[input_blanking];
+ }
+}
+
+
+static void
+hstrips(double **outputs_, const double *restrict input, size_t output_rowsize, size_t output_cellsize,
+ size_t input_rowsize, size_t width, size_t height, const uint8_t *restrict cellmap)
+{
+ double *outputs[3];
+ size_t y, x, output_y, output_i, input_blanking;
+
+ outputs[0] = outputs_[cellmap[0]];
+ outputs[1] = outputs_[cellmap[1]];
+ outputs[2] = outputs_[cellmap[2]];
+
+ output_rowsize *= output_cellsize;
+ input_blanking = input_rowsize * 3 - width;
+
+ for (y = 0, output_y = 0; y < height; y++, output_y += output_rowsize) {
+ for (x = 0, output_i = output_y; x < width; x++, output_i += output_cellsize) {
+
+ outputs[0][output_i] = input[0 * input_rowsize];
+ outputs[1][output_i] = input[1 * input_rowsize];
+ outputs[2][output_i] = input[2 * input_rowsize];
+ input = &input[1];
+ }
+ input = &input[input_blanking];
+ }
+}
+
+
+void
+libglitter_compose_double(double **outputs, size_t noutputs, const double *restrict input,
+ size_t output_rowsize, size_t output_cellsize, size_t input_rowsize,
+ size_t width, size_t height, size_t widthmul, size_t heightmul,
+ const uint8_t *restrict cellmap, const double *restrict ncellweights)
+{
+ if (noutputs == 3 && widthmul == 3 && heightmul == 1) {
+ vstrips(outputs, input, output_rowsize, output_cellsize, input_rowsize, width, height, cellmap);
+ } else if (noutputs == 3 && widthmul == 1 && heightmul == 3) {
+ hstrips(outputs, input, output_rowsize, output_cellsize, input_rowsize, width, height, cellmap);
+ } else {
+ generic(outputs, noutputs, input, output_rowsize, output_cellsize,
+ input_rowsize, width, height, widthmul, heightmul, cellmap, ncellweights);
+ }
+}
diff --git a/libglitter_compose_float.c b/libglitter_compose_float.c
new file mode 100644
index 0000000..197aaea
--- /dev/null
+++ b/libglitter_compose_float.c
@@ -0,0 +1,4 @@
+/* See LICENSE file for copyright and license details. */
+#define libglitter_compose_double libglitter_compose_float
+#define double float
+#include "libglitter_compose_double.c"
diff --git a/mk/linux.mk b/mk/linux.mk
new file mode 100644
index 0000000..ad58f69
--- /dev/null
+++ b/mk/linux.mk
@@ -0,0 +1,6 @@
+LIBEXT = so
+LIBFLAGS = -shared -Wl,-soname,lib$(LIB_NAME).$(LIBEXT).$(LIB_MAJOR)
+LIBMAJOREXT = $(LIBEXT).$(LIB_MAJOR)
+LIBMINOREXT = $(LIBEXT).$(LIB_VERSION)
+
+FIX_INSTALL_NAME = :
diff --git a/mk/macos.mk b/mk/macos.mk
new file mode 100644
index 0000000..0e252f2
--- /dev/null
+++ b/mk/macos.mk
@@ -0,0 +1,6 @@
+LIBEXT = dylib
+LIBFLAGS = -dynamiclib -Wl,-compatibility_version,$(LIB_MAJOR) -Wl,-current_version,$(LIB_VERSION)
+LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT)
+LIBMINOREXT = $(LIB_VERSION).$(LIBEXT)
+
+FIX_INSTALL_NAME = install_name_tool -id "$(PREFIX)/lib/libglitter.$(LIBMAJOREXT)"
diff --git a/mk/windows.mk b/mk/windows.mk
new file mode 100644
index 0000000..ed5ec8d
--- /dev/null
+++ b/mk/windows.mk
@@ -0,0 +1,6 @@
+LIBEXT = dll
+LIBFLAGS = -shared
+LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT)
+LIBMINOREXT = $(LIB_VERSION).$(LIBEXT)
+
+FIX_INSTALL_NAME = :