src/gl/S3GLShader.js
import S3GLSystem from "./S3GLSystem.js";
/**
* WebGLのシェーダー管理クラス。
* 頂点シェーダ/フラグメントシェーダのソースコード・型・GLオブジェクトを保持し、コンパイルや破棄、状態取得などの機能を提供します。
* S3GLProgram 内部で利用され、単体では直接使わないことが多い設計です。
*
* @class
* @module S3
*/
export default class S3GLShader {
/**
* WebGLシェーダーを初期化します。
* @param {S3GLSystem} sys GLシステムインスタンス(GLコンテキスト・コンパイル補助などに必要)
* @param {string} code シェーダーのGLSLソースコード、またはGLSLファイルのURL(1行の場合は自動判別)
*/
constructor(sys, code) {
this._init(sys, code);
}
/**
* 内部初期化処理。
* シェーダーソースの格納、コードの取得(URLならダウンロード)、GLオブジェクト初期化などを行います。
* @private
* @param {S3GLSystem} sys GLシステムインスタンス(GLコンテキスト・コンパイル補助などに必要)
* @param {string} code シェーダーのGLSLソースコード、またはGLSLファイルのURL(1行の場合は自動判別)
*/
_init(sys, code) {
/**
* GLシステムインスタンス
* @type {S3GLSystem}
*/
this.sys = sys;
/**
* シェーダーのGLSLソースコード。GLSLコード文字列、または未ロード時はnull。
* @type {string|null}
*/
this.code = null;
/**
* コンパイル済みWebGLShaderオブジェクト。未生成またはエラー時はnull。
* @type {?WebGLShader}
*/
this.shader = null;
/**
* シェーダーの型。gl.VERTEX_SHADER(35633)かgl.FRAGMENT_SHADER(35632)、未設定時は-1。
* @type {number}
*/
this.sharder_type = -1;
/**
* コンパイルや生成エラーが発生した場合にtrue。
* @type {boolean}
*/
this.is_error = false;
const that = this;
/**
* コードダウンロード時のコールバック関数型。
* @callback DownloadCallback
* @param {string} code ダウンロードしたGLSLコード
*/
/** @type {DownloadCallback} */
const downloadCallback = function (code) {
that.code = code;
};
if (code.indexOf("\n") === -1) {
// 1行の場合はURLとみなす(雑)
this.sys._download(code, downloadCallback);
} else {
this.code = code;
}
}
/**
* このシェーダーでエラーが発生しているか判定します。
* @returns {boolean} エラー発生時はtrue
*/
isError() {
return this.is_error;
}
/**
* シェーダーのソースコードを取得します(GLSL文字列)。
* @returns {string|null} シェーダーソース。まだ取得できていない場合はnull
*/
getCode() {
return this.code;
}
/**
* シェーダーオブジェクト(GLShader)を取得します。
* 初回はGLSLの内容から自動でタイプ(頂点/フラグメント)判定とコンパイルを行います。
* コンパイルエラー時や準備未完了時はnullを返します。
* @returns {?WebGLShader} コンパイル済みGLシェーダーオブジェクト、またはnull
*/
getShader() {
const gl = this.sys.getGL();
if (gl === null || this.is_error || this.code === null) {
// まだ準備ができていないのでエラーを発生させない
return null;
}
if (this.shader !== null) {
// すでにコンパイル済みであれば返す
return this.shader;
}
let code = this.code;
// コメントを除去する
code = code.replace(/\/\/.*/g, "");
code = code.replace(/\/\*([^*]|\*[^/])*\*\//g, "");
// コード内を判定して種別を自動判断する(雑)
let sharder_type = 0;
if (code.indexOf("gl_FragColor") !== -1) {
// フラグメントシェーダである
sharder_type = gl.FRAGMENT_SHADER;
} else {
// バーテックスシェーダである
sharder_type = gl.VERTEX_SHADER;
}
const data = this.sys.glfunc.createShader(sharder_type, code);
if (data.is_error) {
this.is_error = true;
return null;
}
this.shader = data.shader;
this.sharder_type = sharder_type;
return this.shader;
}
/**
* このシェーダーのタイプ(頂点orフラグメント)を返します。
* 準備ができていない場合やエラー時はnullになります。
* @returns {number|null} gl.VERTEX_SHADER または gl.FRAGMENT_SHADER、未定義時は null
*/
getShaderType() {
if (this.sharder_type !== -1) {
return this.sharder_type;
}
if (this.getShader() !== null) {
return this.sharder_type;
}
return null;
}
/**
* シェーダーリソースを解放し、GLオブジェクトを破棄します。
* 以後このシェーダーは再利用できません。
* @returns {boolean|null} 正常終了:true、GL未設定時:null
*/
dispose() {
const gl = this.sys.getGL();
if (gl === null) {
return null;
}
if (this.shader === null) {
return true;
}
this.sys.glfunc.deleteShader(this.shader);
this.shader = null;
this.sharder_type = -1;
return true;
}
}