1 # Module generating C source and headers for various PixelTypes
2 # 2011 - Tomas Gavenciak <gavento@ucw.cz>
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".
10 from pixeltype
import pixeltypes
, channels
11 from gen_utils
import *
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"
22 "/* Automatically generated code for pixel type {{ f.name }}\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"
28 "{% for c in f.chanslist %}"
29 " * {{ c[0] }} offset:{{ c[1] }} size:{{ c[2] }}\n"
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
)
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"
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
]
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'
64 '{% for c in t.chanslist %}'
65 ' { .name = "{{ c[0] }}", .offset = {{ c[1] }}, .size = {{ c[2] }} },\n'
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)"
74 "/* print formatted value of pixel type {{ f.name }} */\n"
75 "void GP_Pixel_Print_{{ f.name }}(GP_Pixel p);\n", f
=ptype
))
77 "/* print formatted value of pixel type {{f.name}} */\n"
78 "void GP_Pixel_Print_{{ f.name }}(GP_Pixel p)\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)"
87 def gen_get_chs(ptype
, header
, code
):
88 "Generate GP_Pixel_GET_<CHAN>_<TYPE> macros"
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
)
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"
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')) }}"
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"
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",
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:]
161 assert bit_endian
in ['LE', 'BE']
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"
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"
174 "#define GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x) \\\n"
175 " ({{ 8-size }} - ((x) % {{ 8//size }}) * {{ size }})\n"
178 size
=size
, size_suffix
=size_suffix
, bit_endian
=bit_endian
))