LScript Ver. 2.0 日本語マニュアル ファイルオブジェクト LScriptの概要 - - - - - - - - - - - - - - - - - - - - - -1 ファイルの名称 - - - - - - - - - - - - - - - - - - -13 LScriptの実行 - - - - - - - - - - - - - - - - - - - - - -1 ユーザー作成のオブジェクトエージェント 15 本章で使用する書式 - - - - - - - - - - - - - - - - -2 本書で使用する書体 - - - - - - - - - - - - - - - - -2 - - - - - - - - - - - - - -12 ビルトイン関数 - - - - - - - - - - - - - - - - - - - -15 事前定義値 LScriptの内部 - - - - - - - - - - - - - - - - - - - - - -3 - - - - - - - - - - - - - - - - - - - - - -15 イメージフィルター - - - - - - - - - - - - - - - - - -16 mainプロシージャ - - - - - - - - - - - - - - - - - -3 プロシージャルテクスチャ - - - - - - - - - - - - -16 ユーザー定義プロシージャ - - - - - - - - - - - -3 変位マップ - - - - - - - - - - - - - - - - - - - - - - - -16 ライブラリ オブジェクト置換 - - - - - - - - - - - - - - - - - - -16 - - - - - - - - - - - - - - - - - - - - - - -4 LScript言語の構造 - - - - - - - - - - - - - - - - - - -5 内部コマンド - - - - - - - - - - - - - - - - - - - - -16 言語で使うキーワード - - - - - - - - - - - - - - -5 LightWave Modelerコマンドおよび関数 - -25 LScript内のコメント - - - - - - - - - - - - - - - -5 LightWave Layoutコマンドおよび関数 - - -48 LScriptの制御構造 - - - - - - - - - - - - - - - - - - -6 レイアウトのLScript - - - - - - - - - - - - - - - -48 LScriptのデータ型 - - - - - - - - - - - - - - - - - - -9 レイアウトのスクリプト構造 数値 - - - - - - - - -48 共有関数 - - - - - - - - - - - - - - - - - - - - - - - -49 - - - - - - - - - - - - - - - - - - - - - - - - - - - -9 文字列 - - - - - - - - - - - - - - - - - - - - - - - - - - -9 レイアウトグローバル 配列 シーンのパブリック情報 - - - - - - - - - - - - -50 - - - - - - - - - - - - - - - - - - - - - - - - - - - -9 - - - - - - - - - - - - - -50 - - - - - - - - - - - - - -10 インデプスのオブジェクト - - - - - - - - - - -52 ベクトル - - - - - - - - - - - - - - - - - - - - - - - -11 リクエスタインタフェースの拡張 - - - - - -54 ポイントID/ポリゴンID - - - - - - - - - - - - - -11 アーキテクチャの詳細 nil - - - - - - - - - - - - - - - - - - - - - - - - - - - - -11 LS/IF(イメージフィルタ) 新バージョンでの変更点 プロセスID - - - - - - - - - - - - - - - - - - - - - -12 LScriptのオブジェクトエージェント - - - - -12 - - - - - - - - - - - - - -55 - - - - - - - - - -55 イメージバッファの選択 - - - - - - - - - - - - - -56 イメージバッファの処理 - - - - - - - - - - - - - -57 イメージデータのキャッシュ化 –目次i– - - - - - - - - -58 LS/IFロジックの流れ - - - - - - - - - - - - - - - - -58 モニタの使用 BobObjの実験 - - - - - - - - - - - - - - - - - - - - - -82 - - - - - - - - - - - - - - - - - - - - - -59 プラグイン間通信 - - - - - - - - - - - - - - - - - -83 LS/PT(プロシージャルテクスチャ) - - -59 適格データタイプ - - - - - - - - - - - - - - - - - - -85 シェーダー関数 - - - - - - - - - - - - - - - - - - - - -60 Macintoshに関するLScriptの注意事項 テクスチャの処理 - - - - - - - - - - - - - - - - - - -60 ShaderObjectメソッド - - - - - - - - - - - - - - - -61 LScriptプリプロセッサ LS/DM(ディスプレイスメントマップ) -62 LS/IA(アイテムアニメーション) - - -86 - - - - - - - - - - - - - -86 LScriptプリプロセッサ - - - - - - - - - - - - - - - -86 - - - - -62 コンパイラディレクティブ - - - - - - - - - - - - -86 モーションの処理 - - - - - - - - - - - - - - - - - - -62 Preprocessor Macros - - - - - - - - - - - - - - - - -89 LS/OR(オブジェクトリプレイスメント) 63 High Visibility - - - - - - - - - - - - - - - - - - - - - - -89 LS/GN(レイアウトジェネリック) ジェネリックスクリプトの構築 - - - -63 Ver.2.0での変更点 - - - - - - - - - - - - - - - - - -90 - - - - - - - - -64 リビジョン履歴 - - - - - - - - - - - - - - - - - - - -99 ジェネリック関数 - - - - - - - - - - - - - - - - - - -64 ベータ 7: - - - - - - - - - - - - - - - - - - - - - - -99 LScriptの拡張:ネイティブコードとのリンク 65 ベータ 6: - - - - - - - - - - - - - - - - - - - - - - -99 メッセージの表示 - - - - - - - - - - - - - - - - - -66 ベータ 5:LScript v2.0 ベータ 5 LScriptへのエクスポート関数 - - - - - - - - -69 ベータ 4: - - - - - - - - - - - - - - - - - - - - - -102 Makefileの使用 - - - - - - - - - - - - - - - - - - - -69 共有ライブラリの使用 ベータ 3: - - - - - - - - - - - - - - - - - - - - - -103 - - - - - - - - - - - - - -70 ベータ 2: - - - - - - - - - - - - - - - - - - - - - -105 LScript共有ライブラリの拡張 - - - - - - - - - -71 "lscript.h"への拡張 索引 - - - - - - - - - - - - - - - - - - - - - - - - - - -107 - - - - - - - - -71 複数のインスタンスのハンドリング BobObjシェル LScript最新情報について - - - - - - - - - - - -105 - - - - - - - - - - - - - - - - -71 プライベートクラスメソッド - - - - - - -99 - - - -73 - - - - - - - - - - - - - - - - - - - -74 オブジェクトエージェントの共有ライブラリの作成 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -81 –目次ii– LScriptの概要 LScriptの実行 LScript(エル・スクリプト)はNewTek社のLightWave用に特 LScript Scripting Pluginを起動すると、ファイル選択ダイアロ 別に設計されたスクリプティング・プラグインです。 グボックスが現れます。最初にLScriptスクリプティングプラ スクリプトのプログラミングは初めてという方や、また グインを起動した場合、このダイアログボックスには使用し Amiga版LightWaveの時代から AREXXをお使いになっている ているモデラー・コンフィギュレーションファイル 方も、LightWaveスクリプトをプログラムする方にはLScript (LWM.CFG)により指定されたプラグイン・ディレクトリが はたいへん便利なものです。すでに使用できるLScriptsの実例 表示されます。次にプラグインを呼び出した場合は、最後に が豊富にありますから、本章をお読みになる前にそれをお試 選択したスクリプトを呼び出したディレクトリが表示されま しください。また、CやC++といった一般的なプログラミング す。 言語での経験があれば、LScriptの全体構造はすぐにご理解い ファイル選択ダイアログを使うと、実行するLScriptファイル が入っているディレクトリを表示することができます。スク ただけるでしょう。 リプトを選択すると、LScriptは、そのスクリプトをコンパイ ル し、コンパイル中にエラーがなければ、続いてスクリプト を実行します。 LScriptスクリプティングプラグインはまた、プラグインサー バーとしても機能しますから、スクリプトを直接Customメニ ューに追加することが可能です。その後、LScript項目を選択 すると、選択されたスクリプトでLScriptスクリプティングプ ラグインが実行されます。LScriptをCustomメニューに追加す るには、 C u s t o mメニューにあるビルトインコマンドC o n f i gure Listを使うか、添付のLScript listadd.lsを実行してください。 サーバーに関連する項目をこの方法でCustomメニューに追加 した場合は、かならずそれらをファイルに保存してください。 こうしておけば、開始するたびにLightWaveモデラーがカス タムマクロを自動的に再ロードします。この機能の詳細につ いては、本マニュアルの『LightWaveモデラー』の章をご覧 ください。 –1– 本章で使用する書式 void 本ユーザーガイドのこれ以降のセクションでは、次のような 識別子を使って各コマンドの呼び出し構文を表現します。次 戻り値を持たない場合、または受け取るパラメータがない場 に、それぞれの意味をまとめます。 合。 数値 型[#] 小数値を含む数値データ型。また、符号インジケータと指数 各タイプのデータ型の " # "個のエレメントに対する配列参照 指定子を処理できます。 ("#"がなければ、可変サイズ) 整数 [] 小数部の値なしとして書かれる数値データ型。また、符号イ 関数のオプション引数で、省略可能なものです。 ンジケータを処理できます。 <データ型> 文字列 上記のデータ型の単一インスタンス 連続した A S C I I文字列からなるデータ型。二重引用符(")で 囲みます。 status コマンドのエラーステータス(autoerrorプラグマが使われて ベクトル いない場合、これが使われていればケースエラーは捕捉され 山形カッコ(<>)で囲み、カンマで区切った3つの数値(例: て実行が停止します。 ) <15,34,5.34>)からなるデータ型。 ブール ポイントID TRUE/true/!0(真)またはFALSE/false/0(偽) ポイント識別子 本書で使用する書体 ポリゴンID ポリゴン識別子 ,,, 上記データ型をカンマで区切り、複数並べたもの。または、 単一のデータ型の複数を表現したもの。 –2– 明朝体 解説などの本文に使用します。 ゴシック体 重要事項などに使用します。 monospace LScriptスクリプト本文に使用します。 下線 スクリプトに対する注釈に使用します。 function LScriptの関数名やキーワードに使用します。 LScriptの内部 これからのセクションでは言語構文、変数、コントロール構 ワードで開始し、終了カッコの代わりにキーワードで終わる 造、コマンドおよび関数を確認しながら、LScriptの詳細を見 構文を用いることもできます。 ていきます。 ユーザー定義プロシージャは、1つまたは複数の引数を受け取 LScriptスクリプトの構造 ることができます。プロシージャ名の次にコロン “:” を付け LScriptは、 Cプログラムの構造によく似ています。スクリプ てから、これらの引数の宣言をします。 トには、プロシージャが必要です。またその数はいくつでも ユーザー定義プロシージャにはまた、リターンコマンドを使 かまいません(使用しているコンピュータのメモリ量により って1つまたは複数の値(戻り値)を呼び出し側に返す機能が 制限されます)。1つにした場合は、文頭に "main" とラベル あります。リターンコマンドは、2つまたはそれ以上の値をカ を付けてください。 ンマ“,”で区切って返すことができます。ユーザー定義関数 が複数の値を返す場合は、受け取り側の変数を配列タイプと main しておくと良いでしょう。しかしLScript言語ではこのことは { 強制しませんから、受け取り側変数が配列でない場合は最初 ・・・ の戻り値が割り当てられ、残りの値は破棄されます。配列タ } イプの変数が使用されるときも、ユーザー定義プロシージャ で返す引数の数と同じ大きさである必要はありません。その mainプロシージャ 位置が配列サイズを越える戻り値は、単に破棄されるからで LScriptの実行は、つねに main()プロシージャによりコント す。 ロールされています。スクリプト内のすべての処理は、この 一例としてユーザー定義関数を作成してみましょう。最初の プロシージャの中で行われます。また main()プロシージャ 引数が0ではないなら特定の値を選択し、最初の引数が0に等 を使って、スクリプトに属している他のプロシージャを選択 しいと判断したら他の値を選択する関数を作ります。次のよ して実行することもできます。こうしたプロシージャは、ビ うに書いて、新規のプロシージャを呼び出すことができます。 ルトイン(LScriptスクリプティングプラグインにとって内部 のもの)の形を取ることができますし、だれもが定義できる スクリプティングプロシージャとすることもできます。こう した外部スクリプティングプロシージャはユーザー定義プロ シージャと言われます。 ユーザー定義プロシージャ ユーザー定義プロシージャは、そのプロシージャの名称を宣 言することによりスクリプト内で作成できます。その後に開 始カッコ“{”を付け、プロシージャの終わりには終了カッコ“}” を付けます。別の方法としては、開始カッコの代わりにキー –3– main library "mylib.lib"; { { ・・・ ・・・ t = which(val1,val2,val3); } ・・・ } 添付のLScript file2.lsは、LScriptライブラリ機能の良い例です。 which: v1,v2,v3 ライブラリファイル( file2.lib)をロードすると、このタスク { が実行できます。ライブラリファイルには、任意の名称を付 if(v1) けられます。ライブラリに関してLScriptでは、名称に関する return(v2); 規約はありません。 else ライブラリのファイル名に2バイト文字(漢字、ひらが return(v3); な、カタカナなど)を使用しした場合は、正常に動作 } しない可能性があります。 LScriptではまた、各スクリプトが実行されるとき自動的にロ ライブラリ ードされるデフォルトライブラリを指定することができます。 ユーザー定義プロシージャは、LScriptライブラリに保管でき ます。LScriptライブラリはLScriptsのスクリプトとよく似て いますが、 main()関数を含んでいないことと、グローバル 変数を宣言できないことが違います。 スクリプトでライブラリを処理するように命令する場合は、 ライブラリ指示語を使います。ライブラリ指示語を与えられ ると、LScriptは主スクリプトにある未解決の参照を満たすユ ーザー定義プロシージャを指定されたライブラリ内で検索し ます。未解決の外部参照を満たすユーザー定義プロシージャ のみが、スクリプトの実行用ランタイムスペースにロードさ れます。LScriptは、スクリプトに関係のないそのほかのライ ブラリ・プロシージャは無視します。(loadallプラグマ指 示語を使うとこの動作は変更できます。これについては本章 の別の箇所で説明します。 ) ライブラリコマンドはグローバルレベルで(つまり宣言した 関数の外部で)スクリプトに指定して、ライブラリファイル の名称をそれに続ければライブラリにアクセスできます。以 下に例を挙げます。 –4– LScript言語の構造 LScript内のコメント 標準的なC/C++構文を使うと、LScriptsにコメントを埋め込む 言語で使うキーワード ことができます。C + +で標準的なダブルスラッシュを使うと、 次の表に、 LScript言語で使うキーワードをまとめます。Cま 1行のコメントを付けられます。 たはC++ のプログラミングの経験のある方ならば、多くのキ jitter(1.5); ーワードはすでにご存知のものだと思います。数はごく少な //見苦しくする いとはいえ、ここで各キーワードを詳細に説明することは本 またCで標準的な"/*" "*/" 記号の対を使うと、複数行のコ 章の範囲を超えています。制御構造を説明するこれ以降のセ メントを付けることができます。 クションで、いくつかのキーワードについて説明しています。 次に掲載した演算子は、Cプログラミングの基本マニュアルに /* 複数行 はかならず掲載されているものです。 の L S c r i p tのCスタイルの構文では、次のキーワードおよび演算 コメント 子が使われます。 */ if else while pragma var break switch case library const continue return True/true False/false Nil/nil = + - * / == != <= >= += -= *= /= ++ -- || && ! % & ^ << >> |= ^= コメントとして、2バイト文字(漢字、ひらなが、カタ カナなど)を使用した場合、LScript実行中にエラーが 発生する場合があります。 &= LScriptではまた、スクリプトの構築に次のようなAREXXスタ イルのキーワードを使うことができます。 begin end then do to select when by この2つ目の構文は、LScriptのスクリプト例、file2.lsでも使 われています。 –5– LScriptの制御構造 とができます。このセクションでは、その制御構造について else節を使うと、 if演算子が"either/or"条件を扱うことがで きるようになります。 else節は if演算子の実行可能文(ま 説明します。 たはブロック制御)に続けます。 LScriptには制御構造があり、構造化プログラムを設計するこ if(lensFlare[index]) if/else { if演算子を使うと、LScriptは実行すべきものを判断できるよ file.writeln("LensFlare 1"); うになります。この演算子では異なる2つのスタイルの構文を ・・・ サポートしています。第1のスタイルはC言語と同じものです。 } if ((f.eof() == false) && (size(tokens) > 1) else &&(tokens[1] == "Plugin")) file.writeln("LensFlare 0"); info(tokens[1]," ",tokens[2]); 2つ目のスタイルはAREXXと同じです。 while while演算子を使うと、LScript内でループを使用できるよう if f.eof() == false and size(tokens) > 1 and になります。文が1つの制御ブロック内にあり、条件が論理上 tokens[1] == "Plugin" then のtrue(真)である限り、1つまたは連続する複数の文を実 info(tokens[1]," ",tokens[2])); 行します。この制御は次のような形をとります。 if演算子が複数の実行可能文を含む場合は、文を1つの制御 while (ブール表現) { ブロック内に納めなければなりません。これは、ユーザー定 義プロシージャが使う構造と同じです。 文1; if (file == nil) 文2; { • error("Cannot create scene file • ",sceneFile); 文n return; } } L S c r i p tでは、スクリプトのプログラマは i f の場合と同様に AREXXの場合は、次のようになります。 whileでも、AREXX風の構文を使うことができます。 if file == nil then while ブール表現 do begin begin error("Cannot create scene file 文 ",sceneFile); end return; スクリプトプログラマがループの流れを変えるためのLScript end コマンドに、 breakおよびcontinueの2つのコマンドがあ –6– ります。このコマンド各々ついては、本ドキュメントの後の switch (式) { セクションで説明します。 case 定数式1 : for 文; break; whileと同様に、for演算子を使ってもループ制御をLScript 内で使うことができます。 whileの場合はループ構造の制御 に制限があり、条件式の評価のみを実行できますが、 for演 case 定数式2 : 文; break; 算子では、ループ条件の評価に加えてループに先立つ初期化 と、ループ後のコードの実行ができる点が異なります。Cバー • ジョンのforは次のような形になります。 • for (カウンタの初期化 ;条件判定 ; カウンタの再設定) { case 定数式n 文; break; 文1; 文2; default: • 文; • break; 文n } } この場合もLScriptには、select演算子というAREXX風バー LScriptではまた、次のような簡潔でAREXX風のfor演算子の ジョンの選択機構があります。ただし、選択基準が数値だけ 形も許されます。 に限定されている switch演算子とは異なり、 select 制御 では式全体が評価され、実行するコードを決定します。 for 変数 = /expr/ to /expr/ [ by /expr/ ] do begin select 文 when 式 then do end 文 end どちらの形式の場合も、 forループ演算子が使う変数は使用 end 前に宣言されている必要があります。 switch, select ?,: (インライン選択) LScriptはスクリプトプロクラマに、構造化された選択機構を インライン選択演算子 "?",":"を使うと、2つの選択項目の 提供します。これは、Cにおける同様の機能と同じものです。 なかから条件に基づいて1つを選択できます。 select演算子 switch演算子を使うと、コードの実行を、式の数値にもと のこの省略形式は、C言語で提供されているものと同じです。 づいて選択できるようになります。 次のような形になります。 ブール式 ? 真の場合 : 偽の場合 –7– この演算子は、LScript内で式を使えるところなら任意のとこ ドはgotoコマンドによく似ていますが、 gotoコマンドの場 ろに配置できます。 合は移動位置は制御ループの冒頭になります。 whileの場合、制御ループの判断の基準となる条件は再度評 例 価されて、プログラムの実行はそこから継続します。 main forループの場合はループの後にあるコードが評価され、制 { 御ループの判断の基準となる条件も再評価されます。プログ var j = 1; ラムの実行は、そのポイントから継続します。 ・・・ info("return is",(j == 1 ? "yes" : while (1) "no")); continue; } break 前述のbreakコマンドは、LScript内のループ制御を途中で終 了するものです。 w h i l eまたは f o r 演算子がその実行中に b r e a kに遭遇すると、すぐにそのループ制御の終端の次の LScript文に移行します。 例 while(j) { if(j == 10) break; ++j; 4行目 info("j == ", j); 7行目 } この例では4行目にあるbreakまで来ると、LScriptはwhile ループを終了して 内部プログラムカウンタを7行目 info() の実行可能文に設定します。 continue continueも、LScript内のループ演算子の実行の流れを変化 させるコマンドです。 breakの場合、プログラムの実行はル ープの次に続く LScriptコード行に移動して継続します。一方 continueコマンドの場合は、ループ演算子が制御ループの 終端に達したときのように振る舞います。 continueコマン –8– //これは無限ループになります LScriptのデータ型 LScriptは、さまざまなタイプのデータをサポートしています。 たとえば二重引用符は、定義する文字列リテラルの開始と終 これらのタイプについて、ここからのセクションで説明しま 了を示す記号です。1つまたは複数の二重引用符を文字列内に す。 入れて表示するにはどうすればよいでしょう。LScriptのコー ド行を次のようにすると、エラーにはなりませんがなにも表 数値 示されません。 LScript内の数値は正負のいずれにもなれますし、浮動小数点 quoteString = ""I don’t like this", he said"; 値を表すために小数点を入れることもできます。LScriptは絶 対値表現もサポートします。 LScriptは最初の2つの二重引用符を、変数 quoteString に main 割り当てる文字列リテラルの開始点と終了点と解釈します。 { その後LScriptの処理は、表示したい文字列の最初の文字から var integer = 15; 継続します。これではどうしようもありません。 var real = 0.3; 文字列内の引用符は、LScriptに特殊文字として無視させなけ var negative = -35.356; ればなりません。次のようにすると、これらをエスケープで var scientific = 7.5E+13; きます。 ・・・ } quoteString = "\"I don’t like this\", he said"; 文字列 文字列リテラルは、文字列の前後に二重引用符 (")を付けて 配列 表します。 LScriptは、10次元までの配列をサポートしています。配列要 LScripではC言語のように、文字列内の特定の文字を"エスケ 素は、 サポートしているものならLScriptデータ型(配列はネ ープ"つまり拡張表記できますし、またそうしなければならな スト不可ですから配列は除く)すべてを保持できます。各配 い場合があります。ある文字をエスケープすると、LScriptは 列には、これらのデータ型をどのように混在させてもかまい その文字をリテラルとして、つまり定義する文字列の一部と ません。 して特殊な意味を付けずに扱います。文字をエスケープする 配列は、2つの異なる形式で作ることができます。最初の形式 には、LScriptに処理させたい文字の直前に¥マーク(¥マー では、配列を単に宣言して配列を含む要素の数を示します。 クは英文フォントでは \(バックスラッシュ)となります。) main を入れます。 { main var check[15]; { ・・・ var astring = "Here is a test string"; } ・・・ } –9– このやり方で配列を宣言すると、新規の配列内の要素それぞ main れは内部的に未初期化とマークされます。この状態の要素は、 それに値を割り当てるまでは使えません。LScriptが未初期化 { var check[15]; 状態の配列要素つまり変数へのアクセスを検知すると、エラ check[] = -1; ー・メッセージを生成します。 //15個の要素すべてに-1'を入れる 次の初期化形式を使うと、ディスクファイル内のエントリか ・・・ ら配列を宣言して初期化できます。このディスクファイルに } は、1行に1つの配列要素(数値または文字)が入らなければ なりません。またこれは、ASCIIテキストフォーマットでなけ 新バージョンでの変更点 ればなりません。各エントリを読み込むたびに、LScriptエン 新しいバージョンのインタプリタでは、1次元(または"リニ ジンがデータ型を判断します。 ア")配列は明示的に宣言する必要はなくなりました。配列の 配列のサイズを示す数値パラメータの替わりに文字列リテラ 要素は、"要求に応じて"配列内に割り当てられます。つまりま ル値を使うと、ディスクファイルからの配列が初期化されま だ存在しない配列内の特定の要素にアクセスする場合は、自 す。 動的に既存の配列を拡張して新しいサイズにします。 main 配列は"急遽"作られたのですから、明示的に宣言された配列を { 使って関数の戻り値を入れるといった状況では、期待通りに var points["\\home\\rbh\\points.txt"]; は動作しないことにご注意ください。 ・・・ 次のサンプルコードをごらんください。 } main { 配列が宣言されると、配列要素を直接参照することで個々の 要素にアクセスできます。L S c r i p t内では、配列要素はCまた はC++のようにオフセット(0)からではなく、Pascalの場合 var firstItem; 3行目 firstItem = parse(" ","Hello there, と同様にオフセット(1)からアクセスされます。使用するコ everybody!"); 5行目 ンピュータで使用可能なメモリ容量による制限以外には、各 if(firstItem == "Hello") 6行目 ・・・ LScriptで使える配列の数に制限はありません。 } 整数値として評価される式はすべて、配列インデックスとし て使うことができます。たとえば次のようになります。 p a r s e ( ) を呼び出すと H e l l o , t h e r e ,および e v e r ybody!という3つの項目が返されます。以前のバージョンで は最初の項目( "Hello")だけが、変数 firstItemに割り当 randElement= points[random(1,size(points))]; 空のインデックスを使って値を配列に割り当てれば、1つの値 てられます。 を使って1つのステップでL S c r i p t配列全体を初期化すること firstItemは作成されたとき、配列として明示的に宣言さ ができます。 れていないからです。よって、これが保持できる値は1つだけ –10– になります。 p a r s e ( ) からの残りの値( t h e r e および ベクトルデータ型の個々の要素を宣言すると、キーワード x、 "everybody!)は、単に破棄されます。 yおよび zを使ってアクセスできます。たとえば次のようにな しかし新しいバージョンでは、配列はインタプリタにより必 ります。 要なときに自動的に作られます。ですから新バージョンでこ main のコードを処理すると、3つの要素からなる配列が自動的に生 { 成されて firstItemに割り当てられます。ご覧のように上 var apoint = <4.5,10,.03>; 記の6行目は、新バージョンでは正しくありません。 ++apoint.x; firstItemは、ここでは3つの要素を持つ配列だからです! --apoint.y; この新しい動作に対応するには、6行目を次のように変更しま if(apoint.x > 4) す。 if(firstItem[1] == "Hello") ・・・ 6行目 } またさらによい解決法は、 firstItemを結合割り当ての"カ ッコ"で囲みます。そうすると、5行目は、前バージョンと同 ポイントID/ポリゴンID 様に動作します。 この2つのデータ型は、L S c r i p tが直接使えるわけではありま (firstItem) = parse(" ","Hello there, せん。 everybody!"); これらを L S c r i p tに含めると、 a d d p o i n t ( ) や a d d p o l y- gon()といったモデラー固有関数の戻り値をサポートできる 複数次元の配列は、キーワード varを使って明示的に ようになります。変数および配列も、このデータ型となりま 宣言しなければなりません。 す。 ベクトル nil L S c r i p tのベクトルタイプは、3つの数値からできています。 nilはLScriptにおいて、条件でもありデータ型でもあります。 各数値はカンマで区切り、山形カッコ" <>"で囲みます。この 変数および配列要素にこの値が割り当てることができますし、 データ型は、多くのビルトインLScriptやモデラー関数へ渡す この値を持つかどうかも検査されます。この値はまた特定の ことができます。またユーザー定義プロシージャへ、プロシ LScriptビルトインコマンドにより返され、ある種の失敗を表 ージャ引数として渡すことができます。LScriptコマンドには、 示します。たとえば、オブジェクト作成コマンド file()は、 ベクトルデータ型を返すものがあります。 ファイルオブジェクトを作成できないとnilを返します。 配列の初期化にこの値を使うとよいでしょう。この値で初期 main 化しておけば、未初期化の配列要素にアクセスしたときにお { こるランタイムエラーを避けることができます。 var apoint = <4.5,10,.03>; ・・・ } –11– main LScriptのオブジェクトエージェント { L S c r i p t環境にはビルトインのオブジェクトが含まれていて、 これをオペレーティングシステムレベルの関数およびデータ var check[15]; check[] = nil; 型へのインターフェイスとして使うことができます。オブジ ・・・ ェクトエージェントといわれるこれらの内部オブジェクトつ いて、このセクションで説明します。 } parse()のような変数戻り値を持つLScriptコマンドを扱う 場合は、配列をnilに初期化するとよいでしょう。 ファイルオブジェクト LScriptファイルオブジェクトエージェントは、オペレーティ ング・システムのファイルシステムへのアクセスを提供しま プロセスID す。LScriptのビルトインコマンド File()は、このタイプの ポイント I Dやポリゴン I Dの場合と同様に、このデータ型も オブジェクトを返します。変数に割り当てられると、次のよ LScriptから直接利用はできません。これをLScriptデータセッ うなさまざまなファイルオブジェクトエージェントメソッド トに入れると、 spawn()、wait()およびterminate() に、ホスト変数からアクセスできます。 の各制御コマンドの処理をサポートできます。 isOpen そのファイルが開いていてアクセス可能なことを示す論理値 を返します。 isOpen (void) open 新規ファイルを指定されたモードで開きます。新規に開かれ たファイルは、既存のファイルオブジェクトエージェントに 割り当てられます。 void open(ファイル名,モード) ファイル名: 文字列; 開くファイルのファイル名 モード: 文字列; 開くために使用するモード reopen すでに開いているファイルを閉じて、それを指定されたモー ドでもう1度開きます。 void reopen(モード) モード: –12– 文字列; ファイルを開くために使用するモード close read すでに開いているファイルを閉じます。 ファイルからテキスト行を1つ読み込み、それを文字列として 返します。ファイル がバイナリモードで開いている場合、こ void close(void) の関数は無効です。 eof read(void) そのファイルがE O Fマーカーに達したかどうかを示す論理値 返す値: 文字列; ファイルからのテキスト行 (TRUE/FALSE)を返します。 readNumber eof(void) 返す値: ASCIIモードの場合、この関数は文字シーケンスをファイルか ブール; trueまたはfalse ら読み込み、それを1つの数値に変換します。バイナリモード の場合、1つの整数値がファイルから読み込まれます。 rewind ファイルの読み込み/書き出しポイントをファイル冒頭に再 readNumber(void) 設定します。 返す値: rewind(void) 返す値: 数値 浮動小数点値または整数値 readVector 文字列 ASCIIモードの場合、この関数は文字列をファイルから読み込 すでにひらいているファイルの名称、あるいはそれがもとも み、それをベクトルデータ型として返します。ファイル内の と指定されている場合はパス が入っている文字列を返します。 データは空白で区切った浮動小数点値でなければなりません。 バイナリモードの場合、サイズのdouble型の3つの数値が読み ファイルの名称 込まれ、ベクトルとして返されます。 write、writeln readVector(void) w r i t e ( )は、1つまたは複数の引数をファイルに入れます。 writeln()はwrite()と同じですが、復帰改行文字を行末 返す値: にアペンドします。 ベクトル ファイル内にあるままのベクトル parse ファイルがバイナリモードで開いている場合は、これらのコ ファイルから1行読み込み、その行のトークンを表す複数の要 マンドは無効です。 素を返します。トークンは、文字列引数で提供する文字のう ち1つによって区切られます。 この関数は、バイナリモード write(アイテム1[,アイテムn]) アイテム: 返す値: では無効です。 1つまたは複数の変数または定数 整数; ファイルに書かれるバイト数 parse(トークン) –13– トークン: 文字列; トークンセパレータの文字列の1 文字 返す値: 文字列; トークンを表している文字列の配列 nl readByte 復帰改行文字をファイルに書き込みます。このコマンドは、 ASCIIモードでは、この関数はテキストファイルから文字を1 バイナリモードでは無効です。 つ整数値として返します。バイナリモードでは、u n s i g n e d charサイズのバイナリ値1つがファイルから読み込まれ、整数 void nl(void) 値として返されます。 linecount readByte(void) ファイルがASCIIモードで開いている場合、この関数はそのと 返す値: 整数; ファイルの1バイト き開いているファイル内のテキスト行数を返します。しかし バイナリモードでは、バイトで表したファイルサイズを返し writeNumber ます。 ASCIIモードの場合、与えられた値がテキスト・ファイルに浮 動小数点値として文字形式で書き込まれます。バイナリモー linecount(void) 返す値 ドの場合、double型のバイナリ値1つがファイルに書き込まれ 整数; ファイルの行数またはバイト数 ます。 line writeNumber(値) ASCIIモードの場合で引数がなにも与えられていなければ、こ 値: 浮動小数点値 の関数はそのファイル内のそのときの行番号を返します。フ 返す値: 整数;ファイルに書き込まれるバイト数 ァイル内のテキスト行数の範囲内に収まる整数値が与えられ ると、ファイルポインタをその行番号まで移動します。 writeInt このコマンドは、バイナリモードでは無効です。 ASCIIモードの場合、与えられた値がテキスト・ファイルに整 数値として文字形式で書き込まれます。バイナリモードの場 line() 返す値: 合、サイズの整数型のバイナリ値1つがファイルに書き込まれ 整数; オプションのパラメータが省略された場合、 ます。 現在の行番号 line(整数) writeInt(値) 整数: 移動する行番号 値: 整数;書き込まれる値 返す値: 整数; ファイル内で移動する行番号 返す値: 整数;ファイルに書き込まれるバイト数 readInt writeByte ASCIIモードの場合、この関数はテキストファイルから文字列 ASCIIモードの場合、与えられた整数値がテキスト・ファイル を読み込み、整数データ型を1つ返します。バイナリモードで に文字として書き込まれます。バイナリモードの場合、与え は、サイズの整数型のバイナリ値1つがファイルから読み込ま られた値はファイル内にunsigned charサイズのバイナリ値1 れます。 つとして格納されます。 readInt(void) 返す値: writeByte(値) 整数; ファイルの整数値 –14– 値: 整数;書き込まれる値 返す値: 整数;ファイルに書き込まれるバイト数 offset ビルトイン関数 このメソッドがパラメータなしで呼び出されると、そのとき アーキテクチャに関係なく、各LScriptはLScriptエンジンにビ のファイルのオフセットのバイトを返します。整数値を与え ルトインされている属性にアクセスできます。こうした"ビル ると、ファイル内でメソッドと相対的に指定したオフセット トイン"には、あらかじめ定義された値、コマンドおよび関数 にファイルポインタを移動できます。 offsetメソッドには、 があります。ユーザー定義変数を使う任意の場所で、これら 次のオプションがあります。 FROMSTARTは、ファイル冒頭 の定数を使うことができます。しかし、その値は変更できま を起点に移動します(これはメソッドが指定されていない場 せん。つまり文の左辺には使えません。 合のデフォルトです)。FROMENDは、ファイル終端を起点に 移動します。 FROMHEREでは、与えられたオフセット値をポ 事前定義値 インタの現在の位置と相対的位置と解釈します。 各LScriptで使用できる定常(つまり読み込み専用)変数がた くさんあります。その中には、モデラーコマンドに直接関係 offset([値[,メソッド]]) 値: 整数;使用されるオフセット するものもいくつかあります。これを次にまとめます。 メソッド: 定数;FROMSTART,FROMEND またはFROMHERE PI E GAMMA DEG 返す値: 整数;ファイル内での現在のオフセット PHI READ WRITE APPEND LScriptファイルオブジェクトを使ったさまざまな例について VERTICAL HORIZONTAL FROMSTART FROMEND は、 添付のLScriptスクリプトの例をご覧ください。 FROMHERE INTEL ALPHA SGI MIPS MACINTOSH AMIGA CREATE ATTACH AUTOCLEAR LAYOUT MODELER SCREAMERNET nil true/TRUE false/FALSE X Z ユーザー作成のオブジェクトエージェント LScriptでは、ユーザーが独自のオブジェクトエージェントを 作ることができます。これを利用するために必要なサポート 事項およびステップについては、「LScript共有ライブラリの拡 Y LightWaveモデラーのもとで使うように設計されたスクリプ 張:ユーザー定義のオブジェクトエージェント」で説明して トには、そのために事前に定義された値を持っています。次 います。 にそれをまとめます。 –15– GAUSSIAN UNIFORM NORMAL SHARP BUFFERED KNOTS SUBTRACT INTERSECT ADD LENGTHS CORE TUNNEL STENCIL SLICE FLAT SMOOTH METAFORM SET CLEAR VOLUME CONNECT NPEQ NPLT NPGT VOLEXCL VOLINCL SURFACE NVEQ NVLT NVGT CURVE NONPLANAR SELECTED FACE UNSELECTED ABORT START END DETAIL GLOBAL 内部コマンド USER RADIAL UNION POLYNDX LScriptには、多くの一般的なビルトインコマンドがあります。 POLYID POINTNDX POINTIDPOINTNDX 但しこれらの関数は、LightWaveのModelerまたはLayoutに直 POINTID 接関係しているわけではありません。その呼び出し構文とそ LightWave レイアウトスクリプトは、次のような独自のグロ の使用法を、このセクションで説明します。 ーバル定数値のセットにアクセスできます。 sqrt SCENEMODE OBJECTMODE MESH LIGHT この関数は、数値の平方根を計算します。また数値を受け取 CAMERA BONE SCENE POSITION り、その値の平方根を返します。 RIGHT UP FORWARD ROTATION この関数は、次のように呼び出します。 SCALING PIVOT WPOSITION 例 そして、LightWave レイアウトでの特殊なアーキテクチャも、 ・・・ その独自の値を持ちます。 angle = 180; //180度 varSquare = sqrt(angle); //角度の平方根を計算する イメージフィルター ・・・ SPECIAL LUMINOUS DIFFUSE SPECULAR MIRROR TRANS RAWRED RAWGREEN RAWBLUE SHADING SHADOW GEOMETRY DEPTH RED GREEN exp この関数は、値の指数を計算します。また数値を受け取り、 その値の指数を返します。 BLUE 例 ALPHA ・・・ プロシージャルテクスチャ v1 = exp(27.5); NORMAL COLOR LUMINOUS DIFFUSE SPECULAR MIRROR TRANSPARENT ETA ROUGHNESS RAYTRACEE ・・・ log この関数は、数値の対数値を計算します。また数値を受け取 変位マップ WORLD り、その数値の対数値を返します。 LOCALL 例 オブジェクト置換 NONE PREVIEW ・・・ RENDER v1 = log(347.495); M o d e l e r特有の定数の詳細については本章後半の L S c r i p tの ・・・ Modeler固有コマンドを説明するセクションを参照してくださ い。 Layout固有定数の詳細については、本章のLScriptのLayout固 有コマンドを説明するセクションを参照してください。 –16– sin, asin, cos, acos, tan, atan, cosh, sinh, tanh, sec, cot, csc random これらの関数は、ラジアンで表された角度の三角法値を計算 この関数を使うと、L S c r i p tが疑似乱数整数を生成できます。 します。また、ラジアン値を受け取り、その値の演算結果を また、2つの整数値を受け取り、これら2つの数字(これも含 返します。 む)の間に存在する乱数値を返します。 関数sinh(),tanh()および cosh()は、それぞれの関数の 例 双曲線正弦、双曲線正接、双曲線余弦の値を計算します。 ・・・ これらの関数の使い方を次に示します。 triggerFrame = random(20,50); ・・・ 例 ・・・ sin1 = sin(45); randu ・・・ この関数は、0と1の間の乱数値を返します。 asin1 = asin(276); 例 ・・・ ・・・ rad = 0.05 * maxlen * (1 + randu()) abs ・・・ この関数は、数字の絶対値を返します。数字の記号に関わり なく、この関数の戻り値はつねに正となります。 min, max 例 min()関数は、2つの数値の引数のうち小さい方を返します。 ・・・ 一方max()は、逆に大きい方を返します。 if(abs(decline) > 30) 例 ・・・ ・・・ t = min(top,7); ceil, floor ・・・ ceil()関数は、引数として渡された数値以上で最小の整数 値を返します。floor()関数は、数値パラメータ以下で最大 となる整数値を返します。 例 ・・・ c = ceil(45.6); f = floor(13.3); ・・・ –17– mod rad, deg mod()関数は、最初の数値引数を2つ目の引数で割り、割り rad()とdeg()の2つの関数は、変換ユーティリティーです。 rad()関数は度数で表現された角度の数値パラメータを1つ 受け取り、それをラジアンに変換します。 deg()関数はラジ 算のモジュロつまり余りを返します。LScript演算子の%を使 っても、この関数を表せます。 アンで表現された角度の数値パラメータ1つを受け取り、それ 例 を度数に変換します。 ・・・ t = mod(34.5,6); 例 4.5を返します ・・・ ・・・ または t = rad(degrees); degrees * (PI / 180) と同等 ・・・ ・・・ t = 34.5 % 6; ・・・ range 最初の数値パラメータが2つ目と3つ目の数値(これを含む) で指定された範囲に入っているかどうかを判断します。これ pow はブール値(trueまたはfalse)を返します。 pow()関数は、最初の数値引数を2つ目の引数だけ累乗しま す。 例 ・・・ 例 if(range(top,3,8)) ・・・ t = pow(5,3); ・・・ 125を返します ・・・ select 最初の2つの数値パラメータを比較して、第1パラメータが第 hypot 2パラメータよりも小さい場合に、3つ目のパラメータを返し hypot()関数は、関数の最初と2つ目の数値引数を2辺とす ます。また第1パラメータが第2パラメータ以上の場合、4つ る直角三角形の斜辺を計算します。 目のパラメータを返します。 例 例 ・・・ ・・・ t = hypot(3,5); t = select(4,7,15,3); ・・・ 15を返します ・・・ t = select(15,7,7,10); ・・・ –18– 10を返します step 例 2つの数値引数を比較して、2つ目の値が1つ目の値よりも小 ・・・ さければ0を返します。また2つ目の値が1つ目の値より大き t = vmag(x,y,z); いか等しいの場合は、3つ目の数値パラメータを返します。 ・・・ 与えられた位置のベクトルの大きさ 例 info, warn, error ・・・ t += step(y,10,.25); これらのコマンドは、サポートされているものであれば任意 0.25でstepします のデータ型(配列を除く)のパラメータを取り、適切なメッ ・・・ セージタイプをユーザーに表示します。 round 例 小数点以下を四捨五入し整数を返します。 ・・・ error("Value ",val," exceeds max limit of ", 例 10 * items," items"); ・・・ t = round(37.7); ・・・ 38を返します ・・・ file このコマンドはディスクファイルの位置を表す文字列、また frac オプションで、ファイルを開くモードを示す文字列を受け取 数値の小数部を返します。 り、ファイル内のオブジェクトを1つ返します。特定のオブジ 例 ェクトやそのメソッドについては、本章前半のLScript のオブ ・・・ ジェクトを説明しているセクションを参照してください。 t = frac(46.75); 0.75を返します 例 ・・・ ・・・ var sceneFile = file("\\temp.lws","w"); fac ・・・ fac()コマンドは、与えられた数値パラメータの階乗を計算 ファイルオープンモードは、Cの場合と同じです。次にそれを します。 まとめます。 例 ・・・ t = fac(5); 120を返します ・・・ vmag vmag()関数は、3次元ベクトルの大きさを計算します。 –19– r w a b 読込(ASCII) バイナリ(つまり、"rb"はバイナリで読込) + 更新(つまり、ファイルポインタは任意に移動可能) 書出(ASCII) 追加(ASCII) たとえばランダムアクセスのバイナリ読込でファイルを開く がベクトルのもの、2つのベクトル(定数または変数として)、 には、"rb+"をファイルのオープンモードとして指定します。 第1のベクトルを表す3つの数値と第2のベクトルを表す3つの オープンモード値オプションが指定されない場合は、デフォ 数値を合わせた6つの数値などを受け取ることができます。 ルトでファイルは読込"r"モード(ASCII)で開かれます。 center()は、ベクトルデータ型を1つ返します。 fileexists boundingbox()は2点のベクトルを返しますから、その出 力をcenter()に与えることができます。 このコマンドは、特定のファイルの存在を示すブール値 例 (true/false)を返します。 var objectCntr = center(boundingbox()); 前述の info(),warn(),error() コマンドと同様にこの コマンドも、ファイルの名称を評価する文字列を作るための extent 引数の変数番号を受け取ります。 このコマンドは c e n t e r ( ) の場合と同様、数値/さまざまな 例 タイプの引数を受け取ります。しかし、2つのベクトルの中点 var index = 1; を計算するのではなく、この2点のエクステント(距離)を返 if(fileexist("\\temp",index,".lwo")) します。 ファイル名 == "\temp1.lwo" extent()は、ベクトルデータ型を1つ返します。その要素 (x,y,z)が各軸方向のエクステントを表しています。 ・・・ 例 filedelete このコマンドは、指定されたディスクファイルを削除します。 fileexists()と同様に、このコマンドも、ファイルの名 var objectSize = extent(boundingbox()); parse 称を評価する文字列を作るための引数の変数番号を受け取り parse()は2つのパラメータを受け取ります。最初のパラメ ます。このコマンドは、実行結果の状態を返します。0が返れ ータは潜在的トークンセパレータの文字列で、2つ目のパラメ ば、エラーがなかったことになります。 ータはそれを処理する文字列です。この関数は、文字列(2つ 目のパラメータ)と比較するトークン配列を返します。 例 var index = 1; p a r s e ( )の戻り値は、データ型配列の変数に割り当てます。 if(filedelete("\\temp",index,".lwo")) そうしないとデータを失うことになります。 error("Cannot remove 例 file\\temp",index,".lwo!"); var tokens[10]; ・・・ var str = "23,45,69.6,100"; tokens[] = nil; center tokens = parse(",",str); 3次元空間内の2点が与えられると、このコマンドはその2点 //"23", "45", "69.6"および"100"を返します の中点を返します。このコマンドは、さまざまなパラメータ ・・・ 計数およびタイプを受け取ります。配列内の最初の2つの要素 –20– size vector このコマンドを使うと、特定のデータ型の特定の変数のサイ このコマンドは文字列引数を受け取り、それをベクトルに変 ズを判断できます。数値の場合は1を返します。ベクトルタイ 換します。 プの場合は3を返します。文字列引数の場合は文字列内の文字 例 数を返し、配列引数の場合は配列内の(配列の全サイズでは var str = "4 6.5 8"; なく)実際の要素数を返します。 var t; 例 t = vector(str); var tokens[10]; //<4,6.5,8>を返します ・・・ var str = "23,45,69.6,100"; var t; string tokens[] = nil; このコマンドは、引数の変数番号を受け取り、文字列を構築 t = size(tokens); //0を返します tokens = parse(",",str); //4つの要素を返します t = size(tokens); tokens[8] = 1.0; //4を返します t = size(tokens); //5を返します します。各々の引数には、L S c r i p tがサポートするデータ型 (配列を除く)を含んでいます。 例 t = string("Value ",val," exceeds max limit of ",10 * items," items"); ・・・ split number, integer split()は、特にファイルのパス/名称の文字列を処理する number()は文字列引数を受け取り、それを数値(浮動小数 点)に変換します。 integer()も同じタイプの引数を受け 取りますが、整数値を返します。 integer()の場合、文字 ために作られたものです。これは文字列を受け取り、その文 字列引数からドライブ、パス、ファイルの名称およびファイ ル名拡張子を表す4つの要素からなる配列を返します。 列内に小数点があればそれは切り捨てます。小数点以下の四 捨五入をするには、round()関数を使います。 例 var str = "69.6"; var t; t = number(str); //69.9を返します t = integer(str); //69を返します t = integer(round(number("69.9"))); //70を返します ・・・ –21– 例 例 var file = getfile("Select A ScreamerNet IIをパラレルで起動します Scene...","*.lws"); snID = spawn("lwsn -2 ", if(file == nil) return; getenv("TMP"),"\\snii.job ", if(fileexists(file)) getenv("TMP"),"\\snii.rpl"); { if(snID == nil) var base[4]; { base = split(file); error("Cannot create ScreamerNet process"); コンポーネントを受け取ります ・・・ ・・・ 文字列の示すコンポーネント(つまり指定されたドライブ) がない場合、nilを返します。 append このコマンドは、文字列および配列のどちらに対しても動作 します。これは LScriptがサポートする任意の整数データ型を、 文字列の最後に文字として追加したり、LScript配列に新規の 要素として追加します。 配列をこの関数を使用する別の配列 に追加することもできます。 spawn このコマンドは、Windows NTまたはWindows 95環境下で外 部処理の実行を始めます。通常、外部処理の実行はすべてこ のコマンド内で起こります。この場合 s p a w n ( ) コマンドは、 指定された処理の実行リザルトコードを返します。 しかし、asyncspawnプラグマ指示語がそのスクリプト内で 宣言されている場合は、spawn()コマンドは、成功すると起 動した外部処理の処理IDを返します。 この処理IDは、処理制御関数 wait()やterminate() の引 数として必要となります。 –22– wait "Plugins"/PLUGINSDIR Layout/Modeler このコマンドは、 s p a w n ( )に同期関数として提供されます。 "Settings"/SETTINSDIR Layout/Modeler spawn()の戻り値である処理IDが渡されると、指定された外 代替コンフィギュレーションの位置) 部処理が停止するまでこのコマンドがスクリプト実行を停止 "Content"/CONTENTDIR Layout します。そして、その処理の停止時の状況を返します。 "Scenes"/SCENESDIR Layout terminate "Hierarchies"/HIERARCHIESDIR Layout コマンドの処理制御用の関数の1つである terminate() は、 "Surfaces"/SURFACESDIR Layout 指定された処理IDをWindowsに停止させます。 "Output"/OUTPUTDIR Layout "Animations"/ANIMATIONSDIR Layout terminate(snID); "Envelopes"/ENVELOPESDIR Layout ScreamerNetをシャットダウンします "Previews"/PREVIEWSDIR Layout "Command"/COMMANDDIR Layout 例 getenv 次のようにすると、これらのディレクトリ値を取得できます。 C言語の getenveと同様に、この関数は環境変数と推定でき る文字列引数を受け取り、変数のそのときの値を返します。 与えられた名称に対応する変数が環境内になければ、 例 ・・・ install = getdir("Install"); getenv()はnilを返します。 ・・・ 例 plugins = getdir(PLUGINSDIR); var tempfile = ・・・ string(getenv("TMP"),"\\33j4ks.$$$"); sleep getdir 次に挙げた定数(文字列リテラル/マニフェスト)について、 sleep()コマンドを使うと、スクリプトをミリ秒(1/1000 秒)で指定した長さ停止し、スリープタイムが過ぎるまでス getdir()はアプリケーションが使う作業用の値を返します。 クリプト(およびModeler)のWindowsタイム・スライスを "Fonts"/FONTSDIR Modeler 解放します。 "Macros"/MACROSDIR Modeler "Install"/INSTALLDIR 例 Layout/Modeler sleep(1000); 1秒スリープします (LightWaveインストレーション・ディレクトリ) "Objects"/OBJECTSDIR Layout/Modeler "Images"/IMAGESDIR Layout/Modeler "Motions"/MOTIONSDIR Layout/Modeler "Temp"/TEMPDIR Layout/Modeler –23– dump サンプル dump()はデバッグ関数です。これを使うと、スクリプト開 main 発者はすべての内部スクリプト変数とその値を、指定したテ { キストファイルにダンプできます。指定したテキストファイ var heading = recall("heading",15); ルがすでに存在する場合、この関数が呼び出されると値はそ var testing = recall("testing",95.34); のファイルにアペンドされます。 var myName = recall("myName","Bob 例 Hood"); dump("\\myscript.var"); var newName = recall("newName", string(myName," has no life!")); dump()コマンドは、ランタイム環境ではサポートされてい ません。このコマンドが入っているスクリプトは、LScriptコ info("got heading == ",heading, ンパイラで正常にコンパイルできます。 ", testing == ",testing); store、recall この2つのコマンドを使うと、再び呼び出されるまでスクリプ info("got myName == ",myName, トが変数値を保持できます。 ", newName == ",newName); store()コマンドはパラメータを2つ取ります。第1のパラ メータは、格納した値を一意に識別するための文字列リテラ store("heading",++heading); ル(または文字列を持つ変数)です。第2のパラメータが、実 store("testing",testing + .5); 際の値です。 store("myName",myName); r e c a l l ( ) は、 s t o r e ( ) されている値を取得します。 store()の場合と同様に、これも2つのパラメータを受け取 ります。第1のパラメータは、 store()の場合と同様に、値 を保持するときに使った識別子値です。しかしstore()とは 異なり、2つ目のパラメータはその識別子に対して store() strleft, strright, strsub, strupper, strlower が発行されたことがあるかどうかを示すデフォルト値を返し これらの文字列処理関数を使うと、スクリプトのプログラマ ます。 はLScript文字列を正確に処理できます。 store("newName",newName); } strleft()およびstrright()は、文字列の一部を指示さ れた方向から返します。どちらの関数も2つのパラメータを受 け取ります。第1のパラメータは処理対象の文字列で、2つ目 のパラメータは抽出する文字数を表す数字です。 次の例では"My first name is "Ted""とプリントされます。 例 info("My first name is \"", strleft("Ted Philmore",3"),"\"); –24– LightWave Modelerコマンドおよび関数 strsub()も抽出関数ですが、この関数を使うと文字列内の 任意の文字数を、文字列の端ではなく任意の位置から抽出で 本セクションでは、LightWave Modelerに関係したLScriptコ きます。 マンドと、その呼び出し構文を扱います。 例 本セクションの各コマンドには、コマンドシーケンス ( C S )ま t = strsub("Ted Philmore",3,3); たはメッシュデータエディット (MD)という記号が付いていま "d P"を返します す。この2つのタイプのオペレーションは別のもので、コマン ドシーケンスオペレーションをメッシュデータエディットオ その名称から想像できるように、strupper()と ペレーション中( editbegin()で初期化、 editend()で strlower()は与えられた文字列をそれぞれ大文字または小 終了)に実行すると違反になります。LScriptはこうした違反 文字で返します。 操作を検知して、そのスクリプトを終了します。この制約の どの関数の場合も、与えられたもとの文字列は修正されませ ないコマンドには、制約なし(IN)という記号を付けます。 ん。 また、LScript1.0以降のバージョンで追加されたコマンド・関 数については、 (CS/1.2)というように、バージョンナンバー を追記しています。 LScriptがサポートしている特定のモデラーの固有コマ ンドを詳細に説明することは、本章の枠を超えていま す。こうしたモデラーコマンドについては、NewTek, Incから 入手できるさまざまなL i g h t W a v eマニュアルで解説していま す。ここでは LScript言語に関係した各コマンドの呼び出し構 文、および(存在すれば)戻り値を扱います。 autoerrorプラグマが宣言されていない場合、特に注記が なければLScriptのModeler固有コマンドはステータス値を返 します。このステータス値は、コマンドが返した結果を表し ています。一般的に、値が0以外の場合はなんらかのエラーを 表すものです。 –25– new (CS) load、save (CS) new()コマンドは、モデラー・システムを完全に初期化しま load()および save()を使うと、ディスク上のLightWave す。データを含むレイヤーすべてがクリアされ、内部構造お オブジェクトにアクセスできます。これらのコマンドは、そ よび設定が起動時の値にリセットされます。 のとき選択されているフォアグラウンドレイヤー内のデータ new()コマンドは、ディスプレイ設定(たとえばウインドウ に対して有効です。 の位置)もリセットするかどうかを示すブールパラメータ status load(string) (true/false )をオプションで受け取ります。この指定が status save(string) ない場合のデフォルトは、trueです。 void new(リセット) setlayer、setblayer (CS) リセット: setlayer()およびsetblayer()の2つの関数を使うとス ブール; 画面のリセット クリプトプログラマは、それぞれフォアグラウンドレイヤー セーブしていない作業はすべて失われます。またこの およびバックグラウンドレイヤーのどちらをアクティブにす コマンドはアンドゥできません。 るかを動的に選択できます。 それぞれの関数は、アクティブとして選択するレイヤーを示 undo (CS) す整数値の配列またはいくつかの整数値を受け取ることがで undo()を呼び出すと、オブジェクトに加えた変更をもとに きます。Ver.5.6までのLightWave Modelerでは、1から10ま 返すことができます。アンドゥできる回数は、L i g h t W a v e- でのレイヤーが実装されています。 Modelerコンフィグファイル(LWM.CFG)で指定できます。 void setblayer(レイヤー1[,レイヤー2・・・レイヤー10]) void undo(void) レイヤーn: delete (CS) 整数; レイヤー番号 void setblayer(layers) delete()は、そのとき選択されているフォアグラウンドレ レイヤーn: イヤー内のポイント/ポリゴン情報をすべて消去します。 整数; レイヤー番号 lyrfg , lyrbg (IN/1.2) void delete(void) このコマンドは選択されているレイヤーのナンバーを返しま cut,copy,paste (CS) す。フォアグラウンドとしてレイヤーが選択されている場合 このコマンドを使うと、モデラーの内部データクリップボー はlyrfg()を使用し、バックグラウンドとしてレイヤーが選 ドを管理できます。ほとんどのモデラーコマンドの場合と同 択されている場合はlyrbg()をを使用します。レイヤーナン 様、これらが有効なのは、そのとき選択されているフォアグ バーは1から10までの値です。 ラウンドレイヤーのみです。 このコマンドが返す値を配列にアサインすることはできませ んが、配列ではない変数に連続的にアサインすることはでき void cut(void) ます。通常、このコマンドは、Lscriptが設定を変える前にユ void copy(void) ーザーが選択しているレイヤーを記憶するために使用します。 void paste(void) スクリプトが終了する時点で、このコマンドによって得た値 –26– をlyrsetfg()に送る(配列がアクティブなバックグラウン lyrswap (CS/1.2) ド情報を保持している場合は lyrsetbg())ことでユーザの lyrswap()を使用することで、レイヤーの選択状態を簡単 元の設定に戻すことができます。 に反転させることができます。フォアグラウンドレイヤーは バックグラウンドレイヤーとなり、バックグラウンドレイヤ lyrfg(void) 返す値: ーはフォアグラウンドレイヤーとなります。 整数[]; 一つ以上のレイヤーの値 このコマンドはシングルクオート (')キーを押して、レイヤ ーをスワップさせるのと同じ働きをします。 lyrbg(void) 返す値: 整数[]; 一つ以上のレイヤーの値 void lyrswap(void) lyrdata,lyrempty (IN/1.2) lyrsetfg, lyrsetbg (IN/1.2) これらの関数はともにレイヤーナンバーの配列を返します。 これらの関数は整数の配列、または整数の変数を受け取り、 lyrdataはメッシュデータが含まれているレイヤーナンバー を返し、 lyremptyは何も含まれていないレイヤーナンバー 複数あるは一つのレイヤーを選択状態にします。LightWave のモデラーのレイヤーナンバーは1から10まであります。 を返します。 void lyrsetfg(レイヤー1[,レイヤー2・・・レイヤー10]) また、これら関数はレイヤーがフォアグラウンドとして選択 レイヤーn: 整数; レイヤーナンバー されているか、バックグラウンドとして選択されているか、 あるいは全く選択されていないかにかかわらず、レイヤーの void lyrsetfg(レイヤー1[,レイヤー2・・・レイヤー10]) 値を返します。 レイヤーn: 整数; レイヤーナンバー lyrdata(void) 返す値: fixedflex (CS) 整数[]; 一つ以上のレイヤーの値 lyrempty(void) この関数を使うとスクリプトプログラマは、フレックストラ 返す値: ンスフォーメーションを呼び出す他のモデラーコマンド用の 整数[]; 一つ以上のレイヤーの値 演算パラメータを作ることができます。こうしたフレックス コマンドには、twist()およびtaper()があります。 yremptyfg, lyremptybg (IN/1.2) lyremptyfg() とlyremptybg() はそれぞれ、選択され fixedflex()は、関数が指定軸に沿った固定範囲で処理が行 ているフォアグラウンドまたはバックグラウンドの空きレイ われるように、これらのフレックス関数の演算パラメータを ヤーを返します。 設定します。また、イーズメント "i"(イーズイン)または "o"(イーズアウト)をフラグを使って指定することもでき lyremptyfg(void) 返す値: ます。 整数[]; 一つ以上のレイヤーの値 lyremptybg(void) status fixedflex(軸,開始点,終点,イーズメント) 返す値: 軸: 定数; X,YまたはZ 開始点: 数値; 度数で表した範囲の開始点 開始点: 数値; 度数で表した範囲の終点 イーズメント: 文字; "i"または"o" 整数[]; 一つ以上のレイヤーの値 –27– autoflex (CS) shear (CS) fixedflex()と同様、この関数はフレックストランスフォ move()と同様shear()も、選択されたポイントを指定した ーメーション関数の演算パラメータを修正します。しかしこ 値でオフセットをします。しかし、ポイントの移動は の関数は、特定の磁極に沿った自動範囲でフレックスコマン fixedflex()または autoflex()コマンドにより設定さ ドの演算が進むようにパラメータを設定します。 れたフレックス軸に沿ってのみ行われることにご注意くださ い。オフセットは、選択されたポイントの中心からの相対距 status autoflex(軸,極性,イーズメント) 軸: 離で、原点からの距離ではないことに注意してください。 定数; X、YまたはZ 極性: 文字; "+"または"-" イーズメント: 文字; "i"または"o" void shear(offset) オフセット: ベクトルまたは数値;すべての軸に適用されるオフセット値 deformregion (CS) void shear(xオフセット, yオフセット, zオフセット) このコマンドは、 vortex()および pole()といった変形関 xオフセット: 数がそのオペレーション中に使う3 D空間領域を確立します。 yオフセット: 数値; Y軸方向のオフセット zオフセット: 数値; Z軸方向のオフセット オプションの軸が省略されると、変形は半径で指定した範囲 数値; X軸方向のオフセット 内の全方向に有効となります。軸が指定されると、有効範囲 magnet (CS) はその特定の軸に沿ったものになります。 magnet()もまた、選択されたポイントに指定された値でオ フセットするものですが、移動は deformregion()コマン status deformregion(半径[,中心点[,軸]]) 半径: ベクトルまたは数値; 範囲の半径 中心点: ベクトルまたは数値; 範囲の中心点 軸: 定数; X、YまたはZ ドで設定した変形領域に収まります。 void magnet(offset) オフセット: move (CS) move()は、選択されたポイントを指定した値でオフセット ベクトルまたは数値;すべての軸に適用されるオフセット値 void magnet(xオフセット, yオフセット, zオフセット) します。オフセットは、選択されたポイントの中心からの相 xオフセット: 対距離で、原点からの距離ではないことに注意してください。 yオフセット: 数値; Y軸方向のオフセット zオフセット: 数値; Z軸方向のオフセット void move(オフセット) オフセット: ベクトルまたは数値;3本の軸に沿った移動オフセット rotate (CS) rotate()は、選択されたポイントを指定された座標軸に沿 void move(xオフセット, yオフセット, zオフセット) xオフセット: yオフセット: 数値; X軸方向のオフセット って指定された度数だけ回転します。 数値; X軸方向のオフセット 数値; Y 軸方向のオフセット status rotate(度数,軸[,中心点]) zオフセット: 数値; Z軸方向のオフセット 度数: –28– 数値; 回転する度数 軸: 定数; X 、YまたはZ 中心点: ベクトルまたは数値; 回転の中心 twist (CS) status scale(量[,中心点]) rotate()と同様に、 twist()は選択されたポイントを指 量: ベクトルまたは数値;拡大縮小係数 定された軸を中心として指定された度数だけ回転します。し 中心点: ベクトルまたは数値; スケールの中心点 かしポイントは、 fixedflex()または autoflex()コマ ンドで指定したフレックス軸を中心として移動します。 taper (CS) taper()はscale()に似ていますが、fixedflex()また status twist(度数,軸[,中心点]) 度数: 数値; ひねる度数 はautoflex()が設定したフレックス軸でその有効範囲が定 軸: 定数; X、YまたはZ 義されている点が異なります。 中心点: ベクトルまたは数値; ひねりの中心 status taper(量[,中心点]) vortex (CS) 量: ベクトルまたは数値; 先細り係数 中心点: ベクトルまたは数値;先細りの中心点 vortex()もまた、選択されたポイントを指定された軸を中 心として指定された度数だけ回転します。しかしこのコマン pole (CS) ドは、deformregion()コマンドにより指定したパラメー taper()と同様、 pole()もscale()ファミリーの1つで すが、これは deformregion()を使ってその有効範囲を制 タを持つ変形領域内で演算を行います。 限した変形領域を使う点が異なります。 status vortex(度数,軸[,中心点]) 度数: 数値; ねじる度数 軸: 定数; X、YまたはZ 中心点: ベクトルまたは数値; ねじりの中心 status pole(量[,中心点]) scale (CS) 量: ベクトルまたは数値;ポール係数 中心点: ベクトルまたは数値; ポール中心点 bend (CS) scale()は、選択されたポイントを与えられた係数を使って このコマンドは選択されたポイントを、オプションで指定し 拡大縮小します。オプションで中心を指定します。係数を1と た中心点の回りで一定方向に指定角度だけ曲げるのに使いま すれば、どの軸方向でもポイントの位置は変わりません。 す。bend()は、 fixedflex() または autoflex() のい たとえば、オブジェクトをX軸およびY軸方向に1/2縮小して、 Z軸方向には縮小しない場合は、次のようになります。 ずれかにより設定したフレックス軸に固定します。 status bend(角度,方向[,中心点]) 量: 数値;ベンドする角度 例 方向: 数値;角度で指定したベンドの方向 scale(<.5,.5,1>); 中心点: ベクトルまたは数値; ベンドの中心点 この例では、センターベクトルが与えられていないことにご 注意ください。この場合、センターベクトルはデフォルトで jitter (CS) 原点(つまり<0,0,0>)となり、各軸の値はここからの相対 jitter()は、選択されたポイントを次に挙げる4つの変位 距離となります。 関数で乱数処理します。 –29– UNIFORM GAUSSIAN NORMAL ポイントは、一定の範囲に分布します。(デフォルト) makebox (CS) 開始点の周囲にベル曲線のオフセットを適用します。 このコマンドは、指定された大きさと指定された数の面を持 ローカルの面に対する法線の両方向にポイントを移動し つ3次元のボックスオブジェクトを作ります。 ます。 RADIAL 中心点パラメータにより与えられた中心点を通過する直 status makebox(底辺,上辺[,セグメント数]) 線に沿って、ポイントを両方向に移動します。 jitter()関数のプロトタイプは次のようになります。 status jitter(半径[,タイプ[,中心点]]) 半径: 数値; ジッター半径 タイプ: 定数; UNIFORM,GAUSSIAN,NORMAL, または ベクトルまたは数値; 低い方の境界ポイント ベクトルまたは数値;高い方の境界ポイント セグメント数: ベクトルまたは数値;ボックスセグメント数 makeball (CS) このコマンドは、3次元の地球のような球体を作ります。 RADIAL 中心点: 底辺: 上辺: status makeball(半径,サイド数,セグメント数[,中心点]) ベクトルまたは数値;RADIAL が使う中心点 半径: ベクトルまたは数値;球体の半径 サイド数: 整数; 球面サイドの数 smooth (CS) セグメント数: 整数; スフィアセグメントの数 smooth()は、関連ポイントを使っているポリゴン内の"ねじ 中心点: ベクトルまたは数値; 球体の中心 れ"を取り去ります。 maketesball (CS) status smooth(繰り返し数[,強さ]) 繰り返し数: 数値; 繰り返す回数 強さ: 数値; スムース処理の強さ maketesball()を使うと、モザイク状の球体を作ることが できます。モザイク状の球体とは、4角形ポリゴンを1 2角形 にしたものです。レベルパラメータが、適用するモザイク処 理の量を決定します。 quantize (CS) このコマンドを使うと、サイズパラメータにより定義された3 status maketesball(半径,レベル[,中心点]) 次元グリッドの中に、選択ポイントをすべて配置することが 半径: ベクトルまたは数値; 球体の半径 できます。 レベル: 整数; モザイク化のレベル 中心点: ベクトルまたは数値; 球体の中心 status quantize(サイズ) サイズ: ベクトルまたは数値;3 次元グリッドを定義します makedisc, makecone (CS) makedisc()コマンドを使用すると、指定した数の側面とセ mergepoints (CS) グメントを持つ円柱状オブジェクトを作ることができます。 mergepoints()を使うと、特定の最短距離内にある選択さ 側面の数が多ければそれだけなめらかな円柱になります。 れたポイントを結合できます。オプションの距離値を省略し makecone()は、makedisc()と同じパラメータを受け取 ります。しかしmakecone()は、円柱ではなく、円錐を作成 た場合は、それは自動的に計算されます。 status mergepoints([距離]) 距離: します。 数値;ポイント間の最短距離 –30– status makedisc(半径,上面,底面,軸,側面数,セグメント数 [,中心点]) maketext(文字,インデックス[,コーナータイプ[,字間[,スケー ル[,軸[,位置]]]]]) 半径: ベクトルまたは数値; 底面円の半径 返す値: 数値;でき上がるモデラーオブジェクトの幅(単位m) 上面: 数値; 軸上の円筒の頭 文字: 文字列; 変換するテキスト 整数; fontload()が返すフォントインデックス 底面: 数値; 軸上の円柱の底面 インデックス: 軸: 定数; X、YまたはZ コーナータイプ: 定数; SHARPまたはBUFFERED 側面数: 整数; 側面の数 字間: 数値; 文字の間隔 セグメント数: 整数; セグメントの数 スケール: 数値; 文字のスケーリング係数 中心点: ベクトルまたは数値; オブジェクトの中心 軸: 定数; X、YまたはZ 位置: ベクトルまたは数値;文字の最初の位置 maketext (CS) この関数は、文字列の形をしたモデラーオブジェクトを作り lathe (CS) ます。できあがるオブジェクトは、fontload()関数でロー lathe()は、カレントオブジェクトを指定された軸の回りで ドされた文字フォントの形となります。fontload()により 自転させ、指定された数の側面を持つ新しいオブジェクトを 返されるフォントインデックス値が、 maketext()関数に渡 作ります。 されなければなりません。 Lathe(回転体)処理されるオブジェクトは、通常は2次元テ 次の短いLScriptコードは、これらの関数(logo.lsスクリプト ンプレートです。 例に入っています)の使い方の実例です。 status lathe(軸,側面数[,中心点[,終了角[,開始角]]]) 例 軸: 定数; X, Y, Z findex = fontload(fontName); 側面数: 整数; 新しいオブジェクトの数 if(findex != nil) 中心点: ベクトルまたは数値; 回転体処理をする際の中心 終了角: 数値; 度数であらわした終了角 開始角: 数値; 度数であらわした開始角 { maketext("LScript",findex); maketext()は、できあがるモデラーオブジェクトの幅(単 extrude (CS) 位はメートル)を返します。 extrude()を使うと、オブジェクトを指定された軸方向に 延ばせます。オプションでセグメントの追加もできます。 status extrude(軸,距離[,セグメント数]) 軸: 定数; X 、YまたはZ 距離: 数値; 軸方向に延ばす距離 セグメント数: 整数; セグメントの数(デフォルトは1) mirror (CS) このコマンドは、指定されたデータを1 8 0゜回転しての面対 称体を作ります。 –31– status mirror(軸,オフセット) status pathextrude(ファイル名[,ステップ[,開始値[,終了 軸: 定数; X 、YまたはZ 値]]]) オフセット: 数値; 軸と平面とのオフセット pathclone, pathextrude (CS) これら2つのコマンドを使うと複製たり、LightWave3D Layoutで作成してセーブしたモーションパス方向にオブジェクト ファイル名: 文字列; モーションパス・ファイルの名称 ステップ: 数値; 作成するオブジェクト/ セグメントの数 開始値: 数値; 開始カウント 終了値: 数値; 終了カウント railclone、railextrude (CS) を延ばすことができます。オプションで開始、終了およびス railclone()および railextrude()は、オブジェクト の複製をしたり延ばすという点で p a t h c l o n e ( ) および テップパラメータをループの計数の引数とすることができま す。これらを省略した場合は、モーションパスファイルに埋 pathextrude()によく似ています。しかしrailコマンドは、 め込まれている開始および終了フレームを開始および終了と モーションパスファイルではなくモデラー曲線を使って演算 して使用し、ステップ値はデフォルトで1となります。これら します。いずれのコマンドが使う曲線(Rail)も、そのときア の値を指定すると、モーションパスファイル内の値を書き換 クティブなバックグラウンドレイヤーになければなりません。 えることができます。 status railextrude(セグメント,分割,フラグ[,強さ]) 開始および終了値を変えれば、オブジェクトをこれらの値で 表されるモーションパス部にのみ従って複製処理をしたり延 セグメント: 数値; セグメントカウント(0=compute) ばすことができます。たとえば、横断するのに3 3 0フレーム 分割: 定数; KNOTSまたはLENGTHS フラグ: 文字列; 方向 強さ: 数値; スケールされる量 必要なモーションパスをロードして、次のようなコマンドを 発行すると、 例 axisdrill (CS) pathextrude("my.mot",1,200,300); axisdrill()は、アクティブなバックグラウンドレイヤー 内の2次元オブジェクトをテンプレートとして使って、アクテ オブジェクトは、モーションパスのフレーム2 0 0の位置から ィブなフォアグラウンドレイヤー内にそのオブジェクトの形 延びはじめ、フレーム3 0 0の位置まで続けられます。フレー の"穴を開け"ます。 axisdrill()には、次のようなドリル ム1から199までと、フレーム301から330までの範囲でオブ 処理が可能です。 ジェクトが延びる部分のパスは空になります。 CORE pathclone()を使ってオブジェクトを複製すると、各ステ フォアグラウンドのポリゴンにバックグラウンドのテン プレートの形に合う穴を開け、その内側を残します。 ップごとに一意なオブジェクトを作ることができます。 TUNNEL pathextrude()を使ってオブジェクトを延ばすと、各ステ COREとは反対に、テンプレートの形に合う部分のポリ ゴンを取り除き、外側部分を残します。 ップごとに新しいセグメントをつけ加えて新しいオブジェク SLICE トが1つできます。 テンプレートのエッジに沿って切り開き、フォアグラウ ンドオブジェクトに穴を開けます。 STENCIL どちらのコマンドも、カウントおよびタイプというパラメー SLICEと同じですが、テンプレートの形に収まるすべて のポリゴンにサーフェイスの名称を割り当てられます。 タを受け取ります。 –32– ステンシル処理を指定する際は、オプションでサーフェイ bevel (CS) ス・パラメータを使います。 bevel()コマンドを使うと、インセットおよびシフト量を指 定してオブジェクトにベベルエッジを追加できます。 status axisdrill(操作,軸[,サーフェイス]) 操作: 定数; CORE,TUNNEL,SLICE またはSTENCIL status bevel(インセット,シフト) 軸: 定数; X, YまたはZ インセット: 数値;ポリゴン平面方向に対する一様な変位量 サーフェイス: 文字列; (STENCILの場合)サーフェイスの名称 シフト: 数値;ポリゴン平面に垂直方向の変位量 soliddrill (CS) shapebevel (CS) soliddrill()は、ほとんど axisdrill()と同じですが、 shapebevel()もまた、オブジェクトに面取りエッジを追 次の点が違います。a)これはアクティブなバックグラウンド 加するものです。しかしこれは、文字列中のインセット/シフ レイヤー内の3次元オブジェクトを使います。b)この場合は、 ト値を何組も受け取ることができます。文字列内には、イン 2つのオブジェクトのボリューム(フォアグラウンドおよびバ セット/シフト値を空白で区切って入れます。 bevel()関数 ックグラウンド)が重っていなければなりません。 をいくつか反復しても同じ効果が得られますが、その結果は つねに正しいわけではありません。自己反復効果が起こるた status soliddrill(操作[,サーフェイス]) 操作: 定数; CORE,TUNNEL,SLICEまたはSTENCIL サーフェイス: 文字列; (STENCILの場合)サーフェイスの名称 めです。 スクリプト例r o u t e r . l sでは、このコマンドを多用してこの効 果を出しています。このコマンドの短いコード例を、このス クリプト例から引用します。 boolean (CS) このコマンドは、アクティブなフォアグラウンドレイヤーの 例 オブジェクトと、アクティブなバックグラウンドレイヤーの s = string(-wide," ",wide," ",-wide," ",deep オブジェクトを結合します。次の4種類のブーリアン処理をサ / 2); ポートしています。 UNION shapebevel(s); 各オブジェクトボリュームを1つの新しいオブジェクトに まとめます。2つのオブジェクトが重なる部分の内部サー フェイスは削除されます。 SUBTRACT status shapebevel(パターン) バックグラウンドオブジェクトのボリュームをフォアグ パターン: ラウンドオブジェクトから取り去ります。 INTERSECT ADD 文字列;inset/shiftの対 2つのオブジェクトの共通領域からオブジェクトを作りま す。 smoothshift (CS) バックグラウンドオブジェクトをフォアグラウンドオブ このコマンドは、選択したポリゴンを指定したオフセットだ ジェクトに加算します。ポリゴンが交わるところには共 け移動します。最大角度以上の角度を指定すると、サーフェ 通のエッジが作られます。 イスが壊れます。 status boolean(操作) 操作: このコマンドのプロトタイプは次のようになります。 status smoothshift(オフセット[,最大角度]) 定数; UNION,SUBTRACT,INTERSECTまたは ADD –33– オフセット: 数値; 移動のオフセット 最大角度: 数値; 度数で表した最大角度 flip (CS) status removepols(void) flip()を使うと、選択したポリゴンのサーフェイスノーマ ルを裏返します。これを使って、モデラー曲線の方向を逆に unifypols (CS) することもできます。 unifypols()は、重なりあうポリゴンを結合します。 status flip(void) status unifypols(void) triple (CS) subdivide (CS) triple()を使うと、アクティブなフォアグラウンドレイヤ subdivide()を使うと、すべての三角形を小さな三角形4 ーにあるポリゴンすべてを三角形に変換します。 つに分割します。このコマンドはまた、四辺形をさらに小さ な四辺形に分割できます。 subdivide()には、3つの形式 status triple(void) があります。 特に、オブジェクトを分割する前(特に4つの側面を持つポリ FLAT ゴンの場合)、t r i p l e ( )するとよいでしょう。次の短いコ ポリゴンを分割して、新規のポリゴンを元のものと同じ 平面上に置きます。 ード例はその好例です。 SMOOTH 分割されたポリゴンがもとのものと同じ曲率を保持する ようにします。 例 METAFORM points = polycount(); なめらかさの度合を最大レベルにします。より細かなも のほどより細かくスムース処理をします。 if(points[5] or points[6]) status subdivide(モード,最大角[,最大角]) //4つ以上の側面を持つポリゴンがあります triple() モード: 定数; FLAT, SMOOTHまたはMETAFORM 最大角: 数値; 度数で表した最大角 subdivide(METAFORM); fracsubdivide (CS) freezecurves (CS) fracsubdivide()はsubdivide()に似ていますが、位 freezecurves()を使用すると、選択したモデラー曲線を 置関数としてフラクタル変位値を新規の頂点それぞれに適用 ポリゴンに変換できます。 します。 status freezecurves(void) status fracsubdivide(モード,フラクタル[,最大角]) モード: 定数; FLAT, SMOOTHまたはMETAFORM alignpols (CS) フラクタル: 数値; フラクタル変位量 このコマンドは、選択したポリゴンすべてを"反転して"(でき 最大角: 数値; 度数で表した最大角 る限り)同方向に向くようにします。 selpoint (CS) status alignpols(void) 全LScriptコマンド中、パラメータ構造がもっとも複雑なもの のひとつです。 s e l p o i n t ( ) には2つの メジャーモード removepols (CS) r e m o v e p o l s ( ) は、選択したポリゴンすべてを削除して、 (S E TとC L E A R )と、多くのマイナーモードがあります。そ そのポイントのみを残します。 –34– れぞれには、独自のパラメータカウントとパラメータタイプ があります。selpoint()のメジャーモードは次のような動 status selpoint(メジャーモード[,マイナーモード,パラメー 作をします。 タ]) もしマイナーモードが次に存在しこれを SETすると、選択す メジャーモード: 定数; SETまたはCLEAR るべきポイントを定義できます。またマイナーモードが次に マイナーモード: 定数; VOLUME, CONNECT,NPEQ,NPLT またはNPGT 存在しこれを CLEARすると、選択を解除するポイントを定義 パラメータ: できます。これらの2つのメジャーモードのいずれかが、かな 値; 前述のマイナーモードパラメータ らずselpoint()の最初のパラメータとなります。この2つ はかならず付けなければならないパラメータですが、パラメ selpolygon (CS) ータリストにこれだけを指定することも可能です。(つまり、 selpolygon()は、selpoint()と同種のコマンドで、こ selpoint(CLEAR)とすれば、そのとき選択されている れを使うとスクリプトのプログラマは、単一ポイントではな くポリゴン全体を選択/選択解除できます。このメジャーモー ポイントすべての選択を解除します) 。 ドはselpoint()と同じですが、マイナーモードの数や機能 selpoint()がサポートするマイナーモードを使うと、スク は異なります。 リプトのプログラマはポイントをさまざなまな方法で選択で マイナーモード 引数 きます。 VOLEXCL selpoint()のマイナーモードを次にまとめます。 を示す2つのベクトル。 マイナーモード 引数 VOLUME バウンディングボックスのローポイントとハイポイン VOLINCL トを示す2 つのベクトル。 CONNECT なし NPEQ ポリゴンが含むべきポイント数を示す数字。 CONNECT NVEQ NVLT なし ポリゴンが持つべき頂点数を示す数字。 ポリゴン内が持つべき頂点数の最高値から1 を引いた数 字。 ポリゴン内にあるべきポイント数の最高値から1 を引 SURFACE ポリゴンが持つべき頂点数の最低値に1を加えた数字。 ポリゴンに割り当てられているサーフェイスの名称を示 す文字列。 いた数字。 NPGT バウンディングボックスのローポイントとハイポイント を示す2つのベクトル。 NVGT NPLT バウンディングボックスのローポイントとハイポイント ポリゴン内にあるべきポイント数の最低値に1を加え た数字。 スクリプトは、かならず selmode() コマンドを使っ てU S E Rモードにしなければなりません。そうしない と、selpoint()(およびselpolygon())は正しく動作 しません。 次に、selpoint()のプロトタイプを示します。 –35– FACE CURVE NONPLANAR なし なし 平面の選択限界を示すオプションの数値。 setsurface (CS) setsurface()は、新規のデータが割り当てられるサーフ selpoint()の場合と同様 selpolygon() を正し ェイスの名称を設定します。もしこれが存在しなければ、新 く 動 作 さ せ る に は 、 ス ク リ プ ト セ ッ シ ョ ンは 規に作られます。 s e l m o d e ( )コマンドを使ってかならずUSERモードにして おかなければなりません。 status setsurface(名称) 名称: status selpolygon(メジャーモード[,マイナーモード,パラメ ータ]) メジャーモード: 定数;SETまたはCLEAR マイナーモード: 定数; VOLEXCL,VOLINCL,CONNECT, getdefaultsurface (IN) このコマンドは、そのとき選択されているサーフェイスの名 称を返します。 NVEQ,NVLT,NVGT,SURFACE,FACE, パラメータ: 文字列; 新規のサーフェイスの名称 CURVEまたはNONPLANAR varies; 前述のマイナーモードパラメータ getdefaultsurface(void) 返す値: 文字列; サーフェイス名 selinvert (CS) changesurface (CS) このコマンドは、そのときの選択状態を逆にします(つまり changesurface()は、そのとき選択されているポリゴン 選択されアイテムは選択解除となり、非選択アイテムが選択 すべてを、新規のまたは既存のサーフェイス名称に割り当て されます) 。 ます。 status selinvert(void) status changesurface(名称) 名称: selhide (CS) 文字列;選択されたポリゴンが所属することになるサ ーフェイスの名称 selhide()は、選択されているデータか選択されていない データかのどちらかを見えなくします。 SELECTEDオプショ ンを使うと選択されているデータを隠し、UNSELECTEDオプ nextsurface (IN) ションを使うと選択されていないデータを隠します。 内 部 リ ス ト を 閲 覧 で き ま す。パラメータを付けずに nextsurface()を使うと、モデラーのサーフェイス名称の status selhide(選択) nextsurface()を呼び出すと、モデラーのリスト内の最初 選択: のサーフェイス名称を返します。nextsurface()にサーフ 定数;SELECTEDまたは UNSELECTED ェイスの名称を渡すと、その次のサーフェイス名称を返すこ selunhide (CS) とができます。与えられたサーフェイス名称がリストの最後 このコマンドは selhide()と同種のもので、隠されたデー のエントリの場合は、値nilを返します。 タを見えるようにするものです。 status selunhide(void) –36– 例 copysurface (IN/1.2) // 現在のサーフェイス名称すべてを表示する このコマンドはモデラー内部のサーフェイスリストに新しい サーフェイス名を加え、既存の任意のサーフェイスの属性を 新しいサーフェイスにコピーします。 var surface = nextsurface(); info(surface); status copysurface(オリジナル,新規) while(true) オリジナル: 文字列; 既に存在しているサーフェイス名 { 新規: 文字列; 新しいサーフェイス名 if((surface = nextsurface(surface)) == nil) fontcount (IN) break; fontcount()は、そのときモデラーにロードされているフ info(surface); ォント数を返します。内部フォントリストが空の場合は、 nilを返します。 } fontcount(void) プロトタイプは次のようになります。 返す値: 整数; ロードされているフォント数 nextsurface([名称]) 返す値: 文字列; サーフェイスの名称 fontindex (IN) 名称: 文字列; オプションサーフェイス名称 fontindex()にフォントの名称を与えると、そのフォント のインデックス値を返します。指定したフォントが見つから renamesurface (IN) ない場合は、nilを返します。 renamesurface()を使うと、スクリプトのプログラマは 既存のサーフェイス名称を変更できます。名前を変更すると、 もとのサーフェイス名称は失われます。 fontindex(名称) 整数; フォントインデックス値 返す値: 名称: 文字列; フォント名称 status renamesurface(オリジナル,新規) オリジナル: 文字列; 既存のサーフェイス名称 fontname (IN) 新規: 文字列; 新規のサーフェイス名称 fontload()または fontindex()が返したフォントイン デックスを与えられると、fontname()は指定されたフォン createsurface (IN) ト名称を返します。与えられたインデックスが有効ではない このコマンドは、新規のサーフェイス名称をモデラーの内部 ときは、nilを返します。 リストに追加します。その名称を持つサーフェイスがすでに fontname(インデックス) 存在する場合は、なにも起こりません。 status createsurface(名称) 名称: 文字列; 新規のサーフェイス名称 –37– 返す値: 文字列またはnil; フォント名称 インデックス: 整数; フォントインデックス値 fontload (IN) 他のプラグインを呼び出すときに使う名称は、プラグインメ fontload()を使うと、スクリプトのプログラマはポストス ニューボタン に現れるものと同じでなければなりません。プ クリプトフォントをモデラーにロードして、テキスト作成コ ラグインに渡す引数は、そのプラグインがどのようにプログ マンドで使うことができます。特定のフォントでの作業を終 ラムされているかに依存します。プラグインはほとんどの場 えたら、これと同類のコマンド fontclear()(後述)を呼 合、パラメータを受け取りません。仕様として、そのように び出さなければなりません。 は設計されていないのです。 例 status cmdseq(名称[,引数]) var fontName = getfile("Select a Font"); 名称: 文字列; プラグイン名称 引数: 文字列; プラグインにより値は変化します if(fontName == nil) return; swaplayers (CS) var findex = fontload(fontName); swaplayers()を使うと、そのとき選択されているレイヤ if(findex != nil) ーを逆にできます。フォアグラウンドレイヤーが選択されて { いればバックグラウンドレイヤーを選択することになり、選 maketext("LScript",findex); 択されているバックグラウンドレイヤーは、アクティブなフ fontclear(findex); // 直ちにフォントを解放 ォアグラウンドレイヤーになります。 ・・・ このコマンドは、モデラー内でレイヤー切り替えに使う一重 引用符(')をタイプした場合と同じです。 プロトタイプは次のようになります。 void swaplayers(void) fontload(名称) 返す値: 整数; フォントインデックスまたはnil 名称: 文字列; オプションでパスを付けたフォントの名称 getfile (CS) getfile()を使うと、LScriptにファイル選択用インターフ fontclear (IN) ェイスを提供できます。ユーザーにファイルを指定してもら fontload()コマンドを使ってロードしたモデラーフォント が必要なくなったら、fontclear()を呼び出します。 う必要がある場合、 getfile()がファイル選択ダイアログ status fontclear(インデックス) インデックス: ボックスを表示して、ユーザーが選択したファイルの名称 (パス情報も)を返します。ユーザーがキャンセルすれば、 getfile()はnilを返します。 整数; フォントインデックス値 getfile()のパラメータすべては省略可能です。ダイアロ グボックスのタイトル、ファイル名称マスク、デフォルトデ cmdseq (CS) ィレクトリも指定できます。 cmdseq()を使うと、モデラーにインストールされている他 のプラグインを LScriptで呼び出せます。このプラグインへの インターフェイスは単一方向性です。つまり、情報を渡すこ とはできますが、戻り値は返せません。 –38– getfile([タイトル[,マスク[,ディレクトリ]]]) getempty(void) タイトル: 返す値: 文字列またはnil; ファイルの名称、ダイアログ 整数[]; 1つ以上のレイヤー値 ボックスタイトル マスク: 文字列;使用するファイルマスク( ワイルドカードも getemptyfg(void) 使用可能) ディレクトリ: 返す値: 文字列; 開始のディレクトリパス 整数[]; 1つ以上のレイヤー値 getemptybg(void) fglayers, bglayers (IN) 返す値: fglayers()コマンドは、フォアグラウンドでそのとき選択 されているモデラーレイヤーを返します。 整数[]; 1つ以上のレイヤー値 getemptyfg()および getemptybg()は、それぞれその またbglayers()コマンドを呼び出せば、バックグラウンド とき選択されているフォアグラウンドレイヤーとバックグラ レイヤーが返ります。1から1 0までの範囲のレイヤー番号が ウンドレイヤー内の空レイヤーを返します。 返されます。これらのコマンドからの戻り値を配列に割り当 てることがひんぱんにありますが、非配列変数にも割り当て moninit (IN) ることができます。その場合は、最初の戻り値のみが保存さ このコマンドは、モニター制御コマンドに対するエントリー れます。 ポイントです。 moninit()は、スクリプトのモニターウイ 普通、LScriptがセッティングを変更する前にこれらのコマン ンドウを初期化します。このコマンドは、他のモニターコマ ドを使って、ユーザーがアクティブに選択したレイヤーを覚 ンドが使われる前に呼び出します。 えます。変更後は、これらの値をsetlayer()(または配列 モニターシステムというものは、基本的には進行インジケー にアクティブなバックグラウンド情報があれば ターです。進行インジケーターにより、ユーザーは進行状況 を知ったり、コンピュータが停止していないことなどを確認 setblayer()に)渡して、ユーザーのもとのレイヤーセッ できます。作業を完了するまでいくつのステップが必要かを ティングを復元します。 伝えて、モニターを初期化します。モニターシステムはこの getempty, getemptyfg, getemptybg (IN) 値を利用して、グラフィカルなプログレスバーを表示します。 これらのコマンドは、オブジェクトデータを含まないレイヤ これを見ると、ユーザーは完了までの残り時間がわかるので ーを返します。 す。 getempty()の場合、アクティブか非アクティブかに関わら オプションで、モニターダイアログボックスの表示中にユー ず、空のレイヤーすべてが返されます。 ザーに見せたいメッセージを与えることができます。モニタ ーウインドウは、実際にはダイアログボックスだという点に ご注意ください。ユーザーは、ダイアログボックスのキャン セルボタンをいつでも押すことができます。このアクション はmonstep()関数(後述)が処理します。 –39– デラーの他の部分が使えるようにします(モニターウインド void moninit(ステップ[,メッセージ]) ステップ: 整数; 完了までのステップ数 メッセージ: 文字列; ユーザーに表示したいメッセージ ウをアクティブにできるのは1度に1つのみです) 。 void monend(void) monstep (IN) reqbegin (CS) monstep()を使うと、進行インジケーターを指定したステ モデラーにはインターフェイス機構が装備してありますから、 ップだけ進められます。値が与えられていない場合、先に進 ユーザーはプラグインをインタテクティブに操作できます。 めるステップ数はデフォルトの1になります。より大きな値を LScriptはこの機構を起動して、スクリプトのプログラマが同 指定すれば、さらにプログレス・インジケーターを進めるこ 様の機能を利用できるようにします。reqbegin()は、これ とができます。 らのインターフェイス関数へのエントリーポイントです。 monstep()は、ブール値を返します。ほとんどの場合、こ reqbegin()が呼び出されると、モデラーの "リクエスタ"が の値はfalseです。しかし、ユーザーがモニターウインドウ 初期化されます。リクエスタとは、ユーザーからの情報や選 上のキャンセルボタンを押すと、このコマンドはtrueを返し 択事項を集めるための入力ダイアログボックスのことです。 ます。そうなった場合、スクリプトをできる限りすみやかに またこれは、情報やメッセージをテキストとして伝えるため 終了する必要があります。 にも使われます。 ブール値; キャンセルボタンが押されたときのみ r e q b e g i n ( )を呼び出すと、リクエスタモードに入ります。 その他のリクエスタ関連関数(たとえば、 addcontrol()) true を使うには、このモードがアクティブになっていなければな 整数; オプションの進める数 りません。また、終了するには reqend()を呼び出さなけれ boolean monstep([ステップ])// 整数; オプションの進める 返す値: ステップ数: ばなりませんが、リクエスタモード中の任意のときにスクリ 例 プトを終了できます。もし r e q e n d ( ) の発行を忘れても editbegin(); LScriptがこれを自動的に発行します。 ・・・ reqbegin()は、リクエスタダイアログで使うタイトル用に if(monstep()) 1つの引数を受け取ります。 { void reqbegin(タイトル) setlayer(fg); タイトル: setblayer(bg); editend(ABORT); 文字列; ダイアログボックスタイトル reqend (CS) return; reqend()は、リクエスタモードを終了する関数です。ユー } ザー入力のすべての処理が完了した後、リクエスタダイアロ グを閉じるにはかならずこれを使います。 monend (IN) このコマンドは、開いているプログレスウインドウを閉じて、 モニターシステムを完了してモニターシステムを解放し、モ –40– void reqend(void) reqpost (CS) 例 このコマンドは、必要なフィールドを設定してリクエスタダ ・・・ イアログの構築が完了したこと、そしてユーザーとの対話の name = "BillyBob"; ためにダイアログを表示したいことをリクエスタシステムに age = 18; 通知します。 c1 = ctlstring("Your name?",name); reqpost()は、与えられた値を使ってユーザーが処理を継 続したいのかそうではないのかを示すブール値( trueまたは c2 = ctlinteger("Your age?",age); ・・・ false)を返します。値 trueは、ユーザーがOKを選択した こと、つまり処理を始めることを示します。また false値が cltvector()はパラメータとして比較的柔軟なフォーマット 返れば、ユーザーは C a n c e lを選択したことになりますから、 を受け取ることができます。単一のベクトルデータタイプ、3 スクリプトを終了します。 つのフィールドを埋める単一の数値、あるいはそれぞれの編集 フィールドを初期化するために3つの別々の値をあてはめるこ reqpost(void) 返す値: とができます。 boolean; ユーザーが"OK"を選択すればtrue ctldistance ctldistance()関数は ctlnumber()と同様に使用する ctlstring, ctlinteger, ctlnumber, ctlvector, ctldistance, ことができます。しかし、得られた編集コントロールは、モ ctlchoice, ctltext, ctlcolor, ctlsurface, ctlfont (CS/1.2) デラーの現在のデフォルトの測定単位に基づいて表示・編集 これらの関数はモデラーLscriptで使われる一連のコントロー されます。 ルの生成を構成します。それぞれの関数はコントロールタイ 例 トルの最初のパラメータを受け取り、コントロール識別子を ・・・ 返し、後でにgetvalue()関数で使用します。 length = .25; コントロールは2番目のパラメータによって初期値が決められ c1 = ctldistance("Length",length); ます。 // デフォルト編集単位がキロメートルとなっている場合 // このフィールドの値は(.25 * 1000) = 250 メートルと // なります また、 c t l s t r i n g , c t l i n t e g e r , c t l n u m b e r , ctlvectorについては単純なデータタイプ、すなわち文字 列、整数、浮動小数点値、そして浮動小数点値によって構成 ・・・ されるベクトルを編集するコントロールを生成するために提 供されています。 ctlchoice ctlchoice()は3つのパラメータを必要とし、オプション として4つめのパラメータをとることができます。第1のパラ メータは他のすべてのコントロール生成関数と同様にコント ロールのタイトルです。第2のパラメータは整数値で、パネル が表示された時にあらかじめ選択されている初期値としてプ ッシュボタンを特定するために使われます。 –41– 第3のパラメータはボタンラベルとして使われる文字列を含む 他のコントロール関数と同様に、 ctltext()は静的テキス 配列参照か、あるいは同じデータを格納する関数コールへ直 トコントロールのコントロールハンドルを返します。しかし、 接置かれる初期ブロックです。選択番号は1から始まります。 コントロールは変化しないので、このハンドルは小さな値と なります。ダイアログボックスを再表示する前にテキストを 例 変更しない場合にはsetvalue()を使うこともできます。 booleans[1] = "Yes"; booleans[2] = "No"; ctlcolor choice = 2; // "No"を初期値に設定する c1 = ctlchoice("Use random このコントロールは ctlvector() と似ており、3つの別々 height?",choice,booleans); c t l v e c t o r ( ) が浮動小数点の編集ができるのに対し、 ctlcolor()によるフィールドには整数値しか入力すること の数値編集フィールドを持つコントロールを表示しますが、 オプションの4番目のパラメータは選択リストの配置を指定す ができません。 るために使われ、選択リストを垂直あるいは水平にすること ctlvector()と同様に、 ctlcolor()はパラメータタイ ができます。省略した場合は水平方向がデフォルトとして使 用されます。 プを組み合わせることも可能です。単一のベクトル型データ (3つのフィールドを全て整数値で埋める)あるいは、それぞ 例 れの編集フィールドで初期化するために3つの独立した整数値 choice = 1; を扱うことも可能です。 // "No" を初期値に設定し 垂直の選択リストを作成する c1 = ctlsurface, ctlfont ctlchoice("Quadrant?",choice,@"90","180","270 これら2つの関数はモデラーのサーフェイスとフォントの属性 "@,true); をそれぞれ管理することができます。生成されたコントロー ルは他のコントロールも多数保持しており、コントロール型 ctltext の特別な機能に関連づけられます。 ctltext()はリクエスタダイアログボックスに静的なテキ どちらの関数も第1のパラメータがコントロールタイトルとな ストを加えるために使われます。この静的テキストはユーザ ります。ctlsurface()は2番目の文字列パラメータがサー に対して特に指示をしたいときなどに使われます。また、 フェイスコントロールを初期化するためのサーフェイス名だ ctltext()は文字列型の変数を取り扱うこともでき、他の と認識します。ctlfont()の2番目のパラメータは整数値で、 すでにロードされているフォントのインデックスを示します。 コントロール生成関数と同様に最初の文字列は常にコントロ ールタイプとして扱われます。 LScript旧バージョンにあった、 addcontrolおよび, addtext関数は、削除されました。 例 ctltext("WARNING", getvalue (CS) //最初の要素はタイトル "This operation could take a long getvalue()を使うと、入力フィールド内の値を取得できま す。addcontrol() が返したコントロールハンドルを、こ time,","and create very many points if の関数に与えなければなりません。戻り値のタイプは、入力 Level is high"); フィールドのタイプに依存します。通常では、 a d d c o n–42– t r o l ( ) で入力フィールドを作るのに使ったもとの変数に getvalue()の戻り値を割り当てます。 listadd()を使うと、ユーザーコマンドメニューに表示す る名称を設定できます。また、選択事項の処理に使うサーバ ー(LScriptsの場合サーバの名称は"LScript")や、そのエント getvalue(ハンドル) 返す値: あらゆる型; フィールド内のデータ値 ハンドル: 整数; コントロールハンドル リーを表すファイルの名称(オプションでパスも)を設定で きます。 listremove()を使うと、エントリーをユーザーコマンド setvalue (CS) メニューから削除できます。メニューエントリーの名前を指 reqend()が呼び出されるまで、構築されたリクエスタダイ 定するだけでかまいません。 アログは必要に応じて何回でも入力のためにユーザーに表示 サーバーベースのエントリーがこのようにユーザーコマンド できますが、コントロール自体は修正できません。修正する メニューに入ると、モデラーはそれを内部コマンド(たとえ には、まずカレントリクエスタを reqend()で消してもう一 ばプラグイン追加)およびプラグインとは別に保持します。 度 r e q b e g i n ( ) で新しいものを作りなおし、 a d d c o n- そうするは、サーバーベースのエントリーを特定のファイル trol()で新規のコントロールを付ける必要があります。し に格納します。モデラーを起動するたびにこのファイルが自 かし、コントロール内の値は変更してから再表示することが 動的にリロードされます。しかし、モデラーがこれらのコマ できます。 ンドを認識するためには、それを追加したセッションを終了 setvalue()を使うと、既存のリクエスタコントロールの値 する前にそれを保存しておく必要があります。後でロードす を修正できます。これは、修正するコントロールに対するハ るために新規エントリーを保存するには、設定メニュー内の ンドルと、新しい値として使う変数または定数値を受け取り コマンド編集コマンドを使います。詳細は、ご使用のモデラ ます。この実例については、ディスクに入っているlightswa.ls ーマニュアルをご覧ください。 スクリプトをごらんください。 status listadd(タイトル,サーバー,ファイル) void setvalue(ハンドル,値 ハンドル: 値: 整数; コントロールハンドル タイトル: 文字列; Userメニュー内のエントリーのタイトル サーバー: 文字列; エントリーの処理に使われるサーバの名称 ファイル: データタイプ; 入力フィールドに対する新しい値 文字列; このエントリーがポイントするディスクフ ァイル status listremove(タイトル) listadd, listremove (CS) タイトル: 文字列; 削除するエントリーのタイトル この2つのコマンドを使うと、LScriptsでモデラーのオブジェ クトパネルにあるユーザーコマンドメニューにアイテムを追 selmode (IN) 加したり削除することができます。一般的にはこれらのコマ セレクションモードは、特に s e l p o i n t ( ) および selpolygon()コマンドといったさまざまなモデラー固有 コマンドが利用します。セレクションモードは、 GLOBALま たはUSERのいずれかのモードになります。デフォルトのモー ドはGLOBALセレクションです。 ンドを使って、LScriptsを直接追加するユーザーコマンドメニ ューに追加します。スクリプトをこうして追加しておけば、 LScriptを呼び出してからファイル選択ダイアログボックスで スクリプトを選択する必要はなく、LScriptsを直接実行できま す。 –43– GLOBALセレクションモードでは、ユーザーがどのデータ軸 数が宣言してあると、それらは隠れます。 editend() を使 を選択したかにかかわらずアクティブなフォアグラウンドレ ってメッシュデータエディットモードモードを終了すると、 イヤー内のすべてのポイント/ポリゴン上でモデラー固有のオ それらはまた見えるようになります。 ペレーションが実行されます。USERセレクションモードでは、 editbegin()は、そのとき選択されているポイント数を返し モデラー固有コマンドのオペレーションが実行されるのは、 ます。この数はpoint[]自動配列のサイズと同じになります。 ユーザーが明示的に選択したポイントとポリゴンのみになり editbegin(void) ます(またはユーザーが何も選択していない場合は、暗黙的 返す値: にすべてのポイントおよびポリゴン) 。 USERセレクションモードがアクティブでなければ、選択コマ ンドselpoint()およびselpolygon()は機能しません。 editend (MD) editend()を使うと、 editbegin()で開始したメッシュ void selmode(モード) モード: 整数; 選択されたポイントの数 データエディットモードを終了できます。呼び出されると、 定数; GLOBAL またはUSER 自動配列point[]とpolygon[]は消滅し、コマンドシーケ ンス( C S )関数およびコマンドがまた利用できるようになりま editbegin (MD) す。 editbegin()は、LScriptがサポートするメッシュデータエ メッシュデータエディットオペレーション中は、モデラーは ディット関数 へのエントリー・ポイントです。コマンドシー オブジェクトデータに加えられたすべての修正をキュー行列 ケンス( C S )コマンドは、ポイントおよびポリゴン集合に対し に入れます。 editend()コマンドを発行するまでは、修正 てオペレーションを実行できるのに対して、メッシュデータ はオブジェクトには適用されません。パラメータを e d i- エディット(MD)オペレーションは、スクリプトのプログラマ tend()に与えない場合、デフォルトでは修正はオブジェク トに適用され処理が継続します。しかし editend()にパラ に個々のポイントやポリゴンデータを直接編集できるように します。 メータを与えて蓄積した修正事項を破棄してから、オブジェ editbegin()で、LScriptをメッシュデータエディットモー クトをそのままにしておくことも可能です。このパラメータ ドにします。このモードに入ると、ある不思議なことが起こ は、すべての修正事項を破棄したいことを示すABORTという ります。 定数、またはゼロではない任意の値とすることが可能です。 1.コマンドシーケンス(CS)コマンドおよび関数はこの時点で無 void editend([ステータス]) 効となります。 editend()を使ってメッシュデータエディ ステータス: ットモードから出るまで、これらのタイプのプロシージャは 定数; ABORT 呼び出せません。 boundingbox (IN) 2 . 新しい自 動 L S c r i p t 配列が利用できるようになります。 boundingbox()は、指定したレイヤー内のオブジェクトの point[]という第1の配列には、そのとき選択されているオ バウンディングボックスを表す上方向および下方向のベクト ブジェクトポイントすべてのポイントI Dが入ります。第2の ルを返します。レイヤーが指定されていない場合は、そのと polygon[]という配列には、そのとき選択されているオブ き選択されているフォアグラウンドレイヤーがデフォルトと ジェクトポリゴンすべてのポリゴンIDが入ります。 して使われます。 自動配列point[]とpolygon[]の場合、メッシュデータエ ディットモードモードのスコープ内で同一名の配列または変 –44– モードには関係なく、boundingbox() は任意のときに呼び このデータを使うと、オブジェクトの状態を調べられます。 出せます。しかしboundingbox()がメッシュデータエディ たとえばオブジェクトを METAFORMする前に、4頂点以上の ットモードで使われた場合は、レイヤーを指定できませんし のポリゴンすべてを三角形に変換しておく場合は、次のよう 指定しても無視されます。 な短いコードを使います。 ポイント/ポリゴンデータが指定されたレイヤー内になければ、 例 各ベクトルにはnilが返されます。 var totalpoints[6]; boundingbox([レイヤー]) totalpoints = polycount(); 返す値: if(totalpoints[5] || totalpoints[6]) ベクトル[2]; バウンディングボックスの下方向お よび上方向のベクトル/データが存在しなければ、 triple(); nil[2] レイヤー: subdivide(METAFORM); 整数または整数[]; レイヤー番号の整数配列、また ••• はカンマで区切ったレイヤー番号 polycount()は任意のときに呼び出せます。メッシュデータ エディットモード内からのみ呼び出す必要はありません。 pointcount (IN) pointcount()は、アクティブなフォアグラウンドレイヤ polycount(void) ー内でそのとき選択されているポイントの数を返します。こ 返す値: の値は、editbegin()関数が返す値と同じです。 pointcount()はいつでも呼び出せます。 addpoint (MD) addpoint()を使うと、新しいポイントをオブジェクトに追 pointcount(void) 返す値: 整数[6]; さまざまなポイント数のポリゴン 加できます。有効なベクトルを与えると、別の関数に提供で 整数; 選択されたポイントの数 きる有効なポイントIDをaddpoint() が返します。何らかの polycount (IN) 原因から a d d p o i n t ( ) が新規ポイントの作成に失敗すると、 polycount()の戻り値は、 pointcount()のものよりも nilが返されます。 複雑です。1つのポリゴンが持っている頂点の数により、戻り addpoint(位置) 値を分類するからです。polycount() は、次の事項を表す 6つの整数要素を返します。 返す値: point id; 新しいベクトルの識別子 位置: 整数[3],ベクトルまたは数値; 新規ポイントの位置 [1] 選択されたポリゴンの総数 [2] [3] [4] [5] [6] ポイントを1つだけ持っている選択されたポリゴンの総数 addpolygon (MD) ポイントを2つだけ持っている選択されたポリゴンの総数 addpolygon()を使うと、新しいポリゴンをオブジェクト ポイントを3つだけ持っている選択されたポリゴンの総数 ポイントを4つだけ持っている選択されたポリゴンの総数 ポイントを4つよりも多く持っている選択されたポリゴン の総数 データに追加できます。1つ以上のポイントIDをこの関数に与 えて新しいポリゴンを作ることができます。1つ以上のポイン トIDが提供されると、それらは配列に格納されます。 新しいポリゴンは、オプションでサーフェイス名称に割り当 てられます。サーフェイスパラメータが省略された場合は、 –45– 新規のポリゴンはデフォルトサーフェイス識別子に属します。 指定されたサーフェイス名が存在しない場合は、それが新し addquad(ポイント) 返す値: く作成されます。 ポイント: 成功すると、新しいポリゴン識別子が返されます。また、失 ポリゴンID; 新規ポリゴン識別子またはnil ID[4]または4つの個々のポイントID; 四辺形の 構築に使うポイント 敗した場合はnilが返されます。 addtriangle (MD) addpolygon(ポイント[,サーフェイス]) 返す値: ポリゴンID またはnil; 新規のポリゴンの識別子 ポイント: ID[]またはポイントID; 新規ポリゴンのポイント サーフェイス: a d d t r i a n g l e ( ) は 、 パ ラ メータタイプの点で addquad()と似ています。しかし、新規のポリゴンを作る 識別子 ために必要なポイントIDは4つではなく3つのみだという点で 文字列; ポリゴンが割り当てられるべきサーフェイ 異なります。 スの名称 addtriangle(ポイント) 返す値: addcurve (MD) addcurve()は、パラメータタイプおよびカウントの観点か らは a d d p o l y g o n ( ) と同じです。しかし a d d c u r v e ( ) は、 与えられたポイントIDをポリゴンではなくモデラー曲線に返 ポイント: polygon ID; 新規ポリゴンIDまたはnil IDs[3]または3つの個々のポイントID; 三角形を 作るときに使うポイント polyinfo (MD) します。ポリゴンと曲線の違いは、曲線ポイント間の角度は polyinfo()関数を使うと、個々のポリゴンについての情報 なめらかに補間されますが、ポリゴンポイント間の角度は厳 を集められます。polyinfo()は、可変数のアイテムを返し 密に線形だという点です。閉じた曲線を作るには、与えられ ますが、その最初の要素はつねにポリゴンが割り当てられる た開始点と終了点を重ねます。 サーフェイス名になります。他の要素は、ポリゴンを作って ディスク内にあるgears.lsというスクリプト例は、 いる個々のポイントIDです。 addpolygon()とaddcurve()の両者を使った好例です。 オブジェクト内のすべてのポリゴンに同じ数のポイントがあ るわけではないので、ポリゴンのポイント計数は、ポリゴン addcurve(ポイント[,サーフェイス]) 返す値: により異なります。ポリゴンが持っているポイント数を判断 ポリゴンID またはnil; 新規の曲線の識別子 するために、polypointcount()関数(後述)を使って適 ポイント: ID[]またはポイントID;新規の曲線のポイント識別子 サーフェイス: 文字列; 曲線が割り当てられるサーフェイスの名称 切なサイズの配列を割り当て、polyinfo()の戻り値を保持 します。 addquad (MD) polyinfo(ポリゴン) addquad()を使うと、四辺形(4ポイント)ポリゴンをオブ 返す値: ジェクトのメッシュデータに追加できます。ポイント I Dは 個々に与えられますし、4つの要素の配列でも与えられます。 ポリゴン: array[]; さまざまなサイズの配列で最初の要素 はサーフェイスの名称残りの要素はポイントID ポリゴンID; 情報を知りたいポリゴン識別子 polypointcount (MD) p o l y i n f o ( )に関連して p o l y p o i n t c o u n t ( )を使うと、 ポリゴンが持っているポイント数を設定できます。 –46– polyinfo()が返す情報を保持するための配列のサイズを決 す。rempolygon() の場合は、ポリゴンを形成するポイン めるときにこの情報が必要になります。たとえば、次のよう トは削除されず、メッシュデータの一部として残ります。 になります。 status rempoint(ポイント) 例 ポイント: ポイントID; 削除されるポイント ・・・ var pcount = polypointcount(polygons[x]); status rempoly(ポリゴン) var ppoints[pcount + 1]; ポリゴン: ポリゴンID; 削除されるポリゴン // surface name[1]のアカウント ppoints = polyinfo(polygons[x]); pointmove (MD) ・・・ pointmove()は、ポイントのベクトル位置を変更します。 status pointmove(ポイント,位置) プロトタイプは次のようになります。 polypointcount(ポリゴン) 返す値: 整数; ポイント計数 ポリゴン: ポリゴンID; 対象のポリゴンID 整数[3],ベクトルまたは数値; ポイントの新規の位置 polysurface()を使うと、 LScriptがポリゴンサーフェイ スの名称を再割り当てします。 pointinfo()は、3D空間内でポイントが存在する位置を返 status polysurface(ポリゴン,サーフェイス) します。 ポリゴン: pointinfo(ポイント) ポイント: ポイントID; 移動するポイントのID 位置: polysurface (MD) pointinfo (MD) 返す値: ポイント: サーフェイス: vector; ポイントの位置 ポイントID; 対象のポイントの識別子 ポリゴンID; 変更するポリゴンのID 文字列; ポリゴンが割り当てられるサーフェイスの 名称 polypoints (MD) polynormal (MD) polypoints()を使うと、ポイントの新規セットをポリゴ polynormal()は、指定したポリゴンの法線ベクトルを返 ンに割り当てられます。ポリゴンを形成する元のポイントは します。 自動的には削除されないので、不要の場合は手動で、 rempoint()を使って削除します。 polynormal(ポリゴン) 返す値: ベクトル; ポリゴンの法線ベクトルまたはnil ポリゴン: ポリゴンID; ポリゴンの識別子 status polypoints(ポリゴン,ポイント) rempoint, rempolygon (MD) rempoint()およびrempolygon()は、それぞれポイント またはポリゴンをオブジェクトメッシュデータから削除しま –47– ポリゴン: ポリゴンID; 変更するポリゴンID ポイント: ポイントID[]; ポリゴンの新規ポイント LightWave Layoutコマンドおよび関数 レイアウトジェネリックスクリプト以外、レイアウトのスク リプト処理は、逆に L i g h t W a v eレイアウトが終了するまで、 レイアウトのLScript あるいはプラグインパネルからレイアウトLScriptを明示的に レイアウトの LScriptシステムは、プラグインプロトタイプの 非アクティブにするまでアクティブ状態のままになりますが、 機能をLightWaveレイアウトに持ち込むように設計された5つ 1つのL S c r i p tは一度だけしか起動されないようにする、新し のLightWaveレイアウトプラグインで構成されます。新しい いスクリプト実行方法を提供します。このスクリプトはLight- プラグインでは次の5つのプラグインアーキテクチャを使用で Waveレイアウト内でユーザが他の関数を実行している間もア きます。 クティブになったままです。LightWaveレイアウトスクリプ トは、この種の協調操作を行うように設計されています。 イメージフィルター (ls-if.p) オブジェクトリプレイスメント (ls-ro.p) ディスプレイスメントマップ (ls-dm.p) アイテムアニメーション (ls-pt.p) は状況に対応して随時呼び出されるよう設計された関数です。 レイアウトジェネリック (ls-gn.p) このようなコールバック関数は起動されるまで、「スリープ」 この協調した実行を容易にするため、レイアウトLScriptのス クリプト処理は「コールバック」関数の概念を中心に据えて います。コールバック関数は、通常、特定のイベントあるい 状態になっており、 C P Uの時間を取ることもなく、 L i g h tWaveレイアウトの処理にも影響しません。 ここから先へ進む前に モデラーL S c r i p tの実行フローは非常に直線的です。実行は レイアウトのLScriptはLScriptコアエンジンで使用でき る機能を基盤として構築されているので、LScriptの開発に使 用するLScript言語あるいはテクニックをよく知らない場合は、 先にこのマニュアルの前節をもう一度読み直しておくことを main()関数から開始され、介入ロジックあるいは関数の呼 び出しがあればそれを実行して、 main()関数が returnス テートメントあるいは関数の論理的な終わりに到達して終了 すると、実行の終了に到達します。 お勧めします。 一方、レイアウトLScriptの実行フローは大きく異なります。 レイアウトLScriptにはスクリプトに対してきちんと定義され レイアウトのスクリプト構造 ている実行ポイントが1つだけでなく、多数存在しています。 モデラーLScriptでは、スクリプトは完結したプログラムと同 事実、レイアウトL S c r i p tは1つのファイル内に個別のスクリ 様に実行されるように作成し、スタート、ボディ、エンドを プトが多数存在すると考えることができます。レイアウトは、 明確に定義します。モデラー LScriptが実行終了位置に達する と、再度そのL S c r i p tのプラグインを特定して要求するまで、 LightWaveモデラーはそのスクリプトを呼び出しません。ま 他のスクリプトを実行したり、他のスクリプトの支援を受け たりすることなく、これらの「個別」スクリプト(関数)を随 時呼び出すことができます。 た、モデラー LScriptを実行中は、そのスクリプトが終了する 前にも述べましたが、レイアウトジェネリックスクリプトは までその他の処理は実行されません。この種のオペレーショ ンは、「 モ ー ダ ル 」 あ る い は 「 同 期 」 と 呼 ば れ て い ま す 。 Microsoft Windowsで使用されているグラフィックスを含め、 グラフィックスのダイアログボックスの多くは、この方法で このメカニズムの例外です。この例外となっている理由は、 レイアウトジェネリックプラグインがレイアウトコンポーネ ント(カメラ、メッシュオブジェクト、ライトなど)に関連 付けられておらず、そのため、アニメーションのフレームの 操作します。 生成には関わらないからです。レイアウトジェネリックスク –48– リプトにはエントリが1ポイントだけしかなく、この関数を用 destroy( ) いて実行を開始、終了するという点では、モデラースクリプ スクリプトがプラグインパネルから非アクティブ化されたと トとほとんど同じです。しかし、レイアウトジェネリックス き、あるいはメモリから削除された時に一度だけ呼び出され、 クリプトは、その他のレイアウトスクリプトが使用している、 スクリプトの「クリーンアップ」処理の実行に使用します。 アーキテクチャを特定しないレイアウトコンポーネントすべ てにアクセスできます。レイアウトジェネリック LScriptにつ save( ) いては、このページでこれから詳細に説明します。 ユーザによってシーンファイルがディスクに保存されるとき に呼び出されます。このとき、スクリプトは、シーンをLight- これらのメカニズムを理解しておくことが、次の説明を理解 Waveレイアウトに再ロードされる際に、復元したいスクリプ するには欠かせません。さらに理解を深めるため、この機会 ト関連の値があれば、それを格納することができます。この に、例示されているスクリプトをご覧になることをおすすめ 関数は、シーン(A S C I I)ファイル、あるいはオブジェクト します。 (バイナリ)ファイルで、シーンをディスクに保存するたびに 共有関数 呼び出されます。 各プラグインアーキテクチャはそれぞれ特定のコールバック Load( ) 関数を必要としますが、各レイアウトスクリプトは、アーキ シーンファイルあるいはオブジェクトファイルから以前に保 テクチャにかかわらず、LightWaveレイアウトが呼び出せる 「共通の」エントリポイントを1つ、あるいは複数提供します。 存しているスクリプト関連値を復元する際に使用します。 これらの共通関数は、すべてオプションで、スクリプトでそ options( ) れらを省略した場合に、レイアウトLScriptは、LightWaveレ スクリプトの「オプション」ボタンが選択されると呼び出さ イアウトの(「空」の)内部バージョンを提供します。 れます。モデラー LScriptで使用できるものと同じ標準リクエ 次のような共通関数があります。 スタ関数を使用して、ユーザインタフェースを生成でき、ユ ーザはこれを用いて操作パラメータを変更できます。リクエ process( ) スタダイアログを正常に作成するには、LightWave Panel Ser- こ の コ ー ル バ ッ ク 関 数 は 、(モデラースクリプト処理に vices Global-Classプラグインが使用できる状態でなければな main()と類似した関数があれば)スクリプトのメインの処 りません。LW Panel Servicesプラグインを用いると、レイア 理を実行する際に使用します。これは何度でも呼び出すこと ウトスクリプトは、付録Cで説明する、複数の「拡張」コントロ ができます。 ールタイプを提供できます。 create( ) レイアウトスクリプトは、これらの「共通」関数の中の起動し ておきたい任意の関数を定義できます。繰り返しますが、ス スクリプトを読み込んだときに、LScriptコアエンジンがスク クリプト内の共通関数に欠けている関数があれば、レイアウ リプトの処理を正常に終了した直後に一度だけ呼び出されま トScriptはデフォルトの動作(つまり、代わりに空の内部関数 す。これは、スクリプトの「スタートアップ」処理を実行しま の呼び出し)を行います。これは、 process()関数の場合 す。 も同じです。 レイアウトジェネリックはこれらの標準関数と は違います。レイアウトジェネリックスクリプトは1つの必須 関数、 generic()があり、ここでは、スクリプトを起動す –49– ると処理が発生します。詳細については、このページのレイ イアウト内のオブジェクト選択パネルでユーザに表示される アウトジェネリック LScriptの節を参照してください。 名前と一致していなければなりません。 名前のついたオブジェクトはライト、メッシュデータ、ある レイアウトグローバル いはボーンを含むことができます。 レイアウトLScriptはレイアウトスクリプトが処理中に使用で filllight = getfirstitem("FillLight"); きるさまざまな「グローバル」値を設定します。これらの値 は読取専用(つまり、値の割り当て不可)で、スクリプトで ボーンへのアクセス識別子がないことに気付いていることで ローカルに宣言したときと同様にアクセスできます。 しょう。その理由は、ボーンオブジェクトはメッシュオブジ 現在レイアウトスクリプトで使用できるグローバル値は以下 ェクトの子オブジェクトであると考えられ、ボーンだけでは のとおりです。 存在し得ないためです。ボーン情報は、親のメッシュオブジ INSTANCE プラグインアーキテクチャに関係なく、スクリプトの各 ェクトを経由して発生しなければなりません。ボーンオブジ インスタンスが固有であることを保証する識別子を表す ェクトは必然的に LScriptのメッシュオブジェクトのデータメ 読取専用文字列です。 ンバーとなります。 名前が示すとおり、 getfirstitem() は指定タイプのオブ シーンのパブリック情報 ジェクトのリスト内にある(L i g h t W a v eレイアウトに従い) 最初のオブジェクトを返します。しかし、現在のシーンに指 getfirstitem() 定タイプのアイテムが全くない場合は、 getfirstitem() レイアウトLScriptスクリプトにはシーンに含まれるパブリッ ク情報へのアクセスがあります。メッシュ、ボーン、ライト、 カメラおよびシーンの各設定値に関するパブリック情報を利 はnilを返します。次のコードの断片はシーンで現在定義さ れているライトの順次スキャンを開始する際に firstitem()を使用する方法を示しています。 用できます。 例 この情報にアクセスするには getfirstitem()レイアウト ・・・ LScript関数を用います。 light = getfirstitem(LIGHT); getfirstitem()は目的のタイプの最初のオブジェクトを 表す値を返します。 getfirstitem() にプル対象のオブジ if light != nil then ェクトリストを示すパラメータ値(便宜上レイアウトLScript begin // すべてのライトをスキャンする で事前定義済み)を指定して使用できるオブジェクトタイプ ・・・ から選択します。事以下のような前定義済みの値があります。 MESH 使用可能なレイアウトメッシュオブジェクトから選択 LIGHT 定義済みレイアウトライトソースから選択 CAMERA レイアウトカメラを表す値を取得 SENE シーン設定値に関する情報を含む値を取得 get- end else // we’re animating by Braille... ・・・ getfirstitem()が返すデータの型は、返されるレイアウ getfirstitem()は、現在レイアウトに存在しているオブ トオブジェクトにインタフェース、あるいはラッパーを提供 ジェクトの名前を表す文字列も受け付けます。この名前はレ するよう設計されている、内部LScriptオブジェクトタイプの –50– インスタンスです。通常の LScriptデータ型(文字列、整数な ェクトを返します。例を挙げると、レイアウトLScriptスクリ ど)とは異なり、このデータ型はアライブ の状態です。レイ プトでレイアウトライトオブジェクトのトラバースを達成す アウトオブジェクトに関連付けられたデータへのアクセスを る場合を見てみましょう。 提供するだけでなく、多くの場合、これらのオブジェクトイ light = getfirstitem(LIGHT); ンスタンス はレイアウトオブジェクトあるいはデータに何ら while(light != nil) かの操作を実行する際に呼び出す関数を提供します。レイア { ウトオブジェクトに対するこれらのラッパーはLScriptではレ ・・・このライトのインスタンスを処理するコード・・・ イアウトオブジェクトエージェントと呼びますが、このマニ light = light.next(); ュアルでは単にオブジェクトエージェントと略しています。 } ファイルオブジェクトと呼ばれるLScriptのデータ型もオブジ ェクトエージェントの1タイプで、ディスクファイル用のエー getfirstitem()が返した、(あるいは別のオブジェクト ジェントとして使用されます。 エージェントを返すすべてのオブジェクトエージェントメソ getfirstitem()は最初のレイアウトオブジェクトのオブ ッドが返した)各オブジェクトエージェントは、次の共通メ ジェクトエージェントを返しますが、ランダムにアクセスす ソッドに応答し、次の共通データメンバーを含みます。 るレイアウトオブジェクトの機能はありません。また、リス parent ト内の次のレイアウトオブジェクトを返す、 get- このレイアウトオブジェクトの親と考えられる、レイア ウトオブジェクトを表すオブジェクトエージェントを指 し示します。 (なければnil) firstitem()のコンパニオン関数もありません。では、同 target じ型のその他のオブジェクトにアクセスするにはどうすれば このレイアウトオブジェクトのターゲットとして指名さ れたレイアウトオブジェクトを表すオブジェクトエージ よいのでしょうか。 ェントを指し示します。(なければnil) 一度、リスト内の最初のオブジェクトエージェントを取得す type ると、そのクラスのレイアウトオブジェクトに順次アクセス する機能を持つことができます。コールから getf i r s t i t e m ( )に返される各オブジェクトエージェントは、 たとえやり方が異なっていても、各オブジェクトエージェン 別する、定数値を保持します。 goal ェントを指し示します。 (なければnil) name な純粋なオブジェクト指向言語では、これらの共通な方法は このレイアウトオブジェクトのゴールとして指定されて いるレイアウトオブジェクトを表すオブジェクトエージ トが同じ機能を実行できる共通関数(あるいは「メソッド」) を提供(または、「エクスポート」)します。Smalltalkのよう このレイアウトオブジェクトのタイプ(メッシュ、ボー ン、ライト、カメラ、あるいはシーンのいずれか)を識 (レイアウトオブジェクトリストに現れる)このレイア ウトオブジェクトの名前を表す、文字列を保持します。 オブジェクトが認識し、応答する「メッセージ」として知ら param(state,time) 指定"time"インデックスの間の、特定レ れています。異なる別の「クラス」(オブジェクトの定義)の イアウトオブジェクトの状態の値を表す3 つの数値からな インスタンスが同じメッセージに応答すると、「多態」と考え る配列を返します。状態値はPOSITION(オブジェクト られます。 座標の位置) 、 RIGHT,UP,FORWARD,ROTATION,SCALING, 各オブジェクトエージェントがエクスポートする、このよう なメソッドは " n e x t " と呼ばれます。 n e x t ( ) メソッドは、 (LScript オブジェクトエージェントインスタンスとして)同 じオブジェクトカテゴリーリスト内の次のレイアウトオブジ –51– PIVOT,WPOSITION(「ワールド」座標の位置)の1 つになります。 limits(state) 特定のレイアウトオブジェクト状態 (POSITION,RIGHT,UP,FORWARD,ROTATION, SCALING,PIVOT,WPOSITION)について既に設定 されている最低[エレメント1-3]限度および最大[エ レメント4-6]限度を表す6個の数値からなる配列を返 のレイアウトオブジェクトに割り当てられたレイアウト けではないので、オブジェクトエージェントはこれらのデー を表す整数値か、そうでない(つまり、カメラ)場合は タメンバーのサブセットだけを提供し、エクスポートしたメ nilが入ります。 ソッドのサブセットに応答します。たとえば、シーンという 該当する場合は、レイアウトオブジェクトのポリゴン数 タイプのオブジェクトエージェントは、これらのメソッドの を表す整数値か、妥当でない(つまり、カメラ)場合は 多くに対して nilを返し、カメラというオブジェクトエージ nilが入ります。 ェントにはポイントあるいはポリゴンがありません。 shadhows[] レイアウトオブジェクトの現在のシャドウオプションを 表す3 つのブーリアン値からなる配列を保持します。 前にリストしたエクスポートしたオブジェクトエージェント メソッドの多くは、「タイムインデックス」として提供する必 [1] == "セルフシャドウ"がオンの場合はtrue、オ フの場合はfalse [2] == "キャストシャドウ"がオンの場合はtrue、 オフの場合はfalse [3] == "レシーブシャドウ"がオンの場合はtrue、 オフの場合はfalse 要のあるパラメータを受け取ります。このインデックス値は シーンに含まれるアニメーションフレームの特定スパンが開 始してからの(時間で表される)オフセットを示します。目 的のタイムインデックスを計算するには、フレームナンバー dissolve(time) このレイアウトオブジェクトが指定された "time"インデックスにディゾルブされるパーセント (1は100%)を返します。 同じカテゴリーのリストにある次のレイアウトオブジェ クトを返します。レイアウトオブジェクトがない場合は、 nilを返します。 firstChild() このレイアウトオブジェクトに属する最初の子オブジ nextChild() クトエージェントメソッドのnext() を使用すると、こ レイアウトオブジェクトすべてに、同じ型のデータがあるわ pointcount 妥当であれば、レイアウトオブジェクトのポイントの数 next() ーンとして指定されたレイアウトオブジェクトを表す、 最初のオブジェクトエージェントを返します(オブジェ レイアウトオブジェクトのある(パスがある場合はパス も含めた)ファイル名を表す文字列を保持します。 polycount このレイアウトオブジェクトに割り当てられる最初のボ ボーンすべてをトラバースできます)。 します。 filename bone() をシーンの1秒あたりのフレーム数で割ります。たとえば、1 秒あたり30フレームで163番目のアニメーションは(163/30) 秒タイムインデックス、つまり、5.43秒後にアニメーション に入れられます。 インデプスのオブジェクト オブジェクトエージェントすべては前述の共通データメンバ ェクトとして指定されたレイアウトオブジェクトを表す ーとエクスポートしたメソッドを共有しますが、特定のオブ オブジェクトエージェント返します。(レイアウトオブジ ジェクトエージェントにはそれ以外のデータメンバーとメソ ) ェクトがなければ、nil を返します。 ッドがあります。この理由は、レイアウトオブジェクトは、 このレイアウトオブジェクトの子として指定されたレ イアウトオブジェクトを表す次のオブジェクトエージェ ントを返します。 (レイアウトオブジェクトがなければ、 nilを返します。) その機能に特有のデータを含んでいることが多い(たとえば、 カメラにはボーンにとっては意味のないズームファクタがあ るように)ので、オブジェクトエージェントはレイアウト LScriptのプログラマーにアクセス方法、そしてできればその エリアを変更する方法を提供しなければなりません。 –52– 本書の執筆時には、L i g h t W a v e 3 Dバージョン5がリリースさ coneangles[] これがスポットライトタイプであれば、このライト用 のコーン角度を表す、2つの浮動小数値からなる配列を保 持します。この最初のエレメント[1]はスポットライト れていますが、この節で説明するすべてのデータメンバーは 読取専用で使われます。これらを変更すると、レイアウトオ コーンの総角度の半分としての半径を表し、エレメント ブジェクト自体に影響しませんが、スクリプトが実行される [2]はスポットライトのソフトエッジの角度幅を示しま と実行時エラーが発生します。 す。 ボーン カメラ flags[] ボーンの現在のオプションを表す2つのブーリアン値から なる配列を保持します。 focallength(time) focaldistance(time) 指定"time"インデックスのカメラのフォ ーカルディスタンスを表す浮動小数値を返します。 特定ボーン状態の値を表す3つの数値から fstop(time) UP、 FORWARD、ROTATION、SCALING、PIVOT、 WPOSITION、(「ワールド」座標位置)のいずれかにな 指定"time"インデックスのカメラのf-stop 設定 値を表す浮動小数値を返します。 blurlength(time) fovangles(time) restlength ボーンの残りの長さをメートルで表す、浮動小数値が入 指定"time"インデックスのカメラのブラ ーレングスを表す浮動小数値を返します。 ります。 指定"time"インデックスのカメラの視野 角度を表す浮動小数値を返します。最初のエレメント ります。 [1]は、水平角度を表し、第2のエレメント[2]は、垂 innerlimit ボーンの内径限度値を表す浮動小数値が入ります。(フラ グ[2]がtrueの場合のみ有効) outerlimit ボーンの外径限度値を表す浮動小数値が入ります。(フラ グ[2]がtrueの場合のみ有効) ライト ambient(time) 指定"time"インデックスにグローバルアンビエン トライトのRGB カラー値を表す3 つの整数値からなる配 直角度を表します。これらの角度(ラジアン)はカメラ の向いている方向を中心にして測定します。 シーン name このシーンの名前を表す文字列を保持します。 filename このシーンのファイル名を表す浮動小数値を保持します。 totalpoints シーン内のメッシュポイントの合計数を表す整数値が 入ります。 列を返します。 totalpolygons シーン内のメッシュポリゴンの合計数を表す整数値が このライトのタイプ(無限遠光、点光源、スポットライ 入ります。 トのいずれか)を識別する定数(読取専用)の整数値を rendertype シーンで発生するレンダリングのタイプ (WIRERENDER、QUICKRENDER、 REALISTICRENDERのいずれか)を識別する定数(読 保持します。 color(time) 指定"time"インデックスのカメラの被写 界深度を表す浮動小数値を返します。 なる配列を返します。状態値はPOSITION、RIGHT、 type 指定"time"インデックスのカメラの倍率 を表す浮動小数値を返します。 [1] == ボーンがアクティブであればtrue、その以 外はfalse [2] == ボーンに制限があればtrue、それ以外は false restparam(state) zoomfactor(time) 指定"time"インデックスのライトのRGBカラー値 を表す3つの整数値配列を返します。 取専用)整数値を保持します。 このライトのシャドウタイプ(SHADOWRAYTRACE 、 renderopts[] シーンの現在のオプションを表す8つのブーリアン値 SHADOWMAP、SHADOWOFFのいずれか)を識別する からなる配列を保持します。 定数(読取り専用)の整数値を保持します。 –53– [1] == x0 [1] == シャドウトレーシングがアクティブの場合は true [2] == y0 [2] == リフレクショントレーシングがアクティブの [3] == x1 場合はtrue [4] == y1 [3] == リフラクショントレーシングがアクティブの 場合はtrue [4] == フィールドレンダリングがアクティブの場合 はtrue [5] == リバースフィールドレンダリングがアクティ ブの場合はtrue [6] == モーションブラーがアクティブの場合は true リクエスタインタフェースの拡張 options()関数の中で、レイアウトスクリプトはモデラー LScriptが使用するリクエスタコードと同じリクエスタコード を使用できます。事実、リクエスタコードは修正を行わなく てもスクリプト間で転送できます。しかしモデラーとは異な り、LightWaveレイアウトコードにはユーザが作成したプラ [7] == デプスオブフィールドがアクティブの場合は true グインを使用可能にする、インテグラルインタフェースコー ドがありません。代わりに、レイアウトはPanel Servicesプラ [8] == リミテッドリジョンがアクティブの場合は true グインを採用して、ユーザが作成したプラグインにインタフ ェース機能を提供します。LScriptは、Panel Servicesプラグイ framestart レンダリング開始番号を表す整数値が入ります。 franeend レンダリング終了番号を表す整数値が入ります。 framestep フレームステップ値を表す整数値が入ります。 fps シーンの1秒あたりのフレーム数を表す整数値が入りま ンを利用して、独自のリクエスタ機能を容易に実現します。 Panel Servicesは、LightWave3Dモデラーにある機能にさらに 機能を追加するコントロールを使用可能にするので、レイア ウトスクリプトは新しい関数としてこの機能をレイアウトス す。(デフォルトは30) クリプトプログラマーに渡します。これらの新しいコントロ framewidth レンダリング対象のフレームの横ピクセル数を表す整数 ールは「標準外」とみなされますが、レイアウトLScript内で 値が入ります。 frameheight レンダリング対象のフレームの縦ピクセル数を表す整 数値が入ります。 pixelaspect シーンのピクセルアスペクトレシオ(ピクセル縦横比) を表す浮動小数値が入ります。 minsamplesperpixel 設計されているので、他のコントロールと同様に機能します。 Panel Servicesはプラグインなので、ユーザのLScriptがリクエ スタパネルを出そうとするときに、そのプラグインが利用で きない可能性が残ります。重要なプラグインが存在しないこ とを検出する機能を、スクリプト作成者に提供するには、 現在のレンダリングオプションに基づい た、最終イメージでの1 ピクセルあたりの最低サンプル数 reqbegin()コマンドをレイアウトLScript内で拡張してお を表す整数値が入ります。 き、trueまたはfalseの論理値を返してPanel Servicesプラ maxsamplesperpixel 現在のレンダリングオプションに基づい た、1ピクセルあたりの最大サンプル数を表す整数値が入 ります。 limitedregion[] グインの存在を示すようにしなければなりません。論理値 trueは、プラグインが存在することを示します。このインジ ケータを使用するとスクリプトからリクエスタを表示するた シーンのリミテッドリージョンエリアの場 所を表す、4個の浮動小数値からなる配列を保持します。 –54– めの準備ができているかどうかを判断できます。 ベクトル addhsv(hsv,title) 例 ・・・ カラー成分に入力する3つの数値入力フィールドと、入力値を if(!reqbegin("My Requester")) 組み合わせ表示するプレビューエリアを含むコントロールを { 作成します。 error("Requester support unavailable"); "hsv"は、'x','y','z'位置の色相、彩度、明るさというカラー成 return; 分を表すベクトル値です。この値はそれぞれ、0から255の整 数となります。 } "タイトル"は、コントロールのラベルを表す文字列値です。 ・・・ Panel Servicesをサポートするため、5つの新しいコントロー (オブジェクトエージェント) additems(タイトル) ル作成コマンドをレイアウトLScriptコマンドセットに追加し カメラとすべてのライトを含めて、シーンで現在使用できる オブジェクトのドロップダウンリストであるコントロールを ました。これらの関数はレイアウトスクリプトでしか使用で 作成します。このコントロールの戻り値は、選択されたLight- きません。モデラーLScriptには、これらのコントロールコマ Waveオブジェクトを表すオブジェクトエージェントとなりま ンドと同等のPanel Servicesはありません。 すが、オブジェクトか選択されていない時はnilとなります。 文字列 addfilename(ファイル名, タイトル) "タイトル"は、コントロールのラベルを表す文字列値です。 テキスト編集フィールドとファイルリクエスタダイアログボ ックスを表示するプッシュボタンを含むコントロールを作成 アーキテクチャの詳細 します。ファイルリクエスタから返された選択肢はテキスト これまでに、すべてのレイアウトスクリプトに共通なメソッ 編集フィールドに置かれます。 ド、関数、データを説明しましたので、スクリプトプログラ "ファイル名 "は、コントロールのファイル名編集フィールド マーに提供されている拡張機能に対する特定プラグインアー の初期値を表す文字列値です。 キテクチャを検討してみます。 "タイトル"は、コントロールのラベルを表す、文字列値です。 LightWave3Dがプラグインに対して公式に使用可能としてい る内部データ構造について説明するので、ユーザが3Dレンダ ベクトル addrgb(rgb,タイトル) リングシステムで採用しているデータ構造とメカニズム、な カラー成分に入力する3つの数値入力フィールドと、入力値を らびに現在業界で使用されている、一般的なコンピュータグ 組み合わせて表示するプレビューエリアを含むコントロール ラフィックファイルフォーマット(例:Targa)について詳し を作成します。 いことを想定しています。 "rgb"は、'x','y','z'位置の赤(Red)、緑(Green)、青(Blue)とい うカラー成分を表す値です。この値はそれぞれ、0から255ま LS/IF(イメージフィルタ) での整数となります。 LS/IFプラグインは、LightWave3Dがレンダリングを完了した "タイトル"は、コントロールのラベルを表す文字列値です。 フレーム(イメージ)の後処理に使用します。 LScriptプラグインはレンダリングした結果生成された赤、緑、 青のカラー値とアルファチャネル値の入ったレイアウトが保 守を行う、内部データバッファにアクセスします。LS/IFは表 –55– 示可能なフレームを表す各カラー値にエフェクトを適用する SPECIAL この値はこのフィルタだけに使用され、サーフェイスご 際に使用します。 とにユーザが割り当てる値です。これは、特定サーフェ イメージバッファの選択 設計され、また、ユーザがバッファに0から255までの イスの後処理エフェクトを起動する際に使用するように 値として割り当てたパーセントは、ここに表示されます。 LS/IFは、flags()と呼ばれるオプションのスクリプトをサ ポートします。スクリプトはこの関数を用いて、使用可能な LUMINOUS,DIFFUSE,MIRROR,TRANS,RAWRED,RAWGREEN, バッファの中でスクリプトがどのバッファにアクセスできる RAWBLUE かに関してレイアウトと通信します。LightWaveのレイアウ これらの8つのバッファはシェーディングをする前のサー フェイスパラメータの未処理値です。 トはこのメカニズムを使用して、メモリを保護します。スク SHADING リプトが特定バッファを必要としない場合は、レイアウトは このバッファは、イメージの未処理形状に適用される拡 散シェーディングのピクチャです。 メモリと CPUタイムを割り当てて、ユーザに対してこれらの SHADOW このバッファは最終イメージ内で影ができる場所を示し バッファがコピーできるようにする必要がありません。 35 ます。これはまた、シーン中のライトにイメージ内のど 2 の部分が見えるかを示す、イルミネーションマップとし ても考えることができます。 レンダリング作業の結果レイアウトが使用、あるいは作成す GEOMETRY る、異なるデータバッファは多数あり、使用しているLS/IFス このバッファの値は視点ベクトルを用いたサーフェイス ノーマルのドットプロダクトから計算されます。これは クリプトはこれらのバッファのすべてあるいは任意のバッフ イメージ内のオブジェクトの下にある形状に関すること ァにアクセスする要求ができます。どのバッファを要求する を示します。このバッファが255(または1.0 )の場合 かにかかわらず、すべての LS/IFスクリプトにはレイアウトが は、サーフェイスはまっすぐカメラの方を向いており、 維持している赤、緑、青、アルファチャネルの各バッファへ このバッファが0の場合は、サーフェイスはカメラに対し の暗示的なアクセスが用意されていますので、明示的にこれ て横向きになっています。 らのバッファを要求する必要はありません。 DEPTH このバッファは、カメラプレーンからの各ピクセルの距 離を示すマップです。他のすべてのバッファとは異なり、 暗示的なバッファ(赤のみ、緑のみなど)という例外はあり このバッファは浮動小数値で、アンチエリアシングある ますが、すべてのレイアウトが維持するバッファは読取専用 いはモーションブラー処理をしません。 です。データを実際に変更したいバッファに対する修正にコ ンテンツを反映させる場合に使用します。 LS/IFスクリプトがアクセスを要求できるバッファは以下のと flags() おりです。 関数がこれらの事前定義値を1つ以上返すと、スクリプトが使 RED,GREEN,BLUE,ALPHA 用可能になり、レイアウトバッファと通信することができま これらのバッファは、すべてのスクリプトで使用でき、レン す。事実、 flags()の目的は、1つあるいは複数の値を返す ダリング済みフレームのR G Bの各値とアルファ値を個別に表 ことです。たとえば、次のコードは暗示バッファを要求して します。すべての使用可能なバッファをオフにすることはで 単にCPUタイムを消費するだけのサンプルの flags()を示し きますが、それだけしか変更はできません。他はすべて完全 ています。 に読取専用です。 –56– LS/IFスクリプトは、赤、緑、青、アルファチャネルの各イメ 例 ージバッファデータにアクセスし、更新するための特殊な内 flags 部関数を呼び出せます。これらの関数は、1つのLS/IF関数に { 対してのみ有効で、他のレイアウトスクリプトとは共有でき return(RED,GREEN,BLUE,ALPHA); ません。 //面白いのでデフォルトを選択 } []bufferline(bufferid,line) 示された垂直イメージ"line"の"bufferid"で識別されるバッファ イメージバッファの処理 内の値を検索する際に使用します。"bufferid"は以前に説明さ 多くのレイアウトスクリプトと同様、LS/IFスクリプトの処理 れた(SPECIAL,DIFFUSE,REDなど)のバッファインジケータ の中心点は process()関数で発生します。 process()関 の1つです。flag()関数で選択されていないバッファが要求 数はLightWave3D レイアウトが生成したアニメーションのす された場合、実行時エラーが発生します。エレメントのカウ べてのフレームについて一度だけ呼び出され、スクリプトが ントが、 process()関数に渡す"width"パラメータと一致す イメージピクセルに適用するように設計されている操作は、 るバッファ値の配列を返します。 その時点でイメージ全体にレンダリングされます。 [] floatline(bufferid,line) LS/IFは呼び出されると process()関数に5つのパラメータ この関数は、浮動小数点データ(現在のところDEPTHバッフ を渡します。これらのパラメータはイメージ幅と高さ、レン ァだけが適格)を含むバッファにアクセスする際に使用する ダリング中の現在のフレーム番号などの情報を提供してレイ アウトバッファ内のデータへのアクセスを支援するように設 こと以外は、bufferline()と同じです。 計されています。LS/IF process()に渡される5つのパラメ setrbg(col,row,buf) ータは次のとおりです。 イメージの指定行/列にある特定イメージピクセルの赤、緑、 width 生成イメージの幅(水平ラインの数)を示す整数値です。 青の値を設定する際に使用します。"buf"は赤([1]) 、緑([2]) 、 この値はユーザがレイアウトカメラ情報パネルで設定し 青([3])を表す3つのカラー値からなる配列です。 た値と等しくなります。 height setalpha(col,row,bufval) 生成イメージの高さ(垂直ラインの数)を示す整数値で す。この値はユーザがレイアウトカメラ情報パネルで設 イメージの指定行/列にある特定イメージピクセルのアルファ 定した値と等しくなります。 値を設定する際に使用します。 frame 生成イメージのフレームナンバーを示す整数値です。 start このフレームの開始時間をタイムインデックス値として processrgb(row,red,blue,alpha) この関数は setrgb()とsetalpha() の関数の代わりをし、 表す浮動小数値です。 end 指定イメージ行の4つのバッファすべてを同時に処理します。 タイムインデックス値として表される、このフレームの 終了時間を表す浮動小数値です。 個別のバッファエレメントは、 setrgb()とsetalpha() このインデックス値はフレームにレイアウトからモーシ の場合のように一時に1バッファではなく、すべて同時に処理 ョンブラーを適用しない限り、開始時刻と同じです。こ されるため、この関数ははるかに高速です。 の場合、開始時刻インデックスと終了時刻インデックス LScript配列に関係するすべての場合と同様に、イメージ列/行 との差はそのフレームの「エクスポージャタイム」です。 インジケータとして使用する値は、各バッファ内の最初のエ –57– レメントが常時[1]という意味の"1ベース"にしなければなりま キャッシュ処理を有効にしてしまうと、他のすべてのLS/IFコ せん。ユーザが最初のエレメント[0]にアクセスしようとする マンドと関数は本物のフィルタ処理を実行しているのと同様 と、実行時エラーが生成され、LS/IFスクリプトはそれ以上の に使用できます。しかし、これらの関数の呼び出しはレイア 動作をしないように使用不可となります。 ウトでバッファ処理されたデータではなく、スクリプトイン スタンス内のローカルデータを検索し、更新することに制限 イメージデータのキャッシュ化 されます。 名前の示すとおり、Image Filterプラグインは名前の示すとお キャッシュ処理が有効になると、新しい内部イメージデータ りフィルタです。データはレイアウトの一端から入り、レイ を明示的に「フラッシュ」する必要はありません。スクリプ アウトの他端から直接返されます。レイアウトレンダリング トのprocess()関数が終了した時点で、LS/IFプラグインが バッファ内のデータのコピーを検索するため、 b u f f e r- 自動的に修正済みデータのレイアウトへの更新を完全に実行 line()を呼び出す場合は、ユーザがその行を処理し、使用 します。 可能な処理コマンドのいずれかを使用してレイアウトに返さ なければなりません。一般的な処理状況では、この修正済み LS/IFロジックの流れ データをレイアウトに渡すと、二度とアクセスすることはで ここで、L i g h t W a v e 3 Dレイアウトから呼び出されるときに、 きません。同じスキャンラインを要求する bufferline() LS/IFスクリプトを経由して渡されるコントロールの流れを検 の呼び出しを行っても、元の、修正していないスキャンライ 討してみましょう。 ンデータを返すだけです。ユーザが修正したデータは、ユー LS/IFスクリプト内の処理シーケンスは一般に flags()関数 ザの手の届かない別のバッファに安全に、しかも永久にしま から始まります。この関数はオプションで、flags()を実際 い込まれます。 にスクリプトで使用すると、 p r o c e s s ( ) 関数では赤、緑、 LS/IFは、レイアウトが提供するレンダリング済みイメージデ 青、およびアルファの各バッファだけが使用可能となります。 ータを取り出し、ローカルでキャッシュ化する、内部メカニ わかりやすくするため、暗示バッファを選択する、スペース ズムをスクリプト作成者に提供します。これにより、複数パ を消耗するだけのflags()関数を呼び出してみます。 スでのイメージデータ処理、あるいはデータすべてを循環す 例 る必要なく、イメージの一部だけの処理などの手順が行えま flags す。このメカニズムは必ずしもLS/IFスクリプトの速度を改善 { することはなく、むしろ、スクリプト作成者に便宜を提供し return(RED,GREEN,BLUE,ALPHA); ます。 } このキャッシュ処理機能を有効にするには、LS/IFスクリプト のprocess()関数の冒頭で次の関数を呼び出します。 スクリプトがアクティブになっていれば、レイアウトは cache() process()関数を呼び出して、レンダリング済みイメージ に処理を追加しようとします。これは一般的にイメージがレ この関数は、LS/IFスクリプトインスタンスにすべてのレンダ ンダリングされた直後で、まだユーザに表示されておらず、 リング済みイメージデータをスクリプトのローカルメモリス ディスクに保存もされていない時に発生します。次に、スク ペースに置かせ、同一データに対して複数のアクセスを容易 リプトが各イメージの複製を必要とする場合の一般的な処理 にします。 のフローを示す、不完全なprocess()関数を示します。 –58– 内の結果を示す場所は、(一般的には、出力時に黒となる、各 例 チャネルにゼロを割り当てた)未定義値RGBになります。 process: width, height, frame, starttime, endtime モニタの使用 { レイアウトLScriptプラグインの中での固有な、LS/IFはモデラ out[3] = nil; // レイアウトに返される新しい値を保持 for(i = 1;i <= height;++i) スを提供します。Image Filterプラグインの内部で大半の処理 ーLScriptが提供するのと同様のプログレスモニタへのアクセ が行われるので、仮想インジケータを使用して、処理の進行 { red 具合をビューアにフィードバックします。 (アニメーションの = bufferline(RED,i); green = bufferline(GREEN,i); 1フレームごとに640x480の各イメージを1ピクセルごとに何 blue らかの関数を実行しなければならないことを想像してみてく = bufferline(BLUE,i); ださい!) alpha = bufferline(ALPHA,i); 次の関数は、レイアウトが提供するモニタアクセスを管理す for(j = 1;j <= width;++j) る際に使用します。見てのとおり、これらの関数の使用方法 { はモデラーLScript内で提供される関数とほとんど同じです。 //バッファ値に関して何らかの操作を //実行 moninit(steps) ・・・ モニタシステムを初期化し、処理タスクを完了するまでに必 setrgb(j,i,out); 要なステップ数を予測します。 setalpha(j,i,alpha[j]); monstep([advance]) } 提供されるオプションの整数値により、モニタインジケータ } を次に進めます。引数がない場合は、アドバンス値は1となり } ます。 特定イメージピクセル、あるいはアルファチャネル値を変更 monend() するかしないかにかかわらず、 cache()への呼び出しを用い モニタシステムを終了します。 てキャッシュ処理を有効にしていないかぎり、 setrgb()と setalpha()(あるいは、代わりにprocessrgb())を作 LS/PT(プロシージャルテクスチャ) 成しなければなりません。名前が示すとおり、LS/IFはイメー (一般的にはシェーダーと呼ばれることの多い)プロシージャ ジフィルタであり、他のすべてのフィルタと同様、何かの入 力を期待し、必要なものを通過させて、結果を出力します。 LightWaveのレイアウトは、赤、緑、青とアルファチャネル の各バッファ内のすべてのピクセルがこのフィルタを通過し、 ルテクスチャは、特定の値に基づいてレンダリング時に計算 されるサーフェイスの表現です。L S / P Tはシェーダースクリ プト処理プラグインで、サーフェイスに任意のテクスチャあ 完全なイメージを生成することを期待しています。ピクセル るいは色を付ける際に使用します。 をレイアウトの出力に処理できなかった場合は、ユーザがそ 組み込まれたスクリプト例のBlotchは、サーフェイスに着色 の他を変更しているかいないかにかかわらず、最終イメージ したスポットを作成します。 –59– シェーダー関数 テクスチャの処理 LS/PTには、2つのLS/PTに特有なサポート関数があります。 すべてのレイアウトスクリプトの場合と同様、L S / P Tスクリ プトの処理ポイントは、 p r o c e s s ( ) 関数です。この init() process()関数はピクセル単位で呼び出されます。 フレームのシーケンス開始時点で呼び出されます。テクスチ LS/PTは、スクリプトの proces()関数に1つの引数を提供し ャを正しく生成するために必要なスクリプト値を初期化しま ます。この引数はオブジェクトエージェントのインスタンス す。 で、シェーダーオブジェクトと呼ばれています。このオブジ cleanup() ェクトにはアクセス可能なデータメンバーとメソッドがあり レンダリングシーケンスが完了した時点で呼び出されます。 ます(変更可能な場合もあります) 。 LS/PT シェーダオブジェクトには次のメンバ/メソッドがあり newtime(frame,time) ます。 現在のレンダリングシーケンス内の新しい時間の開始時に呼 び出されます。整数値" f r a m e "は現在のフレーム番号を示し、 sx (読取専用) (0,0)が左上隅を示す、ピクセル座標の最終イメージ内 "time"は現在のタイムインデックスを示します。 のスポットX位置を表す数値です。 sy flags() 読取専用) 0,0)sが左上隅を示す、ピクセル座標の最終イメージ 内のスポットY 位置を表す数値です。 L S / P Tスクリプトは、変更対象サーフェイスのテクスチャの 属性をレイアウトに示す必要があります。以下の値の中から1 oPos[3] つ、あるいは複数の値がflags()関数から返されます。 (読取専用) オブジェクト座標のスポット位置の座標を表す数値です。 NORMAL wPos[3] (読取専用) ワールド座標のスポット位置の座標を表す数値です。 COLOR gNorm[3] LUMINOUS (読取専用) ワールド座標系でのスポットのジオメトリックノーマル DIFFUSE を表す数値です。これは、そのスポットの未処理の法線 で、スムージングやバンプマッピングで改変されていま SPECULAR せん。 MIRROR spotSize TRANSPARENT (読取専用) おおよそのスポット直径を表す数値です。エッジに見え ETA るサーフェイスのスポットは細長いので、これは非常に ROUGHNESS に使用できます。 近い値です。これは、テクスチャのアンチエリアシング RAYTRACE raySource[3] (読取専用) ワールド座標に入ってくるビュー処理対象のレイの原点 を表す数値です。これは、カメラになりますが、カメラ LS/PTスクリプトが raytrace()メソッド(現在説明中)を でなくてもかまいません。 活用する場合は、L S / P Tスクリプトは f l a g s ( )に返し値の RAYTRACEフラグを組み込んでいなければなりません。 –60– luminous rayLength (読取専用) このスポットに到達するまでの空間をビュー処理対象の サーフェイスの明るさをパーセントで表す数値です。 レイが移動する距離を表す数値です。 cosine (1.0 == 100%) (読取専用) diffuse ビュー処理対象のレイとこのスポットの法線との間の角 サーフェイスのディフューズをパーセントで表す数値で 度に対する余弦を表す数値です。これは、このビューが す。(1.0 == 100%) どのように見えるか、およびスポットサイズがどの程度 specular の概算値であるかを知る手段を提供します。 oXfrm[9] サーフェイスのスペキュラリティをパーセントで表す数 (読取専用) 値です。(1.0 == 100%) オブジェクト座標からワールド座標への変換マトリクス mirror です。これは別の方法で計算することもできますが、速 wXfrm[9] 度を上げるためここに組み込み、主に方向ベクトルに使 サーフェイスのミラーリング(反射)をパーセントで表 用することを目的としています。 す数値です。 (1.0 == 100%) transparency (読取専用) ワールド座標からオブジェクト座標への変換マトリクス サーフェイスのトランスペアレンシーをパーセントで表 です。これは別の方法で計算することもできますが、速 す数値です。 (1.0 == 100%) 度を上げるためここに組み込み、主に方向ベクトルに使 eta 用することを目的としています。 objID サーフェイスの屈折率をパーセントで表す数値です。 (読取専用) (1.0 == 100%) シェーディング対象のオブジェクトを表すオブジェクト roughness エージェントへのポインタです。 polNum サーフェイスの粗さをパーセントで表す数値です。 (1.0 (読取専用) == 100%) シェーディング対象のオブジェクトのポリゴン数を表す 整数です。これは通常のメッシュオブジェクトではポリ ゴン数ですが、メッシュ以外のオブジェクトの場合は他 直接見える色を設定するため、シェーダースクリプトは、1.0 のサブオブジェクト情報の場合もあります。 をとるluminousと、スポットの出力カラーである、colorを除 wNorm[3] く、パラメータすべてをゼロに設定することができます。 ワールド座標のスポットの新しいジオメトリックノーマ ルです。これを変更すると、ジオメトリ(バンプマッピ ShaderObjectメソッド ング)を変更しなくてもサーフェイスをでこぼこの感じ ShaderObjectはサーフェイステクスチャを生成する際に使用 することができます。このシェーダーは、パータベーシ する2つのメソッドを提供します。 ョンの後にベクトルを再度ノーマライズする必要があり illuminate(ライト,位置) ます。 この関数は、現時点で指定のライトから指定位置までの光線 color[3] サーフェイスに使用する色の赤[1] 、緑[2] 、青[3]の (color[1-3]およびdirection[4-6])を表す、6つの数値からなる 各パーセント値を表す数値です。ここで1.0 は100%を 配列を返します。ライトが指定のワールド座標位置を全く照 指します。 らさない場合は、戻り値はゼロになります。c o l o rは、(存在 すれば)シャドウからのエフェクト、フォールオフ、スポッ –61– トライトコーン、ライトとポイント間の透明オブジェクトを oPos[3] (読取専用) 組み込みます。 元の位置で処理されるポイントの位置を表す数値です。 raytrace(位置,方向) ットを計算する際に使用します。 これらの値は変更されず、経過時間にもとづき、オフセ この関数は、(ワールド座標の)指定方向の指定場所からの光 source[3] 線をトレースするために呼び出されます。この関数はray[1]の 現在のフレーム/タイムで処理されるポイントの新しい位 長さを現し、その direction[2-4]から入力されるカラーを表す、 置を表す数値です。 4つのエレメントからなる配列を返します。光線の長さが不定 の場合は-1から0です。使用される方向は外向きの方向で、単 ディスプレイスメントオブジェクトで提供されるメソッドは 位ベクトルに正規化されなければなりません。 ありません。 LS/DM(ディスプレイスメントマップ) LS/IA(アイテムアニメーション) LS/DMのプラグインは、指定フレームあるいは時間に基づき、 LS/IA、アイテムアニメーションプラグインを用いると、ユー オブジェクトのポイントの位置を計算する際に使用します。 ザはアニメーションシーケンス中のオブジェクトの解釈に影 一回の呼び出しで処理が完了するLS/IFと異なり、LS/DMスク 響を及ぼすことができます。レイアウトが計算したオブジェ リプトはポイントごとに呼び出されます。 クトの位置、回転、およびスケーリング、オーバーライドを ディスプレースメント関数 変更できます。 LS/MDは次のディスプレースメント特有の関数を提供します。 モーションの処理 newtime(オブジェクト,フレーム,時間) L S / I Aは p r o c e s s ( ) 関数に3つの引数を提供します。第2、 L S / P Tと同様、この関数は現在のシーケンス内で新しく時間 第3のパラメータは、現在の呼び出しに対する整数のフレーム が開始するときに呼び出されます。 newtime()に提供され 番号と、数値のタイムインデックスです。最初の引数は るパラメータは、処理対象のポイントを含むオブジェクトを MotionObjectのインスタンスです。 表すオブジェクトエージェントと、フレーム番号を表す整数 LS/IA MotionObjectは次のオブジェクトメソッドを提供しま と、現在のタイムインデックスを表す数値です。 す。 flags() get(属性,時間) この関数は、ディスプレースメントがワールド座標内で発生 この関数は指定"時間"の指定属性の値を表すベクトルを返しま するか、あるいはオブジェクトのローカル座標内で発生する す。"属性"は、 POSITION、ROTATION、SCALINGのいずれか かを示す、2つの値のうちのいずれかを返します。 となります。"時間"は、ユーザの関心のあるタイムインデック ディスプレースメントの処理 スです。ROTATIONの場合、値は「度数」です。SCALING値 L S / D Mの p r o c e s s ( )関数には1つの引数があります。この は乗数で、1.0の場合は変更なしです。 引数は、ディスプレイスメントオブジェクトのインスタンス set(属性,値) です。 この関数は指定指定した属性( P O S I T I O N、 R O T A T I O N 、 LS/DM ディスプレイスメントオブジェクトには以下のデータ SCALING)を新たなベクトル値にセットします。 メンバがあります。 –62– LS/IA ディスプレイスメントオブジェクトには次のデータメ curType 現在のレンダリング対象のタイプを示す定数値です。ス ンバーがあります。 objID (読取専用) クリプトはこの値を調べて、対話型プレビューと実際の (読取専用) レンダリング時に異なるジオメトリを提供します。この この特定プラグインを割り当てているオブジェクトエー 値はNONE、 PREVIEW 、RENDERのいずれかになり ジェントへのポインタです。 ます。NONE は現在のタイムインデックスにジオメトリ がロードされていないときに提示されます。PREVIEW LS/OR(オブジェクトリプレイスメント) は、レイアウトプレビューを生成中であることを示し、 LS/ORを用いると、フレーム単位でレイアウトのオブジェク RENDERは完全なレンダリングを実行しているときに使 トを交換できます。 用されます。 newType 交換の処理 次のフレーム/タイムインデックスで実行されるレンダリ LS/ORのプラグインの process()関数は引数を1個受け取り ングのタイプを示す定数です。このメンバはNONE、 ます。この引数はリプレイスメントオブジェクトのインスタ REVIEW、RENDERのいずれかです。 ンスです。 LS/ORのリプレイスメントオブジェクトは次のデ curFilename(読取専用) ータメンバを提供します。 objID (読取専用) 現在ロードされているオブジェクトジオメトリファイル (読取専用) を表す文字列値です。ロードされているジオメトリがな ジオメトリを交換する対象のオブジェクトを表 ければ、nilの場合もあります。 すオブジェクトエージェントです。 curFrame newFilename 新しいタイムインデックスで、このアイテムのジオメト (読取専用) リとしてロードされている新しいオブジェクトファイル 現在ロードされているジオメトリのフレーム番号を表す のファイル名を表す文字列値で、スクリプトが設定する 整数値です。 curTime 唯一のデータメンバです。新しいジオメトリのロードは、 (読取専用) 多大なオーバーヘッドを発生するので、新しいジオメト 現在ロードされているジオメトリのタイムインデックス リが現在ロードされているジオメトリと異なるときにの を表す番号です。 newFrame み設定します。 (読取専用) 次のステップのフレーム番号を表す整数値です。新しい LS/GN(レイアウトジェネリック) フレームでオブジェクトが異なった外観になる必要があ newTime る場合は、新しいジオメトリをロードしなければなりま 最後の、レイアウトジェネリックスクリプト処理になりまし せん。 た。LS/GNを用いると、シーンあるいはシーンのコンポーネ ントと関連付けをしなくても、レイアウトの内部オブジェク (読取専用) 次のステップのタイムインデックスを表す整数値です。 トとデータにアクセスできます。レイアウトジェネリックス オブジェクトが新しいタイムインデックスで異なった外 クリプトはシーンのすべてのコンポーネントと設定値にアク 観になる必要がある場合は、新しいジオメトリをロード セスでき、L S c r i p tエンジンに属するすべての関数とデータ しなければなりません。ネットワークレンダリングはシ ーケンシャルでない時刻と時刻の間でレンダラにジャン (プリプロセッサ、リクエスタサポート、IPCキューなど)に もアクセスできます。 プを発生させることもあるので、"curTime"および "newTime"はシーケンスでない場合があります。 –63– ロードされると、内部的にシーンファイルに名前を付けます。 ジェネリックスクリプトの構築 レイアウトジェネリックスクリプトはモデラースクリプトで このオプション名はシーンの新しいファイル名となります。 使用するフォーマットと非常に類似しています。すべてのレ このパラメータが提供されない場合は、代わりに "filename"パ イアウトジェネリックスクリプトにおいて必須の関数が1つあ ラメータが使用されます。 り、この関数は generic()と呼ばれています。レイアウト savescene(ファイル名) ジェネリックスクリプトが呼び出されると、この関数を用い この関数は、レイアウトに現在ロードされているシーンをの て実行が開始され、この関数が終了すると、スクリプトの実 パスを含んだファイル名を保存します。 行は完了します。 次に、現在レイアウトにロードしているオブジェクトの頂点 数をレポートする、単純なレイアウトジェネリックスクリプ トを紹介します。 generic { if(!reqbegin("Point Count")) return; //パネルサービスプラグインがない場合 c1 = additems("Reference object"); if(reqpost()) { if((item = getvalue(c1)) == nil) return; } else return; reqend(); info("Object ",item.name," has",item.pointcount," points."); } ジェネリック関数 レイアウトジェネリックアーキテクチャは、レイアウトのシ ーンを管理するための2つの関数を使用可能にします。 loadscene(ファイル名[,タイトル]) この関数は、レイアウトのシーンファイルとして示された"フ ァイル名"をロードします。オプションの"title"パラメータは、 –64– LScriptの拡張:ネイティブコードとのリンク L S c r i p t言語はユーザ定義手順( U D F)をサポートします。 #define LSINTEGER 1 BMLコアエンジンの旧リリース(LScriptの前身)では、メイ #define LSNUMBER 2 ンスクリプトの本体にあるか、あるいはBMLスクリプトライ #define LSSTRING 3 ブラリファイルで宣言されているかにかかわらず、 U D Fは #define LSVECTOR 4 BMLスクリプト処理言語だけで定義可能な手順だけに限定さ #define LSFILE 5 #define LSNIL 99 れていました。 LScriptのコアエンジンは共有ライブラリ(Windows DLLある いはUNIXの共有ライブラリ)を直接リンクして、ネイティブ 次に定義されたアイテムはLScriptとDLL関数との間で渡すデ マシンコードで書かれたUDFのパワーと速度を利用できます。 ータを含む構造体です。 このネイティブコードはCあるいはC++ソースから作成します。 typedef struct _ls_var この機能は複数のプラグイン機能を、たとえば、1つのプラグ { インに提供することによく似ています。 int この文書の残りでは、Microsoft Windowsのダイナミックリ type; union ンクライブラリー(D L L)を用いた共有ライブラリを説明す { ることに集中してゆきます。L S c r i p tのU N I Xバージョン下で、 double number; 共有ライブラリを作成する方法はプラットフォームにより異 const char *string; なるので、最も普及したLightWave3Dプラットフォームを中 double vector[3]; 心にして説明します。説明するテクニックのほとんどは }data; LScriptとリンク可能な共有ライブラリを生成する UNIXメソッ }LS_VAR; ドにも同様に適用できます。 Microsoft Windowsでは、LScriptスクリプトを用いてリンク " t y p e "メンバーはファイルの冒頭に定義されたデータタイプ するD L Lライブラリ機能を生成するために必要なステップは (LSINTEGER、LSNUMBERなど)の一つを保持します。 "type" 複数あります。まず、LScriptインターフェイスメカニズムに に基づき、"data"ユニオンメンバ、 "number"、"string"、ある 詳しくなければなりません。このメカニズムを用いるとユー いは" v e c t o r "の一つからデータを抽出できます。ユニオンの ザは実行中の LScriptを用いて直接対話できます。これは、コ "number"メンバは実数値と整数値を包含する際に使用します。 ンパイルするWindows DLLソースファイルに組み込まなけれ たとえば、データの"型"がLSINTEGERであれば、"number"メ ばならない、"lscript.h"ヘッダーファイルに定義されます。 ンバの単純なキャストは整数値を抽出します。 ライブラリを作成する際に使用できるように、"lscript.h"ヘッ ダーファイルには複数のアイテムが定義されます。最初に、 x = (int)・・・data.member; LScriptとDLL関数とで渡されるデータタイプはマニフェスト ヘッダーの次のエントリは、LScriptとの対話を希望するすべ 定数として提供されます。一部の複雑なLScriptデータタイプ てのD L L関数が付加しなければならない関数プロトタイプで はD L L関数では現在利用可能ではありませんが、次のデータ す。DLL関数は、typedefを直接使用することはなく、関数 タイプを用いるとかなり多くのことができます。 を作成する間にガイドとして組み込まれます。LScriptのコア –65– エンジンは、このプロトタイプを用いてD L L関数を呼び出し typedef struct _lsfunc ます。 { typedef LS_VAR * (*DLLfunc)(int *count,LS_VAR char * (*strdup)(const char *); *,LSFunc *); void * (*malloc)(int); LScriptはそれ自体が共有ライブラリなので、LScriptをロード void (*free)(void *); したホストプロセスのリソース(つまり、LightWave3D)を void (*info)(const char *); 活用します。 LScriptがメモリを割り当てたり、ファイルを開 void (*error)(const char *); く場合、LightWave3Dの利用できるリソースを使用して行い } LSFunc; ます。そのため、LScriptはLightWaveのハウスでは、最後に 先に定義した関数に戻ると、各共有ライブラリへの最後のパ クリーンアップを実行してレイアウトへのメモリリークの開 始を避け、礼儀正しいゲストになろうとします。そのため、 LScriptは、終了時にスクリプトの実行時に正しく解放されな ラメータはこのタイプの構造体、L S F u n cへのポインタです。 この構造体ポインタを使用して、内部に含まれる関数ポイン タにアクセスできます。 かったリソースがあれば、それを解放できるように、スクリ プトの実行により発生したメモリの割り当てすべてをトレー LS_VAR *dllfunc(int count,LS_VAR スします。 *parameters,LSFunc *func) LScriptはLScriptのハウス内のゲストに礼儀正しく振る舞うこ { とを期待しています。最後にLScriptは、これらの重要な割り ・・・ 当てを管理する際に使用する内部機能へのアクセスをゲスト に提供します。共有ライブラリ関数がリソース(メモリある // 5個のLA_VARからなる配列を割り当て vars = (LS_VAR *)(*func- いはファイル)を割り当てる必要がある場合は、これらの関 >malloc)(sizeof(LS_VAR) * 5); 数を利用することをお勧めします。しかし、これは、リソー ・・・ スをいいかげんに取り扱ってよいということではありません。 // 割り当てを解放・・・ (*func->free)(vars); 使用する資源を明示的に割り当てて解放する規制を維持すべ ・・・ きですが、標準ライブラリの代わりに、これらのエクスポー } トされた内部 LScript関数を用いて維持してください。そうす れば、明示的なリソースの解放を見落とした場合にも、終了 する前にLScriptがそれを捕捉できます。 メッセージの表示 lscript.hヘッダーファイルの次のエントリはLScriptがエクス LSFunc構造体には、LScriptの関数と名前が似ている info() ポートした各内部リソース管理関数へのポインタを含む構造 とerror()という2つの関数ポインタがあります。これらの 体の定義です。 関数ポインタは、 LScriptの対応する関数と非常に類似してお り、共有ライブラリを提供します。この共有ライブラリは、 情報あるいはエラーメッセージをLScriptの内部メッセージ処 理メカニズムを経由してLightWave3Dユーザに対して表示す る手段です。 –66– これらの関数は、構造体にリストされた他の関数ポインタと char *getVolumeSerialNumber(void) 同じ方法で呼び出されますが、ユーザに見える形で結果を出 { 力します。 ・・・ char tmpPath[MAX_PATH + 1]; char tmpFile[MAX_PATH + 1]; (*func->error)("severe error: bad static char volumeSN[50]; parameter"); BY_HANDLE_FILE_INFORMATION fileInfo; ・・・ HANDLE hFile; GetTempPath(MAX_PATH,tmpPath); これらの関数に関して注意しなければならない重要なことが2 点あります。まず、LScriptに渡したメッセージは表示される GetTempFileName (tmpPath, "LScript", 最終メッセージではないということです。LScriptはユーザに 0, tmpFile); メッセージを表示する前に、メッセージの始め(と潜在的な hFile = CreateFile(tmpFile, 終わり)に情報を配置します。そのため、ユーザはメッセー GENERIC_READ | ジの始めには大文字から始まる単語を使用しないというガイ GENERIC_WRITE,0,NULL,OPEN_ALWAYS, ドラインに従うべきで、ユーザに見えている情報がすべてで FILE_ATTRIBUTE_TEMPORARY,NULL); あると想定してはいけません。 GetFileInformationByHandle(hFile,&fil Line #45, severe error: bad paramerter eInfo); 第2に、 error()関数の呼び出しを行うと、共有ライブラリ sprintf(volumeSN,"%.4X- 関数が終了するときにLScriptに現在のスクリプトの実行を停 %.4X",HIWORD(fileInfo.dwVolumeSerialN 止させるための内部フラグを設定します。そのため、 umber), error()はスクリプト内で後に続けてエラーを発生する共有 ライブラリ関数内で重大なエラーを発見した場合にのみ使用 されることを目的としています。 LOWORD(fileInfo.dwVolumeSerialNumber) 共有ライブラリの構築 ); LScriptとリンク可能な共有ライブラリを作成する際の次のス CloseHandle(hFile); テップでは、D L L関数を定義(前述のガイドラインに従って DeleteFile(tmpFile); いることを確認)します。LightWaveWindowsのプラットフ return(&volumeSN); ォームでは、ローカルドライブのボリュームシリアル番号を } 取得する方法が必要です。これはLScriptから行うことができ ますが面倒です(しかも遅くなります)。この解決策として、 現在の状態では、 LScript内で直接この関数を使用できません 新しく「ビルトイン」関数を作成して同じタスクを行うこと ので、LScriptのリンク条件を満たすようにこの関数を変更し ができます。次に、Windows Win32 APIから関数を借用して なれればなりません。しかし、変更部分は比較的マイナーな 現在のローカルドライブのボリュームシリアル番号を検索す 部分です。 るC関数を紹介します。 –67– 最初に、関数のヘッダーを" l s c r i p t . h "ヘッダーにある に渡されたパラメータのカウントが正しいことを確認するこ typdefと完全に一致するように変更します。すると、 とは共有ライブラリ関数の役目です。 char *getVolumeSerialNumber(void) if(*count != 0) { は、次のようになります。 // 引数なし (*func->error)("invalid parameter LS_VAR * getVolumeSerialNumber(int count to DLL function ... "); *count,LS_VAR *vars,LSFunc *func) return(NULL); } 次に、LScriptに返す値が存在しなければなりません。元の関 数ではスタティックエリアへのポインタを返しただけでした。 これはLScriptとの対話には不十分です。 LScriptが読取り可能 なデータの1アイテムを保持する、1つあるいは複数の ーとなります。 LS_VAR構造体を返さなければなりません。この特定関数の場 関数の本体はほとんど変更しません。ボリュームシリアル番 合は、LS_VAR構造体にラッピングされた文字列と同じ文字列 号を確認できたら、LScriptが理解できるフォーマットにパッ を返します。 ケージングしなければなりません。元の関数では、スタティ 関数の中でプライベートな LS_VAR変数を宣言します。関数が ック文字列エリアへの文字ポインタを返しただけでした。 返された後に、「スタティック」として宣言するために、変数 return(&volumeSN); 自体が存在することも確認しなければなりません。 しかし、LScriptが適切にデータを処理するには、 LS_VAR構 ・・・ static getVolumeSerialNumber()関数の場合は引数を取りま せん(つまり、"void"です)。何かを渡された場合は、エラ 造体でラッピングし、LScriptエンジンにデータ型と返すデー LS_VAR var; タアイテム数を知らせなければなりません。関数の新しい終 ・・・ 了コードは次のようになります。 同様に、返す文字列は関数を返した後にも引き続き存在しな ければなりません。 (でなければ、LScriptが「解放済み」メモ var.type = LSSTRING; リにアクセスする際に大問題が発生します。 )幸運にも、元の var.data.string = volumeSN; 関数内に定義されている「永久」エリアが既にあるので、こ こに、メモリを破壊することを恐れず文字列を置いておけま *count = 1; // 期待するデータアイテムの数 return(&var); す。 } ここで、次に getVolumeSerialNumber()関数全体を紹 ・・・ static char volumeSN[50]; 介します。 ・・・ 次に、関数が受け付けたパラメータを変更しているので、コ ンパイラがコンパイル時に不正なパラメータを検出すること を期待できません。つまり、このパラメータを実行時にチェ ックしなければなりません。LScriptから共有ライブラリ関数 –68– LScriptへのエクスポート関数 #include <stdio.h> #include <windows.h> (さらに関数を追加してから)DLLを生成する準備が整ったら、 #include "lscript.h" 定義ファイルを作成しなければなりません。この定義ファイ ルは、コンパイラが使用するプロセッサが認識できる(エク LS_VAR * getVolumeSerialNumber(int スポートされる)ライブラリの関数をコンパイラに指示しま *count,LS_VAR *vars) す。これは非常に重要なポイントです。関数が定義ファイル { を使用してエクスポートされていないと、LScript内の参照は char tmpPath[MAX_PATH + 1]; char tmpFile[MAX_PATH + 1]; static char volumeSN[50]; LIBRARY static LS_VAR var; EXPORTS 未解決のままとなり、エラーが発生します。 BY_HANDLE_FILE_INFORMATION fileInfo; HANDLE test getVolumeSerialNumber hFile; この定義ファイルは任意の名前を付けて保存できます。ただ if(*count != 0) // 引数は取りません return(NULL); し、D L Lライブラリをコンパイルする際にはその名前を使用 しなければなりません。この例の場合は、 "dll.def"と名 GetTempPath(MAX_PATH,tmpPath); 前を付けました。 D L Lライブラリに関数を追加する場合は、 GetTempFileName ( tmpPath, "LScript" , コンパイルする前に定義ファイルの"EXPORTS"セクションの 0 , tmpFile); 下に名前を追加しなければなりません。 hFile = CreateFile (tmpFile, GENERIC_READ | GENERIC_WRITE,0, NULL, Makefileの使用 OPEN_ALWAYS,FILE_ATTRIBUTE_TEMPORARY, 次に残っているステップの中にDLLライブラリ用のmakefileの NULL); 作成がありますが、Makefileの作成はサイエンスというより GetFileInformationByHandle (hFile, もアートの世界なのでこのマニュアルの対象外です。代わり &fileInfo); に、この節に紹介するサンプルのD L Lソースファイルを直接 sprintf(volumeSN,"%.4X-%.4X",HIWORD コンパイルし、他の makefilesを設計する際にテンプレートと (fileInfo.dwVolumeSerialNumber), して使用できる、ファンクショナルなmakefileをここに示し LOWORD (fileInfo. ます。このmakefileは、Microsoft Visual C++の開発システム dwVolumeSerialNumber)); で使用するためのものです。 CloseHandle(hFile); DeleteFile(tmpFile); var.type = LSSTRING; var.data.string = volumeSN; *count = 1; return(&var); } –69– CFMACH = -D_X86_=1 CFLAGS = -c -W3 $(CFMACH) -DWIN32 -D_WIN32 パスが " l i b r a r y " コマンドに指定されていない場合は、 LScriptエンジンは DLLファイルを探し出すために、次の場所 をスキャンします。 /O2 /I . $(OPT) LFLAGS 1 .現在のディレクトリ(スクリプトがある場所と同じ場合も = -dll -def:.\dll.def ありますがそうでない場合もあります) OBJS = test.obj LLIBS 2 . W i n d o w sのシステムディレクトリ(通常はW i n d o w s ¥ S y s- = libc.lib kernel32.lib temまたはWinNT¥System32) .cpp.dll: 3 .このプラグインタイプ用のL S c r i p tの環境設定でのL i b r a r y- cl $(CFLAGS) $*.cpp Pathエントリ(ls-if、ls-orなど) .c.dll: cl $(CFLAGS) $*.c all : test.dll test.dll: $(OBJS) link $(LFLAGS) -out:test.dll $(OBJS) $(LLIBS) test.obj : test.c 開発システムとしてMicrosoft Visual C++を実際に使用する場 合は、nmakeを呼び出すだけで、LScriptに直接リンクできる 全く新しいD L Lを生成します。他の開発システムでは、提供 されるmakefileと、おそらくその他のファイルも変更する必 要があります。 共有ライブラリの使用 LScriptを拡張する場合の、このプロセスの最後のステップは、 DLLライブラリを使用するLScriptを実際に書くことです。こ れは、ほんの2、3行のLScriptを使用して行うことができます。 library "test.dll"; main { info("Your volume serial number is ",getVolumeSerialNumber()); } –70– LScript共有ライブラリの拡張 D L Lと他のデータポインタについて説明している付録Aの、 LSFuncのインスタンスをハウジングする新しい構造体が定義 共有ライブラリメカニズムを活用すると、ユーザ定義のオブ ジェクトエージェントをインプリメントする際に使用できる、 されます。 共有ライブラリを作成することができます。つまり、 (技術的 typedef struct _lsdll には、クラス定義と呼ばれている)新しいオブジェクトエー { ジェントを共有ライブラリの中に作成でき、これらのオブジ const char *ClassName; ェクトエージェント(クラス定義)のインスタンスは次の宣 const char *InstanceName; 言を使用してプログラマーがLScript内に作成できます。 use "<filename>.dll" as class <ClassName>; LS_VAR *instance[MAXINSTANCE]; LSFunc *func; } LSDLL; 独自のオブジェクトエージェントを作成するためのプロトコ ルは、LScriptの呼び出し可能な共有ライブラリを作成するた "ClassName"メンバーは、LScriptで設計されたオブジェクト めのプロトコルよりはずっと複雑になります。C++クラスの設 エージェントの"クラス"名の入った文字列を指し示します。 計をエミュレートするという苦労をしておいたので、オブジ "InstanceName"は、オブジェクトエージェントの現在の ェクトエージェントの共有ライブラリには、データメンバや インスタンスの入った変数名を含む文字列を指し示します。 エクスポートされたメソッドなどの、LScriptでオブジェクト エージェントを使用できるようにする、 (デストラクタなどの) LScriptエンジンだけからアクセスできる「メソッド」(関数) があります。 "instance"配列は、オブジェクトエージェントのインスタ ンスデータの MAXINSTANCE配列シリーズです。現在のイン スタンスは、独自のインスタンスデータがあれば必ず、 instance[0]からそれにアクセスします。現在は使用され ユーザ定義のオブジェクトエージェントを構築するための必 ていませんが、残りのエレメントはオブジェクトの継承結果 要条件を理解しやすくするため、"BobObj"という名の、役立 として必要となる可能性のある、将来のインスタンスデータ つかどうかは疑問なオブジェクトエージェントを構築してみ 用に予約されています。インスタンスデータについてはこの ます。"BobObj"には「パブリック」メソッドが1つだけしかな く、そのメソッドの s t r a d d ( ) は、2つの文字列を結合し、 新しい文字列を返します。 セクションの後で説明します。 新しいプロトタイプには「パブリック」なオブジェクトエー ジェントメソッドを作成するときに使用するように定義され D L L関数と同様、このセクションで説明するトピックは、プ ます。このプロトタイプはLScriptエンジンがユーザのメソッ ログラム上の内容で、本質的に重要です。これらは本格的な ドを呼び出す際に使用します。 デベロッパ用です。 typedef LS_VAR * (*ObjectAgentMethod)(int *,LS_VAR *,LSDLL *); "lscript.h"への拡張 ユーザ定義のオブジェクトエージェントを活用するには、構 造体と定数を追加して、lscript.hヘッダーファイルに組み込ま プライベートクラスメソッド なければなりません。 各オブジェクトエージェントの共有ライブラリは新しいオブ ジェクトエージェントの管理機能のベースを表す4つのメソッ ドを利用できるようにしなければなりません。これらの4つの –71– 必須メソッドはそれぞれに異なる数のパラメータを受け取り データメンバに適用します。"dataname"は問題のデータメ ます。インターフェイスには4つの必須メソッドのいずれかの ンバの名前の入った文字列です。 動作様式によって必要とされれば、さらに2つのメソッドがオ また、インターフェイスにはさらに3種類のメソッドがありま プションで用意されています。 す。そのうちの2種類のメソッドは、オブジェクトエージェン 4つの必須メソッドを以下に示します。 トクラスの「パブリック」データメンバへのアクセスを管理 する際に使用し、第3のメソッドは、オブジェクトエージェン void constructor(count,variables,classinfo) "count"は、このコンストラクタに渡されたパラメータ数を トを(ヘッダーファイルの l s c r i p t . h の中の O A M A J O R と OAMINOR宣言子を用いて定義された)オブジェクトエージェ 表す整数値です。 ントインターフェイスの特定バージョンにロックします。 "variable"は、コンストラクタに渡されたパラメータの値 LS_VAR *returndata(dataname,classinfo) が入ったLS_VAR配列へのポインタです。パラメータが渡され returndata()は、"dataname->extra"が名前をつけ ない場合は NULL("count"は0)になります。 "class- たオブジェクトエージェントのデータメンバに含まれる値を info"は、クラスとインスタンス名、内で LScript関数へのポ 返します。 v o i d *は c h a r *にキャストすべきです。 o w n- インタ、インスタンスデータへのポインタに関する情報の入 data()に前もってそのデータメンバがこのオブジェクトエ った(前述の)LSDLL構造体のインスタンスです。 ージェントが所有するデータメンバであることを示していな ければ、データメンバのために returndat()が呼び出され void destructor(count,variables,classinfo) ることはありません。 パラメータはコンストラクタのパラメータと同じですが、デ "dataname->data.number"メンバは、参照したデータ ストラクタは直接呼び出すことはできないので、 "count"は メンバが配列の場合は整数をキャストしなければなりません。 必ず0、"variables"は必ずNULLです。 "dataname->data.number"はスクリプト内で使用する インデックス値であり、ゼロを基準にしたオフセットに変換 されます。 boolean ownmethod(methodname) このインターフェイスメソッドはオブジェクトエージェント ご注意ください。この値はインデックス値として必要 のインスタンスが特定メソッドを持っているかどうかを調べ な場合にのみキャストされるべきです。スクリプト処 る際にLScriptが使用します。"methodname"は、問題のメソッ 理エンジンにより明示的に設定されていないときにこの値を ドに名前をつける文字列です。 ownmethod()は、この文字 キャストすると、特定オペレーティングシステム(有名なと 列を使用して、既知の「パブリック」メソッドと比較し、メソ ころでは、DEC Alpha)が浮動小数点例外エラーを発生しま ッドのいずれかとこの名前が一致している場合は trueを、指 す。 定メソッドが使用できない場合はfalseを返します。 assigndata(dataname,data,classinfo) Boolean owndata(dataname) LScriptは、新しいデータをデータメンバに割り当てる場合に このプライベートメソッドは ownmethod()と似ていますが、 このオブジェクトエージェントメソッドを呼び出します。 オブジェクトエージェントが使用可能にする「パブリック」 LScriptは内部的に、既存データメンバら新しい値を割り当て る方法があればそれを使用します。このメソッドは結果を渡 –72– され、それに該当するデータメンバを更新するように期待さ 複数のインスタンスのハンドリング れます。 オブジェクトエージェントの共有ライブラリに置くことので r e t u r n d a t a ( ) の場合と同様、 " d a t a n a m e " は、 " e x t r a "エリアのデータメンバ識別子と、該当する場合は、 きる、1つのプションのプライベートメソッドは、オブジェク トエージェントインスタンスデータの作成をハンドリングす データメンバをインデックス処理できるのであれば、 る設計になっており、instdata()と呼ばれています。最初 "data.number"の要求したインデックスオフセットの両方 に、 「インスタンスデータ」とは何を指すか、およびなぜ必要 をハウジングする、LS_VAR構造体へのポインタです。 なのかを検討しましょう。 "data"は、新しい値の入った別のLS_VARポインタです。 「インスタンスデータ」はオブジェクトが機能するためには必 須の特定データ値のコピー、つまり、インスタンスに過ぎま "classinfo"はLSDLLのインスタンスです。 せん。インスタンスデータの必要性に関する良い例は、ファ version(major,minor) イル処理のオブジェクトエージェントです。ここで示す架空 "major"と"minor"は、このオブジェクトエージェントが のファイル処理オブジェクトエージェントには、オブジェク 機能するために必要なインターフェイスのレベルを示し、要 トエージェントデータの特定機能の一部のタイプを実行する 求したメジャーとマイナーのリビジョン値を受け取る整数の ように定義されたメソッドがあります。インスタンスデータ ポインタです。返された値が、プラグインでサポートしてい をハンドリングする機能がなければ、ファイルごとに別々の る現在のオブジェクトエージェントインターフェイスの指定 オブジェクトエージェントD L Lを維持(および宣言)しなけ と一致していない場合は、ライブラリはロードされず、関数 ればならなくなります。その理由は、D L Lが、ファイル名や での参照が未解決のままという結果になります。 ファイルポインタなどのアイテムを使用する際に(コンパイ インターフェイスの特殊な動作様式は、オブジェクトエージ ル時に宣言される)独自の変数を持っていなければなりませ ェントクラスに「パブリック」データメンバがあるかどうかに んが、この情報を保存できるは場所は1つしかないからです。 関係します。オブジェクトエージェントクラスに「パブリッ 1つのDLLを使用して、新しいファイルを処理する必要がある ク」データメンバがあると、特定のオブジェクトエージェン 場合は、既存のオブジェクトエージェントを新しいファイル トが「パブリック」データメンバを使用可能にしない(つま の情報を用いて初期化するか、宣言されているオブジェクト り、 o w n d a t a ( ) は無条件に f a l s e 値を返す)場合は、 エージェントの新しいインスタンスを作成するかのいずれか returndata()とassigndata()の両メソッドはオプシ を行わなければなりません。どちらの作業もインスタンスを ョンとなり、インターフェイス上に存在する必要がなくなり 上書きするため、そのインスタンスに対して維持してきた前 ます。その理由としては、owndata()がtrueを返さない限 のデータを破壊することになります。(DLLのコピーは1部し り、これらの2つのメソッドがL S c r i p tエンジンから呼び出さ かメモリにロードされず、作成するインスタンスごとにコピ れることはないからです。 ーを用意するのではないことを覚えておいてください。) これらのメソッドの使用方法については、このセクションで もう一つ別の解決策としては、個別のオブジェクトエージェ BobObjというオブジェクトエージェントを作成するときにそ ント共有ライブラリにインスタンスデータを個別に維持する の例を紹介します。 独自のメカニズムを提供させることです。しかし、それには、 オブジェクトエージェント共有ライブラリのプログラマーは、 すでに確立されている標準関数を使用しないで、独自の保存 メカニズムを工夫しなければなりませんし、おそらく数が多 –73– くなるインスタンスそれぞれを区別できるように、共有ライ void version(int *maj,int *min) ブラリ関数に情報を追加しなければなりません。 { LScriptでは、オブジェクトエージェントが適切に機能するた =*maj = 1; めに必要なインスタンスデータを、オブジェクトエージェン =*min = 1; ト自体が新しくコピーできるようにinstdata()関数を採用 // バージョンの1.1が必要です //これはインターフェイスバージョンです。プラ グインではありません) しています。 instdata()がある場合、 instdata() は必 } ずオブジェクトエージェントの(インスタンスデータ値を初 B o b O b jというオブジェクトエージェントでは、ダミーの 期化するには最適な位置である)コンストラクタの前に呼び albeitというインスタンスデータを維持するので、そのメ 出されるので、instdata()により作成するインスタンスデ ソッドから始めます。このメソッドはオプションだというこ ータは、作成時に入力する必要はありません。オブジェクト とを忘れないでください。 エージェントにはinstdata()メソッドが含まれていないの BobObjでは、 "tom"、"dick"と"harry"という名前の3 で、LScriptはオブジェクトエージェントにインスタンスデー 種類のインスタンス値を維持します。これらのインスタンス タ が な い と 仮 定 し 、 L S D L L 構造体の特定の値(つまり、 値はすべて「パブリック」であると考えられ、ホストのLScript instance[0])はNULLに設定されます。 からアクセスします。そのため内部的に名前を付ける必要は オブジェクトエージェントがインスタンスデータを維持する ありませんが、スクリプトがそれらを参照する方法を理解す 必要がある場合は、instdata()関数があり、必要な保存場 ることが必要と考えます。instdata()メソッドではインス 所を割り当てるように設計されていなければなりません。イ タンスデータを初期化しませんので、非常に簡単になります。 ンスタンスデータの各エレメントは LS_VARデータラッパーに 保存され、LS_VARポインタとしてLScriptに返されます。複数 LS_VAR * instdata(LSFunc *func) のエレメントがある場合は、LS_VARデータラッパーの一次配 { 列を割り当てて、処理をコンパイル後に再処理エレメントへ LS_VAR のポインタを LScriptに返す必要があります。 instdata() から返される、このポインタはLSDLL構造体インスタンスの // 3種類のデータメンバがあり、すべて「パブリッ ク」です mydata = (LS_VAR *)(*func->malloc)(3 * 配列(instance[0])の最初のエレメントに置かれ、それ sizeof(LS_VAR)); がオブジェクトエージェントメソッドに渡されます。 return(mydata); これから作成するサンプルのオブジェクトエージェントでは、 *mydata; } インスタンスデータを維持する必要性はありませんが、例と 以下にこのメソッドに関して注意すべき重要な点を示します。 して紹介するためにインスタンスデータを維持します。 1.インスタンスデータをハウジングする際には"静的"変数を使 BobObjシェル 用しないでください。静的変数はインスタンス間で共有する、 まず、オブジェクトエージェントを version()メソッドを 単精度の値です。意図的にするとしても、各インスタンスご 提供してオブジェクトエージェントインターフェイスのバー とにオペレーション対象となる固有のデータ値セットを持た ジョン1.1にロックします。 せたいとは思わないでしょう。そのため、インスタンスデー タは実行時ヒープから割り当てなければなりません。 –74– 2 .インスタンスデータは任意の方法で構成できますが、イン void constructor(int count,LS_VAR スタンスデータのエントリ数についてのカウントはLScriptで *parameters,LSDLL *lsdll) は維持しません。インスタンス配列の内容はすべてオブジェ { クトエージェントが認識しており、配列内のデータへのアク LS_VAR *inst; セスは境界を超えてはいけません。 if(count != 0) 3.LightWave3Dにメモリリークを発生させないように、必ず LScriptが提供する資源管理関数を使用してください。LScript // エラー!パラメータは受 // け付けません。 { は内部メモリのすべての割り当て/解放をトレースし、LScript 標準ライブラリの malloc()を使用すると、LScriptはそれを //(C++では、この署名と一致するクラスメソッ // ドはありません。) (*lsdll->func->error)(...); 理解せず、メモリを明示的に free()し忘れるとリークが発 return; 終了にメモリ割り当てが残っている場合はそれを解放します。 生します。 } instdata()がある場合は、それはスクリプト内で新しいイ if((inst = lsdll->instance[0]) != ンスタンスが作成されるときにLScriptエンジンが最初に呼び NULL) { 出すメソッドです。 // 確認のため... 次に完成させるメソッドはオブジェクトエージェントのコン inst[0].data.number = 145.567; ストラクタです。コンストラクタは必須メソッドで、スクリ inst[1].data.string = "Dick"; プトがオブジェクトエージェントの新しいインスタンスを作 // 定数データメンバ inst[2].data.vector[0] = 10.0; 成する際には必ず呼び出されます。コンストラクタは必ず instdata()呼び出しの直後に呼び出されます。 instdata()がない場合は、コンストラクタが最初に呼び出されるメ inst[2].data.vector[1] = 20.0; inst[2].data.vector[2] = 30.0; ソッドとなります。 } BobObjコンストラクタで、 instdata()で作成されたイン } スタンスデータメンバを初期化します。コンストラクタには スクリプトからパラメータを渡すことができ、これらのパラ 先に説明したように、オブジェクトエージェントのコンスト メータから取り出した値を用いてインスタンスデータを初期 ラクタはLScriptでインスタンスが作成されるときに呼び出さ 化しようとするのが一般的です。BobObjというオブジェクト れます。インスタンスはオブジェクトエージェントというク エージェントではコンストラクタパラメータを使用しません。 ラス名を関数の呼び出しとして使用する場合に、スクリプト プログラマーが作成します。たとえば、BobObjというオブジ ェクトエージェントのインスタンスを作成するときは、クラ スコンストラクタを呼び出します。 –75– 外」となるインスタンスを「クリーンアップ」する際に使用し use "bobobj.dll" as class BobObj; ます。このクリーンアップというのは、クリーンアップを必 ・・・ 要とするインスタンスデータメンバをシャットダウンし、イ main ンスタンスの資源(メモリ、ファイルなど)を解放すること { です。今回は、instdata()メソッドにより割り当てられた ・・・ bob1 = BobObj(); すべての資源もデストラクタの中で解放することにします。 //BobObjインスタンスを作成 今作成中のBobObjというオブジェクトエージェントは、複雑 ・・・ でないインスタンスデータを管理するので、そのデストラク オブジェクトエージェントコンストラクタに引数を渡さなけ タもきわめて簡単なものです。 ればならない場合は、引数を括弧に入れます。 void destructor(int count,LS_VAR *parameters bob1 = BobObj(1,"Hello"); ,LSDLL * lsdll) // パラメータを使用してインスタンスを作成 { オブジェクトエージェントのコンストラクタメソッドに関し if(lsdll->instance[0]) て注意すべき重要事項を以下に示します。 // free instdata()-割り当てリソース (*lsdll->func->free)(lsdll- 1.コンストラクタの中で、目的のクラスのインスタンス用に >instance[0]); ユーザのインスタンスデータにある該当データ値を設定しま す。これらの値は、通常このメソッドに渡されるパラメータ } から何らかの方法で取り出されます。たとえば、ファイル処 もちろん、各インスタンスデータエレメント内に追加リソー 理クラスのタイプであれば、オブジェクトエージェントが管 スを割り当てている場合は、各エレメントをデストラクタに 理しようとしている固有のファイル名を示すパラメータを期 トラバースし、該当するLScript関数を呼び出して、インスタ 待します。 ンスデータ配列自体を解放する前に、先にそれを解放 2.オブジェクトエージェントメソッドに提供する引数のカウ (free()、fclose()など)します。 ントとタイプに柔軟性を持たせるだけで、オブジェクトエー 次は2つの必須オブジェクトエージェントメソッドの、 own- ジェントメソッドを過負荷にするメソッドをシミュレーショ m e t h o d ( )と o w n d a t a ( ) です。これら2つのメソッドは、 ンすることができます。こうすると、オブジェクトエージェ 論理値の trueまたは false を返して、オブジェクトエージ ントがサポートする過負荷状態のオブジェクトエージェント ェントが特定のメソッドあるいはデータメンバを扱う機能が と一致するパターンを探すことができます。 あるかどうかを示すという点で単純です。BobObjというオブ 3.LSDLL構造体の "instanceName" 属性値は、オブジェク ジェクトエージェントは "stradd()"という1つのパブリッ トエージェントのコンストラクタが呼び出されるまで設定さ クメソッドと、"tom"、"dick"、"harry"という3種類の れません。この理由は、作成されたインスタンスはコンスト データメンバを扱います。 ラクタが呼び出された時点ではまだ変数に割り当てられてい ないためです。これは使用しないでください。 クラスの定義はすべてきちんと書き、デストラクタメソッド に組み込んでください。デストラクタメソッドは「対象範囲 –76– int ownmethod(const char *method) て、LScriptのオペレーション内で新しくオブジェクトエージ // 特定メソッドがありますか。 { ジェクトメソッドを検索できない場合に何らかのエラーを生 ェントを作成できるようになります。メソッドあるいはオブ 成しないのは、これらのメソッドからマイナスの値が返され if((method[0] == 's') && ると、LScriptエンジンはペアレント(あるいはスーパークラ (strcmp(method,"stradd") == 0)) ス)に問い合わせをするからです。現在のバージョンでは、 return(TRUE); LScriptエンジンはオブジェクトエージェント自体でのエラー return(FALSE); //このメソッドはありません 状態を生成するだけです。 } おそらく、サイズ的に潜在性が最も大きいのは最後の必須メ ソッドの returndata() とassigndata() です。これら int owndata(const char *data) のメソッドは、オペレーティング・システムのパブリックデー // 特定データメンバがありますか。 { タメンバへのアクセス作業を行います。 Returndata()は要求されたオブジェクトエージェントデ if((data[0] == 't') && ータメンバに入っている値を返します。このメソッドは、ア (strcmp(data,"tom") == 0)) クセス対象のデータメンバが目的のオブジェクトエージェン return(TRUE); トに属していることを確認するための owndata()メソッド else if((data[0] == 'd') && が最初に使用されていなければ、LScriptエンジンから呼び出 (strcmp(data,"dick") == 0)) されることはありません。しかしながら、 returndata() return(TRUE); は、提供されるデータメンバ識別子がそのオブジェクトエー else if((data[0] == 'h') && ジェントに適していないような状況を処理するために必ず用 (strcmp(data,"harry") == 0)) 意してください。戻り値がNULLの場合は、このエラー状態を return(TRUE); 示します。 return(FALSE); 次にreturndata()のBobObjバージョンを示します。 // このデータメンバはありません} } これらの2つのメソッドにはエラー処理が含まれていないこと に注意してください。メソッドあるいはデータメンバが検出 されない場合は、どちらのメソッドもエラーメッセージを全 く生成しません。これは設計上故意にそうしています。 LScriptエンジンにこの状況の取り扱いを任せます。 このインターフェイスのこれからのバージョンでは、LScript エンジンでオブジェクトエージェントの継承をサポートでき るようになり、この場合オブジェクトエージェントは別のオ ブジェクトエージェントのメソッドやデータメンバを継承し –77– LS_VAR * returndata(LS_VAR *datamember,LSDLL lsvar.data.vector[0] = *lsdll) inst[2].data.vector[0]; { lsvar.data.vector[1] = static LS_VAR lsvar; inst[2].data.vector[1]; //各呼び出しに異なる値を割り当てる static LS_VAR *inst; lsvar.data.vector[2] = static char *identifier; static int index; inst[2].data.vector[2]; } else if(!lsdll->instance[0]) { // インスタンスデータがありません それは問題です return(NULL); // owndata()はあると言っていますが実際はありませ // ん。(このようなことは発生してはならないのですが) sprintf(errormsg,"bad datamember inst = lsdll->instance[0]; name %s::%s.%s",lsdll-> // 読みやすくするため一部省略形を使用 identifier = (char *)datamember- ClassName , lsdll->InstanceName, >extra; identifier); index = (int)datamember->data.number; (*lsdll->func->error)(errormsg); if((identifier[0] == 't') && // スクリプトを停止 return(NULL); (strcmp(identifier,"tom") == 0)) } { return(&lsvar); lsvar.type = LSNUMBER; lsvar.data.number = } inst[0].data.number; assigndata()はreturndata()と良く似た機能を実行 } しますが、これは値を返す代わりに、データメンバの値を更 else if((identifier[0] == 'd') && 新します。データメンバの整合性を確認するため、更新に使 (strcmp(identifier,"dick") == 0)) 用する値に対してさまざまなサニティチェックを実行します。 { lsvar.type = LSSTRING; lsvar.data.string = inst[1].data.string; } else if((identifier[0] == 'h') && (strcmp(identifier,"harry") == 0)) { lsvar.type = LSVECTOR; –78– void assigndata(LS_VAR *datamember,LS_VAR else if((identifier[0] == 'd') *value,LSDLL *lsdll) && (strcmp(identifier,"dick") == { 0)) static LS_VAR *inst; { static int i1,i2; // これを「定数」データメンバとみなすため、代 // 入型はすべて不正となります。 sprintf(errormsg, static char static int *identifier; index; "illegal assignment to if((inst = lsdll->instance[0]) == NULL) constant data member // 省略形 return; %s::%s.%s", identifier = (char *)datamember- lsdll->ClassName, lsdll- >extra; >InstanceName, index = (int)datamember->data.number; identifier); if((identifier[0] == 't') && (*lsdll->func- (strcmp(identifier,"tom") == 0)) >error)(errormsg); } { if(value->type != LSINTEGER && else if((identifier[0] == 'h') value->type != LSNUMBER) && (strcmp(identifier,"harry") == 0)) { { sprintf(errormsg, if(value->type != "invalid data type in LSVECTOR && data member assignment %s::%s.%s",lsdll- value->type != LSINTEGER >ClassName, lsdll- && value->type != >InstanceName, LSNUMBER) identifier); { (*lsdll->func- sprintf(errormsg, >error)(errormsg); "invalid data type return; in data member assignment } %s::%s.%s", inst[0].data.number = value- lsdll->ClassName, >data.number; lsdll- } >InstanceName, –79– 最後に、BobObjというオブジェクトエージェントのインプリ identifier); メントを完了させるには、パブリックメソッド stradd()を (*lsdll->func- 作成する必要があります。パブリックメソッドの stradd() >error)(errormsg); は、オブジェクトエージェントの「パブリック」メソッド用 return; に"lscript.h"ヘッダーファイルに用意されている関数プロトタ } イプに付加することに注意してください。 // ベクトル以外にも整数値を使用できます if(value->type == LSVECTOR) LS_VAR * stradd(int *count,LS_VAR *vars,LSDLL { *lsdll) inst[2].data.vector[0] = value- { >data.vector[0]; static LS_VAR var; inst[2].data.vector[1] = value- static char buf[512]; >data.vector[1]; static char num[100]; inst[2].data.vector[2] = value- static LS_VAR *inst; >data.vector[2]; } if(*count != 2) // 「署名」をチェックします return(NULL); else *count = 0; inst[2].data.vector[0] = inst[2].data.vector[1] = // 返す値の数をエンジンに知らせる準備をします if(vars[0].type == LSSTRING && inst[2].data.vector[2] = value- vars[1].type == LSSTRING) >data.number; { } inst = lsdll->instance[0]; else sprintf(num," (( <%g,%g,%g> ))", { //この値が、インスタンスのビジュアルな認証と //して各文字列に付加されます。 inst[2].data.vector[0], sprintf(errormsg,"bad data member name %s::%s.%s", inst[2].data.vector[1], lsdll->ClassName, lsdll- inst[2].data.vector[2]); >InstanceName, identifier); var.type = LSSTRING; (*lsdll->func->error)(errormsg); if(strlen(vars[0].data.string) } >= 512) } strncpy(buf,vars[0].data. string,500); else –80– ンスデータ(instdata())で必要となる追加の値を割り当 strcpy(buf,vars[0].data.string); てることですが、スタティックストレージを使用して値をエ if((strlen(buf) + ンジンに返すメソッドをお勧めします。メモリを割り当てる strlen(vars[1].data.string)) < 500) のは、大切な資源とCPUの時間を消費します。 strcat(buf,vars[1].data.string); スタティックストレージがメソッド内では実現可能なオプシ strcat(buf,num); ョンでなく、毎回同じアイテム数を返す場合には、メソッド の中にスタティックポインタを割り当て、次に提供されてい var.data.string = buf; るLScriptのメモリ割り当て関数の malloc()を使用して、メ *count = 1; ソッドをはじめて呼び出すときに必要なエレメントを割り当 // 返されるエレメントが1つあることをエンジンに知らせます return(&var); てるという、多少エレガントな解決策があります。このよう にすると、メモリは実際に必要になるまで割り当てられるこ } とはなく(スクリプト全体としてメモリが呼び出されない場 else 合もあり) 、LScriptがスクリプトを終了するときに、このよう return(NULL); な解放されていない資源を捕捉するので、オブジェクトエー } ジェントはメモリを解放する機能について関わらなくて済み パブリックオブジェクトエージェントメソッドはモニタする ます。 必要のあるオペレーション上のポイントがいくつかあります。 stradd(...) 1." v a r s " リスト内にあるスクリプトパラメータの数を示す { 際に使用する、 stradd()の最初のパラメータは、値ではな static LS_VAR *myvars = NULL; くポインタであることに注意してください。その理由は、こ ・・・ の場所はメソッドから返されるエレメントの数をLScriptエン if(myvars == NULL) ジンに示すために使用されるからです。 stradd()の場合は、 myvars = (LS_VAR *)(*lsdll->func- 1エレメントだけが返されるので、エレメントを返す前にこの >malloc) 値は1に設定されます(また、エラー時には0に初期化されま (sizeof(LS_VAR) * 5); す) 。 2.LScriptは値を返すために使用する「容器」が、コードの中 に手配されていることを認識しません。スタティックな値を オブジェクトエージェントの共有ライブラリの作成 使用することにしている場合もあるでしょうし、ヒープから オブジェクトエージェントの共有ライブラリは通常のLScript 割り当てている場合もあります。このため、LScriptエンジン リンク可能なD L Lと同様にコンパイルできます。事実、前の は値の処理を終了した時に、容器を捨てるという仮定はでき 節で説明したmakefileのコピーを作成し、その中に埋め込ま ません。(つまり、ヒープから解放するか、単に無視するかで れたファイル名を変更した後直接それを使用することができ す。 )そのため、このメソッド(またはオブジェクトエージェ ます。 ント)がこれらのアイテムの割り当てに全責任を持ちます。 新しいオブジェクトエージェント D L Lをコンパイルしたら、 提案したこれらの資源の作成方法は、 LS_VARのスタティッ 参照を解決しようとするときに、LScriptエンジンが調べる場 ク配列を使用するか、オブジェクトエージェントのインスタ –81– 所の1つにそれを置かなければなりません。これらの場所につ いては前の節で概要を説明してあります。 //bob1とbob2のデストラクタがmain()終了後に呼び出されます } BobObjの実験 // bob0デストラクタはスクリプトが終了次第呼び出されます。 test BobObjというオブジェクトエージェントに関する最後の作業 { はLScript内で実際にテストしてみることです。次に、オブジ bob3 = BobObj(); ェクトエージェントメカニズムの機能と、BobObjからだれで // test()にローカルなインスタンスです info(bob3.harry); も使用できるメソッドとデータメンバを実験できるように書 かれたLScriptを紹介します。 // bob3デストラクタはtest()が終了次第呼び出されます use "bobobj.dll" as class BobObj; bob0 = BobObj(); main } // グローバルなインスタンス LScriptからの出力で、BobObjというオブジェクトエージェン { トの多くのインスタンスがすべてアライブであり、適切に機 bob1 = BobObj(); 能していることを示します。 // main()に対するローカルな2つのインスタンス bob2 = BobObj(); info(bob1); INFO: (ObjectAgent)BobObj::bob1 // オブジェクトエ INFO: (ObjectAgent)BobObj::bob2 ージェントインスタンスはパラメータとして info(bob2); INFO: HelloThere (( <10,20,30> )) // 渡すことができ info(bob1.stradd("Hello","There")); INFO: I’mBob (( <10,20,30> )) INFO: 145.567 info(bob2.stradd("I"m","Bob")); INFO: Dick info(bob1.tom); INFO: <10,20,30> ます。 info(bob1.dick); INFO: calling test! info(bob2.harry); INFO: <10,20,30> info("calling test!"); INFO: 160.567 test(); INFO: <1,2,3> bob1.tom += 15; INFO: <10,20,30> info(bob1.tom); INFO: Dick bob2.harry /= 10; INFO: 145.567 info(bob2.harry); INFO: 146.567 test(); info(bob0.dick); info(bob0.tom++); info(bob0.tom); // インクリメント後 –82– プラグイン間通信 ("$")で区切って指定するだけで済みます。このメカニズム は、キューのオーナーが採用することもできますが、同じ識 LScriptには、アクティブのスクリプトからその他のLScriptイ 別子を使用する複数のスロットを含む複数のキューがある場 ンスタンスへの「メッセージ」の送信を可能にするメカニズ 合にのみ必要となります。キュー名をスロット識別子の前に ムがあります。 このメッセージングメカニズムは「プラグイ 置いて明瞭にしなければなりません。識別子を入力しないと、 ン相互間通信(Inter Plugin Communication)」 、略してIPCと LScriptはその識別子のある、最初のスロットを使用します。 も呼ばれています。 "MyQueue"キューのいずれかのスロットにあるデータ値にア LScript内でIPCを採用する場合は、LScriptエンジンは使用し クセスする必要のある別のスクリプトの中からは、次のよう ているLScript用にメッセージ「スロット」の内部リストを作 にして簡単に、しかも迅速にそのデータ値にアクセスするこ 成します。すると、そのLScriptはこのリストの指名オーナー となります。メッセージングエリアの作成者は「オーナー」 とができます。 になりますが、一度作成してしまうと、他のLScriptをこのリ ・・・ ストにアタッチすることができます。アクセスを調整すれば、 v1 = MyQueue$ObjectFile; これらの「スロット」にスクリプト関連データを入力でき、 ・・・ それを他のスクリプトで読み出すことができます。 IPCメカニズムは自動的に同時に複数のリクエスタからのスロ LScriptのIPCメカニズムを使用するには、「キュー」と呼ばれ ット値へのアクセスが発生しないようにします。2つスクリプ る保持エリアを指定します。この保持エリアには任意の数の トが同じ( CPU)タイムにスロットにアクセスしようとする 確認済みスロットが存在します。作成したいキューごとに、 と、最初のリクエスタがそのスロットを読取り/更新し、スロ exposeコマンドを使用して宣言します。 ットをロックするまで片方のリクエスタは待機しなければな expose <slot identifier(s)> as <queue りません。 identifier>; キュー/スロットの組み合わせが存在しない場合、あるいは データを入力して初期化していない場合は、すべての読取り expose対象のスロット識別子はキューのデータ保存エリア を示す間接的なポインタになります。キューが作成されると、 アクセスから返される値は必ずnilになります。 そのキューのオーナーは、スクリプトの範囲内にある宣言済 配列キューのメンバー みのグローバル変数と同様に、これらのスロット値にアクセ IPCキューメンバーも配列として宣言され、ループのIPCキュ スし、変更することができます。 ーデータをシーケンシャルにアクセスし、更新ができます。 キュー配列は他の LScript配列と同様に宣言され、参照されま expose MakeObject, ObjectFile as MyQueue; す。 ・・・ expose objects[100] as MyQueue; ObjectFile = nil; // キュースロット if(MakeObject != nil) ・・・ { 通常のキュー変数の場合と同様に、ローカル変数を扱うよう ・・・ にスクリプト内の配列エレメントにアクセスします。 IPキュースロットにアクセスする必要がある他のLScriptイン スタンスは、キュー名とそのキュー内のスロットをドル記号 –83– @warnings ・・・ for(x = 1;x <= 100;x++) // この"expose"コマンドは1スロットの"position"を用いて objects[x] = <0,0,0>; // 「マスター」と呼ばれるIPCキューを作成します。 expose position as Master; キュー配列構造に、プリプロセッサマクロを活用することも create できます。 { @insert "lights.inc" setdesc("Channel-lock Demo - Master ・・・ Object"); // 'TOTALLIGHTS' defined as 75 in"lights.inc" } process: ma, frame, time expose light[TOTALLIGHTS] as LightQueue; { ・・・ position = ma.get(POSITION,time); for(x = 1;x <= TOTALLIGHTS;x++) //冗長になっても良ければ、あるいは特定キュースロットを light[x] = <0,0,0>; //識別する必要があれば、代入で明示的にキューを識別す //ることができます。 Master$positon = ma.get(POSITION, 各キューエレメントは必然的にキュースロットエントリとな り、単一プロセスで作成できるスロットエントリ数には実際 time); 的な限度があることに注意してください。この限度はスクリ } プトを実行するオペレーティングシステムが決定します。キ ュー配列の使用はなるべく控えてください。 ここに、Masterキューを問い合わせて、マスタースクリプト この節では、LS/IA(アイテムアニメーション)スクリプト処 の位置を取得し、Xモーションチャネルをプライマリオブジェ 理プラグインと一緒に使用するように設計されている2つの クトのXモーションチャネルと一致させる「スレーブ」スクリプ L S c r i p tについて簡単に説明します。これらのスクリプトは、 トがあります。 2つのオブジェク間の「マスター/スレーブ」関係をセットアッ プします。この場合、「マスター」であるオブジェクトは LScript IPCメカニズムを用いて「スレーブ」オブジェクトに 3 次元での位置をブロードキャストします。処理の間、スレー ブオブジェクトのスクリプトは、マスターがポスティングす るメッセージを待ちます。メッセージがポスティングされる と、スレーブはマスターのX軸位置とスレーブのX軸位置を一 致させ、そのチャネルにスレーブオブジェクトを効果的にロ ックします。 「マスター」スクリプトはIPCキューを作成し、スレーブオブ ジェクトがアクセスし、処理できるように、ここにフレーム 単位で位置をポスティングします。 –84– 適格データタイプ @warnings スクリプト間でデータを通信する場合の、 IPCキューメカニズ create ムを使用した転送に適するデータタイプは次のとおりです。 { setdesc("Channel-lock Demo - X-Axis string (up to 255 characters) Slave"); number } vector process: ma, frame, time 'nil' { メカニズムが進化するにつれ、さらに複雑なデータタイプが pos = ma.get(POSITION,time); IPC転送に適するようになるでしょう。 newpos = Master$position; // マスターのキューへのアクセス if(newpos == nil) // 障害がある場合は、グレースフルに復元してください ma.set(POSITION,pos); else ma.set(POSITION, <newpos.x, pos.y, pos.z>); } これらの2つのスクリプトがレイアウト内のオブジェクトに付 加されている場合は、1つのオブジェクト(「マスター」)だけ がキーフレーム付きアニメーションを必要とします。 「スレー ブ」オブジェクトは、X軸に沿って自動的に移動し、フレーム 単位にスレーブの位置をマスターの位置と合わせます。この エフェクトを達成するためにレイアウトにすべてを読み込む 順序は次のとおりです。 1.「マスター」オブジェクトを読み込む 2.「マスター」LScriptをオブジェクトと関連付け、起動する 3.「スレーブ」オブジェクトの読み込む(「スレーブ」オブジ ェクトが「マスター」オブジェクトの後に現れるように読み 込む) 4.「スレーブ」 LScriptをそのオブジェクトと関連付け、起動 する –85– Macintoshに関するLScriptの注意事項 LScriptプリプロセッサ LScriptのPowerMacポートは、他のLightWave3Dプラットフ プリプロセッサとは? ォームで使用できるすべての機能を提供、あるいはエミュレ 名前が示すとおり、プリプロセッサは入力を別のプロセスに ートするように設計されています。3つの顕著な例外を除き、 渡す前に処理を行い、一部を潜在的に変更するものです。こ この目標は達成されました。他のLightWave3Dプラットフォ の点では、プリプロセッサは入力が通過するフィルタです。 ームで作成された、あるいはコンパイルされたスクリプトは LScriptにプリプロセッサを使用するよう指示する方法 P o w e r M a cのプラットフォームで変更することなく実行でき 指示は必要ありません。 ます。 実行を選択した LScriptは、プリプロセッサ特有の命令あるい LScriptのPowerMacポートに関して注意しなければならない は指示が含まれているかいないかにかかわらず、自動的にプ 例外は system()、systemex()、matchfile() の3つ リプロセッサを通過し、フィルタ処理されます。プリプロセ のコマンドです。これらのコマンドはPowerMacのLScriptに ッサは実行スクリプトのコンパイルプロセスの一部にすぎま 組み込むことができますが、その動作は変更されています。 せん。 この変更が発生する理由は、オペレーティングシステム固有 LScriptプリプロセッサ のコマンドインタープリタ(a.k.a., シェルプロセス)が存在 L S c r i p tプリプロセッサメカニズムは L S c r i p t作成者に対し、 しないことです。オペレーティングシステム固有のコマンド インタープリタが存在すれば、これらのコマンドが必要とす (技術的には、プリプロセッサパーランスで「マニフェスト定 数」として参照される) Compiler Directives 、 Insert Files、Preprocessor Macrosの3つの主要 る機能を提供できます。 s y s t e m ( ) および s y s t e m e x ( )コマンドは共にL S c r i p tの P o w e r M a cバージョンで n i lを返し、提供されるパラメータ 機能を提供します。 すべてを全く無視します。これはシェルプロセスをMacOSが LScript内のプリプロセッサディレクティブはすべて、アット 固有に認識できないからです。 マーク("@")から始まり、次にディレクティブ名が続きます。 次に例を示します。 matchfiles()コマンドは機能しますが、ファイルパター ンパラメータを無視します。これも、MacOS下ではこの機能 に合ったパターンを提供するコマンドインタープリタが存在 // オブジェクトを回転させる単純なスクリプト @warnings しないためです。P o w e r M a cでは、このコマンドは指定パタ ・・・ ーンを無視して、指定ディレクトリにあるすべてのファイル LScriptの旧バージョンでは、 #pragmaキーワードを採用し を返します。 てこの機能の一部を提供していましたが、これは現在も 制限値を超えると、L S c r i p tのP o w e r M a cバージョンはL i g h t- LScriptファイルに表示できます。しかし、それは旧式となっ Wave3Dプラットフォームの機能と全く同様に動作します。 たため、将来的にはLScriptエンジンから外すことになります ので、これを使用することはお勧めできません。 コンパイラディレクティブ コンパイラディレクティブは、コンパイラあるいはインター プリタに対して動作を変更する、あるいは影響するような命 令を指します。L S c r i p tでは、コンパイラディレクティブが –86– LScriptの中に現れる場合に限りコンパイラディレクティブを になると、クリーンアップ手段となります。これはコンパイ 適用します。 ル済みスクリプトや"lax"宣言ではサポートされません。 LScriptのプリプロセッサが認識できるコンパイラディレクテ version {major.minor | "major.minor"} ィブは次のとおりです。 LScriptエンジンではスクリプトに対して、そのスクリプトを warnings [count] 実行いる際に使用するLScriptプラグインの最小バージョンを 指定できます。プラグインの以前のバージョンではコンパイ warningsというディレクティブは、LScriptに実行時警告メ ッセージの表示をしないように命令します。オプションの ルエラーを発生する、新しい機能を利用したスクリプトには [count]パラメータは表示される最大警告数を示します。 有効です。 警告メッセージは、スクリプト実行中にLScriptエンジンがデ バージョンインジケータは、文字どおりの不動小数点値にも、 ータの損失、異常実行環境を検出した場合に生成されます。 あるいは文字列値にもできます。インタープリタはピリオド たとえば、返し引数のカウント以下の配列へのユーザ定義手 (".")で区切ったメジャー値とマイナー値だけを有効とみな 順の返し値を割り当てると、それはLScriptの実行中に必ず警 します。 告メッセージを生成することを保証することになります。 Autoerror 警告はコンパイル済みスクリプトでは自動的にオフに設定さ ト、あるいはモデラー特有のコマンドと関数の戻り値をスク れます。 リプトに提供します。これにより、スクリプトはコマンドが errors count errorsというディレクティブは、表示さ れる最大実行時エラー数をLScriptに提供します。 countパラ とができます。しかし、スクリプトプログラマーが、これら メータは整数値で、必須です。エラーメッセージはオフには の潜在的なエラー条件を管理するために必要なコードを追加 LScriptエンジンは通常、すべてのレイアウ 失敗したかどうかを判断でき、適当と思われる処置を行うこ できませんし、 countパラメータをゼロ (0)に設定すること したくない状況も考えられます。このような場合には、スク もできません。 リプトプログラマーは autoerrorディレクティブを指定で エラーメッセージはコンパイル済みスクリプトではイネーブ きます。このディレクティブはユーザに対してエラーメッセ ルになっています。 ージを発行して、エラー状態を自動的に処理し、スクリプト を終了するようにLScriptに命令します。 unusedスクリプトの開発途中、ご使用のスクリプトと未使 asyncspawn 用の変数とが混ざってしまう可能性があります。大きなスク LScriptには、スクリプトの実行中に外部プロセスを起動させ リプトでは、これらの「死んだ」変数を探し出し、パージす るには膨大な時間がかかります。 る機能があります(この機能の図についてはb a t c h . l sという unusedディレクティブは LScriptに一度も使用されていない、 LScript例を参照してください)。LScriptエンジンのデフォル 宣言されている変数(つまり、割り当てた値を)を検出して トの動作は、これらのプロセスを同時に実行すること(つま レポートさせます。スクリプトが実行を終了すると、LScript り、外部プロセスが完了するまでLScriptの実行を停止するこ は未使用と判定した変数毎にダイアログウィンドウを表示し と)です。しかし、スクリプトプログラマーが外部プロセス ます。 と対話したい場合もあります。この場合、スクリプトプログ ラマーは、LScriptに外部プロセスを非同期に実行するように このディレクティブは strictディレクトリが有効な場合のサポ 指示し、それらを LScriptと平行して操作しなければなりませ ート機能として備えられており、スクリプト開発が完成間近 –87– ん。asyncspawnディレクティブはこのような状況で使用し 様式か、またはvarステートメントで大きさを決定する必要が ます。 あるような動作様式に変更します。 nonrandom n o n r a n d o mディレクティブは、 l i n e ( ) ファイルオブジェクトエージェントメソッドを使用して、 現在の宣言モードに関わりなく、多次元配列は必ず明示的に LScriptがスクリプトプログラマーに提供可能なASCIIテキスト Insert Files ファイルラインへのランダムアクセスを使用不可にします。 ファイルは、LScriptエンジンがコンパイルするときにLScript これを指定すると、LScriptはラインオフセットを決定するた に「挿入」できます。オリジナルのスクリプトの一部と同様に、 めのテキストファイル( ASCIIモードで開いたファイル)のプ これらの挿入ファイルはエンジンを調べます。 (事実、プリプ 宣言しなければなりません。 リプロセスを実行しません。 pragmaを採用したスクリプト ロセッサは実際に最終スクリプトをエンジンに渡す前に、オ でline()メソッドにアクセスしようとすると、実行時エラ リジナルのスクリプトの一部とします。 ) ーとなります。 標準LScriptはプリプロセッサコマンドなどをハウスできます。 スクリプトがラインにランダムにアクセスする必要なく、大 Insert filesは、複数のLScriptに対して利用可能としたい共通 きなテキストファイルを処理するような場合は、このディレ コマンドとコードをハウジングする際に使用します。こうす クティブを活用すると、スクリプト全体の実行速度を目にみ ると、その挿入ファイルを共有するL S c r i p tすべてにおいて、 えて向上させられます。 スクリプトコードが重複することを防ぐことができますが、 literalpaths 類似性が大幅に少なくなり、それをコピーする際にデータの L S c r i p tは(現在のところ)3つの非常に異なるオペレーティ 機能や意味を変えてしまいます。挿入ファイルにハウジング ングシステム上で動作するため、 した共通コードも、1つの場所のすべてのスクリプトに関して matchfiles()、getfile()などの関数に提供するファ 更新を一度実行するだけですべての従属スクリプトを更新で イルパスを現在のオペレーティングシステムにより適したも きるという利点があります。 のにしようとします。たとえば、Macintosh OSでは、UNIXの 挿入するファイルの名前を指定する、文字列リテラルを後に フォワードスラッシュ ( / ) とM S - D O Sのバックスラッシュ (\)は、Macではディレクトリの区切りに標準的に使用され ているコロン(:)に変換されます。 続けた、 insert ディレクティブを使用して、元のスクリプ ト(と、別の挿入ファイルに、30レベルの深さまで)にファ イルを挿入できます。 literalpathsというディレクティブは、この内部処理を ・・・ 使用不可にし、LScriptエンジンにスクリプト内に現れるファ @insert "myinc.lsi" イルパスを使用させます。 strict ・・・ LScriptでは、前の"var"ステートメントで 明示的に宣言せずに(また配列の場合は、上限を明示的に宣 挿入ファイルに絶対パスがない場合、LScriptプリプロセッサ 言する必要なく)必要な場合はいつでも、変数と配列を使用 は次の手順でそのスクリプトを検索しようとします。 できます。しかし、すべての変数と配列を明示的に宣言する 1.現ディレクトリ(実行中のスクリプトと同じロケーション ことを必要にして、スクリプトの開発時にさらに構造体を追 の場合もあればそうでない場合もある)を調査 加したい場合も生じます。 strict というディレクティブは 2.LibPathの構成要素が指定したディレクトリを調査 LScriptエンジンを変数と配列を明示的に宣言するような動作 –88– 挿入ファイルを検索できない場合は、LScriptプリプロセッサ そのため、TOTAL_LIGHTSの定義の後に次のスクリプトコー はエラーメッセージを提示して停止し、LScriptエンジンは終 ドが処理された場合は、 了します。 ・・・ プロセッサディレクティブは各挿入ファイルを処理するごと for(x = 0;x < TOTAL_LIGHTS;x++) に継続して、評価され、蓄積されます。 ・・・ LScriptプリプロセッサはインクルードファイルに対して名前 LScriptエンジンは実際には次のように解釈します。 の付け方を一致させるように要求しません。名前が正確に insertディレクティブに提供されれば、任意の名前を付けられ ・・・ ます。 for(x = 0;x < 100;x++) ・・・ Preprocessor Macros Preprocessor Macros(あるいは、ハードコアソフトウェアデ マクロの置換は他の処理を実行する前にプリプロセッサ内で ベロッパの場合はマニフェスト定数)は、エイリアスに非常 発生します。 に類似した動作をします。スクリプトコード内でプリプロセ ッサがマクロ識別子と遭遇した場合は、マクロ識別子の値を High Visibility 識別子自体に代入します。これにより、(スクリプト内の数多 LScriptプリプロセッサのマクロにはHigh Visibility(高可視性) くの場所の値自体を変更するのではなく)ローカライズの際 と呼ばれる機能があります。つまり、識別子を検索している のコード変更が簡単になり、スクリプトコードを読みやすく 間は、プリプロセッサは識別子の文脈には関与しないという します。(つまり、"SELECT_SPHERE"のほうが"566"よりもず ことです。識別子が開始と終了の2つの引用符 ("")の間に現 っとわかりやすいということです。 ) れない限り、プリプロセッサは置換を実行します。これは、 マクロは、埋め込むことができます。つまり、マクロ識別子 従来のプリプロセッサで置換を実行する前は、識別子をスタ が別のマクロ識別子値の中に現れた場合は、メイン識別子を ンドアロンの文脈にしておかなければならないのとは対照的 スクリプトコードに代える前に、埋め込み識別子に対する置 です。一般に、識別子の周りに句読点と空白スペースがある 換が発生します。 と、従来のプリプロセッサがそれをスタンドアロンの文脈と プリプロセッサマクロはd e f i n eディレクティブを使用して定 理解するには十分です。 義され、マクロ識別子名とその識別子に代入される値が後に この例を見てみましょう。次のコード行が従来のプリプロセ 続きます。 ッサ(たとえば、Cプリプロセッサ)に渡されると、スタンド アロンと理解することが可能な、文脈内に埋め込み識別子が ・・・ ないので(つまり、それは別の識別子の一部なので、読めな @define TOTAL_LIGHTS 100 いため) 、コンパイル時エラーが発生します。 ・・・ #define ONEFIFTY 上の例では、識別子"TOTAL_LIGHTS"には100という値が代入 15 ・・・ されます。この識別子がスクリプトコード内(あるいは、定 x = ONEFIFTY0; 義後に挿入されたファイルで検出したコード内)のどこかで 発生した場合、 LScriptプリプロセッサは、コンパイル対象の LScriptエンジンに渡す前に、出力コード内の値を代入します。 –89– // <--- エラー! 識別子 // "ONEFIFTY0"はありません Ver.2.0での変更点 しかし、LScriptのプリプロセッサはこの状況に対して異なる 処理を行います。 @define ONEFIFTY このドキュメントはLScript v2.0の公式ベータ版に対するリリ ースノートです。 15 ここに記されている版毎の変更点は言語に対してのみの変更 ・・・ x = ONEFIFTY0; 点となります。 // <--- 値15をxに代入 スクリプトシステムにはLightWave v6.0 プラグインAPIに伴 非常にわかりやすいこのメソッドは、強力ですが、埋め込み う変更がまだ完全には統合されてはいません。 マクロ名を含むスクリプト変数あるいは関数識別子を偶然に 使用した場合は多くの問題が発生します。LScriptをコーディ ングするときはこのことを念頭においておいてください。 •関数filefind()が新規追加されました。 まとめ この関数はファイル名(パス情報を除く)を指定すると、ファイ 最後に、十分に機能し、LScriptプリプロセッサの能力を示す ル位置を特定するためアプリケーション内のディレクトリの ことができる、やや歪んだ例を示します。 パスをスキャンします。 関数からはファイルへのパスが返されます。 @define SELECT 15 @define SELECT2 string("SELECT ",SELECT0) if((where = filefind(“lw.cfg”)) != nil) @define SELECT3 "Bob!" { @define VERSION_DIRECTIVE version 1.0 ... @define BEGIN_BOBS_MAIN main { ファイルを検索するためにこの関数では関数 getdir()で指 @define END_BOBS_MAIN } 定するパスを使用します。 @define REM // @insert "includes.h" •関数filecrc()が新規追加されました。 @VERSION_DIRECTIVE この関数はファイルコンテンツのCRC-32値を計算し、整数値 @warnings を返します。 BEGIN_BOBS_MAIN •LScriptは連想配列として知られている配列タイプを新規追加 info(SELECT2); しました。 REM prints "SELECT 150" 連想配列とは整数インデックスの代わりに文字列値を使用し info(SELECT2 + SELECT3); てインデックスをつける配列のことです。連想配列はCやPas- REM using string math, prints "SELECT calでみられるようなユーザー定義の構造体をシミュレートす 150Bob!" るために使われる強力なメカニズムです。 連想配列においては、使用されるインデックス値(キャラクタ END_BOBS_MAIN 文字列)は属性を連想させるようなシンボルとなっており、ま たシンボルを用いてインデックスがつけられている配列の中 に属性が含まれることになります。 混乱してしまいそうですが、実際には非常に明瞭です。 –90– 新しいインライン条件を使用して単一文で条件評価できるよ fruit_color[“apple”] = “red”; fruit_color[“banana”] ... = “yellow”; fruit_shape[“apple”] = “round”; ... fruit_shape[“banana”] ... = “curved”; error(“Division by zero!”) when z == 0; ... うになりました。 x = 1 if y == 15 && cos(4.35); fruit_weight[“apple”] = 128; // グラム x = 1 unless y == 10 || z == 2; fruit_weight[“banana”] ... = 117.3; // グラム ... break if x == 5; ... この簡単な例をみてもわかるとおり、構造体のインスタンス return 5 if !upper_limit; の名称がインデックスシンボル(例:”apple”や”banana”) ... となっています。 各構造体のメンバはそれぞれ実際の各配列の名称となります •最終式の評価結果を保持する暗黙の'this'コンテナが新規追加 (例:”fruit_color”や”fruit_shape”)。 されました。 連想配列は新規追加された連想初期化演算子'$'を使用して作 このシステムはまだ完全には実現していませんが、中間値を 成/初期化が可能です。この新しい演算子は初期化ブロック演 使用して即値をハンドルする必要がなくなります。 算子('@')と同様の形式で使用されます。 ... normal_array = @1,2,3,4@; while(!file.eof()) assoc_array { = $ .. $; file.read(); ただし連想配列を初期化するためには、一組のエレメントを 使用しなければなりません。組となる各エレメントの後者に // 行はC++コメントに続いて // “PUB”で始まりますか? if(s~^PUB.*\/\/.*~) はデータを、前者には後者のデータに対する連想シンボルと なるキャラクタ文字列を指定します。 fruit_color // 行が’this’に入ります info(); = $ “banana”, “yellow”, } “apple”, “red” $; ... •新しい形式の条件式が利用可能となりました。 従来の条件式では前提条件位置においてif()テスト構造を用い ています。 if(<expression>) { ... } –91– // ユーザーに表示... •ブーリアンは”short circuited”(短絡回路)となり、以下のよ •LScriptに正規表現と検索置換用のイン言語がサポートされま うな式が使用できるようになりました。 した。 正規表現とは独自の特定メタ文字言語を持つ強力なパターン ... 一致関数です。 file = “C:\\CONFIG.SYS”; パターン一致システムは UNIX上で編成されたもので、ソフト f = File(file,”r”) || error(“Cannot open file '“,file,”’”); ... ウェアの世界で広く普及してきました。正規表現で利用可能 なリファレンスはとても巨大なものとなるため、ここでは詳 細については説明しません。 •LScriptのジェネリックシステムはレイアウトの新しい それよりも、どのようにLScript内で使用するのかを説明しま CommandSequenceシステムをサポートするようになりまし す。 た。 L S c r i p tで正規表現を使用してパターン一致を実行するには、 現在これを容易にするための1 6 0を超える新規コマンドが用 新規"s~~"演算子を使用します。この演算子は提供された正 意されています。 C Sコマンドは名称によってアクセスされ、 関数としてLScript内に存在しています。 規表現を用いて、キャラクタ文字列を比較しパターンが存在 するか確認するよう LScriptに命令します。 @version 2.0 // 文字列は大文字”B”で始まっているか、 generic // その後ろの文字列内のどこかに { // “o”が連続して2つ入っているかを調べます if(“Bob Hood” == s~^B.*oo~) { AddNull(); } ... CSコマンドがパラメータを要求する場合には、UDFを呼び出 また正規表現はキャラクタ文字列において検索置換を実行す してパラメータを提供します。 •LScriptのプリプロセッサは新規プラグマ指示語”script”をサ ポートすることになりました。 るのにも使用されます。このメカニズムには "r~~~" 演算子 を使用してアクセスします。 この演算子は指定したパターンに一致する文字列を検索し、 この指示語はLightWaveのLCoreシステムがプラグインとして 一致すれば指定した文字(列)で置換するようLScriptに命令し 追加されたスクリプトを識別可能にするための識別子です。 ます。 @script modeler 検索置換メカニズムにアクセスするには、新規の検索置換代 @script displace 入演算子"~="を使用します。 @script generic @script motion @script image @script replace @script master @script shader} –92– // s/r 演算子を使用した検索置換 // s/r演算子を使用した検索置換 if((input = File(“nfa.c”,”r”)) == nil) return; if((input = File(“nfa.c”,”r”)) == nil) return; if((output = File(“nfa.bak”,”w”)) == nil) return; if((output = File(“nfa.bak”,”w”)) == nil) return; while(!input.eof()) sr = r~^PRIVATE~static ~; { while(!input.eof()) line = input.read(); { //行の始端(^)において発見された文字列"PRIVATE"は line = input.read(); // 文字列"static"に置き換えます line ~= sr; output.writeln(line); line ~= r~^PRIVATE~static ~; } output.writeln(line); input.close(); } output.close(); input.close(); またLScriptは新規関数 regexp()を使用してキャラクタ文字 output.close(); 列から正規表現を構成することもできます。この関数により 正規表現パターンは変数への代入も可能なので、代わりに変 使用する正規表現パターンをユーザーが入力することが可能 数を使用することもできます。 となるのでとても便利です。 // 文字”PUB”で始まるファイル内の行を表示します。 // 使用する正規表現をコンパイルします expr = regexp(“^PUB”); // コンパイルに失敗すればregexp()からは’nil’が返ります if(expr == nil) return; if((file = File(“nfa.c”,”r”)) == nil) return; while(!file.eof()) { line = file.read(); if(line == expr) info(line); } –93– さらに正規表現は'this'コンテナも認識します。 a[1] -> nil ... a[2] -> nil while(!file.eof()) a[3] -> [1] -> nil [2] -> nil { [3] -> nil file.read(); [4] -> nil if(expr) [5] -> [1] -> nil info(); [2] -> 0 } 多次元配列はリニア配列をつなげて構成することもできます。 ... a[5] = “Bob”; b[3] = a; •LScript内にはもうエンティティとしての多次元配列は存在し ません。 b[3,5,2] = 'a’; 厳密にいえば配列は全てリニアとなります。しかし他の配列の // 文字列”Bob”が”Bab”となります エレメントとして配列を割り当てることは可能なので、スクリ 配列は他配列のメンバとなる事が可能なので、エレメントと プトにより実行時に多次元配列を構成することができます。 しての配列はユーザー定義関数へ渡すことも可能となります。 このようなユーザー定義の多次元配列はリニアな配列と同様 に動的でどのポイントにも自由にエレメントを追加するでき ます。 // 多次元配列を生成します a[3,5,2] = 0; 効率上、この形式で作成する多次元配列はしっかりとしたも のではありません。 例えば上記の配列は3個のエレメントを持つ配列を生成します。 この配列の3番目のエレメントは5個のエレメントを持つ配列 でありその配列の5番目のエレメントは2個のエレメントを持 つ配列でありその配列の2番目のエレメントに0を代入してい ます。 –94– この形式で参照されるイメージはスクリプトがランタイム実 ... 行用にコンパイルされている場合には無視されます。 // 関数へ渡すサブ配列 コンパイル済みのスクリプトが実行される時点で、参照され るイメージがレイアウトから利用可能な状態でなければなら a[5] = “Bob”; b[2] = 99.9; ないからです。 b[3] = a; •関数ctlimage()はイメージを縮小して表示する場合に使用する c[8] = b; パラメータ(オプション)を新しく3つ追加しました。 5番目のパラメーター(オプションである透明度ベクトルの後) info(c); は縮小ファクターまたはイメージの幅のサイズを指定します。 info(c[8]); 6番目のパラメーターは縮小ファクターもしくはイメージの高 info(c[8,3]); さのサイズを指定します。最後の7番目のパラメーターはブー info(c[8,3,5]); リアンフラグでイメージのアスペクト比を保存するかどうか をLScriptに指示します。 test(c); デフォルトではアスペクト比は保存されません。 test(c[8]); 縮小用に提供される幅と高さをあらわす数値はタイプにより test(c[8,3]); LScriptで解釈されます。どちらか一方のコンポーネントに対 し整数で値を提供すると、値は結果イメージの絶対幅(ピクセ test(c[8,3,5]); ル単位)であると解釈します。 } 一方で浮動小数点数値を渡せばLScriptはパーセンテージファ test: a クター(1.0は 100%)であると解釈し、オリジナルのイメージ { 幅もしくはイメージ高さに対しこの値を適用し最終ピクセル info(a); の幅(高さ)を決定します。 } このメカニズムはイメージを拡大するために設計されてはい ないので、イメージの元の大きさを超えてしまうような結果 •(Image Editorを通して)レイアウトに読み込まれたイメージを を引き起こす値を指定しても元イメージの大きさとなります。 関数ctlimage()を使用して表示できるようになりました。 イメージ名称の前にドル記号文字($)をつけることでディスク 上のイメージファイルを探しにいく代わりに、読み込まれて いる任意のイメージファイルを使用するようになります。 ドル記号文字で始まる名称はレイアウトでイメージに対し表 示される名称文字列と正確に一致している必要があります。 ... ctlimage(“$ph_019.tga”,0,0); ... –95– ... @warnings // (0,0)の位置にオリジナルの40%の幅 // 30%の高さでイメージを表示します ctlimage(“$ph_019.tga”,0,0,,.4,.3); ... output; count; main { // (0,0)の位置に幅100ピクセル、高さ100ピクセルで表示し // アスペクト比を保存します // (表示時には正確には100×100ではなくなるということです) ctlimage(“$ph_019.tga”,0,0,,100,100); ... count = 0; chdir(“\\”); // ルートディレクトリから開始します do_dir(); info(count,” directories processed!”); // (0,0)の位置にオリジナルの形式(修正なし)で表示します ctlimage(“$ph_019.tga”,0,0); } // “depth-first(縦型)” 再帰ディレクトリ走査 do_dir •ユーザー定義関数が再帰的に呼び出せるようになりました。 この機能はユーザー自身がスクリプト内で定義している関数 { に関してのみ拡張が可能です。定義済み関数 ( L S c r i p tでは if((directories = matchdirs(“.”,” *.*”)) == nil) return; main()やoptions()関数など)は再帰的に呼び出すことは できません。 再帰は強力な機能ではありますが、同時に注意が必要で危険 len = directories.size(); なものです。何をしているのか理解していないと、無限ルー for(x = 1;x <= len;x++) プにはまってしまいます (アプリケーションが落ちる原因とも { なります)。LScriptは再帰に関してレベルの制限はありません が、実質的な深さに制限(メモリなど)の限界があります。 chdir(directories[x]); 再帰を使用する前に、何をするのかをよく確かめてください。 ++count; do_dir(); 以下に示す例は、再帰を用いてディレクトリ構造全体を走査 // <-- 再帰 chdir(“..”); しドライブ上に存在するディレクトリ数をカウントするモデ } ラーのLScriptです。 } •LScript言語に反復構造foreach()が新規追加されました。 これは一連のリニアな値を通しての反復処理を簡易化するよ う構成されています。各値を保持するために使用される変数 や反復が可能なデータタイプへと変換するための式を引数と して取得します。反復 foreach()は反復用に以下のデータ タイプを受け付けます: –96– 整数、数値、ファイルオブジェクトエージェント、配列(モデ •LScriptがインターフェイスを提供するレイアウトオブジェク ラーLScriptの自動配列 point[]とpolygons[]も含む)、そしてレ トのリストにイメージオブジェクトエージェントが追加されま イアウトLScriptのレイアウトオブジェクトエージェントです。 した。 getfirstitem()はIMAGEもしくは "IMAGE"を受け付け ... るようになり、レイアウトのイメージリストにおける最初の editbegin(); イメージファイルを返します。 foreach(x,polygons) 読み込まれていない場合には'nil'を返します。 info(x); 各イメージオブジェクトエージェントには以下の属性があり editend(); ます: ... -------------------... foreach(x,10 - 5) name インターフェイス上に表示される名称 isColor width height カラーイメージがモノクロかを示すブーリアン イメージの幅(ピクセル単位) イメージの高さ(ピクセル単位) info(x); ... さらに各イメージオブジェクトエージェントは以下のメソッ -------------------- ドを認識します: ... <string> filename(<frame>) f = File(“c:\\config.sys”,”r”); foreach(x,f) <grey> luma(<col>,<row>) <r>,<g>,<b> rgb(<col>,<row>) info(x); <ImageObject> next(<void) ... -------------------- 以下のメソッドは L S c r i p t / P Tスクリプトにのみ利用可能で ... す: obj = getfirstitem(MESH); <void> foreach(x,obj) <number> info(x.name); lumaSpot(<col>,<row>,<size>,<blend>); ... <num>,<num>,<num> -------------------- rgbSpot(<col>,<row>,<size>,<blend>); ... a = @1,2,3@; foreach(x,a) info(x); ... –97– needAA(void); generic ... { // テキストファイルの開始行を一行に取得します line = File(“f:/dirs.txt”,”r”).read(); info(line); image = getfirstitem(“IMAGE”) || error(“No images loaded!”); foreach(i,image) ... info(i.name,”: ... “,.i.width,”,”,i.height); } // ベクトルにアクセスします v[2] = <1,2,3>; • レ イ ア ウ ト L S c r i p t に2つの関数 l o a d i m a g e ( ) と info(v[2].x); clearimage()が新規追加されました。これらの関数はそ ... れぞれレイアウトのイメージリストに新規イメージファイル を読み込み、イメージをクリア(アンロード)します。 連鎖式は代入文の左側に使用することはできません。 generic 式は代入文の右側においてのみ存在できるからです。 { 例えば、以下の文は不当でありエラーが発生します: image = loadimage ... (“f:/lw/cdrom/FilmImage.tga”) || error(“Can’t load image!”); v[2] = <1,2,3>; info(image.width,”,”,image.height); clearimage(image); ... v[2].x = 0; } •LScriptにおける式の連鎖が可能となりました。 ... // 配列のエレメントからファイルオブジェクトエージェントに // アクセスします v[3] = nil; v[2] = File(“f:/dirs.txt”,”r”); info(v[2].read().isStr()); ... –98– リビジョン履歴 •モデラーのランタイムプラグインはプラグインとしてのスク ベータ 7: た。 リプトのアダプタメカニズムに対しうまく動作しませんでし •5 0を超える C o m m a n d S e q u e n c eのエントリーがレイアウト ベータ 5:LScript v2.0 ベータ 5 LScriptコンパイラの目録から抜け落ちていたため、これらの •レイアウトのCSがビルド411を反映して更新されました。 コマンドを”external”であると判断されていました。 •CSコマンドShadowType()が誤って整数値ではなく文字列引 •浮動小数点数値の同等値テストを制御するための新規プラグ 数を想定していました。 マ指示語が追加されました。このプラグマ 'fpdepth'は小 •初期化されていない変数参照が修正されました。 数点以下の桁数を指定し、浮動小数点数値(数値、ベクトルな ど)の同等比較時の有効桁数とします。 ベータ 6: プラグマ設定はスクリプトのランタイム演算全体を超える定 •スクリプトコンパイラはディレクトリ分離記号のトレーリン 義域を保持しています。 @fpdepth 3 グを正しく処理していませんでした。 •言語に対しオブジェクトのマスク処理が新規追加されました。 • 関数 S e l e c t B y N a m e ( ) 、 S h a d o w T y p e ( ) そして L i g h t FalloffType()は定義されている引数の個数が不当で、どの引数 このメカニズムを使用するとマスク処理をサポートしている を提供してもエラーが発生しました。 整数データタイプのオブジェクトがオブジェクト自身に対し” •LS/GNとLS/MCに8つの新規CS関数を追加しました。 マスク”処理を実行できるようになります。 SaveLWSC1 このマスク処理関数の正確な戻り値はデータタイプによって Layout_SetWindowPos 異なります。 Layout_SetWindowSize •浮動小数点数値(数値、ベクトル)はマスク値を使用して小数 Scene_SetWindowPos 点以下の有効桁数のみをレンダリングします。 Scene_SetWindowSize •キャラクタ文字列はマスク値を使用して左側からの文字数を 返します(strleft()関数と同等です)。 Item_SetWindowPos •他のデータタイプは全て自身を評価します(つまりマスク処 LoadMotion 理は行われません)。オブジェクトにマスク処理を施すには、 SaveMotion オブジェクト演算子の後に整数値をつけます。例えば、以下 のコードでは値”1.34”を表示します。 •LS-RT/GNプラグインはインストールされたコンパイル済み ... のスクリプトに対しうまく動作しませんでした。 bob = 1.34398545; •LightWaveのオブジェクトエージェント全てにオブジェクト info(bob.2); のタイプを保持するデータメンバ'genus'を持たせることにし ... ました。ここには M E S H 、 L I G H T 、 C A M E R A 、 B O N E 、 SCENEもしくはCHANNELが入ります。 –99– マスク演算子は変数にのみ使用が可能です。 また連鎖式にも使用できます。 レイアウトLScriptコンパイラがチャンネルフィルタースクリ プトタイプをサポートするようになりました。 ... •アイテムモーションのLScriptが関数 create()の中にある bob = 1.34398545; info(bob.2.asStr().isStr()); ... メッシュオブジェクトエージェントをオプションで受け付け // 1 を表示 るようになりました。 @script motion •マスタークラスのL S c r i p tがランタイムプラグインを持つよ ... うになりレイアウトLScriptコンパイラがこのタイプをサポー create: obj トするようになりました。 { •一組の新規 L S c r i p tプラグインが追加され、レイアウトのチ info(obj.filename); ャンネルフィルタープラグインアーキテクチャへのスクリプ } ト機能を提供します。 'ls-df.p'と'lsrt-df.p'はテキ ... ストであり、ランタイムはこのアーキテクチャに対するプラ グインをサポートします。 関数process()のUDFは3つの引数を受け取ります。 1番目はチャンネルアクセスオブジェクトエージェント、2番 この引数はオプションなので、UDFの定義でオフのままにし 目はカレントのフレーム番号、そして3番目の引数はカレント ておいても構いません。 のタイムインデックスとなります。 •可能なスクリプトタイプのプリプロセッサリストに”chan- ... nel”スクリプトタイプが追加されました。このタイプはチャ process: ca, frame, time ンネルフィルターLScriptタイプを表します。 { ... } @script channel ... ... チャンネルアクセスオブジェクトエージェントは1つのデータ •L S c r i p tのオブジェクトエージェントが個々のチャンネルに メンバ 'name' をエクスポートします。このメンバはスクリ 対しインターフェイスを提供するようになりました。 プトが適用されるチャンネルの表示可能な名称をあらわしま 新規メソッドとオブジェクトタイプを使用してオブジェクト す。これに加え、チャンネルデータを取得・設定するための のエンベロープチャンネルにおける反復・対話が可能になり 関数get()とset()が追加されました。 ました。 チャンネルデータは浮動小数点数値となります。 新規firstChannel() メソッドはオブジェクトにつけられ get()ではタイムインデックスを必要とします。 ている最初のチャンネルを返します。 firstChild() メソ set()は関数 process()のUDFで提供されたタイムインデ ッドと同様、このメソッドも全てのチャンネルを通し反復の ックスにおけるチャンネルの新しい値を受け付けます。 プリフェースとして使用されなければなりません。 –100– nextChannel()メソッドではオブジェクトに対するチャン event() このメソッドを使用してチャンネル上でイベントが発生 する度に呼び出されるコールバック関数を起動します。 ネルリストにおける次のチャンネルを返します。 エンベロープ内のキーフレームの作成・削除またはキー 両メソッドとも利用可能なチャンネルが(それ以上)存在しない フレーム値の変更といったイベントです。 場合には'nil'を返します。 light = getfirstitem(LIGHT); 以下のチャンネルフィルタースクリプトは新規オブジェクト c = light.firstChannel(); エージェントの使用法を説明します。 while(c) @warnings { @script channel ... @version 2.0 c = light.nextChannel(); } create: channel { •LScriptのOAツールセットにチャンネルオブジェクトエージ ェントが新規追加されました。新規オブジェクトエージェン light = getfirstitem(LIGHT); トは個々のチャンネル機能へ構造化されたインターフェイス c = light.firstChannel(); を提供します。 while(c) { 新規OAメソッドである firstChannel() とnextChan- last if c.name == “Position.X”; c = light.nextChannel(); nel()は新規OAタイプを返します。ある環境においては、チ ャンネルオブジェクトエージェントがUDFに対し提供されま c.event(“lightEvent”); す(チャンネルフィルターLScriptに対しては関数 create() } のUDFが提供されるように)。 } このリリースではチャンネルオブジェクトエージェントは以 // このチャンネル内における変更と同期を保ちます 下のデータメンバをエクスポートします name type レイアウトインターフェイス上に表記されるチャンネル process: ca, frame, time 名称(Graph Editorなどのように) { ca.set(0.0); チャンネルのタイプ。以下の値のうちの一つとなりま す: NUMBER, DISTANCE,PERCENT, ANGLE } lightEvent: channel,event // チャンネルオブジェクトエージェントイベントコード 2つのメソッドが利用可能です: { value() このメソッドでは特定の時間においてチャンネルが評価 されます。返り値はチャンネルのタイプに基づいて補間 された浮動小数点値となります。 // Lightの”Position.X”チャンネルに何かが起こりました info(event); } –101– •タブと改行( '\t'と'\n')に対するC言語仕様のエスケープ •シーンオブジェクトエージェントにレンダリングで使用され シークエンスがサポートされるようになりました。 る整数反復深度を保持するデータメンバ •文字列の値を取得しそれに対応する整数値を返す変換関数 'recursiondepth'が追加されました。 ascii()が追加されました。非表示の文字を比較する際に便 利です。 •レイアウトオブジェクトエージェントは4つの新規データメ ンバをサポートするようになりました。これらのメンバは状 if(ascii(line[x]) == '\t’) ... 態を表すブーリアンフラグです。 selected childrenvisible •変換式'asAsc'が追加されました。 channelsvisible if(line[x].asAsc == '\t’) ... locked •文字列インデックスが誤ってハンドルされ、アプリケーショ •L S c r i p tでコンパイルされたイメージチャンクがランタイム ンがクラッシュしていました。 システムでは適切に認識されませんでした。 •関数SubPatchLevel()はレイアウトへ不当な型の引数整 数値の代わりに浮動小数点数値を渡していました。 ベータ 4: •シーンオブジェクトエージェントにカレントシーンを通じて オブジェクトの選択をサイクルするための2つの反復メソッド •関数 g e t f i l e ( )で使用されるバッファサイズが標準のOS が追加されました。 のバッファサイズ2 5 6バイトの半分よりも少ないサイズとな firstSelect()とnextSelect()メソッドは他の反復メ っていました。 ソッド、例えばレイアウトオブジェクトエージェントの •正規表現がデバッガデータセットに追加されました。 firstChild()やnextChild()と同様の形式で使用され •debug()コマンドは既にデバッグ中であるかを確認してい ます。 ませんでした。 scene = getfirstitem(SCENE); •レイアウトのCSはビルド402を反映して更新されました。 obj = scene.firstSelect(); •レイアウトのCS関数は(SelectItem()やGoalItem()の while(obj) ように)引数としてアイテムのIDが想定されていますが、必要 { とされるレイアウトオブジェクトを指定できるように引数の ... 組み合わせを変更できるようにしました。 obj = scene.nextSelect(); •LightWaveのシーンファイルにおいてフォーマットされてい } るように整数値で指定することが可能です。指定する値は16 進数であるため、ビット演算を行い32ビット整数値へ配置し •シーンオブジェクトエージェントにレイアウトインターフェ なおす必要もあります。 イス内で現在選択されているタイムインデックスを保持する データメンバ'currenttime'が追加されました。 –102– ベータ 3: // 2番目のメッシュオブジェクトを選択します SelectItem((1 << 28) | 1); •反復foreach()で受け入れられるデータタイプに連想配列 タイプが追加されました。キーの値は内部ハッシュツリー内 •カレントシーンにおけるオブジェクト名称を評価するための でみつかる順に処理されます。 文字列値が提供されます。 •アイテムモーションの set() 関数はパラメーター(2)の値を 正しく受け付けていませんでした。 •オブジェクトクラスは (MESH、LIGHT、CAMERA) と、そ •多くのオブジェクトベースの参照問題がアドレス指定されま れに続く整数値で特定されます。整数値はクラスのオブジェ した。 クトリスト内におけるオブジェクトのリニアオフセット(基底 •今まではある状況においてレイアウトL S c r i p tへの再入に問 は1)を特定する値です。 題が生じていました。 // シーン内の3番目のLightを選択します SelectItem(LIGHT,3); 特定の例をあげると、単一のプラグインが相互依存している2 つ以上のオブジェクト(インスタンス)を管理している場合、既 •以下のレイアウトC S関数は新規オブジェクトに名称をつけ にプラグインがある process()関数の中にいる状態で、プ るためにオプションのキャラクタ文字列を受け付けるように ラグインの process()関数が呼び出される可能性がありま なりました。名称が提供されない場合には、レイアウトはユ した。LScriptはグローバル変数を使用(歴史的な経緯から)し ーザーに対しリクエスタを表示します。 ているため、この状況においてはハンドルすることが不可能 AddNull です。 この再入の問題を解決するためにレイアウトLScriptにインス AddBone タンススタックが実現しました。これにより2つ以上のオブジ AddChildBone ェクトにそれぞれ同種類のLScriptプラグインが適用されてい AddDistantLight る場合でも、相互依存が可能となりました。 AddPointLight ここに以前のバージョンのレイアウトLScriptではクラッシュ する可能性が高かった相互依存の例を紹介します(Alexandre AddSpotlight Bonから提供された例に基づいています)。 AddLinearLight 1.シーンに3つのヌルを追加し、”A”、”B”、”C”と名称をつけま AddAreaLight す。 2.ヌル”A”にモーションをつけます。 3.ヌル”C”の下にItem Motionのスクリプトを適用し“B” ReplaceWithObject ReplaceWithNull を監視するようにします。 LoadObject 4. 同じスクリプトを今度はヌル”B”に対して適用し、“A”を監 視するようにします。 •基盤となるプラグインAPIにおいて変更が生じたため、以下 5. アニメーションを走らせます。 のサーフェイスに関するLScript関数が削除されました: _getRawSurf() _setRawSurf() –103– •L S c r i p tのコンパイラはコンパイル済みのスクリプトファイ @version 2.0 ルに記憶されているデータタイプに対し不正なサイズを使用 @script motion していました。 •ランタイムプラグインは古いインターフェイスのバージョン parent; 値を使用していたため、レイアウトから渡されるインターフ process: ma, frame, time ェイス構造体の中のエレメントが初期化されていませんでし { た。プラグインがこれらのNULL値を参照すると、クラッシュ if(!parent) return; します。 newpos = parent.param(POSITION,time); •レイアウト L S c r i p tコンパイラは選択したソーススクリプト newpos.z -= 2; 内で"@script"プラグマを検出すると、自動的にプラグイ ma.set(POSITION,newpos); ンアーキテクチャを選択するようになりました。 } •LScriptのプリプロセッサはスクリプト内に " @ s c r i p t " プ options ラグマを検出すると、アーキテクチャに対し正しいタイプで { あるかを確認するためにチェックを行うようになりました。 if(!reqbegin(“Follow The Leader”)) return; •LScriptプラグインサーバー名称が標準化されました。 名称の一部としてレイアウトにアーキテクチャタイプを表示 c1 = ctlallitems(“Select parent”,parent); if(reqpost()) する代わりに(コンテキストポップアップメニューにおいての みプラグインが表示されるため冗長となっていましたが)、全 て以下の名称をもつことになりました: parent = getvalue(c1); •“LW_LScript” reqend(); これはテキストベースのスクリプトインタープリターに対す } る新規名称です。プラグイン名称をLScript/GN、LScript/MC やLScript/IFなどのように置き換えます。 •L S c r i p tの仮想マシンコードにおけるマイナーな改良がいく •“LW_LScript/RT” つか行われました。 これにより代入文の左側にオブジェクトベースの配列参照が これはバイナリベースのスクリプトインタープリター用の新 使用できるようになりました: 規名称です。プラグイン名称を L S / G N - R T、L S / D M - R Tや LS/IF-RTなどのように置き換えます。 v[1] = <1,2,3>; •“LW_LSCompiler” v[1].x = 10; . . . LScriptコンパイラプラグイン用の新規名称です。 t = 1; LSC/LWやLSC/MDに置き換えます。 obj[t] = ObjectMan(“Cow.lwo”); obj[t].surfaces[t] += “_Bob”; –104– ベータ 2: LScript最新情報について •終端にコンマ分離記号が埋め込まれている文字列があり、以 LScriptは、大小のさまざまなバージョンアップ・リビジョン 下に続く文字列と連鎖していました。このため特定のオブジ アップを行っています。 ェクトメソッド名称が認識されませんでした。 これにあわせて、ドキュメンテーションも常に追加されてい •array()関数はいまだに古い形式で配列を生成していたた ます。 め結果配列にアクセスされると問題が生じていました。 LScript最新情報については、以下のウェブサイトをご覧にな •再帰的関数は配列内の全てのエレメントを特定のデータタイ ることをおすすめします。 プで初期化しなければならないのに、配列が持つサブ配列を http://www.newtek-outpost.com/employees/bobh/ 破壊していました。 •ある特定の状況においてオブジェクトデータメンバは不当な オーナーに連結されていました。 •ある理由により、不可視(オフ)ではない状態の ctltext() コントロールを不可視にした場合に、パネルがクラッシュし ます。不可視状態の ctltext()の値は当分の間サポートさ れません。 •サブ配列が参照された時点で配列処理にバグが起こります。 –105– LScpirt Ver.2.0 日本語マニュアル ©1997−2000 NewTek,Inc./DSTORM,Inc. All Rights Reserved –106– 索引 記号その他 ?,: 7 A abs 17 acos 17 addcurve 46 addfilename 55 addhsv 55 additems 55 addpoint 45 addpolygon 45 addquad 46 addrgb 55 addtriangle 46 alignpols 34 append 22 asin 17 assigndata 72 atan 17 autoflex 28 axisdrill 32 C cache 58 ceil 17 center 20 changesurface 36 cleanup 60 close 13 cmdseq 38 continue 8 copy 26 copysurface 37 cos 17 cosh 17 cot 17 create 49 createsurface 37 csc 17 ctlchoice 41 ctlcolor 41, 42 ctldistance 41 ctlfont 41, 42 ctlinteger 41 ctlnumber 41 B ctlstring 41 bend 29 ctlsurface 41, 42 bevel 33 ctltext 41, 42 bglayers 39 ctlvector 41 boolean 33 cut 26 boundingbox 44 bufferline 57 D deformregion 28 deg 18 frac 19 delete 26 fracsubdivide 34 destroy 49 freezecurves 34 destructor 72 G dump 24 get 62 E getdefaultsurface 36 editbegin 44 getdir 23 editend 44 getempty 39 eof 13 getemptybg 39 error 19 getemptyfg 39 exp 16 getenv 23 extent 20 getfile 38 extrude 31 getfirstitem 50 F getvalue 42 fac 19 H fglayers 39 hypot 18 file 19 I filedelete 20 if/else 6 fileexists 20 illuminate 61 fixedflex 27 info 19 flags 56, 60, 62 init 60 flip 34 integer 21 floatline 57 isOpen 12 floor 17 fontclear 38 fontcount 37 J jitter 29 fontindex 37 L fontload 38 lathe 31 fontname 37 line 14 for 7 linecount 14 listadd 43 listremove 43 move 28 N load 26 new 26 Load 49 newtime 60, 62 loadscene 64 nextsurface 36 log 16 nl 14 lyrbg 26 number 21 lyrdata 27 lyrempty 27 lyremptybg 27 lyrfg 26 lyrsetbg 27 lyrsetfg 27 lyrswap 27 M magnet 28 makeball 30 makebox 30 makecone 30 makedisc 30 maketesball 30 maketext 31 max 17 mergepoints 30 min 17 mirror 31 mod 18 monend 40, 59 moninit 39, 59 monstep 40, 59 O offset 15 open 12 options 49 owndata 72 ownmethod 72 P parse 13, 20 paste 26 pathclone 32 pathextrude 32 pointcount 45 pointinfo 47 pointmove 47 pole 29 polycount 45 polyinfo 46 polynormal 47 polypointcount 46 polypoints 47 polysurface 47 pow 18 process 49 processrgb 57 Q quantize 30 S save 26, 49 savescene 64 scale 29 R rad 18 railclone 32 railextrude 32 random 17 randu 17 range 18 raytrace 62 read 13 readByte 14 readInt 14 readNumber 13 readVector 13 recall 24 removepols 34 rempoint 47 rempolygon 47 renamesurface 37 reopen 12 reqbegin 40 reqend 40 reqpost 41 returndata 72 rewind 13 rotate 28 round 19 sec 17 select 18 selhide 36 selinvert 36 selmode 43 selpoint 34 selpolygon 35 selunhide 36 set 62 setalpha 57 setblayer 26 setlayer 26 setrbg 57 setsurface 36 setvalue 43 shapebevel 33 shear 28 sin 17 sinh 17 size 21 sleep 23 smooth 30 smoothshift 33 soliddrill 33 spawn 22 split 21 sqrt 16 step 19 write 13 store 24 writeByte 14 string 21 writeInt 14 strleft 24 writeln 13 strlower 24 writeNumber 14 strright 24 strsub 24 strupper 24 subdivide 34 swaplayers 38 switch/select 7 T tan 17 tanh 17 taper 29 terminate 23 triple 34 twist 29 U undo 26 unifypols 34 V vector 21 version 73 vmag 19 vortex 29 W wait 23 warn 19 while 6 Y yremptyfg 27
© Copyright 2024 Paperzz