aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2023-01-21 19:30:25 +0100
committerMattias Andrée <maandree@kth.se>2023-01-21 19:32:34 +0100
commit4114f87af993991c7aab55ff86be3003d43244f3 (patch)
treeb5841672b4a48c02a9015ddc273f7b64ad9bec3a
parentAdd integer versions of libglitter_compose_* (diff)
downloadlibglitter-4114f87af993991c7aab55ff86be3003d43244f3.tar.gz
libglitter-4114f87af993991c7aab55ff86be3003d43244f3.tar.bz2
libglitter-4114f87af993991c7aab55ff86be3003d43244f3.tar.xz
Add render context
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--Makefile6
-rw-r--r--TODO4
-rw-r--r--common.h35
-rw-r--r--libglitter.h139
-rw-r--r--libglitter_compose_double.c30
-rw-r--r--libglitter_compose_float.c3
-rw-r--r--libglitter_compose_uint16.c2
-rw-r--r--libglitter_compose_uint32.c2
-rw-r--r--libglitter_compose_uint64.c65
-rw-r--r--libglitter_compose_uint8.c2
-rw-r--r--libglitter_create_render_context.c47
-rw-r--r--libglitter_free_render_context.c13
-rw-r--r--libglitter_update_render_context.c28
13 files changed, 253 insertions, 123 deletions
diff --git a/Makefile b/Makefile
index baf2581..b0f2b07 100644
--- a/Makefile
+++ b/Makefile
@@ -22,9 +22,13 @@ OBJ =\
libglitter_compose_uint16.o\
libglitter_compose_uint32.o\
libglitter_compose_uint64.o\
- libglitter_compose_uint8.o
+ libglitter_compose_uint8.o\
+ libglitter_create_render_context.o\
+ libglitter_free_render_context.o\
+ libglitter_update_render_context.o
HDR =\
+ common.h\
libglitter.h
LOBJ = $(OBJ:.o=.lo)
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..65602ac
--- /dev/null
+++ b/TODO
@@ -0,0 +1,4 @@
+Add colour space conversion and saturation
+Add support for GPU-acceleration
+Add man pages
+Add tests
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..e53843a
--- /dev/null
+++ b/common.h
@@ -0,0 +1,35 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBGLITTER_COMMON_H
+#define LIBGLITTER_COMMON_H
+
+#include "libglitter.h"
+#include <alloca.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+
+#define RENDER_METHOD_VSTRIPS 0
+#define RENDER_METHOD_HSTRIPS 1
+#define RENDER_METHOD_SIMPLE 2
+#define RENDER_METHOD_GENERIC 3
+
+
+struct libglitter_context {
+};
+
+struct libglitter_render_context {
+ const uint8_t *restrict cellmap;
+ const uint8_t *restrict ncellvalues;
+ size_t noutputs;
+ size_t rowsize;
+ size_t widthmul;
+ size_t heightmul;
+ uint8_t render_method;
+ size_t cells[3][2];
+ double *restrict cellweights_double;
+ float *restrict cellweights_float;
+};
+
+
+#endif
diff --git a/libglitter.h b/libglitter.h
index ca358aa..68a7b0e 100644
--- a/libglitter.h
+++ b/libglitter.h
@@ -7,6 +7,62 @@
/**
+ * Rendering context for an input raster's specifications
+ *
+ * Render context's are thread-safe, however updating them are not
+ */
+typedef struct libglitter_render_context LIBGLITTER_RENDER_CONTEXT;
+
+
+/**
+ * Create a render context for an input raster's specifications
+ *
+ * Render context's are thread-safe
+ *
+ * @param noutputs The number of output buffers
+ * @param rowsize The number of cells per row in the input raster
+ * @param widthmul The horizontal number of cells per pixel in the input raster
+ * @param heightmul The vertical number of cells per pixel in the input raster
+ * @param cellmap Subpixel map of size `heightmul * widthmul` that maps a
+ * cell for a pixel in the input raster to an output raster
+ * (the output raster's index); this is row-major map, and
+ * each valid value must appear at least once
+ * @param ncellvalues For each `i` in [0, `noutputs`), `ncellvalues[i]`
+ * shall be the number of times the value `i` occurs
+ * in `cellmap`
+ * @return A render context that can be deallocate using
+ * `libglitter_free_render_context` or updated with
+ * `libglitter_update_render_context`; `NULL` on failure
+ *
+ * @throws ENOMEM Couldn't not allocate enough memory
+ *
+ * If `noutputs` is 3 and either `widthmul` or `heightmul` is 3 and
+ * the other one is 1, `ncellvalues` will not be used as it is preknown
+ * that all its values are 1
+ */
+LIBGLITTER_RENDER_CONTEXT *libglitter_create_render_context(size_t, size_t, size_t, size_t,
+ const uint8_t *, const uint8_t *);
+
+/**
+ * Update a render context (created by `libglitter_create_render_context`)
+ * for a new input raster buffer
+ *
+ * Updating a render context is not thread-safe
+ *
+ * @param this The render context to refresh
+ * @param rowsize The number of cells per row in the input raster
+ */
+void libglitter_update_render_context(LIBGLITTER_RENDER_CONTEXT *, size_t);
+
+/**
+ * Deallocates a render context (created by `libglitter_create_render_context`)
+ *
+ * @param this The render context to deallocate
+ */
+void libglitter_free_render_context(LIBGLITTER_RENDER_CONTEXT *);
+
+
+/**
* Create one raster per monitor colour from a raster of
* subpixels (which may be further divided in the raster)
*
@@ -14,51 +70,32 @@
* model's transfer function: it does not directly give
* you appropriate sRGB values
*
- * @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 outputs Array of output rasters, on for each subpixel colour.
+ * 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 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`), `ncellweights[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 its values are 1
+ * @param render_ctx Rendering context created for the input raster's
+ * specification
*/
-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);
+void libglitter_compose_double(double **, const double *restrict, size_t, size_t,
+ size_t, size_t, const LIBGLITTER_RENDER_CONTEXT *);
/**
* This value is identical to `libglitter_compose_double`,
* apart from it parameter types, see `libglitter_compose_double`
* for details about this function
*/
-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);
+void libglitter_compose_float(float **, const float *restrict, size_t, size_t,
+ size_t, size_t, const LIBGLITTER_RENDER_CONTEXT *);
/**
* Create one raster per monitor colour from a raster of
@@ -74,62 +111,42 @@ void libglitter_compose_float(float **, size_t, const float *restrict,
* 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 ncellvalues For each `i` in [0, `noutputs`), `ncellvalues[i]`
- * shall be the number of times the value `i` occurs
- * in `cellmap`
- *
- * If `noutputs` is 3 and either `widthmul` or `heightmul` is 3 and
- * the other one is 1, `ncellvalues` will not be used as it is preknown
- * that all its values are 1
+ * @param render_ctx Rendering context created for the input raster's
+ * specification
*/
-void libglitter_compose_uint64(uint64_t **, size_t, const uint64_t *restrict,
- size_t, size_t, size_t, size_t, size_t, size_t, size_t,
- const uint8_t *restrict, const uint8_t *restrict);
+void libglitter_compose_uint64(uint64_t **, const uint64_t *restrict, size_t, size_t,
+ size_t, size_t, const LIBGLITTER_RENDER_CONTEXT *);
/**
* This value is identical to `libglitter_compose_uint64`,
* apart from it parameter types, see `libglitter_compose_uint64`
* for details about this function
*/
-void libglitter_compose_uint32(uint32_t **, size_t, const uint32_t *restrict,
- size_t, size_t, size_t, size_t, size_t, size_t, size_t,
- const uint8_t *restrict, const uint8_t *restrict);
+void libglitter_compose_uint32(uint32_t **, const uint32_t *restrict, size_t, size_t,
+ size_t, size_t, const LIBGLITTER_RENDER_CONTEXT *);
/**
* This value is identical to `libglitter_compose_uint64`,
* apart from it parameter types, see `libglitter_compose_uint64`
* for details about this function
*/
-void libglitter_compose_uint16(uint16_t **, size_t, const uint16_t *restrict,
- size_t, size_t, size_t, size_t, size_t, size_t, size_t,
- const uint8_t *restrict, const uint8_t *restrict);
+void libglitter_compose_uint16(uint16_t **, const uint16_t *restrict, size_t, size_t,
+ size_t, size_t, const LIBGLITTER_RENDER_CONTEXT *);
/**
* This value is identical to `libglitter_compose_uint64`,
* apart from it parameter types, see `libglitter_compose_uint64`
* for details about this function
*/
-void libglitter_compose_uint8(uint8_t **, size_t, const uint8_t *restrict,
- size_t, size_t, size_t, size_t, size_t, size_t, size_t,
- const uint8_t *restrict, const uint8_t *restrict);
-
-/* TODO add colour space conversion and saturation */
+void libglitter_compose_uint8(uint8_t **, const uint8_t *restrict, size_t, size_t,
+ size_t, size_t, const LIBGLITTER_RENDER_CONTEXT *);
#endif
diff --git a/libglitter_compose_double.c b/libglitter_compose_double.c
index d0fdc3e..5a8d361 100644
--- a/libglitter_compose_double.c
+++ b/libglitter_compose_double.c
@@ -1,5 +1,5 @@
/* See LICENSE file for copyright and license details. */
-#include "libglitter.h"
+#include "common.h"
static void
@@ -60,12 +60,12 @@ hstrips(double **outputs_, const double *restrict input, size_t output_rowsize,
static void
-generic(double **outputs, const double *restrict input,
+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)
+ const uint8_t *restrict cellmap, const double *restrict cellweights)
{
- size_t y, x, iy, ix, output_y, output_i, input_blanking;
+ size_t y, x, iy, ix, i, output_y, output_i, input_blanking;
uint8_t channel;
double value;
@@ -75,12 +75,14 @@ generic(double **outputs, const double *restrict input,
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 (i = 0; i < noutputs; i++)
+ outputs[i][output_i] = 0;
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];
+ value *= cellweights[channel];
outputs[channel][output_i] += value;
}
@@ -93,18 +95,16 @@ generic(double **outputs, const double *restrict input,
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)
+libglitter_compose_double(double **outputs, const double *restrict input, size_t output_rowsize, size_t output_cellsize,
+ size_t width, size_t height, const LIBGLITTER_RENDER_CONTEXT *render_ctx)
{
- 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);
+ if (render_ctx->render_method == RENDER_METHOD_VSTRIPS) {
+ vstrips(outputs, input, output_rowsize, output_cellsize, render_ctx->rowsize, width, height, render_ctx->cellmap);
+ } else if (render_ctx->render_method == RENDER_METHOD_HSTRIPS) {
+ hstrips(outputs, input, output_rowsize, output_cellsize, render_ctx->rowsize, width, height, render_ctx->cellmap);
} else {
- generic(outputs, input, output_rowsize, output_cellsize, input_rowsize,
- width, height, widthmul, heightmul, cellmap, ncellweights);
+ generic(outputs, render_ctx->noutputs, input, output_rowsize, output_cellsize, render_ctx->rowsize, width, height,
+ render_ctx->widthmul, render_ctx->heightmul, render_ctx->cellmap, render_ctx->cellweights_double);
}
}
diff --git a/libglitter_compose_float.c b/libglitter_compose_float.c
index 6e09fd1..2195ed3 100644
--- a/libglitter_compose_float.c
+++ b/libglitter_compose_float.c
@@ -1,5 +1,6 @@
/* See LICENSE file for copyright and license details. */
-#include "libglitter.h"
+#include "common.h"
#define libglitter_compose_double libglitter_compose_float
+#define cellweights_double cellweights_float
#define double float
#include "libglitter_compose_double.c"
diff --git a/libglitter_compose_uint16.c b/libglitter_compose_uint16.c
index ea24f8e..b1bebe0 100644
--- a/libglitter_compose_uint16.c
+++ b/libglitter_compose_uint16.c
@@ -1,5 +1,5 @@
/* See LICENSE file for copyright and license details. */
-#include "libglitter.h"
+#include "common.h"
typedef uint_fast32_t greater_t;
#define greater_t greater_t
#define libglitter_compose_uint64 libglitter_compose_uint16
diff --git a/libglitter_compose_uint32.c b/libglitter_compose_uint32.c
index 8d74453..a455ee3 100644
--- a/libglitter_compose_uint32.c
+++ b/libglitter_compose_uint32.c
@@ -1,5 +1,5 @@
/* See LICENSE file for copyright and license details. */
-#include "libglitter.h"
+#include "common.h"
typedef uint_fast64_t greater_t;
#define greater_t greater_t
#define libglitter_compose_uint64 libglitter_compose_uint32
diff --git a/libglitter_compose_uint64.c b/libglitter_compose_uint64.c
index fdb9b62..91d6b88 100644
--- a/libglitter_compose_uint64.c
+++ b/libglitter_compose_uint64.c
@@ -1,9 +1,8 @@
/* See LICENSE file for copyright and license details. */
-#include "libglitter.h"
+#include "common.h"
#define ONLY_INT_COMPATIBLE
#define double uint64_t
#include "libglitter_compose_double.c"
-#include <alloca.h>
#ifdef greater_t
# define MIX(A, B) (((greater_t)(A) + (greater_t)(B)) >> 1)
#else
@@ -13,40 +12,24 @@
static void
-simple(uint64_t **outputs, const uint64_t *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)
+simple(uint64_t **outputs, const uint64_t *restrict input, size_t output_rowsize, size_t output_cellsize,
+ size_t input_rowsize, size_t width, size_t height, const LIBGLITTER_RENDER_CONTEXT *render_ctx)
{
size_t y, x, output_y, output_i, input_blanking;
- uint8_t channel;
- size_t cells[3][2];
- size_t cellsi[3] = {0, 0, 0};
+ size_t cell00 = render_ctx->cells[0][0], cell01 = render_ctx->cells[0][1];
+ size_t cell10 = render_ctx->cells[1][0], cell11 = render_ctx->cells[1][1];
+ size_t cell20 = render_ctx->cells[2][0], cell21 = render_ctx->cells[2][1];
output_rowsize *= output_cellsize;
- input_blanking = input_rowsize * heightmul - width * widthmul;
-
- for (y = 0; y < heightmul; y++) {
- for (x = 0; x < widthmul; x++) {
- channel = cellmap[y * widthmul + x];
- cells[channel][cellsi[channel]] = y * input_rowsize + x;
- cellsi[channel] += 1;
- }
- }
- if (cellsi[0] == 1)
- cells[0][1] = cells[0][0];
- if (cellsi[1] == 1)
- cells[1][1] = cells[1][0];
- if (cellsi[2] == 1)
- cells[2][1] = cells[2][0];
+ input_blanking = input_rowsize * render_ctx->heightmul - width * render_ctx->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) {
- outputs[0][output_i] = (uint64_t)MIX(input[cells[0][0]], input[cells[0][1]]);
- outputs[1][output_i] = (uint64_t)MIX(input[cells[0][0]], input[cells[0][1]]);
- outputs[2][output_i] = (uint64_t)MIX(input[cells[0][0]], input[cells[0][1]]);
- input = &input[widthmul];
+ outputs[0][output_i] = (uint64_t)MIX(input[cell00], input[cell01]);
+ outputs[1][output_i] = (uint64_t)MIX(input[cell10], input[cell11]);
+ outputs[2][output_i] = (uint64_t)MIX(input[cell20], input[cell21]);
+ input = &input[render_ctx->widthmul];
}
input = &input[input_blanking];
}
@@ -82,7 +65,7 @@ generic(uint64_t **outputs, size_t noutputs, const uint64_t *restrict input,
}
for (i = 0; i < noutputs; i++)
- outputs[i][output_i] = (uint64_t)(pixel[channel] / (greater_t)ncellvalues[i]);
+ outputs[i][output_i] = (uint64_t)(pixel[i] / (greater_t)ncellvalues[i]);
input = &input[widthmul];
}
@@ -92,20 +75,18 @@ generic(uint64_t **outputs, size_t noutputs, const uint64_t *restrict input,
void
-libglitter_compose_uint64(uint64_t **outputs, size_t noutputs, const uint64_t *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 uint8_t *restrict ncellvalues)
+libglitter_compose_uint64(uint64_t **outputs, const uint64_t *restrict input, size_t output_rowsize, size_t output_cellsize,
+ size_t width, size_t height, const LIBGLITTER_RENDER_CONTEXT *render_ctx)
{
- 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 if (noutputs == 3 && ncellvalues[0] <= 2 && ncellvalues[1] <= 2 && ncellvalues[2] <= 2) {
- simple(outputs, input, output_rowsize, output_cellsize, input_rowsize,
- width, height, widthmul, heightmul, cellmap);
+ if (render_ctx->render_method == RENDER_METHOD_VSTRIPS) {
+ vstrips(outputs, input, output_rowsize, output_cellsize, render_ctx->rowsize, width, height, render_ctx->cellmap);
+ } else if (render_ctx->render_method == RENDER_METHOD_HSTRIPS) {
+ hstrips(outputs, input, output_rowsize, output_cellsize, render_ctx->rowsize, width, height, render_ctx->cellmap);
+ } else if (render_ctx->render_method == RENDER_METHOD_SIMPLE) {
+ simple(outputs, input, output_rowsize, output_cellsize, render_ctx->rowsize, width, height, render_ctx);
} else {
- generic(outputs, noutputs, input, output_rowsize, output_cellsize,
- input_rowsize, width, height, widthmul, heightmul, cellmap, ncellvalues);
+ generic(outputs, render_ctx->noutputs, input, output_rowsize, output_cellsize,
+ render_ctx->rowsize, width, height, render_ctx->widthmul, render_ctx->heightmul,
+ render_ctx->cellmap, render_ctx->ncellvalues);
}
}
diff --git a/libglitter_compose_uint8.c b/libglitter_compose_uint8.c
index 615232b..2c781f7 100644
--- a/libglitter_compose_uint8.c
+++ b/libglitter_compose_uint8.c
@@ -1,5 +1,5 @@
/* See LICENSE file for copyright and license details. */
-#include "libglitter.h"
+#include "common.h"
typedef uint_fast16_t greater_t;
#define greater_t greater_t
#define libglitter_compose_uint64 libglitter_compose_uint8
diff --git a/libglitter_create_render_context.c b/libglitter_create_render_context.c
new file mode 100644
index 0000000..53b0705
--- /dev/null
+++ b/libglitter_create_render_context.c
@@ -0,0 +1,47 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+LIBGLITTER_RENDER_CONTEXT *
+libglitter_create_render_context(size_t noutputs, size_t rowsize, size_t widthmul, size_t heightmul,
+ const uint8_t *cellmap, const uint8_t *ncellvalues)
+{
+ struct libglitter_render_context *this;
+ size_t i;
+
+ this = calloc(1, sizeof(*this));
+ if (!this)
+ return NULL;
+
+ this->cellmap = cellmap;
+ this->ncellvalues = ncellvalues;
+ this->noutputs = noutputs;
+ this->widthmul = widthmul;
+ this->heightmul = heightmul;
+
+ this->cellweights_double = calloc(noutputs, sizeof(*this->cellweights_double));
+ if (!this->cellweights_double)
+ goto fail;
+ this->cellweights_float = calloc(noutputs, sizeof(*this->cellweights_float));
+ if (!this->cellweights_float)
+ goto fail;
+
+ this->render_method =
+ (noutputs == 3 && widthmul == 3 && heightmul == 1) ? RENDER_METHOD_VSTRIPS :
+ (noutputs == 3 && widthmul == 1 && heightmul == 3) ? RENDER_METHOD_HSTRIPS :
+ (noutputs == 3 && ncellvalues[0] <= 2 && ncellvalues[1] <= 2 && ncellvalues[2] <= 2) ? RENDER_METHOD_SIMPLE :
+ RENDER_METHOD_GENERIC;
+
+ for (i = 0; i < noutputs; i++) {
+ this->cellweights_double[i] = 1 / (double)ncellvalues[i];
+ this->cellweights_float[i] = 1 / (float)ncellvalues[i];
+ }
+
+ libglitter_update_render_context(this, rowsize);
+
+ return this;
+
+fail:
+ libglitter_free_render_context(this);
+ return NULL;
+}
diff --git a/libglitter_free_render_context.c b/libglitter_free_render_context.c
new file mode 100644
index 0000000..4eb15c2
--- /dev/null
+++ b/libglitter_free_render_context.c
@@ -0,0 +1,13 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+void
+libglitter_free_render_context(LIBGLITTER_RENDER_CONTEXT *this)
+{
+ if (this) {
+ free(this->cellweights_double);
+ free(this->cellweights_float);
+ free(this);
+ }
+}
diff --git a/libglitter_update_render_context.c b/libglitter_update_render_context.c
new file mode 100644
index 0000000..318ec87
--- /dev/null
+++ b/libglitter_update_render_context.c
@@ -0,0 +1,28 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+void
+libglitter_update_render_context(LIBGLITTER_RENDER_CONTEXT *this, size_t rowsize)
+{
+ size_t y, x;
+ uint8_t channel;
+ size_t cellsi[3] = {0, 0, 0};
+
+ if (this && this->render_method == RENDER_METHOD_SIMPLE && this->rowsize != rowsize) {
+ this->rowsize = rowsize;
+ for (y = 0; y < this->heightmul; y++) {
+ for (x = 0; x < this->widthmul; x++) {
+ channel = this->cellmap[y * this->widthmul + x];
+ this->cells[channel][cellsi[channel]] = y * rowsize + x;
+ cellsi[channel] += 1;
+ }
+ }
+ if (cellsi[0] == 1)
+ this->cells[0][1] = this->cells[0][0];
+ if (cellsi[1] == 1)
+ this->cells[1][1] = this->cells[1][0];
+ if (cellsi[2] == 1)
+ this->cells[2][1] = this->cells[2][0];
+ }
+}