cpct_hflipSpriteMaskedM0

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

C definition

void cpct_hflipSpriteMaskedM0 (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_hflipSpriteMaskedM0_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 0 pixel data byte).  You may check screen pixel format for mode 0 (cpct_px2byteM0).  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 = 2 pixels (mode 0)
  • 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 0), along with its interlaced mask like in this example:

// Example call. Sprite has 8x4 pixels (4x4 bytes)
cpct_hflipSpriteMaskedM0(4, 4, sprite);

// Operation performed by the call and results (mM, nN = mask data bytes)
//
// ---------------------------------------------------------------------------------------------
//  |          Received as parameter             |          Result after flipping              |
// ---------------------------------------------------------------------------------------------
//  | sprite => [mM][05][nN][21][mM][73][nN][40] |  sprite => [Nn][04][Mm][37][Nn][12][Mm][05] |
//  |           [mM][52][nN][23][mM][37][nN][74] |            [Nn][47][Mm][73][Nn][32][Mm][25] |
//  |           [mM][05][nN][11][mM][31][nN][04] |            [Nn][04][Mm][13][Nn][11][Mm][50] |
//  |           [mM][00][nN][55][mM][44][nN][00] |            [Nn][00][Mm][44][Nn][55][Mm][00] |
// ---------------------------------------------------------------------------------------------
//  Sprite takes 32 consecutive bytes in memory: 4 rows with 8 bytes (4 bytes pixel data,
//  and 4 bytes mask data)
//

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_hflipSpriteM0, as time required for doing the flip is a little bit less 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 how to create a function for drawing a 2D-Character sprite that can look either to the left or to the right.  Sprite is only flipped when the character changes the side it is looking.

// Draws the main character sprite always looking to the
// appropriate side (right or left), reversing it whenever required
void drawCharacter(u8 lookingat, u8 x, u8 y) {
   u8* pvmem; // Pointer to video memory to draw the sprite

   // Check if we have to reverse character sprite or not
   if(lookingAt != wasLookingAt) {
      // Horizontally flip character's sprite when it
      // changes the side it is looking at
      cpct_hflipSpriteMaskedM0(4, 8, characterSprite);
      wasLookingAt = lookingAt;
   }

   // Draw main character's sprite
   pvmem = cpct_getScreenPtr(CPCT_VMEM_START, x, y);
   cpct_drawSpriteMasked(characterSprite, pvmem, 4, 8);
}

Destroyed Register values

AF, BC, DE, HL

Required memory

C-bindings62 bytes
ASM-bindings59 bytes

Time Measures

 Case       |      microSecs (us)       |         CPU Cycles          |
-----------------------------------------------------------------------
 Even-width |     (80WW + 18)H + 16     |     (320WW +  72)H + 64     |
  Odd-width |     (80WW + 69)H + 16     |     (320WW + 244)H + 64     |
-----------------------------------------------------------------------
 W=2,H=16   |          1584             |           6336              |
 W=5,H=32   |          7344             |          29376              |
-----------------------------------------------------------------------
 Asm saving |          -12              |            -48              |
-----------------------------------------------------------------------

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

Horizontally flips a sprite, encoded in screen pixel format, mode 0, with interlaced mask.
unsigned char (u8 = unsigned 8-bits, 1 byte )
Transforms 2 pixel colour values [0-15] into a byte value in the video memory pixel format for Mode 0.
Horizontally flips a sprite, encoded in screen pixel format, mode 0.
Close