core: Blit: Implement blit with alpha channel.
[gfxprim.git] / libs / core / GP_Blit.gen.c.t
blob0216cfc7e9c1f8a931326cbb0ccd4ac6a57cd1f6
1 %% extends "base.c.t"
3 {% block descr %}Specialized blit functions and macros.{% endblock %}
5 %% block body
6 #include <string.h>
8 #include "core/GP_Pixel.h"
9 #include "core/GP_GetPutPixel.h"
10 #include "core/GP_Context.h"
11 #include "core/GP_Blit.h"
12 #include "core/GP_Debug.h"
13 #include "core/GP_Convert.h"
14 #include "core/GP_Convert.gen.h"
15 #include "core/GP_Convert_Scale.gen.h"
16 #include "core/GP_MixPixels2.gen.h"
19  * TODO: this is used for same pixel but different offset, could still be optimized
20  */
21 static void blitXYXY_Naive_Raw(const GP_Context *src,
22                         GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
23                         GP_Context *dst, GP_Coord x2, GP_Coord y2)
25         GP_Coord x, y;
27         for (y = y0; y <= y1; y++) {
28                 for (x = x0; x <= x1; x++) {
29                         GP_Pixel p = GP_GetPixel_Raw(src, x, y);
31                         if (src->pixel_type != dst->pixel_type)
32                                 p = GP_ConvertContextPixel(p, src, dst);
34                         GP_PutPixel_Raw(dst, x2 + (x - x0), y2 + (y - y0), p);
35                 }
37         }
40 %% for ps in pixelsizes
42  * Blit for equal pixel types {{ ps.suffix }}
43  */
44 static void blitXYXY_Raw_{{ ps.suffix }}(const GP_Context *src,
45         GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
46         GP_Context *dst, GP_Coord x2, GP_Coord y2)
48 %% if not ps.needs_bit_endian()
49         /* memcpy() each horizontal line */
50         GP_Coord y;
52         for (y = 0; y <= (y1 - y0); y++)
53                 memcpy(GP_PIXEL_ADDR_{{ ps.suffix }}(dst, x2, y2 + y),
54                        GP_PIXEL_ADDR_{{ ps.suffix }}(src, x0, y0 + y),
55                        {{ int(ps.size/8) }} * (x1 - x0 + 1));
56 %% else
57 {#      /* Rectangles may not be bit-aligned in the same way! */
58         /* Alignment (index) of first bits in the first byte */
59         //TODO: This is wrong for subcontexts where the offset
60         //      needs to be summed with context->offset and moduled
61         int al1 = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x0);
62         int al2 = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x2);
63         /* Special case of the same alignment and width >=2 bytes */
64         if ((al1 == al2) && ((x1 - x0 + 1) * {{ ps.size }} >= 16)) {
65                 /* Number of bits in the last partial byte */
66                 int end_al = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x1);
67                 GP_ASSERT(({{ ps.size }} * (x1 - x0 + 1) - al1 - end_al) % 8 == 0);
68                 int copy_size = ({{ ps.size }} * (x1 - x0 + 1) - al1 - end_al) / 8;
69                 /* First and last byte incident to the line */
70                 uint8_t *p1 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(src, x1, y1);
71                 uint8_t *p2 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(dst, x2, y2);
72                 uint8_t *end_p1 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(src, x1, y0);
73                 uint8_t *end_p2 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(dst, x2, y2);
75                 GP_Coord i;
77                 for (i = 0; i < (y1 - y0 + 1); i++) {
78                         if (al1 != 0)
79                                 GP_SET_BITS(al1, 8-al1, *p2, GP_GET_BITS(al1, 8-al1, *p1));
80                         memcpy(p2+(al1!=0), p1+(al1!=0), copy_size);
81                         if (end_al != 0)
82                                 GP_SET_BITS(0, end_al, *end_p2, GP_GET_BITS(0, end_al, *end_p1));
83                         p1 += src->bytes_per_row;
84                         end_p1 += src->bytes_per_row;
85                         p2 += dst->bytes_per_row;
86                         end_p2 += dst->bytes_per_row;
87                 }
88         } else /* Different bit-alignment, can't use memcpy() */
90                 blitXYXY_Naive_Raw(src, x0, y0, x1, y1, dst, x2, y2);
91 %% endif
94 %% endfor
97  * Generate Blits, I know this is n^2 variants but the gain is in speed is
98  * more than 50% and the size footprint for two for cycles is really small.
99  */
100 %% for src in pixeltypes
101 %%  if not src.is_unknown() and not src.is_palette()
102 %%   for dst in pixeltypes
103 %%    if not dst.is_unknown() and not dst.is_palette()
104 %%     if dst.name != src.name
106  * Blits {{ src.name }} to {{ dst.name }}
107  */
108 static void blitXYXY_Raw_{{ src.name }}_{{ dst.name }}(const GP_Context *src,
109         GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
110         GP_Context *dst, GP_Coord x2, GP_Coord y2)
112         GP_Coord x, y, dx, dy;
114         for (y = y0; y <= y1; y++) {
115                 for (x = x0; x <= x1; x++) {
116                         dx = x2 + (x - x0);
117                         dy = y2 + (y - y0);
119                         GP_Pixel p1, p2 = 0, p3 = 0;
120                         
121                         p1 = GP_GetPixel_Raw_{{ src.pixelsize.suffix }}(src, x, y);
122 %%      if src.is_alpha()
123                         p2 = GP_GetPixel_Raw_{{ dst.pixelsize.suffix }}(dst, dx, dy);
124                         p3 = GP_MixPixels_{{ src.name }}_{{ dst.name }}(p1, p2);
125 %%      else
126                         GP_Pixel_{{ src.name }}_TO_RGB888(p1, p2);
127                         GP_Pixel_RGB888_TO_{{ dst.name }}(p2, p3);
128 %%      endif
129                         GP_PutPixel_Raw_{{ dst.pixelsize.suffix }}(dst, dx, dy, p3);
130                 }
131         }
134 %%     endif
135 %%    endif
136 %%   endfor
137 %%  endif
138 %% endfor
140 void GP_BlitXYXY_Raw_Fast(const GP_Context *src,
141                           GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
142                           GP_Context *dst, GP_Coord x2, GP_Coord y2)
144         /* Same pixel type, could be (mostly) optimized to memcpy() */
145         if (src->pixel_type == dst->pixel_type) {
146                 GP_FN_PER_BPP(blitXYXY_Raw, src->bpp, src->bit_endian,
147                               src, x0, y0, x1, y1, dst, x2, y2);
148                 return;
149         }
151         /* Specialized functions */
152         switch (src->pixel_type) {
153 %% for src in pixeltypes
154 %% if not src.is_unknown() and not src.is_palette()
155         case GP_PIXEL_{{ src.name }}:
156                 switch (dst->pixel_type) {
157 %% for dst in pixeltypes
158 %% if not dst.is_unknown() and not dst.is_palette()
159 %% if dst.name != src.name
160                 case GP_PIXEL_{{ dst.name }}:
161                         blitXYXY_Raw_{{ src.name }}_{{ dst.name }}(src, x0, y0, x1, y1, dst, x2, y2);
162                 break;
163 %% endif
164 %% endif
165 %% endfor
166                 default:
167                         GP_ABORT("Invalid destination pixel %s",
168                                  GP_PixelTypeName(dst->pixel_type));
169                 }
170         break;
171 %% endif
172 %% endfor
173         default:
174                 GP_ABORT("Invalid source pixel %s",
175                          GP_PixelTypeName(src->pixel_type));
176         }
180  * And the same for non-raw variants.
181  */
182 %% for src in pixeltypes
183 %% if not src.is_unknown() and not src.is_palette()
184 %% for dst in pixeltypes
185 %% if not dst.is_unknown() and not dst.is_palette()
186 %% if dst.name != src.name
188  * Blits {{ src.name }} to {{ dst.name }}
189  */
190 static void blitXYXY_{{ src.name }}_{{ dst.name }}(const GP_Context *src,
191         GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
192         GP_Context *dst, GP_Coord x2, GP_Coord y2)
194         GP_Coord x, y, xt, yt;
196         for (y = y0; y <= y1; y++)
197                 for (x = x0; x <= x1; x++) {
198                         GP_Pixel p1, p2 = 0;
199                         xt = x; yt = y;
200                         GP_TRANSFORM_POINT(src, xt, yt);
201                         p1 = GP_GetPixel_Raw_{{ src.pixelsize.suffix }}(src, xt, yt);
202                         GP_Pixel_{{ src.name }}_TO_RGB888(p1, p2);
203                         GP_Pixel_RGB888_TO_{{ dst.name }}(p2, p1);
204                         xt = x2 + (x - x0);
205                         yt = y2 + (y - y0);
206                         GP_TRANSFORM_POINT(dst, xt, yt);
207                         GP_PutPixel_Raw_{{ dst.pixelsize.suffix }}(dst, xt, yt, p1);
208                 }
211 %% endif
212 %% endif
213 %% endfor
214 %% endif
215 %% endfor
218  * Same pixel type but with rotation.
219  */
220 %% for ps in pixelsizes
222  * Blits for same pixel type and bpp {{ ps.suffix }}
223  */
224 static void blitXYXY_{{ ps.suffix }}(const GP_Context *src,
225         GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
226         GP_Context *dst, GP_Coord x2, GP_Coord y2)
228         GP_Coord x, y, xt, yt;
230         for (y = y0; y <= y1; y++)
231                 for (x = x0; x <= x1; x++) {
232                         GP_Pixel p;
233                         xt = x; yt = y;
234                         GP_TRANSFORM_POINT(src, xt, yt);
235                         p = GP_GetPixel_Raw_{{ ps.suffix }}(src, xt, yt);
236                         xt = x2 + (x - x0);
237                         yt = y2 + (y - y0);
238                         GP_TRANSFORM_POINT(dst, xt, yt);
239                         GP_PutPixel_Raw_{{ ps.suffix }}(dst, xt, yt, p);
240                 }
242 %% endfor
244 void GP_BlitXYXY_Fast(const GP_Context *src,
245                       GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
246                       GP_Context *dst, GP_Coord x2, GP_Coord y2)
248         /* Same pixel type */
249         if (src->pixel_type == dst->pixel_type) {
250                 GP_FN_PER_BPP(blitXYXY, src->bpp, src->bit_endian,
251                               src, x0, y0, x1, y1, dst, x2, y2);
252                 return;
253         }
254         
255         /* Specialized functions */
256         switch (src->pixel_type) {
257 %% for src in pixeltypes
258 %% if not src.is_unknown() and not src.is_palette()
259         case GP_PIXEL_{{ src.name }}:
260                 switch (dst->pixel_type) {
261 %% for dst in pixeltypes
262 %% if not dst.is_unknown() and not dst.is_palette()
263 %% if dst.name != src.name
264                 case GP_PIXEL_{{ dst.name }}:
265                         blitXYXY_{{ src.name }}_{{ dst.name }}(src, x0, y0, x1, y1, dst, x2, y2);
266                 break;
267 %% endif
268 %% endif
269 %% endfor
270                 default:
271                         GP_ABORT("Invalid destination pixel %s",
272                                  GP_PixelTypeName(dst->pixel_type));
273                 }
274         break;
275 %% endif
276 %% endfor
277         default:
278                 GP_ABORT("Invalid source pixel %s",
279                          GP_PixelTypeName(src->pixel_type));
280         }
283 %% endblock body