fixed loading screen. regression in blitfb
[dosdemo] / src / gfxutil.c
1 #include <string.h>
2 #include "demo.h"
3 #include "gfxutil.h"
4
5 enum {
6         IN              = 0,
7         LEFT    = 1,
8         RIGHT   = 2,
9         TOP             = 4,
10         BOTTOM  = 8
11 };
12
13 static int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax)
14 {
15         int code = 0;
16
17         if(x < xmin) {
18                 code |= LEFT;
19         } else if(x > xmax) {
20                 code |= RIGHT;
21         }
22         if(y < ymin) {
23                 code |= TOP;
24         } else if(y > ymax) {
25                 code |= BOTTOM;
26         }
27         return code;
28 }
29
30 #define FIXMUL(a, b)    (((a) * (b)) >> 8)
31 #define FIXDIV(a, b)    (((a) << 8) / (b))
32
33 #define LERP(a, b, t)   ((a) + FIXMUL((b) - (a), (t)))
34
35 int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax)
36 {
37         int oc_out;
38
39         int oc0 = outcode(*x0, *y0, xmin, ymin, xmax, ymax);
40         int oc1 = outcode(*x1, *y1, xmin, ymin, xmax, ymax);
41
42         long fx0, fy0, fx1, fy1, fxmin, fymin, fxmax, fymax;
43
44         if(!(oc0 | oc1)) return 1;      /* both points are inside */
45
46         fx0 = *x0 << 8;
47         fy0 = *y0 << 8;
48         fx1 = *x1 << 8;
49         fy1 = *y1 << 8;
50         fxmin = xmin << 8;
51         fymin = ymin << 8;
52         fxmax = xmax << 8;
53         fymax = ymax << 8;
54
55         for(;;) {
56                 long x, y, t;
57
58                 if(oc0 & oc1) return 0;         /* both have points with the same outbit, not visible */
59                 if(!(oc0 | oc1)) break;         /* both points are inside */
60
61                 oc_out = oc0 ? oc0 : oc1;
62
63                 if(oc_out & TOP) {
64                         t = FIXDIV(fymin - fy0, fy1 - fy0);
65                         x = LERP(fx0, fx1, t);
66                         y = fymin;
67                 } else if(oc_out & BOTTOM) {
68                         t = FIXDIV(fymax - fy0, fy1 - fy0);
69                         x = LERP(fx0, fx1, t);
70                         y = fymax;
71                 } else if(oc_out & LEFT) {
72                         t = FIXDIV(fxmin - fx0, fx1 - fx0);
73                         x = fxmin;
74                         y = LERP(fy0, fy1, t);
75                 } else if(oc_out & RIGHT) {
76                         t = FIXDIV(fxmax - fx0, fx1 - fx0);
77                         x = fxmax;
78                         y = LERP(fy0, fy1, t);
79                 }
80
81                 if(oc_out == oc0) {
82                         fx0 = x;
83                         fy0 = y;
84                         oc0 = outcode(fx0 >> 8, fy0 >> 8, xmin, ymin, xmax, ymax);
85                 } else {
86                         fx1 = x;
87                         fy1 = y;
88                         oc1 = outcode(fx1 >> 8, fy1 >> 8, xmin, ymin, xmax, ymax);
89                 }
90         }
91
92         *x0 = fx0 >> 8;
93         *y0 = fy0 >> 8;
94         *x1 = fx1 >> 8;
95         *y1 = fy1 >> 8;
96         return 1;
97 }
98
99 void draw_line(int x0, int y0, int x1, int y1, unsigned short color)
100 {
101         int i, dx, dy, x_inc, y_inc, error;
102         unsigned short *fb = fb_pixels;
103
104         fb += y0 * FB_WIDTH + x0;
105
106         dx = x1 - x0;
107         dy = y1 - y0;
108
109         if(dx >= 0) {
110                 x_inc = 1;
111         } else {
112                 x_inc = -1;
113                 dx = -dx;
114         }
115         if(dy >= 0) {
116                 y_inc = FB_WIDTH;
117         } else {
118                 y_inc = -FB_WIDTH;
119                 dy = -dy;
120         }
121
122         if(dx > dy) {
123                 error = dy * 2 - dx;
124                 for(i=0; i<=dx; i++) {
125                         *fb = color;
126                         if(error >= 0) {
127                                 error -= dx * 2;
128                                 fb += y_inc;
129                         }
130                         error += dy * 2;
131                         fb += x_inc;
132                 }
133         } else {
134                 error = dx * 2 - dy;
135                 for(i=0; i<=dy; i++) {
136                         *fb = color;
137                         if(error >= 0) {
138                                 error -= dy * 2;
139                                 fb += x_inc;
140                         }
141                         error += dx * 2;
142                         fb += y_inc;
143                 }
144         }
145 }
146
147
148 #define BLUR(w, h, pstep, sstep) \
149         for(i=0; i<h; i++) { \
150                 int r, g, b; \
151                 int rsum = UNPACK_R16(sptr[0]) * (rad + 1); \
152                 int gsum = UNPACK_G16(sptr[0]) * (rad + 1); \
153                 int bsum = UNPACK_B16(sptr[0]) * (rad + 1); \
154                 int count = (rad * 2 + 1) << 8; \
155                 int midsize = w - rad * 2; \
156                 int rfirstpix = UNPACK_R16(sptr[0]); \
157                 int rlastpix = UNPACK_R16(sptr[pstep * (w - 1)]); \
158                 int gfirstpix = UNPACK_G16(sptr[0]); \
159                 int glastpix = UNPACK_G16(sptr[pstep * (w - 1)]); \
160                 int bfirstpix = UNPACK_B16(sptr[0]); \
161                 int blastpix = UNPACK_B16(sptr[pstep * (w - 1)]); \
162                 /* add up the contributions for the -1 pixel */ \
163                 for(j=0; j<rad; j++) { \
164                         rsum += UNPACK_R16(sptr[pstep * j]); \
165                         gsum += UNPACK_G16(sptr[pstep * j]); \
166                         bsum += UNPACK_B16(sptr[pstep * j]); \
167                 } \
168                 /* first part adding sptr[rad] and subtracting sptr[0] */ \
169                 for(j=0; j<=rad; j++) { \
170                         rsum += UNPACK_R16((int)sptr[pstep * rad]) - rfirstpix; \
171                         gsum += UNPACK_G16((int)sptr[pstep * rad]) - gfirstpix; \
172                         bsum += UNPACK_B16((int)sptr[pstep * rad]) - bfirstpix; \
173                         sptr += pstep; \
174                         r = scale * rsum / count; \
175                         g = scale * gsum / count; \
176                         b = scale * bsum / count; \
177                         *dptr = PACK_RGB16(r, g, b); \
178                         dptr += pstep; \
179                 } \
180                 /* middle part adding sptr[rad] and subtracting sptr[-(rad+1)] */ \
181                 for(j=1; j<midsize; j++) { \
182                         rsum += UNPACK_R16((int)sptr[pstep * rad]) - UNPACK_R16((int)sptr[-(rad + 1) * pstep]); \
183                         gsum += UNPACK_G16((int)sptr[pstep * rad]) - UNPACK_G16((int)sptr[-(rad + 1) * pstep]); \
184                         bsum += UNPACK_B16((int)sptr[pstep * rad]) - UNPACK_B16((int)sptr[-(rad + 1) * pstep]); \
185                         sptr += pstep; \
186                         r = scale * rsum / count; \
187                         g = scale * gsum / count; \
188                         b = scale * bsum / count; \
189                         *dptr = PACK_RGB16(r, g, b); \
190                         dptr += pstep; \
191                 } \
192                 /* last part adding lastpix and subtracting sptr[-(rad+1)] */ \
193                 for(j=0; j<rad; j++) { \
194                         rsum += rlastpix - UNPACK_R16((int)sptr[-(rad + 1) * pstep]); \
195                         gsum += glastpix - UNPACK_G16((int)sptr[-(rad + 1) * pstep]); \
196                         bsum += blastpix - UNPACK_B16((int)sptr[-(rad + 1) * pstep]); \
197                         sptr += pstep; \
198                         r = scale * rsum / count; \
199                         g = scale * gsum / count; \
200                         b = scale * bsum / count; \
201                         *dptr = PACK_RGB16(r, g, b); \
202                         dptr += pstep; \
203                 } \
204                 sptr += sstep; \
205                 dptr += sstep; \
206         }
207
208 /* TODO bound blur rad to image size to avoid inner loop conditionals */
209 /* TODO make version with pow2 (rad*2+1) to avoid div with count everywhere */
210 void blur_horiz(uint16_t *dest, uint16_t *src, int xsz, int ysz, int rad, int scale)
211 {
212         int i, j;
213         uint16_t *dptr = dest;
214         uint16_t *sptr = src;
215
216         BLUR(xsz, ysz, 1, 0);
217 }
218
219
220 void blur_vert(uint16_t *dest, uint16_t *src, int xsz, int ysz, int rad, int scale)
221 {
222         int i, j;
223         uint16_t *dptr = dest;
224         uint16_t *sptr = src;
225         int pixel_step = xsz;
226         int scanline_step = 1 - ysz * pixel_step;
227
228         BLUR(ysz, xsz, pixel_step, scanline_step);
229 }
230
231 void convimg_rgb24_rgb16(uint16_t *dest, unsigned char *src, int xsz, int ysz)
232 {
233         int i;
234         int npixels = xsz * ysz;
235
236         for(i=0; i<npixels; i++) {
237                 int r = *src++;
238                 int g = *src++;
239                 int b = *src++;
240                 *dest++ = PACK_RGB16(r, g, b);
241         }
242 }
243
244 void blitfb(uint16_t *dest, uint16_t *src, int width, int height, int pitch_pix)
245 {
246         int i;
247         for(i=0; i<height; i++) {
248                 memcpy(dest, src, width << 1);
249                 dest += 320;
250                 src += pitch_pix;
251         }
252 }
253
254 void blit(uint16_t *dest, int destwidth, uint16_t *src, int width, int height, int pitch_pix)
255 {
256         int i, spansz = width << 1;
257         for(i=0; i<height; i++) {
258                 memcpy(dest, src, spansz);
259                 dest += destwidth;
260                 src += pitch_pix;
261         }
262 }
263
264 void blit_key(uint16_t *dest, int destwidth, uint16_t *src, int width, int height, int pitch_pix, uint16_t key)
265 {
266         int i, j;
267         int dadv = destwidth - width;
268         int sadv = pitch_pix - width;
269
270         for(i=0; i<height; i++) {
271                 for(j=0; j<width; j++) {
272                         uint16_t scol = *src++;
273                         if(scol != key) *dest = scol;
274                         dest++;
275                 }
276                 dest += dadv;
277                 src += sadv;
278         }
279
280 }