/* * Copyright 2013 Hannes Janetzek * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package org.oscim.renderer; import static org.oscim.backend.GLAdapter.gl; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class GLMatrix { static final Logger log = LoggerFactory.getLogger(GLMatrix.class); private final static boolean dbg = false; private final long pointer; private final FloatBuffer buffer; private final static String INVALID_INPUT = "Bad Array!"; public GLMatrix() { pointer = alloc(); buffer = (getBuffer(pointer)).order(ByteOrder.nativeOrder()).asFloatBuffer(); } /** * Set the Matrix from float array * * @param m float array to copy */ public void set(float[] m) { if (m == null || m.length != 16) throw new IllegalArgumentException(INVALID_INPUT); set(pointer, m); } /** * Get the Matrix as float array * * @param m float array to store Matrix */ public void get(float[] m) { if (m == null || m.length != 16) throw new IllegalArgumentException(INVALID_INPUT); get(pointer, m); } /** * Copy values from mat * * @param mat Matrix to copy */ public void copy(GLMatrix mat) { copy(pointer, mat.pointer); } /** * Project Vector with Matrix * * @param vec3 Vector to project */ public void prj(float[] vec3) { if (vec3 == null || vec3.length < 3) throw new IllegalArgumentException(INVALID_INPUT); prj(pointer, vec3); } /** * Project Vectors with Matrix * * @param vec3 Vector to project */ public void prj3D(float[] vec3, int offset, int length) { if (vec3 == null || vec3.length / (offset + length) < 1) throw new IllegalArgumentException(INVALID_INPUT); prj3D(pointer, vec3, offset, length); } /** * Project Vectors with Matrix * * @param vec2 Vector to project */ public void prj2D(float[] vec2, int offset, int length) { if (vec2 == null || offset < 0 || (length + offset) * 2 > vec2.length) throw new IllegalArgumentException(INVALID_INPUT); prj2D(pointer, vec2, offset, length); } /** * Project Vectors with Matrix * * * @param vec2 Vector to project */ public void prj2D(float[] src, int src_offset, float[] dst, int dst_offset, int length) { if (src == null || src_offset < 0 || length + src_offset * 2 > src.length) throw new IllegalArgumentException(INVALID_INPUT); prj2D2(pointer, src, src_offset, dst, dst_offset, length); } /** * Multiply rhs onto Matrix. * * @param rhs right hand side */ public void multiplyRhs(GLMatrix rhs) { smulrhs(pointer, rhs.pointer); } /** * Use this matrix as rhs, multiply it on lhs and store result. * * @param lhs right hand side */ public void multiplyLhs(GLMatrix lhs) { smullhs(pointer, lhs.pointer); } /** * Multiply rhs onto lhs and store result in Matrix. * * This matrix MUST be different from lhs and rhs! * * when combining matrices for vector projection this * has the same effect first as applying rhs then lhs. * * @param lhs left hand side * @param rhs right hand side */ public void multiplyMM(GLMatrix lhs, GLMatrix rhs) { smul(pointer, lhs.pointer, rhs.pointer); } /** * Transpose mat and store result in Matrix * * @param mat to transpose */ public void transposeM(GLMatrix mat) { strans(pointer, mat.pointer); } /** * Set rotation * * @param a angle in degree * @param x around x-axis * @param y around y-axis * @param z around z-axis */ public void setRotation(float a, float x, float y, float z) { setRotation(pointer, a, x, y, z); } /** * Set translation * * @param x along x-axis * @param y along y-axis * @param z along z-axis */ public void setTranslation(float x, float y, float z) { setTranslation(pointer, x, y, z); } /** * Set scale factor * * @param x axis * @param y axis * @param z axis */ public void setScale(float x, float y, float z) { setScale(pointer, x, y, z); } /** * Set translation and x,y scale * * @param tx translate x * @param ty translate y * @param scale factor x,y */ public void setTransScale(float tx, float ty, float scale) { setTransScale(pointer, tx, ty, scale); } /** * Set Matrix with glUniformMatrix * * @param location GL location id */ public void setAsUniform(int location) { gl.uniformMatrix4fv(location, 1, false, buffer); //setAsUniform(pointer, location); } /** * Set single value * * @param pos at position * @param value value to set */ public void setValue(int pos, float value) { setValueAt(pointer, pos, value); } /** * add some offset (similar to glDepthOffset) * * @param delta offset */ public void addDepthOffset(int delta) { addDepthOffset(pointer, delta); } /** * Set identity matrix */ public void setIdentity() { identity(pointer); } /** * Free native object * */ @Override public void finalize() { if (pointer != 0) delete(pointer); } private native static long alloc(); private native static void delete(long self); private native static void set(long self, float[] m); private native static void copy(long self, long other); private native static void identity(long self); private native static void get(long self, float[] m); private native static void mul(long self, long lhs_ptr); private native static void smul(long self, long rhs_ptr, long lhs_ptr); private native static void smulrhs(long self, long rhs_ptr); private native static void smullhs(long self, long lhs_ptr); private native static void strans(long self, long rhs_ptr); private native static void prj(long self, float[] vec3); private native static void prj3D(long self, float[] vec3, int start, int cnt); private native static void prj2D(long self, float[] vec2, int start, int cnt); private native static void prj2D2(long self, float[] vec2, int src_offset, float[] dst_vec, int dst_offset, int length); private native static void setRotation(long self, float a, float x, float y, float z); private native static void setScale(long self, float x, float y, float z); private native static void setTranslation(long self, float x, float y, float z); private native static void setTransScale(long self, float tx, float ty, float scale); //private native static void setAsUniform(long self, int handle); private native static void setValueAt(long self, int pos, float value); private native static void addDepthOffset(long self, int delta); private native static ByteBuffer getBuffer(long self); /* Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.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-2.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. */ /** * Define a projection matrix in terms of six clip planes * * @param m the float array that holds the perspective matrix * @param offset the offset into float array m where the perspective * matrix data is written */ public static void frustumM(float[] m, int offset, float left, float right, float bottom, float top, float near, float far) { if (left == right) { throw new IllegalArgumentException("left == right"); } if (top == bottom) { throw new IllegalArgumentException("top == bottom"); } if (near == far) { throw new IllegalArgumentException("near == far"); } if (near <= 0.0f) { throw new IllegalArgumentException("near <= 0.0f"); } if (far <= 0.0f) { throw new IllegalArgumentException("far <= 0.0f"); } final float r_width = 1.0f / (right - left); final float r_height = 1.0f / (top - bottom); final float r_depth = 1.0f / (near - far); final float x = 2.0f * (near * r_width); final float y = 2.0f * (near * r_height); final float A = (right + left) * r_width; final float B = (top + bottom) * r_height; final float C = (far + near) * r_depth; final float D = 2.0f * (far * near * r_depth); m[offset + 0] = x; m[offset + 5] = y; m[offset + 8] = A; m[offset + 9] = B; m[offset + 10] = C; m[offset + 14] = D; m[offset + 11] = -1.0f; m[offset + 1] = 0.0f; m[offset + 2] = 0.0f; m[offset + 3] = 0.0f; m[offset + 4] = 0.0f; m[offset + 6] = 0.0f; m[offset + 7] = 0.0f; m[offset + 12] = 0.0f; m[offset + 13] = 0.0f; m[offset + 15] = 0.0f; } /** * Inverts a 4 x 4 matrix. * * @param mInv the array that holds the output inverted matrix * @param mInvOffset an offset into mInv where the inverted matrix is * stored. * @param m the input array * @param mOffset an offset into m where the matrix is stored. * @return true if the matrix could be inverted, false if it could not. */ public static boolean invertM(float[] mInv, int mInvOffset, float[] m, int mOffset) { // Invert a 4 x 4 matrix using Cramer's Rule // transpose matrix final float src0 = m[mOffset + 0]; final float src4 = m[mOffset + 1]; final float src8 = m[mOffset + 2]; final float src12 = m[mOffset + 3]; final float src1 = m[mOffset + 4]; final float src5 = m[mOffset + 5]; final float src9 = m[mOffset + 6]; final float src13 = m[mOffset + 7]; final float src2 = m[mOffset + 8]; final float src6 = m[mOffset + 9]; final float src10 = m[mOffset + 10]; final float src14 = m[mOffset + 11]; final float src3 = m[mOffset + 12]; final float src7 = m[mOffset + 13]; final float src11 = m[mOffset + 14]; final float src15 = m[mOffset + 15]; // calculate pairs for first 8 elements (cofactors) final float atmp0 = src10 * src15; final float atmp1 = src11 * src14; final float atmp2 = src9 * src15; final float atmp3 = src11 * src13; final float atmp4 = src9 * src14; final float atmp5 = src10 * src13; final float atmp6 = src8 * src15; final float atmp7 = src11 * src12; final float atmp8 = src8 * src14; final float atmp9 = src10 * src12; final float atmp10 = src8 * src13; final float atmp11 = src9 * src12; // calculate first 8 elements (cofactors) final float dst0 = (atmp0 * src5 + atmp3 * src6 + atmp4 * src7) - (atmp1 * src5 + atmp2 * src6 + atmp5 * src7); final float dst1 = (atmp1 * src4 + atmp6 * src6 + atmp9 * src7) - (atmp0 * src4 + atmp7 * src6 + atmp8 * src7); final float dst2 = (atmp2 * src4 + atmp7 * src5 + atmp10 * src7) - (atmp3 * src4 + atmp6 * src5 + atmp11 * src7); final float dst3 = (atmp5 * src4 + atmp8 * src5 + atmp11 * src6) - (atmp4 * src4 + atmp9 * src5 + atmp10 * src6); final float dst4 = (atmp1 * src1 + atmp2 * src2 + atmp5 * src3) - (atmp0 * src1 + atmp3 * src2 + atmp4 * src3); final float dst5 = (atmp0 * src0 + atmp7 * src2 + atmp8 * src3) - (atmp1 * src0 + atmp6 * src2 + atmp9 * src3); final float dst6 = (atmp3 * src0 + atmp6 * src1 + atmp11 * src3) - (atmp2 * src0 + atmp7 * src1 + atmp10 * src3); final float dst7 = (atmp4 * src0 + atmp9 * src1 + atmp10 * src2) - (atmp5 * src0 + atmp8 * src1 + atmp11 * src2); // calculate pairs for second 8 elements (cofactors) final float btmp0 = src2 * src7; final float btmp1 = src3 * src6; final float btmp2 = src1 * src7; final float btmp3 = src3 * src5; final float btmp4 = src1 * src6; final float btmp5 = src2 * src5; final float btmp6 = src0 * src7; final float btmp7 = src3 * src4; final float btmp8 = src0 * src6; final float btmp9 = src2 * src4; final float btmp10 = src0 * src5; final float btmp11 = src1 * src4; // calculate second 8 elements (cofactors) final float dst8 = (btmp0 * src13 + btmp3 * src14 + btmp4 * src15) - (btmp1 * src13 + btmp2 * src14 + btmp5 * src15); final float dst9 = (btmp1 * src12 + btmp6 * src14 + btmp9 * src15) - (btmp0 * src12 + btmp7 * src14 + btmp8 * src15); final float dst10 = (btmp2 * src12 + btmp7 * src13 + btmp10 * src15) - (btmp3 * src12 + btmp6 * src13 + btmp11 * src15); final float dst11 = (btmp5 * src12 + btmp8 * src13 + btmp11 * src14) - (btmp4 * src12 + btmp9 * src13 + btmp10 * src14); final float dst12 = (btmp2 * src10 + btmp5 * src11 + btmp1 * src9) - (btmp4 * src11 + btmp0 * src9 + btmp3 * src10); final float dst13 = (btmp8 * src11 + btmp0 * src8 + btmp7 * src10) - (btmp6 * src10 + btmp9 * src11 + btmp1 * src8); final float dst14 = (btmp6 * src9 + btmp11 * src11 + btmp3 * src8) - (btmp10 * src11 + btmp2 * src8 + btmp7 * src9); final float dst15 = (btmp10 * src10 + btmp4 * src8 + btmp9 * src9) - (btmp8 * src9 + btmp11 * src10 + btmp5 * src8); // calculate determinant final float det = src0 * dst0 + src1 * dst1 + src2 * dst2 + src3 * dst3; if (det == 0.0f) { return false; } // calculate matrix inverse final float invdet = 1.0f / det; mInv[mInvOffset] = dst0 * invdet; mInv[1 + mInvOffset] = dst1 * invdet; mInv[2 + mInvOffset] = dst2 * invdet; mInv[3 + mInvOffset] = dst3 * invdet; mInv[4 + mInvOffset] = dst4 * invdet; mInv[5 + mInvOffset] = dst5 * invdet; mInv[6 + mInvOffset] = dst6 * invdet; mInv[7 + mInvOffset] = dst7 * invdet; mInv[8 + mInvOffset] = dst8 * invdet; mInv[9 + mInvOffset] = dst9 * invdet; mInv[10 + mInvOffset] = dst10 * invdet; mInv[11 + mInvOffset] = dst11 * invdet; mInv[12 + mInvOffset] = dst12 * invdet; mInv[13 + mInvOffset] = dst13 * invdet; mInv[14 + mInvOffset] = dst14 * invdet; mInv[15 + mInvOffset] = dst15 * invdet; return true; } }