tengine.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. // Experimental
  2. const tengine = {};
  3. tengine.ModelFactory = class {
  4. async match(context) {
  5. const reader = tengine.Reader.open(context);
  6. if (reader) {
  7. return context.set('tengine', reader);
  8. }
  9. return null;
  10. }
  11. async open(context) {
  12. const metadata = await tengine.Metadata.open(context);
  13. const reader = context.value;
  14. await reader.read();
  15. return new tengine.Model(metadata, reader);
  16. }
  17. };
  18. tengine.Model = class {
  19. constructor(metadata, reader) {
  20. this.format = `Tengine v${reader.version}`;
  21. this.source = reader.source;
  22. this.modules = reader.graphs.map((graph) => new tengine.Graph(metadata, graph));
  23. }
  24. };
  25. tengine.Graph = class {
  26. constructor(metadata, graph) {
  27. this.name = graph.id.toString();
  28. this.inputs = [];
  29. this.outputs = [];
  30. this.nodes = [];
  31. const tensors = graph.tensors.map((tensor) => new tengine.Value(tensor));
  32. for (const input of graph.inputs) {
  33. const node = graph.nodes[input];
  34. this.inputs.push(new tengine.Argument(node.name, node.outputs.map((output) => tensors[output])));
  35. }
  36. for (const output of graph.outputs) {
  37. const node = graph.nodes[output];
  38. this.outputs.push(new tengine.Argument(node.name, node.outputs.map((output) => tensors[output])));
  39. }
  40. for (const node of graph.nodes) {
  41. switch (node.type) {
  42. case 'INPUT':
  43. case 'Const':
  44. break;
  45. default:
  46. this.nodes.push(new tengine.Node(metadata, node, tensors));
  47. break;
  48. }
  49. }
  50. }
  51. };
  52. tengine.Argument = class {
  53. constructor(name, value, type = null, visible = true) {
  54. this.name = name;
  55. this.value = value;
  56. this.type = type;
  57. this.visible = visible;
  58. }
  59. };
  60. tengine.Value = class {
  61. constructor(tensor) {
  62. this.name = tensor.name;
  63. this.type = new tengine.TensorType(tensor.dataType, new tengine.TensorShape(tensor.dims));
  64. this.initializer = (tensor.type === 2) ? new tengine.Tensor(this.type, tensor.buffer) : null;
  65. }
  66. };
  67. tengine.Node = class {
  68. constructor(metadata, node, tensors) {
  69. this.name = node.name;
  70. const type = node.type;
  71. const version = node.version;
  72. this.inputs = [];
  73. this.outputs = [];
  74. this.attributes = [];
  75. this.type = metadata.type(type, version) || { name: type };
  76. for (let i = 0; i < node.params.length; i++) {
  77. const metadata = (this.type && this.type.attributes && i < this.type.attributes.length) ? this.type.attributes[i] : null;
  78. const value = node.params[i];
  79. let name = metadata ? metadata.name : i.toString();
  80. let type = null;
  81. let visible = true;
  82. if (metadata) {
  83. name = !name && metadata.name ? metadata.name : name;
  84. type = !type && metadata.type ? metadata.type : type;
  85. if (metadata.visible === false) {
  86. visible = false;
  87. } else if (metadata.default !== undefined) {
  88. if (value === metadata.default || (value && value.toString() === metadata.default.toString())) {
  89. visible = false;
  90. }
  91. }
  92. }
  93. const attribute = new tengine.Argument(name, value, type, visible);
  94. this.attributes.push(attribute);
  95. }
  96. const inputs = node.inputs;
  97. let inputIndex = 0;
  98. if (this.type && this.type.inputs) {
  99. for (const inputDef of this.type.inputs) {
  100. if (inputIndex < inputs.length || inputDef.option !== 'optional') {
  101. const inputCount = (inputDef.option === 'variadic') ? (inputs.length - inputIndex) : 1;
  102. const inputArguments = inputs.slice(inputIndex, inputIndex + inputCount).filter((id) => id !== '' || inputDef.option !== 'optional').map((id) => tensors[id]);
  103. this.inputs.push(new tengine.Argument(inputDef.name, inputArguments));
  104. inputIndex += inputCount;
  105. }
  106. }
  107. } else {
  108. this.inputs.push(...inputs.slice(inputIndex).map((id, index) => {
  109. const inputName = ((inputIndex + index) === 0) ? 'input' : (inputIndex + index).toString();
  110. return new tengine.Argument(inputName, [tensors[id]]);
  111. }));
  112. }
  113. const outputs = node.outputs;
  114. let outputIndex = 0;
  115. if (this.type && this.type.outputs) {
  116. for (const outputDef of this.type.outputs) {
  117. if (outputIndex < outputs.length || outputDef.option !== 'optional') {
  118. const outputCount = (outputDef.option === 'variadic') ? (outputs.length - outputIndex) : 1;
  119. const outputArguments = outputs.slice(outputIndex, outputIndex + outputCount).map((id) => tensors[id]);
  120. this.outputs.push(new tengine.Argument(outputDef.name, outputArguments));
  121. outputIndex += outputCount;
  122. }
  123. }
  124. } else {
  125. this.outputs.push(...outputs.slice(outputIndex).map((id, index) => {
  126. const outputName = ((outputIndex + index) === 0) ? 'output' : (outputIndex + index).toString();
  127. return new tengine.Argument(outputName, [tensors[id]]);
  128. }));
  129. }
  130. }
  131. };
  132. tengine.Tensor = class {
  133. constructor(type, values) {
  134. this.type = type;
  135. this.values = values;
  136. }
  137. };
  138. tengine.TensorType = class {
  139. constructor(dataType, shape) {
  140. switch (dataType) {
  141. case 0: this.dataType = 'float32'; break;
  142. case 1: this.dataType = 'float16'; break;
  143. case 2: this.dataType = 'int8'; break;
  144. case 3: this.dataType = 'uint8'; break;
  145. case 4: this.dataType = 'int32'; break;
  146. case 5: this.dataType = 'int16'; break;
  147. default: throw new tengine.Error(`Unsupported data type '${dataType}'.`);
  148. }
  149. this.shape = shape;
  150. }
  151. toString() {
  152. return this.dataType + this.shape.toString();
  153. }
  154. };
  155. tengine.TensorShape = class {
  156. constructor(dimensions) {
  157. this.dimensions = dimensions;
  158. }
  159. toString() {
  160. return this.dimensions ? (`[${this.dimensions.map((dimension) => dimension ? dimension.toString() : '?').join(',')}]`) : '';
  161. }
  162. };
  163. tengine.Metadata = class {
  164. static async open(context) {
  165. if (!tengine.Metadata._metadata) {
  166. let data = null;
  167. try {
  168. data = await context.request('tengine-metadata.json');
  169. } catch {
  170. // continue regardless of error
  171. }
  172. tengine.Metadata._metadata = new tengine.Metadata(data);
  173. }
  174. return tengine.Metadata._metadata;
  175. }
  176. constructor(data) {
  177. this._map = new Map();
  178. if (data) {
  179. const metadata = JSON.parse(data);
  180. for (const item of metadata) {
  181. if (item.name) {
  182. const version = item.version || 0;
  183. const name = `${item.name}:${version}`;
  184. this._map.set(name, item);
  185. }
  186. }
  187. }
  188. }
  189. type(name, version) {
  190. let current = version;
  191. while (current > 0) {
  192. if (this._map.has(`${name}:${current}`)) {
  193. break;
  194. }
  195. current--;
  196. }
  197. if (current >= 0) {
  198. const schema = this._map.get(`${name}:${current}`);
  199. if (current !== version) {
  200. this._map.set(`${name}:${version}`, schema);
  201. }
  202. return schema;
  203. }
  204. return null;
  205. }
  206. };
  207. tengine.Reader = class {
  208. static open(context) {
  209. const stream = context.stream;
  210. if (stream && stream.length > 12) {
  211. const buffer = stream.peek(4);
  212. if (buffer[0] < 4 && buffer[1] === 0 && buffer[3] === 0) {
  213. return new tengine.Reader(context);
  214. }
  215. }
  216. return null;
  217. }
  218. constructor(context) {
  219. this.context = context;
  220. // https://github.com/OAID/Tengine/wiki/The-format-of-tmfile
  221. // https://github.com/OAID/Tengine/blob/tengine-lite/source/serializer/tmfile/tm2_format.h
  222. }
  223. async read() {
  224. const types = new Map();
  225. const register = (index, version, name, params) => {
  226. types.set(`${index}:${version}`, { name, params });
  227. };
  228. const operator = (index, version) => {
  229. let current = version;
  230. while (current >= 0) {
  231. if (types.has(`${index}:${current}`)) {
  232. break;
  233. }
  234. current--;
  235. }
  236. if (current >= 0) {
  237. const schema = types.get(`${index}:${current}`);
  238. if (current !== version) {
  239. types.set(`${index}:${version}`, schema);
  240. }
  241. return schema;
  242. }
  243. return null;
  244. };
  245. register(0, 0, 'Accuracy', []);
  246. register(1, 0, 'BatchNormalization', ['f', 'f', 'i']);
  247. register(2, 0, 'BilinearResize', ['f', 'f', 'i']);
  248. register(3, 0, 'Concat', ['i']);
  249. register(4, 0, 'Const', []);
  250. register(5, 0, 'Convolution', ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i']);
  251. register(6, 0, 'Deconvolution', ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i']);
  252. register(7, 0, 'DetectionOutput', ['i', 'i', 'i', 'f', 'f']);
  253. register(8, 0, 'DropOut', []);
  254. register(9, 0, 'Eltwise', ['i', 'i']);
  255. register(10, 0, 'Flatten', ['i']);
  256. register(11, 0, 'FullyConnected', ['i']);
  257. register(12, 0, 'INPUT', []);
  258. register(13, 0, 'LRN', ['i', 'f', 'f', 'i', 'f']);
  259. register(14, 0, 'Normalize', ['i', 'i']);
  260. register(15, 0, 'Permute', ['i', 'i', 'i', 'i', 'i']);
  261. register(16, 0, 'Pooling', ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i']);
  262. register(17, 0, 'Prelu', []);
  263. register(18, 0, 'PriorBox', ['f[]', 'f[]', 'f[]', 'f[]', 'i', 'i', 'i', 'i', 'i', 'f', 'f', 'f', 'i', 'i']);
  264. register(19, 0, 'Region', ['i', 'i', 'i', 'i', 'f', 'f', 'f[]']);
  265. register(20, 0, 'ReLU', ['f']);
  266. register(21, 0, 'ReLU6', []);
  267. register(22, 0, 'Reorg', ['i']);
  268. register(23, 0, 'Reshape', ['i', 'i', 'i', 'i', 'i', 'i']);
  269. // register(23, 0, 'Reshape', [ 'i', 'i', 'i[]' ]);
  270. register(24, 0, 'RoiPooling', ['i', 'i', 'f']);
  271. register(25, 0, 'RPN', ['f[]', 'f[]', 'i', 'i', 'i', 'i', 'i', 'f', 'anchors']);
  272. register(26, 0, 'Scale', ['i', 'i', 'i']);
  273. register(27, 0, 'Slice', ['i', 'i[]', 'i[]', 'i[]', 'i', 'i', 'i', 'i', 'i']);
  274. register(28, 0, 'SoftMax', ['i']);
  275. register(29, 0, 'Split', ['i', 'i', 'boolean', 'boolean', 'i[]']);
  276. register(30, 0, 'DetectionPostProcess', ['i', 'i', 'f', 'f', 'i', 'f[]']);
  277. register(31, 0, 'Gemm', ['f', 'f', 'i', 'i']);
  278. register(32, 0, 'Generic', ['i', 'i', 'string']);
  279. register(33, 0, 'Logistic', []);
  280. register(34, 0, 'LSTM', ['f', 'f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i']);
  281. register(35, 0, 'RNN', ['f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i']);
  282. register(36, 0, 'TanH', []);
  283. register(37, 0, 'Sigmoid', []);
  284. register(38, 0, 'Squeeze', ['i', 'i', 'i', 'i']);
  285. register(39, 0, 'FusedbnScaleRelu', []);
  286. register(40, 0, 'Pad', ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'f']);
  287. register(41, 0, 'StridedSlice', ['i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i']);
  288. register(42, 0, 'ArgMax', ['i']);
  289. register(43, 0, 'ArgMin', ['i']);
  290. register(44, 0, 'TopKV2', ['i', 'i']);
  291. register(45, 0, 'Reduction', ['i', 'i', 'i', 'i', 'i', 'i']);
  292. register(46, 0, 'Max', []);
  293. register(47, 0, 'Min', []);
  294. register(48, 0, 'GRU', ['f', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i', 'i']);
  295. register(49, 0, 'Addn', 'i');
  296. register(50, 0, 'SwapAxis', ['i', 'i']);
  297. register(51, 0, 'Upsample', ['f']);
  298. register(52, 0, 'SpaceToBatchND', ['i', 'i', 'i', 'i', 'i', 'i']);
  299. register(53, 0, 'BatchToSpaceND', ['i', 'i', 'i', 'i', 'i', 'i']);
  300. register(54, 0, 'Resize', ['f', 'f', 'i']);
  301. register(55, 0, 'ShuffleChannel', ['i']);
  302. register(56, 0, 'Crop', ['i', 'i', 'i', 'i', 'i', 'i', 'boolean', 'i', 'i']);
  303. register(57, 0, 'ROIAlign', ['i', 'i', 'f']);
  304. register(58, 0, 'Psroipooling', ['i', 'i', 'f', 'i']);
  305. register(59, 0, 'Unary', ['i']);
  306. register(60, 0, 'Expanddims', ['i']);
  307. register(61, 0, 'Bias', ['i']);
  308. register(62, 0, 'Noop', []);
  309. register(63, 0, 'Threshold', ['f']);
  310. register(64, 0, 'Hardsigmoid', ['f', 'f']);
  311. register(65, 0, 'Embed', ['f', 'f', 'f', 'f']);
  312. register(66, 0, 'InstanceNorm', ['f']);
  313. register(67, 0, 'MVN', ['i', 'i', 'f']);
  314. register(68, 0, 'Absval', []);
  315. register(69, 0, 'Cast', ['i', 'i']);
  316. register(70, 0, 'HardSwish', ['f', 'f']);
  317. register(71, 0, 'Interp', ['i', 'f', 'f', 'i', 'i']);
  318. register(72, 0, 'SELU', ['f', 'f']);
  319. register(73, 0, 'ELU', ['f']);
  320. register(74, 0, 'BroadMul', []);
  321. register(75, 0, 'Logical', ['i']);
  322. register(76, 0, 'Gather', ['i', 'i']);
  323. register(77, 0, 'Transpose', ['i[]']);
  324. register(78, 0, 'Comparison', ['i']);
  325. register(79, 0, 'SpaceToDepth', ['i']);
  326. register(80, 0, 'DepthToSpace', ['i']);
  327. register(81, 0, 'Reverse', []);
  328. register(82, 0, 'SparseToDense', ['i','i','i']);
  329. register(83, 0, 'Ceil', []);
  330. register(84, 0, 'SquaredDifference', []);
  331. register(85, 0, 'Round', []);
  332. register(86, 0, 'ZerosLike', []);
  333. register(87, 0, 'Clip', ['f','f']);
  334. register(88, 0, 'Unsqueeze', ['i[]']);
  335. register(89, 0, 'ReduceL2', ['i','i']);
  336. register(90, 0, 'Mean', []);
  337. register(91, 0, 'MatMul', []);
  338. register(92, 0, 'Expand', ['i[]']);
  339. register(93, 0, 'Scatter', ['i','boolean']);
  340. register(94, 0, 'Shape', []);
  341. register(95, 0, 'Where', []);
  342. register(96, 0, 'Tile', ['i','i']);
  343. register(97, 0, 'Mish', []);
  344. register(98, 0, 'L2Pool', []);
  345. register(99, 0, 'LogSoftmax', []);
  346. register(100, 0, 'ReLU1', []);
  347. register(101, 0, 'L2Normalization', []);
  348. register(102, 0, 'PackModel', ['i','i']);
  349. register(103, 0, 'Num', []);
  350. const reader = await tengine.BinaryReader.open(this.context);
  351. const major = reader.uint16();
  352. const minor = reader.uint16();
  353. if (major !== 2) {
  354. throw new tengine.Error(`Unsupported format version 'v${this.version}'.`);
  355. }
  356. this.version = `${major}.${minor}`;
  357. reader.uint16(); // compileVersion
  358. reader.skip(2); // struct align
  359. reader.seek(reader.uint32()); // root table
  360. const originalFormat = reader.int32();
  361. const subFormat = reader.int32();
  362. const sources = [
  363. '', 'Tengine', 'Caffe', 'ONNX',
  364. 'MXNet', 'TensorFlow', 'TensorFlow Lite', 'Darknet',
  365. `DLA v${subFormat}`, 'ncnn', 'MegEngine', 'OneFlow',
  366. 'Horizon', 'Bitman'
  367. ];
  368. if (originalFormat >= sources.length) {
  369. throw new tengine.Error(`Unsupported source '${originalFormat}'.`);
  370. }
  371. this.source = sources[originalFormat];
  372. this.graphs = [];
  373. const subgraphOffsets = reader.uint32s();
  374. for (const subgraphOffset of subgraphOffsets) {
  375. reader.seek(subgraphOffset);
  376. const subgraph = {};
  377. subgraph.id = reader.int32();
  378. subgraph.graphLayout = reader.int32();
  379. /*
  380. if (graphLayout === 0) {
  381. return "NCHW";
  382. }
  383. if (graphLayout === 1) {
  384. return "NHWC";
  385. }
  386. */
  387. subgraph.originalLayout = reader.int32();
  388. subgraph.inputs = reader.uint32s();
  389. subgraph.outputs = reader.uint32s();
  390. const nodeOffsets = reader.uint32s();
  391. const tensorOffsets = reader.uint32s();
  392. const bufferOffsets = reader.uint32s();
  393. subgraph.name = reader.string();
  394. subgraph.nodes = [];
  395. subgraph.tensors = [];
  396. this.graphs.push(subgraph);
  397. // nodes
  398. for (const nodeOffset of nodeOffsets) {
  399. reader.seek(nodeOffset);
  400. const node = {};
  401. node.id = reader.int32();
  402. node.inputs = reader.uint32s();
  403. node.outputs = reader.uint32s();
  404. const typeOffset = reader.int32();
  405. node.name = reader.string();
  406. const attributeOffsets = reader.uint32s();
  407. node.dynamicShape = reader.boolean();
  408. reader.seek(typeOffset);
  409. node.version = reader.int32();
  410. const index = reader.int32();
  411. const paramsOffset = reader.uint32();
  412. const schema = operator(index, node.version);
  413. node.type = schema ? schema.name : index.toString();
  414. const paramTypes = schema ? schema.params : [];
  415. node.params = [];
  416. if (paramsOffset) {
  417. reader.seek(paramsOffset);
  418. for (const paramType of paramTypes) {
  419. if (paramType !== 'boolean') {
  420. reader.align(4);
  421. }
  422. switch (paramType) {
  423. case 'i':
  424. node.params.push(reader.int32());
  425. break;
  426. case 'f':
  427. node.params.push(reader.float32());
  428. break;
  429. case 'i[]':
  430. node.params.push(reader.int32s());
  431. break;
  432. case 'f[]':
  433. node.params.push(reader.float32s());
  434. break;
  435. case 'boolean':
  436. node.params.push(reader.boolean());
  437. break;
  438. case 'string':
  439. node.params.push(reader.string());
  440. break;
  441. case 'anchors':
  442. node.params.push(reader.anchors(4));
  443. break;
  444. default:
  445. throw new tengine.Error(`Unsupported param type '${paramType}' in '${node.type}'.`);
  446. }
  447. }
  448. }
  449. if (node.type === 'Slice') {
  450. node.params[6] = (originalFormat === 5) ? node.params[6] : 0;
  451. }
  452. node.attributes = attributeOffsets.map((attributeOffset) => {
  453. reader.seek(attributeOffset);
  454. const name = reader.string();
  455. const value = reader.string();
  456. const type = reader.int32();
  457. return { name, value, type };
  458. });
  459. subgraph.nodes.push(node);
  460. }
  461. // buffers
  462. const buffers = bufferOffsets.map((bufferOffset) => {
  463. reader.seek(bufferOffset);
  464. const size = reader.uint32();
  465. const offset = reader.int32();
  466. if (offset !== 0) {
  467. reader.seek(offset);
  468. return reader.read(size);
  469. }
  470. return null;
  471. });
  472. // tensors
  473. subgraph.tensors = tensorOffsets.map((tensorOffset) => {
  474. reader.seek(tensorOffset);
  475. const tensor = {};
  476. tensor.id = reader.int32();
  477. tensor.buffer = buffers[reader.int32()];
  478. tensor.dims = reader.int32s();
  479. tensor.name = reader.string();
  480. const quantparamsOffset = reader.int32();
  481. tensor.layout = reader.int32();
  482. tensor.type = reader.int32(); // ar = 1, const = 2, input = 3, vdep, unknown
  483. tensor.dataType = reader.int32();
  484. if (quantparamsOffset) {
  485. reader.seek(quantparamsOffset);
  486. tensor.quantparams = {
  487. zeroPoint: reader.int32(),
  488. scale: reader.float32(),
  489. width: reader.int32()
  490. };
  491. }
  492. return tensor;
  493. });
  494. for (const node of subgraph.nodes) {
  495. if (node.type === 'Convolution') {
  496. switch (subgraph.graphLayout) {
  497. case 0: // NCHW
  498. node.params[6] = subgraph.tensors[node.inputs[1]].dims[1];
  499. break;
  500. case 1: // NHWC
  501. node.params[6] = subgraph.tensors[node.inputs[1]].dims[3];
  502. break;
  503. default:
  504. throw new tengine.Error(`Unsupported 'Convolution' layout '${subgraph.graphLayout}'.`);
  505. }
  506. }
  507. }
  508. }
  509. delete this.context;
  510. delete this.stream;
  511. }
  512. };
  513. tengine.BinaryReader = class {
  514. static async open(context) {
  515. const reader = await context.read('binary');
  516. return new tengine.BinaryReader(reader);
  517. }
  518. constructor(reader) {
  519. this._reader = reader;
  520. }
  521. get position() {
  522. return this._reader.position;
  523. }
  524. seek(offset) {
  525. this._reader.seek(offset);
  526. }
  527. skip(offset) {
  528. this._reader.skip(offset);
  529. }
  530. align(mod) {
  531. return this._reader.align(mod);
  532. }
  533. read(length) {
  534. return this._reader.read(length);
  535. }
  536. boolean() {
  537. return this._reader.boolean();
  538. }
  539. byte() {
  540. return this._reader.byte();
  541. }
  542. int32() {
  543. return this._reader.int32();
  544. }
  545. int32s() {
  546. const values = [];
  547. const offset = this.uint32();
  548. if (offset) {
  549. const next = this.position;
  550. this.seek(offset);
  551. const count = this.uint32();
  552. for (let i = 0; i < count; i++) {
  553. values.push(this.int32());
  554. }
  555. this.seek(next);
  556. }
  557. return values;
  558. }
  559. uint16() {
  560. return this._reader.uint16();
  561. }
  562. uint32() {
  563. return this._reader.uint32();
  564. }
  565. uint32s() {
  566. const values = [];
  567. const offset = this.uint32();
  568. if (offset) {
  569. const next = this.position;
  570. this.seek(offset);
  571. const count = this.uint32();
  572. for (let i = 0; i < count; i++) {
  573. values.push(this.uint32());
  574. }
  575. this.seek(next);
  576. }
  577. return values;
  578. }
  579. float32() {
  580. return this._reader.float32();
  581. }
  582. float32s() {
  583. const values = [];
  584. const offset = this.uint32();
  585. if (offset) {
  586. const next = this.position;
  587. this.seek(offset);
  588. const count = this.uint32();
  589. for (let i = 0; i < count; i++) {
  590. values.push(this.float32());
  591. }
  592. this.seek(next);
  593. }
  594. return values;
  595. }
  596. string() {
  597. const position = this.uint32();
  598. let content = '';
  599. if (position) {
  600. const next = this.position;
  601. this.seek(position);
  602. const size = this.uint32();
  603. this.seek(this.uint32());
  604. for (let i = 0; i < size - 1; i++) {
  605. content += String.fromCharCode(this.byte());
  606. }
  607. this.seek(next);
  608. }
  609. return content;
  610. }
  611. anchors(length) {
  612. const arrays = [];
  613. const offset = this.uint32();
  614. if (offset) {
  615. const next = this._position;
  616. this.seek(offset);
  617. const count = this.uint32();
  618. for (let i = 0; i < count; i++) {
  619. const array = [];
  620. for (let j = 0; j < length; j++) {
  621. array.push(this.float32());
  622. }
  623. arrays.push(array);
  624. }
  625. this.seek(next);
  626. }
  627. return arrays;
  628. }
  629. };
  630. tengine.Error = class extends Error {
  631. constructor(message) {
  632. super(message);
  633. this.name = 'Error loading Tengine model.';
  634. }
  635. };
  636. export const ModelFactory = tengine.ModelFactory;