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 "config.h"
21 #include "art_rgb.h"
22 
23 #include <string.h>	/* for memset */
24 
25 /* Basic operators for manipulating 24-bit packed RGB buffers. */
26 
27 #define COLOR_RUN_COMPLEX
28 
29 #ifdef COLOR_RUN_SIMPLE
30 /* This is really slow. Is there any way we might speed it up?
31    Two ideas:
32 
33    First, maybe we should be working at 32-bit alignment. Then,
34    this can be a simple loop over word stores.
35 
36    Second, we can keep working at 24-bit alignment, but have some
37    intelligence about storing. For example, we can iterate over
38    4-pixel chunks (aligned at 4 pixels), with an inner loop
39    something like:
40 
41    *buf++ = v1;
42    *buf++ = v2;
43    *buf++ = v3;
44 
45    One source of extra complexity is the need to make sure linebuf is
46    aligned to a 32-bit boundary.
47 
48    This second alternative has some complexity to it, but is
49    appealing because it really minimizes the memory bandwidth. */
50 void
art_rgb_fill_run(art_u8 * buf,art_u8 r,art_u8 g,art_u8 b,gint n)51 art_rgb_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, gint n)
52 {
53   int i;
54 
55   if (r == g && g == b)
56     {
57       memset (buf, g, n + n + n);
58     }
59   else
60     {
61       for (i = 0; i < n; i++)
62 	{
63 	  *buf++ = r;
64 	  *buf++ = g;
65 	  *buf++ = b;
66 	}
67     }
68 }
69 #endif
70 
71 #ifdef COLOR_RUN_COMPLEX
72 /* This implements the second of the two ideas above. The test results
73    are _very_ encouraging - it seems the speed is within 10% of
74    memset, which is quite good! */
75 /**
76  * art_rgb_fill_run: fill a buffer a solid RGB color.
77  * @buf: Buffer to fill.
78  * @r: Red, range 0..255.
79  * @g: Green, range 0..255.
80  * @b: Blue, range 0..255.
81  * @n: Number of RGB triples to fill.
82  *
83  * Fills a buffer with @n copies of the (@r, @g, @b) triple. Thus,
84  * locations @buf (inclusive) through @buf + 3 * @n (exclusive) are
85  * written.
86  *
87  * The implementation of this routine is very highly optimized.
88  **/
89 void
art_rgb_fill_run(art_u8 * buf,art_u8 r,art_u8 g,art_u8 b,int n)90 art_rgb_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int n)
91 {
92   int i;
93   unsigned int v1, v2, v3;
94 
95   if (r == g && g == b)
96     {
97       memset (buf, g, n + n + n);
98     }
99   else
100     {
101       if (n < 8)
102 	{
103 	  for (i = 0; i < n; i++)
104 	    {
105 	      *buf++ = r;
106 	      *buf++ = g;
107 	      *buf++ = b;
108 	    }
109 	} else {
110 	  /* handle prefix up to byte alignment */
111 	  /* I'm worried about this cast on sizeof(long) != sizeof(uchar *)
112 	     architectures, but it _should_ work. */
113 	  for (i = 0; ((unsigned long)buf) & 3; i++)
114 	    {
115 	      *buf++ = r;
116 	      *buf++ = g;
117 	      *buf++ = b;
118 	    }
119 #ifndef WORDS_BIGENDIAN
120 	  v1 = r | (g << 8) | (b << 16) | (r << 24);
121 	  v3 = (v1 << 8) | b;
122 	  v2 = (v3 << 8) | g;
123 #else
124 	  v1 = (r << 24) | (g << 16) | (b << 8) | r;
125 	  v2 = (v1 << 8) | g;
126 	  v3 = (v2 << 8) | b;
127 #endif
128 	  for (; i < n - 3; i += 4)
129 	    {
130 	      ((art_u32 *)buf)[0] = v1;
131 	      ((art_u32 *)buf)[1] = v2;
132 	      ((art_u32 *)buf)[2] = v3;
133 	      buf += 12;
134 	    }
135 	  /* handle postfix */
136 	  for (; i < n; i++)
137 	    {
138 	      *buf++ = r;
139 	      *buf++ = g;
140 	      *buf++ = b;
141 	    }
142 	}
143     }
144 }
145 #endif
146 
147 /**
148  * art_rgb_run_alpha: Render semitransparent color over RGB buffer.
149  * @buf: Buffer for rendering.
150  * @r: Red, range 0..255.
151  * @g: Green, range 0..255.
152  * @b: Blue, range 0..255.
153  * @alpha: Alpha, range 0..256.
154  * @n: Number of RGB triples to render.
155  *
156  * Renders a sequential run of solid (@r, @g, @b) color over @buf with
157  * opacity @alpha.
158  **/
159 void
art_rgb_run_alpha(art_u8 * buf,art_u8 r,art_u8 g,art_u8 b,int alpha,int n)160 art_rgb_run_alpha (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
161 {
162   int i;
163   int v;
164 
165   for (i = 0; i < n; i++)
166     {
167       v = *buf;
168       *buf++ = v + (((r - v) * alpha + 0x80) >> 8);
169       v = *buf;
170       *buf++ = v + (((g - v) * alpha + 0x80) >> 8);
171       v = *buf;
172       *buf++ = v + (((b - v) * alpha + 0x80) >> 8);
173     }
174 }
175 
176