1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include "aalib.h"
5 #include "aaint.h"
6 #include "aamktabl.h"
7 #include "config.h"
8 aa_renderparams aa_defrenderparams =
9 {0, 0, 1.0, AA_FLOYD_S, 0, 0};
10 #define VAL (13)		/*maximum distance good for fill tables */
11 #define pos(i1,i2,i3,i4) (((int)(i1)<<12)+((int)(i2)<<8)+((int)(i3)<<4)+(int)(i4))
12 __AA_CONST char * __AA_CONST aa_dithernames[] =
13 {
14     "no dithering",
15     "error-distribution",
16     "floyd-steelberg dithering",
17     NULL
18 };
19 
20 #define DO_CONTRAST(i,c) (i<c?0:(i>256-c)?255:(i-c)*255/(255-2*c))
aa_getrenderparams(void)21 aa_renderparams *aa_getrenderparams(void)
22 {
23     aa_renderparams *p = calloc(1, sizeof(*p));
24     if (p == NULL)
25 	return NULL;
26     *p = aa_defrenderparams;
27     return (p);
28 }
29 #define MYLONG_MAX 0xffffffffU     /*this is enought for me. */
30 #define myrand() (random() & MYLONG_MAX)
31 
aa_renderpalette(aa_context * c,__AA_CONST aa_palette palette,__AA_CONST aa_renderparams * p,int x1,int y1,int x2,int y2)32 void aa_renderpalette(aa_context * c, __AA_CONST aa_palette palette, __AA_CONST aa_renderparams * p, int x1, int y1, int x2, int y2)
33 {
34     static int rand_init = 0;
35     int x, y;
36     int val;
37     int wi = c->imgwidth;
38     int pos;
39     int i;
40     int pos1;
41     int i1, i2, i3, i4, esum;
42     int *errors[2];
43     int cur = 0;
44     int mval;
45     int gamma = p->gamma != 1.0;
46 
47     int randomval = p->randomval;
48     int dither = p->dither;
49     aa_palette table;
50 
51     if (!rand_init) {
52        srandomdev();
53        rand_init = 1;
54     }
55     if (x2 < 0 || y2 < 0 || x1 > aa_scrwidth(c) || y1 > aa_scrheight(c))
56 	return;
57     if (x2 >= aa_scrwidth(c))
58 	x2 = aa_scrwidth(c);
59     if (y2 >= aa_scrheight(c))
60 	y2 = aa_scrheight(c);
61     if (x1 < 0)
62 	x1 = 0;
63     if (y1 < 0)
64 	y1 = 0;
65     if (c->table == NULL)
66 	aa_mktable(c);
67     if (dither == AA_FLOYD_S) {
68 	errors[0] = calloc(1, (x2 + 5) * sizeof(int));
69 	if (errors[0] == NULL)
70 	    dither = AA_ERRORDISTRIB;
71 	errors[0] += 3;
72 	errors[1] = calloc(1, (x2 + 5) * sizeof(int));
73 	if (errors[1] == NULL)
74 	    free(errors[0]), dither = AA_ERRORDISTRIB;
75 	errors[1] += 3;
76 	cur = 0;
77     }
78     for (i = 0; i < 256; i++) {
79 	y = palette[i] + p->bright;
80 	if (y > 255)
81 	    y = 255;
82 	if (y < 0)
83 	    y = 0;
84 	if (p->contrast)
85 	    y = DO_CONTRAST(y, p->contrast);
86 	if (gamma) {
87 	    y = pow(y / 255.0, p->gamma) * 255 + 0.5;
88 	}
89 	if (p->inversion)
90 	    y = 255 - y;
91 	if (y > 255)
92 	    y = 255;
93 	else if (y < 0)
94 	    y = 0;
95 	table[i] = y;
96     }
97     gamma = 0;
98     if (randomval)
99 	gamma = randomval / 2;
100     mval = (c->parameters[c->filltable[255]].p[4]);
101     for (y = y1; y < y2; y++) {
102 	pos = 2 * y * wi;
103 	pos1 = y * aa_scrwidth(c);
104 	esum = 0;
105 	for (x = x1; x < x2; x++) {
106 	    i1 = table[((((int) c->imagebuffer[pos])))];
107 	    i2 = table[((((int) c->imagebuffer[pos + 1])))];
108 	    i3 = table[((((int) c->imagebuffer[pos + wi])))];
109 	    i4 = table[((((int) c->imagebuffer[pos + 1 + wi])))];
110 	    if (gamma) {
111 		i = myrand();
112 		i1 += (i) % randomval - gamma;
113 		i2 += (i >> 8) % randomval - gamma;
114 		i3 += (i >> 16) % randomval - gamma;
115 		i4 += (i >> 24) % randomval - gamma;
116 		if ((i1 | i2 | i3 | i4) & (~255)) {
117 		    if (i1 < 0)
118 			i1 = 0;
119 		    else if (i1 > 255)
120 			i1 = 255;
121 		    if (i2 < 0)
122 			i2 = 0;
123 		    else if (i2 > 255)
124 			i2 = 255;
125 		    if (i3 < 0)
126 			i3 = 0;
127 		    else if (i3 > 255)
128 			i3 = 255;
129 		    if (i4 < 0)
130 			i4 = 0;
131 		    else if (i4 > 255)
132 			i4 = 255;
133 		}
134 	    }
135 	    switch (dither) {
136 	    case AA_ERRORDISTRIB:
137 		esum = (esum + 2) >> 2;
138 		i1 += esum;
139 		i2 += esum;
140 		i3 += esum;
141 		i4 += esum;
142 		break;
143 	    case AA_FLOYD_S:
144 		if (i1 | i2 | i3 | i4) {
145 		    errors[cur][x - 2] += esum >> 4;
146 		    errors[cur][x - 1] += (5 * esum) >> 4;
147 		    errors[cur][x] = (3 * esum) >> 4;
148 		    esum = (7 * esum) >> 4;
149 		    esum += errors[cur ^ 1][x];
150 		    i1 += (esum + 1) >> 2;
151 		    i2 += (esum) >> 2;
152 		    i3 += (esum + 3) >> 2;
153 		    i4 += (esum + 2) >> 2;
154 		}
155 		break;
156 	    }
157 	    if (dither) {
158 		esum = i1 + i2 + i3 + i4;
159 		val = (esum) >> 2;
160 		if ((abs(i1 - val) < VAL &&
161 		     abs(i2 - val) < VAL &&
162 		     abs(i3 - val) < VAL &&
163 		     abs(i4 - val) < VAL)) {
164 		    if (esum >= 4 * 256)
165 			val = 255, esum = 4 * 256 - 1;
166 		    if (val < 0)
167 			val = 0;
168 		    val = c->filltable[val];
169 		} else {
170 		    if ((i1 | i2 | i3 | i4) & (~255)) {
171 			if (i1 < 0)
172 			    i1 = 0;
173 			else if (i1 > 255)
174 			    i1 = 255;
175 			if (i2 < 0)
176 			    i2 = 0;
177 			else if (i2 > 255)
178 			    i2 = 255;
179 			if (i3 < 0)
180 			    i3 = 0;
181 			else if (i3 > 255)
182 			    i3 = 255;
183 			if (i4 < 0)
184 			    i4 = 0;
185 			else if (i4 > 255)
186 			    i4 = 255;
187 		    }
188 		    esum = i1 + i2 + i3 + i4;
189 		    i1 >>= 4;
190 		    i2 >>= 4;
191 		    i3 >>= 4;
192 		    i4 >>= 4;
193 		    val = c->table[pos(i2, i1, i4, i3)];
194 		}
195 		esum = (esum - (c->parameters[val].p[4]) * 1020 / mval);
196 	    } else {
197 		val = (i1 + i2 + i3 + i4) >> 2;
198 		if ((abs(i1 - val) < VAL &&
199 		     abs(i2 - val) < VAL &&
200 		     abs(i3 - val) < VAL &&
201 		     abs(i4 - val) < VAL)) {
202 		    val = c->filltable[val];
203 		} else {
204 		    i1 >>= 4;
205 		    i2 >>= 4;
206 		    i3 >>= 4;
207 		    i4 >>= 4;
208 		    val = c->table[pos(i2, i1, i4, i3)];
209 		}
210 	    }
211 	    c->attrbuffer[pos1] = val >> 8;
212 	    c->textbuffer[pos1] = val & 0xff;
213 	    pos += 2;
214 	    pos1++;
215 	}
216 	if (dither == AA_FLOYD_S) {
217 	    if (x2 - 1 > x1)
218 		errors[cur][x2 - 2] += (esum) >> 4;
219 	    if (x2 > x1)
220 		errors[cur][x2 - 1] += (5 * esum) >> 4;
221 	    cur ^= 1;
222 	    errors[cur][x1] = 0;
223 	    errors[cur ^ 1][-1] = 0;
224 	}
225     }
226     if (dither == AA_FLOYD_S) {
227 	free(errors[0] - 3);
228 	free(errors[1] - 3);
229     }
230 }
aa_render(aa_context * c,__AA_CONST aa_renderparams * p,int x1,int y1,int x2,int y2)231 void aa_render(aa_context * c, __AA_CONST aa_renderparams * p, int x1, int y1, int x2, int y2)
232 {
233     int i;
234     static aa_palette table;
235     if (table[255] != 255)
236 	for (i = 0; i < 256; i++) {
237 	    table[i] = i;
238 	}
239     aa_renderpalette(c, table, p, x1, y1, x2, y2);
240 }
241