#author("2023-05-25T09:22:57+09:00","","")
#author("2023-05-30T10:48:31+09:00","","")
* 拡大縮小2 [#k72c59ac]
前回に続いてスプライトの拡大縮小は以下のような手順で使用します。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のどのパラメータを使うか指定する必要があります。なお拡大縮小パラメータpa〜pdのフォーマットは16bitのデータで、これはBGで説明したものと同じです。

** スプライトの拡大縮小表示 [#k55173dd]
 #include "lib/gba.h"
 #include "irq.arm.h"
 #include "key.h"
 #include "font.h"
 #include "spr.h"
 
 //---------------------------------------------------------------------------
 int main(void)
 {
 	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関数が定義されています。

 //---------------------------------------------------------------------------
 /*
 	SprSetRotateFlag
 	スプライトの拡大縮小回転機能に関する設定
 	no      ・・・ 使用するスプライトRotateパラメータの番号
 	double_flag ・・・ 描画領域を2倍使用できるようにするか
 	                     0なら通常の描画領域、SP_SIZE_DOUBLEなら2倍
 */
 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;
 }

 #define OBJ_ROT_SCALE(m)	((m)<<9)

double_flagはダブルサイズフラグと呼ばれるものです。スプライトで拡大縮小回転表示を行う場合、元のスプライトのサイズ(この場合は16x16)を超えた領域は描画が行われません。拡大や回転を行って、画像がその領域を超えてしまう場合、画像が欠けてしまうために不都合が起こる場合があります。このような場合にダブルサイズフラグを設定すれば、描画領域が元の画像の下と右に広がり、元の2倍の大きさまで描画するようになります。ダブルサイズフラグを指定しても、2倍を超えた領域は描画されません。ダブルサイズフラグを指定すると元の画像が2倍の大きさで描画されるということではありません。~
double_flagはダブルサイズフラグと呼ばれるものです。スプライトで拡大縮小回転表示を行う場合、元のスプライトのサイズ(この場合は16x16)を超えた領域は描画が行われません。拡大や回転を行って、画像がその領域を超えてしまう場合、画像が欠けてしまうために不都合が起こる場合があります。このような場合にダブルサイズフラグを設定すれば、描画領域が元の画像の下と右に広がり、元の2倍の大きさまで描画するようになります。ダブルサイズフラグを指定しても、2倍を超えた領域は描画されません。元の画像が2倍の大きさで描画されるということでもありません。~

注意点として、ダブルサイズフラグを指定した場合、スプライトの中心位置が移動します。スプライトのサイズの半分だけ、右下方向に移動します。この場合は右方向にスプライトサイズ16/2=8、下方向に16/2=8移動することになります。
注意として、ダブルサイズフラグを指定した場合、スプライトの中心位置が移動します。スプライトのサイズの半分だけ、右下方向に移動します。この場合は右方向にスプライトサイズ16/2=8、下方向に16/2=8移動することになります。

 EWRAM_CODE void SprSetScale(u32 num, u32 xsc, u32 ysc)
 {
 	OBJAFFINE* rot = (OBJAFFINE*)OAM + num;
 
 	rot->pa = Div(256 * 100, xsc);
 	rot->pb = 0;
 	rot->pc = 0;
 	rot->pd = Div(256 * 100, ysc);
 }

こちらのpa〜pd部分はBGとほぼ同じです。先ほど説明したOBJAFFINE構造体を使用しています。

*** 動作画面 [#m56b4aa9]
#ref(1.png,nolink)

** 履歴 [#r4c6ccd3]
- 2023/05/02
- 2007/09/08

トップ   差分 履歴 リロード   一覧 検索 最終更新   ヘルプ   最終更新のRSS