/*
* Copyright 2013 MovingBlocks
*
* 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.
*/
package org.terasology.rendering.cameras;
import org.lwjgl.BufferUtils;
import org.terasology.logic.players.LocalPlayer;
import org.terasology.math.AABB;
import org.terasology.math.geom.Vector3f;
import org.terasology.registry.CoreRegistry;
import java.nio.FloatBuffer;
/**
* View frustum usable for frustum culling.
*
*/
public class ViewFrustum {
private final FrustumPlane[] planes = new FrustumPlane[6];
private final FloatBuffer clip = BufferUtils.createFloatBuffer(16);
/**
* Init. a new view frustum.
*/
public ViewFrustum() {
for (int i = 0; i < 6; i++) {
planes[i] = new FrustumPlane();
}
}
/**
* Updates the view frustum using the currently active modelview and projection matrices.
*/
public void updateFrustum(FloatBuffer modelViewMatrix, FloatBuffer projectionMatrix) {
clip.put(0, modelViewMatrix.get(0) * projectionMatrix.get(0) + modelViewMatrix.get(1) * projectionMatrix.get(4)
+ modelViewMatrix.get(2) * projectionMatrix.get(8) + modelViewMatrix.get(3) * projectionMatrix.get(12));
clip.put(1, modelViewMatrix.get(0) * projectionMatrix.get(1) + modelViewMatrix.get(1) * projectionMatrix.get(5)
+ modelViewMatrix.get(2) * projectionMatrix.get(9) + modelViewMatrix.get(3) * projectionMatrix.get(13));
clip.put(2, modelViewMatrix.get(0) * projectionMatrix.get(2) + modelViewMatrix.get(1) * projectionMatrix.get(6)
+ modelViewMatrix.get(2) * projectionMatrix.get(10) + modelViewMatrix.get(3) * projectionMatrix.get(14));
clip.put(3, modelViewMatrix.get(0) * projectionMatrix.get(3) + modelViewMatrix.get(1) * projectionMatrix.get(7)
+ modelViewMatrix.get(2) * projectionMatrix.get(11) + modelViewMatrix.get(3) * projectionMatrix.get(15));
clip.put(4, modelViewMatrix.get(4) * projectionMatrix.get(0) + modelViewMatrix.get(5) * projectionMatrix.get(4)
+ modelViewMatrix.get(6) * projectionMatrix.get(8) + modelViewMatrix.get(7) * projectionMatrix.get(12));
clip.put(5, modelViewMatrix.get(4) * projectionMatrix.get(1) + modelViewMatrix.get(5) * projectionMatrix.get(5)
+ modelViewMatrix.get(6) * projectionMatrix.get(9) + modelViewMatrix.get(7) * projectionMatrix.get(13));
clip.put(6, modelViewMatrix.get(4) * projectionMatrix.get(2) + modelViewMatrix.get(5) * projectionMatrix.get(6)
+ modelViewMatrix.get(6) * projectionMatrix.get(10) + modelViewMatrix.get(7) * projectionMatrix.get(14));
clip.put(7, modelViewMatrix.get(4) * projectionMatrix.get(3) + modelViewMatrix.get(5) * projectionMatrix.get(7)
+ modelViewMatrix.get(6) * projectionMatrix.get(11) + modelViewMatrix.get(7) * projectionMatrix.get(15));
clip.put(8, modelViewMatrix.get(8) * projectionMatrix.get(0) + modelViewMatrix.get(9) * projectionMatrix.get(4)
+ modelViewMatrix.get(10) * projectionMatrix.get(8) + modelViewMatrix.get(11) * projectionMatrix.get(12));
clip.put(9, modelViewMatrix.get(8) * projectionMatrix.get(1) + modelViewMatrix.get(9) * projectionMatrix.get(5)
+ modelViewMatrix.get(10) * projectionMatrix.get(9) + modelViewMatrix.get(11) * projectionMatrix.get(13));
clip.put(10, modelViewMatrix.get(8) * projectionMatrix.get(2) + modelViewMatrix.get(9) * projectionMatrix.get(6)
+ modelViewMatrix.get(10) * projectionMatrix.get(10) + modelViewMatrix.get(11) * projectionMatrix.get(14));
clip.put(11, modelViewMatrix.get(8) * projectionMatrix.get(3) + modelViewMatrix.get(9) * projectionMatrix.get(7)
+ modelViewMatrix.get(10) * projectionMatrix.get(11) + modelViewMatrix.get(11) * projectionMatrix.get(15));
clip.put(12, modelViewMatrix.get(12) * projectionMatrix.get(0) + modelViewMatrix.get(13) * projectionMatrix.get(4)
+ modelViewMatrix.get(14) * projectionMatrix.get(8) + modelViewMatrix.get(15) * projectionMatrix.get(12));
clip.put(13, modelViewMatrix.get(12) * projectionMatrix.get(1) + modelViewMatrix.get(13) * projectionMatrix.get(5)
+ modelViewMatrix.get(14) * projectionMatrix.get(9) + modelViewMatrix.get(15) * projectionMatrix.get(13));
clip.put(14, modelViewMatrix.get(12) * projectionMatrix.get(2) + modelViewMatrix.get(13) * projectionMatrix.get(6)
+ modelViewMatrix.get(14) * projectionMatrix.get(10) + modelViewMatrix.get(15) * projectionMatrix.get(14));
clip.put(15, modelViewMatrix.get(12) * projectionMatrix.get(3) + modelViewMatrix.get(13) * projectionMatrix.get(7)
+ modelViewMatrix.get(14) * projectionMatrix.get(11) + modelViewMatrix.get(15) * projectionMatrix.get(15));
// RIGHT
planes[0].setA(clip.get(3) - clip.get(0));
planes[0].setB(clip.get(7) - clip.get(4));
planes[0].setC(clip.get(11) - clip.get(8));
planes[0].setD(clip.get(15) - clip.get(12));
planes[0].normalize();
// LEFT
planes[1].setA(clip.get(3) + clip.get(0));
planes[1].setB(clip.get(7) + clip.get(4));
planes[1].setC(clip.get(11) + clip.get(8));
planes[1].setD(clip.get(15) + clip.get(12));
planes[1].normalize();
// BOTTOM
planes[2].setA(clip.get(3) + clip.get(1));
planes[2].setB(clip.get(7) + clip.get(5));
planes[2].setC(clip.get(11) + clip.get(9));
planes[2].setD(clip.get(15) + clip.get(13));
planes[2].normalize();
// TOP
planes[3].setA(clip.get(3) - clip.get(1));
planes[3].setB(clip.get(7) - clip.get(5));
planes[3].setC(clip.get(11) - clip.get(9));
planes[3].setD(clip.get(15) - clip.get(13));
planes[3].normalize();
// FAR
planes[4].setA(clip.get(3) - clip.get(2));
planes[4].setB(clip.get(7) - clip.get(6));
planes[4].setC(clip.get(11) - clip.get(10));
planes[4].setD(clip.get(15) - clip.get(14));
planes[4].normalize();
// NEAR
planes[5].setA(clip.get(3) + clip.get(2));
planes[5].setB(clip.get(7) + clip.get(6));
planes[5].setC(clip.get(11) + clip.get(10));
planes[5].setD(clip.get(15) + clip.get(14));
planes[5].normalize();
}
/**
* Returns true if the given point intersects the view frustum.
*/
public boolean intersects(double x, double y, double z) {
for (int i = 0; i < 6; i++) {
if (planes[i].getA() * x + planes[i].getB() * y + planes[i].getC() * z + planes[i].getD() <= 0) {
return false;
}
}
return true;
}
/**
* Returns true if this view frustum intersects the given AABB.
*/
public boolean intersects(AABB aabb) {
Vector3f[] aabbVertices = aabb.getVertices();
Vector3f cp = CoreRegistry.get(LocalPlayer.class).getViewPosition();
for (int i = 0; i < 6; i++) {
if (planes[i].getA() * (aabbVertices[0].x - cp.x) + planes[i].getB() * (aabbVertices[0].y - cp.y)
+ planes[i].getC() * (aabbVertices[0].z - cp.z) + planes[i].getD() > 0) {
continue;
}
if (planes[i].getA() * (aabbVertices[1].x - cp.x) + planes[i].getB() * (aabbVertices[1].y - cp.y)
+ planes[i].getC() * (aabbVertices[1].z - cp.z) + planes[i].getD() > 0) {
continue;
}
if (planes[i].getA() * (aabbVertices[2].x - cp.x) + planes[i].getB() * (aabbVertices[2].y - cp.y)
+ planes[i].getC() * (aabbVertices[2].z - cp.z) + planes[i].getD() > 0) {
continue;
}
if (planes[i].getA() * (aabbVertices[3].x - cp.x) + planes[i].getB() * (aabbVertices[3].y - cp.y)
+ planes[i].getC() * (aabbVertices[3].z - cp.z) + planes[i].getD() > 0) {
continue;
}
if (planes[i].getA() * (aabbVertices[4].x - cp.x) + planes[i].getB() * (aabbVertices[4].y - cp.y)
+ planes[i].getC() * (aabbVertices[4].z - cp.z) + planes[i].getD() > 0) {
continue;
}
if (planes[i].getA() * (aabbVertices[5].x - cp.x) + planes[i].getB() * (aabbVertices[5].y - cp.y)
+ planes[i].getC() * (aabbVertices[5].z - cp.z) + planes[i].getD() > 0) {
continue;
}
if (planes[i].getA() * (aabbVertices[6].x - cp.x) + planes[i].getB() * (aabbVertices[6].y - cp.y)
+ planes[i].getC() * (aabbVertices[6].z - cp.z) + planes[i].getD() > 0) {
continue;
}
if (planes[i].getA() * (aabbVertices[7].x - cp.x) + planes[i].getB() * (aabbVertices[7].y - cp.y)
+ planes[i].getC() * (aabbVertices[7].z - cp.z) + planes[i].getD() > 0) {
continue;
}
return false;
}
return true;
}
/**
* Returns true if the given sphere intersects the given AABB.
*/
public boolean intersects(Vector3f position, float radius) {
for (int i = 0; i < 6; i++) {
if (planes[i].getA() * position.x + planes[i].getB() * position.y + planes[i].getC() * position.z + planes[i].getD() <= -radius) {
return false;
}
}
return true;
}
}