;============================================================
;	d3module help
;============================================================

%dll
d3module

%ver
1.68

%date
2018/06/01

%author
S.Programs

%note
d3m.hsp をインクルードする。

%url
https://spr.babyblue.jp/
https://spr.babyblue.jp/hsp_d3m.htm

%type
ユーザー拡張命令

%index
d3dist
距離 (ベクトル) の絶対値を求める

%prm
(x, y, z)
x, y, z : 距離を求める x, y, z の値 (0.0)

%inst
入力された x, y, z の距離 (ベクトル) の絶対値 ( sqrt(x*x + y*y + z*z) ) を返す関数型マクロです。返す値の型は実数 (double) です。

z 座標を省略すれば平面座標での距離を求めることができます。

%group
数学サポート命令

%index
d3rotate
平面座標回転演算

%prm
x1, y1,  x0, y0,  va
x1, y1 : 出力値が返る変数 [double]
x0, y0 : 回転させる元のベクトル値
va     : 回転させる角度 [rad]

%inst
平面上のベクトル (あるいは位置) x0, y0 を、原点を中心に va [ラジアン] 回転させたベクトルを求めます。計算結果は、x1, y1 で指定した変数に代入されます。

角度は、ラジアン単位 (2π ≒ 6.2831853 を一回転とする角度単位) で入力します。

%href
d3vrotate

%group
数学サポート命令

%index
d3vrotate
任意軸周りの空間回転演算

%prm
x1,y1,z1, x0,y0,z0, vx,vy,vz, va
x1, y1, z1 : 出力値が返る変数 [double]
x0, y0, z0 : 回転させる元のベクトル値
vx, vy, vz : 回転軸のベクトル
va         : 回転させる角度 [rad]

%inst
ベクトル (あるいは位置) x0, y0, z0 を、原点を通るベクトル vx, vy, vz を軸として、va [ラジアン] 回転したベクトルを求めます。回転方向は、回転軸ベクトルの正方向から見て反時計回りになります。物体をローカル座標で回転させるための行列を求める場合などに応用できます。計算結果は、x1, y1, z1 で指定した変数に代入されます。

角度は、ラジアン単位 (2π ≒ 6.2831853 を一回転とする角度単位) で入力します。回転軸ベクトル vx, vy, vz は、単位ベクトルである必要はありませんが、大きさが 0 の場合はエラーとなります。

%href
d3rotate

%group
数学サポート命令

%index
d3wincx
スクリーン描画時の x 中心座標 (int)

%inst
2D スクリーンに描画するときの中心位置 (整数 ピクセル単位) を表す変数です。この変数は、d3setcam 命令を実行するごとに現在のウィンドウの中心 (ginfo_winx / 2) に設定されます。中心位置を変更したいときは、d3setcam の実行後にこの変数の内容を変更します。

通常は、この変数の値を変更したり参照したりする必要はありません。また、この変数を整数以外の型に変更しないでください。実数など、整数以外の型に変更されると、エラーの原因となります。

%href
d3wincy
d3setcam

%group
3D 制御命令

%index
d3wincy
スクリーン描画時の y 中心座標 (int)

%inst
2D スクリーンに描画するときの中心位置 (整数 ピクセル単位) を表す変数です。この変数は、d3setcam 命令を実行するごとに現在のウィンドウの中心 (ginfo_winy / 2) に設定されます。中心位置を変更したいときは、d3setcam の実行後にこの変数の内容を変更します。

通常は、この変数の値を変更したり参照したりする必要はありません。また、この変数を整数以外の型に変更しないでください。実数など、整数以外の型に変更されると、エラーの原因となります。

%href
d3wincx
d3setcam

%group
3D 制御命令

%index
d3setcam
カメラ位置設定

%prm
x1, y1, z1,  x2, y2, z2, va
x1, y1, z1 : カメラ位置
x2, y2, z2 : ターゲット位置
va         : 視野角スケール (> 0.0) (1.0)

%inst
カメラの座標 x1, y1, z1 と向き (ターゲット位置 x2, y2, z2) 設定します。d3module の描画命令を実行する前に、この命令を使用してカメラの位置を定義する必要があります。

d3module では、+z 方向がカメラの天頂方向となります。イメージとしては、x, y 平面が地平面で、z 方向が上下となります。カメラ位置とターゲット位置の x, y 位置が等しい場合、カメラが正しく設定できませんので注意してください。

パラメータ va によって、視野角スケールを設定できます。省略時のデフォルト値は 1.0 です。この値を大きくすると、値と反比例して画面内に描画される物体が小さくなり、広範囲の物体が描画されるようになります。

%href
d3setlocal

%group
3D 制御命令

%index
d3setlocal
ローカル座標系設定

%prm
px,py,pz, m00,m01,m02, m10,m11,m12, m20,m21,m22
px,  py,  pz   : 原点からの移動位置
m00, m01, m02
m10, m11, m12  : 3x3 座標変換マトリクス
m20, m21, m22

%inst
ローカル座標系を設定します。ローカル座標系は、d3setcam 以外のすべての d3module 命令に適用されます。

この命令を使用することで、d3setcam だけでは実現できなかったさまざまな座標変換設定を行うことができます。ローカル座標系は、d3setcam でカメラ位置を初期化した後に何度でも変更可能で、複数の飛行物体が飛び回る画面の描画などが簡単に行えるようになります。また、ローカル座標系の設定を行っても、d3module の座標変換処理の速度は低下しません。

座標系基準を元のグローバル座標系に戻すには、d3setlocal 0,0,0, 1,0,0, 0,1,0, 0,0,1 としてください。(パラメータを省略した場合、自動的にこの値が入ります。) d3setcam 命令でカメラ位置を設定した後は、ローカル座標系はグローバル座標系と同じ空間としてリセットされます。

・応用例 1 : モデルの位置・姿勢制御
回転したり移動したりする物体 (飛行物体モデルなど) を、自前で回転・移動演算を行うことなく、自由な位置・姿勢で描画できます。px, py, pz は物体の位置、m00〜m22 は物体の姿勢を表現します。座標変換マトリクスの意味合いは下記のようになります。

px,  py,  pz  : 原点からの移動位置
m00, m01, m02 : ローカル座標の +x 方向の単位ベクトル (x, y, z)
m10, m11, m12 : ローカル座標の +y 方向の単位ベクトル (x, y, z)
m20, m21, m22 : ローカル座標の +z 方向の単位ベクトル (x, y, z)

ベクトル m00, m01, m02 と m10, m11, m12 と m20, m21, m22 は、互いに直交する単位ベクトルとなります。

姿勢マトリクスを回転させる場合は、d3vrotate 命令を使うと便利です。
	(例) x, y 方向のベクトルを z ベクトル軸で角度 ang だけ回転 (yow 回転)
	d3vrotate pm00,pm01,pm02,  pm00,pm01,pm02,  pm20,pm21,pm22,  ang
	d3vrotate pm10,pm11,pm12,  pm10,pm11,pm12,  pm20,pm21,pm22,  ang

・応用例 2 : ローカル座標のスケール変更
ローカル座標系のオブジェクトを、グローバル座標系での描画時よりも大きくしたり小さくしたり出来ます。

	; オブジェクトの大きさを x, y, z とも 2 倍に設定
	d3setlocal 0,0,0, 2,0,0, 0,2,0, 0,0,2

	; オブジェクトの大きさを x, y, z とも 0.5 倍に設定
	d3setlocal 0,0,0, 0.5,0,0, 0,0.5,0, 0,0,0.5

・応用例 3 : 座標系変更
d3module のデフォルトの座標系は、右手系で +z 方向を天頂とするものとなっていますが、これを仮想的に変更することが出来ます。たとえば、座標系を左手系の +y 方向を天頂とするものに変更する場合、下記のようにローカル座標系を設定します。

	; 座標系を左手系に変更
	d3setlocal 0,0,0, 1,0,0, 0,0,1, 0,1,0

・応用例 4 : その他の座標変換
その他、オブジェクトを扁平にしたり歪めたりなど、3x3 マトリクスを用いた線形の空間座標変換を自由に行うことが出来ます。

px,  py,  pz  : 原点からの移動位置
m00, m01, m02 : 変換後の x が持つ、変換前の (x, y, z) 成分
m10, m11, m12 : 変換後の y が持つ、変換前の (x, y, z) 成分
m20, m21, m22 : 変換後の z が持つ、変換前の (x, y, z) 成分

	; 描画物体の頂点の z 位置をすべて 0 にする
	d3setlocal 0,0,0, 1,0,0, 0,1,0, 0,0,0

%href
d3setcam

%group
3D 制御命令

%index
d3vpos
d3module 内部のカレントポジション設定

%prm
x, y, z
x, y, z : 設定する位置

%inst
d3module 内部の仮想的なカレントポジションを設定します。この命令で設定した位置は、d3lineto 命令の始点や d3particlem 命令の描画の基準位置となります。

d3pos や d3pset といった命令は、内部的にこの命令を呼び出して動作しています。普通にモジュールを使う上では、この命令を使用する必要はありません。

%group
3D 制御命令

%index
d3getpos
座標変換結果を返す

%prm
vx, vy,  x, y, z
vx, vy  : スクリーン座標 (x, y) が返される変数 [int]
x, y, z : 3D 座標

%inst
入力された 3D 座標に対応するスクリーン座標を返します。

システム変数 stat が 0 の場合、位置がカメラの後ろとなるため座標変換できなかったことを表します。

%group
3D 制御命令

%index
d3pos
カレントポジションを設定

%prm
x, y, z
x, y, z : 設定する座標

%inst
3D 座標に対応する画面上の点にカレントポジションを移動します。

システム変数 stat が 0 の場合、位置がカメラの後ろとなるため座標変換できなかったことを表します。その場合、カレントポジションは変更されません。

%group
3D 制御命令

%index
d3initlineto
d3lineto, d3ribbonto 使用前の初期化

%inst
d3lineto, d3ribbonto を使用する前の初期化を行います。

この命令の直後の d3lineto, d3ribbonto 命令では、描画されずに線の起点のみが設定されます。

%href
d3lineto
d3ribbonto

%group
3D 制御命令

%index
d3pset
点を描画

%prm
x, y, z
x, y, z : 3D 座標

%inst
入力された 3D 座標に対応する画面上の点に pset します。

システム変数 stat が 0 の場合、位置がカメラの後ろとなるため座標変換できなかったことを表します。

%group
ベーシック描画命令

%index
d3lineto
前回描画位置からの線を描画

%prm
x, y, z
x, y, z : 描画先の座標

%inst
前回描画位置からの線分を描画します。

複数の連続線の描画には、座標変換計算が 1 点省略できる分、d3line 命令よりもこの d3lineto 命令を使用したほうが高速です。d3line 命令と違ってクリッピング処理がされませんが、多くの短い線分の描画に向いています。

この命令の連続実行前には、d3initlineto を実行する必要があります。ただし、d3particle や d3circle, d3pset, d3pos, d3getpos などの命令を実行した後であれば、その位置を起点とした直線を描画することができます。

システム変数 stat が 0 の場合、位置がカメラの後ろとなるため座標変換できなかったことを表します。

%href
d3initlineto

%group
ベーシック描画命令

%index
d3line
ライン描画

%prm
x1, y1, z1,  x2, y2, z2
x1, y1, z1 : 3D 座標 点 1
x2, y2, z2 : 3D 座標 点 2

%inst
入力された 3D 座標の 2 点を結ぶラインを描画します。

クリッピング処理を行うため、片方の端がカメラの後ろとなる線分も描画できます。(ただし、その場合は動作が遅くなります。)

システム変数 stat が 0 の場合、位置がカメラの後ろとなるため座標変換できなかったことを表します。

%group
ベーシック描画命令

%index
d3arrow
矢印を描画

%prm
x1, y1, z1,  x2, y2, z2
x1, y1, z1 : 3D 座標 点 1 (矢じり部分)
x2, y2, z2 : 3D 座標 点 2

%inst
入力された 3D 座標の 2 点を結ぶ矢印を描画します。x1, y1, z1 が矢じり部分になります。

システム変数 stat が 0 の場合、位置がカメラの後ろとなるため座標変換できなかったことを表します。

%group
ベーシック描画命令

%index
d3box
ボックスを描画

%prm
x1, y1, z1,  x2, y2, z2
x1, y1, z1 : 3D 座標 点 1
x2, y2, z2 : 3D 座標 点 2

%inst
3D の座標に対応するワイヤーボックスを描画します。

この命令で描画されるボックスは、すべての辺が座標軸と平行なものとなります。

%group
ベーシック描画命令

%index
d3circle
円を描画

%prm
x, y, z, r, f
x, y, z : 中心座標
r       : 半径 ( > 0.0)
f       : 塗りつぶしフラグ (0)

%inst
円を描画します。これは常にカメラ方向を向く円なので、球体に見えます。塗りつぶしフラグが 1 の場合は、円の内部が塗りつぶされます。

システム変数 stat が 0 の場合、位置がカメラの後ろとなるため座標変換できなかったことを表します。

%group
ベーシック描画命令

%index
d3mes
文字列を表示

%prm
str, x, y, z
str     : 表示する文字列
x, y, z : 表示する座標

%inst
指定した 3D 座標に、現在のフォント設定で文字列を表示します。

システム変数 stat が 0 の場合、位置がカメラの後ろとなるため座標変換できなかったことを表します。

%group
ベーシック描画命令

%index
d3particlem
前回描画位置にパーティクル描画

%prm
pid, r
pid : パーティクル ID
r   : パーティクルの半径 ( > 0.0)

%inst
前回 d3module の命令で描画した位置と同じ位置に重ねてパーティクルを描画します。座標変換計算が省略できる分、d3particle より高速に動作します。

この命令を実行する前に、d3mkparticle か d3ldparticle 命令でパーティクルの作成を行ってください。

%href
d3particle
d3particlemr
d3mkparticle
d3ldparticle

%group
拡張描画命令

%index
d3particlemr
前回描画位置にパーティクル描画 (回転指定あり)

%prm
pid, r, a
pid  : パーティクル ID
r    : パーティクルの半径 ( > 0.0)
a    : パーティクルの回転角度 (ラジアン)

%inst
前回 d3module の命令で描画した位置と同じ位置に重ねてパーティクルを描画します。座標変換計算が省略できる分、d3particler より高速に動作します。d3particlemr 命令は、d3particlem 命令の機能に加えて、パーティクルを二次元的に回転して描画する機能を持ちます。(処理が増えるため d3particlem と比べて低速になります)

この命令を実行する前に、d3mkparticle か d3ldparticle 命令でパーティクルの作成を行ってください。

%href
d3particle
d3particler
d3particlem
d3mkparticle
d3ldparticle

%group
拡張描画命令

%index
d3particle
パーティクル描画

%prm
pid, x, y, z, r
pid     : パーティクル ID
x, y, z : パーティクルを描画する 3D 位置
r       : パーティクルの半径 ( > 0.0)

%inst
指定した描画位置に、現在の gmode 設定にしたがってパーティクルを描画します。

この命令を実行する前に、d3mkparticle か d3ldparticle 命令でパーティクルの作成を行ってください。

%href
d3mkparticle
d3ldparticle
d3particler
d3particlem
d3particlemr

%group
拡張描画命令

%index
d3particler
パーティクル描画 (回転指定あり)

%prm
pid, x, y, z, r, a
pid     : パーティクル ID
x, y, z : パーティクルを描画する 3D 位置
r       : パーティクルの半径 ( > 0.0)
a       : パーティクルの回転角度 (ラジアン)

%inst
指定した描画位置に、現在の gmode 設定にしたがってパーティクルを描画します。d3particler 命令は、d3particle 命令の機能に加えて、パーティクルを二次元的に回転して描画する機能を持ちます。(処理が増えるため d3particle と比べて低速になります)

この命令を実行する前に、d3mkparticle か d3ldparticle 命令でパーティクルの作成を行ってください。

%href
d3mkparticle
d3ldparticle
d3particle
d3particlemr

%group
拡張描画命令

%index
d3mkparticle
パーティクル作成

%prm
pid, r, g, b, arry
pid     : パーティクル ID (0 〜)
r, g, b : 作成するパーティクルの色 (RGB)
arry    : パーティクル形状 (default = 円形)

%inst
色や形状を指定してパーティクルを作成します。この命令を実行すると、指定した ID のパーティクルが描画できるようにます。(描画ではなく、パーティクル ID の登録を行います。)

この命令は実行にはやや時間がかかるため、初期化処理時にまとめて実行するようにしてください。パーティクル描画機能を使用すると、スクリーン ID 27 と 29 が d3module で内部的に使用されます。

第 1 パラメータ pid で、作成するパーティクルの ID を指定します。パーティクル ID の上限は特にありませんが、d3module 内部でのパーティクル画像の保持のため、使用した最大 ID * 90KB 程度のメモリが消費されますので注意してください。

第 2〜4 パラメータ r, g, b で、パーティクルの色を指定します。RGB の値が 255 よりも大きい場合は、飽和計算で処理されます。(白飛びしたような画像になります。)

第 5 パラメータ arry にパーティクル形状の数列を格納した整数型の配列変数を指定することによって、さまざまな形状のパーティクルを作成できます。省略した場合、円形のパーティクルが作成されます。

arry 配列は、[繰り返し数], [シーケンス長], [半径シーケンス 0], [半径シーケンス 1] ... の順番で格納されます。[半径シーケンス (0, 1, ...)] には、パーティクルを多角形とみなしたときの、頂点の中心からの半径をプロットしていきます。値は、パーティクルの半径に対するパーセント値を整数で指定します。[シーケンス長] は、配列に格納された [半径シーケンス] の長さを指定します。[繰り返し数] は、半径シーケンスの繰り返し回数を指定します。

たとえば、周囲に 10 個のギザギザがある星型のパーティクルを作成する場合、配列は arr = 10, 2, 100, 80 のようになります。正三角形のパーティクルでは、arr = 3, 1, 100 のようになります。

%sample
#include "d3m.hsp"

	; パーティクル作成

	; デフォルト パーティクル
	d3mkparticle  0,  255, 255, 255

	; デフォルト パーティクル (色飽和サンプル)
	d3mkparticle  1,  333, 555, 777

	; ギザギザ パーティクル
	arr = 10, 2, 100, 80
	d3mkparticle  2,  999, 255, 255,  arr

	; プロペラ？
	arr = 6, 6,  100, 90, 80, 70, 60, 50
	d3mkparticle  3,  255, 999, 255,  arr

	; 表示
	color : boxf
	color , 255
	gmode 5, , , 255

	d3setcam 0, -100, 0

	repeat 4
		x = cnt * 20 - 30
		y = 0
		z = 0

		d3mes "pid " + cnt, x, y, z + 20
		d3particle cnt, x, y, z, 10
	loop

%href
d3ldparticle
d3particle

%group
拡張描画命令

%index
d3ldparticle
パーティクル画像ロード

%prm
pid, sid, x, y, w, h
pid  : パーティクル ID (0 〜)
sid  : パーティクルをロードするスクリーンのウィンドウ ID
x, y : ロードもとの左上座標
w, h : ロードする大きさ

%inst
指定したスクリーン上の画像を使ったパーティクルを作成します。この命令を実行すると、指定した ID のパーティクルが描画できるようにます。(描画ではなく、パーティクル ID の登録を行います。)

この命令は実行にはやや時間がかかるため、初期化処理時にまとめて実行するようにしてください。パーティクル描画機能を使用すると、スクリーン ID 27 と 29 が d3module で内部的に使用されます。

%href
d3mkparticle
d3particle

%group
拡張描画命令

%index
d3texture
四角形面に画像を貼り付け描画

%prm
ax, ay, az, sid, x1, y1, w1, h1, div
ax, ay, az : 四角形の頂点の x, y, z を格納した配列変数
sid        : 貼り付ける画像のあるスクリーンの ID
x1, y1     : 貼り付けもとの左上位置 [ピクセル]
w1, h1     : 貼り付ける画像の幅と高さ [ピクセル]
div        : 四角形の内部分割数 (1)

%inst
四角形の面に、現在の gmode で画像を貼り付けて表示します。

ax, ay, az は、4 つの頂点の座標を 左上、右上、右下、左下 の順番で格納したものとなります。

画像拡縮の描画品質や、四角形がねじれる形になる場合の挙動は、HSP の gsquare 命令の実装に従います。

引数 div に 2 以上の値を指定すると、四角形の各辺を分割して座標変換・描画を行います。たとえば、2 を設定した場合、四角形は「田」の字ように 4 つの四角形・9 頂点に分割され、描画されます。実行速度は犠牲になりますが、これによって奥行き感のあるテクスチャのマッピングが可能になります。四角形がねじれる形になっている場合、div 分割数によってはきれいな曲線で描画できるようになります。ただし、内部で z ソートを行っていないため、奥の頂点が手前に表示される問題が発生する可能性がありますので注意してください。

頂点がカメラの裏側の領域にある場合、その点を頂点に持つ四角形は描画されなくなります。

%href
d3square

%group
拡張描画命令

%index
d3square
四角形面を塗りつぶし描画

%prm
ax, ay, az
ax, ay, az : 四角形の頂点の x, y, z を格納した配列変数

%inst
四角形の面を、現在の選択色と gmode で塗りつぶします。

ax, ay, az は、4 つの頂点の座標を 左上、右上、右下、左下 の順番で格納したものとなります。

四角形がねじれる形になる場合の挙動は、HSP の gsquare 命令の実装に従います。

また、各頂点のうちどれか 1 箇所でもカメラの裏側の領域にあると、図形全体が描画されなくなります。

%href
d3texture
d3ribbonto

%group
拡張描画命令

%index
d3ribbonto
リボン状に連続する四角形面を塗りつぶし描画

%prm
x1, y1, z1, x2, y2, z2
x1, y1, z1 : 描画先位置 1
x2, y2, z2 : 描画先位置 2

%inst
前回 d3ribbonto で指定した位置と、今回指定した (x1, y1, z1), (x2, y2, z2) の 4 点を頂点とする 4 角形を、現在の選択色と gmode で塗りつぶします。この命令を連続して実行することで、リボン状に連続する四角形面を、描画することが出来ます。この命令の連続実行前には、d3initlineto を実行する必要があります。

リボン状に連続する複数の面の描画では、座標変換計算が 2 点省略できる分、d3square 命令よりもこの d3ribbonto 命令を使用したほうが高速です。また、この命令を使用することで、スクリプトを簡単化することが出来ます。

%href
d3initlineto
d3square

%group
拡張描画命令

%index
d3timer
ms タイマー

%prm
()

%inst
Windows が起動してからの経過時間を ms (ミリ秒, 1/1000 秒) 単位で返します。

この関数は、Win32API の timeGetTime() そのものとなっています。

%group
タイマー命令

%index
d3getfps
現在のフレームレート (fps)

%prm
()

%inst
現在のフレームレート (fps 単位) を返します。

この関数を正しく動作させるためには、1 フレームごとに 1 回だけ毎回呼び出す必要があります。

%group
タイマー命令

