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