OSDN Git Service

ソキ・ネ・鬣テ・ラ。「キルハヨ、ノイテ。」
[hengband/hengband.git] / src / maid-x11.c
1 /* File: maid-x11.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison, and others
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.
9  */
10
11 #include <math.h>
12
13
14 /*
15  * This file defines some "XImage" manipulation functions for X11.
16  *
17  * Original code by Desvignes Sebastien (desvigne@solar12.eerie.fr).
18  *
19  * BMP format support by Denis Eropkin (denis@dream.homepage.ru).
20  *
21  * Major fixes and cleanup by Ben Harrison (benh@phial.com).
22  *
23  * This file is designed to be "included" by "main-x11.c" or "main-xaw.c",
24  * which will have already "included" several relevant header files.
25  */
26
27
28
29 #ifndef IsModifierKey
30
31 /*
32  * Keysym macros, used on Keysyms to test for classes of symbols
33  * These were stolen from one of the X11 header files
34  *
35  * Also appears in "main-x11.c".
36  */
37
38 #define IsKeypadKey(keysym) \
39   (((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal))
40
41 #define IsCursorKey(keysym) \
42   (((unsigned)(keysym) >= XK_Home)     && ((unsigned)(keysym) <  XK_Select))
43
44 #define IsPFKey(keysym) \
45   (((unsigned)(keysym) >= XK_KP_F1)     && ((unsigned)(keysym) <= XK_KP_F4))
46
47 #define IsFunctionKey(keysym) \
48   (((unsigned)(keysym) >= XK_F1)       && ((unsigned)(keysym) <= XK_F35))
49
50 #define IsMiscFunctionKey(keysym) \
51   (((unsigned)(keysym) >= XK_Select)   && ((unsigned)(keysym) <  XK_KP_Space))
52
53 #define IsModifierKey(keysym) \
54   (((unsigned)(keysym) >= XK_Shift_L)  && ((unsigned)(keysym) <= XK_Hyper_R))
55
56 #endif /* IsModifierKey */
57
58
59 /*
60  * Checks if the keysym is a special key or a normal key
61  * Assume that XK_MISCELLANY keysyms are special
62  *
63  * Also appears in "main-x11.c".
64  */
65 #define IsSpecialKey(keysym) \
66   ((unsigned)(keysym) >= 0xFF00)
67
68
69 #ifdef SUPPORT_GAMMA
70 static bool gamma_table_ready = FALSE;
71 #endif /* SUPPORT_GAMMA */
72
73
74 /*
75  * Hack -- Convert an RGB value to an X11 Pixel, or die.
76  */
77 static unsigned long create_pixel(Display *dpy, byte red, byte green, byte blue)
78 {
79         Colormap cmap = DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy));
80         XColor xcolour;
81
82 #ifdef SUPPORT_GAMMA
83
84         int gamma = 0;
85
86         if (!gamma_table_ready)
87         {
88                 cptr str = getenv("ANGBAND_X11_GAMMA");
89                 if (str != NULL) gamma = atoi(str);
90                 
91                 gamma_table_ready = TRUE;
92                 
93                 /* Only need to build the table if gamma exists */
94                 if (gamma) build_gamma_table(gamma);
95         }
96
97         /* Hack -- Gamma Correction */
98         if (gamma > 0)
99         {
100                 red = gamma_table[red];
101                 green = gamma_table[green];
102                 blue = gamma_table[blue];
103         }
104
105 #endif /* SUPPORT_GAMMA */
106
107         /* Build the color */
108         
109         xcolour.red = red * 255;
110         xcolour.green = green * 255;
111         xcolour.blue = blue * 255;
112         xcolour.flags = DoRed | DoGreen | DoBlue;
113
114         /* Attempt to Allocate the Parsed color */
115         if (!(XAllocColor(dpy, cmap, &xcolour)))
116         {
117                 quit_fmt("Couldn't allocate bitmap color '#%02x%02x%02x'\n",
118                          red, green, blue);
119         }
120
121         return (xcolour.pixel);
122 }
123
124
125
126 #ifdef USE_GRAPHICS
127
128 /*
129  * The Win32 "BITMAPFILEHEADER" type.
130  *
131  * Note the "bfAlign" field, which is a complete hack to ensure that the
132  * "u32b" fields in the structure get aligned.  Thus, when reading this
133  * header from the file, we must be careful to skip this field.
134  */
135 typedef struct BITMAPFILEHEADER
136 {
137         u16b bfAlign;    /* HATE this */
138         u16b bfType;
139         u32b bfSize;
140         u16b bfReserved1;
141         u16b bfReserved2;
142         u32b bfOffBits;
143 } BITMAPFILEHEADER;
144
145 /*
146  * The Win32 "BITMAPINFOHEADER" type.
147  */
148 typedef struct BITMAPINFOHEADER
149 {
150         u32b biSize;
151         u32b biWidth;
152         u32b biHeight;
153         u16b biPlanes;
154         u16b biBitCount;
155         u32b biCompresion;
156         u32b biSizeImage;
157         u32b biXPelsPerMeter;
158         u32b biYPelsPerMeter;
159         u32b biClrUsed;
160         u32b biClrImportand;
161 } BITMAPINFOHEADER;
162
163 /*
164  * The Win32 "RGBQUAD" type.
165  */
166 typedef struct RGBQUAD
167 {
168         unsigned char b, g, r;
169         unsigned char filler;
170 } RGBQUAD;
171
172
173 /*
174  * Read a Win32 BMP file.
175  *
176  * This function replaces the old ReadRaw and RemapColors functions.
177  *
178  * Assumes that the bitmap has a size such that no padding is needed in
179  * various places.  Currently only handles bitmaps with 3 to 256 colors.
180  */
181 static XImage *ReadBMP(Display *dpy, char *Name)
182 {
183         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
184
185         int depth = DefaultDepth(dpy, DefaultScreen(dpy));
186
187         FILE *f;
188
189         BITMAPFILEHEADER fileheader;
190         BITMAPINFOHEADER infoheader;
191
192         vptr fileheaderhack = (vptr)((char *)(&fileheader) + 2);
193
194         XImage *Res = NULL;
195
196         char *Data;
197
198         int ncol;
199
200         int total;
201
202         int i, j;
203
204         int x, y;
205
206         unsigned long clr_pixels[256];
207
208
209         /* Open the BMP file */
210         f = fopen(Name, "r");
211
212         /* No such file */
213         if (f == NULL)
214         {
215                 return (NULL);
216         }
217
218         /* Read the "BITMAPFILEHEADER" */
219         fread(fileheaderhack, sizeof(fileheader) - 2, 1, f);
220
221         /* Read the "BITMAPINFOHEADER" */
222         fread(&infoheader, sizeof(infoheader), 1, f);
223
224         /* Verify the header */
225         if (feof(f) ||
226             (fileheader.bfType != 19778) ||
227             (infoheader.biSize != 40))
228         {
229                 quit_fmt("Incorrect BMP file format %s", Name);
230         }
231
232         /* The two headers above occupy 54 bytes total */
233         /* The "bfOffBits" field says where the data starts */
234         /* The "biClrUsed" field does not seem to be reliable */
235         /* Compute number of colors recorded */
236         ncol = (fileheader.bfOffBits - 54) / 4;
237
238         for (i = 0; i < ncol; i++)
239         {
240                 RGBQUAD clrg;
241
242                 fread(&clrg, 4, 1, f);
243                 
244                 /* Analyze the color */
245                 clr_pixels[i] = create_pixel(dpy, clrg.r, clrg.g, clrg.b);
246         }
247
248         /* Determine total bytes needed for image */
249         i = 1;
250         j = (depth - 1) >> 2;
251         while (j >>= 1) i <<= 1;
252         total = infoheader.biWidth * infoheader.biHeight * i;
253
254         /* Allocate image memory */
255         C_MAKE(Data, total, char);
256
257         Res = XCreateImage(dpy, visual, depth, ZPixmap, 0 /*offset*/,
258                            Data, infoheader.biWidth, infoheader.biHeight,
259                            8 /*bitmap_pad*/, 0 /*bytes_per_line*/);
260
261         /* Failure */
262         if (Res == NULL)
263         {
264                 C_KILL(Data, total, char);
265                 fclose(f);
266                 return (NULL);
267         }
268
269         for (y = 0; y < infoheader.biHeight; y++)
270         {
271                 int y2 = infoheader.biHeight - y - 1;
272
273                 for (x = 0; x < infoheader.biWidth; x++)
274                 {
275                         int ch = getc(f);
276
277                         /* Verify not at end of file XXX XXX */
278                         if (feof(f)) quit_fmt("Unexpected end of file in %s", Name);
279
280                         if (infoheader.biBitCount == 24)
281                         {
282                                 int c2 = getc(f);
283                                 int c3 = getc(f);
284
285                                 /* Verify not at end of file XXX XXX */
286                                 if (feof(f)) quit_fmt("Unexpected end of file in %s", Name);
287
288                                 XPutPixel(Res, x, y2, create_pixel(dpy, ch, c2, c3));
289                         }
290                         else if (infoheader.biBitCount == 8)
291                         {
292                                 XPutPixel(Res, x, y2, clr_pixels[ch]);
293                         }
294                         else if (infoheader.biBitCount == 4)
295                         {
296                                 XPutPixel(Res, x, y2, clr_pixels[ch / 16]);
297                                 x++;
298                                 XPutPixel(Res, x, y2, clr_pixels[ch % 16]);
299                         }
300                         else
301                         {
302                                 /* Technically 1 bit is legal too */
303                                 quit_fmt("Illegal biBitCount %d in %s",
304                                          infoheader.biBitCount, Name);
305                         }
306                 }
307         }
308
309         fclose(f);
310
311         return Res;
312 }
313
314
315 /* ========================================================*/
316 /* Code for smooth icon rescaling from Uwe Siems, Jan 2000 */
317 /* ========================================================*/
318
319 /*
320  * to save ourselves some labour, define a maximum expected icon width here:
321  */
322 #define MAX_ICON_WIDTH 32
323
324
325 /* some static variables for composing and decomposing pixel values into
326  * red, green and blue values
327  */
328 static unsigned long redMask, greenMask, blueMask;
329 static int redShift, greenShift, blueShift;
330
331
332 /*
333  * Use smooth rescaling?
334  */
335 static bool smoothRescaling = TRUE;
336
337
338 /*
339  * GetScaledRow reads a scan from the given XImage, scales it smoothly
340  * and returns the red, green and blue values in arrays.
341  * The values in this arrays must be divided by a certain value that is
342  * calculated in ScaleIcon.
343  * x, y is the position, iw is the input width and ow the output width
344  * redScan, greenScan and blueScan must be sufficiently sized
345  */
346 static void GetScaledRow(XImage *Im, int x, int y, int iw, int ow,
347                          unsigned long *redScan, unsigned long *greenScan,
348                          unsigned long *blueScan)
349 {
350         int xi, si, sifrac, ci, cifrac, addWhole, addFrac;
351         unsigned long pix;
352         int prevRed, prevGreen, prevBlue, nextRed, nextGreen, nextBlue;
353         bool getNextPix;
354
355         if (iw == ow)
356         {
357                 /* unscaled */
358                 for (xi = 0; xi < ow; xi++)
359                 {
360                         pix = XGetPixel(Im, x + xi, y);
361                         redScan   [xi] = (pix >> redShift) & redMask;
362                         greenScan [xi] = (pix >> greenShift) & greenMask;
363                         blueScan  [xi] = (pix >> blueShift) & blueMask;
364                 }
365         }
366         else if (iw < ow)
367         {
368                 /* scaling by subsampling (grow) */
369                 iw--;
370                 ow--;
371                 /* read first pixel: */
372                 pix = XGetPixel(Im, x, y);
373                 nextRed   = (pix >> redShift) & redMask;
374                 nextGreen = (pix >> greenShift) & greenMask;
375                 nextBlue  = (pix >> blueShift) & blueMask;
376                 prevRed   = nextRed;
377                 prevGreen = nextGreen;
378                 prevBlue  = nextBlue;
379                 /* si and sifrac give the subsampling position: */
380                 si = x;
381                 sifrac = 0;
382                 /* getNextPix tells us, that we need the next pixel */
383                 getNextPix = TRUE;
384
385                 for (xi = 0; xi <= ow; xi++)
386                 {
387                         if (getNextPix)
388                         {
389                                 prevRed   = nextRed;
390                                 prevGreen = nextGreen;
391                                 prevBlue  = nextBlue;
392                                 if (xi < ow)
393                                 {
394                                         /* only get next pixel if in same icon */
395                                         pix = XGetPixel(Im, si + 1, y);
396                                         nextRed   = (pix >> redShift) & redMask;
397                                         nextGreen = (pix >> greenShift) & greenMask;
398                                         nextBlue  = (pix >> blueShift) & blueMask;
399                                 }
400                         }
401
402                         /* calculate subsampled color values: */
403                         /* division by ow occurs in ScaleIcon */
404                         redScan   [xi] = prevRed   * (ow - sifrac) + nextRed   * sifrac;
405                         greenScan [xi] = prevGreen * (ow - sifrac) + nextGreen * sifrac;
406                         blueScan  [xi] = prevBlue  * (ow - sifrac) + nextBlue  * sifrac;
407
408                         /* advance sampling position: */
409                         sifrac += iw;
410                         if (sifrac >= ow)
411                         {
412                                 si++;
413                                 sifrac -= ow;
414                                 getNextPix = TRUE;
415                         }
416                         else
417                         {
418                                 getNextPix = FALSE;
419                         }
420
421                 }
422         }
423         else
424         {
425                 /* scaling by averaging (shrink) */
426                 /* width of an output pixel in input pixels: */
427                 addWhole = iw / ow;
428                 addFrac = iw % ow;
429                 /* start position of the first output pixel: */
430                 si = x;
431                 sifrac = 0;
432                 /* get first input pixel: */
433                 pix = XGetPixel(Im, x, y);
434                 nextRed   = (pix >> redShift) & redMask;
435                 nextGreen = (pix >> greenShift) & greenMask;
436                 nextBlue  = (pix >> blueShift) & blueMask;
437                 for (xi = 0; xi < ow; xi++)
438                 {
439                         /* find endpoint of the current output pixel: */
440                         ci = si + addWhole;
441                         cifrac = sifrac + addFrac;
442                         if (cifrac >= ow)
443                         {
444                                 ci++;
445                                 cifrac -= ow;
446                         }
447                         /* take fraction of current input pixel (starting segment): */
448                         redScan[xi]   = nextRed   * (ow - sifrac);
449                         greenScan[xi] = nextGreen * (ow - sifrac);
450                         blueScan[xi]  = nextBlue  * (ow - sifrac);
451                         si++;
452                         /* add values for whole pixels: */
453                         while (si < ci)
454                         {
455                                 pix = XGetPixel(Im, si, y);
456                                 redScan[xi]   += ((pix >> redShift) & redMask)   *ow;
457                                 greenScan[xi] += ((pix >> greenShift) & greenMask) *ow;
458                                 blueScan[xi]  += ((pix >> blueShift) & blueMask)   *ow;
459                                 si++;
460                         }
461                         /* add fraction of current input pixel (ending segment): */
462                         if (xi < ow - 1)
463                         {
464                                 /* only get next pixel if still in icon: */
465                                 pix = XGetPixel(Im, si, y);
466                                 nextRed   = (pix >> redShift) & redMask;
467                                 nextGreen = (pix >> greenShift) & greenMask;
468                                 nextBlue  = (pix >> blueShift) & blueMask;
469                         }
470                         sifrac = cifrac;
471                         if (sifrac > 0)
472                         {
473                                 redScan[xi]   += nextRed   * sifrac;
474                                 greenScan[xi] += nextGreen * sifrac;
475                                 blueScan[xi]  += nextBlue  * sifrac;
476                         }
477                 }
478         }
479 }
480
481
482 /*
483  * PutRGBScan takes arrays for red, green and blue and writes pixel values
484  * according to this values in the XImage-structure. w is the number of
485  * pixels to write and div is the value by which all red/green/blue values
486  * are divided first.
487  */
488 static void PutRGBScan(XImage *Im, int x, int y, int w, int div,
489                        unsigned long *redScan, unsigned long *greenScan,
490                        unsigned long *blueScan)
491 {
492         int xi;
493         unsigned long pix;
494         unsigned long adj = div / 2;
495         for (xi = 0; xi < w; xi++)
496         {
497                 pix = (((((redScan[xi] + adj) / div) & redMask) << redShift) +
498                        ((((greenScan[xi] + adj) / div) & greenMask) << greenShift) +
499                        ((((blueScan[xi] + adj) / div) & blueMask) << blueShift));
500                 XPutPixel(Im, x + xi, y, pix);
501         }
502 }
503
504
505 /*
506  * ScaleIcon transfers an area from XImage ImIn, locate (x1,y1) to ImOut,
507  * locate (x2, y2).
508  * Source size is (ix, iy) and destination size is (ox, oy).
509  * It does this by getting icon scan line from GetScaledScan and handling
510  * them the same way as pixels are handled in GetScaledScan.
511  * This even allows icons to be scaled differently in horizontal and
512  * vertical directions (eg. shrink horizontal, grow vertical).
513  */
514 static void ScaleIcon(XImage *ImIn, XImage *ImOut,
515                       int x1, int y1, int x2, int y2,
516                       int ix, int iy, int ox, int oy)
517 {
518         int div;
519         int xi, yi, si, sifrac, ci, cifrac, addWhole, addFrac;
520
521         /* buffers for pixel rows: */
522         unsigned long prevRed   [MAX_ICON_WIDTH];
523         unsigned long prevGreen [MAX_ICON_WIDTH];
524         unsigned long prevBlue  [MAX_ICON_WIDTH];
525         unsigned long nextRed   [MAX_ICON_WIDTH];
526         unsigned long nextGreen [MAX_ICON_WIDTH];
527         unsigned long nextBlue  [MAX_ICON_WIDTH];
528         unsigned long tempRed   [MAX_ICON_WIDTH];
529         unsigned long tempGreen [MAX_ICON_WIDTH];
530         unsigned long tempBlue  [MAX_ICON_WIDTH];
531
532         bool getNextRow;
533
534         /* get divider value for the horizontal scaling: */
535         if (ix == ox)
536                 div = 1;
537         else if (ix < ox)
538                 div = ox - 1;
539         else
540                 div = ix;
541
542         if (iy == oy)
543         {
544                 /* no scaling needed vertically: */
545                 for (yi = 0; yi < oy; yi++)
546                 {
547                         GetScaledRow(ImIn, x1, y1 + yi, ix, ox,
548                                      tempRed, tempGreen, tempBlue);
549                         PutRGBScan(ImOut, x2, y2 + yi, ox, div,
550                                    tempRed, tempGreen, tempBlue);
551                 }
552         }
553         else if (iy < oy)
554         {
555                 /* scaling by subsampling (grow): */
556                 iy--;
557                 oy--;
558                 div *= oy;
559                 /* get first row: */
560                 GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue);
561                 /* si and sifrac give the subsampling position: */
562                 si = y1;
563                 sifrac = 0;
564                 /* getNextRow tells us, that we need the next row */
565                 getNextRow = TRUE;
566                 for (yi = 0; yi <= oy; yi++)
567                 {
568                         if (getNextRow)
569                         {
570                                 for (xi = 0; xi < ox; xi++)
571                                 {
572                                         prevRed[xi]   = nextRed[xi];
573                                         prevGreen[xi] = nextGreen[xi];
574                                         prevBlue[xi]  = nextBlue[xi];
575                                 }
576                                 if (yi < oy)
577                                 {
578                                         /* only get next row if in same icon */
579                                         GetScaledRow(ImIn, x1, si + 1, ix, ox,
580                                                      nextRed, nextGreen, nextBlue);
581                                 }
582                         }
583
584                         /* calculate subsampled color values: */
585                         /* division by oy occurs in PutRGBScan */
586                         for (xi = 0; xi < ox; xi++)
587                         {
588                                 tempRed[xi] = (prevRed[xi] * (oy - sifrac) +
589                                                nextRed[xi] * sifrac);
590                                 tempGreen[xi] = (prevGreen[xi] * (oy - sifrac) +
591                                                  nextGreen[xi] * sifrac);
592                                 tempBlue[xi] = (prevBlue[xi] * (oy - sifrac) +
593                                                 nextBlue[xi] * sifrac);
594                         }
595
596                         /* write row to output image: */
597                         PutRGBScan(ImOut, x2, y2 + yi, ox, div,
598                                    tempRed, tempGreen, tempBlue);
599
600                         /* advance sampling position: */
601                         sifrac += iy;
602                         if (sifrac >= oy)
603                         {
604                                 si++;
605                                 sifrac -= oy;
606                                 getNextRow = TRUE;
607                         }
608                         else
609                         {
610                                 getNextRow = FALSE;
611                         }
612
613                 }
614         }
615         else
616         {
617                 /* scaling by averaging (shrink) */
618                 div *= iy;
619                 /* height of a output row in input rows: */
620                 addWhole = iy / oy;
621                 addFrac = iy % oy;
622                 /* start position of the first output row: */
623                 si = y1;
624                 sifrac = 0;
625                 /* get first input row: */
626                 GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue);
627                 for (yi = 0; yi < oy; yi++)
628                 {
629                         /* find endpoint of the current output row: */
630                         ci = si + addWhole;
631                         cifrac = sifrac + addFrac;
632                         if (cifrac >= oy)
633                         {
634                                 ci++;
635                                 cifrac -= oy;
636                         }
637                         /* take fraction of current input row (starting segment): */
638                         for (xi = 0; xi < ox; xi++)
639                         {
640                                 tempRed[xi]   = nextRed[xi]   * (oy - sifrac);
641                                 tempGreen[xi] = nextGreen[xi] * (oy - sifrac);
642                                 tempBlue[xi]  = nextBlue[xi]  * (oy - sifrac);
643                         }
644                         si++;
645                         /* add values for whole pixels: */
646                         while (si < ci)
647                         {
648                                 GetScaledRow(ImIn, x1, si, ix, ox,
649                                              nextRed, nextGreen, nextBlue);
650                                 for (xi = 0; xi < ox; xi++)
651                                 {
652                                         tempRed[xi]   += nextRed[xi]   * oy;
653                                         tempGreen[xi] += nextGreen[xi] * oy;
654                                         tempBlue[xi]  += nextBlue[xi]  * oy;
655                                 }
656                                 si++;
657                         }
658                         /* add fraction of current input row (ending segment): */
659                         if (yi < oy - 1)
660                         {
661                                 /* only get next row if still in icon: */
662                                 GetScaledRow(ImIn, x1, si, ix, ox,
663                                              nextRed, nextGreen, nextBlue);
664                         }
665                         sifrac = cifrac;
666                         for (xi = 0; xi < ox; xi++)
667                         {
668                                 tempRed[xi]   += nextRed[xi]   * sifrac;
669                                 tempGreen[xi] += nextGreen[xi] * sifrac;
670                                 tempBlue[xi]  += nextBlue[xi]  * sifrac;
671                         }
672                         /* write row to output image: */
673                         PutRGBScan(ImOut, x2, y2 + yi, ox, div,
674                                    tempRed, tempGreen, tempBlue);
675                 }
676         }
677 }
678
679
680
681 static XImage *ResizeImageSmooth(Display *dpy, XImage *Im,
682                                  int ix, int iy, int ox, int oy)
683 {
684         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
685
686         int width1, height1, width2, height2;
687         int x1, x2, y1, y2;
688
689         XImage *Tmp;
690
691         char *Data;
692
693         width1 = Im->width;
694         height1 = Im->height;
695
696         width2 = ox * width1 / ix;
697         height2 = oy * height1 / iy;
698
699         Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8);
700
701         Tmp = XCreateImage(dpy, visual,
702                            Im->depth, ZPixmap, 0, Data, width2, height2,
703                            32, 0);
704
705         /* compute values for decomposing pixel into color values: */
706         redMask = Im->red_mask;
707         redShift = 0;
708         while ((redMask & 1) == 0)
709         {
710             redShift++;
711             redMask >>= 1;
712         }
713         greenMask = Im->green_mask;
714         greenShift = 0;
715         while ((greenMask & 1) == 0)
716         {
717             greenShift++;
718             greenMask >>= 1;
719         }
720         blueMask = Im->blue_mask;
721         blueShift = 0;
722         while ((blueMask & 1) == 0)
723         {
724             blueShift++;
725             blueMask >>= 1;
726         }
727
728         /* scale each icon: */
729         for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); y1 += iy, y2 += oy)
730         {
731                 for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); x1 += ix, x2 += ox)
732                 {
733                         ScaleIcon(Im, Tmp, x1, y1, x2, y2,
734                                   ix, iy, ox, oy);
735                 }
736         }
737
738         return Tmp;
739 }
740
741
742 /*
743  * Resize an image. XXX XXX XXX
744  *
745  * Also appears in "main-xaw.c".
746  */
747 static XImage *ResizeImage(Display *dpy, XImage *Im,
748                            int ix, int iy, int ox, int oy)
749 {
750         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
751
752         int width1, height1, width2, height2;
753         int x1, x2, y1, y2, Tx, Ty;
754         int *px1, *px2, *dx1, *dx2;
755         int *py1, *py2, *dy1, *dy2;
756
757         XImage *Tmp;
758
759         char *Data;
760
761         if (smoothRescaling && (ix != ox || iy != oy) &&
762             visual->class == TrueColor)
763         {
764             return ResizeImageSmooth(dpy, Im, ix, iy, ox, oy);
765         }
766
767         width1 = Im->width;
768         height1 = Im->height;
769
770         width2 = ox * width1 / ix;
771         height2 = oy * height1 / iy;
772
773         Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8);
774
775         Tmp = XCreateImage(dpy, visual,
776                            Im->depth, ZPixmap, 0, Data, width2, height2,
777                            32, 0);
778
779         if (ix > ox)
780         {
781                 px1 = &x1;
782                 px2 = &x2;
783                 dx1 = &ix;
784                 dx2 = &ox;
785         }
786         else
787         {
788                 px1 = &x2;
789                 px2 = &x1;
790                 dx1 = &ox;
791                 dx2 = &ix;
792         }
793
794         if (iy > oy)
795         {
796                 py1 = &y1;
797                 py2 = &y2;
798                 dy1 = &iy;
799                 dy2 = &oy;
800         }
801         else
802         {
803                 py1 = &y2;
804                 py2 = &y1;
805                 dy1 = &oy;
806                 dy2 = &iy;
807         }
808
809         Ty = *dy1/2;
810
811         for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); )
812         {
813                 Tx = *dx1/2;
814
815                 for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); )
816                 {
817                         XPutPixel(Tmp, x2, y2, XGetPixel(Im, x1, y1));
818
819                         (*px1)++;
820
821                         Tx -= *dx2;
822                         if (Tx < 0)
823                         {
824                                 Tx += *dx1;
825                                 (*px2)++;
826                         }
827                 }
828
829                 (*py1)++;
830
831                 Ty -= *dy2;
832                 if (Ty < 0)
833                 {
834                         Ty += *dy1;
835                         (*py2)++;
836                 }
837         }
838
839         return Tmp;
840 }
841
842 #endif /* USE_GRAPHICS */
843
844