Adapt gen/ for bit-endianness
[gfxprim.git] / core / gen / gen_pixeltype.py
blob683fe8759318bf81d62af5eed9c4ef45cadb63ee
1 # Module generating C source and headers for various PixelTypes
2 # 2011 - Tomas Gavenciak <gavento@ucw.cz>
4 """
5 The functions gen_* generate both source and header.
6 Such functions accept (and then extend) two list of strins.
7 These should be later joined with "" or "\\n".
8 """
10 from pixeltype import pixeltypes, channels
11 from gen_utils import *
14 def str_start(ptype):
15 "Return a visual separator starting `ptype`-related defs"
16 return ("\n/*************************************************************\n"
17 " * Pixel type " + ptype.name + "\n */\n")
19 def str_description(ptype):
20 "Return a short C comment describing the PixelType"
21 return r(
22 "/* Automatically generated code for pixel type {{ f.name }}\n"
23 " *\n"
24 " * Size (bpp): {{ f.size }} ({{ f.size_suffix }})\n"
25 "{% if f.size<8 %} * Bit endian: {{ f.bit_endian }}\n{% endif %}"
26 " * Pixel structure: {{ ''.join(f.bits) }}\n"
27 " * Channels: \n"
28 "{% for c in f.chanslist %}"
29 " * {{ c[0] }} offset:{{ c[1] }} size:{{ c[2] }}\n"
30 "{% endfor %}"
31 " */\n", f=ptype)
33 def gen_GP_PixelType(header, code):
34 "Generates definition of GP_PixelType enum"
35 pt_by_num = sorted([(t.number, t) for t in pixeltypes.values()])
36 sorted_pts = [t[1] for t in pt_by_num]
37 pt_max = len(sorted_pts)
38 header.append(r(
39 "/* List of all known pixel types */\n"
40 "typedef enum GP_PixelType {\n"
41 "{% for t in sorted_pts %}"
42 " GP_PIXEL_{{ t.name }} = {{ t.number }},\n"
43 "{% endfor %}"
44 " GP_PIXEL_MAX = {{ pt_max }},\n"
45 "} GP_PixelType;\n", sorted_pts=sorted_pts, pt_max=pt_max))
47 def gen_GP_PixelTypes(header, code):
48 "Generate the const structure GP_PixelTypes describing all the PixelTypes"
49 pt_by_num = sorted([(t.number, t) for t in pixeltypes.values()])
50 sorted_pts = [t[1] for t in pt_by_num]
51 code.append(r(
52 "/* Description of all known pixel types */\n"
53 "const GP_PixelTypeDescription const GP_PixelTypes [] = {\n"
54 "{% for t in sorted_pts %}"
55 " /* GP_PIXEL_{{ t.name }} */ {\n"
56 " .type = GP_PIXEL_{{ t.name }},\n"
57 ' .name = "{{ t.name }}",\n'
58 ' .size = {{ t.size }},\n'
59 ' .bit_endian = GP_BIT_ENDIAN_{{ t.bit_endian }},'
60 '{% if t.size>=8 %} /* IGNORED for this type */{% endif %}\n'
61 ' .numchannels = {{ len(t.chanslist) }},\n'
62 ' .bitmap = "{{ t.bits|join("") }}",\n'
63 ' .channels = {\n'
64 '{% for c in t.chanslist %}'
65 ' { .name = "{{ c[0] }}", .offset = {{ c[1] }}, .size = {{ c[2] }} },\n'
66 '{% endfor %}'
67 ' } },\n'
68 '{% endfor %}'
69 '};\n', sorted_pts=sorted_pts, len=len))
71 def gen_print(ptype, header, code):
72 "Generate a GP_Pixel_Print_<TYPE> function (source and header)"
73 header.append(r(
74 "/* print formatted value of pixel type {{ f.name }} */\n"
75 "void GP_Pixel_Print_{{ f.name }}(GP_Pixel p);\n", f=ptype))
76 code.append(r(
77 "/* print formatted value of pixel type {{f.name}} */\n"
78 "void GP_Pixel_Print_{{ f.name }}(GP_Pixel p)\n"
79 "{\n"
80 ' printf("<{{ f.name }} %0{{ (f.size+3)//4 }}x{% for c in f.chanslist %} {{ c[0] }}=%d{% endfor %}>",\n'
81 " GP_GET_BITS(0, {{ f.size }}, p)"
82 "{% for c in f.chanslist %}"
83 ",\n GP_GET_BITS({{ c[1] }}, {{ c[2] }}, p)"
84 "{% endfor %});\n"
85 "}\n", f=ptype))
87 def gen_get_chs(ptype, header, code):
88 "Generate GP_Pixel_GET_<CHAN>_<TYPE> macros"
89 header.append(r(
90 "/* macros to get channels of pixel type {{ f.name }} */\n"
91 "{% for c in f.chanslist %}"
92 "#define GP_Pixel_GET_{{ c[0] }}_{{ f.name }}(p) (GP_GET_BITS({{ c[1] }}, {{ c[2] }}, (p)))\n"
93 "{% endfor %}", f=ptype))
95 def gen_convert_to(f1, f2, header, code):
96 "Generate a macro converting from f1 to f2"
97 "This function supports only RGBVA types (no palettes"
98 allowed_chansets = [ set(list(s)) for s in ['RGB', 'RGBA', 'V', 'VA'] ]
99 assert(set(f1.chans.keys()) in allowed_chansets)
100 assert(set(f2.chans.keys()) in allowed_chansets)
102 header.append(r(
103 "\n/*** {{ f1.name }} -> {{ f2.name }} ***\n"
104 " * macro storing p1 ({{ f1.name }} at bit-offset o1) in p2 ({{ f2.name }} at bit-offset o2),\n"
105 " * the relevant part of p2 is assumed to be clear (zero) */\n\n"
106 "#define GP_Pixel_{{ f1.name }}_TO_{{ f2.name }}_OFFSET(p1, o1, p2, o2) do {\\\n"
108 ## set each of <TARGET> channels
109 "{% for c2 in f2.chanslist %}"
111 # case 1: just copy a channel
112 "{%- if c2[0] in f1.chans.keys() %}{% set c1 = f1.chans[c2[0]] %}"
113 " /* {{ c2[0] }}:={{ c1[0] }} */ GP_SET_BITS({{c2[1]}}+o2, \\\n"
114 " GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1)), p2); \\\n"
116 # case 2: set A to full opacity (not present in source)
117 "{% elif c2[0]=='A' %}"
118 " /* A:={{ hmask(c2[2]) }} */GP_SET_BITS({{c2[1]}}+o2, {{ hmask(c2[2]) }}, p2); \\\n"
120 # case 3: calculate V as average of RGB
121 "{% elif c2[0]=='V' and set('RGB').issubset(set(f1.chans.keys())) %}"
122 " /* V:=RGB_avg */ GP_SET_BITS({{c2[1]}}+o2, ( \\\n"
123 "{% for c1 in [f1.chans['R'], f1.chans['G'], f1.chans['B']] %}"
124 " /* {{c1[0]}} */ GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1), p2) + \\\n"
125 "{% endfor %}"
126 " 0)/3);\\\n"
128 #- case 4: set each RGB to V
129 "{% elif c2[0] in 'RGB' and 'V' in f1.chans.keys() %}{% set c1 = f1.chans['V'] %}"
130 " /* {{ c2[0] }}:=V */ GP_SET_BITS({{c2[1]}}+o2, \\\n"
131 " GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1)), p2); \\\n"
133 # invalid mapping (there should be none, but who knows ...)
134 "{% else %} {{ raise(Error('channel conversion' +f1.name+ ' to ' +f2.name+ ' not supported')) }}"
136 # end of the loop
137 "{% endif %}"
138 "{% endfor %}"
139 "} while (0)\n\n"
141 # add version without offsets
142 "/* a version without offsets */\n"
143 "#define GP_Pixel_{{ f1.name }}_TO_{{ f2.name }}(p1, p2) "
144 "(GP_Pixel_{{ f1.name }}_TO_{{ f2.name }}_OFFSET(p1, 0, p2, 0))\n",
145 f1=f1, f2=f2, hmask=hmask, set=set))
147 def gen_get_pixel_addr(ptype, header, code):
148 "Generate GP_PIXEL_ADDR_<TYPE> and _OFFSET_<TYPE> macros"
149 header.append(r(
150 "/* macro to get address of pixel {{ f.name }} in a context */\n"
151 "#define GP_PIXEL_ADDR_{{ f.name }}(context, x, y) GP_PIXEL_ADDR_{{ f.size_suffix }}(context, x, y)\n"
152 "/* macro to get bit-offset of pixel {{ f.name }} */\n"
153 "#define GP_PIXEL_ADDR_OFFSET_{{ f.name }}(x) \\\n"
154 " GP_PIXEL_ADDR_OFFSET_{{ f.size_suffix }}(x)\n",
155 f=ptype))
157 def gen_get_pixel_addr_bpp(size, size_suffix, header, code):
158 "Generate GP_PIXEL_ADDR_<size_suffix> and _OFFSET_<size_suffix> macros"
159 bit_endian = size_suffix[-2:]
160 if size < 8:
161 assert bit_endian in ['LE', 'BE']
162 header.append(r(
163 "/* macro to get address of pixel in a {{ size_suffix }} context */\n"
164 "#define GP_PIXEL_ADDR_{{ size_suffix }}(context, x, y) \\\n"
165 " ((context)->pixels + (context)->bytes_per_row * (y) + {{ size//8 }} * (x))\n"
166 "/* macro to get bit-offset of pixel in {{ size_suffix }} context */\n"
167 "{% if size >= 8 %}"
168 "#define GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x) (0)\n"
169 "{% else %}" # bit_endian matters
170 "{% if bit_endian=='LE' %}"
171 "#define GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x) \\\n"
172 " (((x) % {{ 8//size }}) * {{ size }})\n"
173 "{% else %}"
174 "#define GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x) \\\n"
175 " ({{ 8-size }} - ((x) % {{ 8//size }}) * {{ size }})\n"
176 "{% endif %}"
177 "{% endif %}",
178 size=size, size_suffix=size_suffix, bit_endian=bit_endian))