]> Dogcows Code - chaz/openbox/commitdiff
new scaling, based on the Bresenham algorithm
authorDana Jansens <danakj@orodu.net>
Thu, 4 Sep 2003 06:23:27 +0000 (06:23 +0000)
committerDana Jansens <danakj@orodu.net>
Thu, 4 Sep 2003 06:23:27 +0000 (06:23 +0000)
render/image.c

index 2ec710438cd32632cb8f09aabd97c7404373b1f9..7e29aa6e756d8a579c2d9facbfc94dcb9a4ca49f 100644 (file)
 
 #include <glib.h>
 
-void RrImageDraw(RrPixel32 *target, RrTextureRGBA *rgba, RrRect *area)
+#define AVERAGE(a, b)   ( ((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b)) )
+
+static void scale_line(RrPixel32 *dest, RrPixel32 *source, gint w, gint dw)
 {
-    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)
-            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;
+    gint num_pixels = dw;
+    gint int_part = w / dw;
+    gint fract_part = w % dw;
+    gint err = 0;
+
+    while (num_pixels-- > 0) {
+        *dest++ = *source;
+        source += int_part;
+        err += fract_part;
+        if (err >= dw) {
+            err -= dw;
+            source++;
         }
+    }
+}
+
+static RrPixel32* scale_half(RrPixel32 *source, gint w, gint h)
+{
+    RrPixel32 *out, *dest, *sourceline, *sourceline2;
+    gint dw, dh, x, y;
+
+    sourceline = source;
+    sourceline2 = source + w;
+
+    dw = w >> 1;
+    dh = h >> 1;
+
+    out = dest = g_new(RrPixel32, dw * dh);
 
-        /* do we use the cache we may have just created, or the original? */
-        if (rgba->width != sfw || rgba->height != sfh)
-            draw = rgba->cache;
+    for (y = 0; y < dh; ++y) {
+        RrPixel32 *s, *s2;
+
+        s = sourceline;
+        s2 = sourceline2;
+
+        for (x = 0; x < dw; ++x) {
+            *dest++ = AVERAGE(AVERAGE(*s, *(s+1)),
+                              AVERAGE(*s2, *(s2+1)));
+            s += 2;
+            s2 += 2;
+        }
+        sourceline += w << 1;
+        sourceline2 += w << 1;
+    }
+    return out;
+}
+
+static RrPixel32* scale_rect(RrPixel32 *fullsource,
+                             gint w, gint h, gint dw, gint dh)
+{
+    RrPixel32 *out, *dest;
+    RrPixel32 *source = fullsource;
+    RrPixel32 *oldsource = NULL;
+    RrPixel32 *prev_source = NULL;
+    gint num_pixels;
+    gint int_part;
+    gint fract_part;
+    gint err = 0;
+
+    while (dw <= (w >> 1) && dh <= (h >> 1)) {
+        source = scale_half(source, w, h);
+        w >>= 1; h >>= 1;
+        g_free(oldsource);
+        oldsource = source;
+    }
+
+    num_pixels = dh;
+    int_part = (h / dh) * w;
+    fract_part = h % dh;
+
+    out = dest = g_new(RrPixel32, dw * dh);
+
+    while (num_pixels-- > 0) {
+        if (source == prev_source) {
+            memcpy(dest, dest - dw, dw * sizeof(RrPixel32));
+        } else {
+            scale_line(dest, source, w, dw);
+            prev_source = source;
+        }
+        dest += dw;
+        source += int_part;
+        err += fract_part;
+        if (err >= dh) {
+            err -= dh;
+            source += w;
+        }
+    }
+
+    g_free(oldsource);
+
+    return out;
+}
+
+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 = (int)(dw * ((double)sh / sw));
+    if (dh > area->height) {
+        dh = area->height;
+        dw = (int)(dh * ((double)sw / sh));
+    }
+
+    if (sw != dw || sh != dh) {
+        /*if (!(rgba->cache && dw == rgba->cwidth && dh == rgba->cheight))*/ {
+            g_free(rgba->cache);
+            rgba->cache = scale_rect(rgba->data, sw, sh, dw, dh);
+            rgba->cwidth = dw;
+            rgba->cheight = dh;
+        }
+        source = rgba->cache;
+    } else {
+        source = rgba->data;
+    }
 
-        /* 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;
+    /* copy source -> dest, and apply the alpha channel */
+    col = 0;
+    num_pixels = dw * dh;
+    dest = target + area->x + target_w * area->y;
+    while (num_pixels-- > 0) {
+        guchar alpha, r, g, b, bgr, bgg, bgb;
 
-            alpha = draw[i] >> RrDefaultAlphaOffset;
-            r = draw[i] >> RrDefaultRedOffset;
-            g = draw[i] >> RrDefaultGreenOffset;
-            b = draw[i] >> RrDefaultBlueOffset;
+        alpha = *source >> RrDefaultAlphaOffset;
+        r = *source >> RrDefaultRedOffset;
+        g = *source >> RrDefaultGreenOffset;
+        b = *source >> RrDefaultBlueOffset;
+        
+        /* background color */
+        bgr = *dest >> RrDefaultRedOffset;
+        bgg = *dest >> RrDefaultGreenOffset;
+        bgb = *dest >> RrDefaultBlueOffset;
 
-            if (c >= sfw) {
-                c = 0;
-                t += area->width - sfw;
-            }
+        r = bgr + (((r - bgr) * alpha) >> 8);
+        g = bgg + (((g - bgg) * alpha) >> 8);
+        b = bgb + (((b - bgb) * alpha) >> 8);
 
-            /* background color */
-            bgr = target[t] >> RrDefaultRedOffset;
-            bgg = target[t] >> RrDefaultGreenOffset;
-            bgb = target[t] >> RrDefaultBlueOffset;
+        *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 << RrDefaultRedOffset)
-                      | (g << RrDefaultGreenOffset)
-                      | (b << RrDefaultBlueOffset);
+        if (col++ >= dw) {
+            col = 0;
+            dest += target_w - dw;
         }
     }
 }
This page took 0.032098 seconds and 4 git commands to generate.