Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/imbuf/intern/antialias.c')
-rw-r--r--source/blender/imbuf/intern/antialias.c471
1 files changed, 471 insertions, 0 deletions
diff --git a/source/blender/imbuf/intern/antialias.c b/source/blender/imbuf/intern/antialias.c
new file mode 100644
index 00000000000..de45a47a708
--- /dev/null
+++ b/source/blender/imbuf/intern/antialias.c
@@ -0,0 +1,471 @@
+/**
+ * antialias.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "imbuf.h"
+
+#include "BLI_blenlib.h"
+#include "DNA_listBase.h"
+
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+
+/* werking:
+
+1 - zoek een overgang in een kolom
+2 - kijk wat de relatie met links en rechts is,
+
+ Is pixel boven overgang links of rechts ervan gelijk aan bovenste kleur,
+ zoek dan naar beneden.
+
+ Is pixel onder overgang links of rechts ervan gelijk aan onderste kleur,
+ zoek dan naar boven.
+
+
+*/
+
+/* er moet een functie * komen die aan kan geven of twee kleuren nu
+ * wel of niet gelijk zijn.
+ * Voor nu maar een define
+ */
+
+
+/*
+ zipfork "cc -g anti.c util.o -lgl_s -limbuf -limage -lm -o anti > /dev/console"
+ zipfork "anti /data/rt > /dev/console"
+ zipfork "anti /pics/martin/03.01.ChambFinal/0001 > /dev/console"
+*/
+
+static unsigned int anti_mask = 0xffffffff;
+static int anti_a, anti_b, anti_g, anti_r;
+
+#define compare(x, y) ((x ^ y) & anti_mask)
+
+typedef struct Edge
+{
+ struct Edge * next, * prev;
+ short position;
+ int col1, col2;
+}Edge;
+
+static void anti_free_listarray(int count, ListBase * listarray)
+{
+ int i;
+
+ if (listarray == 0) return;
+
+ for (i = 0; i < count; i++) BLI_freelistN(listarray + i);
+ MEM_freeN(listarray);
+}
+
+static ListBase * scanimage(struct ImBuf * ibuf, int dir)
+{
+ int step, pixels, lines, nextline, x, y, col1, col2;
+ unsigned int * rect;
+ ListBase * listarray, * curlist;
+ Edge * edge;
+ int count;
+
+ switch (dir) {
+ case 'h':
+ step = 1; nextline = ibuf->x;
+ pixels = ibuf->x; lines = ibuf->y;
+ break;
+ case 'v':
+ step = ibuf->x; nextline = 1;
+ pixels = ibuf->y; lines = ibuf->x;
+ }
+
+ listarray = (ListBase*)MEM_callocN((lines)* sizeof(ListBase), "listarray");
+ for (y = 0; y < lines; y++){
+ rect = ibuf->rect;
+ rect += y * nextline;
+ curlist = listarray + y;
+
+ col1 = rect[0];
+ count = 0;
+
+ for (x = 0; x < pixels; x++) {
+ col2 = rect[0];
+ if (compare(col1, col2)) {
+ edge = NEW(Edge);
+ edge->position = x;
+ edge->col1 = col1;
+ edge->col2 = col2;
+ BLI_addtail(curlist, edge);
+ col1 = col2;
+ count++;
+ if (count > 100) {
+ printf("\n\n%s: Aborting antialias !\n", ibuf->name);
+ printf("To many transitions.\nIs this a natural image ?\n\n"),
+ anti_free_listarray(lines, listarray);
+ return(0);
+ }
+ }
+ rect += step;
+ }
+ }
+
+ return(listarray);
+}
+
+
+static Edge * findmatch(Edge * first, Edge * edge)
+{
+ Edge * match = 0;
+ int in = 0, out = 65535;
+
+ if (edge->prev) in = edge->prev->position;
+ if (edge->next) out = edge->next->position;
+
+ while (first) {
+ if (first->position < edge->position) {
+ if (first->col1 == edge->col1) {
+ if (first->position >= in) match = first;
+ } else if (first->col2 == edge->col2) {
+ if (first->next == 0) match = first;
+ else if (first->next->position >= edge->position) match = first;
+ } else if (first->col2 == edge->col1) {
+ match = 0; /* bij zigzagjes kan deze al 'ns foutief gezet zijn */
+ }
+ } else if (first->position == edge->position) {
+ if (first->col1 == edge->col1 || first->col2 == edge->col2) match = first;
+ } else {
+ if (match) break; /* er is er al een */
+
+ if (first->col1 == edge->col1) {
+ if (first->prev == 0) match = first;
+ else if (first->prev->position <= edge->position) match = first;
+ } else if (first->col2 == edge->col2) {
+ if (first->position <= out) match = first;
+ }
+ }
+
+ first = first->next;
+ }
+
+ return(match);
+}
+
+
+static void filterdraw(unsigned int * ldest, unsigned int * lsrce, int zero, int half, int step)
+{
+ uchar * src, * dst;
+ int count;
+ double weight, add;
+
+ /* we filteren de pixels op ldest tussen in en out met pixels van lsrce
+ * Het gewicht loopt ondertussen van 0 naar 1
+ */
+
+
+ count = half - zero;
+ if (count < 0) count = -count;
+ if (count <= 1) return;
+
+ if (zero < half) {
+ src = (uchar *) (lsrce + (step * zero));
+ dst = (uchar *) (ldest + (step * zero));
+ } else {
+ zero--;
+ src = (uchar *) (lsrce + (step * zero));
+ dst = (uchar *) (ldest + (step * zero));
+ step = -step;
+ }
+
+ step = 4 * step;
+
+ dst += step * (count >> 1);
+ src += step * (count >> 1);
+
+ count = (count + 1) >> 1;
+ add = 0.5 / count;
+ weight = 0.5 * add;
+
+ /* dit moet natuurlijk gamma gecorrigeerd */
+
+ for(; count > 0; count --) {
+ if (anti_a) dst[0] += weight * (src[0] - dst[0]);
+ if (anti_b) dst[1] += weight * (src[1] - dst[1]);
+ if (anti_g) dst[2] += weight * (src[2] - dst[2]);
+ if (anti_r) dst[3] += weight * (src[3] - dst[3]);
+ dst += step;
+ src += step;
+ weight += add;
+ }
+}
+
+static void filterimage(struct ImBuf * ibuf, struct ImBuf * cbuf, ListBase * listarray, int dir)
+{
+ int step, pixels, lines, nextline, y, pos, drawboth;
+ unsigned int * irect, * crect;
+ Edge * left, * middle, * right, temp, * any;
+
+ switch (dir) {
+ case 'h':
+ step = 1; nextline = ibuf->x;
+ pixels = ibuf->x; lines = ibuf->y;
+ break;
+ case 'v':
+ step = ibuf->x; nextline = 1;
+ pixels = ibuf->y; lines = ibuf->x;
+ }
+
+ for (y = 1; y < lines - 1; y++){
+ irect = ibuf->rect;
+ irect += y * nextline;
+ crect = cbuf->rect;
+ crect += y * nextline;
+
+ middle = listarray[y].first;
+ while (middle) {
+ left = findmatch(listarray[y - 1].first, middle);
+ right = findmatch(listarray[y + 1].first, middle);
+ drawboth = FALSE;
+
+ if (left == 0 || right == 0) {
+ /* rand */
+ any = left;
+ if (right) any = right;
+ if (any) {
+ /* spiegelen */
+ pos = 2 * middle->position - any->position;
+
+ if (any->position < middle->position) {
+ if (pos > pixels - 1) pos = pixels - 1;
+ if (middle->next) {
+ if (pos > middle->next->position) pos = middle->next->position;
+ }
+/* if (any->next) {
+ if (pos > any->next->position) pos = any->next->position;
+ }
+*/ } else {
+ if (pos < 0) pos = 0;
+ if (middle->prev) {
+ if (pos < middle->prev->position) pos = middle->prev->position;
+ }
+/* if (any->prev) {
+ if (pos < any->prev->position) pos = any->prev->position;
+ }
+*/ }
+ temp.position = pos;
+ if (left) right = &temp;
+ else left = &temp;
+ drawboth = TRUE;
+ }
+ } else if (left->position == middle->position || right->position == middle->position) {
+ /* recht stuk */
+ /* klein hoekje, met een van de twee op afstand 2 (ander is toch op afstand 0) ? */
+
+ if (abs(left->position - right->position) == 2) drawboth = TRUE;
+ } else if (left->position < middle->position && right->position > middle->position){
+ /* trap 1 */
+ drawboth = TRUE;
+ } else if (left->position > middle->position && right->position < middle->position){
+ /* trap 2 */
+ drawboth = TRUE;
+ } else {
+ /* piek */
+ drawboth = TRUE;
+ }
+
+ if (drawboth) {
+ filterdraw(irect, crect - nextline, left->position, middle->position, step);
+ filterdraw(irect, crect + nextline, right->position, middle->position, step);
+ }
+
+ middle = middle->next;
+ }
+ }
+}
+
+
+void IMB_antialias(struct ImBuf * ibuf)
+{
+ struct ImBuf * cbuf;
+ ListBase * listarray;
+
+ if (ibuf == 0) return;
+ cbuf = IMB_dupImBuf(ibuf);
+
+ anti_a = (anti_mask >> 24) & 0xff;
+ anti_b = (anti_mask >> 16) & 0xff;
+ anti_g = (anti_mask >> 8) & 0xff;
+ anti_r = (anti_mask >> 0) & 0xff;
+
+ listarray = scanimage(cbuf, 'h');
+ if (listarray) {
+ filterimage(ibuf, cbuf, listarray, 'h');
+ anti_free_listarray(ibuf->y, listarray);
+
+ listarray = scanimage(cbuf, 'v');
+ if (listarray) {
+ filterimage(ibuf, cbuf, listarray, 'v');
+ anti_free_listarray(ibuf->x, listarray);
+ }
+ }
+
+ IMB_freeImBuf(cbuf);
+}
+
+
+/* intelligente scaling */
+
+static void _intel_scale(struct ImBuf * ibuf, ListBase * listarray, int dir)
+{
+ int step, lines, nextline, x, y, col;
+ unsigned int * irect, * trect;
+ int start, end;
+ Edge * left, * right;
+ struct ImBuf * tbuf;
+
+ switch (dir) {
+ case 'h':
+ step = 1; nextline = ibuf->x;
+ lines = ibuf->y;
+ tbuf = IMB_double_fast_y(ibuf);
+ break;
+ case 'v':
+ step = 2 * ibuf->x; nextline = 1;
+ lines = ibuf->x;
+ tbuf = IMB_double_fast_x(ibuf);
+ break;
+ default:
+ return;
+ }
+
+ imb_freerectImBuf(ibuf);
+ ibuf->rect = tbuf->rect;
+ ibuf->mall |= IB_rect;
+
+
+ ibuf->x = tbuf->x;
+ ibuf->y = tbuf->y;
+ tbuf->rect = 0;
+ IMB_freeImBuf(tbuf);
+
+ for (y = 0; y < lines - 2; y++){
+ irect = ibuf->rect;
+ irect += ((2 * y) + 1) * nextline;
+
+ left = listarray[y].first;
+ while (left) {
+ right = findmatch(listarray[y + 1].first, left);
+ if (right) {
+ if (left->col2 == right->col2) {
+ if (left->next && right->next) {
+ if (left->next->position >= right->position) {
+ start = ((left->position + right->position) >> 1);
+ end = ((left->next->position + right->next->position) >> 1);
+ col = left->col2;
+ trect = irect + (start * step);
+ for (x = start; x < end; x++) {
+ *trect = col;
+ trect += step;
+ }
+ }
+ }
+ }
+
+ if (left->col1 == right->col1) {
+ if (left->prev && right->prev) {
+ if (left->prev->position <= right->position) {
+ end = ((left->position + right->position) >> 1);
+ start = ((left->prev->position + right->prev->position) >> 1);
+ col = left->col1;
+ trect = irect + (start * step);
+ for (x = start; x < end; x++) {
+ *trect = col;
+ trect += step;
+ }
+ }
+ }
+ }
+
+ }
+ left = left->next;
+ }
+ }
+}
+
+
+void IMB_clever_double(struct ImBuf * ibuf)
+{
+ ListBase * listarray, * curlist;
+ Edge * new;
+ int size;
+ int i;
+
+ if (ibuf == 0) return;
+
+ size = ibuf->x;
+ listarray = scanimage(ibuf, 'v');
+ if (listarray) {
+ for (i = 0; i < size; i++) {
+ curlist = listarray + i;
+ new = (Edge*)MEM_callocN(sizeof(Edge),"Edge");
+ new->col2 = ibuf->rect[i]; /* bovenste pixel */
+ new->col1 = new->col2 - 1;
+ BLI_addhead(curlist, new);
+ new = (Edge*)MEM_callocN(sizeof(Edge),"Edge");
+ new->position = ibuf->y - 1;
+ new->col1 = ibuf->rect[i + ((ibuf->y -1) * ibuf->x)]; /* onderste pixel */
+ new->col2 = new->col1 - 1;
+ BLI_addtail(curlist, new);
+ }
+ _intel_scale(ibuf, listarray, 'v');
+ anti_free_listarray(size, listarray);
+
+ size = ibuf->y;
+ listarray = scanimage(ibuf, 'h');
+ if (listarray) {
+ for (i = 0; i < size; i++) {
+ curlist = listarray + i;
+ new = (Edge*)MEM_callocN(sizeof(Edge),"Edge");
+ new->col2 = ibuf->rect[i * ibuf->x]; /* linkse pixel */
+ new->col1 = new->col2 - 1;
+ BLI_addhead(curlist, new);
+ new = (Edge*)MEM_callocN(sizeof(Edge),"Edge");
+ new->position = ibuf->x - 1;
+ new->col1 = ibuf->rect[((i + 1) * ibuf->x) - 1]; /* rechtse pixel */
+ new->col2 = new->col1 - 1;
+ BLI_addtail(curlist, new);
+ }
+ _intel_scale(ibuf, listarray, 'h');
+ anti_free_listarray(size, listarray);
+ }
+ }
+}