]> Dogcows Code - chaz/openbox/blobdiff - render/image.c
remove trailing whitespace
[chaz/openbox] / render / image.c
index 6667abf7829dbdfb4a1ba571ea9c32b899496443..2eb043a25c72ddec769f0a2ac1d82e770de89a7c 100644 (file)
-#include "../kernel/geom.h"
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   image.c for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   Copyright (c) 2003-2007   Dana Jansens
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "geom.h"
 #include "image.h"
 #include "color.h"
 
 #include <glib.h>
 
-void image_draw(RrPixel32 *target, RrTextureRGBA *rgba, Rect *area)
+#define FRACTION        12
+#define FLOOR(i)        ((i) & (~0UL << FRACTION))
+#define AVERAGE(a, b)   (((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b)))
+
+static void ImageCopyResampled(RrPixel32 *dst, RrPixel32 *src,
+                               gulong dstW, gulong dstH,
+                               gulong srcW, gulong srcH)
+{
+    gulong dstX, dstY, srcX, srcY;
+    gulong srcX1, srcX2, srcY1, srcY2;
+    gulong ratioX, ratioY;
+
+    ratioX = (srcW << FRACTION) / dstW;
+    ratioY = (srcH << FRACTION) / dstH;
+
+    srcY2 = 0;
+    for (dstY = 0; dstY < dstH; dstY++) {
+        srcY1 = srcY2;
+        srcY2 += ratioY;
+
+        srcX2 = 0;
+        for (dstX = 0; dstX < dstW; dstX++) {
+            gulong red = 0, green = 0, blue = 0, alpha = 0;
+            gulong portionX, portionY, portionXY, sumXY = 0;
+            RrPixel32 pixel;
+
+            srcX1 = srcX2;
+            srcX2 += ratioX;
+
+            for (srcY = srcY1; srcY < srcY2; srcY += (1UL << FRACTION)) {
+                if (srcY == srcY1) {
+                    srcY = FLOOR(srcY);
+                    portionY = (1UL << FRACTION) - (srcY1 - srcY);
+                    if (portionY > srcY2 - srcY1)
+                        portionY = srcY2 - srcY1;
+                }
+                else if (srcY == FLOOR(srcY2))
+                    portionY = srcY2 - srcY;
+                else
+                    portionY = (1UL << FRACTION);
+
+                for (srcX = srcX1; srcX < srcX2; srcX += (1UL << FRACTION)) {
+                    if (srcX == srcX1) {
+                        srcX = FLOOR(srcX);
+                        portionX = (1UL << FRACTION) - (srcX1 - srcX);
+                        if (portionX > srcX2 - srcX1)
+                            portionX = srcX2 - srcX1;
+                    }
+                    else if (srcX == FLOOR(srcX2))
+                        portionX = srcX2 - srcX;
+                    else
+                        portionX = (1UL << FRACTION);
+
+                    portionXY = (portionX * portionY) >> FRACTION;
+                    sumXY += portionXY;
+
+                    pixel = *(src + (srcY >> FRACTION) * srcW
+                            + (srcX >> FRACTION));
+                    red   += ((pixel >> RrDefaultRedOffset)   & 0xFF)
+                             * portionXY;
+                    green += ((pixel >> RrDefaultGreenOffset) & 0xFF)
+                             * portionXY;
+                    blue  += ((pixel >> RrDefaultBlueOffset)  & 0xFF)
+                             * portionXY;
+                    alpha += ((pixel >> RrDefaultAlphaOffset) & 0xFF)
+                             * portionXY;
+                }
+            }
+
+            g_assert(sumXY != 0);
+            red   /= sumXY;
+            green /= sumXY;
+            blue  /= sumXY;
+            alpha /= sumXY;
+
+            *dst++ = (red   << RrDefaultRedOffset)   |
+                     (green << RrDefaultGreenOffset) |
+                     (blue  << RrDefaultBlueOffset)  |
+                     (alpha << RrDefaultAlphaOffset);
+        }
+    }
+}
+
+void RrImageDraw(RrPixel32 *target, RrTextureRGBA *rgba,
+                 gint target_w, gint target_h,
+                 RrRect *area)
 {
-    RrPixel32 *draw = rgba->data;
-    gint c, i, e, t, sfw, sfh;
-    sfw = area->width;
-    sfh = area->height;
-
-    g_assert(rgba->data != NULL);
-
-    if ((rgba->width != sfw || rgba->height != sfh) &&
-        (rgba->width != rgba->cwidth || rgba->height != rgba->cheight)) {
-        double dx = rgba->width / (double)sfw;
-        double dy = rgba->height / (double)sfh;
-        double px = 0.0;
-        double py = 0.0;
-        int iy = 0;
-
-        /* scale it and cache it */
-        if (rgba->cache != NULL)
+    RrPixel32 *dest;
+    RrPixel32 *source;
+    gint sw, sh, dw, dh;
+    gint col, num_pixels;
+
+    sw = rgba->width;
+    sh = rgba->height;
+
+    /* keep the ratio */
+    dw = area->width;
+    dh = (gint)(dw * ((gdouble)sh / sw));
+    if (dh > area->height) {
+        dh = area->height;
+        dw = (gint)(dh * ((gdouble)sw / sh));
+    }
+
+    if (!(dw && dh))
+        return; /* XXX sanity check */
+
+    if (sw != dw || sh != dh) {
+        /*if (!(rgba->cache && dw == rgba->cwidth && dh == rgba->cheight))*/ {
             g_free(rgba->cache);
-        rgba->cache = g_new(RrPixel32, sfw * sfh);
-        rgba->cwidth = sfw;
-        rgba->cheight = sfh;
-        for (i = 0, c = 0, e = sfw*sfh; i < e; ++i) {
-            rgba->cache[i] = rgba->data[(int)px + iy];
-            if (++c >= sfw) {
-                c = 0;
-                px = 0;
-                py += dy;
-                iy = (int)py * rgba->width;
-            } else
-                px += dx;
+            rgba->cache = g_new(RrPixel32, dw * dh);
+            ImageCopyResampled(rgba->cache, rgba->data, dw, dh, sw, sh);
+            rgba->cwidth = dw;
+            rgba->cheight = dh;
         }
+        source = rgba->cache;
+    } else {
+        source = rgba->data;
+    }
 
-        /* do we use the cache we may have just created, or the original? */
-        if (rgba->width != sfw || rgba->height != sfh)
-            draw = rgba->cache;
+    /* copy source -> dest, and apply the alpha channel.
 
-        /* apply the alpha channel */
-        for (i = 0, c = 0, t = area->x, e = sfw*sfh; i < e; ++i, ++t) {
-            guchar alpha, r, g, b, bgr, bgg, bgb;
+       center the image if it is smaller than the area */
+    col = 0;
+    num_pixels = dw * dh;
+    dest = target + area->x + (area->width - dw) / 2 +
+        (target_w * (area->y + (area->height - dh) / 2));
+    while (num_pixels-- > 0) {
+        guchar alpha, r, g, b, bgr, bgg, bgb;
 
-            alpha = draw[i] >> default_alpha_offset;
-            r = draw[i] >> default_red_offset;
-            g = draw[i] >> default_green_offset;
-            b = draw[i] >> default_blue_offset;
+        /* apply the rgba's opacity as well */
+        alpha = ((*source >> RrDefaultAlphaOffset) * rgba->alpha) >> 8;
+        r = *source >> RrDefaultRedOffset;
+        g = *source >> RrDefaultGreenOffset;
+        b = *source >> RrDefaultBlueOffset;
 
-            if (c >= sfw) {
-                c = 0;
-                t += area->width - sfw;
-            }
+        /* background color */
+        bgr = *dest >> RrDefaultRedOffset;
+        bgg = *dest >> RrDefaultGreenOffset;
+        bgb = *dest >> RrDefaultBlueOffset;
+
+        r = bgr + (((r - bgr) * alpha) >> 8);
+        g = bgg + (((g - bgg) * alpha) >> 8);
+        b = bgb + (((b - bgb) * alpha) >> 8);
 
-            /* background color */
-            bgr = target[t] >> default_red_offset;
-            bgg = target[t] >> default_green_offset;
-            bgb = target[t] >> default_blue_offset;
+        *dest = ((r << RrDefaultRedOffset) |
+                 (g << RrDefaultGreenOffset) |
+                 (b << RrDefaultBlueOffset));
 
-            r = bgr + (((r - bgr) * alpha) >> 8);
-            g = bgg + (((g - bgg) * alpha) >> 8);
-            b = bgb + (((b - bgb) * alpha) >> 8);
+        dest++;
+        source++;
 
-            target[t] = (r << default_red_offset)
-                      | (g << default_green_offset)
-                      | (b << default_blue_offset);
+        if (++col >= dw) {
+            col = 0;
+            dest += target_w - dw;
         }
     }
 }
This page took 0.026857 seconds and 4 git commands to generate.