Rename GP_Context -> GP_Pixmap
[gfxprim.git] / include / core / GP_GetPutPixel.gen.h.t
blob24e5ca6ea2051e3524d5ade7aeb8e456dd110232
1 @ include header.t
2 /*
3  * Access pixel bytes, Get and PutPixel
4  * Do not include directly, use GP_Pixel.h
5  *
6  * Copyright (C) 2011-2014 Cyril Hrubis <metan@ucw.cz>
7  * Copyright (C) 2011      Tomas Gavenciak <gavento@ucw.cz>
8  */
10  /*
12    Note about byte aligment
13    ~~~~~~~~~~~~~~~~~~~~~~~~
15    Unaligned access happens when instruction that works with multiple byte
16    value gets an address that is not divideable by the size of the value. Eg.
17    if 32 bit integer instruction gets an address that is not a multiple of 4.
18    On intel cpus this type of access works and is supported however the C
19    standard defines this as undefined behavior. This fails to work ARM and most
20    of the non intel cpus. So some more trickery must be done in order to write
21    unaligned multibyte values. First of all we must compute offset and number
22    of bytes to be accessed (which is cruicial for speed as we are going to read
23    the pixel value byte by byte).
25    The offsets (starting with the first one eg. pixel_size mod 8) forms subgroup
26    in the mod 8 cyclic group. The maximal count of bits, from the start of the
27    byte, then will be max from this subgroup + pixel_size. If this number is
28    less or equal to 8 * N, we could write such pixel by writing N bytes.
30    For example the offsets of 16 BPP forms subgroup only with {0} so we only
31    need 2 bytes to write it. As a matter of fact the 16 and 32 BPP are special
32    cases that are always aligned together with the 8 BPP (which is aligned
33    trivially). These three are coded as special cases which yields to faster
34    operations in case of 16 and 32 BPP. The 24 BPP is not aligned as there are
35    no instruction to operate 3 byte long numbers.
37    For second example take offsets of 20 BPP that forms subgroup {4, 0}
38    so the max + pixel_size = 24 and indeed we fit into 3 bytes.
40    If pixel_size is coprime to 8, the offsets generates whole group and so the
41    max + pixel_size = 7 + pixel_size. The 17 BPP fits into 24 bits and so 3
42    bytes are needed. The 19 BPP fits into 26 bits and because of that 4 bytes
43    are needed.
45    Once we figure maximal number of bytes and the offset all that is to be done
46    is to fetch first and last byte to combine it together with given pixel value
47    and write the result back to the bitmap.
49  */
51 #include "GP_GetSetBits.h"
52 #include "GP_Pixmap.h"
54 @ for ps in pixelsizes:
56  * macro to get address of pixel in a {{ ps.suffix }} pixmap
57  */
58 #define GP_PIXEL_ADDR_{{ ps.suffix }}(pixmap, x, y) \
59         ((GP_Pixel*)(((void*)((pixmap)->pixels)) + (pixmap)->bytes_per_row * (y) + ({{ ps.size }} * (x)) / 8))
62  * macro to get bit-offset of pixel in {{ ps.suffix }} pixmap
63  */
64 #define GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x) \
65 @     if not ps.needs_bit_endian():
66         (0)
67 @     else:
68 @         if ps.bit_endian == 'LE':
69 @             if ps.size < 8:
70         (((x) % {{ 8 // ps.size }}) * {{ ps.size }})
71 @             else:
72         (({{ ps.size }} * (x)) % 8)
73 @         else:
74 @              if ps.size < 8:
75         ({{ 8 - ps.size }} - ((x) % {{ 8 // ps.size }}) * {{ ps.size }})
76 @              else:
77         {{ error('Insanity check: big bit-endian with >8 bpp. Are you sure?') }}
78 @     end
81  * GP_GetPixel for {{ ps.suffix }}
82  */
83 static inline GP_Pixel GP_GetPixel_Raw_{{ ps.suffix }}(const GP_Pixmap *c, int x, int y)
85 @     if ps.size == 32:
86         /*
87          * 32 BPP is expected to have aligned pixels
88          */
89         return *((uint32_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y));
90 @     elif ps.size == 16:
91         /*
92          * 16 BPP is expected to have aligned pixels
93          */
94         return *((uint16_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y));
95 @     elif ps.size == 8:
96         /*
97          * 8 BPP is byte aligned
98          */
99         return *((uint8_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y));
100 @     elif ps.size == 1 or ps.size == 2 or ps.size == 4 or ps.size == 8:
101         /*
102          * Whole pixel is stored only and only in one byte
103          *
104          * The full list = {1, 2, 4, 8}
105          */
106         return GP_GET_BITS1_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
107                 *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
108 @     elif ps.size <= 10 or ps.size == 12 or ps.size == 16:
109         /*
110          * The pixel is stored in one or two bytes
111          *
112          * The max from subgroup (of mod 8 factor group) generated by
113          * pixel_size mod 8 + pixel_size <= 16
114          *
115          * The full list = {3, 5, 6, 7, 9, 10, 12, 16}
116          *
117          * Hint: If the pixel size is coprime to 8 the group is generated by
118          *       pixel_size mod 8 and maximal size thus is pixel_size + 7
119          */
120         return GP_GET_BITS2_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
121                 *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
122 @     elif ps.size <= 18 or ps.size == 20 or ps.size == 24:
123         /*
124          * The pixel is stored in two or three bytes
125          *
126          * The max from subgroup (of mod 8 factor group) generated by
127          * pixel_size mod 8 + pixel_size <= 24
128          *
129          * The full list = {11, 13, 14, 15, 17, 18, 20, 24}
130          *
131          * Hint: If the pixel size is coprime to 8 the group is generated by
132          *       pixel_size mod 8 and maximal size thus is pixel_size + 7
133          */
134         return GP_GET_BITS3_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
135                 *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
136 @     elif ps.size <= 23 or ps.size == 25 or ps.size == 26 or ps.size == 28 or ps.size == 32:
137         /*
138          * The pixel is stored in three or four bytes
139          *
140          * The max from subgroup (of mod 8 factor group) generated by
141          * pixel_size mod 8 + pixel_size <= 32
142          *
143          * The full list = {19, 21, 22, 23, 25, 26, 28, 32}
144          *
145          * Hint: If the pixel size is coprime to 8 the group is generated by
146          *       pixel_size mod 8 and maximal size thus is pixel_size + 7
147          */
148         return GP_GET_BITS4_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
149                 *(GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)));
150 @     else:
151         #error not implemented
152 @     end
156  * GP_PutPixel for {{ ps.suffix }}
157  */
158 static inline void GP_PutPixel_Raw_{{ ps.suffix }}(GP_Pixmap *c, int x, int y, GP_Pixel p)
160 @     if ps.size == 32:
161         /*
162          * 32 BPP is expected to have aligned pixels
163          */
164         *((uint32_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)) = p;
165 @     elif ps.size == 16:
166         /*
167          * 16 BPP is expected to have aligned pixels
168          */
169         *((uint16_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)) = p;
170 @     elif ps.size == 8:
171         /*
172          * 8 BPP is byte aligned
173          */
174         *((uint8_t*)GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y)) = p;
175 @     elif ps.size == 1 or ps.size == 2 or ps.size == 4 or ps.size == 8:
176         /*
177          * Whole pixel is stored only and only in one byte
178          *
179          * The full list = {1, 2, 4, 8}
180          */
181         GP_SET_BITS1_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
182                              GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
183 @     elif ps.size <= 10 or ps.size == 12 or ps.size == 16:
184         /*
185          * The pixel is stored in one or two bytes
186          *
187          * The max from subgroup (of mod 8 factor group) generated by
188          * pixel_size mod 8 + pixel_size <= 16
189          *
190          * The full list = {3, 5, 6, 7, 9, 10, 12, 16}
191          *
192          * Hint: If the pixel size is coprime to 8 the group is generated by
193          *       pixel_size mod 8 and maximal size thus is pixel_size + 7
194          */
195         GP_SET_BITS2_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
196                              GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
197 @     elif ps.size <= 18 or ps.size == 20 or ps.size == 24:
198         /*
199          * The pixel is stored in two or three bytes
200          *
201          * The max from subgroup (of mod 8 factor group) generated by
202          * pixel_size mod 8 + pixel_size <= 24
203          *
204          * The full list = {11, 13, 14, 15, 17, 18, 20, 24}
205          *
206          * Hint: If the pixel size is coprime to 8 the group is generated by
207          *       pixel_size mod 8 and maximal size thus is pixel_size + 7
208          */
209         GP_SET_BITS3_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
210                              GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
211 @     elif ps.size <= 23 or ps.size == 25 or ps.size == 26 or ps.size == 28 or ps.size == 32:
212         /*
213          * The pixel is stored in three or four bytes
214          *
215          * The max from subgroup (of mod 8 factor group) generated by
216          * pixel_size mod 8 + pixel_size <= 32
217          *
218          * The full list = {19, 21, 22, 23, 25, 26, 28, 32}
219          *
220          * Hint: If the pixel size is coprime to 8 the group is generated by
221          *       pixel_size mod 8 and maximal size thus is pixel_size + 7
222          */
223         GP_SET_BITS4_ALIGNED(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }},
224                              GP_PIXEL_ADDR_{{ ps.suffix }}(c, x, y), p);
225 @     else:
226         #error not implemented
227 @     end
230 static inline void GP_PutPixel_Raw_Clipped_{{ ps.suffix }}(GP_Pixmap *c, GP_Coord x, GP_Coord y, GP_Pixel p)
232         if (GP_PIXEL_IS_CLIPPED(c, x, y))
233                 return;
235         GP_PutPixel_Raw_{{ ps.suffix }}(c, x, y, p);