前回に続いてスプライトの拡大縮小は以下のような手順で使用します。
拡大縮小パラメータは、OAMのattribute3を使います。ただし、ここは少しヤヤコシイのですが4つのスプライトのattribute3を1つのパラメータとして束ねて使います。次のような構造体を想像していただくとわかりやすいと思います。こちらをマッピングして使用します。
typedef struct { u16 dummy0[3]; s16 pa; u16 dummy1[3]; s16 pb; u16 dummy2[3]; s16 pc; u16 dummy3[3]; s16 pd; } OBJAFFINE; OBJAFFINE* rot = (OBJAFFINE*)OAM
以上のように指定すればrot[0].pa のようにアクセスすることができます。OBJAFFINE構造体は0-31の32個まで設定可能です。128個のスプライトで拡大縮小機能を使うものは、0-31のどのパラメータを使うか指定する必要があります。なお拡大縮小パラメータのフォーマットは16bitのデータで、これはBGで説明したものと同じです。
#include "lib/gba.h" #include "res.h" //--------------------------------------------------------------------------- void WaitForVsync(void) { while (*(volatile u16*)0x4000006 >= 160) {}; while (*(volatile u16*)0x4000006 < 160) {}; } //--------------------------------------------------------------------------- /* SpriteSetRotateFlag スプライトの拡大縮小回転機能に関する設定 no ・・・ 使用するスプライトRotateパラメータの番号 double_flag ・・・ 描画領域を2倍使用できるようにするか 0なら通常の描画領域、SP_SIZE_DOUBLEなら2倍 */ void SpriteSetRotateFlag(u32 num, u32 no, u32 double_flag) { OBJATTR* sp = (OBJATTR*)OAM + num; sp->attr0 |= OBJ_ROT_SCALE_ON; sp->attr1 &= 0xC1ff; sp->attr1 |= OBJ_ROT_SCALE(no); sp->attr0 &= 0xfdff; sp->attr0 |= double_flag; } //--------------------------------------------------------------------------- void SpriteScale(u32 num, u32 xsc, u32 ysc) { OBJAFFINE* rot = (OBJAFFINE*)OAM + num; rot->pa = 256 * 100 / xsc; rot->pb = 0; rot->pc = 0; rot->pd = 256 * 100 / ysc; } //--------------------------------------------------------------------------- void SpriteSetPalNo(u32 num, u32 palNo) { OBJATTR* sp = (OBJATTR*)OAM + num; sp->attr2 &= 0x0fff; sp->attr2 |= (palNo << 12); } //--------------------------------------------------------------------------- void SpriteMove(u32 num, s32 x, s32 y) { OBJATTR* sp = (OBJATTR*)OAM + num; if(x<0) x += 512; if(y<0) y += 256; sp->attr1 &= 0xfe00; sp->attr0 &= 0xff00; sp->attr1 |= (x & 0x01ff); sp->attr0 |= (y & 0x00ff); } //--------------------------------------------------------------------------- void SpriteSetSize(u32 num, u32 size, u32 form, u32 col) { OBJATTR* sp = (OBJATTR*)OAM + num; sp->attr0 &= 0x1fff; sp->attr1 &= 0x3fff; sp->attr0 |= col | form | (160); sp->attr1 |= size | (240); } //--------------------------------------------------------------------------- void SpriteSetChr(u32 num, u32 ch) { OBJATTR* sp = (OBJATTR*)OAM + num; sp->attr2 &= 0xfc00; sp->attr2 |= ch; } //--------------------------------------------------------------------------- void SpriteInit(void) { u32 i; for(i=0; i<128; i++) { SpriteMove(i, 240, 160); } } //--------------------------------------------------------------------------- int main(void) { // モード設定 SetMode(MODE_0 | OBJ_ENABLE | OBJ_1D_MAP); u16* oam = OBJ_BASE_ADR; // スプライトデータ u16* pal = OBJ_COLORS; // スプライトパレット u32 i; // データの格納 for(i=0; i<sprTilesLen/2; i++) { oam[i] = sprTiles[i]; } // パレットの格納 for(i=0; i<16; i++) { pal[i] = sprPal[i]; } SpriteInit(); SpriteSetSize (0, OBJ_SIZE(1), OBJ_SQUARE, OBJ_16_COLOR); SpriteSetChr (0, 0); SpriteMove (0, 20, 20); SpriteSetPalNo(0, 0); SpriteSetRotateFlag(0, 0, OBJ_DOUBLE); SpriteScale(0, 200, 200); for(;;) { WaitForVsync(); } }
SpriteSetRotateFlag関数のdouble_flagは、ダブルサイズフラグと呼ばれるものです。スプライトで拡大縮小回転表示を行う場合、元のスプライトのサイズ(この場合は16x16)を超えた領域は描画が行われません。拡大や回転を行って、画像がその領域を超えてしまう場合、画像が欠けてしまうために不都合が起こる場合があります。このような場合にダブルサイズフラグを設定すれば、描画領域が元の画像の下と右に広がり、元の2倍の大きさまで描画するようになります。ダブルサイズフラグを指定しても、2倍を超えた領域は描画されません。ダブルサイズフラグを指定すると元の画像が2倍の大きさで描画されるということではありません。
ダブルサイズフラグを指定した場合、スプライトの中心位置が移動します。スプライトのサイズの半分だけ、右下方向に移動します。この場合は右方向に16/2=8、下方向に16/2=8移動することになります。ダブルサイズフラグを指定する場合は、スプライトが表示される位置に注意してください。