src/gl/S3GLProgram.js
import S3Matrix from "../math/S3Matrix.js";
import S3Vector from "../math/S3Vector.js";
import S3GLShader from "./S3GLShader.js";
import S3GLSystem from "./S3GLSystem.js";
import S3GLArray from "./S3GLArray.js";
import S3GLMesh from "./S3GLMesh.js";
/**
* @typedef {Int32Array|Float32Array|WebGLBuffer|WebGLTexture|S3GLArray|S3Matrix|S3Vector|number} S3GLProgramBindInputDataSingle bindDataの入力データ(単体)
*/
/**
* @typedef {S3GLProgramBindInputDataSingle|Array<S3GLProgramBindInputDataSingle>} S3GLProgramBindInputData bindDataの入力データ(配列可)
*/
/**
* @typedef {Object.<string, S3GLProgramBindInputData>} S3GLProgramBindInputDataTable
*/
/**
* @typedef {Object} S3GLProgramUniforms
* @property {S3GLProgramBindInputDataTable} uniforms
*/
/**
* WebGLのプログラム(Program)管理クラス。
* 頂点・フラグメント2つのシェーダーと、それらをリンクしたGLプログラムオブジェクトを保持し、
* 各種attribute/uniform変数とのバインドや、プログラム切替・破棄などの管理を担います。
* S3GLSystem経由でのWebGL描画制御のコアとなります。
*
* @class
* @module S3
*/
export default class S3GLProgram {
/**
* WebGLプログラムを初期化します。
* @param {S3GLSystem} sys GLシステムインスタンス
* @param {number} id プログラム一意識別ID
*/
constructor(sys, id) {
this._init(sys, id);
}
/**
* プログラムの内部初期化。
* 変数情報・シェーダー状態・リンク済みフラグ等をリセットします。
* @private
* @param {S3GLSystem} sys
* @param {number} id
*/
_init(sys, id) {
/**
* プログラム一意ID
* @type {number}
*/
this.id = id;
/**
* GLシステムインスタンス
* @type {S3GLSystem}
*/
this.sys = sys;
/**
* 頂点シェーダインスタンス
* @type {?S3GLShader}
*/
this.vertex = null;
/**
* フラグメントシェーダインスタンス
* @type {?S3GLShader}
*/
this.fragment = null;
/**
* 頂点シェーダがダウンロード中かどうか
* @type {boolean}
*/
this.isDLVertex = false;
/**
* フラグメントシェーダがダウンロード中かどうか
* @type {boolean}
*/
this.isDLFragment = false;
/**
* リンク済みGLプログラム
* @type {?WebGLProgram}
*/
this.program = null;
/**
* GL上でリンク済みかどうか
* @type {boolean}
*/
this.is_linked = false;
/**
* エラー発生済みかどうか
* @type {boolean}
*/
this.is_error = false;
/**
* 有効化済みのattributeロケーション番号管理
* @type {Object<number, boolean>}
*/
this.enable_vertex_number = {};
/**
* シェーダ変数管理構造体
* @type {Object<string, S3GLShaderData>}
*/
this.variable = {};
const _this = this;
/**
* 次にバインド予定のアクティブテクスチャ番号
* @type {number}
*/
this.activeTextureId = 0;
/**
* WebGLのuniform変数バインド用関数群。
* 各関数はGLSLの型に応じて正しいuniform関数(uniform1iv/uniformMatrix4fv等)でデータを送る役割を持ちます。
*
* @typedef {Object} S3GLUniformBindFunctions
* @property {function(WebGLUniformLocation, Int32Array):void} uniform1iv 1次元整数配列を送信
* @property {function(WebGLUniformLocation, Int32Array):void} uniform2iv 2次元整数配列を送信
* @property {function(WebGLUniformLocation, Int32Array):void} uniform3iv 3次元整数配列を送信
* @property {function(WebGLUniformLocation, Int32Array):void} uniform4iv 4次元整数配列を送信
* @property {function(WebGLUniformLocation, Float32Array):void} uniform1fv 1次元浮動小数点配列を送信
* @property {function(WebGLUniformLocation, Float32Array):void} uniform2fv 2次元浮動小数点配列を送信
* @property {function(WebGLUniformLocation, Float32Array):void} uniform3fv 3次元浮動小数点配列を送信
* @property {function(WebGLUniformLocation, Float32Array):void} uniform4fv 4次元浮動小数点配列を送信
* @property {function(WebGLUniformLocation, Float32Array):void} uniformMatrix2fv 2x2行列を送信
* @property {function(WebGLUniformLocation, Float32Array):void} uniformMatrix3fv 3x3行列を送信
* @property {function(WebGLUniformLocation, Float32Array):void} uniformMatrix4fv 4x4行列を送信
* @property {function(WebGLUniformLocation, WebGLTexture):void} uniformSampler2D 2Dテクスチャ(sampler2D)を送信
*/
/**
* GLSLのuniform変数型ごとに適切なWebGLバインド関数を提供するオブジェクト
* @type {S3GLUniformBindFunctions}
*/
const g = {
/**
* 1次元整数配列 uniform1iv
* @param {WebGLUniformLocation} location
* @param {Int32Array} value
*/
uniform1iv: function (location, value) {
if (sys.getGL()) {
sys.getGL().uniform1iv(location, value);
}
},
/**
* 2次元整数配列 uniform2iv
* @param {WebGLUniformLocation} location
* @param {Int32Array} value
*/
uniform2iv: function (location, value) {
if (sys.getGL()) {
sys.getGL().uniform2iv(location, value);
}
},
/**
* 3次元整数配列 uniform3iv
* @param {WebGLUniformLocation} location
* @param {Int32Array} value
*/
uniform3iv: function (location, value) {
if (sys.getGL()) {
sys.getGL().uniform3iv(location, value);
}
},
/**
* 4次元整数配列 uniform4iv
* @param {WebGLUniformLocation} location
* @param {Int32Array} value
*/
uniform4iv: function (location, value) {
if (sys.getGL()) {
sys.getGL().uniform4iv(location, value);
}
},
/**
* 1次元浮動小数点配列 uniform1fv
* @param {WebGLUniformLocation} location
* @param {Float32Array} value
*/
uniform1fv: function (location, value) {
if (sys.getGL()) {
sys.getGL().uniform1fv(location, value);
}
},
/**
* 2次元浮動小数点配列 uniform2fv
* @param {WebGLUniformLocation} location
* @param {Float32Array} value
*/
uniform2fv: function (location, value) {
if (sys.getGL()) {
sys.getGL().uniform2fv(location, value);
}
},
/**
* 3次元浮動小数点配列 uniform3fv
* @param {WebGLUniformLocation} location
* @param {Float32Array} value
*/
uniform3fv: function (location, value) {
if (sys.getGL()) {
sys.getGL().uniform3fv(location, value);
}
},
/**
* 4次元浮動小数点配列 uniform4fv
* @param {WebGLUniformLocation} location
* @param {Float32Array} value
*/
uniform4fv: function (location, value) {
if (sys.getGL()) {
sys.getGL().uniform4fv(location, value);
}
},
/**
* 2x2行列 uniformMatrix2fv
* @param {WebGLUniformLocation} location
* @param {Float32Array} value
*/
uniformMatrix2fv: function (location, value) {
if (sys.getGL()) {
sys.getGL().uniformMatrix2fv(location, false, value);
}
},
/**
* 3x3行列 uniformMatrix3fv
* @param {WebGLUniformLocation} location
* @param {Float32Array} value
*/
uniformMatrix3fv: function (location, value) {
if (sys.getGL()) {
sys.getGL().uniformMatrix3fv(location, false, value);
}
},
/**
* 4x4行列 uniformMatrix4fv
* @param {WebGLUniformLocation} location
* @param {Float32Array} value
*/
uniformMatrix4fv: function (location, value) {
if (sys.getGL()) {
sys.getGL().uniformMatrix4fv(location, false, value);
}
},
/**
* サンプラー2D(テクスチャ) uniformSampler2D
* @param {WebGLUniformLocation} location
* @param {WebGLTexture} value
*/
uniformSampler2D: function (location, value) {
const gl = sys.getGL();
if (gl) {
gl.activeTexture(gl.TEXTURE0 + _this.activeTextureId);
gl.bindTexture(gl.TEXTURE_2D, value);
gl.uniform1i(location, _this.activeTextureId);
_this.activeTextureId++;
}
}
};
/**
* GLSL型名ごとのWebGLバインド情報テーブル。
* 各GLSL型(int, float, mat4, vec3, sampler2D等)に対し、
* - glsltype: GLSL型名("vec3" など)
* - instance: 対応するTypedArray型またはImage(サンプラーの場合)
* - size: 必要な要素数(配列長)
* - btype: 内部的なデータ型種別("FLOAT", "INT", "TEXTURE" など)
* - bind: WebGLのuniformバインド関数(g内の該当関数を使用)
* などの情報を保持します。
*
* @typedef {Object} S3GLProgramGLSLTypeInfo
* @property {string} glsltype GLSL型名(例:"vec3")
* @property {(typeof Float32Array | typeof Int32Array | Image)} instance 対応TypedArrayコンストラクタまたはImage
* @property {number} size 要素数(floatなら1, mat4なら16など)
* @property {string} btype 内部データ型区分("FLOAT", "INT", "TEXTURE"等)
* @property {function(WebGLUniformLocation, *):void} bind uniform変数へバインドするための関数
*/
/**
* GLSL型ごとのWebGL情報テーブル。
* 変数型をキーとし、型ごとの詳細プロパティ(GLSL型名/配列型/要素数/バインド関数など)を格納します。
* @type {Object<string, S3GLProgramGLSLTypeInfo>}
*/
const info = {
int: { glsltype: "int", instance: Int32Array, size: 1, btype: "INT", bind: g.uniform1iv },
float: { glsltype: "float", instance: Float32Array, size: 1, btype: "FLOAT", bind: g.uniform1fv },
bool: { glsltype: "bool", instance: Int32Array, size: 1, btype: "INT", bind: g.uniform1iv },
mat2: { glsltype: "mat2", instance: Float32Array, size: 4, btype: "FLOAT", bind: g.uniformMatrix2fv },
mat3: { glsltype: "mat3", instance: Float32Array, size: 9, btype: "FLOAT", bind: g.uniformMatrix3fv },
mat4: { glsltype: "mat4", instance: Float32Array, size: 16, btype: "FLOAT", bind: g.uniformMatrix4fv },
vec2: { glsltype: "vec2", instance: Float32Array, size: 2, btype: "FLOAT", bind: g.uniform2fv },
vec3: { glsltype: "vec3", instance: Float32Array, size: 3, btype: "FLOAT", bind: g.uniform3fv },
vec4: { glsltype: "vec4", instance: Float32Array, size: 4, btype: "FLOAT", bind: g.uniform4fv },
ivec2: { glsltype: "ivec2", instance: Int32Array, size: 2, btype: "INT", bind: g.uniform2iv },
ivec3: { glsltype: "ivec3", instance: Int32Array, size: 3, btype: "INT", bind: g.uniform3iv },
ivec4: { glsltype: "ivec4", instance: Int32Array, size: 4, btype: "INT", bind: g.uniform4iv },
bvec2: { glsltype: "bvec2", instance: Int32Array, size: 2, btype: "INT", bind: g.uniform2iv },
bvec3: { glsltype: "bvec3", instance: Int32Array, size: 3, btype: "INT", bind: g.uniform3iv },
bvec4: { glsltype: "bvec4", instance: Int32Array, size: 4, btype: "INT", bind: g.uniform4iv },
sampler2D: { glsltype: "sampler2D", instance: Image, size: 1, btype: "TEXTURE", bind: g.uniformSampler2D },
samplerCube: { glsltype: "samplerCube", instance: Image, size: 1, btype: "TEXTURE", bind: null }
};
/**
* ソースコードから解析した変数のデータ
*
* - info オブジェクトのキー("int", "float", "vec3"など)を使用して、いくつかのデータはコピーされる
*
* @typedef {Object} S3GLShaderData
* @property {string} glsltype GLSL型名(例:"vec3")
* @property {(typeof Float32Array | typeof Int32Array | Image)} instance 対応TypedArrayコンストラクタまたはImage
* @property {number} size 要素数(floatなら1, mat4なら16など)
* @property {string} btype 内部データ型区分("FLOAT", "INT", "TEXTURE"等)
* @property {function(WebGLUniformLocation, *):void} bind uniform変数へバインドするための関数
* @property {string} name 変数名(例:"M")
* @property {string} modifiers 宣言修飾子(例:"uniform")
* @property {boolean} is_array 配列かどうか(例:`true`なら配列型)
* @property {Array<GLint|WebGLUniformLocation>} location
*/
/**
* 頂点・フラグメントシェーダ内のattribute/uniform宣言を自動解析し、
* 変数型・ロケーションなどを内部情報として登録します。
* (通常はgetProgramで自動的に呼び出されます)
* @param {string} code シェーダーのGLSLソース
* @param {Object<string, S3GLShaderData>} variable 内部変数情報管理オブジェクト
* @private
*/
this.analysisShader = function (code, variable) {
// コメントを除去する
code = code.replace(/\/\/.*/g, "");
code = code.replace(/\/\*([^*]|\*[^/])*\*\//g, "");
// 1行ずつ解析
const codelines = code.split("\n");
for (let i = 0; i < codelines.length; i++) {
// uniform vec4 lights[4]; とすると、 uniform,vec4,lights,[4]で区切られる
const data = codelines[i].match(/(attribute|uniform)\s+(\w+)\s+(\w+)\s*(\[\s*\w+\s*\])?;/);
if (data === null) {
continue;
}
// 見つけたら変数名や、型を記録しておく
// 配列数の調査は、定数などを使用されると簡単に調べられないため取得できない
// そのため自動でテストできないため、bindする際に、正しい配列数の配列をbindすること
/**
* uniform or attribute
*/
const text_space = data[1];
/**
* vec4 ...
*/
const text_type = data[2];
/**
* 変数名
*/
const text_variable = data[3];
/**
* 配列数
*/
const text_array = data[4];
/**
* 配列かどうか
*/
const is_array = text_array !== undefined;
// 型に応じたテンプレートを取得する
// data[1] ... uniform, data[2] ... mat4, data[3] ... M
const targetinfo = info[text_type];
variable[text_variable] = {
glsltype: targetinfo.glsltype, // vec3, mat4 など
instance: targetinfo.instance, // Float32Array, Int32Array, Image など
size: targetinfo.size, // 1, 2, 3, 4, 16 など
btype: targetinfo.btype, // FLOAT, INT, TEXTURE など
bind: targetinfo.bind, // bind関数(uniform1fvなど)
name: text_variable, // 変数名(例:"M")
modifiers: text_space, // uniform, attribute などの修飾子
is_array: is_array, // 配列かどうか
location: [] // ロケーション番号(GLのuniformLocationやattributeLocation)
};
}
return;
};
}
/**
* 使用するアクティブテクスチャ番号をリセットします。
* テクスチャbind前に毎回呼び出し、TEXTUREユニットIDを初期化します。
*/
resetActiveTextureId() {
this.activeTextureId = 0;
}
/**
* プログラムがすでにGL上でリンク済みかどうか判定します。
* @returns {boolean} リンク済みならtrue
*/
isLinked() {
return this.is_linked;
}
/**
* プログラム・シェーダーを全て解放し、GLリソースも破棄します。
* 以後このインスタンスは再利用できません。
* @returns {boolean} 正常終了時true、GL未設定時false
*/
dispose() {
const gl = this.sys.getGL();
if (gl === null) {
return false;
}
if (this.is_linked) {
this.disuseProgram();
this.sys.glfunc.deleteProgram(this.program, this.vertex.getShader(), this.fragment.getShader());
this.program = null;
this.is_linked = false;
}
if (this.vertex !== null) {
this.vertex.dispose();
this.vertex = null;
}
if (this.fragment !== null) {
this.fragment.dispose();
this.fragment = null;
}
this._init(this.sys, this.id);
return true;
}
/**
* 頂点シェーダを設定します。既存のリンク状態なら設定不可。
* @param {string} shader_code GLSLソースコードまたはURL
* @returns {boolean} 成功時true、リンク済みまたはDL中はfalse
*/
setVertexShader(shader_code) {
if (this.isLinked()) {
return false;
}
if (this.vertex !== null) {
this.vertex.dispose();
this.vertex = null;
}
this.vertex = new S3GLShader(this.sys, shader_code);
this.is_error = false;
return true;
}
/**
* フラグメントシェーダを設定します。既存のリンク状態なら設定不可。
* @param {string} shader_code GLSLソースコードまたはURL
* @returns {boolean} 成功時true、リンク済みまたはDL中はfalse
*/
setFragmentShader(shader_code) {
if (this.isLinked()) {
return false;
}
if (this.fragment !== null) {
this.fragment.dispose();
this.fragment = null;
}
this.fragment = new S3GLShader(this.sys, shader_code);
this.is_error = false;
return true;
}
/**
* このプログラムをGLでuseProgram(アクティブ化)します。
* @returns {boolean} 成功時true
*/
useProgram() {
if (!this.isLinked()) {
return false;
}
const program = this.getProgram();
if (program && this.sys.getGL()) {
this.sys.getGL().useProgram(program);
}
return true;
}
/**
* このプログラムの有効化状態を解除します(バッファ属性解放など)。
* @returns {boolean} 成功時true
*/
disuseProgram() {
if (!this.isLinked()) {
return false;
}
const gl = this.sys.getGL();
if (gl) {
// enable化したデータを解放する
for (const key in this.enable_vertex_number) {
if (typeof key === "number") {
gl.disableVertexAttribArray(key);
}
}
this.enable_vertex_number = {};
}
return true;
}
/**
* プログラムのGLオブジェクト(WebGLProgram)を取得・生成します。
* シェーダー・GLの準備やリンク状況など全て検証し、問題なければ生成・返却します。
* @returns {?WebGLProgram} GLプログラムオブジェクト(未生成・エラー時はnull)
*/
getProgram() {
const gl = this.sys.getGL();
// 1度でもエラーが発生したか、glキャンバスの設定をしていない場合
if (gl === null || this.is_error) {
return null;
}
// ダウンロード中なら無視する
if (this.isDLVertex || this.isDLFragment) {
return null;
}
// すでにリンク済みのがあれば返す
if (this.isLinked()) {
return this.program;
}
// シェーダーを取得する
if (this.vertex === null) {
console.log("do not set VERTEX_SHADER");
this.is_error = true;
return null;
}
if (this.fragment === null) {
console.log("do not set FRAGMENT_SHADER");
this.is_error = true;
return null;
}
const is_error_vertex = this.vertex.isError();
const is_error_fragment = this.fragment.isError();
if (is_error_vertex || is_error_fragment) {
console.log("shader compile error");
this.is_error = true;
return null;
}
const shader_vertex = this.vertex.getShader();
const shader_fragment = this.fragment.getShader();
if (shader_vertex === null || shader_fragment === null) {
// まだロードが終わってない可能性あり
return null;
}
if (this.vertex.getShaderType() !== gl.VERTEX_SHADER) {
console.log("VERTEX_SHADER is not VERTEX_SHADER");
this.is_error = true;
return null;
}
if (this.fragment.getShaderType() !== gl.FRAGMENT_SHADER) {
console.log("FRAGMENT_SHADER is not FRAGMENT_SHADER");
this.is_error = true;
return null;
}
// 取得したシェーダーを用いてプログラムをリンクする
const data = this.sys.glfunc.createProgram(shader_vertex, shader_fragment);
if (data.is_error) {
this.is_error = true;
return null;
}
// リンクが成功したらプログラムの解析しておく
this.is_linked = true;
this.program = data.program;
this.analysisShader(this.vertex.getCode(), this.variable);
this.analysisShader(this.fragment.getCode(), this.variable);
return this.program;
}
/**
* attribute/uniform変数にデータをバインドします。
* シェーダー内で使用されている変数名に対し、値・バッファ・テクスチャ等を型に応じて結びつけます。
* @param {string} name 変数名(シェーダー内で宣言された名前)
* @param {S3GLProgramBindInputData} data バインドしたい値やバッファ、テクスチャなど
* @returns {boolean} 正常にバインドできればtrue
*/
bindData(name, data) {
if (!this.isLinked()) {
return false;
}
const gl = this.sys.getGL();
const prg = this.getProgram();
const variable = this.variable[name];
// ---- check Location ----
if (variable === undefined) {
// シェーダーでは利用していないものをbindしようとした。
return false;
}
// 長さが0なら位置が未調査なので調査する
if (variable.location.length === 0) {
if (variable.modifiers === "attribute") {
variable.location[0] = gl.getAttribLocation(prg, name);
} else {
if (!variable.is_array) {
variable.location[0] = gl.getUniformLocation(prg, name);
} else {
if (Array.isArray(data)) {
// 配列の場合は、配列の数だけlocationを調査する
// 予め、シェーダー内の配列数と一致させておくこと
for (let i = 0; i < data.length; i++) {
variable.location[i] = gl.getUniformLocation(prg, name + "[" + i + "]");
}
}
}
}
}
if (variable.location[0] === -1) {
// 変数は宣言されているが、関数の中で使用していないと -1 がかえる
return false;
}
// data が bind できる形になっているか調査する
// ---- check Type ----
// glslの型をチェックして自動型変換する
/**
* @typedef {Int32Array|Float32Array|WebGLBuffer|WebGLTexture} S3GLProgramBindData
*/
/**
* WebGL用のuniform/attributeバインド値として、データ型を自動変換する補助関数。
* シェーダー変数の型(glsltype)に応じて、渡された値を適切なTypedArrayや配列に整形します。
* 型不一致や未対応型は例外となります。
*
* @param {Int32Array|Float32Array|WebGLBuffer|WebGLTexture|S3GLArray|S3Matrix|number} data
* @returns {S3GLProgramBindData}
*/
const toArraydata = function (data) {
if (data instanceof WebGLBuffer) {
// VBO型は、無視する
if (variable.modifiers === "attribute") {
return data;
}
}
if (data instanceof WebGLTexture) {
// テクスチャ型なら無視する
if (variable.glsltype === "sampler2D") {
return data;
}
}
if (data instanceof variable.instance) {
// 型と同じインスタンスであるため問題なし
return data;
}
// GL用の型
if (data instanceof S3GLArray) {
if (variable.glsltype === data.glsltype) {
return data.data;
}
}
// 入力型とGLSLが数値系であれば
if (variable.instance === Float32Array || variable.instance === Int32Array) {
// 入力型が行列型で
if (data instanceof S3Matrix) {
if (variable.glsltype === "mat2" || variable.glsltype === "mat3" || variable.glsltype === "mat4") {
return data.toInstanceArray(variable.instance, variable.size);
}
}
// 入力型がベクトル型
if (data instanceof S3Vector) {
if (
variable.glsltype === "vec2" ||
variable.glsltype === "vec3" ||
variable.glsltype === "vec4" ||
variable.glsltype === "ivec2" ||
variable.glsltype === "ivec3" ||
variable.glsltype === "ivec4" ||
variable.glsltype === "bvec2" ||
variable.glsltype === "bvec3" ||
variable.glsltype === "bvec4"
) {
return data.toInstanceArray(variable.instance, variable.size);
}
}
// 入力型が数値型
if (typeof data === "number") {
if (variable.glsltype === "int" || variable.glsltype === "float" || variable.glsltype === "bool") {
return new variable.instance([data]);
}
}
}
console.log(data);
throw "not toArraydata";
};
// 引数の値をArray型に統一化する
if (!variable.is_array) {
data = toArraydata(data);
} else {
if (Array.isArray(data)) {
for (let i = 0; i < data.length; i++) {
if (variable.location[i] !== -1) {
// 配列の値が NULL になっているものは調査しない
if (data[i] !== null) {
data[i] = toArraydata(data[i]);
}
}
}
}
}
// ---- bind Data ----
// 装飾子によって bind する方法を変更する
if (variable.modifiers === "attribute") {
if (typeof variable.location[0] === "number") {
// bindしたいデータ
gl.bindBuffer(gl.ARRAY_BUFFER, data);
// 有効化していない場合は有効化する
if (!this.enable_vertex_number[variable.location[0]]) {
gl.enableVertexAttribArray(variable.location[0]);
this.enable_vertex_number[variable.location[0]] = true;
}
// bind。型は適当に設定
gl.vertexAttribPointer(
variable.location[0],
variable.size,
variable.btype === "FLOAT" ? gl.FLOAT : gl.SHORT,
false,
0,
0
);
} else {
throw "error location is not number";
}
} else {
// uniform の設定
if (!variable.is_array) {
variable.bind(variable.location[0], data);
} else {
// 配列の場合は、配列の数だけbindする
if (Array.isArray(data)) {
for (let i = 0; i < data.length; i++) {
if (variable.location[i] !== -1) {
// 配列の値が NULL になっているものはbindしない
if (data[i] !== null) {
variable.bind(variable.location[i], data[i]);
}
}
}
} else {
throw "error data is not Array";
}
}
}
return true;
}
/**
* メッシュ(S3GLMesh)全体をこのプログラムにバインドします。
* 内部でattribute変数とVBO/IBOなどを結び付け、必要なバッファ設定も行います。
* @param {S3GLMesh} s3mesh S3GLMesh インスタンス
* @returns {number} IBOのインデックス数(drawElements用)
*/
bindMesh(s3mesh) {
if (!this.isLinked()) {
// programが未作成
return 0;
}
const gl = this.sys.getGL();
if (gl === null) {
// glが用意されていない
return 0;
}
const gldata = s3mesh.getGLData();
if (gldata === null) {
// 入力値が用意されていない
return 0;
}
// インデックスをセット
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gldata.ibo.data);
const index_length = gldata.ibo.array_length;
// 頂点をセット(あらかじめコードから解析した attribute について埋める)
for (const key in this.variable) {
if (this.variable[key].modifiers === "uniform") {
// uniform は共通設定なので省略
continue;
}
// 例えば、vboのリストにあるが、gldata内に情報をもっていない場合がある
// それは、カメラ用の行列などがあげられる。
// 逆に、gldata内に情報をもっているが、vbo内に定義されていないのであれば、
// 使用しない。
if (gldata.vbo[key] === undefined) {
continue;
}
this.bindData(key, gldata.vbo[key].data);
}
// 戻り値でインデックスの長さを返す
// この長さは、drawElementsで必要のため
return index_length;
}
}