★ libgv リファレンス



--------------------------------------------------------------------------------

■ 概要

--------------------------------------------------------------------------------



libgvはメモリ管理や実行単位の制御など、ゲームの一番基本的な部分の管理を

行なうライブラリである。

以下の機能を持つ。



・メモリ管理 ( MALLOC型／freelist型)

・データリスト管理

・実行単位管理( ACTOR system )

・メッセージ管理

・パッドユーティリティ

・ベクトルユーティリティ

・デバッグユーティリティ



--------------------------------------------------------------------------------

■メモリ管理

--------------------------------------------------------------------------------



16バイトタグ・双方向リスト型メモリ管理でメインの管理(GV_AllocMemory系)を

行ない、局所的なデータブロック管理用に、Freeリストのみで管理する

メモリ管理ライブラリ(memlist系)を持つ。



実際にPS２の実メモリをどう設定するかは、libgv.cnfで定義している。



・GV_AllocMemory系



メイン管理は、MAX_MEMSYSで定義されるだけのメモリシステムを管理できる。

各メモリシステムはID（０からの通し番号）で管理される。

メインに使用されるメモリシステムに関しては、GV_Mallocなどのユーティリティで

簡易にアクセスできる。



基本的にはalloc時に最小16バイトから指定サイズまでのアライメントを設定できる。

管理用タグのサイズは16バイト。双方向リンクリストと、allocを高速化するための

Freeblockリスト用のポインタを持つ。



また、DMA系のデータ用に、遅延Free機能を持つ。GV_FreeMemory2で解放されたメモリは、

実際には次のフレームの頭(gvd実行中)に解放される。



void GV_InitMemoryBlock( int id, int type, void *top, int size );

void GV_InitMemorySystemAll( void );

void GV_CleanMemorySystem( void );		// delay freeの実行



void *GV_AllocMemory( int id, void **ptr, int size, int align );

void GV_FreeMemory( int id, void *ptr );

void GV_ZeroMemory( void *to, int size );

void GV_ResizeMemory( int id, void *ptr, int size );

void GV_FreeMemory2( int which, void *addr );	// delayed free予約



int GV_GetMaxFreeMemory( int id );

int GV_GetFreeMemorySize( int id );



// ユーティリティ

void *GV_Malloc( int size );

void GV_Free( void *addr );

void GV_Resize( void *addr, int size );

void GV_DelayedFree( void *addr );



・memlist系



ローカルなメモリブロック内でさらにメモリ管理をするための機構。

memlist.hをincludeする。

管理するメモリブロックに対し、MEMLIST構造体をユーザー側で用意する。



管理用タグをFreeBlockにしか持たないタイプであるため、Freeする時にサイズの指定が

必要になる。



void GV_MlBufferInit( MEMLIST *list, char *name, void *top, void *bottom, int align );

void *GV_MlMalloc( MEMLIST *list, int size );

void GV_MlFree( MEMLIST *list, void *free, int size );



・常駐データ系



常駐データは単純に登録順に確保される。

途中で確保や解放されることは考えていない。



void GV_InitResidentMemory( void );

void *GV_AllocResidentMemory( int size, int id );

void GV_ReinitResidentData( void );





--------------------------------------------------------------------------------

■データリスト管理(CACHE SYTEM)

--------------------------------------------------------------------------------



CACHEと呼ばれる機構で、データのアドレスとIDを管理している。

各データはファイル名から生成される24Bitのハッシュコード（以下文字列ID）で管理される。

データは今の実装では512個まで登録可能。

また、拡張子によって、登録された初期化関数を自動的に呼び出す機能もある。

また、データによっては常駐領域にロードされ、各ステージで再設定される。



// キャッシュID算出

int GV_StrCode( char *string );

int GV_CacheID( int root_id, int spec );

int GV_CacheID2( char *root_name, int spec );

int GV_CacheID3( char *name );



// キャッシュへデータ登録／取得

void GV_InitCacheSystem( void );

void GV_FreeCacheSystem( void );

void *GV_GetCache( int id );

int GV_SetCache( int id, void *buf );



// 初期化関数登録／初期化

void GV_ResetLoader( void );

void GV_SetLoader( int spec, GV_LOADFUNC init );

int GV_LoadInit( void *data, int name, int cache_mode );



--------------------------------------------------------------------------------

■実行単位管理(ACTOR SYSTEM)

--------------------------------------------------------------------------------



各処理単位のプログラムをGV_ACT構造体で管理する。



基本的には、GV_ACT構造体を先頭に持つWorkという構造体を定義し、

その中にそのACTORが必要な情報をすべて入れる。

actとして指定された関数の引数に、そのworkという構造体のアドレスが

渡されるので、それを使って処理を行なうという形式になる。



基本的には、以下の手順で呼び出す。

LEVELは実行LEVEL（後述）



typedef struct {

	GV_ACT actor;

	...

} Work;



void *NewFunc( ... )

{

	Work *work;



	/* ワークの確保と初期設定、リンクリストへの追加 */

	work = ( Work * )GV_NewActor( LEVEL, sizeof( Work ) );

	if( work != NULL ){

		/* 実行関数／終了関数の設定 */

		GV_SetActor( work, Act, Die );



		/* ここで work を初期設定する */

	}

	return work;

}





ACTORは以下の機能を持つ

・メモリ確保／初期化

・act, die関数による各処理の実行

・終了処理

・level, priorityによる実行順序の制御

・level毎に設定されるPAUSE処理

・各ACTORごとのRESET処理

・sleep, wakeupによる実行時間の節約(message待ち等)

・killメッセージを自動処理

・エフェクトのメモリ制限



また、拡張されたGV_ACT_EX構造体を使うことで、以下の機能が使用可能になる。

・ACTOR間の親子関係の構築

・親子間でのシグナル関数を使った情報のやりとり



ACTOR SYSTEMのデバッグ支援機能としては

・ACTORを登録したファイル名の記録

・実行にかかった時間(HSYNC)の記録

を行ない、それをターミナルにダンプすることができる。



使用上の注意点として以下をあげる。

・Die関数中で他のキャラクタを起動しない。



以下、それぞれを説明する。



・メモリ確保／初期化



自前でGV_ACT構造体を初期化した場合は、

void GV_InsertActor( int level, void *work );

void GV_InsertActorPriority( int level, void *work, int prio );



で、リンクリストに接続できる。

void GV_SetActorKillLevel( void *this, int kill_level );

void GV_SetActorClass( void *this, int class );

で、メンバのそれぞれの値を設定。

基本的なものはユーティリティ関数

void *GV_CreateActor( int level, int class, int size, int prio );

で、設定できる。

ユーザープログラムからは、以下のマクロを使うことを推奨

#define GV_NewActor( _l, _s ) GV_CreateActor( _l, GV_CLASS_OBJECT, _s, 0 )

#define GV_NewActorPrio( _l, _s, _p ) GV_CreateActor( _l, GV_CLASS_OBJECT, _s, _p )

#define GV_NewEffect( _l, _s ) GV_CreateActor( _l, GV_CLASS_EFFECT, _s, 0 )

#define GV_NewEffectPrio( _l, _s, _p ) GV_CreateActor( _l, GV_CLASS_EFFECT, _s, _p )



・act, die関数による各処理の実行



GV_ACTには、少なくとも

void ( *act )( GV_ACT *work );	// 1loopに1回呼び出される。

void ( *die )( GV_ACT *work );	// 終了時に呼び出される。

という2つの関数へのポインタを持ち、この関数をGV_ExecActorSystem内から

呼び出すことで各処理を実行する。

act関数を処理の途中で切替えることも可能。



void GV_SetActor( void *this, void *act, void *die );

で設定する。

ACTORがDieした時にWorkそのものをFreeするための関数へのポインタをGV_ACT内に持っている。

GV_CreateActor(GV_NewActor, GV_NewEffect)で初期化されたものはGV_Freeがそこに設定されている。

自前で確保したworkの場合は、

void GV_SetActorFreeFunc( void *this, GV_FREEFUNC free );

で関数を設定できる。freeがNULLの時は終了時になにもしない。

void GV_ChangeActFunc( void *this, void *func );

でactを切替える。



・終了処理



void GV_DestroyActor( void *this );

で「自分自身」を終了させることができる。他のACTORをこれで終了させるのは禁止。

れを実行すると、「次のターン」でDieが実行されてリンクリストから切り離される。



void GV_DestroyOtherActor( void *target );

は、他のACTORを終了させるための関数。

リンクリストをたどって、存在をチェックしてから終了処理を行なう。

必ずこれを使うこと。



void GV_DestroyOtherActorQuick( void *target );

は、他のACTORを直ちに終了させる関数。

「自分のすぐ次」のACTORを終了させると問題が起こるので、基本的に実行レベルの

異なるACTORに対して使用すること。



・level, priorityによる実行順序の制御



ACTORは実行順番を規定するためのlevelとpriorityの2つの属性を持つ。

level毎にACTORのリストが作られ、登録時にpriorityの小さい順に

適切な場所に挿入される。priorityを見ない登録関数もあり、

その場合はリストをたどることなく、そのレベルの最初に登録される。

(初期化時間を最小化するため)

NewActor系はprioはみず、NewActorPrioを使うと設定できる。



・level毎に設定されるPAUSE処理



各レベルに対し、system/libgv/actor.c内でPAUSEフラグが定義される。

PAUSEは、設定された値とGV_PauseLevelとの論理積が０以外であればそのレベルの

実行を行なわれないことで、実現している。



void GV_PauseOnActorSystem( int pause );

void GV_PauseOffActorSystem( int pause );

void GV_PauseToggleActorSystem( int pause );



・各ACTORごとのRESET処理



RESETに関しては、各ACTORのGV_DestroyActorSystemの引数と各GV_ACTのkillメンバに

設定された値とのANDが真ならばそのACTORをDestroyする。ステージ切替えなどの時に

すべてのキャラを終了させる時などに用いられる。



void GV_DestroyActorSystem( int kill );



・sleep, wakeupによる実行時間の節約(message待ち等)



ACTを実行することは、ICACHEの無駄になるので、GV_ACT構造体のclassメンバに

WAITのフラグを設け、これが立っている時にはACTを実行しないようになっている。

このフラグをセットするには、GV_SleepActor(), クリアするには、GV_WakeupActorを使う。

ユーザービットは2つまで空いているのでそれを使うことができる。

GV管轄のメッセージ待ちとGAME管轄のマップ切替え待ちにはそれぞれビットを割り当ててあり、

それぞれ、GV_WaitMessage, GM_WaitMapChangeで待ち状態になり、システムで自動的にwakeupされる。



void GV_SleepActor( void *this, int waitflag );

void GV_WakeupActor( void *this, int waitflag );

void GV_WaitMessage( void *this, int name );



・killメッセージを自動処理



初期化時にGV_SetActorMessageKill( this, name )を実行しておくことで、

GV_ACTのclassメンバにフラグを立て、kill message( 0x00FFFFFF )を自動的に

処理することができる。ただし、これが受け付けられたときは、Actを通らずにDieに

移行するので注意すること。

なお、gclでkill messageを書く時にはきちんとcommand.defで定義しておく必要がある。



void GV_SetActorMessageKill( void *this, int name );



・エフェクトのメモリ制限



ユーティリティ関数GV_NewEffectを使ってキャラを設定すると、GV_ACTのclassメンバに

GV_CLASS_EFFECTビットを立て、GV_CreateActor内でメモリチェックを行ない、

GV_MEM_EFFECT_LIMIT_SIZE (libgv/actor.c内で定義:現状は128K)以上の空きがない場合は

起動しない(NULLを返す)ようにする。これにより、必ず起動しなければならないACTORの

起動を妨げないことが保証できる。



#define GV_NewEffect( _l, _s ) GV_CreateActor( _l, GV_CLASS_EFFECT, _s, 0 )

#define GV_NewEffectPrio( _l, _s, _p ) GV_CreateActor( _l, GV_CLASS_EFFECT, _s, _p )



・ACTOR間の親子関係の構築



GV_ACT構造体をGV_ACT_EX構造体にし、GV_ActorEX()で初期化すると、

GV_SetActorChild( parent, child )を使って、ACTOR同士を親子として定義できるようになる。

親子間ではシグナルを使って情報のやりとりができる。ただし、親子は、あくまでリンクリスト

としてつながっているという意味のみで、実行順番についてはなにも関係がないことには

注意すること。

親がDieした場合は、子にGV_SIGNAL_KILLというシグナルが発生する。このシグナルでは、

デフォルトのシグナル関数で自分にGV_DestroyActorをかけるようになっており、

これによって、「親が死んだら子も死ぬ」を実現している。

したのシグナル機能を使うために、シグナル関数を自前で登録した場合、

GV_SIGNAL_KILLのシグナルに対する処理を書かなければならない。

（ただし、わざと書かないことで、親が死んでも死なない子も作れる）



#define GV_ActorEX( _act )

void GV_SetActorChild( void *parent, void *child );

void GV_DestroyChild( void *this );



・親子間でのシグナル関数を使った情報のやりとり



親子の間では、

GV_CallChildSignalFunc() で子のsignal関数を、

GV_CallParentSignalFunc()で親のsignal関数を

呼び出し、通信することができる。

signalに関しては、GV_SIGNAL_KILL, GV_SIGNAL_DIEが予約済み。

valueは、signalに関して付加情報を割り当てることができる。

デフォルトのシグナル関数として、GV_DefaultSignalFuncが設定されている。

独自のシグナルを使うには、GV_SetActorSignalFuncをつかって、signal関数を設定し、

その中でsignal, valueに応じて処理を行なう。thisには、そのACTORのworkの

先頭アドレスが入ってくる。



void GV_CallChildSignalFunc( void *this, int signal, int value );

int GV_CallParentSignalFunc( void *this, int signal, int value );

int GV_DefaultSignalFunc( void *work, int signal, int value );



・ACTORを登録したファイル名の記録



DEBUG_MODEマクロをONにした状態でコンパイルされると、GV_ACT構造体にデバッグメンバが

追加され、ACTORの初期化時にそのファイル名が記録されるようになる。

これは、ACTの実行時に変数に代入され、ハングアップした時にどのACTの実行中かを

示すことができる。



・実行にかかった時間(HSYNC)の記録



デバッグメンバがある状態では、各ACTの実行時間をHSYNC単位で計測し、累積している。

GV_DumpActorSystem内で、現在のACTORのリストをその平均実行時間とともに出力する。



void GV_DumpActorSystem( int mode );



・Die関数中で他のキャラクタを起動しない。



Die関数中で他のキャラクタの起動関数を呼ぶのは禁止する。

ステージのリセット時にすべてのキャラクタがDieを呼ぶが、そのときに

新規キャラクタが発生するとまずい状況になるからである。

それを防ぐために以下の関数を用意してある。

int GV_IsFollowDestroy( void *this ) ;	// 親が死んだ時に真

int	GV_IsStageDestroy( void *this ) ;	// GV_DestroyActorSystemで死んだ時に真



--------------------------------------------------------------------------------

■メッセージ管理(MESSAGE SYSTEM)

--------------------------------------------------------------------------------



各ACTOR間でのデータのやりとりのためにメッセージシステムが用意されている。

このメッセージシステムは以下の特徴を持つ。



・メッセージボックスに対し、名前IDで登録／取得を行なう。

  同じ名前を持つものに対して、ブロードキャスト的に送られる。

・int複数個のデータをやりとりする。

・ACTORの実行順番によらず、あるフレームで送られたデータは、その次のフレームでのみ

  取得できる。



メッセージのやりとりは、以下の構造体で行なわれる。



typedef struct {

	int address;		/* 宛先 */

	short _len;			/* 内部使用 */

	short _flag;		/* 内部使用 */

	int *message;		/* メッセージ列へのポインタ */

	int message_len;	/* メッセージの数 */

} GV_MSG;



送る側はaddress, message, message_lenを適切に指定していなければならない。

messageは、SendMessage中で内部のバッファにコピーされる。



関数は以下の通り。



void GV_ClearMessageSystem( void ); // システム使用。バッファのフリップ



int GV_SendMessage( GV_MSG *send );

int GV_ReceiveMessage( int address, GV_MSG **msg_ptr ); // 存在するメッセージの数を返す



GV_ReceiveMessage で取得されたGV_MSG *はその時に存在するメッセージ列の先頭。

同一 address(名前ID)に送られたメッセージはメモリ的に連続していることが

保証されている。



--------------------------------------------------------------------------------

■パッド管理(PAD SYSTEM)

--------------------------------------------------------------------------------



PlayStation2のパッド情報を管理するためのライブラリ群。

DualShock2を基本として考えている。



以下の構造体が、gvdの中で毎フレーム更新されている。



typedef struct {

	short type;					/* ペリフェラルタイプ */



	/* デジタルデータ */

	unsigned short status;		/* 状態 */

	unsigned short press;		/* press trigger */

	unsigned short release;		/* release trigger */



	short dir;					/* 十字キー入力方向 */

	short analog_input;			/* アナログ入力の有無 */



	unsigned char right_dx;		/* アナログ */

	unsigned char right_dy;

	unsigned char left_dx;

	unsigned char left_dy;



	unsigned char pressure[ 12 ];		/* 感圧情報へのポインタ */



	int	flag ;			/* パッド状態フラグ */

} GV_PAD;



extern GV_PAD 	GV_PadData[ GV_PAD_MAX ];

extern GV_PAD	GV_PadDataDirect[ GV_PAD_MAX ] ;



以下の関数がシステムから呼び出され、更新を行なう。



void GV_InitPadSystem( void );

void GV_ResetPadSystem( void );

void GV_UpdatePadSystem( void );



dirメンバについては、以下の関数でどの方向を０にするか設定できる。

カメラ位置等で上方向をずらす時に使用する。



int	GV_GetPadOrigin( void ) ;

void GV_OriginPadSystem( int org );



パッドの振動を設定する関数。



void GV_SetPadVibration1( int which, int value );

void GV_SetPadVibration2( int which, int value );



#ifdef DEBUG_MODE

int GV_PadHangupCheck( void );

#endif



パッドをシステム的にリリース状態にしたり、あるボタンをマスクしたりする関数群。



void	GV_PadReleaseOnSystem( int ) ;

void	GV_PadReleaseOffSystem( int ) ;

void	GV_PadReleaseOn( int ) ;

void	GV_PadReleaseOff( int ) ;

void	GV_PadReleaseOnScn( int ) ;

void	GV_PadMaskOn( int, int ) ;

void	GV_PadMaskOff( int ) ;

void	GV_PadMaskOnScn( int, int ) ;

void	GV_PadPressScn( int, int ) ;

void	GV_PadMaskCancelScn( int, int ) ;



void	GV_PadSetDemoData( int, int, void * ) ;



--------------------------------------------------------------------------------

■ベクトルユーティリティ

--------------------------------------------------------------------------------



歴史的経緯により、ベクトル系関数群が一部GVにある。

これについては、

system/libgv/util.h

を参照のこと。



--------------------------------------------------------------------------------

■デバッグユーティリティ

--------------------------------------------------------------------------------



PlayStation2のデバッグレジスタ等を使用するためのマクロが、

system/libgv/break.h

にある。

データリード／ライト／バリュー例外の設定をサポート。



ASSERT, HANGUP

等のマクロをlibgv.hで定義している。

これらのマクロは、DEBUG_MODEマクロを定義していなければ消える。

