OSDN Git Service

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