X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=render%2Fimage.c;h=7e29aa6e756d8a579c2d9facbfc94dcb9a4ca49f;hb=3a607fad9df628ab16e0f7436dfbfc9b22634003;hp=bdc51eeda04562f0856c58723255dea9902566a6;hpb=a081582e3a4c27aede31c170337aed6b5a5309cc;p=chaz%2Fopenbox diff --git a/render/image.c b/render/image.c index bdc51eed..7e29aa6e 100644 --- a/render/image.c +++ b/render/image.c @@ -1,70 +1,169 @@ -#include -#include "../kernel/geom.h" +#include "geom.h" #include "image.h" +#include "color.h" + +#include + +#define AVERAGE(a, b) ( ((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b)) ) + +static void scale_line(RrPixel32 *dest, RrPixel32 *source, gint w, gint dw) +{ + 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++; + } + } +} -void image_draw(pixel32 *target, TextureRGBA *rgba, Rect *position, - Rect *surarea) +static RrPixel32* scale_half(RrPixel32 *source, gint w, gint h) { - 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; + 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); + + 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; + } + + /* 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; -/* do we use the cache we may have just created, or the original? */ - if (rgba->width != sfw || rgba->height != sfh) - draw = rgba->cache; + alpha = *source >> RrDefaultAlphaOffset; + r = *source >> RrDefaultRedOffset; + g = *source >> RrDefaultGreenOffset; + b = *source >> RrDefaultBlueOffset; + + /* 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; + } } - } }