moved over the polyfiller code and implemented blending
[bootcensus] / src / census / gfxutil.c
1 #include "gfxutil.h"
2 #include "census.h"
3
4 enum {
5         IN              = 0,
6         LEFT    = 1,
7         RIGHT   = 2,
8         TOP             = 4,
9         BOTTOM  = 8
10 };
11
12 static int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax)
13 {
14         int code = 0;
15
16         if(x < xmin) {
17                 code |= LEFT;
18         } else if(x > xmax) {
19                 code |= RIGHT;
20         }
21         if(y < ymin) {
22                 code |= TOP;
23         } else if(y > ymax) {
24                 code |= BOTTOM;
25         }
26         return code;
27 }
28
29 #define FIXMUL(a, b)    (((a) * (b)) >> 8)
30 #define FIXDIV(a, b)    (((a) << 8) / (b))
31
32 #define LERP(a, b, t)   ((a) + FIXMUL((b) - (a), (t)))
33
34 int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax)
35 {
36         int oc_out;
37
38         int oc0 = outcode(*x0, *y0, xmin, ymin, xmax, ymax);
39         int oc1 = outcode(*x1, *y1, xmin, ymin, xmax, ymax);
40
41         long fx0, fy0, fx1, fy1, fxmin, fymin, fxmax, fymax;
42
43         if(!(oc0 | oc1)) return 1;      /* both points are inside */
44
45         fx0 = *x0 << 8;
46         fy0 = *y0 << 8;
47         fx1 = *x1 << 8;
48         fy1 = *y1 << 8;
49         fxmin = xmin << 8;
50         fymin = ymin << 8;
51         fxmax = xmax << 8;
52         fymax = ymax << 8;
53
54         for(;;) {
55                 long x, y, t;
56
57                 if(oc0 & oc1) return 0;         /* both have points with the same outbit, not visible */
58                 if(!(oc0 | oc1)) break;         /* both points are inside */
59
60                 oc_out = oc0 ? oc0 : oc1;
61
62                 if(oc_out & TOP) {
63                         t = FIXDIV(fymin - fy0, fy1 - fy0);
64                         x = LERP(fx0, fx1, t);
65                         y = fymin;
66                 } else if(oc_out & BOTTOM) {
67                         t = FIXDIV(fymax - fy0, fy1 - fy0);
68                         x = LERP(fx0, fx1, t);
69                         y = fymax;
70                 } else if(oc_out & LEFT) {
71                         t = FIXDIV(fxmin - fx0, fx1 - fx0);
72                         x = fxmin;
73                         y = LERP(fy0, fy1, t);
74                 } else if(oc_out & RIGHT) {
75                         t = FIXDIV(fxmax - fx0, fx1 - fx0);
76                         x = fxmax;
77                         y = LERP(fy0, fy1, t);
78                 }
79
80                 if(oc_out == oc0) {
81                         fx0 = x;
82                         fy0 = y;
83                         oc0 = outcode(fx0 >> 8, fy0 >> 8, xmin, ymin, xmax, ymax);
84                 } else {
85                         fx1 = x;
86                         fy1 = y;
87                         oc1 = outcode(fx1 >> 8, fy1 >> 8, xmin, ymin, xmax, ymax);
88                 }
89         }
90
91         *x0 = fx0 >> 8;
92         *y0 = fy0 >> 8;
93         *x1 = fx1 >> 8;
94         *y1 = fy1 >> 8;
95         return 1;
96 }
97
98 void draw_line(int x0, int y0, int x1, int y1, uint32_t color)
99 {
100         int i, dx, dy, x_inc, y_inc, error;
101         uint32_t *fb = fb_pixels;
102
103         fb += y0 * fb_width + x0;
104
105         dx = x1 - x0;
106         dy = y1 - y0;
107
108         if(dx >= 0) {
109                 x_inc = 1;
110         } else {
111                 x_inc = -1;
112                 dx = -dx;
113         }
114         if(dy >= 0) {
115                 y_inc = fb_width;
116         } else {
117                 y_inc = -fb_width;
118                 dy = -dy;
119         }
120
121         if(dx > dy) {
122                 error = dy * 2 - dx;
123                 for(i=0; i<=dx; i++) {
124                         *fb = color;
125                         if(error >= 0) {
126                                 error -= dx * 2;
127                                 fb += y_inc;
128                         }
129                         error += dy * 2;
130                         fb += x_inc;
131                 }
132         } else {
133                 error = dx * 2 - dy;
134                 for(i=0; i<=dy; i++) {
135                         *fb = color;
136                         if(error >= 0) {
137                                 error -= dy * 2;
138                                 fb += x_inc;
139                         }
140                         error += dx * 2;
141                         fb += y_inc;
142                 }
143         }
144 }
145
146
147 #define BLUR(w, h, pstep, sstep) \
148         for(i=0; i<h; i++) { \
149                 int sum = sptr[0] * (rad + 1); \
150                 int count = (rad * 2 + 1) << 8; \
151                 int midsize = w - rad * 2; \
152                 int firstpix = sptr[0]; \
153                 int lastpix = sptr[pstep * (w - 1)]; \
154                 /* add up the contributions for the -1 pixel */ \
155                 for(j=0; j<rad; j++) { \
156                         sum += sptr[pstep * j]; \
157                 } \
158                 /* first part adding sptr[rad] and subtracting sptr[0] */ \
159                 for(j=0; j<=rad; j++) { \
160                         sum += (int)sptr[pstep * rad] - firstpix; \
161                         sptr += pstep; \
162                         *dptr = scale * sum / count; \
163                         dptr += pstep; \
164                 } \
165                 /* middle part adding sptr[rad] and subtracting sptr[-(rad+1)] */ \
166                 for(j=1; j<midsize; j++) { \
167                         sum += (int)sptr[pstep * rad] - (int)sptr[-(rad + 1) * pstep]; \
168                         sptr += pstep; \
169                         *dptr = scale * sum / count; \
170                         dptr += pstep; \
171                 } \
172                 /* last part adding lastpix and subtracting sptr[-(rad+1)] */ \
173                 for(j=0; j<rad; j++) { \
174                         sum += lastpix - (int)sptr[-(rad + 1) * pstep]; \
175                         sptr += pstep; \
176                         *dptr = scale * sum / count; \
177                         dptr += pstep; \
178                 } \
179                 sptr += sstep; \
180                 dptr += sstep; \
181         }
182
183 /* TODO bound blur rad to image size to avoid inner loop conditionals */
184 /* TODO make version with pow2 (rad*2+1) to avoid div with count everywhere */
185 void blur_grey_horiz(uint32_t *dest, uint32_t *src, int xsz, int ysz, int rad, int scale)
186 {
187         int i, j;
188         unsigned char *dptr = (unsigned char*)dest;
189         unsigned char *sptr = (unsigned char*)src;
190
191         BLUR(xsz, ysz, 2, 0);
192 }
193
194
195 void blur_grey_vert(uint32_t *dest, uint32_t *src, int xsz, int ysz, int rad, int scale)
196 {
197         int i, j;
198         unsigned char *dptr = (unsigned char*)dest;
199         unsigned char *sptr = (unsigned char*)src;
200         int pixel_step = xsz * 2;
201         int scanline_step = 2 - ysz * pixel_step;
202
203         BLUR(ysz, xsz, pixel_step, scanline_step);
204 }
205
206 void convimg_rgb24_rgb16(uint16_t *dest, unsigned char *src, int xsz, int ysz)
207 {
208         int i;
209         int npixels = xsz * ysz;
210
211         for(i=0; i<npixels; i++) {
212                 int r = *src++;
213                 int g = *src++;
214                 int b = *src++;
215                 *dest++ = PACK_RGB16(r, g, b);
216         }
217 }