# cpct_hflipSpriteM2

Horizontally flips a sprite, encoded in screen pixel format, mode 2.

#### C definition

void cpct_hflipSpriteM2 (u8 width, u8 height, void* sprite) __z88dk_callee;

#### Input Parameters (4 bytes)

(1B C) width | Width of the sprite in bytes (NOT in pixels!). Must be >= 1.
(1B B) height | Height of the sprite in pixels / bytes (both are the same). Must be >= 1.
(2B HL) sprite | Pointer to the sprite array (first byte of consecutive sprite data)

#### Assembly call (Input parameters on registers)

>     call cpct_hflipSpriteM2_asm

#### Parameter Restrictions

- sprite must be an array containing sprite’s pixels data in screen pixel format (Mode 2 data, 8 pixels per byte). Sprite must be rectangular and all bytes in the array must be consecutive pixels, starting from top-left corner and going left-to-right, top-to-bottom down to the bottom-right corner. Total amount of bytes in pixel array should be width x height, having width in bytes. Each byte of the sprite encodes 8 pixles in screen pixel format mode 2 (1 bit per pixel, all pixels consecutive). Warning! This function will admit any 16-bits value as sprite pointer and will modify bytes at the given address. On giving an incorrect address this function will yield undefined behaviour, probably making your program crash or doing odd things due to part of the memory being altered by this function.
- width must be the width of the sprite in bytes and must be 1 or more. Using 0 as width parameter for this function could potentially make the program hang or crash. Always remember that the width must be expressed in bytes and not in pixels. The correspondence is 1 byte = 8 pixels (mode 2)
- height must be the height of the sprite in pixels or bytes (both should be the same amount), and must be greater than 0. There is no practical upper limit to this value, but giving a height greater than the height of the sprite will yield undefined behaviour, as bytes after the sprite array might result modified.

#### Known limitations

- This function will not work from ROM, as it uses self-modifying code.
- This function does not do any kind of boundary check. If you give it incorrect values for width, height or sprite pointer it might potentially alter the contents of memory locations beyond sprite boundaries. This could cause your program to behave erratically, hang or crash. Always take the necessary steps to guarantee that your values are correct.
- As this function receives a byte-pointer to memory, it can only flip byte-sized and byte-aligned sprites. This means that the box cannot start on non-byte aligned pixels (like odd-pixels, for instance) and their sizes must be a multiple of a byte.

#### Details

This function performs an horizontal flipping of the given sprite. To do so, the function inverts byte-order in all sprite rows, and also inverts pixel order inside each byte of the sprite. The function expects to receive an sprite in screen pixel format (mode 2), like in this example:

>     // Example call. Sprite has 24x4 pixels (3x4 bytes)
>     cpct_hflipSpriteM0(3, 4, sprite);

>     // Operation performed by the call and results
>     //
>     // -----------------------------------------------------------------------------------------
>     //  |         Received as parameter            |           Result after flipping           |
>     // -----------------------------------------------------------------------------------------
>     //  | sprite => [01235678][9ABCDEFG][HIJKLMNO] |  sprite => [ONMLKJIH][GFEDCBA9][87653210] |
>     //  |           [qwertyui][asdfghjk][zxcvbnmp] |            [pmnbvcxz][kjhgfdsa][iuytrewq] |
>     //  |           [01235678][9ABCDEFG][HIJKLMNO] |            [01235678][9ABCDEFG][HIJKLMNO] |
>     //  |           [qwertyui][asdfghjk][zxcvbnmp] |            [qwertyui][asdfghjk][zxcvbnmp] |
>     // -----------------------------------------------------------------------------------------
>     //  Sprite takes 12 consecutive bytes in memory (4 rows with 3 bytes, and 8 pixels
>     //  each byte, for a total of 24x4 pixels, 96 pixels)
>     //

As can be seen on the example, the function modifies the bytes of the sprite in-place. Therefore, the sprite becomes horizontally flipped after the call and will not return to normal status unless another horizontally flipping operation is performed.

This function has a high performance if taking into account that it is not using a conversion table. However, it is very slow compared to functions that use memory-aligned conversion tables. The advantage is that this function takes less memory space as it does not require the 256-bytes table to be held in memory. Therefore, the main use for this function is to save space in memory whenever fast flipping is not required. If fast performance is required, it is better to consider the use of functions with memory-aligned conversion tables.

#### Use example

Next example presents a function that draws all enemy ships in a game. Ships are stored in an array, ordered by direction they are facing. Therefore, first ships in the array are facing left, and the rest are facing right. There is also a count of the total number of ships facing left, so as not to be continuously testing.

>     // Draws all the enemy ships that are visible in the present screen.
>     // The enemy ships array contains all the ships facing left first, then
>     // all of those facing right.
>     void drawEnemyShips(TEnemyShip* ships, u8 leftships, u8 rightships) {
>        // First draw all ships that are facing left
>        while (leftships--) {
>           // Draw Ship
>           u8 pvmem = cpct_getScreenPtr(CPCT_VMEM_START, ships->x, ships->y);
>           cpct_drawSprite(g_shipSprite, pvmem, SHIP_WIDTH, SHIP_HEIGHT);

>           // Move the pointer to point to the next ship
>           ships++;
>        }

>        // Now proceed to flip the sprite to be able to draw ships facing right
>        cpct_hflipSpriteM2(SHIP_WIDTH, SHIP_HEIGHT, g_shipSprite);

>        // Now draw all ships facing right
>        while (rightships--) {
>           // Draw Ship
>           u8 pvmem = cpct_getScreenPtr(CPCT_VMEM_START, ships->x, ships->y);
>           cpct_drawSprite(g_shipSprite, pvmem, SHIP_WIDTH, SHIP_HEIGHT);

>           // Move the pointer to point to the next ship
>           ships++;
>        }

>        // Flip the sprite again to left it as it was at the start
>        cpct_hflipSpriteM2(SHIP_WIDTH, SHIP_HEIGHT, g_shipSprite);
>     }

#### Destroyed Register values

AF, BC, DE, HL

#### Required memory

C-bindings | 86 bytes
ASM-bindings | 83 bytes

#### Time Measures

>      Case       |      microSecs (us)       |         CPU Cycles          |
>     -----------------------------------------------------------------------
>      Even-width |     (50WW + 18)H + 32     |     (200WW +  72)H + 128    |
>       Odd-width |     (50WW + 39)H + 37     |     (200WW + 156)H + 148    |
>     -----------------------------------------------------------------------
>      W=2,H=16   |          1120             |           4480              |
>      W=5,H=32   |          4485             |          17940              |
>     -----------------------------------------------------------------------
>      Asm saving |          -12              |            -48              |
>     -----------------------------------------------------------------------

WW = width/2, H = height

Horizontally flips a sprite, encoded in screen pixel format, mode 2.
unsigned char (u8 = unsigned 8-bits, 1 byte )
Close