]> Dogcows Code - chaz/openbox/blobdiff - render/image.c
remove trailing whitespace
[chaz/openbox] / render / image.c
index bdc51eeda04562f0856c58723255dea9902566a6..2eb043a25c72ddec769f0a2ac1d82e770de89a7c 100644 (file)
-#include <glib.h>
-#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(pixel32 *target, TextureRGBA *rgba, Rect *position,
-                Rect *surarea)
+#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)
 {
-  unsigned long *draw = rgba->data;
-  int c, sfw, sfh;
-  unsigned int i, e;
-  sfw = position->width;
-  sfh = position->height;
-
-  /* it would be nice if this worked, but this function is well broken in these
-     cercumstances. */
-  g_assert(position->width == surarea->width &&
-           position->height == surarea->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)
-        g_free(rgba->cache);
-    rgba->cache = g_new(unsigned long, 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;
+    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 *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, dw * dh);
+            ImageCopyResampled(rgba->cache, rgba->data, dw, dh, sw, sh);
+            rgba->cwidth = dw;
+            rgba->cheight = dh;
+        }
+        source = rgba->cache;
+    } else {
+        source = rgba->data;
+    }
+
+    /* copy source -> dest, and apply the alpha channel.
+
+       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;
+
+        /* apply the rgba's opacity as well */
+        alpha = ((*source >> RrDefaultAlphaOffset) * rgba->alpha) >> 8;
+        r = *source >> RrDefaultRedOffset;
+        g = *source >> RrDefaultGreenOffset;
+        b = *source >> RrDefaultBlueOffset;
 
-/* do we use the cache we may have just created, or the original? */
-    if (rgba->width != sfw || rgba->height != sfh)
-        draw = rgba->cache;
+        /* background color */
+        bgr = *dest >> RrDefaultRedOffset;
+        bgg = *dest >> RrDefaultGreenOffset;
+        bgb = *dest >> RrDefaultBlueOffset;
 
-    /* apply the alpha channel */
-    for (i = 0, c = 0, e = sfw*sfh; i < e; ++i) {
-      unsigned char alpha = draw[i] >> 24;
-      unsigned char r = draw[i] >> 16;
-      unsigned char g = draw[i] >> 8;
-      unsigned char b = draw[i];
+        r = bgr + (((r - bgr) * alpha) >> 8);
+        g = bgg + (((g - bgg) * alpha) >> 8);
+        b = bgb + (((b - bgb) * alpha) >> 8);
 
-      /* background color */
-      unsigned char bgr = target[i] >> default_red_shift;
-      unsigned char bgg = target[i] >> default_green_shift;
-      unsigned char bgb = target[i] >> default_blue_shift;
+        *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[i] = (r << default_red_shift) | (g << default_green_shift) |
-        (b << default_blue_shift);
+        if (++col >= dw) {
+            col = 0;
+            dest += target_w - dw;
+        }
     }
-  }
 }
This page took 0.030022 seconds and 4 git commands to generate.