1*5eae8ebbSCole Faust/* 2*5eae8ebbSCole Faust * Copyright (C) 2008 The Android Open Source Project 3*5eae8ebbSCole Faust * 4*5eae8ebbSCole Faust * Licensed under the Apache License, Version 2.0 (the "License"); 5*5eae8ebbSCole Faust * you may not use this file except in compliance with the License. 6*5eae8ebbSCole Faust * You may obtain a copy of the License at 7*5eae8ebbSCole Faust * 8*5eae8ebbSCole Faust * http://www.apache.org/licenses/LICENSE-2.0 9*5eae8ebbSCole Faust * 10*5eae8ebbSCole Faust * Unless required by applicable law or agreed to in writing, software 11*5eae8ebbSCole Faust * distributed under the License is distributed on an "AS IS" BASIS, 12*5eae8ebbSCole Faust * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*5eae8ebbSCole Faust * See the License for the specific language governing permissions and 14*5eae8ebbSCole Faust * limitations under the License. 15*5eae8ebbSCole Faust */ 16*5eae8ebbSCole Faust 17*5eae8ebbSCole Faust /** 18*5eae8ebbSCole Faust * @fileoverview This implements a Photoshop script that can be used to generate 19*5eae8ebbSCole Faust * collision information for the AndouKun game engine. This tool walks over 20*5eae8ebbSCole Faust * each path in the current document and generates a list of edges and normals 21*5eae8ebbSCole Faust * in a new document. It is intended to be used on a file containing 22*5eae8ebbSCole Faust * graphical representations of the collision tiles used by the engine. Each 23*5eae8ebbSCole Faust * path in the file must be closed and may not contain any curved points 24*5eae8ebbSCole Faust * (the tool assumes that the line between any two points in a given path is 25*5eae8ebbSCole Faust * straight). Only one shape may be contained per path layer (each path must go 26*5eae8ebbSCole Faust * in its own path layer). This tool can also output a graphical version of its 27*5eae8ebbSCole Faust * edge calculation for debugging purposes. 28*5eae8ebbSCole Faust */ 29*5eae8ebbSCole Faust 30*5eae8ebbSCole Faust/* If set to true, the computation will be rendered graphically to the output 31*5eae8ebbSCole Faust file */ 32*5eae8ebbSCole Faustvar drawOutput = false; 33*5eae8ebbSCole Faust/* If true, the computation will be printed in a text layer in the 34*5eae8ebbSCole Faust output file.*/ 35*5eae8ebbSCole Faustvar printOutput = true; 36*5eae8ebbSCole Faust 37*5eae8ebbSCole Faust// Back up the ruler units that this file uses before switching to pixel units. 38*5eae8ebbSCole Faustvar defaultRulerUnits = app.preferences.rulerUnits; 39*5eae8ebbSCole Faustapp.preferences.rulerUnits = Units.PIXELS; 40*5eae8ebbSCole Faust 41*5eae8ebbSCole Faustvar tileSizeX = prompt("Tile pixel width:"); 42*5eae8ebbSCole Faustvar tileSizeY = prompt("Tile pixel height:"); 43*5eae8ebbSCole Faust 44*5eae8ebbSCole Faustvar documentWidth = app.activeDocument.width; 45*5eae8ebbSCole Faustvar documentHeight = app.activeDocument.height; 46*5eae8ebbSCole Faust 47*5eae8ebbSCole Faustvar tilesPerRow = documentWidth / tileSizeX; 48*5eae8ebbSCole Faustvar tilesPerColumn = documentHeight / tileSizeY; 49*5eae8ebbSCole Faust 50*5eae8ebbSCole Faustvar tiles = new Array(); 51*5eae8ebbSCole Fausttiles.length = tilesPerRow * tilesPerColumn; 52*5eae8ebbSCole Faust 53*5eae8ebbSCole Faust// Walk the list of paths and extract edges and normals. Store these in 54*5eae8ebbSCole Faust// an array by tile. 55*5eae8ebbSCole Faustvar pathList = app.activeDocument.pathItems; 56*5eae8ebbSCole Faustfor (pathIndex = 0; pathIndex < pathList.length; pathIndex++) { 57*5eae8ebbSCole Faust var main_path = pathList[pathIndex]; 58*5eae8ebbSCole Faust if (main_path) { 59*5eae8ebbSCole Faust var itemList = main_path.subPathItems; 60*5eae8ebbSCole Faust if (!itemList) { 61*5eae8ebbSCole Faust alert("Path has no sub items!"); 62*5eae8ebbSCole Faust } else { 63*5eae8ebbSCole Faust for (var x = 0; x < itemList.length; x++) { 64*5eae8ebbSCole Faust var item = itemList[x]; 65*5eae8ebbSCole Faust var points = item.pathPoints; 66*5eae8ebbSCole Faust var tile = new Object; 67*5eae8ebbSCole Faust tile.edges = new Array(); 68*5eae8ebbSCole Faust 69*5eae8ebbSCole Faust var totalX = 0; 70*5eae8ebbSCole Faust var totalY = 0; 71*5eae8ebbSCole Faust for (var y = 0; y < points.length; y++) { 72*5eae8ebbSCole Faust var firstPoint = points[y]; 73*5eae8ebbSCole Faust var lastPoint = points[(y + 1) % points.length]; 74*5eae8ebbSCole Faust 75*5eae8ebbSCole Faust var edge = new Object; 76*5eae8ebbSCole Faust 77*5eae8ebbSCole Faust edge.startX = firstPoint.anchor[0]; 78*5eae8ebbSCole Faust edge.startY = firstPoint.anchor[1]; 79*5eae8ebbSCole Faust 80*5eae8ebbSCole Faust edge.endX = lastPoint.anchor[0]; 81*5eae8ebbSCole Faust edge.endY = lastPoint.anchor[1]; 82*5eae8ebbSCole Faust 83*5eae8ebbSCole Faust var normalX = -(edge.endY - edge.startY); 84*5eae8ebbSCole Faust var normalY = edge.endX - edge.startX; 85*5eae8ebbSCole Faust 86*5eae8ebbSCole Faust var normalLength = Math.sqrt((normalX * normalX) + (normalY * normalY)); 87*5eae8ebbSCole Faust normalX /= normalLength; 88*5eae8ebbSCole Faust normalY /= normalLength; 89*5eae8ebbSCole Faust 90*5eae8ebbSCole Faust edge.normalX = normalX; 91*5eae8ebbSCole Faust edge.normalY = normalY; 92*5eae8ebbSCole Faust 93*5eae8ebbSCole Faust if (normalX == 0 && normalY == 0) { 94*5eae8ebbSCole Faust alert("Zero length normal calculated at path " + pathIndex); 95*5eae8ebbSCole Faust } 96*5eae8ebbSCole Faust 97*5eae8ebbSCole Faust var normalLength2 = Math.sqrt((normalX * normalX) + (normalY * normalY)); 98*5eae8ebbSCole Faust if (normalLength2 > 1 || normalLength2 < 0.9) { 99*5eae8ebbSCole Faust alert("Normal of invalid length (" + normalLength2 + ") found at path " + pathIndex); 100*5eae8ebbSCole Faust } 101*5eae8ebbSCole Faust 102*5eae8ebbSCole Faust totalX += edge.endX; 103*5eae8ebbSCole Faust totalY += edge.endY; 104*5eae8ebbSCole Faust 105*5eae8ebbSCole Faust var width = edge.endX - edge.startX; 106*5eae8ebbSCole Faust var height = edge.endY - edge.startY; 107*5eae8ebbSCole Faust 108*5eae8ebbSCole Faust edge.centerX = edge.endX - (width / 2); 109*5eae8ebbSCole Faust edge.centerY = edge.endY - (height / 2); 110*5eae8ebbSCole Faust 111*5eae8ebbSCole Faust tile.edges.push(edge); 112*5eae8ebbSCole Faust } 113*5eae8ebbSCole Faust 114*5eae8ebbSCole Faust totalX /= points.length; 115*5eae8ebbSCole Faust totalY /= points.length; 116*5eae8ebbSCole Faust tile.centerX = totalX; 117*5eae8ebbSCole Faust tile.centerY = totalY; 118*5eae8ebbSCole Faust 119*5eae8ebbSCole Faust var column = Math.floor(tile.centerX / tileSizeX); 120*5eae8ebbSCole Faust var row = Math.floor(tile.centerY / tileSizeY); 121*5eae8ebbSCole Faust 122*5eae8ebbSCole Faust tile.xOffset = column * tileSizeX; 123*5eae8ebbSCole Faust tile.yOffset = row * tileSizeY; 124*5eae8ebbSCole Faust 125*5eae8ebbSCole Faust tile.centerX -= tile.xOffset; 126*5eae8ebbSCole Faust tile.centerY -= tile.yOffset; 127*5eae8ebbSCole Faust 128*5eae8ebbSCole Faust var tileIndex = Math.floor(row * tilesPerRow + column); 129*5eae8ebbSCole Faust tiles[tileIndex] = tile; 130*5eae8ebbSCole Faust 131*5eae8ebbSCole Faust } 132*5eae8ebbSCole Faust } 133*5eae8ebbSCole Faust } 134*5eae8ebbSCole Faust} 135*5eae8ebbSCole Faust 136*5eae8ebbSCole Faustvar outputString = ""; 137*5eae8ebbSCole Faust 138*5eae8ebbSCole Faust// For each tile print the edges to a string. 139*5eae8ebbSCole Faustfor (var x = 0; x < tiles.length; x++) { 140*5eae8ebbSCole Faust if (tiles[x]) { 141*5eae8ebbSCole Faust var tile = tiles[x]; 142*5eae8ebbSCole Faust for (var y = 0; y < tile.edges.length; y++) { 143*5eae8ebbSCole Faust var edge = tile.edges[y]; 144*5eae8ebbSCole Faust 145*5eae8ebbSCole Faust // convert to tile space 146*5eae8ebbSCole Faust edge.startX -= tile.xOffset; 147*5eae8ebbSCole Faust edge.startY -= tile.yOffset; 148*5eae8ebbSCole Faust edge.endX -= tile.xOffset; 149*5eae8ebbSCole Faust edge.endY -= tile.yOffset; 150*5eae8ebbSCole Faust edge.centerX -= tile.xOffset; 151*5eae8ebbSCole Faust edge.centerY -= tile.yOffset; 152*5eae8ebbSCole Faust 153*5eae8ebbSCole Faust // The normals that we calculated previously might be facing the wrong 154*5eae8ebbSCole Faust // direction. Detect this case and correct it by checking to see if 155*5eae8ebbSCole Faust // adding the normal to a point on the edge moves the point closer or 156*5eae8ebbSCole Faust // further from the center of the shape. 157*5eae8ebbSCole Faust if (Math.abs(edge.centerX - tile.centerX) > 158*5eae8ebbSCole Faust Math.abs((edge.centerX + edge.normalX) - tile.centerX)) { 159*5eae8ebbSCole Faust edge.normalX *= -1; 160*5eae8ebbSCole Faust edge.normalY *= -1; 161*5eae8ebbSCole Faust } 162*5eae8ebbSCole Faust 163*5eae8ebbSCole Faust if (Math.abs(edge.centerY - tile.centerY) > 164*5eae8ebbSCole Faust Math.abs((edge.centerY + edge.normalY) - tile.centerY)) { 165*5eae8ebbSCole Faust edge.normalX *= -1; 166*5eae8ebbSCole Faust edge.normalY *= -1; 167*5eae8ebbSCole Faust } 168*5eae8ebbSCole Faust 169*5eae8ebbSCole Faust 170*5eae8ebbSCole Faust // Convert to left-handed GL space (the origin is at the bottom-left). 171*5eae8ebbSCole Faust edge.normalY *= -1; 172*5eae8ebbSCole Faust edge.startY = tileSizeY - edge.startY; 173*5eae8ebbSCole Faust edge.endY = tileSizeY - edge.endY; 174*5eae8ebbSCole Faust edge.centerY = tileSizeY - edge.centerY; 175*5eae8ebbSCole Faust 176*5eae8ebbSCole Faust outputString += x + ":" + Math.floor(edge.startX) + "," + 177*5eae8ebbSCole Faust Math.floor(edge.startY) + ":" + Math.floor(edge.endX) + "," + 178*5eae8ebbSCole Faust Math.floor(edge.endY) + ":" + edge.normalX + "," + edge.normalY + 179*5eae8ebbSCole Faust "\r"; 180*5eae8ebbSCole Faust } 181*5eae8ebbSCole Faust } 182*5eae8ebbSCole Faust} 183*5eae8ebbSCole Faust 184*5eae8ebbSCole Faust 185*5eae8ebbSCole Faustif (outputString.length > 0) { 186*5eae8ebbSCole Faust 187*5eae8ebbSCole Faust var newDoc = app.documents.add(600, 700, 72.0, "Edge Output", 188*5eae8ebbSCole Faust NewDocumentMode.RGB); 189*5eae8ebbSCole Faust 190*5eae8ebbSCole Faust if (drawOutput) { 191*5eae8ebbSCole Faust // Render the edges and normals to the new document. 192*5eae8ebbSCole Faust var pathLayer = newDoc.artLayers.add(); 193*5eae8ebbSCole Faust newDoc.activeLayer = pathLayer; 194*5eae8ebbSCole Faust 195*5eae8ebbSCole Faust // draw the edges to make sure everything works 196*5eae8ebbSCole Faust var black = new SolidColor; 197*5eae8ebbSCole Faust black.rgb.red = 0; 198*5eae8ebbSCole Faust black.rgb.blue = 0; 199*5eae8ebbSCole Faust black.rgb.green = 0; 200*5eae8ebbSCole Faust 201*5eae8ebbSCole Faust var redColor = new SolidColor; 202*5eae8ebbSCole Faust redColor.rgb.red = 255; 203*5eae8ebbSCole Faust redColor.rgb.blue = 0; 204*5eae8ebbSCole Faust redColor.rgb.green = 0; 205*5eae8ebbSCole Faust 206*5eae8ebbSCole Faust var greenColor = new SolidColor; 207*5eae8ebbSCole Faust greenColor.rgb.red = 0; 208*5eae8ebbSCole Faust greenColor.rgb.blue = 0; 209*5eae8ebbSCole Faust greenColor.rgb.green = 255; 210*5eae8ebbSCole Faust 211*5eae8ebbSCole Faust var blueColor = new SolidColor; 212*5eae8ebbSCole Faust blueColor.rgb.red = 0; 213*5eae8ebbSCole Faust blueColor.rgb.blue = 255; 214*5eae8ebbSCole Faust blueColor.rgb.green = 0; 215*5eae8ebbSCole Faust 216*5eae8ebbSCole Faust var lineIndex = 0; 217*5eae8ebbSCole Faust for (var x = 0; x < tiles.length; x++) { 218*5eae8ebbSCole Faust if (tiles[x]) { 219*5eae8ebbSCole Faust var tile = tiles[x]; 220*5eae8ebbSCole Faust var lineArray = new Array(); 221*5eae8ebbSCole Faust var offsetX = Math.floor(x % tilesPerRow) * tileSizeX; 222*5eae8ebbSCole Faust var offsetY = Math.floor(x / tilesPerRow) * tileSizeY; 223*5eae8ebbSCole Faust 224*5eae8ebbSCole Faust for (var y = 0; y < tile.edges.length; y++) { 225*5eae8ebbSCole Faust var edge = tile.edges[y]; 226*5eae8ebbSCole Faust 227*5eae8ebbSCole Faust lineArray[y] = Array(offsetX + edge.startX, offsetY + edge.startY); 228*5eae8ebbSCole Faust } 229*5eae8ebbSCole Faust 230*5eae8ebbSCole Faust // I tried to do this by stroking paths, but the documentation 231*5eae8ebbSCole Faust // provided by Adobe is faulty (their sample code doesn't run). The 232*5eae8ebbSCole Faust // same thing can be accomplished with selections instead. 233*5eae8ebbSCole Faust newDoc.selection.select(lineArray); 234*5eae8ebbSCole Faust newDoc.selection.stroke(black, 2); 235*5eae8ebbSCole Faust 236*5eae8ebbSCole Faust for (var y = 0; y < tile.edges.length; y++) { 237*5eae8ebbSCole Faust var edge = tile.edges[y]; 238*5eae8ebbSCole Faust 239*5eae8ebbSCole Faust var normalX = Math.round(tile.centerX + 240*5eae8ebbSCole Faust (edge.normalX * (tileSizeX / 2))); 241*5eae8ebbSCole Faust var normalY = Math.round(tile.centerY + 242*5eae8ebbSCole Faust (edge.normalY * (tileSizeY / 2))); 243*5eae8ebbSCole Faust 244*5eae8ebbSCole Faust var tileCenterArray = new Array(); 245*5eae8ebbSCole Faust tileCenterArray[0] = new Array(offsetX + tile.centerX - 1, 246*5eae8ebbSCole Faust offsetY + tile.centerY - 1); 247*5eae8ebbSCole Faust tileCenterArray[1] = new Array(offsetX + tile.centerX - 1, 248*5eae8ebbSCole Faust offsetY + tile.centerY + 1); 249*5eae8ebbSCole Faust tileCenterArray[2] = new Array(offsetX + tile.centerX + 1, 250*5eae8ebbSCole Faust offsetY + tile.centerY + 1); 251*5eae8ebbSCole Faust tileCenterArray[3] = new Array(offsetX + tile.centerX + 1, 252*5eae8ebbSCole Faust offsetY + tile.centerY - 1); 253*5eae8ebbSCole Faust tileCenterArray[4] = new Array(offsetX + normalX - 1, 254*5eae8ebbSCole Faust offsetY + normalY - 1); 255*5eae8ebbSCole Faust tileCenterArray[5] = new Array(offsetX + normalX + 1, 256*5eae8ebbSCole Faust offsetY + normalY + 1); 257*5eae8ebbSCole Faust tileCenterArray[6] = new Array(offsetX + tile.centerX, 258*5eae8ebbSCole Faust offsetY + tile.centerY); 259*5eae8ebbSCole Faust 260*5eae8ebbSCole Faust newDoc.selection.select(tileCenterArray); 261*5eae8ebbSCole Faust newDoc.selection.fill(redColor); 262*5eae8ebbSCole Faust 263*5eae8ebbSCole Faust var centerArray = new Array(); 264*5eae8ebbSCole Faust centerArray[0] = new Array(offsetX + edge.centerX - 1, 265*5eae8ebbSCole Faust offsetY + edge.centerY - 1); 266*5eae8ebbSCole Faust centerArray[1] = new Array(offsetX + edge.centerX - 1, 267*5eae8ebbSCole Faust offsetY + edge.centerY + 1); 268*5eae8ebbSCole Faust centerArray[2] = new Array(offsetX + edge.centerX + 1, 269*5eae8ebbSCole Faust offsetY + edge.centerY + 1); 270*5eae8ebbSCole Faust centerArray[3] = new Array(offsetX + edge.centerX + 1, 271*5eae8ebbSCole Faust offsetY + edge.centerY - 1); 272*5eae8ebbSCole Faust 273*5eae8ebbSCole Faust newDoc.selection.select(centerArray); 274*5eae8ebbSCole Faust newDoc.selection.fill(greenColor); 275*5eae8ebbSCole Faust 276*5eae8ebbSCole Faust } 277*5eae8ebbSCole Faust 278*5eae8ebbSCole Faust } 279*5eae8ebbSCole Faust } 280*5eae8ebbSCole Faust } 281*5eae8ebbSCole Faust 282*5eae8ebbSCole Faust if (printOutput) { 283*5eae8ebbSCole Faust var textLayer = newDoc.artLayers.add(); 284*5eae8ebbSCole Faust textLayer.kind = LayerKind.TEXT; 285*5eae8ebbSCole Faust textLayer.textItem.contents = outputString; 286*5eae8ebbSCole Faust } 287*5eae8ebbSCole Faust} 288*5eae8ebbSCole Faust 289*5eae8ebbSCole Faustpreferences.rulerUnits = defaultRulerUnits; 290*5eae8ebbSCole Faust 291*5eae8ebbSCole Faust// Convenience function for clamping negative values to zero. Trying to select 292*5eae8ebbSCole Faust// areas outside the canvas causes Bad Things. 293*5eae8ebbSCole Faustfunction clamp(input) { 294*5eae8ebbSCole Faust if (input < 0) { 295*5eae8ebbSCole Faust return 0; 296*5eae8ebbSCole Faust } 297*5eae8ebbSCole Faust return input; 298*5eae8ebbSCole Faust} 299