Freeplaytech Forum
Flipping sprites? - Printable Version

+- Freeplaytech Forum (https://forum.freeplaytech.com)
+-- Forum: Neo Geo Pocket (https://forum.freeplaytech.com/forumdisplay.php?fid=1)
+--- Forum: Software Development (https://forum.freeplaytech.com/forumdisplay.php?fid=4)
+--- Thread: Flipping sprites? (/showthread.php?tid=5103)



Flipping sprites? - winteriscoming - 04-22-2020

Is sprite flipping supported in the C framework?  I haven't come across it in the homebrew source code examples I have checked so far.  Ideally, like for a fighting game or platformers, you would only have to store character sprite data facing one direction and then flip it on X or Y as needed.


RE: Flipping sprites? - Loïc - 04-23-2020

Hi,
tile flipping is hardware supported.
I don't know for C framework, but here's the description of a sprite (64 sprtites, starting from 0x8800): 

0x8800  C.C = Character Tile Number (lower 8 bits of 9)
0x8801  Bit 7 - H.F = Horizontal Flip (0=normal,1=flipped)
              Bit 6 - V.F = Vertical Flip   (0=normal,1=flipped
              Bit 5 - P.C = Palette Code (Valid for K1GE upper palette compatible mode ie BW hardware)
              Bit 4 - PR.C = Priority Code MSB  (00=Hide,01=Furthest,10=Middle,11=Front)
              Bit 3 - PR.C = Priority Code LSB
              Bit 2 - H.ch = H Position Chain (0 = Normal, 1 = Offset coordinates) (Value defined becomes the offset value with respect to the previous character.)
              Bit 1 - V.ch = V Position Chain (0 = Normal, 1 = Offset coordinates) (Value defined becomes the offset value with respect to the previous character.)
              Bit 0 - C.C = Character Tile Number (Upper 1 bit of 9)
0x8802  H.P = Horizontal Position
0x8803  V.P = Vertical Position
[...]


RE: Flipping sprites? - winteriscoming - 04-23-2020

I found a document that mentions sprite flipping is supported by the NGPC in VRAM at bits 6 and 7 at offset 0x8801.

I looked over library.c to see how the sprite functions are modifying VRAM and have successfully added this function: 
Code:
void SetSpriteFlip(u8 SpriteNo, bool XFlip, bool YFlip)
{
  u8 * theSprite = SPRITE_RAM;
  theSprite += (SpriteNo * 4);
 
  switch (XFlip)
  {
 case 1:
*(theSprite+1) ^= 128;
break;
 default:
break;
  }
   switch (YFlip)
  {
 case 1:
*(theSprite+1) ^= 64;
break;
 default:
break;
  }
}

Of course, this has to be added to library.h:
Code:
void SetSpriteFlip(u8 SpriteNo, bool XFlip, bool YFlip);

This successfully flips a tile on X, Y or both.  It only works on the 1 tile specified and does not affect other tiles in a chain.  It appears that flipping a chain would require flipping each tile in the chain and changing X and/or Y positions on each as needed.  It would probably not be too difficult to come up with a function to manage flipping at the chain level.


RE: Flipping sprites? - winteriscoming - 04-23-2020

(04-23-2020, 01:35 AM)Loïc Wrote: Hi,
tile flipping is hardware supported.
I don't know for C framework, but here's the description of a sprite (64 sprtites, starting from 0x8800): 

0x8800  C.C = Character Tile Number (lower 8 bits of 9)
0x8801  Bit 7 - H.F = Horizontal Flip (0=normal,1=flipped)
              Bit 6 - V.F = Vertical Flip   (0=normal,1=flipped
              Bit 5 - P.C = Palette Code (Valid for K1GE upper palette compatible mode ie BW hardware)
              Bit 4 - PR.C = Priority Code MSB  (00=Hide,01=Furthest,10=Middle,11=Front)
              Bit 3 - PR.C = Priority Code LSB
              Bit 2 - H.ch = H Position Chain (0 = Normal, 1 = Offset coordinates) (Value defined becomes the offset value with respect to the previous character.)
              Bit 1 - V.ch = V Position Chain (0 = Normal, 1 = Offset coordinates) (Value defined becomes the offset value with respect to the previous character.)
              Bit 0 - C.C = Character Tile Number (Upper 1 bit of 9)
0x8802  H.P = Horizontal Position
0x8803  V.P = Vertical Position
[...]

Thanks for the reply.  I think I posted my solution at the same time you were replying!


RE: Flipping sprites? - Loïc - 04-23-2020

(04-23-2020, 01:39 AM)winteriscoming Wrote: Thanks for the reply.  I think I posted my solution at the same time you were replying!

You're welcome.

It took me some time to exhume my old documents.
You're right, tile flipping only apply to the current sprite.


RE: Flipping sprites? - winteriscoming - 04-23-2020

As I had hoped, with proper management, a chain can be successfully flipped.  I am working on a function to manage this.

I am surprised the C framework did not accommodate this already (at least not as far as I can tell), given the hardware support for flipping sprites.

I will share my solution when I have it together.


RE: Flipping sprites? - winteriscoming - 04-25-2020

Here's an example of chain flipping:
[attachment=1189]
[attachment=1190]

This goes in library.c:
Code:
//////////////////////////////////////////////////////////////////////////////
// SetSpriteFlipChain
// Flips a sprite chain
// Inputs:
// SpriteNo - 0-63 the sprite to flip
//      XWidth - how many tiles wide the sprite chain is (8 pixels per tile width, so if the sprite is 16 pixels wide, the number of tile width to enter is 2) 
//      YHeight - how many tiles high the sprite chain is (8 pixels per tile height, so if the sprite is 16 pixels tall, the number of tile height to enter is 2)
//      tileCount - number of tiles in chain (if a full rectangle, then XWidth*YHeight, but other orientations with fewer tiles are supported
//      HFlip - 1 to flip horizontally
//      VFlip - 1 to flip vertically
//////////////////////////////////////////////////////////////////////////////
void SetSpriteFlipChain(u8 SpriteNo, u8 XWidth, u8 YHeight, u8 tileCount, bool HFlip, bool VFlip)
{
   u8 i, HFlipped, VFlipped, XMod, YMod, SpriteMods;
   u8 * theSprite = SPRITE_RAM;
   theSprite += (SpriteNo * 4); //Set up pointer to tile in VRAM
   SpriteMods = *(theSprite+1);
   HFlipped = SpriteMods>>7; //get the tile's stored value for Horizontal Flip from VRAM(0=normal,1=flipped)
   VFlipped = SpriteMods<<1;
   VFlipped = VFlipped>>7; //get the tile's stored value for Vertical Flip from VRAM(0=normal,1=flipped)
   XMod=1;
   YMod=1;
   if(HFlip){
       XMod=-1; //if HFlip, then set the X Modifier to -1 to invert the X offset for dependent tiles in the chain
   if(XWidth){
   if(HFlipped){ //Check if main tile is already Horizontally flipped and manage X position when flipping, so that the chain occupies the same space when flipped or flipped back
   *(theSprite+2)-=(XWidth*8-8);
   }else{
   *(theSprite+2)+=(XWidth*8-8);
   }
   }
   
   }
   if(VFlip){
   YMod=-1; //if VFlip, then set the Y Modifier to -1 to invert the Y offset for dependent tiles in the chain
   
   if(YHeight){
   if(VFlipped>0){//Check if main tile is already Verically flipped and manage Y position when flipping, so that the chain occupies the same space when flipped or flipped back
   *(theSprite+3)-=(YHeight*8-8);
   }else{
   *(theSprite+3)+=(YHeight*8-8);
   }
   }
   }
   
   for (i = 0; i < tileCount; i ++) //Loop through all tiles in the chain
   {
  
SetSpriteFlip(SpriteNo + i, HFlip, VFlip); //Flip the tile
if(i>0){//Manage offset modifiers for all dependent tiles
theSprite += (4);
*(theSprite+2) *= XMod; //if XMod is -1, then offset gets inverted
*(theSprite+3) *= YMod; //if YMod is -1, then offset gets inverted
}
   }
   
}


This goes in library.h:
Code:
void SetSpriteFlip(u8 SpriteNo, bool HFlip, bool VFlip);
void SetSpriteFlipChain(u8 SpriteNo, u8 XWidth, u8 YHeight, u8 tileCount, bool HFlip, bool VFlip);

Note 1:  The chain flipping formula edits the X and/or Y position of the main tile to make it so that, when flipped, the chain remains in the same space on the screen.  If something else is directly modifying/setting sprite position outside of this formula, then the effect of this corrective measure is override and will appear not to have worked.  In that case, the tile chain will pivot on the coordinates of the main tile, and the flipped chain will occupy space outside of the chain in its un-flipped state.

Note 2:  The reason tileCount is required is to allow support for sprite chains that do not fill a full rectangle, otherwise tileCount would equal XWidth*YHeight.

Note 3:  XWidth and XHeight are used to determine how far the main tile should be moved when flipped.  Assuming that the main tile is the uppermost and leftmost tile in the chain, then the XWidth and XHeight would be the full number of tiles horizontally and vertically, respectivly.  For example, if a chain is flipped vertically, the uppermost leftmost tile becomes the lowermost leftmost tile, and will be moved down into that position.  If the main sprite is offset from the leftmost uppermost tile, then XWidth and XHieght need to be figured out based on that offset to determine the pivot point.  

Say you have a tile chain like this where the main tile is at the top and in the middle, and you've got 4 total tiles.
 X
XXX

You would want horizontal flipping to pivot directly on the coordinates of the main tile and the main tile would not need to change position in that case.  Therefore XWidth could be set to 0, and Y Height would be set to 2, while tileCount is set to 4.

Examples of 2 sprite groups at the bottom that are not full rectangles.  The lower left is an example of a main tile being offset from the left by 1 tile, and the lower right is a chain were there is a gap between the main tile and the first dependent.  In both cases, the entire chain stays within the same space when flipped.
[attachment=1191]
[attachment=1192]