org.oscim.renderer.GLMatrix Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vtm Show documentation
Show all versions of vtm Show documentation
OpenGL vector map library written in Java - running on Android, iOS, Desktop and within the browser.
/*
* Copyright 2013 Hannes Janetzek
* Copyright 2019 schedul-xor
*
* 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 .
*/
package org.oscim.renderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import static org.oscim.backend.GLAdapter.gl;
public class GLMatrix {
static final Logger log = LoggerFactory.getLogger(GLMatrix.class);
private static final boolean dbg = false;
private final long pointer;
private final FloatBuffer buffer;
private static final 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 static native long alloc();
private static native void delete(long self);
private static native void set(long self, float[] m);
private static native void copy(long self, long other);
private static native void identity(long self);
private static native void get(long self, float[] m);
private static native void mul(long self, long lhs_ptr);
private static native void smul(long self, long rhs_ptr, long lhs_ptr);
private static native void smulrhs(long self, long rhs_ptr);
private static native void smullhs(long self, long lhs_ptr);
private static native void strans(long self, long rhs_ptr);
private static native void prj(long self, float[] vec3);
private static native void prj3D(long self, float[] vec3, int start, int cnt);
private static native void prj2D(long self, float[] vec2, int start, int cnt);
private static native void prj2D2(long self, float[] vec2, int src_offset,
float[] dst_vec, int dst_offset, int length);
private static native void setRotation(long self, float a, float x, float y, float z);
private static native void setScale(long self, float x, float y, float z);
private static native void setTranslation(long self, float x, float y, float z);
private static native void setTransScale(long self, float tx, float ty, float scale);
//private static native void setAsUniform(long self, int handle);
private static native void setValueAt(long self, int pos, float value);
private static native void addDepthOffset(long self, int delta);
private static native 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;
}
public static void lookAt(float[] m, int offset,
float eyex, float eyey, float eyez,
float centerx, float centery, float centerz,
float upx, float upy, float upz) {
float z0 = eyex - centerx;
float z1 = eyey - centery;
float z2 = eyez - centerz;
double len = 1.0 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
z0 *= len;
z1 *= len;
z2 *= len;
float x0 = upy * z2 - upz * z1;
float x1 = upz * z0 - upx * z2;
float x2 = upx * z1 - upy * z0;
len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
if (len == 0) {
x0 = x1 = x2 = 0;
} else {
len = 1.0 / len;
x0 *= len;
x1 *= len;
x2 *= len;
}
float y0 = z1 * x2 - z2 * x1;
float y1 = z2 * x0 - z0 * x2;
float y2 = z0 * x1 - z1 * x0;
len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
if (len == 0) {
y0 = y1 = y2 = 0;
} else {
len = 1.0 / len;
y0 *= len;
y1 *= len;
y2 *= len;
}
m[offset + 0] = x0;
m[offset + 1] = y0;
m[offset + 2] = z0;
m[offset + 3] = 0.0f;
m[offset + 4] = x1;
m[offset + 5] = y1;
m[offset + 6] = z1;
m[offset + 7] = 0.0f;
m[offset + 8] = x2;
m[offset + 9] = y2;
m[offset + 10] = z2;
m[offset + 11] = 0.0f;
m[offset + 12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
m[offset + 13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
m[offset + 14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
m[offset + 15] = 1.0f;
}
public static void orthoM(float[] m, int offset,
float left, float right, float bottom, float top,
float near, float far) {
final float r_width = 1.0f / (left - right);
final float r_height = 1.0f / (bottom - top);
final float r_depth = 1.0f / (near - far);
m[offset + 0] = -2.0f * r_width;
m[offset + 5] = -2.0f * r_height;
m[offset + 10] = 2.0f * r_depth;
m[offset + 12] = (left + right) * r_width;
m[offset + 13] = (top + bottom) * r_height;
m[offset + 14] = (far + near) * r_depth;
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 + 8] = 0.0f;
m[offset + 9] = 0.0f;
m[offset + 11] = 0.0f;
m[offset + 15] = 1.0f;
}
}