From 2962a838d3b51552838e8c6029a18f82190c2a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Szab=C3=B3?= Date: Fri, 26 Aug 2016 01:42:16 +0200 Subject: [PATCH] Add model version 3 serializer --- src/js/utils/serialization/Serializer.js | 194 +++++++++++++++++++---- 1 file changed, 163 insertions(+), 31 deletions(-) diff --git a/src/js/utils/serialization/Serializer.js b/src/js/utils/serialization/Serializer.js index 9666fa06..1da51327 100644 --- a/src/js/utils/serialization/Serializer.js +++ b/src/js/utils/serialization/Serializer.js @@ -1,40 +1,172 @@ (function () { var ns = $.namespace('pskl.utils'); + /** + ********* + * META * + ********* + * // Piskel + * [0] = model version + * [1] = width + * [2] = height + * [3] = fps + * + * // Descriptor + * [4] = name length + * [5] = description length + * + * // Layers + * [6] = layers count + * [layer data index start] = layer name length + * [layer data index start + 1] = opacity + * [layer data index start + 2] = frame count + * [layer data index start + 3] = base 64 png data url length (upper 16 bits) + * [layer data index start + 4] = base 64 png data url length (lower 16 bits) + * + ********* + * DATA * + ********* + * [7..name length-1] = name + * [name length..description length-1] = description + * [layer data index start + 4..layer name length-1] = layer name + * [layer name length..base 64 png data url length-1] = base 64 png data url + * + * + */ + ns.Serializer = { - serializePiskel : function (piskel, expanded) { - var serializedLayers = piskel.getLayers().map(function (l) { - return pskl.utils.Serializer.serializeLayer(l, expanded); - }); - return JSON.stringify({ - modelVersion : Constants.MODEL_VERSION, - piskel : { - name : piskel.getDescriptor().name, - description : piskel.getDescriptor().description, - fps : pskl.app.piskelController.getFPS(), - height : piskel.getHeight(), - width : piskel.getWidth(), - layers : serializedLayers, - expanded : expanded - } - }); + calculateRequiredBytes : function(piskel, framesData) { + var width = piskel.getWidth(); + var height = piskel.getHeight(); + var descriptorNameLength = piskel.getDescriptor().name.length; + var descriptorDescriptionLength = piskel.getDescriptor().description.length; + var layersLength = piskel.getLayers().length; + + var bytes = 0; + + /********/ + /* META */ + /********/ + // Piskel meta + bytes += 4 * 2; + + // Descriptor meta + bytes += 2 * 2; + + // Layers meta + bytes += 1 * 2; + + /********/ + /* DATA */ + /********/ + // Descriptor name + bytes += descriptorNameLength * 2; + + // Descriptor description + bytes += descriptorDescriptionLength * 2; + + // Layers + for (var i = 0, layers = piskel.getLayers(); i < layers.length; i++) { + bytes += 3 * 2; + bytes += layers[i].name.length * 2; + bytes += framesData[i].length; + if (bytes%2 == 1) { + bytes++; + } + } + + return bytes; }, - serializeLayer : function (layer, expanded) { - var frames = layer.getFrames(); - var layerToSerialize = { - name : layer.getName(), - opacity : layer.getOpacity(), - frameCount : frames.length - }; - if (expanded) { - layerToSerialize.grids = frames.map(function (f) {return Array.prototype.slice.call(f.pixels);}); - return layerToSerialize; - } else { - var renderer = new pskl.rendering.FramesheetRenderer(frames); - layerToSerialize.base64PNG = renderer.renderAsCanvas().toDataURL(); - return JSON.stringify(layerToSerialize); + serializePiskel : function (piskel, expanded) { + // Render frames + var framesData = []; + for (var i = 0, layers = piskel.getLayers(); i < layers.length; i++) { + var renderer = new pskl.rendering.FramesheetRenderer(layers[i].getFrames()); + var dataUri = atob(renderer.renderAsCanvas().toDataURL().split(',')[1]); + var dataUriLength = dataUri.length; + framesData.push({uri: dataUri, length: dataUriLength}); } + + var bytes = pskl.utils.Serializer.calculateRequiredBytes(piskel, framesData); + + var buffer = new ArrayBuffer(bytes); + var arr8 = new Uint8Array(buffer); + var arr16 = new Uint16Array(buffer); + var sub; + + var width = piskel.getWidth(); + var height = piskel.getHeight(); + var descriptorName = piskel.getDescriptor().name; + var descriptorNameLength = descriptorName.length; + var descriptorDescription = piskel.getDescriptor().description; + var descriptorDescriptionLength = descriptorDescription.length; + + /********/ + /* META */ + /********/ + // Piskel meta + arr16[0] = Constants.MODEL_VERSION; + arr16[1] = width; + arr16[2] = height; + arr16[3] = pskl.app.piskelController.getFPS(); + + // Descriptor meta + arr16[4] = descriptorNameLength; + arr16[5] = descriptorDescriptionLength; + + // Layers meta + arr16[6] = piskel.getLayers().length; + + /********/ + /* DATA */ + /********/ + // Descriptor name + for (var i = 0; i < descriptorNameLength; i++) { + arr16[7 + i] = descriptorName.charCodeAt(i); + } + + // Descriptor description + for (var i = 0; i < descriptorDescriptionLength; i++) { + arr16[7 + descriptorNameLength + i] = descriptorDescription.charCodeAt(i); + } + + // Layers + var layerStartIndex = 7 + descriptorNameLength + descriptorDescriptionLength; + for (var i = 0, layers = piskel.getLayers(); i < layers.length; i++) { + var layer = layers[i]; + var frames = layer.getFrames(); + + var layerName = layer.getName(); + var layerNameLength = layerName.length; + var opacity = layer.getOpacity(); + var frameCount = frames.length; + + var dataUri = framesData[i].uri + var dataUriLength = framesData[i].length + + // Meta + arr16[layerStartIndex] = layerNameLength; + arr16[layerStartIndex + 1] = Math.floor(opacity * 65535); + arr16[layerStartIndex + 2] = frameCount; + arr16[layerStartIndex + 3] = ((dataUriLength & 0xffff0000) >> 16) >>> 0; // Upper 16 + arr16[layerStartIndex + 4] = ((dataUriLength & 0x0000ffff)) >>> 0; // Lower 16 + + // Name + for (var j = 0; j < layerNameLength; j++) { + arr16[layerStartIndex + 5 + j] = layerName.charCodeAt(j); + } + + // Data URI + for (var j = 0; j < dataUriLength; j++) { + arr8[(layerStartIndex + 5 + layerNameLength) * 2 + j] = dataUri.charCodeAt(j); + } + + layerStartIndex += Math.ceil(5 + layerNameLength + (dataUriLength / 2)); + } + + + return buffer; } - }; + } })();