This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project gfxprim.git.
The branch, generate has been updated via 0acddf9bde07520ba408dbf0772c84d02bc074ba (commit) via cb0e0b9b7a723b92deb33de3dab9f0077e69be0b (commit) via ffa0e5910b52a5fe361e1bc5753665fec90a8db4 (commit) via cfe11b6f6f3c41d3ff6c18d90efdd2615a5e858a (commit) via 35f5e233c07862deeb53bdf9407e2f83eaa15887 (commit) via 7ab0524f10cef16426c70802884bee6cda23d116 (commit) via 89d7a5aa051caddcd3d17d27e17d7d4f4b9661fa (commit) via 938956d49a3627c5fe31c4fcf2ceeae5877fd11b (commit) via 58f99bbee8cf3eac5142540013c8309267b8f55d (commit) via 27781b18ae400421700a31d6b1ed37d836c47f22 (commit) from 1cd5016b247b64d2d0b7b7c6791d5f730248ec64 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- http://repo.or.cz/w/gfxprim.git/commit/0acddf9bde07520ba408dbf0772c84d02bc07...
commit 0acddf9bde07520ba408dbf0772c84d02bc074ba Author: Tomas Gavenciak gavento@ucw.cz Date: Mon Aug 8 14:06:16 2011 +0200
Update generating scripts
diff --git a/gen.mk b/gen.mk index c5586c6..41ad5f5 100644 --- a/gen.mk +++ b/gen.mk @@ -37,14 +37,15 @@ TEMPLATE_DIR=$(TOPDIR)/pylib/templates/
# # ALL templates and potential generated files (not generated automatically) -# +# NOTE: Currently unused +# ALL_TEMPLATES=$(shell find $(TOPDIR) -name '*.t') ALL_GENERATED=$(basename $(ALL_TEMPLATES))
# # And clean them # -CLEAN+=$(ALL_GENERATED) +CLEAN+=$(GENSOURCES) $(RGENHEADERS)
# # Generated files depend on python generators and the template diff --git a/pylib/bin/generate_file.py b/pylib/bin/generate_file.py index bd0ddf1..b8b6b12 100644 --- a/pylib/bin/generate_file.py +++ b/pylib/bin/generate_file.py @@ -22,7 +22,8 @@ def main(options, args): config = render_utils.load_gfxprimconfig(options.config) assert config log.info("Rendering template %s to %s", args[0], args[1]) - render_utils.render_file(args[0], args[1], config, options.templates) + env = render_utils.create_environment(config, options.templates) + render_utils.render_file(env, args[0], args[1])
if __name__ == '__main__': diff --git a/pylib/gfxprim/render_utils.py b/pylib/gfxprim/render_utils.py index a9590e0..e383619 100644 --- a/pylib/gfxprim/render_utils.py +++ b/pylib/gfxprim/render_utils.py @@ -31,8 +31,7 @@ def create_environment(config, template_dir): return env
-def render_file(source, result, config, template_dir): - env = create_environment(config, template_dir) +def render_file(env, source, result): with open(source) as source_file: source_text = source_file.read() # Hack to preserve empty lines before %% line_statement
http://repo.or.cz/w/gfxprim.git/commit/cb0e0b9b7a723b92deb33de3dab9f0077e69b...
commit cb0e0b9b7a723b92deb33de3dab9f0077e69be0b Author: Tomas Gavenciak gavento@ucw.cz Date: Mon Aug 8 14:05:41 2011 +0200
Move test generation to template system, cleanup
diff --git a/pylib/bin/generate_collected_tests.py b/pylib/bin/generate_collected_tests.py new file mode 100644 index 0000000..4038bd8 --- /dev/null +++ b/pylib/bin/generate_collected_tests.py @@ -0,0 +1,35 @@ +#!/usr/bin/python +# +# Script generating collected_tests.gen.c +# +# 2011 - Tomas Gavenciak gavento@ucw.cz +# + +from gfxprim import render_utils, test_collection +import jinja2 +import logging as log +from optparse import OptionParser + +template_file = "collected_tests.c.t" + +parser = OptionParser(usage="usage: %prog [options] <scan_dir> <output_file>") +parser.add_option("-t", "--templates", dest="templates", + help="Directory with templates.", default=".") +parser.add_option("-c", "--config", dest="config", + help="GfxPrim config file.", default=None) + +def main(options, args): + config = render_utils.load_gfxprimconfig(options.config) + assert config + log.info("Scanning dir %s for tests, generating %s", args[0], args[1]) + env = render_utils.create_environment(config, options.templates) + env.globals['suites'] = test_collection.collect_suites(args[0]) + render_utils.render_file(env, options.templates + '/' + template_file, args[1]) + + +if __name__ == '__main__': + log.debug("Jinja version %s", jinja2.__version__) + (options, args) = parser.parse_args() + if len(args) != 2: + parser.error() + main(options, args) diff --git a/pylib/gfxprim/generators/__init__.py b/pylib/gfxprim/generators/__init__.py deleted file mode 100644 index 431c9ef..0000000 --- a/pylib/gfxprim/generators/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -# -# gfxprim.generate - global config and its loading -# - -import os -import sys - -# Global config instance - -config = None - - -def load_gfxprim_config(config_file = None): - """Initialize GfxPrimConfig from a given or guessed config file. - Looks for the file by parameter, in env['PIXELTYPE_DEFS'] and - in dir(__file__)/../../../gfxprim_config.py, in that order. - """ - - if not config_file: - config_file = os.environ.get("PIXELTYPE_DEFS", None) - if not config_file: - path = os.path.dirname(os.path.abspath(__file__)) - config_file = os.path.abspath( - os.path.join(path, "..", "..", "..", "gfxprim_config.py")) - if not os.path.exists(config_file): - sys.stderr.write("WARNING: GfxPrimConfig file %s not found!n" % - config_file) - - global config - assert not config - from gfxprim.generators.pixeltype import PixelType - from gfxprim.generators.gfxprimconfig import GfxPrimConfig - l = {"PixelType": PixelType, "GfxPrimConfig": GfxPrimConfig} - execfile(config_file, globals(), l) - config = l["config"] - assert config diff --git a/pylib/gfxprim/generators/core/__init__.py b/pylib/gfxprim/generators/core/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pylib/gfxprim/generators/core/gen_blit.py b/pylib/gfxprim/generators/core/gen_blit.py deleted file mode 100644 index 0e3196b..0000000 --- a/pylib/gfxprim/generators/core/gen_blit.py +++ /dev/null @@ -1,78 +0,0 @@ -# Module generating C source and headers for various PixelTypes -# - submodule for blit and friends -# 2011 - Tomas Gavenciak gavento@ucw.cz - -from gfxprim.generators.utils import * - - -## all generated direct blits, for generating GP_Blit() and others -generated_blits = [] - - -# TODO: adapt for both bit-endianness (in-byte prefix and suffix) -# WARN: assuming little-endian in sub-byte pixels order (probably) -def gen_blit_same_t(size, size_suffix, header, code): - """Generate a function blitting the same type of pixel. - Only depends on bpp (bit size), size_suffix must be - of form 8BPP, 2BPP_LE and the like. - """ - - header.rbody( - "n/*** Blit preserving type, variant for {{ size_suffix }} ***n" - " * Assumes the contexts to be of the right types and sizesn" - " * Ignores transformations and clipping */nn" - "void GP_Blit_{{ size_suffix }}(const GP_Context *c1, GP_Coord x1, GP_Coord y1, GP_Size w, GP_Size h,n" - " GP_Context *c2, GP_Coord x2, GP_Coord y2);n", - size=size, size_suffix=size_suffix) - - code.rbody( - "n/*** Blit preservimg type, variant for {{ size_suffix }} ***/n" - "void GP_Blit_{{ size_suffix }}(const GP_Context *c1, GP_Coord x1, GP_Coord y1, GP_Size w, GP_Size h,n" - " GP_Context *c2, GP_Coord x2, GP_Coord y2)n" - "{n" - " if (unlikely(w == 0 || h == 0)) return;nn" - " /* Special case - copy whole line-block with one memcpy() */n" - " if ((x1 == 0) && (x2 == 0) && (w == c1->w) && (c1->w == c2->w) &&n" - " (c1->bytes_per_row == c2->bytes_per_row)) {n" - " memcpy(c2->pixels + c2->bytes_per_row * y2,n" - " c1->pixels + c1->bytes_per_row * y1,n" - " c1->bytes_per_row * h);n" - " return;n" - " }nn" - "{% if size>=8 %}" - " /* General case - memcpy() each horizontal line */n" - " for (GP_Size i = 0; i < h; i++)n" - " memcpy(GP_PIXEL_ADDR_{{ size_suffix }}(c2, x2, y2 + i), n" - " GP_PIXEL_ADDR_{{ size_suffix }}(c1, x2, y2 + i),n" - " {{ size/8 }} * w);n" - "{% else %}" # subtle - rectangles may not be byte aligned in the same way - " /* Alignment (index) of first bits in the first byte */n" - " int al1 = GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x1);n" - " int al2 = GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x2);n" - " /* Special case of the same alignment and width >=2 bytes */n" - " if ((al1 == al2) && (w * {{ size }} >= 16)) {n" - " /* Number of bits in the last partial byte */n" - " int end_al = GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x1 + w);n" - " GP_ASSERT(({{ size }} * w - al1 - end_al) % 8 == 0);n" - " int copy_size = ({{ size }} * w - al1 - end_al) / 8;n" - " /* First and last byte incident to the line */n" - " uint8_t *p1 = GP_PIXEL_ADDR_{{ size_suffix }}(c1, x1, y1);n" - " uint8_t *p2 = GP_PIXEL_ADDR_{{ size_suffix }}(c2, x2, y2);n" - " uint8_t *end_p1 = GP_PIXEL_ADDR_{{ size_suffix }}(c1, x1 + w - 1, y1);n" - " uint8_t *end_p2 = GP_PIXEL_ADDR_{{ size_suffix }}(c2, x2 + w - 1, y2);n" - " for (GP_Size i = 0; i < h; i++) {n" - " if (al1 != 0)n" - " GP_SET_BITS(al1, 8-al1, *p2, GP_GET_BITS(al1, 8-al1, *p1));n" - " memcpy(p2+(al1!=0), p1+(al1!=0), copy_size);n" - " if (end_al != 0)n" - " GP_SET_BITS(0, end_al, *end_p2, GP_GET_BITS(0, end_al, *end_p1));n" - " p1 += c1->bytes_per_row;n" - " end_p1 += c1->bytes_per_row;n" - " p2 += c2->bytes_per_row;n" - " end_p2 += c2->bytes_per_row;n" - " }n" - " } else /* Different bit-alignment, can't use memcpy() */n" - " GP_Blit_Naive(c1, x1, y1, w, h, c2, x2, y2);n" - "{% endif %}" - "}n", size=size, size_suffix=size_suffix) - diff --git a/pylib/gfxprim/generators/core/gen_convert.py b/pylib/gfxprim/generators/core/gen_convert.py deleted file mode 100644 index f128824..0000000 --- a/pylib/gfxprim/generators/core/gen_convert.py +++ /dev/null @@ -1,116 +0,0 @@ -# Module generating C source and headers for various PixelType conversions -# 2011 - Tomas Gavenciak gavento@ucw.cz - -from gfxprim.generators.pixeltype import pixeltypes, channels -from gfxprim.generators.utils import hmask - -def gen_fixedtype_to_type(fixedtype, header, code): - "Generate functions converting a fixed PixelType to any other" - "Does not work on palette types at all (yet)" - code.rbody( - "GP_Pixel GP_{{ f.name }}ToPixel(GP_Pixel pixel, GP_PixelType type)n" - "{n" - " GP_Pixel p = 0;n" - " switch(type) {n" - "{% for tf in types %}" - "{% if tf.number == 0 %}" - " case GP_PIXEL_UNKNOWN:n" - " GP_ABORT("Cannot convert to GP_PIXEL_UNKNOWN");n" - " break;n" - "{% elif tf.is_palette() %}" - " case GP_PIXEL_{{ tf.name }}:n" - " GP_ABORT("Cannot convert to palette type {{ tf.name }}");n" - " break;n" - "{% else %}" - " case GP_PIXEL_{{ tf.name }}:n" - " GP_Pixel_{{ f.name }}_TO_{{ tf.name }}(pixel, p);n" - " break;n" - "{% endif %}" - "{% endfor %}" - " default:n" - " GP_ABORT("Unknown PixelType %ud", type);n" - " }n" - " return p;n" - "}nn", f=fixedtype, types=pixeltypes.values()) - -def gen_type_to_fixedtype(fixedtype, header, code): - "Generate functions converting to a fixed PixelType from any other" - "Does not work on palette types at all (yet)" - code.rbody( - "GP_Pixel GP_PixelTo{{ f.name }}(GP_Pixel pixel, GP_PixelType type)n" - "{n" - " GP_Pixel p = 0;n" - " switch(type) {n" - "{% for sf in types %}" - "{% if sf.number == 0 %}" - " case GP_PIXEL_UNKNOWN:n" - " GP_ABORT("Cannot convert from GP_PIXEL_UNKNOWN");n" - " break;n" - "{% elif sf.is_palette() %}" - " case GP_PIXEL_{{ sf.name }}:n" - " GP_ABORT("Cannot convert from palette type {{ sf.name }} (yet)");n" - " break;n" - "{% else %}" - " case GP_PIXEL_{{ sf.name }}:n" - " GP_Pixel_{{ sf.name }}_TO_{{ f.name }}(pixel, p);n" - " break;n" - "{% endif %}" - "{% endfor %}" - " default:n" - " GP_ABORT("Unknown PixelType %u", type);n" - " }n" - " return p;n" - "}nn", f=fixedtype, types=pixeltypes.values()) - -def gen_convert_to(f1, f2, header, code): - "Generate a macro converting from f1 to f2" - "This function supports only RGBVA types (no palettes" - allowed_chansets = [ set(list(s)) for s in ['RGB', 'RGBA', 'V', 'VA'] ] - assert(set(f1.chans.keys()) in allowed_chansets) - assert(set(f2.chans.keys()) in allowed_chansets) - - header.rbody( - "n/*** {{ f1.name }} -> {{ f2.name }} ***n" - " * macro storing p1 ({{ f1.name }} at bit-offset o1) in p2 ({{ f2.name }} at bit-offset o2),n" - " * the relevant part of p2 is assumed to be clear (zero) */nn" - "#define GP_Pixel_{{ f1.name }}_TO_{{ f2.name }}_OFFSET(p1, o1, p2, o2) do { " - - ## set each of <TARGET> channels - "{% for c2 in f2.chanslist %}" - - # case 1: just copy a channel - "{%- if c2[0] in f1.chans.keys() %}{% set c1 = f1.chans[c2[0]] %}" - " /* {{ c2[0] }}:={{ c1[0] }} */ GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2, " - " GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1))); " - - # case 2: set A to full opacity (not present in source) - "{% elif c2[0]=='A' %}" - " /* A:={{ hmask(c2[2]) }} */GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2, {{ hmask(c2[2]) }}); " - - # case 3: calculate V as average of RGB - "{% elif c2[0]=='V' and set('RGB').issubset(set(f1.chans.keys())) %}" - " /* V:=RGB_avg */ GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2, ( " - "{% for c1 in [f1.chans['R'], f1.chans['G'], f1.chans['B']] %}" - " /* {{c1[0]}} */ GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1)) + " - "{% endfor %}" - " 0)/3); " - - #- case 4: set each RGB to V - "{% elif c2[0] in 'RGB' and 'V' in f1.chans.keys() %}{% set c1 = f1.chans['V'] %}" - " /* {{ c2[0] }}:=V */ GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2, " - " GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1))); " - - # invalid mapping (there should be none, but who knows ...) - "{% else %} {{ raise(Error('channel conversion' +f1.name+ ' to ' +f2.name+ ' not supported')) }}" - - # end of the loop - "{% endif %}" - "{% endfor %}" - "} while (0)nn" - - # add version without offsets - "/* a version without offsets */n" - "#define GP_Pixel_{{ f1.name }}_TO_{{ f2.name }}(p1, p2) " - "GP_Pixel_{{ f1.name }}_TO_{{ f2.name }}_OFFSET(p1, 0, p2, 0)n", - f1=f1, f2=f2, hmask=hmask, set=set) - diff --git a/pylib/gfxprim/generators/core/gen_getputpixel.py b/pylib/gfxprim/generators/core/gen_getputpixel.py deleted file mode 100644 index 14e455d..0000000 --- a/pylib/gfxprim/generators/core/gen_getputpixel.py +++ /dev/null @@ -1,52 +0,0 @@ -# Module generating C source and headers for get/putpixel -# 2011 - Tomas Gavenciak gavento@ucw.cz -# 2011 - Cyril Hrubis metan@ucw.cz - -from gfxprim.generators.utils import * - -def gen_get_pixel_addr_bpp(size, size_suffix, header): - "Generate GP_PIXEL_ADDR_<size_suffix> and _OFFSET_<size_suffix> macros" - bit_endian = size_suffix[-2:] - if size < 8: - assert bit_endian in ['LE', 'BE'] - header.rbody( - "/* macro to get address of pixel in a {{ size_suffix }} context */n" - "#define GP_PIXEL_ADDR_{{ size_suffix }}(context, x, y) " - " ((context)->pixels + (context)->bytes_per_row * (y) + {{ size//8 }} * (x))n" - "/* macro to get bit-offset of pixel in {{ size_suffix }} context */n" - "{% if size >= 8 %}" - "#define GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x) (0)n" - "{% else %}" # bit_endian matters - "{% if bit_endian=='LE' %}" - "#define GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x) " - " (((x) % {{ 8//size }}) * {{ size }})n" - "{% else %}" - "#define GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x) " - " ({{ 8-size }} - ((x) % {{ 8//size }}) * {{ size }})n" - "{% endif %}" - "{% endif %}", - size=size, size_suffix=size_suffix, bit_endian=bit_endian) - -def gen_getpixel_bpp(size, size_suffix, header): - "Generate code for GetPixel_Raw_xBPP, no clipping or transform. " - "Only depends on bpp (bit size), size_suffix must be " - "of form 8BPP, 2BPP_LE and the like." - header.rbody( - "n/*** GP_GetPixel for {{ size_suffix }} ***/n" - "static inline GP_Pixel GP_GetPixel_Raw_{{ size_suffix }}(const GP_Context *c, int x, int y)n" - "{n" - " return GP_GET_BITS(GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x), {{ size }},n" - " *(GP_PIXEL_ADDR_{{ size_suffix}}(c, x, y)));n" - "}nn", size=size, size_suffix=size_suffix) - -def gen_putpixel_bpp(size, size_suffix, header): - "Generate code for PutPixel_Raw_xBPP, no clipping or transform. " - "Only depends on bpp (bit size), size_suffix must be " - "of form 8BPP, 2BPP_LE and the like." - header.rbody( - "n/*** GP_PutPixel for {{ size_suffix }} ***/n" - "static inline void GP_PutPixel_Raw_{{ size_suffix }}(GP_Context *c, int x, int y, GP_Pixel p)n" - "{n" - " GP_SET_BITS(GP_PIXEL_ADDR_OFFSET_{{ size_suffix }}(x) , {{ size }},n" - " *(GP_PIXEL_ADDR_{{ size_suffix}}(c, x, y)), p);n" - "}nn", size=size, size_suffix=size_suffix) diff --git a/pylib/gfxprim/generators/core/gen_pixeltype.py b/pylib/gfxprim/generators/core/gen_pixeltype.py deleted file mode 100644 index 942a1a2..0000000 --- a/pylib/gfxprim/generators/core/gen_pixeltype.py +++ /dev/null @@ -1,109 +0,0 @@ -# Module generating C source and headers for various PixelTypes -# 2011 - Tomas Gavenciak gavento@ucw.cz - -from gfxprim.generators.pixeltype import pixeltypes, channels -from gfxprim.generators.utils import j2render as r, hmask - - -def str_start(ptype): - "Return a visual separator starting `ptype`-related defs" - return ("n/*************************************************************n" - " * Pixel type " + ptype.name + "n */n") - -def str_description(ptype): - "Return a short C comment describing the PixelType" - return r( - "/* Automatically generated code for pixel type {{ f.name }}n" - " *n" - " * Size (bpp): {{ f.size }} ({{ f.size_suffix }})n" - "{% if f.size<8 %} * Bit endian: {{ f.bit_endian }}n{% endif %}" - " * Pixel structure: {{ ''.join(f.bits) }}n" - " * Channels: n" - "{% for c in f.chanslist %}" - " * {{ c[0] }} offset:{{ c[1] }} size:{{ c[2] }}n" - "{% endfor %}" - " */n", f=ptype) - -def gen_GP_PixelType(header, code): - "Generates definition of GP_PixelType enum" - pt_by_num = sorted([(t.number, t) for t in pixeltypes.values()]) - sorted_pts = [t[1] for t in pt_by_num] - pt_max = len(sorted_pts) - header.rbody( - "/* List of all known pixel types */n" - "typedef enum GP_PixelType {n" - "{% for t in sorted_pts %}" - " GP_PIXEL_{{ t.name }} = {{ t.number }},n" - "{% endfor %}" - " GP_PIXEL_MAX = {{ pt_max }},n" - "} GP_PixelType;n", sorted_pts=sorted_pts, pt_max=pt_max) - -def gen_GP_PixelTypes(header, code): - "Generate the const structure GP_PixelTypes describing all the PixelTypes" - pt_by_num = sorted([(t.number, t) for t in pixeltypes.values()]) - sorted_pts = [t[1] for t in pt_by_num] - code.rbody( - "/* Description of all known pixel types */n" - "const GP_PixelTypeDescription const GP_PixelTypes [] = {n" - "{% for t in sorted_pts %}" - " /* GP_PIXEL_{{ t.name }} */ {n" - " .type = GP_PIXEL_{{ t.name }},n" - ' .name = "{{ t.name }}",n' - ' .size = {{ t.size }},n' - ' .bit_endian = GP_BIT_ENDIAN_{{ t.bit_endian }},' - '{% if t.size>=8 %} /* IGNORED for this type */{% endif %}n' - ' .numchannels = {{ len(t.chanslist) }},n' - ' .bitmap = "{{ t.bits|join("") }}",n' - ' .channels = {n' - '{% for c in t.chanslist %}' - ' { .name = "{{ c[0] }}", .offset = {{ c[1] }}, .size = {{ c[2] }} },n' - '{% endfor %}' - ' } },n' - '{% endfor %}' - '};n', sorted_pts=sorted_pts, len=len) - -def gen_print(ptype, header, code): - "Generate a GP_PixelSNPrint_<TYPE> function (source and header)" - header.rbody( - "/* snprintf a human readable value of pixel type {{ f.name }} */n" - "void GP_PixelSNPrint_{{ f.name }}(char *buf, size_t len, GP_Pixel p);n", f=ptype) - code.rbody( - "/* snprintf a human readable value of pixel type {{f.name}} */n" - "void GP_PixelSNPrint_{{ f.name }}(char *buf, size_t len, GP_Pixel p)n" - "{n" - ' snprintf(buf, len, "<{{ f.name }} 0x%0{{ (f.size+3)//4 }}x{% for c in f.chanslist %} {{ c[0] }}=%d{% endfor %}>",n' - " GP_GET_BITS(0, {{ f.size }}, p)" - "{% for c in f.chanslist %}" - ",n GP_GET_BITS({{ c[1] }}, {{ c[2] }}, p)" - "{% endfor %});n" - "}n", f=ptype) - -def gen_get_chs(ptype, header, code): - "Generate GP_Pixel_GET_<CHAN>_<TYPE> macros" - header.rbody( - "/* macros to get channels of pixel type {{ f.name }} */n" - "{% for c in f.chanslist %}" - "#define GP_Pixel_GET_{{ c[0] }}_{{ f.name }}(p) (GP_GET_BITS({{ c[1] }}, {{ c[2] }}, (p)))n" - "{% endfor %}", f=ptype) - -def gen_create(ptype, header, code): - "Generate GP_Pixel_CREATE_<TYPE> macros" - header.rbody( - "/* macros to create GP_Pixel of pixel type {{ f.name }} directly from given values.n" - " * The values are NOT clipped to actual value ranges.*/n" - "#define GP_Pixel_CREATE_{{ f.name }}({{ args }}) (0 " - "{% for c in f.chanslist %}" - " + (({{ c[0] }}) << {{ c[1] }}) " - "{% endfor %}" - " )n", f=ptype, args=', '.join([c[0] for c in ptype.chanslist])) - -def gen_get_pixel_addr(ptype, header, code): - "Generate GP_PIXEL_ADDR_<TYPE> and _OFFSET_<TYPE> macros" - header.rbody( - "/* macro to get address of pixel {{ f.name }} in a context */n" - "#define GP_PIXEL_ADDR_{{ f.name }}(context, x, y) GP_PIXEL_ADDR_{{ f.size_suffix }}(context, x, y)n" - "/* macro to get bit-offset of pixel {{ f.name }} */n" - "#define GP_PIXEL_ADDR_OFFSET_{{ f.name }}(x) " - " GP_PIXEL_ADDR_OFFSET_{{ f.size_suffix }}(x)n", - f=ptype) - diff --git a/pylib/gfxprim/generators/generator.py b/pylib/gfxprim/generators/generator.py deleted file mode 100644 index ca6df56..0000000 --- a/pylib/gfxprim/generators/generator.py +++ /dev/null @@ -1,151 +0,0 @@ -# -# gfxprim.generators.generator - Base and C (.c/.h) classes for code generators -# -# 2011 - Tomas Gavenciak gavento@ucw.cz -# - -import os -import time -import logging as log -from gfxprim.generators.utils import j2render - - -# List of known CodeGenerator instances - -known_generators = [] - - -class CodeGenerator(object): - """Args: - fname (required) - name of the generated file (without path) - fdir ('') - directory prefix to match - generating_f (None) - user function called in generate(), should generate content - register (False) - if true, register in global generator list - """ - generator_attributes__ = ['generating_f', 'register'] - - def __init__(self, **kwargs): - self.name = kwargs.pop('name') - self.fdir, self.fname = os.path.split(self.name) - self.generating_f = None - self.register = False - self.head = [] - self.body = [] - self.foot = [] - self.setargs(**kwargs) - if kwargs: - log.fatal('Unknown arguments to CodeGenerator: %s' % str(kwargs.keys())) - - def setargs(self, **kwargs): - for i in self.generator_attributes__: - if i in kwargs: - self.__setattr__(i, kwargs.pop(i)) - - def matches_path(self, path): - return path.endswith(self.name) - - def r(self, s, *args, **kwargs): - return j2render(s, g=self, *args, **kwargs) - - def rhead(self, *args, **kwargs): - self.head.append(self.r(*args, **kwargs)) - - def rbody(self, *args, **kwargs): - self.body.append(self.r(*args, **kwargs)) - - def rfoot(self, *args, **kwargs): - self.foot.append(self.r(*args, **kwargs)) - - def generate(self, run_gen_base=True): - self.head = [] - self.body = [] - self.foot = [] - if run_gen_base: - self.gen_base() - # Run user-specified generation f - if self.generating_f: - f, pos, params = self.generating_f - args = [self if i == pos else global_null_generator - for i in range(params)] - f(*args) - return ''.join(self.head + self.body + self.foot) - - def gen_base(self): - "Fill basic subclass-dependent content into head/body/foot" - pass - - -class NullGenerator(CodeGenerator): - def rhead(self, *args, **kwargs): pass - def rbody(self, *args, **kwargs): pass - def rfoot(self, *args, **kwargs): pass - def generate(self, *args, **kwargs): return '' - def r(self, *args, **kwargs): return '' - -global_null_generator = NullGenerator(name='null_generator') - - -class CCodeGenerator(CodeGenerator): - """Args: - authors ([]) - list of author credits - descr ("") - (multiline) file description - """ - generator_attributes__ = (['authors', 'descr'] + - CodeGenerator.generator_attributes__) - - def __init__(self, **kwargs): - self.authors = [] - self.descr = "" - super(CCodeGenerator, self).__init__(**kwargs) - - def gen_base(self): - super(CCodeGenerator, self).gen_base() - self.head.append(self.r( - "/*n" - " * {{ g.fname }}n" - " *n" - " * GENERATED on {{ date }} by generator "{{ g.name }}"n" - " * DO NOT MODIFY THIS FILE DIRECTLY!n" - " *n" - "{% if g.descr %}" - " * {{ g.descr }}n *n" - "{% endif %}" - "{% for a in g.authors %}" - " * {{ a }}n" - "{% endfor %}" - " */nn", date = time.ctime())) - - -class CSourceGenerator(CCodeGenerator): - def __init__(self, **kwargs): - super(CSourceGenerator, self).__init__(**kwargs) - - -class CHeaderGenerator(CCodeGenerator): - def __init__(self, **kwargs): - super(CHeaderGenerator, self).__init__(**kwargs) - self.hdef = ('GP_HEADER_' + - self.name.replace('.', '_').replace('/', '_').upper()) - - def gen_base(self): - super(CHeaderGenerator, self).gen_base() - self.head.append(self.r( - "#ifndef {{ g.hdef }}n" - "#define {{ g.hdef }}nn")) - self.foot.append(self.r( - "#endif /* {{ g.hdef }} */n")) - - -def generator(*args, **kwargs): - """Decorate functions to be content-creator for given generators. - By default also registers the generator to pool of known generators. - """ - register = kwargs.pop('register', True) - def decorate(f): - for i in range(len(args)): - kwargs['generating_f'] = (f, i, len(args)) - args[i].setargs(**kwargs) - if register: - known_generators.append(args[i]) - return f - return decorate diff --git a/pylib/gfxprim/generators/make_collected_tests.py b/pylib/gfxprim/generators/make_collected_tests.py deleted file mode 100644 index 04af1eb..0000000 --- a/pylib/gfxprim/generators/make_collected_tests.py +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/python -# -# Script generating collected_tests.gen.c -# -# Scrapes the target directory for .test.c files, looks for -# GP_TEST and GP_SUITE macros and generates code creating all the -# tests and the suite -# -# 2011 - Tomas Gavenciak gavento@ucw.cz -# - - -# Also fixed in tests.mk -collected_tests_file = 'collected_tests.gen.c' - -import os -import re -import glob -import logging as log -from gfxprim.generators.generator import * - - -def warn(msg, fname=None, line=None): - "Warning including file and line info" - assert fname - loc = "[%s] " % fname - if line: - loc = "[%s:%d] " % (fname, line) - log.warning(loc + msg) - - -testfile_patterns = ['*.test.c', '*.test.gen.c'] - -# {"suitename":["testname":{test_parameters}]} -suites = {} - -suite_re = re.compile("A\s*GP_SUITE((.*))\s*Z") -test_re = re.compile("A\s*GP_TEST((.*))\s*Z") - - -@generator(CHeaderGenerator(name = collected_tests_file), - descr = 'Code creating the tests and suites for tests collected ' - 'from .test.c files', - authors = ["2011 - Tomas Gavenciak gavento@ucw.cz"]) -def tests_collected_tests(c): - fnames = [] - for pat in testfile_patterns: - fnames += glob.fnmatch.filter(os.listdir(c.fdir or '.'), pat) - for fn in fnames: - dirfn = os.path.join(c.fdir, fn) - with open(dirfn, 'rt') as f: - find_tests(f, fn) - if not fnames: - warn('No .test.c files found in "%s".' % c.fdir) - if not suites: - warn('No suites found, generating empty testsuite.') - - c.rhead("#include <check.h>nn") - - for suite, tests in suites.iteritems(): - c.rbody( - "/****************************************************************n" - " * Suite {{ suite }}n" - " */nn", suite=suite) - for t in tests: - assert ('loop_start' in t) == ('loop_end' in t) - c.rbody( - "/*n" - " * Test {{ suite }}/{{ t['name'] }} defined in {{ t['fname'] }}:{{ t['line'] }}n" - " */nn" - "void GP_TEST_{{ t['name'] }}(int);nn" - "TCase *GP_TC_{{ suite }}_{{ t['name'] }}() {n" - " TCase *tc = tcase_create("{{ t['name'] }}");n" - " _tcase_add_test(tc, GP_TEST_{{ t['name'] }}, "{{ t['name'] }}", " - "{{ t.get('expect_signal', 0) }}, {{ t.get('expect_exit', 0) }}, " - "{{ t.get('loop_start', 0) }}, {{ t.get('loop_end', 1) }});n" - " return tc;n}nn", t=t, suite=suite) - # TODO: Handle special test requirements (timing, fixture, ...) - - c.rbody( - "Suite *GP_TS_{{ suite }}() {n" - " Suite *s = suite_create("{{ suite }}");n" - "{% for t in tests %}" - " suite_add_tcase(s, GP_TC_{{ suite }}_{{ t['name'] }}());n" - "{% endfor %}" - " return s;n}nn", tests=tests, suite=suite) - - # Once for all suites - c.rbody( - "/****************************************************************n" - " * Create and add all suites to a SRunnern" - " */nn" - "void GP_AddSuitesToSRunner(SRunner *sr) {n" - "{% for s in suites %}" - " srunner_add_suite(sr, GP_TS_{{ s }}());n" - "{% endfor %}" - "}nn", suites=suites) - - -def find_GP_directive(name, regexp, l, fname='unknown', line=0): - "Looks for a given GP_* directive, parses args if any, " - "retuns (name, dict_of_args) or (None, None) if not found." - if name in l: - m = regexp.search(l) - if not m: - warn("found unsuitable %s directive, ignoring." % name, fname, line) - else: - d = m.groups()[0].split(',', 1) - args = {} - if len(d)>1: - try: - s = 'dict( ' + d[1].strip(" tn"") + ' )' - args = eval(s) - except: - log.fatal("error parsing arguments: %r" % s, fname, line) - return d[0].strip(), args - return None, None - - -def find_tests(f, fname): - "Finds all tests in a file." - suite = None - ls = f.readlines() - for i in range(len(ls)): - l = ls[i] - # Look for suite declaration - name, args = find_GP_directive("GP_SUITE", suite_re, l, fname=fname, line=i) - if name: - suite = name - if args: - warn("suite should have no arguments other than name.", fname, i) - suites.setdefault(name, []) - # Look for suite declaration - name, args = find_GP_directive("GP_TEST", test_re, l, fname=fname, line=i) - if name: - test_suite = suite - if 'suite' in args: - test_suite = args['suite'] - if not test_suite: - test_suite = 'default' - warn("no suite defined before test %s, using %r." % (name, test_suite), fname, i) - args['name'] = name - args['fname'] = fname - args['line'] = i - suites.setdefault(test_suite, []) - suites[test_suite].append(args) - diff --git a/pylib/gfxprim/generators/utils.py b/pylib/gfxprim/generators/utils.py deleted file mode 100644 index 15d7013..0000000 --- a/pylib/gfxprim/generators/utils.py +++ /dev/null @@ -1,46 +0,0 @@ -# -# gfxprim.generators.utils - Module with templates and tools for writing -# generated code, especially C source and headers. -# -# 2011 - Tomas Gavenciak gavento@ucw.cz -# - - -import jinja2 -import logging as log - -def j2render(tmpl, **kw): - "Internal helper to render jinja2 templates (with StrictUndefined)" - t2 = tmpl.rstrip('n') # Jinja strips the last 'n', so add these later - return jinja2.Template(t2, undefined=jinja2.StrictUndefined).render(**kw) + - tmpl[len(t2):] - - -def load_generators(): - "Load all modules containig generators to allow them to register" - # TODO: write proper discovery - import gfxprim.generators.make_collected_tests - import gfxprim.generators.core.make_GP_Pixel - import gfxprim.generators.core.make_GP_Blit - import gfxprim.generators.core.make_GP_Convert - - -def generate_file(fname): - "Function trying to generate file `fname` using matching known generator." - from gfxprim.generators.generator import known_generators - matches = [] - for k in known_generators: - if k.matches_path(fname): - matches.append(k) - if len(matches) == 0: - log.fatal("No known generators match '%s'" % (fname,)) - if len(matches) > 1: - log.fatal("Multiple generators match '%s': %s" % (fname, str(matches))) - s = matches[0].generate() - with open(fname, "wt") as f: - f.write(s) - - -def hmask(bits): - "Helper returning hex mask for that many bits" - return hex((1<<bits)-1).rstrip('L') diff --git a/pylib/gfxprim/test_collection.py b/pylib/gfxprim/test_collection.py new file mode 100644 index 0000000..db3b5b2 --- /dev/null +++ b/pylib/gfxprim/test_collection.py @@ -0,0 +1,96 @@ +# +# Scrapes the target directory for .test.c files, looks for +# GP_TEST and GP_SUITE macros and generates code creating all the +# tests and the suite +# +# 2011 - Tomas Gavenciak gavento@ucw.cz +# + +import os +import re +import glob +import logging as log +from gfxprim.render_utils import create_environment, render_file + +testfile_patterns = ['*.test.c', '*.test.gen.c'] + +suite_re = re.compile("A\s*GP_SUITE((.*))\s*Z") +test_re = re.compile("A\s*GP_TEST((.*))\s*Z") + +# Also fixed in tests.mk +collected_tests_file = 'collected_tests.gen.c' + +# suites is a dict of tests: +# {"suitename": [Test]} + +# Test is a dict: +# {"attribute": val} +# attributes are: +# name, fname, line + +def find_tests(fname, suites): + "Finds all tests in a file, extend suites." + suite = None + f = open(fname, 'rt') + ls = list(f.readlines()) + f.close() + for i in range(len(ls)): + l = ls[i] + # Look for suite declaration + name, args = find_GP_directive("GP_SUITE", suite_re, l, fname=fname, line=i) + if name: + if args: + log.warn("suite should have no arguments other than name.", fname, i) + suites.setdefault(name, []) + suite = name + # Look for test declaration + name, args = find_GP_directive("GP_TEST", test_re, l, fname=fname, line=i) + if name: + test_suite = suite + if 'suite' in args: + test_suite = args['suite'] + if not test_suite: + test_suite = 'default' + log.warn("No suite defined before test %s, using %r." % (name, test_suite), fname, i) + args['name'] = name + args['fname'] = fname + args['line'] = i + assert ('loop_start' in args) == ('loop_end' in args) + suites.setdefault(test_suite, []) + suites[test_suite].append(args) + + +def collect_suites(fdir): + fnames = [] + suites = {} + for pat in testfile_patterns: + fnames += glob.fnmatch.filter(os.listdir(fdir), pat) + for fn in fnames: + find_tests(os.path.join(fdir, fn), suites) + if not fnames: + log.warn('No .test.c files found in "%s".', fdir) + if not suites: + log.warn('No suites found, generating an empty testsuite.') + return suites + + +def find_GP_directive(name, regexp, l, fname='unknown', line=0): + "Looks for a given GP_* directive, parses args if any, " + "retuns (name, dict_of_args) or (None, None) if not found." + if name in l: + m = regexp.search(l) + if not m: + warn("found unsuitable %s directive, ignoring." % name, fname, line) + else: + d = m.groups()[0].split(',', 1) + args = {} + if len(d)>1: + try: + s = 'dict( ' + d[1].strip(" tn"") + ' )' + args = eval(s) + except: + log.fatal("error parsing arguments: %r" % s, fname, line) + return d[0].strip(), args + return None, None + + diff --git a/pylib/templates/collected_tests.c.t b/pylib/templates/collected_tests.c.t new file mode 100644 index 0000000..cd24232 --- /dev/null +++ b/pylib/templates/collected_tests.c.t @@ -0,0 +1,55 @@ +%% extends "base.c.t" + +%% block descr +Code creating the tests and suites for tests collected from .test.c files. +%% endblock + +%% block body + +#include <check.h> + +%% for suite, tests in suites.items() + +/**************************************************************** + * Suite {{ suite }} + */ + +%% for t in tests +/* + * Test {{ suite }}/{{ t['name'] }} defined in {{ t['fname'] }}:{{ t['line'] }} + */ + +void GP_TEST_{{ t['name'] }}(int); + +## TODO: Handle special test requirements (timing, fixture, ...) +TCase *GP_TC_{{ suite }}_{{ t['name'] }}() +{ + TCase *tc = tcase_create("{{ t['name'] }}"); + _tcase_add_test(tc, GP_TEST_{{ t['name'] }}, "{{ t['name'] }}", + {{ t.get('expect_signal', 0) }}, {{ t.get('expect_exit', 0) }}, + {{ t.get('loop_start', 0) }}, {{ t.get('loop_end', 1) }}); + return tc; +} + +%% endfor + +Suite *GP_TS_{{ suite }}() { + Suite *s = suite_create("{{ suite }}"); +%% for t in tests + suite_add_tcase(s, GP_TC_{{ suite }}_{{ t['name'] }}()); +%% endfor + return s; +} + +%% endfor + +/**************************************************************** + * Create and add all suites to a SRunner + */ +void GP_AddSuitesToSRunner(SRunner *sr) { +%% for suite, tests in suites.items() + srunner_add_suite(sr, GP_TS_{{ suite }}()); +%% endfor +} + +%% endblock body diff --git a/tests.mk b/tests.mk index e4cf3bb..d18d86a 100644 --- a/tests.mk +++ b/tests.mk @@ -19,11 +19,18 @@ CSOURCES+=${GP_TESTLIB_SRCS}
# generated suite creation code TESTSUITE_GEN=collected_tests.gen.c # also fixed in the code generator -GENSOURCES+=${TESTSUITE_GEN} +CLEAN+=${TESTSUITE_GEN}
${TESTSUITE_GEN}: $(filter-out ${TESTSUITE_GEN},${GENSOURCES}) ${GENHEADERS} +ifdef VERBOSE + ${PYTHON} ${TOPDIR}/pylib/bin/generate_collected_tests.py -t $(TEMPLATE_DIR) "." "$@" +else + @echo "TSTS $@" + @${PYTHON} ${TOPDIR}/pylib/bin/generate_collected_tests.py -t $(TEMPLATE_DIR) "." "$@" +endif +
-TESTSUITE_SRCS=$(wildcard *.test.c) ${GENSOURCES} ${GENHEADERS} ${GP_TESTLIB_SRCS} +TESTSUITE_SRCS=$(wildcard *.test.c) ${GENSOURCES} ${GENHEADERS} ${GP_TESTLIB_SRCS} ${TESTSUITE_GEN} INCLUDE+=../tests/common TESTSUITE_OBJS=$(patsubst %.c,%.o,$(TESTSUITE_SRCS)) CLEAN+=${TESTSUITE} ${TESTSUITE_OBJS}
http://repo.or.cz/w/gfxprim.git/commit/ffa0e5910b52a5fe361e1bc5753665fec90a8...
commit ffa0e5910b52a5fe361e1bc5753665fec90a8db4 Author: Tomas Gavenciak gavento@ucw.cz Date: Mon Aug 8 10:40:58 2011 +0200
Modifications to templating library, extensions
diff --git a/pylib/gfxprim/pixelsize.py b/pylib/gfxprim/pixelsize.py index 1586250..88f7364 100644 --- a/pylib/gfxprim/pixelsize.py +++ b/pylib/gfxprim/pixelsize.py @@ -15,6 +15,7 @@ class PixelSize(object): self.bit_endian = bit_endian assert self.bit_endian in [None, LE, BE] assert (bit_endian is not None) == self.needs_bit_endian() + self.bit_endian_const = "GP_BIT_ENDIAN_" + (self.bit_endian or LE)
self.suffix = suffix if not self.suffix: diff --git a/pylib/gfxprim/pixeltype.py b/pylib/gfxprim/pixeltype.py index 5cf356e..e2389a0 100644 --- a/pylib/gfxprim/pixeltype.py +++ b/pylib/gfxprim/pixeltype.py @@ -39,7 +39,7 @@ class PixelType(object): "Check PixelType compatibility with given GfxPrimConfig."
# all types except UNKNOWN must have one of these sizes - if self.name != "UNKNOWN": + if not self.is_unknown(): assert(self.pixelsize in config.pixelsizes)
def __str__(self): @@ -47,3 +47,16 @@ class PixelType(object):
def is_palette(self): return ('P' in self.chans) + + def is_unknown(self): + return (self.name == "UNKNOWN") + + def is_rgb(self): + return all((i in self.chans for i in 'RGB')) + + def is_gray(self): + return ('V' in self.chans) + + def is_alpha(self): + return ('A' in self.chans) + diff --git a/pylib/gfxprim/render_utils.py b/pylib/gfxprim/render_utils.py index 1051f3c..a9590e0 100644 --- a/pylib/gfxprim/render_utils.py +++ b/pylib/gfxprim/render_utils.py @@ -8,15 +8,26 @@ import os import time import re
+def template_error(s, *args): + raise Exception(s, *args) + def create_environment(config, template_dir): env = jinja2.Environment( line_statement_prefix = "%%", + line_comment_prefix = "##", undefined = jinja2.StrictUndefined, loader = jinja2.FileSystemLoader(template_dir)) env.globals['undefined'] = jinja2.StrictUndefined() env.globals['pixelsizes'] = config.pixelsizes env.globals['pixeltypes'] = config.pixeltypes + env.globals['pixeltypes_dict'] = config.pixeltypes_dict env.globals['gfxprim_config'] = config + from gfxprim.pixelsize import LE, BE + env.globals['LE'] = LE + env.globals['BE'] = BE + env.globals['len'] = len + env.globals['error'] = template_error + env.globals['hex'] = lambda(x): hex(x).rstrip('L') return env
diff --git a/pylib/templates/base.h.t b/pylib/templates/base.h.t index 8eb9140..8f60d6a 100644 --- a/pylib/templates/base.h.t +++ b/pylib/templates/base.h.t @@ -1,4 +1,4 @@ -%% extends "body.c.h" +%% extends "base.c.t"
%% block pre_body_guard #ifndef {{ header_guard }}
http://repo.or.cz/w/gfxprim.git/commit/cfe11b6f6f3c41d3ff6c18d90efdd2615a5e8...
commit cfe11b6f6f3c41d3ff6c18d90efdd2615a5e858a Author: Tomas Gavenciak gavento@ucw.cz Date: Mon Aug 8 10:39:12 2011 +0200
Finished moving and cleaning templates from .py to .t
Refactoring time! Also simplified and minor fixes along the way Test generation partially WIP
diff --git a/include/core/GP_Blit.gen.h.t b/include/core/GP_Blit.gen.h.t new file mode 100644 index 0000000..cc1cc6e --- /dev/null +++ b/include/core/GP_Blit.gen.h.t @@ -0,0 +1,16 @@ +%% extends "base.h.t" + +{% block descr %}Specialized blit functions and macros.{% endblock %} + +%% block body + +%% for ps in pixelsizes +/*** Blit preserving type for {{ ps.suffix }} *** + * Assumes the contexts to be of the right types and sizes + * Ignores transformations and clipping */ +void GP_Blit_{{ ps.suffix }}(const GP_Context *c1, GP_Coord x1, GP_Coord y1, GP_Size w, GP_Size h, + GP_Context *c2, GP_Coord x2, GP_Coord y2); + +%% endfor + +%% endblock body diff --git a/include/core/GP_Convert.gen.h.t b/include/core/GP_Convert.gen.h.t new file mode 100644 index 0000000..2b4681a --- /dev/null +++ b/include/core/GP_Convert.gen.h.t @@ -0,0 +1,86 @@ +%% extends "base.h.t" + +{% block descr %}Convert PixelType values macros and functions{% endblock %} + + +%% macro GP_Pixel_TYPE_TO_TYPE(pt1, pt2) +/*** {{ pt1.name }} -> {{ pt2.name }} *** + * macro reads p1 ({{ pt1.name }} at bit-offset o1) + * and writes to p2 ({{ pt2.name }} at bit-offset o2) + * the relevant part of p2 is assumed to be cleared (zero) */ +#define GP_Pixel_{{ pt1.name }}_TO_{{ pt2.name }}_OFFSET(p1, o1, p2, o2) do { +%% for c2 in pt2.chanslist +{# case 1: just copy a channel -#} +%% if c2[0] in pt1.chans.keys() +%% set c1 = pt1.chans[c2[0]] + /* {{ c2[0] }}:={{ c1[0] }} */ GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2,+ GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1))); +{# case 2: set A to full opacity (not present in source) -#} +%% elif c2[0]=='A' + /* A:={{ hex(c2[2]) }} */GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2, {{ hex(c2[2]) }}); +{# case 3: calculate V as average of RGB -#} +%% elif c2[0]=='V' and pt1.is_rgb() + /* V:=RGB_avg */ GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2, ( +%% for c1 in [pt1.chans['R'], pt1.chans['G'], pt1.chans['B']] + /* {{c1[0]}} */ GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1)) + +%% endfor + 0)/3);+{# case 4: set each RGB to V -#} +%% elif c2[0] in 'RGB' and pt1.is_gray() +%% set c1 = pt1.chans['V'] + /* {{ c2[0] }}:=V */ GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2,+ GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1))); +{# case 5: invalid mapping -#} +%% else +{{ error('Channel conversion ' + pt1.name + ' to ' + pt2.name + ' not supported.') }} +%% endif +%% endfor +} while (0) + +/* a version without offsets */ +#define GP_Pixel_{{ pt1.name }}_TO_{{ pt2.name }}(p1, p2) + GP_Pixel_{{ pt1.name }}_TO_{{ pt2.name }}_OFFSET(p1, 0, p2, 0) + +%% endmacro + + +%% block body +#include "GP_Common.h" +#include "GP_Context.h" +#include "GP_Pixel.h" + +## +## Loop around "central" pixel types +## +%% for pt in [pixeltypes_dict['RGB888'], pixeltypes_dict['RGBA8888']] +%% for i in pixeltypes +%% if not i.is_unknown() +%% if not i.is_palette() +{{ GP_Pixel_TYPE_TO_TYPE(pt, i) }} +%% if i.name not in ['RGB888', 'RGBA8888'] +{{ GP_Pixel_TYPE_TO_TYPE(i, pt) }} +%% endif +%% endif +%% endif +%% endfor + +/* + * Convert {{ pt.name }} to any other PixelType + * Does not work on palette types at all (yet) + */ +GP_Pixel GP_{{ pt.name }}ToPixel(GP_Pixel pixel, GP_PixelType type); + +/* + * Function converting to {{ pt.name }} from any other PixelType + * Does not work on palette types at all (yet) + */ +GP_Pixel GP_PixelTo{{ pt.name }}(GP_Pixel pixel, GP_PixelType type); + +%% endfor + +/* Experimental macros testing generated scripts */ +{{ GP_Pixel_TYPE_TO_TYPE(pixeltypes_dict['RGB565'], pixeltypes_dict['RGBA8888']) }} +{{ GP_Pixel_TYPE_TO_TYPE(pixeltypes_dict['RGBA8888'], pixeltypes_dict['V2']) }} +{{ GP_Pixel_TYPE_TO_TYPE(pixeltypes_dict['VA12'], pixeltypes_dict['RGBA8888']) }} + +%% endblock body diff --git a/include/core/GP_Convert_Scale.gen.h.t b/include/core/GP_Convert_Scale.gen.h.t new file mode 100644 index 0000000..86c43b0 --- /dev/null +++ b/include/core/GP_Convert_Scale.gen.h.t @@ -0,0 +1,28 @@ +%% extends "base.h.t" + +{% block descr %}Fast value scaling macros{% endblock %} + +{% macro multcoef(s1, s2) -%} +(0{% for i in range((s2+s1-1)/s1) %}+{{ 2**(i*s1) }}{% endfor %}) +{%- endmacro %} + +%% block body +/* + * Helper macros to transfer s1-bit value to s2-bit value. + * Efficient and accurate for both up- and downscaling. + * WARNING: GP_SCALE_VAL requires constants numbers as first two parameters + */ + +#define GP_SCALE_VAL(s1, s2, val) ( GP_SCALE_VAL_##s1##_##s2(val) ) + +%% for s1 in range(1,9) +%% for s2 in range(1,9) +%% if s2>s1 +#define GP_SCALE_VAL_{{s1}}_{{s2}}(val) (((val) * {{ multcoef(s1, s2) }}) >> {{ (-s2) % s1 }}) +%% else +#define GP_SCALE_VAL_{{s1}}_{{s2}}(val) ((val) >> {{ s1 - s2 }}) +%% endif +%% endfor +%% endfor + +%% endblock body diff --git a/include/core/GP_GetPutPixel.gen.h.t b/include/core/GP_GetPutPixel.gen.h.t new file mode 100644 index 0000000..1ee473c --- /dev/null +++ b/include/core/GP_GetPutPixel.gen.h.t @@ -0,0 +1,63 @@ +%% extends "base.h.t" + +%% block descr +Access pixel bytes, Get and PutPixel +Do not include directly, use GP_Pixel.h +%% endblock + +%% block body + +#include "GP_Common.h" + +struct GP_Context; + +%% for ps in pixelsizes +/* + * macro to get address of pixel in a {{ ps.suffix }} context + */ +#define GP_PIXEL_ADDR_{{ ps.suffix }}(context, x, y) + ((context)->pixels + (context)->bytes_per_row * (y) + {{ ps.size // 8 }} * (x)) + +/* + * macro to get bit-offset of pixel in {{ ps.suffix }} context + */ +#define GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x) +%% if not ps.needs_bit_endian() + (0) +%% else +%% if ps.bit_endian == LE +%% if ps.size < 8 + (((x) % {{ 8 // ps.size }}) * {{ ps.size }}) +%% else + (((x) * {{ ps.size }}) / 8) +%% endif +%% else +%% if ps.size < 8 + ({{ 8 - ps.size }} - ((x) % {{ 8 // ps.size }}) * {{ ps.size }}) +%% else + {{ error('Insanity check: big bit-endian with >8 bpp. Are you sure?') }} +%% endif +%% endif +%% endif + +/* + * GP_GetPixel for {{ ps.suffix }} + */ +static inline GP_Pixel GP_GetPixel_Raw_{{ ps.suffix }}(const GP_Context *c, int x, int y) +{ + return GP_GET_BITS(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }}, + *(GP_PIXEL_ADDR_{{ ps.suffix}}(c, x, y))); +} + +/* + * GP_PutPixel for {{ ps.suffix }} + */ +static inline void GP_PutPixel_Raw_{{ ps.suffix }}(GP_Context *c, int x, int y, GP_Pixel p) +{ + GP_SET_BITS(GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x), {{ ps.size }}, + *(GP_PIXEL_ADDR_{{ ps.suffix}}(c, x, y)), p); +} + +%% endfor + +%% endblock body diff --git a/include/core/GP_Pixel.gen.h.t b/include/core/GP_Pixel.gen.h.t new file mode 100644 index 0000000..a71c461 --- /dev/null +++ b/include/core/GP_Pixel.gen.h.t @@ -0,0 +1,83 @@ +%% extends "base.h.t" + +%% block descr +Pixel type definitions and functions +Do not include directly, use GP_Pixel.h +%% endblock + +%% block body + +/* + * List of all known pixel types + */ +typedef enum GP_PixelType { +%% for pt in pixeltypes + GP_PIXEL_{{ pt.name }}, +%% endfor + GP_PIXEL_MAX, +} GP_PixelType; + +%% for pt in pixeltypes +%% if not pt.is_unknown() +/* Automatically generated code for pixel type {{ pt.name }} + * + * Size (bpp): {{ pt.pixelsize.size }} ({{ pt.pixelsize.suffix }}) + * Bit endian: {{ pt.pixelsize.bit_endian_const }} + * Pixel structure: {{ pt.bits|join("") }} + * Channels: +%% for c in pt.chanslist + * {{ c[0] }} offset:{{ c[1] }} size:{{ c[2] }} +%% endfor + */ + +/* + * snprintf a human readable value of pixel type {{ pt.name }} + */ +void GP_PixelSNPrint_{{ pt.name }}(char *buf, size_t len, GP_Pixel p); + +/* + * macros to get channels of pixel type {{ pt.name }} + */ +%% for c in pt.chanslist +#define GP_Pixel_GET_{{ c[0] }}_{{ pt.name }}(p) (GP_GET_BITS({{ c[1] }}, {{ c[2] }}, (p))) +%% endfor + +/* + * macros to get address and bit-offset of a pixel {{ pt.name }} in a context + */ +#define GP_PIXEL_ADDR_{{ pt.name }}(context, x, y) GP_PIXEL_ADDR_{{ pt.pixelsize.suffix }}(context, x, y) +#define GP_PIXEL_ADDR_OFFSET_{{ pt.name }}(x) GP_PIXEL_ADDR_OFFSET_{{ pt.pixelsize.suffix }}(x) + +/* + * macros to create GP_Pixel of pixel type {{ pt.name }} directly from given values. + * The values MUST be already clipped/converted to relevant value ranges. + */ +#define GP_Pixel_CREATE_{{ pt.name }}({{ pt.chanslist[0][0] }}{% for c in pt.chanslist[1:] %}, {{ c[0] }}{% endfor %}) (0+%% for c in pt.chanslist + + (({{ c[0] }}) << {{ c[1] }}) +%% endfor + ) + +%% endif +%% endfor + +/* + * macros for branching on PixelType (similar to GP_FnPerBpp macros) + */ + +%% for r in ['', 'return '] +#define GP_FN_{% if r %}RET_{% endif %}PER_PIXELTYPE(FN_NAME, type, ...)+ switch (type) { +%% for pt in pixeltypes +%% if not pt.is_unknown() + case GP_PIXEL_{{ pt.name }}:+ {{ r }}FN_NAME{{'##'}}_{{ pt.name }}(__VA_ARGS__);+ break;+%% endif +%% endfor + default: GP_ABORT("Invalid PixelType %d", type);+ } + +%% endfor + +%% endblock body diff --git a/libs/core/GP_Blit.gen.c.t b/libs/core/GP_Blit.gen.c.t new file mode 100644 index 0000000..39f839d --- /dev/null +++ b/libs/core/GP_Blit.gen.c.t @@ -0,0 +1,69 @@ +%% extends "base.c.t" + +{% block descr %}Specialized blit functions and macros.{% endblock %} + +%% block body +#include <stdio.h> +#include <string.h> +#include "GP_Pixel.h" +#include "GP.h" +#include "GP_Context.h" +#include "GP_Blit.h" + +%% for ps in pixelsizes +/*** Blit preservimg PixelType, variant for {{ ps.suffix }} ***/ +void GP_Blit_{{ ps.suffix }}(const GP_Context *c1, GP_Coord x1, GP_Coord y1, GP_Size w, GP_Size h, + GP_Context *c2, GP_Coord x2, GP_Coord y2) +{ + if (unlikely(w == 0 || h == 0)) return; + + /* Special case - copy whole line-block with one memcpy() */ + if ((x1 == 0) && (x2 == 0) && (w == c1->w) && (c1->w == c2->w) && + (c1->bytes_per_row == c2->bytes_per_row)) { + memcpy(c2->pixels + c2->bytes_per_row * y2, + c1->pixels + c1->bytes_per_row * y1, + c1->bytes_per_row * h); + return; + } + +%% if not ps.needs_bit_endian() + /* General case - memcpy() each horizontal line */ + for (GP_Size i = 0; i < h; i++) + memcpy(GP_PIXEL_ADDR_{{ ps.suffix }}(c2, x2, y2 + i), + GP_PIXEL_ADDR_{{ ps.suffix }}(c1, x2, y2 + i), + {{ ps.size/8 }} * w); +%% else + /* Rectangles may not be bit-aligned in the same way! */ + /* Alignment (index) of first bits in the first byte */ + int al1 = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x1); + int al2 = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x2); + /* Special case of the same alignment and width >=2 bytes */ + if ((al1 == al2) && (w * {{ ps.size }} >= 16)) { + /* Number of bits in the last partial byte */ + int end_al = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x1 + w); + GP_ASSERT(({{ ps.size }} * w - al1 - end_al) % 8 == 0); + int copy_size = ({{ ps.size }} * w - al1 - end_al) / 8; + /* First and last byte incident to the line */ + uint8_t *p1 = GP_PIXEL_ADDR_{{ ps.suffix }}(c1, x1, y1); + uint8_t *p2 = GP_PIXEL_ADDR_{{ ps.suffix }}(c2, x2, y2); + uint8_t *end_p1 = GP_PIXEL_ADDR_{{ ps.suffix }}(c1, x1 + w - 1, y1); + uint8_t *end_p2 = GP_PIXEL_ADDR_{{ ps.suffix }}(c2, x2 + w - 1, y2); + for (GP_Size i = 0; i < h; i++) { + if (al1 != 0) + GP_SET_BITS(al1, 8-al1, *p2, GP_GET_BITS(al1, 8-al1, *p1)); + memcpy(p2+(al1!=0), p1+(al1!=0), copy_size); + if (end_al != 0) + GP_SET_BITS(0, end_al, *end_p2, GP_GET_BITS(0, end_al, *end_p1)); + p1 += c1->bytes_per_row; + end_p1 += c1->bytes_per_row; + p2 += c2->bytes_per_row; + end_p2 += c2->bytes_per_row; + } + } else /* Different bit-alignment, can't use memcpy() */ + GP_Blit_Naive(c1, x1, y1, w, h, c2, x2, y2); +%% endif +} + + +%% endfor +%% endblock body diff --git a/libs/core/GP_Convert.gen.c.t b/libs/core/GP_Convert.gen.c.t new file mode 100644 index 0000000..8b65a75 --- /dev/null +++ b/libs/core/GP_Convert.gen.c.t @@ -0,0 +1,70 @@ +%% extends "base.c.t" + +{% block descr %}Convert PixelType values macros and functions{% endblock %} + +%% block body + +#include "GP_Convert.h" + +## +## Loop around "central" pixel types +## +%% for pt in [pixeltypes_dict['RGB888'], pixeltypes_dict['RGBA8888']] + +GP_Pixel GP_{{ pt.name }}ToPixel(GP_Pixel pixel, GP_PixelType type) +{ + GP_Pixel p = 0; + switch(type) { +%% for tf in pixeltypes +%% if tf.is_unknown() + case GP_PIXEL_UNKNOWN: + GP_ABORT("Cannot convert {{ pt.name }} to GP_PIXEL_UNKNOWN"); + break; +%% elif tf.is_palette() + case GP_PIXEL_{{ tf.name }}: + GP_ABORT("Cannot convert {{ pt.name }} to palette type {{ tf.name }}"); + break; +%% else + case GP_PIXEL_{{ tf.name }}: + GP_Pixel_{{ pt.name }}_TO_{{ tf.name }}(pixel, p); + break; +%% endif +%% endfor + default: + GP_ABORT("Unknown PixelType %ud", type); + } + return p; +} + + +GP_Pixel GP_PixelTo{{ pt.name }}(GP_Pixel pixel, GP_PixelType type) +{ + GP_Pixel p = 0; + switch(type) { +%% for sf in pixeltypes +%% if sf.is_unknown() + case GP_PIXEL_UNKNOWN: + GP_ABORT("Cannot convert from GP_PIXEL_UNKNOWN"); + break; +%% elif sf.is_palette() + case GP_PIXEL_{{ sf.name }}: + GP_ABORT("Cannot convert from palette type {{ sf.name }} (yet)"); + break; +%% else + case GP_PIXEL_{{ sf.name }}: + GP_Pixel_{{ sf.name }}_TO_{{ pt.name }}(pixel, p); + break; +%% endif +%% endfor + default: + GP_ABORT("Unknown PixelType %u", type); + } + return p; +} + +## +## Loop arpund "central" pixel types +## +%% endfor + +%% endblock body diff --git a/libs/core/GP_Pixel.gen.c.t b/libs/core/GP_Pixel.gen.c.t new file mode 100644 index 0000000..e0cf7c0 --- /dev/null +++ b/libs/core/GP_Pixel.gen.c.t @@ -0,0 +1,45 @@ +%% extends "base.c.t" + +%% block descr +Pixel type definitions and functions +Do not include directly, use GP_Pixel.h +%% endblock + +%% block body +#include <stdio.h> +#include "GP_Pixel.h" + +/* + * Description of all known pixel types + */ +const GP_PixelTypeDescription const GP_PixelTypes [] = { +%% for pt in pixeltypes + /* GP_PIXEL_{{ pt.name }} */ { + .type = GP_PIXEL_{{ pt.name }}, + .name = "{{ pt.name }}", + .size = {{ pt.pixelsize.size }}, + .bit_endian = {{ pt.pixelsize.bit_endian_const }}, + .numchannels = {{ len(pt.chanslist) }}, + .bitmap = "{{ pt.bits|join("") }}", + .channels = { +%% for c in pt.chanslist + { .name = "{{ c[0] }}", .offset = {{ c[1] }}, .size = {{ c[2] }} }, +%% endfor + } }, +%% endfor +}; + +%% for pt in pixeltypes +%% if not pt.is_unknown() +/* + * snprintf a human readable value of pixel type {{pt.name}} + */ +void GP_PixelSNPrint_{{ pt.name }}(char *buf, size_t len, GP_Pixel p) +{ + snprintf(buf, len, "<{{ pt.name }} 0x%0{{ (pt.pixelsize.size+3)//4 }}x{% for c in pt.chanslist %} {{ c[0] }}=%d{% endfor %}>", + GP_GET_BITS(0, {{ pt.pixelsize.size }}, p){% for c in pt.chanslist %}, GP_GET_BITS({{ c[1] }}, {{ c[2] }}, p){% endfor %}); +} + +%% endif +%% endfor +%% endblock body diff --git a/pylib/gfxprim/generators/core/make_GP_Blit.py b/pylib/gfxprim/generators/core/make_GP_Blit.py deleted file mode 100644 index b10c927..0000000 --- a/pylib/gfxprim/generators/core/make_GP_Blit.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/python -# -# Generators for GP_Pixel_Blit.gen.c and GP_Pixel_Blit.gen.h -# -# 2011 - Tomas Gavenciak gavento@ucw.cz -# - -from gfxprim.generators.generator import * -from gfxprim.generators.pixeltype import * -from gfxprim.generators.core.gen_pixeltype import * -from gfxprim.generators.core.gen_blit import * - -@generator(CHeaderGenerator(name='GP_Blit.gen.h'), - CSourceGenerator(name='GP_Blit.gen.c'), - descr = 'specialized blit functions and macros', - authors = ["2011 - Tomas Gavenciak gavento@ucw.cz"]) -def core_GP_Blit_gen(h, c): - c.rhead( - '#include <stdio.h>n' - '#include <string.h>n' - '#include "GP_Pixel.h"n' - '#include "GP.h"n' - '#include "GP_Context.h"n' - '#include "GP_Blit.h"n' - ) - - for bpp in bitsizes: - for bit_endian in bit_endians: - if (bpp < 8) or (bit_endian == bit_endians[0]): - gen_blit_same_t(bpp, get_size_suffix(bpp, bit_endian), h, c) - diff --git a/pylib/gfxprim/generators/core/make_GP_Convert.py b/pylib/gfxprim/generators/core/make_GP_Convert.py deleted file mode 100644 index 99e4d0b..0000000 --- a/pylib/gfxprim/generators/core/make_GP_Convert.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/python -# -# Script generating: -# -# GP_Convert.gen.c, GP_Convert.gen.h -# GP_Convert_Scale.gen.h -# -# 2011 - Tomas Gavenciak gavento@ucw.cz -# - -from gfxprim.generators.generator import * -from gfxprim.generators.pixeltype import * -from gfxprim.generators.core.gen_convert import * - - -@generator(CHeaderGenerator(name = 'GP_Convert_Scale.gen.h'), - descr = 'Fast value scaling macros', - authors = ["2011 - Tomas Gavenciak gavento@ucw.cz"]) -def core_GP_Pixel_Scale_gen(h): - h.rhead( - "/* helper macros to transfer s1-bit value to s2-bit valuen" - " * NOTE: efficient and accurate for both up- and downscaling,n" - " * WARNING: GP_SCALE_VAL requires constants numbers as first two parametersn" - " */n" - "#define GP_SCALE_VAL(s1, s2, val) ( GP_SCALE_VAL_##s1##_##s2(val) )nn" - - "{% for s1 in range(1,9) %}{% for s2 in range(1,9) %}" - "{% if s2>s1 %}" - "#define GP_SCALE_VAL_{{s1}}_{{s2}}(val) (((val) * {{ multcoef(s1, s2) }}) >> {{ (-s2) % s1 }})n" - "{% else %}" - "#define GP_SCALE_VAL_{{s1}}_{{s2}}(val) ((val) >> {{ s1 - s2 }})n" - "{% endif %}" - "{% endfor %}{% endfor %}", multcoef = lambda s1,s2: hex(sum([1<<(i*s1) for i in range((s2+s1-1)/s1)])) - ) - - -@generator(CHeaderGenerator(name = 'GP_Convert.gen.h'), - CSourceGenerator(name = 'GP_Convert.gen.c'), - descr = 'Convert PixelType values macros and functions', - authors = ["2011 - Tomas Gavenciak gavento@ucw.cz"]) -def core_GP_Convert_gen_h(h, c): - h.rhead('#include "GP_Common.h"n'); - h.rhead('#include "GP_Context.h"n'); - h.rhead('#include "GP_Pixel.h"nn'); - - c.rhead('#include "GP_Convert.h"nn'); - - ## two base types for conversions - for bt in [pixeltypes['RGB888'], pixeltypes['RGBA8888']]: - gen_fixedtype_to_type(bt, h, c) - gen_type_to_fixedtype(bt, h, c) - ## Conversion macros - for t in pixeltypes.values(): - if not t.is_palette() and t.number != 0: - gen_convert_to(t, bt, h, c) - gen_convert_to(bt, t, h, c) - - ## Just experimental conversion macros - gen_convert_to(pixeltypes['RGB565'], pixeltypes['RGBA8888'], h, c) - gen_convert_to(pixeltypes['RGBA8888'], pixeltypes['V2'], h, c) - gen_convert_to(pixeltypes['VA12'], pixeltypes['RGBA8888'], h, c) - - -@generator(CSourceGenerator(name = 'GP_Convert.test.gen.c'), - descr = 'GP_Convert tests', - authors = ["2011 - Tomas Gavenciak gavento@ucw.cz"]) -def core_GP_Convert_gen_h(c): - c.rhead('#include "GP_Tests.h"n') - c.rhead('#include "GP_Convert.h"n') - c.rhead('#include "GP_TestingCore.h"nn') - c.rhead('GP_SUITE(GP_Convert)nn') - for t in pixeltypes.values(): - if not t.is_palette() and t.number != 0: - c.rbody( - 'GP_TEST(GP_ConvertPixel_for_{{ t.name }}, "loop_start=0, loop_end=4")n' - '{n' - ' GP_Pixel p1 = GP_RandomColor(GP_PIXEL_{{ t.name }});n' - ' GP_Pixel p2 = GP_ConvertPixel(p1, GP_PIXEL_{{ t.name }}, GP_PIXEL_RGBA8888);n' - ' GP_Pixel p3 = GP_ConvertPixel(p2, GP_PIXEL_RGBA8888, GP_PIXEL_{{ t.name }});n' - ' GP_CHECK_EqualColors(p1, GP_PIXEL_{{ t.name }}, p3, GP_PIXEL_{{ t.name }});n' - ' GP_CHECK_EqualColors(p1, GP_PIXEL_{{ t.name }}, p2, GP_PIXEL_RGBA8888);n' - '}n' - 'GP_ENDTESTnn', t=t) - c.rbody( - 'GP_TEST(WhiteStaysWhite_via_{{ t.name }}, "loop_start=0, loop_end=4")n' - '{n' - ' GP_Pixel p1 = GP_RGBToPixel(255, 255, 255, GP_PIXEL_RGB888);n' - ' GP_Pixel p2 = GP_RGB888ToPixel(p1, GP_PIXEL_{{ t.name }});n' - ' GP_Pixel p3 = GP_PixelToRGB888(p2, GP_PIXEL_{{ t.name }});n' - ' GP_CHECK_EqualColors(p1, GP_PIXEL_RGB888, p3, GP_PIXEL_RGB888);n' - '}n' - 'GP_ENDTESTnn', t=t) - c.rbody( - 'GP_TEST(BlackStaysBlack_via_{{ t.name }}, "loop_start=0, loop_end=4")n' - '{n' - ' GP_Pixel p1 = GP_RGBToPixel(0, 0, 0, GP_PIXEL_RGB888);n' - ' GP_Pixel p2 = GP_RGB888ToPixel(p1, GP_PIXEL_{{ t.name }});n' - ' GP_Pixel p3 = GP_PixelToRGB888(p2, GP_PIXEL_{{ t.name }});n' - ' GP_CHECK_EqualColors(p1, GP_PIXEL_RGB888, p3, GP_PIXEL_RGB888);n' - '}n' - 'GP_ENDTESTnn', t=t) diff --git a/pylib/gfxprim/generators/core/make_GP_Pixel.py b/pylib/gfxprim/generators/core/make_GP_Pixel.py deleted file mode 100644 index c7f7ee1..0000000 --- a/pylib/gfxprim/generators/core/make_GP_Pixel.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/python -# -# Script generating: -# -# GP_Pixel.gen.c, GP_Pixel.gen.h -# GP_Pixel_Access.gen.h -# -# 2011 - Tomas Gavenciak gavento@ucw.cz -# - -from gfxprim.generators.generator import * -from gfxprim.generators.pixeltype import * -from gfxprim.generators.core.gen_pixeltype import * -from gfxprim.generators.core.gen_getputpixel import * - -@generator(CHeaderGenerator(name='GP_Pixel.gen.h'), - CSourceGenerator(name='GP_Pixel.gen.c'), - descr = 'Pixel type definitions and functionsnDo not include directly, use GP_Pixel.h', - authors = ["2011 - Tomas Gavenciak gavento@ucw.cz"]) -def core_GP_Pixel_gen(h, c): - c.rhead( - '#include <stdio.h>n' - '#include "GP_Pixel.h"nn') - - ## Enum of types - gen_GP_PixelType(h, c) - - ## PixelType parameters in C - gen_GP_PixelTypes(h, c) - - ## List of types - for t in pixeltypes.values(): - if t.name != 'UNKNOWN': - h.rbody(str_start(t)) - h.rbody(str_description(t)) - c.rbody(str_start(t)) - c.rbody(str_description(t)) - - gen_print(t, h, c) - gen_get_chs(t, h, c) - gen_get_pixel_addr(t, h, c) - gen_create(t, h, c) - - ## FnPerPixelType and FnRetPerPixelType - for r in ['', 'return ']: - h.rbody( - 'n/* Macro for branching on PixelType (similar to GP_FnPerBpp macros) */n' - '#define GP_FN_{% if r %}RET_{% endif %}PER_PIXELTYPE(FN_NAME, type, ...) ' - ' switch (type) { ' - '{% for t in types %}{% if t.number != 0 %}' - ' case GP_PIXEL_{{ t.name }}: ' - ' {{ r }}FN_NAME##_{{ t.name }}(__VA_ARGS__); ' - ' break; ' - '{% endif %}{% endfor %}' - ' default: GP_ABORT("Invalid PixelType %d", type); ' - ' }nn', types=pixeltypes.values(), r=r) - -@generator(CHeaderGenerator(name = 'GP_GetPutPixel.gen.h'), - descr = 'Access pixel bytes, Get and PutPixelnDo not include directly, use GP_Pixel.h', - authors = ["2011 - Tomas Gavenciak gavento@ucw.cz"]) -def core_GP_Pixel_Scale_gen(h): - h.rhead('#include "GP_Common.h"nn'); - h.rhead('struct GP_Context;nn'); - # Per-bpp adress/offset macros - for bpp in bitsizes: - for bit_endian in bit_endians: - if (bpp < 8) or (bit_endian == bit_endians[0]): - gen_get_pixel_addr_bpp(bpp, get_size_suffix(bpp, bit_endian), h) - - # Per-bpp adress/offset macros - for bpp in bitsizes: - for bit_endian in bit_endians: - if (bpp < 8) or (bit_endian == bit_endians[0]): - gen_getpixel_bpp(bpp, get_size_suffix(bpp, bit_endian), h) - gen_putpixel_bpp(bpp, get_size_suffix(bpp, bit_endian), h) - diff --git a/pylib/templates/base.test.c.t b/pylib/templates/base.test.c.t new file mode 100644 index 0000000..45d729f --- /dev/null +++ b/pylib/templates/base.test.c.t @@ -0,0 +1,47 @@ +%% extends "base.c.t" + + +%% macro test(name, opts="") +GP_TEST({{ name }}, "{{ opts }}") +{ +{{ caller() }} +} +GP_ENDTEST + +%% endmacro + + +%% macro test_for_all_pixeltypes(name, opts="", + palette=True, unknown=False, rgb=True, + alpha=True, gray=True) +%% for pt in pixeltypes +%% if unknown or not pt.is_unknown() +%% if palette or not pt.is_palette() +%% if rgb or not pt.is_rgb() +%% if alpha or not pt.is_alpha() +%% if gray or not pt.is_gray() +GP_TEST({{ name }}_{{ pt.name }}, "{{ opts }}") +{ +{{ caller(pt) }} +} +GP_ENDTEST + +%% endif +%% endif +%% endif +%% endif +%% endif +%% endfor +%% endmacro + + +%% macro test_for_all_pixelsizes(name, opts="") +%% for ps in pixelsizes +GP_TEST({{ name }}_{{ ps.suffix }}, "{{ opts }}") +{ +{{ caller(ps) }} +} +GP_ENDTEST + +%% endfor +%% endmacro diff --git a/tests/core/GP_Blit.test.c b/tests/core/GP_Blit.test.c new file mode 100644 index 0000000..cc20992 --- /dev/null +++ b/tests/core/GP_Blit.test.c @@ -0,0 +1,28 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2011 Tomas Gavenciak gavento@ucw.cz * + * * + *****************************************************************************/ + +#include <GP_Tests.h> +#include <GP_Common.h> +#include <unistd.h> + +GP_SUITE(GP_Blit) + diff --git a/tests/core/GP_Convert.test.gen.c.t b/tests/core/GP_Convert.test.gen.c.t new file mode 100644 index 0000000..e8180a9 --- /dev/null +++ b/tests/core/GP_Convert.test.gen.c.t @@ -0,0 +1,38 @@ +%% extends "base.test.c.t" + +%% block body +#include "GP_Tests.h" +#include "GP_Convert.h" +#include "GP_TestingCore.h" + +GP_SUITE(GP_Convert) + +%% call(pt) test_for_all_pixeltypes("GP_ConvertPixel_for", + opts="loop_start=0, loop_end=4", + palette=False) + GP_Pixel p1 = GP_RandomColor(GP_PIXEL_{{ pt.name }}); + GP_Pixel p2 = GP_ConvertPixel(p1, GP_PIXEL_{{ pt.name }}, GP_PIXEL_RGBA8888); + GP_Pixel p3 = GP_ConvertPixel(p2, GP_PIXEL_RGBA8888, GP_PIXEL_{{ pt.name }}); + GP_CHECK_EqualColors(p1, GP_PIXEL_{{ pt.name }}, p3, GP_PIXEL_{{ pt.name }}); + GP_CHECK_EqualColors(p1, GP_PIXEL_{{ pt.name }}, p2, GP_PIXEL_RGBA8888); +%% endcall + +%% call(pt) test_for_all_pixeltypes("WhiteStaysWhite_via", + opts="loop_start=0, loop_end=4", + palette=False) + GP_Pixel p1 = GP_RGBToPixel(255, 255, 255, GP_PIXEL_RGB888); + GP_Pixel p2 = GP_RGB888ToPixel(p1, GP_PIXEL_{{ pt.name }}); + GP_Pixel p3 = GP_PixelToRGB888(p2, GP_PIXEL_{{ pt.name }}); + GP_CHECK_EqualColors(p1, GP_PIXEL_RGB888, p3, GP_PIXEL_RGB888); +%% endcall + +%% call(pt) test_for_all_pixeltypes("BlackStaysBlack_via", + opts="loop_start=0, loop_end=4", + palette=False) + GP_Pixel p1 = GP_RGBToPixel(0, 0, 0, GP_PIXEL_RGB888); + GP_Pixel p2 = GP_RGB888ToPixel(p1, GP_PIXEL_{{ pt.name }}); + GP_Pixel p3 = GP_PixelToRGB888(p2, GP_PIXEL_{{ pt.name }}); + GP_CHECK_EqualColors(p1, GP_PIXEL_RGB888, p3, GP_PIXEL_RGB888); +%% endcall + +%% endblock body
http://repo.or.cz/w/gfxprim.git/commit/35f5e233c07862deeb53bdf9407e2f83eaa15...
commit 35f5e233c07862deeb53bdf9407e2f83eaa15887 Author: Tomas Gavenciak gavento@ucw.cz Date: Mon Aug 8 01:12:30 2011 +0200
Add note about "no bit-endian" value
diff --git a/include/core/GP_Pixel.h b/include/core/GP_Pixel.h index 99793f1..45bcf19 100644 --- a/include/core/GP_Pixel.h +++ b/include/core/GP_Pixel.h @@ -62,12 +62,13 @@ typedef uint32_t GP_Pixel; * used in a one bit variable in GP_Context */
-typedef enum { - /* less significant bits contain pixels with lower indices */ +typedef enum { + /* less significant bits contain pixels with lower indices */ + /* also used for irrelevant bit-endian */ GP_BIT_ENDIAN_LE = 0, - /* more significant bits contain pixels with lower indices */ - GP_BIT_ENDIAN_BE, -} GP_BIT_ENDIAN; + /* more significant bits contain pixels with lower indices */ + GP_BIT_ENDIAN_BE, +} GP_BIT_ENDIAN;
/* * Description of one channel
http://repo.or.cz/w/gfxprim.git/commit/7ab0524f10cef16426c70802884bee6cda23d...
commit 7ab0524f10cef16426c70802884bee6cda23d116 Author: Tomas Gavenciak gavento@ucw.cz Date: Sun Aug 7 19:11:58 2011 +0200
Makesystem fix
diff --git a/gen.mk b/gen.mk index ebb8e75..c5586c6 100644 --- a/gen.mk +++ b/gen.mk @@ -49,7 +49,7 @@ CLEAN+=$(ALL_GENERATED) # # Generated files depend on python generators and the template # -$(GENSOURCES) $(GENHEADERS): %: %.t $(PYTHON_FILES) +$(GENSOURCES) $(RGENHEADERS): %: %.t $(PYTHON_FILES) ifdef VERBOSE ${PYTHON} ${TOPDIR}/pylib/bin/generate_file.py -t $(TEMPLATE_DIR) "$@.t" "$@" else
http://repo.or.cz/w/gfxprim.git/commit/89d7a5aa051caddcd3d17d27e17d7d4f4b966...
commit 89d7a5aa051caddcd3d17d27e17d7d4f4b9661fa Author: Tomas Gavenciak gavento@ucw.cz Date: Sat Aug 6 22:25:34 2011 +0200
Adapted make system to templates
diff --git a/gen.mk b/gen.mk index 5df5588..ebb8e75 100644 --- a/gen.mk +++ b/gen.mk @@ -14,7 +14,7 @@ GENSOURCES= endif
# -# Headers goes into include/core/ +# Headers go into include/core/ # INCLUDE_PREFIX=$(TOPDIR)/include/$(LIBNAME)/ RGENHEADERS=$(addprefix $(INCLUDE_PREFIX),$(GENHEADERS)) @@ -28,27 +28,32 @@ CSOURCES+=$(GENSOURCES) # Make the genrated headers actually build # all: $(RGENHEADERS) - $(CSOURCES): $(RGENHEADERS)
# -# And clean them +# Base common templates location +# +TEMPLATE_DIR=$(TOPDIR)/pylib/templates/ + +# +# ALL templates and potential generated files (not generated automatically) # -CLEAN+=$(GENSOURCES) $(RGENHEADERS) +ALL_TEMPLATES=$(shell find $(TOPDIR) -name '*.t') +ALL_GENERATED=$(basename $(ALL_TEMPLATES))
# -# Currently, just depend on all python files +# And clean them # -GENERATORS=$(PYTHON_FILES) +CLEAN+=$(ALL_GENERATED)
# -# Generated files depend on python generators and libs +# Generated files depend on python generators and the template # -%.gen.c %.gen.h: $(GENERATORS) +$(GENSOURCES) $(GENHEADERS): %: %.t $(PYTHON_FILES) ifdef VERBOSE - ${PYTHON} ${TOPDIR}/pylib/bin/generate_file.py "$@" + ${PYTHON} ${TOPDIR}/pylib/bin/generate_file.py -t $(TEMPLATE_DIR) "$@.t" "$@" else @echo "GEN $@" - @${PYTHON} ${TOPDIR}/pylib/bin/generate_file.py "$@" + @${PYTHON} ${TOPDIR}/pylib/bin/generate_file.py -t $(TEMPLATE_DIR) "$@.t" "$@" endif
http://repo.or.cz/w/gfxprim.git/commit/938956d49a3627c5fe31c4fcf2ceeae5877fd...
commit 938956d49a3627c5fe31c4fcf2ceeae5877fd11b Author: Tomas Gavenciak gavento@ucw.cz Date: Sat Aug 6 15:28:13 2011 +0200
Generators changed to templates
Now, the templates are just ordinary files with jinja2 markup
diff --git a/gfxprim_config.py b/gfxprim_config.py index 157f93c..174f82d 100644 --- a/gfxprim_config.py +++ b/gfxprim_config.py @@ -12,6 +12,21 @@ # so a complete recompilation is required after any change. #
+# Declared pixel sizes: +PS_1BPP_LE = PixelSize(1, bit_endian=LE) +PS_1BPP_BE = PixelSize(1, bit_endian=BE) +PS_2BPP_LE = PixelSize(2, bit_endian=LE) +PS_2BPP_BE = PixelSize(2, bit_endian=BE) +PS_4BPP_LE = PixelSize(4, bit_endian=LE) +PS_4BPP_BE = PixelSize(4, bit_endian=BE) +PS_8BPP = PixelSize(8) +PS_16BPP = PixelSize(16) +PS_24BPP = PixelSize(24) +PS_32BPP = PixelSize(32) +# Experimental: +PS_19BPP_LE = PixelSize(19, bit_endian=LE) + + config = GfxPrimConfig(
# C name and bit-size of the GP_pixel type @@ -19,36 +34,36 @@ config = GfxPrimConfig( pixel_size = 32,
# List of pixel sizes (bpp), explicit on purpose - sizes = [1, 2, 4, 8, 16, 32] - - # bit endians to generate, keep this fixed to LE, BE for now - bit_endians = ['LE', 'BE'] + pixelsizes = [PS_1BPP_LE, PS_1BPP_BE, PS_2BPP_LE, PS_2BPP_BE, PS_4BPP_LE, PS_4BPP_BE, + PS_8BPP, PS_16BPP, PS_24BPP, PS_32BPP, + PS_19BPP_LE, + ],
# List of PixelTypes, order defines the numbering. # The "Undefined" type is added automatically. - types = [ + pixeltypes = [
# # Standard RGB types #
- PixelType(name='RGBx8888', size=32, chanslist=[ + PixelType(name='RGBx8888', pixelsize=PS_32BPP, chanslist=[ ('R', 16, 8), ('G', 8, 8), ('B', 0, 8)]),
- PixelType(name='RGBA8888', size=32, chanslist=[ + PixelType(name='RGBA8888', pixelsize=PS_32BPP, chanslist=[ ('R', 24, 8), ('G', 16, 8), ('B', 8, 8), ('A', 0, 8)]),
- PixelType(name='RGB888', size=24, chanslist=[ + PixelType(name='RGB888', pixelsize=PS_24BPP, chanslist=[ ('R', 16, 8), ('G', 8, 8), ('B', 0, 8)]),
- PixelType(name='RGB565', size=16, chanslist=[ + PixelType(name='RGB565', pixelsize=PS_16BPP, chanslist=[ ('R', 11, 5), ('G', 5, 6), ('B', 0, 5)]), @@ -57,36 +72,36 @@ config = GfxPrimConfig( # Palette types #
- PixelType(name='P2', size=2, bit_endian='LE', chanslist=[ + PixelType(name='P2', pixelsize=PS_2BPP_LE, chanslist=[ ('P', 0, 2)]),
- PixelType(name='P4', size=4, bit_endian='LE', chanslist=[ + PixelType(name='P4', pixelsize=PS_4BPP_LE, chanslist=[ ('P', 0, 4)]),
- PixelType(name='P8', size=8, bit_endian='LE', chanslist=[ + PixelType(name='P8', pixelsize=PS_8BPP, chanslist=[ ('P', 0, 8)]),
# # Gray-only pixel types #
- PixelType(name='V1', size=1, bit_endian='LE', chanslist=[ + PixelType(name='V1', pixelsize=PS_1BPP_LE, chanslist=[ ('V', 0, 1)]),
- PixelType(name='V2', size=2, bit_endian='LE', chanslist=[ + PixelType(name='V2', pixelsize=PS_2BPP_LE, chanslist=[ ('V', 0, 2)]),
- PixelType(name='V4', size=4, bit_endian='LE', chanslist=[ + PixelType(name='V4', pixelsize=PS_4BPP_LE, chanslist=[ ('V', 0, 4)]),
- PixelType(name='V8', size=8, bit_endian='LE', chanslist=[ + PixelType(name='V8', pixelsize=PS_8BPP, chanslist=[ ('V', 0, 8)]),
# # Experiments #
- PixelType(name='VA12', size=4, bit_endian='BE', chanslist=[ + PixelType(name='VA12', pixelsize=PS_4BPP_BE, chanslist=[ ('A', 1, 2), ('V', 3, 1)]), ] diff --git a/pylib/bin/generate_file.py b/pylib/bin/generate_file.py index 40ce75c..bd0ddf1 100644 --- a/pylib/bin/generate_file.py +++ b/pylib/bin/generate_file.py @@ -6,20 +6,28 @@ # 2011 - Tomas Gavenciak gavento@ucw.cz #
-import sys -from gfxprim.generators import utils -from gfxprim import die +from gfxprim import render_utils +import jinja2 +import logging as log +from optparse import OptionParser
-usage = """Usage: %s [files_to_generate...] -The files are matched only based on path suffixes, but written to given paths. -"""
-def main(): - utils.load_generators() - if len(sys.argv) <= 1: - die(usage) - for f in sys.argv[1:]: - utils.generate_file(f) +parser = OptionParser(usage="usage: %prog [options] <template> <output>") +parser.add_option("-t", "--templates", dest="templates", + help="Directory with templates.", default=".") +parser.add_option("-c", "--config", dest="config", + help="GfxPrim config file.", default=None) + +def main(options, args): + config = render_utils.load_gfxprimconfig(options.config) + assert config + log.info("Rendering template %s to %s", args[0], args[1]) + render_utils.render_file(args[0], args[1], config, options.templates) +
if __name__ == '__main__': - main() + log.debug("Jinja version %s", jinja2.__version__) + (options, args) = parser.parse_args() + if len(args) != 2: + parser.error() + main(options, args) diff --git a/pylib/gfxprim/generators/gfxprimconfig.py b/pylib/gfxprim/generators/gfxprimconfig.py deleted file mode 100644 index 18d6df4..0000000 --- a/pylib/gfxprim/generators/gfxprimconfig.py +++ /dev/null @@ -1,60 +0,0 @@ -# -# gfxprim.generators.gfxprimconfig - Class for (global) GfxPrim configuration -# -# 2011 - Tomas Gavenciak gavento@ucw.cz - -import os -import logging as log -from gfxprim.generators.pixeltype import PixelType - -class GfxPrimConfig(object): - def __init__(self, pixel_type = None, pixel_size=None, sizes=None, - bit_endians=None, types=None): - - self.pixel_type = pixel_type - assert self.pixel_type - assert isinstance(self.pixel_type, str) - - self.pixel_size = pixel_size - assert isinstance(self.pixel_size, int) - assert self.pixel_size % 8 == 0 - assert self.pixel_size > 0 - - # Allowed bit-sizes of pixel types - self.sizes = sizes - assert isinstance(self.sizes, list) - assert self.pixel_size in self.sizes - assert all(( isinstance(i, int) and i > 0 and i <= self.pixel_size - for i in self.sizes)) - - # bit_endian values - self.bit_endians = bit_endians - assert isinstance(self.bit_endians, list) - assert all(( i in ["LE", "BE"] for i in self.bit_endians)) - - # Set of all encountered channel names - self.channels = set() - - # Dictionary of all pixeltypes { name : PixelType } - self.types_dict = {} - # List of all PixelTypes in order. "Unknown" must be first. - self.types = [] - - self.add_pixeltype(PixelType("UNKNOWN", 0, [], bit_endian=bit_endians[0])) - if types: - for t in types: - self.add_pixeltype(t) - - def add_pixeltype(self, pixeltype): - "Add a PixelType and check its against the config" - - assert pixeltype not in self.types - self.types.append(pixeltype) - assert pixeltype.name not in self.types_dict - self.types_dict[pixeltype.name] = pixeltype - self.channels.update(set(pixeltype.chans.keys())) - try: - pixeltype.check_config(self) - except AssertionError: - log.error("Error checking PixelType %sn" % pixeltype.name) - diff --git a/pylib/gfxprim/generators/pixeltype.py b/pylib/gfxprim/generators/pixeltype.py deleted file mode 100644 index b79f08f..0000000 --- a/pylib/gfxprim/generators/pixeltype.py +++ /dev/null @@ -1,73 +0,0 @@ -# -# gfxprim.generators.pixeltype - Module with PixelType descrition class -# -# 2011 - Tomas Gavenciak gavento@ucw.cz -# - -import re - - -def get_size_suffix(bpp, bit_endian): - "Create pixel-size suffix (like 16BPP or 4BPP_LE)" - - size_suffix = '%dBPP' % (bpp) - if bpp % 8 != 0: - assert bit_endian - if bit_endian: - size_suffix += '_' + bit_endian - return size_suffix - - -class PixelType(object): - """Representation of one GP_PixelType""" - - def __init__(self, name, size, chanslist, bit_endian=None): - """`name` must be a valid C identifier - `size` is type bit-width - `bit_endian` is required in 1,2,4 BPP types to determine the order of - pixels in a byte, either 'BE' or 'LE' - `chanslist` is a list of triplets describing individual channels as - [ (`chan_name`, `bit_offset`, `bit_size`) ] - where `chan_name` is usually one of: R, G, B, - V (value, used for grayscale), A (opacity) - """ - assert re.match('A[A-Za-z][A-Za-z0-9_]*Z', name) - self.name = name - self.chanslist = chanslist - self.chans = dict() # { chan_name: (offset, size) } - self.size = size - self.bit_endian = bit_endian - - if self.size == 0: - self.size_suffix = "INVALID" - else: - self.size_suffix = get_size_suffix(self.size, self.bit_endian) - - # Verify channel bits for overlaps - # also builds a bit-map of the PixelType - self.bits = ['x']*size - for c in chanslist: - assert c[0] not in self.chans.keys() - self.chans[c[0]] = c - for i in range(c[1], c[1] + c[2]): - assert(i<self.size) - assert(self.bits[i]=='x') - self.bits[i] = c[0] - - def valid_for_config(self, config): - "Check PixelType compatibility with given GfxPrimConfig." - - # all types except UNKNOWN=0 must have one of these sizes - if self.name != "UNKNOWN": - assert(self.size in config.sizes) - - # bit_endian matters only for non-multiple-of-8 bpp - if self.size % 8 != 0 or self.bit_endian is not None: - assert self.bit_endian in config.bit_endians - - def __str__(self): - return "<PixelType " + self.name + ">" - - def is_palette(self): - return ('P' in self.chans) - diff --git a/pylib/gfxprim/gfxprimconfig.py b/pylib/gfxprim/gfxprimconfig.py new file mode 100644 index 0000000..fd9088b --- /dev/null +++ b/pylib/gfxprim/gfxprimconfig.py @@ -0,0 +1,62 @@ +# +# gfxprim.generators.gfxprimconfig - Class for (global) GfxPrim configuration +# +# 2011 - Tomas Gavenciak gavento@ucw.cz + +import os +import logging as log +from gfxprim.pixeltype import PixelType +from gfxprim.pixelsize import PixelSize + +class GfxPrimConfig(object): + def __init__(self, pixel_type = None, pixel_size=None, pixelsizes=None, + pixeltypes=None): + """Initialize GfxPrim code generation config + + pixel_type: name of C type for a pixel value + pixel_size: number of bits of pixel_type + pixelsizes: list of generated and allowed PixelSizes + pixeltypes: list of generated PixelTypes, not incl. UNKNOWN + """ + + self.pixel_type = pixel_type + assert self.pixel_type + assert isinstance(self.pixel_type, str) + + self.pixel_size = pixel_size + assert isinstance(self.pixel_size, int) + assert self.pixel_size % 8 == 0 + assert self.pixel_size > 0 + + # Allowed bit-sizes of pixel types + self.pixelsizes = pixelsizes + assert isinstance(self.pixelsizes, list) + assert self.pixel_size in [i.size for i in self.pixelsizes] + assert all((i.size <= self.pixel_size for i in self.pixelsizes)) + + # Set of all encountered channel names + self.channels = set() + + # Dictionary of all pixeltypes { name : PixelType } + self.pixeltypes_dict = {} + # List of all PixelTypes in order. "Unknown" MUST be first. + self.pixeltypes = [] + + self.add_pixeltype(PixelType("UNKNOWN", PixelSize(0), [])) + if pixeltypes: + for t in pixeltypes: + self.add_pixeltype(t) + + def add_pixeltype(self, pixeltype): + "Add a PixelType and check its against the config" + + assert pixeltype not in self.pixeltypes + self.pixeltypes.append(pixeltype) + assert pixeltype.name not in self.pixeltypes_dict + self.pixeltypes_dict[pixeltype.name] = pixeltype + self.channels.update(set(pixeltype.chans.keys())) + try: + pixeltype.valid_for_config(self) + except AssertionError: + log.error("Error checking PixelType %sn" % pixeltype.name) + diff --git a/pylib/gfxprim/pixelsize.py b/pylib/gfxprim/pixelsize.py new file mode 100644 index 0000000..1586250 --- /dev/null +++ b/pylib/gfxprim/pixelsize.py @@ -0,0 +1,38 @@ +# +# gfxprim.pixelsize +# +# 2011 - Tomas Gavenciak gavento@ucw.cz +# + +LE = "LE" +BE = "BE" + +class PixelSize(object): + def __init__(self, size, bit_endian=None, suffix=None): + self.size = size + assert self.size >= 0 + + self.bit_endian = bit_endian + assert self.bit_endian in [None, LE, BE] + assert (bit_endian is not None) == self.needs_bit_endian() + + self.suffix = suffix + if not self.suffix: + if self.size == 0: + self.suffix = "INVALID" + else: + if bit_endian: + self.suffix = '%dBPP_%s' % (size, bit_endian) + else: + self.suffix = '%dBPP' % (size,) + + def needs_bit_endian(self): + return (self.size % 8) != 0 + + def description(self): + if self.bit_endian: + return "pixel size %d, bit endian %s, suffix %s" % (self.size, + self.bit_endian, self.suffix) + else: + return "pixel size %d, suffix %s" % (self.size, self.suffix) + diff --git a/pylib/gfxprim/pixeltype.py b/pylib/gfxprim/pixeltype.py new file mode 100644 index 0000000..5cf356e --- /dev/null +++ b/pylib/gfxprim/pixeltype.py @@ -0,0 +1,49 @@ +# +# gfxprim.pixeltype - Module with PixelType descrition class +# +# 2011 - Tomas Gavenciak gavento@ucw.cz +# + +import re +from gfxprim.pixelsize import PixelSize + +class PixelType(object): + """Representation of one GP_PixelType""" + + def __init__(self, name, pixelsize, chanslist): + """`name` must be a valid C identifier + `pixelsize` is an instance of PixelSize + `chanslist` is a list of triplets describing individual channels as + [ (`chan_name`, `bit_offset`, `bit_size`) ] + where `chan_name` is usually one of: R, G, B, + V (value, used for grayscale), A (opacity) + """ + assert re.match('A[A-Za-z][A-Za-z0-9_]*Z', name) + self.name = name + self.chanslist = chanslist + self.chans = dict() # { chan_name: (offset, size) } + self.pixelsize = pixelsize + + # Verify channel bits for overlaps + # also builds a bit-map of the PixelType + self.bits = ['x'] * pixelsize.size + for c in chanslist: + assert c[0] not in self.chans.keys() + self.chans[c[0]] = c + for i in range(c[1], c[1] + c[2]): + assert(i < self.pixelsize.size) + assert(self.bits[i] == 'x') + self.bits[i] = c[0] + + def valid_for_config(self, config): + "Check PixelType compatibility with given GfxPrimConfig." + + # all types except UNKNOWN must have one of these sizes + if self.name != "UNKNOWN": + assert(self.pixelsize in config.pixelsizes) + + def __str__(self): + return "<PixelType " + self.name + ">" + + def is_palette(self): + return ('P' in self.chans) diff --git a/pylib/gfxprim/render_utils.py b/pylib/gfxprim/render_utils.py new file mode 100644 index 0000000..1051f3c --- /dev/null +++ b/pylib/gfxprim/render_utils.py @@ -0,0 +1,73 @@ +# +# gfxprim.render_utils +# + +import jinja2 +import logging as log +import os +import time +import re + +def create_environment(config, template_dir): + env = jinja2.Environment( + line_statement_prefix = "%%", + undefined = jinja2.StrictUndefined, + loader = jinja2.FileSystemLoader(template_dir)) + env.globals['undefined'] = jinja2.StrictUndefined() + env.globals['pixelsizes'] = config.pixelsizes + env.globals['pixeltypes'] = config.pixeltypes + env.globals['gfxprim_config'] = config + return env + + +def render_file(source, result, config, template_dir): + env = create_environment(config, template_dir) + with open(source) as source_file: + source_text = source_file.read() + # Hack to preserve empty lines before %% line_statement + source_text = re.sub("nn[ t]*%%", "n{{''}}n%%", source_text) + + tmpl = env.from_string(source_text) + result_text = tmpl.render( + date = time.ctime(), + target = result, + template = source, + header_guard = + os.path.split(result)[1].upper().replace('.', '_').replace('-', '_'), + ) + with open(result, "w") as result_file: + result_file.write(result_text) + + +def load_gfxprimconfig(config_file = None): + """Initialize GfxPrimConfig from a given or guessed config file. + Looks for the file by parameter, in env['PIXELTYPE_DEFS'] and + in dir(__file__)/../../gfxprim_config.py, in that order. + + Returns GfxPrimConfig or None on error + """ + + if not config_file: + config_file = os.environ.get("PIXELTYPE_DEFS", None) + if not config_file: + path = os.path.dirname(os.path.abspath(__file__)) + config_file = os.path.abspath( + os.path.join(path, "..", "..", "gfxprim_config.py")) + if not os.path.exists(config_file): + log.error("WARNING: GfxPrimConfig file %s not found!n", + config_file) + return None + + from gfxprim.pixeltype import PixelType + from gfxprim.pixelsize import PixelSize, LE, BE + from gfxprim.gfxprimconfig import GfxPrimConfig + l = {"PixelType": PixelType, + "PixelSize": PixelSize, + "LE": LE, + "BE": BE, + "GfxPrimConfig": GfxPrimConfig + } + execfile(config_file, globals(), l) + config = l["config"] + return config + diff --git a/pylib/templates/base.c.t b/pylib/templates/base.c.t new file mode 100644 index 0000000..57c957a --- /dev/null +++ b/pylib/templates/base.c.t @@ -0,0 +1,15 @@ +/* + * {{ target }} + * + * GENERATED on {{ date }} from {{ template }} + * DO NOT MODIFY THIS FILE DIRECTLY! + * + * {% block descr %}{% endblock %} + */ + +%% block pre_body_guard +%% endblock pre_body_guard +%% block body +%% endblock body +%% block post_body_guard +%% endblock post_body_guard diff --git a/pylib/templates/base.h.t b/pylib/templates/base.h.t new file mode 100644 index 0000000..8eb9140 --- /dev/null +++ b/pylib/templates/base.h.t @@ -0,0 +1,11 @@ +%% extends "body.c.h" + +%% block pre_body_guard +#ifndef {{ header_guard }} +#define {{ header_guard }} + +%% endblock pre_body_guard + +%% block post_body_guard +#endif /* {{ header_guard }} */ +%% endblock post_body_guard
http://repo.or.cz/w/gfxprim.git/commit/58f99bbee8cf3eac5142540013c8309267b8f...
commit 58f99bbee8cf3eac5142540013c8309267b8f55d Author: Tomas Gavenciak gavento@ucw.cz Date: Mon Aug 1 22:43:27 2011 +0200
Whitespace/style cleanup, replace die with logging
diff --git a/pylib/bin/generate_file.py b/pylib/bin/generate_file.py index 086f801..40ce75c 100644 --- a/pylib/bin/generate_file.py +++ b/pylib/bin/generate_file.py @@ -3,7 +3,7 @@ # Main source file generating script # Collects all known file generators from the generators/ directory # -# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Tomas Gavenciak gavento@ucw.cz #
import sys diff --git a/pylib/gfxprim/README b/pylib/gfxprim/README index 17c8d28..2b7baf7 100644 --- a/pylib/gfxprim/README +++ b/pylib/gfxprim/README @@ -21,7 +21,7 @@ typedef enum GP_PixelType { -------------------------------------------------------------------------------- void GP_Pixel_Print_<TYPE>(GP_Pixel p);
-#define GP_Pixel_GET_<CHAN>_<TYPE>(p) +#define GP_Pixel_GET_<CHAN>_<TYPE>(p) --------------------------------------------------------------------------------
.For each pixel type TYPE, pixel adress and bit-offset: @@ -80,7 +80,7 @@ GP_Pixel_Scale.gen.h GP_Blit.gen.[ch] ~~~~~~~~~~~~~~~~~~~~~~
-TODO: Blitting magic +TODO: Blitting magic
.Blits within PixelTypes (defined only by bpp):
diff --git a/pylib/gfxprim/__init__.py b/pylib/gfxprim/__init__.py index 7b3b919..a5fe956 100644 --- a/pylib/gfxprim/__init__.py +++ b/pylib/gfxprim/__init__.py @@ -1,16 +1,4 @@ -# GfxPrim auxiliary libraries -# Contains C code-generation +# GfxPrim auxiliary libraries for C-code generation # -# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Tomas Gavenciak gavento@ucw.cz # - -import sys - -def die(msg): - "Exit(1) with a message." - if not msg.endswith('n'): - msg += 'n' - sys.stderr.write(msg) - sys.exit(1) - - diff --git a/pylib/gfxprim/generators/__init__.py b/pylib/gfxprim/generators/__init__.py index bffe6ea..431c9ef 100644 --- a/pylib/gfxprim/generators/__init__.py +++ b/pylib/gfxprim/generators/__init__.py @@ -1,7 +1,9 @@ # -# gfxprim.generate +# gfxprim.generate - global config and its loading #
+import os +import sys
# Global config instance
@@ -10,22 +12,25 @@ config = None
def load_gfxprim_config(config_file = None): """Initialize GfxPrimConfig from a given or guessed config file. - Looks for the file by parameter, in env['PIXELTYPE_DEFS'] and + Looks for the file by parameter, in env['PIXELTYPE_DEFS'] and in dir(__file__)/../../../gfxprim_config.py, in that order. """ - if not defs_file: - defs_file = os.environ.get("PIXELTYPE_DEFS", None) - if not defs_file: + + if not config_file: + config_file = os.environ.get("PIXELTYPE_DEFS", None) + if not config_file: path = os.path.dirname(os.path.abspath(__file__)) - defs_file = os.path.abspath( + config_file = os.path.abspath( os.path.join(path, "..", "..", "..", "gfxprim_config.py")) - if not os.path.exists(defs_file): - sys.stderr.write("WARNING: GfxPrimConfig file %s not found!n" % defs_file) + if not os.path.exists(config_file): + sys.stderr.write("WARNING: GfxPrimConfig file %s not found!n" % + config_file)
- from gfxprim.generate.pixeltype import PixelType - from gfxprim.generate.gfxprimconfig import GfxPrimConfig + global config + assert not config + from gfxprim.generators.pixeltype import PixelType + from gfxprim.generators.gfxprimconfig import GfxPrimConfig l = {"PixelType": PixelType, "GfxPrimConfig": GfxPrimConfig} - execfile(defs_file, globals(), l) - + execfile(config_file, globals(), l) config = l["config"] assert config diff --git a/pylib/gfxprim/generators/core/gen_blit.py b/pylib/gfxprim/generators/core/gen_blit.py index 78be0f8..0e3196b 100644 --- a/pylib/gfxprim/generators/core/gen_blit.py +++ b/pylib/gfxprim/generators/core/gen_blit.py @@ -1,18 +1,21 @@ # Module generating C source and headers for various PixelTypes # - submodule for blit and friends -# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Tomas Gavenciak gavento@ucw.cz
from gfxprim.generators.utils import *
+ ## all generated direct blits, for generating GP_Blit() and others generated_blits = []
+ # TODO: adapt for both bit-endianness (in-byte prefix and suffix) # WARN: assuming little-endian in sub-byte pixels order (probably) def gen_blit_same_t(size, size_suffix, header, code): - "Generate a function blitting the same type of pixel." - "Only depends on bpp (bit size), size_suffix must be" - "of form 8BPP, 2BPP_LE and the like." + """Generate a function blitting the same type of pixel. + Only depends on bpp (bit size), size_suffix must be + of form 8BPP, 2BPP_LE and the like. + """
header.rbody( "n/*** Blit preserving type, variant for {{ size_suffix }} ***n" diff --git a/pylib/gfxprim/generators/core/gen_convert.py b/pylib/gfxprim/generators/core/gen_convert.py index 84c2b69..f128824 100644 --- a/pylib/gfxprim/generators/core/gen_convert.py +++ b/pylib/gfxprim/generators/core/gen_convert.py @@ -1,5 +1,5 @@ # Module generating C source and headers for various PixelType conversions -# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Tomas Gavenciak gavento@ucw.cz
from gfxprim.generators.pixeltype import pixeltypes, channels from gfxprim.generators.utils import hmask @@ -18,7 +18,7 @@ def gen_fixedtype_to_type(fixedtype, header, code): " GP_ABORT("Cannot convert to GP_PIXEL_UNKNOWN");n" " break;n" "{% elif tf.is_palette() %}" - " case GP_PIXEL_{{ tf.name }}:n" + " case GP_PIXEL_{{ tf.name }}:n" " GP_ABORT("Cannot convert to palette type {{ tf.name }}");n" " break;n" "{% else %}" @@ -47,7 +47,7 @@ def gen_type_to_fixedtype(fixedtype, header, code): " GP_ABORT("Cannot convert from GP_PIXEL_UNKNOWN");n" " break;n" "{% elif sf.is_palette() %}" - " case GP_PIXEL_{{ sf.name }}:n" + " case GP_PIXEL_{{ sf.name }}:n" " GP_ABORT("Cannot convert from palette type {{ sf.name }} (yet)");n" " break;n" "{% else %}" @@ -74,40 +74,40 @@ def gen_convert_to(f1, f2, header, code): " * macro storing p1 ({{ f1.name }} at bit-offset o1) in p2 ({{ f2.name }} at bit-offset o2),n" " * the relevant part of p2 is assumed to be clear (zero) */nn" "#define GP_Pixel_{{ f1.name }}_TO_{{ f2.name }}_OFFSET(p1, o1, p2, o2) do { " - + ## set each of <TARGET> channels "{% for c2 in f2.chanslist %}" - - # case 1: just copy a channel + + # case 1: just copy a channel "{%- if c2[0] in f1.chans.keys() %}{% set c1 = f1.chans[c2[0]] %}" " /* {{ c2[0] }}:={{ c1[0] }} */ GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2, " " GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1))); " - + # case 2: set A to full opacity (not present in source) "{% elif c2[0]=='A' %}" " /* A:={{ hmask(c2[2]) }} */GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2, {{ hmask(c2[2]) }}); " - - # case 3: calculate V as average of RGB + + # case 3: calculate V as average of RGB "{% elif c2[0]=='V' and set('RGB').issubset(set(f1.chans.keys())) %}" " /* V:=RGB_avg */ GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2, ( " "{% for c1 in [f1.chans['R'], f1.chans['G'], f1.chans['B']] %}" " /* {{c1[0]}} */ GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1)) + " "{% endfor %}" " 0)/3); " - - #- case 4: set each RGB to V + + #- case 4: set each RGB to V "{% elif c2[0] in 'RGB' and 'V' in f1.chans.keys() %}{% set c1 = f1.chans['V'] %}" " /* {{ c2[0] }}:=V */ GP_SET_BITS({{c2[1]}}+o2, {{c2[2]}}, p2, " " GP_SCALE_VAL_{{c1[2]}}_{{c2[2]}}(GP_GET_BITS({{c1[1]}}+o1, {{c1[2]}}, p1))); " - - # invalid mapping (there should be none, but who knows ...) + + # invalid mapping (there should be none, but who knows ...) "{% else %} {{ raise(Error('channel conversion' +f1.name+ ' to ' +f2.name+ ' not supported')) }}" - + # end of the loop "{% endif %}" "{% endfor %}" "} while (0)nn" - + # add version without offsets "/* a version without offsets */n" "#define GP_Pixel_{{ f1.name }}_TO_{{ f2.name }}(p1, p2) " diff --git a/pylib/gfxprim/generators/core/gen_getputpixel.py b/pylib/gfxprim/generators/core/gen_getputpixel.py index f360ec0..14e455d 100644 --- a/pylib/gfxprim/generators/core/gen_getputpixel.py +++ b/pylib/gfxprim/generators/core/gen_getputpixel.py @@ -1,6 +1,6 @@ # Module generating C source and headers for get/putpixel -# 2011 - Tomas Gavenciak gavento@ucw.cz -# 2011 - Cyril Hrubis metan@ucw.cz +# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Cyril Hrubis metan@ucw.cz
from gfxprim.generators.utils import *
diff --git a/pylib/gfxprim/generators/core/gen_pixeltype.py b/pylib/gfxprim/generators/core/gen_pixeltype.py index 680a476..942a1a2 100644 --- a/pylib/gfxprim/generators/core/gen_pixeltype.py +++ b/pylib/gfxprim/generators/core/gen_pixeltype.py @@ -1,5 +1,5 @@ # Module generating C source and headers for various PixelTypes -# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Tomas Gavenciak gavento@ucw.cz
from gfxprim.generators.pixeltype import pixeltypes, channels from gfxprim.generators.utils import j2render as r, hmask @@ -28,7 +28,7 @@ def gen_GP_PixelType(header, code): "Generates definition of GP_PixelType enum" pt_by_num = sorted([(t.number, t) for t in pixeltypes.values()]) sorted_pts = [t[1] for t in pt_by_num] - pt_max = len(sorted_pts) + pt_max = len(sorted_pts) header.rbody( "/* List of all known pixel types */n" "typedef enum GP_PixelType {n" diff --git a/pylib/gfxprim/generators/core/make_GP_Blit.py b/pylib/gfxprim/generators/core/make_GP_Blit.py index 03057b0..b10c927 100644 --- a/pylib/gfxprim/generators/core/make_GP_Blit.py +++ b/pylib/gfxprim/generators/core/make_GP_Blit.py @@ -2,7 +2,7 @@ # # Generators for GP_Pixel_Blit.gen.c and GP_Pixel_Blit.gen.h # -# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Tomas Gavenciak gavento@ucw.cz #
from gfxprim.generators.generator import * diff --git a/pylib/gfxprim/generators/core/make_GP_Convert.py b/pylib/gfxprim/generators/core/make_GP_Convert.py index 03b682c..99e4d0b 100644 --- a/pylib/gfxprim/generators/core/make_GP_Convert.py +++ b/pylib/gfxprim/generators/core/make_GP_Convert.py @@ -5,7 +5,7 @@ # GP_Convert.gen.c, GP_Convert.gen.h # GP_Convert_Scale.gen.h # -# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Tomas Gavenciak gavento@ucw.cz #
from gfxprim.generators.generator import * @@ -42,7 +42,7 @@ def core_GP_Convert_gen_h(h, c): h.rhead('#include "GP_Common.h"n'); h.rhead('#include "GP_Context.h"n'); h.rhead('#include "GP_Pixel.h"nn'); - + c.rhead('#include "GP_Convert.h"nn');
## two base types for conversions @@ -54,7 +54,7 @@ def core_GP_Convert_gen_h(h, c): if not t.is_palette() and t.number != 0: gen_convert_to(t, bt, h, c) gen_convert_to(bt, t, h, c) - + ## Just experimental conversion macros gen_convert_to(pixeltypes['RGB565'], pixeltypes['RGBA8888'], h, c) gen_convert_to(pixeltypes['RGBA8888'], pixeltypes['V2'], h, c) diff --git a/pylib/gfxprim/generators/core/make_GP_Pixel.py b/pylib/gfxprim/generators/core/make_GP_Pixel.py index fd5b16c..c7f7ee1 100644 --- a/pylib/gfxprim/generators/core/make_GP_Pixel.py +++ b/pylib/gfxprim/generators/core/make_GP_Pixel.py @@ -5,7 +5,7 @@ # GP_Pixel.gen.c, GP_Pixel.gen.h # GP_Pixel_Access.gen.h # -# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Tomas Gavenciak gavento@ucw.cz #
from gfxprim.generators.generator import * @@ -66,7 +66,7 @@ def core_GP_Pixel_Scale_gen(h): for bit_endian in bit_endians: if (bpp < 8) or (bit_endian == bit_endians[0]): gen_get_pixel_addr_bpp(bpp, get_size_suffix(bpp, bit_endian), h) - + # Per-bpp adress/offset macros for bpp in bitsizes: for bit_endian in bit_endians: diff --git a/pylib/gfxprim/generators/generator.py b/pylib/gfxprim/generators/generator.py index df2e8c9..ca6df56 100644 --- a/pylib/gfxprim/generators/generator.py +++ b/pylib/gfxprim/generators/generator.py @@ -1,24 +1,29 @@ # -# Module with templates and tools for writing generated code, -# especially C source and headers +# gfxprim.generators.generator - Base and C (.c/.h) classes for code generators # -# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Tomas Gavenciak gavento@ucw.cz #
-import sys, os, time -from gfxprim import die +import os +import time +import logging as log from gfxprim.generators.utils import j2render
+ # List of known CodeGenerator instances + known_generators = []
+ class CodeGenerator(object): - "Args:n" - "fname (required) - name of the generated file (without path)n" - "fdir ('') - directory prefix to matchn" - "generating_f (None) - user function called in generate(), should generate contentn" - "register (False) - if true, register in global generator listn" + """Args: + fname (required) - name of the generated file (without path) + fdir ('') - directory prefix to match + generating_f (None) - user function called in generate(), should generate content + register (False) - if true, register in global generator list + """ generator_attributes__ = ['generating_f', 'register'] + def __init__(self, **kwargs): self.name = kwargs.pop('name') self.fdir, self.fname = os.path.split(self.name) @@ -29,20 +34,28 @@ class CodeGenerator(object): self.foot = [] self.setargs(**kwargs) if kwargs: - die('Unknown arguments to CodeGenerator: %s' & str(kwargs.keys())) + log.fatal('Unknown arguments to CodeGenerator: %s' % str(kwargs.keys())) + def setargs(self, **kwargs): for i in self.generator_attributes__: - if i in kwargs: self.__setattr__(i, kwargs.pop(i)) + if i in kwargs: + self.__setattr__(i, kwargs.pop(i)) + def matches_path(self, path): return path.endswith(self.name) + def r(self, s, *args, **kwargs): return j2render(s, g=self, *args, **kwargs) + def rhead(self, *args, **kwargs): self.head.append(self.r(*args, **kwargs)) + def rbody(self, *args, **kwargs): self.body.append(self.r(*args, **kwargs)) + def rfoot(self, *args, **kwargs): self.foot.append(self.r(*args, **kwargs)) + def generate(self, run_gen_base=True): self.head = [] self.body = [] @@ -52,13 +65,16 @@ class CodeGenerator(object): # Run user-specified generation f if self.generating_f: f, pos, params = self.generating_f - args = [self if i == pos else global_null_generator for i in range(params)] + args = [self if i == pos else global_null_generator + for i in range(params)] f(*args) return ''.join(self.head + self.body + self.foot) + def gen_base(self): "Fill basic subclass-dependent content into head/body/foot" pass
+ class NullGenerator(CodeGenerator): def rhead(self, *args, **kwargs): pass def rbody(self, *args, **kwargs): pass @@ -68,15 +84,20 @@ class NullGenerator(CodeGenerator):
global_null_generator = NullGenerator(name='null_generator')
+ class CCodeGenerator(CodeGenerator): - "Args:n" - "authors ([]) - list of author creditsn" - "descr ("") - (multiline) file descriptionn" - generator_attributes__ = ['authors', 'descr'] + CodeGenerator.generator_attributes__ + """Args: + authors ([]) - list of author credits + descr ("") - (multiline) file description + """ + generator_attributes__ = (['authors', 'descr'] + + CodeGenerator.generator_attributes__) + def __init__(self, **kwargs): self.authors = [] self.descr = "" super(CCodeGenerator, self).__init__(**kwargs) + def gen_base(self): super(CCodeGenerator, self).gen_base() self.head.append(self.r( @@ -94,14 +115,18 @@ class CCodeGenerator(CodeGenerator): "{% endfor %}" " */nn", date = time.ctime()))
+ class CSourceGenerator(CCodeGenerator): def __init__(self, **kwargs): super(CSourceGenerator, self).__init__(**kwargs)
+ class CHeaderGenerator(CCodeGenerator): def __init__(self, **kwargs): super(CHeaderGenerator, self).__init__(**kwargs) - self.hdef = 'GP_HEADER_' + self.name.replace('.', '_').replace('/', '_').upper() + self.hdef = ('GP_HEADER_' + + self.name.replace('.', '_').replace('/', '_').upper()) + def gen_base(self): super(CHeaderGenerator, self).gen_base() self.head.append(self.r( @@ -110,15 +135,17 @@ class CHeaderGenerator(CCodeGenerator): self.foot.append(self.r( "#endif /* {{ g.hdef }} */n"))
+ def generator(*args, **kwargs): - "Decorate functions to be content-creator for given generators.n" - "By default also registers the generator to pool of known generators." + """Decorate functions to be content-creator for given generators. + By default also registers the generator to pool of known generators. + """ register = kwargs.pop('register', True) def decorate(f): for i in range(len(args)): kwargs['generating_f'] = (f, i, len(args)) args[i].setargs(**kwargs) if register: - known_generators.append(args[i]) + known_generators.append(args[i]) return f return decorate diff --git a/pylib/gfxprim/generators/gfxprimconfig.py b/pylib/gfxprim/generators/gfxprimconfig.py index 60546d0..18d6df4 100644 --- a/pylib/gfxprim/generators/gfxprimconfig.py +++ b/pylib/gfxprim/generators/gfxprimconfig.py @@ -1,13 +1,15 @@ # -# gfxprimconfig.py - Class for (global) GfxPrim configuration +# gfxprim.generators.gfxprimconfig - Class for (global) GfxPrim configuration # # 2011 - Tomas Gavenciak gavento@ucw.cz
-import re, os, sys - +import os +import logging as log +from gfxprim.generators.pixeltype import PixelType + class GfxPrimConfig(object): def __init__(self, pixel_type = None, pixel_size=None, sizes=None, - bit_endians=None, types=[]): + bit_endians=None, types=None):
self.pixel_type = pixel_type assert self.pixel_type @@ -37,10 +39,11 @@ class GfxPrimConfig(object): self.types_dict = {} # List of all PixelTypes in order. "Unknown" must be first. self.types = [] - + self.add_pixeltype(PixelType("UNKNOWN", 0, [], bit_endian=bit_endians[0])) - for t in types: - self.add_pixeltype(t) + if types: + for t in types: + self.add_pixeltype(t)
def add_pixeltype(self, pixeltype): "Add a PixelType and check its against the config" @@ -53,5 +56,5 @@ class GfxPrimConfig(object): try: pixeltype.check_config(self) except AssertionError: - sys.stderr.write("Error checking PixelType %sn" % pixeltype.name) + log.error("Error checking PixelType %sn" % pixeltype.name)
diff --git a/pylib/gfxprim/generators/make_collected_tests.py b/pylib/gfxprim/generators/make_collected_tests.py index d690dac..04af1eb 100644 --- a/pylib/gfxprim/generators/make_collected_tests.py +++ b/pylib/gfxprim/generators/make_collected_tests.py @@ -2,38 +2,42 @@ # # Script generating collected_tests.gen.c # -# Scrapes the target directory for .test.c files, looks for -# GP_TEST and GP_SUITE macros and generates code creating all the +# Scrapes the target directory for .test.c files, looks for +# GP_TEST and GP_SUITE macros and generates code creating all the # tests and the suite # -# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Tomas Gavenciak gavento@ucw.cz #
+ # Also fixed in tests.mk collected_tests_file = 'collected_tests.gen.c'
-import os, re, glob +import os +import re +import glob +import logging as log from gfxprim.generators.generator import *
-def warn(msg_s, fname=None, line=None): - msg('W', msg_s, fname, line)
-def msg(prefix, msg_s, fname=None, line=None): - s = '[' + prefix - if fname: - s += ' ' + fname - if line: - s += ':%d'%line - s += '] ' - sys.stderr.write(s + msg_s + 'n') +def warn(msg, fname=None, line=None): + "Warning including file and line info" + assert fname + loc = "[%s] " % fname + if line: + loc = "[%s:%d] " % (fname, line) + log.warning(loc + msg) +
testfile_patterns = ['*.test.c', '*.test.gen.c']
-suites = {} # {"suitename":["testname":{test_parameters}]} +# {"suitename":["testname":{test_parameters}]} +suites = {}
suite_re = re.compile("A\s*GP_SUITE((.*))\s*Z") test_re = re.compile("A\s*GP_TEST((.*))\s*Z")
+ @generator(CHeaderGenerator(name = collected_tests_file), descr = 'Code creating the tests and suites for tests collected ' 'from .test.c files', @@ -50,7 +54,7 @@ def tests_collected_tests(c): warn('No .test.c files found in "%s".' % c.fdir) if not suites: warn('No suites found, generating empty testsuite.') - + c.rhead("#include <check.h>nn")
for suite, tests in suites.iteritems(): @@ -92,6 +96,7 @@ def tests_collected_tests(c): "{% endfor %}" "}nn", suites=suites)
+ def find_GP_directive(name, regexp, l, fname='unknown', line=0): "Looks for a given GP_* directive, parses args if any, " "retuns (name, dict_of_args) or (None, None) if not found." @@ -107,10 +112,11 @@ def find_GP_directive(name, regexp, l, fname='unknown', line=0): s = 'dict( ' + d[1].strip(" tn"") + ' )' args = eval(s) except: - die("error parsing arguments: %r" % s, fname, line) + log.fatal("error parsing arguments: %r" % s, fname, line) return d[0].strip(), args return None, None
+ def find_tests(f, fname): "Finds all tests in a file." suite = None diff --git a/pylib/gfxprim/generators/pixeltype.py b/pylib/gfxprim/generators/pixeltype.py index 18531fa..b79f08f 100644 --- a/pylib/gfxprim/generators/pixeltype.py +++ b/pylib/gfxprim/generators/pixeltype.py @@ -1,23 +1,19 @@ # -# gfxprim.pixeltype - Module with PixelType descrition class +# gfxprim.generators.pixeltype - Module with PixelType descrition class # # 2011 - Tomas Gavenciak gavento@ucw.cz #
import re -import os -import sys -import gfxprim -from gfxprim import die
-def get_size_suffix(self.bpp, bit_endian): +def get_size_suffix(bpp, bit_endian): "Create pixel-size suffix (like 16BPP or 4BPP_LE)"
- assert bpp in self.sizes - assert bit_endian in self.bit_endians size_suffix = '%dBPP' % (bpp) - if bpp < 8: + if bpp % 8 != 0: + assert bit_endian + if bit_endian: size_suffix += '_' + bit_endian return size_suffix
@@ -30,14 +26,14 @@ class PixelType(object): `size` is type bit-width `bit_endian` is required in 1,2,4 BPP types to determine the order of pixels in a byte, either 'BE' or 'LE' - `chanslist` is a list of triplets describing individual channels as + `chanslist` is a list of triplets describing individual channels as [ (`chan_name`, `bit_offset`, `bit_size`) ] where `chan_name` is usually one of: R, G, B, V (value, used for grayscale), A (opacity) """ assert re.match('A[A-Za-z][A-Za-z0-9_]*Z', name) - self.name = name - self.chanslist = chanslist + self.name = name + self.chanslist = chanslist self.chans = dict() # { chan_name: (offset, size) } self.size = size self.bit_endian = bit_endian @@ -49,14 +45,14 @@ class PixelType(object):
# Verify channel bits for overlaps # also builds a bit-map of the PixelType - self.bits = ['x']*size + self.bits = ['x']*size for c in chanslist: assert c[0] not in self.chans.keys() self.chans[c[0]] = c - for i in range(c[1],c[1]+c[2]): - assert(i<self.size) - assert(self.bits[i]=='x') - self.bits[i] = c[0] + for i in range(c[1], c[1] + c[2]): + assert(i<self.size) + assert(self.bits[i]=='x') + self.bits[i] = c[0]
def valid_for_config(self, config): "Check PixelType compatibility with given GfxPrimConfig." @@ -66,8 +62,8 @@ class PixelType(object): assert(self.size in config.sizes)
# bit_endian matters only for non-multiple-of-8 bpp - if size % 8 != 0 or bit_endian is not None: - assert bit_endian in config.bit_endians + if self.size % 8 != 0 or self.bit_endian is not None: + assert self.bit_endian in config.bit_endians
def __str__(self): return "<PixelType " + self.name + ">" diff --git a/pylib/gfxprim/generators/utils.py b/pylib/gfxprim/generators/utils.py index fe5abb4..15d7013 100644 --- a/pylib/gfxprim/generators/utils.py +++ b/pylib/gfxprim/generators/utils.py @@ -1,17 +1,20 @@ -# Module with templates and tools for writing generated code, -# especially C source and headers # -# 2011 - Tomas Gavenciak gavento@ucw.cz +# gfxprim.generators.utils - Module with templates and tools for writing +# generated code, especially C source and headers. # +# 2011 - Tomas Gavenciak gavento@ucw.cz +# +
-import sys, os, time -import jinja2 -from gfxprim import die +import jinja2 +import logging as log
def j2render(tmpl, **kw): "Internal helper to render jinja2 templates (with StrictUndefined)" t2 = tmpl.rstrip('n') # Jinja strips the last 'n', so add these later - return jinja2.Template(t2, undefined=jinja2.StrictUndefined).render(**kw) + tmpl[len(t2):] + return jinja2.Template(t2, undefined=jinja2.StrictUndefined).render(**kw) + + tmpl[len(t2):] +
def load_generators(): "Load all modules containig generators to allow them to register" @@ -20,23 +23,24 @@ def load_generators(): import gfxprim.generators.core.make_GP_Pixel import gfxprim.generators.core.make_GP_Blit import gfxprim.generators.core.make_GP_Convert - pass +
def generate_file(fname): - from gfxprim.generators.generator import known_generators "Function trying to generate file `fname` using matching known generator." + from gfxprim.generators.generator import known_generators matches = [] for k in known_generators: if k.matches_path(fname): matches.append(k) if len(matches) == 0: - die("No known generators match '%s'" % (fname,)) + log.fatal("No known generators match '%s'" % (fname,)) if len(matches) > 1: - die("Multiple generators match '%s': %s" % (fname, str(matches))) + log.fatal("Multiple generators match '%s': %s" % (fname, str(matches))) s = matches[0].generate() with open(fname, "wt") as f: f.write(s)
-def hmask(bits): + +def hmask(bits): "Helper returning hex mask for that many bits" return hex((1<<bits)-1).rstrip('L') diff --git a/pylib/gfxprim/pylint.conf b/pylib/gfxprim/pylint.conf new file mode 100644 index 0000000..0fd9fb9 --- /dev/null +++ b/pylib/gfxprim/pylint.conf @@ -0,0 +1,236 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Profiled execution. +profile=no + +# Add <file or directory> to the black list. It should be a base name, not a +# path. You may set this option multiple times. +ignore=CVS + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + + +[MESSAGES CONTROL] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifier separated by comma (,) or put this option +# multiple time. +disable=C0111,C0103 + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html +output-format=text + +# Include message's id in output +include-ids=no + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (R0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (R0004). +comment=no + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching names used for dummy variables (i.e. not used). +dummy-variables-rgx=_|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "t" (1 +# tab). +indent-string=' ' + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +ignored-classes=SQLObject + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. +generated-members=REQUEST,acl_users,aq_parent + + +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-z0-9_]{1,30}$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__ + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=8 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branchs=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=12 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20
http://repo.or.cz/w/gfxprim.git/commit/27781b18ae400421700a31d6b1ed37d836c47...
commit 27781b18ae400421700a31d6b1ed37d836c47f22 Author: Tomas Gavenciak gavento@ucw.cz Date: Mon Aug 1 21:39:01 2011 +0200
First batch of gen config changes
diff --git a/gfxprim_config.py b/gfxprim_config.py new file mode 100644 index 0000000..157f93c --- /dev/null +++ b/gfxprim_config.py @@ -0,0 +1,93 @@ +# +# gfxprim_config.py - module configuring GfxPrim code generation and +# known PixelTypes +# + +# +# 2011 - Tomas Gavenciak gavento@ucw.cz +# 2011 - Cyril Hrubis metan@ucw.cz +# +# This file is sourced by all the generating scripts. +# Moreover, the generated files are sourced by almost all Gfxprim sources, +# so a complete recompilation is required after any change. +# + +config = GfxPrimConfig( + + # C name and bit-size of the GP_pixel type + pixel_type = "uint32_t", + pixel_size = 32, + + # List of pixel sizes (bpp), explicit on purpose + sizes = [1, 2, 4, 8, 16, 32] + + # bit endians to generate, keep this fixed to LE, BE for now + bit_endians = ['LE', 'BE'] + + # List of PixelTypes, order defines the numbering. + # The "Undefined" type is added automatically. + types = [ + + # + # Standard RGB types + # + + PixelType(name='RGBx8888', size=32, chanslist=[ + ('R', 16, 8), + ('G', 8, 8), + ('B', 0, 8)]), + + PixelType(name='RGBA8888', size=32, chanslist=[ + ('R', 24, 8), + ('G', 16, 8), + ('B', 8, 8), + ('A', 0, 8)]), + + PixelType(name='RGB888', size=24, chanslist=[ + ('R', 16, 8), + ('G', 8, 8), + ('B', 0, 8)]), + + PixelType(name='RGB565', size=16, chanslist=[ + ('R', 11, 5), + ('G', 5, 6), + ('B', 0, 5)]), + + # + # Palette types + # + + PixelType(name='P2', size=2, bit_endian='LE', chanslist=[ + ('P', 0, 2)]), + + PixelType(name='P4', size=4, bit_endian='LE', chanslist=[ + ('P', 0, 4)]), + + PixelType(name='P8', size=8, bit_endian='LE', chanslist=[ + ('P', 0, 8)]), + + # + # Gray-only pixel types + # + + PixelType(name='V1', size=1, bit_endian='LE', chanslist=[ + ('V', 0, 1)]), + + PixelType(name='V2', size=2, bit_endian='LE', chanslist=[ + ('V', 0, 2)]), + + PixelType(name='V4', size=4, bit_endian='LE', chanslist=[ + ('V', 0, 4)]), + + PixelType(name='V8', size=8, bit_endian='LE', chanslist=[ + ('V', 0, 8)]), + + # + # Experiments + # + + PixelType(name='VA12', size=4, bit_endian='BE', chanslist=[ + ('A', 1, 2), + ('V', 3, 1)]), + ] + ) diff --git a/pylib/gfxprim/generators/__init__.py b/pylib/gfxprim/generators/__init__.py index e69de29..bffe6ea 100644 --- a/pylib/gfxprim/generators/__init__.py +++ b/pylib/gfxprim/generators/__init__.py @@ -0,0 +1,31 @@ +# +# gfxprim.generate +# + + +# Global config instance + +config = None + + +def load_gfxprim_config(config_file = None): + """Initialize GfxPrimConfig from a given or guessed config file. + Looks for the file by parameter, in env['PIXELTYPE_DEFS'] and + in dir(__file__)/../../../gfxprim_config.py, in that order. + """ + if not defs_file: + defs_file = os.environ.get("PIXELTYPE_DEFS", None) + if not defs_file: + path = os.path.dirname(os.path.abspath(__file__)) + defs_file = os.path.abspath( + os.path.join(path, "..", "..", "..", "gfxprim_config.py")) + if not os.path.exists(defs_file): + sys.stderr.write("WARNING: GfxPrimConfig file %s not found!n" % defs_file) + + from gfxprim.generate.pixeltype import PixelType + from gfxprim.generate.gfxprimconfig import GfxPrimConfig + l = {"PixelType": PixelType, "GfxPrimConfig": GfxPrimConfig} + execfile(defs_file, globals(), l) + + config = l["config"] + assert config diff --git a/pylib/gfxprim/generators/gfxprimconfig.py b/pylib/gfxprim/generators/gfxprimconfig.py new file mode 100644 index 0000000..60546d0 --- /dev/null +++ b/pylib/gfxprim/generators/gfxprimconfig.py @@ -0,0 +1,57 @@ +# +# gfxprimconfig.py - Class for (global) GfxPrim configuration +# +# 2011 - Tomas Gavenciak gavento@ucw.cz + +import re, os, sys + +class GfxPrimConfig(object): + def __init__(self, pixel_type = None, pixel_size=None, sizes=None, + bit_endians=None, types=[]): + + self.pixel_type = pixel_type + assert self.pixel_type + assert isinstance(self.pixel_type, str) + + self.pixel_size = pixel_size + assert isinstance(self.pixel_size, int) + assert self.pixel_size % 8 == 0 + assert self.pixel_size > 0 + + # Allowed bit-sizes of pixel types + self.sizes = sizes + assert isinstance(self.sizes, list) + assert self.pixel_size in self.sizes + assert all(( isinstance(i, int) and i > 0 and i <= self.pixel_size + for i in self.sizes)) + + # bit_endian values + self.bit_endians = bit_endians + assert isinstance(self.bit_endians, list) + assert all(( i in ["LE", "BE"] for i in self.bit_endians)) + + # Set of all encountered channel names + self.channels = set() + + # Dictionary of all pixeltypes { name : PixelType } + self.types_dict = {} + # List of all PixelTypes in order. "Unknown" must be first. + self.types = [] + + self.add_pixeltype(PixelType("UNKNOWN", 0, [], bit_endian=bit_endians[0])) + for t in types: + self.add_pixeltype(t) + + def add_pixeltype(self, pixeltype): + "Add a PixelType and check its against the config" + + assert pixeltype not in self.types + self.types.append(pixeltype) + assert pixeltype.name not in self.types_dict + self.types_dict[pixeltype.name] = pixeltype + self.channels.update(set(pixeltype.chans.keys())) + try: + pixeltype.check_config(self) + except AssertionError: + sys.stderr.write("Error checking PixelType %sn" % pixeltype.name) + diff --git a/pylib/gfxprim/generators/pixeltype.py b/pylib/gfxprim/generators/pixeltype.py index 92586ab..18531fa 100644 --- a/pylib/gfxprim/generators/pixeltype.py +++ b/pylib/gfxprim/generators/pixeltype.py @@ -1,35 +1,21 @@ -# Module with PixelType descrition class +# +# gfxprim.pixeltype - Module with PixelType descrition class +# # 2011 - Tomas Gavenciak gavento@ucw.cz +#
-# pixel format: -# type -# - PAL -# - HSVRGBA -# per chan -# name, pos, size -# bitwidth -# name - -import re, os, sys +import re +import os +import sys import gfxprim from gfxprim import die
-## *Global* dictionary of all pixeltypes { name : PixelType } -pixeltypes = {} - -## *Global* set of all encountered channel names -channels = set() - -## Allowed bit-sizes of pixels -bitsizes = [1,2,4,8,16,24,32]
-## bit_endian values -bit_endians = ['LE', 'BE'] +def get_size_suffix(self.bpp, bit_endian): + "Create pixel-size suffix (like 16BPP or 4BPP_LE)"
-## Create pixel-size suffix (16BPP or 4BPP_LE) -def get_size_suffix(bpp, bit_endian): - assert bpp in bitsizes - assert bit_endian in bit_endians + assert bpp in self.sizes + assert bit_endian in self.bit_endians size_suffix = '%dBPP' % (bpp) if bpp < 8: size_suffix += '_' + bit_endian @@ -38,28 +24,22 @@ def get_size_suffix(bpp, bit_endian):
class PixelType(object): """Representation of one GP_PixelType""" - def __init__(self, name, size, chanslist, number=None, bit_endian=None): + + def __init__(self, name, size, chanslist, bit_endian=None): """`name` must be a valid C identifier - `size` is in bits, allowed are 1, 2, 4, 8, 16, 24, 32 - `bit_endian` is order of 1,2,4BPP pixels in a byte, either 'BE' or 'LE' + `size` is type bit-width + `bit_endian` is required in 1,2,4 BPP types to determine the order of + pixels in a byte, either 'BE' or 'LE' `chanslist` is a list of triplets describing individual channels as - [ (`chan_name`, `bit_offset`, `bit_size`) ] - `chan_name` is usually one of: R, G, B, V (value, used for grayscale), A (opacity) - `number` is auto-assigned (internal use only) + [ (`chan_name`, `bit_offset`, `bit_size`) ] + where `chan_name` is usually one of: R, G, B, + V (value, used for grayscale), A (opacity) """ assert re.match('A[A-Za-z][A-Za-z0-9_]*Z', name) self.name = name self.chanslist = chanslist self.chans = dict() # { chan_name: (offset, size) } - # all types except UNKNOWN=0 must have one of these sizes - if number is not 0: - assert(size in bitsizes) self.size = size - - # bit_endian matters only for 1,2,4bpp - if size>=8 and bit_endian is None: - bit_endian = bit_endians[0] - assert bit_endian in bit_endians self.bit_endian = bit_endian
if self.size == 0: @@ -67,12 +47,6 @@ class PixelType(object): else: self.size_suffix = get_size_suffix(self.size, self.bit_endian)
- # Numbering from 1 - if number is not None: - self.number = number - else: - self.number = max([ptype.number for ptype in pixeltypes.values()] + [0]) + 1 - # Verify channel bits for overlaps # also builds a bit-map of the PixelType self.bits = ['x']*size @@ -84,9 +58,16 @@ class PixelType(object): assert(self.bits[i]=='x') self.bits[i] = c[0]
- assert self.name not in pixeltypes.keys() - pixeltypes[self.name] = self - channels.update(set(self.chans.keys())) + def valid_for_config(self, config): + "Check PixelType compatibility with given GfxPrimConfig." + + # all types except UNKNOWN=0 must have one of these sizes + if self.name != "UNKNOWN": + assert(self.size in config.sizes) + + # bit_endian matters only for non-multiple-of-8 bpp + if size % 8 != 0 or bit_endian is not None: + assert bit_endian in config.bit_endians
def __str__(self): return "<PixelType " + self.name + ">" @@ -94,27 +75,3 @@ class PixelType(object): def is_palette(self): return ('P' in self.chans)
-def load_pixeltypes(defs_file = None): - "Initialize pixeltypes by loading the defs file.n" - "Looks for the file by parameter, env['PIXELTYPE_DEFS'] and " - "in dir(__file__)/../../pixeltypes.py, in that order.n" - "PixelType UNKNOWN is not defined here." - if not defs_file: - defs_file = os.environ.get('PIXELTYPE_DEFS', None) - if not defs_file: - path = os.path.dirname(os.path.abspath(__file__)) - defs_file = os.path.join(path, '..', '..', 'pixeltypes.py') - execfile(defs_file) - -def __init__(): - "Initialize PixelType UNKNOWN.n" - "Currently also reads PIXELTYPE_DEFS, but that may change!" - if 0 not in pixeltypes: - PixelType("UNKNOWN", 0, [], bit_endian=bit_endians[0], number=0) - load_pixeltypes() - # check if some types were loaded - if len(pixeltypes) <= 1: - sys.stderr.write("WARNING: no PixelTypes were loaded.") - -__init__() - diff --git a/pylib/pixeltypes.py b/pylib/pixeltypes.py deleted file mode 100644 index b035b6a..0000000 --- a/pylib/pixeltypes.py +++ /dev/null @@ -1,88 +0,0 @@ -# -# pixeltypes.py - module defining known PixelTypes -# - -# -# 2011 - Tomas Gavenciak gavento@ucw.cz -# 2011 - Cyril Hrubis metan@ucw.cz -# -# Every call to PixelType defines one new GP_PixelType, order defines -# the numbering. Undefined type is defined automatically. -# No other functionality than PixelType() should be defined here. -# -# This file is sourced by all the generating scripts. -# Moreover, the generated files are sourced by almost all Gfxprim sources, -# a complete recompilation is required after any change. -# - -# -# Standard RGB types -# - -PixelType(name='RGBx8888', size=32, chanslist=[ - ('R', 16, 8), - ('G', 8, 8), - ('B', 0, 8)]) - - -PixelType(name='RGBA8888', size=32, chanslist=[ - ('R', 24, 8), - ('G', 16, 8), - ('B', 8, 8), - ('A', 0, 8)]) - - -PixelType(name='RGB888', size=24, chanslist=[ - ('R', 16, 8), - ('G', 8, 8), - ('B', 0, 8)]) - - -PixelType(name='RGB565', size=16, chanslist=[ - ('R', 11, 5), - ('G', 5, 6), - ('B', 0, 5)]) - -# -# Palette types -# - -PixelType(name='P2', size=2, bit_endian='LE', chanslist=[ - ('P', 0, 2)]) - - -PixelType(name='P4', size=4, bit_endian='LE', chanslist=[ - ('P', 0, 4)]) - - -PixelType(name='P8', size=8, bit_endian='LE', chanslist=[ - ('P', 0, 8)]) - -# -# Gray-only pixel types -# - -PixelType(name='V1', size=1, bit_endian='LE', chanslist=[ - ('V', 0, 1)]) - - -PixelType(name='V2', size=2, bit_endian='LE', chanslist=[ - ('V', 0, 2)]) - - -PixelType(name='V4', size=4, bit_endian='LE', chanslist=[ - ('V', 0, 4)]) - - -PixelType(name='V8', size=8, bit_endian='LE', chanslist=[ - ('V', 0, 8)]) - - -# -# Experiments -# - -PixelType(name='VA12', size=4, bit_endian='BE', chanslist=[ - ('A', 1, 2), - ('V', 3, 1)]) -
-----------------------------------------------------------------------
Summary of changes: gen.mk | 26 ++- gfxprim_config.py | 108 ++++++++++ include/core/GP_Blit.gen.h.t | 16 ++ include/core/GP_Convert.gen.h.t | 86 ++++++++ include/core/GP_Convert_Scale.gen.h.t | 28 +++ include/core/GP_GetPutPixel.gen.h.t | 63 ++++++ include/core/GP_Pixel.gen.h.t | 83 ++++++++ include/core/GP_Pixel.h | 11 +- libs/core/GP_Blit.gen.c.t | 69 +++++++ libs/core/GP_Convert.gen.c.t | 70 +++++++ libs/core/GP_Pixel.gen.c.t | 45 ++++ pylib/bin/generate_collected_tests.py | 35 ++++ pylib/bin/generate_file.py | 37 ++-- pylib/gfxprim/README | 4 +- pylib/gfxprim/__init__.py | 16 +-- pylib/gfxprim/generators/core/gen_blit.py | 75 ------- pylib/gfxprim/generators/core/gen_convert.py | 116 ----------- pylib/gfxprim/generators/core/gen_getputpixel.py | 52 ----- pylib/gfxprim/generators/core/gen_pixeltype.py | 109 ---------- pylib/gfxprim/generators/core/make_GP_Blit.py | 31 --- pylib/gfxprim/generators/core/make_GP_Convert.py | 101 --------- pylib/gfxprim/generators/core/make_GP_Pixel.py | 76 ------- pylib/gfxprim/generators/generator.py | 124 ----------- pylib/gfxprim/generators/make_collected_tests.py | 141 ------------- pylib/gfxprim/generators/pixeltype.py | 120 ----------- pylib/gfxprim/generators/utils.py | 42 ---- pylib/gfxprim/gfxprimconfig.py | 62 ++++++ pylib/gfxprim/pixelsize.py | 39 ++++ pylib/gfxprim/pixeltype.py | 62 ++++++ pylib/gfxprim/pylint.conf | 236 ++++++++++++++++++++++ pylib/gfxprim/render_utils.py | 83 ++++++++ pylib/gfxprim/test_collection.py | 96 +++++++++ pylib/pixeltypes.py | 88 -------- pylib/templates/base.c.t | 15 ++ pylib/templates/base.h.t | 11 + pylib/templates/base.test.c.t | 47 +++++ pylib/templates/collected_tests.c.t | 55 +++++ tests.mk | 11 +- LICENSE => tests/core/GP_Blit.test.c | 12 +- tests/core/GP_Convert.test.gen.c.t | 38 ++++ 40 files changed, 1413 insertions(+), 1126 deletions(-) create mode 100644 gfxprim_config.py create mode 100644 include/core/GP_Blit.gen.h.t create mode 100644 include/core/GP_Convert.gen.h.t create mode 100644 include/core/GP_Convert_Scale.gen.h.t create mode 100644 include/core/GP_GetPutPixel.gen.h.t create mode 100644 include/core/GP_Pixel.gen.h.t create mode 100644 libs/core/GP_Blit.gen.c.t create mode 100644 libs/core/GP_Convert.gen.c.t create mode 100644 libs/core/GP_Pixel.gen.c.t create mode 100644 pylib/bin/generate_collected_tests.py delete mode 100644 pylib/gfxprim/generators/__init__.py delete mode 100644 pylib/gfxprim/generators/core/__init__.py delete mode 100644 pylib/gfxprim/generators/core/gen_blit.py delete mode 100644 pylib/gfxprim/generators/core/gen_convert.py delete mode 100644 pylib/gfxprim/generators/core/gen_getputpixel.py delete mode 100644 pylib/gfxprim/generators/core/gen_pixeltype.py delete mode 100644 pylib/gfxprim/generators/core/make_GP_Blit.py delete mode 100644 pylib/gfxprim/generators/core/make_GP_Convert.py delete mode 100644 pylib/gfxprim/generators/core/make_GP_Pixel.py delete mode 100644 pylib/gfxprim/generators/generator.py delete mode 100644 pylib/gfxprim/generators/make_collected_tests.py delete mode 100644 pylib/gfxprim/generators/pixeltype.py delete mode 100644 pylib/gfxprim/generators/utils.py create mode 100644 pylib/gfxprim/gfxprimconfig.py create mode 100644 pylib/gfxprim/pixelsize.py create mode 100644 pylib/gfxprim/pixeltype.py create mode 100644 pylib/gfxprim/pylint.conf create mode 100644 pylib/gfxprim/render_utils.py create mode 100644 pylib/gfxprim/test_collection.py delete mode 100644 pylib/pixeltypes.py create mode 100644 pylib/templates/base.c.t create mode 100644 pylib/templates/base.h.t create mode 100644 pylib/templates/base.test.c.t create mode 100644 pylib/templates/collected_tests.c.t copy LICENSE => tests/core/GP_Blit.test.c (84%) create mode 100644 tests/core/GP_Convert.test.gen.c.t
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos@gmail.com if you want to unsubscribe, or site admin admin@repo.or.cz if you receive no reply.