- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2023-05-01T18:52:22+09:00","","")
#author("2023-05-02T23:48:06+09:00","","")
* 拡大縮小2 [#k72c59ac]
前回に続いてスプライトの拡大縮小は以下のような手順で使用します。~
前回に続いてスプライトの拡大縮小は以下のような手順で使用します。1.属性(Object Attribute Memory)に関する設定をして、2.拡大縮小パラメータをセットします。拡大縮小パラメータは、OAMのattribute3を使います。ここは少しヤヤコシイのですが、4つのスプライトのattribute3を束ねて1つのパラメータとして使います。次のような構造体を想像してください。こちらをマッピングして使用します。~
- 1.属性(Object Attribute Memory)に関する設定をする。
- 2.拡大縮小パラメータをセットする。
拡大縮小パラメータは、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で説明したものと同じです。~
このように指定すればrot[0].pa としてアクセスすることができます。OBJAFFINE構造体は0-31の32個まで設定可能です。128個のスプライトで拡大縮小機能を使うものは、0-31のどのパラメータを使うか指定する必要があります。なお拡大縮小パラメータのフォーマットは16bitのデータで、これはBGで説明したものと同じです。~
** 200%拡大してスプライトを表示する例 [#e3ca586d]
** スプライトの拡大縮小表示 [#k55173dd]
#include "lib/gba.h"
#include "res.h"
#include "irq.arm.h"
#include "key.h"
#include "font.h"
#include "spr.h"
//---------------------------------------------------------------------------
void WaitForVsync(void)
int main(void)
{
while (*(volatile u16*)0x4000006 >= 160) {};
while (*(volatile u16*)0x4000006 < 160) {};
REG_WSCNT = 0x4317;
IrqInit();
KeyInit();
FontInit();
SprInit();
SetMode(MODE_3 | BG2_ENABLE | OBJ_ENABLE | OBJ_1D_MAP);
s32 x = 40;
s32 y = 40;
u16 cnt;
SprSetSize (0, OBJ_SIZE(1), OBJ_SQUARE, OBJ_16_COLOR);
SprSetChr (0, 512);
SprSetXy (0, x, y);
SprSetRotateFlag(0, 0, OBJ_DOUBLE);
SprSetScale(0, 200, 200);
for(;;)
{
VBlankIntrWait();
SprSetXy(0, x, y);
FontDrawPrintf(16, 16, RGB5(31,31,31), "[%3d][%3d]", x, y);
KeyExec();
cnt = KeyGetCnt();
if(cnt & KEY_UP ) y--;
if(cnt & KEY_DOWN ) y++;
if(cnt & KEY_LEFT ) x--;
if(cnt & KEY_RIGHT) x++;
if(x > 240+32) x = 240+32;
if(x < -32) x = -32;
if(y > 160+32) y = 160+32;
if(y < -32) y = -32;
if(cnt & KEY_A) SprSetScale(0, 100, 100);
if(cnt & KEY_B) SprSetScale(0, 200, 200);
}
}
spr.c内にてSprSetRotateFlag関数が定義されています。
//---------------------------------------------------------------------------
/*
SpriteSetRotateFlag
SprSetRotateFlag
スプライトの拡大縮小回転機能に関する設定
no ・・・ 使用するスプライトRotateパラメータの番号
double_flag ・・・ 描画領域を2倍使用できるようにするか
0なら通常の描画領域、SP_SIZE_DOUBLEなら2倍
*/
void SpriteSetRotateFlag(u32 num, u32 no, u32 double_flag)
EWRAM_CODE void SprSetRotateFlag(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)
#define OBJ_ROT_SCALE(m) ((m)<<9)
double_flagはダブルサイズフラグと呼ばれるものです。スプライトで拡大縮小回転表示を行う場合、元のスプライトのサイズ(この場合は16x16)を超えた領域は描画が行われません。拡大や回転を行って、画像がその領域を超えてしまう場合、画像が欠けてしまうために不都合が起こる場合があります。このような場合にダブルサイズフラグを設定すれば、描画領域が元の画像の下と右に広がり、元の2倍の大きさまで描画するようになります。ダブルサイズフラグを指定しても、2倍を超えた領域は描画されません。ダブルサイズフラグを指定すると元の画像が2倍の大きさで描画されるということではありません。注意点として、ダブルサイズフラグを指定した場合、スプライトの中心位置が移動します。スプライトのサイズの半分だけ、右下方向に移動します。この場合は右方向に16/2=8、下方向に16/2=8移動することになります。~
EWRAM_CODE void SprSetScale(u32 num, u32 xsc, u32 ysc)
{
OBJAFFINE* rot = (OBJAFFINE*)OAM + num;
rot->pa = 256 * 100 / xsc;
rot->pa = Div(256 * 100, xsc);
rot->pb = 0;
rot->pc = 0;
rot->pd = 256 * 100 / ysc;
rot->pd = Div(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倍の大きさで描画されるということではありません。~
こちらの部分はBGとほぼ同じです。先ほど説明したOBJAFFINE構造体を使用しています。
#br
ダブルサイズフラグを指定した場合、スプライトの中心位置が移動します。スプライトのサイズの半分だけ、右下方向に移動します。この場合は右方向に16/2=8、下方向に16/2=8移動することになります。ダブルサイズフラグを指定する場合は、スプライトが表示される位置に注意してください。~
*** 動作画面 [#m56b4aa9]
-[[github:https://github.com/akkera102/gbadev-ja/tree/main/tut18%20%E6%8B%A1%E5%A4%A7%E7%B8%AE%E5%B0%8F2]]
#ref(1.png,nolink)
** 履歴 [#r4c6ccd3]
- 2023/05/01
- 2023/05/02
- 2007/09/08