cpct_hflipSpriteMaskedM2

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

C definition

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

Input Parameters (4 bytes)

(1B C) widthWidth of the sprite in bytes (NOT in pixels!).  Must be >= 1.
(1B B) heightHeight of the sprite in pixels / bytes (both are the same).  Must be >= 1.
(2B HL) spritePointer to the sprite array (first byte of consecutive sprite data)

Assembly call (Input parameters on registers)

call cpct_hflipSpriteMaskedM2_asm

Parameter Restrictions

  • sprite must be an array containing sprite’s pixels data in screen pixel format with interlaced mask data (Pairs of bytes, 1st: mask data for next byte, 2nd: mode 1 pixel data byte).  You may check screen pixel format for mode 2 (1 bit per pixel).  Each mask byte will contain enabled bits as those that should be picked from the background (transparent) and disabled bits for those that will be printed from sprite colour data.  Each mask data byte must precede its associated colour data 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 2 x width x height.
  • width must be the width of the sprite in bytes, without accounting for mask 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 / 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 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.
  • 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 along with its interlaced mask.  To do so, the function inverts the order of the pairs of bytes formed by each mask byte and its associated pixel-definition byte, for all sprite rows.  It also inverts pixel order inside each byte of the sprite (be it pixel byte or mask byte).  The function expects to receive an sprite in screen pixel format (mode 2), along with its interlaced mask like in this example:

// Example call. Sprite has 16x4 pixels (2x4 bytes)
cpct_hflipSpriteMaskedM2(2, 4, sprite);

// Operation performed by the call and results (mM, nN: mask bits)
//
// -------------------------------------------------------
//  |                Received as parameter               |
// -------------------------------------------------------
//  | sprite => [mMmMmMmM][01235678][mMmMmMmM][HGFEDCBA] |
//  |           [nNnNnNnN][98765432][nNnNnNnN][abcdefgh] |
//  |           [mMmMmMmM][01235678][mMmMmMmM][HGFEDCBA] |
//  |           [nNnNnNnN][98765432][nNnNnNnN][abcdefgh] |
// -------------------------------------------------------
//  |               Result after flipping                |
// -------------------------------------------------------
//  | sprite => [MmMmMmMm][ABCDEFGH][MmMmMmMm][87653210] |
//  |           [NnNnNnNn][hgfedcba][NnNnNnNn][23456789] |
//  |           [MmMmMmMm][ABCDEFGH][MmMmMmMm][87653210] |
//  |           [NnNnNnNn][hgfedcba][NnNnNnNn][23456789] |
// -----------------------------------------------------------------------------
//  Sprite takes 16 consecutive bytes in memory (4 rows with 4 bytes, 2 mask bytes
//  and 2 pixel definition bytes, 8 pixels each pixel byte, for a total of
//  16x4 = 64 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 performs reasonably well compared to cpct_hflipSpriteM2, as time required for doing the flip is a little bit more than doubled, for double amount of bytes.  However, for maximum performance, functions making use of memory-aligned conversion tables are advised.  Also, having memory-aligned sprites will permit developing even faster versions.  In any case, The most important advantage of this function is its reduced size, compared to requiring a function and a 256-bytes aligned table together.

Use example

Next example shows a function designed to draw an animated flag that flips right-to-left as if it was being agitated.  To do so, every 30 times it is redrawn, it is flipped horizontally to simulate that right-to-left animated movement:

// Draws an animated flag that changes from left-to-right periodically
//(every 30 times it is redrawn). Flag is 24x16 mode 2 pixels
//(3x16 bytes, 6x16 bytes taking interlaced mask into account)
void drawFlag(u8 x, u8 y) {
   static u8 timesdrawn;  // Statically count the number of times the flag has been drawn
   u8* pvmem;             // Pointer to video memory to draw the sprite

   // Count for a new redraw of the flag and check if it has been
   // drawn 30 or more times in order to flip it
   if(++timesdrawn > 30) {
      // Horizontally flip the flag to animate it
      cpct_hflipSpriteMaskedM2(3, 16, flagSprite);
      timesdrawn = 0;
   }

   // Draw the flag
   pvmem = cpct_getScreenPtr(CPCT_VMEM_START, x, y);
   cpct_drawSpriteMasked(flagSprite, pvmem, 3, 16);
}

Destroyed Register values

AF, BC, DE, HL

Required memory

C-bindings80 bytes
ASM-bindings77 bytes

Time Measures

 Case       |      microSecs (us)       |         CPU Cycles          |
-----------------------------------------------------------------------
 Even-width |    (116WW + 18)H + 16     |     (464WW +  72)H + 64     |
  Odd-width |    (116WW + 87)H + 16     |     (464WW + 348)H + 64     |
-----------------------------------------------------------------------
 W=2,H=16   |          2160             |           8640              |
 W=5,H=32   |         10224             |          40896              |
-----------------------------------------------------------------------
 Asm saving |          -12              |            -48              |
-----------------------------------------------------------------------

WW = (int)(width/2), H = height

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