Page 1 of 1

Blending sprites

Posted: Tue Aug 17, 2010 12:29 am
by surffer3d
Hello,

I'm learning about libnds, and now I'm facing sprite blending. I could get the sprites to blend all at once, but I need to enable/disable the effect on each one. I don't know if this is possible, or maybe I missed it in the provided examples. Anyway, I'm finding this blending topic a little difficult, so I wanted to ask if the way I'm approaching it is correct:

1) Activate alpha blending. For that I use the following code, since I didn't found any function to do that tasks (the offset 0x1000 just for the subengine). The register information comes from http://nocash.emubase.de/gbatek.htm

Code: Select all

    u16* mem_BLDCNT_SUB = (u16*)(0x04000050 + 0x1000);
    *mem_BLDCNT_SUB = BIT(4) | BIT(6) | BIT(11); // Alpha blend objects with bg_layer 3

    u16* mem_BLDALPHA_SUB = (u16*)(0x04000052 + 0x1000);
    *mem_BLDALPHA_SUB = (8) | (16<<8); // Change the factors as needed
2) Well, I couldn't get anywhere else. The documentation states that in bitmap sprites the palette index of oamSet is used as alpha factor, but I coudln't get any change in that way (just using the up global value worked). Then I checked the oamSet function in sprite.c and found the following code:

Code: Select all

    // format is of type SpriteColorFormat
    if(format != SpriteColorFormat_Bmp) {
        oam->oamMemory[id].colorMode = format;
    } else {
        oam->oamMemory[id].blendMode = format;
    }
I've tried changing myself the blendMode option directly for different kinds of tiles (bitmap and 8bit palette), but nothing worked. Has anyone a solution for this or knows if it is possible to achieve?

Re: Blending sprites

Posted: Tue Aug 17, 2010 1:59 am
by zeromus
you can modify the bitmap_sprites example to get the desired effect.

change line 23:
{0, SpriteSize_32x32, SpriteColorFormat_Bmp, 0, 8, 20, 0}, //moves it up so that you can see it blend on text, and changes alpha from 15 to 8

and add this somewhere

//blend objects onto all layers, and backdrop
vu16* mem_BLDCNT_SUB = (vu16*)(0x04000050 + 0x1000);
*mem_BLDCNT_SUB = BIT(4) | BIT(0) | BIT(8) | BIT(9) | BIT(10) | BIT(11) | BIT(12) | BIT(13);

registers should be volatile (check all the dozens of libnds headers). speaking of libnds headers, why not use the register declared in there?

Youre using the sub engine blend controls. Are you putting the sprites on sub engine?

One other thing you may try is manually setting colormode=0

oamSub.oamMemory[0].colorMode = (ObjColMode)0;

It seems from available reference material and personal experiments that this truly must be 0 to get a bitmap sprite

Re: Blending sprites

Posted: Tue Aug 17, 2010 2:29 am
by WinterMute

Code: Select all

REG_BLDALPHA_SUB = (8) | (16<<8); // Change the factors as needed
REG_BLDCNT_SUB = BLEND_ALPHA | BLEND_SRC_SPRITE | BLEND_DST_BG0 |BLEND_DST_BG1 | BLEND_DST_BG2 | BLEND_DST_BG3 | BLEND_DST_SPRITE | BLEND_DST_BACKDROP;
might be a bit more obvious about what it's doing, although I guess we could do with some macros for the blend factors.

Re: Blending sprites

Posted: Tue Aug 17, 2010 11:31 am
by surffer3d
Thanks for the replies! I didn't know that the registers where available in the documentation, so thanks to point this out! It would be nice if them could be also added to the documentation in the future. And also I didn't realize about the variables should be declared volatile.

I've tried with the example that zeromus suggested, and I modified it a little for testing the blending capabilites in the following ways:
1) now the 3 sprites are of bitmap type
2) I simplified it a little to avoid unnecessay code for the test (so no orientation, for instance). Here is the code:

Code: Select all

#include <cstdio>
#include <nds.h>

//a simple sprite structure 
//it is generally preferred to separate your game object
//from OAM
typedef struct  
{
   u16* gfx;
   SpriteSize size;
   SpriteColorFormat format;
   int rotationIndex;
   int paletteAlpha;
   int x;
   int y;
}MySprite;

int main(int argc, char** argv) {
	
   //three bitmap sprites
   MySprite sprites[] = {
      {0, SpriteSize_32x32, SpriteColorFormat_Bmp, -1, 0, 20, 5},
      {0, SpriteSize_32x32, SpriteColorFormat_Bmp, -1, 8, 20, 70},
      {0, SpriteSize_32x32, SpriteColorFormat_Bmp, -1, 15, 20, 126}
   };

   videoSetModeSub(MODE_0_2D);

   consoleDemoInit();
   
   REG_BLDALPHA_SUB = (8) | (8<<8); // Change the factors as needed
   REG_BLDCNT_SUB = BLEND_ALPHA | 
                    BLEND_SRC_SPRITE | 
                    BLEND_DST_BG0 |BLEND_DST_BG1 | BLEND_DST_BG2 | BLEND_DST_BG3 | BLEND_DST_SPRITE | BLEND_DST_BACKDROP;

   //initialize the sub sprite engine with 1D mapping 128 byte boundary
   //and no external palette support
   oamInit(&oamSub, SpriteMapping_Bmp_1D_128, false);

  
   vramSetBankD(VRAM_D_SUB_SPRITE);
   
   //allocate some space for the sprite graphics
   for(int i = 0; i < 3; i++)
      sprites[i].gfx = oamAllocateGfx(&oamSub, sprites[i].size, sprites[i].format);
   
   //ugly positional printf
   printf("\x1b[1;1HDirect Bitmap: RED");
   printf("\x1b[9;1HDirect Bitmap: GREEN");
   printf("\x1b[16;1HDirect Bitmap: BLUE");
   
   //fill bmp sprite with the color red
   dmaFillHalfWords(ARGB16(1,31,0,0), sprites[0].gfx, 32*32*2);
   //fill the 256 color sprite with index 1 (2 pixels at a time)
   dmaFillHalfWords(ARGB16(1,0,31,0), sprites[1].gfx, 32*32*2);
   //fill the 16 color sprite with index 1 (4 pixels at a time)
   dmaFillHalfWords(ARGB16(1,0,0,31), sprites[2].gfx, 32*32*2);

   while(1)
   {
      for(int i = 0; i < 3; i++)
      {
         oamSet(
         &oamSub, //sub display 
         i,       //oam entry to set
         sprites[i].x, sprites[i].y, //position 
         0, //priority
		 sprites[i].paletteAlpha, //alpha (since we just have bmp sprites)
         sprites[i].size, 
		 sprites[i].format, 
		 sprites[i].gfx, 
		 -1,  // no rotation
         true, //double the size of rotated sprites
         false, //don't hide the sprite
		 false, false, //vflip, hflip
		 false //apply mosaic
         );

        //oamSub.oamMemory[i].colorMode = (ObjColMode)1;
        //oamSub.oamMemory[i].blendMode = (ObjBlendMode)3;
      }

      swiWaitForVBlank();

      //send the updates to the hardware
      oamUpdate(&oamSub);
   }
   return 0;
}
However, if you try it (I'm trying on No$GBA) you'll see all the sprites share the same alpha blending level, even I assigned to them different values in the array construction (0,8 and 15). Commenting the REG_BLDALPHA_SUB line just makes the sprites completely black, but I think this is just the case where the blending coeficients are both 0.

So the problem is that I still can't get a different alpha level for each sprite. (I also played directly modifying colorMode and blendMode, but nothing). Could you tell me how to do that?

Re: Blending sprites

Posted: Tue Aug 17, 2010 10:44 pm
by zeromus
two problems:

1. always test on hardware
2. if you are testing in emulators, always use more than one. if you insist on only using one, then make it desmume, where at least you have some recourse if the emulation fails. in this case, nocash is rendering incorrectly.

Re: Blending sprites

Posted: Wed Aug 18, 2010 12:53 am
by surffer3d
You were right ... it was working fine on the console but not on the emulator, my fault. From now I will test more often on console.