private void aabbCompute () { float minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE; Array<FloatArray> polygons = this.polygons; for (int i = 0, n = polygons.size; i < n; i++) { FloatArray polygon = polygons.get(i); float[] vertices = polygon.items; for (int ii = 0, nn = polygon.size; ii < nn; ii += 2) { float x = vertices[ii]; float y = vertices[ii + 1]; minX = Math.min(minX, x); minY = Math.min(minY, y); maxX = Math.max(maxX, x); maxY = Math.max(maxY, y); } } this.minX = minX; this.minY = minY; this.maxX = maxX; this.maxY = maxY; }
/** Returns true if the polygon contains the point. */ public boolean containsPoint (FloatArray polygon, float x, float y) { float[] vertices = polygon.items; int nn = polygon.size; int prevIndex = nn - 2; boolean inside = false; for (int ii = 0; ii < nn; ii += 2) { float vertexY = vertices[ii + 1]; float prevY = vertices[prevIndex + 1]; if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { float vertexX = vertices[ii]; if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; } prevIndex = ii; } return inside; }
/** Returns true if the polygon contains any part of the line segment. */ public boolean intersectsSegment (FloatArray polygon, float x1, float y1, float x2, float y2) { float[] vertices = polygon.items; int nn = polygon.size; float width12 = x1 - x2, height12 = y1 - y2; float det1 = x1 * y2 - y1 * x2; float x3 = vertices[nn - 2], y3 = vertices[nn - 1]; for (int ii = 0; ii < nn; ii += 2) { float x4 = vertices[ii], y4 = vertices[ii + 1]; float det2 = x3 * y4 - y3 * x4; float width34 = x3 - x4, height34 = y3 - y4; float det3 = width12 * height34 - height12 * width34; float x = (det1 * width34 - width12 * det2) / det3; if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { float y = (det1 * height34 - height12 * det2) / det3; if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; } x3 = x4; y3 = y4; } return false; }
private Vertices readVertices (DataInput input, int vertexCount) throws IOException { int verticesLength = vertexCount << 1; Vertices vertices = new Vertices(); if (!input.readBoolean()) { vertices.vertices = readFloatArray(input, verticesLength, scale); return vertices; } FloatArray weights = new FloatArray(verticesLength * 3 * 3); IntArray bonesArray = new IntArray(verticesLength * 3); for (int i = 0; i < vertexCount; i++) { int boneCount = input.readInt(true); bonesArray.add(boneCount); for (int ii = 0; ii < boneCount; ii++) { bonesArray.add(input.readInt(true)); weights.add(input.readFloat() * scale); weights.add(input.readFloat() * scale); weights.add(input.readFloat()); } } vertices.vertices = weights.toArray(); vertices.bones = bonesArray.toArray(); return vertices; }
private void readVertices (JsonValue map, VertexAttachment attachment, int verticesLength) { attachment.setWorldVerticesLength(verticesLength); float[] vertices = map.require("vertices").asFloatArray(); if (verticesLength == vertices.length) { if (scale != 1) { for (int i = 0, n = vertices.length; i < n; i++) vertices[i] *= scale; } attachment.setVertices(vertices); return; } FloatArray weights = new FloatArray(verticesLength * 3 * 3); IntArray bones = new IntArray(verticesLength * 3); for (int i = 0, n = vertices.length; i < n;) { int boneCount = (int)vertices[i++]; bones.add(boneCount); for (int nn = i + boneCount * 4; i < nn; i += 4) { bones.add((int)vertices[i]); weights.add(vertices[i + 1] * scale); weights.add(vertices[i + 2] * scale); weights.add(vertices[i + 3]); } } attachment.setBones(bones.toArray()); attachment.setVertices(weights.toArray()); }
public float[] getFlatPixelArray() { FloatArray floats = new FloatArray(); flatPixelArray = new float[width * height * 3]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { float r = pixels[y][x][0]; float g = pixels[y][x][1]; float b = pixels[y][x][2]; floats.addAll(r, g, b); } } for (int i = 0; i < floats.size; i++) { flatPixelArray[i] = floats.get(i); } floats.clear(); return flatPixelArray; }
/** Creates chain light from specified vertices * * @param rayHandler not {@code null} instance of RayHandler * @param rays number of rays - more rays make light to look more realistic but will decrease performance, can't be less than * MIN_RAYS * @param color color, set to {@code null} to use the default color * @param distance distance of light * @param rayDirection direction of rays * <ul> * <li>1 = left</li> * <li>-1 = right</li> * </ul> * @param chain float array of (x, y) vertices from which rays will be evenly distributed */ public RavChainLight (RayHandler rayHandler, int rays, Color color, float distance, int rayDirection, float[] chain) { super(rayHandler, rays, color, distance, 0f); rayStartOffset = ChainLight.defaultRayStartOffset; this.rayDirection = rayDirection; vertexNum = (vertexNum - 1) * 2; endX = new float[rays]; endY = new float[rays]; startX = new float[rays]; startY = new float[rays]; this.chain = (chain != null) ? new FloatArray(chain) : new FloatArray(); lightMesh = new Mesh(VertexDataType.VertexArray, false, vertexNum, 0, new VertexAttribute(Usage.Position, 2, "vertex_positions"), new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"), new VertexAttribute(Usage.Generic, 1, "s")); softShadowMesh = new Mesh(VertexDataType.VertexArray, false, vertexNum * 2, 0, new VertexAttribute(Usage.Position, 2, "vertex_positions"), new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"), new VertexAttribute(Usage.Generic, 1, "s")); setMesh(); }
/** Draws a polygon, using ray start and end points as vertices */ public void debugRender (PolygonShapeRenderer shapeRenderer) { shapeRenderer.setColor(Color.BLUE); FloatArray vertices = Pools.obtain(FloatArray.class); vertices.clear(); for (int i = 0; i < rayNum; i++) { vertices.addAll(mx[i], my[i]); } for (int i = rayNum - 1; i > -1; i--) { vertices.addAll(startX[i], startY[i]); } vertices.add(vertices.get(0)); vertices.add(vertices.get(1)); shapeRenderer.polyline(vertices.shrink()); Pools.free(vertices); }
/** Returns true if the polygon contains the line segment. */ public boolean intersectsSegment (FloatArray polygon, float x1, float y1, float x2, float y2) { float[] vertices = polygon.items; int nn = polygon.size; float width12 = x1 - x2, height12 = y1 - y2; float det1 = x1 * y2 - y1 * x2; float x3 = vertices[nn - 2], y3 = vertices[nn - 1]; for (int ii = 0; ii < nn; ii += 2) { float x4 = vertices[ii], y4 = vertices[ii + 1]; float det2 = x3 * y4 - y3 * x4; float width34 = x3 - x4, height34 = y3 - y4; float det3 = width12 * height34 - height12 * width34; float x = (det1 * width34 - width12 * det2) / det3; if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { float y = (det1 * height34 - height12 * det2) / det3; if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; } x3 = x4; y3 = y4; } return false; }
/** @see #intersectSegments(float, float, float, float, float[], boolean, com.badlogic.gdx.utils.FloatArray) */ public static void intersectSegments(Vector2 a, Vector2 b, float[] segments, boolean polygon, Array<Vector2> intersections) { FloatArray fa = Pools.obtain(FloatArray.class); intersectSegments(a.x, a.y, b.x, b.y, segments, polygon, fa); if(fa.size < 1) { intersections.clear(); Pools.free(fa); return; } intersections.ensureCapacity(fa.size / 2 - intersections.size); for(int i = 1; i < fa.size; i += 2) if(intersections.size > i / 2) intersections.get(i / 2).set(fa.get(i - 1), fa.get(i)); else intersections.add(new Vector2(fa.get(i - 1), fa.get(i))); Pools.free(fa); }
/** @param segments the segments * @param polygon if the segments represent a closed polygon * @param intersections the array to store the intersections in */ public static void intersectSegments(float x1, float y1, float x2, float y2, float[] segments, boolean polygon, FloatArray intersections) { if(polygon && segments.length < 6) throw new IllegalArgumentException("a polygon consists of at least 3 points: " + segments.length); else if(segments.length < 4) throw new IllegalArgumentException("segments does not contain enough vertices to represent at least one segment: " + segments.length); if(segments.length % 2 != 0) throw new IllegalArgumentException("malformed segments; the number of vertices is not dividable by 2: " + segments.length); intersections.clear(); Vector2 tmp = Pools.obtain(Vector2.class); for(int i = 0, n = segments.length - (polygon ? 0 : 2); i < n; i += 2) { float x3 = segments[i], y3 = segments[i + 1], x4 = wrapIndex(i + 2, segments), y4 = wrapIndex(i + 3, segments); if(Intersector.intersectSegments(x1, y1, x2, y2, x3, y3, x4, y4, tmp)) { intersections.add(tmp.x); intersections.add(tmp.y); } } Pools.free(tmp); }
@Override public void mesh() { if (meshRequest && !meshing) { if (!loaded) return; meshing = true; opaqueMeshData = new FloatArray(); transpMeshData = new FloatArray(); try { getVertices(); int opaqueNumVerts = opaqueMeshData.size / VERTEX_SIZE; int transpNumVerts = transpMeshData.size / VERTEX_SIZE; opaqueVerts = opaqueNumVerts / 4 * 6; transpVerts = transpNumVerts / 4 * 6; meshRequest = false; doneMeshing = true; meshing = false; } catch (Exception e) { meshing = true; } } }
public static void buildMeshes() { if (indices == null) { int len = 3 * 6 * 6 / 3; indices = new short[len]; short j = 0; for (int i = 0; i < len; i += 6, j += 4) { indices[i + 0] = (short) (j + 0); indices[i + 1] = (short) (j + 1); indices[i + 2] = (short) (j + 2); indices[i + 3] = (short) (j + 2); indices[i + 4] = (short) (j + 3); indices[i + 5] = (short) (j + 0); } } for (Voxel v : voxels.values()) { v.mesh = new Mesh(true, 24, indices.length, VertexAttribute.Position(), VertexAttribute.Normal(), VertexAttribute.ColorPacked(), VertexAttribute.TexCoords(0), VertexAttribute.TexCoords(1)); v.mesh.setIndices(indices); verts = new FloatArray(); for (Direction d : Direction.values()) new TextureFace(d, new Vector3(), v.getTextureUV(0, 0, 0, d)).getVertexData(verts); v.mesh.setVertices(verts.items, 0, verts.size); } }
public void update (Skeleton skeleton, boolean updateAabb) { if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); Array<BoundingBoxAttachment> boundingBoxes = this.boundingBoxes; Array<FloatArray> polygons = this.polygons; Array<Slot> slots = skeleton.slots; int slotCount = slots.size; boundingBoxes.clear(); polygonPool.freeAll(polygons); polygons.clear(); for (int i = 0; i < slotCount; i++) { Slot slot = slots.get(i); Attachment attachment = slot.attachment; if (attachment instanceof BoundingBoxAttachment) { BoundingBoxAttachment boundingBox = (BoundingBoxAttachment)attachment; boundingBoxes.add(boundingBox); FloatArray polygon = polygonPool.obtain(); polygons.add(polygon); boundingBox.computeWorldVertices(slot, polygon.setSize(boundingBox.getWorldVerticesLength())); } } if (updateAabb) aabbCompute(); }
/** * Calculates the travel time of each segment to allow for * smooth lerping along the path between 0 and 1 */ private void calculateTimes() { //find total length of the path float length = 0, dst = 0; for (int i = 1; i < points.size; i++) { dst = points.get(i).dst(points.get(i-1)); length += dst; } //calculate percentage that each segment takes of the path's total length times = new FloatArray(); times.add(0); float l = 0; for (int i = 1; i < points.size; i++) { dst = points.get(i).dst(points.get(i-1)); l += dst; times.add(l/length); } }
private float a(FloatArray paramFloatArray, float paramFloat1, float paramFloat2, float paramFloat3) { int i1 = 0; if (i1 < paramFloatArray.size) { float f = paramFloatArray.items[i1]; if (Math.abs(f - paramFloat1) < this.e.getHeight()) if (f >= (paramFloat2 + paramFloat3) / 2.0F) break label67; label67: for (paramFloat1 += this.e.getHeight(); ; paramFloat1 -= this.e.getHeight()) { i1++; break; } } return paramFloat1; }
@Override public void write(Kryo kryo, Output output, FloatArray array) { output.writeVarInt(array.size, true); output.writeBoolean(array.ordered); for (int i = 0; i < array.size; i++) { output.writeFloat(array.get(i)); } }
@Override public FloatArray read(Kryo kryo, Input input, Class<FloatArray> type) { int length = input.readVarInt(true); boolean ordered = input.readBoolean(); FloatArray array = new FloatArray(ordered, length); for (int i = 0; i < length; i++) { array.add(input.readFloat()); } return array; }
/** Clears any previous polygons, finds all visible bounding box attachments, and computes the world vertices for each bounding * box's polygon. * @param updateAabb If true, the axis aligned bounding box containing all the polygons is computed. If false, the * SkeletonBounds AABB methods will always return true. */ public void update (Skeleton skeleton, boolean updateAabb) { if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); Array<BoundingBoxAttachment> boundingBoxes = this.boundingBoxes; Array<FloatArray> polygons = this.polygons; Array<Slot> slots = skeleton.slots; int slotCount = slots.size; boundingBoxes.clear(); polygonPool.freeAll(polygons); polygons.clear(); for (int i = 0; i < slotCount; i++) { Slot slot = slots.get(i); Attachment attachment = slot.attachment; if (attachment instanceof BoundingBoxAttachment) { BoundingBoxAttachment boundingBox = (BoundingBoxAttachment)attachment; boundingBoxes.add(boundingBox); FloatArray polygon = polygonPool.obtain(); polygons.add(polygon); boundingBox.computeWorldVertices(slot, polygon.setSize(boundingBox.getWorldVerticesLength())); } } if (updateAabb) aabbCompute(); else { minX = Integer.MIN_VALUE; minY = Integer.MIN_VALUE; maxX = Integer.MAX_VALUE; maxY = Integer.MAX_VALUE; } }
/** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ public BoundingBoxAttachment containsPoint (float x, float y) { Array<FloatArray> polygons = this.polygons; for (int i = 0, n = polygons.size; i < n; i++) if (containsPoint(polygons.get(i), x, y)) return boundingBoxes.get(i); return null; }
/** Returns the first bounding box attachment that contains any part of the line segment, or null. When doing many checks, it * is usually more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns * true. */ public BoundingBoxAttachment intersectsSegment (float x1, float y1, float x2, float y2) { Array<FloatArray> polygons = this.polygons; for (int i = 0, n = polygons.size; i < n; i++) if (intersectsSegment(polygons.get(i), x1, y1, x2, y2)) return boundingBoxes.get(i); return null; }
/** * Creates chain light from specified vertices * * @param rayHandler * not {@code null} instance of RayHandler * @param rays * number of rays - more rays make light to look more realistic * but will decrease performance, can't be less than MIN_RAYS * @param color * color, set to {@code null} to use the default color * @param distance * distance of light * @param rayDirection * direction of rays * <ul> * <li>1 = left</li> * <li>-1 = right</li> * </ul> * @param chain * float array of (x, y) vertices from which rays will be * evenly distributed */ public ChainLight(RayHandler rayHandler, int rays, Color color, float distance, int rayDirection, float[] chain) { super(rayHandler, rays, color, distance, 0f); rayStartOffset = ChainLight.defaultRayStartOffset; this.rayDirection = rayDirection; vertexNum = (vertexNum - 1) * 2; endX = new float[rays]; endY = new float[rays]; startX = new float[rays]; startY = new float[rays]; this.chain = (chain != null) ? new FloatArray(chain) : new FloatArray(); lightMesh = new Mesh( VertexDataType.VertexArray, false, vertexNum, 0, new VertexAttribute(Usage.Position, 2, "vertex_positions"), new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"), new VertexAttribute(Usage.Generic, 1, "s")); softShadowMesh = new Mesh( VertexDataType.VertexArray, false, vertexNum * 2, 0, new VertexAttribute(Usage.Position, 2, "vertex_positions"), new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"), new VertexAttribute(Usage.Generic, 1, "s")); setMesh(); }
/** * Draws a polygon, using ray start and end points as vertices */ public void debugRender(ShapeRenderer shapeRenderer) { shapeRenderer.setColor(Color.YELLOW); FloatArray vertices = Pools.obtain(FloatArray.class); vertices.clear(); for (int i = 0; i < rayNum; i++) { vertices.addAll(mx[i], my[i]); } for (int i = rayNum - 1; i > -1; i--) { vertices.addAll(startX[i], startY[i]); } shapeRenderer.polygon(vertices.shrink()); Pools.free(vertices); }
@Override public boolean contains(float x, float y) { // fast fail if (!this.chainLightBounds.contains(x, y)) return false; // actual check FloatArray vertices = Pools.obtain(FloatArray.class); vertices.clear(); for (int i = 0; i < rayNum; i++) { vertices.addAll(mx[i], my[i]); } for (int i = rayNum - 1; i > -1; i--) { vertices.addAll(startX[i], startY[i]); } int intersects = 0; for (int i = 0; i < vertices.size; i += 2) { float x1 = vertices.items[i]; float y1 = vertices.items[i + 1]; float x2 = vertices.items[(i + 2) % vertices.size]; float y2 = vertices.items[(i + 3) % vertices.size]; if (((y1 <= y && y < y2) || (y2 <= y && y < y1)) && x < ((x2 - x1) / (y2 - y1) * (y - y1) + x1)) intersects++; } boolean result = (intersects & 1) == 1; Pools.free(vertices); return result; }
/** * Resizes list to exact size, filling with given value when expanding. */ public static void resize(FloatArray list, int size, float value) { while (list.size < size) { list.add(value); } while (list.size > size) { list.removeIndex(list.size - 1); } }
@Override public boolean contains (float x, float y) { // fast fail if (!this.chainLightBounds.contains(x, y)) return false; // actual check FloatArray vertices = Pools.obtain(FloatArray.class); vertices.clear(); for (int i = 0; i < rayNum; i++) { vertices.addAll(mx[i], my[i]); } for (int i = rayNum - 1; i > -1; i--) { vertices.addAll(startX[i], startY[i]); } int intersects = 0; for (int i = 0; i < vertices.size; i += 2) { float x1 = vertices.items[i]; float y1 = vertices.items[i + 1]; float x2 = vertices.items[(i + 2) % vertices.size]; float y2 = vertices.items[(i + 3) % vertices.size]; if (((y1 <= y && y < y2) || (y2 <= y && y < y1)) && x < ((x2 - x1) / (y2 - y1) * (y - y1) + x1)) intersects++; } boolean result = (intersects & 1) == 1; Pools.free(vertices); return result; }
public void update (Skeleton skeleton, boolean updateAabb) { Array<BoundingBoxAttachment> boundingBoxes = this.boundingBoxes; Array<FloatArray> polygons = this.polygons; Array<Slot> slots = skeleton.slots; int slotCount = slots.size; boundingBoxes.clear(); polygonPool.freeAll(polygons); polygons.clear(); for (int i = 0; i < slotCount; i++) { Slot slot = slots.get(i); Attachment attachment = slot.attachment; if (attachment instanceof BoundingBoxAttachment) { BoundingBoxAttachment boundingBox = (BoundingBoxAttachment)attachment; boundingBoxes.add(boundingBox); FloatArray polygon = polygonPool.obtain(); polygons.add(polygon); int vertexCount = boundingBox.getVertices().length; polygon.ensureCapacity(vertexCount); polygon.size = vertexCount; boundingBox.computeWorldVertices(slot.bone, polygon.items); } } if (updateAabb) aabbCompute(); }
/** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually * more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. */ public BoundingBoxAttachment intersectsSegment (float x1, float y1, float x2, float y2) { Array<FloatArray> polygons = this.polygons; for (int i = 0, n = polygons.size; i < n; i++) if (intersectsSegment(polygons.get(i), x1, y1, x2, y2)) return boundingBoxes.get(i); return null; }