/** * Copyright 2008 - 2012 * * Licensed under the Apache License, Version SIZEOF_SHORT.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-SIZEOF_SHORT.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.3.3 */ package loon.jni; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; import java.nio.DoubleBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.LongBuffer; import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.HashSet; import java.util.zip.CRC32; import loon.core.graphics.device.LColor; import loon.core.resource.Resources; //自0.3.3起,将部分耗时代码本地化。如果携带有lplus库时,将调用so文件,否则依旧纯Java。 //用户可有选择的使用(事实上,随着Android版本的提高,本地运行与虚拟机运行的速度差距已经 //在逐渐缩小)。 public final class NativeSupport { static boolean isWindows = System.getProperty("os.name") .contains("Windows"); static boolean isLinux = System.getProperty("os.name").contains("Linux"); static boolean isMac = System.getProperty("os.name").contains("Mac"); static boolean isAndroid = false; static boolean is64Bit = System.getProperty("os.arch").equals("amd64"); private static HashSet<String> loadedLibraries = new HashSet<String>(); public static String CRC(InputStream input) { if (input == null) { return "" + System.nanoTime(); } CRC32 crc = new CRC32(); byte[] buffer = new byte[4096]; try { while (true) { int length = input.read(buffer); if (length == -1) break; crc.update(buffer, 0, length); } } catch (Exception ex) { try { input.close(); } catch (Exception ignored) { } } return Long.toString(crc.getValue()); } public static String libNames(String libraryName) { if (isWindows) { return libraryName + (is64Bit ? "64.dll" : ".dll"); } if (isLinux) { return "lib" + libraryName + (is64Bit ? "64.so" : ".so"); } if (isMac) { return "lib" + libraryName + ".dylib"; } return libraryName; } public static synchronized void loadJNI(String libraryName) throws Throwable { libraryName = libNames(libraryName); if (loadedLibraries.contains(libraryName)) { return; } try { if (isAndroid) { System.loadLibrary(libraryName); } else { System.load(export(libraryName, null).getAbsolutePath()); } } catch (Throwable ex) { throw new Exception(ex); } loadedLibraries.add(libraryName); } public static File export(String sourcePath, String dirName) throws IOException { String sourceCrc = CRC(Resources.openResource(sourcePath)); if (dirName == null) { dirName = sourceCrc; } File extractedDir = new File(System.getProperty("java.io.tmpdir") + "/loon" + System.getProperty("user.name") + "/" + dirName); File extractedFile = new File(extractedDir, new File(sourcePath).getName()); String extractedCrc = null; if (extractedFile.exists()) { try { extractedCrc = CRC(new FileInputStream(extractedFile)); } catch (FileNotFoundException ignored) { } } if (extractedCrc == null || !extractedCrc.equals(sourceCrc)) { try { InputStream input = Resources.openResource(sourcePath); if (input == null) { return null; } extractedDir.mkdirs(); FileOutputStream output = new FileOutputStream(extractedFile); byte[] buffer = new byte[4096]; while (true) { int length = input.read(buffer); if (length == -1) break; output.write(buffer, 0, length); } input.close(); output.close(); } catch (IOException ex) { throw new RuntimeException("Error extracting file: " + sourcePath, ex); } } return extractedFile.exists() ? extractedFile : null; } private static boolean nativesLoaded; public static final int SIZEOF_BYTE = 1; public static final int SIZEOF_SHORT = 2; public static final int SIZEOF_FLOAT = 4; public static final int SIZEOF_INT = SIZEOF_FLOAT; public static final int SIZEOF_DOUBLE = 8; public static final int SIZEOF_LONG = SIZEOF_DOUBLE; private static boolean useLoonNative = false; private static boolean isInJavaWebStart() { try { Method method = Class.forName("javax.jnlp.ServiceManager") .getDeclaredMethod("lookup", new Class<?>[] { String.class }); method.invoke(null, "javax.jnlp.PersistenceService"); return true; } catch (Throwable ignored) { return false; } } static { String vm = System.getProperty("java.vm.name"); if (vm != null && vm.contains("Dalvik")) { isAndroid = true; isWindows = false; isLinux = false; isMac = false; is64Bit = false; } System.setProperty("org.lwjgl.input.Mouse.allowNegativeMouseCoords", "true"); if (!isInJavaWebStart()) { File nativesDir = null; try { if (isWindows) { nativesDir = export(is64Bit ? "lwjgl64.dll" : "lwjgl.dll", null).getParentFile(); export(is64Bit ? "OpenAL64.dll" : "OpenAL32.dll", nativesDir.getName()); } else if (isMac) { nativesDir = export("liblwjgl.jnilib", null) .getParentFile(); export("openal.dylib", nativesDir.getName()); } else if (isLinux) { nativesDir = export( is64Bit ? "liblwjgl64.so" : "liblwjgl.so", null) .getParentFile(); export(is64Bit ? "libopenal64.so" : "libopenal.so", nativesDir.getName()); } } catch (Throwable ex) { throw new RuntimeException("Unable to extract LWJGL natives.", ex); } System.setProperty("org.lwjgl.librarypath", nativesDir.getAbsolutePath()); try { loadJNI("lplus"); useLoonNative = true; System.out.println("Support of the native method call"); } catch (Throwable e) { useLoonNative = false; } } else { useLoonNative = true; } } public static boolean UseLoonNative() { return useLoonNative; } public static void OpenLoonNative() { useLoonNative = false; } public static void CloseLoonNative() { useLoonNative = false; } public static void makeBuffer(byte[] data, int size, int tag) { if (useLoonNative) { jniencode(data, size, tag); } else { for (int i = 0; i < size; i++) { data[i] ^= tag; } } } public static void copy(float[] src, Buffer dst, int numFloats) { copy(src, dst, 0, numFloats); } public static void copy(float[] src, Buffer dst, int offset, int numFloats) { if (useLoonNative) { bufferCopy(src, dst, numFloats, offset); dst.position(0); if (dst instanceof ByteBuffer) dst.limit(numFloats << 2); else if (dst instanceof FloatBuffer) dst.limit(numFloats); } else { putBuffer(dst, src, offset, numFloats); } } public static IntBuffer newIntBuffer(final int[] src) { if (src == null) { return null; } int size = src.length; IntBuffer buffer = newIntBuffer(size); copy(src, 0, buffer, size); return buffer; } public static FloatBuffer newFloatBuffer(float[] src, int offset, int numFloats) { FloatBuffer buffer = newFloatBuffer(numFloats); copy(src, buffer, offset, numFloats); return buffer; } public static ByteBuffer clone(final ByteBuffer dst) { if (dst == null) { return null; } int size = dst.limit(); ByteBuffer copy = newByteBuffer(size); copy(copy, dst, size); return copy; } public static FloatBuffer clone(final FloatBuffer dst) { if (dst == null) { return null; } int size = dst.limit(); FloatBuffer copy = newFloatBuffer(size); copy(copy, dst, size); return copy; } public static void copy(byte[] src, int srcOffset, Buffer dst, int numElements) { if (useLoonNative) { bufferCopy(src, srcOffset, dst, positionInBytes(dst), numElements); dst.limit(dst.position() + bytesToElements(dst, numElements)); } else { putBuffer(dst, src, srcOffset, numElements); } } public static void copy(short[] src, int srcOffset, Buffer dst, int numElements) { if (useLoonNative) { bufferCopy(src, srcOffset, dst, positionInBytes(dst), numElements << 1); dst.limit(dst.position() + bytesToElements(dst, numElements << 1)); } else { putBuffer(dst, src, srcOffset, numElements); } } public static void copy(char[] src, int srcOffset, Buffer dst, int numElements) { if (useLoonNative) { bufferCopy(src, srcOffset, dst, positionInBytes(dst), numElements << 1); dst.limit(dst.position() + bytesToElements(dst, numElements << 1)); } else { putBuffer(dst, src, srcOffset, numElements); } } public static void copy(int[] src, int srcOffset, Buffer dst, int numElements) { if (useLoonNative) { bufferCopy(src, srcOffset, dst, positionInBytes(dst), numElements << 2); dst.limit(dst.position() + bytesToElements(dst, numElements << 2)); } else { putBuffer(dst, src, srcOffset, numElements); } } public static void copy(long[] src, int srcOffset, Buffer dst, int numElements) { if (useLoonNative) { bufferCopy(src, srcOffset, dst, positionInBytes(dst), numElements << 3); } else { putBuffer(dst, src, srcOffset, numElements); } } public static void copy(float[] src, int srcOffset, Buffer dst, int numElements) { if (useLoonNative) { bufferCopy(src, srcOffset, dst, positionInBytes(dst), numElements << 2); dst.limit(dst.position() + bytesToElements(dst, numElements << 2)); } else { putBuffer(dst, src, srcOffset, numElements); } } public static void copy(double[] src, int srcOffset, Buffer dst, int numElements) { if (useLoonNative) { bufferCopy(src, srcOffset, dst, positionInBytes(dst), numElements << 3); dst.limit(dst.position() + bytesToElements(dst, numElements << 3)); } else { putBuffer(dst, src, srcOffset, numElements); } } public static void copy(Buffer src, Buffer dst, int numElements) { if (useLoonNative) { int numBytes = elementsToBytes(src, numElements); bufferCopy(src, positionInBytes(src), dst, positionInBytes(dst), numBytes); dst.limit(dst.position() + bytesToElements(dst, numBytes)); } else { putBuffer(dst, src, numElements); } } private static int positionInBytes(Buffer dst) { if (dst instanceof ByteBuffer) { return dst.position(); } else if (dst instanceof ShortBuffer) { return dst.position() << 1; } else if (dst instanceof CharBuffer) { return dst.position() << 1; } else if (dst instanceof IntBuffer) { return dst.position() << 2; } else if (dst instanceof LongBuffer) { return dst.position() << 3; } else if (dst instanceof FloatBuffer) { return dst.position() << 2; } else if (dst instanceof DoubleBuffer) { return dst.position() << 3; } else { throw new RuntimeException("Can't copy to a " + dst.getClass().getName() + " instance"); } } private static int bytesToElements(Buffer dst, int bytes) { if (dst instanceof ByteBuffer) { return bytes; } else if (dst instanceof ShortBuffer) { return bytes >>> 1; } else if (dst instanceof CharBuffer) { return bytes >>> 1; } else if (dst instanceof IntBuffer) { return bytes >>> 2; } else if (dst instanceof LongBuffer) { return bytes >>> 3; } else if (dst instanceof FloatBuffer) { return bytes >>> 2; } else if (dst instanceof DoubleBuffer) { return bytes >>> 3; } else { throw new RuntimeException("Can't copy to a " + dst.getClass().getName() + " instance"); } } private static int elementsToBytes(Buffer dst, int elements) { if (dst instanceof ByteBuffer) { return elements; } else if (dst instanceof ShortBuffer) { return elements << 1; } else if (dst instanceof CharBuffer) { return elements << 1; } else if (dst instanceof IntBuffer) { return elements << 2; } else if (dst instanceof LongBuffer) { return elements << 3; } else if (dst instanceof FloatBuffer) { return elements << 2; } else if (dst instanceof DoubleBuffer) { return elements << 3; } else { throw new RuntimeException("Can't copy to a " + dst.getClass().getName() + " instance"); } } private static void putBuffer(Buffer dst, Object src, int offset, int numFloats) { dst.clear(); if (dst instanceof ByteBuffer) { byte[] buffer = (byte[]) src; ByteBuffer writer = (ByteBuffer) dst; writer.limit(numFloats); writer.put(buffer, offset, numFloats); } else if (dst instanceof ShortBuffer) { short[] buffer = (short[]) src; ShortBuffer writer = (ShortBuffer) dst; writer.limit(numFloats); writer.put(buffer, offset, numFloats); } else if (dst instanceof CharBuffer) { char[] buffer = (char[]) src; CharBuffer writer = (CharBuffer) dst; writer.limit(numFloats); writer.put(buffer, offset, numFloats); } else if (dst instanceof IntBuffer) { int[] buffer = (int[]) src; IntBuffer writer = (IntBuffer) dst; writer.limit(numFloats); writer.put(buffer, offset, numFloats); } else if (dst instanceof LongBuffer) { long[] buffer = (long[]) src; LongBuffer writer = (LongBuffer) dst; writer.limit(numFloats); writer.put(buffer, offset, numFloats); } else if (dst instanceof FloatBuffer) { float[] buffer = (float[]) src; FloatBuffer writer = (FloatBuffer) dst; writer.limit(numFloats); writer.put(buffer, offset, numFloats); } else if (dst instanceof DoubleBuffer) { double[] buffer = (double[]) src; DoubleBuffer writer = (DoubleBuffer) dst; writer.limit(numFloats); writer.put(buffer, offset, numFloats); } else { throw new RuntimeException("Can't copy to a " + dst.getClass().getName() + " instance"); } dst.position(0); } private static void putBuffer(Buffer dst, Buffer src, int numFloats) { dst.clear(); if (dst instanceof ByteBuffer) { ByteBuffer buffer = (ByteBuffer) dst; buffer.limit(numFloats); buffer.put((ByteBuffer) src); } else if (dst instanceof ShortBuffer) { ShortBuffer buffer = (ShortBuffer) dst; buffer.limit(numFloats); buffer.put((ShortBuffer) src); } else if (dst instanceof CharBuffer) { CharBuffer buffer = (CharBuffer) dst; buffer.limit(numFloats); buffer.put((CharBuffer) src); } else if (dst instanceof IntBuffer) { IntBuffer buffer = (IntBuffer) dst; buffer.limit(numFloats); buffer.put((IntBuffer) src); } else if (dst instanceof LongBuffer) { LongBuffer buffer = (LongBuffer) dst; buffer.limit(numFloats); buffer.put((LongBuffer) src); } else if (dst instanceof FloatBuffer) { FloatBuffer buffer = (FloatBuffer) dst; buffer.limit(numFloats); buffer.put((FloatBuffer) src); } else if (dst instanceof DoubleBuffer) { DoubleBuffer buffer = (DoubleBuffer) dst; buffer.limit(numFloats); buffer.put((DoubleBuffer) src); } else { throw new RuntimeException("Can't copy to a " + dst.getClass().getName() + " instance"); } dst.position(0); } public static ByteBuffer replaceBytes(ByteBuffer dst, float[] src) { int size = src.length; dst.clear(); copy(src, 0, dst, size); dst.position(0); return dst; } public static FloatBuffer replaceFloats(FloatBuffer dst, float[] src) { int size = src.length; dst.clear(); copy(src, 0, dst, size); dst.position(0); return dst; } public static ByteBuffer getByteBuffer(byte[] bytes) { if (useLoonNative) { final int size = bytes.length; ByteBuffer buffer = newByteBuffer(size); copy(bytes, 0, buffer, size); buffer.position(0); return buffer; } else { ByteBuffer buffer = newByteBuffer(bytes.length).put(bytes); buffer.position(0); return buffer; } } public static FloatBuffer getFloatBuffer(float[] floats) { if (useLoonNative) { final int size = floats.length; FloatBuffer buffer = newFloatBuffer(size); copy(floats, 0, buffer, size); buffer.position(0); return buffer; } else { FloatBuffer buffer = newFloatBuffer(floats.length).put(floats); buffer.position(0); return buffer; } } public static ByteBuffer newByteBuffer(int numBytes) { ByteBuffer buffer = ByteBuffer.allocateDirect(numBytes); buffer.order(ByteOrder.nativeOrder()); return buffer; } public static FloatBuffer newFloatBuffer(int numFloats) { ByteBuffer buffer = ByteBuffer.allocateDirect(numFloats * 4); buffer.order(ByteOrder.nativeOrder()); return buffer.asFloatBuffer(); } public static DoubleBuffer newDoubleBuffer(int numDoubles) { ByteBuffer buffer = ByteBuffer.allocateDirect(numDoubles * 8); buffer.order(ByteOrder.nativeOrder()); return buffer.asDoubleBuffer(); } public static ShortBuffer newShortBuffer(int numShorts) { ByteBuffer buffer = ByteBuffer.allocateDirect(numShorts * 2); buffer.order(ByteOrder.nativeOrder()); return buffer.asShortBuffer(); } public static CharBuffer newCharBuffer(int numChars) { ByteBuffer buffer = ByteBuffer.allocateDirect(numChars * 2); buffer.order(ByteOrder.nativeOrder()); return buffer.asCharBuffer(); } public static IntBuffer newIntBuffer(int numInts) { ByteBuffer buffer = ByteBuffer.allocateDirect(numInts * 4); buffer.order(ByteOrder.nativeOrder()); return buffer.asIntBuffer(); } public static LongBuffer newLongBuffer(int numLongs) { ByteBuffer buffer = ByteBuffer.allocateDirect(numLongs * 8); buffer.order(ByteOrder.nativeOrder()); return buffer.asLongBuffer(); } public static void put(final Buffer buffer, final float[] source, final int offset, final int length) { if (useLoonNative) { bufferPut(buffer, source, length, offset); buffer.position(0); buffer.limit(length << 2); } else { putBuffer(buffer, source, offset, length); } } private static ArrayList<ByteBuffer> unsafeBuffers = new ArrayList<ByteBuffer>(); private static int allocatedUnsafe = 0; public static int getAllocatedBytesUnsafe() { return allocatedUnsafe; } public static void disposeUnsafeByteBuffer(ByteBuffer buffer) { int size = buffer.capacity(); synchronized (unsafeBuffers) { if (!unsafeBuffers.remove(buffer)) throw new IllegalArgumentException( "buffer not allocated with newUnsafeByteBuffer or already disposed"); } allocatedUnsafe -= size; freeMemory(buffer); } public static ByteBuffer newUnsafeByteBuffer(int numBytes) { ByteBuffer buffer = allocateDirect(numBytes); buffer.order(ByteOrder.nativeOrder()); allocatedUnsafe += numBytes; synchronized (unsafeBuffers) { unsafeBuffers.add(buffer); } return buffer; } public static ByteBuffer allocateDirect(final int capacity) { if (useLoonNative) { return bufferDirect(capacity); } else { return ByteBuffer.allocateDirect(capacity); } } private static void freeMemory(Buffer buffer) { if (useLoonNative) { bufferFreeDirect(buffer); } buffer.clear(); buffer = null; } public static void clear(Buffer buffer) { if (useLoonNative) { bufferClear(buffer, buffer.limit()); } else { buffer.clear(); } } public final static void filterColor(int maxPixel, int pixelStart, int pixelEnd, int[] src, int[] dst, int[] colors, int c1, int c2) { if (useLoonNative) { if (src == null) { return; } updateArray(maxPixel, pixelStart, pixelEnd, src, dst, colors, c1, c2); } else { final int length = src.length; if (pixelStart < pixelEnd) { final int start = pixelStart + 1; final int end = pixelEnd + 1; if (end > maxPixel) { return; } for (int i = 0; i < length; i++) { if (dst[i] != 0xffffff) { for (int pixIndex = start; pixIndex < end; pixIndex++) { if (colors[pixIndex] == src[i]) { dst[i] = 0xffffff; } else if (src[i] == c1) { dst[i] = 0xffffff; } } } } } else { final int start = pixelEnd - 1; final int end = pixelStart; if (start < 0) { return; } for (int i = 0; i < length; i++) { if (dst[i] != 0xffffff) { for (int pixIndex = start; pixIndex < end; pixIndex++) { if (colors[pixIndex] == src[i]) { dst[i] = 0xffffff; } else if (src[i] == c2) { dst[i] = 0xffffff; } } } } } } } public static void filterFractions(int size, float[] fractions, int width, int height, int[] pixels, int numElements) { if (useLoonNative) { updateFractions(size, fractions, width, height, pixels, numElements); } else { int x, y; int idx = 0; for (int j = 0; j < size; j++) { idx = j * numElements; if (fractions[idx + 4] != 0xffffff) { if (fractions[idx + 5] <= 0) { fractions[idx + 0] += fractions[idx + 2]; fractions[idx + 1] += fractions[idx + 3]; fractions[idx + 3] += 0.1; } else { fractions[idx + 5]--; } x = (int) fractions[idx + 0]; y = (int) fractions[idx + 1]; if (x > -1 && y > -1 && x < width && y < height) { pixels[x + y * width] = (int) fractions[idx + 4]; } } } } } public static final int M00 = 0; public static final int M01 = 4; public static final int M02 = 8; public static final int M03 = 12; public static final int M10 = 1; public static final int M11 = 5; public static final int M12 = 9; public static final int M13 = 13; public static final int M20 = 2; public static final int M21 = 6; public static final int M22 = 10; public static final int M23 = 14; public static final int M30 = 3; public static final int M31 = 7; public static final int M32 = 11; public static final int M33 = 15; public static void mul(float[] mata, float[] matb) { if (useLoonNative) { jnimul(mata, matb); } else { float[] tmp = new float[16]; tmp[M00] = mata[M00] * matb[M00] + mata[M01] * matb[M10] + mata[M02] * matb[M20] + mata[M03] * matb[M30]; tmp[M01] = mata[M00] * matb[M01] + mata[M01] * matb[M11] + mata[M02] * matb[M21] + mata[M03] * matb[M31]; tmp[M02] = mata[M00] * matb[M02] + mata[M01] * matb[M12] + mata[M02] * matb[M22] + mata[M03] * matb[M32]; tmp[M03] = mata[M00] * matb[M03] + mata[M01] * matb[M13] + mata[M02] * matb[M23] + mata[M03] * matb[M33]; tmp[M10] = mata[M10] * matb[M00] + mata[M11] * matb[M10] + mata[M12] * matb[M20] + mata[M13] * matb[M30]; tmp[M11] = mata[M10] * matb[M01] + mata[M11] * matb[M11] + mata[M12] * matb[M21] + mata[M13] * matb[M31]; tmp[M12] = mata[M10] * matb[M02] + mata[M11] * matb[M12] + mata[M12] * matb[M22] + mata[M13] * matb[M32]; tmp[M13] = mata[M10] * matb[M03] + mata[M11] * matb[M13] + mata[M12] * matb[M23] + mata[M13] * matb[M33]; tmp[M20] = mata[M20] * matb[M00] + mata[M21] * matb[M10] + mata[M22] * matb[M20] + mata[M23] * matb[M30]; tmp[M21] = mata[M20] * matb[M01] + mata[M21] * matb[M11] + mata[M22] * matb[M21] + mata[M23] * matb[M31]; tmp[M22] = mata[M20] * matb[M02] + mata[M21] * matb[M12] + mata[M22] * matb[M22] + mata[M23] * matb[M32]; tmp[M23] = mata[M20] * matb[M03] + mata[M21] * matb[M13] + mata[M22] * matb[M23] + mata[M23] * matb[M33]; tmp[M30] = mata[M30] * matb[M00] + mata[M31] * matb[M10] + mata[M32] * matb[M20] + mata[M33] * matb[M30]; tmp[M31] = mata[M30] * matb[M01] + mata[M31] * matb[M11] + mata[M32] * matb[M21] + mata[M33] * matb[M31]; tmp[M32] = mata[M30] * matb[M02] + mata[M31] * matb[M12] + mata[M32] * matb[M22] + mata[M33] * matb[M32]; tmp[M33] = mata[M30] * matb[M03] + mata[M31] * matb[M13] + mata[M32] * matb[M23] + mata[M33] * matb[M33]; System.arraycopy(tmp, 0, mata, 0, 16); } } public static void mulVec(float[] mat, float[] vec) { if (useLoonNative) { jnimulVec(mat, vec); } else { float x = vec[0] * mat[M00] + vec[1] * mat[M01] + vec[2] * mat[M02] + mat[M03]; float y = vec[0] * mat[M10] + vec[1] * mat[M11] + vec[2] * mat[M12] + mat[M13]; float z = vec[0] * mat[M20] + vec[1] * mat[M21] + vec[2] * mat[M22] + mat[M23]; vec[0] = x; vec[1] = y; vec[2] = z; } } public static void mulVec(float[] mat, float[] vecs, int offset, int numVecs, int stride) { if (useLoonNative) { jnimulVec(mat, vecs, offset, numVecs, stride); } else { for (int i = 0; i < numVecs; i++) { float[] vecPtr = new float[stride]; System.arraycopy(vecs, offset, vecPtr, 0, stride); mulVec(mat, vecPtr); } } } public static void prj(float[] mat, float[] vec) { if (useLoonNative) { jniprj(mat, vec); } else { float inv_w = 1.0f / (vec[0] * mat[M30] + vec[1] * mat[M31] + vec[2] * mat[M32] + mat[M33]); float x = (vec[0] * mat[M00] + vec[1] * mat[M01] + vec[2] * mat[M02] + mat[M03]) * inv_w; float y = (vec[0] * mat[M10] + vec[1] * mat[M11] + vec[2] * mat[M12] + mat[M13]) * inv_w; float z = (vec[0] * mat[M20] + vec[1] * mat[M21] + vec[2] * mat[M22] + mat[M23]) * inv_w; vec[0] = x; vec[1] = y; vec[2] = z; } } public static void prj(float[] mat, float[] vecs, int offset, int numVecs, int stride) { if (useLoonNative) { jniprj(mat, vecs, offset, numVecs, stride); } else { for (int i = 0; i < numVecs; i++) { float[] vecPtr = new float[stride]; System.arraycopy(vecs, offset, vecPtr, 0, stride); prj(mat, vecPtr); } } } public static void rot(float[] mat, float[] vec) { if (useLoonNative) { jnirot(mat, vec); } else { float x = vec[0] * mat[M00] + vec[1] * mat[M01] + vec[2] * mat[M02]; float y = vec[0] * mat[M10] + vec[1] * mat[M11] + vec[2] * mat[M12]; float z = vec[0] * mat[M20] + vec[1] * mat[M21] + vec[2] * mat[M22]; vec[0] = x; vec[1] = y; vec[2] = z; } } public static void rot(float[] mat, float[] vecs, int offset, int numVecs, int stride) { if (useLoonNative) { jnirot(mat, vecs, offset, numVecs, stride); } else { for (int i = 0; i < numVecs; i++) { float[] vecPtr = new float[stride]; System.arraycopy(vecs, offset, vecPtr, 0, stride); rot(mat, vecPtr); } } } public static boolean inv(float[] values) { if (useLoonNative) { return jniinv(values); } else { float[] tmp = new float[16]; float l_det = det(values); if (l_det == 0) return false; tmp[M00] = values[M12] * values[M23] * values[M31] - values[M13] * values[M22] * values[M31] + values[M13] * values[M21] * values[M32] - values[M11] * values[M23] * values[M32] - values[M12] * values[M21] * values[M33] + values[M11] * values[M22] * values[M33]; tmp[M01] = values[M03] * values[M22] * values[M31] - values[M02] * values[M23] * values[M31] - values[M03] * values[M21] * values[M32] + values[M01] * values[M23] * values[M32] + values[M02] * values[M21] * values[M33] - values[M01] * values[M22] * values[M33]; tmp[M02] = values[M02] * values[M13] * values[M31] - values[M03] * values[M12] * values[M31] + values[M03] * values[M11] * values[M32] - values[M01] * values[M13] * values[M32] - values[M02] * values[M11] * values[M33] + values[M01] * values[M12] * values[M33]; tmp[M03] = values[M03] * values[M12] * values[M21] - values[M02] * values[M13] * values[M21] - values[M03] * values[M11] * values[M22] + values[M01] * values[M13] * values[M22] + values[M02] * values[M11] * values[M23] - values[M01] * values[M12] * values[M23]; tmp[M10] = values[M13] * values[M22] * values[M30] - values[M12] * values[M23] * values[M30] - values[M13] * values[M20] * values[M32] + values[M10] * values[M23] * values[M32] + values[M12] * values[M20] * values[M33] - values[M10] * values[M22] * values[M33]; tmp[M11] = values[M02] * values[M23] * values[M30] - values[M03] * values[M22] * values[M30] + values[M03] * values[M20] * values[M32] - values[M00] * values[M23] * values[M32] - values[M02] * values[M20] * values[M33] + values[M00] * values[M22] * values[M33]; tmp[M12] = values[M03] * values[M12] * values[M30] - values[M02] * values[M13] * values[M30] - values[M03] * values[M10] * values[M32] + values[M00] * values[M13] * values[M32] + values[M02] * values[M10] * values[M33] - values[M00] * values[M12] * values[M33]; tmp[M13] = values[M02] * values[M13] * values[M20] - values[M03] * values[M12] * values[M20] + values[M03] * values[M10] * values[M22] - values[M00] * values[M13] * values[M22] - values[M02] * values[M10] * values[M23] + values[M00] * values[M12] * values[M23]; tmp[M20] = values[M11] * values[M23] * values[M30] - values[M13] * values[M21] * values[M30] + values[M13] * values[M20] * values[M31] - values[M10] * values[M23] * values[M31] - values[M11] * values[M20] * values[M33] + values[M10] * values[M21] * values[M33]; tmp[M21] = values[M03] * values[M21] * values[M30] - values[M01] * values[M23] * values[M30] - values[M03] * values[M20] * values[M31] + values[M00] * values[M23] * values[M31] + values[M01] * values[M20] * values[M33] - values[M00] * values[M21] * values[M33]; tmp[M22] = values[M01] * values[M13] * values[M30] - values[M03] * values[M11] * values[M30] + values[M03] * values[M10] * values[M31] - values[M00] * values[M13] * values[M31] - values[M01] * values[M10] * values[M33] + values[M00] * values[M11] * values[M33]; tmp[M23] = values[M03] * values[M11] * values[M20] - values[M01] * values[M13] * values[M20] - values[M03] * values[M10] * values[M21] + values[M00] * values[M13] * values[M21] + values[M01] * values[M10] * values[M23] - values[M00] * values[M11] * values[M23]; tmp[M30] = values[M12] * values[M21] * values[M30] - values[M11] * values[M22] * values[M30] - values[M12] * values[M20] * values[M31] + values[M10] * values[M22] * values[M31] + values[M11] * values[M20] * values[M32] - values[M10] * values[M21] * values[M32]; tmp[M31] = values[M01] * values[M22] * values[M30] - values[M02] * values[M21] * values[M30] + values[M02] * values[M20] * values[M31] - values[M00] * values[M22] * values[M31] - values[M01] * values[M20] * values[M32] + values[M00] * values[M21] * values[M32]; tmp[M32] = values[M02] * values[M11] * values[M30] - values[M01] * values[M12] * values[M30] - values[M02] * values[M10] * values[M31] + values[M00] * values[M12] * values[M31] + values[M01] * values[M10] * values[M32] - values[M00] * values[M11] * values[M32]; tmp[M33] = values[M01] * values[M12] * values[M20] - values[M02] * values[M11] * values[M20] + values[M02] * values[M10] * values[M21] - values[M00] * values[M12] * values[M21] - values[M01] * values[M10] * values[M22] + values[M00] * values[M11] * values[M22]; float inv_det = 1.0f / l_det; values[M00] = tmp[M00] * inv_det; values[M01] = tmp[M01] * inv_det; values[M02] = tmp[M02] * inv_det; values[M03] = tmp[M03] * inv_det; values[M10] = tmp[M10] * inv_det; values[M11] = tmp[M11] * inv_det; values[M12] = tmp[M12] * inv_det; values[M13] = tmp[M13] * inv_det; values[M20] = tmp[M20] * inv_det; values[M21] = tmp[M21] * inv_det; values[M22] = tmp[M22] * inv_det; values[M23] = tmp[M23] * inv_det; values[M30] = tmp[M30] * inv_det; values[M31] = tmp[M31] * inv_det; values[M32] = tmp[M32] * inv_det; values[M33] = tmp[M33] * inv_det; return true; } } public static float det(float[] values) { if (useLoonNative) { return jnidet(values); } else { return values[M30] * values[M21] * values[M12] * values[M03] - values[M20] * values[M31] * values[M12] * values[M03] - values[M30] * values[M11] * values[M22] * values[M03] + values[M10] * values[M31] * values[M22] * values[M03] + values[M20] * values[M11] * values[M32] * values[M03] - values[M10] * values[M21] * values[M32] * values[M03] - values[M30] * values[M21] * values[M02] * values[M13] + values[M20] * values[M31] * values[M02] * values[M13] + values[M30] * values[M01] * values[M22] * values[M13] - values[M00] * values[M31] * values[M22] * values[M13] - values[M20] * values[M01] * values[M32] * values[M13] + values[M00] * values[M21] * values[M32] * values[M13] + values[M30] * values[M11] * values[M02] * values[M23] - values[M10] * values[M31] * values[M02] * values[M23] - values[M30] * values[M01] * values[M12] * values[M23] + values[M00] * values[M31] * values[M12] * values[M23] + values[M10] * values[M01] * values[M32] * values[M23] - values[M00] * values[M11] * values[M32] * values[M23] - values[M20] * values[M11] * values[M02] * values[M33] + values[M10] * values[M21] * values[M02] * values[M33] + values[M20] * values[M01] * values[M12] * values[M33] - values[M00] * values[M21] * values[M12] * values[M33] - values[M10] * values[M01] * values[M22] * values[M33] + values[M00] * values[M11] * values[M22] * values[M33]; } } public static int[] toColorKey(int[] buffer, int colorKey) { if (useLoonNative) { return setColorKey(buffer, colorKey); } else { int size = buffer.length; for (int i = 0; i < size; i++) { int pixel = buffer[i]; if (pixel == colorKey) { buffer[i] = 0x00FFFFFF; } } } return buffer; } public static int[] toColorKeys(int[] buffer, int[] colors) { if (useLoonNative) { return setColorKeys(buffer, colors); } else { int length = colors.length; int size = buffer.length; for (int n = 0; n < length; n++) { for (int i = 0; i < size; i++) { int pixel = buffer[i]; if (pixel == colors[n]) { buffer[i] = 0x00FFFFFF; } } } } return buffer; } public static int[] toColorKeyLimit(int[] buffer, int start, int end) { if (useLoonNative) { return setColorKeyLimit(buffer, start, end); } else { int sred = LColor.getRed(start); int sgreen = LColor.getGreen(start); int sblue = LColor.getBlue(start); int ered = LColor.getRed(end); int egreen = LColor.getGreen(end); int eblue = LColor.getBlue(end); int size = buffer.length; for (int i = 0; i < size; i++) { int pixel = buffer[i]; int r = LColor.getRed(pixel); int g = LColor.getGreen(pixel); int b = LColor.getBlue(pixel); if ((r >= sred && g >= sgreen && b >= sblue) && (r <= ered && g <= egreen && b <= eblue)) { buffer[i] = 0x00FFFFFF; } } } return buffer; } public static int[] toGray(int[] buffer, int w, int h) { if (useLoonNative) { return getGray(buffer, w, h); } else { int size = w * h; int[] newResult = new int[size]; System.arraycopy(buffer, 0, newResult, 0, size); int alpha = 0xFF << 24; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { int idx = w * i + j; int color = newResult[idx]; if (color != 0x00FFFFFF) { int red = ((color & 0x00FF0000) >> 16); int green = ((color & 0x0000FF00) >> 8); int blue = color & 0x000000FF; color = (red + green + blue) / 3; color = alpha | (color << 16) | (color << 8) | color; newResult[idx] = color; } } } return newResult; } } private native static void jniencode(byte[] src, int size, int tag); private native static void jnimul(float[] mata, float[] matb); private native static void jnimulVec(float[] mat, float[] vec); private native static void jnimulVec(float[] mat, float[] vecs, int offset, int numVecs, int stride); private native static void jniprj(float[] mat, float[] vec); private native static void jniprj(float[] mat, float[] vecs, int offset, int numVecs, int stride); private native static void jnirot(float[] mat, float[] vec); private native static void jnirot(float[] mat, float[] vecs, int offset, int numVecs, int stride); private native static boolean jniinv(float[] values); private native static float jnidet(float[] values); private native static ByteBuffer bufferDirect(final int size); private native static void bufferClear(Buffer buffer, int numBytes); private native static void bufferFreeDirect(final Buffer buffer); private native static void bufferPut(final Buffer buffer, final float[] source, final int length, final int offset); private native static void bufferCopy(float[] src, Buffer dst, int numFloats, int offset); private native static void bufferCopy(byte[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); private native static void bufferCopy(char[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); private native static void bufferCopy(short[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); private native static void bufferCopy(int[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); private native static void bufferCopy(long[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); private native static void bufferCopy(float[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); private native static void bufferCopy(double[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); private native static void bufferCopy(Buffer src, int srcOffset, Buffer dst, int dstOffset, int numBytes); private native static void updateArray(int maxPixel, int pixelStart, int pixelEnd, int[] src, int[] dst, int[] colors, int c1, int c2); private native static void updateFractions(int size, float[] src, int width, int height, int[] dst, int numElements); private native static int[] setColorKey(int[] buffer, int colorKey); private native static int[] setColorKeys(int[] buffer, int[] colorKey); private native static int[] setColorKeyLimit(int[] buffer, int start, int end); private native static int[] getGray(int[] buffer, int w, int h); }