The BIG graph update
[rrdtool.git] / libraries / libart_lgpl-2.3.7 / art_rgb.c
1 /* Libart_LGPL - library of basic graphic primitives
2  * Copyright (C) 1998 Raph Levien
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <string.h>     /* for memset */
21 #include "art_misc.h"
22 #include "art_rgb.h"
23
24 #include "config.h" /* for endianness */
25
26 /* Basic operators for manipulating 24-bit packed RGB buffers. */
27
28 #define COLOR_RUN_COMPLEX
29
30 #ifdef COLOR_RUN_SIMPLE
31 /* This is really slow. Is there any way we might speed it up?
32    Two ideas:
33
34    First, maybe we should be working at 32-bit alignment. Then,
35    this can be a simple loop over word stores.
36
37    Second, we can keep working at 24-bit alignment, but have some
38    intelligence about storing. For example, we can iterate over
39    4-pixel chunks (aligned at 4 pixels), with an inner loop
40    something like:
41
42    *buf++ = v1;
43    *buf++ = v2;
44    *buf++ = v3;
45
46    One source of extra complexity is the need to make sure linebuf is
47    aligned to a 32-bit boundary.
48
49    This second alternative has some complexity to it, but is
50    appealing because it really minimizes the memory bandwidth. */
51 void
52 art_rgb_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, gint n)
53 {
54   int i;
55
56   if (r == g && g == b)
57     {
58       memset (buf, g, n + n + n);
59     }
60   else
61     {
62       for (i = 0; i < n; i++)
63         {
64           *buf++ = r;
65           *buf++ = g;
66           *buf++ = b;
67         }
68     }
69 }
70 #endif
71
72 #ifdef COLOR_RUN_COMPLEX
73 /* This implements the second of the two ideas above. The test results
74    are _very_ encouraging - it seems the speed is within 10% of
75    memset, which is quite good! */
76 /**
77  * art_rgb_fill_run: fill a buffer a solid RGB color.
78  * @buf: Buffer to fill.
79  * @r: Red, range 0..255.
80  * @g: Green, range 0..255.
81  * @b: Blue, range 0..255.
82  * @n: Number of RGB triples to fill.
83  *
84  * Fills a buffer with @n copies of the (@r, @g, @b) triple. Thus,
85  * locations @buf (inclusive) through @buf + 3 * @n (exclusive) are
86  * written.
87  *
88  * The implementation of this routine is very highly optimized.
89  **/
90 void
91 art_rgb_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int n)
92 {
93   int i;
94   unsigned int v1, v2, v3;
95
96   if (r == g && g == b)
97     {
98       memset (buf, g, n + n + n);
99     }
100   else
101     {
102       if (n < 8)
103         {
104           for (i = 0; i < n; i++)
105             {
106               *buf++ = r;
107               *buf++ = g;
108               *buf++ = b;
109             }
110         } else {
111           /* handle prefix up to byte alignment */
112           /* I'm worried about this cast on sizeof(long) != sizeof(uchar *)
113              architectures, but it _should_ work. */
114           for (i = 0; ((unsigned long)buf) & 3; i++)
115             {
116               *buf++ = r;
117               *buf++ = g;
118               *buf++ = b;
119             }
120 #ifndef WORDS_BIGENDIAN
121           v1 = r | (g << 8) | (b << 16) | (r << 24);
122           v3 = (v1 << 8) | b;
123           v2 = (v3 << 8) | g;
124 #else
125           v1 = (r << 24) | (g << 16) | (b << 8) | r;
126           v2 = (v1 << 8) | g;
127           v3 = (v2 << 8) | b;
128 #endif
129           for (; i < n - 3; i += 4)
130             {
131               ((art_u32 *)buf)[0] = v1;
132               ((art_u32 *)buf)[1] = v2;
133               ((art_u32 *)buf)[2] = v3;
134               buf += 12;
135             }
136           /* handle postfix */
137           for (; i < n; i++)
138             {
139               *buf++ = r;
140               *buf++ = g;
141               *buf++ = b;
142             }
143         }
144     }
145 }
146 #endif
147
148 /**
149  * art_rgb_run_alpha: Render semitransparent color over RGB buffer.
150  * @buf: Buffer for rendering.
151  * @r: Red, range 0..255.
152  * @g: Green, range 0..255.
153  * @b: Blue, range 0..255.
154  * @alpha: Alpha, range 0..256.
155  * @n: Number of RGB triples to render.
156  *
157  * Renders a sequential run of solid (@r, @g, @b) color over @buf with
158  * opacity @alpha.
159  **/
160 void
161 art_rgb_run_alpha (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
162 {
163   int i;
164   int v;
165
166   for (i = 0; i < n; i++)
167     {
168       v = *buf;
169       *buf++ = v + (((r - v) * alpha + 0x80) >> 8);
170       v = *buf;
171       *buf++ = v + (((g - v) * alpha + 0x80) >> 8);
172       v = *buf;
173       *buf++ = v + (((b - v) * alpha + 0x80) >> 8);
174     }
175 }
176