main.js

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

// 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);

// コンテキストを失ったとき

// https://www.khronos.org/webgl/wiki/HandlingContextLost

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;

};