/** * Loads a PolygonRegion from a PSH (Polygon SHape) file. The PSH file format defines the polygon * vertices before triangulation: * * <p>s 200.0, 100.0, ... * * <p>Lines not prefixed with "s" are ignored. PSH files can be created with external tools, eg: * <br> * https://code.google.com/p/libgdx-polygoneditor/ <br> * http://www.codeandweb.com/physicseditor/ * * @param file file handle to the shape definition file */ public PolygonRegion load(TextureRegion textureRegion, FileHandle file) { BufferedReader reader = file.reader(256); try { while (true) { String line = reader.readLine(); if (line == null) break; if (line.startsWith("s")) { // Read shape. String[] polygonStrings = line.substring(1).trim().split(","); float[] vertices = new float[polygonStrings.length]; for (int i = 0, n = vertices.length; i < n; i++) vertices[i] = Float.parseFloat(polygonStrings[i]); // It would probably be better if PSH stored the vertices and triangles, then we don't // have to triangulate here. return new PolygonRegion( textureRegion, vertices, triangulator.computeTriangles(vertices).toArray()); } } } catch (IOException ex) { throw new GdxRuntimeException("Error reading polygon shape file: " + file, ex); } finally { StreamUtils.closeQuietly(reader); } throw new GdxRuntimeException("Polygon shape not found: " + file); }
/** * Sets polygon with repeating texture region, the size of repeating grid is equal to region size * * @param region - region to repeat * @param vertices - cw vertices of polygon * @param density - number of regions per polygon width bound */ public void setPolygon(TextureRegion region, float[] vertices, float density) { this.region = region; vertices = offset(vertices); Polygon polygon = new Polygon(vertices); Polygon tmpPoly = new Polygon(); Polygon intersectionPoly = new Polygon(); EarClippingTriangulator triangulator = new EarClippingTriangulator(); int idx; Rectangle boundRect = polygon.getBoundingRectangle(); if (density == -1) density = boundRect.getWidth() / region.getRegionWidth(); float regionAspectRatio = (float) region.getRegionHeight() / (float) region.getRegionWidth(); cols = (int) (Math.ceil(density)); gridWidth = boundRect.getWidth() / density; gridHeight = regionAspectRatio * gridWidth; rows = (int) Math.ceil(boundRect.getHeight() / gridHeight); for (int col = 0; col < cols; col++) { for (int row = 0; row < rows; row++) { float[] verts = new float[8]; idx = 0; verts[idx++] = col * gridWidth; verts[idx++] = row * gridHeight; verts[idx++] = (col) * gridWidth; verts[idx++] = (row + 1) * gridHeight; verts[idx++] = (col + 1) * gridWidth; verts[idx++] = (row + 1) * gridHeight; verts[idx++] = (col + 1) * gridWidth; verts[idx] = (row) * gridHeight; tmpPoly.setVertices(verts); Intersector.intersectPolygons(polygon, tmpPoly, intersectionPoly); verts = intersectionPoly.getVertices(); if (verts.length > 0) { parts.add(snapToGrid(verts)); ShortArray arr = triangulator.computeTriangles(verts); indices.add(arr.toArray()); } else { // adding null for key consistancy, needed to get col/row from key // the other alternative is to make parts - IntMap<FloatArray> parts.add(null); } } } buildVertices(); }
/** * Creates an array of PolySpatials based on fixture information from the scene. Note that * fixtures create aligned textures. * * @param scene */ private void createPolySpatialsFromRubeFixtures(RubeScene scene) { Array<Body> bodies = scene.getBodies(); EarClippingTriangulator ect = new EarClippingTriangulator(); if ((bodies != null) && (bodies.size > 0)) { polySpatials = new Array<PolySpatial>(); Vector2 bodyPos = new Vector2(); // for each body in the scene... for (int i = 0; i < bodies.size; i++) { Body body = bodies.get(i); bodyPos.set(body.getPosition()); Array<Fixture> fixtures = body.getFixtureList(); if ((fixtures != null) && (fixtures.size > 0)) { // for each fixture on the body... for (int j = 0; j < fixtures.size; j++) { Fixture fixture = fixtures.get(j); String textureName = (String) scene.getCustom(fixture, "TextureMask", null); if (textureName != null) { String textureFileName = "data/" + textureName; Texture texture = textureMap.get(textureFileName); TextureRegion textureRegion = null; if (texture == null) { texture = new Texture(textureFileName); texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat); textureMap.put(textureFileName, texture); textureRegion = new TextureRegion(texture); textureRegionMap.put(texture, textureRegion); } else { textureRegion = textureRegionMap.get(texture); } // only handle polygons at this point -- no chain, edge, or circle fixtures. if (fixture.getType() == Shape.Type.Polygon) { PolygonShape shape = (PolygonShape) fixture.getShape(); int vertexCount = shape.getVertexCount(); float[] vertices = new float[vertexCount * 2]; // static bodies are texture aligned and do not get drawn based off of the related // body. if (body.getType() == BodyType.StaticBody) { for (int k = 0; k < vertexCount; k++) { shape.getVertex(k, mTmp); mTmp.rotate(body.getAngle() * MathUtils.radiansToDegrees); mTmp.add( bodyPos); // convert local coordinates to world coordinates to that textures // are // aligned vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER; vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER; } short[] triangleIndices = ect.computeTriangles(vertices).toArray(); PolygonRegion region = new PolygonRegion(textureRegion, vertices, triangleIndices); PolySpatial spatial = new PolySpatial(region, Color.WHITE); polySpatials.add(spatial); } else { // all other fixtures are aligned based on their associated body. for (int k = 0; k < vertexCount; k++) { shape.getVertex(k, mTmp); vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER; vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER; } short[] triangleIndices = ect.computeTriangles(vertices).toArray(); PolygonRegion region = new PolygonRegion(textureRegion, vertices, triangleIndices); PolySpatial spatial = new PolySpatial(region, body, Color.WHITE); polySpatials.add(spatial); } } else if (fixture.getType() == Shape.Type.Circle) { CircleShape shape = (CircleShape) fixture.getShape(); float radius = shape.getRadius(); int vertexCount = (int) (12f * radius); float[] vertices = new float[vertexCount * 2]; System.out.println("SpatialFactory: radius: " + radius); if (body.getType() == BodyType.StaticBody) { mTmp3.set(shape.getPosition()); for (int k = 0; k < vertexCount; k++) { // set the initial position mTmp.set(radius, 0); // rotate it by 1/vertexCount * k mTmp.rotate(360f * k / vertexCount); // add it to the position. mTmp.rotate(body.getAngle() * MathUtils.radiansToDegrees); mTmp.add(mTmp3); mTmp.add( bodyPos); // convert local coordinates to world coordinates to that textures // are aligned vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER; vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER; } short[] triangleIndices = ect.computeTriangles(vertices).toArray(); PolygonRegion region = new PolygonRegion(textureRegion, vertices, triangleIndices); PolySpatial spatial = new PolySpatial(region, Color.WHITE); polySpatials.add(spatial); } else { mTmp3.set(shape.getPosition()); for (int k = 0; k < vertexCount; k++) { // set the initial position mTmp.set(radius, 0); // rotate it by 1/vertexCount * k mTmp.rotate(360f * k / vertexCount); // add it to the position. mTmp.add(mTmp3); vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER; vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER; } short[] triangleIndices = ect.computeTriangles(vertices).toArray(); PolygonRegion region = new PolygonRegion(textureRegion, vertices, triangleIndices); PolySpatial spatial = new PolySpatial(region, body, Color.WHITE); polySpatials.add(spatial); } } } } } } } }