From 347e6a0551381ef7fdde9cbe0f24c8e82f2e55bd Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Mon, 16 Jun 2014 23:33:27 +0000 Subject: [PATCH] image: port libpipi stock images, plus noise and screen rendering. --- TODO | 76 +++++++-------- src/Makefile.am | 6 +- src/image/image.cpp | 8 +- src/image/render/noise.cpp | 88 ++++++++--------- src/image/render/screen.cpp | 146 +++++++++++++--------------- src/image/stock.cpp | 186 +++++++++++++++++------------------- src/lol/image/image.h | 13 ++- 7 files changed, 247 insertions(+), 276 deletions(-) diff --git a/TODO b/TODO index 0fce7277..8b611ce4 100644 --- a/TODO +++ b/TODO @@ -12,57 +12,53 @@ Image: - Handle pitch in SDL codec (and all others, actually) - port libpipi files: · accessors.cpp - · pipi-stubs.h - · render/noise.cpp - · render/screen.cpp - · tiles.cpp - · pipi-internals.h - · pipi-template.h - · paint/rectangle.cpp - · paint/line.cpp - · paint/floodfill.cpp - · paint/bezier.cpp - · paint/tile.cpp - · pipi-types.h - · stock.cpp - · context.cpp - · pipi.h - · dither.cpp - · colorstring.cpp + · analysis/histogram.cpp + · analysis/measure.cpp · codec/coreimage.cpp · codec/coreimage.h - · codec/oric.cpp + · codec.cpp · codec/jpeg.cpp - · resample/bresenham.cpp - · resample/bicubic.cpp - · quantize/reduce.cpp - · analysis/histogram.cpp - · analysis/measure.cpp + · codec/oric.cpp + · colorstring.cpp + · combine/blit.cpp + · combine/merge.cpp + · combine/minmax.cpp + · combine/mulscreen.cpp + · combine/rgb.cpp + · combine/subadd.cpp + · context.cpp · crop.cpp - · pipi.cpp - · codec.cpp + · dither.cpp + · dither/dbs.cpp · dither/ediff.cpp + · dither/ordered.cpp · dither/ostromoukhov.cpp · dither/random.cpp - · dither/ordered.cpp - · dither/dbs.cpp - · sequence.cpp + · filter/autocontrast.cpp + · filter/blur.cpp + · filter/color.cpp · filter/convolution.cpp - · filter/wave.cpp · filter/dilate.cpp - · filter/color.cpp - · filter/blur.cpp - · filter/yuv.cpp - · filter/autocontrast.cpp · filter/median.cpp · filter/rotate.cpp - · filter/transform.cpp · filter/sharpen.cpp - · combine/rgb.cpp - · combine/blit.cpp - · combine/minmax.cpp - · combine/subadd.cpp - · combine/merge.cpp - · combine/mulscreen.cpp + · filter/transform.cpp + · filter/wave.cpp + · filter/yuv.cpp + · paint/bezier.cpp + · paint/floodfill.cpp + · paint/line.cpp + · paint/rectangle.cpp + · paint/tile.cpp + · pipi.h + · pipi-internals.h + · pipi-stubs.h + · pipi-template.h + · pipi-types.h · pixels.cpp + · quantize/reduce.cpp + · resample/bicubic.cpp + · resample/bresenham.cpp + · sequence.cpp + · tiles.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 75d97e35..225a37b3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -110,13 +110,13 @@ liblolcore_sources = \ sys/init.cpp sys/timer.cpp sys/file.cpp \ sys/thread.cpp sys/threadbase.h \ \ - image/image.cpp image/image-private.h \ + image/image.cpp image/image-private.h image/stock.cpp \ image/codec/gdiplus-image.cpp image/codec/imlib2-image.cpp \ image/codec/sdl-image.cpp image/codec/ios-image.cpp \ image/codec/zed-image.cpp image/codec/zed-palette-image.cpp \ image/codec/dummy-image.cpp \ - image/color/cie1931.cpp \ - image/color/color.cpp \ + image/color/cie1931.cpp image/color/color.cpp \ + image/render/noise.cpp image/render/screen.cpp \ \ loldebug.h \ debug/fps.cpp debug/fps.h debug/lines.cpp \ diff --git a/src/image/image.cpp b/src/image/image.cpp index ef9a5546..d9acf665 100644 --- a/src/image/image.cpp +++ b/src/image/image.cpp @@ -15,8 +15,6 @@ #include "core.h" #include "image-private.h" -using namespace std; - namespace lol { @@ -196,8 +194,7 @@ void Image::SetFormat(PixelFormat fmt) } /* The Lock() method */ -template -typename PixelType::type *Image::Lock() +template typename PixelType::type *Image::Lock() { SetFormat(T); @@ -215,8 +212,7 @@ _T(PixelFormat::RGBA_F32); #undef _T /* Special case for the "any" format: return the last active buffer */ -template<> -void *Image::Lock() +template<> void *Image::Lock() { ASSERT(m_data->m_format != PixelFormat::Unknown); diff --git a/src/image/render/noise.cpp b/src/image/render/noise.cpp index 6a736ae5..ec5e1d5f 100644 --- a/src/image/render/noise.cpp +++ b/src/image/render/noise.cpp @@ -1,61 +1,55 @@ -/* - * libpipi Pathetic image processing interface library - * Copyright (c) 2004-2008 Sam Hocevar - * All Rights Reserved - * - * $Id$ - * - * This library is free software. It comes without any warranty, to - * the extent permitted by applicable law. You can redistribute it - * and/or modify it under the terms of the Do What The Fuck You Want - * To Public License, Version 2, as published by Sam Hocevar. See - * http://sam.zoy.org/wtfpl/COPYING for more details. - */ +// +// Lol Engine +// +// Copyright: (c) 2004-2014 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" /* - * noise.c: noise rendering functions + * Noise rendering functions */ -#include "config.h" - -#include -#include -#include - -#include "pipi.h" -#include "pipi-internals.h" +namespace lol +{ -pipi_image_t *pipi_render_random(int w, int h) +bool Image::RenderRandom(ivec2 size) { - pipi_image_t *ret; - pipi_pixels_t *pix; - float *data; unsigned int ctx = 1; - int x, y, t; - ret = pipi_new(w, h); - pix = pipi_get_pixels(ret, PIPI_PIXELS_RGBA_F32); - data = (float *)pix->pixels; + SetSize(size); + vec4 *pixels = Lock(); + int count = size.x * size.y; - for(y = 0; y < h; y++) - for(x = 0; x < w; x++) + for (int n = 0; n < count; ++n) + { + for (int t : { 0, 1, 2 }) { - for(t = 0; t < 3; t++) - { - long hi, lo; - - hi = ctx / 12773L; - lo = ctx % 12773L; - ctx = 16807L * lo - 2836L * hi; - if(ctx <= 0) - ctx += 0x7fffffffL; - - data[4 * (y * w + x) + t] - = (double)((ctx % 65536) / 65535.); - } - data[4 * (y * w + x) + 3] = 1.0; + long hi, lo; + + hi = ctx / 12773L; + lo = ctx % 12773L; + ctx = 16807L * lo - 2836L * hi; + if(ctx <= 0) + ctx += 0x7fffffffL; + + pixels[n][t] = (float)((ctx % 65536) / 65535.); } + pixels[n][3] = 1.0f; + } - return ret; + Unlock(pixels); + + return true; } +} /* namespace lol */ + diff --git a/src/image/render/screen.cpp b/src/image/render/screen.cpp index 3b5671dc..cceaf075 100644 --- a/src/image/render/screen.cpp +++ b/src/image/render/screen.cpp @@ -1,71 +1,59 @@ -/* - * libpipi Pathetic image processing interface library - * Copyright (c) 2004-2008 Sam Hocevar - * All Rights Reserved - * - * $Id$ - * - * This library is free software. It comes without any warranty, to - * the extent permitted by applicable law. You can redistribute it - * and/or modify it under the terms of the Do What The Fuck You Want - * To Public License, Version 2, as published by Sam Hocevar. See - * http://sam.zoy.org/wtfpl/COPYING for more details. - */ +// +// Lol Engine +// +// Copyright: (c) 2004-2014 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" /* - * screen.c: halftoning screen functions + * Halftoning screen functions */ -#include "config.h" - -#include -#include -#include -#include - -#ifndef M_PI -# define M_PI 3.14159265358979323846 -#endif - -#include "pipi.h" -#include "pipi-internals.h" - -pipi_image_t *pipi_render_bayer(int w, int h) +namespace lol { - pipi_image_t *ret; - pipi_pixels_t *pix; - float *data; - int i, j, n; - if(w <= 0 || h <= 0) - return NULL; +bool Image::RenderBayer(ivec2 size) +{ + if (size.x <= 0 || size.y <= 0) + return false; - for(n = 1; n < w || n < h; n *= 2) - ; + int n = 1; + while (n < size.x || n < size.y) + n *= 2; - ret = pipi_new(w, h); - pix = pipi_get_pixels(ret, PIPI_PIXELS_Y_F32); - data = (float *)pix->pixels; + SetSize(size); + float *pixels = Lock(); - for(j = 0; j < h; j++) - for(i = 0; i < w; i++) + for (int j = 0; j < size.y; j++) + for (int i = 0; i < size.x; i++) { - int k, l, x = 0; + int x = 0; - for(k = 1, l = n * n / 4; k < n; k *= 2, l /= 4) + for (int k = 1, l = n * n / 4; k < n; k *= 2, l /= 4) { - if((i & k) && (j & k)) + if ((i & k) && (j & k)) x += l; - else if(i & k) + else if (i & k) x += 3 * l; - else if(j & k) + else if (j & k) x += 2 * l; } - data[j * w + i] = (double)(x + 1) / (n * n + 1); + pixels[j * size.x + i] = (float)(x + 1) / (n * n + 1); } - return ret; + Unlock(pixels); + + return true; } typedef struct @@ -80,49 +68,43 @@ static int cmpdot(const void *p1, const void *p2) return ((dot_t const *)p1)->dist > ((dot_t const *)p2)->dist; } -pipi_image_t *pipi_render_halftone(int w, int h) +bool Image::RenderHalftone(ivec2 size) { - pipi_image_t *ret; - pipi_pixels_t *pix; - float *data; - dot_t *circle; - int x, y, n; - - if(w <= 0 || h <= 0) - return NULL; + if (size.x <= 0 || size.y <= 0) + return false; - circle = malloc(w * h * sizeof(dot_t)); - - for(y = 0; y < h; y++) - for(x = 0; x < w; x++) + Array circle; + circle.Resize(size.x * size.y); + for (int y = 0; y < size.y; y++) + for (int x = 0; x < size.x; x++) { - double dy = ((double)y + .07) / h - .5; - double dx = (double)x / w - .5; + double dy = ((double)y + .07) / size.y - .5; + double dx = (double)x / size.x - .5; /* Using dx²+dy² here creates another interesting halftone. */ double r = - cos(M_PI * (dx - dy)) - cos(M_PI * (dx + dy)); - circle[y * w + x].x = x; - circle[y * w + x].y = y; - circle[y * w + x].dist = r; + circle[y * size.x + x].x = x; + circle[y * size.x + x].y = y; + circle[y * size.x + x].dist = r; } - qsort(circle, w * h, sizeof(dot_t), cmpdot); - - ret = pipi_new(w * 2, h * 2); - pix = pipi_get_pixels(ret, PIPI_PIXELS_Y_F32); - data = (float *)pix->pixels; + std::qsort(circle.Data(), size.x * size.y, sizeof(dot_t), cmpdot); - for(n = 0; n < w * h; n++) + SetSize(2 * size); + float *pixels = Lock(); + float mul = 1.f / (size.x * size.y * 4 + 1); + for (int n = 0; n < size.x * size.y; n++) { - x = circle[n].x; - y = circle[n].y; + int x = circle[n].x; + int y = circle[n].y; - data[y * (2 * w) + x] = (float)(2 * n + 1) / (w * h * 4 + 1); - data[(y + h) * (2 * w) + x + w] = (float)(2 * n + 2) / (w * h * 4 + 1); - data[(y + h) * (2 * w) + x] = 1. - (float)(2 * n + 1) / (w * h * 4 + 1); - data[y * (2 * w) + x + w] = 1. - (float)(2 * n + 2) / (w * h * 4 + 1); + pixels[y * (2 * size.x) + x] = (float)(2 * n + 1) * mul; + pixels[(y + size.y) * (2 * size.x) + x + size.x] = (float)(2 * n + 2) * mul; + pixels[(y + size.y) * (2 * size.x) + x] = 1. - (float)(2 * n + 1) * mul; + pixels[y * (2 * size.x) + x + size.x] = 1. - (float)(2 * n + 2) * mul; } + Unlock(pixels); - free(circle); - - return ret; + return true; } +} /* namespace lol */ + diff --git a/src/image/stock.cpp b/src/image/stock.cpp index 6184bcea..e91b8c3d 100644 --- a/src/image/stock.cpp +++ b/src/image/stock.cpp @@ -1,201 +1,193 @@ -/* - * libpipi Pathetic image processing interface library - * Copyright (c) 2004-2008 Sam Hocevar - * All Rights Reserved - * - * $Id$ - * - * This library is free software. It comes without any warranty, to - * the extent permitted by applicable law. You can redistribute it - * and/or modify it under the terms of the Do What The Fuck You Want - * To Public License, Version 2, as published by Sam Hocevar. See - * http://sam.zoy.org/wtfpl/COPYING for more details. - */ +// +// Lol Engine +// +// Copyright: (c) 2004-2013 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" /* - * stock.c: stock images + * Stock images */ -#include "config.h" - -#include -#include -#include - -#include "pipi.h" -#include "pipi-internals.h" - -pipi_image_t *pipi_load_stock(char const *name) +namespace lol { - pipi_image_t *ret; - pipi_pixels_t *pix; +bool Image::Stock(char const *name) +{ /* Generate a Bayer dithering pattern. */ - if(!strncmp(name, "bayer:", 6)) + if (!strncmp(name, "bayer:", 6)) { - int w, h = 0; - - w = atoi(name + 6); + ivec2 size(0); + size.x = atoi(name + 6); name = strchr(name + 6, 'x'); - if(name) - h = atoi(name + 1); - if(!h) - h = w; + if (name) + size.y = atoi(name + 1); + if (!size.y) + size.y = size.x; - return pipi_render_bayer(w, h); + return RenderBayer(size); } /* Generate a clustered dithering pattern. */ - if(!strncmp(name, "halftone:", 9)) + if (!strncmp(name, "halftone:", 9)) { - int w, h = 0; - - w = atoi(name + 9); + ivec2 size(0); + size.x = atoi(name + 9); name = strchr(name + 9, 'x'); - if(name) - h = atoi(name + 1); - if(!h) - h = w; + if (name) + size.y = atoi(name + 1); + if (!size.y) + size.y = size.x; - return pipi_render_halftone(w, h); + return RenderHalftone(size); } /* Generate an error diffusion matrix. */ - if(!strncmp(name, "ediff:", 6)) + if (!strncmp(name, "ediff:", 6)) { float const *ker; - int w, h; + ivec2 size(0); - if(!strcmp(name + 6, "fs")) + if (!strcmp(name + 6, "fs")) { - static float const myker[] = + float const myker[] = { 0., 1., 7./16, 3./16, 5./16, 1./16, }; - ker = myker; w = 3; h = 2; + ker = myker; size = ivec2(3, 2); } - else if(!strcmp(name + 6, "jajuni")) + else if (!strcmp(name + 6, "jajuni")) { - static float const myker[] = + float const myker[] = { 0., 0., 1., 7./48, 5./48, 3./48, 5./48, 7./48, 5./48, 3./48, 1./48, 3./48, 5./48, 3./48, 1./48, }; - ker = myker; w = 5; h = 3; + ker = myker; size = ivec2(5, 3); } - else if(!strcmp(name + 6, "atkinson")) + else if (!strcmp(name + 6, "atkinson")) { - static float const myker[] = + float const myker[] = { 0., 1., 1./8, 1./8, 1./8, 1./8, 1./8, 0., 0., 1./8, 0., 0., }; - ker = myker; w = 4; h = 3; + ker = myker; size = ivec2(4, 3); } - else if(!strcmp(name + 6, "fan")) + else if (!strcmp(name + 6, "fan")) { - static float const myker[] = + float const myker[] = { 0., 0., 1., 7./16, 1./16, 3./16, 5./16, 0., }; - ker = myker; w = 4; h = 2; + ker = myker; size = ivec2(4, 2); } - else if(!strcmp(name + 6, "shiaufan")) + else if (!strcmp(name + 6, "shiaufan")) { - static float const myker[] = + float const myker[] = { 0., 0., 1., 1./2, 1./8, 1./8, 1./4, 0., }; - ker = myker; w = 4; h = 2; + ker = myker; size = ivec2(4, 2); } - else if(!strcmp(name + 6, "shiaufan2")) + else if (!strcmp(name + 6, "shiaufan2")) { - static float const myker[] = + float const myker[] = { 0., 0., 0., 1., 1./2, 1./16, 1./16, 1./8, 1./4, 0., }; - ker = myker; w = 5; h = 2; + ker = myker; size = ivec2(5, 2); } - else if(!strcmp(name + 6, "stucki")) + else if (!strcmp(name + 6, "stucki")) { - static float const myker[] = + float const myker[] = { 0., 0., 1., 8./42, 4./42, 2./42, 4./42, 8./42, 4./42, 2./42, 1./42, 2./42, 4./42, 2./42, 1./42, }; - ker = myker; w = 5; h = 3; + ker = myker; size = ivec2(5, 3); } - else if(!strcmp(name + 6, "burkes")) + else if (!strcmp(name + 6, "burkes")) { - static float const myker[] = + float const myker[] = { 0., 0., 1., 4./16, 2./16, 1./16, 2./16, 4./16, 2./16, 1./16, }; - ker = myker; w = 5; h = 2; + ker = myker; size = ivec2(5, 2); } - else if(!strcmp(name + 6, "sierra")) + else if (!strcmp(name + 6, "sierra")) { - static float const myker[] = + float const myker[] = { 0., 0., 1., 5./32, 3./32, 2./32, 4./32, 5./32, 4./32, 2./32, 0., 2./32, 3./32, 2./32, 0., }; - ker = myker; w = 5; h = 3; + ker = myker; size = ivec2(5, 3); } - else if(!strcmp(name + 6, "sierra2")) + else if (!strcmp(name + 6, "sierra2")) { - static float const myker[] = + float const myker[] = { 0., 0., 1., 4./16, 3./16, 1./16, 2./16, 3./16, 2./16, 1./16, }; - ker = myker; w = 5; h = 2; + ker = myker; size = ivec2(5, 2); } - else if(!strcmp(name + 6, "lite")) + else if (!strcmp(name + 6, "lite")) { - static float const myker[] = + float const myker[] = { 0., 1., 1./2, 1./4, 1./4, 0., }; - ker = myker; w = 3; h = 2; + ker = myker; size = ivec2(3, 2); } - else - return NULL; - ret = pipi_new(w, h); - pix = pipi_get_pixels(ret, PIPI_PIXELS_Y_F32); - memcpy(pix->pixels, ker, w * h * sizeof(float)); + SetSize(size); + float *pixels = Lock(); + memcpy(pixels, ker, size.x * size.y * sizeof(float)); + Unlock(pixels); - return ret; + return true; } /* Generate a completely random image. */ - if(!strncmp(name, "random:", 7)) + if (!strncmp(name, "random:", 7)) { - int w, h = 0; + ivec2 size(0); - w = atoi(name + 7); + size.x = atoi(name + 7); name = strchr(name + 7, 'x'); - if(name) - h = atoi(name + 1); - if(!h) - h = w; - if(w <= 0 || h <= 0) - return NULL; - - return pipi_render_random(w, h); + if (name) + size.y = atoi(name + 1); + if (!size.y) + size.y = size.x; + if (size.x <= 0 || size.y <= 0) + return false; + + return RenderRandom(size); } - return NULL; + return false; } +} /* namespace lol */ + diff --git a/src/lol/image/image.h b/src/lol/image/image.h index 1abea19e..56fb0f15 100644 --- a/src/lol/image/image.h +++ b/src/lol/image/image.h @@ -39,13 +39,14 @@ public: Image(char const *path); /* Rule of three */ - Image (Image const &other); + Image(Image const &other); Image & operator =(Image other); ~Image(); bool Load(char const *path); bool Save(char const *path); + /* Low level access */ ivec2 GetSize() const; void SetSize(ivec2); @@ -58,6 +59,16 @@ public: bool RetrieveTiles(Array& tiles) const; + /* Rendering */ + bool Stock(char const *desc); + bool RenderBayer(ivec2 size); + bool RenderHalftone(ivec2 size); + bool RenderRandom(ivec2 size); + + /* Image processing */ + + + private: class ImageData *m_data; };