xref: /aosp_15_r20/external/replicaisland/tools/ExtractPoints.js (revision 5eae8ebb3c5756e41e77a1f7201fcf94b0eade1f)
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