/** @param arrayId index of the array argument to increment. */ private void incrementIndex(final int arrayId) { indexes.set(arrayId, indexes.get(arrayId) + 1); if (arrayId > 0 && indexes.get(arrayId) == values.get(arrayId).length) { indexes.set(arrayId, 0); incrementIndex(arrayId - 1); } }
int obtainSource(boolean isMusic) { if (noDevice) return 0; for (int i = 0, n = idleSources.size; i < n; i++) { int sourceId = idleSources.get(i); int state = alGetSourcei(sourceId, AL_SOURCE_STATE); if (state != AL_PLAYING && state != AL_PAUSED) { if (isMusic) { idleSources.removeIndex(i); } else { if (sourceToSoundId.containsKey(sourceId)) { long soundId = sourceToSoundId.get(sourceId); sourceToSoundId.remove(sourceId); soundIdToSource.remove(soundId); } long soundId = nextSoundId++; sourceToSoundId.put(sourceId, soundId); soundIdToSource.put(soundId, sourceId); } alSourceStop(sourceId); alSourcei(sourceId, AL_BUFFER, 0); AL10.alSourcef(sourceId, AL10.AL_GAIN, 1); AL10.alSourcef(sourceId, AL10.AL_PITCH, 1); AL10.alSource3f(sourceId, AL10.AL_POSITION, 0, 0, 1f); return sourceId; } } return -1; }
private boolean isEarTip(int earTipIndex) { IntArray vertexTypes = this.vertexTypes; if (vertexTypes.get(earTipIndex) == CONCAVE) return false; int previousIndex = previousIndex(earTipIndex); int nextIndex = nextIndex(earTipIndex); float[] vertices = this.vertices; float p1x = vertices[previousIndex * 2]; float p1y = vertices[previousIndex * 2 + 1]; float p2x = vertices[earTipIndex * 2]; float p2y = vertices[earTipIndex * 2 + 1]; float p3x = vertices[nextIndex * 2]; float p3y = vertices[nextIndex * 2 + 1]; // Check if any point is inside the triangle formed by previous, current and next vertices. // Only consider vertices that are not part of this triangle, or else we'll always find one // inside. for (int i = nextIndex(nextIndex); i != previousIndex; i = nextIndex(i)) { // Concave vertices can obviously be inside the candidate ear, but so can tangential vertices // if they coincide with one of the triangle's vertices. if (vertexTypes.get(i) != CONVEX) { float vx = vertices[i * 2]; float vy = vertices[i * 2 + 1]; // Because the polygon has clockwise winding order, the area sign will be positive if the // point is strictly inside. // It will be 0 on the edge, which we want to include as well. if (computeSpannedAreaSign(p1x, p1y, p2x, p2y, vx, vy) >= 0) { if (computeSpannedAreaSign(p2x, p2y, p3x, p3y, vx, vy) >= 0) { if (computeSpannedAreaSign(p3x, p3y, p1x, p1y, vx, vy) >= 0) return false; } } } } return true; }
private static IntArray createFromCSV(String values) { IntArray list = new IntArray(false, (values.length() + 1) / 2); StringTokenizer st = new StringTokenizer(values, ","); while (st.hasMoreTokens()) { list.add(Integer.parseInt(st.nextToken())); } list.shrink(); return list; }
@Override public long loop(float volume) { if (streamIds.size == 8) streamIds.pop(); int streamId = soundPool.play(soundId, volume, volume, 1, -1, 1); // standardise error code with other backends if (streamId == 0) return -1; streamIds.insert(0, streamId); return streamId; }
private int addBlock(int[][] layer, int layerNum, int blockRow, int blockCol, boolean blended) { int tile; AtlasRegion region; cache.beginCache(); int firstCol = blockCol * tilesPerBlockX; int firstRow = blockRow * tilesPerBlockY; int lastCol = firstCol + tilesPerBlockX; int lastRow = firstRow + tilesPerBlockY; int row, col; float x, y; for (row = firstRow; row < lastRow && row < layer.length; row++) { for (col = firstCol; col < lastCol && col < layer[row].length; col++) { tile = layer[row][col]; if (tile != 0) { if (blended == blendedTiles.contains(tile)) { region = atlas.getRegion(tile); if (region != null) { y = (layer.length - row) * tileHeight - (region.packedHeight + region.offsetY); x = col * tileWidth + region.offsetX; cache.add(region, x, y); } } } } } return cache.endCache(); }
void pauseSourcesWithBuffer(int bufferID) { if (noDevice) return; for (int i = 0, n = idleSources.size; i < n; i++) { int sourceID = idleSources.get(i); if (alGetSourcei(sourceID, AL_BUFFER) == bufferID) alSourcePause(sourceID); } }
@Override protected boolean hasNext() { if (GdxArrays.isEmpty(indexes)) { return false; } return indexes.first() < values.first().length; }
@Override public long loop(float volume, float pitch, float pan) { if (streamIds.size == 8) streamIds.pop(); float leftVolume = volume; float rightVolume = volume; if (pan < 0) { rightVolume *= (1 - Math.abs(pan)); } else if (pan > 0) { leftVolume *= (1 - Math.abs(pan)); } int streamId = soundPool.play(soundId, leftVolume, rightVolume, 1, -1, pitch); // standardise error code with other backends if (streamId == 0) return -1; streamIds.insert(0, streamId); return streamId; }
@Override protected void next(final ObjectMap<String, String> arguments) { for (int arrayId = 0, length = indexes.size; arrayId < length; arrayId++) { arguments.put(argumentNames.get(arrayId), values.get(arrayId)[indexes.get(arrayId)]); } incrementIndex(indexes.size - 1); currentIndex++; }
private void fillArrays() { for (final Entry<String, String> attribute : getNamedAttributes()) { indexes.add(0); argumentNames.add(attribute.key); final String[] array = getParser().parseArray(attribute.value, getActor()); values.add(array); } }
private int findEarTip() { for (int i = 0, n = vertexCount; i < n; i++) if (isEarTip(i)) return i; // Desperate mode: if no vertex is an ear tip, we are dealing with a degenerate polygon (e.g. // nearly collinear). // Note that the input was not necessarily degenerate, but we could have made it so by clipping // some valid ears. // Idea taken from Martin Held, "FIST: Fast industrial-strength triangulation of polygons", // Algorithmica (1998), // http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.115.291 // Return a convex or tangential vertex if one exists. IntArray vertexTypes = this.vertexTypes; for (int i = 0, n = vertexCount; i < n; i++) if (vertexTypes.get(i) != CONCAVE) return i; return 0; // If all vertices are concave, just return the first one. }
void resumeSourcesWithBuffer(int bufferID) { if (noDevice) return; for (int i = 0, n = idleSources.size; i < n; i++) { int sourceID = idleSources.get(i); if (alGetSourcei(sourceID, AL_BUFFER) == bufferID) { if (alGetSourcei(sourceID, AL_SOURCE_STATE) == AL_PAUSED) alSourcePlay(sourceID); } } }
void freeSource(int sourceID) { if (noDevice) return; alSourceStop(sourceID); alSourcei(sourceID, AL_BUFFER, 0); if (sourceToSoundId.containsKey(sourceID)) { long soundId = sourceToSoundId.remove(sourceID); soundIdToSource.remove(soundId); } idleSources.add(sourceID); }
void stopSourcesWithBuffer(int bufferID) { if (noDevice) return; for (int i = 0, n = idleSources.size; i < n; i++) { int sourceID = idleSources.get(i); if (alGetSourcei(sourceID, AL_BUFFER) == bufferID) { if (sourceToSoundId.containsKey(sourceID)) { long soundId = sourceToSoundId.remove(sourceID); soundIdToSource.remove(soundId); } alSourceStop(sourceID); } } }
public OpenALAudio(int simultaneousSources, int deviceBufferCount, int deviceBufferSize) { this.deviceBufferSize = deviceBufferSize; this.deviceBufferCount = deviceBufferCount; registerSound("ogg", Ogg.Sound.class); registerMusic("ogg", Ogg.Music.class); registerSound("wav", Wav.Sound.class); registerMusic("wav", Wav.Music.class); registerSound("mp3", Mp3.Sound.class); registerMusic("mp3", Mp3.Music.class); try { AL.create(); } catch (LWJGLException ex) { noDevice = true; ex.printStackTrace(); return; } allSources = new IntArray(false, simultaneousSources); for (int i = 0; i < simultaneousSources; i++) { int sourceID = alGenSources(); if (alGetError() != AL_NO_ERROR) break; allSources.add(sourceID); } idleSources = new IntArray(allSources); soundIdToSource = new LongMap<Integer>(); sourceToSoundId = new IntMap<Long>(); FloatBuffer orientation = (FloatBuffer) BufferUtils.createFloatBuffer(6) .put(new float[] {0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f}) .flip(); alListener(AL_ORIENTATION, orientation); FloatBuffer velocity = (FloatBuffer) BufferUtils.createFloatBuffer(3).put(new float[] {0.0f, 0.0f, 0.0f}).flip(); alListener(AL_VELOCITY, velocity); FloatBuffer position = (FloatBuffer) BufferUtils.createFloatBuffer(3).put(new float[] {0.0f, 0.0f, 0.0f}).flip(); alListener(AL_POSITION, position); recentSounds = new OpenALSound[simultaneousSources]; }
public void dispose() { if (noDevice) return; for (int i = 0, n = allSources.size; i < n; i++) { int sourceID = allSources.get(i); int state = alGetSourcei(sourceID, AL_SOURCE_STATE); if (state != AL_STOPPED) alSourceStop(sourceID); alDeleteSources(sourceID); } sourceToSoundId.clear(); soundIdToSource.clear(); AL.destroy(); while (AL.isCreated()) { try { Thread.sleep(10); } catch (InterruptedException e) { } } }
private void cutEarTip(int earTipIndex) { float[] vertices = this.vertices; FloatArray triangles = this.triangles; int previousIndex = previousIndex(earTipIndex) * 2; int nextIndex = nextIndex(earTipIndex) * 2; vertexTypes.removeIndex(earTipIndex); vertexCount--; triangles.add(vertices[previousIndex]); triangles.add(vertices[previousIndex + 1]); earTipIndex *= 2; triangles.add(vertices[earTipIndex]); triangles.add(vertices[earTipIndex + 1]); triangles.add(vertices[nextIndex]); triangles.add(vertices[nextIndex + 1]); // Remove both indexes with a single copy. verticesArray.size -= 2; System.arraycopy( vertices, earTipIndex + 2, vertices, earTipIndex, verticesArray.size - earTipIndex); }
private FloatArray computeTriangles() { FloatArray verticesArray = this.verticesArray; float[] vertices = this.vertices = verticesArray.items; IntArray vertexTypes = this.vertexTypes; vertexCount = verticesArray.size / 2; vertexTypes.ensureCapacity(vertexCount); for (int i = 0, n = vertexCount; i < n; ++i) vertexTypes.add(classifyVertex(i)); FloatArray triangles = this.triangles; triangles.clear(); // A polygon with n vertices has a triangulation of n-2 triangles. triangles.ensureCapacity(Math.max(0, vertexCount - 2) * 3 * 2); while (vertexCount > 3) { int earTipIndex = findEarTip(); cutEarTip(earTipIndex); // The type of the two vertices adjacent to the clipped vertex may have changed. int previousIndex = previousIndex(earTipIndex); int nextIndex = earTipIndex == vertexCount ? 0 : earTipIndex; vertexTypes.set(previousIndex, classifyVertex(previousIndex)); vertexTypes.set(nextIndex, classifyVertex(nextIndex)); } if (vertexCount == 3) { triangles.add(vertices[0]); triangles.add(vertices[1]); triangles.add(vertices[2]); triangles.add(vertices[3]); triangles.add(vertices[4]); triangles.add(vertices[5]); } verticesArray.clear(); vertexTypes.clear(); return triangles; }
private SubMesh[] generateSubMeshes(Mesh ogreMesh) { List<Submesh> ogreSubmeshes = ogreMesh.getSubmeshes().getSubmesh(); SubMesh[] submeshes = new SubMesh[ogreSubmeshes.size()]; for (int i = 0; i < ogreSubmeshes.size(); i++) { Submesh ogreSubmesh = ogreSubmeshes.get(i); boolean usesTriangleList = false; if (ogreSubmesh.use32Bitindexes) throw new GdxRuntimeException("submesh '" + i + "' uses 32-bit indices"); if (ogreSubmesh.getOperationtype().equals("triangle_list")) { usesTriangleList = true; } short[] indices = new short[ogreSubmesh.getFaces().count * (usesTriangleList ? 3 : 1)]; for (int j = 0, idx = 0; j < ogreSubmesh.getFaces().count; j++) { Face face = ogreSubmesh.getFaces().getFace().get(j); indices[idx++] = face.v1; if (usesTriangleList || j == 0) { indices[idx++] = face.v2; indices[idx++] = face.v3; } } List<VertexAttribute> attributes = new ArrayList<VertexAttribute>(); IntArray offsets = new IntArray(); int offset = 0; BaseGeometry geom; if (ogreSubmesh.useSharedVertices) { geom = ogreMesh.getSharedgeometry(); } else { geom = ogreSubmesh.getGeometry(); } for (int j = 0; j < geom.getVertexbuffer().size(); j++) { Vertexbuffer buffer = geom.getVertexbuffer().get(j); offsets.add(offset); if (buffer.positions) { attributes.add(new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE)); offset += 3; } if (buffer.normals) { attributes.add(new VertexAttribute(Usage.Normal, 3, ShaderProgram.NORMAL_ATTRIBUTE)); offset += 3; } if (buffer.tangents) { attributes.add( new VertexAttribute( Usage.Generic, buffer.tangentDimensions, ShaderProgram.TANGENT_ATTRIBUTE)); offset += buffer.tangentDimensions; } if (buffer.binormals) { attributes.add(new VertexAttribute(Usage.Generic, 3, ShaderProgram.BINORMAL_ATTRIBUTE)); offset += 3; } if (buffer.coloursDiffuse) { attributes.add(new VertexAttribute(Usage.ColorPacked, 4, ShaderProgram.COLOR_ATTRIBUTE)); offset += 4; } for (int k = 0; k < buffer.textureCoords; k++) { try { int numTexCoords = 0; switch (k) { case 0: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions0()); break; case 1: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions1()); break; case 2: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions2()); break; case 3: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions3()); break; case 4: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions4()); break; case 5: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions5()); break; case 6: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions6()); break; case 7: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions7()); break; } attributes.add( new VertexAttribute( Usage.TextureCoordinates, numTexCoords, ShaderProgram.TEXCOORD_ATTRIBUTE + k)); offset += numTexCoords; } catch (NumberFormatException e) { throw new GdxRuntimeException( "Can't process texture coords with dimensions != 1, 2, 3, 4 (e.g. float1)"); } } } VertexAttributes attribs = new VertexAttributes(attributes.toArray(new VertexAttribute[0])); int vertexSize = offset; float[] vertices = new float[geom.getVertexCount() * offset]; for (int j = 0; j < geom.getVertexbuffer().size(); j++) { Vertexbuffer buffer = geom.getVertexbuffer().get(j); offset = offsets.get(j); int idx = offset; for (int k = 0; k < buffer.getVertex().size(); k++) { Vertex v = buffer.getVertex().get(k); if (v.getPosition() != null) { vertices[idx++] = v.getPosition().x; vertices[idx++] = v.getPosition().y; vertices[idx++] = v.getPosition().z; } if (v.getNormal() != null) { vertices[idx++] = v.getNormal().x; vertices[idx++] = v.getNormal().y; vertices[idx++] = v.getNormal().z; } if (v.getTangent() != null) { vertices[idx++] = v.getTangent().x; vertices[idx++] = v.getTangent().y; vertices[idx++] = v.getTangent().z; if (buffer.tangentDimensions == 4) vertices[idx++] = v.getTangent().w; } if (v.getBinormal() != null) { vertices[idx++] = v.getBinormal().x; vertices[idx++] = v.getBinormal().y; vertices[idx++] = v.getBinormal().z; } if (v.getColourDiffuse() != null) { float color = getColor(v.getColourDiffuse()); vertices[idx++] = color; } if (v.getTexcoord() != null) { for (int l = 0; l < v.getTexcoord().size(); l++) { Texcoord texCoord = v.getTexcoord().get(l); int numTexCoords = 0; switch (l) { case 0: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions0()); break; case 1: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions1()); break; case 2: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions2()); break; case 3: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions3()); break; case 4: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions4()); break; case 5: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions5()); break; case 6: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions6()); break; case 7: numTexCoords = Integer.valueOf(buffer.getTextureCoordDimensions7()); break; } if (numTexCoords == 1) { vertices[idx++] = texCoord.u; } if (numTexCoords == 2) { vertices[idx++] = texCoord.u; vertices[idx++] = texCoord.v; } if (numTexCoords == 3) { vertices[idx++] = texCoord.u; vertices[idx++] = texCoord.v; vertices[idx++] = texCoord.w; } if (numTexCoords == 4) { vertices[idx++] = texCoord.u; vertices[idx++] = texCoord.v; vertices[idx++] = texCoord.w; vertices[idx++] = texCoord.x; } } } offset += vertexSize; idx = offset; } } com.badlogic.gdx.graphics.Mesh mesh = new com.badlogic.gdx.graphics.Mesh( false, vertices.length / vertexSize, indices.length, attribs); mesh.setIndices(indices); mesh.setVertices(vertices); String meshName = ""; if (ogreMesh.getSubmeshnames() != null) { List<Submeshname> names = ogreMesh.getSubmeshnames().getSubmeshname(); for (int n = 0; n < names.size(); ++n) { if (Integer.parseInt(names.get(n).getIndex()) == i) meshName = names.get(n).getName(); } } SubMesh subMesh; Boneassignments boneAssigments = (ogreSubmesh.getBoneassignments() != null) ? ogreSubmesh.getBoneassignments() : ogreMesh.getBoneassignments(); if (boneAssigments != null) { subMesh = new SkeletonSubMesh(meshName, mesh, GL10.GL_TRIANGLES); } else { subMesh = new StillSubMesh(meshName, mesh, GL10.GL_TRIANGLES); } // FIXME ? subMesh.materialName = ogreSubmesh.material; if (boneAssigments != null) { SkeletonSubMesh subSkelMesh = (SkeletonSubMesh) subMesh; subSkelMesh.setVertices(vertices); subSkelMesh.setIndices(indices); subSkelMesh.skinnedVertices = new float[vertices.length]; System.arraycopy( subSkelMesh.vertices, 0, subSkelMesh.skinnedVertices, 0, subSkelMesh.vertices.length); loadBones(boneAssigments, subSkelMesh); } if (ogreSubmesh.getOperationtype().equals("triangle_list")) subMesh.primitiveType = GL10.GL_TRIANGLES; if (ogreSubmesh.getOperationtype().equals("triangle_fan")) subMesh.primitiveType = GL10.GL_TRIANGLE_FAN; if (ogreSubmesh.getOperationtype().equals("triangle_strip")) subMesh.primitiveType = GL10.GL_TRIANGLE_STRIP; submeshes[i] = subMesh; } return submeshes; }
private int addBlock(int[][] layer, int blockRow, int blockCol, boolean blended) { cache.beginCache(); int firstCol = blockCol * tilesPerBlockX; int firstRow = blockRow * tilesPerBlockY; int lastCol = firstCol + tilesPerBlockX; int lastRow = firstRow + tilesPerBlockY; float offsetX = ((tileWidth - unitsPerTileX) / 2); float offsetY = ((tileHeight - unitsPerTileY) / 2); for (int row = firstRow; row < lastRow && row < layer.length; row++) { for (int col = firstCol; col < lastCol && col < layer[row].length; col++) { int tile = layer[row][col]; boolean flipX = ((tile & FLAG_FLIP_X) != 0); boolean flipY = ((tile & FLAG_FLIP_Y) != 0); boolean rotate = ((tile & FLAG_ROTATE) != 0); tile = tile & ~MASK_CLEAR; if (tile != 0) { if (blended == blendedTiles.contains(tile)) { TextureRegion reg = atlas.getRegion(tile); if (reg != null) { float x = col * unitsPerTileX - offsetX; float y = (layer.length - row - 1) * unitsPerTileY - offsetY; float width = reg.getRegionWidth(); float height = reg.getRegionHeight(); float originX = width * 0.5f; float originY = height * 0.5f; float scaleX = unitsPerTileX / tileWidth; float scaleY = unitsPerTileY / tileHeight; float rotation = 0; int sourceX = reg.getRegionX(); int sourceY = reg.getRegionY(); int sourceWidth = reg.getRegionWidth(); int sourceHeight = reg.getRegionHeight(); if (rotate) { if (flipX && flipY) { rotation = -90; sourceX += sourceWidth; sourceWidth = -sourceWidth; } else if (flipX && !flipY) { rotation = -90; } else if (flipY && !flipX) { rotation = +90; } else if (!flipY && !flipX) { rotation = -90; sourceY += sourceHeight; sourceHeight = -sourceHeight; } } else { if (flipX) { sourceX += sourceWidth; sourceWidth = -sourceWidth; } if (flipY) { sourceY += sourceHeight; sourceHeight = -sourceHeight; } } cache.add( reg.getTexture(), x, y, originX, originY, width, height, scaleX, scaleY, rotation, sourceX, sourceY, sourceWidth, sourceHeight, false, false); } } } } } return cache.endCache(); }
public void stop() { for (int i = 0, n = streamIds.size; i < n; i++) soundPool.stop(streamIds.get(i)); }
private Attachment readAttachment( DataInput input, Skin skin, String attachmentName, boolean nonessential) throws IOException { float scale = this.scale; String name = input.readString(); if (name == null) name = attachmentName; switch (AttachmentType.values()[input.readByte()]) { case region: { String path = input.readString(); if (path == null) path = name; RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path); if (region == null) return null; region.setPath(path); region.setX(input.readFloat() * scale); region.setY(input.readFloat() * scale); region.setScaleX(input.readFloat()); region.setScaleY(input.readFloat()); region.setRotation(input.readFloat()); region.setWidth(input.readFloat() * scale); region.setHeight(input.readFloat() * scale); Color.rgba8888ToColor(region.getColor(), input.readInt()); region.updateOffset(); return region; } case boundingbox: { BoundingBoxAttachment box = attachmentLoader.newBoundingBoxAttachment(skin, name); if (box == null) return null; box.setVertices(readFloatArray(input, scale)); return box; } case mesh: { String path = input.readString(); if (path == null) path = name; MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path); if (mesh == null) return null; mesh.setPath(path); float[] uvs = readFloatArray(input, 1); short[] triangles = readShortArray(input); float[] vertices = readFloatArray(input, scale); mesh.setVertices(vertices); mesh.setTriangles(triangles); mesh.setRegionUVs(uvs); mesh.updateUVs(); Color.rgba8888ToColor(mesh.getColor(), input.readInt()); mesh.setHullLength(input.readInt(true) * 2); if (nonessential) { mesh.setEdges(readIntArray(input)); mesh.setWidth(input.readFloat() * scale); mesh.setHeight(input.readFloat() * scale); } return mesh; } case skinnedmesh: { String path = input.readString(); if (path == null) path = name; SkinnedMeshAttachment mesh = attachmentLoader.newSkinnedMeshAttachment(skin, name, path); if (mesh == null) return null; mesh.setPath(path); float[] uvs = readFloatArray(input, 1); short[] triangles = readShortArray(input); int vertexCount = input.readInt(true); FloatArray weights = new FloatArray(uvs.length * 3 * 3); IntArray bones = new IntArray(uvs.length * 3); for (int i = 0; i < vertexCount; i++) { int boneCount = (int) input.readFloat(); bones.add(boneCount); for (int nn = i + boneCount * 4; i < nn; i += 4) { bones.add((int) input.readFloat()); weights.add(input.readFloat() * scale); weights.add(input.readFloat() * scale); weights.add(input.readFloat()); } } mesh.setBones(bones.toArray()); mesh.setWeights(weights.toArray()); mesh.setTriangles(triangles); mesh.setRegionUVs(uvs); mesh.updateUVs(); Color.rgba8888ToColor(mesh.getColor(), input.readInt()); mesh.setHullLength(input.readInt(true) * 2); if (nonessential) { mesh.setEdges(readIntArray(input)); mesh.setWidth(input.readFloat() * scale); mesh.setHeight(input.readFloat() * scale); } return mesh; } } return null; }