vap.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global.howLongUntilLunch = factory());
  5. }(this, (function () { 'use strict';
  6. var classCallCheck = function (instance, Constructor) {
  7. if (!(instance instanceof Constructor)) {
  8. throw new TypeError("Cannot call a class as a function");
  9. }
  10. };
  11. var createClass = function () {
  12. function defineProperties(target, props) {
  13. for (var i = 0; i < props.length; i++) {
  14. var descriptor = props[i];
  15. descriptor.enumerable = descriptor.enumerable || false;
  16. descriptor.configurable = true;
  17. if ("value" in descriptor) descriptor.writable = true;
  18. Object.defineProperty(target, descriptor.key, descriptor);
  19. }
  20. }
  21. return function (Constructor, protoProps, staticProps) {
  22. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  23. if (staticProps) defineProperties(Constructor, staticProps);
  24. return Constructor;
  25. };
  26. }();
  27. var get = function get(object, property, receiver) {
  28. if (object === null) object = Function.prototype;
  29. var desc = Object.getOwnPropertyDescriptor(object, property);
  30. if (desc === undefined) {
  31. var parent = Object.getPrototypeOf(object);
  32. if (parent === null) {
  33. return undefined;
  34. } else {
  35. return get(parent, property, receiver);
  36. }
  37. } else if ("value" in desc) {
  38. return desc.value;
  39. } else {
  40. var getter = desc.get;
  41. if (getter === undefined) {
  42. return undefined;
  43. }
  44. return getter.call(receiver);
  45. }
  46. };
  47. var inherits = function (subClass, superClass) {
  48. if (typeof superClass !== "function" && superClass !== null) {
  49. throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
  50. }
  51. subClass.prototype = Object.create(superClass && superClass.prototype, {
  52. constructor: {
  53. value: subClass,
  54. enumerable: false,
  55. writable: true,
  56. configurable: true
  57. }
  58. });
  59. if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
  60. };
  61. var possibleConstructorReturn = function (self, call) {
  62. if (!self) {
  63. throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  64. }
  65. return call && (typeof call === "object" || typeof call === "function") ? call : self;
  66. };
  67. var slicedToArray = function () {
  68. function sliceIterator(arr, i) {
  69. var _arr = [];
  70. var _n = true;
  71. var _d = false;
  72. var _e = undefined;
  73. try {
  74. for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
  75. _arr.push(_s.value);
  76. if (i && _arr.length === i) break;
  77. }
  78. } catch (err) {
  79. _d = true;
  80. _e = err;
  81. } finally {
  82. try {
  83. if (!_n && _i["return"]) _i["return"]();
  84. } finally {
  85. if (_d) throw _e;
  86. }
  87. }
  88. return _arr;
  89. }
  90. return function (arr, i) {
  91. if (Array.isArray(arr)) {
  92. return arr;
  93. } else if (Symbol.iterator in Object(arr)) {
  94. return sliceIterator(arr, i);
  95. } else {
  96. throw new TypeError("Invalid attempt to destructure non-iterable instance");
  97. }
  98. };
  99. }();
  100. /*
  101. * Tencent is pleased to support the open source community by making vap available.
  102. *
  103. * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  104. *
  105. * Licensed under the MIT License (the "License"); you may not use this file except in
  106. * compliance with the License. You may obtain a copy of the License at
  107. *
  108. * http://opensource.org/licenses/MIT
  109. *
  110. * Unless required by applicable law or agreed to in writing, software distributed under the License is
  111. * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  112. * either express or implied. See the License for the specific language governing permissions and
  113. * limitations under the License.
  114. */
  115. var FrameParser = function () {
  116. function FrameParser(source, headData) {
  117. classCallCheck(this, FrameParser);
  118. this.config = source || {};
  119. this.headData = headData;
  120. this.frame = [];
  121. this.textureMap = {};
  122. }
  123. createClass(FrameParser, [{
  124. key: 'init',
  125. value: function init() {
  126. var _this2 = this;
  127. return Promise.resolve().then(function () {
  128. _this2.initCanvas();
  129. return _this2.parseSrc(_this2.config);
  130. }).then(function () {
  131. _this2.canvas.parentNode.removeChild(_this2.canvas);
  132. _this2.frame = _this2.config.frame || [];
  133. return _this2;
  134. });
  135. }
  136. }, {
  137. key: 'initCanvas',
  138. value: function initCanvas() {
  139. var canvas = document.createElement('canvas');
  140. var ctx = canvas.getContext('2d');
  141. canvas.style.display = 'none';
  142. document.body.appendChild(canvas);
  143. this.ctx = ctx;
  144. this.canvas = canvas;
  145. }
  146. }, {
  147. key: 'loadImg',
  148. value: function loadImg(url) {
  149. return new Promise(function (resolve, reject) {
  150. // console.log('load img:', url)
  151. var img = new Image();
  152. img.crossOrigin = 'anonymous';
  153. img.onload = function () {
  154. resolve(this);
  155. };
  156. img.onerror = function (e) {
  157. console.error('frame 资源加载失败:' + url);
  158. reject(new Error('frame 资源加载失败:' + url));
  159. };
  160. img.src = url;
  161. });
  162. }
  163. }, {
  164. key: 'parseSrc',
  165. value: function parseSrc(dataJson) {
  166. var _this = this;
  167. var src = this.srcData = {};
  168. return Promise.all((dataJson.src || []).map(function (item) {
  169. return Promise.resolve().then(function () {
  170. if (item.srcType === 'txt') {
  171. item.textStr = item.srcTag.replace(/\[(.*)\]/, function ($0, $1) {
  172. return _this.headData[$1];
  173. });
  174. item.img = _this.makeTextImg(item);
  175. } else {
  176. if (item.srcType === 'img') {
  177. item.imgUrl = item.srcTag.replace(/\[(.*)\]/, function ($0, $1) {
  178. return _this.headData[$1];
  179. });
  180. return Promise.resolve().then(function () {
  181. return _this.loadImg(item.imgUrl + '?t=' + Date.now());
  182. }).then(function (_resp) {
  183. item.img = _resp;
  184. }).catch(function (e) {
  185. return Promise.resolve();
  186. });
  187. }
  188. }
  189. }).then(function () {
  190. src[item.srcId] = item;
  191. });
  192. }));
  193. }
  194. /**
  195. * 文字转换图片
  196. * @param {*} param0
  197. */
  198. }, {
  199. key: 'makeTextImg',
  200. value: function makeTextImg(_ref) {
  201. var textStr = _ref.textStr,
  202. w = _ref.w,
  203. h = _ref.h,
  204. color = _ref.color,
  205. style = _ref.style;
  206. var ctx = this.ctx;
  207. ctx.canvas.width = w;
  208. ctx.canvas.height = h;
  209. var fontSize = Math.min(parseInt(w / textStr.length, 10), h - 8); // 需留一定间隙
  210. var font = [fontSize + 'px', 'Arial'];
  211. if (style === 'b') {
  212. font.unshift('bold');
  213. }
  214. ctx.font = font.join(' ');
  215. ctx.textBaseline = 'middle';
  216. ctx.textAlign = 'center';
  217. ctx.fillStyle = color;
  218. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  219. ctx.fillText(textStr, w / 2, h / 2);
  220. // console.log('frame : ' + textStr, ctx.canvas.toDataURL('image/png'))
  221. return ctx.getImageData(0, 0, w, h);
  222. }
  223. }, {
  224. key: 'getFrame',
  225. value: function getFrame(frame) {
  226. return this.frame.find(function (item) {
  227. return item.i === frame;
  228. });
  229. }
  230. }]);
  231. return FrameParser;
  232. }();
  233. /*
  234. * Tencent is pleased to support the open source community by making vap available.
  235. *
  236. * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  237. *
  238. * Licensed under the MIT License (the "License"); you may not use this file except in
  239. * compliance with the License. You may obtain a copy of the License at
  240. *
  241. * http://opensource.org/licenses/MIT
  242. *
  243. * Unless required by applicable law or agreed to in writing, software distributed under the License is
  244. * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  245. * either express or implied. See the License for the specific language governing permissions and
  246. * limitations under the License.
  247. */
  248. function createShader(gl, type, source) {
  249. var shader = gl.createShader(type);
  250. gl.shaderSource(shader, source);
  251. gl.compileShader(shader);
  252. // if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
  253. // console.error(gl.getShaderInfoLog(shader))
  254. // }
  255. return shader;
  256. }
  257. function createProgram(gl, vertexShader, fragmentShader) {
  258. var program = gl.createProgram();
  259. gl.attachShader(program, vertexShader);
  260. gl.attachShader(program, fragmentShader);
  261. gl.linkProgram(program);
  262. // if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
  263. // console.error(gl.getProgramInfoLog(program))
  264. // }
  265. gl.useProgram(program);
  266. return program;
  267. }
  268. function createTexture(gl, index, imgData) {
  269. var texture = gl.createTexture();
  270. var textrueIndex = gl.TEXTURE0 + index;
  271. gl.activeTexture(textrueIndex);
  272. gl.bindTexture(gl.TEXTURE_2D, texture);
  273. // gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true)
  274. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  275. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  276. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  277. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  278. if (imgData) {
  279. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgData);
  280. }
  281. return texture;
  282. }
  283. /*
  284. * Tencent is pleased to support the open source community by making vap available.
  285. *
  286. * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  287. *
  288. * Licensed under the MIT License (the "License"); you may not use this file except in
  289. * compliance with the License. You may obtain a copy of the License at
  290. *
  291. * http://opensource.org/licenses/MIT
  292. *
  293. * Unless required by applicable law or agreed to in writing, software distributed under the License is
  294. * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  295. * either express or implied. See the License for the specific language governing permissions and
  296. * limitations under the License.
  297. */
  298. var VapVideo = function () {
  299. function VapVideo(options) {
  300. classCallCheck(this, VapVideo);
  301. if (!options.container || !options.src) {
  302. return console.warn('[Alpha video]: options container and src cannot be empty!');
  303. }
  304. this.options = Object.assign({
  305. // 视频url
  306. src: '',
  307. // 循环播放
  308. loop: false,
  309. fps: 20,
  310. // 视频宽度
  311. width: 375,
  312. // 视频高度
  313. height: 375,
  314. // 容器
  315. container: null,
  316. config: ''
  317. }, options);
  318. this.fps = 20;
  319. this.requestAnim = this.requestAnimFunc(this.fps);
  320. this.container = this.options.container;
  321. if (!this.options.src || !this.options.config || !this.options.container) {
  322. console.error('参数出错:src(视频地址)、config(配置文件地址)、container(dom容器)');
  323. } else {
  324. // 创建video
  325. this.initVideo();
  326. }
  327. }
  328. createClass(VapVideo, [{
  329. key: 'initVideo',
  330. value: function initVideo() {
  331. var _this = this;
  332. var options = this.options;
  333. // 创建video
  334. var video = this.video = document.createElement('video');
  335. video.crossOrigin = 'anonymous';
  336. video.autoplay = false;
  337. // video.muted = true
  338. // video.volume = 0
  339. video.style.display = 'none';
  340. video.src = options.src;
  341. video.loop = !!options.loop;
  342. // 这里要插在body上,避免container移动带来无法播放的问题
  343. document.body.appendChild(this.video);
  344. // 绑定事件
  345. this.events = {};['playing', 'pause', 'ended', 'error'].forEach(function (item) {
  346. _this.on(item, _this['on' + item].bind(_this));
  347. });
  348. video.load();
  349. }
  350. }, {
  351. key: 'drawFrame',
  352. value: function drawFrame() {
  353. this._drawFrame = this._drawFrame || this.drawFrame.bind(this);
  354. this.animId = this.requestAnim(this._drawFrame);
  355. }
  356. }, {
  357. key: 'play',
  358. value: function play() {
  359. var _this2 = this;
  360. var prom = this.video && this.video.play();
  361. if (prom && prom.then) {
  362. prom.catch(function (e) {
  363. if (!_this2.video) {
  364. return;
  365. }
  366. _this2.video.muted = true;
  367. _this2.video.volume = 0;
  368. _this2.video.play().catch(function (e) {
  369. (_this2.events.error || []).forEach(function (item) {
  370. item(e);
  371. });
  372. });
  373. });
  374. }
  375. }
  376. }, {
  377. key: 'requestAnimFunc',
  378. value: function requestAnimFunc() {
  379. var me = this;
  380. if (window.requestAnimationFrame) {
  381. var index = -1;
  382. return function (cb) {
  383. index++;
  384. return requestAnimationFrame(function () {
  385. if (!(index % (60 / me.fps))) {
  386. return cb();
  387. }
  388. me.animId = me.requestAnim(cb);
  389. });
  390. };
  391. }
  392. return function (cb) {
  393. return setTimeout(cb, 1000 / me.fps);
  394. };
  395. }
  396. }, {
  397. key: 'cancelRequestAnimation',
  398. value: function cancelRequestAnimation() {
  399. if (window.cancelAnimationFrame) {
  400. cancelAnimationFrame(this.animId);
  401. }
  402. clearTimeout(this.animId);
  403. }
  404. }, {
  405. key: 'destroy',
  406. value: function destroy() {
  407. if (this.video) {
  408. this.video.parentNode && this.video.parentNode.removeChild(this.video);
  409. this.video = null;
  410. }
  411. this.cancelRequestAnimation(this.animId);
  412. }
  413. }, {
  414. key: 'clear',
  415. value: function clear() {
  416. this.destroy();
  417. }
  418. }, {
  419. key: 'on',
  420. value: function on(event, callback) {
  421. var cbs = this.events[event] || [];
  422. cbs.push(callback);
  423. this.events[event] = cbs;
  424. this.video.addEventListener(event, callback);
  425. return this;
  426. }
  427. }, {
  428. key: 'onplaying',
  429. value: function onplaying() {
  430. if (!this.firstPlaying) {
  431. this.firstPlaying = true;
  432. this.drawFrame();
  433. }
  434. }
  435. }, {
  436. key: 'onpause',
  437. value: function onpause() {}
  438. }, {
  439. key: 'onended',
  440. value: function onended() {
  441. this.destroy();
  442. }
  443. }, {
  444. key: 'onerror',
  445. value: function onerror(err) {
  446. console.error('[Alpha video]: play error: ', err);
  447. this.destroy();
  448. }
  449. }]);
  450. return VapVideo;
  451. }();
  452. /*
  453. * Tencent is pleased to support the open source community by making vap available.
  454. *
  455. * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  456. *
  457. * Licensed under the MIT License (the "License"); you may not use this file except in
  458. * compliance with the License. You may obtain a copy of the License at
  459. *
  460. * http://opensource.org/licenses/MIT
  461. *
  462. * Unless required by applicable law or agreed to in writing, software distributed under the License is
  463. * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  464. * either express or implied. See the License for the specific language governing permissions and
  465. * limitations under the License.
  466. */
  467. var clearTimer = null;
  468. var instances = {};
  469. var PER_SIZE = 9;
  470. function computeCoord(x, y, w, h, vw, vh) {
  471. // leftX rightX bottomY topY
  472. return [x / vw, (x + w) / vw, (vh - y - h) / vh, (vh - y) / vh];
  473. }
  474. var WebglRenderVap = function (_VapVideo) {
  475. inherits(WebglRenderVap, _VapVideo);
  476. function WebglRenderVap(options) {
  477. classCallCheck(this, WebglRenderVap);
  478. var _this = possibleConstructorReturn(this, (WebglRenderVap.__proto__ || Object.getPrototypeOf(WebglRenderVap)).call(this, options));
  479. _this.insType = _this.options.type;
  480. if (instances[_this.insType]) {
  481. _this.instance = instances[_this.insType];
  482. } else {
  483. _this.instance = instances[_this.insType] = {};
  484. }
  485. _this.textures = [];
  486. _this.buffers = [];
  487. _this.shaders = [];
  488. _this.init();
  489. return _this;
  490. }
  491. createClass(WebglRenderVap, [{
  492. key: 'init',
  493. value: function init() {
  494. var _this3 = this;
  495. return Promise.resolve().then(function () {
  496. _this3.setCanvas();
  497. if (_this3.options.config) {
  498. return Promise.resolve().then(function () {
  499. return new FrameParser(_this3.options.config, _this3.options).init();
  500. }).then(function (_resp) {
  501. _this3.vapFrameParser = _resp;
  502. _this3.resources = _this3.vapFrameParser.srcData;
  503. }).catch(function (e) {
  504. console.error('[Alpha video] parse vap frame error.', e);
  505. });
  506. }
  507. }).then(function () {
  508. _this3.resources = _this3.resources || {};
  509. _this3.initWebGL();
  510. _this3.play();
  511. });
  512. }
  513. }, {
  514. key: 'setCanvas',
  515. value: function setCanvas() {
  516. var canvas = this.instance.canvas;
  517. var _options = this.options,
  518. width = _options.width,
  519. height = _options.height;
  520. if (!canvas) {
  521. canvas = this.instance.canvas = document.createElement('canvas');
  522. }
  523. canvas.width = width;
  524. canvas.height = height;
  525. this.container.appendChild(canvas);
  526. }
  527. }, {
  528. key: 'initWebGL',
  529. value: function initWebGL() {
  530. var canvas = this.instance.canvas;
  531. var _instance = this.instance,
  532. gl = _instance.gl,
  533. vertexShader = _instance.vertexShader,
  534. fragmentShader = _instance.fragmentShader,
  535. program = _instance.program;
  536. if (!canvas) {
  537. return;
  538. }
  539. if (!gl) {
  540. this.instance.gl = gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
  541. gl.enable(gl.BLEND);
  542. gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  543. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
  544. }
  545. if (gl) {
  546. gl.viewport(0, 0, canvas.width, canvas.height);
  547. if (!vertexShader) {
  548. vertexShader = this.instance.vertexShader = this.initVertexShader();
  549. }
  550. if (!fragmentShader) {
  551. fragmentShader = this.instance.fragmentShader = this.initFragmentShader();
  552. }
  553. if (!program) {
  554. program = this.instance.program = createProgram(gl, vertexShader, fragmentShader);
  555. }
  556. this.program = program;
  557. this.initTexture();
  558. this.initVideoTexture();
  559. return gl;
  560. }
  561. }
  562. /**
  563. * 顶点着色器
  564. */
  565. }, {
  566. key: 'initVertexShader',
  567. value: function initVertexShader() {
  568. var gl = this.instance.gl;
  569. return createShader(gl, gl.VERTEX_SHADER, 'attribute vec2 a_position; // \u63A5\u53D7\u9876\u70B9\u5750\u6807\n attribute vec2 a_texCoord; // \u63A5\u53D7\u7EB9\u7406\u5750\u6807\n attribute vec2 a_alpha_texCoord; // \u63A5\u53D7\u7EB9\u7406\u5750\u6807\n varying vec2 v_alpha_texCoord; // \u63A5\u53D7\u7EB9\u7406\u5750\u6807\n varying vec2 v_texcoord; // \u4F20\u9012\u7EB9\u7406\u5750\u6807\u7ED9\u7247\u5143\u7740\u8272\u5668\n void main(void){\n gl_Position = vec4(a_position, 0.0, 1.0); // \u8BBE\u7F6E\u5750\u6807\n v_texcoord = a_texCoord; // \u8BBE\u7F6E\u7EB9\u7406\u5750\u6807\n v_alpha_texCoord = a_alpha_texCoord; // \u8BBE\u7F6E\u7EB9\u7406\u5750\u6807\n }');
  570. }
  571. /**
  572. * 片元着色器
  573. */
  574. }, {
  575. key: 'initFragmentShader',
  576. value: function initFragmentShader() {
  577. var gl = this.instance.gl;
  578. var bgColor = 'vec4(texture2D(u_image_video, v_texcoord).rgb, texture2D(u_image_video,v_alpha_texCoord).r);';
  579. var textureSize = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) - 1;
  580. // const textureSize =0
  581. var sourceTexure = '';
  582. var sourceUniform = '';
  583. if (textureSize > 0) {
  584. var imgColor = [];
  585. for (var i = 0; i < textureSize; i++) {
  586. imgColor.push('if(ndx == ' + i + '){\n color = texture2D(textures[' + i + '],uv);\n }');
  587. }
  588. sourceUniform = '\n uniform sampler2D u_image[' + textureSize + '];\n uniform float image_pos[' + textureSize * PER_SIZE + '];\n vec4 getSampleFromArray(sampler2D textures[' + textureSize + '], int ndx, vec2 uv) {\n vec4 color;\n ' + imgColor.join(' else ') + '\n return color;\n }\n ';
  589. sourceTexure = '\n vec4 srcColor,maskColor;\n vec2 srcTexcoord,maskTexcoord;\n int srcIndex;\n float x1,x2,y1,y2,mx1,mx2,my1,my2; //\u663E\u793A\u7684\u533A\u57DF\n\n for(int i=0;i<' + textureSize * PER_SIZE + ';i+= ' + PER_SIZE + '){\n if ((int(image_pos[i]) > 0)) {\n srcIndex = int(image_pos[i]);\n \n x1 = image_pos[i+1];\n x2 = image_pos[i+2];\n y1 = image_pos[i+3];\n y2 = image_pos[i+4];\n \n mx1 = image_pos[i+5];\n mx2 = image_pos[i+6];\n my1 = image_pos[i+7];\n my2 = image_pos[i+8];\n \n \n if (v_texcoord.s>x1 && v_texcoord.s<x2 && v_texcoord.t>y1 && v_texcoord.t<y2) {\n srcTexcoord = vec2((v_texcoord.s-x1)/(x2-x1),(v_texcoord.t-y1)/(y2-y1));\n maskTexcoord = vec2(mx1+srcTexcoord.s*(mx2-mx1),my1+srcTexcoord.t*(my2-my1));\n srcColor = getSampleFromArray(u_image,srcIndex,srcTexcoord);\n maskColor = texture2D(u_image_video, maskTexcoord);\n srcColor.a = srcColor.a*(maskColor.r);\n \n bgColor = vec4(srcColor.rgb*srcColor.a,srcColor.a) + (1.0-srcColor.a)*bgColor;\n \n } \n }\n }\n ';
  590. }
  591. var fragmentSharder = '\n precision lowp float;\n varying vec2 v_texcoord;\n varying vec2 v_alpha_texCoord;\n uniform sampler2D u_image_video;\n ' + sourceUniform + '\n \n void main(void) {\n vec4 bgColor = ' + bgColor + '\n ' + sourceTexure + '\n // bgColor = texture2D(u_image[0], v_texcoord);\n gl_FragColor = bgColor;\n }\n ';
  592. return createShader(gl, gl.FRAGMENT_SHADER, fragmentSharder);
  593. }
  594. }, {
  595. key: 'initTexture',
  596. value: function initTexture() {
  597. var gl = this.instance.gl;
  598. var i = 1;
  599. if (!this.vapFrameParser || !this.vapFrameParser.srcData) {
  600. return;
  601. }
  602. var resources = this.vapFrameParser.srcData;
  603. for (var key in resources) {
  604. var resource = resources[key];
  605. this.textures.push(createTexture(gl, i, resource.img));
  606. var _sampler = gl.getUniformLocation(this.program, 'u_image[' + i + ']');
  607. gl.uniform1i(_sampler, i);
  608. this.vapFrameParser.textureMap[resource.srcId] = i++;
  609. }
  610. this.videoTexture = createTexture(gl, i);
  611. var sampler = gl.getUniformLocation(this.program, 'u_image_video');
  612. gl.uniform1i(sampler, i);
  613. }
  614. }, {
  615. key: 'initVideoTexture',
  616. value: function initVideoTexture() {
  617. var gl = this.instance.gl;
  618. var vertexBuffer = gl.createBuffer();
  619. this.buffers.push(vertexBuffer);
  620. if (!this.vapFrameParser || !this.vapFrameParser.config || !this.vapFrameParser.config.info) {
  621. return;
  622. }
  623. var info = this.vapFrameParser.config.info;
  624. var ver = [];
  625. var vW = info.videoW,
  626. vH = info.videoH;
  627. var _info$rgbFrame = slicedToArray(info.rgbFrame, 4),
  628. rgbX = _info$rgbFrame[0],
  629. rgbY = _info$rgbFrame[1],
  630. rgbW = _info$rgbFrame[2],
  631. rgbH = _info$rgbFrame[3];
  632. var _info$aFrame = slicedToArray(info.aFrame, 4),
  633. aX = _info$aFrame[0],
  634. aY = _info$aFrame[1],
  635. aW = _info$aFrame[2],
  636. aH = _info$aFrame[3];
  637. var rgbCoord = computeCoord(rgbX, rgbY, rgbW, rgbH, vW, vH);
  638. var aCoord = computeCoord(aX, aY, aW, aH, vW, vH);
  639. ver.push.apply(ver, [-1, 1, rgbCoord[0], rgbCoord[3], aCoord[0], aCoord[3]]);
  640. ver.push.apply(ver, [1, 1, rgbCoord[1], rgbCoord[3], aCoord[1], aCoord[3]]);
  641. ver.push.apply(ver, [-1, -1, rgbCoord[0], rgbCoord[2], aCoord[0], aCoord[2]]);
  642. ver.push.apply(ver, [1, -1, rgbCoord[1], rgbCoord[2], aCoord[1], aCoord[2]]);
  643. var view = new Float32Array(ver);
  644. gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  645. gl.bufferData(gl.ARRAY_BUFFER, view, gl.STATIC_DRAW);
  646. this.aPosition = gl.getAttribLocation(this.program, 'a_position');
  647. gl.enableVertexAttribArray(this.aPosition);
  648. this.aTexCoord = gl.getAttribLocation(this.program, 'a_texCoord');
  649. gl.enableVertexAttribArray(this.aTexCoord);
  650. this.aAlphaTexCoord = gl.getAttribLocation(this.program, 'a_alpha_texCoord');
  651. gl.enableVertexAttribArray(this.aAlphaTexCoord);
  652. // 将缓冲区对象分配给a_position变量、a_texCoord变量
  653. var size = view.BYTES_PER_ELEMENT;
  654. gl.vertexAttribPointer(this.aPosition, 2, gl.FLOAT, false, size * 6, 0); // 顶点着色器位置
  655. gl.vertexAttribPointer(this.aTexCoord, 2, gl.FLOAT, false, size * 6, size * 2); // rgb像素位置
  656. gl.vertexAttribPointer(this.aAlphaTexCoord, 2, gl.FLOAT, false, size * 6, size * 4); // rgb像素位置
  657. }
  658. }, {
  659. key: 'drawFrame',
  660. value: function drawFrame() {
  661. var _this2 = this;
  662. var gl = this.instance.gl;
  663. if (!gl) {
  664. get(WebglRenderVap.prototype.__proto__ || Object.getPrototypeOf(WebglRenderVap.prototype), 'drawFrame', this).call(this);
  665. return;
  666. }
  667. gl.clear(gl.COLOR_BUFFER_BIT);
  668. if (this.vapFrameParser) {
  669. var frame = Math.floor(this.video.currentTime * this.options.fps);
  670. var frameData = this.vapFrameParser.getFrame(frame);
  671. var posArr = [];
  672. if (frameData && frameData.obj) {
  673. frameData.obj.forEach(function (frame, index) {
  674. posArr[posArr.length] = +_this2.vapFrameParser.textureMap[frame.srcId];
  675. var info = _this2.vapFrameParser.config.info;
  676. var vW = info.videoW,
  677. vH = info.videoH;
  678. var _frame$frame = slicedToArray(frame.frame, 4),
  679. x = _frame$frame[0],
  680. y = _frame$frame[1],
  681. w = _frame$frame[2],
  682. h = _frame$frame[3];
  683. var _frame$mFrame = slicedToArray(frame.mFrame, 4),
  684. mX = _frame$mFrame[0],
  685. mY = _frame$mFrame[1],
  686. mW = _frame$mFrame[2],
  687. mH = _frame$mFrame[3];
  688. var coord = computeCoord(x, y, w, h, vW, vH);
  689. var mCoord = computeCoord(mX, mY, mW, mH, vW, vH);
  690. posArr = posArr.concat(coord).concat(mCoord);
  691. });
  692. }
  693. //
  694. var size = (gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) - 1) * PER_SIZE;
  695. posArr = posArr.concat(new Array(size - posArr.length).fill(0));
  696. this._imagePos = this._imagePos || gl.getUniformLocation(this.program, 'image_pos');
  697. gl.uniform1fv(this._imagePos, new Float32Array(posArr));
  698. }
  699. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, this.video); // 指定二维纹理方式
  700. gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  701. get(WebglRenderVap.prototype.__proto__ || Object.getPrototypeOf(WebglRenderVap.prototype), 'drawFrame', this).call(this);
  702. }
  703. }, {
  704. key: 'destroy',
  705. value: function destroy() {
  706. var canvas = this.instance.canvas;
  707. if (canvas) {
  708. canvas.parentNode && canvas.parentNode.removeChild(canvas);
  709. }
  710. // glUtil.cleanWebGL(gl, this.shaders, this.program, this.textures, this.buffers)
  711. get(WebglRenderVap.prototype.__proto__ || Object.getPrototypeOf(WebglRenderVap.prototype), 'destroy', this).call(this);
  712. this.clearMemoryCache();
  713. }
  714. }, {
  715. key: 'clearMemoryCache',
  716. value: function clearMemoryCache() {
  717. if (clearTimer) {
  718. clearTimeout(clearTimer);
  719. }
  720. clearTimer = setTimeout(function () {
  721. instances = {};
  722. }, 30 * 60 * 1000);
  723. }
  724. }]);
  725. return WebglRenderVap;
  726. }(VapVideo);
  727. /*
  728. * Tencent is pleased to support the open source community by making vap available.
  729. *
  730. * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  731. *
  732. * Licensed under the MIT License (the "License"); you may not use this file except in
  733. * compliance with the License. You may obtain a copy of the License at
  734. *
  735. * http://opensource.org/licenses/MIT
  736. *
  737. * Unless required by applicable law or agreed to in writing, software distributed under the License is
  738. * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  739. * either express or implied. See the License for the specific language governing permissions and
  740. * limitations under the License.
  741. */
  742. var isCanWebGL = void 0;
  743. /**
  744. * @param options
  745. * @constructor
  746. * @return {null}
  747. */
  748. function index (options) {
  749. if (canWebGL()) {
  750. return new WebglRenderVap(Object.assign({}, options));
  751. } else {
  752. throw new Error('your browser not support webgl');
  753. }
  754. }
  755. function canWebGL() {
  756. if (typeof isCanWebGL !== 'undefined') {
  757. return isCanWebGL;
  758. }
  759. try {
  760. if (!window.WebGLRenderingContext) {
  761. return false;
  762. }
  763. var canvas = document.createElement('canvas');
  764. var context = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
  765. isCanWebGL = !!context;
  766. context = null;
  767. } catch (err) {
  768. isCanWebGL = false;
  769. }
  770. return isCanWebGL;
  771. }
  772. return index;
  773. })));