Browse Source

Sprite Updates

 - Fixed the sprite managers JSON loading now supports JSON string and Standard Objects.
- Introduction of spriteMap to handle grid deployments of spriteAtlas
- Sample spriteMap scene added to playground
- adding resources to the playground to support additional spriteMap samples.
Pryme8 5 years ago
parent
commit
f414374269

+ 648 - 0
Playground/scripts/spriteMap.js

@@ -0,0 +1,648 @@
+var createScene = function () {
+    var scene = new BABYLON.Scene(engine);
+    // Create camera and light
+    var light = new BABYLON.PointLight("Point", new BABYLON.Vector3(5, 10, 5), scene);
+    var camera = new BABYLON.FreeCamera("Camera", new BABYLON.Vector3(0, 0, -30), scene);
+    
+    // Attach the Controls to the canvas
+    camera.attachControl(canvas, true);
+    
+    // Load the JSON file, for simplicity in this demonstration it is included inline.
+    let atlasJSON = getJSONFile();
+    
+    // Load the SpriteSheet Associated with the JSON Atlas.
+    let spriteSheet = new BABYLON.Texture('./textures/spriteMap/none_trimmed/Legends_Level_A.png', scene,
+    false, //NoMipMaps
+    false, //InvertY usuaslly false if exported from TexturePacker
+    0, //Sampling Mode
+    null, //Onload, you could spin up the sprite map in a function nested here
+    null, //OnError
+    null, //CustomBuffer
+    false, //DeleteBuffer
+    5 //ImageFormageType RGBA
+    );
+    
+    spriteSheet.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+    spriteSheet.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE; //Or Wrap, its up to you...
+    
+    let backgroundSize = new BABYLON.Vector2(200,60);
+    
+    let background = new BABYLON.SpriteMap('background', atlasJSON, spriteSheet,
+    {
+        stageSize: backgroundSize,
+        maxAnimationFrames:8,
+        baseTile : 42,
+        layerCount: 2,
+        flipU: true, //Sometimes you gotta flip the depending on the sprite format.
+        colorMultiply : new BABYLON.Vector3(0.3,0.3,0.3)
+    },
+    scene);    
+    
+    //Set all the available tiles to the top left corner of the background for Visual debugging, and refrence.
+    for(var i = 0; i<background.spriteCount; i++){
+        background.changeTiles(0, new BABYLON.Vector2(i+1, backgroundSize.y-1), i)
+    }
+
+    //TILE, FRAME, NEXT TILE, Timing, Speed
+    //See documentation for Animation Map Information. - TODO
+    let eighth = 1/8
+    let speed = 0.5
+    background.addAnimationToTile(1, 0, 2, eighth*1, speed)
+    background.addAnimationToTile(1, 1, 3, eighth*2, speed)
+    background.addAnimationToTile(1, 2, 4, eighth*3, speed)
+    background.addAnimationToTile(1, 3, 5, eighth*4, speed)
+    background.addAnimationToTile(1, 4, 6, eighth*5, speed)
+    background.addAnimationToTile(1, 5, 7, eighth*6, speed)
+    background.addAnimationToTile(1, 6, 8, eighth*7, speed)
+    background.addAnimationToTile(1, 7, 1, 1   , speed)
+
+    background.addAnimationToTile(25, 0, 26, eighth*1, speed)
+    background.addAnimationToTile(25, 1, 27, eighth*2, speed)
+    background.addAnimationToTile(25, 2, 28, eighth*3, speed)
+    background.addAnimationToTile(25, 3, 29, eighth*4, speed)
+    background.addAnimationToTile(25, 4, 30, eighth*5, speed)
+    background.addAnimationToTile(25, 5, 31, eighth*6, speed)
+    background.addAnimationToTile(25, 6, 29, eighth*7, speed)
+    background.addAnimationToTile(25, 7, 25, 1     , speed)
+
+    background.addAnimationToTile(48, 0, 49, 0.25, speed)
+    background.addAnimationToTile(48, 1, 50, 0.5, speed)
+    background.addAnimationToTile(48, 2, 51, 0.75, speed)
+    background.addAnimationToTile(48, 4, 48, 1, speed)
+
+    background.addAnimationToTile(49, 0, 50, 0.25, speed*0.5)
+    background.addAnimationToTile(49, 1, 51, 0.5, speed*0.5)
+    background.addAnimationToTile(49, 2, 48, 0.75, speed*0.5)
+    background.addAnimationToTile(49, 4, 49, 1, speed*0.5)
+
+    background.addAnimationToTile(50, 0, 51, 0.25, speed*0.3)
+    background.addAnimationToTile(50, 1, 48, 0.5, speed*0.3)
+    background.addAnimationToTile(50, 2, 49, 0.75, speed*0.3)
+    background.addAnimationToTile(50, 4, 50, 1, speed*0.3)
+
+    background.position.z = 5;
+
+
+    //Procedurally Editing the Tiles
+    //Adding Water to BG
+    let tilePositions = []
+    for(let x=15; x<backgroundSize.x-15; x++){
+        for(let y=backgroundSize.y-26; y>0; y--){
+            if(x%12 == 0){
+                tilePositions.push(new BABYLON.Vector2(x, y))
+            }
+        }
+    }
+    background.changeTiles(1, tilePositions, 1)
+    
+    //Adding Sewer Drains to BG
+    tilePositions = []
+    for(let x=15; x<backgroundSize.x-15; x++){
+        if(x%12 == 0){
+            tilePositions.push(new BABYLON.Vector2(x, backgroundSize.y-26))
+        }
+    }
+    background.changeTiles(1, tilePositions, 25)
+    
+    //More Water!
+    tilePositions = []
+    for(let x=15; x<backgroundSize.x-15; x++){
+        for(let y=backgroundSize.y-12; y>0; y--){
+            if((x+6)%12 == 0){
+                tilePositions.push(new BABYLON.Vector2(x, y))
+            }
+        }
+    }
+    
+    background.changeTiles(1, tilePositions, 1);
+
+    tilePositions = [];
+    
+    //Random Array for placing variations of the torches animation.
+    let pTiles = [48, 49, 50, 48, 49, 50, 48];
+    
+    //Making the Base of the level
+    let levelSize = new BABYLON.Vector2(80,40);
+    
+    let levelBase = new BABYLON.SpriteMap('base', atlasJSON, spriteSheet,
+    {
+        stageSize: levelSize,
+        maxAnimationFrames:8,
+        baseTile : 42,
+        layerCount: 2,
+        flipU: true,
+        colorMultiply : new BABYLON.Vector3(0.6,0.6,0.6)
+    },
+    scene);
+    
+    //Duplicating over the animation map from the background system.
+    levelBase.animationMap = background.animationMap
+    
+    
+    //Making a hole.
+    tilePositions = []
+    for(let x=15; x<levelSize.x-15; x++){
+        for(let y=levelSize.y-15; y>15; y--){
+            tilePositions.push(new BABYLON.Vector2(x, y))
+        }
+    }
+    levelBase.changeTiles(0, tilePositions, 0)
+
+    //Adding Columns
+    tilePositions = []
+    for(let x=15; x<levelSize.x-15; x++){
+        for(let y=levelSize.y-16; y>16; y--){
+            if(x%6 == 0){
+                tilePositions.push(new BABYLON.Vector2(x, y))
+            }
+        }
+    }
+    levelBase.changeTiles(0, tilePositions, 23)
+
+    //Adding Torches
+    for(let x=15; x<levelSize.x-15; x++){
+        if((x+6)%12 == 0){
+            levelBase.changeTiles(1, new BABYLON.Vector2(x, 18),
+            pTiles[Math.floor(Math.random()*pTiles.length)])
+        }
+    }
+
+    //Adding Caps
+    tilePositions = []
+    for(let x=15; x<levelSize.x-15; x++){
+        if(x%6 == 0){
+         tilePositions.push(new BABYLON.Vector2(x, 16))
+        }
+    }
+    levelBase.changeTiles(0, tilePositions, 24)
+
+
+    //Adding Bases
+    tilePositions = []
+    for(let x=15; x<levelSize.x-15; x++){
+        if(x%6 == 0){
+            tilePositions.push(new BABYLON.Vector2(x, 25))
+        }
+    }
+    levelBase.changeTiles(0, tilePositions, 22)
+
+    //Now this last section was created like all the last two, except it was later exported from the browser and saved.
+    //This shows how to load from the .tilemaps file
+    //Additonally if you uncomment the editable argument and hit play
+    //You will go into editor mode for that spritemap allowing you to paint tiles.
+    // - and + to change tile number
+    // [ and ] to change layer number
+    //Make sure you right click on the canvas to get focus before trying to edit.
+    //Left click to paint, right click to  pan camera.
+    
+    levelStage = new BABYLON.SpriteMap('levelStage', atlasJSON, spriteSheet,
+    {
+        stageSize: levelSize,
+        maxAnimationFrames:8,
+        baseTile : 42,
+        layerCount: 2,
+        flipU: true,
+        //editable : true
+    },
+    scene);
+
+    levelStage.loadTileMaps('./textures/spriteMap/none_trimmed/levelStage.tilemaps')
+    levelStage.animationMap = background.animationMap
+    levelStage.position.z = -5   
+
+    //To download .tilemaps file for this SpriteMap uncomment the below line.
+    //levelStage.saveTileMaps();
+
+    return scene;
+}
+
+const getJSONFile = ()=>{
+    return {"frames": [
+{
+	"filename": "blank.png",
+	"frame": {"x":221,"y":221,"w":1,"h":1},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-0.png",
+	"frame": {"x":1,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-1.png",
+	"frame": {"x":1,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-2.png",
+	"frame": {"x":1,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-3.png",
+	"frame": {"x":1,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-4.png",
+	"frame": {"x":1,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-5.png",
+	"frame": {"x":1,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-6.png",
+	"frame": {"x":1,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-7.png",
+	"frame": {"x":1,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-0.png",
+	"frame": {"x":36,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-1.png",
+	"frame": {"x":71,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-2.png",
+	"frame": {"x":106,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-3.png",
+	"frame": {"x":141,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-0.png",
+	"frame": {"x":176,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-1.png",
+	"frame": {"x":211,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-2.png",
+	"frame": {"x":246,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-3.png",
+	"frame": {"x":36,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-0.png",
+	"frame": {"x":36,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-1.png",
+	"frame": {"x":36,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-2.png",
+	"frame": {"x":36,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-3.png",
+	"frame": {"x":36,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-0.png",
+	"frame": {"x":36,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-1.png",
+	"frame": {"x":36,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-2.png",
+	"frame": {"x":71,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-3.png",
+	"frame": {"x":106,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-0.png",
+	"frame": {"x":141,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-1.png",
+	"frame": {"x":176,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-2.png",
+	"frame": {"x":211,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-3.png",
+	"frame": {"x":246,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-4.png",
+	"frame": {"x":71,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-5.png",
+	"frame": {"x":71,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-6.png",
+	"frame": {"x":71,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-7.png",
+	"frame": {"x":71,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-0.png",
+	"frame": {"x":71,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-1.png",
+	"frame": {"x":71,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-2.png",
+	"frame": {"x":106,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-3.png",
+	"frame": {"x":106,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-4.png",
+	"frame": {"x":106,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-5.png",
+	"frame": {"x":106,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-6.png",
+	"frame": {"x":106,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-7.png",
+	"frame": {"x":141,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-8.png",
+	"frame": {"x":176,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-9.png",
+	"frame": {"x":211,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-10.png",
+	"frame": {"x":106,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-11.png",
+	"frame": {"x":141,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-12.png",
+	"frame": {"x":176,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-13.png",
+	"frame": {"x":211,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-14.png",
+	"frame": {"x":246,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-0.png",
+	"frame": {"x":246,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-1.png",
+	"frame": {"x":141,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-2.png",
+	"frame": {"x":141,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-3.png",
+	"frame": {"x":141,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+}],
+"meta": {
+	"app": "https://www.codeandweb.com/texturepacker",
+	"version": "1.0",
+	"image": "Legends_Level_A.png",
+	"format": "RGBA8888",
+	"size": {"w":279,"h":279},
+	"scale": "1",
+	"smartupdate": "$TexturePacker:SmartUpdate:a755ec93daaec56d1c8bcd801e167677:2e759c84cbaf9134b80c1a34b50e5c9c:9f820b9412efc8199e0407f80b8c0011$"
+}
+}
+
+}

BIN
Playground/textures/spriteMap/Game_Pack.png


BIN
Playground/textures/spriteMap/Game_Pack_n.png


+ 420 - 0
Playground/textures/spriteMap/none_trimmed/Legends_Level_A.json

@@ -0,0 +1,420 @@
+{"frames": [
+
+{
+	"filename": "Falling-Water-0.png",
+	"frame": {"x":1,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-1.png",
+	"frame": {"x":1,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-2.png",
+	"frame": {"x":1,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-3.png",
+	"frame": {"x":1,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-4.png",
+	"frame": {"x":1,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-5.png",
+	"frame": {"x":1,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-6.png",
+	"frame": {"x":1,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-7.png",
+	"frame": {"x":1,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-0.png",
+	"frame": {"x":36,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-1.png",
+	"frame": {"x":71,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-2.png",
+	"frame": {"x":106,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-3.png",
+	"frame": {"x":141,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-0.png",
+	"frame": {"x":176,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-1.png",
+	"frame": {"x":211,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-2.png",
+	"frame": {"x":246,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-3.png",
+	"frame": {"x":36,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-0.png",
+	"frame": {"x":36,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-1.png",
+	"frame": {"x":36,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-2.png",
+	"frame": {"x":36,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-3.png",
+	"frame": {"x":36,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-0.png",
+	"frame": {"x":36,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-1.png",
+	"frame": {"x":36,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-2.png",
+	"frame": {"x":71,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-3.png",
+	"frame": {"x":106,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-0.png",
+	"frame": {"x":141,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-1.png",
+	"frame": {"x":176,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-2.png",
+	"frame": {"x":211,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-3.png",
+	"frame": {"x":246,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-4.png",
+	"frame": {"x":71,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-5.png",
+	"frame": {"x":71,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-6.png",
+	"frame": {"x":71,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-7.png",
+	"frame": {"x":71,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-0.png",
+	"frame": {"x":71,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-1.png",
+	"frame": {"x":71,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-2.png",
+	"frame": {"x":106,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-3.png",
+	"frame": {"x":106,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-4.png",
+	"frame": {"x":106,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-5.png",
+	"frame": {"x":106,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-6.png",
+	"frame": {"x":106,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-7.png",
+	"frame": {"x":141,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-8.png",
+	"frame": {"x":176,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-9.png",
+	"frame": {"x":211,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-10.png",
+	"frame": {"x":106,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-11.png",
+	"frame": {"x":141,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-12.png",
+	"frame": {"x":176,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-13.png",
+	"frame": {"x":211,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-14.png",
+	"frame": {"x":246,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-0.png",
+	"frame": {"x":246,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-1.png",
+	"frame": {"x":141,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-2.png",
+	"frame": {"x":141,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-3.png",
+	"frame": {"x":141,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+}],
+"meta": {
+	"app": "https://www.codeandweb.com/texturepacker",
+	"version": "1.0",
+	"image": "Legends_Level_A.png",
+	"format": "RGBA8888",
+	"size": {"w":279,"h":279},
+	"scale": "1",
+	"smartupdate": "$TexturePacker:SmartUpdate:a755ec93daaec56d1c8bcd801e167677:2e759c84cbaf9134b80c1a34b50e5c9c:9f820b9412efc8199e0407f80b8c0011$"
+}
+}

BIN
Playground/textures/spriteMap/none_trimmed/Legends_Level_A.png


File diff suppressed because it is too large
+ 2 - 0
Playground/textures/spriteMap/none_trimmed/levelStage.tilemaps


+ 125 - 0
src/Shaders/spriteMap.fragment.fx

@@ -0,0 +1,125 @@
+precision highp float;
+
+varying vec3 vPosition;
+varying vec2 vUV;
+varying vec2 tUV;
+
+uniform float time;
+uniform float spriteCount;
+uniform sampler2D spriteSheet;
+uniform vec2 spriteMapSize;
+
+uniform vec2 outputSize;
+uniform vec2 stageSize;
+
+uniform float maxAnimationFrames;
+
+uniform sampler2D frameMap;
+uniform sampler2D tileMaps[LAYERS];
+uniform sampler2D animationMap;
+
+uniform vec3 colorMul;
+uniform float flipU;
+
+#ifdef EDITABLE
+	uniform vec2 mousePosition;
+	uniform float curTile;
+#endif
+
+float mt;
+
+float fdStep = 1./4.;
+mat4 getFrameData(float frameID){
+	float fX = frameID/spriteCount;
+
+	return mat4(
+		texture(frameMap, vec2(fX, 0.), 0.),
+		texture(frameMap, vec2(fX, fdStep*1.), 0.),
+		texture(frameMap, vec2(fX, fdStep*2.), 0.),
+		vec4(0.)
+	);
+}
+
+void main(){
+    vec4 color = vec4(0.);    
+    vec2 tileUV = fract(tUV);
+    if(flipU==1.0){
+        tileUV.y = 1.0 - tileUV.y;
+    }   	
+    vec2 tileID = floor(tUV);	
+    vec2 sheetUnits = 1./spriteMapSize;
+    float spriteUnits = 1./spriteCount;
+	vec2 stageUnits = 1./stageSize;	
+	
+	for(int i = 0; i<LAYERS; i++){	
+		float frameID = texture(tileMaps[i], (tileID+0.5)/stageSize, 0.).x;		
+		
+		vec4 animationData = texture(animationMap, vec2((frameID+0.5)/spriteCount, 0.), 0.); 
+		if(animationData.y>0.){
+		mt = mod(time*animationData.z, 1.0);
+		float aFrameSteps = 1./maxAnimationFrames;
+			for(float f = 0.; f<maxAnimationFrames; f++){
+				if(animationData.y>mt){
+					frameID = animationData.x;
+					break;
+				}
+				animationData = texture(animationMap, vec2((frameID+0.5)/spriteCount, aFrameSteps*f), 0.); 
+			}
+		}
+    
+		//Get Animation Frame
+
+		mat4 frameData = getFrameData(frameID+0.5);	
+		vec2 frameSize = (frameData[0].wz)/spriteMapSize;    
+		vec2 offset = frameData[0].xy*sheetUnits;	
+		vec2 ratio = frameData[2].xy/frameData[0].wz;
+
+		//rotated
+		if(frameData[2].z == 1.){
+			tileUV.xy = tileUV.yx;
+		}
+
+		if(i==0){
+			color = texture(spriteSheet, tileUV*frameSize+offset);
+		}else{
+			vec4 nc = texture(spriteSheet, tileUV*frameSize+offset);
+			float alpha = min(color.a+nc.a, 1.0);
+			vec3 mixed = mix(color.xyz, nc.xyz, nc.a);
+			color = vec4(mixed, alpha);
+		}	
+	}
+	
+	color.xyz*=colorMul;
+	
+	#ifdef EDITABLE
+		if(tileID == floor(mousePosition*stageSize)){
+			
+			vec2 eUV = fract(tUV);
+            if(flipU==1.0){
+                eUV.y = 1.0 - eUV.y;
+            }
+						
+			mat4 eframeData = getFrameData(curTile+0.5);	
+			vec2 eframeSize = (eframeData[0].wz)/spriteMapSize;    
+			vec2 eoffset = eframeData[0].xy*sheetUnits;	
+			vec2 eratio = eframeData[2].xy/eframeData[0].wz;	
+			
+			//rotated
+			if(eframeData[2].z == 1.){
+				eUV.xy = eUV.yx;
+			}
+			
+			vec4 nt = texture(spriteSheet, eUV*eframeSize+eoffset);
+			
+			
+			color.a = max(max(color.a , 0.5), nt.a*0.5);
+			color.rgb = mix(color.rgb, nt.rgb, 0.85);			
+			color.r *= 2.5;
+			color.g *= 2.5;
+			color.b *= 0.5;
+			
+		}		
+	#endif
+	
+	gl_FragColor =  color;
+}

+ 32 - 0
src/Shaders/spriteMap.vertex.fx

@@ -0,0 +1,32 @@
+precision highp float;
+
+// Attributes
+attribute vec3 position;
+attribute vec3 normal;
+attribute vec2 uv;
+
+//Varyings
+varying vec3 vPosition;
+varying vec2 vUV;
+varying vec2 tUV;
+varying vec2 stageUnits;
+varying vec2 levelUnits;
+varying vec2 tileID;
+
+// Uniforms
+uniform float time;
+uniform mat4 worldViewProjection;
+
+uniform vec2 outputSize;
+uniform vec2 stageSize;
+uniform vec2 spriteMapSize;
+
+uniform float stageScale;
+
+void main() {
+    vec4 p = vec4( position, 1. );
+    vPosition = p.xyz;
+    vUV = uv;
+    tUV = uv*stageSize;	
+	gl_Position = worldViewProjection * p;
+}

+ 1 - 0
src/Sprites/index.ts

@@ -1,4 +1,5 @@
 export * from "./sprite";
 export * from "./spriteManager";
+export * from "./spriteMap";
 export * from "./spritePackedManager";
 export * from "./spriteSceneComponent";

+ 27 - 3
src/Sprites/spriteManager.ts

@@ -155,7 +155,7 @@ export class SpriteManager implements ISpriteManager {
     constructor(
         /** defines the manager's name */
         public name: string,
-        imgUrl: string, capacity: number, cellSize: any, scene: Scene, epsilon: number = 0.01, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, fromPacked: boolean = false, spriteJSON: string | null = null) {
+        imgUrl: string, capacity: number, cellSize: any, scene: Scene, epsilon: number = 0.01, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, fromPacked: boolean = false, spriteJSON: any | null = null) {
         if (!scene._getComponent(SceneComponentConstants.NAME_SPRITE)) {
             scene._addComponent(new SpriteSceneComponent(scene));
         }
@@ -226,11 +226,35 @@ export class SpriteManager implements ISpriteManager {
         }
     }
 
-    private _makePacked(imgUrl: string, spriteJSON: string | null) {
+    private _makePacked(imgUrl: string, spriteJSON: any) {
         if (spriteJSON !== null) {
             try {
-                let celldata = JSON.parse(spriteJSON);
+                //Get the JSON and Check its stucture.  If its an array parse it if its a JSON sring etc...
+                let celldata: any;
+                if (typeof spriteJSON === "string") {
+                    celldata = JSON.parse(spriteJSON);
+                }else {
+                    celldata = spriteJSON;
+                }
+
+                if (celldata.frames.length) {
+                    let frametemp: any = {};
+                    for (let i = 0; i < celldata.frames.length; i++) {
+                        let _f = celldata.frames[i];
+                        if (typeof (Object.keys(_f))[0] !== "string") {
+                            throw new Error("Invalid JSON Format.  Check the frame values and make sure the name is the first parameter.");
+                        }
+
+                        let name: string = _f[(Object.keys(_f))[0]];
+                        frametemp[name] = _f;
+                    }
+                    celldata.frames = frametemp;
+                }
+
                 let spritemap = (<string[]>(<any>Reflect).ownKeys(celldata.frames));
+
+                console.log(spritemap);
+
                 this._spriteMap = spritemap;
                 this._packedAndReady = true;
                 this._cellData = celldata.frames;

+ 627 - 0
src/Sprites/spriteMap.ts

@@ -0,0 +1,627 @@
+import { Engine } from "../Engines/engine";
+import { IDisposable, Scene } from "../scene";
+import { Nullable } from "../types";
+import { Vector2, Vector3 } from "../Maths/math.vector";
+//import { Color3 } from "../Maths/math.color";
+//import { Camera } from "../Cameras/camera";
+import { Texture } from "../Materials/Textures/texture";
+import { RawTexture } from "../Materials/Textures/rawTexture";
+import { ShaderMaterial } from "../Materials/shaderMaterial";
+import { Mesh } from "../Meshes/mesh";
+import { Observer } from "../Misc/observable";
+import { ExecuteCodeAction } from "../Actions/directActions";
+import { ActionManager } from "../Actions/actionManager";
+import { PickingInfo } from "../Collisions/pickingInfo";
+
+import "../Meshes/Builders/planeBuilder";
+
+/**
+ * Defines the minimum interface to fulfill in order to be a sprite map.
+ */
+export interface ISpriteMap extends IDisposable {
+
+}
+
+/**
+ * Class used to manage a grid restricted sprite deployment on an Output plane.
+ */
+export class SpriteMap implements ISpriteMap {
+
+    /** The Name of the spriteMap */
+    public name : string;
+
+    /** The JSON file with the frame and meta data */
+    public atlasJSON : {frames: Array<any>, meta: object};
+
+     /** The systems Sprite Sheet Texture */
+    public spriteSheet : Texture;
+
+    /** Arguments passed with the Constructor */
+    public options : any;
+
+    /** Public Sprite Storage array, parsed from atlasJSON */
+    public sprites : Array<any>;
+
+    /** Returns the Number of Sprites in the System */
+    public get spriteCount(): number {
+        return this.sprites.length;
+    }
+
+    /** Returns the Position of Output Plane*/
+    public get position(): Vector3 {
+        return this._output.position;
+    }
+
+    /** Returns the Position of Output Plane*/
+    public set position(v: Vector3) {
+        this._output.position = v;
+    }
+
+    /** Sets the AnimationMap*/
+    public get animationMap() {
+        return this._animationMap;
+    }
+        /** Sets the AnimationMap*/
+    public set animationMap(v: RawTexture) {
+        let buffer = v!._texture!._bufferView;
+        let am = this.createTileAnimationBuffer(buffer);
+        this._animationMap.dispose();
+        this._animationMap = am;
+        this._material.setTexture('animationMap', this._animationMap);
+    }
+
+    /** gets Editor Tile*/
+    public get editorTile() {
+        return this._editorTile;
+    }
+    /** Sets Editor Tile*/
+    public set editorTile(v) {
+        this._editorTile = v;
+    }
+
+    /** gets Editor Layer*/
+    public get editorLayer() {
+        return this._editorLayer;
+    }
+    /** Sets Editor Layer*/
+    public set editorLayer(v) {
+        this._editorLayer = v;
+    }
+
+    /** gets Editor Last Position*/
+    public get editorPos() {
+        return this._editorPos;
+    }
+    /** Sets Editor Last Position*/
+    public set editorPos(v) {
+        this._editorPos = v;
+    }
+
+    /** Scene that the SpriteMap was created in */
+    private _scene: Scene;
+
+    /** Texture Buffer of Float32 that holds tile frame data*/
+    private _frameMap: RawTexture;
+
+    /** Texture Buffers of Float32 that holds tileMap data*/
+    private _tileMaps: RawTexture[];
+
+    /** Texture Buffer of Float32 that holds Animation Data*/
+    private _animationMap: RawTexture;
+
+    /** Custom ShaderMaterial Central to the System*/
+    private _material: ShaderMaterial;
+
+    /** Custom ShaderMaterial Central to the System*/
+    private _output: Mesh;
+
+    /** Systems Time Ticker*/
+    private _time: number;
+
+    /** Private param that controls the editor mode of the SpriteMap*/
+    private _editable : boolean;
+
+    /**Storage for the Edtior mode*/
+    private _editorTile : number = 0;
+    /**Storage for the Edtior mode*/
+    private _editorLayer : number = 0;
+    /**Storage for the Edtior mode*/
+    private _editorPos : Vector2 = new Vector2(-1, -1);
+
+    /**
+     * Creates a new SpriteMap
+     * @param name defines the SpriteMaps Name
+     * @param atlasJSON is the JSON file that controls the Sprites Frames and Meta
+     * @param spriteSheet is the Texture that the Sprites are on.
+     * @param options a basic deployment configuration
+     * @param scene The Scene that the map is deployed on
+     */
+    constructor(name : string, atlasJSON: { meta: object, frames: Array<any> }, spriteSheet: Texture, options: {
+        stageSize?: Vector2,
+        outputSize?: Vector2
+        outputPosition?: Vector3,
+        layerCount?: number,
+        maxAnimationFrames?: number,
+        baseTile?: number,
+        flipU?: number,
+        colorMultiply?: Vector3,
+        editable?: boolean
+    }, scene : Scene) {
+
+    this.name = name;
+    this.sprites = [];
+    this.atlasJSON = atlasJSON;
+    this.sprites = this.atlasJSON['frames'];
+    this.spriteSheet = spriteSheet;
+
+    /**
+    * Run through the options and set what ever defaults are needed that where not declared.
+    */
+    options.stageSize = options.stageSize || new Vector2(1, 1);
+    options.outputSize = options.outputSize || options.stageSize;
+    options.outputPosition = options.outputPosition || Vector3.Zero();
+    options.layerCount = options.layerCount || 1;
+    options.maxAnimationFrames = options.maxAnimationFrames || 0;
+    options.baseTile = options.baseTile || 0;
+    options.flipU = options.flipU || 0;
+    options.editable = options.editable || false;
+    options.colorMultiply = options.colorMultiply || new Vector3(1, 1, 1);
+
+    this._scene = scene;
+    this.options = options;
+
+    this._frameMap = this.createFrameBuffer();
+
+    this._tileMaps = new Array();
+    for (let i = 0; i < options.layerCount; i++) {
+            this._tileMaps.push(this.createTileBuffer(null, i));
+    }
+
+    this._animationMap = this.createTileAnimationBuffer(null);
+    this._editable = options.editable;
+
+    let defines = [];
+    defines.push("#define LAYERS " + this.options.layerCount);
+
+    if (this.options.editable) {
+        defines.push("#define EDITABLE");
+    }
+
+   this._material = new ShaderMaterial("spriteMap:" + this.name, this._scene, {
+        vertex: "spriteMap",
+        fragment: "spriteMap",
+    }, {
+        defines,
+        attributes: ["position", "normal", "uv"],
+        uniforms: [
+            "worldViewProjection",
+            "time",
+            'stageSize',
+            'outputSize',
+            'spriteMapSize',
+            'spriteCount',
+            'time',
+            'maxAnimationFrames',
+            'colorMul',
+            'mousePosition',
+            'curTile',
+            'flipU'
+        ],
+        samplers: [
+           "spriteSheet", "frameMap", "tileMaps", "animationMap"
+        ],
+        needAlphaBlending: true
+    });
+
+    this._time = 0;
+
+    this._material.setFloat('spriteCount', this.spriteCount);
+    this._material.setFloat('maxAnimationFrames', this.options.maxAnimationFrames);
+    this._material.setVector2('stageSize', this.options.stageSize);
+    this._material.setVector2('outputSize', this.options.outputSize);
+    this._material.setTexture('spriteSheet', this.spriteSheet);
+    this._material.setVector2('spriteMapSize', new Vector2(1, 1));
+    this._material.setVector3('colorMul', this.options.colorMultiply);
+    this._material.setFloat('flipU', this.options.flipU);
+
+    //let parent = this;
+    let tickSave = 0;
+    const bindSpriteTexture = () => {
+        if ((this.spriteSheet) && this.spriteSheet.isReady()) {
+            if (this.spriteSheet._texture) {
+                console.log('SpriteSheet size Set!');
+                this._material.setVector2('spriteMapSize', new Vector2(this.spriteSheet._texture.baseWidth || 1, this.spriteSheet._texture.baseHeight || 1));
+                return;
+            }
+        }
+        if (tickSave < 100) {
+            setTimeout(() => {tickSave++; bindSpriteTexture(); }, 100);
+        }
+    };
+
+    bindSpriteTexture();
+
+    this._material.setVector3('colorMul', this.options.colorMultiply);
+    this._material.setTexture("frameMap", this._frameMap);
+    this._material.setTextureArray("tileMaps", this._tileMaps);
+    this._material.setTexture("animationMap", this._animationMap);
+    this._material.setFloat('time', this._time);
+
+    this._output = Mesh.CreatePlane(name + ":output", 1, scene, true);
+    this._output.scaling.x = this.options.outputSize.x;
+    this._output.scaling.y = this.options.outputSize.y;
+
+    let obfunction = null;
+       if (this._editable) {
+
+            obfunction = () => {
+                this._time += this._scene.getEngine().getDeltaTime() * 0.01;
+                this._material.setFloat('time', this._time);
+                this._material.setVector2('mousePosition', this.getMousePosition());
+                this._material.setFloat('curTile', this.editorTile);
+            };
+
+            this._output.actionManager = new ActionManager(this._scene);
+            const drawing = () => {
+                let pos = this.getTileID();
+                console.log(pos);
+                if (pos.x == this.editorPos.x &&
+                    pos.y == this.editorPos.y) {
+                        return;
+                    }
+                this.editorPos = pos;
+                this.changeTiles(this.editorLayer, pos, this.editorTile);
+            };
+
+            let _drawObs: Nullable<Observer<Scene>> = null;
+
+            this._output.actionManager.registerAction(new ExecuteCodeAction(
+                ActionManager.OnLeftPickTrigger,
+                (evt: any) => {
+                        if (((this._scene) && this._scene.activeCamera)) {
+                        if (this._scene.getEngine && this._scene.getEngine().getInputElement) {
+                            let canvas: Nullable<HTMLElement> = this._scene.getEngine().getInputElement();
+                            if (!canvas) {
+                                return;
+                            }
+                            this._scene.activeCamera.detachControl(canvas);
+                            _drawObs = this._scene.onAfterRenderObservable.add(drawing);
+                        }
+                    }
+                })
+            );
+
+            this._output.actionManager.registerAction(new ExecuteCodeAction(
+                ActionManager.OnPickUpTrigger,
+                (evt: any) => {
+                    if (((this._scene) && this._scene.activeCamera)) {
+                        if (this._scene.getEngine && this._scene.getEngine().getInputElement) {
+                            let canvas: Nullable<HTMLElement> = this._scene.getEngine().getInputElement();
+                            if (!canvas) {
+                                return;
+                            }
+                            this._scene.activeCamera.attachControl(canvas);
+                            this._scene.onAfterRenderObservable.remove(_drawObs);
+                            this.editorPos = new Vector2(-1, -1);
+                        }
+                    }
+                })
+            );
+
+            if (!this._scene.actionManager) {
+                 this._scene.actionManager = new ActionManager(this._scene);
+            }
+
+            this._scene.actionManager.registerAction(
+                new ExecuteCodeAction(ActionManager.OnKeyDownTrigger, (evt: any) => {
+                    switch (evt.sourceEvent.key){
+                        case '-':
+                            this.editorTile = Math.max(0.0, this.editorTile - 1) ;
+                        break;
+                        case '=':
+                            this.editorTile = Math.min(this.editorTile + 1, this.spriteCount);
+                        break;
+                        case '[':
+                            this.editorLayer = Math.max(0.0, this.editorLayer - 1) ;
+                        break;
+                        case ']':
+                            this.editorLayer = Math.min(this.editorLayer + 1, this.options.layerCount);
+                        break;
+                    }
+                })
+            );
+
+        }else {
+            obfunction = () => {
+                this._time += this._scene.getEngine().getDeltaTime() * 0.01;
+                this._material.setFloat('time', this._time);
+            };
+        }
+
+        this._scene.onBeforeRenderObservable.add(obfunction);
+        this._output.material = this._material;
+    }
+
+    /**
+    * Returns tileID location
+    * @returns Vector2 the cell position ID
+    */
+    getTileID(): Vector2 {
+        let p = this.getMousePosition();
+        p.multiplyInPlace(this.options.stageSize);
+        p.x = Math.floor(p.x);
+        p.y = Math.floor(p.y);
+        return p;
+    }
+
+    /**
+    * Gets the UV location of the mouse over the SpriteMap, if In editable mode.
+    * @returns Vector2 the UV position of the mouse interaction
+    */
+    getMousePosition(): Vector2 {
+        let out = this._output;
+        var pickinfo: Nullable<PickingInfo> = this._scene.pick(this._scene.pointerX, this._scene.pointerY, (mesh) => {
+            if (mesh !== out) {
+                return false;
+            }
+          return true;
+        });
+
+        if (((!pickinfo) || !pickinfo.hit) || !pickinfo.getTextureCoordinates) {
+            return new Vector2(-1, -1);
+        }
+
+        let coords = pickinfo.getTextureCoordinates();
+        if (coords) {
+            return coords;
+        }
+
+        return 	new Vector2(-1, -1);
+    }
+
+    /**
+    * Creates the "frame" texture Buffer
+    * -------------------------------------
+    * Structure of frames
+    *  "filename": "Falling-Water-2.png",
+    * "frame": {"x":69,"y":103,"w":24,"h":32},
+    * "rotated": true,
+    * "trimmed": true,
+    * "spriteSourceSize": {"x":4,"y":0,"w":24,"h":32},
+    * "sourceSize": {"w":32,"h":32}
+    * @returns RawTexture of the frameMap
+    */
+    createFrameBuffer(): RawTexture {
+        let data = new Array();
+        //Do two Passes
+        for (let i = 0; i < this.spriteCount; i++) {
+            data.push(0, 0, 0, 0); //frame
+            data.push(0, 0, 0, 0); //spriteSourceSize
+            data.push(0, 0, 0, 0); //sourceSize, rotated, trimmed
+            data.push(0, 0, 0, 0); //Keep it pow2 cause I'm cool like that... it helps with sampling accuracy as well. Plus then we have 4 other parameters for future stuff.
+        }
+        //Second Pass
+        for (let i = 0; i < this.spriteCount; i++) {
+            let f = this.sprites[i]['frame'];
+            let sss = this.sprites[i]['spriteSourceSize'];
+            let ss = this.sprites[i]['sourceSize'];
+            let r = (this.sprites[i]['rotated']) ? 1 : 0;
+            let t = (this.sprites[i]['trimmed']) ? 1 : 0;
+
+            //frame
+            data[i * 4] = f.x;
+            data[i * 4 + 1] = f.y;
+            data[i * 4 + 2] = f.w;
+            data[i * 4 + 3] = f.h;
+            //spriteSourceSize
+            data[i * 4 + (this.spriteCount * 4)] = sss.x;
+            data[i * 4 + 1 + (this.spriteCount * 4)] = sss.y;
+            data[i * 4 + 2 + (this.spriteCount * 4)] = sss.w;
+            data[i * 4 + 3 + (this.spriteCount * 4)] = sss.h;
+            //sourceSize, rotated, trimmed
+            data[i * 4 + (this.spriteCount * 8)] = ss.w;
+            data[i * 4 + 1 + (this.spriteCount * 8)] = ss.h;
+            data[i * 4 + 2 + (this.spriteCount * 8)] = r;
+            data[i * 4 + 3 + (this.spriteCount * 8)] = t ;
+        }
+
+        let floatArray = new Float32Array(data);
+
+        let t = RawTexture.CreateRGBATexture(
+        floatArray,
+        this.spriteCount,
+        4,
+        this._scene,
+        false,
+        false,
+        Texture.NEAREST_NEAREST,
+        Engine.TEXTURETYPE_FLOAT
+        );
+
+        return t;
+    }
+
+    /**
+    * Creates the tileMap texture Buffer
+    * @param buffer normaly and array of numbers, or a false to generate from scratch
+    * @param _layer indicates what layer for a logic trigger dealing with the baseTile.  The system uses this
+    * @returns RawTexture of the tileMap
+    */
+    createTileBuffer(buffer: any, _layer: number= 0): RawTexture {
+        let data = new Array();
+
+        if (!buffer) {
+            let bt = this.options.baseTile;
+            if (_layer != 0) {
+                bt = 0;
+            }
+            for (let y = 0; y < this.options.stageSize.y; y++) {
+                for (let x = 0; x < this.options.stageSize.x * 4; x += 4) {
+                    data.push(bt, 0, 0, 0);
+                }
+            }
+        }else {
+            data = buffer;
+        }
+
+        let floatArray = new Float32Array(data);
+        let t = RawTexture.CreateRGBATexture(
+        floatArray,
+        this.options.stageSize.x,
+        this.options.stageSize.y,
+        this._scene,
+        false,
+        false,
+        Texture.NEAREST_NEAREST,
+        Engine.TEXTURETYPE_FLOAT
+        );
+
+        return t;
+    }
+
+    /**
+    * Modfies the data of the tileMaps
+    * @param _layer is the ID of the layer you want to edit on the SpriteMap
+    * @param pos is the iVector2 Coordinates of the Tile
+    * @param tile The SpriteIndex of the new Tile
+    */
+    changeTiles(_layer: number= 0, pos: any , tile: number= 0): void {
+
+        let buffer: any = [];
+        buffer = this._tileMaps[_layer]!._texture!._bufferView;
+        if (!buffer) {
+            return;
+        }
+
+        let p = new Array();
+        if (pos instanceof Vector2) {
+            p.push(pos);
+        }else {
+            p = pos;
+        }
+
+        for (let i = 0; i < p.length; i++) {
+            let _p = p[i];
+            _p.x = Math.floor(_p.x);
+            _p.y = Math.floor(_p.y);
+            let id = (_p.x * 4) + (_p.y * (this.options.stageSize.x * 4));
+            buffer[id] = tile;
+        }
+
+        let t = this.createTileBuffer(buffer);
+        this._tileMaps[_layer].dispose();
+        this._tileMaps[_layer] = t;
+        this._material.setTextureArray("tileMap", this._tileMaps);
+    }
+
+    /**
+    * Creates the animationMap texture Buffer
+    * @param buffer normaly and array of numbers, or a false to generate from scratch
+    * @returns RawTexture of the animationMap
+    */
+    createTileAnimationBuffer(buffer: any): RawTexture {
+        let data = new Array();
+        if (!buffer) {
+            for (let i = 0; i < this.spriteCount; i++) {
+                data.push(0, 0, 0, 0);
+                let count = 1;
+                while (count < (this.options.maxAnimationFrames || 4)) {
+                    data.push(0, 0, 0, 0);
+                    count++;
+                }
+            }
+        }else {
+            data = buffer;
+        }
+
+        let floatArray = new Float32Array(data);
+        let t = RawTexture.CreateRGBATexture(
+        floatArray,
+        this.spriteCount,
+        (this.options.maxAnimationFrames || 4),
+        this._scene,
+        false,
+        false,
+        Texture.NEAREST_NEAREST,
+        Engine.TEXTURETYPE_FLOAT
+        );
+
+        return t;
+    }
+    /**
+    * Modfies the data of the animationMap
+    * @param cellID is the Index of the Sprite
+    * @param _frame is the target Animation frame
+    * @param toCell is the Target Index of the next frame of the animation
+    * @param time is a value between 0-1 that is the trigger for when the frame should change tiles
+    * @param speed is a global scalar of the time varable on the map.
+    */
+    addAnimationToTile(cellID: number= 0, _frame: number= 0, toCell: number= 0, time: number= 0, speed: number = 1): void {
+        let buffer: any = this._animationMap!._texture!._bufferView;
+        let id: number = (cellID * 4) + (this.spriteCount * 4 * _frame);
+        if (!buffer) {
+            return;
+        }
+        buffer[id || 0] = toCell;
+        buffer[id + 1 || 0] = time;
+        buffer[id + 2 || 0] = speed;
+        let t = this.createTileAnimationBuffer(buffer);
+        this._animationMap.dispose();
+        this._animationMap = t;
+        this._material.setTexture("animationMap", this._animationMap);
+    }
+
+    /**
+    * Exports the .tilemaps file
+    */
+    saveTileMaps(): void {
+        let maps = '';
+        for (var i = 0; i < this._tileMaps.length; i++) {
+            if (i > 0) {maps += '\n\r'; }
+
+            maps += this._tileMaps[i]!._texture!._bufferView!.toString();
+        }
+        var hiddenElement = document.createElement('a');
+        hiddenElement.href = 'data:octet/stream;charset=utf-8,' + encodeURI(maps);
+        hiddenElement.target = '_blank';
+        hiddenElement.download = this.name + '.tilemaps';
+        hiddenElement.click();
+        hiddenElement.remove();
+    }
+
+    /**
+    * Imports the .tilemaps file
+    * @param url of the .tilemaps file
+    */
+    loadTileMaps(url: string): void {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", url);
+        //xhr.responseType = "octet/stream"
+
+        xhr.onload = () =>
+        {
+            let data = xhr.response.split('\n\r');
+            for (let i = 0; i < this.options.layerCount; i++) {
+                let d = (data[i].split(',')).map(Number);
+                let t = this.createTileBuffer(d);
+                this._tileMaps[i].dispose();
+                this._tileMaps[i] = t;
+            }
+            this._material.setTextureArray("tileMap", this._tileMaps);
+        };
+        xhr.send();
+    }
+
+    /**
+     * Release associated resources
+     */
+    public dispose(): void {
+        this._output.dispose();
+        this._material.dispose();
+        this._animationMap.dispose();
+        this._tileMaps.forEach((tm) => {
+            tm.dispose();
+        });
+        this._frameMap.dispose();
+    }
+}