Templating Engine
-----------------

The GFXprim uses python templating engine to generate code for different pixel
types. This is documentation to the engine internals.

GFXprim Config
~~~~~~~~~~~~~~

The configuration which describes pixel layout could be found in
'gen/include/gfxprim_config.py' which is used to create objects described
below.

Main Objects
~~~~~~~~~~~~

Pixel Size
^^^^^^^^^^

[source,python]
-------------------------------------------------------------------------------
class PixelPack(object):
    self.size = size

    self.suffix = suffix

    self.pack = 'GP_PIXEL_PACK_' + suffix

    ...

-------------------------------------------------------------------------------

The PixelPack object represents pixel as a continous block of data.

The 'size' is size in bits and is sometimes called bpp which stands for "bits
per pixel". This number includes padding bits, if any.

The 'suffix' is a string used as a suffix for functions, macros and other
identifiers that operate with this pixel size.

The 'pack' is a pixel packing name. Note that for a given pixel size in bits
you can have different packings. Consider for example 4-bit grayscale, there
are two different orders how to put the two 4-bit blocks inside a byte and
none of them is better.

Different pixel types (i.e. RGB888 and BGR888) can share the same pixel
packing, since certain types of operations do not depend on the actual
arrangement of the color channels in a pixel (i.e. get/put pixel, rotate
buffer 90 degrees, etc.). These operations are generated per packing.

The following two figures describe bit layout in 1 bpp and 2 bpp
grayscale bitmaps. The rectangles in the figures represents bytes as they are
in the bitmap memory. The start of the image (i.e. topleft corner
and coodinates (0,0)) is on the left side.
The numbers describe position of the bit in the byte, 'i' representing
value '1<<i', that is 7-th bit representing value 128 and 0-th bit value 1.

BE
++

["graphviz", "bit-endian-be-1bit.png"]
------------------------------------------------------------------------------
digraph bit_endian {
	graph [ dpi = 70 ];
	node [shape = record];
	rankdir = LR;

	node0 [label = "{<e> ...}"];
	node1 [label = "{7 | 6 | 5 | 4 | 3 | 2 | 1 | <e> 0}"];
	node2 [label = "{<b> 7 | 6 | 5 | 4 | 3 | 2 | 1 | <e> 0}"];
	node3 [label = "{<b> 7 | 6 | 5 | 4 | 3 | 2 | 1 | <e> 0}"];
	node4 [label = "{<b> ...}"];

	node0:e -> node1:b;
	node1:e -> node2:b;
	node2:e -> node3:b;
	node3:e -> node4:b;
}
------------------------------------------------------------------------------

["graphviz", "bit-endian-be-2bits.png"]
------------------------------------------------------------------------------
digraph bit_endian {
	graph [ dpi = 70 ];
	node [shape = record];
	rankdir = LR;

	node0 [label = "{<e> ...}"];
	node1 [label = "{7 6 | 5 4 | 3 2 | <e> 1 0}"];
	node2 [label = "{<b> 7 6 | 5 4 | 3 2 | <e> 1 0}"];
	node3 [label = "{<b> 7 6 | 5 4 | 3 2 | <e> 1 0}"];
	node4 [label = "{<b> ...}"];

	node0:e -> node1:b;
	node1:e -> node2:b;
	node2:e -> node3:b;
	node3:e -> node4:b;
}
------------------------------------------------------------------------------

LE
++

["graphviz", "bit-endian-le-1bit.png"]
------------------------------------------------------------------------------
digraph bit_endian {
	graph [ dpi = 70 ];
	node [shape = record];
	rankdir = LR;

	node0 [label = "{<e> ...}"];
	node1 [label = "{0 | 1 | 2 | 3 | 4 | 5 | 6 | <e> 7}"];
	node2 [label = "{<b> 0 | 1 | 2 | 3 | 4 | 5 | 6 | <e> 7}"];
	node3 [label = "{<b> 0 | 1 | 2 | 3 | 4 | 5 | 6 | <e> 7}"];
	node4 [label = "{<b> ...}"];

	node0:e -> node1:b;
	node1:e -> node2:b;
	node2:e -> node3:b;
	node3:e -> node4:b;
}
------------------------------------------------------------------------------

["graphviz", "bit-endian-le-2bits.png"]
------------------------------------------------------------------------------
digraph bit_endian {
	graph [ dpi = 70 ];
	node [shape = record];
	rankdir = LR;

	node0 [label = "<e> ..."];
	node1 [label = "{1 0 | 3 2 | 5 4 | <e> 7 6}"];
	node2 [label = "{<b> 1 0 | 3 2 | 5 4 | <e> 7 6}"];
	node3 [label = "{<b> 1 0 | 3 2 | 5 4 | <e> 7 6}"];
	node4 [label = "{<b> ...}"];

	node0:e -> node1:b;
	node1:e -> node2:b;
	node2:e -> node3:b;
	node3:e -> node4:b;
}
------------------------------------------------------------------------------

Pixel Type
^^^^^^^^^^

[source,python]
-------------------------------------------------------------------------------
class PixelType(object):
    self.name = name
    self.chanslist = chanslist
    self.chans = dict() # { chan_name: (offset, size) }
    self.pixelsize = pixelsize # An instance of PixelSize

    def is_palette(self):
        ...

    def is_unknown(self):
        ...

    def is_rgb(self):
        ...

    def is_cmyk(self):
        ...

    def is_gray(self):
        ...

    def is_alpha(self):
        ...

-------------------------------------------------------------------------------

This object represents pixel type which describes the sizes and arrangements of
channels in a pixel. Note that it carries an instance of pixel size described
above.

[source,python]
-------------------------------------------------------------------------------
class PixelChannel():
    # Index (position in pixel from left)
    self.idx = idx
    # Pixel channel name such as R, G, B, A, ...
    self.name = name
    # Bit offset in pixel
    self.off = offset
    # Channel bit size
    self.size = size
    # Maximal channel value
    self.max = 2 ** size - 1
    ...
-------------------------------------------------------------------------------

The chanslist describes pixel channel. There are some convenient members to be
used directly from C code whose value is a hexadecimal string, i.e. 'C_mask',
'C_max', 'C_shift'.

Templating language
~~~~~~~~~~~~~~~~~~~

GFXprim uses https://github.com/metan-ucw/cct[CCT] templating engine which is
crafted especially for generating source code. CCT is a Python based language
that contains global variables with objects described in gfxprim config.

Quick Syntax Help
^^^^^^^^^^^^^^^^^

CCT basics:

- Each written line is verbatim (reproduced as it is) unless it starts with
  +@\s+

- Lines starting with +@\s+ are interpreted as a Python code

- Comments are lines starting with +@ #+

- Verbatim lines may also contain 'Expressions' or 'Function call'

- 'Expression' is a Python code that yields a value which is included in the
   output and is enclosed between curly braces +{{ expression }}+.

- 'Function call' is a Python function whose output is included in the output.
   It is called as {@ func() @}.

More complete documentation could be found in
https://github.com/metan-ucw/cct/blob/master/HOWTO[CCT howto].
