image sprite partial
diff --git a/extension/CSXS/manifest.xml b/extension/CSXS/manifest.xml
index f5eee37..56a8f2a 100644
--- a/extension/CSXS/manifest.xml
+++ b/extension/CSXS/manifest.xml
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
-<ExtensionManifest Version="5.0" ExtensionBundleId="com.bodymovin.bodymovin" ExtensionBundleVersion="4.0.4"
+<ExtensionManifest Version="6.0" ExtensionBundleId="com.bodymovin.bodymovin" ExtensionBundleVersion="4.0.4"
ExtensionBundleName="bodymovin" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ExtensionList>
<Extension Id="com.bodymovin.bodymovin" Version="4.0.4" />
</ExtensionList>
<ExecutionEnvironment>
<HostList>
- <Host Name="AEFT" Version="[13.0,13.9]" />
- <Host Name="AEFX" Version="[13.0,13.9]" />
+ <Host Name="AEFT" Version="13.0" />
+ <Host Name="AEFX" Version="13.0" />
<!-- Illustrator -->
<!-- <Host Name="ILST" Version="[18.0,18.9]" />-->
@@ -27,7 +27,7 @@
<Locale Code="All" />
</LocaleList>
<RequiredRuntimeList>
- <RequiredRuntime Name="CSXS" Version="5.0" />
+ <RequiredRuntime Name="CSXS" Version="6.0" />
</RequiredRuntimeList>
</ExecutionEnvironment>
<DispatchInfoList>
@@ -36,6 +36,11 @@
<Resources>
<MainPath>./index.html</MainPath>
<ScriptPath>./jsx/hostscript.jsx</ScriptPath>
+ <CEFCommandLine>
+ <Parameter>--enable-nodejs</Parameter>
+ <Parameter>--mixed-context</Parameter>
+ <Parameter>--enable-media-stream</Parameter>
+ </CEFCommandLine>
</Resources>
<Lifecycle>
<AutoVisible>true</AutoVisible>
diff --git a/extension/index.html b/extension/index.html
index c30d05f..00c4af9 100644
--- a/extension/index.html
+++ b/extension/index.html
@@ -186,6 +186,7 @@
<script src="js/controllers/messageController.js"></script>
<script src="js/controllers/InfoController.js"></script>
<script src="js/utils/storage.js"></script>
+ <script src="js/utils/binpacking.js"></script>
<script src="js/controllers/snapshotController.js"></script>
<script src="js/main.js"></script>
diff --git a/extension/js/controllers/CompRenderController.js b/extension/js/controllers/CompRenderController.js
index e7e2cd1..b30e191 100644
--- a/extension/js/controllers/CompRenderController.js
+++ b/extension/js/controllers/CompRenderController.js
@@ -198,6 +198,17 @@
});
}
+ function renderAtlasHandler(ev) {
+ var messageData = ev.data;
+ bm_binpacker.reset();
+ bm_binpacker.addBlocks(messageData.images);
+ var atlasPack = bm_binpacker.getPack();
+ var atlasDataString = JSON.stringify(atlasPack);
+ var eScript = 'bm_renderManager.setAtlasData(' + atlasDataString + ')';
+ csInterface.evalScript(eScript);
+
+ }
+
function renderCharsHandler(ev) {
var messageData = ev.data;
var chars;
@@ -272,6 +283,7 @@
csInterface.addEventListener('bm:render:complete', renderCompleteHandler);
csInterface.addEventListener('bm:render:fonts', renderFontsHandler);
csInterface.addEventListener('bm:render:chars', renderCharsHandler);
+ csInterface.addEventListener('bm:render:atlas', renderAtlasHandler);
cancelButton = view.find('.cancel');
returnButton = view.find('.return');
diff --git a/extension/js/main.js b/extension/js/main.js
index c653953..8e4f766 100644
--- a/extension/js/main.js
+++ b/extension/js/main.js
@@ -8,10 +8,6 @@
var csInterface = new CSInterface();
var mainViews = [];
-
- var gulp = require('gulp');
- var gzip = require('gulp-gzip');
-
function showView(view) {
var i, len = mainViews.length;
for (i = 0; i < len; i += 1) {
diff --git a/extension/js/utils/binpacking.js b/extension/js/utils/binpacking.js
new file mode 100644
index 0000000..3abfcf3
--- /dev/null
+++ b/extension/js/utils/binpacking.js
@@ -0,0 +1,43 @@
+/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
+/*global console, require*/
+
+var bm_binpacker = (function () {
+ 'use strict';
+ var ob = {}, blocks = [], packer, binpacking, GrowingPacker;
+ if (typeof require === 'function') {
+ ob.enabled = true;
+ binpacking = require('binpacking');
+ GrowingPacker = binpacking.GrowingPacker;
+ }
+
+ function addBlocks(blocks) {
+ console.log(blocks);
+ var i, len = blocks.length;
+ for(i = 0; i < len; i += 1) {
+ addBlock(blocks[i]);
+ }
+ }
+
+ function addBlock(block) {
+ blocks.push(block);
+ }
+
+ function getPack() {
+ var packer = new GrowingPacker();
+ blocks.sort(function(a, b) { return (b.h > a.h); });
+ packer.fit(blocks);
+ console.log(blocks);
+ return blocks;
+ }
+
+ function reset() {
+ blocks.length = 0;
+ }
+
+ ob.addBlock = addBlock;
+ ob.addBlocks = addBlocks;
+ ob.reset = reset;
+ ob.getPack = getPack;
+
+ return ob;
+}());
\ No newline at end of file
diff --git a/extension/jsx/renderManager.jsx b/extension/jsx/renderManager.jsx
index e033ba2..aebd618 100644
--- a/extension/jsx/renderManager.jsx
+++ b/extension/jsx/renderManager.jsx
@@ -107,6 +107,7 @@
function reset() {
pendingLayers.length = 0;
pendingComps.length = 0;
+ ob.renderData.exportData.assets.length = 0;
currentCompSettings = null;
}
@@ -215,7 +216,10 @@
saveData();
}
- function imagesReady() {
+ function imagesReady(assetsArray) {
+ if(assetsArray) {
+ ob.renderData.exportData.assets = assetsArray;
+ }
checkFonts();
}
@@ -238,6 +242,7 @@
ob.setChars = setChars;
ob.imagesReady = imagesReady;
ob.setFontData = setFontData;
+ ob.setAtlasData = bm_sourceHelper.setAtlasData;
ob.setCharsData = setCharsData;
ob.hasExpressions = hasExpressions;
diff --git a/extension/jsx/utils/sourceHelper.jsx b/extension/jsx/utils/sourceHelper.jsx
index 3d98203..08193cc 100644
--- a/extension/jsx/utils/sourceHelper.jsx
+++ b/extension/jsx/utils/sourceHelper.jsx
@@ -3,6 +3,7 @@
var bm_sourceHelper = (function () {
'use strict';
var compSources = [], imageSources = [], fonts = [], currentExportingImage, destinationPath, assetsArray, folder, helperComp, currentCompID, imageCount = 0;
+ var ob = {};
function checkCompSource(item) {
var arr = compSources;
@@ -79,6 +80,72 @@
saveNextImage();
}
+ function createAtlas() {
+ var i, len = imageSources.length;
+ var imagesList = [];
+ for (i = 0; i < len; i += 1) {
+ imagesList.push({
+ w: imageSources[i].width + 4,
+ h: imageSources[i].height + 4,
+ id: imageSources[i].id
+ });
+ }
+ bm_eventDispatcher.sendEvent('bm:render:atlas', {images: imagesList});
+ }
+
+ function getSourceDataById(id) {
+ var i = 0, len = imageSources.length;
+ while( i < len) {
+ if(imageSources[i].id === id) {
+ return imageSources[i];
+ }
+ i += 1;
+ }
+ }
+
+ function setAtlasData(blocks) {
+ if (bm_compsManager.cancelled) {
+ return;
+ }
+ var compWidth = 0;
+ var compHeight = 0;
+ var i, len = blocks.length;
+ for (i = 0; i < len; i += 1) {
+ compWidth = Math.max(blocks[i].fit.w + blocks[i].fit.x, compWidth);
+ compHeight = Math.max(blocks[i].fit.h + blocks[i].fit.y, compHeight);
+ }
+ var helperComp = app.project.items.addComp('atlasConverterComp', Math.max(4, compWidth), Math.max(4, compHeight), 1, 1, 1);
+ var source, sourceData, layer;
+ for (i = 0; i < len; i += 1) {
+ sourceData = getSourceDataById(blocks[i].id);
+ source = sourceData.source;
+ layer = helperComp.layers.add(source);
+ layer.transform['Anchor Point'].setValue([0, 0]);
+ layer.transform['Position'].setValue([blocks[i].fit.x + 2, blocks[i].fit.y + 2]);
+ assetsArray.push({
+ id: blocks[i].id,
+ w: blocks[i].w,
+ h: blocks[i].h,
+ x: blocks[i].fit.x + 2,
+ y: blocks[i].fit.y + 2,
+ p: 'images/atlas_' + '0' + '.png'
+ });
+ }
+ bm_eventDispatcher.log('assetsArray len: ' + assetsArray.length);
+ bm_renderManager.imagesReady(assetsArray);
+ var file = new File(folder.absoluteURI + '/atlas_' + '0' + '.png');
+ helperComp.saveFrameToPng(0, file);
+ helperComp.remove();
+ }
+
+ function saveImages() {
+ if (ob.atlas) {
+ createAtlas();
+ } else {
+ saveNextImage();
+ }
+ }
+
function exportImages(path, assets, compId) {
if (imageSources.length === 0) {
bm_renderManager.imagesReady();
@@ -93,12 +160,12 @@
assetsArray = assets;
if (!folder.exists) {
if (folder.create()) {
- saveNextImage();
+ saveImages();
} else {
bm_eventDispatcher.sendEvent('alert', 'folder failed to be created at: ' + folder.fsName);
}
} else {
- saveNextImage();
+ saveImages();
}
}
@@ -127,16 +194,21 @@
imageSources.length = 0;
fonts.length = 0;
imageCount = 0;
+ assetsArray = null;
}
- return {
+ ob = {
checkCompSource: checkCompSource,
checkImageSource: checkImageSource,
setCompSourceId: setCompSourceId,
+ setAtlasData: setAtlasData,
exportImages : exportImages,
addFont : addFont,
getFonts : getFonts,
+ atlas: true,
reset: reset
};
+ return ob;
+
}());
\ No newline at end of file
diff --git a/player/index.html b/player/index.html
index 137879b..26f0c17 100644
--- a/player/index.html
+++ b/player/index.html
@@ -40,6 +40,7 @@
<script src="js/utils/bez.js"></script>
<script src="js/utils/DataManager.js"></script>
<script src="js/utils/FontManager.js"></script>
+ <script src="js/utils/ImageManager.js"></script>
<script src="js/utils/expressions/ExpressionManager.js"></script>
<script src="js/utils/expressions/ExpressionComp.js"></script>
<script src="js/utils/expressions/ShapeInterface.js"></script>
diff --git a/player/js/elements/ImageElement.js b/player/js/elements/ImageElement.js
index 8ffadea..3fd27a3 100644
--- a/player/js/elements/ImageElement.js
+++ b/player/js/elements/ImageElement.js
@@ -10,15 +10,26 @@
var self = this;
var imageLoaded = function(){
- self.innerElem.setAttributeNS('http://www.w3.org/1999/xlink','href',self.path+self.assetData.p);
+ var cv = document.createElement('canvas');
+ cv.width = self.assetData.w;
+ cv.height = self.assetData.h;
+ var ctx = cv.getContext('2d');
+ ctx.drawImage(img,self.assetData.x,self.assetData.y,self.assetData.w,self.assetData.h,0,0,self.assetData.w,self.assetData.h);
+ var dataUri = cv.toDataURL();
+ self.innerElem.setAttributeNS('http://www.w3.org/1999/xlink','href',dataUri);
+ //self.innerElem.setAttributeNS('http://www.w3.org/1999/xlink','href',self.path+self.assetData.p);
self.maskedElement = self.innerElem;
+ ImageManager.unregisterImage(imgLoader);
};
- var img = new Image();
- img.addEventListener('load', imageLoaded, false);
- img.addEventListener('error', imageLoaded, false);
-
- img.src = this.path+this.assetData.p;
+ var imgLoader = ImageManager.getImage(this.path+this.assetData.p);
+ var img = imgLoader.elem;
+ if(imgLoader.loaded) {
+ imageLoaded();
+ } else {
+ img.addEventListener('load', imageLoaded, false);
+ img.addEventListener('error', imageLoaded, false);
+ }
this.parent.createElements.call(this);
diff --git a/player/js/utils/ImageManager.js b/player/js/utils/ImageManager.js
new file mode 100644
index 0000000..12cd903
--- /dev/null
+++ b/player/js/utils/ImageManager.js
@@ -0,0 +1,48 @@
+var ImageManager = (function(){
+
+ var images = [];
+ var ob = {};
+
+ function getImage(path){
+ var i = 0, len = images.length;
+ while(i<len) {
+ if(images[i].path === path){
+ images[i].count += 1;
+ return images[i];
+ }
+ i += 1;
+ }
+
+ function imageLoaded(){
+ imageOb.loaded = true;
+ }
+
+ var img = document.createElement('img');
+ img.addEventListener('load', imageLoaded, false);
+ img.addEventListener('error', imageLoaded, false);
+
+ var imageOb = {
+ elem: img,
+ path: path,
+ loaded: false,
+ count: 1
+ };
+ img.src = path;
+ images.push(imageOb);
+ return imageOb;
+ }
+
+ function unregisterImage(ob){
+ ob.count -= 1;
+ if(ob.count === 0) {
+ var ind = images.indexOf(ob);
+ images.splice(ind, 1);
+ ob.elem = null;
+ }
+ }
+
+ ob.getImage = getImage;
+ ob.unregisterImage = unregisterImage;
+
+ return ob;
+}());
\ No newline at end of file