]> Dogcows Code - chaz/openbox/blob - render/image.c
7e29aa6e756d8a579c2d9facbfc94dcb9a4ca49f
[chaz/openbox] / render / image.c
1 #include "geom.h"
2 #include "image.h"
3 #include "color.h"
4
5 #include <glib.h>
6
7 #define AVERAGE(a, b) ( ((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b)) )
8
9 static void scale_line(RrPixel32 *dest, RrPixel32 *source, gint w, gint dw)
10 {
11 gint num_pixels = dw;
12 gint int_part = w / dw;
13 gint fract_part = w % dw;
14 gint err = 0;
15
16 while (num_pixels-- > 0) {
17 *dest++ = *source;
18 source += int_part;
19 err += fract_part;
20 if (err >= dw) {
21 err -= dw;
22 source++;
23 }
24 }
25 }
26
27 static RrPixel32* scale_half(RrPixel32 *source, gint w, gint h)
28 {
29 RrPixel32 *out, *dest, *sourceline, *sourceline2;
30 gint dw, dh, x, y;
31
32 sourceline = source;
33 sourceline2 = source + w;
34
35 dw = w >> 1;
36 dh = h >> 1;
37
38 out = dest = g_new(RrPixel32, dw * dh);
39
40 for (y = 0; y < dh; ++y) {
41 RrPixel32 *s, *s2;
42
43 s = sourceline;
44 s2 = sourceline2;
45
46 for (x = 0; x < dw; ++x) {
47 *dest++ = AVERAGE(AVERAGE(*s, *(s+1)),
48 AVERAGE(*s2, *(s2+1)));
49 s += 2;
50 s2 += 2;
51 }
52 sourceline += w << 1;
53 sourceline2 += w << 1;
54 }
55 return out;
56 }
57
58 static RrPixel32* scale_rect(RrPixel32 *fullsource,
59 gint w, gint h, gint dw, gint dh)
60 {
61 RrPixel32 *out, *dest;
62 RrPixel32 *source = fullsource;
63 RrPixel32 *oldsource = NULL;
64 RrPixel32 *prev_source = NULL;
65 gint num_pixels;
66 gint int_part;
67 gint fract_part;
68 gint err = 0;
69
70 while (dw <= (w >> 1) && dh <= (h >> 1)) {
71 source = scale_half(source, w, h);
72 w >>= 1; h >>= 1;
73 g_free(oldsource);
74 oldsource = source;
75 }
76
77 num_pixels = dh;
78 int_part = (h / dh) * w;
79 fract_part = h % dh;
80
81 out = dest = g_new(RrPixel32, dw * dh);
82
83 while (num_pixels-- > 0) {
84 if (source == prev_source) {
85 memcpy(dest, dest - dw, dw * sizeof(RrPixel32));
86 } else {
87 scale_line(dest, source, w, dw);
88 prev_source = source;
89 }
90 dest += dw;
91 source += int_part;
92 err += fract_part;
93 if (err >= dh) {
94 err -= dh;
95 source += w;
96 }
97 }
98
99 g_free(oldsource);
100
101 return out;
102 }
103
104 void RrImageDraw(RrPixel32 *target, RrTextureRGBA *rgba,
105 gint target_w, gint target_h,
106 RrRect *area)
107 {
108 RrPixel32 *dest;
109 RrPixel32 *source;
110 gint sw, sh, dw, dh;
111 gint col, num_pixels;
112
113 sw = rgba->width;
114 sh = rgba->height;
115
116 /* keep the ratio */
117 dw = area->width;
118 dh = (int)(dw * ((double)sh / sw));
119 if (dh > area->height) {
120 dh = area->height;
121 dw = (int)(dh * ((double)sw / sh));
122 }
123
124 if (sw != dw || sh != dh) {
125 /*if (!(rgba->cache && dw == rgba->cwidth && dh == rgba->cheight))*/ {
126 g_free(rgba->cache);
127 rgba->cache = scale_rect(rgba->data, sw, sh, dw, dh);
128 rgba->cwidth = dw;
129 rgba->cheight = dh;
130 }
131 source = rgba->cache;
132 } else {
133 source = rgba->data;
134 }
135
136 /* copy source -> dest, and apply the alpha channel */
137 col = 0;
138 num_pixels = dw * dh;
139 dest = target + area->x + target_w * area->y;
140 while (num_pixels-- > 0) {
141 guchar alpha, r, g, b, bgr, bgg, bgb;
142
143 alpha = *source >> RrDefaultAlphaOffset;
144 r = *source >> RrDefaultRedOffset;
145 g = *source >> RrDefaultGreenOffset;
146 b = *source >> RrDefaultBlueOffset;
147
148 /* background color */
149 bgr = *dest >> RrDefaultRedOffset;
150 bgg = *dest >> RrDefaultGreenOffset;
151 bgb = *dest >> RrDefaultBlueOffset;
152
153 r = bgr + (((r - bgr) * alpha) >> 8);
154 g = bgg + (((g - bgg) * alpha) >> 8);
155 b = bgb + (((b - bgb) * alpha) >> 8);
156
157 *dest = ((r << RrDefaultRedOffset) |
158 (g << RrDefaultGreenOffset) |
159 (b << RrDefaultBlueOffset));
160
161 dest++;
162 source++;
163
164 if (col++ >= dw) {
165 col = 0;
166 dest += target_w - dw;
167 }
168 }
169 }
This page took 0.038743 seconds and 3 git commands to generate.