From 38d23cbf5b3870830339c9c12fd30bd5270112d8 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 21 Jan 2023 16:38:52 +0100 Subject: Initial commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- .gitignore | 14 ++++++ LICENSE | 15 +++++++ Makefile | 72 ++++++++++++++++++++++++++++++ config.mk | 8 ++++ libglitter.h | 95 +++++++++++++++++++++++++++++++++++++++ libglitter_compose_double.c | 106 ++++++++++++++++++++++++++++++++++++++++++++ libglitter_compose_float.c | 4 ++ mk/linux.mk | 6 +++ mk/macos.mk | 6 +++ mk/windows.mk | 6 +++ 10 files changed, 332 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 config.mk create mode 100644 libglitter.h create mode 100644 libglitter_compose_double.c create mode 100644 libglitter_compose_float.c create mode 100644 mk/linux.mk create mode 100644 mk/macos.mk create mode 100644 mk/windows.mk 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 + +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 +#include + + +/** + * 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 = : -- cgit v1.2.3-70-g09d2