update forward page cache docs
[alioth/magicpoint.git] / background.c
1 /*
2  * Copyright (C) 1997 and 1998 WIDE Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. Neither the name of the project nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <math.h>
30 #include "mgp.h"
31
32 /* background gradation */
33 #define G_PI    3.1415926535897932385
34 #define G_PI2   1.5707963267948966192
35
36 static void draw_gradation0(int, int, int, int, int, int,
37         byte *, byte *, int, int, u_int);
38 static void g_rotate(byte *, struct ctrl_grad *, int, int);
39
40 /*
41  * generate gradation for single color plane.
42  * x: color plane
43  * y: axis for gradation
44  * z: extra axis
45  */
46 static void
47 draw_gradation0(int x1, int x2, int y1v, int y2, int z1, int z2,
48     byte *p1, byte *p2, /* delta p in x/y direction */ int dpy, int dpz,
49     u_int mask)
50 {
51         int s, step;
52         int dx, dy;
53         int z;
54         byte *p;
55
56         dx = abs(x2 - x1);
57         dy = abs(y2 - y1v);
58
59         if (dx > dy) {
60                 if (x1 > x2) {
61                         step = (y1v > y2) ? 1 : -1;
62                         s = x1; x1 = x2; x2 = s; /*swap*/
63                         y1v = y2;
64                         p = p2;
65                 } else {
66                         step = (y1v < y2) ? 1 : -1;
67                         p = p1;
68                 }
69
70                 for (z = z1; z < z2; z++)
71                         *(p + z * dpz) = x1 & mask;
72                 s = dx >> 1;
73                 while (++x1 <= x2) {
74                         if ((s -= dy) < 0) {
75                                 s += dx;
76                                 y1v += step;
77                                 p += (dpy * step);
78                         }
79                         for (z = z1; z < z2; z+=3){
80                                 *(p + z * dpz) =     x1 * (30 + (y1v % 3)) / 32 & mask;
81                                 *(p + (z+1) * dpz) = x1 * (30 + ((y1v + 2) % 3)) / 32 & mask;
82                                 *(p + (z+2) * dpz) = x1 * (30 + ((y1v + 1) % 3)) / 32 & mask;
83                         }
84                 }
85         } else {
86                 if (y1v > y2) {
87                         step = (x1 > x2) ? 1 : -1;
88                         s = y1v; y1v = y2; y2 = s; /*swap*/
89                         x1 = x2;
90                         p = p2;
91                 } else {
92                         step = (x1 < x2) ? 1 : -1;
93                         p = p1;
94                 }
95
96                 for (z = z1; z < z2; z++)
97                         *(p + z * dpz) = x1 & mask;
98                 s = dy >> 1;
99                 while (++y1v <= y2) {
100                         p += dpy;       /*y always inc*/
101                         if ((s -= dx) < 0) {
102                                 s += dy;
103                                 x1 += step;
104                         }
105                         for (z = z1; z < z2; z+=3){
106                                 *(p + z * dpz) =     x1 * (30 + (y1v % 3)) / 32 & mask;
107                                 *(p + (z+1) * dpz) = x1 * (30 + ((y1v + 2) % 3)) / 32 & mask;
108                                 *(p + (z+2) * dpz) = x1 * (30 + ((y1v + 1) % 3)) / 32 & mask;
109                         }
110                 }
111         }
112 }
113
114 byte *
115 draw_gradation(int width, int height, struct ctrl_grad *cg)
116 {
117         int bmask[8] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
118         byte *pic;
119         const u_int bits = 8;
120         int i, j;
121         int x1 = 0, x2 = 0;
122         int y1v = 0, y2 = 0, dpy = 0;
123         int z1 = 0, z2 = 0, dpz = 0;
124         byte *p1 = NULL, *p2 = NULL;
125         byte mask;
126
127         pic = (byte *)malloc(width * height * 3 * sizeof(byte));
128         if (!pic) {
129                 fprintf(stderr,"couldn't alloc space for gradation image\n");
130                 return NULL;
131         }
132
133         memset(pic, 0, width * height * 3 * sizeof(byte));
134
135         if (cg->ct_direction % 90) {
136                 g_rotate(pic, cg, width, height);
137                 return pic;
138         }
139
140         for (j = 0; j < 3; j++) {       /*r, g, b*/
141                 for (i = 0; i < cg->ct_g_colors - 1; i++) {
142                         switch (j) {
143                         case 0:
144                                 x1 = cg->colors[i]->r;
145                                 x2 = cg->colors[i + 1]->r;
146                                 break;
147                         case 1:
148                                 x1 = cg->colors[i]->g;
149                                 x2 = cg->colors[i + 1]->g;
150                                 break;
151                         case 2:
152                                 x1 = cg->colors[i]->b;
153                                 x2 = cg->colors[i + 1]->b;
154                                 break;
155                         }
156
157                         mask = bmask[bits - 1];
158                         switch (cg->ct_direction) {
159                         case 0:
160                                 y1v = ((height - 1) * i) / (cg->ct_g_colors - 1);
161                                 y2 = ((height - 1) * (i + 1))
162                                         / (cg->ct_g_colors - 1);
163                                 p1 = pic + j + width * 3 * y1v;
164                                 p2 = pic + j + width * 3 * y2;
165                                 z1 = 0;
166                                 z2 = width;
167                                 dpy = width * 3;
168                                 dpz = 3;
169                                 break;
170                         case 90:
171                                 y1v = ((width - 1) * i) / (cg->ct_g_colors - 1);
172                                 y2 = ((width - 1) * (i + 1))
173                                         / (cg->ct_g_colors - 1);
174                                 p1 = pic + j + 3 * y1v;
175                                 p2 = pic + j + 3 * y2;
176                                 z1 = 0;
177                                 z2 = height;
178                                 dpy = 3;
179                                 dpz = width * 3;
180                                 break;
181                         case 180:
182                                 y1v = ((height - 1) * (cg->ct_g_colors - i - 1))
183                                         / (cg->ct_g_colors - 1);
184                                 y2 = ((height - 1) * (cg->ct_g_colors - i - 2))
185                                         / (cg->ct_g_colors - 1);
186                                 p1 = pic + j + width * 3 * y1v;
187                                 p2 = pic + j + width * 3 * y2;
188                                 z1 = 0;
189                                 z2 = width;
190                                 dpy = width * 3;
191                                 dpz = 3;
192                                 break;
193                         case 270:
194                                 y1v = ((width - 1) * (cg->ct_g_colors - i - 1))
195                                         / (cg->ct_g_colors - 1);
196                                 y2 = ((width - 1) * (cg->ct_g_colors - i - 2))
197                                         / (cg->ct_g_colors - 1);
198                                 p1 = pic + j + 3 * y1v;
199                                 p2 = pic + j + 3 * y2;
200                                 z1 = 0;
201                                 z2 = height;
202                                 dpy = 3;
203                                 dpz = width * 3;
204                                 break;
205                         }
206                         draw_gradation0(x1, x2, y1v, y2, z1, z2, p1, p2,
207                                 dpy, dpz, mask);
208                 }
209         }
210
211         return pic;
212 }
213
214 static double cost, sint;
215 static double cos2t, sin2t;
216 static double dcost, dsint;
217
218 /* rotate graphic */
219 static void
220 g_rotate(byte *pic, struct ctrl_grad *cg, int width, int height)
221 {
222     byte *pp;
223     double maxd, mind, del, d, rat, crat, cval;
224     double theta, dy, ey, td1, td2;
225     int    x, y, cx, cy, r, g, b, bc, nc1;
226     int    rot, mode;
227     struct g_color * c1;
228     struct g_color * c2;
229
230     rot   = cg->ct_direction;
231     mode  = cg->ct_mode;
232
233     cx = width/2;  cy = height/2;
234     theta = (double) rot * G_PI / 180.0;
235     cost  = cos(theta);
236     sint  = sin(theta);
237     dsint = sint*sint;
238     dcost = cost*cost;
239     sin2t = sin(2*theta);
240     cos2t = cos(2*theta);
241
242     nc1 = cg->ct_g_colors - 1;
243
244     /* compute max/min distances */
245     if (rot > 0 && rot < 90) {
246         mind = cdist(0, 0, cx, cy, rot, mode);
247         maxd = cdist(width-1, height-1, cx, cy, rot, mode);
248     }
249     else if (rot >= 90 && rot < 180) {
250         mind = cdist(0, height-1, cx, cy, rot, mode);
251         maxd = cdist(width-1, 0,  cx, cy, rot, mode);
252     }
253     else if (rot >= 180 && rot < 270) {
254         mind = cdist(width-1, height-1, cx, cy, rot, mode);
255         maxd = cdist(0, 0, cx, cy, rot, mode);
256     }
257     else {
258         mind = cdist(width-1,  0, cx, cy, rot, mode);
259         maxd = cdist(0, height-1, cx, cy, rot, mode);
260     }
261
262     del = maxd - mind;         /* maximum distance */
263
264     /* loop start */
265
266     td1 = cx - cx*dcost;
267     td2 = cy + 0.5*cx*sin2t;
268
269     for (y = 0; y < height; y++) {
270         pp = pic + (y * width * 3);
271         dy = (cy-y)*0.5*sin2t + td1;
272         ey = (y-cy)*dsint + td2;
273
274         for (x = 0; x < width; x++) {
275             d = lcdist(x, y, cx, cy, rot, mode, dy, ey);
276             rat = (d - mind) / del;
277
278             if (rat < 0.0){
279                 cval = bc = crat = 0.0;
280             } else if (rat > 1.0){
281                 cval = bc = (double)nc1;
282                 crat = 0.0;
283             } else {
284                 cval = rat * nc1;
285                 bc   = floor(cval);
286                 crat = cval - bc;
287             }
288
289             if (bc < nc1) {
290                 c1 = (cg->colors)[bc];
291                 c2 = (cg->colors)[bc+1];
292
293                 r = c1->r + crat * ((c2->r) - (c1->r));
294                 g = c1->g + crat * ((c2->g) - (c1->g));
295                 b = c1->b + crat * ((c2->b) - (c1->b));
296             } else {
297                 c1 = (cg->colors)[nc1];
298                 r = c1->r; g = c1->g; b = c1->b;
299             }
300             *pp++ = (byte) r;  *pp++ = (byte) g;  *pp++ = (byte) b;
301         }
302     }
303 }
304
305 /* compute distance */
306 double cdist(int x, int y, int cx, int cy, int rot, int mode)
307 {
308     double x1, y1v, x2, y2, x3, d ;
309
310     /* special case */
311     if (rot == 0)   return (double) (y - cy);
312     if (rot == 90)  return (double) (x - cx);
313     if (rot == 180) return (double) (cy - y);
314     if (rot == 270) return (double) (cx - x);
315
316 /* experimental routine for circle patern gradation */
317     if (mode == 1) {
318         d = sqrt((y-cy)*(y-cy)*cost + (x-cx)*(x-cx)*sint);
319         if (x + y - cy < 0) d = -d;
320         return d;
321     }
322
323     /* x1,y1v = original point */
324     x1 = (double) x;  y1v = (double) y;
325     x2 = cx + (cy-y1v)*0.5*sin2t - (cx-x1)*dcost;
326     y2 = cy - (cy-y1v)*dsint + (cx-x1)*0.5*sin2t;
327     x3 = x1-x2;
328
329     d = sqrt(x3*x3 + (y1v - y2)*(y1v - y2));
330     if ((rot < 180 && x3<0) || (rot > 180 && x3>0)) d = -d;
331     return d;
332 }
333
334 double lcdist(int x, int y, int cx, int cy, int rot, int mode,
335     double dy, double ey)
336 {
337     double x1, y1v, x2, y2, x3, d ;
338
339     /* special case */
340     if (rot == 0)   return (double) (y - cy);
341     if (rot == 90)  return (double) (x - cx);
342     if (rot == 180) return (double) (cy - y);
343     if (rot == 270) return (double) (cx - x);
344
345 /* experimental routine for circle patern gradation */
346     if (mode == 1) {
347         d = sqrt((y-cy)*(y-cy)*cost + (x-cx)*(x-cx)*sint);
348         if (x + y - cy < 0) d = -d;
349         return d;
350     }
351
352     x1 = (double) x;
353     y1v = (double) y;
354
355     x2 = dy + x1*dcost;
356     y2 = ey - x1*0.5*sin2t;
357     x3 = x1-x2;
358
359     d = sqrt(x3*x3 + (y1v - y2)*(y1v - y2));
360     if ((rot < 180 && x3<0) || (rot > 180 && x3>0)) d = -d;
361     return d;
362 }
363
364 Image *
365 make_XImage(byte *pic, u_int width, u_int height)
366 {
367     Image        *image;
368
369     /* make Image structure (stolen from image/new.c)*/
370     image= (Image *)lmalloc(sizeof(Image));
371     image->type= ITRUE;
372     image->title= strdup("");
373     image->rgb.used= image->rgb.size= 0;
374     image->width= width;
375     image->height= height;
376     image->depth= 24;
377     image->pixlen= 3;
378     image->data= pic;
379
380     return(image);
381 }