Gfxprim
Threads by month
- ----- 2026 -----
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- 929 discussions
[repo.or.cz] gfxprim.git branch master updated: d4c258f6b3bd05560a400bb20a9d428782262eb9
by metan 17 Jun '12
by metan 17 Jun '12
17 Jun '12
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via d4c258f6b3bd05560a400bb20a9d428782262eb9 (commit)
from 767b1a983317b48ebddd9fb64d33ca977dea7611 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/d4c258f6b3bd05560a400bb20a9d42878226…
commit d4c258f6b3bd05560a400bb20a9d428782262eb9
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 23:28:33 2012 +0200
filters: Add fixed point, table based, cubic curve aproximation.
diff --git a/libs/filters/GP_Cubic.gen.c.t b/libs/filters/GP_Cubic.gen.c.t
new file mode 100644
index 0000000..4d66517
--- /dev/null
+++ b/libs/filters/GP_Cubic.gen.c.t
@@ -0,0 +1,27 @@
+%% extends "base.c.t"
+
+{% block descr %}Table for fixed point cubic coeficients for A=0.5{% endblock %}
+
+%% block body
+
+/*
+ * Fixed point cubic coeficients.
+ *
+ * Copyright (c) 2012 Cyril Hrubis <metan(a)ucw.cz>
+ */
+
+#include <stdint.h>
+
+int16_t GP_CubicTable[2047] = {
+%% set A=0.5
+%% for i in range(0, 1023)
+%% set x = i/1024
+ {{ round(((2 - A)*x*x*x + (A - 3)*x*x + 1) * 1024) }}, /* {{ i }} {{ x }} */
+%% endfor
+%% for i in range(1024, 2047)
+%% set x = i/1024
+ {{ round((-A*x*x*x + 5*A*x*x - 8*A*x + 4*A) * 1024) }}, /* {{ i }} {{ x }} */
+%% endfor
+};
+
+%% endblock body
diff --git a/libs/filters/GP_Cubic.h b/libs/filters/GP_Cubic.h
new file mode 100644
index 0000000..3e7dbef
--- /dev/null
+++ b/libs/filters/GP_Cubic.h
@@ -0,0 +1,69 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+ /*
+
+ This header contains cubic resampling function aproximation.
+
+ */
+
+#ifndef FILTERS_GP_CUBIC_H
+#define FILTERS_GP_CUBIC_H
+
+#define A 0.5
+
+static inline float cubic_float(float x)
+{
+ if (x < 0)
+ x = -x;
+
+ if (x < 1)
+ return (2 - A)*x*x*x + (A - 3)*x*x + 1;
+
+ if (x < 2)
+ return -A*x*x*x + 5*A*x*x - 8*A*x + 4*A;
+
+ return 0;
+}
+
+#include <stdint.h>
+
+/* Defined in GP_Cubic.gen.c */
+extern int16_t GP_CubicTable[];
+
+/*
+ * Fixed point version of above.
+ *
+ * Both input and output value are multiplied by MUL.
+ */
+static inline int cubic_int(int x)
+{
+ if (x < 0)
+ x = -x;
+
+ if (x >= 2048)
+ return 0;
+
+ return GP_CubicTable[x];
+}
+
+#endif /* FILTERS_GP_CUBIC_H */
diff --git a/libs/filters/GP_Resize.c b/libs/filters/GP_Resize.c
index b7182f9..79362ef 100644
--- a/libs/filters/GP_Resize.c
+++ b/libs/filters/GP_Resize.c
@@ -252,6 +252,8 @@ int GP_FilterInterpolate_Cubic(const GP_Context *src, GP_Context *dst,
return 0;
}
+#include "GP_Cubic.h"
+
#define MUL 1024
#define MUL_I(a, b) ({ @@ -299,23 +301,24 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
int32_t xmap_c[dst->w][4];
for (i = 0; i < dst->w; i++) {
- float x = (1.00 * i / (dst->w - 1)) * (src->w - 1);
-
- xmap[i][0] = floor(x - 1);
- xmap[i][1] = x;
- xmap[i][2] = x + 1;
- xmap[i][3] = x + 2;
+ float x = (1.00 * i / (dst->w - 1)) * (src->w - 1);
+
+ xmap[i][0] = floor(x - 1);
+ xmap[i][1] = x;
+ xmap[i][2] = x + 1;
+ xmap[i][3] = x + 2;
+
- xmap_c[i][0] = cubic(xmap[i][0] - x) * MUL + 0.5;
- xmap_c[i][1] = cubic(xmap[i][1] - x) * MUL + 0.5;
- xmap_c[i][2] = cubic(xmap[i][2] - x) * MUL + 0.5;
- xmap_c[i][3] = cubic(xmap[i][3] - x) * MUL + 0.5;
+ xmap_c[i][0] = cubic_int((xmap[i][0] - x) * MUL + 0.5);
+ xmap_c[i][1] = cubic_int((xmap[i][1] - x) * MUL + 0.5);
+ xmap_c[i][2] = cubic_int((xmap[i][2] - x) * MUL + 0.5);
+ xmap_c[i][3] = cubic_int((xmap[i][3] - x) * MUL + 0.5);
- if (xmap[i][0] < 0)
- xmap[i][0] = 0;
+ if (xmap[i][0] < 0)
+ xmap[i][0] = 0;
- if (xmap[i][3] >= (int32_t)src->w)
- xmap[i][3] = src->w - 1;
+ if (xmap[i][3] >= (int32_t)src->w)
+ xmap[i][3] = src->w - 1;
}
/* cubic resampling */
@@ -329,10 +332,10 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
yi[2] = y + 1;
yi[3] = y + 2;
- cvy[0] = cubic(yi[0] - y) * MUL + 0.5;
- cvy[1] = cubic(yi[1] - y) * MUL + 0.5;
- cvy[2] = cubic(yi[2] - y) * MUL + 0.5;
- cvy[3] = cubic(yi[3] - y) * MUL + 0.5;
+ cvy[0] = cubic_int((yi[0] - y) * MUL + 0.5);
+ cvy[1] = cubic_int((yi[1] - y) * MUL + 0.5);
+ cvy[2] = cubic_int((yi[2] - y) * MUL + 0.5);
+ cvy[3] = cubic_int((yi[3] - y) * MUL + 0.5);
if (yi[0] < 0)
yi[0] = 0;
diff --git a/libs/filters/Makefile b/libs/filters/Makefile
index 1470e55..e07d92a 100644
--- a/libs/filters/Makefile
+++ b/libs/filters/Makefile
@@ -8,7 +8,7 @@ POINT_FILTERS=GP_Contrast.gen.c GP_Brightness.gen.c GP_Invert.gen.c ARITHMETIC_FILTERS=GP_Difference.gen.c GP_Addition.gen.c GP_Min.gen.c GP_Max.gen.c GP_Multiply.gen.c
-RESAMPLING_FILTERS=GP_ResizeNN.gen.c
+RESAMPLING_FILTERS=GP_ResizeNN.gen.c GP_Cubic.gen.c
GENSOURCES=GP_MirrorV.gen.c GP_Rotate.gen.c GP_FloydSteinberg.gen.c GP_HilbertPeano.gen.c $(POINT_FILTERS) $(ARITHMETIC_FILTERS) $(STATS_FILTERS) $(RESAMPLING_FILTERS)
-----------------------------------------------------------------------
Summary of changes:
libs/filters/GP_Cubic.gen.c.t | 27 +++++++++
.../loaders_example.c => libs/filters/GP_Cubic.h | 58 +++++++++++---------
libs/filters/GP_Resize.c | 39 +++++++------
libs/filters/Makefile | 2 +-
4 files changed, 82 insertions(+), 44 deletions(-)
create mode 100644 libs/filters/GP_Cubic.gen.c.t
copy demos/c_simple/loaders_example.c => libs/filters/GP_Cubic.h (72%)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 767b1a983317b48ebddd9fb64d33ca977dea7611
by metan 17 Jun '12
by metan 17 Jun '12
17 Jun '12
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 767b1a983317b48ebddd9fb64d33ca977dea7611 (commit)
from 6c21c9015f98423f9f880ae220a6956defed011c (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/767b1a983317b48ebddd9fb64d33ca977dea…
commit 767b1a983317b48ebddd9fb64d33ca977dea7611
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 21:38:02 2012 +0200
filters: cubic resampling: Cache coordinates mapping.
This moves the mapping computation out of the main loop (something I've
had in mind for quite some time) which yields in 4 x boost in speed.
diff --git a/libs/filters/GP_Resize.c b/libs/filters/GP_Resize.c
index b453ffd..b7182f9 100644
--- a/libs/filters/GP_Resize.c
+++ b/libs/filters/GP_Resize.c
@@ -294,6 +294,31 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
B_2_GAMMA = src->gamma->tables[5]->u8;
}
+ /* pre-generate x mapping and constants */
+ int32_t xmap[dst->w][4];
+ int32_t xmap_c[dst->w][4];
+
+ for (i = 0; i < dst->w; i++) {
+ float x = (1.00 * i / (dst->w - 1)) * (src->w - 1);
+
+ xmap[i][0] = floor(x - 1);
+ xmap[i][1] = x;
+ xmap[i][2] = x + 1;
+ xmap[i][3] = x + 2;
+
+ xmap_c[i][0] = cubic(xmap[i][0] - x) * MUL + 0.5;
+ xmap_c[i][1] = cubic(xmap[i][1] - x) * MUL + 0.5;
+ xmap_c[i][2] = cubic(xmap[i][2] - x) * MUL + 0.5;
+ xmap_c[i][3] = cubic(xmap[i][3] - x) * MUL + 0.5;
+
+ if (xmap[i][0] < 0)
+ xmap[i][0] = 0;
+
+ if (xmap[i][3] >= (int32_t)src->w)
+ xmap[i][3] = src->w - 1;
+ }
+
+ /* cubic resampling */
for (i = 0; i < dst->h; i++) {
float y = (1.00 * i / (dst->h - 1)) * (src->h - 1);
int32_t cvy[4];
@@ -369,45 +394,27 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
/* now interpolate column for new image */
for (j = 0; j < dst->w; j++) {
- float x = (1.00 * j / (dst->w - 1)) * (src->w - 1);
- int32_t cvx[4], rv[4], gv[4], bv[4];
+ int32_t rv[4], gv[4], bv[4];
int32_t r, g, b;
- int xi[4];
- xi[0] = floor(x - 1);
- xi[1] = x;
- xi[2] = x + 1;
- xi[3] = x + 2;
-
- cvx[0] = cubic(xi[0] - x) * MUL + 0.5;
- cvx[1] = cubic(xi[1] - x) * MUL + 0.5;
- cvx[2] = cubic(xi[2] - x) * MUL + 0.5;
- cvx[3] = cubic(xi[3] - x) * MUL + 0.5;
-
- if (xi[0] < 0)
- xi[0] = 0;
-
- if (xi[3] >= (int)src->w)
- xi[3] = src->w - 1;
-
- rv[0] = col_r[xi[0]];
- rv[1] = col_r[xi[1]];
- rv[2] = col_r[xi[2]];
- rv[3] = col_r[xi[3]];
+ rv[0] = col_r[xmap[j][0]];
+ rv[1] = col_r[xmap[j][1]];
+ rv[2] = col_r[xmap[j][2]];
+ rv[3] = col_r[xmap[j][3]];
- gv[0] = col_g[xi[0]];
- gv[1] = col_g[xi[1]];
- gv[2] = col_g[xi[2]];
- gv[3] = col_g[xi[3]];
+ gv[0] = col_g[xmap[j][0]];
+ gv[1] = col_g[xmap[j][1]];
+ gv[2] = col_g[xmap[j][2]];
+ gv[3] = col_g[xmap[j][3]];
- bv[0] = col_b[xi[0]];
- bv[1] = col_b[xi[1]];
- bv[2] = col_b[xi[2]];
- bv[3] = col_b[xi[3]];
+ bv[0] = col_b[xmap[j][0]];
+ bv[1] = col_b[xmap[j][1]];
+ bv[2] = col_b[xmap[j][2]];
+ bv[3] = col_b[xmap[j][3]];
- MUL_I(rv, cvx);
- MUL_I(gv, cvx);
- MUL_I(bv, cvx);
+ MUL_I(rv, xmap_c[j]);
+ MUL_I(gv, xmap_c[j]);
+ MUL_I(bv, xmap_c[j]);
r = (SUM_I(rv) + MUL*MUL/2) / MUL / MUL;
g = (SUM_I(gv) + MUL*MUL/2) / MUL / MUL;
-----------------------------------------------------------------------
Summary of changes:
libs/filters/GP_Resize.c | 75 +++++++++++++++++++++++++---------------------
1 files changed, 41 insertions(+), 34 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 6c21c9015f98423f9f880ae220a6956defed011c
by metan 17 Jun '12
by metan 17 Jun '12
17 Jun '12
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 6c21c9015f98423f9f880ae220a6956defed011c (commit)
from cdf4a7d83af42ed412a8b705b3ad50cb43a9ecb9 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/6c21c9015f98423f9f880ae220a6956defed…
commit 6c21c9015f98423f9f880ae220a6956defed011c
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 21:10:11 2012 +0200
filters: resize NN: Remove forgotten debug print.
diff --git a/libs/filters/GP_ResizeNN.gen.c.t b/libs/filters/GP_ResizeNN.gen.c.t
index 7c7bd51..cf364a0 100644
--- a/libs/filters/GP_ResizeNN.gen.c.t
+++ b/libs/filters/GP_ResizeNN.gen.c.t
@@ -27,11 +27,8 @@ static int GP_FilterResizeNN_{{ pt.name }}_Raw(const GP_Context *src,
1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
/* Pre-compute mapping for interpolation */
- for (i = 0; i < dst->w; i++) {
+ for (i = 0; i < dst->w; i++)
xmap[i] = ((((i * (src->w - 1))<<8) + (dst->w - 1)/2) / (dst->w - 1) + (1<<7))>>8;
- printf("%i-%i ", i, xmap[i]);
- }
- printf("n%i -> %in", src->w, dst->w);
for (i = 0; i < dst->h; i++)
ymap[i] = ((((i * (src->h - 1))<<8) + (dst->h - 1)/2) / (dst->h - 1) + (1<<7))>>8;
-----------------------------------------------------------------------
Summary of changes:
libs/filters/GP_ResizeNN.gen.c.t | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: cdf4a7d83af42ed412a8b705b3ad50cb43a9ecb9
by metan 17 Jun '12
by metan 17 Jun '12
17 Jun '12
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via cdf4a7d83af42ed412a8b705b3ad50cb43a9ecb9 (commit)
via 76e823c5cd0ff172cb3649655b468b920a861f06 (commit)
via 3b60a5fe873cde45782b7ef870ecc94bfbc209d2 (commit)
via 667776d0fdc6195be8c9ad201f48bb6a4b4da460 (commit)
via d3f29ef699671a32207092195cc96926ed2937e3 (commit)
via 0223a7dca0a58c112f3b60100e0e5f66de5263d1 (commit)
via 5bc6361309104e85c8a54add16ca23554bf65827 (commit)
from 4dad87b8900261ecaadbc43dedb932683089b414 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/cdf4a7d83af42ed412a8b705b3ad50cb43a9…
commit cdf4a7d83af42ed412a8b705b3ad50cb43a9ecb9
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 20:09:43 2012 +0200
filters: resize: Fix off-by-one for rest of the algorithms.
diff --git a/libs/filters/GP_Resize.c b/libs/filters/GP_Resize.c
index 6fbd5eb..b453ffd 100644
--- a/libs/filters/GP_Resize.c
+++ b/libs/filters/GP_Resize.c
@@ -130,7 +130,7 @@ int GP_FilterInterpolate_Cubic(const GP_Context *src, GP_Context *dst,
1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
for (i = 0; i < dst->w; i++) {
- float x = (1.00 * i / dst->w) * src->w;
+ float x = (1.00 * i / (dst->w - 1)) * (src->w - 1);
v4f cvx;
int xi[4];
@@ -189,7 +189,7 @@ int GP_FilterInterpolate_Cubic(const GP_Context *src, GP_Context *dst,
/* now interpolate column for new image */
for (j = 0; j < dst->h; j++) {
- float y = (1.00 * j / dst->h) * src->h;
+ float y = (1.00 * j / (dst->h - 1)) * (src->h - 1);
v4f cvy, rv, gv, bv;
float r, g, b;
int yi[4];
@@ -295,7 +295,7 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
}
for (i = 0; i < dst->h; i++) {
- float y = (1.00 * i / dst->h) * src->h;
+ float y = (1.00 * i / (dst->h - 1)) * (src->h - 1);
int32_t cvy[4];
int yi[4];
@@ -312,9 +312,6 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
if (yi[0] < 0)
yi[0] = 0;
- if (yi[2] >= (int)src->h)
- yi[2] = src->h - 1;
-
if (yi[3] >= (int)src->h)
yi[3] = src->h - 1;
@@ -372,7 +369,7 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
/* now interpolate column for new image */
for (j = 0; j < dst->w; j++) {
- float x = (1.00 * j / dst->w) * src->w;
+ float x = (1.00 * j / (dst->w - 1)) * (src->w - 1);
int32_t cvx[4], rv[4], gv[4], bv[4];
int32_t r, g, b;
int xi[4];
@@ -390,9 +387,6 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
if (xi[0] < 0)
xi[0] = 0;
- if (xi[2] >= (int)src->w)
- xi[2] = src->w - 1;
-
if (xi[3] >= (int)src->w)
xi[3] = src->w - 1;
@@ -537,8 +531,8 @@ static int interpolate_linear_lp_xy(const GP_Context *src, GP_Context *dst,
uint32_t i, j;
/* Pre-compute mapping for interpolation */
- uint32_t xstep = (src->w << 16) / dst->w;
- uint32_t xpix_dist = (dst->w << 14) / src->w;
+ uint32_t xstep = ((src->w - 1) << 16) / (dst->w - 1);
+ uint32_t xpix_dist = ((dst->w - 1) << 14) / (src->w - 1);
for (i = 0; i < dst->w + 1; i++) {
uint32_t val = i * xstep;
@@ -546,8 +540,8 @@ static int interpolate_linear_lp_xy(const GP_Context *src, GP_Context *dst,
xoff[i] = ((255 - ((val >> 8) & 0xff)) * xpix_dist)>>8;
}
- uint32_t ystep = (src->h << 16) / dst->h;
- uint32_t ypix_dist = (dst->h << 14) / src->h;
+ uint32_t ystep = ((src->h - 1) << 16) / (dst->h - 1);
+ uint32_t ypix_dist = ((dst->h - 1) << 14) / (src->h - 1);
for (i = 0; i < dst->h + 1; i++) {
uint32_t val = i * ystep;
@@ -634,7 +628,7 @@ int GP_FilterInterpolate_LinearInt(const GP_Context *src, GP_Context *dst,
1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
/* Pre-compute mapping for interpolation */
- uint32_t xstep = (src->w << 16) / dst->w;
+ uint32_t xstep = ((src->w - 1) << 16) / (dst->w - 1);
for (i = 0; i < dst->w + 1; i++) {
uint32_t val = i * xstep;
@@ -642,7 +636,7 @@ int GP_FilterInterpolate_LinearInt(const GP_Context *src, GP_Context *dst,
xoff[i] = (val >> 8) & 0xff;
}
- uint32_t ystep = (src->h << 16) / dst->h;
+ uint32_t ystep = ((src->h - 1) << 16) / (dst->h - 1);
for (i = 0; i < dst->h + 1; i++) {
uint32_t val = i * ystep;
http://repo.or.cz/w/gfxprim.git/commit/76e823c5cd0ff172cb3649655b468b920a86…
commit 76e823c5cd0ff172cb3649655b468b920a861f06
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 19:54:12 2012 +0200
filters: resize NN, fix off-by-one in coordinates mapping.
diff --git a/libs/filters/GP_ResizeNN.gen.c.t b/libs/filters/GP_ResizeNN.gen.c.t
index 7719efb..7c7bd51 100644
--- a/libs/filters/GP_ResizeNN.gen.c.t
+++ b/libs/filters/GP_ResizeNN.gen.c.t
@@ -27,15 +27,14 @@ static int GP_FilterResizeNN_{{ pt.name }}_Raw(const GP_Context *src,
1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
/* Pre-compute mapping for interpolation */
- uint32_t xstep = (src->w << 16) / dst->w;
-
- for (i = 0; i < dst->w + 1; i++)
- xmap[i] = ((i * xstep) + (1<<15)) >> 16;
-
- uint32_t ystep = (src->h << 16) / dst->h;
+ for (i = 0; i < dst->w; i++) {
+ xmap[i] = ((((i * (src->w - 1))<<8) + (dst->w - 1)/2) / (dst->w - 1) + (1<<7))>>8;
+ printf("%i-%i ", i, xmap[i]);
+ }
+ printf("n%i -> %in", src->w, dst->w);
- for (i = 0; i < dst->h + 1; i++)
- ymap[i] = ((i * ystep) + (1<<15)) >> 16;
+ for (i = 0; i < dst->h; i++)
+ ymap[i] = ((((i * (src->h - 1))<<8) + (dst->h - 1)/2) / (dst->h - 1) + (1<<7))>>8;
/* Interpolate */
for (y = 0; y < (GP_Coord)dst->h; y++) {
http://repo.or.cz/w/gfxprim.git/commit/3b60a5fe873cde45782b7ef870ecc94bfbc2…
commit 3b60a5fe873cde45782b7ef870ecc94bfbc209d2
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 19:37:27 2012 +0200
spiv: A few fixes and features.
* Adds keys to change resampling at runtime.
- left and right square brackets change resampling
- l forces to turn on/off low pass filter
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index 43c9f8d..19f6d56 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -47,7 +47,33 @@ static GP_Backend *backend = NULL;
/* image loader thread */
static int abort_flag = 0;
static int show_progress = 0;
-static int resampling_method = GP_INTERP_LINEAR_LF_INT;
+
+struct loader_params {
+ /* current image path */
+ const char *img_path;
+ /* current resize ratio */
+ float rat;
+
+ /* show loader progress */
+ long show_progress:1;
+ long show_progress_once:2;
+ /* show image info in topleft corner */
+ long show_info:3;
+ /* use nearest neighbour resampling first */
+ long show_nn_first:4;
+ /* use dithering when blitting to display */
+ long use_dithering:5;
+ /* use low pass before resampling */
+ long use_low_pass:6;
+ /* image orientation 0, 90, 180, 270 */
+ int rotate;
+ /* resampling method */
+ int resampling_method;
+
+ /* caches for loaded images */
+ struct image_cache *img_resized_cache;
+ struct image_cache *img_orig_cache;
+};
static int image_loader_callback(GP_ProgressCallback *self)
{
@@ -81,26 +107,6 @@ static int image_loader_callback(GP_ProgressCallback *self)
return 0;
}
-struct loader_params {
- const char *img_path;
-
- /* Show loader progress */
- long show_progress:1;
- long show_progress_once:2;
- /* show image info in topleft corner */
- long show_info:3;
- /* use nearest neighbour resampling first */
- long show_nn_first:4;
- /* use dithering when blitting to display */
- long use_dithering:5;
-
- /* Image orientation */
- int rotate;
-
- /* cached loaded images */
- struct image_cache *img_resized_cache;
- struct image_cache *img_orig_cache;
-};
static float calc_img_size(uint32_t img_w, uint32_t img_h,
uint32_t src_w, uint32_t src_h)
@@ -182,7 +188,7 @@ GP_Context *load_image(struct loader_params *params, int elevate)
/*
* Updates display.
*/
-static void update_display(struct loader_params *params, GP_Context *img, float rat)
+static void update_display(struct loader_params *params, GP_Context *img)
{
GP_Context *context = backend->context;
struct cpu_timer timer;
@@ -235,7 +241,7 @@ static void update_display(struct loader_params *params, GP_Context *img, float
GP_FillRectXYWH(context, img->w + cx, 0, context->w - img->w - cx, context->h, black_pixel);
GP_FillRectXYWH(context, 0, img->h + cy, context->w, context->h - img->h - cy, black_pixel);
- set_caption(params->img_path, rat);
+ set_caption(params->img_path, params->rat);
if (!params->show_info) {
GP_BackendFlip(backend);
@@ -251,10 +257,10 @@ static void update_display(struct loader_params *params, GP_Context *img, float
white_pixel, black_pixel, "%ux%u", img->w, img->h);
GP_Print(context, NULL, 11, 13 + th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
- black_pixel, white_pixel, "1:%3.3f", rat);
+ black_pixel, white_pixel, "1:%3.3f", params->rat);
GP_Print(context, NULL, 10, 12 + th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
- white_pixel, black_pixel, "1:%3.3f", rat);
+ white_pixel, black_pixel, "1:%3.3f", params->rat);
GP_Print(context, NULL, 11, 15 + 2 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
black_pixel, white_pixel, "%s", img_name(params->img_path));
@@ -262,18 +268,30 @@ static void update_display(struct loader_params *params, GP_Context *img, float
GP_Print(context, NULL, 10, 14 + 2 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
white_pixel, black_pixel, "%s", img_name(params->img_path));
+ GP_Print(context, NULL, 11, 17 + 3 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
+ black_pixel, white_pixel, "%s%s",
+ params->use_low_pass && params->rat < 1 ? "Gaussian LP + " : "",
+ GP_InterpolationTypeName(params->resampling_method));
+
+ GP_Print(context, NULL, 10, 16 + 3 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
+ white_pixel, black_pixel, "%s%s",
+ params->use_low_pass && params->rat < 1 ? "Gaussian LP + " : "",
+ GP_InterpolationTypeName(params->resampling_method));
+
GP_BackendFlip(backend);
}
-GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size h, float rat)
+GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size h)
{
long cookie = (w & 0xffff) | (h & 0xffff)<<16;
GP_Context *img, *res = NULL;
struct cpu_timer timer;
GP_ProgressCallback callback = {.callback = image_loader_callback};
+
+ int key = (params->resampling_method<<1) | !!(params->use_low_pass);
/* Try to get resized cached image */
- img = image_cache_get(params->img_resized_cache, params->img_path, cookie, resampling_method, 1);
+ img = image_cache_get(params->img_resized_cache, params->img_path, cookie, key, 1);
if (img != NULL)
return img;
@@ -286,35 +304,34 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size
/* Do simple interpolation and blit the result */
GP_Context *nn = GP_FilterResizeNNAlloc(img, w, h, NULL);
if (nn != NULL) {
- update_display(params, nn, rat);
+ update_display(params, nn);
GP_ContextFree(nn);
}
}
/* Do low pass filter */
- if (resampling_method != GP_INTERP_LINEAR_LF_INT && rat < 1) {
+ if (params->use_low_pass && params->rat < 1) {
cpu_timer_start(&timer, "Blur");
callback.priv = "Blurring Image";
- res = GP_FilterGaussianBlur(img, NULL, 0.4/rat, 0.4/rat, &callback);
-
+ res = GP_FilterGaussianBlur(img, NULL,
+ 0.3/params->rat, 0.3/params->rat,
+ &callback);
if (res == NULL)
return NULL;
img = res;
- // img->gamma = GP_GammaAcquire(img->pixel_type, 2.2);
-
cpu_timer_stop(&timer);
- } else {
- // img->gamma = GP_GammaAcquire(img->pixel_type, 2.2);
}
+
+// img->gamma = GP_GammaAcquire(img->pixel_type, 2.2);
cpu_timer_start(&timer, "Resampling");
callback.priv = "Resampling Image";
- GP_Context *i1 = GP_FilterResize(img, NULL, resampling_method, w, h, &callback);
+ GP_Context *i1 = GP_FilterResize(img, NULL, params->resampling_method, w, h, &callback);
// img->gamma = NULL;
-// GP_Context *i2 = GP_FilterResize(img, NULL, resampling_method, w, h, &callback);
+// GP_Context *i2 = GP_FilterResize(img, NULL, params->resampling_method, w, h, &callback);
// img = GP_FilterDifferenceAlloc(i2, i1, NULL);
// img = GP_FilterInvert(img, NULL, NULL);
img = i1;
@@ -326,7 +343,7 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size
if (img == NULL)
return NULL;
- image_cache_put(params->img_resized_cache, img, params->img_path, cookie, resampling_method);
+ image_cache_put(params->img_resized_cache, img, params->img_path, cookie, key);
return img;
}
@@ -380,12 +397,12 @@ static void *image_loader(void *ptr)
if ((img = load_image(params, 0)) == NULL)
return NULL;
- float rat = calc_img_size(img->w, img->h, w, h);
+ params->rat = calc_img_size(img->w, img->h, w, h);
w = img->w;
h = img->h;
- img = load_resized_image(params, w * rat + 0.5, h * rat + 0.5, rat);
+ img = load_resized_image(params, w * params->rat + 0.5, h * params->rat + 0.5);
if (img == NULL)
return NULL;
@@ -393,7 +410,7 @@ static void *image_loader(void *ptr)
image_cache_print(params->img_resized_cache);
image_cache_print(params->img_orig_cache);
- update_display(params, img, rat);
+ update_display(params, img);
cpu_timer_stop(&sum_timer);
@@ -552,13 +569,13 @@ int main(int argc, char *argv[])
struct loader_params params = {
.img_path = NULL,
- .rotate = 0,
-
.show_progress = 0,
.show_progress_once = 0,
.show_info = 0,
.show_nn_first = 0,
.use_dithering = 0,
+ .rotate = 0,
+ .resampling_method = GP_INTERP_LINEAR_LF_INT,
.img_resized_cache = NULL,
.img_orig_cache = NULL,
@@ -579,7 +596,9 @@ int main(int argc, char *argv[])
sleep_sec = atoi(optarg);
break;
case 'c':
- resampling_method = GP_INTERP_CUBIC_INT;
+ params.resampling_method = GP_INTERP_CUBIC_INT;
+ /* Cubic resampling needs low pass */
+ params.use_low_pass = 1;
/* Cubic resampling is slow, show nn first */
params.show_nn_first = 1;
break;
@@ -679,6 +698,46 @@ int main(int argc, char *argv[])
params.show_progress_once = 1;
show_image(¶ms, NULL);
break;
+ case GP_KEY_RIGHT_BRACE:
+ params.resampling_method++;
+
+ if (params.resampling_method > GP_INTERP_MAX)
+ params.resampling_method = 0;
+
+ if (params.resampling_method == GP_INTERP_LINEAR_LF_INT) {
+ params.use_low_pass = 0;
+ params.show_nn_first = 0;
+ } else {
+ params.use_low_pass = 1;
+ params.show_nn_first = 1;
+ }
+
+ params.show_progress_once = 1;
+ show_image(¶ms, argv[argn]);
+ break;
+ case GP_KEY_LEFT_BRACE:
+ if (params.resampling_method == 0)
+ params.resampling_method = GP_INTERP_MAX;
+ else
+ params.resampling_method--;
+
+ if (params.resampling_method == GP_INTERP_LINEAR_LF_INT) {
+ params.use_low_pass = 0;
+ params.show_nn_first = 0;
+ } else {
+ params.use_low_pass = 1;
+ params.show_nn_first = 1;
+ }
+
+ params.show_progress_once = 1;
+ show_image(¶ms, argv[argn]);
+ break;
+ case GP_KEY_L:
+ params.use_low_pass = !params.use_low_pass;
+
+ params.show_progress_once = 1;
+ show_image(¶ms, argv[argn]);
+ break;
case GP_KEY_D:
image_cache_drop(params.img_resized_cache);
image_cache_drop(params.img_orig_cache);
http://repo.or.cz/w/gfxprim.git/commit/667776d0fdc6195be8c9ad201f48bb6a4b4d…
commit 667776d0fdc6195be8c9ad201f48bb6a4b4da460
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 19:34:21 2012 +0200
filters: resize: Add GP_InterpolationTypeName().
diff --git a/include/filters/GP_Resize.h b/include/filters/GP_Resize.h
index 1c84f2c..7b1473c 100644
--- a/include/filters/GP_Resize.h
+++ b/include/filters/GP_Resize.h
@@ -71,8 +71,11 @@ typedef enum GP_InterpolationType {
GP_INTERP_LINEAR_LF_INT, /* Bilinear + low pass filter on downscaling */
GP_INTERP_CUBIC, /* Bicubic */
GP_INTERP_CUBIC_INT, /* Bicubic - fixed point arithmetics */
+ GP_INTERP_MAX = GP_INTERP_CUBIC_INT,
} GP_InterpolationType;
+const char *GP_InterpolationTypeName(enum GP_InterpolationType interp_type);
+
/*
* Just interpolate the source context into destination context.
*/
diff --git a/libs/filters/GP_Resize.c b/libs/filters/GP_Resize.c
index a1c0d71..6fbd5eb 100644
--- a/libs/filters/GP_Resize.c
+++ b/libs/filters/GP_Resize.c
@@ -58,6 +58,21 @@ GP_Context *GP_FilterResizeNNAlloc(const GP_Context *src,
return res;
}
+static const char *interp_types[] = {
+ "Nearest Neighbour",
+ "Linear (Int)",
+ "Linear with Low Pass (Int)",
+ "Cubic (Float)",
+ "Cubic (Int)",
+};
+
+const char *GP_InterpolationTypeName(enum GP_InterpolationType interp_type)
+{
+ if (interp_type > GP_INTERP_MAX)
+ return "Unknown";
+
+ return interp_types[interp_type];
+}
#define A 0.5
http://repo.or.cz/w/gfxprim.git/commit/d3f29ef699671a32207092195cc96926ed29…
commit d3f29ef699671a32207092195cc96926ed2937e3
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 18:18:16 2012 +0200
spiv: Make use of the Nearest Neighbour resampling.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index d6b3da3..43c9f8d 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -46,10 +46,8 @@ static GP_Backend *backend = NULL;
/* image loader thread */
static int abort_flag = 0;
-static int rotate = 0;
static int show_progress = 0;
static int resampling_method = GP_INTERP_LINEAR_LF_INT;
-static int dithering = 0;
static int image_loader_callback(GP_ProgressCallback *self)
{
@@ -86,9 +84,18 @@ static int image_loader_callback(GP_ProgressCallback *self)
struct loader_params {
const char *img_path;
- int show_progress;
- int show_progress_once;
- int show_info;
+ /* Show loader progress */
+ long show_progress:1;
+ long show_progress_once:2;
+ /* show image info in topleft corner */
+ long show_info:3;
+ /* use nearest neighbour resampling first */
+ long show_nn_first:4;
+ /* use dithering when blitting to display */
+ long use_dithering:5;
+
+ /* Image orientation */
+ int rotate;
/* cached loaded images */
struct image_cache *img_resized_cache;
@@ -144,6 +151,10 @@ GP_Context *load_image(struct loader_params *params, int elevate)
cpu_timer_start(&timer, "Loading");
if ((img = GP_LoadImage(params->img_path, &callback)) == NULL) {
+
+ if (errno == ECANCELED)
+ return NULL;
+
GP_Fill(context, black_pixel);
GP_Print(context, NULL, context->w/2, context->h/2,
GP_ALIGN_CENTER|GP_VALIGN_CENTER, white_pixel, black_pixel,
@@ -168,6 +179,92 @@ GP_Context *load_image(struct loader_params *params, int elevate)
return img;
}
+/*
+ * Updates display.
+ */
+static void update_display(struct loader_params *params, GP_Context *img, float rat)
+{
+ GP_Context *context = backend->context;
+ struct cpu_timer timer;
+ GP_ProgressCallback callback = {.callback = image_loader_callback};
+
+ switch (params->rotate) {
+ case 0:
+ break;
+ case 90:
+ callback.priv = "Rotating image (90)";
+ img = GP_FilterRotate90_Alloc(img, &callback);
+ break;
+ case 180:
+ callback.priv = "Rotating image (180)";
+ img = GP_FilterRotate180_Alloc(img, &callback);
+ break;
+ case 270:
+ callback.priv = "Rotating image (270)";
+ img = GP_FilterRotate270_Alloc(img, &callback);
+ break;
+ }
+
+ if (img == NULL)
+ return;
+
+ uint32_t cx = (context->w - img->w)/2;
+ uint32_t cy = (context->h - img->h)/2;
+
+ GP_Context sub_display;
+
+ cpu_timer_start(&timer, "Blitting");
+
+ if (params->use_dithering) {
+ callback.priv = "Dithering";
+ GP_SubContext(context, &sub_display, cx, cy, img->w, img->h);
+ GP_FilterFloydSteinberg_RGB888(img, &sub_display, NULL);
+ // GP_FilterHilbertPeano_RGB888(img, &sub_display, NULL);
+ } else {
+ GP_Blit_Raw(img, 0, 0, img->w, img->h, context, cx, cy);
+ }
+
+ cpu_timer_stop(&timer);
+
+ if (params->rotate)
+ GP_ContextFree(img);
+
+ /* clean up the rest of the display */
+ GP_FillRectXYWH(context, 0, 0, cx, context->h, black_pixel);
+ GP_FillRectXYWH(context, 0, 0, context->w, cy, black_pixel);
+ GP_FillRectXYWH(context, img->w + cx, 0, context->w - img->w - cx, context->h, black_pixel);
+ GP_FillRectXYWH(context, 0, img->h + cy, context->w, context->h - img->h - cy, black_pixel);
+
+ set_caption(params->img_path, rat);
+
+ if (!params->show_info) {
+ GP_BackendFlip(backend);
+ return;
+ }
+
+ GP_Size th = GP_TextHeight(NULL);
+
+ GP_Print(context, NULL, 11, 11, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
+ black_pixel, white_pixel, "%ux%u", img->w, img->h);
+
+ GP_Print(context, NULL, 10, 10, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
+ white_pixel, black_pixel, "%ux%u", img->w, img->h);
+
+ GP_Print(context, NULL, 11, 13 + th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
+ black_pixel, white_pixel, "1:%3.3f", rat);
+
+ GP_Print(context, NULL, 10, 12 + th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
+ white_pixel, black_pixel, "1:%3.3f", rat);
+
+ GP_Print(context, NULL, 11, 15 + 2 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
+ black_pixel, white_pixel, "%s", img_name(params->img_path));
+
+ GP_Print(context, NULL, 10, 14 + 2 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
+ white_pixel, black_pixel, "%s", img_name(params->img_path));
+
+ GP_BackendFlip(backend);
+}
+
GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size h, float rat)
{
long cookie = (w & 0xffff) | (h & 0xffff)<<16;
@@ -185,6 +282,15 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size
if ((img = load_image(params, 1)) == NULL)
return NULL;
+ if (params->show_nn_first) {
+ /* Do simple interpolation and blit the result */
+ GP_Context *nn = GP_FilterResizeNNAlloc(img, w, h, NULL);
+ if (nn != NULL) {
+ update_display(params, nn, rat);
+ GP_ContextFree(nn);
+ }
+ }
+
/* Do low pass filter */
if (resampling_method != GP_INTERP_LINEAR_LF_INT && rat < 1) {
cpu_timer_start(&timer, "Blur");
@@ -246,9 +352,8 @@ static int resize_backend_and_blit(struct loader_params *params)
static void *image_loader(void *ptr)
{
struct loader_params *params = ptr;
- struct cpu_timer timer, sum_timer;
+ struct cpu_timer sum_timer;
GP_Context *img, *context = backend->context;
- GP_ProgressCallback callback = {.callback = image_loader_callback};
cpu_timer_start(&sum_timer, "sum");
@@ -258,7 +363,7 @@ static void *image_loader(void *ptr)
/* Figure out rotation */
GP_Size w, h;
- switch (rotate) {
+ switch (params->rotate) {
case 0:
case 180:
default:
@@ -288,84 +393,10 @@ static void *image_loader(void *ptr)
image_cache_print(params->img_resized_cache);
image_cache_print(params->img_orig_cache);
- switch (rotate) {
- case 0:
- break;
- case 90:
- callback.priv = "Rotating image (90)";
- img = GP_FilterRotate90_Alloc(img, &callback);
- break;
- case 180:
- callback.priv = "Rotating image (180)";
- img = GP_FilterRotate180_Alloc(img, &callback);
- break;
- case 270:
- callback.priv = "Rotating image (270)";
- img = GP_FilterRotate270_Alloc(img, &callback);
- break;
- }
-
- if (img == NULL)
- return NULL;
-
- uint32_t cx = (context->w - img->w)/2;
- uint32_t cy = (context->h - img->h)/2;
-
- GP_Context sub_display;
-
- cpu_timer_start(&timer, "Blitting");
+ update_display(params, img, rat);
- if (dithering) {
- callback.priv = "Dithering";
- GP_SubContext(context, &sub_display, cx, cy, img->w, img->h);
- // GP_FilterFloydSteinberg_RGB888(ret, &sub_display, NULL);
- GP_FilterHilbertPeano_RGB888(img, &sub_display, NULL);
- } else {
- GP_Blit_Raw(img, 0, 0, img->w, img->h, context, cx, cy);
- }
-
- cpu_timer_stop(&timer);
-
- if (rotate)
- GP_ContextFree(img);
-
- /* clean up the rest of the display */
- GP_FillRectXYWH(context, 0, 0, cx, context->h, black_pixel);
- GP_FillRectXYWH(context, 0, 0, context->w, cy, black_pixel);
- GP_FillRectXYWH(context, img->w + cx, 0, context->w - img->w - cx, context->h, black_pixel);
- GP_FillRectXYWH(context, 0, img->h + cy, context->w, context->h - img->h - cy, black_pixel);
-
cpu_timer_stop(&sum_timer);
-
- set_caption(params->img_path, rat);
-
- if (!params->show_info) {
- GP_BackendFlip(backend);
- return NULL;
- }
-
- GP_Size th = GP_TextHeight(NULL);
-
- GP_Print(context, NULL, 11, 11, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
- black_pixel, white_pixel, "%ux%u", w, h);
-
- GP_Print(context, NULL, 10, 10, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
- white_pixel, black_pixel, "%ux%u", w, h);
- GP_Print(context, NULL, 11, 13 + th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
- black_pixel, white_pixel, "1:%3.3f", rat);
-
- GP_Print(context, NULL, 10, 12 + th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
- white_pixel, black_pixel, "1:%3.3f", rat);
-
- GP_Print(context, NULL, 11, 15 + 2 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
- black_pixel, white_pixel, "%s", img_name(params->img_path));
-
- GP_Print(context, NULL, 10, 14 + 2 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM,
- white_pixel, black_pixel, "%s", img_name(params->img_path));
-
- GP_BackendFlip(backend);
-
return NULL;
}
@@ -505,6 +536,9 @@ static void init_caches(struct loader_params *params)
params->img_resized_cache = image_cache_create(resized_size);
params->img_orig_cache = image_cache_create(orig_size);
+
+// params->img_resized_cache = NULL;
+// params->img_orig_cache = NULL;
}
int main(int argc, char *argv[])
@@ -512,9 +546,23 @@ int main(int argc, char *argv[])
GP_Context *context = NULL;
const char *backend_opts = "X11";
int sleep_sec = -1;
- struct loader_params params = {NULL, 0, 0, 0, NULL, NULL};
int opt, debug_level = 0;
GP_PixelType emul_type = GP_PIXEL_UNKNOWN;
+
+ struct loader_params params = {
+ .img_path = NULL,
+
+ .rotate = 0,
+
+ .show_progress = 0,
+ .show_progress_once = 0,
+ .show_info = 0,
+ .show_nn_first = 0,
+ .use_dithering = 0,
+
+ .img_resized_cache = NULL,
+ .img_orig_cache = NULL,
+ };
while ((opt = getopt(argc, argv, "b:cd:e:fIPs:r:")) != -1) {
switch (opt) {
@@ -525,13 +573,15 @@ int main(int argc, char *argv[])
params.show_progress = 1;
break;
case 'f':
- dithering = 1;
+ params.use_dithering = 1;
break;
case 's':
sleep_sec = atoi(optarg);
break;
case 'c':
resampling_method = GP_INTERP_CUBIC_INT;
+ /* Cubic resampling is slow, show nn first */
+ params.show_nn_first = 1;
break;
case 'd':
debug_level = atoi(optarg);
@@ -546,11 +596,11 @@ int main(int argc, char *argv[])
break;
case 'r':
if (!strcmp(optarg, "90"))
- rotate = 90;
+ params.rotate = 90;
else if (!strcmp(optarg, "180"))
- rotate = 180;
+ params.rotate = 180;
else if (!strcmp(optarg, "270"))
- rotate = 270;
+ params.rotate = 270;
case 'b':
backend_opts = optarg;
break;
@@ -622,9 +672,9 @@ int main(int argc, char *argv[])
params.show_progress = !params.show_progress;
break;
case GP_KEY_R:
- rotate += 90;
- if (rotate > 270)
- rotate = 0;
+ params.rotate += 90;
+ if (params.rotate > 270)
+ params.rotate = 0;
params.show_progress_once = 1;
show_image(¶ms, NULL);
http://repo.or.cz/w/gfxprim.git/commit/0223a7dca0a58c112f3b60100e0e5f66de52…
commit 0223a7dca0a58c112f3b60100e0e5f66de5263d1
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 18:16:30 2012 +0200
filters: Add generated Nearest Neighbour filter.
diff --git a/include/filters/GP_Resize.h b/include/filters/GP_Resize.h
index fe6afbf..1c84f2c 100644
--- a/include/filters/GP_Resize.h
+++ b/include/filters/GP_Resize.h
@@ -56,6 +56,15 @@
#include "GP_Filter.h"
+/* Nearest Neighbour */
+int GP_FilterResizeNN(const GP_Context *src, GP_Context *dst,
+ GP_ProgressCallback *callback);
+
+GP_Context *GP_FilterResizeNNAlloc(const GP_Context *src,
+ GP_Size w, GP_Size h,
+ GP_ProgressCallback *callback);
+
+
typedef enum GP_InterpolationType {
GP_INTERP_NN, /* Nearest Neighbour */
GP_INTERP_LINEAR_INT, /* Bilinear - fixed point arithmetics */
diff --git a/libs/core/GP_Context.c b/libs/core/GP_Context.c
index 88a0298..85530d1 100644
--- a/libs/core/GP_Context.c
+++ b/libs/core/GP_Context.c
@@ -276,7 +276,7 @@ void GP_ContextPrintInfo(const GP_Context *self)
printf("Offsett%u (only unaligned pixel types)n", self->offset);
printf("Flagstaxes_swap=%u x_swap=%u y_swap=%u free_pixels=%un",
self->axes_swap, self->x_swap, self->y_swap, self->free_pixels);
- printf("Gamma table %p", self->gamma);
+ printf("Gamma table %pn", self->gamma);
}
/*
diff --git a/libs/filters/GP_Resize.c b/libs/filters/GP_Resize.c
index 5f42da5..a1c0d71 100644
--- a/libs/filters/GP_Resize.c
+++ b/libs/filters/GP_Resize.c
@@ -30,45 +30,35 @@
#include "GP_Resize.h"
-int GP_FilterInterpolate_NN(const GP_Context *src, GP_Context *dst,
- GP_ProgressCallback *callback)
-{
- uint32_t xmap[dst->w];
- uint32_t ymap[dst->h];
- uint32_t i;
- GP_Coord x, y;
-
- GP_DEBUG(1, "Scaling image %ux%u -> %ux%u %2.2f %2.2f",
- src->w, src->h, dst->w, dst->h,
- 1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
+int GP_FilterResizeNN_Raw(const GP_Context *src, GP_Context *dst,
+ GP_ProgressCallback *callback);
- /* Pre-compute mapping for interpolation */
- uint32_t xstep = (src->w << 16) / dst->w;
+int GP_FilterResizeNN(const GP_Context *src, GP_Context *dst,
+ GP_ProgressCallback *callback)
+{
+ GP_ASSERT(src->pixel_type == dst->pixel_type);
- for (i = 0; i < dst->w + 1; i++)
- xmap[i] = ((i * xstep) + (1<<15)) >> 16;
-
- uint32_t ystep = (src->h << 16) / dst->h;
+ return GP_FilterResizeNN_Raw(src, dst, callback);
+}
- for (i = 0; i < dst->h + 1; i++)
- ymap[i] = ((i * ystep) + (1<<15)) >> 16;
+GP_Context *GP_FilterResizeNNAlloc(const GP_Context *src,
+ GP_Size w, GP_Size h,
+ GP_ProgressCallback *callback)
+{
+ GP_Context *res = GP_ContextAlloc(w, h, src->pixel_type);
- /* Interpolate */
- for (y = 0; y < (GP_Coord)dst->h; y++) {
- for (x = 0; x < (GP_Coord)dst->w; x++) {
- GP_Pixel pix = GP_GetPixel_Raw_24BPP(src, xmap[x], ymap[y]);
+ if (res == NULL)
+ return NULL;
- GP_PutPixel_Raw_24BPP(dst, x, y, pix);
- }
-
- if (GP_ProgressCallbackReport(callback, y, dst->h, dst->w))
- return 1;
+ if (GP_FilterResizeNN_Raw(src, res, callback)) {
+ GP_ContextFree(res);
+ return NULL;
}
- GP_ProgressCallbackDone(callback);
- return 0;
+ return res;
}
+
#define A 0.5
static float cubic(float x)
@@ -725,7 +715,7 @@ int GP_FilterResize_Raw(const GP_Context *src, GP_Context *dst,
{
switch (type) {
case GP_INTERP_NN:
- return GP_FilterInterpolate_NN(src, dst, callback);
+ return GP_FilterResizeNN_Raw(src, dst, callback);
case GP_INTERP_LINEAR_INT:
return GP_FilterInterpolate_LinearInt(src, dst, callback);
case GP_INTERP_LINEAR_LF_INT:
diff --git a/libs/filters/GP_ResizeNN.gen.c.t b/libs/filters/GP_ResizeNN.gen.c.t
new file mode 100644
index 0000000..7719efb
--- /dev/null
+++ b/libs/filters/GP_ResizeNN.gen.c.t
@@ -0,0 +1,75 @@
+%% extends "filter.c.t"
+
+{% block descr %}Nearest Neighbour resampling{% endblock %}
+
+%% block body
+
+#include "core/GP_Context.h"
+#include "core/GP_GetPutPixel.h"
+
+#include "core/GP_Debug.h"
+
+#include "GP_Resize.h"
+
+%% for pt in pixeltypes
+%% if not pt.is_unknown()
+
+static int GP_FilterResizeNN_{{ pt.name }}_Raw(const GP_Context *src,
+ GP_Context *dst, GP_ProgressCallback *callback)
+{
+ uint32_t xmap[dst->w];
+ uint32_t ymap[dst->h];
+ uint32_t i;
+ GP_Coord x, y;
+
+ GP_DEBUG(1, "Scaling image %ux%u -> %ux%u %2.2f %2.2f",
+ src->w, src->h, dst->w, dst->h,
+ 1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
+
+ /* Pre-compute mapping for interpolation */
+ uint32_t xstep = (src->w << 16) / dst->w;
+
+ for (i = 0; i < dst->w + 1; i++)
+ xmap[i] = ((i * xstep) + (1<<15)) >> 16;
+
+ uint32_t ystep = (src->h << 16) / dst->h;
+
+ for (i = 0; i < dst->h + 1; i++)
+ ymap[i] = ((i * ystep) + (1<<15)) >> 16;
+
+ /* Interpolate */
+ for (y = 0; y < (GP_Coord)dst->h; y++) {
+ for (x = 0; x < (GP_Coord)dst->w; x++) {
+ GP_Pixel pix = GP_GetPixel_Raw_{{ pt.pixelsize.suffix }}(src, xmap[x], ymap[y]);
+
+ GP_PutPixel_Raw_{{ pt.pixelsize.suffix }}(dst, x, y, pix);
+ }
+
+ if (GP_ProgressCallbackReport(callback, y, dst->h, dst->w))
+ return 1;
+ }
+
+ GP_ProgressCallbackDone(callback);
+ return 0;
+}
+
+%% endif
+%% endfor
+
+int GP_FilterResizeNN_Raw(const GP_Context *src, GP_Context *dst,
+ GP_ProgressCallback *callback)
+{
+ switch (src->pixel_type) {
+ %% for pt in pixeltypes
+ %% if not pt.is_unknown()
+ case GP_PIXEL_{{ pt.name }}:
+ return GP_FilterResizeNN_{{ pt.name }}_Raw(src, dst, callback);
+ break;
+ %% endif
+ %% endfor
+ default:
+ return -1;
+ }
+}
+
+%% endblock body
diff --git a/libs/filters/Makefile b/libs/filters/Makefile
index 49993aa..1470e55 100644
--- a/libs/filters/Makefile
+++ b/libs/filters/Makefile
@@ -8,8 +8,10 @@ POINT_FILTERS=GP_Contrast.gen.c GP_Brightness.gen.c GP_Invert.gen.c ARITHMETIC_FILTERS=GP_Difference.gen.c GP_Addition.gen.c GP_Min.gen.c GP_Max.gen.c GP_Multiply.gen.c
+RESAMPLING_FILTERS=GP_ResizeNN.gen.c
+
GENSOURCES=GP_MirrorV.gen.c GP_Rotate.gen.c GP_FloydSteinberg.gen.c GP_HilbertPeano.gen.c- $(POINT_FILTERS) $(ARITHMETIC_FILTERS) $(STATS_FILTERS)
+ $(POINT_FILTERS) $(ARITHMETIC_FILTERS) $(STATS_FILTERS) $(RESAMPLING_FILTERS)
CSOURCES=$(filter-out $(wildcard *.gen.c),$(wildcard *.c))
LIBNAME=filters
http://repo.or.cz/w/gfxprim.git/commit/5bc6361309104e85c8a54add16ca23554bf6…
commit 5bc6361309104e85c8a54add16ca23554bf65827
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 17:37:27 2012 +0200
spiv: Make image cache functions No-Op when cache pointer is NULL.
Spiv is not ready for the change though.
diff --git a/demos/spiv/image_cache.c b/demos/spiv/image_cache.c
index 4cb194f..924c392 100644
--- a/demos/spiv/image_cache.c
+++ b/demos/spiv/image_cache.c
@@ -155,6 +155,9 @@ GP_Context *image_cache_get(struct image_cache *self, const char *path,
long cookie1, long cookie2, int elevate)
{
struct image *i;
+
+ if (self == NULL)
+ return NULL;
GP_DEBUG(2, "Looking for image '%s:%10li:%10li'", path, cookie1, cookie2);
@@ -186,6 +189,11 @@ void image_cache_print(struct image_cache *self)
{
struct image *i;
+ if (self == NULL) {
+ printf("Image cache disabledn");
+ return;
+ }
+
printf("Image cache size %u used %un", self->max_size, self->cur_size);
for (i = self->root; i != NULL; i = i->next)
@@ -214,7 +222,12 @@ static int assert_size(struct image_cache *self, size_t size)
int image_cache_put(struct image_cache *self, GP_Context *ctx, const char *path,
long cookie1, long cookie2)
{
- size_t size = image_size2(ctx, path);
+ size_t size;
+
+ if (self == NULL)
+ return 1;
+
+ size = image_size2(ctx, path);
if (assert_size(self, size))
return 1;
@@ -242,8 +255,11 @@ int image_cache_put(struct image_cache *self, GP_Context *ctx, const char *path,
void image_cache_drop(struct image_cache *self)
{
+ if (self == NULL)
+ return;
+
GP_DEBUG(1, "Dropping images in cache");
-
+
while (self->end != NULL)
remove_img_free(self, self->end, 0);
@@ -252,8 +268,11 @@ void image_cache_drop(struct image_cache *self)
void image_cache_destroy(struct image_cache *self)
{
+ if (self == NULL)
+ return;
+
GP_DEBUG(1, "Destroying image cache");
-
+
while (self->end != NULL)
remove_img_free(self, self->end, 0);
-----------------------------------------------------------------------
Summary of changes:
demos/spiv/image_cache.c | 25 +++-
demos/spiv/spiv.c | 339 +++++++++++++++++++++++++-------------
include/filters/GP_Resize.h | 12 ++
libs/core/GP_Context.c | 2 +-
libs/filters/GP_Resize.c | 93 +++++------
libs/filters/GP_ResizeNN.gen.c.t | 74 ++++++++
libs/filters/Makefile | 4 +-
7 files changed, 382 insertions(+), 167 deletions(-)
create mode 100644 libs/filters/GP_ResizeNN.gen.c.t
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 4dad87b8900261ecaadbc43dedb932683089b414
by metan 17 Jun '12
by metan 17 Jun '12
17 Jun '12
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 4dad87b8900261ecaadbc43dedb932683089b414 (commit)
via 84a1d252db8cd13901a64caa34bf68d543c99828 (commit)
from 986b9dbf07932b754d452f84271e0a28c5bfd684 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/4dad87b8900261ecaadbc43dedb932683089…
commit 4dad87b8900261ecaadbc43dedb932683089b414
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 15:58:23 2012 +0200
git: Add more gitignore files.
diff --git a/demos/c_simple/.gitignore b/demos/c_simple/.gitignore
new file mode 100644
index 0000000..a9d725a
--- /dev/null
+++ b/demos/c_simple/.gitignore
@@ -0,0 +1,9 @@
+backend_example
+filters_symmetry
+gfx_koch
+loaders
+loaders_example
+meta_data
+meta_data_dump
+tmp_file
+virtual_backend_example
diff --git a/demos/grinder/.gitignore b/demos/grinder/.gitignore
new file mode 100644
index 0000000..f2b8012
--- /dev/null
+++ b/demos/grinder/.gitignore
@@ -0,0 +1 @@
+grinder
diff --git a/demos/particle/.gitignore b/demos/particle/.gitignore
new file mode 100644
index 0000000..c1293c9
--- /dev/null
+++ b/demos/particle/.gitignore
@@ -0,0 +1 @@
+particle_demo
diff --git a/demos/spiv/.gitignore b/demos/spiv/.gitignore
new file mode 100644
index 0000000..71f7841
--- /dev/null
+++ b/demos/spiv/.gitignore
@@ -0,0 +1 @@
+spiv
diff --git a/demos/ttf2img/.gitignore b/demos/ttf2img/.gitignore
new file mode 100644
index 0000000..2d22d83
--- /dev/null
+++ b/demos/ttf2img/.gitignore
@@ -0,0 +1 @@
+ttf2img
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000..2d19fc7
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1 @@
+*.html
http://repo.or.cz/w/gfxprim.git/commit/84a1d252db8cd13901a64caa34bf68d543c9…
commit 84a1d252db8cd13901a64caa34bf68d543c99828
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 17 15:50:38 2012 +0200
core, filters: Add initial version of gamma correction.
* This commit introduces concept of per-context per-channel
gamma correction.
* The GP_Context structure gets a new pointer to GP_Gamma
structure that describes gamma values and tables for
each individual context channel.
* One of the resampling algorithms gets experimental support
for gamma tables.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index 11d24bf..d6b3da3 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -159,7 +159,7 @@ GP_Context *load_image(struct loader_params *params, int elevate)
GP_ContextFree(img);
img = tmp;
}
-
+
image_cache_put(params->img_orig_cache, img, params->img_path, 0, 0);
cpu_timer_stop(&timer);
@@ -196,13 +196,22 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size
return NULL;
img = res;
+
+ // img->gamma = GP_GammaAcquire(img->pixel_type, 2.2);
cpu_timer_stop(&timer);
+ } else {
+ // img->gamma = GP_GammaAcquire(img->pixel_type, 2.2);
}
cpu_timer_start(&timer, "Resampling");
callback.priv = "Resampling Image";
- img = GP_FilterResize(img, NULL, resampling_method, w, h, &callback);
+ GP_Context *i1 = GP_FilterResize(img, NULL, resampling_method, w, h, &callback);
+// img->gamma = NULL;
+// GP_Context *i2 = GP_FilterResize(img, NULL, resampling_method, w, h, &callback);
+// img = GP_FilterDifferenceAlloc(i2, i1, NULL);
+// img = GP_FilterInvert(img, NULL, NULL);
+ img = i1;
cpu_timer_stop(&timer);
/* Free low passed context if needed */
diff --git a/include/core/GP_Context.h b/include/core/GP_Context.h
index feed975..9de8572 100644
--- a/include/core/GP_Context.h
+++ b/include/core/GP_Context.h
@@ -33,6 +33,8 @@
#include "GP_Types.h"
#include "GP_Pixel.h"
+struct GP_Gamma;
+
/* This structure holds all information needed for drawing into an image. */
typedef struct GP_Context {
uint8_t *pixels; /* pointer to image pixels */
@@ -47,7 +49,19 @@ typedef struct GP_Context {
*/
uint8_t offset;
- enum GP_PixelType pixel_type; /* pixel format */
+ /*
+ * Pixel format. See GP_Pixel.gen.h and GP_Pixel.gen.c.
+ */
+ enum GP_PixelType pixel_type;
+
+ /*
+ * Pointer to optional Gamma table.
+ *
+ * If NULL, the channel values are considered linear.
+ *
+ * See GP_GammaCorrection.h.
+ */
+ struct GP_Gamma *gamma;
/*
* Image orientation. Most common is landscape (0, 0, 0),
diff --git a/include/core/GP_Core.h b/include/core/GP_Core.h
index 3987d07..987196e 100644
--- a/include/core/GP_Core.h
+++ b/include/core/GP_Core.h
@@ -41,6 +41,9 @@
/* ... and it's trasformations */
#include "core/GP_Transform.h"
+/* Gamma */
+#include "core/GP_Gamma.h"
+
/* Pixeltypes */
#include "core/GP_Pixel.h"
diff --git a/include/core/GP_Gamma.h b/include/core/GP_Gamma.h
new file mode 100644
index 0000000..a4112a7
--- /dev/null
+++ b/include/core/GP_Gamma.h
@@ -0,0 +1,174 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+/*
+
+ Gamma correction.
+
+ What is gamma and what is it doing in my computer?
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ First of all gamma is a function, or better there is a gamma function and
+ it's inverse function. Both gamma function and it's inverse are defined on
+ interval [0,1] and are defined as out = in^(gamma) and it's inverse as
+ out = in^(1/gamma).
+
+ The purpose of this function is to compensate nonlinearity of human eye
+ perception. The human eye is more sensitive to dark tones than the light ones
+ so without gamma correction storage and manipulation with image data would
+ either be less efficient in space (in case you decided to use more bits and
+ encode the image lineary) or quantization in darker tones would be more
+ visible resulting in "pixelated" images (aliasing).
+
+ So there is a gamma, the internet seems to suggest that usual values for
+ gamma are 2.5 for old CRT monitors and about 2.2 for LCD ones, ideally you
+ should have color profile for your device (you need special hardware to
+ measure it). So if you are trying to draw linear gradient on the screen
+ you need to generate sequence of numbers accordinly to gamma function
+ (the 50% intensity is around 186 for gamma = 2.2 and 8bit grayscale pixel).
+
+ Moreover image formats tend to save data in nonlinear fashion (some formats
+ include gama value used to for the image) so before you apply filter that
+ manipulates with pixel values, you need to convert it to linear space (adding
+ some more bits to compensate for rounding errors).
+
+ Also it's important to take gamma, into an accound, when drawing anti aliased
+ shapes, you can't get right results otherwise.
+
+ */
+
+ /*
+
+ This code implements management functions for easy, per context, per
+ channel, gamma tables.
+
+ The tables for particular gamma are reference counted. There is only one
+ table for particulal gamma value and bit depth in memory at a time.
+
+ Also the table output, for linear values, has two more bits than original in
+ order not to loose precision.
+
+ The pointers to gamma tables are storied in GP_Gamma structure the pointers
+ are organized in the same order as channes. First N tables for each channel
+ and gamma value gamma, then N tables for inverse 1/gamma function.
+
+ So when we have RGB888 pixel and gamma 2.2 there are two tables in the
+ memory, one for gamma 2.2 input 8bit output 10bit and it's inverse input
+ 10bit output 8bit. The GP_Gamma contains six pointers. First three points to
+ the gamma table for gamma 2.2 whith 8bit input (256 array members) and the
+ output format is 10bits so each array member is uint16_t. The other three
+ are for inverse gamma funcion (gamma = 0.454545...) with 10bit input (1024
+ array members) and 8bit output so each member is uint8_t.
+
+ The whole interface is designed for speed, so that conversion to linear
+ space or from linear space is just a matter of indexing arrays. Imagine you
+ need to get gamma-corrected pixel value. First you take individual pixel
+ channels then use the GP_Gamma structure as follows:
+
+ gamma->tables[chan_number].u16[chan_val]
+
+ or when result has no more than 8bits
+
+ gamma->tables[chan_number].u8[chan_val]
+
+ The inverse transformation is done as:
+
+ gamma->tables[chan_count + chan_number].u8[chan_val]
+
+ of when original pixel channel had more than 8bits
+
+ gamma->tables[chan_count + chan_number].u16[chan_val]
+
+ When doing more than one conversion it's better to save pointers to
+ individual table (example for RGB888):
+
+ uint16_t *R2Lin = gamma->tables[0].u16;
+ ...
+ uint8_t *R2Gamma = gamma->tables[3].u8;
+ ...
+
+ */
+
+#ifndef CORE_GP_GAMMA_H
+#define CORE_GP_GAMMA_H
+
+#include <stdint.h>
+
+#include "GP_Context.h"
+
+/*
+ * Gamma table.
+ */
+typedef struct GP_GammaTable {
+ /* Table description */
+ float gamma;
+ uint8_t in_bits;
+ uint8_t out_bits;
+
+ /* Used for internal purpose */
+ unsigned int ref_count;
+ struct GP_GammaTable *next;
+
+ /* The table itself */
+ union {
+ uint8_t u8[0];
+ uint16_t u16[0];
+ };
+} GP_GammaTable;
+
+/*
+ * Gamma structure for general pixel type.
+ *
+ * The GP_Gamma structure contains pointers to tables for each pixel
+ * channel and for gamma and it's inverse transfomation.
+ *
+ * The interface is specialy designed so that getting Gamma corrected value is
+ * a matter of indexing two arrays.
+ */
+typedef struct GP_Gamma {
+ GP_PixelType pixel_type;
+
+ unsigned int ref_count;
+
+ GP_GammaTable *tables[];
+} GP_Gamma;
+
+/*
+ * Returns pointer to a gamma translation table, the same gamma is used for all
+ * channels.
+ *
+ * May fail, in case malloc() has failed.
+ */
+GP_Gamma *GP_GammaAcquire(GP_PixelType pixel_type, float gamma);
+
+/*
+ * Copies Gamma table (actually increases ref_count) so it's fast and can't
+ * fail.
+ */
+GP_Gamma *GP_GammaCopy(GP_Gamma *gamma);
+
+/*
+ * Releases gamma table.
+ */
+void GP_GammaRelease(GP_Gamma *self);
+
+#endif /* CORE_GP_GAMMA_H */
diff --git a/include/core/GP_GammaCorrection.h b/include/core/GP_GammaCorrection.h
index e06ab9a..6c47687 100644
--- a/include/core/GP_GammaCorrection.h
+++ b/include/core/GP_GammaCorrection.h
@@ -61,6 +61,8 @@
#include <stdint.h>
-#include "core/GP_GammaCorrection.gen.h"
+#include "GP_Context.h"
+
+#include "GP_GammaCorrection.gen.h"
#endif /* CORE_GP_GAMMA_CORRECTION_H */
diff --git a/include/core/GP_GammaPixel.gen.h.t b/include/core/GP_GammaPixel.gen.h.t
new file mode 100644
index 0000000..3c8f832
--- /dev/null
+++ b/include/core/GP_GammaPixel.gen.h.t
@@ -0,0 +1,73 @@
+%% extends "base.h.t"
+
+{% block descr %}Gamma correction for pixels.{% endblock %}
+
+%% block body
+
+#include "GP_Context.h"
+#include "GP_GammaCorrection.h"
+
+%% for pt in pixeltypes
+%% if not pt.is_unknown() and not pt.is_palette()
+%% set idx = 0
+
+%% for c in pt.chanslist
+
+/*
+ * Converts gamma encoded pixel value to linear value.
+ *
+ * Parameters are, converted value and GP_Gamma structure.
+ */
+#define GP_Gamma2Lin_{{ pt.name }}_{{ c[0] }}(val, gamma) ({ +%% if c[2] > 6
+ gamma->tables[{{ idx }}]->u16[val]; +%% else
+ gamma->tables[{{ idx }}]->u8[val]; +%% endif
+})
+
+/*
+ * Converts linear encoded pixel into gamma encoded pixel.
+ *
+ * Parameters are, converted value and GP_Gamma structure.
+ */
+#define GP_Lin2Gamma_{{ pt.name }}_{{ c[0] }}(val, gamma) ({ +%% if c[2] > 8
+ gamma->tables[{{ len(pt.chanslist) + idx}}]->u16[val]; +%% else
+ gamma->tables[{{ len(pt.chanslist) + idx}}]->u8[val]; +%% endif
+})
+
+static inline GP_GammaTable *GP_GammaTable_{{ pt.name }}_{{ c[0] }}(GP_Gamma *gamma)
+{
+ return gamma->tables[{{ idx }}];
+}
+
+static inline GP_GammaTable *GP_GammaInverseTable_{{ pt.name }}_{{ c[0] }}(GP_Gamma *gamma)
+{
+ return gamma->tables[{{ len(pt.chanslist) + idx }}];
+}
+
+%% set idx = idx + 1
+%% endfor
+%% endif
+%% endfor
+
+#define GP_Gamma2Lin(val, chan_bits, gamma_table) ({ +#if chan_bits > 6
+ gamma_table->u16[val] +#else
+ gamma_table->u8[val] +#endif
+})
+
+#define GP_Lin2Gamma(val, chan_bits, gamma_table) ({ +#if chan_bits > 8
+ gamma_table->table16[val] +#else
+ gamma_table->table8[val] +#endif
+})
+
+%% endblock body
diff --git a/include/core/Makefile b/include/core/Makefile
index 340958b..c68d42e 100644
--- a/include/core/Makefile
+++ b/include/core/Makefile
@@ -1,7 +1,7 @@
TOPDIR=../..
GENHEADERS=GP_Convert_Scale.gen.h GP_Pixel.gen.h GP_GetPutPixel.gen.h GP_Convert.gen.h GP_FnPerBpp.gen.h - GP_MixPixels.gen.h GP_GammaCorrection.gen.h
+ GP_MixPixels.gen.h GP_GammaCorrection.gen.h GP_GammaPixel.gen.h
LIBNAME=core
include $(TOPDIR)/pre.mk
diff --git a/libs/core/GP_Context.c b/libs/core/GP_Context.c
index ee7cc2d..88a0298 100644
--- a/libs/core/GP_Context.c
+++ b/libs/core/GP_Context.c
@@ -30,6 +30,7 @@
#include "GP_Transform.h"
#include "GP_Pixel.h"
#include "GP_GetPutPixel.h"
+#include "GP_GammaCorrection.h"
#include "GP_Context.h"
#include "GP_Blit.h"
@@ -65,6 +66,8 @@ GP_Context *GP_ContextAlloc(GP_Size w, GP_Size h, GP_PixelType type)
context->w = w;
context->h = h;
+ context->gamma = NULL;
+
context->pixel_type = type;
#warning Hmm, bit endianity... Why is not this settled by different pixel types?
context->bit_endian = 0;
@@ -87,6 +90,9 @@ void GP_ContextFree(GP_Context *context)
if (context->free_pixels)
free(context->pixels);
+ if (context->gamma)
+ GP_GammaRelease(context->gamma);
+
free(context);
}
@@ -106,6 +112,8 @@ GP_Context *GP_ContextInit(GP_Context *context, GP_Size w, GP_Size h,
context->pixel_type = type;
context->bit_endian = 0;
+
+ context->gamma = NULL;
/* rotation and mirroring */
GP_ContextSetRotation(context, 0, 0, 0);
@@ -172,6 +180,9 @@ GP_Context *GP_ContextCopy(const GP_Context *src, int flags)
else
GP_ContextSetRotation(new, 0, 0, 0);
+ //TODO: Copy the gamma too
+ new->gamma = NULL;
+
new->free_pixels = 1;
return new;
@@ -239,6 +250,9 @@ GP_Context *GP_SubContext(const GP_Context *context, GP_Context *subcontext,
subcontext->pixel_type = context->pixel_type;
subcontext->bit_endian = context->bit_endian;
+
+ /* gamma */
+ subcontext->gamma = context->gamma;
/* rotation and mirroring */
GP_ContextCopyRotation(context, subcontext);
@@ -262,6 +276,7 @@ void GP_ContextPrintInfo(const GP_Context *self)
printf("Offsett%u (only unaligned pixel types)n", self->offset);
printf("Flagstaxes_swap=%u x_swap=%u y_swap=%u free_pixels=%un",
self->axes_swap, self->x_swap, self->y_swap, self->free_pixels);
+ printf("Gamma table %p", self->gamma);
}
/*
diff --git a/libs/core/GP_Gamma.c b/libs/core/GP_Gamma.c
new file mode 100644
index 0000000..b1f113c
--- /dev/null
+++ b/libs/core/GP_Gamma.c
@@ -0,0 +1,199 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <math.h>
+
+#include "GP_Pixel.h"
+#include "GP_Debug.h"
+
+#include "GP_Gamma.h"
+
+static GP_GammaTable *tables = NULL;
+
+static void fill_table8(GP_GammaTable *table, float gamma,
+ uint8_t in_bits, uint8_t out_bits)
+{
+ unsigned int i;
+ unsigned int in_max = (1<<in_bits) - 1;
+ unsigned int out_max = (1<<out_bits) - 1;
+
+ GP_DEBUG(3, "Initalizing gamma table %f", gamma);
+
+ for (i = 0; i < (1U<<in_bits); i++)
+ table->u8[i] = pow((float)i / in_max, gamma) * out_max + 0.5;
+}
+
+static void fill_table16(GP_GammaTable *table, float gamma,
+ uint8_t in_bits, uint8_t out_bits)
+{
+ unsigned int i;
+ unsigned int in_max = (1<<in_bits) - 1;
+ unsigned int out_max = (1<<out_bits) - 1;
+
+ GP_DEBUG(3, "Initalizing gamma table %f", gamma);
+
+ for (i = 0; i < (1U<<in_bits); i++)
+ table->u16[i] = pow((float)i / in_max, gamma) * out_max + 0.5;
+}
+
+static GP_GammaTable *get_table(float gamma, uint8_t in_bits, uint8_t out_bits)
+{
+ GP_GammaTable *i;
+
+ for (i = tables; i != NULL; i = i->next)
+ if (gamma == i->gamma && in_bits == i->in_bits &&
+ out_bits == i->out_bits)
+ break;
+
+ if (i != NULL) {
+ GP_DEBUG(2, "Found Gamma table Gamma %f, in_bits %u, "
+ "out_bits %u, ref_count %u", i->gamma, i->in_bits,
+ i->out_bits, i->ref_count);
+ i->ref_count++;
+ return i;
+ }
+
+ GP_DEBUG(2, "Creating Gamma table Gamma %f, in_bits %u, out_bits %u",
+ gamma, in_bits, out_bits);
+
+ i = malloc(sizeof(GP_GammaTable) + (1U<<in_bits) * (out_bits > 8 ? 2 : 1));
+
+ if (i == NULL) {
+ GP_WARN("Malloc failed :(");
+ return NULL;
+ }
+
+ i->gamma = gamma;
+ i->in_bits = in_bits;
+ i->out_bits = out_bits;
+ i->ref_count = 1;
+
+ if (out_bits > 8)
+ fill_table16(i, gamma, in_bits, out_bits);
+ else
+ fill_table8(i, gamma, in_bits, out_bits);
+
+ /* Insert it into link list */
+ i->next = tables;
+ tables = i;
+
+ return i;
+}
+
+static void put_table(GP_GammaTable *table)
+{
+ if (table == NULL)
+ return;
+
+ table->ref_count--;
+
+ GP_DEBUG(2, "Putting gamma table Gamma %f, in_bits %u, out_bits %u, "
+ "ref_count %u", table->gamma, table->in_bits, table->out_bits,
+ table->ref_count);
+
+ if (table->ref_count == 0) {
+ GP_DEBUG(2, "Gamma table ref_count == 0, removing...");
+
+ GP_GammaTable *i, *prev = NULL;
+
+ /* Remove from link list and free */
+ for (i = tables; i != NULL; i = i->next) {
+ if (table == i)
+ break;
+ prev = i;
+ }
+
+ if (prev == NULL)
+ tables = table->next;
+ else
+ prev->next = table->next;
+
+ free(table);
+ }
+}
+
+GP_Gamma *GP_GammaAcquire(GP_PixelType pixel_type, float gamma)
+{
+ GP_CHECK_VALID_PIXELTYPE(pixel_type);
+ int channels = GP_PixelTypes[pixel_type].numchannels, i;
+
+ GP_DEBUG(1, "Acquiring Gamma table %s gamma %f", GP_PixelTypeName(pixel_type), gamma);
+
+ GP_Gamma *res = malloc(sizeof(struct GP_Gamma) + 2 * channels * sizeof(void*));
+
+ if (res == NULL) {
+ GP_WARN("Malloc failed :(");
+ return NULL;
+ }
+
+ /* NULL the pointers */
+ for (i = 0; i < 2 * channels; i++)
+ res->tables[i] = NULL;
+
+ res->pixel_type = pixel_type;
+ res->ref_count = 1;
+
+ /* Gamma to linear tables n bits -> n + 2 bits */
+ for (i = 0; i < channels; i++) {
+ unsigned int chan_size = GP_PixelTypes[pixel_type].channels[i].size;
+ res->tables[i] = get_table(gamma, chan_size, chan_size + 2);
+
+ if (res->tables[i] == NULL) {
+ GP_GammaRelease(res);
+ return NULL;
+ }
+ }
+
+ /* And reverse tables, n + 2 bits -> n bits */
+ for (i = 0; i < channels; i++) {
+ unsigned int chan_size = GP_PixelTypes[pixel_type].channels[i].size;
+ res->tables[i + channels] = get_table(1/gamma, chan_size + 2, chan_size);
+
+ if (res->tables[i] == NULL) {
+ GP_GammaRelease(res);
+ return NULL;
+ }
+ }
+
+ return res;
+}
+
+GP_Gamma *GP_GammaCopy(GP_Gamma *self)
+{
+ self->ref_count++;
+ return self;
+}
+
+void GP_GammaRelease(GP_Gamma *self)
+{
+ int channels = GP_PixelTypes[self->pixel_type].numchannels, i;
+
+ GP_DEBUG(1, "Releasing Gamma table %s gamma %f", GP_PixelTypeName(self->pixel_type), self->tables[0]->gamma);
+
+ for (i = 0; i < channels; i++)
+ put_table(self->tables[i]);
+
+ if (--self->ref_count == 0) {
+ GP_DEBUG(2, "Gamma ref_count == 0, releasing...");
+ free(self);
+ }
+}
diff --git a/libs/filters/GP_Resize.c b/libs/filters/GP_Resize.c
index 81db9ed..5f42da5 100644
--- a/libs/filters/GP_Resize.c
+++ b/libs/filters/GP_Resize.c
@@ -22,12 +22,13 @@
#include <math.h>
-#include <GP_Context.h>
-#include <GP_GetPutPixel.h>
+#include "core/GP_Context.h"
+#include "core/GP_GetPutPixel.h"
+#include "core/GP_Gamma.h"
-#include <GP_Debug.h>
+#include "core/GP_Debug.h"
-#include <GP_Resize.h>
+#include "GP_Resize.h"
int GP_FilterInterpolate_NN(const GP_Context *src, GP_Context *dst,
GP_ProgressCallback *callback)
@@ -246,7 +247,7 @@ int GP_FilterInterpolate_Cubic(const GP_Context *src, GP_Context *dst,
return 0;
}
-#define MUL 2048
+#define MUL 1024
#define MUL_I(a, b) ({ a[0] *= b[0]; @@ -258,6 +259,8 @@ int GP_FilterInterpolate_Cubic(const GP_Context *src, GP_Context *dst,
#define SUM_I(a) ((a)[0] + (a)[1] + (a)[2] + (a)[3])
+#include "core/GP_GammaCorrection.h"
+
int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
GP_ProgressCallback *callback)
{
@@ -268,6 +271,24 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
src->w, src->h, dst->w, dst->h,
1.00 * dst->w / src->w, 1.00 * dst->h / src->h);
+ uint16_t *R_2_LIN = NULL;
+ uint16_t *G_2_LIN = NULL;
+ uint16_t *B_2_LIN = NULL;
+
+ uint8_t *R_2_GAMMA = NULL;
+ uint8_t *G_2_GAMMA = NULL;
+ uint8_t *B_2_GAMMA = NULL;
+
+ if (src->gamma) {
+ R_2_LIN = src->gamma->tables[0]->u16;
+ G_2_LIN = src->gamma->tables[1]->u16;
+ B_2_LIN = src->gamma->tables[2]->u16;
+
+ R_2_GAMMA = src->gamma->tables[3]->u8;
+ G_2_GAMMA = src->gamma->tables[4]->u8;
+ B_2_GAMMA = src->gamma->tables[5]->u8;
+ }
+
for (i = 0; i < dst->h; i++) {
float y = (1.00 * i / dst->h) * src->h;
int32_t cvy[4];
@@ -306,7 +327,7 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
rv[1] = GP_Pixel_GET_R_RGB888(pix[1]);
rv[2] = GP_Pixel_GET_R_RGB888(pix[2]);
rv[3] = GP_Pixel_GET_R_RGB888(pix[3]);
-
+
gv[0] = GP_Pixel_GET_G_RGB888(pix[0]);
gv[1] = GP_Pixel_GET_G_RGB888(pix[1]);
gv[2] = GP_Pixel_GET_G_RGB888(pix[2]);
@@ -316,6 +337,24 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
bv[1] = GP_Pixel_GET_B_RGB888(pix[1]);
bv[2] = GP_Pixel_GET_B_RGB888(pix[2]);
bv[3] = GP_Pixel_GET_B_RGB888(pix[3]);
+
+
+ if (src->gamma) {
+ rv[0] = R_2_LIN[rv[0]];
+ rv[1] = R_2_LIN[rv[1]];
+ rv[2] = R_2_LIN[rv[2]];
+ rv[3] = R_2_LIN[rv[3]];
+
+ gv[0] = G_2_LIN[gv[0]];
+ gv[1] = G_2_LIN[gv[1]];
+ gv[2] = G_2_LIN[gv[2]];
+ gv[3] = G_2_LIN[gv[3]];
+
+ bv[0] = G_2_LIN[bv[0]];
+ bv[1] = G_2_LIN[bv[1]];
+ bv[2] = G_2_LIN[bv[2]];
+ bv[3] = G_2_LIN[bv[3]];
+ }
MUL_I(rv, cvy);
MUL_I(gv, cvy);
@@ -374,10 +413,30 @@ int GP_FilterInterpolate_CubicInt(const GP_Context *src, GP_Context *dst,
r = (SUM_I(rv) + MUL*MUL/2) / MUL / MUL;
g = (SUM_I(gv) + MUL*MUL/2) / MUL / MUL;
b = (SUM_I(bv) + MUL*MUL/2) / MUL / MUL;
-
- CLAMP(r);
- CLAMP(g);
- CLAMP(b);
+
+ if (src->gamma) {
+ if (r > 1023)
+ r = 1023;
+ if (g > 1023)
+ g = 1023;
+ if (b > 1023)
+ b = 1023;
+
+ if (r < 0)
+ r = 0;
+ if (g < 0)
+ g = 0;
+ if (b < 0)
+ b = 0;
+
+ r = R_2_GAMMA[r];
+ g = G_2_GAMMA[g];
+ b = B_2_GAMMA[b];
+ } else {
+ CLAMP(r);
+ CLAMP(g);
+ CLAMP(b);
+ }
GP_Pixel pix = GP_Pixel_CREATE_RGB888((uint8_t)r, (uint8_t)g, (uint8_t)b);
GP_PutPixel_Raw_24BPP(dst, j, i, pix);
-----------------------------------------------------------------------
Summary of changes:
demos/c_simple/.gitignore | 9 ++
demos/grinder/.gitignore | 1 +
demos/particle/.gitignore | 1 +
demos/spiv/.gitignore | 1 +
demos/spiv/spiv.c | 13 ++-
demos/ttf2img/.gitignore | 1 +
doc/.gitignore | 1 +
include/core/GP_Context.h | 16 +++-
include/core/GP_Core.h | 3 +
include/core/GP_Gamma.h | 174 +++++++++++++++++++++++++++++++
include/core/GP_GammaCorrection.h | 4 +-
include/core/GP_GammaPixel.gen.h.t | 73 +++++++++++++
include/core/Makefile | 2 +-
libs/core/GP_Context.c | 15 +++
libs/core/GP_Gamma.c | 199 ++++++++++++++++++++++++++++++++++++
libs/filters/GP_Resize.c | 79 +++++++++++++--
16 files changed, 577 insertions(+), 15 deletions(-)
create mode 100644 demos/c_simple/.gitignore
create mode 100644 demos/grinder/.gitignore
create mode 100644 demos/particle/.gitignore
create mode 100644 demos/spiv/.gitignore
create mode 100644 demos/ttf2img/.gitignore
create mode 100644 doc/.gitignore
create mode 100644 include/core/GP_Gamma.h
create mode 100644 include/core/GP_GammaPixel.gen.h.t
create mode 100644 libs/core/GP_Gamma.c
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 986b9dbf07932b754d452f84271e0a28c5bfd684
by metan 12 Jun '12
by metan 12 Jun '12
12 Jun '12
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 986b9dbf07932b754d452f84271e0a28c5bfd684 (commit)
via 910f02b31ebb40a594febaa6069b77c569568123 (commit)
from bcb2459351a67a9e7e5eabaf1fe081cc1aa724bd (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/986b9dbf07932b754d452f84271e0a28c5bf…
commit 986b9dbf07932b754d452f84271e0a28c5bfd684
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jun 12 22:37:31 2012 +0200
loaders: Add TmpFile interface.
diff --git a/demos/c_simple/Makefile b/demos/c_simple/Makefile
index 22efd37..44926f8 100644
--- a/demos/c_simple/Makefile
+++ b/demos/c_simple/Makefile
@@ -6,7 +6,7 @@ INCLUDE=
LDLIBS+=-lGP -lGP_backends -lSDL -L$(TOPDIR)/build/
APPS=backend_example loaders_example loaders filters_symmetry gfx_koch- virtual_backend_example meta_data meta_data_dump
+ virtual_backend_example meta_data meta_data_dump tmp_file
include $(TOPDIR)/pre.mk
include $(TOPDIR)/app.mk
diff --git a/include/loaders/GP_Loaders.h b/demos/c_simple/tmp_file.c
similarity index 51%
copy from include/loaders/GP_Loaders.h
copy to demos/c_simple/tmp_file.c
index c7aab95..99becbc 100644
--- a/include/loaders/GP_Loaders.h
+++ b/demos/c_simple/tmp_file.c
@@ -16,63 +16,95 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos *
- * <jiri.bluebear.dluhos(a)gmail.com> *
- * *
* Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
/*
- Core include file for loaders API.
+ Tmp file is interface for storing GP_Context data on disk in uncompressed
+ fast but non-portable format (more or less GP_Context dump).
*/
-#ifndef LOADERS_GP_LOADERS_H
-#define LOADERS_GP_LOADERS_H
-
-#include "core/GP_Context.h"
-#include "core/GP_ProgressCallback.h"
-
-#include "GP_PBM.h"
-#include "GP_PGM.h"
-#include "GP_PPM.h"
-
-#include "GP_BMP.h"
-#include "GP_PNG.h"
-#include "GP_JPG.h"
-#include "GP_GIF.h"
-
-#include "GP_MetaData.h"
-
-/*
- * Tries to load image accordingly to the file extension.
- *
- * If operation fails NULL is returned and errno is filled.
- */
-GP_Context *GP_LoadImage(const char *src_path, GP_ProgressCallback *callback);
-
-/*
- * Loads image Meta Data (if possible).
- */
-int GP_LoadMetaData(const char *src_path, GP_MetaData *data);
-
-/*
- * Simple saving function, the image format is matched by file extension.
- *
- * Retruns zero on succes.
- *
- * On failure non-zero is returned.
- *
- * When file type wasn't recognized by extension or if support for requested
- * image format wasn't compiled in non-zero is returned and errno is set to
- * ENOSYS.
- *
- * The resulting errno may also be set to any possible error from fopen(3), open(3),
- * write(3), fwrite(3), seek(3), etc..
- */
-int GP_SaveImage(const GP_Context *src, const char *dst_path,
- GP_ProgressCallback *callback);
-
-#endif /* LOADERS_GP_LOADERS_H */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <GP.h>
+
+struct callback_priv {
+ char *op;
+ char *name;
+};
+
+static int progress_callback(GP_ProgressCallback *self)
+{
+ struct callback_priv *priv = self->priv;
+
+ printf("r%s '%s' %3.1f%%", priv->op, priv->name, self->percentage);
+ fflush(stdout);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ GP_Context *img;
+ struct callback_priv priv;
+ GP_ProgressCallback callback = {.callback = progress_callback,
+ .priv = &priv};
+
+ if (argc != 2) {
+ fprintf(stderr, "Takes an image as an parametern");
+ return 1;
+ }
+
+ priv.op = "Loading";
+ priv.name = argv[1];
+
+ img = GP_LoadImage(argv[1], &callback);
+
+ if (img == NULL) {
+ fprintf(stderr, "Failed to load image '%s':%sn", argv[1],
+ strerror(errno));
+ return 1;
+ }
+
+ printf("n");
+
+ priv.op = "Saving";
+ priv.name = "tmp.gfx";
+
+ if (GP_SaveTmpFile(img, priv.name, &callback)) {
+ fprintf(stderr, "Failed to save temp file %sn", strerror(errno));
+ return 1;
+ }
+
+ printf("n");
+
+ GP_ContextFree(img);
+
+ priv.op = "Loading";
+
+ img = GP_LoadTmpFile(priv.name, &callback);
+
+ if (img == NULL) {
+ fprintf(stderr, "Failed to load temp file %sn", strerror(errno));
+ return 1;
+ }
+
+ priv.op = "Saving";
+ priv.name = "out.png";
+
+ printf("n");
+
+ if (GP_SavePNG(img, "out.png", &callback)) {
+ fprintf(stderr, "Failed to save image %sn", strerror(errno));
+ return 1;
+ }
+
+ printf("n");
+
+ return 0;
+}
diff --git a/include/loaders/GP_Loaders.h b/include/loaders/GP_Loaders.h
index c7aab95..ab0f4ef 100644
--- a/include/loaders/GP_Loaders.h
+++ b/include/loaders/GP_Loaders.h
@@ -44,6 +44,8 @@
#include "GP_JPG.h"
#include "GP_GIF.h"
+#include "GP_TmpFile.h"
+
#include "GP_MetaData.h"
/*
diff --git a/include/loaders/GP_Loaders.h b/include/loaders/GP_TmpFile.h
similarity index 56%
copy from include/loaders/GP_Loaders.h
copy to include/loaders/GP_TmpFile.h
index c7aab95..fe1f8d1 100644
--- a/include/loaders/GP_Loaders.h
+++ b/include/loaders/GP_TmpFile.h
@@ -16,63 +16,43 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
- * Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos *
- * <jiri.bluebear.dluhos(a)gmail.com> *
- * *
* Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
/*
-
- Core include file for loaders API.
+
+ This is interface for saving GP_Context into non-portable uncompressed file,
+ which is usefull for caching GP_Context to disk.
*/
-#ifndef LOADERS_GP_LOADERS_H
-#define LOADERS_GP_LOADERS_H
+#ifndef LOADERS_GP_TMP_FILE_H
+#define LOADERS_GP_TMP_FILE_H
#include "core/GP_Context.h"
#include "core/GP_ProgressCallback.h"
-#include "GP_PBM.h"
-#include "GP_PGM.h"
-#include "GP_PPM.h"
-
-#include "GP_BMP.h"
-#include "GP_PNG.h"
-#include "GP_JPG.h"
-#include "GP_GIF.h"
-
-#include "GP_MetaData.h"
-
/*
- * Tries to load image accordingly to the file extension.
+ * The possible errno values:
*
- * If operation fails NULL is returned and errno is filled.
+ * - Anything FILE operation may return (fopen(), fclose(), fseek(), ...).
+ * - EIO for fread()/fwrite() failure
+ * - ENOMEM from malloc()
+ * - ECANCELED when call was aborted from callback
*/
-GP_Context *GP_LoadImage(const char *src_path, GP_ProgressCallback *callback);
/*
- * Loads image Meta Data (if possible).
+ * Opens up and loads file.
+ *
+ * On failure NULL is returned and errno is set.
*/
-int GP_LoadMetaData(const char *src_path, GP_MetaData *data);
+GP_Context *GP_LoadTmpFile(const char *src_path, GP_ProgressCallback *callback);
/*
- * Simple saving function, the image format is matched by file extension.
- *
- * Retruns zero on succes.
- *
- * On failure non-zero is returned.
- *
- * When file type wasn't recognized by extension or if support for requested
- * image format wasn't compiled in non-zero is returned and errno is set to
- * ENOSYS.
- *
- * The resulting errno may also be set to any possible error from fopen(3), open(3),
- * write(3), fwrite(3), seek(3), etc..
+ * Saves context into a file. On failure non-zero is returned and errno is set.
*/
-int GP_SaveImage(const GP_Context *src, const char *dst_path,
- GP_ProgressCallback *callback);
+int GP_SaveTmpFile(const GP_Context *src, const char *dst_path,
+ GP_ProgressCallback *callback);
-#endif /* LOADERS_GP_LOADERS_H */
+#endif /* LOADERS_GP_TMP_FILE_H */
diff --git a/libs/loaders/GP_TmpFile.c b/libs/loaders/GP_TmpFile.c
new file mode 100644
index 0000000..9d4a412
--- /dev/null
+++ b/libs/loaders/GP_TmpFile.c
@@ -0,0 +1,176 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include "core/GP_Debug.h"
+
+#include "GP_TmpFile.h"
+
+const char file_sig[] = {'G', 'F', 'X', 'p', 'r', 'i', 'm'};
+
+GP_Context *GP_LoadTmpFile(const char *src_path, GP_ProgressCallback *callback)
+{
+ FILE *f;
+ uint32_t w, h, y;
+ uint8_t offset, flags;
+ uint32_t bpr;
+ enum GP_PixelType pixel_type;
+ char sig[sizeof(file_sig)];
+ GP_Context *ret;
+ int err;
+
+ f = fopen(src_path, "r");
+
+ if (f == NULL)
+ return NULL;
+
+ /* Read an signature */
+ if (fread(sig, sizeof(sig), 1, f) != 1) {
+ err = EIO;
+ goto err0;
+ }
+
+ if (strncmp(sig, file_sig, sizeof(sig))) {
+ GP_WARN("Invalid file '%s' signature", src_path);
+ err = EINVAL;
+ goto err0;
+ }
+
+ /* Read context metadata */
+ fread(&w, sizeof(w), 1, f);
+ fread(&h, sizeof(h), 1, f);
+ fread(&offset, sizeof(offset), 1, f);
+ fread(&bpr, sizeof(bpr), 1, f);
+ fread(&pixel_type, sizeof(pixel_type), 1, f);
+ fread(&flags, 1, 1, f);
+
+ if (ferror(f)) {
+ err = EIO;
+ goto err0;
+ }
+
+ ret = GP_ContextAlloc(w, h, pixel_type);
+
+ if (ret == NULL) {
+ err = errno;
+ goto err0;
+ }
+
+ //TODO: We may disagree here on ill aligned subcontexts
+ GP_ASSERT(ret->bytes_per_row == bpr, "Invalid bytes per row");
+
+ ret->offset = offset;
+
+ /* And pixels */
+ for (y = 0; y < h; y++) {
+ if (fread(ret->pixels + bpr * y, bpr, 1, f) != 1) {
+ err = EIO;
+ goto err1;
+ }
+
+ GP_ProgressCallbackReport(callback, y, h, w);
+ }
+
+ /* Set the rotation flags */
+ if (flags & 0x01)
+ ret->axes_swap = 1;
+
+ if (flags & 0x02)
+ ret->x_swap = 1;
+
+ if (flags & 0x04)
+ ret->y_swap = 1;
+
+ fclose(f);
+
+ GP_ProgressCallbackDone(callback);
+
+ return ret;
+err1:
+ GP_ContextFree(ret);
+err0:
+ fclose(f);
+ errno = err;
+ return NULL;
+}
+
+int GP_SaveTmpFile(const GP_Context *src, const char *dst_path,
+ GP_ProgressCallback *callback)
+{
+ FILE *f;
+ int err;
+ uint32_t y;
+
+ f = fopen(dst_path, "w");
+
+ if (f == NULL)
+ return 1;
+
+ /* Write a signature */
+ fwrite(file_sig, sizeof(file_sig), 1, f);
+
+ /* Write block of metadata */
+ fwrite(&src->w, sizeof(src->w), 1, f);
+ fwrite(&src->h, sizeof(src->h), 1, f);
+ fwrite(&src->offset, sizeof(src->offset), 1, f);
+ fwrite(&src->bytes_per_row, sizeof(src->bytes_per_row), 1, f);
+ fwrite(&src->pixel_type, sizeof(src->pixel_type), 1, f);
+
+ uint8_t flags = 0;
+
+ if (src->axes_swap)
+ flags |= 0x01;
+
+ if (src->x_swap)
+ flags |= 0x02;
+
+ if (src->y_swap)
+ flags |= 0x04;
+
+ fwrite(&flags, 1, 1, f);
+
+ /* And pixels */
+ for (y = 0; y < src->h; y++) {
+ if (fwrite(src->pixels + src->bytes_per_row * y, src->bytes_per_row, 1, f) != 1) {
+ err = EIO;
+ goto err1;
+ }
+
+ GP_ProgressCallbackReport(callback, y, src->h, src->w);
+ }
+
+ if (fclose(f))
+ goto err0;
+
+ GP_ProgressCallbackDone(callback);
+
+ return 0;
+err1:
+ fclose(f);
+err0:
+ unlink(dst_path);
+ errno = err;
+ return 1;
+}
http://repo.or.cz/w/gfxprim.git/commit/910f02b31ebb40a594febaa6069b77c56956…
commit 910f02b31ebb40a594febaa6069b77c569568123
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jun 12 21:50:42 2012 +0200
core: Make sure Context functions set errno on failure.
diff --git a/libs/core/GP_Context.c b/libs/core/GP_Context.c
index 3cf3ecf..ee7cc2d 100644
--- a/libs/core/GP_Context.c
+++ b/libs/core/GP_Context.c
@@ -23,6 +23,9 @@
* *
*****************************************************************************/
+#include <errno.h>
+#include <string.h>
+
#include "GP_Debug.h"
#include "GP_Transform.h"
#include "GP_Pixel.h"
@@ -30,8 +33,6 @@
#include "GP_Context.h"
#include "GP_Blit.h"
-#include <string.h>
-
static uint32_t get_bpr(uint32_t bpp, uint32_t w)
{
return (bpp * w) / 8 + !!((bpp * w) % 8);
@@ -52,6 +53,7 @@ GP_Context *GP_ContextAlloc(GP_Size w, GP_Size h, GP_PixelType type)
free(pixels);
free(context);
GP_WARN("Malloc failed :(");
+ errno = ENOMEM;
return NULL;
}
@@ -146,6 +148,7 @@ GP_Context *GP_ContextCopy(const GP_Context *src, int flags)
free(pixels);
free(new);
GP_WARN("Malloc failed :(");
+ errno = ENOMEM;
return NULL;
}
@@ -209,6 +212,7 @@ GP_Context *GP_SubContextAlloc(const GP_Context *context,
if (res == NULL) {
GP_WARN("Malloc failed :(");
+ errno = ENOMEM;
return NULL;
}
-----------------------------------------------------------------------
Summary of changes:
demos/c_simple/Makefile | 2 +-
demos/c_simple/{loaders.c => tmp_file.c} | 31 ++++-
include/loaders/GP_Loaders.h | 2 +
include/loaders/{GP_GIF.h => GP_TmpFile.h} | 33 +++---
libs/core/GP_Context.c | 8 +-
libs/loaders/GP_TmpFile.c | 176 ++++++++++++++++++++++++++++
6 files changed, 225 insertions(+), 27 deletions(-)
copy demos/c_simple/{loaders.c => tmp_file.c} (81%)
copy include/loaders/{GP_GIF.h => GP_TmpFile.h} (72%)
create mode 100644 libs/loaders/GP_TmpFile.c
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: bcb2459351a67a9e7e5eabaf1fe081cc1aa724bd
by metan 12 Jun '12
by metan 12 Jun '12
12 Jun '12
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via bcb2459351a67a9e7e5eabaf1fe081cc1aa724bd (commit)
via 42be3cae59405f7867c489e4be12f85c40e4a54e (commit)
via dbcb0965a2d31e572ab897d23ca4cbc14377fc02 (commit)
via 5df856f5af17bd0922b99fc21c1236f01f3d2f27 (commit)
via 5261b44a10e5bcf3d7abd86d97076161449b2ef4 (commit)
via e1e008bfb7e62140b69da17b0a6b30eed15de653 (commit)
via 4fddc1754f1d4f739c318adb305041595efbfa1f (commit)
via 79adf5cfb66ddd38140c64f8015be735bad2a985 (commit)
via ca0579cff49cfb79bcc2382c4508a8c5aef6f04e (commit)
via d082267d9e82e53500d0989dbc158a1725cc68b4 (commit)
via 6a75eaa20c6561c387c324b8013e1ff04517b33b (commit)
via 382a79d9e517a63ab444030f0003c045c3c55d17 (commit)
from f5c3fdd85dc385b05af7f41ede836a6074fb4c3c (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/bcb2459351a67a9e7e5eabaf1fe081cc1aa7…
commit bcb2459351a67a9e7e5eabaf1fe081cc1aa724bd
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jun 12 21:00:55 2012 +0200
build: Add gfxprim-config into the .gitignore
diff --git a/.gitignore b/.gitignore
index 7d18a2b..7007e36 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@
*.a
config.h
config.gen.mk
+gfxprim-config
http://repo.or.cz/w/gfxprim.git/commit/42be3cae59405f7867c489e4be12f85c40e4…
commit 42be3cae59405f7867c489e4be12f85c40e4a54e
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jun 12 18:49:05 2012 +0200
core: Slight cleanup in GP_Context.
The most notable changes are:
* Split the subcontext API into two functions
* Split the ContextConvert API into two functions
* Added inline helpers for rotation flags handling
* Added GP_ContextPrintInfo() function
+ Various cleanups and fixups.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index 72d8595..11d24bf 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -154,7 +154,8 @@ GP_Context *load_image(struct loader_params *params, int elevate)
/* Workaround */
if (img->pixel_type != GP_PIXEL_RGB888) {
- GP_Context *tmp = GP_ContextConvert(img, GP_PIXEL_RGB888);
+ GP_Context *tmp;
+ tmp = GP_ContextConvertAlloc(img, GP_PIXEL_RGB888);
GP_ContextFree(img);
img = tmp;
}
@@ -307,7 +308,7 @@ static void *image_loader(void *ptr)
if (dithering) {
callback.priv = "Dithering";
- GP_ContextSubContext(context, &sub_display, cx, cy, img->w, img->h);
+ GP_SubContext(context, &sub_display, cx, cy, img->w, img->h);
// GP_FilterFloydSteinberg_RGB888(ret, &sub_display, NULL);
GP_FilterHilbertPeano_RGB888(img, &sub_display, NULL);
} else {
diff --git a/doc/context.txt b/doc/context.txt
index 809f995..f92473c 100644
--- a/doc/context.txt
+++ b/doc/context.txt
@@ -1,7 +1,7 @@
Drawing Context
---------------
-The 'GP_Context' structure describes a bitmap in memory. It contains all
+The 'GP_Context' structure describes an 'in memory' memory. It contains all
metadata needed for drawing into a bitmap.
Data Structure
@@ -22,7 +22,7 @@ typedef struct GP_Context {
*/
uint8_t offset;
- GP_PixelType pixel_type; /* pixel format enum */
+ enum GP_PixelType pixel_type; /* pixel format */
uint8_t axes_swap:1; /* swap axes */
uint8_t x_swap:1; /* mirror x */
@@ -42,8 +42,8 @@ Rotation
The orientation flags affects the gfx and text drawing functions and blits. If
some of the flags is changed the origin and direction of the drawing is
-changed. Note that the image pixels are not affected by this at all only the
-coordinates passed to drawing functions are transformed accordingly.
+changed accordingly. Note that the image pixels are not affected by this at
+all only the coordinates passed to drawing functions are transformed.
If you don't need this functionality just don't touch the flags the as
overhead of these transformations is not measurable.
@@ -81,12 +81,28 @@ GP_RETRANSFORM_POINT(context, x, y)
/*
* Rotate context flags clock wise.
*/
-void GP_ContextFlagsRotateCW(GP_Context *context);
+void GP_ContextRotateCW(GP_Context *context);
/*
* Rotate context flags counter clock wise.
*/
-void GP_ContextFlagsRotateCCW(GP_Context *context);
+void GP_ContextRotateCCW(GP_Context *context);
+
+/*
+ * Retruns 1 if rotation flags are equal.
+ */
+int GP_ContextRotationEqual(const GP_Context *c1, const GP_Context *c2);
+
+/*
+ * Sets context rotation flags.
+ */
+void GP_ContextSetRotation(GP_Context *dst, int axes_swap,
+ int x_swap, int y_swap);
+
+/*
+ * Copies rotation flags.
+ */
+void GP_ContextCopyRotation(const GP_Context *src, GP_Context *dst);
/*
* Returns context width and height taking the rotation flags into the account.
@@ -104,8 +120,8 @@ Basic context functions
/* or */
#include <GP.h>
-void GP_ContextInit(GP_Context *context, GP_Size w, GP_Size h,
- GP_PixelType type, void *pixels);
+GP_Context *GP_ContextInit(GP_Context *context, GP_Size w, GP_Size h,
+ GP_PixelType type, void *pixels);
-------------------------------------------------------------------------------
Initialize given context accordingly to parameters, the rest of context
@@ -116,6 +132,9 @@ bytes per row are computed from the given pixel type and size.
The 'pixels' pointer can be 'NULL' and can be changed later manually (the call
will *not* try to allocate the pixel memory automatically).
+The function returns a pointer to the initialized context (i.e. the same
+pointer you passed as second argument).
+
[source,c]
-------------------------------------------------------------------------------
#include <core/GP_Context.h>
@@ -138,13 +157,34 @@ appropriate size; the initial contents of the bitmap are undefined.
/* or */
#include <GP.h>
-GP_Context *GP_ContextCopy(const GP_Context *src, int flag);
+enum GP_ContextCopyFlags {
+ /*
+ * Copy bitmap pixels too. If not set pixels are uninitialized.
+ */
+ GP_COPY_WITH_PIXELS = 0x01,
+ /*
+ * Copy image rotation flags. If not set flags are set to (0, 0, 0).
+ */
+ GP_COPY_WITH_ROTATION = 0x02,
+};
+
+GP_Context *GP_ContextCopy(const GP_Context *src, int flags);
-------------------------------------------------------------------------------
The 'GP_ContextCopy()' allocates and initializes a copy of the context passed
-as argument. If 'flag' is set, the bitmap contents ('src->pixels')
-are also copied; otherwise the copy will have the same dimensions but
-undefined contents.
+as arguments.
+
+The call returns pointer to newly allocated context or in case of 'malloc()'
+failure NULL.
+
+If 'GP_COPY_WITH_PIXELS' is set, the bitmap contents ('src->pixels') are also
+copied; otherwise the copy will have the same dimensions but undefined
+contents.
+
+If 'GP_COPY_WITH_ROTATION' is set rotation flags are copied; otherwise rotation
+flags are set to zero.
+
+The 'free_pixels' flag for the resulting context is set.
[source,c]
-------------------------------------------------------------------------------
@@ -163,10 +203,16 @@ Subcontext
A subcontext is a context that refers to a rectangular area within another
context. Subcontexts can be used as any other context (including creating
-another subcontexts).
+another subcontexts). Generally the subcontexts behave exactly as any other
+contexts with one exception, if you create several overlapping subcontexts the
+results may be unexpected.
-Calling 'GP_ContextFree()' on a subcontext is safe; the bitmap is not freed as
-it belongs to another context; it will be freed with the hosting context.
+Calling 'GP_ContextFree()' on a allocated subcontext is safe; the bitmap is not
+freed as it belongs to another context; it will be freed with the hosting
+context (i.e. the 'free_pixels' flag is not set when creating subcontext). On
+the other hand, the subcontext doesn't hold a reference to the original
+context, so once the parent context is freed the subcontext pixel pointer is
+not valid anymore.
[source,c]
-------------------------------------------------------------------------------
@@ -174,18 +220,23 @@ it belongs to another context; it will be freed with the hosting context.
/* or */
#include <GP.h>
-GP_Context *GP_ContextSubContext(GP_Context *context, GP_Context *subcontext,
- GP_Coord x, GP_Coord y, GP_Size w, GP_Size h);
+GP_Context *GP_SubContext(const GP_Context *context, GP_Context *subcontext,
+ GP_Coord x, GP_Coord y, GP_Size w, GP_Size h);
+
+GP_Context *GP_SubContextAlloc(const GP_Context *context,
+ GP_Coord x, GP_Coord y, GP_Size w, GP_Size h);
-------------------------------------------------------------------------------
Creates subcontext of a context. The rectangular area must fit into the context.
-If subcontext pointer is 'NULL', the context structure is allocated; otherwise
-the metadata are filled into the context structure pointed by subcontext
-pointer.
+The 'GP_SubContext()' function initializes the passed pointer as a subcontext
+of a context and returns pointer to initialized subcontext (i.e. the same
+pointer you passed as the subcontext parameter).
-In both cases, the call returns either a pointer to the new subcontext,
-or NULL on failure (when there is not enough memory).
+The 'GP_SubContextAlloc()' function allocates 'GP_Context' structure and
+initializes it as a subcontext. This function may return NULL in case of
+'malloc()' failure and the newly created context should be later freed with
+'GP_ContextFree()'.
Conversions
~~~~~~~~~~~
@@ -196,13 +247,30 @@ Conversions
/* or */
#include <GP.h>
-GP_Context *GP_ContextConvert(const GP_Context *src, GP_Context *dst,
- GP_PixelType dst_pixel_type);
+GP_Context *GP_ContextConvertAlloc(const GP_Context *src,
+ GP_PixelType dst_pixel_type);
+
+GP_Context *GP_ContextConvert(const GP_Context *src, GP_Context *dst);
+
-------------------------------------------------------------------------------
-Provides basic context conversion functionality. A newly allocated context is
-returned.
+Converts a context to different pixel type.
+
+This is naive implementation that only multiplies/divides the pixel values.
+
+To get a better result use dithering filters instead.
+
+Misc
+~~~~
-This function does no error distribution, it only multiplies or rounds the pixel
-values. If you need something better use Floyd Steinberg dithering instead.
+[source,c]
+-------------------------------------------------------------------------------
+#include <core/GP_Context.h>
+/* or */
+#include <GP.h>
+
+void GP_ContextPrintInfo(const GP_Context *self);
+-------------------------------------------------------------------------------
+This function prints the content of 'GP_Context' structure, in a readable
+format, into the stdout.
diff --git a/include/core/GP_Context.h b/include/core/GP_Context.h
index 494199a..feed975 100644
--- a/include/core/GP_Context.h
+++ b/include/core/GP_Context.h
@@ -36,7 +36,7 @@
/* This structure holds all information needed for drawing into an image. */
typedef struct GP_Context {
uint8_t *pixels; /* pointer to image pixels */
- uint8_t bpp; /* pixel length in bits */
+ uint8_t bpp; /* pixel size in bits */
uint32_t bytes_per_row;
uint32_t w; /* width in pixels */
uint32_t h; /* height in pixels */
@@ -47,14 +47,15 @@ typedef struct GP_Context {
*/
uint8_t offset;
- GP_PixelType pixel_type; /* hardware pixel format */
+ enum GP_PixelType pixel_type; /* pixel format */
- /* image orientation. Most common is landscape (0, 0, 0),
+ /*
+ * Image orientation. Most common is landscape (0, 0, 0),
* portrait with normal topleft corner is (1, 0, 0).
*/
uint8_t axes_swap:1; /* swap axes so that x is y and y is x */
- uint8_t x_swap:1; /* swap direction on x */
- uint8_t y_swap:1; /* swap direction on y */
+ uint8_t x_swap:1; /* swap direction on x */
+ uint8_t y_swap:1; /* swap direction on y */
uint8_t bit_endian:1; /* GP_BIT_ENDIAN */
uint8_t free_pixels:1; /* If set pixels are freed on GP_ContextFree */
} GP_Context;
@@ -87,54 +88,70 @@ typedef struct GP_Context {
|| (y) < 0 || y >= (typeof(y)) context->h)
/*
- * Check for exactly same rotation flags.
+ * Allocate context.
+ *
+ * The context consists of two parts, the GP_Context structure and pixels array.
+ *
+ * The rotation flags are set to (0, 0, 0).
*/
-#define GP_CONTEXT_ROTATION_EQUAL(c1, c2) - ((c1)->axes_swap == (c2)->axes_swap && - (c1)->x_swap == (c2)->x_swap && - (c1)->y_swap == (c2)->y_swap)
+GP_Context *GP_ContextAlloc(GP_Size w, GP_Size h, GP_PixelType type);
/*
- * Allocate context.
+ * Free context.
+ *
+ * If context->free_pixels, also free pixel data.
*/
-GP_Context *GP_ContextAlloc(GP_Size w, GP_Size h, GP_PixelType type);
+void GP_ContextFree(GP_Context *context);
/*
* Initalize context, pixels pointer is not dereferenced so it's safe to pass
* NULL there and allocate it later with size context->bpr * context->h.
+ *
+ * The returned pointer is the pointer you passed as first argument.
*/
-void GP_ContextInit(GP_Context *context, GP_Size w, GP_Size h,
- GP_PixelType type, void *pixels);
+GP_Context *GP_ContextInit(GP_Context *context, GP_Size w, GP_Size h,
+ GP_PixelType type, void *pixels);
/*
- * Resizes context->pixels array and changes metadata to match.
+ * Resizes context->pixels array and changes metadata to match the new size.
+ *
+ * Returns non-zero on failure (malloc() has failed).
*
- * Returns non-zero on failure (remalloc() has failed).
+ * This call only resizes the pixel array. The pixel values, after resizing,
+ * are __UNINITALIZED__ use resampling filters to resize image data.
*/
int GP_ContextResize(GP_Context *context, GP_Size w, GP_Size h);
+enum GP_ContextCopyFlags {
+ /*
+ * Copy bitmap pixels too. If not set pixels are uninitalized.
+ */
+ GP_COPY_WITH_PIXELS = 0x01,
+ /*
+ * Copy image rotation flags. If not set flags are set to (0, 0, 0).
+ */
+ GP_COPY_WITH_ROTATION = 0x02,
+};
+
/*
- * If passed the pixels are copied to newly created context, otherwise
- * the pixels are allocated but uninitalized.
+ * Allocates a contex with exactly same values as source context.
*/
-#define GP_COPY_WITH_PIXELS 1
+GP_Context *GP_ContextCopy(const GP_Context *src, int flags);
/*
- * Copy context.
+ * Initalize subcontext. The returned pointer points to passed subcontext.
*/
-GP_Context *GP_ContextCopy(const GP_Context *src, int flag);
+GP_Context *GP_SubContext(const GP_Context *context, GP_Context *subcontext,
+ GP_Coord x, GP_Coord y, GP_Size w, GP_Size h);
/*
- * Create subcontext.
+ * Allocate and initalize subcontext.
*
- * If pointer to subcontext is NULL, new context is allocated
- * otherwise context pointed by subcontext pointer is initalized.
- *
* The free_pixels flag is set to 0 upon subcontext initalization so the
* GP_ContextFree() would not call free() upon the subcontext->pixels pointer.
*/
-GP_Context *GP_ContextSubContext(GP_Context *context, GP_Context *subcontext,
- GP_Coord x, GP_Coord y, GP_Size w, GP_Size h);
+GP_Context *GP_SubContextAlloc(const GP_Context *context,
+ GP_Coord x, GP_Coord y, GP_Size w, GP_Size h);
/*
* Converts context to a different pixel type.
@@ -143,30 +160,64 @@ GP_Context *GP_ContextSubContext(GP_Context *context, GP_Context *subcontext,
* This is naive implementation that doesn't do any ditherings or error
* diffusions.
*/
-GP_Context *GP_ContextConvert(const GP_Context *src,
- GP_PixelType dst_pixel_type);
+GP_Context *GP_ContextConvertAlloc(const GP_Context *src,
+ GP_PixelType dst_pixel_type);
/*
- * Prints context information into stdout.
+ * Converts context to a different pixel type.
+ *
+ * This is naive implementation that doesn't do any ditherings or error
+ * diffusions.
*/
-void GP_ContextInfoPrint(const GP_Context *self);
+GP_Context *GP_ContextConvert(const GP_Context *src, GP_Context *dst);
/*
- * Free context.
- *
- * If context->free_pixels, also free pixel data.
+ * Prints context information into stdout.
*/
-void GP_ContextFree(GP_Context *context);
+void GP_ContextPrintInfo(const GP_Context *self);
/*
* Rotates context flags clock wise.
*/
-void GP_ContextFlagsRotateCW(GP_Context *context);
+void GP_ContextRotateCW(GP_Context *context);
/*
* Rotates context flags counter clock wise.
*/
-void GP_ContextFlagsRotateCCW(GP_Context *context);
+void GP_ContextRotateCCW(GP_Context *context);
+
+/*
+ * Retruns 1 if rotation flags are equal.
+ */
+static inline int GP_ContextRotationEqual(const GP_Context *c1,
+ const GP_Context *c2)
+{
+ return c1->axes_swap == c2->axes_swap &&
+ c1->x_swap == c2->x_swap &&
+ c1->y_swap == c2->y_swap;
+}
+
+/*
+ * Sets rotation flags.
+ */
+static inline void GP_ContextSetRotation(GP_Context *dst, int axes_swap,
+ int x_swap, int y_swap)
+{
+ dst->axes_swap = axes_swap;
+ dst->x_swap = x_swap;
+ dst->y_swap = y_swap;
+}
+
+/*
+ * Copies rotation flags.
+ */
+static inline void GP_ContextCopyRotation(const GP_Context *src,
+ GP_Context *dst)
+{
+ dst->axes_swap = src->axes_swap;
+ dst->x_swap = src->x_swap;
+ dst->y_swap = src->y_swap;
+}
/*
* Returns context width and height taking the rotation flags into a account.
diff --git a/libs/core/GP_Blit.c b/libs/core/GP_Blit.c
index eadfe1d..58e818a 100644
--- a/libs/core/GP_Blit.c
+++ b/libs/core/GP_Blit.c
@@ -77,7 +77,7 @@ void GP_BlitXYXY(const GP_Context *src,
GP_CHECK(x2 + (x1 - x0) < (GP_Coord)GP_ContextW(dst));
GP_CHECK(y2 + (y1 - y0) < (GP_Coord)GP_ContextH(dst));
- if (GP_CONTEXT_ROTATION_EQUAL(src, dst))
+ if (GP_ContextRotationEqual(src, dst))
GP_BlitXYXY_Raw_Fast(src, x0, y0, x1, y1, dst, x2, y2);
else
GP_BlitXYXY_Fast(src, x0, y0, x1, y1, dst, x2, y2);
@@ -138,7 +138,7 @@ void GP_BlitXYXY_Clipped(const GP_Context *src,
x0, y0, x1, y1, GP_ContextW(src), GP_ContextH(src),
x2, y2, GP_ContextW(dst), GP_ContextH(dst));
- if (GP_CONTEXT_ROTATION_EQUAL(src, dst))
+ if (GP_ContextRotationEqual(src, dst))
GP_BlitXYXY_Raw_Fast(src, x0, y0, x1, y1, dst, x2, y2);
else
GP_BlitXYXY_Fast(src, x0, y0, x1, y1, dst, x2, y2);
diff --git a/libs/core/GP_Context.c b/libs/core/GP_Context.c
index c7b2d89..3cf3ecf 100644
--- a/libs/core/GP_Context.c
+++ b/libs/core/GP_Context.c
@@ -19,57 +19,19 @@
* Copyright (C) 2009-2011 Jiri "BlueBear" Dluhos *
* <jiri.bluebear.dluhos(a)gmail.com> *
* *
- * Copyright (C) 2009-2011 Cyril Hrubis <metan(a)ucw.cz> *
+ * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
* *
*****************************************************************************/
-#include "GP_Core.h"
+#include "GP_Debug.h"
+#include "GP_Transform.h"
+#include "GP_Pixel.h"
+#include "GP_GetPutPixel.h"
+#include "GP_Context.h"
#include "GP_Blit.h"
#include <string.h>
-GP_Context *GP_ContextCopy(const GP_Context *src, int flag)
-{
- GP_Context *new;
- uint8_t *pixels;
-
- if (src == NULL)
- return NULL;
-
- new = malloc(sizeof(GP_Context));
- pixels = malloc(src->bytes_per_row * src->h);
-
- if (pixels == NULL || new == NULL) {
- free(pixels);
- free(new);
- return NULL;
- }
-
- new->pixels = pixels;
-
- if (flag)
- memcpy(pixels, src->pixels, src->bytes_per_row * src->h);
-
- new->bpp = src->bpp;
- new->bytes_per_row = src->bytes_per_row;
- new->offset = 0;
-
- new->w = src->w;
- new->h = src->h;
-
- new->pixel_type = src->pixel_type;
- new->bit_endian = src->bit_endian;
-
- /* rotation and mirroring */
- new->axes_swap = src->axes_swap;
- new->y_swap = src->y_swap;
- new->x_swap = src->x_swap;
-
- new->free_pixels = 1;
-
- return new;
-}
-
static uint32_t get_bpr(uint32_t bpp, uint32_t w)
{
return (bpp * w) / 8 + !!((bpp * w) % 8);
@@ -78,16 +40,18 @@ static uint32_t get_bpr(uint32_t bpp, uint32_t w)
GP_Context *GP_ContextAlloc(GP_Size w, GP_Size h, GP_PixelType type)
{
GP_CHECK_VALID_PIXELTYPE(type);
- GP_Context *context = malloc(sizeof(GP_Context));
+ GP_Context *context;
uint32_t bpp = GP_PixelSize(type);
uint32_t bpr = get_bpr(bpp, w);
void *pixels;
pixels = malloc(bpr * h);
+ context = malloc(sizeof(GP_Context));
if (pixels == NULL || context == NULL) {
free(pixels);
free(context);
+ GP_WARN("Malloc failed :(");
return NULL;
}
@@ -100,19 +64,55 @@ GP_Context *GP_ContextAlloc(GP_Size w, GP_Size h, GP_PixelType type)
context->h = h;
context->pixel_type = type;
- #warning Hmm, bit endianity... Why isn't this settled by different pixel types?
+ #warning Hmm, bit endianity... Why is not this settled by different pixel types?
context->bit_endian = 0;
/* rotation and mirroring */
- context->axes_swap = 0;
- context->y_swap = 0;
- context->x_swap = 0;
-
+ GP_ContextSetRotation(context, 0, 0, 0);
+
context->free_pixels = 1;
return context;
}
+void GP_ContextFree(GP_Context *context)
+{
+ GP_DEBUG(1, "Freeing context (%p)", context);
+
+ if (context == NULL)
+ return;
+
+ if (context->free_pixels)
+ free(context->pixels);
+
+ free(context);
+}
+
+GP_Context *GP_ContextInit(GP_Context *context, GP_Size w, GP_Size h,
+ GP_PixelType type, void *pixels)
+{
+ uint32_t bpp = GP_PixelSize(type);
+ uint32_t bpr = get_bpr(bpp, w);
+
+ context->pixels = pixels;
+ context->bpp = bpp;
+ context->bytes_per_row = bpr;
+ context->offset = 0;
+
+ context->w = w;
+ context->h = h;
+
+ context->pixel_type = type;
+ context->bit_endian = 0;
+
+ /* rotation and mirroring */
+ GP_ContextSetRotation(context, 0, 0, 0);
+
+ context->free_pixels = 0;
+
+ return context;
+}
+
int GP_ContextResize(GP_Context *context, GP_Size w, GP_Size h)
{
uint32_t bpr = get_bpr(context->bpp, w);
@@ -131,57 +131,92 @@ int GP_ContextResize(GP_Context *context, GP_Size w, GP_Size h)
return 0;
}
-void GP_ContextInit(GP_Context *context, GP_Size w, GP_Size h,
- GP_PixelType type, void *pixels)
+GP_Context *GP_ContextCopy(const GP_Context *src, int flags)
{
- uint32_t bpp = GP_PixelSize(type);
- uint32_t bpr = get_bpr(bpp, w);
+ GP_Context *new;
+ uint8_t *pixels;
- context->pixels = pixels;
- context->bpp = bpp;
- context->bytes_per_row = bpr;
- context->offset = 0;
+ if (src == NULL)
+ return NULL;
- context->w = w;
- context->h = h;
+ new = malloc(sizeof(GP_Context));
+ pixels = malloc(src->bytes_per_row * src->h);
- context->pixel_type = type;
- context->bit_endian = 0;
+ if (pixels == NULL || new == NULL) {
+ free(pixels);
+ free(new);
+ GP_WARN("Malloc failed :(");
+ return NULL;
+ }
- /* rotation and mirroring */
- context->axes_swap = 0;
- context->y_swap = 0;
- context->x_swap = 0;
+ new->pixels = pixels;
+
+ if (flags & GP_COPY_WITH_PIXELS)
+ memcpy(pixels, src->pixels, src->bytes_per_row * src->h);
+
+ new->bpp = src->bpp;
+ new->bytes_per_row = src->bytes_per_row;
+ new->offset = 0;
+
+ new->w = src->w;
+ new->h = src->h;
+
+ new->pixel_type = src->pixel_type;
+ new->bit_endian = src->bit_endian;
+
+ if (flags & GP_COPY_WITH_ROTATION)
+ GP_ContextCopyRotation(src, new);
+ else
+ GP_ContextSetRotation(new, 0, 0, 0);
- context->free_pixels = 0;
+ new->free_pixels = 1;
+
+ return new;
}
-GP_Context *GP_ContextConvert(const GP_Context *src,
- GP_PixelType dst_pixel_type)
+
+GP_Context *GP_ContextConvertAlloc(const GP_Context *src,
+ GP_PixelType dst_pixel_type)
{
int w = GP_ContextW(src);
int h = GP_ContextH(src);
+
GP_Context *ret = GP_ContextAlloc(w, h, dst_pixel_type);
+
if (ret == NULL)
return NULL;
GP_Blit(src, 0, 0, w, h, ret, 0, 0);
+
return ret;
}
-void GP_ContextFree(GP_Context *context)
+GP_Context *GP_ContextConvert(const GP_Context *src, GP_Context *dst)
{
- if (context == NULL)
- return;
+ //TODO: Asserts
+ int w = GP_ContextW(src);
+ int h = GP_ContextH(src);
+
+ GP_Blit(src, 0, 0, w, h, dst, 0, 0);
- if (context->free_pixels)
- free(context->pixels);
+ return dst;
+}
- free(context);
+GP_Context *GP_SubContextAlloc(const GP_Context *context,
+ GP_Coord x, GP_Coord y, GP_Size w, GP_Size h)
+{
+ GP_Context *res = malloc(sizeof(GP_Context));
+
+ if (res == NULL) {
+ GP_WARN("Malloc failed :(");
+ return NULL;
+ }
+
+ return GP_SubContext(context, res, x, y, w, h);
}
-GP_Context *GP_ContextSubContext(GP_Context *context, GP_Context *subcontext,
- GP_Coord x, GP_Coord y, GP_Size w, GP_Size h)
+GP_Context *GP_SubContext(const GP_Context *context, GP_Context *subcontext,
+ GP_Coord x, GP_Coord y, GP_Size w, GP_Size h)
{
GP_CHECK(context, "NULL context");
@@ -190,46 +225,36 @@ GP_Context *GP_ContextSubContext(GP_Context *context, GP_Context *subcontext,
GP_CHECK(context->w >= x + w, "Subcontext w out of original context.");
GP_CHECK(context->h >= y + h, "Subcontext h out of original context.");
- GP_Context *ret = subcontext;
-
- if (ret == NULL) {
- ret = malloc(sizeof(GP_Context));
+ subcontext->bpp = context->bpp;
+ subcontext->bytes_per_row = context->bytes_per_row;
+ subcontext->offset = (context->offset +
+ GP_PixelAddrOffset(x, context->pixel_type)) % 8;
- if (ret == NULL)
- return NULL;
- }
-
- ret->bpp = context->bpp;
- ret->bytes_per_row = context->bytes_per_row;
- ret->offset = (context->offset +
- GP_PixelAddrOffset(x, context->pixel_type)) % 8;
+ subcontext->w = w;
+ subcontext->h = h;
- ret->w = w;
- ret->h = h;
-
- ret->pixel_type = context->pixel_type;
- ret->bit_endian = context->bit_endian;
+ subcontext->pixel_type = context->pixel_type;
+ subcontext->bit_endian = context->bit_endian;
/* rotation and mirroring */
- ret->axes_swap = context->axes_swap;
- ret->y_swap = context->y_swap;
- ret->x_swap = context->x_swap;
+ GP_ContextCopyRotation(context, subcontext);
- ret->pixels = GP_PIXEL_ADDR(context, x, y);
+ subcontext->pixels = GP_PIXEL_ADDR(context, x, y);
- ret->free_pixels = 0;
+ subcontext->free_pixels = 0;
- return ret;
+ return subcontext;
}
-void GP_ContextInfoPrint(const GP_Context *self)
+void GP_ContextPrintInfo(const GP_Context *self)
{
printf("Context infon");
printf("------------n");
printf("Sizet%ux%un", self->w, self->h);
printf("BPPt%un", self->bpp);
printf("BPRt%un", self->bytes_per_row);
- printf("Pixelt%sn", GP_PixelTypeName(self->pixel_type));
+ printf("Pixelt%s (%u)n", GP_PixelTypeName(self->pixel_type),
+ self->pixel_type);
printf("Offsett%u (only unaligned pixel types)n", self->offset);
printf("Flagstaxes_swap=%u x_swap=%u y_swap=%u free_pixels=%un",
self->axes_swap, self->x_swap, self->y_swap, self->free_pixels);
@@ -258,7 +283,7 @@ void GP_ContextInfoPrint(const GP_Context *self)
* 0 1 0
*
*/
-void GP_ContextFlagsRotateCW(GP_Context *context)
+void GP_ContextRotateCW(GP_Context *context)
{
context->axes_swap = !context->axes_swap;
@@ -280,7 +305,7 @@ void GP_ContextFlagsRotateCW(GP_Context *context)
context->y_swap = 0;
}
-void GP_ContextFlagsRotateCCW(GP_Context *context)
+void GP_ContextRotateCCW(GP_Context *context)
{
context->axes_swap = !context->axes_swap;
diff --git a/libs/filters/GP_Resize.c b/libs/filters/GP_Resize.c
index 76d1621..81db9ed 100644
--- a/libs/filters/GP_Resize.c
+++ b/libs/filters/GP_Resize.c
@@ -702,7 +702,7 @@ GP_Context *GP_FilterResize(const GP_Context *src, GP_Context *dst,
/*
* The size of w and h is asserted in subcontext initalization
*/
- res = GP_ContextSubContext(dst, &sub, 0, 0, w, h);
+ res = GP_SubContext(dst, &sub, 0, 0, w, h);
}
/*
diff --git a/pylib/gfxprim/core/core.i b/pylib/gfxprim/core/core.i
index 86b0233..bfd4649 100644
--- a/pylib/gfxprim/core/core.i
+++ b/pylib/gfxprim/core/core.i
@@ -91,14 +91,14 @@ and self.thisown.") GP_Context;
ERROR_ON_NONZERO(GP_ContextResize);
ERROR_ON_NULL(GP_ContextAlloc);
ERROR_ON_NULL(GP_ContextCopy);
-ERROR_ON_NULL(GP_ContextSubContext);
-ERROR_ON_NULL(GP_ContextConvert);
+ERROR_ON_NULL(GP_ContextConvertAlloc);
+ERROR_ON_NULL(GP_SubContextAlloc);
/* Indicate new wrapper-owned GP_Context */
%newobject GP_ContextAlloc;
%newobject GP_ContextCopy;
-%newobject GP_ContextSubContext;
-%newobject GP_ContextConvert;
+%newobject GP_ContextConvertAlloc;
+%newobject GP_SubContextAlloc;
%include "GP_Context.h"
diff --git a/tests/SDL/blittest.c b/tests/SDL/blittest.c
index 2d09436..c23776c 100644
--- a/tests/SDL/blittest.c
+++ b/tests/SDL/blittest.c
@@ -212,7 +212,7 @@ int main(int argc, char *argv[])
GP_SDL_ContextFromSurface(&context, display);
- bitmap_conv = GP_ContextConvert(bitmap_raw, context.pixel_type);
+ bitmap_conv = GP_ContextConvertAlloc(bitmap_raw, context.pixel_type);
change_bitmap();
black = GP_ColorToContextPixel(GP_COL_BLACK, &context);
diff --git a/tests/SDL/subcontext.c b/tests/SDL/subcontext.c
index 5147ddf..a9348e6 100644
--- a/tests/SDL/subcontext.c
+++ b/tests/SDL/subcontext.c
@@ -260,7 +260,7 @@ int main(int argc, char *argv[])
white = GP_ColorToContextPixel(GP_COL_WHITE, &context);
gray = GP_ColorToContextPixel(GP_COL_GRAY_DARK, &context);
- sub_context = GP_ContextSubContext(&context, NULL, 100, 100, 440, 280);
+ sub_context = GP_SubContextAlloc(&context, 100, 100, 440, 280);
GP_Fill(sub_context, gray);
timer = SDL_AddTimer(60, timer_callback, NULL);
http://repo.or.cz/w/gfxprim.git/commit/dbcb0965a2d31e572ab897d23ca4cbc14377…
commit dbcb0965a2d31e572ab897d23ca4cbc14377fc02
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jun 12 15:22:06 2012 +0200
core: Add GP_ContextInfoPrint().
diff --git a/include/core/GP_Context.h b/include/core/GP_Context.h
index 5057481..494199a 100644
--- a/include/core/GP_Context.h
+++ b/include/core/GP_Context.h
@@ -147,6 +147,11 @@ GP_Context *GP_ContextConvert(const GP_Context *src,
GP_PixelType dst_pixel_type);
/*
+ * Prints context information into stdout.
+ */
+void GP_ContextInfoPrint(const GP_Context *self);
+
+/*
* Free context.
*
* If context->free_pixels, also free pixel data.
diff --git a/libs/core/GP_Context.c b/libs/core/GP_Context.c
index 3226c1c..c7b2d89 100644
--- a/libs/core/GP_Context.c
+++ b/libs/core/GP_Context.c
@@ -222,6 +222,19 @@ GP_Context *GP_ContextSubContext(GP_Context *context, GP_Context *subcontext,
return ret;
}
+void GP_ContextInfoPrint(const GP_Context *self)
+{
+ printf("Context infon");
+ printf("------------n");
+ printf("Sizet%ux%un", self->w, self->h);
+ printf("BPPt%un", self->bpp);
+ printf("BPRt%un", self->bytes_per_row);
+ printf("Pixelt%sn", GP_PixelTypeName(self->pixel_type));
+ printf("Offsett%u (only unaligned pixel types)n", self->offset);
+ printf("Flagstaxes_swap=%u x_swap=%u y_swap=%u free_pixels=%un",
+ self->axes_swap, self->x_swap, self->y_swap, self->free_pixels);
+}
+
/*
* The context rotations consists of two cyclic permutation groups that are
* mirrored.
http://repo.or.cz/w/gfxprim.git/commit/5df856f5af17bd0922b99fc21c1236f01f3d…
commit 5df856f5af17bd0922b99fc21c1236f01f3d2f27
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jun 12 15:06:28 2012 +0200
core: Remove GP_ContextDump().
diff --git a/include/core/GP_Context.h b/include/core/GP_Context.h
index 141fa76..5057481 100644
--- a/include/core/GP_Context.h
+++ b/include/core/GP_Context.h
@@ -154,11 +154,6 @@ GP_Context *GP_ContextConvert(const GP_Context *src,
void GP_ContextFree(GP_Context *context);
/*
- * Dump context into file
- */
-GP_RetCode GP_ContextDump(GP_Context *context, const char *path);
-
-/*
* Rotates context flags clock wise.
*/
void GP_ContextFlagsRotateCW(GP_Context *context);
diff --git a/libs/core/GP_Context.c b/libs/core/GP_Context.c
index 967edcb..3226c1c 100644
--- a/libs/core/GP_Context.c
+++ b/libs/core/GP_Context.c
@@ -222,25 +222,6 @@ GP_Context *GP_ContextSubContext(GP_Context *context, GP_Context *subcontext,
return ret;
}
-GP_RetCode GP_ContextDump(GP_Context *context, const char *path)
-{
- FILE *f = fopen(path, "w");
- uint32_t x, y;
-
- if (f == NULL)
- return GP_EBADFILE;
-
- for (y = 0; y < context->h; y++) {
- for (x = 0; x < context->bytes_per_row; x++)
- fprintf(f, "0x%02x ", ((uint8_t *)context->pixels)
- [y * context->bytes_per_row + x]);
- fprintf(f, "n");
- }
-
- fclose(f);
- return GP_ESUCCESS;
-}
-
/*
* The context rotations consists of two cyclic permutation groups that are
* mirrored.
http://repo.or.cz/w/gfxprim.git/commit/5261b44a10e5bcf3d7abd86d97076161449b…
commit 5261b44a10e5bcf3d7abd86d97076161449b2ef4
Merge: e1e008b f5c3fdd
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Jun 12 13:34:42 2012 +0200
Merge ssh://repo.or.cz/srv/git/gfxprim
http://repo.or.cz/w/gfxprim.git/commit/e1e008bfb7e62140b69da17b0a6b30eed15d…
commit e1e008bfb7e62140b69da17b0a6b30eed15de653
Merge: 4fddc17 46fc9fc
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sat Jun 9 00:31:11 2012 +0200
Merge ssh://repo.or.cz/srv/git/gfxprim
http://repo.or.cz/w/gfxprim.git/commit/4fddc1754f1d4f739c318adb305041595efb…
commit 4fddc1754f1d4f739c318adb305041595efbfa1f
Merge: 79adf5c 9dc7c88
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Mon May 28 21:17:03 2012 +0200
Merge ssh://repo.or.cz/srv/git/gfxprim
http://repo.or.cz/w/gfxprim.git/commit/79adf5cfb66ddd38140c64f8015be735bad2…
commit 79adf5cfb66ddd38140c64f8015be735bad2a985
Merge: ca0579c 60acd49
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Mon May 21 00:56:44 2012 +0200
Merge ssh://repo.or.cz/srv/git/gfxprim
http://repo.or.cz/w/gfxprim.git/commit/ca0579cff49cfb79bcc2382c4508a8c5aef6…
commit ca0579cff49cfb79bcc2382c4508a8c5aef6f04e
Merge: d082267 3447cc0
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Apr 29 20:37:59 2012 +0200
Merge ssh://repo.or.cz/srv/git/gfxprim
http://repo.or.cz/w/gfxprim.git/commit/d082267d9e82e53500d0989dbc158a1725cc…
commit d082267d9e82e53500d0989dbc158a1725cc68b4
Merge: 6a75eaa b4f2a25
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Tue Apr 17 21:12:21 2012 +0200
Merge ssh://repo.or.cz/srv/git/gfxprim
http://repo.or.cz/w/gfxprim.git/commit/6a75eaa20c6561c387c324b8013e1ff04517…
commit 6a75eaa20c6561c387c324b8013e1ff04517b33b
Merge: 382a79d 4f696f6
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Mon Apr 16 21:32:08 2012 +0200
Merge ssh://repo.or.cz/srv/git/gfxprim
http://repo.or.cz/w/gfxprim.git/commit/382a79d9e517a63ab444030f0003c045c3c5…
commit 382a79d9e517a63ab444030f0003c045c3c55d17
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sat Mar 3 23:48:31 2012 +0100
core: Add info to the existing call.
diff --git a/include/core/GP_Context.h b/include/core/GP_Context.h
index a6b76df..affb8d5 100644
--- a/include/core/GP_Context.h
+++ b/include/core/GP_Context.h
@@ -100,7 +100,8 @@ typedef struct GP_Context {
GP_Context *GP_ContextAlloc(GP_Size w, GP_Size h, GP_PixelType type);
/*
- * Initalize context.
+ * Initalize context, pixels pointer is not dereferenced so it's safe to pass
+ * NULL there and allocate it later with size context->bpr * context->h.
*/
void GP_ContextInit(GP_Context *context, GP_Size w, GP_Size h,
GP_PixelType type, void *pixels);
-----------------------------------------------------------------------
Summary of changes:
.gitignore | 1 +
demos/spiv/spiv.c | 5 +-
doc/context.txt | 124 +++++++++++++++++-----
include/core/GP_Context.h | 126 ++++++++++++++++-------
libs/core/GP_Blit.c | 4 +-
libs/core/GP_Context.c | 255 ++++++++++++++++++++++++---------------------
libs/filters/GP_Resize.c | 2 +-
pylib/gfxprim/core/core.i | 8 +-
tests/SDL/blittest.c | 2 +-
tests/SDL/subcontext.c | 2 +-
10 files changed, 335 insertions(+), 194 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: f5c3fdd85dc385b05af7f41ede836a6074fb4c3c
by metan 12 Jun '12
by metan 12 Jun '12
12 Jun '12
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via f5c3fdd85dc385b05af7f41ede836a6074fb4c3c (commit)
via b237bf3df004656f0668fbcf5c507b95a6e94504 (commit)
via 66a5907055cd5fe7831d88f633dfff20be27a5bf (commit)
via e26ee6f9de0c0ba897df7f61de6b92622c874a8f (commit)
from 46fc9fc756d28ff45e30d962eb98fb1b8d80586c (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/f5c3fdd85dc385b05af7f41ede836a6074fb…
commit f5c3fdd85dc385b05af7f41ede836a6074fb4c3c
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 10 22:56:36 2012 +0200
spiv: Make the original image cache larger.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index c0e918d..72d8595 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -487,8 +487,8 @@ static void init_caches(struct loader_params *params)
if (resized_size > 100 * 1024 * 1024)
resized_size = 100 * 1024 * 1024;
- if (orig_size > 20 * 1024 * 1024)
- orig_size = 20 * 1024 * 1024;
+ if (orig_size > 40 * 1024 * 1024)
+ orig_size = 40 * 1024 * 1024;
GP_DEBUG(1, "Cache sizes original = %u, resized = %u",
orig_size, resized_size);
http://repo.or.cz/w/gfxprim.git/commit/b237bf3df004656f0668fbcf5c507b95a6e9…
commit b237bf3df004656f0668fbcf5c507b95a6e94504
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 10 22:51:30 2012 +0200
spiv: Fix progress callback.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index 531dfc8..c0e918d 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -140,9 +140,6 @@ GP_Context *load_image(struct loader_params *params, int elevate)
/* Image not cached, load it */
if (img == NULL) {
- show_progress = params->show_progress || params->show_progress_once;
- params->show_progress_once = 0;
-
fprintf(stderr, "Loading '%s'n", params->img_path);
cpu_timer_start(&timer, "Loading");
@@ -244,6 +241,9 @@ static void *image_loader(void *ptr)
GP_ProgressCallback callback = {.callback = image_loader_callback};
cpu_timer_start(&sum_timer, "sum");
+
+ show_progress = params->show_progress || params->show_progress_once;
+ params->show_progress_once = 0;
/* Figure out rotation */
GP_Size w, h;
http://repo.or.cz/w/gfxprim.git/commit/66a5907055cd5fe7831d88f633dfff20be27…
commit 66a5907055cd5fe7831d88f633dfff20be27a5bf
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 10 12:44:42 2012 +0200
spiv: PgUp and PgDown to scrolls by 10 images.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index cec4ab6..531dfc8 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -594,7 +594,7 @@ int main(int argc, char *argv[])
while (GP_EventGet(&ev)) {
- GP_EventDump(&ev);
+ // GP_EventDump(&ev);
switch (ev.type) {
case GP_EV_KEY:
@@ -629,6 +629,24 @@ int main(int argc, char *argv[])
GP_BackendExit(backend);
return 0;
break;
+ case GP_KEY_PAGE_UP:
+ argn+=10;
+ //TODO
+ if (argn >= argc)
+ argn = argf;
+
+ params.show_progress_once = 1;
+ show_image(¶ms, argv[argn]);
+ break;
+ case GP_KEY_PAGE_DOWN:
+ argn-=10;
+ //TODO
+ if (argn < argf)
+ argn = argc - 1 ;
+
+ params.show_progress_once = 1;
+ show_image(¶ms, argv[argn]);
+ break;
case GP_KEY_RIGHT:
case GP_KEY_UP:
case GP_KEY_SPACE:
http://repo.or.cz/w/gfxprim.git/commit/e26ee6f9de0c0ba897df7f61de6b92622c87…
commit e26ee6f9de0c0ba897df7f61de6b92622c874a8f
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sun Jun 10 12:43:31 2012 +0200
backends: Add Wait method.
diff --git a/include/backends/GP_Backend.h b/include/backends/GP_Backend.h
index b28917e..159892d 100644
--- a/include/backends/GP_Backend.h
+++ b/include/backends/GP_Backend.h
@@ -105,14 +105,23 @@ typedef struct GP_Backend {
int fd;
/*
- * Some of the backends doesn't expose file descriptor
- * (for example SDL is broken that way).
+ * Non-blocking event loop.
*
- * In that case the fd_list is NULL and this function
- * is non NULL.
+ * The events are filled into the event queue see GP_Input.h.
*/
void (*Poll)(struct GP_Backend *self);
+ /*
+ * Blocking event loop. Blocks until events are ready.
+ *
+ * Note that events received by a backend are not necessarily
+ * translated to input events. So input queue may be empty
+ * after Wait has returned.
+ *
+ * The events are filled into the event queue see GP_Input.h.
+ */
+ void (*Wait)(struct GP_Backend *self);
+
/* Backed private data */
char priv[];
} GP_Backend;
@@ -151,6 +160,14 @@ static inline void GP_BackendPoll(GP_Backend *backend)
}
/*
+ * Waits for backend events.
+ */
+static inline void GP_BackendWait(GP_Backend *backend)
+{
+ backend->Wait(backend);
+}
+
+/*
* Sets backend caption, if supported.
*
* When setting caption is not possible/implemented non zero is returned.
diff --git a/libs/backends/GP_BackendVirtual.c b/libs/backends/GP_BackendVirtual.c
index b28c3cb..89598f7 100644
--- a/libs/backends/GP_BackendVirtual.c
+++ b/libs/backends/GP_BackendVirtual.c
@@ -60,9 +60,9 @@ static void virt_update_rect(GP_Backend *self, GP_Coord x0, GP_Coord y0,
virt->backend->UpdateRect(virt->backend, x0, y0, x1, y1);
}
-static int virt_set_attributes(struct GP_Backend *self,
- uint32_t w, uint32_t h,
- const char *caption)
+static int virt_set_attrs(struct GP_Backend *self,
+ uint32_t w, uint32_t h,
+ const char *caption)
{
struct virt_priv *virt = GP_BACKEND_PRIV(self);
int ret;
@@ -86,6 +86,13 @@ static void virt_poll(GP_Backend *self)
virt->backend->Poll(virt->backend);
}
+static void virt_wait(GP_Backend *self)
+{
+ struct virt_priv *virt = GP_BACKEND_PRIV(self);
+
+ virt->backend->Wait(virt->backend);
+}
+
static void virt_exit(GP_Backend *self)
{
struct virt_priv *virt = GP_BACKEND_PRIV(self);
@@ -130,12 +137,9 @@ GP_Backend *GP_BackendVirtualInit(GP_Backend *backend,
self->Flip = virt_flip;
self->UpdateRect = virt_update_rect;
self->Exit = virt_exit;
-
- if (backend->Poll)
- self->Poll = virt_poll;
-
- if (backend->SetAttributes)
- self->SetAttributes = virt_set_attributes;
+ self->Poll = backend->Poll ? virt_poll : NULL;
+ self->Wait = backend->Wait ? virt_wait : NULL;
+ self->SetAttributes = backend->SetAttributes ? virt_set_attrs : NULL;
return self;
diff --git a/libs/backends/GP_LinuxFB.c b/libs/backends/GP_LinuxFB.c
index a374cbe..6d69ce4 100644
--- a/libs/backends/GP_LinuxFB.c
+++ b/libs/backends/GP_LinuxFB.c
@@ -29,6 +29,7 @@
#include <errno.h>
#include <termios.h>
#include <unistd.h>
+#include <poll.h>
#include <linux/fb.h>
#include <linux/kd.h>
@@ -188,6 +189,18 @@ static void fb_poll(GP_Backend *self)
GP_InputDriverKBDEventPut(buf[i]);
}
+static void fb_wait(GP_Backend *self)
+{
+ struct fb_priv *fb = GP_BACKEND_PRIV(self);
+
+ struct pollfd fd = {.fd = fb->con_fd, .events = POLLIN, .revents = 0};
+
+ if (poll(&fd, 1, -1) > 0)
+ fb_poll(self);
+ else
+ GP_WARN("poll(): %s", strerror(errno));
+}
+
static void fb_exit(GP_Backend *self)
{
struct fb_priv *fb = GP_BACKEND_PRIV(self);
@@ -312,6 +325,7 @@ GP_Backend *GP_BackendLinuxFBInit(const char *path, int flag)
backend->Exit = fb_exit;
backend->SetAttributes = NULL;
backend->Poll = flag ? fb_poll : NULL;
+ backend->Wait = flag ? fb_wait : NULL;
backend->fd = fb->con_fd;
return backend;
diff --git a/libs/backends/GP_SDL.c b/libs/backends/GP_SDL.c
index 5705eec..d487dd6 100644
--- a/libs/backends/GP_SDL.c
+++ b/libs/backends/GP_SDL.c
@@ -82,6 +82,21 @@ static void sdl_poll(struct GP_Backend *self __attribute__((unused)))
SDL_mutexV(mutex);
}
+static void sdl_wait(struct GP_Backend *self __attribute__((unused)))
+{
+ SDL_Event ev;
+
+ SDL_mutexP(mutex);
+
+ SDL_WaitEvent(&ev);
+ GP_InputDriverSDLEventPut(&ev);
+
+ while (SDL_PollEvent(&ev))
+ GP_InputDriverSDLEventPut(&ev);
+
+ SDL_mutexV(mutex);
+}
+
int context_from_surface(GP_Context *context, SDL_Surface *surf)
{
/* sanity checks on the SDL surface */
@@ -145,6 +160,7 @@ static struct GP_Backend backend = {
.Exit = sdl_exit,
.fd = -1,
.Poll = sdl_poll,
+ .Wait = sdl_wait,
};
static void sdl_exit(struct GP_Backend *self __attribute__((unused)))
diff --git a/libs/backends/GP_X11.c b/libs/backends/GP_X11.c
index 8b12562..d95e2de 100644
--- a/libs/backends/GP_X11.c
+++ b/libs/backends/GP_X11.c
@@ -105,6 +105,34 @@ static void x11_flip(GP_Backend *self)
XUnlockDisplay(x11->dpy);
}
+static void x11_ev(GP_Backend *self, XEvent *ev)
+{
+ struct x11_priv *x11 = GP_BACKEND_PRIV(self);
+
+ switch (ev->type) {
+ case Expose:
+ GP_DEBUG(4, "Expose %ix%i-%ix%i %i",
+ ev->xexpose.x, ev->xexpose.y,
+ ev->xexpose.width, ev->xexpose.height,
+ ev->xexpose.count);
+
+ if (x11->resized_flag)
+ break;
+
+ x11_update_rect(self, ev->xexpose.x, ev->xexpose.y,
+ ev->xexpose.x + ev->xexpose.width - 1,
+ ev->xexpose.y + ev->xexpose.height - 1);
+ break;
+ case ConfigureNotify:
+ if (ev->xconfigure.width == (int)self->context->w &&
+ ev->xconfigure.height == (int)self->context->h)
+ break;
+ default:
+ GP_InputDriverX11EventPut(ev);
+ break;
+ }
+}
+
static void x11_poll(GP_Backend *self)
{
struct x11_priv *x11 = GP_BACKEND_PRIV(self);
@@ -114,34 +142,25 @@ static void x11_poll(GP_Backend *self)
while (XPending(x11->dpy)) {
XNextEvent(x11->dpy, &ev);
-
- switch (ev.type) {
- case Expose:
- GP_DEBUG(4, "Expose %ix%i-%ix%i %i",
- ev.xexpose.x, ev.xexpose.y,
- ev.xexpose.width, ev.xexpose.height,
- ev.xexpose.count);
-
- if (x11->resized_flag)
- break;
-
- x11_update_rect(self, ev.xexpose.x, ev.xexpose.y,
- ev.xexpose.x + ev.xexpose.width - 1,
- ev.xexpose.y + ev.xexpose.height - 1);
- break;
- case ConfigureNotify:
- if (ev.xconfigure.width == (int)self->context->w &&
- ev.xconfigure.height == (int)self->context->h)
- break;
- default:
- GP_InputDriverX11EventPut(&ev);
- break;
- }
+ x11_ev(self, &ev);
}
XUnlockDisplay(x11->dpy);
}
+static void x11_wait(GP_Backend *self)
+{
+ struct x11_priv *x11 = GP_BACKEND_PRIV(self);
+ XEvent ev;
+
+ XLockDisplay(x11->dpy);
+
+ XNextEvent(x11->dpy, &ev);
+ x11_ev(self, &ev);
+
+ XUnlockDisplay(x11->dpy);
+}
+
static int x11_set_attributes(struct GP_Backend *self,
uint32_t w, uint32_t h,
const char *caption)
@@ -495,6 +514,7 @@ GP_Backend *GP_BackendX11Init(const char *display, int x, int y,
backend->UpdateRect = x11_update_rect;
backend->Exit = x11_exit;
backend->Poll = x11_poll;
+ backend->Wait = x11_wait;
backend->SetAttributes = x11_set_attributes;
backend->fd = XConnectionNumber(x11->dpy);
-----------------------------------------------------------------------
Summary of changes:
demos/spiv/spiv.c | 30 +++++++++++++---
include/backends/GP_Backend.h | 25 ++++++++++++--
libs/backends/GP_BackendVirtual.c | 22 +++++++-----
libs/backends/GP_LinuxFB.c | 14 ++++++++
libs/backends/GP_SDL.c | 16 +++++++++
libs/backends/GP_X11.c | 66 ++++++++++++++++++++++++-------------
6 files changed, 131 insertions(+), 42 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 46fc9fc756d28ff45e30d962eb98fb1b8d80586c
by metan 09 Jun '12
by metan 09 Jun '12
09 Jun '12
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 46fc9fc756d28ff45e30d962eb98fb1b8d80586c (commit)
from 5e2e627e16c613ffee331d5ac32071caca27a369 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/46fc9fc756d28ff45e30d962eb98fb1b8d80…
commit 46fc9fc756d28ff45e30d962eb98fb1b8d80586c
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Sat Jun 9 00:27:14 2012 +0200
spiv: Split the caches for resized and original images.
diff --git a/demos/spiv/image_cache.c b/demos/spiv/image_cache.c
index 4a8c2b7..4cb194f 100644
--- a/demos/spiv/image_cache.c
+++ b/demos/spiv/image_cache.c
@@ -47,7 +47,7 @@ struct image_cache {
struct image *end;
};
-static size_t read_total_memory(void)
+size_t image_cache_get_ram_size(void)
{
FILE *f;
size_t ret;
@@ -84,7 +84,7 @@ static size_t image_size(struct image *img)
return image_size2(img->ctx, img->path);
}
-struct image_cache *image_cache_create(unsigned int max_size)
+struct image_cache *image_cache_create(unsigned int max_size_bytes)
{
struct image_cache *self;
@@ -93,7 +93,7 @@ struct image_cache *image_cache_create(unsigned int max_size)
if (self == NULL)
return NULL;
- self->max_size = max_size ? max_size : read_total_memory();
+ self->max_size = max_size_bytes;
self->cur_size = sizeof(struct image_cache);
self->root = NULL;
diff --git a/demos/spiv/image_cache.h b/demos/spiv/image_cache.h
index e946709..023ccd8 100644
--- a/demos/spiv/image_cache.h
+++ b/demos/spiv/image_cache.h
@@ -32,12 +32,14 @@
struct image_cache;
/*
+ * Returns size of the ram in kbytes.
+ */
+size_t image_cache_get_ram_size(void);
+
+/*
* Creates an image cache with maximal memory size.
- *
- * When memory size is set to zero it's set to 10% of total machine memory
- * (as reported by /proc/meminfo).
*/
-struct image_cache *image_cache_create(unsigned int max_size);
+struct image_cache *image_cache_create(unsigned int max_size_bytes);
/*
* Returns cached image, or NULL.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index ec5a656..cec4ab6 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -85,12 +85,14 @@ static int image_loader_callback(GP_ProgressCallback *self)
struct loader_params {
const char *img_path;
+
int show_progress;
int show_progress_once;
int show_info;
/* cached loaded images */
- struct image_cache *image_cache;
+ struct image_cache *img_resized_cache;
+ struct image_cache *img_orig_cache;
};
static float calc_img_size(uint32_t img_w, uint32_t img_h,
@@ -134,7 +136,7 @@ GP_Context *load_image(struct loader_params *params, int elevate)
GP_ProgressCallback callback = {.callback = image_loader_callback,
.priv = "Loading image"};
- img = image_cache_get(params->image_cache, params->img_path, 0, 0, elevate);
+ img = image_cache_get(params->img_orig_cache, params->img_path, 0, 0, elevate);
/* Image not cached, load it */
if (img == NULL) {
@@ -160,7 +162,7 @@ GP_Context *load_image(struct loader_params *params, int elevate)
img = tmp;
}
- image_cache_put(params->image_cache, img, params->img_path, 0, 0);
+ image_cache_put(params->img_orig_cache, img, params->img_path, 0, 0);
cpu_timer_stop(&timer);
}
@@ -176,7 +178,7 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size
GP_ProgressCallback callback = {.callback = image_loader_callback};
/* Try to get resized cached image */
- img = image_cache_get(params->image_cache, params->img_path, cookie, resampling_method, 1);
+ img = image_cache_get(params->img_resized_cache, params->img_path, cookie, resampling_method, 1);
if (img != NULL)
return img;
@@ -211,7 +213,7 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size
if (img == NULL)
return NULL;
- image_cache_put(params->image_cache, img, params->img_path, cookie, resampling_method);
+ image_cache_put(params->img_resized_cache, img, params->img_path, cookie, resampling_method);
return img;
}
@@ -268,12 +270,13 @@ static void *image_loader(void *ptr)
w = img->w;
h = img->h;
- img = load_resized_image(params, img->w * rat + 0.5, img->h * rat + 0.5, rat);
+ img = load_resized_image(params, w * rat + 0.5, h * rat + 0.5, rat);
if (img == NULL)
return NULL;
- image_cache_print(params->image_cache);
+ image_cache_print(params->img_resized_cache);
+ image_cache_print(params->img_orig_cache);
switch (rotate) {
case 0:
@@ -475,17 +478,34 @@ static int wait_for_event(int sleep_msec)
}
}
+static void init_caches(struct loader_params *params)
+{
+ size_t size = image_cache_get_ram_size();
+ unsigned int resized_size = (1024 * size)/10;
+ unsigned int orig_size = (1024 * size)/50;
+
+ if (resized_size > 100 * 1024 * 1024)
+ resized_size = 100 * 1024 * 1024;
+
+ if (orig_size > 20 * 1024 * 1024)
+ orig_size = 20 * 1024 * 1024;
+
+ GP_DEBUG(1, "Cache sizes original = %u, resized = %u",
+ orig_size, resized_size);
+
+ params->img_resized_cache = image_cache_create(resized_size);
+ params->img_orig_cache = image_cache_create(orig_size);
+}
+
int main(int argc, char *argv[])
{
GP_Context *context = NULL;
const char *backend_opts = "X11";
int sleep_sec = -1;
- struct loader_params params = {NULL, 0, 0, 0, NULL};
+ struct loader_params params = {NULL, 0, 0, 0, NULL, NULL};
int opt, debug_level = 0;
GP_PixelType emul_type = GP_PIXEL_UNKNOWN;
- params.image_cache = image_cache_create(0);
-
while ((opt = getopt(argc, argv, "b:cd:e:fIPs:r:")) != -1) {
switch (opt) {
case 'I':
@@ -535,6 +555,8 @@ int main(int argc, char *argv[])
signal(SIGSEGV, sighandler);
signal(SIGBUS, sighandler);
signal(SIGABRT, sighandler);
+
+ init_caches(¶ms);
init_backend(backend_opts);
@@ -598,7 +620,8 @@ int main(int argc, char *argv[])
show_image(¶ms, NULL);
break;
case GP_KEY_D:
- image_cache_drop(params.image_cache);
+ image_cache_drop(params.img_resized_cache);
+ image_cache_drop(params.img_orig_cache);
break;
case GP_KEY_ESC:
case GP_KEY_ENTER:
-----------------------------------------------------------------------
Summary of changes:
demos/spiv/image_cache.c | 6 +++---
demos/spiv/image_cache.h | 10 ++++++----
demos/spiv/spiv.c | 45 ++++++++++++++++++++++++++++++++++-----------
3 files changed, 43 insertions(+), 18 deletions(-)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0
[repo.or.cz] gfxprim.git branch master updated: 5e2e627e16c613ffee331d5ac32071caca27a369
by metan 08 Jun '12
by metan 08 Jun '12
08 Jun '12
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project gfxprim.git.
The branch, master has been updated
via 5e2e627e16c613ffee331d5ac32071caca27a369 (commit)
via 43ae478827afcbdb94f4ce3d46a0881c6e2f9c01 (commit)
via 5073ef02014ec1f3d2ca23e50951a6db7785c23e (commit)
via cdf48d7342a48c7a5225403bfc371ba0ec7e74d5 (commit)
via 7831f900a2f1ad24e66b999a6ddb7d664236d0d7 (commit)
via ea3d8a3b3ff7deca52c6320bcbc30f3115f5aa32 (commit)
via f027b0f012e6ea1e694dd0618be0d9c18c840dc5 (commit)
from b45098c71ca5dab7345e2b2f704ae6452a7b52cb (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://repo.or.cz/w/gfxprim.git/commit/5e2e627e16c613ffee331d5ac32071caca27…
commit 5e2e627e16c613ffee331d5ac32071caca27a369
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jun 8 20:21:18 2012 +0200
spiv: Temporarily fix the bussy loop.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index 28ae50d..ec5a656 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -416,6 +416,7 @@ static int wait_for_event(int sleep_msec)
if (sleep_msec < 0) {
GP_BackendPoll(backend);
+ usleep(10000);
return 0;
}
http://repo.or.cz/w/gfxprim.git/commit/43ae478827afcbdb94f4ce3d46a0881c6e2f…
commit 43ae478827afcbdb94f4ce3d46a0881c6e2f9c01
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jun 8 20:12:06 2012 +0200
spiv: image_cache: Add elevator count, drop cache on d.
diff --git a/demos/spiv/image_cache.c b/demos/spiv/image_cache.c
index 3f26474..4a8c2b7 100644
--- a/demos/spiv/image_cache.c
+++ b/demos/spiv/image_cache.c
@@ -30,6 +30,9 @@ struct image {
struct image *prev;
struct image *next;
+ /* number of elevated get calls */
+ unsigned int elevated;
+
/* this identifies an image */
long cookie1;
long cookie2;
@@ -172,6 +175,8 @@ GP_Context *image_cache_get(struct image_cache *self, const char *path,
remove_img(self, i, size);
add_img(self, i, size);
+
+ i->elevated++;
}
return i->ctx;
@@ -184,8 +189,8 @@ void image_cache_print(struct image_cache *self)
printf("Image cache size %u used %un", self->max_size, self->cur_size);
for (i = self->root; i != NULL; i = i->next)
- printf(" Image '%s:%10li:%10li' size %zun", i->path,
- i->cookie1, i->cookie2, image_size(i));
+ printf(" Image '%s:%10li:%10li' size %10zu elevated %un", i->path,
+ i->cookie1, i->cookie2, image_size(i), i->elevated);
}
static int assert_size(struct image_cache *self, size_t size)
@@ -227,6 +232,7 @@ int image_cache_put(struct image_cache *self, GP_Context *ctx, const char *path,
img->ctx = ctx;
img->cookie1 = cookie1;
img->cookie2 = cookie2;
+ img->elevated = 0;
strcpy(img->path, path);
add_img(self, img, size);
@@ -234,6 +240,16 @@ int image_cache_put(struct image_cache *self, GP_Context *ctx, const char *path,
return 0;
}
+void image_cache_drop(struct image_cache *self)
+{
+ GP_DEBUG(1, "Dropping images in cache");
+
+ while (self->end != NULL)
+ remove_img_free(self, self->end, 0);
+
+ self->cur_size = sizeof(struct image_cache);
+}
+
void image_cache_destroy(struct image_cache *self)
{
GP_DEBUG(1, "Destroying image cache");
diff --git a/demos/spiv/image_cache.h b/demos/spiv/image_cache.h
index 38efb0d..e946709 100644
--- a/demos/spiv/image_cache.h
+++ b/demos/spiv/image_cache.h
@@ -55,6 +55,11 @@ int image_cache_put(struct image_cache *self, GP_Context *img,
const char *path, long cookie1, long cookie2);
/*
+ * Drop all image in cache.
+ */
+void image_cache_drop(struct image_cache *self);
+
+/*
* Destroys image cache and all it's images.
*/
void image_cache_destroy(struct image_cache *self);
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index e4a6747..28ae50d 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -596,6 +596,9 @@ int main(int argc, char *argv[])
params.show_progress_once = 1;
show_image(¶ms, NULL);
break;
+ case GP_KEY_D:
+ image_cache_drop(params.image_cache);
+ break;
case GP_KEY_ESC:
case GP_KEY_ENTER:
case GP_KEY_Q:
http://repo.or.cz/w/gfxprim.git/commit/5073ef02014ec1f3d2ca23e50951a6db7785…
commit 5073ef02014ec1f3d2ca23e50951a6db7785c23e
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jun 8 20:00:36 2012 +0200
spiv: image_cache: Add elevate parameter to get function.
diff --git a/demos/spiv/image_cache.c b/demos/spiv/image_cache.c
index 759febc..3f26474 100644
--- a/demos/spiv/image_cache.c
+++ b/demos/spiv/image_cache.c
@@ -148,8 +148,8 @@ static void add_img(struct image_cache *self, struct image *img, size_t size)
self->end = img;
}
-GP_Context *image_cache_get(struct image_cache *self,
- const char *path, long cookie1, long cookie2)
+GP_Context *image_cache_get(struct image_cache *self, const char *path,
+ long cookie1, long cookie2, int elevate)
{
struct image *i;
@@ -164,12 +164,15 @@ GP_Context *image_cache_get(struct image_cache *self,
return NULL;
/* Push the image to the root of the list */
- size_t size = image_size(i);
+ if (elevate) {
+ size_t size = image_size(i);
- GP_DEBUG(2, "Refreshing image '%s:%10li:%10li", path, cookie1, cookie2);
+ GP_DEBUG(2, "Refreshing image '%s:%10li:%10li",
+ path, cookie1, cookie2);
- remove_img(self, i, size);
- add_img(self, i, size);
+ remove_img(self, i, size);
+ add_img(self, i, size);
+ }
return i->ctx;
}
diff --git a/demos/spiv/image_cache.h b/demos/spiv/image_cache.h
index d2e3019..38efb0d 100644
--- a/demos/spiv/image_cache.h
+++ b/demos/spiv/image_cache.h
@@ -42,11 +42,11 @@ struct image_cache *image_cache_create(unsigned int max_size);
/*
* Returns cached image, or NULL.
*
- * Also image, if found, is rotated to the top, so recently touched images have
- * lesser chance of being freed.
+ * If elevate set and image is found, the image is elevated to the top so
+ * it has lesser chance of being freed.
*/
-GP_Context *image_cache_get(struct image_cache *self,
- const char *path, long cookie1, long cookie2);
+GP_Context *image_cache_get(struct image_cache *self, const char *path,
+ long cookie1, long cookie2, int elevate);
/*
* Puts an image into a cache.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index 93c066f..e4a6747 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -126,7 +126,7 @@ static void set_caption(const char *path, float rat)
/*
* Loads image
*/
-GP_Context *load_image(struct loader_params *params)
+GP_Context *load_image(struct loader_params *params, int elevate)
{
struct cpu_timer timer;
GP_Context *img, *context = backend->context;
@@ -134,7 +134,7 @@ GP_Context *load_image(struct loader_params *params)
GP_ProgressCallback callback = {.callback = image_loader_callback,
.priv = "Loading image"};
- img = image_cache_get(params->image_cache, params->img_path, 0, 0);
+ img = image_cache_get(params->image_cache, params->img_path, 0, 0, elevate);
/* Image not cached, load it */
if (img == NULL) {
@@ -176,13 +176,13 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size
GP_ProgressCallback callback = {.callback = image_loader_callback};
/* Try to get resized cached image */
- img = image_cache_get(params->image_cache, params->img_path, cookie, resampling_method);
+ img = image_cache_get(params->image_cache, params->img_path, cookie, resampling_method, 1);
if (img != NULL)
return img;
/* Otherwise load image and resize it */
- if ((img = load_image(params)) == NULL)
+ if ((img = load_image(params, 1)) == NULL)
return NULL;
/* Do low pass filter */
@@ -222,7 +222,7 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size
*/
static int resize_backend_and_blit(struct loader_params *params)
{
- GP_Context *img = load_image(params);
+ GP_Context *img = load_image(params, 1);
if (GP_BackendResize(backend, img->w, img->h))
return 1;
@@ -260,7 +260,7 @@ static void *image_loader(void *ptr)
break;
}
- if ((img = load_image(params)) == NULL)
+ if ((img = load_image(params, 0)) == NULL)
return NULL;
float rat = calc_img_size(img->w, img->h, w, h);
http://repo.or.cz/w/gfxprim.git/commit/cdf48d7342a48c7a5225403bfc371ba0ec7e…
commit cdf48d7342a48c7a5225403bfc371ba0ec7e74d5
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jun 8 19:50:50 2012 +0200
spiv: image_cache: Count image size more properly.
diff --git a/demos/spiv/image_cache.c b/demos/spiv/image_cache.c
index 7ff0c56..759febc 100644
--- a/demos/spiv/image_cache.c
+++ b/demos/spiv/image_cache.c
@@ -67,6 +67,20 @@ static size_t read_total_memory(void)
return ret * 1024 / 10;
}
+/*
+ * Reports correct image record size.
+ */
+static size_t image_size2(GP_Context *ctx, const char *path)
+{
+ return ctx->bytes_per_row * ctx->h + sizeof(GP_Context) +
+ sizeof(struct image) + strlen(path) + 1;
+}
+
+static size_t image_size(struct image *img)
+{
+ return image_size2(img->ctx, img->path);
+}
+
struct image_cache *image_cache_create(unsigned int max_size)
{
struct image_cache *self;
@@ -77,7 +91,7 @@ struct image_cache *image_cache_create(unsigned int max_size)
return NULL;
self->max_size = max_size ? max_size : read_total_memory();
- self->cur_size = 0;
+ self->cur_size = sizeof(struct image_cache);
self->root = NULL;
self->end = NULL;
@@ -87,10 +101,8 @@ struct image_cache *image_cache_create(unsigned int max_size)
return self;
}
-static void remove_img(struct image_cache *self, struct image *img)
+static void remove_img(struct image_cache *self, struct image *img, size_t size)
{
- size_t size = img->ctx->bytes_per_row * img->ctx->h;
-
if (img == self->end)
self->end = img->prev;
@@ -106,13 +118,13 @@ static void remove_img(struct image_cache *self, struct image *img)
self->cur_size -= size;
}
-static void remove_img_free(struct image_cache *self, struct image *img)
+static void remove_img_free(struct image_cache *self,
+ struct image *img, size_t size)
{
- GP_DEBUG(2, "Freeing image '%s:%10li:%10li' size %u",
- img->path, img->cookie1, img->cookie2,
- img->ctx->bytes_per_row * img->ctx->h);
+ GP_DEBUG(2, "Freeing image '%s:%10li:%10li' size %zu",
+ img->path, img->cookie1, img->cookie2, size);
- remove_img(self, img);
+ remove_img(self, img, size);
GP_ContextFree(img->ctx);
free(img);
}
@@ -120,10 +132,8 @@ static void remove_img_free(struct image_cache *self, struct image *img)
/*
* Adds image to the start of the double linked list
*/
-static void add_img(struct image_cache *self, struct image *img)
+static void add_img(struct image_cache *self, struct image *img, size_t size)
{
- size_t size = img->ctx->bytes_per_row * img->ctx->h;
-
img->next = self->root;
if (img->next)
@@ -154,9 +164,12 @@ GP_Context *image_cache_get(struct image_cache *self,
return NULL;
/* Push the image to the root of the list */
+ size_t size = image_size(i);
+
GP_DEBUG(2, "Refreshing image '%s:%10li:%10li", path, cookie1, cookie2);
- remove_img(self, i);
- add_img(self, i);
+
+ remove_img(self, i, size);
+ add_img(self, i, size);
return i->ctx;
}
@@ -168,8 +181,8 @@ void image_cache_print(struct image_cache *self)
printf("Image cache size %u used %un", self->max_size, self->cur_size);
for (i = self->root; i != NULL; i = i->next)
- printf(" Image '%s:%10li:%10li' size %un", i->path, i->cookie1, i->cookie2,
- i->ctx->bytes_per_row * i->ctx->h);
+ printf(" Image '%s:%10li:%10li' size %zun", i->path,
+ i->cookie1, i->cookie2, image_size(i));
}
static int assert_size(struct image_cache *self, size_t size)
@@ -184,7 +197,7 @@ static int assert_size(struct image_cache *self, size_t size)
return 1;
}
- remove_img_free(self, self->end);
+ remove_img_free(self, self->end, image_size(self->end));
}
return 0;
@@ -193,7 +206,7 @@ static int assert_size(struct image_cache *self, size_t size)
int image_cache_put(struct image_cache *self, GP_Context *ctx, const char *path,
long cookie1, long cookie2)
{
- size_t size = ctx->bytes_per_row * ctx->h;
+ size_t size = image_size2(ctx, path);
if (assert_size(self, size))
return 1;
@@ -213,7 +226,8 @@ int image_cache_put(struct image_cache *self, GP_Context *ctx, const char *path,
img->cookie2 = cookie2;
strcpy(img->path, path);
- add_img(self, img);
+ add_img(self, img, size);
+
return 0;
}
@@ -222,7 +236,7 @@ void image_cache_destroy(struct image_cache *self)
GP_DEBUG(1, "Destroying image cache");
while (self->end != NULL)
- remove_img_free(self, self->end);
+ remove_img_free(self, self->end, 0);
free(self);
}
diff --git a/demos/spiv/image_cache.h b/demos/spiv/image_cache.h
index fc008ed..d2e3019 100644
--- a/demos/spiv/image_cache.h
+++ b/demos/spiv/image_cache.h
@@ -34,13 +34,16 @@ struct image_cache;
/*
* Creates an image cache with maximal memory size.
*
- * When memory size is set to zero, the size is read from /proc/meminfo
- * as 10% of total memory.
+ * When memory size is set to zero it's set to 10% of total machine memory
+ * (as reported by /proc/meminfo).
*/
struct image_cache *image_cache_create(unsigned int max_size);
/*
* Returns cached image, or NULL.
+ *
+ * Also image, if found, is rotated to the top, so recently touched images have
+ * lesser chance of being freed.
*/
GP_Context *image_cache_get(struct image_cache *self,
const char *path, long cookie1, long cookie2);
http://repo.or.cz/w/gfxprim.git/commit/7831f900a2f1ad24e66b999a6ddb7d664236…
commit 7831f900a2f1ad24e66b999a6ddb7d664236d0d7
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jun 8 19:30:58 2012 +0200
spiv: Fix low pass filtering, edhance cache.
diff --git a/demos/spiv/image_cache.c b/demos/spiv/image_cache.c
index f252013..7ff0c56 100644
--- a/demos/spiv/image_cache.c
+++ b/demos/spiv/image_cache.c
@@ -26,11 +26,13 @@
struct image {
GP_Context *ctx;
- int cookie;
struct image *prev;
struct image *next;
+ /* this identifies an image */
+ long cookie1;
+ long cookie2;
char path[];
};
@@ -106,8 +108,8 @@ static void remove_img(struct image_cache *self, struct image *img)
static void remove_img_free(struct image_cache *self, struct image *img)
{
- GP_DEBUG(2, "Freeing image '%s:%i' size %u",
- img->path, img->cookie,
+ GP_DEBUG(2, "Freeing image '%s:%10li:%10li' size %u",
+ img->path, img->cookie1, img->cookie2,
img->ctx->bytes_per_row * img->ctx->h);
remove_img(self, img);
@@ -137,21 +139,22 @@ static void add_img(struct image_cache *self, struct image *img)
}
GP_Context *image_cache_get(struct image_cache *self,
- const char *path, int cookie)
+ const char *path, long cookie1, long cookie2)
{
struct image *i;
- GP_DEBUG(2, "Looking for image '%s:%i'", path, cookie);
+ GP_DEBUG(2, "Looking for image '%s:%10li:%10li'", path, cookie1, cookie2);
for (i = self->root; i != NULL; i = i->next)
- if (!strcmp(path, i->path) && i->cookie == cookie)
+ if (!strcmp(path, i->path) &&
+ i->cookie1 == cookie1 && i->cookie2 == cookie2)
break;
if (i == NULL)
return NULL;
/* Push the image to the root of the list */
- GP_DEBUG(2, "Refreshing image '%s:%i", path, cookie);
+ GP_DEBUG(2, "Refreshing image '%s:%10li:%10li", path, cookie1, cookie2);
remove_img(self, i);
add_img(self, i);
@@ -165,7 +168,7 @@ void image_cache_print(struct image_cache *self)
printf("Image cache size %u used %un", self->max_size, self->cur_size);
for (i = self->root; i != NULL; i = i->next)
- printf(" Image '%s:%i' size %un", i->path, i->cookie,
+ printf(" Image '%s:%10li:%10li' size %un", i->path, i->cookie1, i->cookie2,
i->ctx->bytes_per_row * i->ctx->h);
}
@@ -187,8 +190,8 @@ static int assert_size(struct image_cache *self, size_t size)
return 0;
}
-int image_cache_put(struct image_cache *self,
- GP_Context *ctx, const char *path, int cookie)
+int image_cache_put(struct image_cache *self, GP_Context *ctx, const char *path,
+ long cookie1, long cookie2)
{
size_t size = ctx->bytes_per_row * ctx->h;
@@ -202,11 +205,12 @@ int image_cache_put(struct image_cache *self,
return 1;
}
- GP_DEBUG(2, "Adding image '%s:%i' size %zu",
- img->path, img->cookie, size);
+ GP_DEBUG(2, "Adding image '%s:%10li:%10li' size %zu",
+ img->path, img->cookie1, img->cookie2, size);
img->ctx = ctx;
- img->cookie = cookie;
+ img->cookie1 = cookie1;
+ img->cookie2 = cookie2;
strcpy(img->path, path);
add_img(self, img);
diff --git a/demos/spiv/image_cache.h b/demos/spiv/image_cache.h
index ad3ecdd..fc008ed 100644
--- a/demos/spiv/image_cache.h
+++ b/demos/spiv/image_cache.h
@@ -43,13 +43,13 @@ struct image_cache *image_cache_create(unsigned int max_size);
* Returns cached image, or NULL.
*/
GP_Context *image_cache_get(struct image_cache *self,
- const char *path, int cookie);
+ const char *path, long cookie1, long cookie2);
/*
* Puts an image into a cache.
*/
-int image_cache_put(struct image_cache *self,
- GP_Context *img, const char *path, int cookie);
+int image_cache_put(struct image_cache *self, GP_Context *img,
+ const char *path, long cookie1, long cookie2);
/*
* Destroys image cache and all it's images.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index c1ec6d2..93c066f 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -134,7 +134,7 @@ GP_Context *load_image(struct loader_params *params)
GP_ProgressCallback callback = {.callback = image_loader_callback,
.priv = "Loading image"};
- img = image_cache_get(params->image_cache, params->img_path, 0);
+ img = image_cache_get(params->image_cache, params->img_path, 0, 0);
/* Image not cached, load it */
if (img == NULL) {
@@ -160,7 +160,7 @@ GP_Context *load_image(struct loader_params *params)
img = tmp;
}
- image_cache_put(params->image_cache, img, params->img_path, 0);
+ image_cache_put(params->image_cache, img, params->img_path, 0, 0);
cpu_timer_stop(&timer);
}
@@ -171,33 +171,33 @@ GP_Context *load_image(struct loader_params *params)
GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size h, float rat)
{
long cookie = (w & 0xffff) | (h & 0xffff)<<16;
- GP_Context *img;
+ GP_Context *img, *res = NULL;
struct cpu_timer timer;
GP_ProgressCallback callback = {.callback = image_loader_callback};
/* Try to get resized cached image */
- img = image_cache_get(params->image_cache, params->img_path, cookie);
+ img = image_cache_get(params->image_cache, params->img_path, cookie, resampling_method);
if (img != NULL)
return img;
/* Otherwise load image and resize it */
- img = load_image(params);
-
- if (img == NULL)
+ if ((img = load_image(params)) == NULL)
return NULL;
/* Do low pass filter */
- if (resampling_method != GP_INTERP_LINEAR_LF_INT) {
- if (rat < 1) {
- cpu_timer_start(&timer, "Blur");
- callback.priv = "Blurring Image";
- //TODO: We can't blur saved image!
- if (GP_FilterGaussianBlur(img, img, 0.4/rat, 0.4/rat,
- &callback) == NULL)
- return NULL;
- cpu_timer_stop(&timer);
- }
+ if (resampling_method != GP_INTERP_LINEAR_LF_INT && rat < 1) {
+ cpu_timer_start(&timer, "Blur");
+ callback.priv = "Blurring Image";
+
+ res = GP_FilterGaussianBlur(img, NULL, 0.4/rat, 0.4/rat, &callback);
+
+ if (res == NULL)
+ return NULL;
+
+ img = res;
+
+ cpu_timer_stop(&timer);
}
cpu_timer_start(&timer, "Resampling");
@@ -205,11 +205,14 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size
img = GP_FilterResize(img, NULL, resampling_method, w, h, &callback);
cpu_timer_stop(&timer);
+ /* Free low passed context if needed */
+ GP_ContextFree(res);
+
if (img == NULL)
return NULL;
- image_cache_put(params->image_cache, img, params->img_path, cookie);
-
+ image_cache_put(params->image_cache, img, params->img_path, cookie, resampling_method);
+
return img;
}
@@ -270,6 +273,8 @@ static void *image_loader(void *ptr)
if (img == NULL)
return NULL;
+ image_cache_print(params->image_cache);
+
switch (rotate) {
case 0:
break;
http://repo.or.cz/w/gfxprim.git/commit/ea3d8a3b3ff7deca52c6320bcbc30f3115f5…
commit ea3d8a3b3ff7deca52c6320bcbc30f3115f5aa32
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jun 8 18:59:27 2012 +0200
spiv: Cache resized images too, not optimal yet though.
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index 26eb45b..c1ec6d2 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -168,6 +168,51 @@ GP_Context *load_image(struct loader_params *params)
return img;
}
+GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size h, float rat)
+{
+ long cookie = (w & 0xffff) | (h & 0xffff)<<16;
+ GP_Context *img;
+ struct cpu_timer timer;
+ GP_ProgressCallback callback = {.callback = image_loader_callback};
+
+ /* Try to get resized cached image */
+ img = image_cache_get(params->image_cache, params->img_path, cookie);
+
+ if (img != NULL)
+ return img;
+
+ /* Otherwise load image and resize it */
+ img = load_image(params);
+
+ if (img == NULL)
+ return NULL;
+
+ /* Do low pass filter */
+ if (resampling_method != GP_INTERP_LINEAR_LF_INT) {
+ if (rat < 1) {
+ cpu_timer_start(&timer, "Blur");
+ callback.priv = "Blurring Image";
+ //TODO: We can't blur saved image!
+ if (GP_FilterGaussianBlur(img, img, 0.4/rat, 0.4/rat,
+ &callback) == NULL)
+ return NULL;
+ cpu_timer_stop(&timer);
+ }
+ }
+
+ cpu_timer_start(&timer, "Resampling");
+ callback.priv = "Resampling Image";
+ img = GP_FilterResize(img, NULL, resampling_method, w, h, &callback);
+ cpu_timer_stop(&timer);
+
+ if (img == NULL)
+ return NULL;
+
+ image_cache_put(params->image_cache, img, params->img_path, cookie);
+
+ return img;
+}
+
/*
* This function tries to resize spiv window
* and if succedes blits the image directly to the screen.
@@ -189,26 +234,12 @@ static int resize_backend_and_blit(struct loader_params *params)
static void *image_loader(void *ptr)
{
struct loader_params *params = ptr;
- struct cpu_timer timer;
- struct cpu_timer sum_timer;
+ struct cpu_timer timer, sum_timer;
GP_Context *img, *context = backend->context;
GP_ProgressCallback callback = {.callback = image_loader_callback};
cpu_timer_start(&sum_timer, "sum");
- /* Load Image */
- img = load_image(params);
-
- if (img == NULL)
- return NULL;
-
- /*
- if (img->w < 320 && img->h < 240) {
- if (!resize_backend_and_blit(img, params))
- return NULL;
- }
- */
-
/* Figure out rotation */
GP_Size w, h;
@@ -226,32 +257,17 @@ static void *image_loader(void *ptr)
break;
}
+ if ((img = load_image(params)) == NULL)
+ return NULL;
+
float rat = calc_img_size(img->w, img->h, w, h);
w = img->w;
h = img->h;
- GP_Context *ret;
-
- /* Do low pass filter */
- if (resampling_method != GP_INTERP_LINEAR_LF_INT) {
- if (rat < 1) {
- cpu_timer_start(&timer, "Blur");
- callback.priv = "Blurring Image";
- //TODO: We can't blur saved image!
- if (GP_FilterGaussianBlur(img, img, 0.4/rat, 0.4/rat,
- &callback) == NULL)
- return NULL;
- cpu_timer_stop(&timer);
- }
- }
-
- cpu_timer_start(&timer, "Resampling");
- callback.priv = "Resampling Image";
- ret = GP_FilterResize(img, NULL, resampling_method, img->w * rat, img->h * rat, &callback);
- cpu_timer_stop(&timer);
+ img = load_resized_image(params, img->w * rat + 0.5, img->h * rat + 0.5, rat);
- if (ret == NULL)
+ if (img == NULL)
return NULL;
switch (rotate) {
@@ -259,28 +275,23 @@ static void *image_loader(void *ptr)
break;
case 90:
callback.priv = "Rotating image (90)";
- img = GP_FilterRotate90_Alloc(ret, &callback);
+ img = GP_FilterRotate90_Alloc(img, &callback);
break;
case 180:
callback.priv = "Rotating image (180)";
- img = GP_FilterRotate180_Alloc(ret, &callback);
+ img = GP_FilterRotate180_Alloc(img, &callback);
break;
case 270:
callback.priv = "Rotating image (270)";
- img = GP_FilterRotate270_Alloc(ret, &callback);
+ img = GP_FilterRotate270_Alloc(img, &callback);
break;
}
-
- if (rotate) {
- GP_ContextFree(ret);
- ret = img;
- }
-
+
if (img == NULL)
return NULL;
- uint32_t cx = (context->w - ret->w)/2;
- uint32_t cy = (context->h - ret->h)/2;
+ uint32_t cx = (context->w - img->w)/2;
+ uint32_t cy = (context->h - img->h)/2;
GP_Context sub_display;
@@ -288,21 +299,23 @@ static void *image_loader(void *ptr)
if (dithering) {
callback.priv = "Dithering";
- GP_ContextSubContext(context, &sub_display, cx, cy, ret->w, ret->h);
+ GP_ContextSubContext(context, &sub_display, cx, cy, img->w, img->h);
// GP_FilterFloydSteinberg_RGB888(ret, &sub_display, NULL);
- GP_FilterHilbertPeano_RGB888(ret, &sub_display, NULL);
+ GP_FilterHilbertPeano_RGB888(img, &sub_display, NULL);
} else {
- GP_Blit_Raw(ret, 0, 0, ret->w, ret->h, context, cx, cy);
+ GP_Blit_Raw(img, 0, 0, img->w, img->h, context, cx, cy);
}
cpu_timer_stop(&timer);
- GP_ContextFree(ret);
+
+ if (rotate)
+ GP_ContextFree(img);
/* clean up the rest of the display */
GP_FillRectXYWH(context, 0, 0, cx, context->h, black_pixel);
GP_FillRectXYWH(context, 0, 0, context->w, cy, black_pixel);
- GP_FillRectXYWH(context, ret->w+cx, 0, context->w - ret->w - cx, context->h, black_pixel);
- GP_FillRectXYWH(context, 0, ret->h+cy, context->w, context->h - ret->h - cy, black_pixel);
+ GP_FillRectXYWH(context, img->w + cx, 0, context->w - img->w - cx, context->h, black_pixel);
+ GP_FillRectXYWH(context, 0, img->h + cy, context->w, context->h - img->h - cy, black_pixel);
cpu_timer_stop(&sum_timer);
http://repo.or.cz/w/gfxprim.git/commit/f027b0f012e6ea1e694dd0618be0d9c18c84…
commit f027b0f012e6ea1e694dd0618be0d9c18c840dc5
Author: Cyril Hrubis <metan(a)ucw.cz>
Date: Fri Jun 8 18:40:43 2012 +0200
spiv: Add image cache.
diff --git a/demos/spiv/Makefile b/demos/spiv/Makefile
index 13b416c..431e6ce 100644
--- a/demos/spiv/Makefile
+++ b/demos/spiv/Makefile
@@ -9,7 +9,7 @@ LDLIBS+=-lGP -lGP_backends -lSDL -L$(TOPDIR)/build/
APPS=spiv
-spiv: cpu_timer.o
+spiv: cpu_timer.o image_cache.o
include $(TOPDIR)/pre.mk
include $(TOPDIR)/app.mk
diff --git a/demos/spiv/image_cache.c b/demos/spiv/image_cache.c
new file mode 100644
index 0000000..f252013
--- /dev/null
+++ b/demos/spiv/image_cache.c
@@ -0,0 +1,224 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+#include <string.h>
+#include <GP.h>
+#include "image_cache.h"
+
+struct image {
+ GP_Context *ctx;
+ int cookie;
+
+ struct image *prev;
+ struct image *next;
+
+ char path[];
+};
+
+struct image_cache {
+ unsigned int max_size;
+ unsigned int cur_size;
+
+ struct image *root;
+ struct image *end;
+};
+
+static size_t read_total_memory(void)
+{
+ FILE *f;
+ size_t ret;
+
+ f = fopen("/proc/meminfo", "r");
+
+ if (f == NULL) {
+ GP_WARN("Failed to read /proc/meminfo");
+ return 0;
+ }
+
+ if (fscanf(f, "MemTotal: %zu", &ret) != 1) {
+ fclose(f);
+ GP_WARN("Failed to read /proc/meminfo");
+ return 0;
+ }
+
+ fclose(f);
+
+ return ret * 1024 / 10;
+}
+
+struct image_cache *image_cache_create(unsigned int max_size)
+{
+ struct image_cache *self;
+
+ self = malloc(sizeof(struct image_cache));
+
+ if (self == NULL)
+ return NULL;
+
+ self->max_size = max_size ? max_size : read_total_memory();
+ self->cur_size = 0;
+
+ self->root = NULL;
+ self->end = NULL;
+
+ GP_DEBUG(1, "Created image cache size %u bytes", self->max_size);
+
+ return self;
+}
+
+static void remove_img(struct image_cache *self, struct image *img)
+{
+ size_t size = img->ctx->bytes_per_row * img->ctx->h;
+
+ if (img == self->end)
+ self->end = img->prev;
+
+ if (img->prev)
+ img->prev->next = img->next;
+
+ if (img->next)
+ img->next->prev = img->prev;
+
+ if (img == self->root)
+ self->root = img->next;
+
+ self->cur_size -= size;
+}
+
+static void remove_img_free(struct image_cache *self, struct image *img)
+{
+ GP_DEBUG(2, "Freeing image '%s:%i' size %u",
+ img->path, img->cookie,
+ img->ctx->bytes_per_row * img->ctx->h);
+
+ remove_img(self, img);
+ GP_ContextFree(img->ctx);
+ free(img);
+}
+
+/*
+ * Adds image to the start of the double linked list
+ */
+static void add_img(struct image_cache *self, struct image *img)
+{
+ size_t size = img->ctx->bytes_per_row * img->ctx->h;
+
+ img->next = self->root;
+
+ if (img->next)
+ img->next->prev = img;
+
+ img->prev = NULL;
+
+ self->root = img;
+ self->cur_size += size;
+
+ if (self->end == NULL)
+ self->end = img;
+}
+
+GP_Context *image_cache_get(struct image_cache *self,
+ const char *path, int cookie)
+{
+ struct image *i;
+
+ GP_DEBUG(2, "Looking for image '%s:%i'", path, cookie);
+
+ for (i = self->root; i != NULL; i = i->next)
+ if (!strcmp(path, i->path) && i->cookie == cookie)
+ break;
+
+ if (i == NULL)
+ return NULL;
+
+ /* Push the image to the root of the list */
+ GP_DEBUG(2, "Refreshing image '%s:%i", path, cookie);
+ remove_img(self, i);
+ add_img(self, i);
+
+ return i->ctx;
+}
+
+void image_cache_print(struct image_cache *self)
+{
+ struct image *i;
+
+ printf("Image cache size %u used %un", self->max_size, self->cur_size);
+
+ for (i = self->root; i != NULL; i = i->next)
+ printf(" Image '%s:%i' size %un", i->path, i->cookie,
+ i->ctx->bytes_per_row * i->ctx->h);
+}
+
+static int assert_size(struct image_cache *self, size_t size)
+{
+ if (self->cur_size + size < self->max_size)
+ return 0;
+
+ while (self->cur_size + size > self->max_size) {
+
+ if (self->end == NULL) {
+ GP_WARN("Cache too small for image size %zu", size);
+ return 1;
+ }
+
+ remove_img_free(self, self->end);
+ }
+
+ return 0;
+}
+
+int image_cache_put(struct image_cache *self,
+ GP_Context *ctx, const char *path, int cookie)
+{
+ size_t size = ctx->bytes_per_row * ctx->h;
+
+ if (assert_size(self, size))
+ return 1;
+
+ struct image *img = malloc(sizeof(struct image) + strlen(path) + 1);
+
+ if (img == NULL) {
+ GP_WARN("Malloc failed :(");
+ return 1;
+ }
+
+ GP_DEBUG(2, "Adding image '%s:%i' size %zu",
+ img->path, img->cookie, size);
+
+ img->ctx = ctx;
+ img->cookie = cookie;
+ strcpy(img->path, path);
+
+ add_img(self, img);
+ return 0;
+}
+
+void image_cache_destroy(struct image_cache *self)
+{
+ GP_DEBUG(1, "Destroying image cache");
+
+ while (self->end != NULL)
+ remove_img_free(self, self->end);
+
+ free(self);
+}
diff --git a/demos/spiv/image_cache.h b/demos/spiv/image_cache.h
new file mode 100644
index 0000000..ad3ecdd
--- /dev/null
+++ b/demos/spiv/image_cache.h
@@ -0,0 +1,64 @@
+/*****************************************************************************
+ * This file is part of gfxprim library. *
+ * *
+ * Gfxprim is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2.1 of the License, or (at your option) any later version. *
+ * *
+ * Gfxprim is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with gfxprim; if not, write to the Free Software *
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
+ * Boston, MA 02110-1301 USA *
+ * *
+ * Copyright (C) 2009-2012 Cyril Hrubis <metan(a)ucw.cz> *
+ * *
+ *****************************************************************************/
+
+ /*
+
+ Image loader chache.
+
+ */
+
+#ifndef __IMAGE_CACHE_H__
+#define __IMAGE_CACHE_H__
+
+struct image_cache;
+
+/*
+ * Creates an image cache with maximal memory size.
+ *
+ * When memory size is set to zero, the size is read from /proc/meminfo
+ * as 10% of total memory.
+ */
+struct image_cache *image_cache_create(unsigned int max_size);
+
+/*
+ * Returns cached image, or NULL.
+ */
+GP_Context *image_cache_get(struct image_cache *self,
+ const char *path, int cookie);
+
+/*
+ * Puts an image into a cache.
+ */
+int image_cache_put(struct image_cache *self,
+ GP_Context *img, const char *path, int cookie);
+
+/*
+ * Destroys image cache and all it's images.
+ */
+void image_cache_destroy(struct image_cache *self);
+
+/*
+ * Print the image cache content.
+ */
+void image_cache_print(struct image_cache *self);
+
+#endif /* __IMAGE_CACHE_H__ */
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c
index 6e03531..26eb45b 100644
--- a/demos/spiv/spiv.c
+++ b/demos/spiv/spiv.c
@@ -36,6 +36,7 @@
#include <backends/GP_Backends.h>
#include <input/GP_InputDriverLinux.h>
+#include "image_cache.h"
#include "cpu_timer.h"
static GP_Pixel black_pixel;
@@ -88,8 +89,8 @@ struct loader_params {
int show_progress_once;
int show_info;
- /* cached loaded image */
- GP_Context *img;
+ /* cached loaded images */
+ struct image_cache *image_cache;
};
static float calc_img_size(uint32_t img_w, uint32_t img_h,
@@ -125,46 +126,46 @@ static void set_caption(const char *path, float rat)
/*
* Loads image
*/
-int load_image(struct loader_params *params)
+GP_Context *load_image(struct loader_params *params)
{
struct cpu_timer timer;
GP_Context *img, *context = backend->context;
-
- if (params->img != NULL) {
- fprintf(stderr, "Image cached!n");
- return 0;
- }
GP_ProgressCallback callback = {.callback = image_loader_callback,
.priv = "Loading image"};
-
- show_progress = params->show_progress || params->show_progress_once;
- params->show_progress_once = 0;
- fprintf(stderr, "Loading '%s'n", params->img_path);
+ img = image_cache_get(params->image_cache, params->img_path, 0);
- cpu_timer_start(&timer, "Loading");
- if ((img = GP_LoadImage(params->img_path, &callback)) == NULL) {
- GP_Fill(context, black_pixel);
- GP_Print(context, NULL, context->w/2, context->h/2,
- GP_ALIGN_CENTER|GP_VALIGN_CENTER, white_pixel, black_pixel,
- "Failed to load image :( (%s)", strerror(errno));
- GP_BackendFlip(backend);
- return 1;
- }
+ /* Image not cached, load it */
+ if (img == NULL) {
+ show_progress = params->show_progress || params->show_progress_once;
+ params->show_progress_once = 0;
+
+ fprintf(stderr, "Loading '%s'n", params->img_path);
+
+ cpu_timer_start(&timer, "Loading");
+ if ((img = GP_LoadImage(params->img_path, &callback)) == NULL) {
+ GP_Fill(context, black_pixel);
+ GP_Print(context, NULL, context->w/2, context->h/2,
+ GP_ALIGN_CENTER|GP_VALIGN_CENTER, white_pixel, black_pixel,
+ "Failed to load image :( (%s)", strerror(errno));
+ GP_BackendFlip(backend);
+ return NULL;
+ }
+
+ /* Workaround */
+ if (img->pixel_type != GP_PIXEL_RGB888) {
+ GP_Context *tmp = GP_ContextConvert(img, GP_PIXEL_RGB888);
+ GP_ContextFree(img);
+ img = tmp;
+ }
- /* Workaround */
- if (img->pixel_type != GP_PIXEL_RGB888) {
- GP_Context *tmp = GP_ContextConvert(img, GP_PIXEL_RGB888);
- GP_ContextFree(img);
- img = tmp;
+ image_cache_put(params->image_cache, img, params->img_path, 0);
+
+ cpu_timer_stop(&timer);
}
-
- cpu_timer_stop(&timer);
-
- params->img = img;
- return 0;
+ return img;
}
/*
@@ -173,7 +174,7 @@ int load_image(struct loader_params *params)
*/
static int resize_backend_and_blit(struct loader_params *params)
{
- GP_Context *img = params->img;
+ GP_Context *img = load_image(params);
if (GP_BackendResize(backend, img->w, img->h))
return 1;
@@ -196,10 +197,10 @@ static void *image_loader(void *ptr)
cpu_timer_start(&sum_timer, "sum");
/* Load Image */
- if (load_image(params))
- return NULL;
+ img = load_image(params);
- img = params->img;
+ if (img == NULL)
+ return NULL;
/*
if (img->w < 320 && img->h < 240) {
@@ -351,13 +352,8 @@ static void show_image(struct loader_params *params, const char *path)
abort_flag = 0;
}
- /* invalidate cached image if path has changed */
- if (params->img_path == NULL ||
- (path != NULL && strcmp(params->img_path, path))) {
- GP_ContextFree(params->img);
- params->img = NULL;
+ if (path != NULL)
params->img_path = path;
- }
ret = pthread_create(&loader_thread, NULL, image_loader, (void*)params);
@@ -465,10 +461,12 @@ int main(int argc, char *argv[])
GP_Context *context = NULL;
const char *backend_opts = "X11";
int sleep_sec = -1;
- struct loader_params params = {NULL, 0, 0, 0, .img = NULL};
+ struct loader_params params = {NULL, 0, 0, 0, NULL};
int opt, debug_level = 0;
GP_PixelType emul_type = GP_PIXEL_UNKNOWN;
+ params.image_cache = image_cache_create(0);
+
while ((opt = getopt(argc, argv, "b:cd:e:fIPs:r:")) != -1) {
switch (opt) {
case 'I':
-----------------------------------------------------------------------
Summary of changes:
demos/spiv/Makefile | 2 +-
demos/spiv/image_cache.c | 261 ++++++++++++++++++++
.../loaders/GP_JPG.h => demos/spiv/image_cache.h | 49 ++--
demos/spiv/spiv.c | 196 ++++++++-------
4 files changed, 398 insertions(+), 110 deletions(-)
create mode 100644 demos/spiv/image_cache.c
copy include/loaders/GP_JPG.h => demos/spiv/image_cache.h (61%)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos(a)gmail.com
if you want to unsubscribe, or site admin admin(a)repo.or.cz if you receive
no reply.
--
gfxprim.git ("A simple 2D graphics library with emphasis on correctness and well-defined operation.")
1
0