// Live2Dモデルのインスタンス
live2DModel =
null
;
/* Live2DModel型オブジェクト */
// モデルの初期化が完了したら true
var
initLive2DCompleted =
false
;
// モデルのロードが完了したら true
var
loadLive2DCompleted =
false
;
// テクスチャ用イメージオブジェクト
var
loadedImages = [];
/* Image型の配列 */
// Live2D モデル設定
var
modelDef = {
"type"
:
"Live2D Model Setting"
,
"name"
:
"haru"
,
"model"
:
"assets/haru/haru.moc"
,
"textures"
: [
"assets/haru/haru.1024/texture_00.png"
,
"assets/haru/haru.1024/texture_01.png"
,
"assets/haru/haru.1024/texture_02.png"
]
};
// アニメーション停止用ID
var
requestID;
window.onload =
function
() {
main();
};
/**
* 最初に実行される関数
*/
function
main() {
"use strict"
;
// Canvas要素の取得・初期化
var
canvas = initCanvas(
"glcanvas"
);
// WebGLの取得・初期化
var
gl = initWebGL(canvas);
// Live2Dの初期化
initLive2D(canvas, gl);
}
/**
* Live2Dの初期化とテクスチャの準備
*/
function
initLive2D(canvas, gl) {
"use strict"
;
// Live2Dの初期化
Live2D.init();
// mocファイルからLive2Dモデルのインスタンスを生成
loadBytes(modelDef.model,
function
(buf){
live2DModel = Live2DModelWebGL.loadModel(buf);
});
// テクスチャの読み込み
var
loadCount = 0;
for
(
var
i = 0; i < modelDef.textures.length; i++){
// 即時関数で i の値を tno に固定する(onerror用)
(
function
(tno){
loadedImages[tno] =
new
Image();
loadedImages[tno].src = modelDef.textures[tno];
loadedImages[tno].onload =
function
(){
if
((++loadCount) == modelDef.textures.length) {
loadLive2DCompleted =
true
;
//全て読み終わった
}
}
loadedImages[tno].onerror =
function
() {
console.error(
"Failed to load image : "
+
modelDef.textures[tno]);
}
})(i);
}
//------------ 描画ループ ------------
(
function
tick() {
draw(gl);
// 1回分描画
var
requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
// 一定時間後に自身を呼び出す
requestID = requestAnimationFrame(tick ,canvas);
})();
}
/**
* Canvas要素を取得してイベントを登録
*/
function
initCanvas(id
/*string*/
) {
"use strict"
;
// canvasオブジェクトを取得
var
canvas = document.getElementById(id);
// コンテキストを失ったとき
canvas.addEventListener(
"webglcontextlost"
,
function
(e) {
console.error(
"webglcontext lost"
);
loadLive2DCompleted =
false
;
initLive2DCompleted =
false
;
var
cancelAnimationFrame =
window.cancelAnimationFrame ||
window.mozCancelAnimationFrame;
cancelAnimationFrame(requestID);
//アニメーションを停止
e.preventDefault();
},
false
);
// コンテキストが復元されたとき
canvas.addEventListener(
"webglcontextrestored"
,
function
(e){
console.error(
"webglcontext restored"
);
var
gl = initWebGL(canvas);
initLive2D(canvas, gl);
},
false
);
return
canvas;
}
/**
* WebGLオブジェクトを取得・初期化
*/
function
initWebGL(canvas
/*Canvas Object*/
) {
"use strict"
;
// WebGLのコンテキストを取得する
var
gl = getWebGLContext(canvas);
if
(!gl) {
console.error(
"Failed to create WebGL context."
);
return
;
}
// 描画エリアを白でクリア
gl.clearColor( 0.0, 0.0, 0.0, 0.0 );
return
gl;
}
/**
* モデルにテクスチャ、マトリクスを割り当てて更新・描画
*/
function
draw(gl)
{
"use strict"
;
// Canvasをクリアする
gl.clear(gl.COLOR_BUFFER_BIT);
if
(!live2DModel || !loadLive2DCompleted) {
return
;
//ロードが完了していないので何もしないで返る
}
// ロード完了後に初回のみ初期化する
if
(!initLive2DCompleted) {
initLive2DCompleted =
true
;
// 画像からWebGLテクスチャを生成し、モデルに登録
for
(
var
i = 0; i < loadedImages.length; i++){
// Image型オブジェクトからテクスチャを生成
var
texName = createTexture(gl, loadedImages[i]);
//モデルにテクスチャをセット
live2DModel.setTexture(i, texName);
}
// テクスチャの元画像の参照をクリア
loadedImages =
null
;
// WebGLのコンテキストをセット
live2DModel.setGL(gl);
// 表示位置を指定するための行列を定義する
// canvasの横幅を-1..1区間に収める
var
s = 2.0 / live2DModel.getCanvasWidth();
var
matrix4x4 = [s, 0, 0, 0,
0, -s, 0, 0,
0, 0, 1, 0,
-1, 1, 0, 1];
live2DModel.setMatrix(matrix4x4);
}
// Live2Dモデルを更新して描画
live2DModel.update();
// 現在のパラメータに合わせて頂点等を計算
live2DModel.draw();
// 描画
};
/**
* WebGLのコンテキストを取得する
*/
function
getWebGLContext(canvas) {
"use strict"
;
var
NAMES = [
"webgl"
,
"experimental-webgl"
,
"webkit-3d"
,
"moz-webgl"
];
for
(
var
i = 0; i < NAMES.length; i++ ){
try
{
var
ctx = canvas.getContext(NAMES[i]);
if
( ctx )
return
ctx;
}
catch
(e){
console.error(e);
}
}
return
null
;
};
/**
* Image型オブジェクトからテクスチャを生成
*/
function
createTexture(gl
/*WebGL*/
, image
/*Image*/
) {
"use strict"
;
//テクスチャオブジェクトを作成する
var
texture = gl.createTexture();
if
(!texture) {
console.error(
"Failed to generate gl texture name."
);
return
-1;
}
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
//imageを上下反転
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.generateMipmap(gl.TEXTURE_2D);
return
texture;
};
/**
* ファイルをバイト配列としてロードする
*/
function
loadBytes(path, callback) {
"use strict"
;
var
request =
new
XMLHttpRequest();
request.open(
"GET"
, path,
true
);
request.responseType =
"arraybuffer"
;
request.onload =
function
() {
switch
(request.status) {
case
200:
callback(request.response);
break
;
default
:
console.error(
"Failed to load ("
+
request.status +
") : "
+ path);
break
;
}
}
request.send(
null
);
return
request;
};