summaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/com/jogamp')
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java97
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/Region.java158
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java354
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java203
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java83
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java105
-rw-r--r--src/jogl/classes/com/jogamp/graph/font/Font.java95
-rw-r--r--src/jogl/classes/com/jogamp/graph/font/FontFactory.java2
-rw-r--r--src/jogl/classes/com/jogamp/graph/font/FontScale.java129
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/Outline.java8
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/SVertex.java224
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/Triangle.java14
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/Vertex.java181
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/plane/AffineTransform.java76
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLAutoDrawable.java9
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLEventListener.java8
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLOffscreenAutoDrawable.java2
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLRunnable.java7
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLUniformData.java153
-rw-r--r--src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java111
-rw-r--r--src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java123
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java1027
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/Matrix4.java172
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/Matrix4f.java2153
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/Quaternion.java404
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/Ray.java13
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/Recti.java134
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/Vec2f.java377
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/Vec2i.java153
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/Vec3f.java393
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/Vec4f.java384
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java673
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/Vert2fImmutable.java7
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/Vert3fImmutable.java4
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java456
-rw-r--r--src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java169
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java25
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java2
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java1514
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/SyncAction.java47
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/SyncBuffer.java61
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/SyncMatrices4f.java41
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/SyncMatrices4f16.java (renamed from src/jogl/classes/com/jogamp/opengl/util/av/AudioSinkFactory.java)76
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/SyncMatrix4f.java42
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/SyncMatrix4f16.java74
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/TimeFrameI.java81
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/av/AudioSink.java436
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java201
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java38
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java27
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java2
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java2
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java17
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java9
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java15
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java44
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java20
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java7
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/texture/ImageSequence.java14
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/texture/TextureSequence.java50
60 files changed, 7415 insertions, 4091 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
index fc8d41660..1a1bd94dd 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
@@ -40,7 +40,9 @@ import com.jogamp.graph.geom.plane.AffineTransform;
import com.jogamp.graph.geom.plane.Path2F;
import com.jogamp.graph.geom.plane.Winding;
import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.math.VectorUtil;
+import com.jogamp.opengl.math.Vert2fImmutable;
import com.jogamp.opengl.math.geom.AABBox;
/**
@@ -128,29 +130,6 @@ public final class OutlineShape implements Comparable<OutlineShape> {
}
}
- /**
- * General purpose {@link OutlineShape} visitor.
- */
- public static interface Visitor {
- /**
- * Visiting the given {@link OutlineShape} with it's corresponding {@link AffineTransform}.
- * @param shape may be used as is, otherwise a copy shall be made if intended to be modified.
- * @param t may be used immediately as is, otherwise a copy shall be made if stored.
- */
- public void visit(final OutlineShape shape, final AffineTransform t);
- }
-
- /**
- * Constrained {@link OutlineShape} visitor w/o {@link AffineTransform}.
- */
- public static interface Visitor2 {
- /**
- * Visiting the given {@link OutlineShape}.
- * @param shape may be used as is, otherwise a copy shall be made if intended to be modified.
- */
- public void visit(final OutlineShape shape);
- }
-
/** Initial {@link #getSharpness()} value, which can be modified via {@link #setSharpness(float)}. */
public static final float DEFAULT_SHARPNESS = 0.5f;
@@ -164,8 +143,6 @@ public final class OutlineShape implements Comparable<OutlineShape> {
*/
public static final int DIRTY_TRIANGLES = 1 << 2;
- private final Vertex.Factory<? extends Vertex> vertexFactory;
-
/** The list of {@link Outline}s that are part of this
* outline shape.
*/
@@ -183,14 +160,14 @@ public final class OutlineShape implements Comparable<OutlineShape> {
private float sharpness;
- private final float[] tmpV1 = new float[3];
- private final float[] tmpV2 = new float[3];
- private final float[] tmpV3 = new float[3];
+ private final Vec3f tmpV1 = new Vec3f();
+ private final Vec3f tmpV2 = new Vec3f();
+ private final Vec3f tmpV3 = new Vec3f();
- /** Create a new Outline based Shape
+ /**
+ * Create a new Outline based Shape
*/
- public OutlineShape(final Vertex.Factory<? extends Vertex> factory) {
- this.vertexFactory = factory;
+ public OutlineShape() {
this.outlines = new ArrayList<Outline>(3);
this.outlines.add(new Outline());
this.outlineState = VerticesState.UNDEFINED;
@@ -241,16 +218,20 @@ public final class OutlineShape implements Comparable<OutlineShape> {
dirtyBits |= DIRTY_TRIANGLES | DIRTY_VERTICES;
}
- /**
- * Returns the associated vertex factory of this outline shape
- * @return Vertex.Factory object
- */
- public final Vertex.Factory<? extends Vertex> vertexFactory() { return vertexFactory; }
-
+ /** Returns the number of {@link Outline}s. */
public final int getOutlineCount() {
return outlines.size();
}
+ /** Returns the total {@link Outline#getVertexCount() vertex number} of all {@link Outline}s. */
+ public final int getVertexCount() {
+ int res = 0;
+ for(final Outline o : outlines) {
+ res += o.getVertexCount();
+ }
+ return res;
+ }
+
/**
* Compute the {@link Winding} of the {@link #getLastOutline()} using the {@link #area(ArrayList)} function over all of its vertices.
* @return {@link Winding#CCW} or {@link Winding#CW}
@@ -438,7 +419,7 @@ public final class OutlineShape implements Comparable<OutlineShape> {
* @see <a href="#windingrules">see winding rules</a>
*/
public final void addVertex(final float x, final float y, final boolean onCurve) {
- addVertex(vertexFactory.create(x, y, 0f, onCurve));
+ addVertex(new Vertex(x, y, 0f, onCurve));
}
/**
@@ -452,7 +433,7 @@ public final class OutlineShape implements Comparable<OutlineShape> {
* @see <a href="#windingrules">see winding rules</a>
*/
public final void addVertex(final int position, final float x, final float y, final boolean onCurve) {
- addVertex(position, vertexFactory.create(x, y, 0f, onCurve));
+ addVertex(position, new Vertex(x, y, 0f, onCurve));
}
/**
@@ -465,7 +446,7 @@ public final class OutlineShape implements Comparable<OutlineShape> {
* @see <a href="#windingrules">see winding rules</a>
*/
public final void addVertex(final float x, final float y, final float z, final boolean onCurve) {
- addVertex(vertexFactory.create(x, y, z, onCurve));
+ addVertex(new Vertex(x, y, z, onCurve));
}
/**
@@ -479,7 +460,7 @@ public final class OutlineShape implements Comparable<OutlineShape> {
* @see <a href="#windingrules">see winding rules</a>
*/
public final void addVertex(final int position, final float x, final float y, final float z, final boolean onCurve) {
- addVertex(position, vertexFactory.create(x, y, z, onCurve));
+ addVertex(position, new Vertex(x, y, z, onCurve));
}
/**
@@ -496,7 +477,7 @@ public final class OutlineShape implements Comparable<OutlineShape> {
* @see <a href="#windingrules">see winding rules</a>
*/
public final void addVertex(final float[] coordsBuffer, final int offset, final int length, final boolean onCurve) {
- addVertex(vertexFactory.create(coordsBuffer, offset, length, onCurve));
+ addVertex(new Vertex(coordsBuffer, offset, length, onCurve));
}
/**
@@ -514,7 +495,7 @@ public final class OutlineShape implements Comparable<OutlineShape> {
* @see <a href="#windingrules">see winding rules</a>
*/
public final void addVertex(final int position, final float[] coordsBuffer, final int offset, final int length, final boolean onCurve) {
- addVertex(position, vertexFactory.create(coordsBuffer, offset, length, onCurve));
+ addVertex(position, new Vertex(coordsBuffer, offset, length, onCurve));
}
/**
@@ -579,9 +560,9 @@ public final class OutlineShape implements Comparable<OutlineShape> {
}
{
// Skip if last vertex in last outline matching this point -> already connected.
- final float[] llc = lo.getVertex(lo_sz-1).getCoord();
- if( llc[0] == points[idx+0] &&
- llc[1] == points[idx+1] ) {
+ final Vert2fImmutable llc = lo.getVertex(lo_sz-1);
+ if( llc.x() == points[idx+0] &&
+ llc.y() == points[idx+1] ) {
break;
}
}
@@ -653,9 +634,9 @@ public final class OutlineShape implements Comparable<OutlineShape> {
}
{
// Skip if last vertex in last outline matching this point -> already connected.
- final float[] llc = lo.getVertex(0).getCoord();
- if( llc[0] == points[idx+0] &&
- llc[1] == points[idx+1] ) {
+ final Vert2fImmutable llc = lo.getVertex(0);
+ if( llc.x() == points[idx+0] &&
+ llc.y() == points[idx+1] ) {
break;
}
}
@@ -791,11 +772,11 @@ public final class OutlineShape implements Comparable<OutlineShape> {
VectorUtil.midVec3(tmpV2, tmpV1, tmpV3);
//drop off-curve vertex to image on the curve
- b.setCoord(tmpV2, 0, 3);
+ b.setCoord(tmpV2);
b.setOnCurve(true);
- outline.addVertex(index, vertexFactory.create(tmpV1, 0, 3, false));
- outline.addVertex(index+2, vertexFactory.create(tmpV3, 0, 3, false));
+ outline.addVertex(index, new Vertex(tmpV1, false));
+ outline.addVertex(index+2, new Vertex(tmpV3, false));
addedVerticeCount += 2;
}
@@ -833,7 +814,7 @@ public final class OutlineShape implements Comparable<OutlineShape> {
} else {
overlap = null;
}
- if( overlaps.contains(currentVertex) || overlap != null ) {
+ if( null != overlap || overlaps.contains(currentVertex) ) {
overlaps.remove(currentVertex);
subdivideTriangle(outline, prevV, currentVertex, nextV, i);
@@ -935,7 +916,7 @@ public final class OutlineShape implements Comparable<OutlineShape> {
if ( !currentVertex.isOnCurve() && !nextVertex.isOnCurve() ) {
VectorUtil.midVec3(tmpV1, currentVertex.getCoord(), nextVertex.getCoord());
System.err.println("XXX: Cubic: "+i+": "+currentVertex+", "+j+": "+nextVertex);
- final Vertex v = vertexFactory.create(tmpV1, 0, 3, true);
+ final Vertex v = new Vertex(tmpV1, true);
i++;
vertexCount++;
addedVerticeCount++;
@@ -947,8 +928,8 @@ public final class OutlineShape implements Comparable<OutlineShape> {
outlines.remove(outline);
cc--;
count--;
- } else if( 0 < vertexCount &&
- VectorUtil.isVec3Equal( outline.getVertex(0).getCoord(), 0, outline.getLastVertex().getCoord(), 0, FloatUtil.EPSILON )) {
+ } else if( 0 < vertexCount &&
+ outline.getVertex(0).getCoord().isEqual( outline.getLastVertex().getCoord() ) ) {
outline.removeVertex(vertexCount-1);
}
}
@@ -1048,10 +1029,10 @@ public final class OutlineShape implements Comparable<OutlineShape> {
* </p>
*/
public final OutlineShape transform(final AffineTransform t) {
- final OutlineShape newOutlineShape = new OutlineShape(vertexFactory);
+ final OutlineShape newOutlineShape = new OutlineShape();
final int osize = outlines.size();
for(int i=0; i<osize; i++) {
- newOutlineShape.addOutline( outlines.get(i).transform(t, vertexFactory) );
+ newOutlineShape.addOutline( outlines.get(i).transform(t) );
}
return newOutlineShape;
}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/Region.java b/src/jogl/classes/com/jogamp/graph/curve/Region.java
index 0ffcad2c1..28ac1a134 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/Region.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/Region.java
@@ -33,6 +33,7 @@ import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.concurrent.TimeUnit;
import jogamp.opengl.Debug;
@@ -44,7 +45,10 @@ import com.jogamp.common.nio.Buffers;
import com.jogamp.common.os.Clock;
import com.jogamp.common.util.PerfCounterCtrl;
import com.jogamp.graph.curve.opengl.GLRegion;
+import com.jogamp.opengl.GLCapabilitiesImmutable;
import com.jogamp.opengl.GLProfile;
+import com.jogamp.opengl.math.Vec3f;
+import com.jogamp.opengl.math.Vec4f;
import com.jogamp.opengl.math.geom.AABBox;
import com.jogamp.opengl.math.geom.Frustum;
import com.jogamp.opengl.util.texture.TextureSequence;
@@ -64,6 +68,14 @@ public abstract class Region {
/**
* Rendering-Mode bit for {@link #getRenderModes() Region}
* <p>
+ * One pass `norm` rendering either using no AA or underlying full-screen AA (fsaa).
+ * </p>
+ */
+ public static final int NORM_RENDERING_BIT = 0;
+
+ /**
+ * Rendering-Mode bit for {@link #getRenderModes() Region}
+ * <p>
* MSAA based Anti-Aliasing, a two pass region rendering, slower and more
* resource hungry (FBO), but providing fast MSAA in case
* the whole scene is not rendered with MSAA.
@@ -169,6 +181,13 @@ public abstract class Region {
return 0 != (renderModes & Region.COLORTEXTURE_RENDERING_BIT);
}
+ /**
+ * Returns a unique technical description string for renderModes as follows:
+ * <pre>
+ * (vbaa|msaa|norm)[-curve][-cols][-ctex]
+ * </pre>
+ * @param renderModes Graph renderModes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}
+ */
public static String getRenderModeString(final int renderModes) {
final String curveS = hasVariableWeight(renderModes) ? "-curve" : "";
final String cChanS = hasColorChannel(renderModes) ? "-cols" : "";
@@ -182,6 +201,20 @@ public abstract class Region {
}
}
+ /**
+ * Return a unique technical description string for renderModes and sample counts as follows:
+ * <pre>
+ * {@link #getRenderModeString(int)}-s{sampleCount}-fsaa{CapsNumSamples}
+ * </pre>
+ *
+ * @param renderModes the used Graph renderModes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}
+ * @param graphSampleCount Graph sample count for {@link Region#VBAA_RENDERING_BIT} or {@link Region#MSAA_RENDERING_BIT}
+ * @param fsaaSampleCount full-screen AA (fsaa) sample count, retrieved e.g. via {@link GLCapabilitiesImmutable#getNumSamples()}
+ */
+ public static String getRenderModeString(final int renderModes, final int graphSampleCount, final int fsaaSampleCount) {
+ return String.format((Locale)null, "%s-s%02d-fsaa%d", Region.getRenderModeString(renderModes), graphSampleCount, fsaaSampleCount);
+ }
+
protected Region(final int regionRenderModes, final boolean use_int32_idx) {
this.renderModes = regionRenderModes;
this.use_int32_idx = use_int32_idx;
@@ -203,36 +236,41 @@ public abstract class Region {
public final boolean usesI32Idx() { return this.use_int32_idx; }
/**
- * Allow the renderer buffers to pre-emptively grow for given vertices- and index counts.
- * @param verticesCount number of vertices to hold
- * @param indicesCount number of indices to hold
+ * Increase the renderer buffers if necessary to add given counts of vertices- and index elements.
+ * <p>
+ * Buffers will not change if remaining free slots, capacity less position, satisfy count elements.
+ * </p>
+ * @param verticesCount number of vertex elements to add if necessary
+ * @param indicesCount number of index elements to add if necessary
+ * @return true if buffer size has changed, i.e. grown. Otherwise false.
* @see #setBufferCapacity(int, int)
* @see #countOutlineShape(OutlineShape, int[])
* @see #countOutlineShapes(List, int[])
*/
- public abstract void growBuffer(int verticesCount, int indicesCount);
+ public abstract boolean growBuffer(int verticesCount, int indicesCount);
/**
* Set the renderer buffers pre-emptively for given vertices- and index counts.
* <p>
- * If the buffers already exceeds given numbers, the buffers are unchanged.
+ * Buffers will not change if given count elements is lower or equal current capacity.
* </p>
* @param verticesCount number of vertices to hold
* @param indicesCount number of indices to hold
+ * @return true if buffer size has changed, i.e. grown. Otherwise false.
* @see #growBuffer(int, int)
* @see #countOutlineShape(OutlineShape, int[])
* @see #countOutlineShapes(List, int[])
*/
- public abstract void setBufferCapacity(int verticesCount, int indicesCount);
+ public abstract boolean setBufferCapacity(int verticesCount, int indicesCount);
- protected abstract void pushVertex(final float[] coords, final float[] texParams, float[] rgba);
- protected abstract void pushVertices(final float[] coords1, final float[] coords2, final float[] coords3,
- final float[] texParams1, final float[] texParams2, final float[] texParams3, float[] rgba);
+ protected abstract void pushVertex(final Vec3f coords, final Vec3f texParams, Vec4f rgba);
+ protected abstract void pushVertices(final Vec3f coords1, final Vec3f coords2, final Vec3f coords3,
+ final Vec3f texParams1, final Vec3f texParams2, final Vec3f texParams3, Vec4f rgba);
protected abstract void pushIndex(int idx);
protected abstract void pushIndices(int idx1, int idx2, int idx3);
/**
- * Return bit-field of render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence)}.
+ * Returns bit-field of render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}.
*/
public final int getRenderModes() { return renderModes; }
@@ -242,7 +280,7 @@ public abstract class Region {
/** See {@link #MAX_QUALITY} */
public final void setQuality(final int q) { quality=q; }
- protected void clearImpl() {
+ protected final void clearImpl() {
dirty = DIRTY_SHAPE | DIRTY_STATE;
numVertices = 0;
box.reset();
@@ -280,7 +318,7 @@ public abstract class Region {
* @see #addOutlineShape(OutlineShape, AffineTransform, float[])
* @see com.jogamp.graph.curve.opengl.RegionRenderer#setColorStatic(com.jogamp.opengl.GL2ES2, float, float, float, float)
*/
- public boolean hasColorChannel() {
+ public final boolean hasColorChannel() {
return Region.hasColorChannel(renderModes);
}
@@ -290,7 +328,7 @@ public abstract class Region {
* otherwise false.
* @see #getRenderModes()
*/
- public boolean hasColorTexture() {
+ public final boolean hasColorTexture() {
return Region.hasColorTexture(renderModes);
}
@@ -305,12 +343,9 @@ public abstract class Region {
this.frustum = frustum;
}
- private void pushNewVertexImpl(final Vertex vertIn, final AffineTransform transform, final float[] rgba) {
+ private void pushNewVertexImpl(final Vertex vertIn, final AffineTransform transform, final Vec4f rgba) {
if( null != transform ) {
- final float[] coordsEx1 = new float[3];
- final float[] coordsIn = vertIn.getCoord();
- transform.transform(coordsIn, coordsEx1);
- coordsEx1[2] = coordsIn[2];
+ final Vec3f coordsEx1 = transform.transform(vertIn.getCoord(), new Vec3f());
box.resize(coordsEx1);
pushVertex(coordsEx1, vertIn.getTexCoord(), rgba);
} else {
@@ -320,20 +355,11 @@ public abstract class Region {
numVertices++;
}
- private void pushNewVerticesImpl(final Vertex vertIn1, final Vertex vertIn2, final Vertex vertIn3, final AffineTransform transform, final float[] rgba) {
+ private void pushNewVerticesImpl(final Vertex vertIn1, final Vertex vertIn2, final Vertex vertIn3, final AffineTransform transform, final Vec4f rgba) {
if( null != transform ) {
- final float[] coordsEx1 = new float[3];
- final float[] coordsEx2 = new float[3];
- final float[] coordsEx3 = new float[3];
- final float[] coordsIn1 = vertIn1.getCoord();
- final float[] coordsIn2 = vertIn2.getCoord();
- final float[] coordsIn3 = vertIn3.getCoord();
- transform.transform(coordsIn1, coordsEx1);
- transform.transform(coordsIn2, coordsEx2);
- transform.transform(coordsIn3, coordsEx3);
- coordsEx1[2] = coordsIn1[2];
- coordsEx2[2] = coordsIn2[2];
- coordsEx3[2] = coordsIn3[2];
+ final Vec3f coordsEx1 = transform.transform(vertIn1.getCoord(), new Vec3f());
+ final Vec3f coordsEx2 = transform.transform(vertIn2.getCoord(), new Vec3f());
+ final Vec3f coordsEx3 = transform.transform(vertIn3.getCoord(), new Vec3f());
box.resize(coordsEx1);
box.resize(coordsEx2);
box.resize(coordsEx3);
@@ -350,11 +376,11 @@ public abstract class Region {
}
@SuppressWarnings("unused")
- private void pushNewVertexIdxImpl(final Vertex vertIn, final AffineTransform transform, final float[] rgba) {
+ private void pushNewVertexIdxImpl(final Vertex vertIn, final AffineTransform transform, final Vec4f rgba) {
pushIndex(numVertices);
pushNewVertexImpl(vertIn, transform, rgba);
}
- private void pushNewVerticesIdxImpl(final Vertex vertIn1, final Vertex vertIn2, final Vertex vertIn3, final AffineTransform transform, final float[] rgba) {
+ private void pushNewVerticesIdxImpl(final Vertex vertIn1, final Vertex vertIn2, final Vertex vertIn3, final AffineTransform transform, final Vec4f rgba) {
pushIndices(numVertices, numVertices+1, numVertices+2);
pushNewVerticesImpl(vertIn1, vertIn2, vertIn3, transform, rgba);
}
@@ -365,12 +391,15 @@ public abstract class Region {
protected static void put3s(final ShortBuffer b, final short v1, final short v2, final short v3) {
b.put(v1); b.put(v2); b.put(v3);
}
- protected static void put3f(final FloatBuffer b, final float v1, final float v2, final float v3) {
- b.put(v1); b.put(v2); b.put(v3);
+ protected static void put3f(final FloatBuffer b, final Vec3f v) {
+ b.put(v.x()); b.put(v.y()); b.put(v.z());
}
protected static void put4f(final FloatBuffer b, final float v1, final float v2, final float v3, final float v4) {
b.put(v1); b.put(v2); b.put(v3); b.put(v4);
}
+ protected static void put4f(final FloatBuffer b, final Vec4f v) {
+ b.put(v.x()); b.put(v.y()); b.put(v.z()); b.put(v.w());
+ }
private final AABBox tmpBox = new AABBox();
@@ -453,38 +482,51 @@ public abstract class Region {
/**
* Count required number of vertices and indices adding to given int[2] `vertIndexCount` array.
* <p>
- * The region's buffer can be either set using {@link Region#setBufferCapacity(int, int)} or grown using {@link Region#growBuffer(int, int)}.
+ * The region's buffer can be either set using {@link Region#setBufferCapacity(int, int)},
+ * {@link GLRegion#create(GLProfile, int, TextureSequence, int, int) GLRegion ctor w/ initial capacities}
+ * or grown using {@link Region#growBuffer(int, int)}.
+ * </p>
+ * <p>
+ * Method is utilized in {@link GLRegion#create(GLProfile, int, TextureSequence, com.jogamp.graph.font.Font, CharSequence) GLRegion ctor w/ font + text},
+ * computing the initial capacity.
* </p>
* @param shape the {@link OutlineShape} to count
* @param vertIndexCount the int[2] storage where the counted vertices and indices are added, vertices at [0] and indices at [1]
+ * @return the given int[2] storage for chaining
* @see #setBufferCapacity(int, int)
* @see #growBuffer(int, int)
*/
- public final void countOutlineShape(final OutlineShape shape, final int[/*2*/] vertIndexCount) {
+ public static final int[] countOutlineShape(final OutlineShape shape, final int[/*2*/] vertIndexCount) {
+ if( null == shape ) {
+ return vertIndexCount;
+ }
final List<Triangle> trisIn = shape.getTriangles(OutlineShape.VerticesState.QUADRATIC_NURBS);
final ArrayList<Vertex> vertsIn = shape.getVertices();
{
- final int verticeCount = vertsIn.size() + shape.getAddedVerticeCount();
- final int indexCount = trisIn.size() * 3;
- vertIndexCount[0] += verticeCount;
- vertIndexCount[1] += Math.min( Math.ceil(verticeCount * 0.6), indexCount );
+ vertIndexCount[0] += vertsIn.size() + shape.getAddedVerticeCount(); // verticesCount
+ vertIndexCount[1] += trisIn.size() * 3; // indicesCount
}
+ return vertIndexCount;
}
/**
* Count required number of vertices and indices adding to given int[2] `vertIndexCount` array.
* <p>
- * The region's buffer can be either set using {@link Region#setBufferCapacity(int, int)} or grown using {@link Region#growBuffer(int, int)}.
+ * The region's buffer can be either set using {@link Region#setBufferCapacity(int, int)},
+ * {@link GLRegion#create(GLProfile, int, TextureSequence, int, int) GLRegion ctor w/ initial capacities}
+ * or grown using {@link Region#growBuffer(int, int)}.
* </p>
* @param shapes list of {@link OutlineShape} to count
* @param vertIndexCount the int[2] storage where the counted vertices and indices are added, vertices at [0] and indices at [1]
+ * @return the given int[2] storage for chaining
* @see #setBufferCapacity(int, int)
* @see #growBuffer(int, int)
*/
- public final void countOutlineShapes(final List<OutlineShape> shapes, final int[/*2*/] vertIndexCount) {
+ public static final int[] countOutlineShapes(final List<OutlineShape> shapes, final int[/*2*/] vertIndexCount) {
for (int i = 0; i < shapes.size(); i++) {
countOutlineShape(shapes.get(i), vertIndexCount);
}
+ return vertIndexCount;
}
/**
@@ -498,7 +540,7 @@ public abstract class Region {
* @param t the optional {@link AffineTransform} to be applied on each vertex
* @param rgbaColor if {@link #hasColorChannel()} RGBA color must be passed, otherwise value is ignored.
*/
- public final void addOutlineShape(final OutlineShape shape, final AffineTransform t, final float[] rgbaColor) {
+ public final void addOutlineShape(final OutlineShape shape, final AffineTransform t, final Vec4f rgbaColor) {
if( null != frustum ) {
final AABBox shapeBox = shape.getBounds();
final AABBox shapeBoxT;
@@ -515,11 +557,14 @@ public abstract class Region {
if( null == perf && !DEBUG_INSTANCE ) {
addOutlineShape0(shape, t, rgbaColor);
} else {
+ if( null == perf ) {
+ perfCounter().enable(true);
+ }
addOutlineShape1(shape, t, rgbaColor);
}
markShapeDirty();
}
- private final void addOutlineShape0(final OutlineShape shape, final AffineTransform t, final float[] rgbaColor) {
+ private final void addOutlineShape0(final OutlineShape shape, final AffineTransform t, final Vec4f rgbaColor) {
final List<Triangle> trisIn = shape.getTriangles(OutlineShape.VerticesState.QUADRATIC_NURBS);
final ArrayList<Vertex> vertsIn = shape.getVertices();
{
@@ -556,7 +601,7 @@ public abstract class Region {
}
}
}
- private final void addOutlineShape1(final OutlineShape shape, final AffineTransform t, final float[] rgbaColor) {
+ private final void addOutlineShape1(final OutlineShape shape, final AffineTransform t, final Vec4f rgbaColor) {
++perf.count;
final long t0 = Clock.currentNanos();
final List<Triangle> trisIn = shape.getTriangles(OutlineShape.VerticesState.QUADRATIC_NURBS);
@@ -651,7 +696,7 @@ public abstract class Region {
* @param t the optional {@link AffineTransform} to be applied on each vertex
* @param rgbaColor if {@link #hasColorChannel()} RGBA color must be passed, otherwise value is ignored.
*/
- public final void addOutlineShapes(final List<OutlineShape> shapes, final AffineTransform transform, final float[] rgbaColor) {
+ public final void addOutlineShapes(final List<OutlineShape> shapes, final AffineTransform transform, final Vec4f rgbaColor) {
for (int i = 0; i < shapes.size(); i++) {
addOutlineShape(shapes.get(i), transform, rgbaColor);
}
@@ -663,8 +708,14 @@ public abstract class Region {
}
/**
- * Mark this region's shape dirty, i.e. it's
- * Vertices, Triangles, and or Lines changed.
+ * Mark this region's shape dirty,
+ * i.e. its vertices, triangles, lines and/or color-texture coordinates changed.
+ * <p>
+ * The data will be re-uploaded to the GPU at next {@link GLRegion#draw(com.jogamp.opengl.GL2ES2, com.jogamp.graph.curve.opengl.RegionRenderer, int[]) draw(..)}.
+ * </p>
+ * <p>
+ * In 2-pass mode, this implies updating the FBO itself as well.
+ * </p>
*/
public final void markShapeDirty() {
dirty |= DIRTY_SHAPE;
@@ -674,8 +725,11 @@ public abstract class Region {
return 0 != ( dirty & DIRTY_SHAPE ) ;
}
/**
- * Mark this region's state dirty, i.e.
- * it's render attributes or parameters changed.
+ * Mark this region's render-state dirty, i.e. re-selecting a shader program regarding color-texture and -channel,
+ * and rendering the region into the FBO in 2-pass mode.
+ * <p>
+ * In 1-pass mode, re-selection of the shader-program is based on color-texture and -channel only.
+ * </p>
*/
public final void markStateDirty() {
dirty |= DIRTY_STATE;
@@ -695,6 +749,6 @@ public abstract class Region {
@Override
public String toString() {
- return "Region["+getRenderModeString(this.renderModes)+", q "+quality+", dirty "+dirty+", vertices "+numVertices+", box "+box+"]";
+ return "Region[0x"+Integer.toHexString(hashCode())+", "+getRenderModeString(this.renderModes)+", q "+quality+", dirty "+dirty+", vertices "+numVertices+", box "+box+"]";
}
} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java
index e02752f73..49daa344b 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java
@@ -32,17 +32,28 @@ import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GLArrayData;
import com.jogamp.opengl.util.GLArrayDataClient;
import com.jogamp.opengl.util.GLArrayDataEditable;
+import com.jogamp.opengl.util.GLArrayDataServer;
+import com.jogamp.opengl.util.GLArrayDataWrapper;
import com.jogamp.opengl.GLProfile;
+import com.jogamp.opengl.math.Vec3f;
+import com.jogamp.opengl.math.Vec4f;
import jogamp.graph.curve.opengl.VBORegion2PMSAAES2;
import jogamp.graph.curve.opengl.VBORegion2PVBAAES2;
import jogamp.graph.curve.opengl.VBORegionSPES2;
+import jogamp.graph.curve.opengl.shader.AttributeNames;
+import jogamp.opengl.Debug;
import com.jogamp.opengl.util.PMVMatrix;
+import com.jogamp.opengl.util.glsl.ShaderProgram;
import com.jogamp.opengl.util.texture.TextureSequence;
import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.font.Font;
import java.io.PrintStream;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
import com.jogamp.graph.curve.OutlineShape;
@@ -65,22 +76,27 @@ public abstract class GLRegion extends Region {
* - Ubuntu Light ~ vertices 100/char, indices 50/char
* - FreeSerif ~ vertices 115/char, indices 61/char
*
- * Now let's assume a minimum of 10 chars will be rendered
+ * However, proper initial size is pre-calculated via ..
+ * - {@link GLRegion#create(GLProfile, int, TextureSequence, Font, CharSequence)}
+ * - {@Link Region#countOutlineShape(OutlineShape, int[])}
+ * - {@link TextRegionUtil#countStringRegion(Font, CharSequence, int[])}
*/
/**
- * Default initial vertices count based on 10 chars w/ FreeSans @ 64 vertices/char avg.
+ * Default initial vertices count {@value}, assuming small sized shapes.
*/
- public static final int defaultVerticesCount = 10*64;
+ public static final int defaultVerticesCount = 64;
/**
- * Default initial indices count based on 10 chars w/ FreeSans @ 33 indices/char avg.
+ * Default initial indices count {@value}, assuming small sized shapes.
*/
- public static final int defaultIndicesCount = 10*33;
+ public static final int defaultIndicesCount = 64;
// private static final float growthFactor = 1.2f; // avg +5% size but 15% more overhead (34% total)
protected static final float growthFactor = GLArrayDataClient.DEFAULT_GROWTH_FACTOR; // avg +20% size, but 15% less CPU overhead compared to 1.2 (19% total)
+ private static final boolean DEBUG_BUFFER = Debug.debug("graph.curve.Buffer");
+
/**
* Create a GLRegion using the passed render mode
*
@@ -108,7 +124,7 @@ public abstract class GLRegion extends Region {
}
/**
- * Create a GLRegion using the passed render mode
+ * Create a GLRegion using the passed render mode and default initial buffer sizes {@link #defaultVerticesCount} and {@link #defaultIndicesCount}.
*
* <p> In case {@link Region#VBAA_RENDERING_BIT} is being requested the default texture unit
* {@link Region#DEFAULT_TWO_PASS_TEXTURE_UNIT} is being used.</p>
@@ -120,9 +136,61 @@ public abstract class GLRegion extends Region {
return GLRegion.create(glp, renderModes, colorTexSeq, defaultVerticesCount, defaultIndicesCount);
}
+ /**
+ * Create a GLRegion using the passed render mode and pre-calculating its buffer sizes
+ * using {@link Region#countOutlineShape(OutlineShape, int[])}.
+ *
+ * <p> In case {@link Region#VBAA_RENDERING_BIT} is being requested the default texture unit
+ * {@link Region#DEFAULT_TWO_PASS_TEXTURE_UNIT} is being used.</p>
+ * @param glp intended GLProfile to use. Instance may use higher OpenGL features if indicated by GLProfile.
+ * @param renderModes bit-field of modes, e.g. {@link Region#VARWEIGHT_RENDERING_BIT}, {@link Region#VBAA_RENDERING_BIT}
+ * @param colorTexSeq optional {@link TextureSequence} for {@link Region#COLORTEXTURE_RENDERING_BIT} rendering mode.
+ * @param shape the {@link OutlineShape} used to determine {@link GLRegion}'s buffer sizes via {@link Region#countOutlineShape(OutlineShape, int[])}
+ */
+ public static GLRegion create(final GLProfile glp, final int renderModes, final TextureSequence colorTexSeq, final OutlineShape shape) {
+ final int[/*2*/] vertIndexCount = Region.countOutlineShape(shape, new int[2]);
+ return GLRegion.create(glp, renderModes, colorTexSeq, vertIndexCount[0], vertIndexCount[1]);
+ }
+
+ /**
+ * Create a GLRegion using the passed render mode and pre-calculating its buffer sizes
+ * using given font's {@link Font#processString(com.jogamp.graph.font.Font.GlyphVisitor2, CharSequence)}
+ * to {@link #countOutlineShape(OutlineShape, int[])}.
+ *
+ * <p> In case {@link Region#VBAA_RENDERING_BIT} is being requested the default texture unit
+ * {@link Region#DEFAULT_TWO_PASS_TEXTURE_UNIT} is being used.</p>
+ * @param glp intended GLProfile to use. Instance may use higher OpenGL features if indicated by GLProfile.
+ * @param renderModes bit-field of modes, e.g. {@link Region#VARWEIGHT_RENDERING_BIT}, {@link Region#VBAA_RENDERING_BIT}
+ * @param colorTexSeq optional {@link TextureSequence} for {@link Region#COLORTEXTURE_RENDERING_BIT} rendering mode.
+ * @param font Font used to {@link Font#processString(com.jogamp.graph.curve.OutlineShape.Visitor2, CharSequence)} to {@link #countOutlineShape(OutlineShape, int[]) to count initial number of vertices and indices}
+ * @param str the string used to to {@link #countOutlineShape(OutlineShape, int[]) to count initial number of vertices and indices}
+ */
+ public static GLRegion create(final GLProfile glp, final int renderModes, final TextureSequence colorTexSeq, final Font font, final CharSequence str) {
+ final int[] vertIndexCount = { 0, 0 };
+ final Font.GlyphVisitor2 visitor = new Font.GlyphVisitor2() {
+ @Override
+ public final void visit(final char symbol, final Font.Glyph glyph) {
+ Region.countOutlineShape(glyph.getShape(), vertIndexCount);
+ } };
+ font.processString(visitor, str);
+ return GLRegion.create(glp, renderModes, colorTexSeq, vertIndexCount[0], vertIndexCount[1]);
+ }
+
private final int gl_idx_type;
protected final TextureSequence colorTexSeq;
+ // pass-1 common data
+ protected int curVerticesCap = 0;
+ protected int curIndicesCap = 0;
+ protected int growCount = 0;
+
+ /** Interleaved buffer for GLSL attributes: vectices, curveParams and optionally colors */
+ protected GLArrayDataServer vpc_ileave = null;
+ protected GLArrayDataWrapper gca_VerticesAttr = null;
+ protected GLArrayDataWrapper gca_CurveParamsAttr = null;
+ protected GLArrayDataWrapper gca_ColorsAttr = null;
+ protected GLArrayDataServer indicesBuffer = null;
+
protected GLRegion(final GLProfile glp, final int renderModes, final TextureSequence colorTexSeq) {
super(renderModes, glp.isGL2ES3() /* use_int32_idx */);
this.gl_idx_type = usesI32Idx() ? GL.GL_UNSIGNED_INT : GL.GL_UNSIGNED_SHORT;
@@ -131,19 +199,125 @@ public abstract class GLRegion extends Region {
protected final int glIdxType() { return this.gl_idx_type; }
- /**
- * Updates a graph region by updating the ogl related
- * objects for use in rendering if {@link #isShapeDirty()}.
- * <p>Allocates the ogl related data and initializes it the 1st time.<p>
- * <p>Called by {@link #draw(GL2ES2, RenderState, int, int, int)}.</p>
- */
- protected abstract void updateImpl(final GL2ES2 gl);
+ public GLArrayDataServer createInterleaved(final boolean useMappedBuffers, final int comps, final int dataType, final boolean normalized, final int initialSize, final int vboUsage) {
+ if( useMappedBuffers ) {
+ return GLArrayDataServer.createGLSLInterleavedMapped(comps, dataType, normalized, initialSize, vboUsage);
+ } else {
+ return GLArrayDataServer.createGLSLInterleaved(comps, dataType, normalized, initialSize, vboUsage);
+ }
+ }
- protected abstract void destroyImpl(final GL2ES2 gl);
+ public void addInterleavedVertexAndNormalArrays(final GLArrayDataServer array, final int components) {
+ array.addGLSLSubArray("vertices", components, GL.GL_ARRAY_BUFFER);
+ array.addGLSLSubArray("normals", components, GL.GL_ARRAY_BUFFER);
+ }
- protected abstract void clearImpl(final GL2ES2 gl);
+ protected final void initBuffer(final int verticeCount, final int indexCount) {
+ indicesBuffer = GLArrayDataServer.createData(3, glIdxType(), indexCount, GL.GL_STATIC_DRAW, GL.GL_ELEMENT_ARRAY_BUFFER);
+ indicesBuffer.setGrowthFactor(growthFactor);
+ curIndicesCap = indicesBuffer.getElemCapacity();
+
+ final boolean cc = hasColorChannel();
+ final int totalCompsPerElem = 3 + 3 + (cc ? 4 : 0);
+ vpc_ileave = GLArrayDataServer.createGLSLInterleaved(totalCompsPerElem, GL.GL_FLOAT, false /* normalized */, verticeCount, GL.GL_STATIC_DRAW);
+ vpc_ileave.setGrowthFactor(growthFactor);
+
+ gca_VerticesAttr = vpc_ileave.addGLSLSubArray(AttributeNames.VERTEX_ATTR_NAME, 3, GL.GL_ARRAY_BUFFER);
+ gca_CurveParamsAttr = vpc_ileave.addGLSLSubArray(AttributeNames.CURVEPARAMS_ATTR_NAME, 3, GL.GL_ARRAY_BUFFER);
+ if( cc ) {
+ gca_ColorsAttr = vpc_ileave.addGLSLSubArray(AttributeNames.COLOR_ATTR_NAME, 4, GL.GL_ARRAY_BUFFER);
+ }
+ curVerticesCap = vpc_ileave.getElemCapacity();
+ growCount = 0;
+ }
+
+ @Override
+ public final boolean growBuffer(final int verticesCount, final int indicesCount) {
+ boolean grown = false;
+ if( !DEBUG_BUFFER ) {
+ if( curIndicesCap < indicesBuffer.elemPosition() + indicesCount ) {
+ indicesBuffer.growIfNeeded(indicesCount * indicesBuffer.getCompsPerElem());
+ curIndicesCap = indicesBuffer.getElemCapacity();
+ grown = true;
+ }
+ if( curVerticesCap < vpc_ileave.elemPosition() + verticesCount ) {
+ vpc_ileave.growIfNeeded(verticesCount * vpc_ileave.getCompsPerElem());
+ curVerticesCap = vpc_ileave.getElemCapacity();
+ grown = true;
+ }
+ } else {
+ if( curIndicesCap < indicesBuffer.elemPosition() + indicesCount ) {
+ System.err.printf("GLRegion: Buffer grow - Indices: %d < ( %d = %d + %d ); Status: %s%n",
+ curIndicesCap, indicesBuffer.elemPosition() + indicesCount, indicesBuffer.elemPosition(), indicesCount, indicesBuffer.elemStatsToString());
+
+ indicesBuffer.growIfNeeded(indicesCount * indicesBuffer.getCompsPerElem());
+
+ System.err.println("GLRegion: Grew Indices 0x"+Integer.toHexString(hashCode())+": "+curIndicesCap+" -> "+indicesBuffer.getElemCapacity()+", "+indicesBuffer.elemStatsToString());
+ Thread.dumpStack();
+
+ curIndicesCap = indicesBuffer.getElemCapacity();
+ grown = true;
+ }
+ if( curVerticesCap < vpc_ileave.elemPosition() + verticesCount ) {
+ System.err.printf("GLRegion: Buffer grow - Vertices: %d < ( %d = %d + %d ); Status: %s%n",
+ curVerticesCap, gca_VerticesAttr.elemPosition() + verticesCount, gca_VerticesAttr.elemPosition(), verticesCount, gca_VerticesAttr.elemStatsToString());
+
+ vpc_ileave.growIfNeeded(verticesCount * vpc_ileave.getCompsPerElem());
+
+ System.err.println("GLRegion: Grew Vertices 0x"+Integer.toHexString(hashCode())+": "+curVerticesCap+" -> "+gca_VerticesAttr.getElemCapacity()+", "+gca_VerticesAttr.elemStatsToString());
+
+ curVerticesCap = vpc_ileave.getElemCapacity();
+ grown = true;
+ }
+ }
+ if( grown ) {
+ ++growCount;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public final boolean setBufferCapacity(final int verticesCount, final int indicesCount) {
+ boolean grown = false;
+ if( curIndicesCap < indicesCount ) {
+ indicesBuffer.reserve(indicesCount);
+ curIndicesCap = indicesBuffer.getElemCapacity();
+ grown = true;
+ }
+ if( curVerticesCap < verticesCount ) {
+ vpc_ileave.reserve(verticesCount);
+ curVerticesCap = vpc_ileave.getElemCapacity();
+ grown = true;
+ }
+ return grown;
+ }
- protected static void printAndCount(final PrintStream out, final String name, final GLArrayData data, final int[] size, final int[] capacity) {
+ @Override
+ public final void printBufferStats(final PrintStream out) {
+ final int[] size= { 0 }, capacity= { 0 };
+ out.println("GLRegion: idx32 "+usesI32Idx()+", obj 0x"+Integer.toHexString(hashCode()));
+ printAndCount(out, " indices ", indicesBuffer, size, capacity);
+ out.println();
+ printAndCount(out, " ileave ", vpc_ileave, size, capacity);
+ out.println();
+ {
+ print(out, " - vertices ", gca_VerticesAttr);
+ out.println();
+ print(out, " - params ", gca_CurveParamsAttr);
+ out.println();
+ print(out, " - color ", gca_ColorsAttr);
+ out.println();
+ }
+ final float filled = (float)size[0]/(float)capacity[0];
+ out.printf(" total [bytes %,d / %,d], filled[%.1f%%, left %.1f%%], grow-cnt %d, obj 0x%x%n",
+ size[0], capacity[0], filled*100f, (1f-filled)*100f, growCount, hashCode());
+ // out.printf(" vpc_ileave: %s%n", vpc_ileave.toString());
+ // out.printf(" - vertices: %s%n", gca_VerticesAttr.toString());
+ }
+
+ private static void printAndCount(final PrintStream out, final String name, final GLArrayData data, final int[] size, final int[] capacity) {
out.print(name+"[");
if( null != data ) {
out.print(data.fillStatsToString());
@@ -154,6 +328,76 @@ public abstract class GLRegion extends Region {
out.print("null]");
}
}
+ private static void print(final PrintStream out, final String name, final GLArrayData data) {
+ out.print(name+"[");
+ if( null != data ) {
+ out.print(data.fillStatsToString());
+ out.print("]");
+ } else {
+ out.print("null]");
+ }
+ }
+
+ @Override
+ protected final void pushVertex(final Vec3f coords, final Vec3f texParams, final Vec4f rgba) {
+ // NIO array[3] is much slows than group/single
+ // gca_VerticesAttr.putf(coords, 0, 3);
+ // gca_CurveParamsAttr.putf(texParams, 0, 3);
+ // gca_VerticesAttr.put3f(coords.x(), coords.y(), coords.z());
+ put3f((FloatBuffer)vpc_ileave.getBuffer(), coords);
+ put3f((FloatBuffer)vpc_ileave.getBuffer(), texParams);
+ if( hasColorChannel() ) {
+ if( null != rgba ) {
+ put4f((FloatBuffer)vpc_ileave.getBuffer(), rgba);
+ } else {
+ throw new IllegalArgumentException("Null color given for COLOR_CHANNEL rendering mode");
+ }
+ }
+ }
+
+ @Override
+ protected final void pushVertices(final Vec3f coords1, final Vec3f coords2, final Vec3f coords3,
+ final Vec3f texParams1, final Vec3f texParams2, final Vec3f texParams3, final Vec4f rgba) {
+ final boolean cc = hasColorChannel();
+ if( cc && null == rgba ) {
+ throw new IllegalArgumentException("Null color given for COLOR_CHANNEL rendering mode");
+ }
+ put3f((FloatBuffer)vpc_ileave.getBuffer(), coords1);
+ put3f((FloatBuffer)vpc_ileave.getBuffer(), texParams1);
+ if( cc ) {
+ put4f((FloatBuffer)vpc_ileave.getBuffer(), rgba);
+ }
+ put3f((FloatBuffer)vpc_ileave.getBuffer(), coords2);
+ put3f((FloatBuffer)vpc_ileave.getBuffer(), texParams2);
+ if( cc ) {
+ put4f((FloatBuffer)vpc_ileave.getBuffer(), rgba);
+ }
+ put3f((FloatBuffer)vpc_ileave.getBuffer(), coords3);
+ put3f((FloatBuffer)vpc_ileave.getBuffer(), texParams3);
+ if( cc ) {
+ put4f((FloatBuffer)vpc_ileave.getBuffer(), rgba);
+ }
+ }
+
+ @Override
+ protected final void pushIndex(final int idx) {
+ if( usesI32Idx() ) {
+ indicesBuffer.puti(idx);
+ } else {
+ indicesBuffer.puts((short)idx);
+ }
+ }
+
+ @Override
+ protected final void pushIndices(final int idx1, final int idx2, final int idx3) {
+ if( usesI32Idx() ) {
+ // indicesBuffer.put3i(idx1, idx2, idx3);
+ put3i((IntBuffer)indicesBuffer.getBuffer(), idx1, idx2, idx3);
+ } else {
+ // indicesBuffer.put3s((short)idx1, (short)idx2, (short)idx3);
+ put3s((ShortBuffer)indicesBuffer.getBuffer(), (short)idx1, (short)idx2, (short)idx3);
+ }
+ }
/**
* Clears all buffers, i.e. triangles, vertices etc and and resets states accordingly, see {@link GLArrayDataEditable#clear(GL)}.
@@ -165,19 +409,58 @@ public abstract class GLRegion extends Region {
* @return this {@link GLRegion} for chaining.
* @see GLArrayDataEditable#clear(GL)
*/
- public GLRegion clear(final GL2ES2 gl) {
+ public final GLRegion clear(final GL2ES2 gl) {
+ lastRenderModes = 0;
+ if(DEBUG_INSTANCE) {
+ System.err.println("GLRegion Clear: " + this);
+ }
+ if( null != indicesBuffer ) {
+ indicesBuffer.clear(gl);
+ }
+ if( null != vpc_ileave ) {
+ vpc_ileave.clear(gl);
+ }
clearImpl(gl);
clearImpl();
return this;
}
+ protected abstract void clearImpl(final GL2ES2 gl);
/**
* Delete and clear the associated OGL objects.
+ * <p>
+ * The {@link ShaderProgram}s references are nullified but not {@link ShaderProgram#destroy(GL2ES2) destroyed}
+ * as they are owned by {@link RegionRenderer}.
+ * </p>
*/
public final void destroy(final GL2ES2 gl) {
clear(gl);
+ if( null != vpc_ileave ) {
+ vpc_ileave.destroy(gl);
+ vpc_ileave = null;
+ }
+ if( null != gca_VerticesAttr ) {
+ gca_VerticesAttr.destroy(gl);
+ gca_VerticesAttr = null;
+ }
+ if( null != gca_CurveParamsAttr ) {
+ gca_CurveParamsAttr.destroy(gl);
+ gca_CurveParamsAttr = null;
+ }
+ if( null != gca_ColorsAttr ) {
+ gca_ColorsAttr.destroy(gl);
+ gca_ColorsAttr = null;
+ }
+ if(null != indicesBuffer) {
+ indicesBuffer.destroy(gl);
+ indicesBuffer = null;
+ }
+ curVerticesCap = 0;
+ curIndicesCap = 0;
+ growCount = 0;
destroyImpl(gl);
}
+ protected abstract void destroyImpl(final GL2ES2 gl);
/**
* Renders the associated OGL objects specifying
@@ -199,22 +482,49 @@ public abstract class GLRegion extends Region {
* The <i>alpha</i> component shall be set to zero.
* Note: If {@link GL#GL_BLEND blending} is enabled, the
* {@link RegionRenderer} might need to be
- * {@link RegionRenderer#create(RenderState, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback) created}
+ * {@link RegionRenderer#create(Vertex.Factory<? extends Vertex>, RenderState, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback) created}
* with the appropriate {@link RegionRenderer.GLCallback callbacks}.
* </p>
* @param matrix current {@link PMVMatrix}.
* @param renderer the {@link RegionRenderer} to be used
- * @param sampleCount desired multisampling sample count for msaa-rendering.
+ * @param sampleCount desired multisampling sample count for vbaa- or msaa-rendering.
+ * Use -1 for glSelect mode, pass1 w/o any color texture nor channel, use static select color only.
* The actual used scample-count is written back when msaa-rendering is enabled, otherwise the store is untouched.
* @see RegionRenderer#enable(GL2ES2, boolean)
*/
public final void draw(final GL2ES2 gl, final RegionRenderer renderer, final int[/*1*/] sampleCount) {
+ final int curRenderModes;
+ if( null == sampleCount || 0 == sampleCount[0] ) {
+ // no sampling, reduce to pass1
+ curRenderModes = getRenderModes() & ~( VBAA_RENDERING_BIT | MSAA_RENDERING_BIT );
+ } else if( 0 > sampleCount[0] ) {
+ // negative sampling, hint we perform glSelect: pass1 w/o any color texture nor channel, use static select color only
+ curRenderModes = getRenderModes() & ~( VBAA_RENDERING_BIT | MSAA_RENDERING_BIT | COLORCHANNEL_RENDERING_BIT | COLORTEXTURE_RENDERING_BIT );
+ } else {
+ // normal 2-pass sampling
+ curRenderModes = getRenderModes();
+ }
+ if( lastRenderModes != curRenderModes ) {
+ markShapeDirty();
+ markStateDirty();
+ }
if( isShapeDirty() ) {
- updateImpl(gl);
+ updateImpl(gl, curRenderModes);
}
- drawImpl(gl, renderer, sampleCount);
+ drawImpl(gl, renderer, curRenderModes, sampleCount);
clearDirtyBits(DIRTY_SHAPE|DIRTY_STATE);
+ lastRenderModes = curRenderModes;
}
+ private int lastRenderModes = 0;
+
+ /**
+ * Updates a graph region by updating the ogl related
+ * objects for use in rendering if {@link #isShapeDirty()}.
+ * <p>Allocates the ogl related data and initializes it the 1st time.<p>
+ * <p>Called by {@link #draw(GL2ES2, RenderState, int, int, int)}.</p>
+ * @param curRenderModes TODO
+ */
+ protected abstract void updateImpl(final GL2ES2 gl, int curRenderModes);
- protected abstract void drawImpl(final GL2ES2 gl, final RegionRenderer renderer, final int[/*1*/] sampleCount);
+ protected abstract void drawImpl(final GL2ES2 gl, final RegionRenderer renderer, int curRenderModes, final int[/*1*/] sampleCount);
}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
index 6f419704b..4863e97d6 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -35,11 +35,13 @@ import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GLES2;
import com.jogamp.opengl.GLException;
import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
+import com.jogamp.opengl.math.Recti;
import jogamp.graph.curve.opengl.shader.AttributeNames;
import jogamp.graph.curve.opengl.shader.UniformNames;
import com.jogamp.opengl.GLExtensions;
+import com.jogamp.opengl.GLRendererQuirks;
import com.jogamp.opengl.util.glsl.ShaderCode;
import com.jogamp.opengl.util.glsl.ShaderProgram;
import com.jogamp.opengl.util.texture.TextureSequence;
@@ -50,18 +52,23 @@ import com.jogamp.graph.curve.Region;
/**
* OpenGL {@link Region} renderer
- * <p>
- * All OpenGL related operations regarding {@link Region}s
- * are passed through an instance of this class.
- * </p>
+ *
+ * All {@link Region} rendering operations utilize a RegionRenderer.
+ *
+ * The RegionRenderer owns its {@link RenderState}, a composition.
+ *
+ * The RegionRenderer manages and own all used {@link ShaderProgram}s, a composition.
+ *
+ * At its {@link #destroy(GL2ES2) destruction}, all {@link ShaderProgram}s and its {@link RenderState}
+ * will be destroyed and released.
*/
-public class RegionRenderer {
+public final class RegionRenderer {
protected static final boolean DEBUG = Region.DEBUG;
protected static final boolean DEBUG_INSTANCE = Region.DEBUG_INSTANCE;
/**
* May be passed to
- * {@link RegionRenderer#create(RenderState, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback) RegionRenderer ctor},
+ * {@link RegionRenderer#create(Vertex.Factory<? extends Vertex>, RenderState, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback, com.jogamp.graph.curve.opengl.RegionRenderer.GLCallback) RegionRenderer ctor},
* e.g.
* <ul>
* <li>{@link RegionRenderer#defaultBlendEnable}</li>
@@ -86,7 +93,7 @@ public class RegionRenderer {
* to set the proper {@link GL#glBlendFuncSeparate(int, int, int, int) blend-function}
* and the clear-color to <i>transparent-black</i> in case of {@link Region#isTwoPass(int) multipass} FBO rendering.
* </p>
- * @see #create(RenderState, GLCallback, GLCallback)
+ * @see #create(Vertex.Factory<? extends Vertex>, RenderState, GLCallback, GLCallback)
* @see #enable(GL2ES2, boolean)
*/
public static final GLCallback defaultBlendEnable = new GLCallback() {
@@ -110,7 +117,7 @@ public class RegionRenderer {
* <p>
* Implementation also clears {@link RegionRenderer#getRenderState() RenderState}'s {@link RenderState#BITHINT_BLENDING_ENABLED blending bit-hint}.
* </p>
- * @see #create(RenderState, GLCallback, GLCallback)
+ * @see #create(Vertex.Factory<? extends Vertex>, RenderState, GLCallback, GLCallback)
* @see #enable(GL2ES2, boolean)
*/
public static final GLCallback defaultBlendDisable = new GLCallback() {
@@ -127,14 +134,48 @@ public class RegionRenderer {
};
/**
- * Create a Hardware accelerated Region Renderer.
+ * Create a hardware accelerated RegionRenderer including its {@link RenderState} composition.
+ * <p>
+ * The optional {@link GLCallback}s <code>enableCallback</code> and <code>disableCallback</code>
+ * maybe used to issue certain tasks at {@link #enable(GL2ES2, boolean)}.<br/>
+ * For example, instances {@link #defaultBlendEnable} and {@link #defaultBlendDisable}
+ * can be utilized to enable and disable {@link GL#GL_BLEND}.
+ * </p>
+ * @return an instance of Region Renderer
+ * @see #enable(GL2ES2, boolean)
+ */
+ public static RegionRenderer create() {
+ return new RegionRenderer(null, null, null);
+ }
+
+ /**
+ * Create a hardware accelerated RegionRenderer including its {@link RenderState} composition.
+ * <p>
+ * The optional {@link GLCallback}s <code>enableCallback</code> and <code>disableCallback</code>
+ * maybe used to issue certain tasks at {@link #enable(GL2ES2, boolean)}.<br/>
+ * For example, instances {@link #defaultBlendEnable} and {@link #defaultBlendDisable}
+ * can be utilized to enable and disable {@link GL#GL_BLEND}.
+ * </p>
+ * @param enableCallback optional {@link GLCallback}, if not <code>null</code> will be issued at
+ * {@link #init(GL2ES2) init(gl)} and {@link #enable(GL2ES2, boolean) enable(gl, true)}.
+ * @param disableCallback optional {@link GLCallback}, if not <code>null</code> will be issued at
+ * {@link #enable(GL2ES2, boolean) enable(gl, false)}.
+ * @return an instance of Region Renderer
+ * @see #enable(GL2ES2, boolean)
+ */
+ public static RegionRenderer create(final GLCallback enableCallback, final GLCallback disableCallback) {
+ return new RegionRenderer(enableCallback, disableCallback);
+ }
+
+ /**
+ * Create a hardware accelerated RegionRenderer including its {@link RenderState} composition.
* <p>
* The optional {@link GLCallback}s <code>enableCallback</code> and <code>disableCallback</code>
* maybe used to issue certain tasks at {@link #enable(GL2ES2, boolean)}.<br/>
* For example, instances {@link #defaultBlendEnable} and {@link #defaultBlendDisable}
* can be utilized to enable and disable {@link GL#GL_BLEND}.
* </p>
- * @param rs the used {@link RenderState}
+ * @param sharedPMVMatrix optional shared {@link PMVMatrix} to be used for the {@link RenderState} composition.
* @param enableCallback optional {@link GLCallback}, if not <code>null</code> will be issued at
* {@link #init(GL2ES2) init(gl)} and {@link #enable(GL2ES2, boolean) enable(gl, true)}.
* @param disableCallback optional {@link GLCallback}, if not <code>null</code> will be issued at
@@ -142,9 +183,9 @@ public class RegionRenderer {
* @return an instance of Region Renderer
* @see #enable(GL2ES2, boolean)
*/
- public static RegionRenderer create(final RenderState rs, final GLCallback enableCallback,
- final GLCallback disableCallback) {
- return new RegionRenderer(rs, enableCallback, disableCallback);
+ public static RegionRenderer create(final PMVMatrix sharedPMVMatrix,
+ final GLCallback enableCallback, final GLCallback disableCallback) {
+ return new RegionRenderer(sharedPMVMatrix, enableCallback, disableCallback);
}
private final RenderState rs;
@@ -152,35 +193,42 @@ public class RegionRenderer {
private final GLCallback enableCallback;
private final GLCallback disableCallback;
- private final int[] viewport = new int[] { 0, 0, 0, 0 };
+ private final Recti viewport = new Recti();
private boolean initialized;
private boolean vboSupported = false;
public final boolean isInitialized() { return initialized; }
- /** Copies the current viewport in given target and returns it for chaining. */
- public final int[/*4*/] getViewport(final int[/*4*/] target) {
- System.arraycopy(viewport, 0, target, 0, 4);
+ /** Copies the current Rect4i viewport in given target and returns it for chaining. */
+ public final Recti getViewport(final Recti target) {
+ target.set(viewport);
return target;
}
- /** Borrows the current viewport w/o copying. */
- public final int[/*4*/] getViewport() {
+ /** Borrows the current Rect4i viewport w/o copying. */
+ public final Recti getViewport() {
return viewport;
}
/** Return width of current viewport */
- public final int getWidth() { return viewport[2]; }
+ public final int getWidth() { return viewport.width(); }
/** Return height of current viewport */
- public final int getHeight() { return viewport[3]; }
+ public final int getHeight() { return viewport.height(); }
+ /** Borrow the current {@link PMVMatrix}. */
public final PMVMatrix getMatrix() { return rs.getMatrix(); }
//////////////////////////////////////
- /**
- * @param rs the used {@link RenderState}
- */
- protected RegionRenderer(final RenderState rs, final GLCallback enableCallback, final GLCallback disableCallback) {
- this.rs = rs;
+ protected RegionRenderer(final GLCallback enableCallback, final GLCallback disableCallback)
+ {
+ this.rs = new RenderState(null);
+ this.enableCallback = enableCallback;
+ this.disableCallback = disableCallback;
+ }
+
+ protected RegionRenderer(final PMVMatrix sharedPMVMatrix,
+ final GLCallback enableCallback, final GLCallback disableCallback)
+ {
+ this.rs = new RenderState(sharedPMVMatrix);
this.enableCallback = enableCallback;
this.disableCallback = disableCallback;
}
@@ -223,6 +271,7 @@ public class RegionRenderer {
initialized = true;
}
+ /** Deletes all {@link ShaderProgram}s and nullifies its references including {@link RenderState#destroy(GL2ES2)}. */
public final void destroy(final GL2ES2 gl) {
if(!initialized){
if(DEBUG_INSTANCE) {
@@ -235,29 +284,51 @@ public class RegionRenderer {
sp.destroy(gl);
}
shaderPrograms.clear();
- rs.destroy(gl);
+ rs.destroy();
initialized = false;
}
+ /** Return the {@link RenderState} composition. */
public final RenderState getRenderState() { return rs; }
/**
* Enabling or disabling the {@link #getRenderState() RenderState}'s
- * {@link RenderState#getShaderProgram() shader program}.
+ * current {@link RenderState#getShaderProgram() shader program}.
+ * <p>
+ * {@link #useShaderProgram(GL2ES2, int, boolean, int, int, TextureSequence)}
+ * generates, selects and caches the desired Curve-Graph {@link ShaderProgram}
+ * and {@link RenderState#setShaderProgram(GL2ES2, ShaderProgram) sets it current} in the {@link RenderState} composition.
+ * </p>
* <p>
- * In case enable and disable {@link GLCallback}s are setup via {@link #create(RenderState, GLCallback, GLCallback)},
+ * In case enable and disable {@link GLCallback}s are setup via {@link #create(Vertex.Factory<? extends Vertex>, RenderState, GLCallback, GLCallback)},
* they will be called before toggling the shader program.
* </p>
- * @see #create(RenderState, GLCallback, GLCallback)
+ * @param gl current GL object
+ * @param enable if true enable the current {@link ShaderProgram}, otherwise disable.
+ * @see #create(Vertex.Factory<? extends Vertex>, RenderState, GLCallback, GLCallback)
+ * @see #useShaderProgram(GL2ES2, int, boolean, int, int, TextureSequence)
+ * @see RenderState#setShaderProgram(GL2ES2, ShaderProgram)
+ * @see RenderState#getShaderProgram()
*/
public final void enable(final GL2ES2 gl, final boolean enable) {
+ enable(gl, enable, enableCallback, disableCallback);
+ }
+
+ /**
+ * Same as {@link #enable(GL2ES2, boolean)} but allowing to force {@link GLCallback}s off.
+ * @param gl current GL object
+ * @param enable if true enable the current {@link ShaderProgram}, otherwise disable.
+ * @param doCallbacks if true (default) perform {@link GLCallback}s, otherwise don't.
+ * @see #enable(GL2ES2, boolean)
+ */
+ public final void enable(final GL2ES2 gl, final boolean enable, final GLCallback enableCB, final GLCallback disableCB) {
if( enable ) {
- if( null != enableCallback ) {
- enableCallback.run(gl, this);
+ if( null != enableCB ) {
+ enableCB.run(gl, this);
}
} else {
- if( null != disableCallback ) {
- disableCallback.run(gl, this);
+ if( null != disableCB ) {
+ disableCB.run(gl, this);
}
}
if( !enable ) {
@@ -271,13 +342,12 @@ public class RegionRenderer {
/**
* No PMVMatrix operation is performed here.
*/
- public final void reshapeNotify(final int width, final int height) {
- viewport[2] = width;
- viewport[3] = height;
+ public final void reshapeNotify(final int x, final int y, final int width, final int height) {
+ viewport.set(x, y, width, height);
}
public final void reshapePerspective(final float angle, final int width, final int height, final float near, final float far) {
- reshapeNotify(width, height);
+ reshapeNotify(0, 0, width, height);
final float ratio = (float)width/(float)height;
final PMVMatrix p = rs.getMatrix();
p.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
@@ -289,7 +359,7 @@ public class RegionRenderer {
* Perspective orthogonal, method calls {@link #reshapeNotify(int, int, int, int)}.
*/
public final void reshapeOrtho(final int width, final int height, final float near, final float far) {
- reshapeNotify(width, height);
+ reshapeNotify(0, 0, width, height);
final PMVMatrix p = rs.getMatrix();
p.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
p.glLoadIdentity();
@@ -303,12 +373,13 @@ public class RegionRenderer {
private static final String SHADER_SRC_SUB = "";
private static final String SHADER_BIN_SUB = "bin";
- private static String GLSL_USE_COLOR_CHANNEL = "#define USE_COLOR_CHANNEL 1\n";
- private static String GLSL_USE_COLOR_TEXTURE = "#define USE_COLOR_TEXTURE 1\n";
- private static String GLSL_DEF_SAMPLE_COUNT = "#define SAMPLE_COUNT ";
- private static String GLSL_CONST_SAMPLE_COUNT = "const float sample_count = ";
- private static String GLSL_MAIN_BEGIN = "void main (void)\n{\n";
+ private static final String GLSL_USE_COLOR_CHANNEL = "#define USE_COLOR_CHANNEL 1\n";
+ private static final String GLSL_USE_COLOR_TEXTURE = "#define USE_COLOR_TEXTURE 1\n";
+ private static final String GLSL_DEF_SAMPLE_COUNT = "#define SAMPLE_COUNT ";
+ private static final String GLSL_CONST_SAMPLE_COUNT = "const float sample_count = ";
+ private static final String GLSL_MAIN_BEGIN = "void main (void)\n{\n";
private static final String gcuTexture2D = "gcuTexture2D";
+ private static final String GLSL_USE_DISCARD = "#define USE_DISCARD 1\n";
private String getVersionedShaderName() {
return "curverenderer01";
@@ -412,6 +483,11 @@ public class RegionRenderer {
private static final int TWO_PASS_BIT = 1 << 31;
/**
+ * Generate, selects and caches the desired Curve-Graph {@link ShaderProgram} according to the given parameters.
+ *
+ * The newly generated or cached {@link ShaderProgram} is {@link RenderState#setShaderProgram(GL2ES2, ShaderProgram) set current} in the {@link RenderState} composition
+ * and can be retrieved via {@link RenderState#getShaderProgram()}.
+ *
* @param gl
* @param renderModes
* @param pass1
@@ -420,19 +496,27 @@ public class RegionRenderer {
* @param colorTexSeq
* @return true if a new shader program is being used and hence external uniform-data and -location,
* as well as the attribute-location must be updated, otherwise false.
+ * @see #enable(GL2ES2, boolean)
+ * @see RenderState#setShaderProgram(GL2ES2, ShaderProgram)
+ * @see RenderState#getShaderProgram()
*/
public final boolean useShaderProgram(final GL2ES2 gl, final int renderModes,
final boolean pass1, final int quality, final int sampleCount, final TextureSequence colorTexSeq) {
+ final ShaderModeSelector1 sel1 = pass1 ? ShaderModeSelector1.selectPass1(renderModes) :
+ ShaderModeSelector1.selectPass2(renderModes, quality, sampleCount);
+ final boolean isTwoPass = Region.isTwoPass( renderModes );
+ final boolean hasColorChannel = Region.hasColorChannel( renderModes );
+ final boolean hasColorTexture = Region.hasColorTexture( renderModes ) && null != colorTexSeq;
+ final boolean isPass1ColorTexSeq = pass1 && hasColorTexture;
final int colorTexSeqHash;
- if( null != colorTexSeq ) {
+ final String texLookupFuncName;
+ if( isPass1ColorTexSeq ) {
+ texLookupFuncName = colorTexSeq.setTextureLookupFunctionName(gcuTexture2D);
colorTexSeqHash = colorTexSeq.getTextureFragmentShaderHashCode();
} else {
+ texLookupFuncName = null;
colorTexSeqHash = 0;
}
- final ShaderModeSelector1 sel1 = pass1 ? ShaderModeSelector1.selectPass1(renderModes) :
- ShaderModeSelector1.selectPass2(renderModes, quality, sampleCount);
- final boolean isTwoPass = Region.isTwoPass( renderModes );
- final boolean isPass1ColorTexSeq = pass1 && null != colorTexSeq;
final int shaderKey = ( (colorTexSeqHash << 5) - colorTexSeqHash ) +
( sel1.ordinal() | ( HIGH_MASK & renderModes ) | ( isTwoPass ? TWO_PASS_BIT : 0 ) );
@@ -445,7 +529,7 @@ public class RegionRenderer {
ShaderProgram sp = (ShaderProgram) shaderPrograms.get( shaderKey );
if( null != sp ) {
final boolean spChanged = getRenderState().setShaderProgram(gl, sp);
- if(DEBUG) {
+ if( DEBUG ) {
if( spChanged ) {
System.err.printf("RegionRendererImpl01.useShaderProgram.X1: GOT renderModes %s, sel1 %s, key 0x%X -> sp %d / %d (changed)%n", Region.getRenderModeString(renderModes), sel1, shaderKey, sp.program(), sp.id());
} else {
@@ -503,11 +587,15 @@ public class RegionRenderer {
// GLSL append from here on
posFp = -1;
- if( Region.hasColorChannel( renderModes ) ) {
+ if( !gl.getContext().hasRendererQuirk(GLRendererQuirks.GLSLBuggyDiscard) ) {
+ posFp = rsFp.insertShaderSource(0, posFp, GLSL_USE_DISCARD);
+ }
+
+ if( hasColorChannel ) {
posVp = rsVp.insertShaderSource(0, posVp, GLSL_USE_COLOR_CHANNEL);
posFp = rsFp.insertShaderSource(0, posFp, GLSL_USE_COLOR_CHANNEL);
}
- if( Region.hasColorTexture( renderModes ) ) {
+ if( isPass1ColorTexSeq ) {
rsVp.insertShaderSource(0, posVp, GLSL_USE_COLOR_TEXTURE);
posFp = rsFp.insertShaderSource(0, posFp, GLSL_USE_COLOR_TEXTURE);
}
@@ -526,13 +614,9 @@ public class RegionRenderer {
throw new RuntimeException("Failed to read: includes");
}
- final String texLookupFuncName;
if( isPass1ColorTexSeq ) {
posFp = rsFp.insertShaderSource(0, posFp, "uniform "+colorTexSeq.getTextureSampler2DType()+" "+UniformNames.gcu_ColorTexUnit+";\n");
- texLookupFuncName = colorTexSeq.getTextureLookupFunctionName(gcuTexture2D);
posFp = rsFp.insertShaderSource(0, posFp, colorTexSeq.getTextureLookupFragmentShaderImpl());
- } else {
- texLookupFuncName = null;
}
posFp = rsFp.insertShaderSource(0, posFp, GLSL_MAIN_BEGIN);
@@ -570,9 +654,10 @@ public class RegionRenderer {
getRenderState().setShaderProgram(gl, sp);
shaderPrograms.put(shaderKey, sp);
- if(DEBUG) {
- System.err.printf("RegionRendererImpl01.useShaderProgram.X1: PUT renderModes %s, sel1 %s, key 0x%X -> sp %d / %d (changed)%n",
+ if( DEBUG ) {
+ System.err.printf("RegionRendererImpl01.useShaderProgram.X1: PUT renderModes %s, sel1 %s, key 0x%X -> sp %d / %d (changed, new)%n",
Region.getRenderModeString(renderModes), sel1, shaderKey, sp.program(), sp.id());
+ // rsFp.dumpShaderSource(System.err);
}
return true;
}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java
index 2b243e6cf..f38383c83 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2011 JogAmp Community. All rights reserved.
+ * Copyright 2011-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -33,17 +33,22 @@ import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GLException;
import com.jogamp.opengl.GLUniformData;
+import com.jogamp.opengl.math.Vec4f;
import jogamp.common.os.PlatformPropsImpl;
import jogamp.graph.curve.opengl.shader.UniformNames;
-import com.jogamp.common.os.Platform;
import com.jogamp.graph.curve.Region;
-import com.jogamp.graph.geom.Vertex;
-import com.jogamp.opengl.util.GLArrayDataServer;
+import com.jogamp.opengl.util.GLArrayDataWrapper;
import com.jogamp.opengl.util.PMVMatrix;
import com.jogamp.opengl.util.glsl.ShaderProgram;
+/**
+ * The RenderState is owned by {@link RegionRenderer}.
+ *
+ * It holds rendering state data like {@link PMVMatrix}, viewport,
+ * but also the current {@link #getColorStatic(float[]) static color}.
+ */
public class RenderState {
private static final String thisKey = "jogamp.graph.curve.RenderState" ;
@@ -82,19 +87,10 @@ public class RenderState {
*/
public static final int BITHINT_GLOBAL_DEPTH_TEST_ENABLED = 1 << 1 ;
- public static RenderState createRenderState(final Vertex.Factory<? extends Vertex> pointFactory) {
- return new RenderState(pointFactory, null);
- }
-
- public static RenderState createRenderState(final Vertex.Factory<? extends Vertex> pointFactory, final PMVMatrix pmvMatrix) {
- return new RenderState(pointFactory, pmvMatrix);
- }
-
public static final RenderState getRenderState(final GL2ES2 gl) {
return (RenderState) gl.getContext().getAttachedObject(thisKey);
}
- private final Vertex.Factory<? extends Vertex> vertexFactory;
private final PMVMatrix pmvMatrix;
private final float[] weight;
private final FloatBuffer weightBuffer;
@@ -110,7 +106,7 @@ public class RenderState {
private static int nextID = 1;
/**
- * Representation of {@link RenderState} data for one {@link ShaderProgram}
+ * Representation of {@link RenderState} data per {@link ShaderProgram}
* as {@link GLUniformData}.
* <p>
* FIXME: Utilize 'ARB_Uniform_Buffer_Object' where available!
@@ -143,7 +139,8 @@ public class RenderState {
*/
public final boolean update(final GL2ES2 gl, final RenderState rs, final boolean updateLocation, final int renderModes, final boolean pass1, final boolean throwOnError) {
if( rs.id() != rsId ) {
- gcu_PMVMatrix01.setData(rs.pmvMatrix.glGetPMvMatrixf());
+ // Assignment of Renderstate buffers to uniforms (no copy, direct reference)
+ gcu_PMVMatrix01.setData(rs.pmvMatrix.getSyncPMvMat());
gcu_Weight.setData(rs.weightBuffer);
gcu_ColorStatic.setData(rs.colorStaticBuffer);
rsId = rs.id();
@@ -186,11 +183,14 @@ public class RenderState {
}
}
- protected RenderState(final Vertex.Factory<? extends Vertex> vertexFactory, final PMVMatrix pmvMatrix) {
+ /**
+ * Create a RenderState, a composition of RegionRenderer
+ * @param sharedPMVMatrix optional shared PMVMatrix, if null using a local instance
+ */
+ /* pp */ RenderState(final PMVMatrix sharedPMVMatrix) {
this.id = getNextID();
this.sp = null;
- this.vertexFactory = vertexFactory;
- this.pmvMatrix = null != pmvMatrix ? pmvMatrix : new PMVMatrix();
+ this.pmvMatrix = null != sharedPMVMatrix ? sharedPMVMatrix : new PMVMatrix();
this.weight = new float[1];
this.weightBuffer = FloatBuffer.wrap(weight);
this.colorStatic = new float[4];
@@ -199,14 +199,20 @@ public class RenderState {
}
public final int id() { return id; }
+
+ /** Return the current {@link ShaderProgram} */
public final ShaderProgram getShaderProgram() { return sp; }
+
+ /** Return whether the current {@link ShaderProgram} is {@link ShaderProgram#inUse() in use}. */
public final boolean isShaderProgramInUse() { return null != sp ? sp.inUse() : false; }
/**
- * Set a {@link ShaderProgram} and enable it. If the given {@link ShaderProgram} is new,
- * method returns true, otherwise false.
+ * Sets the current {@link ShaderProgram} and enables it.
+ *
+ * If the given {@link ShaderProgram} is not {@link #getShaderProgram() the current}, method returns true, otherwise false.
+ *
* @param gl
- * @param spNext
+ * @param spNext the next current {@link ShaderProgram} to be set and enabled
* @return true if a new shader program is being used and hence external uniform-data and -location,
* as well as the attribute-location must be updated, otherwise false.
*/
@@ -223,8 +229,6 @@ public class RenderState {
return true;
}
- public final Vertex.Factory<? extends Vertex> getVertexFactory() { return vertexFactory; }
-
public final PMVMatrix getMatrix() { return pmvMatrix; }
public static boolean isWeightValid(final float v) {
@@ -238,10 +242,14 @@ public class RenderState {
weight[0] = v;
}
-
- public final float[] getColorStatic(final float[] rgbaColor) {
- System.arraycopy(colorStatic, 0, rgbaColor, 0, 4);
- return rgbaColor;
+ public final Vec4f getColorStatic(final Vec4f rgbaColor) {
+ return rgbaColor.set(colorStatic);
+ }
+ public final void setColorStatic(final Vec4f rgbaColor){
+ colorStatic[0] = rgbaColor.x();
+ colorStatic[1] = rgbaColor.y();
+ colorStatic[2] = rgbaColor.z();
+ colorStatic[3] = rgbaColor.w();
}
public final void setColorStatic(final float r, final float g, final float b, final float a){
colorStatic[0] = r;
@@ -263,7 +271,8 @@ public class RenderState {
if( updateLocation || 0 > data.getLocation() ) {
final boolean ok = 0 <= data.setLocation(gl, sp.program());
if( throwOnError && !ok ) {
- throw new GLException("Could not locate "+data);
+ sp.dumpSource(System.err);
+ throw new GLException("Could not locate "+data.getName()+" in "+sp+", "+data);
}
return ok;
} else {
@@ -285,7 +294,8 @@ public class RenderState {
if( updateLocation ) {
updateData = 0 <= data.setLocation(gl, sp.program());
if( throwOnError && !updateData ) {
- throw new GLException("Could not locate "+data);
+ sp.dumpSource(System.err);
+ throw new GLException("Could not locate "+data.getName()+" in "+sp+", "+data);
}
}
if( updateData ){
@@ -302,11 +312,12 @@ public class RenderState {
* @param throwOnError TODO
* @return true if no error occured, i.e. all locations found, otherwise false.
*/
- public final boolean updateAttributeLoc(final GL2ES2 gl, final boolean updateLocation, final GLArrayDataServer data, final boolean throwOnError) {
+ public final boolean updateAttributeLoc(final GL2ES2 gl, final boolean updateLocation, final GLArrayDataWrapper data, final boolean throwOnError) {
if( updateLocation || 0 > data.getLocation() ) {
final boolean ok = 0 <= data.setLocation(gl, sp.program());
if( throwOnError && !ok ) {
- throw new GLException("Could not locate "+data);
+ sp.dumpSource(System.err);
+ throw new GLException("Could not locate "+data.getName()+" in "+sp+", "+data);
}
return ok;
} else {
@@ -325,11 +336,11 @@ public class RenderState {
hintBitfield &= ~mask;
}
- public void destroy(final GL2ES2 gl) {
- if( null != sp ) {
- sp.destroy(gl);
- sp = null;
- }
+ /**
+ * Only nullifies {@link ShaderProgram} reference owned by {@link RegionRenderer}.
+ */
+ /* pp */ void destroy() {
+ sp = null; // owned by RegionRenderer
}
public final RenderState attachTo(final GL2ES2 gl) {
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java
index 8d55c6136..428bb350d 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java
@@ -33,10 +33,12 @@ import java.util.Iterator;
import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GLException;
+import com.jogamp.opengl.math.Vec4f;
import com.jogamp.opengl.math.geom.AABBox;
import com.jogamp.graph.curve.OutlineShape;
import com.jogamp.graph.curve.Region;
import com.jogamp.graph.font.Font;
+import com.jogamp.graph.font.Font.Glyph;
import com.jogamp.graph.geom.plane.AffineTransform;
/**
@@ -73,6 +75,9 @@ public class TextRegionUtil {
* <p>
* Origin of rendered text is 0/0 at bottom left.
* </p>
+ * <p>
+ * The region buffer's size is grown by pre-calculating required size via {@link #countStringRegion(Font, CharSequence, int[])}.
+ * </p>
* @param region the {@link GLRegion} sink
* @param font the target {@link Font}
* @param transform optional given transform
@@ -81,8 +86,8 @@ public class TextRegionUtil {
* @return the bounding box of the given string by taking each glyph's font em-sized [0..1] OutlineShape into account.
*/
public static AABBox addStringToRegion(final Region region, final Font font, final AffineTransform transform,
- final CharSequence str, final float[] rgbaColor) {
- return addStringToRegion(region, font, transform, str, rgbaColor, new AffineTransform(), new AffineTransform());
+ final CharSequence str, final Vec4f rgbaColor) {
+ return addStringToRegion(true /* preGrowRegion */, region, font, transform, str, rgbaColor, new AffineTransform(), new AffineTransform());
}
/**
@@ -94,6 +99,9 @@ public class TextRegionUtil {
* <p>
* Origin of rendered text is 0/0 at bottom left.
* </p>
+ * <p>
+ * The region buffer's size is grown by pre-calculating required size via {@link #countStringRegion(Font, CharSequence, int[])}.
+ * </p>
* @param region the {@link GLRegion} sink
* @param font the target {@link Font}
* @param transform optional given transform
@@ -104,13 +112,49 @@ public class TextRegionUtil {
* @return the bounding box of the given string by taking each glyph's font em-sized [0..1] OutlineShape into account.
*/
public static AABBox addStringToRegion(final Region region, final Font font, final AffineTransform transform,
- final CharSequence str, final float[] rgbaColor,
+ final CharSequence str, final Vec4f rgbaColor,
final AffineTransform temp1, final AffineTransform temp2) {
- final OutlineShape.Visitor visitor = new OutlineShape.Visitor() {
+ return addStringToRegion(true /* preGrowRegion */, region, font, transform, str, rgbaColor, temp1, temp2);
+ }
+
+ /**
+ * Add the string in 3D space w.r.t. the font in font em-size [0..1] at the end of the {@link GLRegion}
+ * while passing the progressed {@link AffineTransform}.
+ * <p>
+ * The shapes added to the GLRegion are in font em-size [0..1], but can be adjusted with the given transform, progressed and passed to the visitor.
+ * </p>
+ * <p>
+ * Origin of rendered text is 0/0 at bottom left.
+ * </p>
+ * <p>
+ * Depending on `preGrowRegion`, the region buffer's size is grown by pre-calculating required size via {@link #countStringRegion(Font, CharSequence, int[])}.
+ * </p>
+ * @param preGrowRegion if true, utilizes {@link #countStringRegion(Font, CharSequence, int[])} to pre-calc required buffer size, otherwise not.
+ * @param region the {@link GLRegion} sink
+ * @param font the target {@link Font}
+ * @param transform optional given transform
+ * @param str string text
+ * @param rgbaColor if {@link Region#hasColorChannel()} RGBA color must be passed, otherwise value is ignored.
+ * @param temp1 temporary AffineTransform storage, mandatory
+ * @param temp2 temporary AffineTransform storage, mandatory
+ * @return the bounding box of the given string by taking each glyph's font em-sized [0..1] OutlineShape into account.
+ */
+ public static AABBox addStringToRegion(final boolean preGrowRegion, final Region region, final Font font, final AffineTransform transform,
+ final CharSequence str, final Vec4f rgbaColor,
+ final AffineTransform temp1, final AffineTransform temp2) {
+ final Font.GlyphVisitor visitor = new Font.GlyphVisitor() {
@Override
- public final void visit(final OutlineShape shape, final AffineTransform t) {
- region.addOutlineShape(shape, t, region.hasColorChannel() ? rgbaColor : null);
- } };
+ public void visit(final char symbol, final Glyph glyph, final AffineTransform t) {
+ if( glyph.isWhiteSpace() ) {
+ return;
+ }
+ region.addOutlineShape(glyph.getShape(), t, rgbaColor);
+ }
+ };
+ if( preGrowRegion ) {
+ final int[] vertIndCount = countStringRegion(font, str, new int[2]);
+ region.growBuffer(vertIndCount[0], vertIndCount[1]);
+ }
return font.processString(visitor, transform, str, temp1, temp2);
}
@@ -119,20 +163,22 @@ public class TextRegionUtil {
* <p>
* The region's buffer can be either set using {@link Region#setBufferCapacity(int, int)} or grown using {@link Region#growBuffer(int, int)}.
* </p>
- * @param region the {@link GLRegion} sink
* @param font the target {@link Font}
* @param str string text
* @param vertIndexCount the int[2] storage where the counted vertices and indices are added, vertices at [0] and indices at [1]
+ * @return the given int[2] storage for chaining
* @see Region#setBufferCapacity(int, int)
* @see Region#growBuffer(int, int)
+ * @see #drawString3D(GL2ES2, GLRegion, RegionRenderer, Font, CharSequence, float[], int[], AffineTransform, AffineTransform)
*/
- public static void countStringRegion(final Region region, final Font font, final CharSequence str, final int[/*2*/] vertIndexCount) {
- final OutlineShape.Visitor2 visitor = new OutlineShape.Visitor2() {
+ public static int[] countStringRegion(final Font font, final CharSequence str, final int[/*2*/] vertIndexCount) {
+ final Font.GlyphVisitor2 visitor = new Font.GlyphVisitor2() {
@Override
- public final void visit(final OutlineShape shape) {
- region.countOutlineShape(shape, vertIndexCount);
+ public final void visit(final char symbol, final Font.Glyph glyph) {
+ Region.countOutlineShape(glyph.getShape(), vertIndexCount);
} };
font.processString(visitor, str);
+ return vertIndexCount;
}
/**
@@ -146,6 +192,9 @@ public class TextRegionUtil {
* <p>
* Cached {@link GLRegion}s will be destroyed w/ {@link #clear(GL2ES2)} or to free memory.
* </p>
+ * <p>
+ * The region's buffer size is pre-calculated via {@link GLRegion#create(com.jogamp.opengl.GLProfile, int, com.jogamp.opengl.util.texture.TextureSequence, Font, CharSequence)}
+ * </p>
* @param gl the current GL state
* @param renderer TODO
* @param font {@link Font} to be used
@@ -158,15 +207,15 @@ public class TextRegionUtil {
*/
public AABBox drawString3D(final GL2ES2 gl,
final RegionRenderer renderer, final Font font, final CharSequence str,
- final float[] rgbaColor, final int[/*1*/] sampleCount) {
+ final Vec4f rgbaColor, final int[/*1*/] sampleCount) {
if( !renderer.isInitialized() ) {
throw new GLException("TextRendererImpl01: not initialized!");
}
GLRegion region = getCachedRegion(font, str);
AABBox res;
if(null == region) {
- region = GLRegion.create(gl.getGLProfile(), renderModes, null);
- res = addStringToRegion(region, font, null, str, rgbaColor, tempT1, tempT2);
+ region = GLRegion.create(gl.getGLProfile(), renderModes, null, font, str);
+ res = addStringToRegion(false /* preGrowRegion */, region, font, null, str, rgbaColor, tempT1, tempT2);
addCachedRegion(gl, font, str, region);
} else {
res = new AABBox();
@@ -178,10 +227,13 @@ public class TextRegionUtil {
/**
* Try using {@link #drawString3D(GL2ES2, int, RegionRenderer, Font, CharSequence, float[], int[], AffineTransform, AffineTransform)} to reuse {@link AffineTransform} instances.
+ * <p>
+ * The region's buffer size is pre-calculated via {@link GLRegion#create(com.jogamp.opengl.GLProfile, int, com.jogamp.opengl.util.texture.TextureSequence, Font, CharSequence)}
+ * </p>
*/
public static AABBox drawString3D(final GL2ES2 gl, final int renderModes,
final RegionRenderer renderer, final Font font, final CharSequence str,
- final float[] rgbaColor, final int[/*1*/] sampleCount) {
+ final Vec4f rgbaColor, final int[/*1*/] sampleCount) {
return drawString3D(gl, renderModes, renderer, font, str, rgbaColor, sampleCount, new AffineTransform(), new AffineTransform());
}
@@ -194,6 +246,9 @@ public class TextRegionUtil {
* Origin of rendered text is 0/0 at bottom left.
* </p>
* <p>
+ * The region's buffer size is pre-calculated via {@link GLRegion#create(com.jogamp.opengl.GLProfile, int, com.jogamp.opengl.util.texture.TextureSequence, Font, CharSequence)}
+ * </p>
+ * <p>
* In case of a multisampling region renderer, i.e. {@link Region#VBAA_RENDERING_BIT}, recreating the {@link GLRegion}
* is a huge performance impact.
* In such case better use {@link #drawString3D(GL2ES2, GLRegion, RegionRenderer, Font, CharSequence, float[], int[], AffineTransform, AffineTransform)}
@@ -213,12 +268,12 @@ public class TextRegionUtil {
*/
public static AABBox drawString3D(final GL2ES2 gl, final int renderModes,
final RegionRenderer renderer, final Font font, final CharSequence str,
- final float[] rgbaColor, final int[/*1*/] sampleCount, final AffineTransform tmp1, final AffineTransform tmp2) {
+ final Vec4f rgbaColor, final int[/*1*/] sampleCount, final AffineTransform tmp1, final AffineTransform tmp2) {
if(!renderer.isInitialized()){
throw new GLException("TextRendererImpl01: not initialized!");
}
- final GLRegion region = GLRegion.create(gl.getGLProfile(), renderModes, null);
- final AABBox res = addStringToRegion(region, font, null, str, rgbaColor, tmp1, tmp2);
+ final GLRegion region = GLRegion.create(gl.getGLProfile(), renderModes, null, font, str);
+ final AABBox res = addStringToRegion(false /* preGrowRegion */, region, font, null, str, rgbaColor, tmp1, tmp2);
region.draw(gl, renderer, sampleCount);
region.destroy(gl);
return res;
@@ -226,9 +281,12 @@ public class TextRegionUtil {
/**
* Try using {@link #drawString3D(GL2ES2, GLRegion, RegionRenderer, Font, CharSequence, float[], int[], AffineTransform, AffineTransform)} to reuse {@link AffineTransform} instances.
+ * <p>
+ * The region buffer's size is grown by pre-calculating required size via {@link #countStringRegion(Font, CharSequence, int[])}.
+ * </p>
*/
public static AABBox drawString3D(final GL2ES2 gl, final GLRegion region, final RegionRenderer renderer,
- final Font font, final CharSequence str, final float[] rgbaColor, final int[/*1*/] sampleCount) {
+ final Font font, final CharSequence str, final Vec4f rgbaColor, final int[/*1*/] sampleCount) {
return drawString3D(gl, region, renderer, font, str, rgbaColor, sampleCount, new AffineTransform(), new AffineTransform());
}
@@ -243,6 +301,9 @@ public class TextRegionUtil {
* <p>
* Origin of rendered text is 0/0 at bottom left.
* </p>
+ * <p>
+ * The region buffer's size is grown by pre-calculating required size via {@link #countStringRegion(Font, CharSequence, int[])}.
+ * </p>
* @param gl the current GL state
* @param region
* @param renderer
@@ -257,12 +318,12 @@ public class TextRegionUtil {
* @throws Exception if TextRenderer not initialized
*/
public static AABBox drawString3D(final GL2ES2 gl, final GLRegion region, final RegionRenderer renderer,
- final Font font, final CharSequence str, final float[] rgbaColor,
+ final Font font, final CharSequence str, final Vec4f rgbaColor,
final int[/*1*/] sampleCount, final AffineTransform tmp1, final AffineTransform tmp2) {
if(!renderer.isInitialized()){
throw new GLException("TextRendererImpl01: not initialized!");
}
- final AABBox res = addStringToRegion(region, font, null, str, rgbaColor, tmp1, tmp2);
+ final AABBox res = addStringToRegion(true /* preGrowRegion */, region, font, null, str, rgbaColor, tmp1, tmp2);
region.draw(gl, renderer, sampleCount);
return res;
}
diff --git a/src/jogl/classes/com/jogamp/graph/font/Font.java b/src/jogl/classes/com/jogamp/graph/font/Font.java
index 1b5452a45..314040adf 100644
--- a/src/jogl/classes/com/jogamp/graph/font/Font.java
+++ b/src/jogl/classes/com/jogamp/graph/font/Font.java
@@ -145,13 +145,13 @@ public interface Font {
* @param dest AABBox instance set to this metrics boundary in font-units
* @return the given and set AABBox 'dest' in font units
*/
- AABBox getBBoxFU(final AABBox dest);
+ AABBox getBoundsFU(final AABBox dest);
/**
* @param dest AABBox instance set to this metrics boundary in font em-size [0..1]
* @return the given and set AABBox 'dest' in font units
*/
- AABBox getBBox(final AABBox dest, final float[] tmpV3);
+ AABBox getBounds(final AABBox dest);
}
/**
@@ -166,36 +166,44 @@ public interface Font {
// http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#ba57949e
public static final int ID_UNKNOWN = 0;
+ /** Return the {@link Font} owning this {@link Glyph}. */
+ Font getFont();
+
/** Return this glyph's ID */
int getID();
/** Return the glyph's name, source from `post` table */
String getName();
+ /** Return true if the underlying {@link #getShape()} is a whitespace, otherwise false. */
+ boolean isWhiteSpace();
+
+ /** Return true if the Glyph denotes an undefined {@link #getID()} symbol, i.e. {@link #getName()} == `.notdef`. */
+ boolean isUndefined();
+
/**
* Return the AABBox in font-units, borrowing internal instance.
*/
- AABBox getBBoxFU();
+ AABBox getBoundsFU();
/**
* Return the AABBox in font-units, copying into given dest.
* @param dest AABBox instance set to this metrics boundary in font-units
* @return the given and set AABBox 'dest' in font-units
*/
- AABBox getBBoxFU(final AABBox dest);
+ AABBox getBoundsFU(final AABBox dest);
/**
* Return the AABBox in font em-size [0..1], copying into given dest.
* @param dest AABBox instance set to this metrics boundary in font em-size [0..1]
- * @param tmpV3 caller provided temporary 3-component vector
* @return the given and set AABBox 'dest' in font em-size [0..1]
*/
- AABBox getBBox(final AABBox dest, float[] tmpV3);
+ AABBox getBounds(final AABBox dest);
/**
* Return the AABBox in font em-size [0..1], creating a new copy.
*/
- AABBox getBBox();
+ AABBox getBounds();
/** Return advance in font units, sourced from `hmtx` table. */
int getAdvanceFU();
@@ -246,6 +254,32 @@ public interface Font {
String fullString();
}
+ /**
+ * General purpose {@link Font.Glyph} visitor.
+ */
+ public static interface GlyphVisitor {
+ /**
+ * Visiting the given {@link Font.Glyph} having an {@link OutlineShape} with it's corresponding {@link AffineTransform}.
+ * @param symbol the character symbol matching the given glyph
+ * @param glyph {@link Font.Glyph} which contains an {@link OutlineShape} via {@link Font.Glyph#getShape()}.
+ * @param t may be used immediately as is, otherwise a copy shall be made if stored.
+ */
+ public void visit(final char symbol, final Glyph glyph, final AffineTransform t);
+ }
+
+ /**
+ * Constrained {@link Font.Glyph} visitor w/o {@link AffineTransform}.
+ */
+ public static interface GlyphVisitor2 {
+ /**
+ * Visiting the given {@link Font.Glyph} having an {@link OutlineShape}.
+ * @param symbol the character symbol matching the given glyph
+ * @param glyph {@link Font.Glyph} which contains an {@link OutlineShape} via {@link Font.Glyph#getShape()}.
+ */
+ public void visit(final char symbol, final Glyph glyph);
+ }
+
+
String getName(final int nameIndex);
/** Shall return the family and subfamily name, separated a dash.
@@ -287,8 +321,13 @@ public interface Font {
Metrics getMetrics();
+ /** Return the {@link Glyph} ID mapped to given `symbol`, usually UTF16 unicode. Returned ID can be used to retrieve the {@link Glyph} via {@link #getGlyph(int)}. */
int getGlyphID(final char symbol);
+ /** Return number of {@link Glyph} IDs available, i.e. retrievable via {@link #getGlyph(int)} [0..count). */
+ int getGlyphCount();
+
+ /** Return the {@link Glyph} using given ID, see {@link #getGlyphCount()}. */
Glyph getGlyph(final int glyph_id);
int getNumGlyphs();
@@ -312,7 +351,20 @@ public interface Font {
int getLineHeightFU();
/**
- * Return line height in font em-size [0..1]
+ * Return line height, baseline-to-baseline in em-size [0..1], composed from `hhea' table entries.
+ * <pre>
+ * return ascent - descent + linegap;
+ * </pre>
+ * or
+ * <pre>
+ * // lineGap positive value
+ * // descent negative value
+ * // ascent positive value
+ * return ascent - descent + linegap;
+ * </pre>
+ * @see Metrics#getAscent()
+ * @see Metrics#getDescent()
+ * @see Metrics#getLineGap()
*/
float getLineHeight();
@@ -406,50 +458,55 @@ public interface Font {
* <p>
* This method is only exposed to validate the produced {@link OutlineShape} against {@link #getGlyphBounds(CharSequence)}.
* </p>
+ * @param transform optional given transform
* @param string string text
+ * @param tmp1 temp {@link AffineTransform} to be reused
+ * @param tmp2 temp {@link AffineTransform} to be reused
* @return the bounding box of the given string in font-units [0..1]
- * @see #getGlyphShapeBounds(AffineTransform, CharSequence)
+ * @see #getGlyphShapeBounds(CharSequence)
* @see #getGlyphBounds(CharSequence)
* @see #getMetricBounds(CharSequence)
*/
- AABBox getGlyphShapeBounds(final CharSequence string);
+ AABBox getGlyphShapeBounds(final AffineTransform transform, final CharSequence string, final AffineTransform tmp1, final AffineTransform tmp2);
boolean isPrintableChar(final char c);
/**
- * Try using {@link #processString(com.jogamp.graph.curve.OutlineShape.Visitor, AffineTransform, CharSequence, AffineTransform, AffineTransform)}
+ * Try using {@link #processString(GlyphVisitor, AffineTransform, CharSequence, AffineTransform, AffineTransform)}
* to reuse {@link AffineTransform} instances.
+ * @see #processString(GlyphVisitor, AffineTransform, CharSequence, AffineTransform, AffineTransform)
*/
- AABBox processString(final OutlineShape.Visitor visitor, final AffineTransform transform,
+ AABBox processString(final Font.GlyphVisitor visitor, final AffineTransform transform,
final CharSequence string);
/**
- * Visit each {@link Glyph}'s {@link OutlineShape} of the string with the {@link OutlineShape.Visitor}
+ * Visit each {@link Glyph} and perhaps its {@link OutlineShape} of the string with the {@link Font.GlyphVisitor}
* while passing the progressed {@link AffineTransform}.
* <p>
* The processed shapes are in font em-size [0..1], but can be adjusted with the given transform, progressed and passed to the visitor.
* </p>
- * @param visitor handling each glyph's outline shape in font em-size [0..1] and the given {@link AffineTransform}
- * @param transform optional given transform
+ * @param visitor handling each {@link Font.Glyph} and perhaps its {@link OutlineShape} in font em-size [0..1] and the given {@link AffineTransform}
+ * @param transform optional given transform for size and position
* @param font the target {@link Font}
* @param string string text
* @param temp1 temporary AffineTransform storage, mandatory
* @param temp2 temporary AffineTransform storage, mandatory
* @return the bounding box of the given string by taking each glyph's font em-sized [0..1] {@link OutlineShape} into account.
+ * @see #processString(GlyphVisitor, AffineTransform, CharSequence)
*/
- AABBox processString(final OutlineShape.Visitor visitor, final AffineTransform transform,
+ AABBox processString(final Font.GlyphVisitor visitor, final AffineTransform transform,
final CharSequence string,
final AffineTransform temp1, final AffineTransform temp2);
/**
- * Visit each {@link Glyph}'s {@link OutlineShape} of the string with the constrained {@link OutlineShape.Visitor2}.
+ * Visit each {@link Glyph} and perhaps its {@link OutlineShape} of the string with the constrained {@link Font.GlyphVisitor2}.
* <p>
* The processed shapes are in font em-size [0..1].
* </p>
- * @param visitor handling each glyph's outline shape in font em-size [0..1]
+ * @param visitor handling each {@link Font.Glyph} and perhaps its {@link OutlineShape} in font em-size [0..1]
* @param string string text
*/
- void processString(final OutlineShape.Visitor2 visitor, final CharSequence string);
+ void processString(final Font.GlyphVisitor2 visitor, final CharSequence string);
/** Returns {@link #getFullFamilyName()} */
@Override
diff --git a/src/jogl/classes/com/jogamp/graph/font/FontFactory.java b/src/jogl/classes/com/jogamp/graph/font/FontFactory.java
index ac42274f6..9b9762a05 100644
--- a/src/jogl/classes/com/jogamp/graph/font/FontFactory.java
+++ b/src/jogl/classes/com/jogamp/graph/font/FontFactory.java
@@ -147,7 +147,7 @@ public class FontFactory {
InputStream bis = null;
try {
tempFile[0] = IOUtil.createTempFile( "jogl.font", ".ttf", false);
- streamLen[0] = IOUtil.copyStream2File(stream, tempFile[0], -1);
+ streamLen[0] = IOUtil.copyStream2File(stream, tempFile[0]);
if( 0 == streamLen[0] ) {
throw new IOException("Font stream has zero bytes");
}
diff --git a/src/jogl/classes/com/jogamp/graph/font/FontScale.java b/src/jogl/classes/com/jogamp/graph/font/FontScale.java
index a0f2ef4e0..da8df807f 100644
--- a/src/jogl/classes/com/jogamp/graph/font/FontScale.java
+++ b/src/jogl/classes/com/jogamp/graph/font/FontScale.java
@@ -1,48 +1,100 @@
+/**
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
package com.jogamp.graph.font;
/**
- * Simple static font scale methods for unit conversion.
+ * Simple static font scale methods for unit conversions.
+ *
+ * PostScript - current DTP point system used e.g in CSS (Cascading Style Sheets).
+ * - 1 point = 1pt = 1/72in (cala) = 0.3528 mm
+ * - 1 pica = 1pc = 12pt= 1/6in (cala) = 4.233(3) mm
*/
public class FontScale {
/**
- * Converts typical font size in points (per-inch) and screen resolution in dpi to font size in pixels (per-inch),
- * which can be used for pixel-size font scaling operations.
- * <p>
- * Note that 1em == size of the selected font.<br/>
- * In case the pixel per em size is required (advance etc),
- * the resulting pixel-size (per-inch) of this method shall be used if rendering directly into the screen resolution!
- * </p>
+ * Converts the the given points size to inch, dividing by {@code 72} points per inch.
+ * <pre>
+ 1 points = 1/72 inch
+ *
+ * </pre>
+ */
+ public static float ptToInch(final float points) {
+ return points / 72f /* points per inch */;
+ }
+
+ /**
+ * Converts the the given points size to mm, dividing by {@code 72 * 25.4} points per inch.
* <pre>
- Font Scale Formula:
1 inch = 25.4 mm
+ 1 points = 1/72 inch
+ 1 points = 1/72 * 25.4 mm
+ *
+ * </pre>
+ */
+ public static float ptToMM(final float points) {
+ return points / 72f /* points per inch */ * 25.4f /* mm_per_inch */;
+ }
- 1 inch = 72 points
- pointSize: [point] = [1/72 inch]
+ /**
+ * Converts typical font size in points and screen resolution in dpi (pixels-per-inch) to font size in pixels,
+ * which can be used for pixel-size font scaling operations.
+ * <pre>
+ Font Scale Formula:
+ 1 points = 1/72 inch
- [1] Scale := pointSize * resolution / ( 72 points per inch * units_per_em )
- [2] PixelSize := pointSize * resolution / ( 72 points per inch )
- [3] Scale := PixelSize / units_per_em
+ pixels = points / 72 * res_dpi
* </pre>
- * @param font_sz_pt in points (per-inch)
- * @param res_dpi display resolution in dots-per-inch
- * @return pixel-per-inch, pixelSize scale factor for font operations.
+ * @param points in points
+ * @param res_dpi display resolution in pixels-per-inch
+ * @return pixelSize scale factor for font operations.
* @see #toPixels2(float, float)
*/
- public static float toPixels(final float font_sz_pt /* points per inch */, final float res_dpi /* dots per inch */) {
- return ( font_sz_pt / 72f /* points per inch */ ) * res_dpi;
+ public static float toPixels(final float points /* points */, final float res_dpi /* pixels per inch */) {
+ return ptToInch( points ) * res_dpi;
}
/**
- * Converts typical font size in points-per-inch and screen resolution in points-per-mm to font size in pixels (per-inch),
+ * Converts typical font size in points and screen resolution in pixels (pixels-per-mm) to font size in pixels,
* which can be used for pixel-size font scaling operations.
- *
- * @param font_sz_pt in points (per-inch)
- * @param res_ppmm display resolution in dots-per-mm
- * @return pixel-per-inch, pixelSize scale factor for font operations.
+ * <pre>
+ Font Scale Formula:
+ 1 inch = 25.4 mm
+ 1 points = 1/72 inch
+ 1 points = 1/72 * 25.4 mm
+
+ pixels = points / 72 * 25.4 * res_ppmm
+ * </pre>
+ * @param points in points
+ * @param res_ppmm display resolution in pixels-per-mm
+ * @return pixelSize scale factor for font operations.
* @see #toPixels(float, float)
*/
- public static float toPixels2(final float font_sz_pt /* points per inch */, final float res_ppmm /* pixels per mm */) {
- return ( font_sz_pt / 72f /* points per inch */ ) * ( res_ppmm * 25.4f /* mm per inch */ ) ;
+ public static float toPixels2(final float points /* points */, final float res_ppmm /* pixels per mm */) {
+ return ptToMM( points ) * res_ppmm;
}
/**
@@ -50,7 +102,7 @@ public class FontScale {
* @param ppmm float[2] [1/mm] value
* @return return [1/inch] value
*/
- public static float[/*2*/] perMMToPerInch(final float[/*2*/] ppmm) {
+ public static float[/*2*/] ppmmToPPI(final float[/*2*/] ppmm) {
ppmm[0] *= 25.4f;
ppmm[1] *= 25.4f;
return ppmm;
@@ -67,4 +119,27 @@ public class FontScale {
res[1] = ppmm[1] * 25.4f;
return res;
}
+
+ /**
+ * Converts [1/inch] to [1/mm] in place
+ * @param ppi float[2] [1/inch] value
+ * @return return [1/mm] value
+ */
+ public static float[/*2*/] ppiToPPMM(final float[/*2*/] ppi) {
+ ppi[0] /= 25.4f;
+ ppi[1] /= 25.4f;
+ return ppi;
+ }
+
+ /**
+ * Converts [1/inch] to [1/mm] into res storage
+ * @param ppi float[2] [1/inch] value
+ * @param res the float[2] result storage
+ * @return return [1/mm] value, i.e. the given res storage
+ */
+ public static float[/*2*/] ppiToPPMM(final float[/*2*/] ppi, final float[/*2*/] res) {
+ res[0] = ppi[0] / 25.4f;
+ res[1] = ppi[1] / 25.4f;
+ return res;
+ }
}
diff --git a/src/jogl/classes/com/jogamp/graph/geom/Outline.java b/src/jogl/classes/com/jogamp/graph/geom/Outline.java
index bd25aeccc..a0999baa1 100644
--- a/src/jogl/classes/com/jogamp/graph/geom/Outline.java
+++ b/src/jogl/classes/com/jogamp/graph/geom/Outline.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -268,7 +268,7 @@ public class Outline implements Comparable<Outline> {
if( !isEmpty() ) {
final Vertex first = vertices.get(0);
final Vertex last = getLastVertex();
- if( !VectorUtil.isVec3Equal( first.getCoord(), 0, last.getCoord(), 0, FloatUtil.EPSILON ) ) {
+ if( !first.getCoord().isEqual( last.getCoord() ) ) {
if( closeTail ) {
vertices.add(first.clone());
} else {
@@ -283,12 +283,12 @@ public class Outline implements Comparable<Outline> {
/**
* Return a transformed instance with all vertices are copied and transformed.
*/
- public final Outline transform(final AffineTransform t, final Vertex.Factory<? extends Vertex> vertexFactory) {
+ public final Outline transform(final AffineTransform t) {
final Outline newOutline = new Outline();
final int vsize = vertices.size();
for(int i=0; i<vsize; i++) {
final Vertex v = vertices.get(i);
- newOutline.addVertex(t.transform(v, vertexFactory.create()));
+ newOutline.addVertex(t.transform(v, new Vertex()));
}
newOutline.closed = this.closed;
return newOutline;
diff --git a/src/jogl/classes/com/jogamp/graph/geom/SVertex.java b/src/jogl/classes/com/jogamp/graph/geom/SVertex.java
deleted file mode 100644
index dc6982025..000000000
--- a/src/jogl/classes/com/jogamp/graph/geom/SVertex.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/**
- * Copyright 2010 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
-package com.jogamp.graph.geom;
-
-import com.jogamp.opengl.math.FloatUtil;
-import com.jogamp.opengl.math.VectorUtil;
-
-/** A Simple Vertex Implementation. Where the coordinates, and other attributes are
- * float based, and the coordinates and texture coordinates are saved in two float arrays.
- *
- */
-public class SVertex implements Vertex {
- private int id;
- protected boolean onCurve;
- protected final float[] coord = new float[3];
- private final float[] texCoord = new float[3];
-
- static final Factory factory = new Factory();
-
- public static Factory factory() { return factory; }
-
- public static class Factory implements Vertex.Factory<SVertex> {
- @Override
- public SVertex create() {
- return new SVertex();
- }
-
- public SVertex create(final Vertex src) {
- return new SVertex(src);
- }
-
- @Override
- public SVertex create(final int id, final boolean onCurve, final float[] texCoordsBuffer) {
- return new SVertex(id, onCurve, texCoordsBuffer);
- }
-
- @Override
- public SVertex create(final float x, final float y, final float z, final boolean onCurve) {
- return new SVertex(x, y, z, onCurve);
- }
-
- @Override
- public SVertex create(final float[] coordsBuffer, final int offset, final int length, final boolean onCurve) {
- return new SVertex(coordsBuffer, offset, length, onCurve);
- }
- }
-
- public SVertex() {
- this.id = Integer.MAX_VALUE;
- }
-
- public SVertex(final Vertex src) {
- this.id = Integer.MAX_VALUE;
- System.arraycopy(src.getCoord(), 0, coord, 0, 3);
- System.arraycopy(src.getTexCoord(), 0, texCoord, 0, 3);
- setOnCurve(src.isOnCurve());
- }
-
- public SVertex(final int id, final boolean onCurve, final float[] texCoordsBuffer) {
- this.id = id;
- this.onCurve = onCurve;
- System.arraycopy(texCoordsBuffer, 0, texCoord, 0, 3);
- }
-
- public SVertex(final float x, final float y, final float z, final boolean onCurve) {
- this.id = Integer.MAX_VALUE;
- setCoord(x, y, z);
- setOnCurve(onCurve);
- }
-
- public SVertex(final float[] coordsBuffer, final int offset, final int length, final boolean onCurve) {
- this.id = Integer.MAX_VALUE;
- setCoord(coordsBuffer, offset, length);
- setOnCurve(onCurve);
- }
-
- @Override
- public final void setCoord(final float x, final float y, final float z) {
- coord[0] = x;
- coord[1] = y;
- coord[2] = z;
- }
-
- @Override
- public final void setCoord(final float[] coordsBuffer, final int offset, final int length) {
- System.arraycopy(coordsBuffer, offset, coord, 0, length);
- }
-
- @Override
- public int getCoordCount() {
- return 3;
- }
-
- @Override
- public final float[] getCoord() {
- return coord;
- }
-
- @Override
- public final void setX(final float x) {
- this.coord[0] = x;
- }
-
- @Override
- public final void setY(final float y) {
- this.coord[1] = y;
- }
-
- @Override
- public final void setZ(final float z) {
- this.coord[2] = z;
- }
-
- @Override
- public final float getX() {
- return this.coord[0];
- }
-
- @Override
- public final float getY() {
- return this.coord[1];
- }
-
- @Override
- public final float getZ() {
- return this.coord[2];
- }
-
- @Override
- public final boolean isOnCurve() {
- return onCurve;
- }
-
- @Override
- public final void setOnCurve(final boolean onCurve) {
- this.onCurve = onCurve;
- }
-
- @Override
- public final int getId(){
- return id;
- }
-
- @Override
- public final void setId(final int id){
- this.id = id;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if( obj == this) {
- return true;
- }
- if( null == obj || !(obj instanceof Vertex) ) {
- return false;
- }
- final Vertex v = (Vertex) obj;
- return this == v ||
- isOnCurve() == v.isOnCurve() &&
- VectorUtil.isVec3Equal(getTexCoord(), 0, v.getTexCoord(), 0, FloatUtil.EPSILON) &&
- VectorUtil.isVec3Equal(getCoord(), 0, v.getCoord(), 0, FloatUtil.EPSILON) ;
- }
- @Override
- public final int hashCode() {
- throw new InternalError("hashCode not designed");
- }
-
- @Override
- public final float[] getTexCoord() {
- return texCoord;
- }
-
- @Override
- public final void setTexCoord(final float s, final float t, final float p) {
- texCoord[0] = s;
- texCoord[1] = t;
- texCoord[2] = p;
- }
-
- @Override
- public final void setTexCoord(final float[] texCoordsBuffer, final int offset, final int length) {
- System.arraycopy(texCoordsBuffer, offset, texCoord, 0, length);
- }
-
- /**
- * @return deep clone of this Vertex elements
- */
- @Override
- public SVertex clone(){
- return new SVertex(this); // OK to not call super.clone(), using own copy-ctor
- }
-
- @Override
- public String toString() {
- return "[ID: " + id + ", onCurve: " + onCurve +
- ": p " + coord[0] + ", " + coord[1] + ", " + coord[2] +
- ", t " + texCoord[0] + ", " + texCoord[1] + ", " + texCoord[2] + "]";
- }
-}
diff --git a/src/jogl/classes/com/jogamp/graph/geom/Triangle.java b/src/jogl/classes/com/jogamp/graph/geom/Triangle.java
index 1c63c4005..6b07501a6 100644
--- a/src/jogl/classes/com/jogamp/graph/geom/Triangle.java
+++ b/src/jogl/classes/com/jogamp/graph/geom/Triangle.java
@@ -64,11 +64,11 @@ public class Triangle {
/**
* Returns a transformed a clone of this instance using the given AffineTransform.
*/
- public Triangle transform(final AffineTransform t, final Vertex.Factory<? extends Vertex> vertexFactory) {
+ public Triangle transform(final AffineTransform t) {
final Triangle tri = new Triangle(id, boundaryEdges, boundaryVertices);
- tri.vertices[0] = t.transform(vertices[0], vertexFactory.create());
- tri.vertices[1] = t.transform(vertices[1], vertexFactory.create());
- tri.vertices[2] = t.transform(vertices[2], vertexFactory.create());
+ tri.vertices[0] = t.transform(vertices[0], new Vertex());
+ tri.vertices[1] = t.transform(vertices[1], new Vertex());
+ tri.vertices[2] = t.transform(vertices[2], new Vertex());
return tri;
}
@@ -83,9 +83,9 @@ public class Triangle {
* Returns true if all vertices are lines, i.e. zero tex-coord, otherwise false.
*/
public final boolean isLine() {
- return VectorUtil.isVec2Zero(vertices[0].getTexCoord(), 0) &&
- VectorUtil.isVec2Zero(vertices[1].getTexCoord(), 0) &&
- VectorUtil.isVec2Zero(vertices[2].getTexCoord(), 0) ;
+ return VectorUtil.isVec2Zero(vertices[0].getTexCoord()) &&
+ VectorUtil.isVec2Zero(vertices[1].getTexCoord()) &&
+ VectorUtil.isVec2Zero(vertices[2].getTexCoord()) ;
}
public int getId() {
diff --git a/src/jogl/classes/com/jogamp/graph/geom/Vertex.java b/src/jogl/classes/com/jogamp/graph/geom/Vertex.java
index e9c8dd193..e5fe76c28 100644
--- a/src/jogl/classes/com/jogamp/graph/geom/Vertex.java
+++ b/src/jogl/classes/com/jogamp/graph/geom/Vertex.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2011 JogAmp Community. All rights reserved.
+ * Copyright 2011-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -27,64 +27,185 @@
*/
package com.jogamp.graph.geom;
+import com.jogamp.opengl.math.Vec2f;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.math.Vert3fImmutable;
/**
- * A Vertex with custom memory layout using custom factory.
+ * A Vertex exposing Vec3f vertex- and texture-coordinates.
*/
-public interface Vertex extends Vert3fImmutable, Cloneable {
+public final class Vertex implements Vert3fImmutable, Cloneable {
+ private int id;
+ private boolean onCurve;
+ private final Vec3f coord = new Vec3f();
+ private final Vec3f texCoord = new Vec3f();
+
+ public Vertex() {
+ this.id = Integer.MAX_VALUE;
+ }
- public static interface Factory <T extends Vertex> {
- T create();
+ public Vertex(final Vertex src) {
+ this.id = Integer.MAX_VALUE;
+ coord.set(src.getCoord());
+ texCoord.set(src.getTexCoord());
+ setOnCurve(src.isOnCurve());
+ }
- T create(Vertex src);
+ public Vertex(final int id, final boolean onCurve, final Vec3f texCoord) {
+ this.id = id;
+ this.onCurve = onCurve;
+ this.texCoord.set(texCoord);
+ }
- T create(int id, boolean onCurve, float[] texCoordsBuffer);
+ public Vertex(final int id, final boolean onCurve, final float texCoordX, final float texCoordY, final float texCoordZ) {
+ this.id = id;
+ this.onCurve = onCurve;
+ this.texCoord.set(texCoordX, texCoordY, texCoordZ);
+ }
- T create(float x, float y, float z, boolean onCurve);
+ public Vertex(final Vec3f coord, final boolean onCurve) {
+ this.id = Integer.MAX_VALUE;
+ this.coord.set(coord);
+ setOnCurve(onCurve);
+ }
- T create(float[] coordsBuffer, int offset, int length, boolean onCurve);
+ public Vertex(final Vec2f coord, final boolean onCurve) {
+ this.id = Integer.MAX_VALUE;
+ this.coord.set(coord, 0f);
+ setOnCurve(onCurve);
}
- void setCoord(float x, float y, float z);
+ public Vertex(final float x, final float y, final boolean onCurve) {
+ this(x, y, 0, onCurve);
+ }
- /**
- * @see System#arraycopy(Object, int, Object, int, int) for thrown IndexOutOfBoundsException
- */
- void setCoord(float[] coordsBuffer, int offset, int length);
+ public Vertex(final float[] coordsBuffer, final int offset, final int length, final boolean onCurve) {
+ this(coordsBuffer[offset+0], coordsBuffer[offset+1], 2 < length ? coordsBuffer[offset+2] : 0f, onCurve);
+ }
- void setX(float x);
+ public Vertex(final float x, final float y, final float z, final boolean onCurve) {
+ this.id = Integer.MAX_VALUE;
+ coord.set(x, y, z);
+ setOnCurve(onCurve);
+ }
- void setY(float y);
+ public final void setCoord(final Vec3f coord) {
+ this.coord.set(coord);
+ }
- void setZ(float z);
+ public void setCoord(final Vec2f coord) {
+ this.coord.set(coord, 0f);
+ }
+
+ public final void setCoord(final float x, final float y, final float z) {
+ coord.set(x, y, z);
+ }
- boolean isOnCurve();
+ public final void setCoord(final float x, final float y) {
+ coord.set(x, y, 0f);
+ }
- void setOnCurve(boolean onCurve);
+ @Override
+ public int getCoordCount() {
+ return 3;
+ }
- int getId();
+ @Override
+ public final Vec3f getCoord() {
+ return coord;
+ }
- void setId(int id);
+ public final void setX(final float x) {
+ coord.setX(x);
+ }
- float[] getTexCoord();
+ public final void setY(final float y) {
+ coord.setY(y);
+ }
- void setTexCoord(float s, float t, float p);
+ public final void setZ(final float z) {
+ coord.setZ(z);
+ }
- /**
- * @see System#arraycopy(Object, int, Object, int, int) for thrown IndexOutOfBoundsException
- */
- void setTexCoord(float[] texCoordsBuffer, int offset, int length);
+ @Override
+ public final float x() {
+ return coord.x();
+ }
+
+ @Override
+ public final float y() {
+ return coord.y();
+ }
+
+ @Override
+ public final float z() {
+ return coord.z();
+ }
+
+ public final boolean isOnCurve() {
+ return onCurve;
+ }
+
+ public final void setOnCurve(final boolean onCurve) {
+ this.onCurve = onCurve;
+ }
+
+ public final int getId(){
+ return id;
+ }
+
+ public final void setId(final int id){
+ this.id = id;
+ }
/**
* @param obj the Object to compare this Vertex with
* @return true if {@code obj} is a Vertex and not null, on-curve flag is equal and has same vertex- and tex-coords.
*/
@Override
- boolean equals(Object obj);
+ public boolean equals(final Object obj) {
+ if( obj == this) {
+ return true;
+ }
+ if( null == obj || !(obj instanceof Vertex) ) {
+ return false;
+ }
+ final Vertex v = (Vertex) obj;
+ return this == v ||
+ isOnCurve() == v.isOnCurve() &&
+ getTexCoord().isEqual( v.getTexCoord() ) &&
+ getCoord().isEqual( v.getCoord() );
+ }
+
+ @Override
+ public final int hashCode() {
+ throw new InternalError("hashCode not designed");
+ }
+
+ public final Vec3f getTexCoord() {
+ return texCoord;
+ }
+
+ public final void setTexCoord(final Vec3f v) {
+ texCoord.set(v);
+ }
+
+ public final void setTexCoord(final float s, final float t, final float p) {
+ texCoord.set(s, t, p);
+ }
/**
- * @return deep clone of this Vertex
+ * @return deep clone of this Vertex elements
*/
- Vertex clone();
+ @Override
+ public Vertex clone(){
+ return new Vertex(this); // OK to not call super.clone(), using own copy-ctor
+ }
+
+ @Override
+ public String toString() {
+ return "[ID: " + id + ", onCurve: " + onCurve +
+ ": p " + coord +
+ ", t " + texCoord + "]";
+ }
}
diff --git a/src/jogl/classes/com/jogamp/graph/geom/plane/AffineTransform.java b/src/jogl/classes/com/jogamp/graph/geom/plane/AffineTransform.java
index 62cda0322..434746240 100644
--- a/src/jogl/classes/com/jogamp/graph/geom/plane/AffineTransform.java
+++ b/src/jogl/classes/com/jogamp/graph/geom/plane/AffineTransform.java
@@ -16,6 +16,7 @@
*/
/**
* @author Denis M. Kishenko
+ * @author Sven Gothel, (c) 2010-2023
*/
package com.jogamp.graph.geom.plane;
@@ -23,6 +24,8 @@ package com.jogamp.graph.geom.plane;
import com.jogamp.graph.geom.Vertex;
import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Vec2f;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.math.geom.AABBox;
public class AffineTransform implements Cloneable {
@@ -53,17 +56,17 @@ public class AffineTransform implements Cloneable {
/**
* The values of transformation matrix
*/
- float m00;
- float m10;
- float m01;
- float m11;
- float m02;
- float m12;
+ private float m00;
+ private float m10;
+ private float m01;
+ private float m11;
+ private float m02;
+ private float m12;
/**
* The transformation <code>type</code>
*/
- transient int type;
+ private transient int type;
public AffineTransform() {
setToIdentity();
@@ -404,10 +407,10 @@ public class AffineTransform implements Cloneable {
* @return dst for chaining
*/
public final AABBox transform(final AABBox src, final AABBox dst) {
- final float[] srcLo = src.getLow();
- final float[] srcHi = src.getHigh();
- dst.setSize(srcLo[0] * m00 + srcLo[1] * m01 + m02, srcLo[0] * m10 + srcLo[1] * m11 + m12, srcLo[2],
- srcHi[0] * m00 + srcHi[1] * m01 + m02, srcHi[0] * m10 + srcHi[1] * m11 + m12, srcHi[2]);
+ final Vec3f lo = src.getLow();
+ final Vec3f hi = src.getHigh();
+ dst.setSize(lo.x() * m00 + lo.y() * m01 + m02, lo.x() * m10 + lo.y() * m11 + m12, lo.z(),
+ hi.x() * m00 + hi.y() * m01 + m02, hi.x() * m10 + hi.y() * m11 + m12, hi.z());
return dst;
}
@@ -417,9 +420,9 @@ public class AffineTransform implements Cloneable {
* @return dst for chaining
*/
public final Vertex transform(final Vertex src, final Vertex dst) {
- final float x = src.getX();
- final float y = src.getY();
- dst.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12, src.getZ());
+ final float x = src.x();
+ final float y = src.y();
+ dst.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12, src.z());
return dst;
}
@@ -430,9 +433,9 @@ public class AffineTransform implements Cloneable {
if (dstPoint == null) {
throw new IllegalArgumentException("dst["+dstOff+"] is null");
}
- final float x = srcPoint.getX();
- final float y = srcPoint.getY();
- dstPoint.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12, srcPoint.getZ());
+ final float x = srcPoint.x();
+ final float y = srcPoint.y();
+ dstPoint.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12, srcPoint.z());
dst[dstOff++] = dstPoint;
}
}
@@ -475,15 +478,42 @@ public class AffineTransform implements Cloneable {
}
/**
+ * @param src source of transformation
+ * @param dst destination of transformation, maybe be equal to <code>src</code>
+ * @return dst for chaining
+ */
+ public final Vec2f transform(final Vec2f src, final Vec2f dst) {
+ final float x = src.x();
+ final float y = src.y();
+ dst.setX( x * m00 + y * m01 + m02 );
+ dst.setY( x * m10 + y * m11 + m12 );
+ return dst;
+ }
+
+ /**
+ * @param src source of transformation
+ * @param dst destination of transformation, maybe be equal to <code>src</code>
+ * @return dst for chaining
+ */
+ public final Vec3f transform(final Vec3f src, final Vec3f dst) {
+ final float x = src.x();
+ final float y = src.y();
+ dst.setX( x * m00 + y * m01 + m02 );
+ dst.setY( x * m10 + y * m11 + m12 );
+ dst.setZ( src.z() ); // just copy z
+ return dst;
+ }
+
+ /**
*
* @param src
* @param dst
* @return return dst for chaining
*/
public final Vertex deltaTransform(final Vertex src, final Vertex dst) {
- final float x = src.getX();
- final float y = src.getY();
- dst.setCoord(x * m00 + y * m01, x * m10 + y * m11, src.getZ());
+ final float x = src.x();
+ final float y = src.y();
+ dst.setCoord(x * m00 + y * m01, x * m10 + y * m11, src.z());
return dst;
}
@@ -508,9 +538,9 @@ public class AffineTransform implements Cloneable {
if (FloatUtil.abs(det) < ZERO) {
throw new NoninvertibleTransformException(determinantIsZero);
}
- final float x = src.getX() - m02;
- final float y = src.getY() - m12;
- dst.setCoord((x * m11 - y * m01) / det, (y * m00 - x * m10) / det, src.getZ());
+ final float x = src.x() - m02;
+ final float y = src.y() - m12;
+ dst.setCoord((x * m11 - y * m01) / det, (y * m00 - x * m10) / det, src.z());
return dst;
}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawable.java b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawable.java
index 385acf082..a2a04f3fe 100644
--- a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawable.java
+++ b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawable.java
@@ -175,7 +175,7 @@ public interface GLAutoDrawable extends GLDrawable {
* <li>If the old context was current on this thread, it is being released after disassociating this auto-drawable.</li>
* <li>If the new context was current on this thread, it is being released before associating this auto-drawable
* and made current afterwards.</li>
- * <li>Implementation may issue {@link #makeCurrent()} and {@link #release()} while drawable reassociation.</li>
+ * <li>Implementation may issue {@link GLContext#makeCurrent()} and {@link GLContext#release()} while drawable reassociation.</li>
* <li>The user shall take extra care of thread synchronization,
* i.e. lock the involved {@link GLAutoDrawable auto-drawable's}
* {@link GLAutoDrawable#getUpstreamLock() upstream-locks} and {@link GLAutoDrawable#getNativeSurface() surfaces}
@@ -417,6 +417,13 @@ public interface GLAutoDrawable extends GLDrawable {
* {@link GLEventListener#display(GLAutoDrawable) display(GLAutoDrawable)}
* methods have been called.
* <p>
+ * The given {@link GLRunnable#run(GLAutoDrawable)} shall return true to indicate
+ * that the GL [back] framebuffer remains intact by this runnable. <br/>
+ * If returning false {@link GLAutoDrawable} will call
+ * {@link GLEventListener#display(GLAutoDrawable) display(GLAutoDrawable)}
+ * of all registered {@link GLEventListener}s once more to reinstate the framebuffer.
+ * </p>
+ * <p>
* If no {@link GLAnimatorControl} is animating (default),<br>
* or if the current thread is the animator thread,<br>
* a {@link #display()} call is issued after enqueue the <code>GLRunnable</code>,
diff --git a/src/jogl/classes/com/jogamp/opengl/GLEventListener.java b/src/jogl/classes/com/jogamp/opengl/GLEventListener.java
index 8c5dfd3b3..6b3786b0d 100644
--- a/src/jogl/classes/com/jogamp/opengl/GLEventListener.java
+++ b/src/jogl/classes/com/jogamp/opengl/GLEventListener.java
@@ -93,10 +93,10 @@ public interface GLEventListener extends EventListener {
* </p>
*
* @param drawable the triggering {@link GLAutoDrawable}
- * @param x viewport x-coord in pixel units
- * @param y viewport y-coord in pixel units
- * @param width viewport width in pixel units
- * @param height viewport height in pixel units
+ * @param x lower left corner of the viewport rectangle in pixel units
+ * @param y lower left corner of the viewport rectangle in pixel units
+ * @param width width of the viewport rectangle in pixel units
+ * @param height height of the viewport rectangle in pixel units
*/
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height);
}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLOffscreenAutoDrawable.java b/src/jogl/classes/com/jogamp/opengl/GLOffscreenAutoDrawable.java
index a2d0f5fdb..7d150c517 100644
--- a/src/jogl/classes/com/jogamp/opengl/GLOffscreenAutoDrawable.java
+++ b/src/jogl/classes/com/jogamp/opengl/GLOffscreenAutoDrawable.java
@@ -30,8 +30,6 @@ package com.jogamp.opengl;
import com.jogamp.nativewindow.NativeWindowException;
-import com.jogamp.opengl.FBObject;
-
/**
* Platform-independent {@link GLAutoDrawable} specialization,
* exposing offscreen functionality.
diff --git a/src/jogl/classes/com/jogamp/opengl/GLRunnable.java b/src/jogl/classes/com/jogamp/opengl/GLRunnable.java
index 97a72d6cd..f8bd56fdc 100644
--- a/src/jogl/classes/com/jogamp/opengl/GLRunnable.java
+++ b/src/jogl/classes/com/jogamp/opengl/GLRunnable.java
@@ -41,6 +41,13 @@ package com.jogamp.opengl;
* The OpenGL context is current while executing the GLRunnable.
* </p>
* <p>
+ * {@link GLRunnable#run(GLAutoDrawable)} shall return true to indicate
+ * that the GL [back] framebuffer remains intact by this runnable. <br/>
+ * If returning false {@link GLAutoDrawable} will call
+ * {@link GLEventListener#display(GLAutoDrawable) display(GLAutoDrawable)}
+ * of all registered {@link GLEventListener}s once more to reinstate the framebuffer.
+ * </p>
+ * <p>
* This might be useful to inject OpenGL commands from an I/O event listener.
* </p>
*/
diff --git a/src/jogl/classes/com/jogamp/opengl/GLUniformData.java b/src/jogl/classes/com/jogamp/opengl/GLUniformData.java
index 55a2e0cf1..c4cc3fe8f 100644
--- a/src/jogl/classes/com/jogamp/opengl/GLUniformData.java
+++ b/src/jogl/classes/com/jogamp/opengl/GLUniformData.java
@@ -1,18 +1,52 @@
-
+/**
+ * Copyright 2009-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
package com.jogamp.opengl;
-import java.nio.*;
+import java.nio.Buffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.util.SyncAction;
+import com.jogamp.opengl.util.SyncBuffer;
-public class GLUniformData {
+/**
+ * GLSL uniform data wrapper encapsulating data to be uploaded to the GPU as a uniform.
+ */
+public final class GLUniformData {
/**
* int atom
*
* Number of objects is 1
*
+ * @param name the uniform name as used in the shader
*/
public GLUniformData(final String name, final int val) {
initScalar(name, 1, Integer.valueOf(val));
@@ -23,6 +57,7 @@ public class GLUniformData {
*
* Number of objects is 1
*
+ * @param name the uniform name as used in the shader
*/
public GLUniformData(final String name, final float val) {
initScalar(name, 1, Float.valueOf(val));
@@ -33,10 +68,12 @@ public class GLUniformData {
*
* Number of objects is calculated by data.limit()/components
*
+ * @param name the uniform name as used in the shader
* @param components number of elements of one object, ie 4 for GL_FLOAT_VEC4,
+ * @param data the data
*/
public GLUniformData(final String name, final int components, final IntBuffer data) {
- initBuffer(name, components, data);
+ initBuffer(name, components, data, null);
}
/**
@@ -44,14 +81,29 @@ public class GLUniformData {
*
* Number of objects is calculated by data.limit()/components
*
+ * @param name the uniform name as used in the shader
* @param components number of elements of one object, ie 4 for GL_FLOAT_VEC4,
+ * @param data the underlying data
*/
public GLUniformData(final String name, final int components, final FloatBuffer data) {
- initBuffer(name, components, data);
+ initBuffer(name, components, data, null);
+ }
+
+ /**
+ * Multiple IntBuffer or FloatBuffer Vector
+ *
+ * Number of objects is calculated by data.limit()/components
+ *
+ * @param name the uniform name as used in the shader
+ * @param components number of elements of one object, ie 4 for GL_FLOAT_VEC4,
+ * @param syncBuffer {@link SyncBuffer} providing {@link SyncAction} and {@link Buffer}, allowing to sync the buffer with the underlying data, see {@link #getBuffer()}
+ */
+ public GLUniformData(final String name, final int components, final SyncBuffer syncBuffer) {
+ initBuffer(name, components, syncBuffer.getBuffer(), syncBuffer.getAction());
}
private GLUniformData(final int components, final String name) {
- initBuffer(name, components, null);
+ initBuffer(name, components, null, null);
}
public static GLUniformData creatEmptyVector(final String name, final int components) {
@@ -59,7 +111,7 @@ public class GLUniformData {
}
public static GLUniformData creatEmptyMatrix(final String name, final int rows, final int columns) {
- return new GLUniformData(name, rows, columns, null);
+ return new GLUniformData(name, rows, columns, (FloatBuffer)null);
}
/**
@@ -67,17 +119,35 @@ public class GLUniformData {
*
* Number of objects is calculated by data.limit()/(rows*columns)
*
+ * @param name the uniform name as used in the shader
* @param rows the matrix rows
* @param column the matrix column
+ * @param data the underlying data
*/
public GLUniformData(final String name, final int rows, final int columns, final FloatBuffer data) {
- initBuffer(name, rows, columns, data);
+ initBuffer(name, rows, columns, data, null);
+ }
+
+ /**
+ * Multiple FloatBuffer Matrix
+ *
+ * Number of objects is calculated by data.limit()/(rows*columns)
+ *
+ * @param name the uniform name as used in the shader
+ * @param rows the matrix rows
+ * @param column the matrix column
+ * @param syncBuffer {@link SyncBuffer} providing {@link SyncAction} and {@link Buffer}, allowing to sync the buffer with the underlying data, see {@link #getBuffer()}
+ */
+ public GLUniformData(final String name, final int rows, final int columns, final SyncBuffer syncBuffer) {
+ initBuffer(name, rows, columns, syncBuffer.getBuffer(), syncBuffer.getAction());
}
public GLUniformData setData(final int data) { initScalar(Integer.valueOf(data)); return this; }
public GLUniformData setData(final float data) { initScalar(Float.valueOf(data)); return this; }
- public GLUniformData setData(final IntBuffer data) { initBuffer(data); return this; }
- public GLUniformData setData(final FloatBuffer data) { initBuffer(data); return this; }
+
+ public GLUniformData setData(final IntBuffer data) { initBuffer(data, null); return this; }
+ public GLUniformData setData(final FloatBuffer data) { initBuffer(data, null); return this; }
+ public GLUniformData setData(final SyncBuffer syncedBuffer) { initBuffer(syncedBuffer.getBuffer(), syncedBuffer.getAction()); return this; }
public int intValue() { return ((Integer)data).intValue(); };
public float floatValue() { return ((Float)data).floatValue(); };
@@ -115,16 +185,16 @@ public class GLUniformData {
return toString(null).toString();
}
- private void initBuffer(final String name, final int rows, final int columns, final Buffer buffer) {
+ private void initBuffer(final String name, final int rows, final int columns, final Buffer buffer, final SyncAction syncAction) {
if( 2>rows || rows>4 || 2>columns || columns>4 ) {
throw new GLException("rowsXcolumns must be within [2..4]X[2..4], is: "+rows+"X"+columns);
}
this.name=name;
this.rows=rows;
this.columns=columns;
- this.isMatrix=true;
+ this.bits=BIT_MATRIX;
this.location=-1;
- initBuffer(buffer);
+ initBuffer(buffer, syncAction);
}
private void initScalar(final String name, final int components, final Object data) {
if( 1>components || components>4 ) {
@@ -133,27 +203,27 @@ public class GLUniformData {
this.name=name;
this.columns=components;
this.rows=1;
- this.isMatrix=false;
+ this.bits=0;
this.location=-1;
initScalar(data);
}
- private void initBuffer(final String name, final int components, final Buffer buffer) {
+ private void initBuffer(final String name, final int components, final Buffer buffer, final SyncAction syncAction) {
if( 1>components || components>4 ) {
throw new GLException("components must be within [1..4], is: "+components);
}
this.name=name;
this.columns=components;
this.rows=1;
- this.isMatrix=false;
+ this.bits=0;
this.location=-1;
- initBuffer(buffer);
+ initBuffer(buffer, syncAction);
}
private void initScalar(final Object data) {
if(data instanceof Buffer) {
- initBuffer((Buffer)data);
+ initBuffer((Buffer)data, null);
} else if( null != data ) {
- if(isMatrix) {
+ if( isMatrix() ) {
throw new GLException("Atom type not allowed for matrix : "+this);
}
this.count=1;
@@ -164,8 +234,9 @@ public class GLUniformData {
}
}
- private void initBuffer(final Buffer buffer) {
+ private void initBuffer(final Buffer buffer, final SyncAction syncAction) {
if( null != buffer ) {
+ this.bits |= BIT_BUFFER;
final int sz = rows*columns;
if(buffer.remaining()<sz || 0!=buffer.remaining()%sz) {
throw new GLException("remaining data buffer size invalid: buffer: "+buffer.toString()+"\n\t"+this);
@@ -176,8 +247,10 @@ public class GLUniformData {
this.count=0;
this.data=null;
}
+ this.syncAction = syncAction;
}
+ /** Return the uniform name as used in the shader */
public String getName() { return name; }
public int getLocation() { return location; }
@@ -189,7 +262,7 @@ public class GLUniformData {
public int setLocation(final int location) { this.location=location; return location; }
/**
- * Retrieves the location of the shader uniform from the linked shader program.
+ * Retrieves the location of the shader uniform with {@link #getName()} from the linked shader program.
* <p>
* No validation is performed within the implementation.
* </p>
@@ -203,26 +276,54 @@ public class GLUniformData {
return location;
}
+ /**
+ * Returns the data object.
+ * <p>
+ * In case a {@link SyncAction} has been set,
+ * it is invoked to {@link SyncAction#sync() synchronize} the object with the underlying data before returning the object.
+ * </p>
+ * @return the data object.
+ * @see SyncAction#sync()
+ */
public Object getObject() {
+ if( null != syncAction ) {
+ syncAction.sync();
+ }
return data;
}
+
+ /**
+ * Returns the data buffer.
+ * <p>
+ * In case a {@link SyncAction} has been set,
+ * it is invoked to {@link SyncAction#sync() synchronize} the buffer with the underlying data before returning the buffer.
+ * </p>
+ * @return the data buffer.
+ * @see SyncAction#sync()
+ */
public Buffer getBuffer() {
+ if( null != syncAction ) {
+ syncAction.sync();
+ }
return (data instanceof Buffer)?(Buffer)data:null;
}
- public boolean isBuffer() {
- return (data instanceof Buffer);
- }
- public boolean isMatrix() { return isMatrix; }
+
+ public boolean isMatrix() { return 0 != ( BIT_MATRIX & bits ); }
+ public boolean isBuffer() { return 0 != ( BIT_BUFFER & bits ); }
public int count() { return count; }
public int components() { return rows*columns; }
public int rows() { return rows; }
public int columns() { return columns; }
+ private static final short BIT_MATRIX = 0b0000000000000001;
+ private static final short BIT_BUFFER = 0b0000000000000010;
+
private String name;
private int location;
private int rows, columns;
private int count;
private Object data;
- private boolean isMatrix;
+ private short bits;
+ private SyncAction syncAction;
}
diff --git a/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java
index 602671f6e..735a2a21c 100644
--- a/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java
+++ b/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
- * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ * Copyright (c) 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -175,10 +175,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
private volatile JAWTWindow jawtWindow; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle
private volatile GLContextImpl context; // volatile: avoid locking for read-only access
private volatile boolean sendReshape = false; // volatile: maybe written by EDT w/o locking
- private final float[] minPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
- private final float[] maxPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
private final float[] hasPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
- final float[] reqPixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
// copy of the cstr args, mainly for recreation
private final GLCapabilitiesImmutable capsReqUser;
@@ -564,9 +561,10 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
function properly. <P>
<B>Overrides:</B>
- <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
- @SuppressWarnings("deprecation")
- @Override
+ <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL>
+ */
+ @SuppressWarnings("deprecation")
+ @Override
public void addNotify() {
final RecursiveLock _lock = lock;
_lock.lock();
@@ -634,62 +632,51 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
}
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation returns false, i.e. not supporting manual change of pixel-scale.
+ * </p>
+ */
@Override
- public final boolean setSurfaceScale(final float[] pixelScale) {
- System.arraycopy(pixelScale, 0, reqPixelScale, 0, 2);
- if( isRealized() && isShowing ) {
- Threading.invoke(true, setSurfaceScaleOnEDTAction, getTreeLock());
- return true;
- } else {
- return false;
- }
- }
- private final Runnable setSurfaceScaleOnEDTAction = new Runnable() {
- @Override
- public void run() {
- final RecursiveLock _lock = lock;
- _lock.lock();
- try {
- if( null != drawable && drawable.isRealized() ) {
- if( setSurfaceScaleImpl(jawtWindow) ) {
- reshapeImpl(getWidth(), getHeight());
- if( !helper.isAnimatorAnimatingOnOtherThread() ) {
- helper.invokeGL(drawable, context, displayAction, initAction); // display
- }
- }
- }
- } finally {
- _lock.unlock();
- }
- } };
+ public final boolean canSetSurfaceScale() { return false; }
- private final boolean setSurfaceScaleImpl(final ScalableSurface ns) {
- if(DEBUG) {
- System.err.printf("GLCanvas.setSurfaceScaleImpl reqPixelScale %.2f %.2f, hasPixelScale %.2f %.2f\n",
- reqPixelScale[0], reqPixelScale[1], hasPixelScale[0], hasPixelScale[1]);
- }
-
- if( ns.setSurfaceScale(hasPixelScale) ) {
- ns.getCurrentSurfaceScale(hasPixelScale);
- return true;
- } else {
- return false;
- }
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Ignored for an AWT widget since pixelScale is dictated by AWT mechanisms.
+ * </p>
+ */
+ @Override
+ public final boolean setSurfaceScale(final float[] pixelScale) {
+ return false;
}
private final boolean updatePixelScale() {
if( jawtWindow.hasPixelScaleChanged() ) {
- jawtWindow.getMaximumSurfaceScale(maxPixelScale);
- jawtWindow.getMinimumSurfaceScale(minPixelScale);
- return setSurfaceScaleImpl(jawtWindow);
+ if(DEBUG) {
+ final float[] old = { hasPixelScale[0], hasPixelScale[1] };
+ jawtWindow.getCurrentSurfaceScale(hasPixelScale);
+ System.err.printf("GLCanvas.updatePixelScale hasPixelScale %.2f %.2f -> %.2f %.2f\n", old[0], old[1], hasPixelScale[0], hasPixelScale[1]);
+ } else {
+ jawtWindow.getCurrentSurfaceScale(hasPixelScale);
+ }
+ return true;
} else {
return false;
}
}
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Returns {@link ScalableSurface#AUTOMAX_PIXELSCALE}, always.
+ * </p>
+ */
@Override
public final float[] getRequestedSurfaceScale(final float[] result) {
- System.arraycopy(reqPixelScale, 0, result, 0, 2);
+ result[0] = ScalableSurface.AUTOMAX_PIXELSCALE;
+ result[1] = ScalableSurface.AUTOMAX_PIXELSCALE;
return result;
}
@@ -699,15 +686,28 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
return result;
}
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Returns 1.0, always.
+ * </p>
+ */
@Override
public float[] getMinimumSurfaceScale(final float[] result) {
- System.arraycopy(minPixelScale, 0, result, 0, 2);
+ result[0] = 1f;
+ result[1] = 1f;
return result;
}
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Returns {@link #getCurrentSurfaceScale(float[])}.
+ * </p>
+ */
@Override
public float[] getMaximumSurfaceScale(final float[] result) {
- System.arraycopy(maxPixelScale, 0, result, 0, 2);
+ System.arraycopy(hasPixelScale, 0, result, 0, 2);
return result;
}
@@ -723,12 +723,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer);
jawtWindow.lockSurface();
try {
- jawtWindow.setSurfaceScale(reqPixelScale);
drawable = (GLDrawableImpl) GLDrawableFactory.getFactory(capsReqUser.getGLProfile()).createGLDrawable(jawtWindow);
createContextImpl(drawable);
jawtWindow.getCurrentSurfaceScale(hasPixelScale);
- jawtWindow.getMinimumSurfaceScale(minPixelScale);
- jawtWindow.getMaximumSurfaceScale(maxPixelScale);
} finally {
jawtWindow.unlockSurface();
}
@@ -1388,10 +1385,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing
}
hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
- minPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
- minPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
- maxPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
- maxPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
if(null != awtConfig) {
final AbstractGraphicsConfiguration aconfig = awtConfig.getNativeGraphicsConfiguration();
diff --git a/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java b/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java
index 20dc71958..fb0df6aaf 100644
--- a/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java
+++ b/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
- * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ * Copyright (c) 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -263,10 +263,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
private boolean handleReshape = false;
private boolean sendReshape = true;
- private final float[] minPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
- private final float[] maxPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
private final float[] hasPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
- private final float[] reqPixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
/** For handling reshape events lazily: reshapeWidth -> panelWidth -> backend.width in pixel units (scaled) */
private int reshapeWidth;
@@ -397,6 +394,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
public final boolean initializeBackend(final boolean offthread) {
if( offthread ) {
new InterruptSource.Thread(null, null, getThreadName()+"-GLJPanel_Init") {
+ @Override
public void run() {
if( !isInitialized ) {
initializeBackendImpl();
@@ -581,59 +579,52 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
}
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation returns false, i.e. not supporting manual change of pixel-scale.
+ * </p>
+ */
@Override
- public final boolean setSurfaceScale(final float[] pixelScale) { // HiDPI support
- System.arraycopy(pixelScale, 0, reqPixelScale, 0, 2);
- final Backend b = backend;
- if ( isInitialized && null != b && isShowing ) {
- if( isShowing || ( printActive && isVisible() ) ) {
- if (EventQueue.isDispatchThread()) {
- setSurfaceScaleAction.run();
- } else {
- try {
- EventQueue.invokeAndWait(setSurfaceScaleAction);
- } catch (final Exception e) {
- throw new GLException(e);
- }
- }
- }
- return true;
- } else {
- return false;
- }
- }
- private final Runnable setSurfaceScaleAction = new Runnable() {
- @Override
- public void run() {
- final Backend b = backend;
- if( null != b && setSurfaceScaleImpl(b) ) {
- if( !helper.isAnimatorAnimatingOnOtherThread() ) {
- paintImmediatelyAction.run(); // display
- }
- }
- }
- };
+ public final boolean canSetSurfaceScale() { return false; }
- private final boolean setSurfaceScaleImpl(final Backend b) {
- if( SurfaceScaleUtils.setNewPixelScale(hasPixelScale, hasPixelScale, reqPixelScale, minPixelScale, maxPixelScale, DEBUG ? getClass().getSimpleName() : null) ) {
- reshapeImpl(getWidth(), getHeight());
- updateWrappedSurfaceScale(b.getDrawable());
- return true;
- }
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Ignored for an AWT widget since pixelScale is dictated by AWT mechanisms.
+ * </p>
+ */
+ @Override
+ public final boolean setSurfaceScale(final float[] pixelScale) { // HiDPI support
return false;
}
private final boolean updatePixelScale(final Backend b) {
- if( JAWTUtil.getPixelScale(getGraphicsConfiguration(), minPixelScale, maxPixelScale) ) {
- return setSurfaceScaleImpl(b);
- } else {
- return false;
- }
+ final float[] min = { 1, 1 };
+ final float[] max = { hasPixelScale[0], hasPixelScale[1] };
+ if( JAWTUtil.getPixelScale(getGraphicsConfiguration(), min, max) ) {
+ if( DEBUG ) {
+ System.err.printf("GLJPanel.updatePixelScale %.2f %.2f -> %.2f %.2f\n", hasPixelScale[0], hasPixelScale[1], max[0], max[1]);
+ }
+ System.arraycopy(max, 0, hasPixelScale, 0, 2);
+ reshapeImpl(getWidth(), getHeight());
+ updateWrappedSurfaceScale(b.getDrawable());
+ return true;
+ } else {
+ return false;
+ }
}
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Returns {@link ScalableSurface#AUTOMAX_PIXELSCALE}, always.
+ * </p>
+ */
@Override
public final float[] getRequestedSurfaceScale(final float[] result) {
- System.arraycopy(reqPixelScale, 0, result, 0, 2);
+ result[0] = ScalableSurface.AUTOMAX_PIXELSCALE;
+ result[1] = ScalableSurface.AUTOMAX_PIXELSCALE;
return result;
}
@@ -643,15 +634,28 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
return result;
}
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Returns 1.0, always.
+ * </p>
+ */
@Override
public float[] getMinimumSurfaceScale(final float[] result) {
- System.arraycopy(minPixelScale, 0, result, 0, 2);
+ result[0] = 1f;
+ result[1] = 1f;
return result;
}
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Returns {@link #getCurrentSurfaceScale(float[])}.
+ * </p>
+ */
@Override
public float[] getMaximumSurfaceScale(final float[] result) {
- System.arraycopy(maxPixelScale, 0, result, 0, 2);
+ System.arraycopy(hasPixelScale, 0, result, 0, 2);
return result;
}
@@ -667,8 +671,17 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
awtWindowClosingProtocol.addClosingListener();
// HiDPI support
- JAWTUtil.getPixelScale(getGraphicsConfiguration(), minPixelScale, maxPixelScale);
- SurfaceScaleUtils.setNewPixelScale(hasPixelScale, hasPixelScale, reqPixelScale, minPixelScale, maxPixelScale, DEBUG ? getClass().getSimpleName() : null);
+ {
+ final float[] min = { 1, 1 };
+ final float[] max = { hasPixelScale[0], hasPixelScale[1] };
+ if( JAWTUtil.getPixelScale(getGraphicsConfiguration(), min, max) ) {
+ if( DEBUG ) {
+ System.err.printf("GLJPanel.addNotify: pixelScale %.2f %.2f -> %.2f %.2f\n", hasPixelScale[0], hasPixelScale[1], max[0], max[1]);
+ }
+ System.arraycopy(max, 0, hasPixelScale, 0, 2);
+ reshapeImpl(getWidth(), getHeight());
+ }
+ }
if (DEBUG) {
System.err.println(getThreadName()+": GLJPanel.addNotify()");
@@ -688,10 +701,6 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
dispose(null);
hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
- minPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
- minPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
- maxPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
- maxPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
super.removeNotify();
}
@@ -1345,7 +1354,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
if( !isInitialized ) {
if( handleReshape ) {
if (DEBUG) {
- System.err.println(getThreadName()+": GLJPanel.createAndInitializeBackend.1: ["+(printActive?"printing":"paint")+"] "+
+ System.err.println(getThreadName()+": GLJPanel.initializeBackendImpl.1: ["+(printActive?"printing":"paint")+"] "+
panelWidth+"x"+panelHeight+" @ scale "+getPixelScaleStr() + " -> " +
reshapeWidth+"x"+reshapeHeight+" @ scale "+getPixelScaleStr());
}
@@ -1354,7 +1363,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
handleReshape = false;
} else {
if (DEBUG) {
- System.err.println(getThreadName()+": GLJPanel.createAndInitializeBackend.0: ["+(printActive?"printing":"paint")+"] "+
+ System.err.println(getThreadName()+": GLJPanel.initializeBackendImpl.0: ["+(printActive?"printing":"paint")+"] "+
panelWidth+"x"+panelHeight+" @ scale "+getPixelScaleStr());
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java
index 73244cb13..004562767 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -35,8 +35,6 @@ import com.jogamp.opengl.GLException;
import jogamp.opengl.Debug;
import com.jogamp.common.os.Platform;
-import com.jogamp.opengl.math.geom.AABBox;
-import com.jogamp.opengl.math.geom.Frustum;
/**
* Basic Float math utility functions.
@@ -44,20 +42,26 @@ import com.jogamp.opengl.math.geom.Frustum;
* Implementation assumes linear matrix layout in column-major order
* matching OpenGL's implementation, illustration:
* <pre>
- Row-Major Column-Major (OpenGL):
+ Row-Major Column-Major (OpenGL):
- | 0 1 2 3 | | 0 4 8 12 |
- | | | |
- | 4 5 6 7 | | 1 5 9 13 |
- M = | | M = | |
- | 8 9 10 11 | | 2 6 10 14 |
- | | | |
- | 12 13 14 15 | | 3 7 11 15 |
+ | 0 1 2 tx |
+ | |
+ | 4 5 6 ty |
+ M = | |
+ | 8 9 10 tz |
+ | |
+ | 12 13 14 15 |
- C R C R
+ R C R C
m[0*4+3] = tx; m[0+4*3] = tx;
m[1*4+3] = ty; m[1+4*3] = ty;
m[2*4+3] = tz; m[2+4*3] = tz;
+
+ RC (std subscript order) RC (std subscript order)
+ m03 = tx; m03 = tx;
+ m13 = ty; m13 = ty;
+ m23 = tz; m23 = tz;
+
* </pre>
* </p>
* <p>
@@ -71,7 +75,7 @@ import com.jogamp.opengl.math.geom.Frustum;
* Implementation utilizes unrolling of small vertices and matrices wherever possible
* while trying to access memory in a linear fashion for performance reasons, see:
* <ul>
- * <li><a href="https://code.google.com/p/java-matrix-benchmark/">java-matrix-benchmark</a></li>
+ * <li><a href="https://lessthanoptimal.github.io/Java-Matrix-Benchmark/">java-matrix-benchmark</a></li>
* <li><a href="https://github.com/lessthanoptimal/ejml">EJML Efficient Java Matrix Library</a></li>
* </ul>
* </p>
@@ -81,40 +85,12 @@ public final class FloatUtil {
//
// Matrix Ops
+ // Only a subset will remain here, try using Matrix4f and perhaps PMVMatrix, SyncMatrix4f16 or SyncMatrices4f16
//
/**
* Make matrix an identity matrix
* @param m 4x4 matrix in column-major order (also result)
- * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
- * @return given matrix for chaining
- */
- public static float[] makeIdentity(final float[] m, final int m_offset) {
- m[m_offset+0+4*0] = 1f;
- m[m_offset+1+4*0] = 0f;
- m[m_offset+2+4*0] = 0f;
- m[m_offset+3+4*0] = 0f;
-
- m[m_offset+0+4*1] = 0f;
- m[m_offset+1+4*1] = 1f;
- m[m_offset+2+4*1] = 0f;
- m[m_offset+3+4*1] = 0f;
-
- m[m_offset+0+4*2] = 0f;
- m[m_offset+1+4*2] = 0f;
- m[m_offset+2+4*2] = 1f;
- m[m_offset+3+4*2] = 0f;
-
- m[m_offset+0+4*3] = 0f;
- m[m_offset+1+4*3] = 0f;
- m[m_offset+2+4*3] = 0f;
- m[m_offset+3+4*3] = 1f;
- return m;
- }
-
- /**
- * Make matrix an identity matrix
- * @param m 4x4 matrix in column-major order (also result)
* @return given matrix for chaining
*/
public static float[] makeIdentity(final float[] m) {
@@ -153,43 +129,6 @@ public final class FloatUtil {
* All matrix fields are only set if <code>initM</code> is <code>true</code>.
* </p>
* @param m 4x4 matrix in column-major order (also result)
- * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
- * @param initM if true, given matrix will be initialized w/ identity matrix,
- * otherwise only the diagonal and last-row is set.
- * The latter can be utilized to share a once {@link #makeIdentity(float[], int) identity set} matrix
- * for {@link #makeScale(float[], int, boolean, float, float, float) scaling}
- * and {@link #makeTranslation(float[], int, boolean, float, float, float) translation},
- * while leaving the other fields untouched for performance reasons.
- * @return given matrix for chaining
- */
- public static float[] makeTranslation(final float[] m, final int m_offset, final boolean initM, final float tx, final float ty, final float tz) {
- if( initM ) {
- makeIdentity(m, m_offset);
- } else {
- m[m_offset+0+4*0] = 1;
- m[m_offset+1+4*1] = 1;
- m[m_offset+2+4*2] = 1;
- m[m_offset+3+4*3] = 1;
- }
- m[m_offset+0+4*3] = tx;
- m[m_offset+1+4*3] = ty;
- m[m_offset+2+4*3] = tz;
- return m;
- }
-
- /**
- * Make a translation matrix in column-major order from the given axis deltas
- * <pre>
- Translation matrix (Column Order):
- 1 0 0 0
- 0 1 0 0
- 0 0 1 0
- x y z 1
- * </pre>
- * <p>
- * All matrix fields are only set if <code>initM</code> is <code>true</code>.
- * </p>
- * @param m 4x4 matrix in column-major order (also result)
* @param initM if true, given matrix will be initialized w/ identity matrix,
* otherwise only the diagonal and last-row is set.
* The latter can be utilized to share a once {@link #makeIdentity(float[], int) identity set} matrix
@@ -226,43 +165,6 @@ public final class FloatUtil {
* All matrix fields are only set if <code>initM</code> is <code>true</code>.
* </p>
* @param m 4x4 matrix in column-major order (also result)
- * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
- * @param initM if true, given matrix will be initialized w/ identity matrix,
- * otherwise only the diagonal and last-row is set.
- * The latter can be utilized to share a once {@link #makeIdentity(float[], int) identity set} matrix
- * for {@link #makeScale(float[], int, boolean, float, float, float) scaling}
- * and {@link #makeTranslation(float[], int, boolean, float, float, float) translation},
- * while leaving the other fields untouched for performance reasons.
- * @return given matrix for chaining
- */
- public static float[] makeScale(final float[] m, final int m_offset, final boolean initM, final float sx, final float sy, final float sz) {
- if( initM ) {
- makeIdentity(m, m_offset);
- } else {
- m[m_offset+0+4*3] = 0;
- m[m_offset+1+4*3] = 0;
- m[m_offset+2+4*3] = 0;
- m[m_offset+3+4*3] = 1;
- }
- m[m_offset+0+4*0] = sx;
- m[m_offset+1+4*1] = sy;
- m[m_offset+2+4*2] = sz;
- return m;
- }
-
- /**
- * Make a scale matrix in column-major order from the given axis factors
- * <pre>
- Scale matrix (Any Order):
- x 0 0 0
- 0 y 0 0
- 0 0 z 0
- 0 0 0 1
- * </pre>
- * <p>
- * All matrix fields are only set if <code>initM</code> is <code>true</code>.
- * </p>
- * @param m 4x4 matrix in column-major order (also result)
* @param initM if true, given matrix will be initialized w/ identity matrix,
* otherwise only the diagonal and last-row is set.
* The latter can be utilized to share a once {@link #makeIdentity(float[], int) identity set} matrix
@@ -287,189 +189,6 @@ public final class FloatUtil {
}
/**
- * Make a rotation matrix from the given axis and angle in radians.
- * <pre>
- Rotation matrix (Column Order):
- xx(1-c)+c xy(1-c)+zs xz(1-c)-ys 0
- xy(1-c)-zs yy(1-c)+c yz(1-c)+xs 0
- xz(1-c)+ys yz(1-c)-xs zz(1-c)+c 0
- 0 0 0 1
- * </pre>
- * <p>
- * All matrix fields are set.
- * </p>
- * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a>
- * @param m 4x4 matrix in column-major order (also result)
- * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
- * @return given matrix for chaining
- */
- public static float[] makeRotationAxis(final float[] m, final int m_offset, final float angrad, float x, float y, float z, final float[] tmpVec3f) {
- final float c = cos(angrad);
- final float ic= 1.0f - c;
- final float s = sin(angrad);
-
- tmpVec3f[0]=x; tmpVec3f[1]=y; tmpVec3f[2]=z;
- VectorUtil.normalizeVec3(tmpVec3f);
- x = tmpVec3f[0]; y = tmpVec3f[1]; z = tmpVec3f[2];
-
- final float xy = x*y;
- final float xz = x*z;
- final float xs = x*s;
- final float ys = y*s;
- final float yz = y*z;
- final float zs = z*s;
- m[0+0*4+m_offset] = x*x*ic+c;
- m[1+0*4+m_offset] = xy*ic+zs;
- m[2+0*4+m_offset] = xz*ic-ys;
- m[3+0*4+m_offset] = 0;
-
- m[0+1*4+m_offset] = xy*ic-zs;
- m[1+1*4+m_offset] = y*y*ic+c;
- m[2+1*4+m_offset] = yz*ic+xs;
- m[3+1*4+m_offset] = 0;
-
- m[0+2*4+m_offset] = xz*ic+ys;
- m[1+2*4+m_offset] = yz*ic-xs;
- m[2+2*4+m_offset] = z*z*ic+c;
- m[3+2*4+m_offset] = 0;
-
- m[0+3*4+m_offset] = 0f;
- m[1+3*4+m_offset] = 0f;
- m[2+3*4+m_offset] = 0f;
- m[3+3*4+m_offset] = 1f;
-
- return m;
- }
-
- /**
- * Make a concatenated rotation matrix in column-major order from the given Euler rotation angles in radians.
- * <p>
- * The rotations are applied in the given order:
- * <ul>
- * <li>y - heading</li>
- * <li>z - attitude</li>
- * <li>x - bank</li>
- * </ul>
- * </p>
- * <p>
- * All matrix fields are set.
- * </p>
- * @param m 4x4 matrix in column-major order (also result)
- * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
- * @param bankX the Euler pitch angle in radians. (rotation about the X axis)
- * @param headingY the Euler yaw angle in radians. (rotation about the Y axis)
- * @param attitudeZ the Euler roll angle in radians. (rotation about the Z axis)
- * @return given matrix for chaining
- * <p>
- * Implementation does not use Quaternion and hence is exposed to
- * <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q34">Gimbal-Lock</a>
- * </p>
- * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q36">Matrix-FAQ Q36</a>
- * @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm">euclideanspace.com-eulerToMatrix</a>
- */
- public static float[] makeRotationEuler(final float[] m, final int m_offset, final float bankX, final float headingY, final float attitudeZ) {
- // Assuming the angles are in radians.
- final float ch = cos(headingY);
- final float sh = sin(headingY);
- final float ca = cos(attitudeZ);
- final float sa = sin(attitudeZ);
- final float cb = cos(bankX);
- final float sb = sin(bankX);
-
- m[0+0*4+m_offset] = ch*ca;
- m[1+0*4+m_offset] = sa;
- m[2+0*4+m_offset] = -sh*ca;
- m[3+0*4+m_offset] = 0;
-
- m[0+1*4+m_offset] = sh*sb - ch*sa*cb;
- m[1+1*4+m_offset] = ca*cb;
- m[2+1*4+m_offset] = sh*sa*cb + ch*sb;
- m[3+1*4+m_offset] = 0;
-
- m[0+2*4+m_offset] = ch*sa*sb + sh*cb;
- m[1+2*4+m_offset] = -ca*sb;
- m[2+2*4+m_offset] = -sh*sa*sb + ch*cb;
- m[3+2*4+m_offset] = 0;
-
- m[0+3*4+m_offset] = 0;
- m[1+3*4+m_offset] = 0;
- m[2+3*4+m_offset] = 0;
- m[3+3*4+m_offset] = 1;
-
- return m;
- }
-
- /**
- * Make given matrix the orthogonal matrix based on given parameters.
- * <pre>
- Ortho matrix (Column Order):
- 2/dx 0 0 0
- 0 2/dy 0 0
- 0 0 2/dz 0
- tx ty tz 1
- * </pre>
- * <p>
- * All matrix fields are only set if <code>initM</code> is <code>true</code>.
- * </p>
- * @param m 4x4 matrix in column-major order (also result)
- * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
- * @param initM if true, given matrix will be initialized w/ identity matrix,
- * otherwise only the orthogonal fields are set.
- * @param left
- * @param right
- * @param bottom
- * @param top
- * @param zNear
- * @param zFar
- * @return given matrix for chaining
- */
- public static float[] makeOrtho(final float[] m, final int m_offset, final boolean initM,
- final float left, final float right,
- final float bottom, final float top,
- final float zNear, final float zFar) {
- if( initM ) {
- // m[m_offset+0+4*0] = 1f;
- m[m_offset+1+4*0] = 0f;
- m[m_offset+2+4*0] = 0f;
- m[m_offset+3+4*0] = 0f;
-
- m[m_offset+0+4*1] = 0f;
- // m[m_offset+1+4*1] = 1f;
- m[m_offset+2+4*1] = 0f;
- m[m_offset+3+4*1] = 0f;
-
- m[m_offset+0+4*2] = 0f;
- m[m_offset+1+4*2] = 0f;
- // m[m_offset+2+4*2] = 1f;
- m[m_offset+3+4*2] = 0f;
-
- // m[m_offset+0+4*3] = 0f;
- // m[m_offset+1+4*3] = 0f;
- // m[m_offset+2+4*3] = 0f;
- // m[m_offset+3+4*3] = 1f;
- }
- final float dx=right-left;
- final float dy=top-bottom;
- final float dz=zFar-zNear;
- final float tx=-1.0f*(right+left)/dx;
- final float ty=-1.0f*(top+bottom)/dy;
- final float tz=-1.0f*(zFar+zNear)/dz;
-
- m[m_offset+0+4*0] = 2.0f/dx;
-
- m[m_offset+1+4*1] = 2.0f/dy;
-
- m[m_offset+2+4*2] = -2.0f/dz;
-
- m[m_offset+0+4*3] = tx;
- m[m_offset+1+4*3] = ty;
- m[m_offset+2+4*3] = tz;
- m[m_offset+3+4*3] = 1f;
-
- return m;
- }
-
- /**
* Make given matrix the frustum matrix based on given parameters.
* <pre>
Frustum matrix (Column Order):
@@ -580,35 +299,6 @@ public final class FloatUtil {
}
/**
- * Make given matrix the perspective {@link #makeFrustum(float[], int, boolean, float, float, float, float, float, float) frustum}
- * matrix based on given parameters.
- * <p>
- * All matrix fields are only set if <code>initM</code> is <code>true</code>.
- * </p>
- *
- * @param m 4x4 matrix in column-major order (also result)
- * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
- * @param initM if true, given matrix will be initialized w/ identity matrix,
- * otherwise only the frustum fields are set.
- * @param fovhv {@link FovHVHalves} field of view in both directions, may not be centered, either in radians or tangent
- * @param zNear
- * @param zFar
- * @return given matrix for chaining
- * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear}
- * @see #makeFrustum(float[], int, boolean, float, float, float, float, float, float)
- * @see Frustum#updateByFovDesc(float[], int, boolean, Frustum.FovDesc)
- */
- public static float[] makePerspective(final float[] m, final int m_offset, final boolean initM,
- final FovHVHalves fovhv, final float zNear, final float zFar) throws GLException {
- final FovHVHalves fovhvTan = fovhv.toTangents(); // use tangent of half-fov !
- final float top = fovhvTan.top * zNear;
- final float bottom = -1.0f * fovhvTan.bottom * zNear;
- final float left = -1.0f * fovhvTan.left * zNear;
- final float right = fovhvTan.right * zNear;
- return makeFrustum(m, m_offset, initM, left, right, bottom, top, zNear, zFar);
- }
-
- /**
* Make given matrix the <i>look-at</i> matrix based on given parameters.
* <p>
* Consist out of two matrix multiplications:
@@ -722,7 +412,7 @@ public final class FloatUtil {
* @param mat4Tmp temp float[16] storage
* @return given matrix <code>m</code> for chaining or <code>null</code> if either delta value is <= zero.
*/
- public static float[] makePick(final float[] m, final int m_offset,
+ public static float[] makePick(final float[] m,
final float x, final float y,
final float deltaX, final float deltaY,
final int[] viewport, final int viewport_offset,
@@ -732,13 +422,13 @@ public final class FloatUtil {
}
/* Translate and scale the picked region to the entire window */
- makeTranslation(m, m_offset, true,
+ makeTranslation(m, true,
(viewport[2+viewport_offset] - 2 * (x - viewport[0+viewport_offset])) / deltaX,
(viewport[3+viewport_offset] - 2 * (y - viewport[1+viewport_offset])) / deltaY,
0);
makeScale(mat4Tmp, true,
viewport[2+viewport_offset] / deltaX, viewport[3+viewport_offset] / deltaY, 1.0f);
- multMatrix(m, m_offset, mat4Tmp, 0);
+ multMatrix(m, mat4Tmp);
return m;
}
@@ -746,42 +436,6 @@ public final class FloatUtil {
* Transpose the given matrix.
*
* @param msrc 4x4 matrix in column-major order, the source
- * @param msrc_offset offset in given array <i>msrc</i>, i.e. start of the 4x4 matrix
- * @param mres 4x4 matrix in column-major order, the result
- * @param mres_offset offset in given array <i>mres</i>, i.e. start of the 4x4 matrix
- * @return given result matrix <i>mres</i> for chaining
- */
- public static float[] transposeMatrix(final float[] msrc, final int msrc_offset, final float[] mres, final int mres_offset) {
- mres[mres_offset+0] = msrc[msrc_offset+0*4];
- mres[mres_offset+1] = msrc[msrc_offset+1*4];
- mres[mres_offset+2] = msrc[msrc_offset+2*4];
- mres[mres_offset+3] = msrc[msrc_offset+3*4];
-
- final int i4_1 = 1*4;
- mres[mres_offset+0+i4_1] = msrc[msrc_offset+1+0*4];
- mres[mres_offset+1+i4_1] = msrc[msrc_offset+1+1*4];
- mres[mres_offset+2+i4_1] = msrc[msrc_offset+1+2*4];
- mres[mres_offset+3+i4_1] = msrc[msrc_offset+1+3*4];
-
- final int i4_2 = 2*4;
- mres[mres_offset+0+i4_2] = msrc[msrc_offset+2+0*4];
- mres[mres_offset+1+i4_2] = msrc[msrc_offset+2+1*4];
- mres[mres_offset+2+i4_2] = msrc[msrc_offset+2+2*4];
- mres[mres_offset+3+i4_2] = msrc[msrc_offset+2+3*4];
-
- final int i4_3 = 3*4;
- mres[mres_offset+0+i4_3] = msrc[msrc_offset+3+0*4];
- mres[mres_offset+1+i4_3] = msrc[msrc_offset+3+1*4];
- mres[mres_offset+2+i4_3] = msrc[msrc_offset+3+2*4];
- mres[mres_offset+3+i4_3] = msrc[msrc_offset+3+3*4];
-
- return mres;
- }
-
- /**
- * Transpose the given matrix.
- *
- * @param msrc 4x4 matrix in column-major order, the source
* @param mres 4x4 matrix in column-major order, the result
* @return given result matrix <i>mres</i> for chaining
*/
@@ -815,40 +469,6 @@ public final class FloatUtil {
/**
* Returns the determinant of the given matrix
* @param m 4x4 matrix in column-major order, the source
- * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
- * @return the matrix determinant
- */
- public static float matrixDeterminant(final float[] m, final int m_offset) {
- float a11 = m[ 1+4*1 + m_offset ];
- float a21 = m[ 2+4*1 + m_offset ];
- float a31 = m[ 3+4*1 + m_offset ];
- float a12 = m[ 1+4*2 + m_offset ];
- float a22 = m[ 2+4*2 + m_offset ];
- float a32 = m[ 3+4*2 + m_offset ];
- float a13 = m[ 1+4*3 + m_offset ];
- float a23 = m[ 2+4*3 + m_offset ];
- float a33 = m[ 3+4*3 + m_offset ];
-
- float ret = 0;
- ret += m[ 0 + m_offset ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31));
- a11 = m[ 1+4*0 + m_offset ];
- a21 = m[ 2+4*0 + m_offset ];
- a31 = m[ 3+4*0 + m_offset ];
- ret -= m[ 0+4*1 + m_offset ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31));
- a12 = m[ 1+4*1 + m_offset ];
- a22 = m[ 2+4*1 + m_offset ];
- a32 = m[ 3+4*1 + m_offset ];
- ret += m[ 0+4*2 + m_offset ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31));
- a13 = m[ 1+4*2 + m_offset ];
- a23 = m[ 2+4*2 + m_offset ];
- a33 = m[ 3+4*2 + m_offset ];
- ret -= m[ 0+4*3 + m_offset ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31));
- return ret;
- }
-
- /**
- * Returns the determinant of the given matrix
- * @param m 4x4 matrix in column-major order, the source
* @return the matrix determinant
*/
public static float matrixDeterminant(final float[] m) {
@@ -878,94 +498,6 @@ public final class FloatUtil {
ret -= m[ 0+4*3 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31));
return ret;
}
-
- /**
- * Invert the given matrix.
- * <p>
- * Returns <code>null</code> if inversion is not possible,
- * e.g. matrix is singular due to a bad matrix.
- * </p>
- *
- * @param msrc 4x4 matrix in column-major order, the source
- * @param msrc_offset offset in given array <i>msrc</i>, i.e. start of the 4x4 matrix
- * @param mres 4x4 matrix in column-major order, the result - may be <code>msrc</code> (in-place)
- * @param mres_offset offset in given array <i>mres</i>, i.e. start of the 4x4 matrix - may be <code>msrc_offset</code> (in-place)
- * @return given result matrix <i>mres</i> for chaining if successful, otherwise <code>null</code>. See above.
- */
- public static float[] invertMatrix(final float[] msrc, final int msrc_offset, final float[] mres, final int mres_offset) {
- final float scale;
- {
- float max = Math.abs(msrc[0]);
-
- for( int i = 1; i < 16; i++ ) {
- final float a = Math.abs(msrc[i]);
- if( a > max ) max = a;
- }
- if( 0 == max ) {
- return null;
- }
- scale = 1.0f/max;
- }
-
- final float a11 = msrc[0+4*0+msrc_offset]*scale;
- final float a21 = msrc[1+4*0+msrc_offset]*scale;
- final float a31 = msrc[2+4*0+msrc_offset]*scale;
- final float a41 = msrc[3+4*0+msrc_offset]*scale;
- final float a12 = msrc[0+4*1+msrc_offset]*scale;
- final float a22 = msrc[1+4*1+msrc_offset]*scale;
- final float a32 = msrc[2+4*1+msrc_offset]*scale;
- final float a42 = msrc[3+4*1+msrc_offset]*scale;
- final float a13 = msrc[0+4*2+msrc_offset]*scale;
- final float a23 = msrc[1+4*2+msrc_offset]*scale;
- final float a33 = msrc[2+4*2+msrc_offset]*scale;
- final float a43 = msrc[3+4*2+msrc_offset]*scale;
- final float a14 = msrc[0+4*3+msrc_offset]*scale;
- final float a24 = msrc[1+4*3+msrc_offset]*scale;
- final float a34 = msrc[2+4*3+msrc_offset]*scale;
- final float a44 = msrc[3+4*3+msrc_offset]*scale;
-
- final float m11 = + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42);
- final float m12 = -( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41));
- final float m13 = + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41);
- final float m14 = -( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41));
- final float m21 = -( + a12*(a33*a44 - a34*a43) - a13*(a32*a44 - a34*a42) + a14*(a32*a43 - a33*a42));
- final float m22 = + a11*(a33*a44 - a34*a43) - a13*(a31*a44 - a34*a41) + a14*(a31*a43 - a33*a41);
- final float m23 = -( + a11*(a32*a44 - a34*a42) - a12*(a31*a44 - a34*a41) + a14*(a31*a42 - a32*a41));
- final float m24 = + a11*(a32*a43 - a33*a42) - a12*(a31*a43 - a33*a41) + a13*(a31*a42 - a32*a41);
- final float m31 = + a12*(a23*a44 - a24*a43) - a13*(a22*a44 - a24*a42) + a14*(a22*a43 - a23*a42);
- final float m32 = -( + a11*(a23*a44 - a24*a43) - a13*(a21*a44 - a24*a41) + a14*(a21*a43 - a23*a41));
- final float m33 = + a11*(a22*a44 - a24*a42) - a12*(a21*a44 - a24*a41) + a14*(a21*a42 - a22*a41);
- final float m34 = -( + a11*(a22*a43 - a23*a42) - a12*(a21*a43 - a23*a41) + a13*(a21*a42 - a22*a41));
- final float m41 = -( + a12*(a23*a34 - a24*a33) - a13*(a22*a34 - a24*a32) + a14*(a22*a33 - a23*a32));
- final float m42 = + a11*(a23*a34 - a24*a33) - a13*(a21*a34 - a24*a31) + a14*(a21*a33 - a23*a31);
- final float m43 = -( + a11*(a22*a34 - a24*a32) - a12*(a21*a34 - a24*a31) + a14*(a21*a32 - a22*a31));
- final float m44 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31);
-
- final float det = (a11*m11 + a12*m12 + a13*m13 + a14*m14)/scale;
-
- if( 0 == det ) {
- return null;
- }
-
- mres[0+4*0+mres_offset] = m11 / det;
- mres[1+4*0+mres_offset] = m12 / det;
- mres[2+4*0+mres_offset] = m13 / det;
- mres[3+4*0+mres_offset] = m14 / det;
- mres[0+4*1+mres_offset] = m21 / det;
- mres[1+4*1+mres_offset] = m22 / det;
- mres[2+4*1+mres_offset] = m23 / det;
- mres[3+4*1+mres_offset] = m24 / det;
- mres[0+4*2+mres_offset] = m31 / det;
- mres[1+4*2+mres_offset] = m32 / det;
- mres[2+4*2+mres_offset] = m33 / det;
- mres[3+4*2+mres_offset] = m34 / det;
- mres[0+4*3+mres_offset] = m41 / det;
- mres[1+4*3+mres_offset] = m42 / det;
- mres[2+4*3+mres_offset] = m43 / det;
- mres[3+4*3+mres_offset] = m44 / det;
- return mres;
- }
-
/**
* Invert the given matrix.
* <p>
@@ -1027,27 +559,27 @@ public final class FloatUtil {
final float m44 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31);
final float det = (a11*m11 + a12*m12 + a13*m13 + a14*m14)/scale;
-
if( 0 == det ) {
return null;
}
-
- mres[0+4*0] = m11 / det;
- mres[1+4*0] = m12 / det;
- mres[2+4*0] = m13 / det;
- mres[3+4*0] = m14 / det;
- mres[0+4*1] = m21 / det;
- mres[1+4*1] = m22 / det;
- mres[2+4*1] = m23 / det;
- mres[3+4*1] = m24 / det;
- mres[0+4*2] = m31 / det;
- mres[1+4*2] = m32 / det;
- mres[2+4*2] = m33 / det;
- mres[3+4*2] = m34 / det;
- mres[0+4*3] = m41 / det;
- mres[1+4*3] = m42 / det;
- mres[2+4*3] = m43 / det;
- mres[3+4*3] = m44 / det;
+ final float invdet = 1.0f / det;
+
+ mres[0+4*0] = m11 * invdet;
+ mres[1+4*0] = m12 * invdet;
+ mres[2+4*0] = m13 * invdet;
+ mres[3+4*0] = m14 * invdet;
+ mres[0+4*1] = m21 * invdet;
+ mres[1+4*1] = m22 * invdet;
+ mres[2+4*1] = m23 * invdet;
+ mres[3+4*1] = m24 * invdet;
+ mres[0+4*2] = m31 * invdet;
+ mres[1+4*2] = m32 * invdet;
+ mres[2+4*2] = m33 * invdet;
+ mres[3+4*2] = m34 * invdet;
+ mres[0+4*3] = m41 * invdet;
+ mres[1+4*3] = m42 * invdet;
+ mres[2+4*3] = m43 * invdet;
+ mres[3+4*3] = m44 * invdet;
return mres;
}
@@ -1072,12 +604,12 @@ public final class FloatUtil {
* @param vec4Tmp2 4 component vector for temp storage
* @return true if successful, otherwise false (z is 1)
*/
- public static boolean mapObjToWinCoords(final float objx, final float objy, final float objz,
- final float[] modelMatrix, final int modelMatrix_offset,
- final float[] projMatrix, final int projMatrix_offset,
- final int[] viewport, final int viewport_offset,
- final float[] win_pos, final int win_pos_offset,
- final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
+ public static boolean mapObjToWin(final float objx, final float objy, final float objz,
+ final float[] modelMatrix, final int modelMatrix_offset,
+ final float[] projMatrix, final int projMatrix_offset,
+ final int[] viewport, final int viewport_offset,
+ final float[] win_pos, final int win_pos_offset,
+ final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
vec4Tmp1[0] = objx;
vec4Tmp1[1] = objy;
vec4Tmp1[2] = objz;
@@ -1110,56 +642,6 @@ public final class FloatUtil {
}
/**
- * Map object coordinates to window coordinates.
- * <p>
- * Traditional <code>gluProject</code> implementation.
- * </p>
- *
- * @param objx
- * @param objy
- * @param objz
- * @param mat4PMv [projection] x [modelview] matrix, i.e. P x Mv
- * @param viewport 4 component viewport vector
- * @param viewport_offset
- * @param win_pos 3 component window coordinate, the result
- * @param win_pos_offset
- * @param vec4Tmp1 4 component vector for temp storage
- * @param vec4Tmp2 4 component vector for temp storage
- * @return true if successful, otherwise false (z is 1)
- */
- public static boolean mapObjToWinCoords(final float objx, final float objy, final float objz,
- final float[/*16*/] mat4PMv,
- final int[] viewport, final int viewport_offset,
- final float[] win_pos, final int win_pos_offset,
- final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
- vec4Tmp2[0] = objx;
- vec4Tmp2[1] = objy;
- vec4Tmp2[2] = objz;
- vec4Tmp2[3] = 1.0f;
-
- // vec4Tmp1 = P * Mv * o
- multMatrixVec(mat4PMv, vec4Tmp2, vec4Tmp1);
-
- if (vec4Tmp1[3] == 0.0f) {
- return false;
- }
-
- vec4Tmp1[3] = (1.0f / vec4Tmp1[3]) * 0.5f;
-
- // Map x, y and z to range 0-1
- vec4Tmp1[0] = vec4Tmp1[0] * vec4Tmp1[3] + 0.5f;
- vec4Tmp1[1] = vec4Tmp1[1] * vec4Tmp1[3] + 0.5f;
- vec4Tmp1[2] = vec4Tmp1[2] * vec4Tmp1[3] + 0.5f;
-
- // Map x,y to viewport
- win_pos[0+win_pos_offset] = vec4Tmp1[0] * viewport[2+viewport_offset] + viewport[0+viewport_offset];
- win_pos[1+win_pos_offset] = vec4Tmp1[1] * viewport[3+viewport_offset] + viewport[1+viewport_offset];
- win_pos[2+win_pos_offset] = vec4Tmp1[2];
-
- return true;
- }
-
- /**
* Map window coordinates to object coordinates.
* <p>
* Traditional <code>gluUnProject</code> implementation.
@@ -1180,12 +662,12 @@ public final class FloatUtil {
* @param mat4Tmp2 16 component matrix for temp storage
* @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
*/
- public static boolean mapWinToObjCoords(final float winx, final float winy, final float winz,
- final float[] modelMatrix, final int modelMatrix_offset,
- final float[] projMatrix, final int projMatrix_offset,
- final int[] viewport, final int viewport_offset,
- final float[] obj_pos, final int obj_pos_offset,
- final float[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) {
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz,
+ final float[] modelMatrix, final int modelMatrix_offset,
+ final float[] projMatrix, final int projMatrix_offset,
+ final int[] viewport, final int viewport_offset,
+ final float[] obj_pos, final int obj_pos_offset,
+ final float[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) {
// mat4Tmp1 = P x Mv
multMatrix(projMatrix, projMatrix_offset, modelMatrix, modelMatrix_offset, mat4Tmp1, 0);
@@ -1227,137 +709,6 @@ public final class FloatUtil {
/**
* Map window coordinates to object coordinates.
* <p>
- * Traditional <code>gluUnProject</code> implementation.
- * </p>
- *
- * @param winx
- * @param winy
- * @param winz
- * @param mat4PMvI inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv)
- * @param viewport 4 component viewport vector
- * @param viewport_offset
- * @param obj_pos 3 component object coordinate, the result
- * @param obj_pos_offset
- * @param vec4Tmp1 4 component vector for temp storage
- * @param vec4Tmp2 4 component vector for temp storage
- * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
- */
- public static boolean mapWinToObjCoords(final float winx, final float winy, final float winz,
- final float[/*16*/] mat4PMvI,
- final int[] viewport, final int viewport_offset,
- final float[] obj_pos, final int obj_pos_offset,
- final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
- vec4Tmp1[0] = winx;
- vec4Tmp1[1] = winy;
- vec4Tmp1[2] = winz;
- vec4Tmp1[3] = 1.0f;
-
- // Map x and y from window coordinates
- vec4Tmp1[0] = (vec4Tmp1[0] - viewport[0+viewport_offset]) / viewport[2+viewport_offset];
- vec4Tmp1[1] = (vec4Tmp1[1] - viewport[1+viewport_offset]) / viewport[3+viewport_offset];
-
- // Map to range -1 to 1
- vec4Tmp1[0] = vec4Tmp1[0] * 2 - 1;
- vec4Tmp1[1] = vec4Tmp1[1] * 2 - 1;
- vec4Tmp1[2] = vec4Tmp1[2] * 2 - 1;
-
- // object raw coords = Inv(P x Mv) * winPos -> mat4Tmp2
- multMatrixVec(mat4PMvI, vec4Tmp1, vec4Tmp2);
-
- if (vec4Tmp2[3] == 0.0) {
- return false;
- }
-
- vec4Tmp2[3] = 1.0f / vec4Tmp2[3];
-
- obj_pos[0+obj_pos_offset] = vec4Tmp2[0] * vec4Tmp2[3];
- obj_pos[1+obj_pos_offset] = vec4Tmp2[1] * vec4Tmp2[3];
- obj_pos[2+obj_pos_offset] = vec4Tmp2[2] * vec4Tmp2[3];
-
- return true;
- }
-
- /**
- * Map two window coordinates to two object coordinates,
- * distinguished by their z component.
- *
- * @param winx
- * @param winy
- * @param winz1
- * @param winz2
- * @param mat4PMvI inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv)
- * @param viewport 4 component viewport vector
- * @param viewport_offset
- * @param obj1_pos 3 component object coordinate, the result for winz1
- * @param obj1_pos_offset
- * @param obj2_pos 3 component object coordinate, the result for winz2
- * @param obj2_pos_offset
- * @param vec4Tmp1 4 component vector for temp storage
- * @param vec4Tmp2 4 component vector for temp storage
- * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
- */
- public static boolean mapWinToObjCoords(final float winx, final float winy, final float winz1, final float winz2,
- final float[/*16*/] mat4PMvI,
- final int[] viewport, final int viewport_offset,
- final float[] obj1_pos, final int obj1_pos_offset,
- final float[] obj2_pos, final int obj2_pos_offset,
- final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
- vec4Tmp1[0] = winx;
- vec4Tmp1[1] = winy;
- vec4Tmp1[3] = 1.0f;
-
- // Map x and y from window coordinates
- vec4Tmp1[0] = (vec4Tmp1[0] - viewport[0+viewport_offset]) / viewport[2+viewport_offset];
- vec4Tmp1[1] = (vec4Tmp1[1] - viewport[1+viewport_offset]) / viewport[3+viewport_offset];
-
- // Map to range -1 to 1
- vec4Tmp1[0] = vec4Tmp1[0] * 2 - 1;
- vec4Tmp1[1] = vec4Tmp1[1] * 2 - 1;
-
- //
- // winz1
- //
- vec4Tmp1[2] = winz1;
- vec4Tmp1[2] = vec4Tmp1[2] * 2 - 1;
-
- // object raw coords = Inv(P x Mv) * winPos -> mat4Tmp2
- multMatrixVec(mat4PMvI, vec4Tmp1, vec4Tmp2);
-
- if (vec4Tmp2[3] == 0.0) {
- return false;
- }
-
- vec4Tmp2[3] = 1.0f / vec4Tmp2[3];
-
- obj1_pos[0+obj1_pos_offset] = vec4Tmp2[0] * vec4Tmp2[3];
- obj1_pos[1+obj1_pos_offset] = vec4Tmp2[1] * vec4Tmp2[3];
- obj1_pos[2+obj1_pos_offset] = vec4Tmp2[2] * vec4Tmp2[3];
-
- //
- // winz2
- //
- vec4Tmp1[2] = winz2;
- vec4Tmp1[2] = vec4Tmp1[2] * 2 - 1;
-
- // object raw coords = Inv(P x Mv) * winPos -> mat4Tmp2
- multMatrixVec(mat4PMvI, vec4Tmp1, vec4Tmp2);
-
- if (vec4Tmp2[3] == 0.0) {
- return false;
- }
-
- vec4Tmp2[3] = 1.0f / vec4Tmp2[3];
-
- obj2_pos[0+obj2_pos_offset] = vec4Tmp2[0] * vec4Tmp2[3];
- obj2_pos[1+obj2_pos_offset] = vec4Tmp2[1] * vec4Tmp2[3];
- obj2_pos[2+obj2_pos_offset] = vec4Tmp2[2] * vec4Tmp2[3];
-
- return true;
- }
-
- /**
- * Map window coordinates to object coordinates.
- * <p>
* Traditional <code>gluUnProject4</code> implementation.
* </p>
*
@@ -1379,13 +730,13 @@ public final class FloatUtil {
* @param mat4Tmp2 16 component matrix for temp storage
* @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
*/
- public static boolean mapWinToObjCoords(final float winx, final float winy, final float winz, final float clipw,
- final float[] modelMatrix, final int modelMatrix_offset,
- final float[] projMatrix, final int projMatrix_offset,
- final int[] viewport, final int viewport_offset,
- final float near, final float far,
- final float[] obj_pos, final int obj_pos_offset,
- final float[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) {
+ public static boolean mapWinToObj4(final float winx, final float winy, final float winz, final float clipw,
+ final float[] modelMatrix, final int modelMatrix_offset,
+ final float[] projMatrix, final int projMatrix_offset,
+ final int[] viewport, final int viewport_offset,
+ final float near, final float far,
+ final float[] obj_pos, final int obj_pos_offset,
+ final float[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) {
// mat4Tmp1 = P x Mv
multMatrix(projMatrix, projMatrix_offset, modelMatrix, modelMatrix_offset, mat4Tmp1, 0);
@@ -1397,7 +748,7 @@ public final class FloatUtil {
mat4Tmp2[0] = winx;
mat4Tmp2[1] = winy;
mat4Tmp2[2] = winz;
- mat4Tmp2[3] = 1.0f;
+ mat4Tmp2[3] = clipw;
// Map x and y from window coordinates
mat4Tmp2[0] = (mat4Tmp2[0] - viewport[0+viewport_offset]) / viewport[2+viewport_offset];
@@ -1417,8 +768,6 @@ public final class FloatUtil {
return false;
}
- mat4Tmp2[3+raw_off] = 1.0f / mat4Tmp2[3+raw_off];
-
obj_pos[0+obj_pos_offset] = mat4Tmp2[0+raw_off];
obj_pos[1+obj_pos_offset] = mat4Tmp2[1+raw_off];
obj_pos[2+obj_pos_offset] = mat4Tmp2[2+raw_off];
@@ -1427,67 +776,13 @@ public final class FloatUtil {
return true;
}
-
- /**
- * Map two window coordinates w/ shared X/Y and distinctive Z
- * to a {@link Ray}. The resulting {@link Ray} maybe used for <i>picking</i>
- * using a {@link AABBox#getRayIntersection(Ray, float[]) bounding box}.
- * <p>
- * Notes for picking <i>winz0</i> and <i>winz1</i>:
- * <ul>
- * <li>see {@link #getZBufferEpsilon(int, float, float)}</li>
- * <li>see {@link #getZBufferValue(int, float, float, float)}</li>
- * <li>see {@link #getOrthoWinZ(float, float, float)}</li>
- * </ul>
- * </p>
- * @param winx
- * @param winy
- * @param winz0
- * @param winz1
- * @param modelMatrix 4x4 modelview matrix
- * @param modelMatrix_offset
- * @param projMatrix 4x4 projection matrix
- * @param projMatrix_offset
- * @param viewport 4 component viewport vector
- * @param viewport_offset
- * @param ray storage for the resulting {@link Ray}
- * @param mat4Tmp1 16 component matrix for temp storage
- * @param mat4Tmp2 16 component matrix for temp storage
- * @param vec4Tmp2 4 component vector for temp storage
- * @return true if successful, otherwise false (failed to invert matrix, or becomes z is infinity)
- */
- public static boolean mapWinToRay(final float winx, final float winy, final float winz0, final float winz1,
- final float[] modelMatrix, final int modelMatrix_offset,
- final float[] projMatrix, final int projMatrix_offset,
- final int[] viewport, final int viewport_offset,
- final Ray ray,
- final float[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2, final float[/*4*/] vec4Tmp2) {
- // mat4Tmp1 = P x Mv
- multMatrix(projMatrix, projMatrix_offset, modelMatrix, modelMatrix_offset, mat4Tmp1, 0);
-
- // mat4Tmp1 = Inv(P x Mv)
- if ( null == invertMatrix(mat4Tmp1, mat4Tmp1) ) {
- return false;
- }
- if( mapWinToObjCoords(winx, winy, winz0, winz1, mat4Tmp1,
- viewport, viewport_offset,
- ray.orig, 0, ray.dir, 0,
- mat4Tmp2, vec4Tmp2) ) {
- VectorUtil.normalizeVec3( VectorUtil.subVec3(ray.dir, ray.dir, ray.orig) );
- return true;
- } else {
- return false;
- }
- }
-
/**
* Multiply matrix: [d] = [a] x [b]
* @param a 4x4 matrix in column-major order
* @param b 4x4 matrix in column-major order
* @param d result a*b in column-major order
- * @return given result matrix <i>d</i> for chaining
*/
- public static float[] multMatrix(final float[] a, final int a_off, final float[] b, final int b_off, final float[] d, final int d_off) {
+ public static void multMatrix(final float[] a, final int a_off, final float[] b, final int b_off, final float[] d, final int d_off) {
final float b00 = b[b_off+0+0*4];
final float b10 = b[b_off+1+0*4];
final float b20 = b[b_off+2+0*4];
@@ -1540,8 +835,6 @@ public final class FloatUtil {
d[d_off+3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
d[d_off+3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
d[d_off+3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
-
- return d;
}
/**
@@ -1612,9 +905,8 @@ public final class FloatUtil {
* Multiply matrix: [a] = [a] x [b]
* @param a 4x4 matrix in column-major order (also result)
* @param b 4x4 matrix in column-major order
- * @return given result matrix <i>a</i> for chaining
*/
- public static float[] multMatrix(final float[] a, final int a_off, final float[] b, final int b_off) {
+ public static void multMatrix(final float[] a, final int a_off, final float[] b, final int b_off) {
final float b00 = b[b_off+0+0*4];
final float b10 = b[b_off+1+0*4];
final float b20 = b[b_off+2+0*4];
@@ -1667,8 +959,6 @@ public final class FloatUtil {
a[a_off+3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
a[a_off+3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
a[a_off+3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
-
- return a;
}
/**
@@ -1778,11 +1068,10 @@ public final class FloatUtil {
* @param m_in_off
* @param v_in 4-component column-vector
* @param v_out m_in * v_in
- * @return given result vector <i>v_out</i> for chaining
*/
- public static float[] multMatrixVec(final float[] m_in, final int m_in_off,
- final float[] v_in, final int v_in_off,
- final float[] v_out, final int v_out_off) {
+ public static void multMatrixVec(final float[] m_in, final int m_in_off,
+ final float[] v_in, final int v_in_off,
+ final float[] v_out, final int v_out_off) {
// (one matrix row in column-major order) X (column vector)
v_out[0 + v_out_off] = v_in[0+v_in_off] * m_in[0*4+m_in_off ] + v_in[1+v_in_off] * m_in[1*4+m_in_off ] +
v_in[2+v_in_off] * m_in[2*4+m_in_off ] + v_in[3+v_in_off] * m_in[3*4+m_in_off ];
@@ -1798,8 +1087,31 @@ public final class FloatUtil {
final int m_in_off_3 = 3+m_in_off;
v_out[3 + v_out_off] = v_in[0+v_in_off] * m_in[0*4+m_in_off_3] + v_in[1+v_in_off] * m_in[1*4+m_in_off_3] +
v_in[2+v_in_off] * m_in[2*4+m_in_off_3] + v_in[3+v_in_off] * m_in[3*4+m_in_off_3];
+ }
- return v_out;
+ /**
+ * @param m_in 4x4 matrix in column-major order
+ * @param m_in_off
+ * @param v_in 4-component column-vector
+ * @param v_out m_in * v_in
+ */
+ public static void multMatrixVec(final float[] m_in, final int m_in_off,
+ final float[] v_in, final float[] v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ v_out[0] = v_in[0] * m_in[0*4+m_in_off ] + v_in[1] * m_in[1*4+m_in_off ] +
+ v_in[2] * m_in[2*4+m_in_off ] + v_in[3] * m_in[3*4+m_in_off ];
+
+ final int m_in_off_1 = 1+m_in_off;
+ v_out[1] = v_in[0] * m_in[0*4+m_in_off_1] + v_in[1] * m_in[1*4+m_in_off_1] +
+ v_in[2] * m_in[2*4+m_in_off_1] + v_in[3] * m_in[3*4+m_in_off_1];
+
+ final int m_in_off_2 = 2+m_in_off;
+ v_out[2] = v_in[0] * m_in[0*4+m_in_off_2] + v_in[1] * m_in[1*4+m_in_off_2] +
+ v_in[2] * m_in[2*4+m_in_off_2] + v_in[3] * m_in[3*4+m_in_off_2];
+
+ final int m_in_off_3 = 3+m_in_off;
+ v_out[3] = v_in[0] * m_in[0*4+m_in_off_3] + v_in[1] * m_in[1*4+m_in_off_3] +
+ v_in[2] * m_in[2*4+m_in_off_3] + v_in[3] * m_in[3*4+m_in_off_3];
}
/**
@@ -1845,46 +1157,29 @@ public final class FloatUtil {
}
/**
- * Copy the named column of the given column-major matrix to v_out.
- * <p>
- * v_out may be 3 or 4 components long, hence the 4th row may not be stored.
- * </p>
- * @param m_in input column-major matrix
- * @param m_in_off offset to input matrix
- * @param column named column to copy
- * @param v_out the column-vector storage, at least 3 components long
- * @param v_out_off offset to storage
+ * Affine 3f-vector transformation by 4x4 matrix
+ *
+ * 4x4 matrix multiplication with 3-component vector,
+ * using {@code 1} for for {@code v_in[3]} and dropping {@code v_out[3]},
+ * which shall be {@code 1}.
+ *
+ * @param m_in 4x4 matrix in column-major order
+ * @param m_in_off
+ * @param v_in 3-component column-vector
+ * @param v_out m_in * v_in, 3-component column-vector
* @return given result vector <i>v_out</i> for chaining
*/
- public static float[] copyMatrixColumn(final float[] m_in, final int m_in_off, final int column, final float[] v_out, final int v_out_off) {
- v_out[0+v_out_off]=m_in[0+column*4+m_in_off];
- v_out[1+v_out_off]=m_in[1+column*4+m_in_off];
- v_out[2+v_out_off]=m_in[2+column*4+m_in_off];
- if( v_out.length > 3+v_out_off ) {
- v_out[3+v_out_off]=m_in[3+column*4+m_in_off];
- }
- return v_out;
- }
+ public static float[] multMatrixVec3(final float[] m_in, final float[] v_in, final float[] v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ v_out[0] = v_in[0] * m_in[0*4 ] + v_in[1] * m_in[1*4 ] +
+ v_in[2] * m_in[2*4 ] + 1f * m_in[3*4 ];
+
+ v_out[1] = v_in[0] * m_in[0*4+1] + v_in[1] * m_in[1*4+1] +
+ v_in[2] * m_in[2*4+1] + 1f * m_in[3*4+1];
+
+ v_out[2] = v_in[0] * m_in[0*4+2] + v_in[1] * m_in[1*4+2] +
+ v_in[2] * m_in[2*4+2] + 1f * m_in[3*4+2];
- /**
- * Copy the named row of the given column-major matrix to v_out.
- * <p>
- * v_out may be 3 or 4 components long, hence the 4th column may not be stored.
- * </p>
- * @param m_in input column-major matrix
- * @param m_in_off offset to input matrix
- * @param row named row to copy
- * @param v_out the row-vector storage, at least 3 components long
- * @param v_out_off offset to storage
- * @return given result vector <i>v_out</i> for chaining
- */
- public static float[] copyMatrixRow(final float[] m_in, final int m_in_off, final int row, final float[] v_out, final int v_out_off) {
- v_out[0+v_out_off]=m_in[row+0*4+m_in_off];
- v_out[1+v_out_off]=m_in[row+1*4+m_in_off];
- v_out[2+v_out_off]=m_in[row+2*4+m_in_off];
- if( v_out.length > 3+v_out_off ) {
- v_out[3+v_out_off]=m_in[row+3*4+m_in_off];
- }
return v_out;
}
@@ -1908,11 +1203,11 @@ public final class FloatUtil {
final int a0 = aOffset + a.position();
if(rowMajorOrder) {
for(int c=0; c<columns; c++) {
- sb.append( String.format((Locale)null, f+" ", a.get( a0 + row*columns + c ) ) );
+ sb.append( String.format((Locale)null, f+", ", a.get( a0 + row*columns + c ) ) );
}
} else {
for(int r=0; r<columns; r++) {
- sb.append( String.format((Locale)null, f+" ", a.get( a0 + row + r*rows ) ) );
+ sb.append( String.format((Locale)null, f+", ", a.get( a0 + row + r*rows ) ) );
}
}
return sb;
@@ -1936,11 +1231,11 @@ public final class FloatUtil {
}
if(rowMajorOrder) {
for(int c=0; c<columns; c++) {
- sb.append( String.format((Locale)null, f+" ", a[ aOffset + row*columns + c ] ) );
+ sb.append( String.format((Locale)null, f+", ", a[ aOffset + row*columns + c ] ) );
}
} else {
for(int r=0; r<columns; r++) {
- sb.append( String.format((Locale)null, f+" ", a[ aOffset + row + r*rows ] ) );
+ sb.append( String.format((Locale)null, f+", ", a[ aOffset + row + r*rows ] ) );
}
}
return sb;
@@ -1963,11 +1258,15 @@ public final class FloatUtil {
sb = new StringBuilder();
}
final String prefix = ( null == rowPrefix ) ? "" : rowPrefix;
+ sb.append(prefix).append("{ ");
for(int i=0; i<rows; i++) {
- sb.append(prefix).append("[ ");
+ if( 0 < i ) {
+ sb.append(prefix).append(" ");
+ }
matrixRowToString(sb, f, a, aOffset, rows, columns, rowMajorOrder, i);
- sb.append("]").append(Platform.getNewline());
+ sb.append(System.lineSeparator());
}
+ sb.append(prefix).append("}").append(System.lineSeparator());
return sb;
}
@@ -1988,71 +1287,15 @@ public final class FloatUtil {
sb = new StringBuilder();
}
final String prefix = ( null == rowPrefix ) ? "" : rowPrefix;
+ sb.append(prefix).append("{ ");
for(int i=0; i<rows; i++) {
- sb.append(prefix).append("[ ");
- matrixRowToString(sb, f, a, aOffset, rows, columns, rowMajorOrder, i);
- sb.append("]").append(Platform.getNewline());
- }
- return sb;
- }
-
- /**
- * @param sb optional passed StringBuilder instance to be used
- * @param rowPrefix optional prefix for each row
- * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
- * @param a 4x4 matrix in column major order (OpenGL)
- * @param aOffset offset to <code>a</code>'s current position
- * @param b 4x4 matrix in column major order (OpenGL)
- * @param bOffset offset to <code>a</code>'s current position
- * @param rows
- * @param columns
- * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL)
- * @return side by side representation
- */
- public static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f,
- final FloatBuffer a, final int aOffset, final FloatBuffer b, final int bOffset,
- final int rows, final int columns, final boolean rowMajorOrder) {
- if(null == sb) {
- sb = new StringBuilder();
- }
- final String prefix = ( null == rowPrefix ) ? "" : rowPrefix;
- for(int i=0; i<rows; i++) {
- sb.append(prefix).append("[ ");
- matrixRowToString(sb, f, a, aOffset, rows, columns, rowMajorOrder, i);
- sb.append("=?= ");
- matrixRowToString(sb, f, b, bOffset, rows, columns, rowMajorOrder, i);
- sb.append("]").append(Platform.getNewline());
- }
- return sb;
- }
-
- /**
- * @param sb optional passed StringBuilder instance to be used
- * @param rowPrefix optional prefix for each row
- * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
- * @param a 4x4 matrix in column major order (OpenGL)
- * @param aOffset offset to <code>a</code>'s current position
- * @param b 4x4 matrix in column major order (OpenGL)
- * @param bOffset offset to <code>a</code>'s current position
- * @param rows
- * @param columns
- * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL)
- * @return side by side representation
- */
- public static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f,
- final float[] a, final int aOffset, final float[] b, final int bOffset,
- final int rows, final int columns, final boolean rowMajorOrder) {
- if(null == sb) {
- sb = new StringBuilder();
- }
- final String prefix = ( null == rowPrefix ) ? "" : rowPrefix;
- for(int i=0; i<rows; i++) {
- sb.append(prefix).append("[ ");
+ if( 0 < i ) {
+ sb.append(prefix).append(" ");
+ }
matrixRowToString(sb, f, a, aOffset, rows, columns, rowMajorOrder, i);
- sb.append("=?= ");
- matrixRowToString(sb, f, b, bOffset, rows, columns, rowMajorOrder, i);
- sb.append("]").append(Platform.getNewline());
+ sb.append(System.lineSeparator());
}
+ sb.append(prefix).append("}").append(System.lineSeparator());
return sb;
}
@@ -2121,6 +1364,16 @@ public final class FloatUtil {
/** The value PI^2. */
public final static float SQUARED_PI = PI * PI;
+ /** Converts arc-degree to radians */
+ public static float adegToRad(final float arc_degree) {
+ return arc_degree * PI / 180.0f;
+ }
+
+ /** Converts radians to arc-degree */
+ public static float radToADeg(final float rad) {
+ return rad * 180.0f / PI;
+ }
+
/**
* Epsilon for floating point {@value}, as once computed via {@link #getMachineEpsilon()} on an AMD-64 CPU.
* <p>
@@ -2257,6 +1510,14 @@ public final class FloatUtil {
return Math.abs(a) < epsilon;
}
+ /**
+ * Return true if value is zero, i.e. it's absolute value < {@link #EPSILON}.
+ * @see #EPSILON
+ */
+ public static boolean isZero(final float a) {
+ return Math.abs(a) < FloatUtil.EPSILON;
+ }
+
public static float abs(final float a) { return java.lang.Math.abs(a); }
public static float pow(final float a, final float b) { return (float) java.lang.Math.pow(a, b); }
@@ -2314,10 +1575,10 @@ public final class FloatUtil {
/**
* Returns orthogonal distance
- * (1f/zNear-1f/orthoDist)/(1f/zNear-1f/zFar);
+ * (1f/zNear-1f/orthoZ) / (1f/zNear-1f/zFar);
*/
public static float getOrthoWinZ(final float orthoZ, final float zNear, final float zFar) {
- return (1f/zNear-1f/orthoZ)/(1f/zNear-1f/zFar);
+ return (1f/zNear-1f/orthoZ) / (1f/zNear-1f/zFar);
}
} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java b/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java
deleted file mode 100644
index a080d4442..000000000
--- a/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * Copyright 2014 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
-
-package com.jogamp.opengl.math;
-
-import com.jogamp.opengl.GLException;
-import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
-
-import com.jogamp.opengl.util.PMVMatrix;
-
-/**
- * Simple float array-backed float 4x4 matrix
- * exposing {@link FloatUtil} matrix functionality in an object oriented manner.
- * <p>
- * Unlike {@link PMVMatrix}, this class only represents one single matrix
- * without a complete {@link GLMatrixFunc} implementation,
- * allowing this class to be more lightweight.
- * </p>
- * <p>
- * Implementation is not mature - WIP and subject to change.
- * </p>
- */
-public class Matrix4 {
-
- public Matrix4() {
- matrix = new float[16];
- matrixTxSx = new float[16];
- mat4Tmp1 = new float[16];
- vec4Tmp1 = new float[4];
- FloatUtil.makeIdentity(matrixTxSx);
- loadIdentity();
- }
-
- public final float[] getMatrix() {
- return matrix;
- }
-
- public final void loadIdentity() {
- FloatUtil.makeIdentity(matrix);
- }
-
- /**
- * Multiply matrix: [this] = [this] x [m]
- * @param m 4x4 matrix in column-major order
- */
- public final void multMatrix(final float[] m, final int m_offset) {
- FloatUtil.multMatrix(matrix, 0, m, m_offset);
- }
-
- /**
- * Multiply matrix: [this] = [this] x [m]
- * @param m 4x4 matrix in column-major order
- */
- public final void multMatrix(final float[] m) {
- FloatUtil.multMatrix(matrix, m);
- }
-
- /**
- * Multiply matrix: [this] = [this] x [m]
- * @param m 4x4 matrix in column-major order
- */
- public final void multMatrix(final Matrix4 m) {
- FloatUtil.multMatrix(matrix, m.getMatrix());
- }
-
- /**
- * @param v_in 4-component column-vector
- * @param v_out this * v_in
- */
- public final void multVec(final float[] v_in, final float[] v_out) {
- FloatUtil.multMatrixVec(matrix, v_in, v_out);
- }
-
- /**
- * @param v_in 4-component column-vector
- * @param v_out this * v_in
- */
- public final void multVec(final float[] v_in, final int v_in_offset, final float[] v_out, final int v_out_offset) {
- FloatUtil.multMatrixVec(matrix, 0, v_in, v_in_offset, v_out, v_out_offset);
- }
-
- public final void translate(final float x, final float y, final float z) {
- multMatrix(FloatUtil.makeTranslation(matrixTxSx, false, x, y, z));
- }
-
- public final void scale(final float x, final float y, final float z) {
- multMatrix(FloatUtil.makeScale(matrixTxSx, false, x, y, z));
- }
-
- public final void rotate(final float angrad, final float x, final float y, final float z) {
- multMatrix(FloatUtil.makeRotationAxis(mat4Tmp1, 0, angrad, x, y, z, vec4Tmp1));
- }
-
- /**
- * Rotate the current matrix with the given {@link Quaternion}'s rotation {@link Quaternion#toMatrix(float[], int) matrix representation}.
- */
- public final void rotate(final Quaternion quat) {
- multMatrix(quat.toMatrix(mat4Tmp1, 0));
- }
-
- public final void transpose() {
- System.arraycopy(matrix, 0, mat4Tmp1, 0, 16);
- FloatUtil.transposeMatrix(mat4Tmp1, matrix);
- }
-
- public final float determinant() {
- return FloatUtil.matrixDeterminant(matrix);
- }
-
- public final boolean invert() {
- return null != FloatUtil.invertMatrix(matrix, matrix);
- }
-
- public final void makeOrtho(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) {
- multMatrix( FloatUtil.makeOrtho(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar) );
- }
-
- /**
- * @param left
- * @param right
- * @param bottom
- * @param top
- * @param zNear
- * @param zFar
- * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear}
- * or {@code left == right}, or {@code bottom == top}.
- * @see FloatUtil#makeFrustum(float[], int, boolean, float, float, float, float, float, float)
- */
- public final void makeFrustum(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) throws GLException {
- multMatrix( FloatUtil.makeFrustum(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar) );
- }
-
- /**
- * @param fovy_rad
- * @param aspect
- * @param zNear
- * @param zFar
- * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear}
- * @see FloatUtil#makePerspective(float[], int, boolean, float, float, float, float)
- */
- public final void makePerspective(final float fovy_rad, final float aspect, final float zNear, final float zFar) throws GLException {
- multMatrix( FloatUtil.makePerspective(mat4Tmp1, 0, true, fovy_rad, aspect, zNear, zFar) );
- }
-
- private final float[] matrix, matrixTxSx;
- private final float[] mat4Tmp1, vec4Tmp1;
-}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Matrix4f.java b/src/jogl/classes/com/jogamp/opengl/math/Matrix4f.java
new file mode 100644
index 000000000..77971b72d
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/math/Matrix4f.java
@@ -0,0 +1,2153 @@
+/**
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.math;
+
+import java.nio.FloatBuffer;
+
+import com.jogamp.opengl.math.geom.AABBox;
+import com.jogamp.opengl.math.geom.Frustum;
+import com.jogamp.opengl.math.geom.Frustum.Plane;
+
+/**
+ * Basic 4x4 float matrix implementation using fields for intensive use-cases (host operations).
+ * <p>
+ * Implementation covers {@link FloatUtil} matrix functionality, exposed in an object oriented manner.
+ * </p>
+ * <p>
+ * Unlike {@link com.jogamp.opengl.util.PMVMatrix PMVMatrix}, this class only represents one single matrix
+ * without a complete {@link com.jogamp.opengl.fixedfunc.GLMatrixFunc GLMatrixFunc} implementation.
+ * </p>
+ * <p>
+ * For array operations the layout is expected in column-major order
+ * matching OpenGL's implementation, illustration:
+ * <pre>
+ Row-Major Column-Major (OpenGL):
+
+ | 0 1 2 tx |
+ | |
+ | 4 5 6 ty |
+ M = | |
+ | 8 9 10 tz |
+ | |
+ | 12 13 14 15 |
+
+ R C R C
+ m[0*4+3] = tx; m[0+4*3] = tx;
+ m[1*4+3] = ty; m[1+4*3] = ty;
+ m[2*4+3] = tz; m[2+4*3] = tz;
+
+ RC (std subscript order) RC (std subscript order)
+ m03 = tx; m03 = tx;
+ m13 = ty; m13 = ty;
+ m23 = tz; m23 = tz;
+
+ * </pre>
+ * </p>
+ * <p>
+ * <ul>
+ * <li><a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix-FAQ</a></li>
+ * <li><a href="https://en.wikipedia.org/wiki/Matrix_%28mathematics%29">Wikipedia-Matrix</a></li>
+ * <li><a href="http://www.euclideanspace.com/maths/algebra/matrix/index.htm">euclideanspace.com-Matrix</a></li>
+ * </ul>
+ * </p>
+ * <p>
+ * Implementation utilizes unrolling of small vertices and matrices wherever possible
+ * while trying to access memory in a linear fashion for performance reasons, see:
+ * <ul>
+ * <li><a href="https://lessthanoptimal.github.io/Java-Matrix-Benchmark/">java-matrix-benchmark</a></li>
+ * <li><a href="https://github.com/lessthanoptimal/ejml">EJML Efficient Java Matrix Library</a></li>
+ * </ul>
+ * </p>
+ * @see com.jogamp.opengl.util.PMVMatrix
+ * @see FloatUtil
+ */
+public class Matrix4f {
+
+ /**
+ * Creates a new identity matrix.
+ */
+ public Matrix4f() {
+ m00 = m11 = m22 = m33 = 1.0f;
+ // remaining fields have default init to zero
+ }
+
+ /**
+ * Creates a new matrix copying the values of the given {@code src} matrix.
+ */
+ public Matrix4f(final Matrix4f src) {
+ load(src);
+ }
+
+ /**
+ * Creates a new matrix based on given float[4*4] column major order.
+ * @param m 4x4 matrix in column-major order
+ */
+ public Matrix4f(final float[] m) {
+ load(m);
+ }
+
+ /**
+ * Creates a new matrix based on given float[4*4] column major order.
+ * @param m 4x4 matrix in column-major order
+ * @param m_off offset for matrix {@code m}
+ */
+ public Matrix4f(final float[] m, final int m_off) {
+ load(m, m_off);
+ }
+
+ /**
+ * Creates a new matrix based on given {@link FloatBuffer} 4x4 column major order.
+ * @param m 4x4 matrix in column-major order
+ */
+ public Matrix4f(final FloatBuffer m) {
+ load(m);
+ }
+
+ //
+ // Write to Matrix via set(..) or load(..)
+ //
+
+ /** Sets the {@code i}th component with float {@code v} 0 <= i < 16 */
+ public void set(final int i, final float v) {
+ switch (i) {
+ case 0+4*0: m00 = v; break;
+ case 1+4*0: m10 = v; break;
+ case 2+4*0: m20 = v; break;
+ case 3+4*0: m30 = v; break;
+
+ case 0+4*1: m01 = v; break;
+ case 1+4*1: m11 = v; break;
+ case 2+4*1: m21 = v; break;
+ case 3+4*1: m31 = v; break;
+
+ case 0+4*2: m02 = v; break;
+ case 1+4*2: m12 = v; break;
+ case 2+4*2: m22 = v; break;
+ case 3+4*2: m32 = v; break;
+
+ case 0+4*3: m03 = v; break;
+ case 1+4*3: m13 = v; break;
+ case 2+4*3: m23 = v; break;
+ case 3+4*3: m33 = v; break;
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Set this matrix to identity.
+ * <pre>
+ Translation matrix (Column Order):
+ 1 0 0 0
+ 0 1 0 0
+ 0 0 1 0
+ 0 0 0 1
+ * </pre>
+ * @return this matrix for chaining
+ */
+ public final Matrix4f loadIdentity() {
+ m00 = m11 = m22 = m33 = 1.0f;
+ m01 = m02 = m03 =
+ m10 = m12 = m13 =
+ m20 = m21 = m23 =
+ m30 = m31 = m32 = 0.0f;
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code b} to this matrix.
+ * @param src the source values
+ * @return this matrix for chaining
+ */
+ public Matrix4f load(final Matrix4f src) {
+ m00 = src.m00; m10 = src.m10; m20 = src.m20; m30 = src.m30;
+ m01 = src.m01; m11 = src.m11; m21 = src.m21; m31 = src.m31;
+ m02 = src.m02; m12 = src.m12; m22 = src.m22; m32 = src.m32;
+ m03 = src.m03; m13 = src.m13; m23 = src.m23; m33 = src.m33;
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code src} to this matrix.
+ * @param src 4x4 matrix float[16] in column-major order
+ * @return this matrix for chaining
+ */
+ public Matrix4f load(final float[] src) {
+ m00 = src[0+0*4]; // column 0
+ m10 = src[1+0*4];
+ m20 = src[2+0*4];
+ m30 = src[3+0*4];
+ m01 = src[0+1*4]; // column 1
+ m11 = src[1+1*4];
+ m21 = src[2+1*4];
+ m31 = src[3+1*4];
+ m02 = src[0+2*4]; // column 2
+ m12 = src[1+2*4];
+ m22 = src[2+2*4];
+ m32 = src[3+2*4];
+ m03 = src[0+3*4]; // column 3
+ m13 = src[1+3*4];
+ m23 = src[2+3*4];
+ m33 = src[3+3*4];
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code src} to this matrix.
+ * @param src 4x4 matrix float[16] in column-major order
+ * @param src_off offset for matrix {@code src}
+ * @return this matrix for chaining
+ */
+ public Matrix4f load(final float[] src, final int src_off) {
+ m00 = src[src_off+0+0*4];
+ m10 = src[src_off+1+0*4];
+ m20 = src[src_off+2+0*4];
+ m30 = src[src_off+3+0*4];
+ m01 = src[src_off+0+1*4];
+ m11 = src[src_off+1+1*4];
+ m21 = src[src_off+2+1*4];
+ m31 = src[src_off+3+1*4];
+ m02 = src[src_off+0+2*4];
+ m12 = src[src_off+1+2*4];
+ m22 = src[src_off+2+2*4];
+ m32 = src[src_off+3+2*4];
+ m03 = src[src_off+0+3*4];
+ m13 = src[src_off+1+3*4];
+ m23 = src[src_off+2+3*4];
+ m33 = src[src_off+3+3*4];
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code src} to this matrix.
+ * <p>
+ * Implementation uses relative {@link FloatBuffer#get()},
+ * hence caller may want to issue {@link FloatBuffer#reset()} thereafter.
+ * </p>
+ * @param src 4x4 matrix {@link FloatBuffer} in column-major order
+ * @return this matrix for chaining
+ */
+ public Matrix4f load(final FloatBuffer src) {
+ m00 = src.get();
+ m10 = src.get();
+ m20 = src.get();
+ m30 = src.get();
+ m01 = src.get();
+ m11 = src.get();
+ m21 = src.get();
+ m31 = src.get();
+ m02 = src.get();
+ m12 = src.get();
+ m22 = src.get();
+ m32 = src.get();
+ m03 = src.get();
+ m13 = src.get();
+ m23 = src.get();
+ m33 = src.get();
+ return this;
+ }
+
+ //
+ // Read out Matrix via get(..)
+ //
+
+ /** Gets the {@code i}th component, 0 <= i < 16 */
+ public float get(final int i) {
+ switch (i) {
+ case 0+4*0: return m00;
+ case 1+4*0: return m10;
+ case 2+4*0: return m20;
+ case 3+4*0: return m30;
+
+ case 0+4*1: return m01;
+ case 1+4*1: return m11;
+ case 2+4*1: return m21;
+ case 3+4*1: return m31;
+
+ case 0+4*2: return m02;
+ case 1+4*2: return m12;
+ case 2+4*2: return m22;
+ case 3+4*2: return m32;
+
+ case 0+4*3: return m03;
+ case 1+4*3: return m13;
+ case 2+4*3: return m23;
+ case 3+4*3: return m33;
+
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Get the named column of the given column-major matrix to v_out.
+ * @param column named column to copy
+ * @param v_out the column-vector storage
+ * @return given result vector <i>v_out</i> for chaining
+ */
+ public Vec4f getColumn(final int column, final Vec4f v_out) {
+ v_out.set( get(0+column*4),
+ get(1+column*4),
+ get(2+column*4),
+ get(3+column*4) );
+ return v_out;
+ }
+
+ /**
+ * Get the named column of the given column-major matrix to v_out.
+ * @param column named column to copy
+ * @param v_out the column-vector storage
+ * @return given result vector <i>v_out</i> for chaining
+ */
+ public Vec3f getColumn(final int column, final Vec3f v_out) {
+ v_out.set( get(0+column*4),
+ get(1+column*4),
+ get(2+column*4) );
+ return v_out;
+ }
+
+ /**
+ * Get the named row of the given column-major matrix to v_out.
+ * @param row named row to copy
+ * @param v_out the row-vector storage
+ * @return given result vector <i>v_out</i> for chaining
+ */
+ public Vec4f getRow(final int row, final Vec4f v_out) {
+ v_out.set( get(row+0*4),
+ get(row+1*4),
+ get(row+2*4),
+ get(row+3*4) );
+ return v_out;
+ }
+
+ /**
+ * Get the named row of the given column-major matrix to v_out.
+ * @param row named row to copy
+ * @param v_out the row-vector storage
+ * @return given result vector <i>v_out</i> for chaining
+ */
+ public Vec3f getRow(final int row, final Vec3f v_out) {
+ v_out.set( get(row+0*4),
+ get(row+1*4),
+ get(row+2*4) );
+ return v_out;
+ }
+
+ /**
+ * Get this matrix into the given float[16] array at {@code dst_off} in column major order.
+ *
+ * @param dst float[16] array storage in column major order
+ * @param dst_off offset
+ * @return {@code dst} for chaining
+ */
+ public float[] get(final float[] dst, final int dst_off) {
+ dst[dst_off+0+0*4] = m00;
+ dst[dst_off+1+0*4] = m10;
+ dst[dst_off+2+0*4] = m20;
+ dst[dst_off+3+0*4] = m30;
+ dst[dst_off+0+1*4] = m01;
+ dst[dst_off+1+1*4] = m11;
+ dst[dst_off+2+1*4] = m21;
+ dst[dst_off+3+1*4] = m31;
+ dst[dst_off+0+2*4] = m02;
+ dst[dst_off+1+2*4] = m12;
+ dst[dst_off+2+2*4] = m22;
+ dst[dst_off+3+2*4] = m32;
+ dst[dst_off+0+3*4] = m03;
+ dst[dst_off+1+3*4] = m13;
+ dst[dst_off+2+3*4] = m23;
+ dst[dst_off+3+3*4] = m33;
+ return dst;
+ }
+
+ /**
+ * Get this matrix into the given float[16] array in column major order.
+ *
+ * @param dst float[16] array storage in column major order
+ * @return {@code dst} for chaining
+ */
+ public float[] get(final float[] dst) {
+ dst[0+0*4] = m00;
+ dst[1+0*4] = m10;
+ dst[2+0*4] = m20;
+ dst[3+0*4] = m30;
+ dst[0+1*4] = m01;
+ dst[1+1*4] = m11;
+ dst[2+1*4] = m21;
+ dst[3+1*4] = m31;
+ dst[0+2*4] = m02;
+ dst[1+2*4] = m12;
+ dst[2+2*4] = m22;
+ dst[3+2*4] = m32;
+ dst[0+3*4] = m03;
+ dst[1+3*4] = m13;
+ dst[2+3*4] = m23;
+ dst[3+3*4] = m33;
+ return dst;
+ }
+
+ /**
+ * Get this matrix into the given {@link FloatBuffer} in column major order.
+ * <p>
+ * Implementation uses relative {@link FloatBuffer#put(float)},
+ * hence caller may want to issue {@link FloatBuffer#reset()} thereafter.
+ * </p>
+ *
+ * @param dst {@link FloatBuffer} array storage in column major order
+ * @return {@code dst} for chaining
+ */
+ public FloatBuffer get(final FloatBuffer dst) {
+ dst.put( m00 );
+ dst.put( m10 );
+ dst.put( m20 );
+ dst.put( m30 );
+ dst.put( m01 );
+ dst.put( m11 );
+ dst.put( m21 );
+ dst.put( m31 );
+ dst.put( m02 );
+ dst.put( m12 );
+ dst.put( m22 );
+ dst.put( m32 );
+ dst.put( m03 );
+ dst.put( m13 );
+ dst.put( m23 );
+ dst.put( m33 );
+ return dst;
+ }
+
+ //
+ // Basic matrix operations
+ //
+
+ /**
+ * Returns the determinant of this matrix
+ * @return the matrix determinant
+ */
+ public float determinant() {
+ float ret = 0;
+ ret += m00 * ( + m11*(m22*m33 - m23*m32) - m12*(m21*m33 - m23*m31) + m13*(m21*m32 - m22*m31));
+ ret -= m01 * ( + m10*(m22*m33 - m23*m32) - m12*(m20*m33 - m23*m30) + m13*(m20*m32 - m22*m30));
+ ret += m02 * ( + m10*(m21*m33 - m23*m31) - m11*(m20*m33 - m23*m30) + m13*(m20*m31 - m21*m30));
+ ret -= m03 * ( + m10*(m21*m32 - m22*m31) - m11*(m20*m32 - m22*m30) + m12*(m20*m31 - m21*m30));
+ return ret;
+ }
+
+ /**
+ * Transpose this matrix.
+ *
+ * @return this matrix for chaining
+ */
+ public final Matrix4f transpose() {
+ float tmp;
+
+ tmp = m10;
+ m10 = m01;
+ m01 = tmp;
+
+ tmp = m20;
+ m20 = m02;
+ m02 = tmp;
+
+ tmp = m30;
+ m30 = m03;
+ m03 = tmp;
+
+ tmp = m21;
+ m21 = m12;
+ m12 = tmp;
+
+ tmp = m31;
+ m31 = m13;
+ m13 = tmp;
+
+ tmp = m32;
+ m32 = m23;
+ m23 = tmp;
+
+ return this;
+ }
+
+ /**
+ * Transpose the given {@code src} matrix into this matrix.
+ *
+ * @param src source 4x4 matrix
+ * @return this matrix (result) for chaining
+ */
+ public final Matrix4f transpose(final Matrix4f src) {
+ if( src == this ) {
+ return transpose();
+ }
+ m00 = src.m00;
+ m10 = src.m01;
+ m20 = src.m02;
+ m30 = src.m03;
+
+ m01 = src.m10;
+ m11 = src.m11;
+ m21 = src.m12;
+ m31 = src.m13;
+
+ m02 = src.m20;
+ m12 = src.m21;
+ m22 = src.m22;
+ m32 = src.m23;
+
+ m03 = src.m30;
+ m13 = src.m31;
+ m23 = src.m32;
+ m33 = src.m33;
+ return this;
+ }
+
+ /**
+ * Invert this matrix.
+ * @return false if this matrix is singular and inversion not possible, otherwise true
+ */
+ public boolean invert() {
+ final float scale;
+ try {
+ scale = mulScale();
+ } catch(final ArithmeticException aex) {
+ return false; // max was 0
+ }
+ final float a00 = m00*scale;
+ final float a10 = m10*scale;
+ final float a20 = m20*scale;
+ final float a30 = m30*scale;
+
+ final float a01 = m01*scale;
+ final float a11 = m11*scale;
+ final float a21 = m21*scale;
+ final float a31 = m31*scale;
+
+ final float a02 = m02*scale;
+ final float a12 = m12*scale;
+ final float a22 = m22*scale;
+ final float a32 = m32*scale;
+
+ final float a03 = m03*scale;
+ final float a13 = m13*scale;
+ final float a23 = m23*scale;
+ final float a33 = m33*scale;
+
+ final float b00 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31);
+ final float b01 = -( + a10*(a22*a33 - a23*a32) - a12*(a20*a33 - a23*a30) + a13*(a20*a32 - a22*a30));
+ final float b02 = + a10*(a21*a33 - a23*a31) - a11*(a20*a33 - a23*a30) + a13*(a20*a31 - a21*a30);
+ final float b03 = -( + a10*(a21*a32 - a22*a31) - a11*(a20*a32 - a22*a30) + a12*(a20*a31 - a21*a30));
+
+ final float b10 = -( + a01*(a22*a33 - a23*a32) - a02*(a21*a33 - a23*a31) + a03*(a21*a32 - a22*a31));
+ final float b11 = + a00*(a22*a33 - a23*a32) - a02*(a20*a33 - a23*a30) + a03*(a20*a32 - a22*a30);
+ final float b12 = -( + a00*(a21*a33 - a23*a31) - a01*(a20*a33 - a23*a30) + a03*(a20*a31 - a21*a30));
+ final float b13 = + a00*(a21*a32 - a22*a31) - a01*(a20*a32 - a22*a30) + a02*(a20*a31 - a21*a30);
+
+ final float b20 = + a01*(a12*a33 - a13*a32) - a02*(a11*a33 - a13*a31) + a03*(a11*a32 - a12*a31);
+ final float b21 = -( + a00*(a12*a33 - a13*a32) - a02*(a10*a33 - a13*a30) + a03*(a10*a32 - a12*a30));
+ final float b22 = + a00*(a11*a33 - a13*a31) - a01*(a10*a33 - a13*a30) + a03*(a10*a31 - a11*a30);
+ final float b23 = -( + a00*(a11*a32 - a12*a31) - a01*(a10*a32 - a12*a30) + a02*(a10*a31 - a11*a30));
+
+ final float b30 = -( + a01*(a12*a23 - a13*a22) - a02*(a11*a23 - a13*a21) + a03*(a11*a22 - a12*a21));
+ final float b31 = + a00*(a12*a23 - a13*a22) - a02*(a10*a23 - a13*a20) + a03*(a10*a22 - a12*a20);
+ final float b32 = -( + a00*(a11*a23 - a13*a21) - a01*(a10*a23 - a13*a20) + a03*(a10*a21 - a11*a20));
+ final float b33 = + a00*(a11*a22 - a12*a21) - a01*(a10*a22 - a12*a20) + a02*(a10*a21 - a11*a20);
+
+ final float det = (a00*b00 + a01*b01 + a02*b02 + a03*b03) / scale;
+ if( 0 == det ) {
+ return false;
+ }
+ final float invdet = 1.0f / det;
+
+ m00 = b00 * invdet;
+ m10 = b01 * invdet;
+ m20 = b02 * invdet;
+ m30 = b03 * invdet;
+
+ m01 = b10 * invdet;
+ m11 = b11 * invdet;
+ m21 = b12 * invdet;
+ m31 = b13 * invdet;
+
+ m02 = b20 * invdet;
+ m12 = b21 * invdet;
+ m22 = b22 * invdet;
+ m32 = b23 * invdet;
+
+ m03 = b30 * invdet;
+ m13 = b31 * invdet;
+ m23 = b32 * invdet;
+ m33 = b33 * invdet;
+ return true;
+ }
+
+ /**
+ * Invert the {@code src} matrix values into this matrix
+ * @param src the source matrix, which values are to be inverted
+ * @return false if {@code src} matrix is singular and inversion not possible, otherwise true
+ */
+ public boolean invert(final Matrix4f src) {
+ final float scale;
+ try {
+ scale = src.mulScale();
+ } catch(final ArithmeticException aex) {
+ return false; // max was 0
+ }
+ final float a00 = src.m00*scale;
+ final float a10 = src.m10*scale;
+ final float a20 = src.m20*scale;
+ final float a30 = src.m30*scale;
+
+ final float a01 = src.m01*scale;
+ final float a11 = src.m11*scale;
+ final float a21 = src.m21*scale;
+ final float a31 = src.m31*scale;
+
+ final float a02 = src.m02*scale;
+ final float a12 = src.m12*scale;
+ final float a22 = src.m22*scale;
+ final float a32 = src.m32*scale;
+
+ final float a03 = src.m03*scale;
+ final float a13 = src.m13*scale;
+ final float a23 = src.m23*scale;
+ final float a33 = src.m33*scale;
+
+ final float b00 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31);
+ final float b01 = -( + a10*(a22*a33 - a23*a32) - a12*(a20*a33 - a23*a30) + a13*(a20*a32 - a22*a30));
+ final float b02 = + a10*(a21*a33 - a23*a31) - a11*(a20*a33 - a23*a30) + a13*(a20*a31 - a21*a30);
+ final float b03 = -( + a10*(a21*a32 - a22*a31) - a11*(a20*a32 - a22*a30) + a12*(a20*a31 - a21*a30));
+
+ final float b10 = -( + a01*(a22*a33 - a23*a32) - a02*(a21*a33 - a23*a31) + a03*(a21*a32 - a22*a31));
+ final float b11 = + a00*(a22*a33 - a23*a32) - a02*(a20*a33 - a23*a30) + a03*(a20*a32 - a22*a30);
+ final float b12 = -( + a00*(a21*a33 - a23*a31) - a01*(a20*a33 - a23*a30) + a03*(a20*a31 - a21*a30));
+ final float b13 = + a00*(a21*a32 - a22*a31) - a01*(a20*a32 - a22*a30) + a02*(a20*a31 - a21*a30);
+
+ final float b20 = + a01*(a12*a33 - a13*a32) - a02*(a11*a33 - a13*a31) + a03*(a11*a32 - a12*a31);
+ final float b21 = -( + a00*(a12*a33 - a13*a32) - a02*(a10*a33 - a13*a30) + a03*(a10*a32 - a12*a30));
+ final float b22 = + a00*(a11*a33 - a13*a31) - a01*(a10*a33 - a13*a30) + a03*(a10*a31 - a11*a30);
+ final float b23 = -( + a00*(a11*a32 - a12*a31) - a01*(a10*a32 - a12*a30) + a02*(a10*a31 - a11*a30));
+
+ final float b30 = -( + a01*(a12*a23 - a13*a22) - a02*(a11*a23 - a13*a21) + a03*(a11*a22 - a12*a21));
+ final float b31 = + a00*(a12*a23 - a13*a22) - a02*(a10*a23 - a13*a20) + a03*(a10*a22 - a12*a20);
+ final float b32 = -( + a00*(a11*a23 - a13*a21) - a01*(a10*a23 - a13*a20) + a03*(a10*a21 - a11*a20));
+ final float b33 = + a00*(a11*a22 - a12*a21) - a01*(a10*a22 - a12*a20) + a02*(a10*a21 - a11*a20);
+
+ final float det = (a00*b00 + a01*b01 + a02*b02 + a03*b03) / scale;
+
+ if( 0 == det ) {
+ return false;
+ }
+ final float invdet = 1.0f / det;
+
+ m00 = b00 * invdet;
+ m10 = b01 * invdet;
+ m20 = b02 * invdet;
+ m30 = b03 * invdet;
+
+ m01 = b10 * invdet;
+ m11 = b11 * invdet;
+ m21 = b12 * invdet;
+ m31 = b13 * invdet;
+
+ m02 = b20 * invdet;
+ m12 = b21 * invdet;
+ m22 = b22 * invdet;
+ m32 = b23 * invdet;
+
+ m03 = b30 * invdet;
+ m13 = b31 * invdet;
+ m23 = b32 * invdet;
+ m33 = b33 * invdet;
+ return true;
+ }
+
+ private final float mulScale() {
+ /**
+ // No Hotspot intrinsic Math.* optimization for at least Math.max(),
+ // hence this chunk is slower.
+ float max = Math.abs(m00);
+
+ max = Math.max(max, Math.abs(m01));
+ max = Math.max(max, Math.abs(m02));
+ ... etc
+ */
+ float a = Math.abs(m00);
+ float max = a;
+ a = Math.abs(m01); if( a > max ) max = a;
+ a = Math.abs(m02); if( a > max ) max = a;
+ a = Math.abs(m03); if( a > max ) max = a;
+
+ a = Math.abs(m10); if( a > max ) max = a;
+ a = Math.abs(m11); if( a > max ) max = a;
+ a = Math.abs(m12); if( a > max ) max = a;
+ a = Math.abs(m13); if( a > max ) max = a;
+
+ a = Math.abs(m20); if( a > max ) max = a;
+ a = Math.abs(m21); if( a > max ) max = a;
+ a = Math.abs(m22); if( a > max ) max = a;
+ a = Math.abs(m23); if( a > max ) max = a;
+
+ a = Math.abs(m30); if( a > max ) max = a;
+ a = Math.abs(m31); if( a > max ) max = a;
+ a = Math.abs(m32); if( a > max ) max = a;
+ a = Math.abs(m33); if( a > max ) max = a;
+
+ return 1.0f/max;
+ }
+
+ /**
+ * Multiply matrix: [this] = [this] x [b]
+ * @param b 4x4 matrix
+ * @return this matrix for chaining
+ * @see #mul(Matrix4f, Matrix4f)
+ */
+ public final Matrix4f mul(final Matrix4f b) {
+ // return mul(new Matrix4f(this), b); // <- roughly half speed
+ float ai0=m00; // row-0, m[0+0*4]
+ float ai1=m01;
+ float ai2=m02;
+ float ai3=m03;
+ m00 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ;
+ m01 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ;
+ m02 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ;
+ m03 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ;
+
+ ai0=m10; //row-1, m[1+0*4]
+ ai1=m11;
+ ai2=m12;
+ ai3=m13;
+ m10 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ;
+ m11 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ;
+ m12 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ;
+ m13 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ;
+
+ ai0=m20; // row-2, m[2+0*4]
+ ai1=m21;
+ ai2=m22;
+ ai3=m23;
+ m20 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ;
+ m21 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ;
+ m22 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ;
+ m23 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ;
+
+ ai0=m30; // row-3, m[3+0*4]
+ ai1=m31;
+ ai2=m32;
+ ai3=m33;
+ m30 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ;
+ m31 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ;
+ m32 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ;
+ m33 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ;
+ return this;
+ }
+
+ /**
+ * Multiply matrix: [this] = [a] x [b]
+ * @param a 4x4 matrix, can't be this matrix
+ * @param b 4x4 matrix, can't be this matrix
+ * @return this matrix for chaining
+ * @see #mul(Matrix4f)
+ */
+ public final Matrix4f mul(final Matrix4f a, final Matrix4f b) {
+ // row-0, m[0+0*4]
+ m00 = a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20 + a.m03 * b.m30 ;
+ m01 = a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21 + a.m03 * b.m31 ;
+ m02 = a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22 + a.m03 * b.m32 ;
+ m03 = a.m00 * b.m03 + a.m01 * b.m13 + a.m02 * b.m23 + a.m03 * b.m33 ;
+
+ //row-1, m[1+0*4]
+ m10 = a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20 + a.m13 * b.m30 ;
+ m11 = a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31 ;
+ m12 = a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32 ;
+ m13 = a.m10 * b.m03 + a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33 ;
+
+ // row-2, m[2+0*4]
+ m20 = a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20 + a.m23 * b.m30 ;
+ m21 = a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31 ;
+ m22 = a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32 ;
+ m23 = a.m20 * b.m03 + a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33 ;
+
+ // row-3, m[3+0*4]
+ m30 = a.m30 * b.m00 + a.m31 * b.m10 + a.m32 * b.m20 + a.m33 * b.m30 ;
+ m31 = a.m30 * b.m01 + a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31 ;
+ m32 = a.m30 * b.m02 + a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32 ;
+ m33 = a.m30 * b.m03 + a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33 ;
+
+ return this;
+ }
+
+ /**
+ * @param v_in 4-component column-vector, can be v_out for in-place transformation
+ * @param v_out this * v_in
+ * @returns v_out for chaining
+ */
+ public final Vec4f mulVec4f(final Vec4f v_in, final Vec4f v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_in.x(), y = v_in.y(), z = v_in.z(), w = v_in.w();
+ v_out.set( x * m00 + y * m01 + z * m02 + w * m03,
+ x * m10 + y * m11 + z * m12 + w * m13,
+ x * m20 + y * m21 + z * m22 + w * m23,
+ x * m30 + y * m31 + z * m32 + w * m33 );
+ return v_out;
+ }
+
+ /**
+ * @param v_inout 4-component column-vector input and output, i.e. in-place transformation
+ * @returns v_inout for chaining
+ */
+ public final Vec4f mulVec4f(final Vec4f v_inout) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_inout.x(), y = v_inout.y(), z = v_inout.z(), w = v_inout.w();
+ v_inout.set( x * m00 + y * m01 + z * m02 + w * m03,
+ x * m10 + y * m11 + z * m12 + w * m13,
+ x * m20 + y * m21 + z * m22 + w * m23,
+ x * m30 + y * m31 + z * m32 + w * m33 );
+ return v_inout;
+ }
+
+ /**
+ * Affine 3f-vector transformation by 4x4 matrix
+ *
+ * 4x4 matrix multiplication with 3-component vector,
+ * using {@code 1} for for {@code v_in.w()} and dropping {@code v_out.w()},
+ * which shall be {@code 1}.
+ *
+ * @param v_in 3-component column-vector {@link Vec3f}, can be v_out for in-place transformation
+ * @param v_out m_in * v_in, 3-component column-vector {@link Vec3f}
+ * @returns v_out for chaining
+ */
+ public final Vec3f mulVec3f(final Vec3f v_in, final Vec3f v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_in.x(), y = v_in.y(), z = v_in.z();
+ v_out.set( x * m00 + y * m01 + z * m02 + 1f * m03,
+ x * m10 + y * m11 + z * m12 + 1f * m13,
+ x * m20 + y * m21 + z * m22 + 1f * m23 );
+ return v_out;
+ }
+
+ /**
+ * Affine 3f-vector transformation by 4x4 matrix
+ *
+ * 4x4 matrix multiplication with 3-component vector,
+ * using {@code 1} for for {@code v_inout.w()} and dropping {@code v_inout.w()},
+ * which shall be {@code 1}.
+ *
+ * @param v_inout 3-component column-vector {@link Vec3f} input and output, i.e. in-place transformation
+ * @returns v_inout for chaining
+ */
+ public final Vec3f mulVec3f(final Vec3f v_inout) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_inout.x(), y = v_inout.y(), z = v_inout.z();
+ v_inout.set( x * m00 + y * m01 + z * m02 + 1f * m03,
+ x * m10 + y * m11 + z * m12 + 1f * m13,
+ x * m20 + y * m21 + z * m22 + 1f * m23 );
+ return v_inout;
+ }
+
+ //
+ // Matrix setTo...(), affine + basic
+ //
+
+ /**
+ * Set this matrix to translation.
+ * <pre>
+ Translation matrix (Column Order):
+ 1 0 0 0
+ 0 1 0 0
+ 0 0 1 0
+ x y z 1
+ * </pre>
+ * @param x x-axis translate
+ * @param y y-axis translate
+ * @param z z-axis translate
+ * @return this matrix for chaining
+ */
+ public final Matrix4f setToTranslation(final float x, final float y, final float z) {
+ m00 = m11 = m22 = m33 = 1.0f;
+ m03 = x;
+ m13 = y;
+ m23 = z;
+ m01 = m02 =
+ m10 = m12 =
+ m20 = m21 =
+ m30 = m31 = m32 = 0.0f;
+ return this;
+ }
+
+ /**
+ * Set this matrix to translation.
+ * <pre>
+ Translation matrix (Column Order):
+ 1 0 0 0
+ 0 1 0 0
+ 0 0 1 0
+ x y z 1
+ * </pre>
+ * @param t translate Vec3f
+ * @return this matrix for chaining
+ */
+ public final Matrix4f setToTranslation(final Vec3f t) {
+ return setToTranslation(t.x(), t.y(), t.z());
+ }
+
+ /**
+ * Set this matrix to scale.
+ * <pre>
+ Scale matrix (Any Order):
+ x 0 0 0
+ 0 y 0 0
+ 0 0 z 0
+ 0 0 0 1
+ * </pre>
+ * @param x x-axis scale
+ * @param y y-axis scale
+ * @param z z-axis scale
+ * @return this matrix for chaining
+ */
+ public final Matrix4f setToScale(final float x, final float y, final float z) {
+ m33 = 1.0f;
+ m00 = x;
+ m11 = y;
+ m22 = z;
+ m01 = m02 = m03 =
+ m10 = m12 = m13 =
+ m20 = m21 = m23 =
+ m30 = m31 = m32 = 0.0f;
+ return this;
+ }
+
+ /**
+ * Set this matrix to scale.
+ * <pre>
+ Scale matrix (Any Order):
+ x 0 0 0
+ 0 y 0 0
+ 0 0 z 0
+ 0 0 0 1
+ * </pre>
+ * @param s scale Vec3f
+ * @return this matrix for chaining
+ */
+ public final Matrix4f setToScale(final Vec3f s) {
+ return setToScale(s.x(), s.y(), s.z());
+ }
+
+ /**
+ * Set this matrix to rotation from the given axis and angle in radians.
+ * <pre>
+ Rotation matrix (Column Order):
+ xx(1-c)+c xy(1-c)+zs xz(1-c)-ys 0
+ xy(1-c)-zs yy(1-c)+c yz(1-c)+xs 0
+ xz(1-c)+ys yz(1-c)-xs zz(1-c)+c 0
+ 0 0 0 1
+ * </pre>
+ * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a>
+ * @param ang_rad angle in radians
+ * @param x x of rotation axis
+ * @param y y of rotation axis
+ * @param z z of rotation axis
+ * @return this matrix for chaining
+ */
+ public final Matrix4f setToRotationAxis(final float ang_rad, float x, float y, float z) {
+ final float c = FloatUtil.cos(ang_rad);
+ final float ic= 1.0f - c;
+ final float s = FloatUtil.sin(ang_rad);
+
+ final Vec3f tmp = new Vec3f(x, y, z).normalize();
+ x = tmp.x(); y = tmp.y(); z = tmp.z();
+
+ final float xy = x*y;
+ final float xz = x*z;
+ final float xs = x*s;
+ final float ys = y*s;
+ final float yz = y*z;
+ final float zs = z*s;
+ m00 = x*x*ic+c;
+ m10 = xy*ic+zs;
+ m20 = xz*ic-ys;
+ m30 = 0;
+
+ m01 = xy*ic-zs;
+ m11 = y*y*ic+c;
+ m21 = yz*ic+xs;
+ m31 = 0;
+
+ m02 = xz*ic+ys;
+ m12 = yz*ic-xs;
+ m22 = z*z*ic+c;
+ m32 = 0;
+
+ m03 = 0f;
+ m13 = 0f;
+ m23 = 0f;
+ m33 = 1f;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to rotation from the given axis and angle in radians.
+ * <pre>
+ Rotation matrix (Column Order):
+ xx(1-c)+c xy(1-c)+zs xz(1-c)-ys 0
+ xy(1-c)-zs yy(1-c)+c yz(1-c)+xs 0
+ xz(1-c)+ys yz(1-c)-xs zz(1-c)+c 0
+ 0 0 0 1
+ * </pre>
+ * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a>
+ * @param ang_rad angle in radians
+ * @param axis rotation axis
+ * @return this matrix for chaining
+ */
+ public final Matrix4f setToRotationAxis(final float ang_rad, final Vec3f axis) {
+ return setToRotationAxis(ang_rad, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Set this matrix to rotation from the given Euler rotation angles in radians.
+ * <p>
+ * The rotations are applied in the given order:
+ * <ul>
+ * <li>y - heading</li>
+ * <li>z - attitude</li>
+ * <li>x - bank</li>
+ * </ul>
+ * </p>
+ * @param bankX the Euler pitch angle in radians. (rotation about the X axis)
+ * @param headingY the Euler yaw angle in radians. (rotation about the Y axis)
+ * @param attitudeZ the Euler roll angle in radians. (rotation about the Z axis)
+ * @return this matrix for chaining
+ * <p>
+ * Implementation does not use Quaternion and hence is exposed to
+ * <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q34">Gimbal-Lock</a>,
+ * consider using {@link #setToRotation(Quaternion)}.
+ * </p>
+ * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q36">Matrix-FAQ Q36</a>
+ * @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm">euclideanspace.com-eulerToMatrix</a>
+ * @see #setToRotation(Quaternion)
+ */
+ public Matrix4f setToRotationEuler(final float bankX, final float headingY, final float attitudeZ) {
+ // Assuming the angles are in radians.
+ final float ch = FloatUtil.cos(headingY);
+ final float sh = FloatUtil.sin(headingY);
+ final float ca = FloatUtil.cos(attitudeZ);
+ final float sa = FloatUtil.sin(attitudeZ);
+ final float cb = FloatUtil.cos(bankX);
+ final float sb = FloatUtil.sin(bankX);
+
+ m00 = ch*ca;
+ m10 = sa;
+ m20 = -sh*ca;
+ m30 = 0;
+
+ m01 = sh*sb - ch*sa*cb;
+ m11 = ca*cb;
+ m21 = sh*sa*cb + ch*sb;
+ m31 = 0;
+
+ m02 = ch*sa*sb + sh*cb;
+ m12 = -ca*sb;
+ m22 = -sh*sa*sb + ch*cb;
+ m32 = 0;
+
+ m03 = 0;
+ m13 = 0;
+ m23 = 0;
+ m33 = 1;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to rotation from the given Euler rotation angles in radians.
+ * <p>
+ * The rotations are applied in the given order:
+ * <ul>
+ * <li>y - heading</li>
+ * <li>z - attitude</li>
+ * <li>x - bank</li>
+ * </ul>
+ * </p>
+ * @param angradXYZ euler angle vector in radians holding x-bank, y-heading and z-attitude
+ * @return this quaternion for chaining.
+ * <p>
+ * Implementation does not use Quaternion and hence is exposed to
+ * <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q34">Gimbal-Lock</a>,
+ * consider using {@link #setToRotation(Quaternion)}.
+ * </p>
+ * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q36">Matrix-FAQ Q36</a>
+ * @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm">euclideanspace.com-eulerToMatrix</a>
+ * @see #setToRotation(Quaternion)
+ */
+ public Matrix4f setToRotationEuler(final Vec3f angradXYZ) {
+ return setToRotationEuler(angradXYZ.x(), angradXYZ.y(), angradXYZ.z());
+ }
+
+ /**
+ * Set this matrix to rotation using the given Quaternion.
+ * <p>
+ * Implementation Details:
+ * <ul>
+ * <li> makes identity matrix if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li>
+ * <li> The fields [m00 .. m22] define the rotation</li>
+ * </ul>
+ * </p>
+ *
+ * @param q the Quaternion representing the rotation
+ * @return this matrix for chaining
+ * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54">Matrix-FAQ Q54</a>
+ * @see Quaternion#toMatrix(float[])
+ * @see #getRotation()
+ */
+ public final Matrix4f setToRotation(final Quaternion q) {
+ // pre-multiply scaled-reciprocal-magnitude to reduce multiplications
+ final float norm = q.magnitudeSquared();
+ if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) {
+ // identity matrix -> srecip = 0f
+ loadIdentity();
+ return this;
+ }
+ final float srecip;
+ if ( FloatUtil.isEqual(1f, norm, FloatUtil.EPSILON) ) {
+ srecip = 2f;
+ } else {
+ srecip = 2.0f / norm;
+ }
+
+ final float x = q.x();
+ final float y = q.y();
+ final float z = q.z();
+ final float w = q.w();
+
+ final float xs = srecip * x;
+ final float ys = srecip * y;
+ final float zs = srecip * z;
+
+ final float xx = x * xs;
+ final float xy = x * ys;
+ final float xz = x * zs;
+ final float xw = xs * w;
+ final float yy = y * ys;
+ final float yz = y * zs;
+ final float yw = ys * w;
+ final float zz = z * zs;
+ final float zw = zs * w;
+
+ m00 = 1f - ( yy + zz );
+ m01 = ( xy - zw );
+ m02 = ( xz + yw );
+ m03 = 0f;
+
+ m10 = ( xy + zw );
+ m11 = 1f - ( xx + zz );
+ m12 = ( yz - xw );
+ m13 = 0f;
+
+ m20 = ( xz - yw );
+ m21 = ( yz + xw );
+ m22 = 1f - ( xx + yy );
+ m23 = 0f;
+
+ m30 = m31 = m32 = 0f;
+ m33 = 1f;
+ return this;
+ }
+
+ /**
+ * Returns the rotation [m00 .. m22] fields converted to a Quaternion.
+ * @param res resulting Quaternion
+ * @return the resulting Quaternion for chaining.
+ * @see Quaternion#setFromMatrix(float, float, float, float, float, float, float, float, float)
+ * @see #setToRotation(Quaternion)
+ */
+ public final Quaternion getRotation(final Quaternion res) {
+ res.setFromMatrix(m00, m01, m02, m10, m11, m12, m20, m21, m22);
+ return res;
+ }
+
+ /**
+ * Set this matrix to orthogonal projection.
+ * <pre>
+ Ortho matrix (Column Order):
+ 2/dx 0 0 0
+ 0 2/dy 0 0
+ 0 0 2/dz 0
+ tx ty tz 1
+ * </pre>
+ * @param left
+ * @param right
+ * @param bottom
+ * @param top
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ */
+ public Matrix4f setToOrtho(final float left, final float right,
+ final float bottom, final float top,
+ final float zNear, final float zFar) {
+ {
+ // m00 = m11 = m22 = m33 = 1f;
+ m10 = m20 = m30 = 0f;
+ m01 = m21 = m31 = 0f;
+ m02 = m12 = m32 = 0f;
+ // m03 = m13 = m23 = 0f;
+ }
+ final float dx=right-left;
+ final float dy=top-bottom;
+ final float dz=zFar-zNear;
+ final float tx=-1.0f*(right+left)/dx;
+ final float ty=-1.0f*(top+bottom)/dy;
+ final float tz=-1.0f*(zFar+zNear)/dz;
+
+ m00 = 2.0f/dx;
+ m11 = 2.0f/dy;
+ m22 = -2.0f/dz;
+
+ m03 = tx;
+ m13 = ty;
+ m23 = tz;
+ m33 = 1f;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to frustum.
+ * <pre>
+ Frustum matrix (Column Order):
+ 2*zNear/dx 0 0 0
+ 0 2*zNear/dy 0 0
+ A B C -1
+ 0 0 D 0
+ * </pre>
+ * @param left
+ * @param right
+ * @param bottom
+ * @param top
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear}
+ * or {@code left == right}, or {@code bottom == top}.
+ */
+ public Matrix4f setToFrustum(final float left, final float right,
+ final float bottom, final float top,
+ final float zNear, final float zFar) throws IllegalArgumentException {
+ if( zNear <= 0.0f || zFar <= zNear ) {
+ throw new IllegalArgumentException("Requirements zNear > 0 and zFar > zNear, but zNear "+zNear+", zFar "+zFar);
+ }
+ if( left == right || top == bottom) {
+ throw new IllegalArgumentException("GL_INVALID_VALUE: top,bottom and left,right must not be equal");
+ }
+ {
+ // m00 = m11 = m22 = m33 = 1f;
+ m10 = m20 = m30 = 0f;
+ m01 = m21 = m31 = 0f;
+ m03 = m13 = 0f;
+ }
+ final float zNear2 = 2.0f*zNear;
+ final float dx=right-left;
+ final float dy=top-bottom;
+ final float dz=zFar-zNear;
+ final float A=(right+left)/dx;
+ final float B=(top+bottom)/dy;
+ final float C=-1.0f*(zFar+zNear)/dz;
+ final float D=-2.0f*(zFar*zNear)/dz;
+
+ m00 = zNear2/dx;
+ m11 = zNear2/dy;
+
+ m02 = A;
+ m12 = B;
+ m22 = C;
+ m32 = -1.0f;
+
+ m23 = D;
+ m33 = 0f;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to perspective {@link #setToFrustum(float, float, float, float, float, float) frustum} projection.
+ *
+ * @param fovy_rad angle in radians
+ * @param aspect aspect ratio width / height
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear}
+ * @see #setToFrustum(float, float, float, float, float, float)
+ */
+ public Matrix4f setToPerspective(final float fovy_rad, final float aspect, final float zNear, final float zFar) throws IllegalArgumentException {
+ final float top = FloatUtil.tan(fovy_rad/2f) * zNear; // use tangent of half-fov !
+ final float bottom = -1.0f * top; // -1f * fovhvTan.top * zNear
+ final float left = aspect * bottom; // aspect * -1f * fovhvTan.top * zNear
+ final float right = aspect * top; // aspect * fovhvTan.top * zNear
+ return setToFrustum(left, right, bottom, top, zNear, zFar);
+ }
+
+ /**
+ * Set this matrix to perspective {@link #setToFrustum(float, float, float, float, float, float) frustum} projection.
+ *
+ * @param fovhv {@link FovHVHalves} field of view in both directions, may not be centered, either in radians or tangent
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear}
+ * @see #setToFrustum(float, float, float, float, float, float)
+ * @see Frustum#updateByFovDesc(Matrix4f, com.jogamp.opengl.math.geom.Frustum.FovDesc)
+ */
+ public Matrix4f setToPerspective(final FovHVHalves fovhv, final float zNear, final float zFar) throws IllegalArgumentException {
+ final FovHVHalves fovhvTan = fovhv.toTangents(); // use tangent of half-fov !
+ final float top = fovhvTan.top * zNear;
+ final float bottom = -1.0f * fovhvTan.bottom * zNear;
+ final float left = -1.0f * fovhvTan.left * zNear;
+ final float right = fovhvTan.right * zNear;
+ return setToFrustum(left, right, bottom, top, zNear, zFar);
+ }
+
+ /**
+ * Calculate the frustum planes in world coordinates
+ * using this premultiplied P*MV (column major order) matrix.
+ * <p>
+ * Frustum plane's normals will point to the inside of the viewing frustum,
+ * as required by this class.
+ * </p>
+ * <p>
+ * Usually called by {@link Frustum#updateFrustumPlanes(Matrix4f)}.
+ * </p>
+ */
+ public void updateFrustumPlanes(final Frustum frustum) {
+ // Left: a = m41 + m11, b = m42 + m12, c = m43 + m13, d = m44 + m14 - [1..4] column-major
+ // Left: a = m30 + m00, b = m31 + m01, c = m32 + m02, d = m33 + m03 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.LEFT];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 + m00,
+ m31 + m01,
+ m32 + m02 );
+ p.d = m33 + m03;
+ }
+
+ // Right: a = m41 - m11, b = m42 - m12, c = m43 - m13, d = m44 - m14 - [1..4] column-major
+ // Right: a = m30 - m00, b = m31 - m01, c = m32 - m02, d = m33 - m03 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.RIGHT];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 - m00,
+ m31 - m01,
+ m32 - m02 );
+ p.d = m33 - m03;
+ }
+
+ // Bottom: a = m41m21, b = m42m22, c = m43m23, d = m44m24 - [1..4] column-major
+ // Bottom: a = m30m10, b = m31m11, c = m32m12, d = m33m13 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.BOTTOM];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 + m10,
+ m31 + m11,
+ m32 + m12 );
+ p.d = m33 + m13;
+ }
+
+ // Top: a = m41 - m21, b = m42 - m22, c = m43 - m23, d = m44 - m24 - [1..4] column-major
+ // Top: a = m30 - m10, b = m31 - m11, c = m32 - m12, d = m33 - m13 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.TOP];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 - m10,
+ m31 - m11,
+ m32 - m12 );
+ p.d = m33 - m13;
+ }
+
+ // Near: a = m41m31, b = m42m32, c = m43m33, d = m44m34 - [1..4] column-major
+ // Near: a = m30m20, b = m31m21, c = m32m22, d = m33m23 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.NEAR];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 + m20,
+ m31 + m21,
+ m32 + m22 );
+ p.d = m33 + m23;
+ }
+
+ // Far: a = m41 - m31, b = m42 - m32, c = m43 - m33, d = m44 - m34 - [1..4] column-major
+ // Far: a = m30 - m20, b = m31 - m21, c = m32m22, d = m33m23 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.FAR];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 - m20,
+ m31 - m21,
+ m32 - m22 );
+ p.d = m33 - m23;
+ }
+
+ // Normalize all planes
+ for (int i = 0; i < 6; ++i) {
+ final Plane p = frustum.getPlanes()[i];
+ final Vec3f p_n = p.n;
+ final float invLen = 1f / p_n.length();
+ p_n.scale(invLen);
+ p.d *= invLen;
+ }
+ }
+
+ /**
+ * Set this matrix to the <i>look-at</i> matrix based on given parameters.
+ * <p>
+ * Consist out of two matrix multiplications:
+ * <pre>
+ * <b>R</b> = <b>L</b> x <b>T</b>,
+ * with <b>L</b> for <i>look-at</i> matrix and
+ * <b>T</b> for eye translation.
+ *
+ * Result <b>R</b> can be utilized for <i>projection or modelview</i> multiplication, i.e.
+ * <b>M</b> = <b>M</b> x <b>R</b>,
+ * with <b>M</b> being the <i>projection or modelview</i> matrix.
+ * </pre>
+ * </p>
+ * @param eye 3 component eye vector
+ * @param center 3 component center vector
+ * @param up 3 component up vector
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public Matrix4f setToLookAt(final Vec3f eye, final Vec3f center, final Vec3f up, final Matrix4f tmp) {
+ // normalized forward!
+ final Vec3f fwd = new Vec3f( center.x() - eye.x(),
+ center.y() - eye.y(),
+ center.z() - eye.z() ).normalize();
+
+ /* Side = forward x up, normalized */
+ final Vec3f side = fwd.cross(up).normalize();
+
+ /* Recompute up as: up = side x forward */
+ final Vec3f up2 = side.cross(fwd);
+
+ m00 = side.x();
+ m10 = up2.x();
+ m20 = -fwd.x();
+ m30 = 0;
+
+ m01 = side.y();
+ m11 = up2.y();
+ m21 = -fwd.y();
+ m31 = 0;
+
+ m02 = side.z();
+ m12 = up2.z();
+ m22 = -fwd.z();
+ m32 = 0;
+
+ m03 = 0;
+ m13 = 0;
+ m23 = 0;
+ m33 = 1;
+
+ return mul( tmp.setToTranslation( -eye.x(), -eye.y(), -eye.z() ) );
+ }
+
+ /**
+ * Set this matrix to the <i>pick</i> matrix based on given parameters.
+ * <p>
+ * Traditional <code>gluPickMatrix</code> implementation.
+ * </p>
+ * <p>
+ * Consist out of two matrix multiplications:
+ * <pre>
+ * <b>R</b> = <b>T</b> x <b>S</b>,
+ * with <b>T</b> for viewport translation matrix and
+ * <b>S</b> for viewport scale matrix.
+ *
+ * Result <b>R</b> can be utilized for <i>projection</i> multiplication, i.e.
+ * <b>P</b> = <b>P</b> x <b>R</b>,
+ * with <b>P</b> being the <i>projection</i> matrix.
+ * </pre>
+ * </p>
+ * <p>
+ * To effectively use the generated pick matrix for picking,
+ * call {@link #setToPick(float, float, float, float, Recti, Matrix4f) setToPick(..)}
+ * and multiply a {@link #setToPerspective(float, float, float, float) custom perspective matrix}
+ * by this pick matrix. Then you may load the result onto the perspective matrix stack.
+ * </p>
+ * @param x the center x-component of a picking region in window coordinates
+ * @param y the center y-component of a picking region in window coordinates
+ * @param deltaX the width of the picking region in window coordinates.
+ * @param deltaY the height of the picking region in window coordinates.
+ * @param viewport Rect4i viewport
+ * @param mat4Tmp temp storage
+ * @return this matrix for chaining or {@code null} if either delta value is <= zero.
+ */
+ public Matrix4f setToPick(final float x, final float y, final float deltaX, final float deltaY,
+ final Recti viewport, final Matrix4f mat4Tmp) {
+ if (deltaX <= 0 || deltaY <= 0) {
+ return null;
+ }
+ /* Translate and scale the picked region to the entire window */
+ setToTranslation( ( viewport.width() - 2 * ( x - viewport.x() ) ) / deltaX,
+ ( viewport.height() - 2 * ( y - viewport.y() ) ) / deltaY,
+ 0);
+ mat4Tmp.setToScale( viewport.width() / deltaX, viewport.height() / deltaY, 1.0f );
+ return mul(mat4Tmp);
+ }
+
+ //
+ // Matrix affine operations using setTo..()
+ //
+
+ /**
+ * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(float, float, float, float) axis-rotation matrix}.
+ * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a>
+ * @param angrad angle in radians
+ * @param x x of rotation axis
+ * @param y y of rotation axis
+ * @param z z of rotation axis
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f rotate(final float ang_rad, final float x, final float y, final float z, final Matrix4f tmp) {
+ return mul( tmp.setToRotationAxis(ang_rad, x, y, z) );
+ }
+
+ /**
+ * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(float, Vec3f) axis-rotation matrix}.
+ * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a>
+ * @param angrad angle in radians
+ * @param axis rotation axis
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f rotate(final float ang_rad, final Vec3f axis, final Matrix4f tmp) {
+ return mul( tmp.setToRotationAxis(ang_rad, axis) );
+ }
+
+ /**
+ * Rotate this matrix with the given {@link Quaternion}, i.e. multiply by {@link #setToRotation(Quaternion) Quaternion's rotation matrix}.
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f rotate(final Quaternion quat, final Matrix4f tmp) {
+ return mul( tmp.setToRotation(quat) );
+ }
+
+ /**
+ * Translate this matrix, i.e. multiply by {@link #setToTranslation(float, float, float) translation matrix}.
+ * @param x x translation
+ * @param y y translation
+ * @param z z translation
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f translate(final float x, final float y, final float z, final Matrix4f tmp) {
+ return mul( tmp.setToTranslation(x, y, z) );
+ }
+
+ /**
+ * Translate this matrix, i.e. multiply by {@link #setToTranslation(Vec3f) translation matrix}.
+ * @param t translation Vec3f
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f translate(final Vec3f t, final Matrix4f tmp) {
+ return mul( tmp.setToTranslation(t) );
+ }
+
+ /**
+ * Scale this matrix, i.e. multiply by {@link #setToScale(float, float, float) scale matrix}.
+ * @param x x scale
+ * @param y y scale
+ * @param z z scale
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f scale(final float x, final float y, final float z, final Matrix4f tmp) {
+ return mul( tmp.setToScale(x, y, z) );
+ }
+
+ /**
+ * Scale this matrix, i.e. multiply by {@link #setToScale(float, float, float) scale matrix}.
+ * @param s scale for x-, y- and z-axis
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f scale(final float s, final Matrix4f tmp) {
+ return mul( tmp.setToScale(s, s, s) );
+ }
+
+ //
+ // Matrix Stack
+ //
+
+ /**
+ * Push the matrix to it's stack, while preserving this matrix values.
+ * @see #pop()
+ */
+ public final void push() {
+ stack.push(this);
+ }
+
+ /**
+ * Pop the current matrix from it's stack, replacing this matrix values.
+ * @see #push()
+ */
+ public final void pop() {
+ stack.pop(this);
+ }
+
+ //
+ // equals
+ //
+
+ /**
+ * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ * <p>
+ * Implementation considers following corner cases:
+ * <ul>
+ * <li>NaN == NaN</li>
+ * <li>+Inf == +Inf</li>
+ * <li>-Inf == -Inf</li>
+ * </ul>
+ * @param o comparison value
+ * @param epsilon consider using {@link FloatUtil#EPSILON}
+ * @return true if all components differ less than {@code epsilon}, otherwise false.
+ */
+ public boolean isEqual(final Matrix4f o, final float epsilon) {
+ if( this == o ) {
+ return true;
+ } else {
+ return FloatUtil.isEqual(m00, o.m00, epsilon) &&
+ FloatUtil.isEqual(m01, o.m01, epsilon) &&
+ FloatUtil.isEqual(m02, o.m02, epsilon) &&
+ FloatUtil.isEqual(m03, o.m03, epsilon) &&
+ FloatUtil.isEqual(m10, o.m10, epsilon) &&
+ FloatUtil.isEqual(m11, o.m11, epsilon) &&
+ FloatUtil.isEqual(m12, o.m12, epsilon) &&
+ FloatUtil.isEqual(m13, o.m13, epsilon) &&
+ FloatUtil.isEqual(m20, o.m20, epsilon) &&
+ FloatUtil.isEqual(m21, o.m21, epsilon) &&
+ FloatUtil.isEqual(m22, o.m22, epsilon) &&
+ FloatUtil.isEqual(m23, o.m23, epsilon) &&
+ FloatUtil.isEqual(m30, o.m30, epsilon) &&
+ FloatUtil.isEqual(m31, o.m31, epsilon) &&
+ FloatUtil.isEqual(m32, o.m32, epsilon) &&
+ FloatUtil.isEqual(m33, o.m33, epsilon);
+ }
+ }
+
+ /**
+ * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ * <p>
+ * Implementation considers following corner cases:
+ * <ul>
+ * <li>NaN == NaN</li>
+ * <li>+Inf == +Inf</li>
+ * <li>-Inf == -Inf</li>
+ * </ul>
+ * @param o comparison value
+ * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false.
+ */
+ public boolean isEqual(final Matrix4f o) {
+ return isEqual(o, FloatUtil.EPSILON);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if( o instanceof Matrix4f ) {
+ return isEqual((Matrix4f)o, FloatUtil.EPSILON);
+ } else {
+ return false;
+ }
+ }
+
+ //
+ // Static multi Matrix ops
+ //
+
+ /**
+ * Map object coordinates to window coordinates.
+ * <p>
+ * Traditional <code>gluProject</code> implementation.
+ * </p>
+ *
+ * @param obj object position, 3 component vector
+ * @param mMv modelview matrix
+ * @param mP projection matrix
+ * @param viewport Rect4i viewport
+ * @param winPos 3 component window coordinate, the result
+ * @return true if successful, otherwise false (z is 1)
+ */
+ public static boolean mapObjToWin(final Vec3f obj, final Matrix4f mMv, final Matrix4f mP,
+ final Recti viewport, final Vec3f winPos)
+ {
+ final Vec4f vec4Tmp1 = new Vec4f(obj, 1f);
+
+ // vec4Tmp2 = Mv * o
+ // rawWinPos = P * vec4Tmp2
+ // rawWinPos = P * ( Mv * o )
+ // rawWinPos = P * Mv * o
+ final Vec4f vec4Tmp2 = mMv.mulVec4f(vec4Tmp1, new Vec4f());
+ final Vec4f rawWinPos = mP.mulVec4f(vec4Tmp2, vec4Tmp1);
+
+ if (rawWinPos.w() == 0.0f) {
+ return false;
+ }
+
+ final float s = ( 1.0f / rawWinPos.w() ) * 0.5f;
+
+ // Map x, y and z to range 0-1 (w is ignored)
+ rawWinPos.scale(s).add(0.5f, 0.5f, 0.5f, 0f);
+
+ // Map x,y to viewport
+ winPos.set( rawWinPos.x() * viewport.width() + viewport.x(),
+ rawWinPos.y() * viewport.height() + viewport.y(),
+ rawWinPos.z() );
+
+ return true;
+ }
+
+ /**
+ * Map object coordinates to window coordinates.
+ * <p>
+ * Traditional <code>gluProject</code> implementation.
+ * </p>
+ *
+ * @param obj object position, 3 component vector
+ * @param mPMv [projection] x [modelview] matrix, i.e. P x Mv
+ * @param viewport Rect4i viewport
+ * @param winPos 3 component window coordinate, the result
+ * @return true if successful, otherwise false (z is 1)
+ */
+ public static boolean mapObjToWin(final Vec3f obj, final Matrix4f mPMv,
+ final Recti viewport, final Vec3f winPos)
+ {
+ final Vec4f vec4Tmp2 = new Vec4f(obj, 1f);
+
+ // rawWinPos = P * Mv * o
+ final Vec4f rawWinPos = mPMv.mulVec4f(vec4Tmp2, new Vec4f());
+
+ if (rawWinPos.w() == 0.0f) {
+ return false;
+ }
+
+ final float s = ( 1.0f / rawWinPos.w() ) * 0.5f;
+
+ // Map x, y and z to range 0-1 (w is ignored)
+ rawWinPos.scale(s).add(0.5f, 0.5f, 0.5f, 0f);
+
+ // Map x,y to viewport
+ winPos.set( rawWinPos.x() * viewport.width() + viewport.x(),
+ rawWinPos.y() * viewport.height() + viewport.y(),
+ rawWinPos.z() );
+
+ return true;
+ }
+
+ /**
+ * Map window coordinates to object coordinates.
+ * <p>
+ * Traditional <code>gluUnProject</code> implementation.
+ * </p>
+ *
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param mMv 4x4 modelview matrix
+ * @param mP 4x4 projection matrix
+ * @param viewport Rect4i viewport
+ * @param objPos 3 component object coordinate, the result
+ * @param mat4Tmp 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz,
+ final Matrix4f mMv, final Matrix4f mP,
+ final Recti viewport,
+ final Vec3f objPos,
+ final Matrix4f mat4Tmp)
+ {
+ // invPMv = Inv(P x Mv)
+ final Matrix4f invPMv = mat4Tmp.mul(mP, mMv);
+ if( !invPMv.invert() ) {
+ return false;
+ }
+
+ final Vec4f winPos = new Vec4f(winx, winy, winz, 1f);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport.x(), -viewport.y(), 0f, 0f).scale(1f/viewport.width(), 1f/viewport.height(), 1f, 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // rawObjPos = Inv(P x Mv) * winPos
+ final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f());
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ return true;
+ }
+
+ /**
+ * Map window coordinates to object coordinates.
+ * <p>
+ * Traditional <code>gluUnProject</code> implementation.
+ * </p>
+ *
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv), if null method returns false
+ * @param viewport Rect4i viewport
+ * @param objPos 3 component object coordinate, the result
+ * @return true if successful, otherwise false (null invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz,
+ final Matrix4f invPMv,
+ final Recti viewport,
+ final Vec3f objPos)
+ {
+ if( null == invPMv ) {
+ return false;
+ }
+ final Vec4f winPos = new Vec4f(winx, winy, winz, 1f);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport.x(), -viewport.y(), 0f, 0f).scale(1f/viewport.width(), 1f/viewport.height(), 1f, 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // rawObjPos = Inv(P x Mv) * winPos
+ final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f());
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ return true;
+ }
+
+ /**
+ * Map two window coordinates to two object coordinates,
+ * distinguished by their z component.
+ * <p>
+ * Traditional <code>gluUnProject</code> implementation.
+ * </p>
+ *
+ * @param winx
+ * @param winy
+ * @param winz1
+ * @param winz2
+ * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv), if null method returns false
+ * @param viewport Rect4i viewport vector
+ * @param objPos1 3 component object coordinate, the result
+ * @return true if successful, otherwise false (null invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz1, final float winz2,
+ final Matrix4f invPMv,
+ final Recti viewport,
+ final Vec3f objPos1, final Vec3f objPos2)
+ {
+ if( null == invPMv ) {
+ return false;
+ }
+ final Vec4f winPos = new Vec4f(winx, winy, winz1, 1f);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport.x(), -viewport.y(), 0f, 0f).scale(1f/viewport.width(), 1f/viewport.height(), 1f, 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // rawObjPos = Inv(P x Mv) * winPos1
+ final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f());
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos1.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ //
+ // winz2
+ //
+ // Map Z to range -1 to 1
+ winPos.setZ( winz2 * 2f - 1f );
+
+ // rawObjPos = Inv(P x Mv) * winPos2
+ invPMv.mulVec4f(winPos, rawObjPos);
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos2.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ return true;
+ }
+
+ /**
+ * Map window coordinates to object coordinates.
+ * <p>
+ * Traditional <code>gluUnProject4</code> implementation.
+ * </p>
+ *
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param clipw
+ * @param mMv 4x4 modelview matrix
+ * @param mP 4x4 projection matrix
+ * @param viewport Rect4i viewport vector
+ * @param near
+ * @param far
+ * @param obj_pos 4 component object coordinate, the result
+ * @param mat4Tmp 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj4(final float winx, final float winy, final float winz, final float clipw,
+ final Matrix4f mMv, final Matrix4f mP,
+ final Recti viewport,
+ final float near, final float far,
+ final Vec4f objPos,
+ final Matrix4f mat4Tmp)
+ {
+ // invPMv = Inv(P x Mv)
+ final Matrix4f invPMv = mat4Tmp.mul(mP, mMv);
+ if( !invPMv.invert() ) {
+ return false;
+ }
+
+ final Vec4f winPos = new Vec4f(winx, winy, winz, clipw);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport.x(), -viewport.y(), -near, 0f).scale(1f/viewport.width(), 1f/viewport.height(), 1f/(far-near), 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // objPos = Inv(P x Mv) * winPos
+ invPMv.mulVec4f(winPos, objPos);
+
+ if ( objPos.w() == 0.0f ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Map window coordinates to object coordinates.
+ * <p>
+ * Traditional <code>gluUnProject4</code> implementation.
+ * </p>
+ *
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param clipw
+ * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv), if null method returns false
+ * @param viewport Rect4i viewport vector
+ * @param near
+ * @param far
+ * @param obj_pos 4 component object coordinate, the result
+ * @return true if successful, otherwise false (null invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj4(final float winx, final float winy, final float winz, final float clipw,
+ final Matrix4f invPMv,
+ final Recti viewport,
+ final float near, final float far,
+ final Vec4f objPos)
+ {
+ if( null == invPMv ) {
+ return false;
+ }
+ final Vec4f winPos = new Vec4f(winx, winy, winz, clipw);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport.x(), -viewport.y(), -near, 0f).scale(1f/viewport.width(), 1f/viewport.height(), 1f/(far-near), 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // objPos = Inv(P x Mv) * winPos
+ invPMv.mulVec4f(winPos, objPos);
+
+ if ( objPos.w() == 0.0f ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Map two window coordinates w/ shared X/Y and distinctive Z
+ * to a {@link Ray}. The resulting {@link Ray} maybe used for <i>picking</i>
+ * using a {@link AABBox#getRayIntersection(Vec3f, Ray, float, boolean)}.
+ * <p>
+ * Notes for picking <i>winz0</i> and <i>winz1</i>:
+ * <ul>
+ * <li>see {@link FloatUtil#getZBufferEpsilon(int, float, float)}</li>
+ * <li>see {@link FloatUtil#getZBufferValue(int, float, float, float)}</li>
+ * <li>see {@link FloatUtil#getOrthoWinZ(float, float, float)}</li>
+ * </ul>
+ * </p>
+ * @param winx
+ * @param winy
+ * @param winz0
+ * @param winz1
+ * @param mMv 4x4 modelview matrix
+ * @param mP 4x4 projection matrix
+ * @param viewport Rect4i viewport
+ * @param ray storage for the resulting {@link Ray}
+ * @param mat4Tmp1 16 component matrix for temp storage
+ * @param mat4Tmp2 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes z is infinity)
+ */
+ public static boolean mapWinToRay(final float winx, final float winy, final float winz0, final float winz1,
+ final Matrix4f mMv, final Matrix4f mP,
+ final Recti viewport,
+ final Ray ray,
+ final Matrix4f mat4Tmp1, final Matrix4f mat4Tmp2) {
+ // invPMv = Inv(P x Mv)
+ final Matrix4f invPMv = mat4Tmp1.mul(mP, mMv);
+ if( !invPMv.invert() ) {
+ return false;
+ }
+
+ if( mapWinToObj(winx, winy, winz0, winz1, invPMv, viewport, ray.orig, ray.dir) ) {
+ ray.dir.sub(ray.orig).normalize();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Map two window coordinates w/ shared X/Y and distinctive Z
+ * to a {@link Ray}. The resulting {@link Ray} maybe used for <i>picking</i>
+ * using a {@link AABBox#getRayIntersection(Vec3f, Ray, float, boolean)}.
+ * <p>
+ * Notes for picking <i>winz0</i> and <i>winz1</i>:
+ * <ul>
+ * <li>see {@link FloatUtil#getZBufferEpsilon(int, float, float)}</li>
+ * <li>see {@link FloatUtil#getZBufferValue(int, float, float, float)}</li>
+ * <li>see {@link FloatUtil#getOrthoWinZ(float, float, float)}</li>
+ * </ul>
+ * </p>
+ * @param winx
+ * @param winy
+ * @param winz0
+ * @param winz1
+ * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv), if null method returns false
+ * @param viewport Rect4i viewport
+ * @param ray storage for the resulting {@link Ray}
+ * @return true if successful, otherwise false (null invert matrix, or becomes z is infinity)
+ */
+ public static boolean mapWinToRay(final float winx, final float winy, final float winz0, final float winz1,
+ final Matrix4f invPMv,
+ final Recti viewport,
+ final Ray ray) {
+ if( mapWinToObj(winx, winy, winz0, winz1, invPMv, viewport, ray.orig, ray.dir) ) {
+ ray.dir.sub(ray.orig).normalize();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ //
+ // String and internals
+ //
+
+ /**
+ * @param sb optional passed StringBuilder instance to be used
+ * @param rowPrefix optional prefix for each row
+ * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
+ * @return matrix string representation
+ */
+ public StringBuilder toString(final StringBuilder sb, final String rowPrefix, final String f) {
+ final float[] tmp = new float[16];
+ this.get(tmp);
+ return FloatUtil.matrixToString(sb, rowPrefix, f,tmp, 0, 4, 4, false /* rowMajorOrder */);
+ }
+
+ @Override
+ public String toString() {
+ return toString(null, null, "%10.5f").toString();
+ }
+
+ private float m00, m10, m20, m30;
+ private float m01, m11, m21, m31;
+ private float m02, m12, m22, m32;
+ private float m03, m13, m23, m33;
+
+ final Stack stack = new Stack(0, 16*16); // start w/ zero size, growSize is half GL-min size (32)
+
+ private static class Stack {
+ private int position;
+ private float[] buffer;
+ private final int growSize;
+
+ /**
+ * @param initialSize initial size
+ * @param growSize grow size if {@link #position()} is reached, maybe <code>0</code>
+ * in which case an {@link IndexOutOfBoundsException} is thrown.
+ */
+ public Stack(final int initialSize, final int growSize) {
+ this.position = 0;
+ this.growSize = growSize;
+ this.buffer = new float[initialSize];
+ }
+
+ private final void growIfNecessary(final int length) throws IndexOutOfBoundsException {
+ if( position + length > buffer.length ) {
+ if( 0 >= growSize ) {
+ throw new IndexOutOfBoundsException("Out of fixed stack size: "+this);
+ }
+ final float[] newBuffer =
+ new float[buffer.length + growSize];
+ System.arraycopy(buffer, 0, newBuffer, 0, position);
+ buffer = newBuffer;
+ }
+ }
+
+ public final Matrix4f push(final Matrix4f src) throws IndexOutOfBoundsException {
+ growIfNecessary(16);
+ src.get(buffer, position);
+ position += 16;
+ return src;
+ }
+
+ public final Matrix4f pop(final Matrix4f dest) throws IndexOutOfBoundsException {
+ position -= 16;
+ dest.load(buffer, position);
+ return dest;
+ }
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java b/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java
index 430450767..a285774f8 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -99,7 +99,7 @@ public class Quaternion {
return FloatUtil.sqrt(magnitudeSQ);
}
- public final float getW() {
+ public final float w() {
return w;
}
@@ -107,7 +107,7 @@ public class Quaternion {
this.w = w;
}
- public final float getX() {
+ public final float x() {
return x;
}
@@ -115,7 +115,7 @@ public class Quaternion {
this.x = x;
}
- public final float getY() {
+ public final float y() {
return y;
}
@@ -123,7 +123,7 @@ public class Quaternion {
this.y = y;
}
- public final float getZ() {
+ public final float z() {
return z;
}
@@ -142,15 +142,15 @@ public class Quaternion {
* Returns the dot product of this quaternion with the given quaternion
*/
public final float dot(final Quaternion quat) {
- return dot(quat.getX(), quat.getY(), quat.getZ(), quat.getW());
+ return dot(quat.x(), quat.y(), quat.z(), quat.w());
}
/**
* Returns <code>true</code> if this quaternion has identity.
* <p>
* Implementation uses {@link FloatUtil#EPSILON epsilon} to compare
- * {@link #getW() W} {@link FloatUtil#isEqual(float, float, float) against 1f} and
- * {@link #getX() X}, {@link #getY() Y} and {@link #getZ() Z}
+ * {@link #w() W} {@link FloatUtil#isEqual(float, float, float) against 1f} and
+ * {@link #x() X}, {@link #y() Y} and {@link #z() Z}
* {@link FloatUtil#isZero(float, float) against zero}.
* </p>
*/
@@ -404,12 +404,12 @@ public class Quaternion {
* </ul>
* </p>
* For details see {@link #rotateByEuler(float, float, float)}.
- * @param angradXYZ euler angel array in radians
+ * @param angradXYZ euler angle array in radians
* @return this quaternion for chaining.
* @see #rotateByEuler(float, float, float)
*/
- public final Quaternion rotateByEuler(final float[] angradXYZ) {
- return rotateByEuler(angradXYZ[0], angradXYZ[1], angradXYZ[2]);
+ public final Quaternion rotateByEuler(final Vec3f angradXYZ) {
+ return rotateByEuler(angradXYZ.x(), angradXYZ.y(), angradXYZ.z());
}
/**
@@ -450,48 +450,42 @@ public class Quaternion {
/***
* Rotate the given vector by this quaternion
+ * @param vecIn vector to be rotated
+ * @param vecOut result storage for rotated vector, maybe equal to vecIn for in-place rotation
*
- * @param vecOut result float[3] storage for rotated vector, maybe equal to vecIn for in-place rotation
- * @param vecOutOffset offset in result storage
- * @param vecIn float[3] vector to be rotated
- * @param vecInOffset offset in vecIn
* @return the given vecOut store for chaining
* @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q63">Matrix-FAQ Q63</a>
*/
- public final float[] rotateVector(final float[] vecOut, final int vecOutOffset, final float[] vecIn, final int vecInOffset) {
- if ( VectorUtil.isVec3Zero(vecIn, vecInOffset, FloatUtil.EPSILON) ) {
- vecOut[0+vecOutOffset] = 0f;
- vecOut[1+vecOutOffset] = 0f;
- vecOut[2+vecOutOffset] = 0f;
+ public final Vec3f rotateVector(final Vec3f vecIn, final Vec3f vecOut) {
+ if( vecIn.isZero() ) {
+ vecOut.set(0, 0, 0);
} else {
- final float vecX = vecIn[0+vecInOffset];
- final float vecY = vecIn[1+vecInOffset];
- final float vecZ = vecIn[2+vecInOffset];
+ final float vecX = vecIn.x();
+ final float vecY = vecIn.y();
+ final float vecZ = vecIn.z();
final float x_x = x*x;
final float y_y = y*y;
final float z_z = z*z;
final float w_w = w*w;
- vecOut[0+vecOutOffset] = w_w * vecX
- + x_x * vecX
- - z_z * vecX
- - y_y * vecX
- + 2f * ( y*w*vecZ - z*w*vecY + y*x*vecY + z*x*vecZ );
+ vecOut.setX( w_w * vecX
+ + x_x * vecX
+ - z_z * vecX
+ - y_y * vecX
+ + 2f * ( y*w*vecZ - z*w*vecY + y*x*vecY + z*x*vecZ ) );
;
- vecOut[1+vecOutOffset] = y_y * vecY
- - z_z * vecY
- + w_w * vecY
- - x_x * vecY
- + 2f * ( x*y*vecX + z*y*vecZ + w*z*vecX - x*w*vecZ );
- ;
-
- vecOut[2+vecOutOffset] = z_z * vecZ
- - y_y * vecZ
- - x_x * vecZ
- + w_w * vecZ
- + 2f * ( x*z*vecX + y*z*vecY - w*y*vecX + w*x*vecY );
- ;
+ vecOut.setY( y_y * vecY
+ - z_z * vecY
+ + w_w * vecY
+ - x_x * vecY
+ + 2f * ( x*y*vecX + z*y*vecZ + w*z*vecX - x*w*vecZ ) );;
+
+ vecOut.setZ( z_z * vecZ
+ - y_y * vecZ
+ - x_x * vecZ
+ + w_w * vecZ
+ + 2f * ( x*z*vecX + y*z*vecY - w*y*vecX + w*x*vecY ) );
}
return vecOut;
}
@@ -593,21 +587,19 @@ public class Quaternion {
* @return this quaternion for chaining.
* @see <a href="http://www.euclideanspace.com/maths/algebra/vectors/lookat/index.htm">euclideanspace.com-LookUp</a>
*/
- public Quaternion setLookAt(final float[] directionIn, final float[] upIn,
- final float[] xAxisOut, final float[] yAxisOut, final float[] zAxisOut) {
+ public Quaternion setLookAt(final Vec3f directionIn, final Vec3f upIn,
+ final Vec3f xAxisOut, final Vec3f yAxisOut, final Vec3f zAxisOut) {
// Z = norm(dir)
- VectorUtil.normalizeVec3(zAxisOut, directionIn);
+ zAxisOut.set(directionIn).normalize();
// X = upIn x Z
// (borrow yAxisOut for upNorm)
- VectorUtil.normalizeVec3(yAxisOut, upIn);
- VectorUtil.crossVec3(xAxisOut, yAxisOut, zAxisOut);
- VectorUtil.normalizeVec3(xAxisOut);
+ yAxisOut.set(upIn).normalize();
+ xAxisOut.cross(yAxisOut, zAxisOut).normalize();
// Y = Z x X
//
- VectorUtil.crossVec3(yAxisOut, zAxisOut, xAxisOut);
- VectorUtil.normalizeVec3(yAxisOut);
+ yAxisOut.cross(zAxisOut, xAxisOut).normalize();
/**
final float m00 = xAxisOut[0];
@@ -642,42 +634,42 @@ public class Quaternion {
* </p>
* @param v1 not normalized
* @param v2 not normalized
- * @param tmpPivotVec float[3] temp storage for cross product
- * @param tmpNormalVec float[3] temp storage to normalize vector
+ * @param tmpPivotVec temp storage for cross product
+ * @param tmpNormalVec temp storage to normalize vector
* @return this quaternion for chaining.
*/
- public final Quaternion setFromVectors(final float[] v1, final float[] v2, final float[] tmpPivotVec, final float[] tmpNormalVec) {
- final float factor = VectorUtil.normVec3(v1) * VectorUtil.normVec3(v2);
+ public final Quaternion setFromVectors(final Vec3f v1, final Vec3f v2, final Vec3f tmpPivotVec, final Vec3f tmpNormalVec) {
+ final float factor = v1.length() * v2.length();
if ( FloatUtil.isZero(factor, FloatUtil.EPSILON ) ) {
return setIdentity();
} else {
- final float dot = VectorUtil.dotVec3(v1, v2) / factor; // normalize
+ final float dot = v1.dot(v2) / factor; // normalize
final float theta = FloatUtil.acos(Math.max(-1.0f, Math.min(dot, 1.0f))); // clipping [-1..1]
- VectorUtil.crossVec3(tmpPivotVec, v1, v2);
+ tmpPivotVec.cross(v1, v2);
- if ( dot < 0.0f && FloatUtil.isZero( VectorUtil.normVec3(tmpPivotVec), FloatUtil.EPSILON ) ) {
+ if ( dot < 0.0f && FloatUtil.isZero( tmpPivotVec.length(), FloatUtil.EPSILON ) ) {
// Vectors parallel and opposite direction, therefore a rotation of 180 degrees about any vector
// perpendicular to this vector will rotate vector a onto vector b.
//
// The following guarantees the dot-product will be 0.0.
int dominantIndex;
- if (Math.abs(v1[0]) > Math.abs(v1[1])) {
- if (Math.abs(v1[0]) > Math.abs(v1[2])) {
+ if (Math.abs(v1.x()) > Math.abs(v1.y())) {
+ if (Math.abs(v1.x()) > Math.abs(v1.z())) {
dominantIndex = 0;
} else {
dominantIndex = 2;
}
} else {
- if (Math.abs(v1[1]) > Math.abs(v1[2])) {
+ if (Math.abs(v1.y()) > Math.abs(v1.z())) {
dominantIndex = 1;
} else {
dominantIndex = 2;
}
}
- tmpPivotVec[dominantIndex] = -v1[(dominantIndex + 1) % 3];
- tmpPivotVec[(dominantIndex + 1) % 3] = v1[dominantIndex];
- tmpPivotVec[(dominantIndex + 2) % 3] = 0f;
+ tmpPivotVec.set( dominantIndex, -v1.get( (dominantIndex + 1) % 3 ) );
+ tmpPivotVec.set( (dominantIndex + 1) % 3, v1.get( dominantIndex ) );
+ tmpPivotVec.set( (dominantIndex + 2) % 3, 0f );
}
return setFromAngleAxis(theta, tmpPivotVec, tmpNormalVec);
}
@@ -698,41 +690,41 @@ public class Quaternion {
* </p>
* @param v1 normalized
* @param v2 normalized
- * @param tmpPivotVec float[3] temp storage for cross product
+ * @param tmpPivotVec temp storage for cross product
* @return this quaternion for chaining.
*/
- public final Quaternion setFromNormalVectors(final float[] v1, final float[] v2, final float[] tmpPivotVec) {
- final float factor = VectorUtil.normVec3(v1) * VectorUtil.normVec3(v2);
+ public final Quaternion setFromNormalVectors(final Vec3f v1, final Vec3f v2, final Vec3f tmpPivotVec) {
+ final float factor = v1.length() * v2.length();
if ( FloatUtil.isZero(factor, FloatUtil.EPSILON ) ) {
return setIdentity();
} else {
- final float dot = VectorUtil.dotVec3(v1, v2) / factor; // normalize
+ final float dot = v1.dot(v2) / factor; // normalize
final float theta = FloatUtil.acos(Math.max(-1.0f, Math.min(dot, 1.0f))); // clipping [-1..1]
- VectorUtil.crossVec3(tmpPivotVec, v1, v2);
+ tmpPivotVec.cross(v1, v2);
- if ( dot < 0.0f && FloatUtil.isZero( VectorUtil.normVec3(tmpPivotVec), FloatUtil.EPSILON ) ) {
+ if ( dot < 0.0f && FloatUtil.isZero( tmpPivotVec.length(), FloatUtil.EPSILON ) ) {
// Vectors parallel and opposite direction, therefore a rotation of 180 degrees about any vector
// perpendicular to this vector will rotate vector a onto vector b.
//
// The following guarantees the dot-product will be 0.0.
int dominantIndex;
- if (Math.abs(v1[0]) > Math.abs(v1[1])) {
- if (Math.abs(v1[0]) > Math.abs(v1[2])) {
+ if (Math.abs(v1.x()) > Math.abs(v1.y())) {
+ if (Math.abs(v1.x()) > Math.abs(v1.z())) {
dominantIndex = 0;
} else {
dominantIndex = 2;
}
} else {
- if (Math.abs(v1[1]) > Math.abs(v1[2])) {
+ if (Math.abs(v1.y()) > Math.abs(v1.z())) {
dominantIndex = 1;
} else {
dominantIndex = 2;
}
}
- tmpPivotVec[dominantIndex] = -v1[(dominantIndex + 1) % 3];
- tmpPivotVec[(dominantIndex + 1) % 3] = v1[dominantIndex];
- tmpPivotVec[(dominantIndex + 2) % 3] = 0f;
+ tmpPivotVec.set( dominantIndex, -v1.get( (dominantIndex + 1) % 3 ) );
+ tmpPivotVec.set( (dominantIndex + 1) % 3, v1.get( dominantIndex ) );
+ tmpPivotVec.set( (dominantIndex + 2) % 3, 0f );
}
return setFromAngleNormalAxis(theta, tmpPivotVec);
}
@@ -748,14 +740,14 @@ public class Quaternion {
* </p>
* @param angle rotation angle (rads)
* @param vector axis vector not normalized
- * @param tmpV3f float[3] temp storage to normalize vector
+ * @param tmpV3f temp storage to normalize vector
* @return this quaternion for chaining.
*
* @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56">Matrix-FAQ Q56</a>
- * @see #toAngleAxis(float[])
+ * @see #toAngleAxis(Vec3f)
*/
- public final Quaternion setFromAngleAxis(final float angle, final float[] vector, final float[] tmpV3f) {
- VectorUtil.normalizeVec3(tmpV3f, vector);
+ public final Quaternion setFromAngleAxis(final float angle, final Vec3f vector, final Vec3f tmpV3f) {
+ tmpV3f.set(vector).normalize();
return setFromAngleNormalAxis(angle, tmpV3f);
}
@@ -772,17 +764,17 @@ public class Quaternion {
* @return this quaternion for chaining.
*
* @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56">Matrix-FAQ Q56</a>
- * @see #toAngleAxis(float[])
+ * @see #toAngleAxis(Vec3f)
*/
- public final Quaternion setFromAngleNormalAxis(final float angle, final float[] vector) {
- if ( VectorUtil.isVec3Zero(vector, 0, FloatUtil.EPSILON) ) {
+ public final Quaternion setFromAngleNormalAxis(final float angle, final Vec3f vector) {
+ if( vector.isZero() ) {
setIdentity();
} else {
final float halfangle = angle * 0.5f;
final float sin = FloatUtil.sin(halfangle);
- x = vector[0] * sin;
- y = vector[1] * sin;
- z = vector[2] * sin;
+ x = vector.x() * sin;
+ y = vector.y() * sin;
+ z = vector.z() * sin;
w = FloatUtil.cos(halfangle);
}
return this;
@@ -791,24 +783,22 @@ public class Quaternion {
/**
* Transform the rotational quaternion to axis based rotation angles
*
- * @param axis float[3] storage for computed axis
+ * @param axis storage for computed axis
* @return the rotation angle in radians
- * @see #setFromAngleAxis(float, float[], float[])
+ * @see #setFromAngleAxis(float, Vec3f, Vec3f)
*/
- public final float toAngleAxis(final float[] axis) {
+ public final float toAngleAxis(final Vec3f axis) {
final float sqrLength = x*x + y*y + z*z;
float angle;
if ( FloatUtil.isZero(sqrLength, FloatUtil.EPSILON) ) { // length is ~0
angle = 0.0f;
- axis[0] = 1.0f;
- axis[1] = 0.0f;
- axis[2] = 0.0f;
+ axis.set( 1.0f, 0.0f, 0.0f );
} else {
angle = FloatUtil.acos(w) * 2.0f;
final float invLength = 1.0f / FloatUtil.sqrt(sqrLength);
- axis[0] = x * invLength;
- axis[1] = y * invLength;
- axis[2] = z * invLength;
+ axis.set( x * invLength,
+ y * invLength,
+ z * invLength );
}
return angle;
}
@@ -816,7 +806,7 @@ public class Quaternion {
/**
* Initializes this quaternion from the given Euler rotation array <code>angradXYZ</code> in radians.
* <p>
- * The <code>angradXYZ</code> array is laid out in natural order:
+ * The <code>angradXYZ</code> vector is laid out in natural order:
* <ul>
* <li>x - bank</li>
* <li>y - heading</li>
@@ -824,12 +814,12 @@ public class Quaternion {
* </ul>
* </p>
* For details see {@link #setFromEuler(float, float, float)}.
- * @param angradXYZ euler angel array in radians
+ * @param angradXYZ euler angle vector in radians holding x-bank, y-heading and z-attitude
* @return this quaternion for chaining.
* @see #setFromEuler(float, float, float)
*/
- public final Quaternion setFromEuler(final float[] angradXYZ) {
- return setFromEuler(angradXYZ[0], angradXYZ[1], angradXYZ[2]);
+ public final Quaternion setFromEuler(final Vec3f angradXYZ) {
+ return setFromEuler(angradXYZ.x(), angradXYZ.y(), angradXYZ.z());
}
/**
@@ -857,7 +847,7 @@ public class Quaternion {
* @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q60">Matrix-FAQ Q60</a>
* @see <a href="http://vered.rose.utoronto.ca/people/david_dir/GEMS/GEMS.html">Gems</a>
* @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm">euclideanspace.com-eulerToQuaternion</a>
- * @see #toEuler(float[])
+ * @see #toEuler(Vec3f)
*/
public final Quaternion setFromEuler(final float bankX, final float headingY, final float attitudeZ) {
if ( VectorUtil.isZero(bankX, headingY, attitudeZ, FloatUtil.EPSILON) ) {
@@ -889,58 +879,45 @@ public class Quaternion {
/**
* Transform this quaternion to Euler rotation angles in radians (pitchX, yawY and rollZ).
+ * <p>
+ * The <code>result</code> array is laid out in natural order:
+ * <ul>
+ * <li>x - bank</li>
+ * <li>y - heading</li>
+ * <li>z - attitude</li>
+ * </ul>
+ * </p>
*
- * @param result the float[] array storing the computed angles.
- * @return the double[] array, filled with heading, attitude and bank in that order..
+ * @param result euler angle result vector for radians x-bank, y-heading and z-attitude
+ * @return the Vec3f `result` filled with x-bank, y-heading and z-attitude
* @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm">euclideanspace.com-quaternionToEuler</a>
* @see #setFromEuler(float, float, float)
*/
- public float[] toEuler(final float[] result) {
+ public Vec3f toEuler(final Vec3f result) {
final float sqw = w*w;
final float sqx = x*x;
final float sqy = y*y;
final float sqz = z*z;
- final float unit = sqx + sqy + sqz + sqw; // if normalized is one, otherwise
- // is correction factor
+ final float unit = sqx + sqy + sqz + sqw; // if normalized is one, otherwise, is correction factor
final float test = x*y + z*w;
if (test > 0.499f * unit) { // singularity at north pole
- result[0] = 0f;
- result[1] = 2f * FloatUtil.atan2(x, w);
- result[2] = FloatUtil.HALF_PI;
+ result.set( 0f, // x-bank
+ 2f * FloatUtil.atan2(x, w), // y-heading
+ FloatUtil.HALF_PI ); // z-attitude
} else if (test < -0.499f * unit) { // singularity at south pole
- result[0] = 0f;
- result[1] = -2 * FloatUtil.atan2(x, w);
- result[2] = -FloatUtil.HALF_PI;
+ result.set( 0f, // x-bank
+ -2 * FloatUtil.atan2(x, w), // y-heading
+ -FloatUtil.HALF_PI ); // z-attitude
} else {
- result[0] = FloatUtil.atan2(2f * x * w - 2 * y * z, -sqx + sqy - sqz + sqw);
- result[1] = FloatUtil.atan2(2f * y * w - 2 * x * z, sqx - sqy - sqz + sqw);
- result[2] = FloatUtil.asin( 2f * test / unit);
+ result.set( FloatUtil.atan2(2f * x * w - 2 * y * z, -sqx + sqy - sqz + sqw), // x-bank
+ FloatUtil.atan2(2f * y * w - 2 * x * z, sqx - sqy - sqz + sqw), // y-heading
+ FloatUtil.asin( 2f * test / unit) ); // z-attitude
}
return result;
}
/**
- * Initializes this quaternion from a 4x4 column rotation matrix
- * <p>
- * See <a href="ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z">Graphics Gems Code</a>,<br/>
- * <a href="http://mathworld.wolfram.com/MatrixTrace.html">MatrixTrace</a>.
- * </p>
- * <p>
- * Buggy <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q55">Matrix-FAQ Q55</a>
- * </p>
- *
- * @param m 4x4 column matrix
- * @return this quaternion for chaining.
- * @see #toMatrix(float[], int)
- */
- public final Quaternion setFromMatrix(final float[] m, final int m_off) {
- return setFromMatrix(m[0+0*4+m_off], m[0+1*4+m_off], m[0+2*4+m_off],
- m[1+0*4+m_off], m[1+1*4+m_off], m[1+2*4+m_off],
- m[2+0*4+m_off], m[2+1*4+m_off], m[2+2*4+m_off]);
- }
-
- /**
* Compute the quaternion from a 3x3 column rotation matrix
* <p>
* See <a href="ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z">Graphics Gems Code</a>,<br/>
@@ -951,7 +928,7 @@ public class Quaternion {
* </p>
*
* @return this quaternion for chaining.
- * @see #toMatrix(float[], int)
+ * @see #setFromMatrix(Matrix4f)
*/
public Quaternion setFromMatrix(final float m00, final float m01, final float m02,
final float m10, final float m11, final float m12,
@@ -996,6 +973,24 @@ public class Quaternion {
}
/**
+ * Compute the quaternion from a 3x3 column rotation matrix
+ * <p>
+ * See <a href="ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z">Graphics Gems Code</a>,<br/>
+ * <a href="http://mathworld.wolfram.com/MatrixTrace.html">MatrixTrace</a>.
+ * </p>
+ * <p>
+ * Buggy <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q55">Matrix-FAQ Q55</a>
+ * </p>
+ *
+ * @return this quaternion for chaining.
+ * @see Matrix4f#getRotation(Quaternion)
+ * @see #setFromMatrix(float, float, float, float, float, float, float, float, float)
+ */
+ public Quaternion setFromMatrix(final Matrix4f m) {
+ return m.getRotation(this);
+ }
+
+ /**
* Transform this quaternion to a normalized 4x4 column matrix representing the rotation.
* <p>
* Implementation Details:
@@ -1005,17 +1000,17 @@ public class Quaternion {
* </p>
*
* @param matrix float[16] store for the resulting normalized column matrix 4x4
- * @param mat_offset
* @return the given matrix store
* @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54">Matrix-FAQ Q54</a>
- * @see #setFromMatrix(float[], int)
+ * @see #setFromMatrix(Matrix4f)
+ * @see #setFromMatrix(float, float, float, float, float, float, float, float, float)
*/
- public final float[] toMatrix(final float[] matrix, final int mat_offset) {
+ public final float[] toMatrix(final float[] matrix) {
// pre-multiply scaled-reciprocal-magnitude to reduce multiplications
final float norm = magnitudeSquared();
if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) {
// identity matrix -> srecip = 0f
- return FloatUtil.makeIdentity(matrix, mat_offset);
+ return FloatUtil.makeIdentity(matrix);
}
final float srecip;
if ( FloatUtil.isEqual(1f, norm, FloatUtil.EPSILON) ) {
@@ -1038,81 +1033,45 @@ public class Quaternion {
final float zz = z * zs;
final float zw = zs * w;
- matrix[0+0*4+mat_offset] = 1f - ( yy + zz );
- matrix[0+1*4+mat_offset] = ( xy - zw );
- matrix[0+2*4+mat_offset] = ( xz + yw );
- matrix[0+3*4+mat_offset] = 0f;
-
- matrix[1+0*4+mat_offset] = ( xy + zw );
- matrix[1+1*4+mat_offset] = 1f - ( xx + zz );
- matrix[1+2*4+mat_offset] = ( yz - xw );
- matrix[1+3*4+mat_offset] = 0f;
-
- matrix[2+0*4+mat_offset] = ( xz - yw );
- matrix[2+1*4+mat_offset] = ( yz + xw );
- matrix[2+2*4+mat_offset] = 1f - ( xx + yy );
- matrix[2+3*4+mat_offset] = 0f;
-
- matrix[3+0*4+mat_offset] = 0f;
- matrix[3+1*4+mat_offset] = 0f;
- matrix[3+2*4+mat_offset] = 0f;
- matrix[3+3*4+mat_offset] = 1f;
+ matrix[0+0*4] = 1f - ( yy + zz );
+ matrix[0+1*4] = ( xy - zw );
+ matrix[0+2*4] = ( xz + yw );
+ matrix[0+3*4] = 0f;
+
+ matrix[1+0*4] = ( xy + zw );
+ matrix[1+1*4] = 1f - ( xx + zz );
+ matrix[1+2*4] = ( yz - xw );
+ matrix[1+3*4] = 0f;
+
+ matrix[2+0*4] = ( xz - yw );
+ matrix[2+1*4] = ( yz + xw );
+ matrix[2+2*4] = 1f - ( xx + yy );
+ matrix[2+3*4] = 0f;
+
+ matrix[3+0*4] = 0f;
+ matrix[3+1*4] = 0f;
+ matrix[3+2*4] = 0f;
+ matrix[3+3*4] = 1f;
return matrix;
}
/**
- * @param index the 3x3 rotation matrix column to retrieve from this quaternion (normalized). Must be between 0 and 2.
- * @param result the vector object to store the result in.
- * @return the result column-vector for chaining.
+ * Transform this quaternion to a normalized 4x4 column matrix representing the rotation.
+ * <p>
+ * Implementation Details:
+ * <ul>
+ * <li> makes identity matrix if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li>
+ * </ul>
+ * </p>
+ *
+ * @param matrix store for the resulting normalized column matrix 4x4
+ * @return the given matrix store
+ * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54">Matrix-FAQ Q54</a>
+ * @see #setFromMatrix(float, float, float, float, float, float, float, float, float)
+ * @see Matrix4f#setToRotation(Quaternion)
*/
- public float[] copyMatrixColumn(final int index, final float[] result, final int resultOffset) {
- // pre-multipliy scaled-reciprocal-magnitude to reduce multiplications
- final float norm = magnitudeSquared();
- final float srecip;
- if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) {
- srecip= 0f;
- } else if ( FloatUtil.isEqual(1f, norm, FloatUtil.EPSILON) ) {
- srecip= 2f;
- } else {
- srecip= 2.0f / norm;
- }
-
- // compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs
- // will be used 2-4 times each.
- final float xs = x * srecip;
- final float ys = y * srecip;
- final float zs = z * srecip;
- final float xx = x * xs;
- final float xy = x * ys;
- final float xz = x * zs;
- final float xw = w * xs;
- final float yy = y * ys;
- final float yz = y * zs;
- final float yw = w * ys;
- final float zz = z * zs;
- final float zw = w * zs;
-
- // using s=2/norm (instead of 1/norm) saves 3 multiplications by 2 here
- switch (index) {
- case 0:
- result[0+resultOffset] = 1.0f - (yy + zz);
- result[1+resultOffset] = xy + zw;
- result[2+resultOffset] = xz - yw;
- break;
- case 1:
- result[0+resultOffset] = xy - zw;
- result[1+resultOffset] = 1.0f - (xx + zz);
- result[2+resultOffset] = yz + xw;
- break;
- case 2:
- result[0+resultOffset] = xz + yw;
- result[1+resultOffset] = yz - xw;
- result[2+resultOffset] = 1.0f - (xx + yy);
- break;
- default:
- throw new IllegalArgumentException("Invalid column index. " + index);
- }
- return result;
+ public final Matrix4f toMatrix(final Matrix4f matrix) {
+ return matrix.setToRotation(this);
}
/**
@@ -1126,10 +1085,10 @@ public class Quaternion {
* @param zAxis vector representing the <i>orthogonal</i> z-axis of the coordinate system.
* @return this quaternion for chaining.
*/
- public final Quaternion setFromAxes(final float[] xAxis, final float[] yAxis, final float[] zAxis) {
- return setFromMatrix(xAxis[0], yAxis[0], zAxis[0],
- xAxis[1], yAxis[1], zAxis[1],
- xAxis[2], yAxis[2], zAxis[2]);
+ public final Quaternion setFromAxes(final Vec3f xAxis, final Vec3f yAxis, final Vec3f zAxis) {
+ return setFromMatrix(xAxis.x(), yAxis.x(), zAxis.x(),
+ xAxis.y(), yAxis.y(), zAxis.y(),
+ xAxis.z(), yAxis.z(), zAxis.z());
}
/**
@@ -1140,11 +1099,11 @@ public class Quaternion {
* @param zAxis vector representing the <i>orthogonal</i> z-axis of the coordinate system.
* @param tmpMat4 temporary float[4] matrix, used to transform this quaternion to a matrix.
*/
- public void toAxes(final float[] xAxis, final float[] yAxis, final float[] zAxis, final float[] tmpMat4) {
- toMatrix(tmpMat4, 0);
- FloatUtil.copyMatrixColumn(tmpMat4, 0, 2, zAxis, 0);
- FloatUtil.copyMatrixColumn(tmpMat4, 0, 1, yAxis, 0);
- FloatUtil.copyMatrixColumn(tmpMat4, 0, 0, xAxis, 0);
+ public void toAxes(final Vec3f xAxis, final Vec3f yAxis, final Vec3f zAxis, final Matrix4f tmpMat4) {
+ tmpMat4.setToRotation(this);
+ tmpMat4.getColumn(2, zAxis);
+ tmpMat4.getColumn(1, yAxis);
+ tmpMat4.getColumn(0, xAxis);
}
/**
@@ -1154,6 +1113,7 @@ public class Quaternion {
* @param m 3x3 column matrix
* @return true if representing a rotational matrix, false otherwise
*/
+ @Deprecated
public final boolean isRotationMatrix3f(final float[] m) {
final float epsilon = 0.01f; // margin to allow for rounding errors
if (FloatUtil.abs(m[0] * m[3] + m[3] * m[4] + m[6] * m[7]) > epsilon)
@@ -1171,6 +1131,7 @@ public class Quaternion {
return (FloatUtil.abs(determinant3f(m) - 1) < epsilon);
}
+ @Deprecated
private final float determinant3f(final float[] m) {
return m[0] * m[4] * m[8] + m[3] * m[7] * m[2] + m[6] * m[1] * m[5]
- m[0] * m[7] * m[5] - m[3] * m[1] * m[8] - m[6] * m[4] * m[2];
@@ -1193,17 +1154,18 @@ public class Quaternion {
return false;
}
final Quaternion comp = (Quaternion) o;
- return Math.abs(x - comp.getX()) <= ALLOWED_DEVIANCE &&
- Math.abs(y - comp.getY()) <= ALLOWED_DEVIANCE &&
- Math.abs(z - comp.getZ()) <= ALLOWED_DEVIANCE &&
- Math.abs(w - comp.getW()) <= ALLOWED_DEVIANCE;
+ return Math.abs(x - comp.x()) <= ALLOWED_DEVIANCE &&
+ Math.abs(y - comp.y()) <= ALLOWED_DEVIANCE &&
+ Math.abs(z - comp.z()) <= ALLOWED_DEVIANCE &&
+ Math.abs(w - comp.w()) <= ALLOWED_DEVIANCE;
}
@Override
public final int hashCode() {
throw new InternalError("hashCode not designed");
}
+ @Override
public String toString() {
- return "Quaternion[x "+x+", y "+y+", z "+z+", w "+w+"]";
+ return "Quat[x "+x+", y "+y+", z "+z+", w "+w+"]";
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Ray.java b/src/jogl/classes/com/jogamp/opengl/math/Ray.java
index 4d651d1c3..25a7d9a70 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/Ray.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/Ray.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -47,13 +47,14 @@ import com.jogamp.opengl.math.geom.AABBox;
* </p>
*/
public class Ray {
- /** Origin of Ray, float[3]. */
- public final float[] orig = new float[3];
+ /** Origin of Ray. */
+ public final Vec3f orig = new Vec3f();
- /** Normalized direction vector of ray, float[3]. */
- public final float[] dir = new float[3];
+ /** Normalized direction vector of ray. */
+ public final Vec3f dir = new Vec3f();
+ @Override
public String toString() {
- return "Ray[orig["+orig[0]+", "+orig[1]+", "+orig[2]+"], dir["+dir[0]+", "+dir[1]+", "+dir[2]+"]]";
+ return "Ray[orig["+orig+"], dir["+dir+"]]";
}
} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Recti.java b/src/jogl/classes/com/jogamp/opengl/math/Recti.java
new file mode 100644
index 000000000..58f5e5e77
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/math/Recti.java
@@ -0,0 +1,134 @@
+/**
+ * Copyright 2022-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.math;
+
+/**
+ * Rectangle with x, y, width and height integer components.
+ */
+public final class Recti {
+ private int x;
+ private int y;
+ private int width;
+ private int height;
+
+ public Recti() {}
+
+ public Recti(final Recti o) {
+ set(o);
+ }
+
+ public Recti copy() {
+ return new Recti(this);
+ }
+
+ public Recti(final int[/*4*/] xywh) {
+ set(xywh);
+ }
+
+ public Recti(final int x, final int y, final int width, final int height) {
+ set(x, y, width, height);
+ }
+
+ /** this = o, returns this. */
+ public void set(final Recti o) {
+ this.x = o.x;
+ this.y = o.y;
+ this.width = o.width;
+ this.height= o.height;
+ }
+
+ /** this = { x, y, width, height }, returns this. */
+ public void set(final int x, final int y, final int width, final int height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height= height;
+ }
+
+ /** this = xywh, returns this. */
+ public Recti set(final int[/*2*/] xywh) {
+ this.x = xywh[0];
+ this.y = xywh[1];
+ this.width = xywh[2];
+ this.height= xywh[3];
+ return this;
+ }
+
+ /** xywh = this, returns xy. */
+ public int[] get(final int[/*4*/] xywh) {
+ xywh[0] = this.x;
+ xywh[1] = this.y;
+ xywh[2] = this.width;
+ xywh[3] = this.height;
+ return xywh;
+ }
+
+ public int x() { return x; }
+ public int y() { return y; }
+ public int width() { return width; }
+ public int height() { return height; }
+
+ public void setX(final int x) { this.x = x; }
+ public void setY(final int y) { this.y = y; }
+ public void setWidth(final int width) { this.width = width; }
+ public void setHeight(final int height) { this.height = height; }
+
+ /** Return true if all components are zero. */
+ public boolean isZero() {
+ return 0 == x && 0 == y;
+ }
+
+ /**
+ * Equals check.
+ * @param o comparison value
+ * @return true if all components are equal
+ */
+ public boolean isEqual(final Recti o) {
+ if( this == o ) {
+ return true;
+ } else {
+ return x == o.x && y == o.y &&
+ width == o.width && height == o.height;
+ }
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if( o instanceof Recti ) {
+ return isEqual((Recti)o);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return x + " / " + y + " " + width + " x " + height;
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vec2f.java b/src/jogl/classes/com/jogamp/opengl/math/Vec2f.java
new file mode 100644
index 000000000..47d1a78dc
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/math/Vec2f.java
@@ -0,0 +1,377 @@
+/**
+ * Copyright 2022-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.math;
+
+/**
+ * 2D Vector based upon two float components.
+ *
+ * Implementation borrowed from [gfxbox2](https://jausoft.com/cgit/cs_class/gfxbox2.git/tree/include/pixel/pixel2f.hpp#n29)
+ * and its data layout from JOAL's Vec3f.
+ */
+public final class Vec2f {
+ private float x;
+ private float y;
+
+ public static Vec2f from_length_angle(final float magnitude, final float radians) {
+ return new Vec2f((float)(magnitude * Math.cos(radians)), (float)(magnitude * Math.sin(radians)));
+ }
+
+ public Vec2f() {}
+
+ public Vec2f(final Vec2f o) {
+ set(o);
+ }
+
+ /** Creating new Vec2f using Vec3f, dropping z. */
+ public Vec2f(final Vec3f o) {
+ set(o);
+ }
+
+ public Vec2f copy() {
+ return new Vec2f(this);
+ }
+
+ public Vec2f(final float[/*2*/] xy) {
+ set(xy);
+ }
+
+ public Vec2f(final float x, final float y) {
+ set(x, y);
+ }
+
+ /** this = o, returns this. */
+ public void set(final Vec2f o) {
+ this.x = o.x;
+ this.y = o.y;
+ }
+
+ /** this = o while dropping z, returns this. */
+ public void set(final Vec3f o) {
+ this.x = o.x();
+ this.y = o.y();
+ }
+
+ /** this = { x, y }, returns this. */
+ public void set(final float x, final float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /** this = xy, returns this. */
+ public Vec2f set(final float[/*2*/] xy) {
+ this.x = xy[0];
+ this.y = xy[1];
+ return this;
+ }
+
+ /** Sets the ith component, 0 <= i < 2 */
+ public void set(final int i, final float val) {
+ switch (i) {
+ case 0: x = val; break;
+ case 1: y = val; break;
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /** xy = this, returns xy. */
+ public float[] get(final float[/*2*/] xy) {
+ xy[0] = this.x;
+ xy[1] = this.y;
+ return xy;
+ }
+
+ /** Gets the ith component, 0 <= i < 2 */
+ public float get(final int i) {
+ switch (i) {
+ case 0: return x;
+ case 1: return y;
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public float x() { return x; }
+ public float y() { return y; }
+
+ public void setX(final float x) { this.x = x; }
+ public void setY(final float y) { this.y = y; }
+
+ /** this = max(this, m), returns this. */
+ public Vec2f max(final Vec2f m) {
+ this.x = Math.max(this.x, m.x);
+ this.y = Math.max(this.y, m.y);
+ return this;
+ }
+ /** this = min(this, m), returns this. */
+ public Vec2f min(final Vec2f m) {
+ this.x = Math.min(this.x, m.x);
+ this.y = Math.min(this.y, m.y);
+ return this;
+ }
+
+ /** Returns this * val; creates new vector */
+ public Vec2f mul(final float val) {
+ return new Vec2f(this).scale(val);
+ }
+
+ /** this = a * b, returns this. */
+ public Vec2f mul(final Vec2f a, final Vec2f b) {
+ x = a.x * b.x;
+ y = a.y * b.y;
+ return this;
+ }
+
+ /** this = this * s, returns this. */
+ public Vec2f scale(final float s) {
+ x *= s;
+ y *= s;
+ return this;
+ }
+
+ /** this = this * { sx, sy }, returns this. */
+ public Vec2f scale(final float sx, final float sy) {
+ x *= sx;
+ y *= sy;
+ return this;
+ }
+
+ /** Returns this + arg; creates new vector */
+ public Vec2f plus(final Vec2f arg) {
+ return new Vec2f(this).add(arg);
+ }
+
+ /** this = a + b, returns this. */
+ public Vec2f plus(final Vec2f a, final Vec2f b) {
+ x = a.x + b.x;
+ y = a.y + b.y;
+ return this;
+ }
+
+ /** this = this + { dx, dy }, returns this. */
+ public Vec2f add(final float dx, final float dy) {
+ x += dx;
+ y += dy;
+ return this;
+ }
+
+ /** this = this + b, returns this. */
+ public Vec2f add(final Vec2f b) {
+ x += b.x;
+ y += b.y;
+ return this;
+ }
+
+ /** Returns this - arg; creates new vector */
+ public Vec2f minus(final Vec2f arg) {
+ return new Vec2f(this).sub(arg);
+ }
+
+ /** this = a - b, returns this. */
+ public Vec2f minus(final Vec2f a, final Vec2f b) {
+ x = a.x - b.x;
+ y = a.y - b.y;
+ return this;
+ }
+
+ /** this = this - b, returns this. */
+ public Vec2f sub(final Vec2f b) {
+ x -= b.x;
+ y -= b.y;
+ return this;
+ }
+
+ /** Return true if all components are zero, i.e. it's absolute value < {@link #EPSILON}. */
+ public boolean isZero() {
+ return FloatUtil.isZero(x) && FloatUtil.isZero(y);
+ }
+
+ public void rotate(final float radians, final Vec2f ctr) {
+ final float cos = (float)Math.cos(radians);
+ final float sin = (float)Math.sin(radians);
+ rotate(sin, cos, ctr);
+ }
+
+ public void rotate(final float sin, final float cos, final Vec2f ctr) {
+ final float x0 = x - ctr.x;
+ final float y0 = y - ctr.y;
+ final float tmp = x0 * cos - y0 * sin + ctr.x;
+ y = x0 * sin + y0 * cos + ctr.y;
+ x = tmp;
+ }
+
+ /**
+ * Return the length of this vector, a.k.a the <i>norm</i> or <i>magnitude</i>
+ */
+ public float length() {
+ return (float) Math.sqrt(lengthSq());
+ }
+
+ /**
+ * Return the squared length of this vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i>
+ */
+ public float lengthSq() {
+ return x*x + y*y;
+ }
+
+ /**
+ * Return the direction angle of this vector in radians
+ */
+ public float angle() {
+ // Utilize atan2 taking y=sin(a) and x=cos(a), resulting in proper direction angle for all quadrants.
+ return (float) Math.atan2(y, x);
+ }
+
+ /**
+ * Normalize this vector in place
+ */
+ public Vec2f normalize() {
+ final float lengthSq = lengthSq();
+ if ( FloatUtil.isZero( lengthSq ) ) {
+ x = 0.0f;
+ y = 0.0f;
+ } else {
+ final float invSqr = 1.0f / (float)Math.sqrt(lengthSq);
+ x *= invSqr;
+ y *= invSqr;
+ }
+ return this;
+ }
+
+ /**
+ * Return the squared distance between this vector and the given one.
+ * <p>
+ * When comparing the relative distance between two points it is usually sufficient to compare the squared
+ * distances, thus avoiding an expensive square root operation.
+ * </p>
+ */
+ public float distSq(final Vec2f o) {
+ final float dx = x - o.x;
+ final float dy = y - o.y;
+ return dx*dx + dy*dy;
+ }
+
+ /**
+ * Return the distance between this vector and the given one.
+ */
+ public float dist(final Vec2f o) {
+ return (float)Math.sqrt(distSq(o));
+ }
+
+
+ /**
+ * Return the dot product of this vector and the given one
+ * @return the dot product as float
+ */
+ public float dot(final Vec2f arg) {
+ return x * arg.x + y * arg.y;
+ }
+
+ /**
+ * Returns cross product of this vectors and the given one, i.e. *this x o.
+ *
+ * The 2D cross product is identical with the 2D perp dot product.
+ *
+ * @return the resulting scalar
+ */
+ public float cross(final Vec2f o) {
+ return x * o.y - y * o.x;
+ }
+
+ /**
+ * Return the cosines of the angle between two vectors
+ */
+ public float cosAngle(final Vec2f o) {
+ return dot(o) / ( length() * o.length() ) ;
+ }
+
+ /**
+ * Return the angle between two vectors in radians
+ */
+ public float angle(final Vec2f o) {
+ return (float) Math.acos( cosAngle(o) );
+ }
+
+ /**
+ * Return the counter-clock-wise (CCW) normal of this vector, i.e. perp(endicular) vector
+ */
+ public Vec2f normal_ccw() {
+ return new Vec2f(-y, x);
+ }
+
+ /**
+ * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ * <p>
+ * Implementation considers following corner cases:
+ * <ul>
+ * <li>NaN == NaN</li>
+ * <li>+Inf == +Inf</li>
+ * <li>-Inf == -Inf</li>
+ * </ul>
+ * @param o comparison value
+ * @param epsilon consider using {@link FloatUtil#EPSILON}
+ * @return true if all components differ less than {@code epsilon}, otherwise false.
+ */
+ public boolean isEqual(final Vec2f o, final float epsilon) {
+ if( this == o ) {
+ return true;
+ } else {
+ return FloatUtil.isEqual(x, o.x, epsilon) &&
+ FloatUtil.isEqual(y, o.y, epsilon);
+ }
+ }
+
+ /**
+ * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ * <p>
+ * Implementation considers following corner cases:
+ * <ul>
+ * <li>NaN == NaN</li>
+ * <li>+Inf == +Inf</li>
+ * <li>-Inf == -Inf</li>
+ * </ul>
+ * @param o comparison value
+ * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false.
+ */
+ public boolean isEqual(final Vec2f o) {
+ return isEqual(o, FloatUtil.EPSILON);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if( o instanceof Vec2f ) {
+ return isEqual((Vec2f)o, FloatUtil.EPSILON);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return x + " / " + y;
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vec2i.java b/src/jogl/classes/com/jogamp/opengl/math/Vec2i.java
new file mode 100644
index 000000000..9e70a502f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/math/Vec2i.java
@@ -0,0 +1,153 @@
+/**
+ * Copyright 2022-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.math;
+
+/**
+ * 2D Vector based upon two integer components.
+ */
+public final class Vec2i {
+ private int x;
+ private int y;
+
+ public Vec2i() {}
+
+ public Vec2i(final Vec2i o) {
+ set(o);
+ }
+
+ public Vec2i copy() {
+ return new Vec2i(this);
+ }
+
+ public Vec2i(final int[/*2*/] xy) {
+ set(xy);
+ }
+
+ public Vec2i(final int x, final int y) {
+ set(x, y);
+ }
+
+ /** this = o, returns this. */
+ public void set(final Vec2i o) {
+ this.x = o.x;
+ this.y = o.y;
+ }
+
+ /** this = { x, y }, returns this. */
+ public void set(final int x, final int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /** this = xy, returns this. */
+ public Vec2i set(final int[/*2*/] xy) {
+ this.x = xy[0];
+ this.y = xy[1];
+ return this;
+ }
+
+ /** xy = this, returns xy. */
+ public int[] get(final int[/*2*/] xy) {
+ xy[0] = this.x;
+ xy[1] = this.y;
+ return xy;
+ }
+
+ public int x() { return x; }
+ public int y() { return y; }
+
+ public void setX(final int x) { this.x = x; }
+ public void setY(final int y) { this.y = y; }
+
+ /** Return true if all components are zero. */
+ public boolean isZero() {
+ return 0 == x && 0 == y;
+ }
+
+ /**
+ * Return the length of this vector, a.k.a the <i>norm</i> or <i>magnitude</i>
+ */
+ public int length() {
+ return (int) Math.sqrt(lengthSq());
+ }
+
+ /**
+ * Return the squared length of this vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i>
+ */
+ public int lengthSq() {
+ return x*x + y*y;
+ }
+
+ /**
+ * Return the squared distance between this vector and the given one.
+ * <p>
+ * When comparing the relative distance between two points it is usually sufficient to compare the squared
+ * distances, thus avoiding an expensive square root operation.
+ * </p>
+ */
+ public int distSq(final Vec2i o) {
+ final int dx = x - o.x;
+ final int dy = y - o.y;
+ return dx*dx + dy*dy;
+ }
+
+ /**
+ * Return the distance between this vector and the given one.
+ */
+ public int dist(final Vec2i o) {
+ return (int)Math.sqrt(distSq(o));
+ }
+
+ /**
+ * Equals check.
+ * @param o comparison value
+ * @return true if all components are equal
+ */
+ public boolean isEqual(final Vec2i o) {
+ if( this == o ) {
+ return true;
+ } else {
+ return x == o.x && y == o.y;
+ }
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if( o instanceof Vec2i ) {
+ return isEqual((Vec2i)o);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return x + " / " + y;
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vec3f.java b/src/jogl/classes/com/jogamp/opengl/math/Vec3f.java
new file mode 100644
index 000000000..eb1144c07
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/math/Vec3f.java
@@ -0,0 +1,393 @@
+/**
+ * Copyright 2022-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.math;
+
+/**
+ * 3D Vector based upon three float components.
+ *
+ * Implementation borrowed from [gfxbox2](https://jausoft.com/cgit/cs_class/gfxbox2.git/tree/include/pixel/pixel3f.hpp#n29)
+ * and its data layout from JOAL's Vec3f.
+ */
+public final class Vec3f {
+ public static final Vec3f ONE = new Vec3f(1f, 1f, 1f);
+ public static final Vec3f UNIT_Y = new Vec3f(0f, 1f, 0f);
+ public static final Vec3f UNIT_Y_NEG = new Vec3f(0f, -1f, 0f);
+ public static final Vec3f UNIT_Z = new Vec3f(0f, 0f, 1f);
+ public static final Vec3f UNIT_Z_NEG = new Vec3f(0f, 0f, -1f);
+
+ private float x;
+ private float y;
+ private float z;
+
+ public Vec3f() {}
+
+ public Vec3f(final Vec3f o) {
+ set(o);
+ }
+
+ /** Creating new Vec3f using Vec4f, dropping w. */
+ public Vec3f(final Vec4f o) {
+ set(o);
+ }
+
+ /** Creating new Vec3f using { Vec2f, z}. */
+ public Vec3f(final Vec2f o, final float z) {
+ set(o, z);
+ }
+
+ public Vec3f copy() {
+ return new Vec3f(this);
+ }
+
+ public Vec3f(final float[/*3*/] xyz) {
+ set(xyz);
+ }
+
+ public Vec3f(final float x, final float y, final float z) {
+ set(x, y, z);
+ }
+
+ /** this = o, returns this. */
+ public Vec3f set(final Vec3f o) {
+ this.x = o.x;
+ this.y = o.y;
+ this.z = o.z;
+ return this;
+ }
+
+ /** this = { o, z }, returns this. */
+ public Vec3f set(final Vec2f o, final float z) {
+ this.x = o.x();
+ this.y = o.y();
+ this.z = z;
+ return this;
+ }
+
+ /** this = o while dropping w, returns this. */
+ public Vec3f set(final Vec4f o) {
+ this.x = o.x();
+ this.y = o.y();
+ this.z = o.z();
+ return this;
+ }
+
+ /** this = { x, y, z }, returns this. */
+ public Vec3f set(final float x, final float y, final float z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+
+ /** this = xyz, returns this. */
+ public Vec3f set(final float[/*3*/] xyz) {
+ this.x = xyz[0];
+ this.y = xyz[1];
+ this.z = xyz[2];
+ return this;
+ }
+
+ /** Sets the ith component, 0 <= i < 3 */
+ public void set(final int i, final float val) {
+ switch (i) {
+ case 0: x = val; break;
+ case 1: y = val; break;
+ case 2: z = val; break;
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /** xyz = this, returns xyz. */
+ public float[] get(final float[/*3*/] xyz) {
+ xyz[0] = this.x;
+ xyz[1] = this.y;
+ xyz[2] = this.z;
+ return xyz;
+ }
+
+ /** Gets the ith component, 0 <= i < 3 */
+ public float get(final int i) {
+ switch (i) {
+ case 0: return x;
+ case 1: return y;
+ case 2: return z;
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public float x() { return x; }
+ public float y() { return y; }
+ public float z() { return z; }
+
+ public void setX(final float x) { this.x = x; }
+ public void setY(final float y) { this.y = y; }
+ public void setZ(final float z) { this.z = z; }
+
+ /** this = max(this, m), returns this. */
+ public Vec3f max(final Vec3f m) {
+ this.x = Math.max(this.x, m.x);
+ this.y = Math.max(this.y, m.y);
+ this.z = Math.max(this.z, m.z);
+ return this;
+ }
+ /** this = min(this, m), returns this. */
+ public Vec3f min(final Vec3f m) {
+ this.x = Math.min(this.x, m.x);
+ this.y = Math.min(this.y, m.y);
+ this.z = Math.min(this.z, m.z);
+ return this;
+ }
+
+ /** Returns this * val; creates new vector */
+ public Vec3f mul(final float val) {
+ return new Vec3f(this).scale(val);
+ }
+
+ /** this = a * b, returns this. */
+ public Vec3f mul(final Vec3f a, final Vec3f b) {
+ x = a.x * b.x;
+ y = a.y * b.y;
+ z = a.z * b.z;
+ return this;
+ }
+
+ /** this = this * s, returns this. */
+ public Vec3f scale(final float s) {
+ x *= s;
+ y *= s;
+ z *= s;
+ return this;
+ }
+
+ /** this = this * { sx, sy, sz }, returns this. */
+ public Vec3f scale(final float sx, final float sy, final float sz) {
+ x *= sx;
+ y *= sy;
+ z *= sz;
+ return this;
+ }
+
+ /** Returns this + arg; creates new vector */
+ public Vec3f plus(final Vec3f arg) {
+ return new Vec3f(this).add(arg);
+ }
+
+ /** this = a + b, returns this. */
+ public Vec3f plus(final Vec3f a, final Vec3f b) {
+ x = a.x + b.x;
+ y = a.y + b.y;
+ z = a.z + b.z;
+ return this;
+ }
+
+ /** this = this + { dx, dy, dz }, returns this. */
+ public Vec3f add(final float dx, final float dy, final float dz) {
+ x += dx;
+ y += dy;
+ z += dz;
+ return this;
+ }
+
+ /** this = this + b, returns this. */
+ public Vec3f add(final Vec3f b) {
+ x += b.x;
+ y += b.y;
+ z += b.z;
+ return this;
+ }
+
+ /** Returns this - arg; creates new vector */
+ public Vec3f minus(final Vec3f arg) {
+ return new Vec3f(this).sub(arg);
+ }
+
+ /** this = a - b, returns this. */
+ public Vec3f minus(final Vec3f a, final Vec3f b) {
+ x = a.x - b.x;
+ y = a.y - b.y;
+ z = a.z - b.z;
+ return this;
+ }
+
+ /** this = this - b, returns this. */
+ public Vec3f sub(final Vec3f b) {
+ x -= b.x;
+ y -= b.y;
+ z -= b.z;
+ return this;
+ }
+
+ /** Return true if all components are zero, i.e. it's absolute value < {@link #EPSILON}. */
+ public boolean isZero() {
+ return FloatUtil.isZero(x) && FloatUtil.isZero(y) && FloatUtil.isZero(z);
+ }
+
+ /**
+ * Return the length of this vector, a.k.a the <i>norm</i> or <i>magnitude</i>
+ */
+ public float length() {
+ return (float) Math.sqrt(lengthSq());
+ }
+
+ /**
+ * Return the squared length of this vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i>
+ */
+ public float lengthSq() {
+ return x*x + y*y + z*z;
+ }
+
+ /**
+ * Normalize this vector in place
+ */
+ public Vec3f normalize() {
+ final float lengthSq = lengthSq();
+ if ( FloatUtil.isZero( lengthSq ) ) {
+ x = 0.0f;
+ y = 0.0f;
+ z = 0.0f;
+ } else {
+ final float invSqr = 1.0f / (float)Math.sqrt(lengthSq);
+ x *= invSqr;
+ y *= invSqr;
+ z *= invSqr;
+ }
+ return this;
+ }
+
+ /**
+ * Return the squared distance between this vector and the given one.
+ * <p>
+ * When comparing the relative distance between two points it is usually sufficient to compare the squared
+ * distances, thus avoiding an expensive square root operation.
+ * </p>
+ */
+ public float distSq(final Vec3f o) {
+ final float dx = x - o.x;
+ final float dy = y - o.y;
+ final float dz = z - o.z;
+ return dx*dx + dy*dy + dz*dz;
+ }
+
+ /**
+ * Return the distance between this vector and the given one.
+ */
+ public float dist(final Vec3f o) {
+ return (float)Math.sqrt(distSq(o));
+ }
+
+
+ /**
+ * Return the dot product of this vector and the given one
+ * @return the dot product as float
+ */
+ public float dot(final Vec3f o) {
+ return x*o.x + y*o.y + z*o.z;
+ }
+
+ /** Returns this cross arg; creates new vector */
+ public Vec3f cross(final Vec3f arg) {
+ return new Vec3f().cross(this, arg);
+ }
+
+ /** this = a cross b. NOTE: "this" must be a different vector than
+ both a and b. */
+ public Vec3f cross(final Vec3f a, final Vec3f b) {
+ x = a.y * b.z - a.z * b.y;
+ y = a.z * b.x - a.x * b.z;
+ z = a.x * b.y - a.y * b.x;
+ return this;
+ }
+
+ /**
+ * Return the cosines of the angle between two vectors
+ */
+ public float cosAngle(final Vec3f o) {
+ return dot(o) / ( length() * o.length() ) ;
+ }
+
+ /**
+ * Return the angle between two vectors in radians
+ */
+ public float angle(final Vec3f o) {
+ return (float) Math.acos( cosAngle(o) );
+ }
+
+ /**
+ * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ * <p>
+ * Implementation considers following corner cases:
+ * <ul>
+ * <li>NaN == NaN</li>
+ * <li>+Inf == +Inf</li>
+ * <li>-Inf == -Inf</li>
+ * </ul>
+ * @param o comparison value
+ * @param epsilon consider using {@link FloatUtil#EPSILON}
+ * @return true if all components differ less than {@code epsilon}, otherwise false.
+ */
+ public boolean isEqual(final Vec3f o, final float epsilon) {
+ if( this == o ) {
+ return true;
+ } else {
+ return FloatUtil.isEqual(x, o.x, epsilon) &&
+ FloatUtil.isEqual(y, o.y, epsilon) &&
+ FloatUtil.isEqual(z, o.z, epsilon);
+ }
+ }
+
+ /**
+ * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ * <p>
+ * Implementation considers following corner cases:
+ * <ul>
+ * <li>NaN == NaN</li>
+ * <li>+Inf == +Inf</li>
+ * <li>-Inf == -Inf</li>
+ * </ul>
+ * @param o comparison value
+ * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false.
+ */
+ public boolean isEqual(final Vec3f o) {
+ return isEqual(o, FloatUtil.EPSILON);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if( o instanceof Vec3f ) {
+ return isEqual((Vec3f)o, FloatUtil.EPSILON);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return x + " / " + y + " / " + z;
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vec4f.java b/src/jogl/classes/com/jogamp/opengl/math/Vec4f.java
new file mode 100644
index 000000000..f86fe5dad
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/math/Vec4f.java
@@ -0,0 +1,384 @@
+/**
+ * Copyright 2022-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.math;
+
+/**
+ * 4D Vector based upon four float components.
+ *
+ * Implementation borrowed from [gfxbox2](https://jausoft.com/cgit/cs_class/gfxbox2.git/tree/include/pixel/pixel3f.hpp#n29)
+ * and its data layout from JOAL's Vec3f.
+ */
+public final class Vec4f {
+ private float x;
+ private float y;
+ private float z;
+ private float w;
+
+ public Vec4f() {}
+
+ public Vec4f(final Vec4f o) {
+ set(o);
+ }
+
+ /** Creating new Vec4f using { o, w }. */
+ public Vec4f(final Vec3f o, final float w) {
+ set(o, w);
+ }
+
+ public Vec4f copy() {
+ return new Vec4f(this);
+ }
+
+ public Vec4f(final float[/*4*/] xyzw) {
+ set(xyzw);
+ }
+
+ public Vec4f(final float x, final float y, final float z, final float w) {
+ set(x, y, z, w);
+ }
+
+ /** this = o, returns this. */
+ public Vec4f set(final Vec4f o) {
+ this.x = o.x;
+ this.y = o.y;
+ this.z = o.z;
+ this.w = o.w;
+ return this;
+ }
+
+ /** this = { o, w }, returns this. */
+ public Vec4f set(final Vec3f o, final float w) {
+ this.x = o.x();
+ this.y = o.y();
+ this.z = o.z();
+ this.w = w;
+ return this;
+ }
+
+ /** this = { x, y, z, w }, returns this. */
+ public Vec4f set(final float x, final float y, final float z, final float w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /** this = xyzw, returns this. */
+ public Vec4f set(final float[/*4*/] xyzw) {
+ this.x = xyzw[0];
+ this.y = xyzw[1];
+ this.z = xyzw[2];
+ this.w = xyzw[3];
+ return this;
+ }
+
+ /** Sets the ith component, 0 <= i < 4 */
+ public void set(final int i, final float val) {
+ switch (i) {
+ case 0: x = val; break;
+ case 1: y = val; break;
+ case 2: z = val; break;
+ case 3: w = val; break;
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /** xyzw = this, returns xyzw. */
+ public float[] get(final float[/*4*/] xyzw) {
+ xyzw[0] = this.x;
+ xyzw[1] = this.y;
+ xyzw[2] = this.z;
+ xyzw[3] = this.w;
+ return xyzw;
+ }
+
+ /** Gets the ith component, 0 <= i < 4 */
+ public float get(final int i) {
+ switch (i) {
+ case 0: return x;
+ case 1: return y;
+ case 2: return z;
+ case 3: return w;
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public float x() { return x; }
+ public float y() { return y; }
+ public float z() { return z; }
+ public float w() { return w; }
+
+ public void setX(final float x) { this.x = x; }
+ public void setY(final float y) { this.y = y; }
+ public void setZ(final float z) { this.z = z; }
+ public void setW(final float w) { this.w = w; }
+
+ /** this = max(this, m), returns this. */
+ public Vec4f max(final Vec4f m) {
+ this.x = Math.max(this.x, m.x);
+ this.y = Math.max(this.y, m.y);
+ this.z = Math.max(this.z, m.z);
+ this.w = Math.max(this.w, m.w);
+ return this;
+ }
+ /** this = min(this, m), returns this. */
+ public Vec4f min(final Vec4f m) {
+ this.x = Math.min(this.x, m.x);
+ this.y = Math.min(this.y, m.y);
+ this.z = Math.min(this.z, m.z);
+ this.w = Math.min(this.w, m.w);
+ return this;
+ }
+
+ /** Returns this * val; creates new vector */
+ public Vec4f mul(final float val) {
+ return new Vec4f(this).scale(val);
+ }
+
+ /** this = a * b, returns this. */
+ public Vec4f mul(final Vec4f a, final Vec4f b) {
+ x = a.x * b.x;
+ y = a.y * b.y;
+ z = a.z * b.z;
+ w = a.w * b.w;
+ return this;
+ }
+
+ /** this = this * s, returns this. */
+ public Vec4f scale(final float s) {
+ x *= s;
+ y *= s;
+ z *= s;
+ w *= s;
+ return this;
+ }
+
+ /** this = this * { sx, sy, sz, sw }, returns this. */
+ public Vec4f scale(final float sx, final float sy, final float sz, final float sw) {
+ x *= sx;
+ y *= sy;
+ z *= sz;
+ w *= sw;
+ return this;
+ }
+
+ /** Returns this + arg; creates new vector */
+ public Vec4f plus(final Vec4f arg) {
+ return new Vec4f(this).add(arg);
+ }
+
+ /** this = a + b, returns this. */
+ public Vec4f plus(final Vec4f a, final Vec4f b) {
+ x = a.x + b.x;
+ y = a.y + b.y;
+ z = a.z + b.z;
+ w = a.w + b.w;
+ return this;
+ }
+
+ /** this = this + { dx, dy, dz, dw }, returns this. */
+ public Vec4f add(final float dx, final float dy, final float dz, final float dw) {
+ x += dx;
+ y += dy;
+ z += dz;
+ w += dw;
+ return this;
+ }
+
+ /** this = this + b, returns this. */
+ public Vec4f add(final Vec4f b) {
+ x += b.x;
+ y += b.y;
+ z += b.z;
+ w += b.w;
+ return this;
+ }
+
+ /** Returns this - arg; creates new vector */
+ public Vec4f minus(final Vec4f arg) {
+ return new Vec4f(this).sub(arg);
+ }
+
+ /** this = a - b, returns this. */
+ public Vec4f minus(final Vec4f a, final Vec4f b) {
+ x = a.x - b.x;
+ y = a.y - b.y;
+ z = a.z - b.z;
+ w = a.w - b.w;
+ return this;
+ }
+
+ /** this = this - b, returns this. */
+ public Vec4f sub(final Vec4f b) {
+ x -= b.x;
+ y -= b.y;
+ z -= b.z;
+ w -= b.w;
+ return this;
+ }
+
+ /** Return true if all components are zero, i.e. it's absolute value < {@link #EPSILON}. */
+ public boolean isZero() {
+ return FloatUtil.isZero(x) && FloatUtil.isZero(y) && FloatUtil.isZero(z) && FloatUtil.isZero(w);
+ }
+
+ /**
+ * Return the length of this vector, a.k.a the <i>norm</i> or <i>magnitude</i>
+ */
+ public float length() {
+ return (float) Math.sqrt(lengthSq());
+ }
+
+ /**
+ * Return the squared length of this vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i>
+ */
+ public float lengthSq() {
+ return x*x + y*y + z*z + w*w;
+ }
+
+ /**
+ * Normalize this vector in place
+ */
+ public Vec4f normalize() {
+ final float lengthSq = lengthSq();
+ if ( FloatUtil.isZero( lengthSq ) ) {
+ x = 0.0f;
+ y = 0.0f;
+ z = 0.0f;
+ w = 0.0f;
+ } else {
+ final float invSqr = 1.0f / (float)Math.sqrt(lengthSq);
+ x *= invSqr;
+ y *= invSqr;
+ z *= invSqr;
+ w *= invSqr;
+ }
+ return this;
+ }
+
+ /**
+ * Return the squared distance between this vector and the given one.
+ * <p>
+ * When comparing the relative distance between two points it is usually sufficient to compare the squared
+ * distances, thus avoiding an expensive square root operation.
+ * </p>
+ */
+ public float distSq(final Vec4f o) {
+ final float dx = x - o.x;
+ final float dy = y - o.y;
+ final float dz = z - o.z;
+ final float dw = w - o.w;
+ return dx*dx + dy*dy + dz*dz + dw*dw;
+ }
+
+ /**
+ * Return the distance between this vector and the given one.
+ */
+ public float dist(final Vec4f o) {
+ return (float)Math.sqrt(distSq(o));
+ }
+
+
+ /**
+ * Return the dot product of this vector and the given one
+ * @return the dot product as float
+ */
+ public float dot(final Vec4f o) {
+ return x*o.x + y*o.y + z*o.z + w*o.w;
+ }
+
+ /**
+ * Return the cosines of the angle between two vectors
+ */
+ public float cosAngle(final Vec4f o) {
+ return dot(o) / ( length() * o.length() ) ;
+ }
+
+ /**
+ * Return the angle between two vectors in radians
+ */
+ public float angle(final Vec4f o) {
+ return (float) Math.acos( cosAngle(o) );
+ }
+
+ /**
+ * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ * <p>
+ * Implementation considers following corner cases:
+ * <ul>
+ * <li>NaN == NaN</li>
+ * <li>+Inf == +Inf</li>
+ * <li>-Inf == -Inf</li>
+ * </ul>
+ * @param o comparison value
+ * @param epsilon consider using {@link FloatUtil#EPSILON}
+ * @return true if all components differ less than {@code epsilon}, otherwise false.
+ */
+ public boolean isEqual(final Vec4f o, final float epsilon) {
+ if( this == o ) {
+ return true;
+ } else {
+ return FloatUtil.isEqual(x, o.x, epsilon) &&
+ FloatUtil.isEqual(y, o.y, epsilon) &&
+ FloatUtil.isEqual(z, o.z, epsilon) &&
+ FloatUtil.isEqual(w, o.w, epsilon);
+ }
+ }
+
+ /**
+ * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ * <p>
+ * Implementation considers following corner cases:
+ * <ul>
+ * <li>NaN == NaN</li>
+ * <li>+Inf == +Inf</li>
+ * <li>-Inf == -Inf</li>
+ * </ul>
+ * @param o comparison value
+ * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false.
+ */
+ public boolean isEqual(final Vec4f o) {
+ return isEqual(o, FloatUtil.EPSILON);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if( o instanceof Vec4f ) {
+ return isEqual((Vec4f)o, FloatUtil.EPSILON);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return x + " / " + y + " / " + z + " / " + w;
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java b/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java
index a07153155..d3b2c3cfd 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -32,145 +32,11 @@ import java.util.ArrayList;
import com.jogamp.graph.geom.plane.Winding;
public final class VectorUtil {
-
- public static final float[] VEC3_ONE = { 1f, 1f, 1f };
- public static final float[] VEC3_ZERO = { 0f, 0f, 0f };
- public static final float[] VEC3_UNIT_Y = { 0f, 1f, 0f };
- public static final float[] VEC3_UNIT_Y_NEG = { 0f, -1f, 0f };
- public static final float[] VEC3_UNIT_Z = { 0f, 0f, 1f };
- public static final float[] VEC3_UNIT_Z_NEG = { 0f, 0f, -1f };
-
- /**
- * Copies a vector of length 2
- * @param dst output vector
- * @param dstOffset offset of dst in array
- * @param src input vector
- * @param srcOffset offset of src in array
- * @return copied output vector for chaining
- */
- public static float[] copyVec2(final float[] dst, final int dstOffset, final float[] src, final int srcOffset)
- {
- System.arraycopy(src, srcOffset, dst, dstOffset, 2);
- return dst;
- }
-
- /**
- * Copies a vector of length 3
- * @param dst output vector
- * @param dstOffset offset of dst in array
- * @param src input vector
- * @param srcOffset offset of src in array
- * @return copied output vector for chaining
- */
- public static float[] copyVec3(final float[] dst, final int dstOffset, final float[] src, final int srcOffset)
- {
- System.arraycopy(src, srcOffset, dst, dstOffset, 3);
- return dst;
- }
-
- /**
- * Copies a vector of length 4
- * @param dst output vector
- * @param dstOffset offset of dst in array
- * @param src input vector
- * @param srcOffset offset of src in array
- * @return copied output vector for chaining
- */
- public static float[] copyVec4(final float[] dst, final int dstOffset, final float[] src, final int srcOffset)
- {
- System.arraycopy(src, srcOffset, dst, dstOffset, 4);
- return dst;
- }
-
- /**
- * Return true if both vectors are equal w/o regarding an epsilon.
- * <p>
- * Implementation uses {@link FloatUtil#isEqual(float, float)}, see API doc for details.
- * </p>
- */
- public static boolean isVec2Equal(final float[] vec1, final int vec1Offset, final float[] vec2, final int vec2Offset) {
- return FloatUtil.isEqual(vec1[0+vec1Offset], vec2[0+vec2Offset]) &&
- FloatUtil.isEqual(vec1[1+vec1Offset], vec2[1+vec2Offset]) ;
- }
-
- /**
- * Return true if both vectors are equal w/o regarding an epsilon.
- * <p>
- * Implementation uses {@link FloatUtil#isEqual(float, float)}, see API doc for details.
- * </p>
- */
- public static boolean isVec3Equal(final float[] vec1, final int vec1Offset, final float[] vec2, final int vec2Offset) {
- return FloatUtil.isEqual(vec1[0+vec1Offset], vec2[0+vec2Offset]) &&
- FloatUtil.isEqual(vec1[1+vec1Offset], vec2[1+vec2Offset]) &&
- FloatUtil.isEqual(vec1[2+vec1Offset], vec2[2+vec2Offset]) ;
- }
-
- /**
- * Return true if both vectors are equal, i.e. their absolute delta < <code>epsilon</code>.
- * <p>
- * Implementation uses {@link FloatUtil#isEqual(float, float, float)}, see API doc for details.
- * </p>
- */
- public static boolean isVec2Equal(final float[] vec1, final int vec1Offset, final float[] vec2, final int vec2Offset, final float epsilon) {
- return FloatUtil.isEqual(vec1[0+vec1Offset], vec2[0+vec2Offset], epsilon) &&
- FloatUtil.isEqual(vec1[1+vec1Offset], vec2[1+vec2Offset], epsilon) ;
- }
-
/**
- * Return true if both vectors are equal, i.e. their absolute delta < <code>epsilon</code>.
- * <p>
- * Implementation uses {@link FloatUtil#isEqual(float, float, float)}, see API doc for details.
- * </p>
- */
- public static boolean isVec3Equal(final float[] vec1, final int vec1Offset, final float[] vec2, final int vec2Offset, final float epsilon) {
- return FloatUtil.isEqual(vec1[0+vec1Offset], vec2[0+vec2Offset], epsilon) &&
- FloatUtil.isEqual(vec1[1+vec1Offset], vec2[1+vec2Offset], epsilon) &&
- FloatUtil.isEqual(vec1[2+vec1Offset], vec2[2+vec2Offset], epsilon) ;
- }
-
- /**
- * Return true if vector is zero, no {@link FloatUtil#EPSILON} is taken into consideration.
- */
- public static boolean isVec2Zero(final float[] vec, final int vecOffset) {
- return 0f == vec[0+vecOffset] && 0f == vec[1+vecOffset];
- }
-
- /**
- * Return true if vector is zero, no {@link FloatUtil#EPSILON} is taken into consideration.
- */
- public static boolean isVec3Zero(final float[] vec, final int vecOffset) {
- return 0f == vec[0+vecOffset] && 0f == vec[1+vecOffset] && 0f == vec[2+vecOffset];
- }
-
- /**
- * Return true if vector is zero, i.e. it's absolute components < <code>epsilon</code>.
- * <p>
- * Implementation uses {@link FloatUtil#isZero(float, float)}, see API doc for details.
- * </p>
- */
- public static boolean isVec2Zero(final float[] vec, final int vecOffset, final float epsilon) {
- return isZero(vec[0+vecOffset], vec[1+vecOffset], epsilon);
- }
-
- /**
- * Return true if vector is zero, i.e. it's absolute components < <code>epsilon</code>.
- * <p>
- * Implementation uses {@link FloatUtil#isZero(float, float)}, see API doc for details.
- * </p>
- */
- public static boolean isVec3Zero(final float[] vec, final int vecOffset, final float epsilon) {
- return isZero(vec[0+vecOffset], vec[1+vecOffset], vec[2+vecOffset], epsilon);
- }
-
- /**
- * Return true if all two vector components are zero, i.e. it's their absolute value < <code>epsilon</code>.
- * <p>
- * Implementation uses {@link FloatUtil#isZero(float, float)}, see API doc for details.
- * </p>
+ * Return true if 2D vector components are zero, no {@link FloatUtil#EPSILON} is taken into consideration.
*/
- public static boolean isZero(final float x, final float y, final float epsilon) {
- return FloatUtil.isZero(x, epsilon) &&
- FloatUtil.isZero(y, epsilon) ;
+ public static boolean isVec2Zero(final Vec3f vec) {
+ return 0f == vec.x() && 0f == vec.y();
}
/**
@@ -207,34 +73,6 @@ public final class VectorUtil {
}
/**
- * Return the dot product of two points
- * @param vec1 vector 1
- * @param vec2 vector 2
- * @return the dot product as float
- */
- public static float dotVec3(final float[] vec1, final float[] vec2) {
- return vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2];
- }
-
- /**
- * Return the cosines of the angle between to vectors
- * @param vec1 vector 1
- * @param vec2 vector 2
- */
- public static float cosAngleVec3(final float[] vec1, final float[] vec2) {
- return dotVec3(vec1, vec2) / ( normVec3(vec1) * normVec3(vec2) ) ;
- }
-
- /**
- * Return the angle between to vectors in radians
- * @param vec1 vector 1
- * @param vec2 vector 2
- */
- public static float angleVec3(final float[] vec1, final float[] vec2) {
- return FloatUtil.acos(cosAngleVec3(vec1, vec2));
- }
-
- /**
* Return the squared length of a vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i>
*/
public static float normSquareVec2(final float[] vec) {
@@ -244,16 +82,6 @@ public final class VectorUtil {
/**
* Return the squared length of a vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i>
*/
- public static float normSquareVec2(final float[] vec, final int offset) {
- float v = vec[0+offset];
- final float r = v*v;
- v = vec[1+offset];
- return r + v*v;
- }
-
- /**
- * Return the squared length of a vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i>
- */
public static float normSquareVec3(final float[] vec) {
return vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2];
}
@@ -278,73 +106,6 @@ public final class VectorUtil {
}
/**
- * Return the length of a vector, a.k.a the <i>norm</i> or <i>magnitude</i>
- */
- public static float normVec3(final float[] vec) {
- return FloatUtil.sqrt(normSquareVec3(vec));
- }
-
- /**
- * Normalize a vector
- * @param result output vector, may be vector (in-place)
- * @param vector input vector
- * @return normalized output vector
- * @return result vector for chaining
- */
- public static float[] normalizeVec2(final float[] result, final float[] vector) {
- final float lengthSq = normSquareVec2(vector);
- if ( FloatUtil.isZero(lengthSq, FloatUtil.EPSILON) ) {
- result[0] = 0f;
- result[1] = 0f;
- } else {
- final float invSqr = 1f / FloatUtil.sqrt(lengthSq);
- result[0] = vector[0] * invSqr;
- result[1] = vector[1] * invSqr;
- }
- return result;
- }
-
- /**
- * Normalize a vector in place
- * @param vector input vector
- * @return normalized output vector
- */
- public static float[] normalizeVec2(final float[] vector) {
- final float lengthSq = normSquareVec2(vector);
- if ( FloatUtil.isZero(lengthSq, FloatUtil.EPSILON) ) {
- vector[0] = 0f;
- vector[1] = 0f;
- } else {
- final float invSqr = 1f / FloatUtil.sqrt(lengthSq);
- vector[0] *= invSqr;
- vector[1] *= invSqr;
- }
- return vector;
- }
-
- /**
- * Normalize a vector
- * @param result output vector, may be vector (in-place)
- * @param vector input vector
- * @return normalized output vector
- * @return result vector for chaining
- */
- public static float[] normalizeVec3(final float[] result, final float[] vector) {
- final float lengthSq = normSquareVec3(vector);
- if ( FloatUtil.isZero(lengthSq, FloatUtil.EPSILON) ) {
- result[0] = 0f;
- result[1] = 0f;
- result[2] = 0f;
- } else {
- final float invSqr = 1f / FloatUtil.sqrt(lengthSq);
- result[0] = vector[0] * invSqr;
- result[1] = vector[1] * invSqr;
- result[2] = vector[2] * invSqr;
- }
- return result;
- }
-
- /**
* Normalize a vector in place
* @param vector input vector
* @return normalized output vector
@@ -401,35 +162,6 @@ public final class VectorUtil {
* Scales a vector by param using given result float[], result = vector * scale
* @param result vector for the result, may be vector (in-place)
* @param vector input vector
- * @param scale single scale constant for all vector components
- * @return result vector for chaining
- */
- public static float[] scaleVec3(final float[] result, final float[] vector, final float scale) {
- result[0] = vector[0] * scale;
- result[1] = vector[1] * scale;
- result[2] = vector[2] * scale;
- return result;
- }
-
- /**
- * Scales a vector by param using given result float[], result = vector * scale
- * @param result vector for the result, may be vector (in-place)
- * @param vector input vector
- * @param scale 3 component scale constant for each vector component
- * @return result vector for chaining
- */
- public static float[] scaleVec3(final float[] result, final float[] vector, final float[] scale)
- {
- result[0] = vector[0] * scale[0];
- result[1] = vector[1] * scale[1];
- result[2] = vector[2] * scale[2];
- return result;
- }
-
- /**
- * Scales a vector by param using given result float[], result = vector * scale
- * @param result vector for the result, may be vector (in-place)
- * @param vector input vector
* @param scale 2 component scale constant for each vector component
* @return result vector for chaining
*/
@@ -457,35 +189,6 @@ public final class VectorUtil {
* Divides a vector by param using given result float[], result = vector / scale
* @param result vector for the result, may be vector (in-place)
* @param vector input vector
- * @param scale single scale constant for all vector components
- * @return result vector for chaining
- */
- public static float[] divVec3(final float[] result, final float[] vector, final float scale) {
- result[0] = vector[0] / scale;
- result[1] = vector[1] / scale;
- result[2] = vector[2] / scale;
- return result;
- }
-
- /**
- * Divides a vector by param using given result float[], result = vector / scale
- * @param result vector for the result, may be vector (in-place)
- * @param vector input vector
- * @param scale 3 component scale constant for each vector component
- * @return result vector for chaining
- */
- public static float[] divVec3(final float[] result, final float[] vector, final float[] scale)
- {
- result[0] = vector[0] / scale[0];
- result[1] = vector[1] / scale[1];
- result[2] = vector[2] / scale[2];
- return result;
- }
-
- /**
- * Divides a vector by param using given result float[], result = vector / scale
- * @param result vector for the result, may be vector (in-place)
- * @param vector input vector
* @param scale 2 component scale constant for each vector component
* @return result vector for chaining
*/
@@ -510,20 +213,6 @@ public final class VectorUtil {
}
/**
- * Adds two vectors, result = v1 + v2
- * @param result float[3] result vector, may be either v1 or v2 (in-place)
- * @param v1 vector 1
- * @param v2 vector 2
- * @return result vector for chaining
- */
- public static float[] addVec3(final float[] result, final float[] v1, final float[] v2) {
- result[0] = v1[0] + v2[0];
- result[1] = v1[1] + v2[1];
- result[2] = v1[2] + v2[2];
- return result;
- }
-
- /**
* Subtracts two vectors, result = v1 - v2
* @param result float[2] result vector, may be either v1 or v2 (in-place)
* @param v1 vector 1
@@ -537,34 +226,6 @@ public final class VectorUtil {
}
/**
- * Subtracts two vectors, result = v1 - v2
- * @param result float[3] result vector, may be either v1 or v2 (in-place)
- * @param v1 vector 1
- * @param v2 vector 2
- * @return result vector for chaining
- */
- public static float[] subVec3(final float[] result, final float[] v1, final float[] v2) {
- result[0] = v1[0] - v2[0];
- result[1] = v1[1] - v2[1];
- result[2] = v1[2] - v2[2];
- return result;
- }
-
- /**
- * cross product vec1 x vec2
- * @param v1 vector 1
- * @param v2 vector 2
- * @return the resulting vector
- */
- public static float[] crossVec3(final float[] result, final float[] v1, final float[] v2)
- {
- result[0] = v1[1] * v2[2] - v1[2] * v2[1];
- result[1] = v1[2] * v2[0] - v1[0] * v2[2];
- result[2] = v1[0] * v2[1] - v1[1] * v2[0];
- return result;
- }
-
- /**
* cross product vec1 x vec2
* @param v1 vector 1
* @param v2 vector 2
@@ -579,55 +240,15 @@ public final class VectorUtil {
}
/**
- * Multiplication of column-major 4x4 matrix with vector
- * @param colMatrix column matrix (4x4)
- * @param vec vector(x,y,z)
- * @return result
- */
- public static float[] mulColMat4Vec3(final float[] result, final float[] colMatrix, final float[] vec)
- {
- result[0] = vec[0]*colMatrix[0] + vec[1]*colMatrix[4] + vec[2]*colMatrix[8] + colMatrix[12];
- result[1] = vec[0]*colMatrix[1] + vec[1]*colMatrix[5] + vec[2]*colMatrix[9] + colMatrix[13];
- result[2] = vec[0]*colMatrix[2] + vec[1]*colMatrix[6] + vec[2]*colMatrix[10] + colMatrix[14];
-
- return result;
- }
-
- /**
- * Matrix Vector multiplication
- * @param rawMatrix column matrix (4x4)
- * @param vec vector(x,y,z)
- * @return result
- */
- public static float[] mulRowMat4Vec3(final float[] result, final float[] rawMatrix, final float[] vec)
- {
- result[0] = vec[0]*rawMatrix[0] + vec[1]*rawMatrix[1] + vec[2]*rawMatrix[2] + rawMatrix[3];
- result[1] = vec[0]*rawMatrix[4] + vec[1]*rawMatrix[5] + vec[2]*rawMatrix[6] + rawMatrix[7];
- result[2] = vec[0]*rawMatrix[8] + vec[1]*rawMatrix[9] + vec[2]*rawMatrix[10] + rawMatrix[11];
-
- return result;
- }
-
- /**
- * Calculate the midpoint of two values
- * @param p1 first value
- * @param p2 second vale
- * @return midpoint
- */
- public static float mid(final float p1, final float p2) {
- return (p1+p2)*0.5f;
- }
-
- /**
* Calculate the midpoint of two points
* @param p1 first point vector
* @param p2 second point vector
* @return midpoint
*/
- public static float[] midVec3(final float[] result, final float[] p1, final float[] p2) {
- result[0] = (p1[0] + p2[0])*0.5f;
- result[1] = (p1[1] + p2[1])*0.5f;
- result[2] = (p1[2] + p2[2])*0.5f;
+ public static Vec3f midVec3(final Vec3f result, final Vec3f p1, final Vec3f p2) {
+ result.set( (p1.x() + p2.x())*0.5f,
+ (p1.y() + p2.y())*0.5f,
+ (p1.z() + p2.z())*0.5f );
return result;
}
@@ -638,8 +259,8 @@ public final class VectorUtil {
* @param c vector 3
* @return the determinant value
*/
- public static float determinantVec3(final float[] a, final float[] b, final float[] c) {
- return a[0]*b[1]*c[2] + a[1]*b[2]*c[0] + a[2]*b[0]*c[1] - a[0]*b[2]*c[1] - a[1]*b[0]*c[2] - a[2]*b[1]*c[0];
+ public static float determinantVec3(final Vec3f a, final Vec3f b, final Vec3f c) {
+ return a.x()*b.y()*c.z() + a.y()*b.z()*c.x() + a.z()*b.x()*c.y() - a.x()*b.z()*c.y() - a.y()*b.x()*c.z() - a.z()*b.y()*c.x();
}
/**
@@ -649,7 +270,7 @@ public final class VectorUtil {
* @param v3 vertex 3
* @return true if collinear, false otherwise
*/
- public static boolean isCollinearVec3(final float[] v1, final float[] v2, final float[] v3) {
+ public static boolean isCollinearVec3(final Vec3f v1, final Vec3f v2, final Vec3f v3) {
return FloatUtil.isZero( determinantVec3(v1, v2, v3), FloatUtil.EPSILON );
}
@@ -663,14 +284,10 @@ public final class VectorUtil {
* vertices a, b, c. from paper by Guibas and Stolfi (1985).
*/
public static boolean isInCircleVec2(final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c, final Vert2fImmutable d) {
- final float[] A = a.getCoord();
- final float[] B = b.getCoord();
- final float[] C = c.getCoord();
- final float[] D = d.getCoord();
- return (A[0] * A[0] + A[1] * A[1]) * triAreaVec2(B, C, D) -
- (B[0] * B[0] + B[1] * B[1]) * triAreaVec2(A, C, D) +
- (C[0] * C[0] + C[1] * C[1]) * triAreaVec2(A, B, D) -
- (D[0] * D[0] + D[1] * D[1]) * triAreaVec2(A, B, C) > 0;
+ return (a.x() * a.x() + a.y() * a.y()) * triAreaVec2(b, c, d) -
+ (b.x() * b.x() + b.y() * b.y()) * triAreaVec2(a, c, d) +
+ (c.x() * c.x() + c.y() * c.y()) * triAreaVec2(a, b, d) -
+ (d.x() * d.x() + d.y() * d.y()) * triAreaVec2(a, b, c) > 0;
}
/**
@@ -682,47 +299,34 @@ public final class VectorUtil {
* is positive if the triangle is oriented counterclockwise.
*/
public static float triAreaVec2(final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c){
- final float[] A = a.getCoord();
- final float[] B = b.getCoord();
- final float[] C = c.getCoord();
- return (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1]) * (C[0] - A[0]);
- }
-
- /**
- * Computes oriented area of a triangle
- * @param A first vertex
- * @param B second vertex
- * @param C third vertex
- * @return compute twice the area of the oriented triangle (a,b,c), the area
- * is positive if the triangle is oriented counterclockwise.
- */
- public static float triAreaVec2(final float[] A, final float[] B, final float[] C){
- return (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1])*(C[0] - A[0]);
+ return (b.x() - a.x()) * (c.y() - a.y()) - (b.y() - a.y()) * (c.x() - a.x());
}
/**
- * Check if a vertex is in triangle using
- * barycentric coordinates computation.
+ * Check if a vertex is in triangle using barycentric coordinates computation.
* @param a first triangle vertex
* @param b second triangle vertex
* @param c third triangle vertex
* @param p the vertex in question
+ * @param ac temporary storage
+ * @param ab temporary storage
+ * @param ap temporary storage
* @return true if p is in triangle (a, b, c), false otherwise.
*/
- public static boolean isInTriangleVec3(final float[] a, final float[] b, final float[] c,
- final float[] p,
- final float[] ac, final float[] ab, final float[] ap){
+ public static boolean isInTriangleVec3(final Vec3f a, final Vec3f b, final Vec3f c,
+ final Vec3f p,
+ final Vec3f ac, final Vec3f ab, final Vec3f ap){
// Compute vectors
- subVec3(ac, c, a); //v0
- subVec3(ab, b, a); //v1
- subVec3(ap, p, a); //v2
+ ac.minus( c, a); // v0
+ ab.minus( b, a); // v1
+ ap.minus( p, a); // v2
// Compute dot products
- final float dotAC_AC = dotVec3(ac, ac);
- final float dotAC_AB = dotVec3(ac, ab);
- final float dotAB_AB = dotVec3(ab, ab);
- final float dotAC_AP = dotVec3(ac, ap);
- final float dotAB_AP = dotVec3(ab, ap);
+ final float dotAC_AC = ac.dot(ac);
+ final float dotAC_AB = ac.dot(ab);
+ final float dotAB_AB = ab.dot(ab);
+ final float dotAC_AP = ac.dot(ap);
+ final float dotAB_AP = ab.dot(ap);
// Compute barycentric coordinates
final float invDenom = 1 / (dotAC_AC * dotAB_AB - dotAC_AB * dotAC_AB);
@@ -734,37 +338,36 @@ public final class VectorUtil {
}
/**
- * Check if one of three vertices are in triangle using
- * barycentric coordinates computation.
+ * Check if one of three vertices are in triangle using barycentric coordinates computation.
* @param a first triangle vertex
* @param b second triangle vertex
* @param c third triangle vertex
* @param p1 the vertex in question
* @param p2 the vertex in question
* @param p3 the vertex in question
- * @param tmpAC
- * @param tmpAB
- * @param tmpAP
+ * @param ac temporary storage
+ * @param ab temporary storage
+ * @param ap temporary storage
* @return true if p1 or p2 or p3 is in triangle (a, b, c), false otherwise.
*/
- public static boolean isVec3InTriangle3(final float[] a, final float[] b, final float[] c,
- final float[] p1, final float[] p2, final float[] p3,
- final float[] tmpAC, final float[] tmpAB, final float[] tmpAP){
+ public static boolean isVec3InTriangle3(final Vec3f a, final Vec3f b, final Vec3f c,
+ final Vec3f p1, final Vec3f p2, final Vec3f p3,
+ final Vec3f ac, final Vec3f ab, final Vec3f ap){
// Compute vectors
- subVec3(tmpAC, c, a); //v0
- subVec3(tmpAB, b, a); //v1
+ ac.minus(c, a); // v0
+ ab.minus(b, a); // v1
// Compute dot products
- final float dotAC_AC = dotVec3(tmpAC, tmpAC);
- final float dotAC_AB = dotVec3(tmpAC, tmpAB);
- final float dotAB_AB = dotVec3(tmpAB, tmpAB);
+ final float dotAC_AC = ac.dot(ac);
+ final float dotAC_AB = ac.dot(ab);
+ final float dotAB_AB = ab.dot(ab);
// Compute barycentric coordinates
final float invDenom = 1 / (dotAC_AC * dotAB_AB - dotAC_AB * dotAC_AB);
{
- subVec3(tmpAP, p1, a); //v2
- final float dotAC_AP1 = dotVec3(tmpAC, tmpAP);
- final float dotAB_AP1 = dotVec3(tmpAB, tmpAP);
+ ap.minus(p1, a); // v2
+ final float dotAC_AP1 = ac.dot(ap);
+ final float dotAB_AP1 = ab.dot(ap);
final float u = (dotAB_AB * dotAC_AP1 - dotAC_AB * dotAB_AP1) * invDenom;
final float v = (dotAC_AC * dotAB_AP1 - dotAC_AB * dotAC_AP1) * invDenom;
@@ -775,9 +378,9 @@ public final class VectorUtil {
}
{
- subVec3(tmpAP, p1, a); //v2
- final float dotAC_AP2 = dotVec3(tmpAC, tmpAP);
- final float dotAB_AP2 = dotVec3(tmpAB, tmpAP);
+ ap.minus(p2, a); // v2
+ final float dotAC_AP2 = ac.dot(ap);
+ final float dotAB_AP2 = ab.dot(ap);
final float u = (dotAB_AB * dotAC_AP2 - dotAC_AB * dotAB_AP2) * invDenom;
final float v = (dotAC_AC * dotAB_AP2 - dotAC_AB * dotAC_AP2) * invDenom;
@@ -788,9 +391,9 @@ public final class VectorUtil {
}
{
- subVec3(tmpAP, p2, a); //v2
- final float dotAC_AP3 = dotVec3(tmpAC, tmpAP);
- final float dotAB_AP3 = dotVec3(tmpAB, tmpAP);
+ ap.minus(p3, a); // v3
+ final float dotAC_AP3 = ac.dot(ap);
+ final float dotAB_AP3 = ab.dot(ap);
final float u = (dotAB_AB * dotAC_AP3 - dotAC_AB * dotAB_AP3) * invDenom;
final float v = (dotAC_AC * dotAB_AP3 - dotAC_AB * dotAC_AP3) * invDenom;
@@ -815,25 +418,25 @@ public final class VectorUtil {
* @param tmpAP
* @return true if p1 or p2 or p3 is in triangle (a, b, c), false otherwise.
*/
- public static boolean isVec3InTriangle3(final float[] a, final float[] b, final float[] c,
- final float[] p1, final float[] p2, final float[] p3,
- final float[] tmpAC, final float[] tmpAB, final float[] tmpAP,
- final float epsilon){
+ public static boolean isVec3InTriangle3(final Vec3f a, final Vec3f b, final Vec3f c,
+ final Vec3f p1, final Vec3f p2, final Vec3f p3,
+ final Vec3f ac, final Vec3f ab, final Vec3f ap,
+ final float epsilon) {
// Compute vectors
- subVec3(tmpAC, c, a); //v0
- subVec3(tmpAB, b, a); //v1
+ ac.minus(c, a); // v0
+ ab.minus(b, a); // v1
// Compute dot products
- final float dotAC_AC = dotVec3(tmpAC, tmpAC);
- final float dotAC_AB = dotVec3(tmpAC, tmpAB);
- final float dotAB_AB = dotVec3(tmpAB, tmpAB);
+ final float dotAC_AC = ac.dot(ac);
+ final float dotAC_AB = ac.dot(ab);
+ final float dotAB_AB = ab.dot(ab);
// Compute barycentric coordinates
final float invDenom = 1 / (dotAC_AC * dotAB_AB - dotAC_AB * dotAC_AB);
{
- subVec3(tmpAP, p1, a); //v2
- final float dotAC_AP1 = dotVec3(tmpAC, tmpAP);
- final float dotAB_AP1 = dotVec3(tmpAB, tmpAP);
+ ap.minus(p1, a); // v2
+ final float dotAC_AP1 = ac.dot(ap);
+ final float dotAB_AP1 = ab.dot(ap);
final float u = (dotAB_AB * dotAC_AP1 - dotAC_AB * dotAB_AP1) * invDenom;
final float v = (dotAC_AC * dotAB_AP1 - dotAC_AB * dotAC_AP1) * invDenom;
@@ -846,9 +449,9 @@ public final class VectorUtil {
}
{
- subVec3(tmpAP, p1, a); //v2
- final float dotAC_AP2 = dotVec3(tmpAC, tmpAP);
- final float dotAB_AP2 = dotVec3(tmpAB, tmpAP);
+ ap.minus(p2, a); // v3
+ final float dotAC_AP2 = ac.dot(ap);
+ final float dotAB_AP2 = ab.dot(ap);
final float u = (dotAB_AB * dotAC_AP2 - dotAC_AB * dotAB_AP2) * invDenom;
final float v = (dotAC_AC * dotAB_AP2 - dotAC_AB * dotAC_AP2) * invDenom;
@@ -861,9 +464,9 @@ public final class VectorUtil {
}
{
- subVec3(tmpAP, p2, a); //v2
- final float dotAC_AP3 = dotVec3(tmpAC, tmpAP);
- final float dotAB_AP3 = dotVec3(tmpAB, tmpAP);
+ ap.minus(p3, a); // v4
+ final float dotAC_AP3 = ac.dot(ap);
+ final float dotAB_AP3 = ab.dot(ap);
final float u = (dotAB_AB * dotAC_AP3 - dotAC_AB * dotAB_AP3) * invDenom;
final float v = (dotAC_AC * dotAB_AP3 - dotAC_AB * dotAC_AP3) * invDenom;
@@ -874,7 +477,6 @@ public final class VectorUtil {
return true;
}
}
-
return false;
}
@@ -918,9 +520,9 @@ public final class VectorUtil {
final int n = vertices.size();
float area = 0.0f;
for (int p = n - 1, q = 0; q < n; p = q++) {
- final float[] pCoord = vertices.get(p).getCoord();
- final float[] qCoord = vertices.get(q).getCoord();
- area += pCoord[0] * qCoord[1] - qCoord[0] * pCoord[1];
+ final Vert2fImmutable pCoord = vertices.get(p);
+ final Vert2fImmutable qCoord = vertices.get(q);
+ area += pCoord.x() * qCoord.y() - qCoord.x() * pCoord.y();
}
return area;
}
@@ -940,36 +542,6 @@ public final class VectorUtil {
}
/**
- * @param result vec2 result for normal
- * @param v1 vec2
- * @param v2 vec2
- * @return result for chaining
- */
- public static float[] getNormalVec2(final float[] result, final float[] v1, final float[] v2 ) {
- subVec2(result, v2, v1);
- final float tmp = result [ 0 ] ; result [ 0 ] = -result [ 1 ] ; result [ 1 ] = tmp ;
- return normalizeVec2 ( result ) ;
- }
-
- /**
- * Returns the 3d surface normal of a triangle given three vertices.
- *
- * @param result vec3 result for normal
- * @param v1 vec3
- * @param v2 vec3
- * @param v3 vec3
- * @param tmp1Vec3 temp vec3
- * @param tmp2Vec3 temp vec3
- * @return result for chaining
- */
- public static float[] getNormalVec3(final float[] result, final float[] v1, final float[] v2, final float[] v3,
- final float[] tmp1Vec3, final float[] tmp2Vec3) {
- subVec3 ( tmp1Vec3, v2, v1 );
- subVec3 ( tmp2Vec3, v3, v1 ) ;
- return normalizeVec3 ( crossVec3(result, tmp1Vec3, tmp2Vec3) ) ;
- }
-
- /**
* Finds the plane equation of a plane given its normal and a point on the plane.
*
* @param resultV4 vec4 plane equation
@@ -977,15 +549,14 @@ public final class VectorUtil {
* @param pVec3
* @return result for chaining
*/
- public static float[] getPlaneVec3(final float[/*4*/] resultV4, final float[] normalVec3, final float[] pVec3) {
+ public static Vec4f getPlaneVec3(final Vec4f resultV4, final Vec3f normalVec3, final Vec3f pVec3) {
/**
Ax + By + Cz + D == 0 ;
D = - ( Ax + By + Cz )
= - ( A*a[0] + B*a[1] + C*a[2] )
= - vec3Dot ( normal, a ) ;
*/
- System.arraycopy(normalVec3, 0, resultV4, 0, 3);
- resultV4 [ 3 ] = -dotVec3(normalVec3, pVec3) ;
+ resultV4.set(normalVec3, -normalVec3.dot(pVec3));
return resultV4;
}
@@ -1000,16 +571,16 @@ public final class VectorUtil {
* @param temp2V3
* @return result for chaining
*/
- public static float[] getPlaneVec3(final float[/*4*/] resultVec4, final float[] v1, final float[] v2, final float[] v3,
- final float[] temp1V3, final float[] temp2V3) {
+ public static Vec4f getPlaneVec3(final Vec4f resultVec4, final Vec3f v1, final Vec3f v2, final Vec3f v3,
+ final Vec3f temp1V3, final Vec3f temp2V3, final Vec3f temp3V3) {
/**
Ax + By + Cz + D == 0 ;
D = - ( Ax + By + Cz )
= - ( A*a[0] + B*a[1] + C*a[2] )
= - vec3Dot ( normal, a ) ;
*/
- getNormalVec3( resultVec4, v1, v2, v3, temp1V3, temp2V3 ) ;
- resultVec4 [ 3 ] = -dotVec3 (resultVec4, v1) ;
+ temp3V3.cross(temp1V3.minus(v2, v1), temp2V3.minus(v3, v1)).normalize();
+ resultVec4.set(temp3V3, -temp3V3.dot(v1));
return resultVec4;
}
@@ -1025,14 +596,15 @@ public final class VectorUtil {
* @param epsilon
* @return resulting intersecting if exists, otherwise null
*/
- public static float[] line2PlaneIntersection(final float[] result, final Ray ray, final float[/*4*/] plane, final float epsilon) {
- final float tmp = dotVec3(ray.dir, plane) ;
+ public static Vec3f line2PlaneIntersection(final Vec3f result, final Ray ray, final Vec4f plane, final float epsilon) {
+ final Vec3f plane3 = new Vec3f(plane);
+ final float tmp = ray.dir.dot(plane3);
if ( Math.abs(tmp) < epsilon ) {
return null; // ray is parallel to plane
}
- scaleVec3 ( result, ray.dir, -( dotVec3(ray.orig, plane) + plane[3] ) / tmp ) ;
- return addVec3(result, result, ray.orig);
+ result.set( ray.dir );
+ return result.scale( -( ray.orig.dot(plane3) + plane.w() ) / tmp ).add(ray.orig);
}
/** Compute intersection between two segments
@@ -1042,26 +614,23 @@ public final class VectorUtil {
* @param d vertex 2 of second segment
* @return the intersection coordinates if the segments intersect, otherwise returns null
*/
- public static float[] seg2SegIntersection(final float[] result, final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c, final Vert2fImmutable d) {
- final float determinant = (a.getX()-b.getX())*(c.getY()-d.getY()) - (a.getY()-b.getY())*(c.getX()-d.getX());
+ public static Vec3f seg2SegIntersection(final Vec3f result, final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c, final Vert2fImmutable d) {
+ final float determinant = (a.x()-b.x())*(c.y()-d.y()) - (a.y()-b.y())*(c.x()-d.x());
if (determinant == 0)
return null;
- final float alpha = (a.getX()*b.getY()-a.getY()*b.getX());
- final float beta = (c.getX()*d.getY()-c.getY()*d.getY());
- final float xi = ((c.getX()-d.getX())*alpha-(a.getX()-b.getX())*beta)/determinant;
- final float yi = ((c.getY()-d.getY())*alpha-(a.getY()-b.getY())*beta)/determinant;
+ final float alpha = (a.x()*b.y()-a.y()*b.x());
+ final float beta = (c.x()*d.y()-c.y()*d.y());
+ final float xi = ((c.x()-d.x())*alpha-(a.x()-b.x())*beta)/determinant;
+ final float yi = ((c.y()-d.y())*alpha-(a.y()-b.y())*beta)/determinant;
- final float gamma = (xi - a.getX())/(b.getX() - a.getX());
- final float gamma1 = (xi - c.getX())/(d.getX() - c.getX());
+ final float gamma = (xi - a.x())/(b.x() - a.x());
+ final float gamma1 = (xi - c.x())/(d.x() - c.x());
if(gamma <= 0 || gamma >= 1) return null;
if(gamma1 <= 0 || gamma1 >= 1) return null;
- result[0] = xi;
- result[1] = yi;
- result[2] = 0;
- return result;
+ return result.set(xi, yi, 0);
}
/**
@@ -1074,23 +643,18 @@ public final class VectorUtil {
*/
public static boolean testSeg2SegIntersection(final Vert2fImmutable a, final Vert2fImmutable b,
final Vert2fImmutable c, final Vert2fImmutable d) {
- final float[] A = a.getCoord();
- final float[] B = b.getCoord();
- final float[] C = c.getCoord();
- final float[] D = d.getCoord();
-
- final float determinant = (A[0]-B[0])*(C[1]-D[1]) - (A[1]-B[1])*(C[0]-D[0]);
+ final float determinant = (a.x()-b.x())*(c.y()-d.y()) - (a.y()-b.y())*(c.x()-d.x());
if (determinant == 0) {
return false;
}
- final float alpha = (A[0]*B[1]-A[1]*B[0]);
- final float beta = (C[0]*D[1]-C[1]*D[1]);
- final float xi = ((C[0]-D[0])*alpha-(A[0]-B[0])*beta)/determinant;
+ final float alpha = (a.x()*b.y()-a.y()*b.x());
+ final float beta = (c.x()*d.y()-c.y()*d.y());
+ final float xi = ((c.x()-d.x())*alpha-(a.x()-b.x())*beta)/determinant;
- final float gamma0 = (xi - A[0])/(B[0] - A[0]);
- final float gamma1 = (xi - C[0])/(D[0] - C[0]);
+ final float gamma0 = (xi - a.x())/(b.x() - a.x());
+ final float gamma1 = (xi - c.x())/(d.x() - c.x());
if(gamma0 <= 0 || gamma0 >= 1 || gamma1 <= 0 || gamma1 >= 1) {
return false;
}
@@ -1108,23 +672,19 @@ public final class VectorUtil {
public static boolean testSeg2SegIntersection(final Vert2fImmutable a, final Vert2fImmutable b,
final Vert2fImmutable c, final Vert2fImmutable d,
final float epsilon) {
- final float[] A = a.getCoord();
- final float[] B = b.getCoord();
- final float[] C = c.getCoord();
- final float[] D = d.getCoord();
-
- final float determinant = (A[0]-B[0])*(C[1]-D[1]) - (A[1]-B[1])*(C[0]-D[0]);
+ final float determinant = (a.x()-b.x())*(c.y()-d.y()) - (a.y()-b.y())*(c.x()-d.x());
if ( FloatUtil.isZero(determinant, epsilon) ) {
return false;
}
- final float alpha = (A[0]*B[1]-A[1]*B[0]);
- final float beta = (C[0]*D[1]-C[1]*D[1]);
- final float xi = ((C[0]-D[0])*alpha-(A[0]-B[0])*beta)/determinant;
+ final float alpha = (a.x()*b.y()-a.y()*b.x());
+ final float beta = (c.x()*d.y()-c.y()*d.y());
+ final float xi = ((c.x()-d.x())*alpha-(a.x()-b.x())*beta)/determinant;
+
+ final float gamma0 = (xi - a.x())/(b.x() - a.x());
+ final float gamma1 = (xi - c.x())/(d.x() - c.x());
- final float gamma0 = (xi - A[0])/(B[0] - A[0]);
- final float gamma1 = (xi - C[0])/(D[0] - C[0]);
if( FloatUtil.compare(gamma0, 0.0f, epsilon) <= 0 ||
FloatUtil.compare(gamma0, 1.0f, epsilon) >= 0 ||
FloatUtil.compare(gamma1, 0.0f, epsilon) <= 0 ||
@@ -1148,23 +708,20 @@ public final class VectorUtil {
* @return the intersection coordinates if the lines intersect, otherwise
* returns null
*/
- public static float[] line2lineIntersection(final float[] result,
- final Vert2fImmutable a, final Vert2fImmutable b,
- final Vert2fImmutable c, final Vert2fImmutable d) {
- final float determinant = (a.getX()-b.getX())*(c.getY()-d.getY()) - (a.getY()-b.getY())*(c.getX()-d.getX());
+ public static Vec3f line2lineIntersection(final Vec3f result,
+ final Vert2fImmutable a, final Vert2fImmutable b,
+ final Vert2fImmutable c, final Vert2fImmutable d) {
+ final float determinant = (a.x()-b.x())*(c.y()-d.y()) - (a.y()-b.y())*(c.x()-d.x());
if (determinant == 0)
return null;
- final float alpha = (a.getX()*b.getY()-a.getY()*b.getX());
- final float beta = (c.getX()*d.getY()-c.getY()*d.getY());
- final float xi = ((c.getX()-d.getX())*alpha-(a.getX()-b.getX())*beta)/determinant;
- final float yi = ((c.getY()-d.getY())*alpha-(a.getY()-b.getY())*beta)/determinant;
+ final float alpha = (a.x()*b.y()-a.y()*b.x());
+ final float beta = (c.x()*d.y()-c.y()*d.y());
+ final float xi = ((c.x()-d.x())*alpha-(a.x()-b.x())*beta)/determinant;
+ final float yi = ((c.y()-d.y())*alpha-(a.y()-b.y())*beta)/determinant;
- result[0] = xi;
- result[1] = yi;
- result[2] = 0;
- return result;
+ return result.set(xi, yi, 0);
}
/**
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vert2fImmutable.java b/src/jogl/classes/com/jogamp/opengl/math/Vert2fImmutable.java
index ec90b401f..66bf078f3 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/Vert2fImmutable.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/Vert2fImmutable.java
@@ -28,12 +28,9 @@
package com.jogamp.opengl.math;
public interface Vert2fImmutable {
- float getX();
+ float x();
- float getY();
+ float y();
int getCoordCount();
-
- float[] getCoord();
-
}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vert3fImmutable.java b/src/jogl/classes/com/jogamp/opengl/math/Vert3fImmutable.java
index 76bd02fbc..6f63a746c 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/Vert3fImmutable.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/Vert3fImmutable.java
@@ -28,5 +28,7 @@
package com.jogamp.opengl.math;
public interface Vert3fImmutable extends Vert2fImmutable {
- float getZ();
+ float z();
+
+ Vec3f getCoord();
}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java b/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java
index 234b2121b..531ea99ec 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -29,9 +29,12 @@ package com.jogamp.opengl.math.geom;
import com.jogamp.graph.geom.plane.AffineTransform;
import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.Quaternion;
import com.jogamp.opengl.math.Ray;
-import com.jogamp.opengl.math.VectorUtil;
+import com.jogamp.opengl.math.Recti;
+import com.jogamp.opengl.math.Vec3f;
+import com.jogamp.opengl.util.PMVMatrix;
/**
@@ -51,13 +54,17 @@ import com.jogamp.opengl.math.VectorUtil;
*/
public class AABBox {
private static final boolean DEBUG = FloatUtil.DEBUG;
- private final float[] low = new float[3];
- private final float[] high = new float[3];
- private final float[] center = new float[3];
+ private final Vec3f low = new Vec3f();
+ private final Vec3f high = new Vec3f();
+ private final Vec3f center = new Vec3f();
/**
- * Create an Axis Aligned bounding box (AABBox)
- * where the low and and high MAX float Values.
+ * Create an Axis Aligned bounding box (AABBox) with the
+ * inverse low/high, allowing the next {@link #resize(float, float, float)} command to hit.
+ * <p>
+ * The dimension, i.e. {@link #getWidth()} abd {@link #getHeight()} is {@link Float#isInfinite()} thereafter.
+ * </p>
+ * @see #reset()
*/
public AABBox() {
reset();
@@ -96,48 +103,43 @@ public class AABBox {
}
/**
- * resets this box to the inverse low/high, allowing the next {@link #resize(float, float, float)} command to hit.
+ * Resets this box to the inverse low/high, allowing the next {@link #resize(float, float, float)} command to hit.
+ * <p>
+ * The dimension, i.e. {@link #getWidth()} abd {@link #getHeight()} is {@link Float#isInfinite()} thereafter.
+ * </p>
* @return this AABBox for chaining
*/
public final AABBox reset() {
setLow(Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE);
setHigh(-1*Float.MAX_VALUE,-1*Float.MAX_VALUE,-1*Float.MAX_VALUE);
- center[0] = 0f;
- center[1] = 0f;
- center[2] = 0f;
+ center.set( 0f, 0f, 0f);
return this;
}
/** Get the max xyz-coordinates
- * @return a float array containing the max xyz coordinates
+ * @return max xyz coordinates
*/
- public final float[] getHigh() {
+ public final Vec3f getHigh() {
return high;
}
private final void setHigh(final float hx, final float hy, final float hz) {
- this.high[0] = hx;
- this.high[1] = hy;
- this.high[2] = hz;
+ this.high.set(hx, hy, hz);
}
/** Get the min xyz-coordinates
- * @return a float array containing the min xyz coordinates
+ * @return min xyz coordinates
*/
- public final float[] getLow() {
+ public final Vec3f getLow() {
return low;
}
private final void setLow(final float lx, final float ly, final float lz) {
- this.low[0] = lx;
- this.low[1] = ly;
- this.low[2] = lz;
+ this.low.set(lx, ly, lz);
}
private final void computeCenter() {
- center[0] = (high[0] + low[0])/2f;
- center[1] = (high[1] + low[1])/2f;
- center[2] = (high[2] + low[2])/2f;
+ center.set(high).add(low).scale(1f/2f);
}
/**
@@ -147,9 +149,9 @@ public class AABBox {
* @return this AABBox for chaining
*/
public final AABBox copy(final AABBox src) {
- System.arraycopy(src.low, 0, low, 0, 3);
- System.arraycopy(src.high, 0, high, 0, 3);
- System.arraycopy(src.center, 0, center, 0, 3);
+ low.set(src.low);
+ high.set(src.high);
+ center.set(src.center);
return this;
}
@@ -179,12 +181,23 @@ public class AABBox {
*/
public final AABBox setSize(final float lx, final float ly, final float lz,
final float hx, final float hy, final float hz) {
- this.low[0] = lx;
- this.low[1] = ly;
- this.low[2] = lz;
- this.high[0] = hx;
- this.high[1] = hy;
- this.high[2] = hz;
+ this.low.set(lx, ly, lz);
+ this.high.set(hx, hy, hz);
+ computeCenter();
+ return this;
+ }
+
+ /**
+ * Set size of the AABBox specifying the coordinates
+ * of the low and high.
+ *
+ * @param low min xyz-coordinates
+ * @param high max xyz-coordinates
+ * @return this AABBox for chaining
+ */
+ public final AABBox setSize(final Vec3f low, final Vec3f high) {
+ this.low.set(low);
+ this.high.set(high);
computeCenter();
return this;
}
@@ -195,25 +208,30 @@ public class AABBox {
* @return this AABBox for chaining
*/
public final AABBox resize(final AABBox newBox) {
- final float[] newLow = newBox.getLow();
- final float[] newHigh = newBox.getHigh();
+ final Vec3f newLow = newBox.getLow();
+ final Vec3f newHigh = newBox.getHigh();
/** test low */
- if (newLow[0] < low[0])
- low[0] = newLow[0];
- if (newLow[1] < low[1])
- low[1] = newLow[1];
- if (newLow[2] < low[2])
- low[2] = newLow[2];
+ if (newLow.x() < low.x()) {
+ low.setX( newLow.x() );
+ }
+ if (newLow.y() < low.y()) {
+ low.setY( newLow.y() );
+ }
+ if (newLow.z() < low.z()) {
+ low.setZ( newLow.z() );
+ }
/** test high */
- if (newHigh[0] > high[0])
- high[0] = newHigh[0];
- if (newHigh[1] > high[1])
- high[1] = newHigh[1];
- if (newHigh[2] > high[2])
- high[2] = newHigh[2];
-
+ if (newHigh.x() > high.x()) {
+ high.setX( newHigh.x() );
+ }
+ if (newHigh.y() > high.y()) {
+ high.setY( newHigh.y() );
+ }
+ if (newHigh.z() > high.z()) {
+ high.setZ( newHigh.z() );
+ }
computeCenter();
return this;
}
@@ -222,34 +240,32 @@ public class AABBox {
* Resize the AABBox to encapsulate another AABox, which will be <i>transformed</i> on the fly first.
* @param newBox AABBox to be encapsulated in
* @param t the {@link AffineTransform} applied on <i>newBox</i> on the fly
- * @param tmpV3 temp float[3] storage
+ * @param tmpV3 temporary storage
* @return this AABBox for chaining
*/
- public final AABBox resize(final AABBox newBox, final AffineTransform t, final float[] tmpV3) {
+ public final AABBox resize(final AABBox newBox, final AffineTransform t, final Vec3f tmpV3) {
/** test low */
{
- final float[] newBoxLow = newBox.getLow();
+ final Vec3f newBoxLow = newBox.getLow();
t.transform(newBoxLow, tmpV3);
- tmpV3[2] = newBoxLow[2];
- if (tmpV3[0] < low[0])
- low[0] = tmpV3[0];
- if (tmpV3[1] < low[1])
- low[1] = tmpV3[1];
- if (tmpV3[2] < low[2])
- low[2] = tmpV3[2];
+ if (tmpV3.x() < low.x())
+ low.setX( tmpV3.x() );
+ if (tmpV3.y() < low.y())
+ low.setY( tmpV3.y() );
+ if (tmpV3.z() < low.z())
+ low.setZ( tmpV3.z() );
}
/** test high */
{
- final float[] newBoxHigh = newBox.getHigh();
+ final Vec3f newBoxHigh = newBox.getHigh();
t.transform(newBoxHigh, tmpV3);
- tmpV3[2] = newBoxHigh[2];
- if (tmpV3[0] > high[0])
- high[0] = tmpV3[0];
- if (tmpV3[1] > high[1])
- high[1] = tmpV3[1];
- if (tmpV3[2] > high[2])
- high[2] = tmpV3[2];
+ if (tmpV3.x() > high.x())
+ high.setX( tmpV3.x() );
+ if (tmpV3.y() > high.y())
+ high.setY( tmpV3.y() );
+ if (tmpV3.z() > high.z())
+ high.setZ( tmpV3.z() );
}
computeCenter();
@@ -266,25 +282,25 @@ public class AABBox {
*/
public final AABBox resize(final float x, final float y, final float z) {
/** test low */
- if (x < low[0]) {
- low[0] = x;
+ if (x < low.x()) {
+ low.setX( x );
}
- if (y < low[1]) {
- low[1] = y;
+ if (y < low.y()) {
+ low.setY( y );
}
- if (z < low[2]) {
- low[2] = z;
+ if (z < low.z()) {
+ low.setZ( z );
}
/** test high */
- if (x > high[0]) {
- high[0] = x;
+ if (x > high.x()) {
+ high.setX( x );
}
- if (y > high[1]) {
- high[1] = y;
+ if (y > high.y()) {
+ high.setY( y );
}
- if (z > high[2]) {
- high[2] = z;
+ if (z > high.z()) {
+ high.setZ( z );
}
computeCenter();
@@ -313,6 +329,16 @@ public class AABBox {
}
/**
+ * Resize the AABBox to encapsulate the passed
+ * xyz-coordinates.
+ * @param xyz xyz-axis coordinate values
+ * @return this AABBox for chaining
+ */
+ public final AABBox resize(final Vec3f xyz) {
+ return resize(xyz.x(), xyz.y(), xyz.z());
+ }
+
+ /**
* Check if the x & y coordinates are bounded/contained
* by this AABBox
* @param x x-axis coordinate value
@@ -321,10 +347,10 @@ public class AABBox {
* y belong to (low.y, high.y)
*/
public final boolean contains(final float x, final float y) {
- if(x<low[0] || x>high[0]){
+ if(x<low.x() || x>high.x()){
return false;
}
- if(y<low[1]|| y>high[1]){
+ if(y<low.y()|| y>high.y()){
return false;
}
return true;
@@ -340,13 +366,13 @@ public class AABBox {
* y belong to (low.y, high.y) and z belong to (low.z, high.z)
*/
public final boolean contains(final float x, final float y, final float z) {
- if(x<low[0] || x>high[0]){
+ if(x<low.x() || x>high.x()){
return false;
}
- if(y<low[1]|| y>high[1]){
+ if(y<low.y()|| y>high.y()){
return false;
}
- if(z<low[2] || z>high[2]){
+ if(z<low.z() || z>high.z()){
return false;
}
return true;
@@ -398,19 +424,19 @@ public class AABBox {
// diff[XYZ] -> VectorUtil.subVec3(diff, ray.orig, center);
// ext[XYZ] -> extend VectorUtil.subVec3(ext, high, center);
- final float dirX = ray.dir[0];
- final float diffX = ray.orig[0] - center[0];
- final float extX = high[0] - center[0];
+ final float dirX = ray.dir.x();
+ final float diffX = ray.orig.x() - center.x();
+ final float extX = high.x() - center.x();
if( Math.abs(diffX) > extX && diffX*dirX >= 0f ) return false;
- final float dirY = ray.dir[1];
- final float diffY = ray.orig[1] - center[1];
- final float extY = high[1] - center[1];
+ final float dirY = ray.dir.y();
+ final float diffY = ray.orig.y() - center.y();
+ final float extY = high.y() - center.y();
if( Math.abs(diffY) > extY && diffY*dirY >= 0f ) return false;
- final float dirZ = ray.dir[2];
- final float diffZ = ray.orig[2] - center[2];
- final float extZ = high[2] - center[2];
+ final float dirZ = ray.dir.z();
+ final float diffZ = ray.orig.z() - center.z();
+ final float extZ = high.z() - center.z();
if( Math.abs(diffZ) > extZ && diffZ*dirZ >= 0f ) return false;
final float absDirY = Math.abs(dirY);
@@ -460,45 +486,45 @@ public class AABBox {
* @param assumeIntersection if true, method assumes an intersection, i.e. by pre-checking via {@link #intersectsRay(Ray)}.
* In this case method will not validate a possible non-intersection and just computes
* coordinates.
- * @param tmp1V3 temp vec3
- * @param tmp2V3 temp vec3
- * @param tmp3V3 temp vec3
* @return float[3] result of intersection coordinates, or null if none exists
*/
- public final float[] getRayIntersection(final float[] result, final Ray ray, final float epsilon,
- final boolean assumeIntersection,
- final float[] tmp1V3, final float[] tmp2V3, final float[] tmp3V3) {
+ public final Vec3f getRayIntersection(final Vec3f result, final Ray ray, final float epsilon,
+ final boolean assumeIntersection) {
final float[] maxT = { -1f, -1f, -1f };
- final float[] origin = ray.orig;
- final float[] dir = ray.dir;
+ final Vec3f origin = ray.orig;
+ final Vec3f dir = ray.dir;
boolean inside = true;
// Find candidate planes.
for(int i=0; i<3; i++) {
- if(origin[i] < low[i]) {
- result[i] = low[i];
+ final float origin_i = origin.get(i);
+ final float dir_i = dir.get(i);
+ final float low_i = low.get(i);
+ final float high_i = high.get(i);
+ if(origin_i < low_i) {
+ result.set(i, low_i);
inside = false;
// Calculate T distances to candidate planes
- if( 0 != Float.floatToIntBits(dir[i]) ) {
- maxT[i] = (low[i] - origin[i]) / dir[i];
+ if( 0 != Float.floatToIntBits(dir_i) ) {
+ maxT[i] = (low_i - origin_i) / dir_i;
}
- } else if(origin[i] > high[i]) {
- result[i] = high[i];
+ } else if(origin_i > high_i) {
+ result.set(i, high_i);
inside = false;
// Calculate T distances to candidate planes
- if( 0 != Float.floatToIntBits(dir[i]) ) {
- maxT[i] = (high[i] - origin[i]) / dir[i];
+ if( 0 != Float.floatToIntBits(dir_i) ) {
+ maxT[i] = (high_i - origin_i) / dir_i;
}
}
}
// Ray origin inside bounding box
if(inside) {
- System.arraycopy(origin, 0, result, 0, 3);
+ result.set(origin);
return result;
}
@@ -523,22 +549,22 @@ public class AABBox {
} */
switch( whichPlane ) {
case 0:
- result[1] = origin[1] + maxT[whichPlane] * dir[1];
- if(result[1] < low[1] - epsilon || result[1] > high[1] + epsilon) { return null; }
- result[2] = origin[2] + maxT[whichPlane] * dir[2];
- if(result[2] < low[2] - epsilon || result[2] > high[2] + epsilon) { return null; }
+ result.setY( origin.y() + maxT[whichPlane] * dir.y() );
+ if(result.y() < low.y() - epsilon || result.y() > high.y() + epsilon) { return null; }
+ result.setZ( origin.z() + maxT[whichPlane] * dir.z() );
+ if(result.z() < low.z() - epsilon || result.z() > high.z() + epsilon) { return null; }
break;
case 1:
- result[0] = origin[0] + maxT[whichPlane] * dir[0];
- if(result[0] < low[0] - epsilon || result[0] > high[0] + epsilon) { return null; }
- result[2] = origin[2] + maxT[whichPlane] * dir[2];
- if(result[2] < low[2] - epsilon || result[2] > high[2] + epsilon) { return null; }
+ result.setX( origin.x() + maxT[whichPlane] * dir.x() );
+ if(result.x() < low.x() - epsilon || result.x() > high.x() + epsilon) { return null; }
+ result.setZ( origin.z() + maxT[whichPlane] * dir.z() );
+ if(result.z() < low.z() - epsilon || result.z() > high.z() + epsilon) { return null; }
break;
case 2:
- result[0] = origin[0] + maxT[whichPlane] * dir[0];
- if(result[0] < low[0] - epsilon || result[0] > high[0] + epsilon) { return null; }
- result[1] = origin[1] + maxT[whichPlane] * dir[1];
- if(result[1] < low[1] - epsilon || result[1] > high[1] + epsilon) { return null; }
+ result.setX( origin.x() + maxT[whichPlane] * dir.x() );
+ if(result.x() < low.x() - epsilon || result.x() > high.x() + epsilon) { return null; }
+ result.setY( origin.y() + maxT[whichPlane] * dir.y() );
+ if(result.y() < low.y() - epsilon || result.y() > high.y() + epsilon) { return null; }
break;
default:
throw new InternalError("XXX");
@@ -546,16 +572,16 @@ public class AABBox {
} else {
switch( whichPlane ) {
case 0:
- result[1] = origin[1] + maxT[whichPlane] * dir[1];
- result[2] = origin[2] + maxT[whichPlane] * dir[2];
+ result.setY( origin.y() + maxT[whichPlane] * dir.y() );
+ result.setZ( origin.z() + maxT[whichPlane] * dir.z() );
break;
case 1:
- result[0] = origin[0] + maxT[whichPlane] * dir[0];
- result[2] = origin[2] + maxT[whichPlane] * dir[2];
+ result.setX( origin.x() + maxT[whichPlane] * dir.x() );
+ result.setZ( origin.z() + maxT[whichPlane] * dir.z() );
break;
case 2:
- result[0] = origin[0] + maxT[whichPlane] * dir[0];
- result[1] = origin[1] + maxT[whichPlane] * dir[1];
+ result.setX( origin.x() + maxT[whichPlane] * dir.x() );
+ result.setY( origin.y() + maxT[whichPlane] * dir.y() );
break;
default:
throw new InternalError("XXX");
@@ -570,14 +596,14 @@ public class AABBox {
* @return a float representing the size of the AABBox
*/
public final float getSize() {
- return VectorUtil.distVec3(low, high);
+ return low.dist(high);
}
/**
* Get the Center of this AABBox
* @return the xyz-coordinates of the center of the AABBox
*/
- public final float[] getCenter() {
+ public final Vec3f getCenter() {
return center;
}
@@ -587,23 +613,17 @@ public class AABBox {
* high and low is recomputed by scaling its distance to fixed center.
* </p>
* @param size a constant float value
- * @param tmpV3 caller provided temporary 3-component vector
* @return this AABBox for chaining
+ * @see #scale2(float, float[])
*/
- public final AABBox scale(final float size, final float[] tmpV3) {
- tmpV3[0] = high[0] - center[0];
- tmpV3[1] = high[1] - center[1];
- tmpV3[2] = high[2] - center[2];
-
- VectorUtil.scaleVec3(tmpV3, tmpV3, size); // in-place scale
- VectorUtil.addVec3(high, center, tmpV3);
+ public final AABBox scale(final float size) {
+ final Vec3f tmp = new Vec3f();
+ tmp.set(high).sub(center).scale(size);
+ high.set(center).add(tmp);
- tmpV3[0] = low[0] - center[0];
- tmpV3[1] = low[1] - center[1];
- tmpV3[2] = low[2] - center[2];
+ tmp.set(low).sub(center).scale(size);
+ low.set(center).add(tmp);
- VectorUtil.scaleVec3(tmpV3, tmpV3, size); // in-place scale
- VectorUtil.addVec3(low, center, tmpV3);
return this;
}
@@ -613,12 +633,27 @@ public class AABBox {
* high and low is scaled and center recomputed.
* </p>
* @param size a constant float value
- * @param tmpV3 caller provided temporary 3-component vector
+ * @return this AABBox for chaining
+ * @see #scale(float, float[])
+ */
+ public final AABBox scale2(final float size) {
+ high.scale(size);
+ low.scale(size);
+ computeCenter();
+ return this;
+ }
+
+ /**
+ * Translate this AABBox by a float[3] vector
+ * @param dx the translation x-component
+ * @param dy the translation y-component
+ * @param dz the translation z-component
+ * @param t the float[3] translation vector
* @return this AABBox for chaining
*/
- public final AABBox scale2(final float size, final float[] tmpV3) {
- VectorUtil.scaleVec3(high, high, size); // in-place scale
- VectorUtil.scaleVec3(low, low, size); // in-place scale
+ public final AABBox translate(final float dx, final float dy, final float dz) {
+ low.add(dx, dy, dz);
+ high.add(dx, dy, dz);
computeCenter();
return this;
}
@@ -628,9 +663,9 @@ public class AABBox {
* @param t the float[3] translation vector
* @return this AABBox for chaining
*/
- public final AABBox translate(final float[] t) {
- VectorUtil.addVec3(low, low, t); // in-place translate
- VectorUtil.addVec3(high, high, t); // in-place translate
+ public final AABBox translate(final Vec3f t) {
+ low.add(t);
+ high.add(t);
computeCenter();
return this;
}
@@ -641,46 +676,46 @@ public class AABBox {
* @return this AABBox for chaining
*/
public final AABBox rotate(final Quaternion quat) {
- quat.rotateVector(low, 0, low, 0);
- quat.rotateVector(high, 0, high, 0);
+ quat.rotateVector(low, low);
+ quat.rotateVector(high, high);
computeCenter();
return this;
}
public final float getMinX() {
- return low[0];
+ return low.x();
}
public final float getMinY() {
- return low[1];
+ return low.y();
}
public final float getMinZ() {
- return low[2];
+ return low.z();
}
public final float getMaxX() {
- return high[0];
+ return high.x();
}
public final float getMaxY() {
- return high[1];
+ return high.y();
}
public final float getMaxZ() {
- return high[2];
+ return high.z();
}
public final float getWidth(){
- return high[0] - low[0];
+ return high.x() - low.x();
}
public final float getHeight() {
- return high[1] - low[1];
+ return high.y() - low.y();
}
public final float getDepth() {
- return high[2] - low[2];
+ return high.z() - low.z();
}
@Override
@@ -692,8 +727,7 @@ public class AABBox {
return false;
}
final AABBox other = (AABBox) obj;
- return VectorUtil.isVec2Equal(low, 0, other.low, 0, FloatUtil.EPSILON) &&
- VectorUtil.isVec3Equal(high, 0, other.high, 0, FloatUtil.EPSILON) ;
+ return low.isEqual(other.low) && high.isEqual(other.high);
}
@Override
public final int hashCode() {
@@ -701,79 +735,103 @@ public class AABBox {
}
/**
+ * Transform this box using the given {@link Matrix4f} into {@code out}
+ * @param mat transformation {@link Matrix4f}
+ * @param out the resulting {@link AABBox}
+ * @return the resulting {@link AABBox} for chaining
+ */
+ public AABBox transform(final Matrix4f mat, final AABBox out) {
+ final Vec3f tmp = new Vec3f();
+ out.reset();
+ out.resize( mat.mulVec3f(low, tmp) );
+ out.resize( mat.mulVec3f(high, tmp) );
+ out.computeCenter();
+ return out;
+ }
+
+ /**
+ * Transform this box using the {@link PMVMatrix#getMvMat() modelview} of the given {@link PMVMatrix} into {@code out}
+ * @param pmv transformation {@link PMVMatrix}
+ * @param out the resulting {@link AABBox}
+ * @return the resulting {@link AABBox} for chaining
+ */
+ public AABBox transformMv(final PMVMatrix pmv, final AABBox out) {
+ final Vec3f tmp = new Vec3f();
+ out.reset();
+ out.resize( pmv.mulMvMatVec3f(low, tmp) );
+ out.resize( pmv.mulMvMatVec3f(high, tmp) );
+ out.computeCenter();
+ return out;
+ }
+
+ /**
* Assume this bounding box as being in object space and
* compute the window bounding box.
* <p>
* If <code>useCenterZ</code> is <code>true</code>,
- * only 4 {@link FloatUtil#mapObjToWinCoords(float, float, float, float[], int[], int, float[], int, float[], float[]) mapObjToWinCoords}
+ * only 4 {@link FloatUtil#mapObjToWin(float, float, float, float[], int[], float[], float[], float[]) mapObjToWinCoords}
* operations are made on points [1..4] using {@link #getCenter()}'s z-value.
- * Otherwise 8 {@link FloatUtil#mapObjToWinCoords(float, float, float, float[], int[], int, float[], int, float[], float[]) mapObjToWinCoords}
+ * Otherwise 8 {@link FloatUtil#mapObjToWin(float, float, float, float[], int[], float[], float[], float[]) mapObjToWinCoords}
* operation on all 8 points are performed.
* </p>
* <pre>
- * [2] ------ [4]
+ * .z() ------ [4]
* | |
* | |
- * [1] ------ [3]
+ * .y() ------ [3]
* </pre>
- * @param mat4PMv P x Mv matrix
- * @param view
+ * @param mat4PMv [projection] x [modelview] matrix, i.e. P x Mv
+ * @param viewport viewport rectangle
* @param useCenterZ
* @param vec3Tmp0 3 component vector for temp storage
* @param vec4Tmp1 4 component vector for temp storage
* @param vec4Tmp2 4 component vector for temp storage
* @return
*/
- public AABBox mapToWindow(final AABBox result, final float[/*16*/] mat4PMv, final int[] view, final boolean useCenterZ,
- final float[] vec3Tmp0, final float[] vec4Tmp1, final float[] vec4Tmp2) {
+ public AABBox mapToWindow(final AABBox result, final Matrix4f mat4PMv, final Recti viewport, final boolean useCenterZ) {
+ final Vec3f tmp = new Vec3f();
+ final Vec3f winPos = new Vec3f();
{
- // System.err.printf("AABBox.mapToWindow.0: view[%d, %d, %d, %d], this %s%n", view[0], view[1], view[2], view[3], toString());
- final float objZ = useCenterZ ? center[2] : getMinZ();
- FloatUtil.mapObjToWinCoords(getMinX(), getMinY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- // System.err.printf("AABBox.mapToWindow.p1: %f, %f, %f -> %f, %f, %f%n", getMinX(), getMinY(), objZ, vec3Tmp0[0], vec3Tmp0[1], vec3Tmp0[2]);
- // System.err.println("AABBox.mapToWindow.p1:");
- // System.err.println(FloatUtil.matrixToString(null, " mat4PMv", "%10.5f", mat4PMv, 0, 4, 4, false /* rowMajorOrder */));
-
+ final float objZ = useCenterZ ? center.z() : getMinZ();
result.reset();
- result.resize(vec3Tmp0, 0);
- FloatUtil.mapObjToWinCoords(getMinX(), getMaxY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- // System.err.printf("AABBox.mapToWindow.p2: %f, %f, %f -> %f, %f, %f%n", getMinX(), getMaxY(), objZ, vec3Tmp0[0], vec3Tmp0[1], vec3Tmp0[2]);
- result.resize(vec3Tmp0, 0);
+ Matrix4f.mapObjToWin(tmp.set(getMinX(), getMinY(), objZ), mat4PMv, viewport, winPos);
+ result.resize(winPos);
+
+ Matrix4f.mapObjToWin(tmp.set(getMinX(), getMaxY(), objZ), mat4PMv, viewport, winPos);
+ result.resize(winPos);
- FloatUtil.mapObjToWinCoords(getMaxX(), getMinY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- // System.err.printf("AABBox.mapToWindow.p3: %f, %f, %f -> %f, %f, %f%n", getMaxX(), getMinY(), objZ, vec3Tmp0[0], vec3Tmp0[1], vec3Tmp0[2]);
- result.resize(vec3Tmp0, 0);
+ Matrix4f.mapObjToWin(tmp.set(getMaxX(), getMaxY(), objZ), mat4PMv, viewport, winPos);
+ result.resize(winPos);
- FloatUtil.mapObjToWinCoords(getMaxX(), getMaxY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- // System.err.printf("AABBox.mapToWindow.p4: %f, %f, %f -> %f, %f, %f%n", getMaxX(), getMaxY(), objZ, vec3Tmp0[0], vec3Tmp0[1], vec3Tmp0[2]);
- result.resize(vec3Tmp0, 0);
+ Matrix4f.mapObjToWin(tmp.set(getMaxX(), getMinY(), objZ), mat4PMv, viewport, winPos);
+ result.resize(winPos);
}
if( !useCenterZ ) {
final float objZ = getMaxZ();
- FloatUtil.mapObjToWinCoords(getMinX(), getMinY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- result.resize(vec3Tmp0, 0);
- FloatUtil.mapObjToWinCoords(getMinX(), getMaxY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- result.resize(vec3Tmp0, 0);
+ Matrix4f.mapObjToWin(tmp.set(getMinX(), getMinY(), objZ), mat4PMv, viewport, winPos);
+ result.resize(winPos);
+
+ Matrix4f.mapObjToWin(tmp.set(getMinX(), getMaxY(), objZ), mat4PMv, viewport, winPos);
+ result.resize(winPos);
- FloatUtil.mapObjToWinCoords(getMaxX(), getMinY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- result.resize(vec3Tmp0, 0);
+ Matrix4f.mapObjToWin(tmp.set(getMaxX(), getMaxY(), objZ), mat4PMv, viewport, winPos);
+ result.resize(winPos);
- FloatUtil.mapObjToWinCoords(getMaxX(), getMaxY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- result.resize(vec3Tmp0, 0);
+ Matrix4f.mapObjToWin(tmp.set(getMaxX(), getMinY(), objZ), mat4PMv, viewport, winPos);
+ result.resize(winPos);
}
if( DEBUG ) {
- System.err.printf("AABBox.mapToWindow: view[%d, %d], this %s -> %s%n", view[0], view[1], toString(), result.toString());
+ System.err.printf("AABBox.mapToWindow: view[%s], this %s -> %s%n", viewport, toString(), result.toString());
}
return result;
}
@Override
public final String toString() {
- return "[ dim "+getWidth()+" x "+getHeight()+" x "+getDepth()+
- ", box "+low[0]+" / "+low[1]+" / "+low[2]+" .. "+high[0]+" / "+high[1]+" / "+high[2]+
- ", ctr "+center[0]+" / "+center[1]+" / "+center[2]+" ]";
+ return "[dim "+getWidth()+" x "+getHeight()+" x "+getDepth()+
+ ", box "+low+" .. "+high+", ctr "+center+"]";
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java b/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java
index 8b0fa559e..73079959b 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -27,15 +27,13 @@
*/
package com.jogamp.opengl.math.geom;
-import jogamp.common.os.PlatformPropsImpl;
-
-import com.jogamp.common.os.Platform;
-import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Matrix4f;
+import com.jogamp.opengl.math.Vec3f;
/**
* Providing frustum {@link #getPlanes() planes} derived by different inputs
- * ({@link #updateByPMV(float[], int) P*MV}, ..) used to classify objects
+ * ({@link #updateFrustumPlanes(float[], int) P*MV}, ..) used to classify objects
* <ul>
* <li> {@link #classifyPoint(float[]) point} </li>
* <li> {@link #classifySphere(float[], float) sphere} </li>
@@ -103,6 +101,7 @@ public class Frustum {
this.zNear = zNear;
this.zFar = zFar;
}
+ @Override
public final String toString() {
return "FrustumFovDesc["+fovhv.toStringInDegrees()+", Z["+zNear+" - "+zFar+"]]";
}
@@ -117,7 +116,7 @@ public class Frustum {
* Use one of the <code>update(..)</code> methods to set the {@link #getPlanes() planes}.
* </p>
* @see #updateByPlanes(Plane[])
- * @see #updateByPMV(float[], int)
+ * @see #updateFrustumPlanes(float[], int)
*/
public Frustum() {
for (int i = 0; i < 6; ++i) {
@@ -134,7 +133,7 @@ public class Frustum {
*/
public static class Plane {
/** Normal of the plane */
- public final float[] n = new float[3];
+ public final Vec3f n = new Vec3f();
/** Distance to origin */
public float d;
@@ -155,17 +154,17 @@ public class Frustum {
* </p>
**/
public final float distanceTo(final float x, final float y, final float z) {
- return n[0] * x + n[1] * y + n[2] * z + d;
+ return n.x() * x + n.y() * y + n.z() * z + d;
}
/** Return distance of plane to given point, see {@link #distanceTo(float, float, float)}. */
- public final float distanceTo(final float[] p) {
- return n[0] * p[0] + n[1] * p[1] + n[2] * p[2] + d;
+ public final float distanceTo(final Vec3f p) {
+ return n.x() * p.x() + n.y() * p.y() + n.z() * p.z() + d;
}
@Override
public String toString() {
- return "Plane[ [ " + n[0] + ", " + n[1] + ", " + n[2] + " ], " + d + "]";
+ return "Plane[ [ " + n + " ], " + d + "]";
}
}
@@ -221,9 +220,9 @@ public class Frustum {
* Operation Details:
* <ul>
* <li>The given {@link FovDesc} will be transformed
- * into the given float[16] as a perspective matrix (column major order) first,
- * see {@link FloatUtil#makePerspective(float[], int, boolean, FovHVHalves, float, float)}.</li>
- * <li>Then the float[16] perspective matrix is used to {@link #updateByPMV(float[], int)} this instance.</li>
+ * into the given perspective matrix (column major order) first,
+ * see {@link Matrix4f#setToPerspective(FovHVHalves, float, float)}.</li>
+ * <li>Then the perspective matrix is used to {@link Matrix4f#updateFrustumPlanes(Frustum)} this instance.</li>
* </ul>
* </p>
* <p>
@@ -232,120 +231,42 @@ public class Frustum {
* </p>
*
* @param m 4x4 matrix in column-major order (also result)
- * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
- * @param initM if true, given matrix will be initialized w/ identity matrix,
- * otherwise only the frustum fields are set.
* @param fovDesc {@link Frustum} {@link FovDesc}
* @return given matrix for chaining
- * @see FloatUtil#makePerspective(float[], int, boolean, FovHVHalves, float, float)
+ * @see Matrix4f#setToPerspective(FovHVHalves, float, float)
+ * @see Matrix4f#updateFrustumPlanes(Frustum)
+ * @see Matrix4f#getFrustum(Frustum, FovDesc)
*/
- public float[] updateByFovDesc(final float[] m, final int m_offset, final boolean initM,
- final FovDesc fovDesc) {
- FloatUtil.makePerspective(m, m_offset, initM, fovDesc.fovhv, fovDesc.zNear, fovDesc.zFar);
- updateByPMV(m, 0);
+ public Matrix4f updateByFovDesc(final Matrix4f m, final FovDesc fovDesc) {
+ m.setToPerspective(fovDesc.fovhv, fovDesc.zNear, fovDesc.zFar);
+ m.updateFrustumPlanes(this);
return m;
}
/**
* Calculate the frustum planes in world coordinates
- * using the passed float[16] as premultiplied P*MV (column major order).
+ * using the passed premultiplied P*MV (column major order) matrix.
* <p>
* Frustum plane's normals will point to the inside of the viewing frustum,
* as required by this class.
* </p>
*/
- public void updateByPMV(final float[] pmv, final int pmv_off) {
- // Left: a = m41 + m11, b = m42 + m12, c = m43 + m13, d = m44 + m14 - [1..4] column-major
- // Left: a = m30 + m00, b = m31 + m01, c = m32 + m02, d = m33 + m03 - [0..3] column-major
- {
- final Plane p = planes[LEFT];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 0 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 0 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 0 + 2 * 4 ];
- p.d = pmv[ pmv_off + 3 + 3 * 4 ] + pmv[ pmv_off + 0 + 3 * 4 ];
- }
-
- // Right: a = m41 - m11, b = m42 - m12, c = m43 - m13, d = m44 - m14 - [1..4] column-major
- // Right: a = m30 - m00, b = m31 - m01, c = m32 - m02, d = m33 - m03 - [0..3] column-major
- {
- final Plane p = planes[RIGHT];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 0 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 0 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 0 + 2 * 4 ];
- p.d = pmv[ pmv_off + 3 + 3 * 4 ] - pmv[ pmv_off + 0 + 3 * 4 ];
- }
-
- // Bottom: a = m41 + m21, b = m42 + m22, c = m43 + m23, d = m44 + m24 - [1..4] column-major
- // Bottom: a = m30 + m10, b = m31 + m11, c = m32 + m12, d = m33 + m13 - [0..3] column-major
- {
- final Plane p = planes[BOTTOM];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 1 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 1 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 1 + 2 * 4 ];
- p.d = pmv[ pmv_off + 3 + 3 * 4 ] + pmv[ pmv_off + 1 + 3 * 4 ];
- }
-
- // Top: a = m41 - m21, b = m42 - m22, c = m43 - m23, d = m44 - m24 - [1..4] column-major
- // Top: a = m30 - m10, b = m31 - m11, c = m32 - m12, d = m33 - m13 - [0..3] column-major
- {
- final Plane p = planes[TOP];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 1 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 1 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 1 + 2 * 4 ];
- p.d = pmv[ pmv_off + 3 + 3 * 4 ] - pmv[ pmv_off + 1 + 3 * 4 ];
- }
-
- // Near: a = m41 + m31, b = m42 + m32, c = m43 + m33, d = m44 + m34 - [1..4] column-major
- // Near: a = m30 + m20, b = m31 + m21, c = m32 + m22, d = m33 + m23 - [0..3] column-major
- {
- final Plane p = planes[NEAR];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 2 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 2 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 2 + 2 * 4 ];
- p.d = pmv[ pmv_off + 3 + 3 * 4 ] + pmv[ pmv_off + 2 + 3 * 4 ];
- }
-
- // Far: a = m41 - m31, b = m42 - m32, c = m43 - m33, d = m44 - m34 - [1..4] column-major
- // Far: a = m30 - m20, b = m31 - m21, c = m32 + m22, d = m33 + m23 - [0..3] column-major
- {
- final Plane p = planes[FAR];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 2 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 2 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 2 + 2 * 4 ];
- p.d = pmv[ pmv_off + 3 + 3 * 4 ] - pmv[ pmv_off + 2 + 3 * 4 ];
- }
-
- // Normalize all planes
- for (int i = 0; i < 6; ++i) {
- final Plane p = planes[i];
- final float[] p_n = p.n;
- final double invl = Math.sqrt(p_n[0] * p_n[0] + p_n[1] * p_n[1] + p_n[2] * p_n[2]);
-
- p_n[0] /= invl;
- p_n[1] /= invl;
- p_n[2] /= invl;
- p.d /= invl;
- }
+ public void updateFrustumPlanes(final Matrix4f pmv) {
+ pmv.updateFrustumPlanes(this);
}
private static final boolean isOutsideImpl(final Plane p, final AABBox box) {
- final float[] low = box.getLow();
- final float[] high = box.getHigh();
-
- if ( p.distanceTo(low[0], low[1], low[2]) > 0.0f ||
- p.distanceTo(high[0], low[1], low[2]) > 0.0f ||
- p.distanceTo(low[0], high[1], low[2]) > 0.0f ||
- p.distanceTo(high[0], high[1], low[2]) > 0.0f ||
- p.distanceTo(low[0], low[1], high[2]) > 0.0f ||
- p.distanceTo(high[0], low[1], high[2]) > 0.0f ||
- p.distanceTo(low[0], high[1], high[2]) > 0.0f ||
- p.distanceTo(high[0], high[1], high[2]) > 0.0f ) {
+ final Vec3f lo = box.getLow();
+ final Vec3f hi = box.getHigh();
+
+ if ( p.distanceTo(lo.x(), lo.y(), lo.z()) > 0.0f ||
+ p.distanceTo(hi.x(), lo.y(), lo.z()) > 0.0f ||
+ p.distanceTo(lo.x(), hi.y(), lo.z()) > 0.0f ||
+ p.distanceTo(hi.x(), hi.y(), lo.z()) > 0.0f ||
+ p.distanceTo(lo.x(), lo.y(), hi.z()) > 0.0f ||
+ p.distanceTo(hi.x(), lo.y(), hi.z()) > 0.0f ||
+ p.distanceTo(lo.x(), hi.y(), hi.z()) > 0.0f ||
+ p.distanceTo(hi.x(), hi.y(), hi.z()) > 0.0f ) {
return false;
}
return true;
@@ -377,7 +298,7 @@ public class Frustum {
* @param p the point
* @return {@link Location} of point related to frustum planes
*/
- public final Location classifyPoint(final float[] p) {
+ public final Location classifyPoint(final Vec3f p) {
Location res = Location.INSIDE;
for (int i = 0; i < 6; ++i) {
@@ -397,7 +318,7 @@ public class Frustum {
* @param p the point
* @return true if outside of the frustum, otherwise inside or on a plane
*/
- public final boolean isPointOutside(final float[] p) {
+ public final boolean isPointOutside(final Vec3f p) {
return Location.OUTSIDE == classifyPoint(p);
}
@@ -408,7 +329,7 @@ public class Frustum {
* @param radius radius of the sphere
* @return {@link Location} of point related to frustum planes
*/
- public final Location classifySphere(final float[] p, final float radius) {
+ public final Location classifySphere(final Vec3f p, final float radius) {
Location res = Location.INSIDE; // fully inside
for (int i = 0; i < 6; ++i) {
@@ -431,7 +352,7 @@ public class Frustum {
* @param radius radius of the sphere
* @return true if outside of the frustum, otherwise inside or intersecting
*/
- public final boolean isSphereOutside(final float[] p, final float radius) {
+ public final boolean isSphereOutside(final Vec3f p, final float radius) {
return Location.OUTSIDE == classifySphere(p, radius);
}
@@ -439,13 +360,13 @@ public class Frustum {
if( null == sb ) {
sb = new StringBuilder();
}
- sb.append("Frustum[ Planes[ ").append(PlatformPropsImpl.NEWLINE)
- .append(" L: ").append(planes[0]).append(", ").append(PlatformPropsImpl.NEWLINE)
- .append(" R: ").append(planes[1]).append(", ").append(PlatformPropsImpl.NEWLINE)
- .append(" B: ").append(planes[2]).append(", ").append(PlatformPropsImpl.NEWLINE)
- .append(" T: ").append(planes[3]).append(", ").append(PlatformPropsImpl.NEWLINE)
- .append(" N: ").append(planes[4]).append(", ").append(PlatformPropsImpl.NEWLINE)
- .append(" F: ").append(planes[5]).append("], ").append(PlatformPropsImpl.NEWLINE)
+ sb.append("Frustum[Planes[").append(System.lineSeparator())
+ .append(" L: ").append(planes[0]).append(", ").append(System.lineSeparator())
+ .append(" R: ").append(planes[1]).append(", ").append(System.lineSeparator())
+ .append(" B: ").append(planes[2]).append(", ").append(System.lineSeparator())
+ .append(" T: ").append(planes[3]).append(", ").append(System.lineSeparator())
+ .append(" N: ").append(planes[4]).append(", ").append(System.lineSeparator())
+ .append(" F: ").append(planes[5]).append("], ").append(System.lineSeparator())
.append("]");
return sb;
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java
index e5f9e5336..61de9155a 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java
@@ -431,29 +431,13 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData
/**
* Increase the capacity of the buffer if necessary to add given spareComponents components.
* <p>
- * Buffer will not change if current capacity satisfies spareComponents components.
+ * Buffer will not change if remaining free slots, capacity less position, satisfy spareComponents components.
* </p>
* @param spareComponents number of components to add if necessary.
* @return true if buffer size has changed, i.e. grown. Otherwise false.
*/
public final boolean growIfNeeded(final int spareComponents) {
- if( buffer.remaining() < spareComponents ) {
- if( 0 != mappedElemCount ) {
- throw new GLException("Mapped buffer can't grow. Insufficient storage size: Needed "+spareComponents+" components, "+
- "mappedElementCount "+mappedElemCount+
- ", has mapped buffer "+buffer+"; "+this);
- }
- final int has_comps = buffer.capacity();
- final int required_elems = compsToElemCount(has_comps + spareComponents);
- final int new_elems = compsToElemCount( (int)( has_comps * growthFactor + 0.5f ) );
- final int elementCount = Math.max( new_elems, required_elems );
- return reserve( elementCount );
- }
- return false;
- }
-
- public final boolean growIfNeeded0(final int spareComponents) {
- if( buffer==null || buffer.remaining()<spareComponents ) {
+ if( null == buffer || buffer.remaining() < spareComponents ) {
if( 0 != mappedElemCount ) {
throw new GLException("Mapped buffer can't grow. Insufficient storage size: Needed "+spareComponents+" components, "+
"mappedElementCount "+mappedElemCount+
@@ -467,9 +451,6 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData
final int required_elems = compsToElemCount(has_comps + spareComponents);
final int new_elems = compsToElemCount( (int)( has_comps * growthFactor + 0.5f ) );
final int elementCount = Math.max( new_elems, required_elems );
- if( DEBUG ) {
- System.err.println("*** Size: Grow: elems "+compsToElemCount(has_comps)+" -> max("+new_elems+", "+required_elems+") -> "+elementCount);
- }
return reserve( elementCount );
}
}
@@ -480,7 +461,7 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData
* Increase the capacity of the buffer to given elementCount element size,
* i.e. elementCount * componentsPerElement components.
* <p>
- * Buffer will not change if given elementCount is lower than current size.
+ * Buffer will not change if given elementCount is lower or equal current capacity.
* </p>
* @param elementCount number of elements to hold.
* @return true if buffer size has changed, i.e. grown. Otherwise false.
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java
index e530ad627..433a25eb8 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java
@@ -412,7 +412,7 @@ public class GLArrayDataServer extends GLArrayDataClient implements GLArrayDataE
* @param comps This interleaved array segment's component count per element
* @param vboTarget {@link GL#GL_ARRAY_BUFFER} or {@link GL#GL_ELEMENT_ARRAY_BUFFER}
*/
- public GLArrayData addGLSLSubArray(final String name, final int comps, final int vboTarget) {
+ public GLArrayDataWrapper addGLSLSubArray(final String name, final int comps, final int vboTarget) {
if(interleavedOffset >= getCompsPerElem() * getBytesPerComp()) {
final int iOffC = interleavedOffset / getBytesPerComp();
throw new GLException("Interleaved offset > total components ("+iOffC+" > "+getCompsPerElem()+")");
diff --git a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java
index 5383f91be..b8b2925ae 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java
@@ -1,64 +1,66 @@
-/*
- * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
- * Copyright (c) 2011 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
+/**
+ * Copyright 2009-2023 JogAmp Community. All rights reserved.
*
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
*
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
*
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
*
- * This software is provided "AS IS," without a warranty of any kind. ALL
- * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
- * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
- * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
- * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
- * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
- * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
- * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
- * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
- * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
*/
-
package com.jogamp.opengl.util;
+import java.nio.Buffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GLException;
import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
-
-import jogamp.common.os.PlatformPropsImpl;
+import com.jogamp.opengl.GLUniformData;
import com.jogamp.common.nio.Buffers;
-import com.jogamp.common.util.FloatStack;
import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.Quaternion;
import com.jogamp.opengl.math.Ray;
+import com.jogamp.opengl.math.Recti;
+import com.jogamp.opengl.math.Vec3f;
+import com.jogamp.opengl.math.Vec4f;
import com.jogamp.opengl.math.geom.AABBox;
import com.jogamp.opengl.math.geom.Frustum;
/**
* PMVMatrix implements a subset of the fixed function pipeline
- * regarding the projection (P), modelview (Mv) matrix operation
+ * regarding the projection (P), modelview (Mv) and texture (T) matrix operations,
* which is specified in {@link GLMatrixFunc}.
* <p>
- * Further more, PMVMatrix provides the {@link #glGetMviMatrixf() inverse modelview matrix (Mvi)} and
- * {@link #glGetMvitMatrixf() inverse transposed modelview matrix (Mvit)}.
- * {@link Frustum} is also provided by {@link #glGetFrustum()}.
+ * This is the second implementation of `PMVMatrix` using
+ * direct {@link Matrix4f}, {@link Vec4f} and {@link Vec3f} math operations instead of `float[]`
+ * via {@link com.jogamp.opengl.math.FloatUtil FloatUtil}.
+ * </p>
+ * <p>
+ * PMVMatrix provides the {@link #getMviMat() inverse modelview matrix (Mvi)} and
+ * {@link #getMvitMat() inverse transposed modelview matrix (Mvit)}.
+ * {@link Frustum} is also provided by {@link #getFrustum()}.
+ *
* To keep these derived values synchronized after mutable Mv operations like {@link #glRotatef(float, float, float, float) glRotatef(..)}
* in {@link #glMatrixMode(int) glMatrixMode}({@link GLMatrixFunc#GL_MODELVIEW GL_MODELVIEW}),
* users have to call {@link #update()} before using Mvi and Mvit.
@@ -66,7 +68,7 @@ import com.jogamp.opengl.math.geom.Frustum;
* <p>
* All matrices are provided in column-major order,
* as specified in the OpenGL fixed function pipeline, i.e. compatibility profile.
- * See {@link FloatUtil}.
+ * See {@link Matrix4f}.
* </p>
* <p>
* PMVMatrix can supplement {@link GL2ES2} applications w/ the
@@ -74,6 +76,23 @@ import com.jogamp.opengl.math.geom.Frustum;
* </p>
* <a name="storageDetails"><h5>Matrix storage details</h5></a>
* <p>
+ * The {@link SyncBuffer} abstraction is provided, e.g. {@link #getSyncPMvMviMat()},
+ * to synchronize the respective {@link Matrix4f matrices} with the `float[]` backing store.
+ * The latter is represents the data to {@link GLUniformData} via its {@link FloatBuffer}s, see {@link SyncBuffer#getBuffer()},
+ * and is pushed to the GPU eventually.
+ *
+ * {@link SyncBuffer}'s {@link SyncAction} is called by {@link GLUniformData#getBuffer()},
+ * i.e. before the data is pushed to the GPU.
+ *
+ * The provided {@link SyncAction} ensures that the {@link Matrix4f matrices data}
+ * gets copied into the `float[]` backing store.
+ *
+ * PMVMatrix provides two specializations of {@link SyncBuffer}, {@link SyncMatrix4f} for single {@link Matrix4f} mappings
+ * and {@link SyncMatrices4f} for multiple {@link Matrix4f} mappings.
+ *
+ * They can be feed directly to instantiate a {@link GLUniformData} object via e.g. {@link GLUniformData#GLUniformData(String, int, int, SyncBuffer)}.
+ * </p>
+ * <p>
* All matrices are backed up by a common primitive float-array for performance considerations
* and are a {@link Buffers#slice2Float(float[], int, int) sliced} representation of it.
* </p>
@@ -88,23 +107,27 @@ import com.jogamp.opengl.math.geom.Frustum;
*/
public final class PMVMatrix implements GLMatrixFunc {
- /** Bit value stating a modified {@link #glGetPMatrixf() projection matrix (P)}, since last {@link #update()} call. */
+ /** Bit value stating a modified {@link #getPMat() projection matrix (P)}, since last {@link #update()} call. */
public static final int MODIFIED_PROJECTION = 1 << 0;
- /** Bit value stating a modified {@link #glGetMvMatrixf() modelview matrix (Mv)}, since last {@link #update()} call. */
+ /** Bit value stating a modified {@link #getMvMat() modelview matrix (Mv)}, since last {@link #update()} call. */
public static final int MODIFIED_MODELVIEW = 1 << 1;
- /** Bit value stating a modified {@link #glGetTMatrixf() texture matrix (T)}, since last {@link #update()} call. */
+ /** Bit value stating a modified {@link #getTMat() texture matrix (T)}, since last {@link #update()} call. */
public static final int MODIFIED_TEXTURE = 1 << 2;
/** Bit value stating all is modified */
public static final int MODIFIED_ALL = MODIFIED_PROJECTION | MODIFIED_MODELVIEW | MODIFIED_TEXTURE ;
- /** Bit value stating a dirty {@link #glGetMviMatrixf() inverse modelview matrix (Mvi)}. */
- public static final int DIRTY_INVERSE_MODELVIEW = 1 << 0;
- /** Bit value stating a dirty {@link #glGetMvitMatrixf() inverse transposed modelview matrix (Mvit)}. */
- public static final int DIRTY_INVERSE_TRANSPOSED_MODELVIEW = 1 << 1;
- /** Bit value stating a dirty {@link #glGetFrustum() frustum}. */
- public static final int DIRTY_FRUSTUM = 1 << 2;
- /** Bit value stating all is dirty */
- public static final int DIRTY_ALL = DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM;
+ /** Bit value for {@link #getMviMat() inverse modelview matrix (Mvi)}, updated via {@link #update()}. */
+ public static final int INVERSE_MODELVIEW = 1 << 1;
+ /** Bit value for {@link #getMvitMat() inverse transposed modelview matrix (Mvit)}, updated via {@link #update()}. */
+ public static final int INVERSE_TRANSPOSED_MODELVIEW = 1 << 2;
+ /** Bit value for {@link #getFrustum() frustum} and updated by {@link #getFrustum()}. */
+ public static final int FRUSTUM = 1 << 3;
+ /** Bit value for {@link #getPMvMat() pre-multiplied P * Mv}, updated by {@link #getPMvMat()}. */
+ public static final int PREMUL_PMV = 1 << 4;
+ /** Bit value for {@link #getPMviMat() pre-multiplied invert(P * Mv)}, updated by {@link #getPMviMat()}. */
+ public static final int PREMUL_PMVI = 1 << 5;
+ /** Manual bits not covered by {@link #update()} but {@link #getFrustum()}, {@link #FRUSTUM}, {@link #getPMvMat()}, {@link #PREMUL_PMV}, {@link #getPMviMat()}, {@link #PREMUL_PMVI}, etc. */
+ public static final int MANUAL_BITS = FRUSTUM | PREMUL_PMV | PREMUL_PMVI;
/**
* @param matrixModeName One of {@link GLMatrixFunc#GL_MODELVIEW GL_MODELVIEW}, {@link GLMatrixFunc#GL_PROJECTION GL_PROJECTION} or {@link GL#GL_TEXTURE GL_TEXTURE}
@@ -170,86 +193,147 @@ public final class PMVMatrix implements GLMatrixFunc {
}
/**
- * @param sb optional passed StringBuilder instance to be used
- * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
- * @param a 4x4 matrix in column major order (OpenGL)
- * @return matrix string representation
- */
- @SuppressWarnings("deprecation")
- public static StringBuilder matrixToString(final StringBuilder sb, final String f, final FloatBuffer a) {
- return FloatUtil.matrixToString(sb, null, f, a, 0, 4, 4, false);
- }
-
- /**
- * @param sb optional passed StringBuilder instance to be used
- * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
- * @param a 4x4 matrix in column major order (OpenGL)
- * @param b 4x4 matrix in column major order (OpenGL)
- * @return side by side representation
+ * Creates an instance of PMVMatrix.
+ * <p>
+ * This constructor only sets up an instance w/o additional {@link #INVERSE_MODELVIEW} or {@link #INVERSE_TRANSPOSED_MODELVIEW}.
+ * </p>
+ * <p>
+ * Implementation uses non-direct non-NIO Buffers with guaranteed backing array,
+ * which are synchronized to the actual Matrix4f instances.
+ * This allows faster access in Java computation.
+ * </p>
+ * @see #PMVMatrix(int)
*/
- @SuppressWarnings("deprecation")
- public static StringBuilder matrixToString(final StringBuilder sb, final String f, final FloatBuffer a, final FloatBuffer b) {
- return FloatUtil.matrixToString(sb, null, f, a, 0, b, 0, 4, 4, false);
+ public PMVMatrix() {
+ this(0);
}
/**
* Creates an instance of PMVMatrix.
* <p>
+ * Additional derived matrices can be requested via `derivedMatrices`, i.e.
+ * - {@link #INVERSE_MODELVIEW}
+ * - {@link #INVERSE_TRANSPOSED_MODELVIEW}
+ * </p>
+ * <p>
* Implementation uses non-direct non-NIO Buffers with guaranteed backing array,
- * which allows faster access in Java computation.
+ * which are synchronized to the actual Matrix4f instances.
+ * This allows faster access in Java computation.
* </p>
+ * @param derivedMatrices additional matrices can be requested by passing bits {@link #INVERSE_MODELVIEW} and {@link #INVERSE_TRANSPOSED_MODELVIEW}.
+ * @see #getReqBits()
+ * @see #isReqDirty()
+ * @see #getDirtyBits()
+ * @see #update()
*/
- public PMVMatrix() {
- // I Identity
- // T Texture
- // P Projection
- // Mv ModelView
- // Mvi Modelview-Inverse
- // Mvit Modelview-Inverse-Transpose
- matrixArray = new float[5*16];
-
- mP_offset = 0*16;
- mMv_offset = 1*16;
- mTex_offset = 4*16;
-
- matrixPMvMvit = Buffers.slice2Float(matrixArray, 0*16, 4*16); // P + Mv + Mvi + Mvit
- matrixPMvMvi = Buffers.slice2Float(matrixArray, 0*16, 3*16); // P + Mv + Mvi
- matrixPMv = Buffers.slice2Float(matrixArray, 0*16, 2*16); // P + Mv
- matrixP = Buffers.slice2Float(matrixArray, 0*16, 1*16); // P
- matrixMv = Buffers.slice2Float(matrixArray, 1*16, 1*16); // Mv
- matrixMvi = Buffers.slice2Float(matrixArray, 2*16, 1*16); // Mvi
- matrixMvit = Buffers.slice2Float(matrixArray, 3*16, 1*16); // Mvit
- matrixTex = Buffers.slice2Float(matrixArray, 4*16, 1*16); // T
-
- mat4Tmp1 = new float[16];
- mat4Tmp2 = new float[16];
- mat4Tmp3 = new float[16];
- matrixTxSx = new float[16];
- FloatUtil.makeIdentity(matrixTxSx);
-
- // Start w/ zero size to save memory
- matrixTStack = new FloatStack( 0, 2*16); // growSize: GL-min size (2)
- matrixPStack = new FloatStack( 0, 2*16); // growSize: GL-min size (2)
- matrixMvStack= new FloatStack( 0, 16*16); // growSize: half GL-min size (32)
-
- reset();
-
- frustum = null;
+ public PMVMatrix(final int derivedMatrices) {
+ // I Identity
+ // T Texture
+ // P Projection
+ // Mv ModelView
+ // Mvi Modelview-Inverse
+ // Mvit Modelview-Inverse-Transpose
+ {
+ int mask = 0;
+ if( 0 != ( derivedMatrices & ( INVERSE_MODELVIEW | INVERSE_TRANSPOSED_MODELVIEW ) ) ) {
+ mask |= INVERSE_MODELVIEW;
+ }
+ if( 0 != ( derivedMatrices & INVERSE_TRANSPOSED_MODELVIEW ) ) {
+ mask |= INVERSE_TRANSPOSED_MODELVIEW;
+ }
+ requestBits = mask;
+ }
+
+ // actual underlying Matrix4f count
+ int mcount = 3;
+
+ // actual underlying Matrix4f data
+ matP = new Matrix4f();
+ matMv = new Matrix4f();
+ matTex = new Matrix4f();
+
+ if( 0 != ( requestBits & INVERSE_MODELVIEW ) ) {
+ matMvi = new Matrix4f();
+ mMvi_offset = 2*16;
+ ++mcount;
+ } else {
+ matMvi = null;
+ mMvi_offset = -1;
+ }
+ if( 0 != ( requestBits & INVERSE_TRANSPOSED_MODELVIEW ) ) {
+ matMvit = new Matrix4f();
+ mMvit_offset = 3*16;
+ ++mcount;
+ } else {
+ matMvit = null;
+ mMvit_offset = -1;
+ }
+ mTex_offset = (mcount-1)*16; // last one
+
+ // float back buffer for GPU, Matrix4f -> matrixStore via SyncedBuffer
+ matrixStore = new float[mcount*16];
+
+ // FloatBuffer for single Matrix4f back-buffer
+ bufP = Buffers.slice2Float(matrixStore, mP_offset, 1*16); // P
+ syncP = new SyncBuffer0(matP, bufP); // mP_offset
+
+ bufMv = Buffers.slice2Float(matrixStore, mMv_offset, 1*16); // Mv
+ syncMv = new SyncBuffer1(matMv, bufMv, mMv_offset);
+
+ bufP_Mv = Buffers.slice2Float(matrixStore, mP_offset, 2*16); // P + Mv
+ syncP_Mv = new SyncBufferN(new Matrix4f[] { matP, matMv }, bufP_Mv, mP_offset);
+
+ bufTex = Buffers.slice2Float(matrixStore, mTex_offset, 1*16); // T
+ syncT = new SyncBuffer1(matTex, bufTex, mTex_offset);
+
+ if( null != matMvi ) {
+ bufMvi = Buffers.slice2Float(matrixStore, mMvi_offset, 1*16); // Mvi
+ bufP_Mv_Mvi = Buffers.slice2Float(matrixStore, mP_offset, 3*16); // P + Mv + Mvi
+ syncMvi = new SyncBuffer1U(matMvi, bufMvi, mMvi_offset);
+ syncP_Mv_Mvi = new SyncBufferNU(new Matrix4f[] { matP, matMv, matMvi }, bufP_Mv_Mvi, mP_offset);
+ } else {
+ bufMvi = null;
+ bufP_Mv_Mvi = null;
+ syncMvi = null;
+ syncP_Mv_Mvi = null;
+ }
+ if( null != matMvit ) {
+ bufMvit = Buffers.slice2Float(matrixStore, mMvit_offset, 1*16); // Mvit
+ bufP_Mv_Mvi_Mvit = Buffers.slice2Float(matrixStore, mP_offset, 4*16); // P + Mv + Mvi + Mvit
+ syncMvit = new SyncBuffer1U(matMvit, bufMvit, mMvit_offset);
+ syncP_Mv_Mvi_Mvit = new SyncBufferNU(new Matrix4f[] { matP, matMv, matMvi, matMvit }, bufP_Mv_Mvi_Mvit, mP_offset);
+ } else {
+ bufMvit = null;
+ bufP_Mv_Mvi_Mvit = null;
+ syncMvit = null;
+ syncP_Mv_Mvi_Mvit = null;
+ }
+
+ mat4Tmp1 = new Matrix4f();
+
+ mat4Tmp2 = null; // on demand
+ matPMv = null; // on demand
+ matPMvi = null; // on demand
+ matPMviOK = false;
+ frustum = null; // on demand
+
+ reset();
}
/**
* Issues {@link #glLoadIdentity()} on all matrices,
* i.e. {@link GLMatrixFunc#GL_MODELVIEW GL_MODELVIEW}, {@link GLMatrixFunc#GL_PROJECTION GL_PROJECTION} or {@link GL#GL_TEXTURE GL_TEXTURE}
* and resets all internal states.
+ *
+ * Leaves {@link GLMatrixFunc#GL_MODELVIEW GL_MODELVIEW} the active matrix mode.
*/
public final void reset() {
- FloatUtil.makeIdentity(matrixArray, mMv_offset);
- FloatUtil.makeIdentity(matrixArray, mP_offset);
- FloatUtil.makeIdentity(matrixArray, mTex_offset);
+ matP.loadIdentity();
+ matMv.loadIdentity();
+ matTex.loadIdentity();
modifiedBits = MODIFIED_ALL;
- dirtyBits = DIRTY_ALL;
- requestMask = 0;
+ dirtyBits = requestBits | MANUAL_BITS;
matrixMode = GL_MODELVIEW;
}
@@ -258,126 +342,189 @@ public final class PMVMatrix implements GLMatrixFunc {
return matrixMode;
}
+ //
+ // Temporary storage access for efficiency
+ //
+
+ /**
+ * Return the second temporary Matrix4f exposed to be reused for efficiency.
+ * <p>
+ * Temporary storage is only used by this class within single method calls,
+ * hence has no side-effects.
+ * </p>
+ */
+ private final Matrix4f getTmp2Mat() {
+ if( null == mat4Tmp2 ) {
+ mat4Tmp2 = new Matrix4f();
+ }
+ return mat4Tmp2;
+ }
+
+ //
+ // Regular Matrix4f access as well as their SyncedBuffer counterpart SyncedMatrix and SyncedMatrices
+ //
+
/**
* Returns the {@link GLMatrixFunc#GL_TEXTURE_MATRIX texture matrix} (T).
* <p>
* See <a href="#storageDetails"> matrix storage details</a>.
* </p>
*/
- public final FloatBuffer glGetTMatrixf() {
- return matrixTex;
+ public final Matrix4f getTMat() {
+ return matTex;
}
/**
- * Returns the {@link GLMatrixFunc#GL_PROJECTION_MATRIX projection matrix} (P).
+ * Returns the {@link SyncMatrix} of {@link GLMatrixFunc#GL_TEXTURE_MATRIX texture matrix} (T).
* <p>
* See <a href="#storageDetails"> matrix storage details</a>.
* </p>
*/
- public final FloatBuffer glGetPMatrixf() {
- return matrixP;
+ public final SyncMatrix4f getSyncTMat() {
+ return syncT;
}
/**
- * Returns the {@link GLMatrixFunc#GL_MODELVIEW_MATRIX modelview matrix} (Mv).
+ * Returns the {@link GLMatrixFunc#GL_PROJECTION_MATRIX projection matrix} (P).
* <p>
* See <a href="#storageDetails"> matrix storage details</a>.
* </p>
*/
- public final FloatBuffer glGetMvMatrixf() {
- return matrixMv;
+ public final Matrix4f getPMat() {
+ return matP;
}
/**
- * Returns the inverse {@link GLMatrixFunc#GL_MODELVIEW_MATRIX modelview matrix} (Mvi).
+ * Returns the {@link SyncMatrix} of {@link GLMatrixFunc#GL_PROJECTION_MATRIX projection matrix} (P).
* <p>
- * Method enables the Mvi matrix update, and performs it's update w/o clearing the modified bits.
+ * See <a href="#storageDetails"> matrix storage details</a>.
* </p>
+ */
+ public final SyncMatrix4f getSyncPMat() {
+ return syncP;
+ }
+
+ /**
+ * Returns the {@link GLMatrixFunc#GL_MODELVIEW_MATRIX modelview matrix} (Mv).
* <p>
- * See {@link #update()} and <a href="#storageDetails"> matrix storage details</a>.
+ * See <a href="#storageDetails"> matrix storage details</a>.
* </p>
- * @see #update()
- * @see #clearAllUpdateRequests()
*/
- public final FloatBuffer glGetMviMatrixf() {
- requestMask |= DIRTY_INVERSE_MODELVIEW ;
- updateImpl(false);
- return matrixMvi;
+ public final Matrix4f getMvMat() {
+ return matMv;
}
/**
- * Returns the inverse transposed {@link GLMatrixFunc#GL_MODELVIEW_MATRIX modelview matrix} (Mvit).
+ * Returns the {@link SyncMatrix} of {@link GLMatrixFunc#GL_MODELVIEW_MATRIX modelview matrix} (Mv).
* <p>
- * Method enables the Mvit matrix update, and performs it's update w/o clearing the modified bits.
+ * See <a href="#storageDetails"> matrix storage details</a>.
* </p>
+ */
+ public final SyncMatrix4f getSyncMvMat() {
+ return syncMv;
+ }
+
+ /**
+ * Returns {@link SyncMatrices4f} of 2 matrices within one FloatBuffer: {@link #getPMat() P} and {@link #getMvMat() Mv}.
* <p>
- * See {@link #update()} and <a href="#storageDetails"> matrix storage details</a>.
+ * See <a href="#storageDetails"> matrix storage details</a>.
* </p>
- * @see #update()
- * @see #clearAllUpdateRequests()
*/
- public final FloatBuffer glGetMvitMatrixf() {
- requestMask |= DIRTY_INVERSE_TRANSPOSED_MODELVIEW ;
- updateImpl(false);
- return matrixMvit;
+ public final SyncMatrices4f getSyncPMvMat() {
+ return syncP_Mv;
}
/**
- * Returns 2 matrices within one FloatBuffer: {@link #glGetPMatrixf() P} and {@link #glGetMvMatrixf() Mv}.
+ * Returns the inverse {@link GLMatrixFunc#GL_MODELVIEW_MATRIX modelview matrix} (Mvi) if requested.
* <p>
* See <a href="#storageDetails"> matrix storage details</a>.
* </p>
+ * @throws IllegalArgumentException if {@link #INVERSE_MODELVIEW} has not been requested in ctor {@link #PMVMatrix(int)}.
*/
- public final FloatBuffer glGetPMvMatrixf() {
- return matrixPMv;
+ public final Matrix4f getMviMat() {
+ if( 0 == ( INVERSE_MODELVIEW & requestBits ) ) {
+ throw new IllegalArgumentException("Not requested in ctor");
+ }
+ updateImpl(false);
+ return matMvi;
}
/**
- * Returns 3 matrices within one FloatBuffer: {@link #glGetPMatrixf() P}, {@link #glGetMvMatrixf() Mv} and {@link #glGetMviMatrixf() Mvi}.
+ * Returns the {@link SyncMatrix} of inverse {@link GLMatrixFunc#GL_MODELVIEW_MATRIX modelview matrix} (Mvi) if requested.
* <p>
- * Method enables the Mvi matrix update, and performs it's update w/o clearing the modified bits.
+ * See <a href="#storageDetails"> matrix storage details</a>.
* </p>
+ * @throws IllegalArgumentException if {@link #INVERSE_MODELVIEW} has not been requested in ctor {@link #PMVMatrix(int)}.
+ */
+ public final SyncMatrix4f getSyncMviMat() {
+ if( 0 == ( INVERSE_MODELVIEW & requestBits ) ) {
+ throw new IllegalArgumentException("Not requested in ctor");
+ }
+ return syncMvi;
+ }
+
+ /**
+ * Returns the inverse transposed {@link GLMatrixFunc#GL_MODELVIEW_MATRIX modelview matrix} (Mvit) if requested.
* <p>
- * See {@link #update()} and <a href="#storageDetails"> matrix storage details</a>.
+ * See <a href="#storageDetails"> matrix storage details</a>.
* </p>
- * @see #update()
- * @see #clearAllUpdateRequests()
+ * @throws IllegalArgumentException if {@link #INVERSE_TRANSPOSED_MODELVIEW} has not been requested in ctor {@link #PMVMatrix(int)}.
*/
- public final FloatBuffer glGetPMvMviMatrixf() {
- requestMask |= DIRTY_INVERSE_MODELVIEW ;
+ public final Matrix4f getMvitMat() {
+ if( 0 == ( INVERSE_TRANSPOSED_MODELVIEW & requestBits ) ) {
+ throw new IllegalArgumentException("Not requested in ctor");
+ }
updateImpl(false);
- return matrixPMvMvi;
+ return matMvit;
}
/**
- * Returns 4 matrices within one FloatBuffer: {@link #glGetPMatrixf() P}, {@link #glGetMvMatrixf() Mv}, {@link #glGetMviMatrixf() Mvi} and {@link #glGetMvitMatrixf() Mvit}.
+ * Returns the {@link SyncMatrix} of inverse transposed {@link GLMatrixFunc#GL_MODELVIEW_MATRIX modelview matrix} (Mvit) if requested.
* <p>
- * Method enables the Mvi and Mvit matrix update, and performs it's update w/o clearing the modified bits.
+ * See <a href="#storageDetails"> matrix storage details</a>.
* </p>
+ * @throws IllegalArgumentException if {@link #INVERSE_TRANSPOSED_MODELVIEW} has not been requested in ctor {@link #PMVMatrix(int)}.
+ */
+ public final SyncMatrix4f getSyncMvitMat() {
+ if( 0 == ( INVERSE_TRANSPOSED_MODELVIEW & requestBits ) ) {
+ throw new IllegalArgumentException("Not requested in ctor");
+ }
+ return syncMvit;
+ }
+
+ /**
+ * Returns {@link SyncMatrices4f} of 3 matrices within one FloatBuffer: {@link #getPMat() P}, {@link #getMvMat() Mv} and {@link #getMviMat() Mvi} if requested.
* <p>
- * See {@link #update()} and <a href="#storageDetails"> matrix storage details</a>.
+ * See <a href="#storageDetails"> matrix storage details</a>.
* </p>
- * @see #update()
- * @see #clearAllUpdateRequests()
+ * @throws IllegalArgumentException if {@link #INVERSE_MODELVIEW} has not been requested in ctor {@link #PMVMatrix(int)}.
*/
- public final FloatBuffer glGetPMvMvitMatrixf() {
- requestMask |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW ;
- updateImpl(false);
- return matrixPMvMvit;
+ public final SyncMatrices4f getSyncPMvMviMat() {
+ if( 0 == ( INVERSE_MODELVIEW & requestBits ) ) {
+ throw new IllegalArgumentException("Not requested in ctor");
+ }
+ return syncP_Mv_Mvi;
}
- /** Returns the frustum, derived from projection * modelview */
- public final Frustum glGetFrustum() {
- requestMask |= DIRTY_FRUSTUM;
- updateImpl(false);
- return frustum;
+ /**
+ * Returns {@link SyncMatrices4f} of 4 matrices within one FloatBuffer: {@link #getPMat() P}, {@link #getMvMat() Mv}, {@link #getMviMat() Mvi} and {@link #getMvitMat() Mvit} if requested.
+ * <p>
+ * See <a href="#storageDetails"> matrix storage details</a>.
+ * </p>
+ * @throws IllegalArgumentException if {@link #INVERSE_TRANSPOSED_MODELVIEW} has not been requested in ctor {@link #PMVMatrix(int)}.
+ */
+ public final SyncMatrices4f getSyncPMvMviMvitMat() {
+ if( 0 == ( INVERSE_TRANSPOSED_MODELVIEW & requestBits ) ) {
+ throw new IllegalArgumentException("Not requested in ctor");
+ }
+ return syncP_Mv_Mvi_Mvit;
}
- /*
+ /**
* @return the matrix of the current matrix-mode
*/
- public final FloatBuffer glGetMatrixf() {
- return glGetMatrixf(matrixMode);
+ public final Matrix4f getCurrentMat() {
+ return getMat(matrixMode);
}
/**
@@ -387,49 +534,182 @@ public final class PMVMatrix implements GLMatrixFunc {
* {@link GLMatrixFunc#GL_MODELVIEW GL_MODELVIEW}, {@link GLMatrixFunc#GL_PROJECTION GL_PROJECTION} or {@link GL#GL_TEXTURE GL_TEXTURE}
* @return the named matrix, not a copy!
*/
- public final FloatBuffer glGetMatrixf(final int matrixName) {
+ public final Matrix4f getMat(final int matrixName) {
switch(matrixName) {
case GL_MODELVIEW_MATRIX:
case GL_MODELVIEW:
- return matrixMv;
+ return matMv;
case GL_PROJECTION_MATRIX:
case GL_PROJECTION:
- return matrixP;
+ return matP;
case GL_TEXTURE_MATRIX:
case GL.GL_TEXTURE:
- return matrixTex;
+ return matTex;
default:
throw new GLException("unsupported matrixName: "+matrixName);
}
}
+ //
+ // Basic Matrix4f, Vec3f and Vec4f operations similar to GLMatrixFunc
+ //
/**
- * Multiplies the {@link #glGetPMatrixf() P} and {@link #glGetMvMatrixf() Mv} matrix, i.e.
+ * Multiplies the {@link #getPMat() P} and {@link #getMvMat() Mv} matrix, i.e.
* <pre>
- * mat4PMv = P x Mv
+ * result = P x Mv
* </pre>
- * @param mat4PMv 4x4 matrix storage for result
- * @param mat4PMv_offset
- * @return given matrix for chaining
+ * @param result 4x4 matrix storage for result
+ * @return given result matrix for chaining
*/
- public final float[] multPMvMatrixf(final float[/*16*/] mat4PMv, final int mat4PMv_offset) {
- FloatUtil.multMatrix(matrixArray, mP_offset, matrixArray, mMv_offset, mat4PMv, mat4PMv_offset);
- return mat4PMv;
+ public final Matrix4f mulPMvMat(final Matrix4f result) {
+ return result.mul(matP, matMv);
}
/**
- * Multiplies the {@link #glGetMvMatrixf() Mv} and {@link #glGetPMatrixf() P} matrix, i.e.
+ * Multiplies the {@link #getMvMat() Mv} and {@link #getPMat() P} matrix, i.e.
* <pre>
- * mat4MvP = Mv x P
+ * result = Mv x P
* </pre>
- * @param mat4MvP 4x4 matrix storage for result
- * @param mat4MvP_offset
- * @return given matrix for chaining
+ * @param result 4x4 matrix storage for result
+ * @return given result matrix for chaining
+ */
+ public final Matrix4f mulMvPMat(final Matrix4f result) {
+ return result.mul(matMv, matP);
+ }
+
+ /**
+ * v_out = Mv * v_in
+ * @param v_in input vector, can be v_out for in-place transformation
+ * @param v_out output vector
+ * @returns v_out for chaining
+ */
+ public final Vec4f mulMvMatVec4f(final Vec4f v_in, final Vec4f v_out) {
+ return matMv.mulVec4f(v_in, v_out);
+ }
+
+ /**
+ * v_inout = Mv * v_inout
+ * @param v_inout input and output vector, i.e. in-place transformation
+ * @returns v_inout for chaining
+ */
+ public final Vec4f mulMvMatVec4f(final Vec4f v_inout) {
+ return matMv.mulVec4f(v_inout);
+ }
+
+ /**
+ * v_out = Mv * v_in
+ *
+ * Affine 3f-vector transformation by 4x4 matrix, see {@link Matrix4f#mulVec3f(Vec3f, Vec3f)}.
+ *
+ * @param v_in input vector, can be v_out for in-place transformation
+ * @param v_out output vector
+ * @returns v_out for chaining
+ */
+ public final Vec3f mulMvMatVec3f(final Vec3f v_in, final Vec3f v_out) {
+ return matMv.mulVec3f(v_in, v_out);
+ }
+
+ /**
+ * v_inout = Mv * v_inout
+ *
+ * Affine 3f-vector transformation by 4x4 matrix, see {@link Matrix4f#mulVec3f(Vec3f, Vec3f)}.
+ *
+ * @param v_inout input and output vector, i.e. in-place transformation
+ * @returns v_inout for chaining
+ */
+ public final Vec3f mulMvMatVec3f(final Vec3f v_inout) {
+ return matMv.mulVec3f(v_inout);
+ }
+
+ /**
+ * v_out = P * v_in
+ * @param v_in input vector, can be v_out for in-place transformation
+ * @param v_out output vector
+ * @return given result vector for chaining
+ * @returns v_out for chaining
+ */
+ public final Vec4f mulPMatVec4f(final Vec4f v_in, final Vec4f v_out) {
+ return matP.mulVec4f(v_in, v_out);
+ }
+
+ /**
+ * v_inout = P * v_inout
+ * @param v_inout input and output vector, i.e. in-place transformation
+ * @return given result vector for chaining
+ * @returns v_inout for chaining
+ */
+ public final Vec4f mulPMatVec4f(final Vec4f v_inout) {
+ return matP.mulVec4f(v_inout);
+ }
+
+ /**
+ * v_out = P * v_in
+ *
+ * Affine 3f-vector transformation by 4x4 matrix, see {@link Matrix4f#mulVec3f(Vec3f, Vec3f)}.
+ *
+ * @param v_in float[3] input vector, can be v_out for in-place transformation
+ * @param v_out float[3] output vector
+ * @returns v_out for chaining
+ */
+ public final Vec3f mulPMatVec3f(final Vec3f v_in, final Vec3f v_out) {
+ return matP.mulVec3f(v_in, v_out);
+ }
+
+ /**
+ * v_inout = P * v_inout
+ *
+ * Affine 3f-vector transformation by 4x4 matrix, see {@link Matrix4f#mulVec3f(Vec3f, Vec3f)}.
+ *
+ * @param v_inout input and output vector, i.e. in-place transformation
+ * @returns v_inout for chaining
+ */
+ public final Vec3f mulPMatVec3f(final Vec3f v_inout) {
+ return matP.mulVec3f(v_inout);
+ }
+
+ /**
+ * v_out = P * Mv * v_in
+ * @param v_in float[4] input vector, can be v_out for in-place transformation
+ * @param v_out float[4] output vector
+ * @returns v_out for chaining
+ */
+ public final Vec4f mulPMvMatVec4f(final Vec4f v_in, final Vec4f v_out) {
+ return matP.mulVec4f( matMv.mulVec4f( v_in, v_out ) );
+ }
+
+ /**
+ * v_inout = P * Mv * v_inout
+ * @param v_inout input and output vector, i.e. in-place transformation
+ * @returns v_inout for chaining
+ */
+ public final Vec4f mulPMvMatVec4f(final Vec4f v_inout) {
+ return matP.mulVec4f( matMv.mulVec4f( v_inout ) );
+ }
+
+ /**
+ * v_out = P * Mv * v_in
+ *
+ * Affine 3f-vector transformation by 4x4 matrix, see {@link Matrix4f#mulVec3f(Vec3f, Vec3f)}.
+ *
+ * @param v_in float[3] input vector, can be v_out for in-place transformation
+ * @param v_out float[3] output vector
+ * @returns v_out for chaining
+ */
+ public final Vec3f mulPMvMatVec3f(final Vec3f v_in, final Vec3f v_out) {
+ return matP.mulVec3f( matMv.mulVec3f( v_in, v_out ) );
+ }
+
+ /**
+ * v_inout = P * Mv * v_inout
+ *
+ * Affine 3f-vector transformation by 4x4 matrix, see {@link Matrix4f#mulVec3f(Vec3f, Vec3f)}.
+ *
+ * @param v_inout float[3] input and output vector, i.e. in-place transformation
+ * @returns v_inout for chaining
*/
- public final float[] multMvPMatrixf(final float[/*16*/] mat4MvP, final int mat4MvP_offset) {
- FloatUtil.multMatrix(matrixArray, mMv_offset, matrixArray, mP_offset, mat4MvP, mat4MvP_offset);
- return mat4MvP;
+ public final Vec3f mulPMvMatVec3f(final Vec3f v_inout) {
+ return matP.mulVec3f( matMv.mulVec3f( v_inout ) );
}
//
@@ -455,9 +735,7 @@ public final class PMVMatrix implements GLMatrixFunc {
if(matrixGetName==GL_MATRIX_MODE) {
params.put(matrixMode);
} else {
- final FloatBuffer matrix = glGetMatrixf(matrixGetName);
- params.put(matrix); // matrix -> params
- matrix.reset();
+ getMat(matrixGetName).get(params); // matrix -> params
}
params.position(pos);
}
@@ -467,9 +745,7 @@ public final class PMVMatrix implements GLMatrixFunc {
if(matrixGetName==GL_MATRIX_MODE) {
params[params_offset]=matrixMode;
} else {
- final FloatBuffer matrix = glGetMatrixf(matrixGetName);
- matrix.get(params, params_offset, 16); // matrix -> params
- matrix.reset();
+ getMat(matrixGetName).get(params, params_offset); // matrix -> params
}
}
@@ -496,18 +772,15 @@ public final class PMVMatrix implements GLMatrixFunc {
@Override
public final void glLoadMatrixf(final float[] values, final int offset) {
if(matrixMode==GL_MODELVIEW) {
- matrixMv.put(values, offset, 16);
- matrixMv.reset();
- dirtyBits |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM ;
+ matMv.load(values, offset);
+ dirtyBits |= requestBits | MANUAL_BITS ;
modifiedBits |= MODIFIED_MODELVIEW;
} else if(matrixMode==GL_PROJECTION) {
- matrixP.put(values, offset, 16);
- matrixP.reset();
- dirtyBits |= DIRTY_FRUSTUM ;
+ matP.load(values, offset);
+ dirtyBits |= MANUAL_BITS ;
modifiedBits |= MODIFIED_PROJECTION;
} else if(matrixMode==GL.GL_TEXTURE) {
- matrixTex.put(values, offset, 16);
- matrixTex.reset();
+ matTex.load(values, offset);
modifiedBits |= MODIFIED_TEXTURE;
}
}
@@ -516,148 +789,234 @@ public final class PMVMatrix implements GLMatrixFunc {
public final void glLoadMatrixf(final java.nio.FloatBuffer m) {
final int spos = m.position();
if(matrixMode==GL_MODELVIEW) {
- matrixMv.put(m);
- matrixMv.reset();
- dirtyBits |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM ;
+ matMv.load(m);
+ dirtyBits |= requestBits | MANUAL_BITS ;
modifiedBits |= MODIFIED_MODELVIEW;
} else if(matrixMode==GL_PROJECTION) {
- matrixP.put(m);
- matrixP.reset();
- dirtyBits |= DIRTY_FRUSTUM ;
+ matP.load(m);
+ dirtyBits |= MANUAL_BITS ;
modifiedBits |= MODIFIED_PROJECTION;
} else if(matrixMode==GL.GL_TEXTURE) {
- matrixTex.put(m);
- matrixTex.reset();
+ matTex.load(m);
modifiedBits |= MODIFIED_TEXTURE;
}
m.position(spos);
}
/**
- * Load the current matrix with the values of the given {@link Quaternion}'s rotation {@link Quaternion#toMatrix(float[], int) matrix representation}.
+ * Load the current matrix with the values of the given {@link Matrix4f}.
+ * <p>
+ * Extension to {@link GLMatrixFunc}.
+ * </p>
+ */
+ public final void glLoadMatrixf(final Matrix4f m) {
+ if(matrixMode==GL_MODELVIEW) {
+ matMv.load(m);
+ dirtyBits |= requestBits | MANUAL_BITS ;
+ modifiedBits |= MODIFIED_MODELVIEW;
+ } else if(matrixMode==GL_PROJECTION) {
+ matP.load(m);
+ dirtyBits |= MANUAL_BITS ;
+ modifiedBits |= MODIFIED_PROJECTION;
+ } else if(matrixMode==GL.GL_TEXTURE) {
+ matTex.load(m);
+ modifiedBits |= MODIFIED_TEXTURE;
+ }
+ }
+
+ /**
+ * Load the current matrix with the values of the given {@link Quaternion}'s rotation {@link Matrix4f#setToRotation(Quaternion) matrix representation}.
+ * <p>
+ * Extension to {@link GLMatrixFunc}.
+ * </p>
*/
public final void glLoadMatrix(final Quaternion quat) {
if(matrixMode==GL_MODELVIEW) {
- quat.toMatrix(matrixArray, mMv_offset);
- matrixMv.reset();
- dirtyBits |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM ;
+ matMv.setToRotation(quat);
+ dirtyBits |= requestBits | MANUAL_BITS ;
modifiedBits |= MODIFIED_MODELVIEW;
} else if(matrixMode==GL_PROJECTION) {
- quat.toMatrix(matrixArray, mP_offset);
- matrixP.reset();
- dirtyBits |= DIRTY_FRUSTUM ;
+ matP.setToRotation(quat);
+ dirtyBits |= MANUAL_BITS ;
modifiedBits |= MODIFIED_PROJECTION;
} else if(matrixMode==GL.GL_TEXTURE) {
- quat.toMatrix(matrixArray, mTex_offset);
- matrixTex.reset();
+ matTex.setToRotation(quat);
modifiedBits |= MODIFIED_TEXTURE;
}
}
@Override
public final void glPopMatrix() {
- final FloatStack stack;
if(matrixMode==GL_MODELVIEW) {
- stack = matrixMvStack;
+ matMv.pop();
+ dirtyBits |= requestBits | MANUAL_BITS ;
+ modifiedBits |= MODIFIED_MODELVIEW;
} else if(matrixMode==GL_PROJECTION) {
- stack = matrixPStack;
+ matP.pop();
+ dirtyBits |= MANUAL_BITS ;
+ modifiedBits |= MODIFIED_PROJECTION;
} else if(matrixMode==GL.GL_TEXTURE) {
- stack = matrixTStack;
- } else {
- throw new InternalError("XXX: mode "+matrixMode);
+ matTex.pop();
+ modifiedBits |= MODIFIED_TEXTURE;
}
- stack.position(stack.position() - 16);
- glLoadMatrixf(stack.buffer(), stack.position());
}
@Override
public final void glPushMatrix() {
if(matrixMode==GL_MODELVIEW) {
- matrixMvStack.putOnTop(matrixMv, 16);
- matrixMv.reset();
+ matMv.push();
} else if(matrixMode==GL_PROJECTION) {
- matrixPStack.putOnTop(matrixP, 16);
- matrixP.reset();
+ matP.push();
} else if(matrixMode==GL.GL_TEXTURE) {
- matrixTStack.putOnTop(matrixTex, 16);
- matrixTex.reset();
+ matTex.push();
}
}
@Override
public final void glLoadIdentity() {
if(matrixMode==GL_MODELVIEW) {
- FloatUtil.makeIdentity(matrixArray, mMv_offset);
- dirtyBits |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM ;
+ matMv.loadIdentity();
+ dirtyBits |= requestBits | MANUAL_BITS ;
modifiedBits |= MODIFIED_MODELVIEW;
} else if(matrixMode==GL_PROJECTION) {
- FloatUtil.makeIdentity(matrixArray, mP_offset);
- dirtyBits |= DIRTY_FRUSTUM ;
+ matP.loadIdentity();
+ dirtyBits |= MANUAL_BITS ;
modifiedBits |= MODIFIED_PROJECTION;
} else if(matrixMode==GL.GL_TEXTURE) {
- FloatUtil.makeIdentity(matrixArray, mTex_offset);
+ matTex.loadIdentity();
modifiedBits |= MODIFIED_TEXTURE;
}
}
- @SuppressWarnings("deprecation")
@Override
public final void glMultMatrixf(final FloatBuffer m) {
+ final int spos = m.position();
if(matrixMode==GL_MODELVIEW) {
- FloatUtil.multMatrix(matrixMv, m);
- dirtyBits |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM ;
+ matMv.mul( mat4Tmp1.load( m ) );
+ dirtyBits |= requestBits | MANUAL_BITS ;
modifiedBits |= MODIFIED_MODELVIEW;
} else if(matrixMode==GL_PROJECTION) {
- FloatUtil.multMatrix(matrixP, m);
- dirtyBits |= DIRTY_FRUSTUM ;
+ matP.mul( mat4Tmp1.load( m ) );
+ dirtyBits |= MANUAL_BITS ;
modifiedBits |= MODIFIED_PROJECTION;
} else if(matrixMode==GL.GL_TEXTURE) {
- FloatUtil.multMatrix(matrixTex, m);
+ matTex.mul( mat4Tmp1.load( m ) );
modifiedBits |= MODIFIED_TEXTURE;
}
+ m.position(spos);
}
@Override
public final void glMultMatrixf(final float[] m, final int m_offset) {
if(matrixMode==GL_MODELVIEW) {
- FloatUtil.multMatrix(matrixArray, mMv_offset, m, m_offset);
- dirtyBits |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM ;
+ matMv.mul( mat4Tmp1.load( m, m_offset ) );
+ dirtyBits |= requestBits | MANUAL_BITS ;
+ modifiedBits |= MODIFIED_MODELVIEW;
+ } else if(matrixMode==GL_PROJECTION) {
+ matP.mul( mat4Tmp1.load( m, m_offset ) );
+ dirtyBits |= MANUAL_BITS ;
+ modifiedBits |= MODIFIED_PROJECTION;
+ } else if(matrixMode==GL.GL_TEXTURE) {
+ matTex.mul( mat4Tmp1.load( m, m_offset ) );
+ modifiedBits |= MODIFIED_TEXTURE;
+ }
+ }
+
+ /**
+ * Multiply the current matrix: [c] = [c] x [m]
+ * <p>
+ * Extension to {@link GLMatrixFunc}.
+ * </p>
+ * @param m the right hand Matrix4f
+ * @return this instance of chaining
+ */
+ public final PMVMatrix glMultMatrixf(final Matrix4f m) {
+ if(matrixMode==GL_MODELVIEW) {
+ matMv.mul( m );
+ dirtyBits |= requestBits | MANUAL_BITS ;
modifiedBits |= MODIFIED_MODELVIEW;
} else if(matrixMode==GL_PROJECTION) {
- FloatUtil.multMatrix(matrixArray, mP_offset, m, m_offset);
- dirtyBits |= DIRTY_FRUSTUM ;
+ matP.mul( m );
+ dirtyBits |= MANUAL_BITS ;
modifiedBits |= MODIFIED_PROJECTION;
} else if(matrixMode==GL.GL_TEXTURE) {
- FloatUtil.multMatrix(matrixArray, mTex_offset, m, m_offset);
+ matTex.mul( m );
modifiedBits |= MODIFIED_TEXTURE;
}
+ return this;
}
@Override
public final void glTranslatef(final float x, final float y, final float z) {
- glMultMatrixf(FloatUtil.makeTranslation(matrixTxSx, false, x, y, z), 0);
+ glMultMatrixf( mat4Tmp1.setToTranslation(x, y, z) );
+ }
+
+ /**
+ * Translate the current matrix.
+ * <p>
+ * Extension to {@link GLMatrixFunc}.
+ * </p>
+ * @param t translation vec3
+ * @return this instance of chaining
+ */
+ public final PMVMatrix glTranslatef(final Vec3f t) {
+ return glMultMatrixf( mat4Tmp1.setToTranslation(t) );
}
@Override
public final void glScalef(final float x, final float y, final float z) {
- glMultMatrixf(FloatUtil.makeScale(matrixTxSx, false, x, y, z), 0);
+ glMultMatrixf( mat4Tmp1.setToScale(x, y, z) );
+ }
+
+ /**
+ * Scale the current matrix.
+ * <p>
+ * Extension to {@link GLMatrixFunc}.
+ * </p>
+ * @param s scale vec4f
+ * @return this instance of chaining
+ */
+ public final PMVMatrix glScalef(final Vec3f s) {
+ return glMultMatrixf( mat4Tmp1.setToScale(s) );
}
@Override
public final void glRotatef(final float ang_deg, final float x, final float y, final float z) {
- glMultMatrixf(FloatUtil.makeRotationAxis(mat4Tmp1, 0, ang_deg * FloatUtil.PI / 180.0f, x, y, z, mat4Tmp2), 0);
+ glMultMatrixf( mat4Tmp1.setToRotationAxis(FloatUtil.adegToRad(ang_deg), x, y, z) );
+ }
+
+ /**
+ * Rotate the current matrix by the given axis and angle in radians.
+ * <p>
+ * Consider using {@link #glRotate(Quaternion)}
+ * </p>
+ * <p>
+ * Extension to {@link GLMatrixFunc}.
+ * </p>
+ * @param ang_rad angle in radians
+ * @param axis rotation axis
+ * @return this instance of chaining
+ * @see #glRotate(Quaternion)
+ */
+ public final PMVMatrix glRotatef(final float ang_rad, final Vec3f axis) {
+ return glMultMatrixf( mat4Tmp1.setToRotationAxis(ang_rad, axis) );
}
/**
- * Rotate the current matrix with the given {@link Quaternion}'s rotation {@link Quaternion#toMatrix(float[], int) matrix representation}.
+ * Rotate the current matrix with the given {@link Quaternion}'s rotation {@link Matrix4f#setToRotation(Quaternion) matrix representation}.
+ * <p>
+ * Extension to {@link GLMatrixFunc}.
+ * </p>
+ * @param quat the {@link Quaternion}
+ * @return this instance of chaining
*/
- public final void glRotate(final Quaternion quat) {
- glMultMatrixf(quat.toMatrix(mat4Tmp1, 0), 0);
+ public final PMVMatrix glRotate(final Quaternion quat) {
+ return glMultMatrixf( mat4Tmp1.setToRotation(quat) );
}
@Override
public final void glOrthof(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) {
- glMultMatrixf( FloatUtil.makeOrtho(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar), 0 );
+ glMultMatrixf( mat4Tmp1.setToOrtho(left, right, bottom, top, zNear, zFar) );
}
/**
@@ -665,11 +1024,11 @@ public final class PMVMatrix implements GLMatrixFunc {
*
* @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear}
* or {@code left == right}, or {@code bottom == top}.
- * @see FloatUtil#makeFrustum(float[], int, boolean, float, float, float, float, float, float)
+ * @see Matrix4f#setToFrustum(float, float, float, float, float, float)
*/
@Override
public final void glFrustumf(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) throws GLException {
- glMultMatrixf( FloatUtil.makeFrustum(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar), 0 );
+ glMultMatrixf( mat4Tmp1.setToFrustum(left, right, bottom, top, zNear, zFar) );
}
//
@@ -684,30 +1043,18 @@ public final class PMVMatrix implements GLMatrixFunc {
* @param zNear
* @param zFar
* @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear}
- * @see FloatUtil#makePerspective(float[], int, boolean, float, float, float, float)
+ * @see Matrix4f#setToPerspective(float, float, float, float)
*/
public final void gluPerspective(final float fovy_deg, final float aspect, final float zNear, final float zFar) throws GLException {
- glMultMatrixf( FloatUtil.makePerspective(mat4Tmp1, 0, true, fovy_deg * FloatUtil.PI / 180.0f, aspect, zNear, zFar), 0 );
+ glMultMatrixf( mat4Tmp1.setToPerspective(FloatUtil.adegToRad(fovy_deg), aspect, zNear, zFar) );
}
/**
* {@link #glMultMatrixf(FloatBuffer) Multiply} and {@link #glTranslatef(float, float, float) translate} the {@link #glGetMatrixMode() current matrix}
* with the eye, object and orientation.
*/
- public final void gluLookAt(final float eyex, final float eyey, final float eyez,
- final float centerx, final float centery, final float centerz,
- final float upx, final float upy, final float upz) {
- mat4Tmp2[0+0] = eyex;
- mat4Tmp2[1+0] = eyey;
- mat4Tmp2[2+0] = eyez;
- mat4Tmp2[0+4] = centerx;
- mat4Tmp2[1+4] = centery;
- mat4Tmp2[2+4] = centerz;
- mat4Tmp2[0+8] = upx;
- mat4Tmp2[1+8] = upy;
- mat4Tmp2[2+8] = upz;
- glMultMatrixf(
- FloatUtil.makeLookAt(mat4Tmp1, 0, mat4Tmp2 /* eye */, 0, mat4Tmp2 /* center */, 4, mat4Tmp2 /* up */, 8, mat4Tmp3), 0);
+ public final void gluLookAt(final Vec3f eye, final Vec3f center, final Vec3f up) {
+ glMultMatrixf( mat4Tmp1.setToLookAt(eye, center, up, getTmp2Mat()) );
}
/**
@@ -716,24 +1063,13 @@ public final class PMVMatrix implements GLMatrixFunc {
* Traditional <code>gluProject</code> implementation.
* </p>
*
- * @param objx
- * @param objy
- * @param objz
- * @param viewport 4 component viewport vector
- * @param viewport_offset
- * @param win_pos 3 component window coordinate, the result
- * @param win_pos_offset
+ * @param objPos 3 component object coordinate
+ * @param viewport Rect4i viewport
+ * @param winPos 3 component window coordinate, the result
* @return true if successful, otherwise false (z is 1)
*/
- public final boolean gluProject(final float objx, final float objy, final float objz,
- final int[] viewport, final int viewport_offset,
- final float[] win_pos, final int win_pos_offset ) {
- return FloatUtil.mapObjToWinCoords(objx, objy, objz,
- matrixArray, mMv_offset,
- matrixArray, mP_offset,
- viewport, viewport_offset,
- win_pos, win_pos_offset,
- mat4Tmp1, mat4Tmp2);
+ public final boolean gluProject(final Vec3f objPos, final Recti viewport, final Vec3f winPos ) {
+ return Matrix4f.mapObjToWin(objPos, matMv, matP, viewport, winPos);
}
/**
@@ -745,21 +1081,17 @@ public final class PMVMatrix implements GLMatrixFunc {
* @param winx
* @param winy
* @param winz
- * @param viewport 4 component viewport vector
- * @param viewport_offset
- * @param obj_pos 3 component object coordinate, the result
- * @param obj_pos_offset
+ * @param viewport Rect4i viewport
+ * @param objPos 3 component object coordinate, the result
* @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
*/
public final boolean gluUnProject(final float winx, final float winy, final float winz,
- final int[] viewport, final int viewport_offset,
- final float[] obj_pos, final int obj_pos_offset) {
- return FloatUtil.mapWinToObjCoords(winx, winy, winz,
- matrixArray, mMv_offset,
- matrixArray, mP_offset,
- viewport, viewport_offset,
- obj_pos, obj_pos_offset,
- mat4Tmp1, mat4Tmp2);
+ final Recti viewport, final Vec3f objPos) {
+ if( Matrix4f.mapWinToObj(winx, winy, winz, getPMviMat(), viewport, objPos) ) {
+ return true;
+ } else {
+ return false;
+ }
}
/**
@@ -772,58 +1104,27 @@ public final class PMVMatrix implements GLMatrixFunc {
* @param winy
* @param winz
* @param clipw
- * @param modelMatrix 4x4 modelview matrix
- * @param modelMatrix_offset
- * @param projMatrix 4x4 projection matrix
- * @param projMatrix_offset
- * @param viewport 4 component viewport vector
- * @param viewport_offset
+ * @param viewport Rect4i viewport
* @param near
* @param far
- * @param obj_pos 4 component object coordinate, the result
- * @param obj_pos_offset
+ * @param objPos 4 component object coordinate, the result
* @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
*/
public boolean gluUnProject4(final float winx, final float winy, final float winz, final float clipw,
- final int[] viewport, final int viewport_offset,
+ final Recti viewport,
final float near, final float far,
- final float[] obj_pos, final int obj_pos_offset ) {
- return FloatUtil.mapWinToObjCoords(winx, winy, winz, clipw,
- matrixArray, mMv_offset,
- matrixArray, mP_offset,
- viewport, viewport_offset,
- near, far,
- obj_pos, obj_pos_offset,
- mat4Tmp1, mat4Tmp2);
- }
-
- /**
- * Make given matrix the <i>pick</i> matrix based on given parameters.
- * <p>
- * Traditional <code>gluPickMatrix</code> implementation.
- * </p>
- * <p>
- * See {@link FloatUtil#makePick(float[], int, float, float, float, float, int[], int, float[]) FloatUtil.makePick(..)} for details.
- * </p>
- * @param x the center x-component of a picking region in window coordinates
- * @param y the center y-component of a picking region in window coordinates
- * @param deltaX the width of the picking region in window coordinates.
- * @param deltaY the height of the picking region in window coordinates.
- * @param viewport 4 component viewport vector
- * @param viewport_offset
- */
- public final void gluPickMatrix(final float x, final float y,
- final float deltaX, final float deltaY,
- final int[] viewport, final int viewport_offset) {
- if( null != FloatUtil.makePick(mat4Tmp1, 0, x, y, deltaX, deltaY, viewport, viewport_offset, mat4Tmp2) ) {
- glMultMatrixf(mat4Tmp1, 0);
+ final Vec4f objPos) {
+ if( Matrix4f.mapWinToObj4(winx, winy, winz, clipw, getPMviMat(), viewport, near, far, objPos) ) {
+ return true;
+ } else {
+ return false;
}
}
/**
* Map two window coordinates w/ shared X/Y and distinctive Z
* to a {@link Ray}. The resulting {@link Ray} maybe used for <i>picking</i>
- * using a {@link AABBox#getRayIntersection(Ray, float[]) bounding box}.
+ * using a {@link AABBox#getRayIntersection(Vec3f, Ray, float, boolean) bounding box}.
* <p>
* Notes for picking <i>winz0</i> and <i>winz1</i>:
* <ul>
@@ -837,52 +1138,93 @@ public final class PMVMatrix implements GLMatrixFunc {
* @param winz0
* @param winz1
* @param viewport
- * @param viewport_offset
* @param ray storage for the resulting {@link Ray}
* @return true if successful, otherwise false (failed to invert matrix, or becomes z is infinity)
*/
public final boolean gluUnProjectRay(final float winx, final float winy, final float winz0, final float winz1,
- final int[] viewport, final int viewport_offset,
- final Ray ray) {
- return FloatUtil.mapWinToRay(winx, winy, winz0, winz1,
- matrixArray, mMv_offset,
- matrixArray, mP_offset,
- viewport, viewport_offset,
- ray,
- mat4Tmp1, mat4Tmp2, mat4Tmp3);
+ final Recti viewport, final Ray ray) {
+ return Matrix4f.mapWinToRay(winx, winy, winz0, winz1, getPMviMat(), viewport, ray);
+ }
+
+ /**
+ * Make given matrix the <i>pick</i> matrix based on given parameters.
+ * <p>
+ * Traditional <code>gluPickMatrix</code> implementation.
+ * </p>
+ * <p>
+ * See {@link Matrix4f#setToPick(float, float, float, float, Recti, int, Matrix4f) for details.
+ * </p>
+ * @param x the center x-component of a picking region in window coordinates
+ * @param y the center y-component of a picking region in window coordinates
+ * @param deltaX the width of the picking region in window coordinates.
+ * @param deltaY the height of the picking region in window coordinates.
+ * @param viewport Rect4i viewport vector
+ */
+ public final void gluPickMatrix(final float x, final float y,
+ final float deltaX, final float deltaY, final Recti viewport) {
+ if( null != mat4Tmp1.setToPick(x, y, deltaX, deltaY, viewport, getTmp2Mat()) ) {
+ glMultMatrixf( mat4Tmp1 );
+ }
}
public StringBuilder toString(StringBuilder sb, final String f) {
if(null == sb) {
sb = new StringBuilder();
}
- final boolean mviDirty = 0 != (DIRTY_INVERSE_MODELVIEW & dirtyBits);
- final boolean mvitDirty = 0 != (DIRTY_INVERSE_TRANSPOSED_MODELVIEW & dirtyBits);
- final boolean frustumDirty = 0 != (DIRTY_FRUSTUM & dirtyBits);
- final boolean mviReq = 0 != (DIRTY_INVERSE_MODELVIEW & requestMask);
- final boolean mvitReq = 0 != (DIRTY_INVERSE_TRANSPOSED_MODELVIEW & requestMask);
- final boolean frustumReq = 0 != (DIRTY_FRUSTUM & requestMask);
+ final boolean pmvDirty = 0 != (PREMUL_PMV & dirtyBits);
+ final boolean pmvUsed = null != matPMv;
+
+ final boolean pmviDirty = 0 != (PREMUL_PMVI & dirtyBits);
+ final boolean pmviUsed = null != matPMvi;
+
+ final boolean frustumDirty = 0 != (FRUSTUM & dirtyBits);
+ final boolean frustumUsed = null != frustum;
+
+ final boolean mviDirty = 0 != (INVERSE_MODELVIEW & dirtyBits);
+ final boolean mviReq = 0 != (INVERSE_MODELVIEW & requestBits);
+
+ final boolean mvitDirty = 0 != (INVERSE_TRANSPOSED_MODELVIEW & dirtyBits);
+ final boolean mvitReq = 0 != (INVERSE_TRANSPOSED_MODELVIEW & requestBits);
+
final boolean modP = 0 != ( MODIFIED_PROJECTION & modifiedBits );
final boolean modMv = 0 != ( MODIFIED_MODELVIEW & modifiedBits );
final boolean modT = 0 != ( MODIFIED_TEXTURE & modifiedBits );
+ int count = 3; // P, Mv, T
sb.append("PMVMatrix[modified[P ").append(modP).append(", Mv ").append(modMv).append(", T ").append(modT);
- sb.append("], dirty/req[Mvi ").append(mviDirty).append("/").append(mviReq).append(", Mvit ").append(mvitDirty).append("/").append(mvitReq).append(", Frustum ").append(frustumDirty).append("/").append(frustumReq).append("]").append(PlatformPropsImpl.NEWLINE);
- sb.append(", Projection").append(PlatformPropsImpl.NEWLINE);
- matrixToString(sb, f, matrixP);
- sb.append(", Modelview").append(PlatformPropsImpl.NEWLINE);
- matrixToString(sb, f, matrixMv);
- sb.append(", Texture").append(PlatformPropsImpl.NEWLINE);
- matrixToString(sb, f, matrixTex);
- if( 0 != ( requestMask & DIRTY_INVERSE_MODELVIEW ) ) {
- sb.append(", Inverse Modelview").append(PlatformPropsImpl.NEWLINE);
- matrixToString(sb, f, matrixMvi);
+ sb.append("], dirty/used[PMv ").append(pmvDirty).append("/").append(pmvUsed).append(", Pmvi ").append(pmviDirty).append("/").append(pmviUsed).append(", Frustum ").append(frustumDirty).append("/").append(frustumUsed);
+ sb.append("], dirty/req[Mvi ").append(mviDirty).append("/").append(mviReq).append(", Mvit ").append(mvitDirty).append("/").append(mvitReq).append("]").append(System.lineSeparator());
+ sb.append(", Projection").append(System.lineSeparator());
+ matP.toString(sb, null, f);
+ sb.append(", Modelview").append(System.lineSeparator());
+ matMv.toString(sb, null, f);
+ sb.append(", Texture").append(System.lineSeparator());
+ matTex.toString(sb, null, f);
+ if( null != matPMv ) {
+ sb.append(", P * Mv").append(System.lineSeparator());
+ matPMv.toString(sb, null, f);
+ ++count;
+ }
+ if( null != matPMvi ) {
+ sb.append(", P * Mv").append(System.lineSeparator());
+ matPMvi.toString(sb, null, f);
+ ++count;
}
- if( 0 != ( requestMask & DIRTY_INVERSE_TRANSPOSED_MODELVIEW ) ) {
- sb.append(", Inverse Transposed Modelview").append(PlatformPropsImpl.NEWLINE);
- matrixToString(sb, f, matrixMvit);
+ if( mviReq ) {
+ sb.append(", Inverse Modelview").append(System.lineSeparator());
+ matMvi.toString(sb, null, f);
+ ++count;
}
- sb.append("]");
+ if( mvitReq ) {
+ sb.append(", Inverse Transposed Modelview").append(System.lineSeparator());
+ matMvit.toString(sb, null, f);
+ ++count;
+ }
+ int tmpCount = 1;
+ if( null != mat4Tmp2 ) {
+ ++tmpCount;
+ }
+ sb.append(", matrices "+count+" + "+tmpCount+" temp = "+(count+tmpCount)+"]");
return sb;
}
@@ -902,6 +1244,8 @@ public final class PMVMatrix implements GLMatrixFunc {
* @see #MODIFIED_PROJECTION
* @see #MODIFIED_MODELVIEW
* @see #MODIFIED_TEXTURE
+ * @see #getDirtyBits()
+ * @see #isReqDirty()
*/
public final int getModifiedBits(final boolean clear) {
final int r = modifiedBits;
@@ -912,169 +1256,399 @@ public final class PMVMatrix implements GLMatrixFunc {
}
/**
- * Returns the dirty bits due to mutable operations.
+ * Returns the dirty bits due to mutable operations,
+ * i.e.
+ * - {@link #INVERSE_MODELVIEW} (if requested)
+ * - {@link #INVERSE_TRANSPOSED_MODELVIEW} (if requested)
+ * - {@link #FRUSTUM} (always, cleared via {@link #getFrustum()}
+ * <p>
+ * A dirty bit is set, if the corresponding matrix had been modified by a mutable operation
+ * since last {@link #update()} call and requested in the constructor {@link #PMVMatrix(int)}.
+ * </p>
* <p>
- * A dirty bit is set , if the corresponding matrix had been modified by a mutable operation
- * since last {@link #update()} call. The latter clears the dirty state only if the dirty matrix (Mvi or Mvit) or {@link Frustum}
- * has been requested by one of the {@link #glGetMviMatrixf() Mvi get}, {@link #glGetMvitMatrixf() Mvit get}
- * or {@link #glGetFrustum() Frustum get} methods.
+ * {@link #update()} clears the dirty state for the matrices and {@link #getFrustum()} for {@link #FRUSTUM}.
* </p>
*
- * @see #DIRTY_INVERSE_MODELVIEW
- * @see #DIRTY_INVERSE_TRANSPOSED_MODELVIEW
- * @see #DIRTY_FRUSTUM
- * @see #glGetMviMatrixf()
- * @see #glGetMvitMatrixf()
- * @see #glGetPMvMviMatrixf()
- * @see #glGetPMvMvitMatrixf()
- * @see #glGetFrustum()
+ * @see #isReqDirty()
+ * @see #INVERSE_MODELVIEW
+ * @see #INVERSE_TRANSPOSED_MODELVIEW
+ * @see #FRUSTUM
+ * @see #PMVMatrix(int)
+ * @see #getMviMat()
+ * @see #getMvitMat()
+ * @see #getSyncPMvMviMat()
+ * @see #getSyncPMvMviMvitMat()
+ * @see #getFrustum()
*/
public final int getDirtyBits() {
return dirtyBits;
}
/**
- * Returns the request bit mask, which uses bit values equal to the dirty mask.
+ * Returns true if the one of the {@link #getReqBits() requested bits} are are set dirty due to mutable operations,
+ * i.e. at least one of
+ * - {@link #INVERSE_MODELVIEW}
+ * - {@link #INVERSE_TRANSPOSED_MODELVIEW}
+ * <p>
+ * A dirty bit is set, if the corresponding matrix had been modified by a mutable operation
+ * since last {@link #update()} call and requested in the constructor {@link #PMVMatrix(int)}.
+ * </p>
* <p>
- * The request bit mask is set by one of the {@link #glGetMviMatrixf() Mvi get}, {@link #glGetMvitMatrixf() Mvit get}
- * or {@link #glGetFrustum() Frustum get} methods.
+ * {@link #update()} clears the dirty state for the matrices and {@link #getFrustum()} for {@link #FRUSTUM}.
* </p>
*
- * @see #clearAllUpdateRequests()
- * @see #DIRTY_INVERSE_MODELVIEW
- * @see #DIRTY_INVERSE_TRANSPOSED_MODELVIEW
- * @see #DIRTY_FRUSTUM
- * @see #glGetMviMatrixf()
- * @see #glGetMvitMatrixf()
- * @see #glGetPMvMviMatrixf()
- * @see #glGetPMvMvitMatrixf()
- * @see #glGetFrustum()
+ * @see #INVERSE_MODELVIEW
+ * @see #INVERSE_TRANSPOSED_MODELVIEW
+ * @see #PMVMatrix(int)
+ * @see #getMviMat()
+ * @see #getMvitMat()
+ * @see #getSyncPMvMviMat()
+ * @see #getSyncPMvMviMvitMat()
*/
- public final int getRequestMask() {
- return requestMask;
+ public final boolean isReqDirty() {
+ return 0 != ( requestBits & dirtyBits );
}
-
/**
- * Clears all {@link #update()} requests of the Mvi and Mvit matrix and Frustum
- * after it has been enabled by one of the {@link #glGetMviMatrixf() Mvi get}, {@link #glGetMvitMatrixf() Mvit get}
- * or {@link #glGetFrustum() Frustum get} methods.
+ * Returns the request bit mask, which uses bit values equal to the dirty mask
+ * and may contain
+ * - {@link #INVERSE_MODELVIEW}
+ * - {@link #INVERSE_TRANSPOSED_MODELVIEW}
* <p>
- * Allows user to disable subsequent Mvi, Mvit and {@link Frustum} updates if no more required.
+ * The request bit mask is set by in the constructor {@link #PMVMatrix(int)}.
* </p>
*
- * @see #glGetMviMatrixf()
- * @see #glGetMvitMatrixf()
- * @see #glGetPMvMviMatrixf()
- * @see #glGetPMvMvitMatrixf()
- * @see #glGetFrustum()
- * @see #getRequestMask()
+ * @see #INVERSE_MODELVIEW
+ * @see #INVERSE_TRANSPOSED_MODELVIEW
+ * @see #PMVMatrix(int)
+ * @see #getMviMat()
+ * @see #getMvitMat()
+ * @see #getSyncPMvMviMat()
+ * @see #getSyncPMvMviMvitMat()
+ * @see #getFrustum()
+ */
+ public final int getReqBits() {
+ return requestBits;
+ }
+
+ /**
+ * Returns the pre-multiplied projection x modelview, P x Mv.
+ * <p>
+ * This {@link Matrix4f} instance should be re-fetched via this method and not locally stored
+ * to have it updated from a potential modification of underlying projection and/or modelview matrix.
+ * {@link #update()} has no effect on this {@link Matrix4f}.
+ * </p>
+ * <p>
+ * This pre-multipled P x Mv is considered dirty, if its corresponding
+ * {@link #getPMat() P matrix} or {@link #getMvMat() Mv matrix} has been modified since its last update.
+ * </p>
+ * @see #update()
+ */
+ public final Matrix4f getPMvMat() {
+ if( 0 != ( dirtyBits & PREMUL_PMV ) ) {
+ if( null == matPMv ) {
+ matPMv = new Matrix4f();
+ }
+ matPMv.mul(matP, matMv);
+ dirtyBits &= ~PREMUL_PMV;
+ }
+ return matPMv;
+ }
+
+ /**
+ * Returns the pre-multiplied inverse projection x modelview,
+ * if {@link Matrix4f#invert(Matrix4f)} succeeded, otherwise `null`.
+ * <p>
+ * This {@link Matrix4f} instance should be re-fetched via this method and not locally stored
+ * to have it updated from a potential modification of underlying projection and/or modelview matrix.
+ * {@link #update()} has no effect on this {@link Matrix4f}.
+ * </p>
+ * <p>
+ * This pre-multipled invert(P x Mv) is considered dirty, if its corresponding
+ * {@link #getPMat() P matrix} or {@link #getMvMat() Mv matrix} has been modified since its last update.
+ * </p>
+ * @see #update()
*/
- public final void clearAllUpdateRequests() {
- requestMask &= ~DIRTY_ALL;
+ public final Matrix4f getPMviMat() {
+ if( 0 != ( dirtyBits & PREMUL_PMVI ) ) {
+ if( null == matPMvi ) {
+ matPMvi = new Matrix4f();
+ }
+ final Matrix4f mPMv = getPMvMat();
+ matPMviOK = matPMvi.invert(mPMv);
+ dirtyBits &= ~PREMUL_PMVI;
+ }
+ return matPMviOK ? matPMvi : null;
+ }
+
+ /**
+ * Returns the frustum, derived from projection x modelview.
+ * <p>
+ * This {@link Frustum} instance should be re-fetched via this method and not locally stored
+ * to have it updated from a potential modification of underlying projection and/or modelview matrix.
+ * {@link #update()} has no effect on this {@link Frustum}.
+ * </p>
+ * <p>
+ * The {@link Frustum} is considered dirty, if its corresponding
+ * {@link #getPMat() P matrix} or {@link #getMvMat() Mv matrix} has been modified since its last update.
+ * </p>
+ * @see #update()
+ */
+ public final Frustum getFrustum() {
+ if( 0 != ( dirtyBits & FRUSTUM ) ) {
+ if( null == frustum ) {
+ frustum = new Frustum();
+ }
+ final Matrix4f mPMv = getPMvMat();
+ frustum.updateFrustumPlanes(mPMv);
+ dirtyBits &= ~FRUSTUM;
+ }
+ return frustum;
}
/**
- * Update the derived {@link #glGetMviMatrixf() inverse modelview (Mvi)},
- * {@link #glGetMvitMatrixf() inverse transposed modelview (Mvit)} matrices and {@link Frustum}
- * <b>if</b> they are dirty <b>and</b> they were requested
- * by one of the {@link #glGetMviMatrixf() Mvi get}, {@link #glGetMvitMatrixf() Mvit get}
- * or {@link #glGetFrustum() Frustum get} methods.
+ * Update the derived {@link #getMviMat() inverse modelview (Mvi)},
+ * {@link #getMvitMat() inverse transposed modelview (Mvit)} matrices
+ * <b>if</b> they {@link #isReqDirty() are dirty} <b>and</b>
+ * requested via the constructor {@link #PMVMatrix(int)}.<br/>
+ * Hence updates the following dirty bits.
+ * - {@link #INVERSE_MODELVIEW}
+ * - {@link #INVERSE_TRANSPOSED_MODELVIEW}
+ * <p>
+ * The {@link Frustum} is updated only via {@link #getFrustum()} separately.
+ * </p>
* <p>
- * The Mvi and Mvit matrices and {@link Frustum} are considered dirty, if their corresponding
- * {@link #glGetMvMatrixf() Mv matrix} has been modified since their last update.
+ * The Mvi and Mvit matrices are considered dirty, if their corresponding
+ * {@link #getMvMat() Mv matrix} has been modified since their last update.
* </p>
* <p>
- * Method should be called manually in case mutable operations has been called
+ * Method is automatically called by {@link SyncMatrix4f} and {@link SyncMatrices4f}
+ * instances {@link SyncAction} as retrieved by e.g. {@link #getSyncMvitMat()}.
+ * This ensures an automatic update cycle if used with {@link GLUniformData}.
+ * </p>
+ * <p>
+ * Method may be called manually in case mutable operations has been called
* and caller operates on already fetched references, i.e. not calling
- * {@link #glGetMviMatrixf() Mvi get}, {@link #glGetMvitMatrixf() Mvit get}
- * or {@link #glGetFrustum() Frustum get} etc anymore.
+ * {@link #getMviMat()}, {@link #getMvitMat()} anymore.
* </p>
* <p>
- * This method clears the modified bits like {@link #getModifiedBits(boolean) getModifiedBits(true)},
+ * Method clears the modified bits like {@link #getModifiedBits(boolean) getModifiedBits(true)},
* which are set by any mutable operation. The modified bits have no impact
* on this method, but the return value.
* </p>
*
* @return true if any matrix has been modified since last update call or
- * if the derived matrices Mvi and Mvit or {@link Frustum} were updated, otherwise false.
+ * if the derived matrices Mvi and Mvit were updated, otherwise false.
* In other words, method returns true if any matrix used by the caller must be updated,
* e.g. uniforms in a shader program.
*
* @see #getModifiedBits(boolean)
- * @see #MODIFIED_PROJECTION
- * @see #MODIFIED_MODELVIEW
- * @see #MODIFIED_TEXTURE
- * @see #DIRTY_INVERSE_MODELVIEW
- * @see #DIRTY_INVERSE_TRANSPOSED_MODELVIEW
- * @see #DIRTY_FRUSTUM
- * @see #glGetMviMatrixf()
- * @see #glGetMvitMatrixf()
- * @see #glGetPMvMviMatrixf()
- * @see #glGetPMvMvitMatrixf()
- * @see #glGetFrustum()
- * @see #clearAllUpdateRequests()
+ * @see #isReqDirty()
+ * @see #INVERSE_MODELVIEW
+ * @see #INVERSE_TRANSPOSED_MODELVIEW
+ * @see #PMVMatrix(int)
+ * @see #getMviMat()
+ * @see #getMvitMat()
+ * @see #getSyncPMvMviMat()
+ * @see #getSyncPMvMviMvitMat()
*/
public final boolean update() {
return updateImpl(true);
}
+
+ //
+ // private
+ //
+
private final boolean updateImpl(final boolean clearModBits) {
boolean mod = 0 != modifiedBits;
- if(clearModBits) {
+ if( clearModBits ) {
modifiedBits = 0;
}
-
- if( 0 != ( dirtyBits & ( DIRTY_FRUSTUM & requestMask ) ) ) {
- if( null == frustum ) {
- frustum = new Frustum();
+ if( 0 != ( requestBits & ( ( dirtyBits & ( INVERSE_MODELVIEW | INVERSE_TRANSPOSED_MODELVIEW ) ) ) ) ) { // only if dirt requested & dirty
+ if( !matMvi.invert(matMv) ) {
+ throw new GLException(msgCantComputeInverse);
}
- FloatUtil.multMatrix(matrixArray, mP_offset, matrixArray, mMv_offset, mat4Tmp1, 0);
- // FloatUtil.multMatrix(matrixP, matrixMv, mat4Tmp1, 0);
- frustum.updateByPMV(mat4Tmp1, 0);
- dirtyBits &= ~DIRTY_FRUSTUM;
+ dirtyBits &= ~INVERSE_MODELVIEW;
+ mod = true;
+ }
+ if( 0 != ( requestBits & ( dirtyBits & INVERSE_TRANSPOSED_MODELVIEW ) ) ) { // only if requested & dirty
+ matMvit.transpose(matMvi);
+ dirtyBits &= ~INVERSE_TRANSPOSED_MODELVIEW;
mod = true;
}
+ return mod;
+ }
+ private static final String msgCantComputeInverse = "Invalid source Mv matrix, can't compute inverse";
- if( 0 == ( dirtyBits & requestMask ) ) {
- return mod; // nothing more requested which may have been dirty
+ private final Matrix4f matP;
+ private final Matrix4f matMv;
+ private final Matrix4f matTex;
+
+ private final Matrix4f matMvi;
+ private final Matrix4f matMvit;
+
+ private static final int mP_offset = 0*16;
+ private static final int mMv_offset = 1*16;
+ private final int mMvi_offset;
+ private final int mMvit_offset;
+ private final int mTex_offset;
+
+ private final float[] matrixStore;
+
+ private final FloatBuffer bufP, bufMv, bufTex;
+ private final FloatBuffer bufMvi, bufMvit;
+ private final FloatBuffer bufP_Mv, bufP_Mv_Mvi, bufP_Mv_Mvi_Mvit;
+
+ private final SyncMatrix4f syncP, syncMv, syncT;
+ private final SyncMatrix4f syncMvi, syncMvit;
+ private final SyncMatrices4f syncP_Mv, syncP_Mv_Mvi, syncP_Mv_Mvi_Mvit;
+
+ private final Matrix4f mat4Tmp1;
+
+ private int matrixMode = GL_MODELVIEW;
+ private int modifiedBits = MODIFIED_ALL;
+ private int dirtyBits = 0; // contains the dirty bits, i.e. hinting for update operation
+ private final int requestBits; // may contain the requested bits: INVERSE_MODELVIEW | INVERSE_TRANSPOSED_MODELVIEW
+ private Matrix4f mat4Tmp2;
+ private Matrix4f matPMv;
+ private Matrix4f matPMvi;
+ private boolean matPMviOK;
+ private Frustum frustum;
+
+ private abstract class PMVSyncBuffer implements SyncMatrix4f {
+ protected final Matrix4f mat;
+ private final FloatBuffer fbuf;
+
+ public PMVSyncBuffer(final Matrix4f m, final FloatBuffer fbuf) {
+ this.mat = m;
+ this.fbuf = fbuf;
}
- return setMviMvit() || mod;
+ @Override
+ public final Buffer getBuffer() { return fbuf; }
+
+ @Override
+ public final SyncBuffer sync() { getAction().sync(); return this; }
+
+ @Override
+ public final Buffer getSyncBuffer() { getAction().sync(); return fbuf; }
+
+ @Override
+ public final Matrix4f getMatrix() { return mat; }
+
+ @Override
+ public final FloatBuffer getSyncFloats() { getAction().sync(); return fbuf; }
}
+ private final class SyncBuffer0 extends PMVSyncBuffer {
+ private final SyncAction action = new SyncAction() {
+ @Override
+ public void sync() { mat.get(matrixStore); }
+ };
- //
- // private
- //
- private static final String msgCantComputeInverse = "Invalid source Mv matrix, can't compute inverse";
+ public SyncBuffer0(final Matrix4f m, final FloatBuffer fbuf) { super(m, fbuf); }
- private final boolean setMviMvit() {
- final float[] _matrixMvi = matrixMvi.array();
- final int _matrixMviOffset = matrixMvi.position();
- boolean res = false;
- if( 0 != ( dirtyBits & DIRTY_INVERSE_MODELVIEW ) ) { // only if dirt; always requested at this point, see update()
- if( null == FloatUtil.invertMatrix(matrixArray, mMv_offset, _matrixMvi, _matrixMviOffset) ) {
- throw new GLException(msgCantComputeInverse);
+ @Override
+ public SyncAction getAction() { return action; }
+
+ }
+ private final class SyncBuffer1 extends PMVSyncBuffer {
+ private final int offset;
+ private final SyncAction action = new SyncAction() {
+ @Override
+ public void sync() { mat.get(matrixStore, offset); }
+ };
+
+ public SyncBuffer1(final Matrix4f m, final FloatBuffer fbuf, final int offset) {
+ super(m, fbuf);
+ this.offset = offset;
+ }
+
+ @Override
+ public SyncAction getAction() { return action; }
+ }
+ private final class SyncBuffer1U extends PMVSyncBuffer {
+ private final int offset;
+ private final SyncAction action = new SyncAction() {
+ @Override
+ public void sync() {
+ updateImpl(true);
+ mat.get(matrixStore, offset);
}
- dirtyBits &= ~DIRTY_INVERSE_MODELVIEW;
- res = true;
+ };
+
+ public SyncBuffer1U(final Matrix4f m, final FloatBuffer fbuf, final int offset) {
+ super(m, fbuf);
+ this.offset = offset;
+ }
+
+ @Override
+ public SyncAction getAction() { return action; }
+ }
+
+ private abstract class PMVSyncBufferN implements SyncMatrices4f {
+ protected final Matrix4f[] mats;
+ private final FloatBuffer fbuf;
+
+ public PMVSyncBufferN(final Matrix4f[] ms, final FloatBuffer fbuf) {
+ this.mats = ms;
+ this.fbuf = fbuf;
}
- if( 0 != ( requestMask & ( dirtyBits & DIRTY_INVERSE_TRANSPOSED_MODELVIEW ) ) ) { // only if requested & dirty
- FloatUtil.transposeMatrix(_matrixMvi, _matrixMviOffset, matrixMvit.array(), matrixMvit.position());
- dirtyBits &= ~DIRTY_INVERSE_TRANSPOSED_MODELVIEW;
- res = true;
+
+ @Override
+ public final Buffer getBuffer() { return fbuf; }
+
+ @Override
+ public final SyncBuffer sync() { getAction().sync(); return this; }
+
+ @Override
+ public final Buffer getSyncBuffer() { getAction().sync(); return fbuf; }
+
+ @Override
+ public Matrix4f[] getMatrices() { return mats; }
+
+ @Override
+ public final FloatBuffer getSyncFloats() { getAction().sync(); return fbuf; }
+ }
+ private final class SyncBufferN extends PMVSyncBufferN {
+ private final int offset;
+ private final SyncAction action = new SyncAction() {
+ @Override
+ public void sync() {
+ int ioff = offset;
+ for(int i=0; i<mats.length; ++i, ioff+=16) {
+ mats[i].get(matrixStore, ioff);
+ }
+ }
+ };
+
+ public SyncBufferN(final Matrix4f[] ms, final FloatBuffer fbuf, final int offset) {
+ super(ms, fbuf);
+ this.offset = offset;
}
- return res;
+
+ @Override
+ public SyncAction getAction() { return action; }
}
+ private final class SyncBufferNU extends PMVSyncBufferN {
+ private final int offset;
+ private final SyncAction action = new SyncAction() {
+ @Override
+ public void sync() {
+ updateImpl(true);
+ int ioff = offset;
+ for(int i=0; i<mats.length; ++i, ioff+=16) {
+ mats[i].get(matrixStore, ioff);
+ }
+ }
+ };
- private final float[] matrixArray;
- private final int mP_offset, mMv_offset, mTex_offset;
- private final FloatBuffer matrixPMvMvit, matrixPMvMvi, matrixPMv, matrixP, matrixTex, matrixMv, matrixMvi, matrixMvit;
- private final float[] matrixTxSx;
- private final float[] mat4Tmp1, mat4Tmp2, mat4Tmp3;
- private final FloatStack matrixTStack, matrixPStack, matrixMvStack;
- private int matrixMode = GL_MODELVIEW;
- private int modifiedBits = MODIFIED_ALL;
- private int dirtyBits = DIRTY_ALL; // contains the dirty bits, i.e. hinting for update operation
- private int requestMask = 0; // may contain the requested dirty bits: DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW
- private Frustum frustum;
+ public SyncBufferNU(final Matrix4f[] ms, final FloatBuffer fbuf, final int offset) {
+ super(ms, fbuf);
+ this.offset = offset;
+ }
+
+ @Override
+ public SyncAction getAction() { return action; }
+ }
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/SyncAction.java b/src/jogl/classes/com/jogamp/opengl/util/SyncAction.java
new file mode 100644
index 000000000..fbf55e683
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/util/SyncAction.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright 2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.util;
+
+/**
+ * Specific data synchronization action implemented by the data provider
+ * to update the buffer with the underlying data before usage, e.g. uploading the {@link com.jogamp.opengl.GLUniformData GLUniformData} data to the GPU.
+ * <p>
+ * Example: Invoked before delivering {@link com.jogamp.opengl.GLUniformData GLUniformData}'s data via {@link com.jogamp.opengl.GLUniformData#getObject() getObject()}
+ * or {@link com.jogamp.opengl.GLUniformData#getBuffer() getBuffer()}.
+ * </p>
+ */
+public interface SyncAction {
+ /**
+ * Synchronizes the buffer with the underlying data before usage.
+ * <p>
+ * Example: {@link com.jogamp.opengl.GLUniformData GLUniformData} issues this method before delivering data via {@link com.jogamp.opengl.GLUniformData#getObject() getObject()}
+ * or {@link com.jogamp.opengl.GLUniformData#getBuffer() getBuffer()}.
+ * </p>
+ */
+ void sync();
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/SyncBuffer.java b/src/jogl/classes/com/jogamp/opengl/util/SyncBuffer.java
new file mode 100644
index 000000000..27bdb5dfb
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/util/SyncBuffer.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.util;
+
+import java.nio.Buffer;
+
+/**
+ * Convenient tuple of a {@link SyncAction} and {@link Buffer}.
+ * <p>
+ * {@link SyncAction#sync()} is used to update the {@link Buffer} with the underlying data
+ * known to the data provider.
+ * </p>
+ * @see SyncAction
+ */
+public interface SyncBuffer {
+ /**
+ * Return the {@link SyncAction}.
+ * @see SyncAction
+ */
+ SyncAction getAction();
+
+ /** Return the {@link Buffer}, i.e. underlying data. */
+ Buffer getBuffer();
+
+ /**
+ * Synchronizes the underlying data before usage.
+ * <p>
+ * Convenient shortcut for {@link #getAction()}.{@link SyncAction#sync() sync()} plus chaining.
+ * </p>
+ */
+ SyncBuffer sync();
+
+ /** Return the {@link Buffer} after {@link SyncAction#sync() synchronizing} it. */
+ Buffer getSyncBuffer();
+
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/SyncMatrices4f.java b/src/jogl/classes/com/jogamp/opengl/util/SyncMatrices4f.java
new file mode 100644
index 000000000..055345d65
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/util/SyncMatrices4f.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright 2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.util;
+
+import java.nio.FloatBuffer;
+
+import com.jogamp.opengl.math.Matrix4f;
+
+/** {@link SyncBuffer} with a multiple underlying {@link Matrix4f}, used in {@link SyncMatrices4f16} and {@link PMVMatrix} */
+public interface SyncMatrices4f extends SyncBuffer {
+ /** Return the underlying multiple {@link Matrix4f}, used to {@link SyncAction#sync() synchronize} to the {@link #getBuffer()}. */
+ Matrix4f[] getMatrices();
+
+ /** Return the {@link FloatBuffer} after {@link SyncAction#sync() synchronizing} it w/ the underlying {@link #getMatrices()}. */
+ FloatBuffer getSyncFloats();
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/av/AudioSinkFactory.java b/src/jogl/classes/com/jogamp/opengl/util/SyncMatrices4f16.java
index a2b29b4eb..bca827b9f 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/av/AudioSinkFactory.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/SyncMatrices4f16.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2013 JogAmp Community. All rights reserved.
+ * Copyright 2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -25,44 +25,50 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
-package com.jogamp.opengl.util.av;
+package com.jogamp.opengl.util;
-import jogamp.opengl.util.av.NullAudioSink;
+import java.nio.Buffer;
+import java.nio.FloatBuffer;
-import com.jogamp.common.util.ReflectionUtil;
+import com.jogamp.opengl.math.Matrix4f;
-public class AudioSinkFactory {
- private static final String ALAudioSinkClazzName = "jogamp.opengl.openal.av.ALAudioSink";
- private static final String JavaAudioSinkClazzName = "jogamp.opengl.util.av.JavaSoundAudioSink";
-
- public static AudioSink createDefault() {
- final ClassLoader cl = GLMediaPlayerFactory.class.getClassLoader();
- AudioSink sink = create(cl, ALAudioSinkClazzName);
- if( null == sink ) {
- sink = create(cl, JavaAudioSinkClazzName);
- }
- if( null == sink ) {
- sink = createNull();
- }
- return sink;
- }
- public static AudioSink createNull() {
- return new NullAudioSink();
- }
-
- public static AudioSink create(final ClassLoader cl, final String implName) {
- final AudioSink audioSink;
- if(ReflectionUtil.isClassAvailable(implName, cl)){
- try {
- audioSink = (AudioSink) ReflectionUtil.createInstance(implName, cl);
- if( audioSink.isInitialized() ) {
- return audioSink;
- }
- } catch (final Throwable t) {
- if(AudioSink.DEBUG) { System.err.println("Caught "+t.getClass().getName()+": "+t.getMessage()); t.printStackTrace(); }
+/** {@link SyncBuffer} {@link SyncMatrices4f16} implementation for multiple underlying {@link Matrix4f} instances using one {@code float[16*n]} backing array. */
+public final class SyncMatrices4f16 implements SyncMatrices4f {
+ private final Matrix4f[] mats;
+ private final float[] f16s;
+ private final FloatBuffer fbuf;
+ private final SyncAction action = new SyncAction() {
+ @Override
+ public void sync() {
+ int ioff = 0;
+ for(int i=0; i<mats.length; ++i, ioff+=16) {
+ mats[i].get(f16s, ioff);
}
}
- return null;
+ };
+
+ public SyncMatrices4f16(final Matrix4f[] mats) {
+ this.mats = mats;
+ this.f16s = new float[16*mats.length];
+ this.fbuf = FloatBuffer.wrap(f16s);
}
-}
+ @Override
+ public SyncAction getAction() { return action; }
+
+ @Override
+ public Buffer getBuffer() { return fbuf; }
+
+ @Override
+ public SyncBuffer sync() { getAction().sync(); return this; }
+
+ @Override
+ public Buffer getSyncBuffer() { getAction().sync(); return fbuf; }
+
+ @Override
+ public Matrix4f[] getMatrices() { return mats; }
+
+ @Override
+ public FloatBuffer getSyncFloats() { getAction().sync(); return fbuf; }
+
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/SyncMatrix4f.java b/src/jogl/classes/com/jogamp/opengl/util/SyncMatrix4f.java
new file mode 100644
index 000000000..6ab473771
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/util/SyncMatrix4f.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright 2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.util;
+
+import java.nio.FloatBuffer;
+
+import com.jogamp.opengl.math.Matrix4f;
+
+/** {@link SyncBuffer} interface with a single underlying {@link Matrix4f}, used in {@link SyncMatrix4f16} and {@link PMVMatrix}. */
+public interface SyncMatrix4f extends SyncBuffer {
+ /** Return the underlying {@link Matrix4f}, used to {@link SyncAction#sync() synchronize} to the {@link #getBuffer()}. */
+ Matrix4f getMatrix();
+
+ /** Return the {@link FloatBuffer} after {@link SyncAction#sync() synchronizing} it w/ the underlying {@link #getMatrix()}. */
+ FloatBuffer getSyncFloats();
+
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/SyncMatrix4f16.java b/src/jogl/classes/com/jogamp/opengl/util/SyncMatrix4f16.java
new file mode 100644
index 000000000..03a4b64fa
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/util/SyncMatrix4f16.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright 2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.util;
+
+import java.nio.Buffer;
+import java.nio.FloatBuffer;
+
+import com.jogamp.opengl.math.Matrix4f;
+
+/** {@link SyncBuffer} {@link SyncMatrix4f} implementation for a single underlying {@link Matrix4f} using one {@code float[16]} backing array. */
+public final class SyncMatrix4f16 implements SyncMatrix4f {
+ private final Matrix4f mat;
+ private final float[] f16;
+ private final FloatBuffer fbuf;
+ private final SyncAction action = new SyncAction() {
+ @Override
+ public void sync() { mat.get(f16); }
+ };
+
+ public SyncMatrix4f16() {
+ this.mat = new Matrix4f();
+ this.f16 = new float[16];
+ this.fbuf = FloatBuffer.wrap(f16);
+ }
+
+ public SyncMatrix4f16(final Matrix4f m) {
+ this.mat = m;
+ this.f16 = new float[16];
+ this.fbuf = FloatBuffer.wrap(f16);
+ }
+
+ @Override
+ public SyncAction getAction() { return action; }
+
+ @Override
+ public Buffer getBuffer() { return fbuf; }
+
+ @Override
+ public SyncBuffer sync() { getAction().sync(); return this; }
+
+ @Override
+ public Buffer getSyncBuffer() { getAction().sync(); return fbuf; }
+
+ @Override
+ public Matrix4f getMatrix() { return mat; }
+
+ @Override
+ public FloatBuffer getSyncFloats() { getAction().sync(); return fbuf; }
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/TimeFrameI.java b/src/jogl/classes/com/jogamp/opengl/util/TimeFrameI.java
deleted file mode 100644
index 99def6f5c..000000000
--- a/src/jogl/classes/com/jogamp/opengl/util/TimeFrameI.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * Copyright 2013 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
-package com.jogamp.opengl.util;
-
-/**
- * Integer time frame in milliseconds, maybe specialized for texture/video, audio, .. animated content.
- * <p>
- * Type and value range has been chosen to suit embedded CPUs
- * and characteristics of audio / video streaming and animations.
- * Milliseconds of type integer with a maximum value of {@link Integer#MAX_VALUE}
- * will allow tracking time up 2,147,483.647 seconds or
- * 24 days 20 hours 31 minutes and 23 seconds.
- * </p>
- * <p>
- * Milliseconds granularity is also more than enough to deal with A-V synchronization,
- * where the threshold usually lies within 22ms.
- * </p>
- * <p>
- * Milliseconds granularity for displaying video frames might seem inaccurate
- * for each single frame, i.e. 60Hz != 16ms, however, accumulated values diminish
- * this error and vertical sync is achieved by build-in V-Sync of the video drivers.
- * </p>
- */
-public class TimeFrameI {
- /** Constant marking an invalid PTS, i.e. Integer.MIN_VALUE == 0x80000000 == {@value}. Sync w/ native code. */
- public static final int INVALID_PTS = 0x80000000;
-
- /** Constant marking the end of the stream PTS, i.e. Integer.MIN_VALUE - 1 == 0x7FFFFFFF == {@value}. Sync w/ native code. */
- public static final int END_OF_STREAM_PTS = 0x7FFFFFFF;
-
- protected int pts;
- protected int duration;
-
- public TimeFrameI() {
- pts = INVALID_PTS;
- duration = 0;
- }
- public TimeFrameI(final int pts, final int duration) {
- this.pts = pts;
- this.duration = duration;
- }
-
- /** Get this frame's presentation timestamp (PTS) in milliseconds. */
- public final int getPTS() { return pts; }
- /** Set this frame's presentation timestamp (PTS) in milliseconds. */
- public final void setPTS(final int pts) { this.pts = pts; }
- /** Get this frame's duration in milliseconds. */
- public final int getDuration() { return duration; }
- /** Set this frame's duration in milliseconds. */
- public final void setDuration(final int duration) { this.duration = duration; }
-
- @Override
- public String toString() {
- return "TimeFrame[pts " + pts + " ms, l " + duration + " ms]";
- }
-}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/av/AudioSink.java b/src/jogl/classes/com/jogamp/opengl/util/av/AudioSink.java
deleted file mode 100644
index fd6172e13..000000000
--- a/src/jogl/classes/com/jogamp/opengl/util/av/AudioSink.java
+++ /dev/null
@@ -1,436 +0,0 @@
-/**
- * Copyright 2013 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
-package com.jogamp.opengl.util.av;
-
-import java.nio.ByteBuffer;
-
-import com.jogamp.opengl.util.TimeFrameI;
-
-import jogamp.opengl.Debug;
-
-public interface AudioSink {
- public static final boolean DEBUG = Debug.debug("AudioSink");
-
- /** Default frame duration in millisecond, i.e. 1 frame per {@value} ms. */
- public static final int DefaultFrameDuration = 32;
-
- /** Initial audio queue size in milliseconds. {@value} ms, i.e. 16 frames per 32 ms. See {@link #init(AudioFormat, float, int, int, int)}.*/
- public static final int DefaultInitialQueueSize = 16 * 32; // 512 ms
- /** Audio queue grow size in milliseconds. {@value} ms, i.e. 16 frames per 32 ms. See {@link #init(AudioFormat, float, int, int, int)}.*/
- public static final int DefaultQueueGrowAmount = 16 * 32; // 512 ms
- /** Audio queue limit w/ video in milliseconds. {@value} ms, i.e. 96 frames per 32 ms. See {@link #init(AudioFormat, float, int, int, int)}.*/
- public static final int DefaultQueueLimitWithVideo = 96 * 32; // 3072 ms
- /** Audio queue limit w/o video in milliseconds. {@value} ms, i.e. 32 frames per 32 ms. See {@link #init(AudioFormat, float, int, int, int)}.*/
- public static final int DefaultQueueLimitAudioOnly = 32 * 32; // 1024 ms
-
- /**
- * Specifies the linear audio PCM format.
- */
- public static class AudioFormat {
- /**
- * @param sampleRate sample rate in Hz (1/s)
- * @param sampleSize sample size in bits
- * @param channelCount number of channels
- * @param signed true if signed number, false for unsigned
- * @param fixedP true for fixed point value, false for unsigned floating point value with a sampleSize of 32 (float) or 64 (double)
- * @param planar true for planar data package (each channel in own data buffer), false for packed data channels interleaved in one buffer.
- * @param littleEndian true for little-endian, false for big endian
- */
- public AudioFormat(final int sampleRate, final int sampleSize, final int channelCount, final boolean signed, final boolean fixedP, final boolean planar, final boolean littleEndian) {
- this.sampleRate = sampleRate;
- this.sampleSize = sampleSize;
- this.channelCount = channelCount;
- this.signed = signed;
- this.fixedP = fixedP;
- this.planar = planar;
- this.littleEndian = littleEndian;
- if( !fixedP ) {
- if( sampleSize != 32 && sampleSize != 64 ) {
- throw new IllegalArgumentException("Floating point: sampleSize "+sampleSize+" bits");
- }
- if( !signed ) {
- throw new IllegalArgumentException("Floating point: unsigned");
- }
- }
- }
-
- /** Sample rate in Hz (1/s). */
- public final int sampleRate;
- /** Sample size in bits. */
- public final int sampleSize;
- /** Number of channels. */
- public final int channelCount;
- public final boolean signed;
- /** Fixed or floating point values. Floating point 'float' has {@link #sampleSize} 32, 'double' has {@link #sampleSize} 64. */
- public final boolean fixedP;
- /** Planar or packed samples. If planar, each channel has their own data buffer. If packed, channel data is interleaved in one buffer. */
- public final boolean planar;
- public final boolean littleEndian;
-
-
- //
- // Time <-> Bytes
- //
-
- /**
- * Returns the byte size of the given milliseconds
- * according to {@link #sampleSize}, {@link #channelCount} and {@link #sampleRate}.
- * <p>
- * Time -> Byte Count
- * </p>
- */
- public final int getDurationsByteSize(final int millisecs) {
- final int bytesPerSample = sampleSize >>> 3; // /8
- return millisecs * ( channelCount * bytesPerSample * ( sampleRate / 1000 ) );
- }
-
- /**
- * Returns the duration in milliseconds of the given byte count
- * according to {@link #sampleSize}, {@link #channelCount} and {@link #sampleRate}.
- * <p>
- * Byte Count -> Time
- * </p>
- */
- public final int getBytesDuration(final int byteCount) {
- final int bytesPerSample = sampleSize >>> 3; // /8
- return byteCount / ( channelCount * bytesPerSample * ( sampleRate / 1000 ) );
- }
-
- /**
- * Returns the duration in milliseconds of the given sample count per frame and channel
- * according to the {@link #sampleRate}, i.e.
- * <pre>
- * ( 1000f * sampleCount ) / sampleRate
- * </pre>
- * <p>
- * Sample Count -> Time
- * </p>
- * @param sampleCount sample count per frame and channel
- */
- public final float getSamplesDuration(final int sampleCount) {
- return ( 1000f * sampleCount ) / sampleRate;
- }
-
- /**
- * Returns the rounded frame count of the given milliseconds and frame duration.
- * <pre>
- * Math.max( 1, millisecs / frameDuration + 0.5f )
- * </pre>
- * <p>
- * Note: <code>frameDuration</code> can be derived by <i>sample count per frame and channel</i>
- * via {@link #getSamplesDuration(int)}.
- * </p>
- * <p>
- * Frame Time -> Frame Count
- * </p>
- * @param millisecs time in milliseconds
- * @param frameDuration duration per frame in milliseconds.
- */
- public final int getFrameCount(final int millisecs, final float frameDuration) {
- return Math.max(1, (int) ( millisecs / frameDuration + 0.5f ));
- }
-
- /**
- * Returns the byte size of given sample count
- * according to the {@link #sampleSize}, i.e.:
- * <pre>
- * sampleCount * ( sampleSize / 8 )
- * </pre>
- * <p>
- * Note: To retrieve the byte size for all channels,
- * you need to pre-multiply <code>sampleCount</code> with {@link #channelCount}.
- * </p>
- * <p>
- * Sample Count -> Byte Count
- * </p>
- * @param sampleCount sample count
- */
- public final int getSamplesByteCount(final int sampleCount) {
- return sampleCount * ( sampleSize >>> 3 );
- }
-
- /**
- * Returns the sample count of given byte count
- * according to the {@link #sampleSize}, i.e.:
- * <pre>
- * ( byteCount * 8 ) / sampleSize
- * </pre>
- * <p>
- * Note: If <code>byteCount</code> covers all channels and you request the sample size per channel,
- * you need to divide the result by <code>sampleCount</code> by {@link #channelCount}.
- * </p>
- * <p>
- * Byte Count -> Sample Count
- * </p>
- * @param byteCount number of bytes
- */
- public final int getBytesSampleCount(final int byteCount) {
- return ( byteCount << 3 ) / sampleSize;
- }
-
- @Override
- public String toString() {
- return "AudioDataFormat[sampleRate "+sampleRate+", sampleSize "+sampleSize+", channelCount "+channelCount+
- ", signed "+signed+", fixedP "+fixedP+", "+(planar?"planar":"packed")+", "+(littleEndian?"little":"big")+"-endian]"; }
- }
- /** Default {@link AudioFormat}, [type PCM, sampleRate 44100, sampleSize 16, channelCount 2, signed, fixedP, !planar, littleEndian]. */
- public static final AudioFormat DefaultFormat = new AudioFormat(44100, 16, 2, true /* signed */,
- true /* fixed point */, false /* planar */, true /* littleEndian */);
-
- public static abstract class AudioFrame extends TimeFrameI {
- protected int byteSize;
-
- public AudioFrame() {
- this.byteSize = 0;
- }
- public AudioFrame(final int pts, final int duration, final int byteCount) {
- super(pts, duration);
- this.byteSize=byteCount;
- }
-
- /** Get this frame's size in bytes. */
- public final int getByteSize() { return byteSize; }
- /** Set this frame's size in bytes. */
- public final void setByteSize(final int size) { this.byteSize=size; }
-
- @Override
- public String toString() {
- return "AudioFrame[pts " + pts + " ms, l " + duration + " ms, "+byteSize + " bytes]";
- }
- }
- public static class AudioDataFrame extends AudioFrame {
- protected final ByteBuffer data;
-
- public AudioDataFrame(final int pts, final int duration, final ByteBuffer bytes, final int byteCount) {
- super(pts, duration, byteCount);
- if( byteCount > bytes.remaining() ) {
- throw new IllegalArgumentException("Give size "+byteCount+" exceeds remaining bytes in ls "+bytes+". "+this);
- }
- this.data=bytes;
- }
-
- /** Get this frame's data. */
- public final ByteBuffer getData() { return data; }
-
- @Override
- public String toString() {
- return "AudioDataFrame[pts " + pts + " ms, l " + duration + " ms, "+byteSize + " bytes, " + data + "]";
- }
- }
-
- /**
- * Returns the <code>initialized state</code> of this instance.
- * <p>
- * The <code>initialized state</code> is affected by this instance
- * overall availability, i.e. after instantiation,
- * as well as by {@link #destroy()}.
- * </p>
- */
- public boolean isInitialized();
-
- /** Returns the playback speed. */
- public float getPlaySpeed();
-
- /**
- * Sets the playback speed.
- * <p>
- * To simplify test, play speed is <i>normalized</i>, i.e.
- * <ul>
- * <li><code>1.0f</code>: if <code> Math.abs(1.0f - rate) < 0.01f </code></li>
- * </ul>
- * </p>
- * @return true if successful, otherwise false, i.e. due to unsupported value range of implementation.
- */
- public boolean setPlaySpeed(float s);
-
- /** Returns the volume. */
- public float getVolume();
-
- /**
- * Sets the volume [0f..1f].
- * <p>
- * To simplify test, volume is <i>normalized</i>, i.e.
- * <ul>
- * <li><code>0.0f</code>: if <code> Math.abs(v) < 0.01f </code></li>
- * <li><code>1.0f</code>: if <code> Math.abs(1.0f - v) < 0.01f </code></li>
- * </ul>
- * </p>
- * @return true if successful, otherwise false, i.e. due to unsupported value range of implementation.
- */
- public boolean setVolume(float v);
-
- /**
- * Returns the preferred {@link AudioFormat} by this sink.
- * <p>
- * The preferred format is guaranteed to be supported
- * and shall reflect this sinks most native format,
- * i.e. best performance w/o data conversion.
- * </p>
- * <p>
- * Known {@link #AudioFormat} attributes considered by implementations:
- * <ul>
- * <li>ALAudioSink: {@link AudioFormat#sampleRate}.
- * </ul>
- * </p>
- * @see #initSink(AudioFormat)
- * @see #isSupported(AudioFormat)
- */
- public AudioFormat getPreferredFormat();
-
- /** Return the maximum number of supported channels. */
- public int getMaxSupportedChannels();
-
- /**
- * Returns true if the given format is supported by the sink, otherwise false.
- * @see #initSink(AudioFormat)
- * @see #getPreferredFormat()
- */
- public boolean isSupported(AudioFormat format);
-
- /**
- * Initializes the sink.
- * <p>
- * Implementation must match the given <code>requestedFormat</code> {@link AudioFormat}.
- * </p>
- * <p>
- * Caller shall validate <code>requestedFormat</code> via {@link #isSupported(AudioFormat)}
- * beforehand and try to find a suitable supported one.
- * {@link #getPreferredFormat()} and {@link #getMaxSupportedChannels()} may help.
- * </p>
- * @param requestedFormat the requested {@link AudioFormat}.
- * @param frameDuration average or fixed frame duration in milliseconds
- * helping a caching {@link AudioFrame} based implementation to determine the frame count in the queue.
- * See {@link #DefaultFrameDuration}.
- * @param initialQueueSize initial time in milliseconds to queue in this sink, see {@link #DefaultInitialQueueSize}.
- * @param queueGrowAmount time in milliseconds to grow queue if full, see {@link #DefaultQueueGrowAmount}.
- * @param queueLimit maximum time in milliseconds the queue can hold (and grow), see {@link #DefaultQueueLimitWithVideo} and {@link #DefaultQueueLimitAudioOnly}.
- * @return true if successful, otherwise false
- */
- public boolean init(AudioFormat requestedFormat, float frameDuration,
- int initialQueueSize, int queueGrowAmount, int queueLimit);
-
- /**
- * Returns the {@link AudioFormat} as chosen by {@link #init(AudioFormat, float, int, int, int)},
- * i.e. it shall match the <i>requestedFormat</i>.
- */
- public AudioFormat getChosenFormat();
-
- /**
- * Returns true, if {@link #play()} has been requested <i>and</i> the sink is still playing,
- * otherwise false.
- */
- public boolean isPlaying();
-
- /**
- * Play buffers queued via {@link #enqueueData(AudioFrame)} from current internal position.
- * If no buffers are yet queued or the queue runs empty, playback is being continued when buffers are enqueued later on.
- * @see #enqueueData(AudioFrame)
- * @see #pause()
- */
- public void play();
-
- /**
- * Pause playing buffers while keeping enqueued data incl. it's internal position.
- * @see #play()
- * @see #flush()
- * @see #enqueueData(AudioFrame)
- */
- public void pause();
-
- /**
- * Flush all queued buffers, implies {@link #pause()}.
- * <p>
- * {@link #init(AudioFormat, float, int, int, int)} must be called first.
- * </p>
- * @see #play()
- * @see #pause()
- * @see #enqueueData(AudioFrame)
- */
- public void flush();
-
- /** Destroys this instance, i.e. closes all streams and devices allocated. */
- public void destroy();
-
- /**
- * Returns the number of allocated buffers as requested by
- * {@link #init(AudioFormat, float, int, int, int)}.
- */
- public int getFrameCount();
-
- /** @return the current enqueued frames count since {@link #init(AudioFormat, float, int, int, int)}. */
- public int getEnqueuedFrameCount();
-
- /**
- * Returns the current number of frames queued for playing.
- * <p>
- * {@link #init(AudioFormat, float, int, int, int)} must be called first.
- * </p>
- */
- public int getQueuedFrameCount();
-
- /**
- * Returns the current number of bytes queued for playing.
- * <p>
- * {@link #init(AudioFormat, float, int, int, int)} must be called first.
- * </p>
- */
- public int getQueuedByteCount();
-
- /**
- * Returns the current queued frame time in milliseconds for playing.
- * <p>
- * {@link #init(AudioFormat, float, int, int, int)} must be called first.
- * </p>
- */
- public int getQueuedTime();
-
- /**
- * Return the current audio presentation timestamp (PTS) in milliseconds.
- */
- public int getPTS();
-
- /**
- * Returns the current number of frames in the sink available for writing.
- * <p>
- * {@link #init(AudioFormat, float, int, int, int)} must be called first.
- * </p>
- */
- public int getFreeFrameCount();
-
- /**
- * Enqueue <code>byteCount</code> bytes of the remaining bytes of the given NIO {@link ByteBuffer} to this sink.
- * <p>
- * The data must comply with the chosen {@link AudioFormat} as returned by {@link #initSink(AudioFormat)}.
- * </p>
- * <p>
- * {@link #init(AudioFormat, float, int, int, int)} must be called first.
- * </p>
- * @returns the enqueued internal {@link AudioFrame}.
- */
- public AudioFrame enqueueData(int pts, ByteBuffer bytes, int byteCount);
-}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
index c2de32372..51724d240 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
@@ -33,10 +33,14 @@ import com.jogamp.opengl.GLException;
import jogamp.opengl.Debug;
+import java.util.List;
+
+import com.jogamp.common.av.AudioFormat;
+import com.jogamp.common.av.AudioSink;
+import com.jogamp.common.av.TimeFrameI;
import com.jogamp.common.net.Uri;
import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureSequence;
-import com.jogamp.opengl.util.TimeFrameI;
/**
* GLMediaPlayer interface specifies a {@link TextureSequence} state machine
@@ -45,7 +49,7 @@ import com.jogamp.opengl.util.TimeFrameI;
* Audio maybe supported and played back internally or via an {@link AudioSink} implementation.
* </p>
* <p>
- * Audio and video streams can be selected or muted via {@link #initStream(Uri, int, int, int)}
+ * Audio and video streams can be selected or muted via {@link #playStream(Uri, int, int, int)}
* using the appropriate <a href="#streamIDs">stream id</a>'s.
* </p>
* <p>
@@ -56,7 +60,7 @@ import com.jogamp.opengl.util.TimeFrameI;
* <p>
* Most of the stream processing is performed on the decoding thread, a.k.a. <i>StreamWorker</i>:
* <ul>
- * <li>Stream initialization triggered by {@link #initStream(Uri, int, int, int) initStream(..)} - User gets notified whether the stream has been initialized or not via {@link GLMediaEventListener#attributesChanged(GLMediaPlayer, int, long) attributesChanges(..)}.</li>
+ * <li>Stream initialization triggered by {@link #playStream(Uri, int, int, int) playStream(..)} - User gets notified whether the stream has been initialized or not via {@link GLMediaEventListener#attributesChanged(GLMediaPlayer, int, long) attributesChanges(..)}.</li>
* <li>Stream decoding - User gets notified of a new frame via {@link GLMediaEventListener#newFrameAvailable(GLMediaPlayer, com.jogamp.opengl.util.texture.TextureSequence.TextureFrame, long) newFrameAvailable(...)}.</li>
* <li>Caught <a href="#streamerror">exceptions on the decoding thread</a> are delivered as {@link StreamException}s.</li>
* </ul>
@@ -81,17 +85,18 @@ import com.jogamp.opengl.util.TimeFrameI;
* <a name="lifecycle"><h5>GLMediaPlayer Lifecycle</h5></a>
* <p>
* <table border="1">
- * <tr><th>Action</th> <th>{@link State} Before</th> <th>{@link State} After</th> <th>{@link GLMediaEventListener Event}</th></tr>
- * <tr><td>{@link #initStream(Uri, int, int, int)}</td> <td>{@link State#Uninitialized Uninitialized}</td> <td>{@link State#Initialized Initialized}<sup><a href="#streamworker">1</a></sup>, {@link State#Uninitialized Uninitialized}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_INIT EVENT_CHANGE_INIT} or ( {@link GLMediaEventListener#EVENT_CHANGE_ERR EVENT_CHANGE_ERR} + {@link GLMediaEventListener#EVENT_CHANGE_UNINIT EVENT_CHANGE_UNINIT} )</td></tr>
- * <tr><td>{@link #initGL(GL)}</td> <td>{@link State#Initialized Initialized}</td> <td>{@link State#Paused Paused}, , {@link State#Uninitialized Uninitialized}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_PAUSE EVENT_CHANGE_PAUSE} or ( {@link GLMediaEventListener#EVENT_CHANGE_ERR EVENT_CHANGE_ERR} + {@link GLMediaEventListener#EVENT_CHANGE_UNINIT EVENT_CHANGE_UNINIT} )</td></tr>
- * <tr><td>{@link #play()}</td> <td>{@link State#Paused Paused}</td> <td>{@link State#Playing Playing}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_PLAY EVENT_CHANGE_PLAY}</td></tr>
- * <tr><td>{@link #pause(boolean)}</td> <td>{@link State#Playing Playing}</td> <td>{@link State#Paused Paused}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_PAUSE EVENT_CHANGE_PAUSE}</td></tr>
+ * <tr><th>Action</th> <th>{@link State} Before</th> <th>{@link State} After</th> <th>{@link EventMask#Bit Event}</th></tr>
+ * <tr><td>{@link #playStream(Uri, int, int, int)}</td> <td>{@link State#Uninitialized Uninitialized}</td> <td>{@link State#Initialized Initialized}<sup><a href="#streamworker">1</a></sup>, {@link State#Uninitialized Uninitialized}</td> <td>{@link EventMask.Bit#Init Init} or ( {@link EventMask.Bit#Error Error} + {@link EventMask.Bit#Uninit Uninit} )</td></tr>
+ * <tr><td>{@link #initGL(GL)}</td> <td>{@link State#Initialized Initialized}, {@link State#Uninitialized Uninitialized} </td> <td>{@link State#Playing Playing}, {@link State#Uninitialized Uninitialized}</td> <td>{@link EventMask.Bit#Play Play} or ( {@link EventMask.Bit#Error Error} + {@link EventMask.Bit#Uninit Uninit} )</td></tr>
+ * <tr><td>{@link #pause(boolean)}</td> <td>{@link State#Playing Playing}</td> <td>{@link State#Paused Paused}</td> <td>{@link EventMask.Bit#Pause Pause}</td></tr>
+ * <tr><td>{@link #resume()}</td> <td>{@link State#Paused Paused}</td> <td>{@link State#Playing Playing}</td> <td>{@link EventMask.Bit#Play Play}</td></tr>
+ * <tr><td>{@link #stop()}</td> <td>{@link State#Playing Playing}, {@link State#Paused Paused}</td> <td>{@link State#Uninitialized Uninitialized}</td> <td>{@link EventMask.Bit#Pause Pause}</td></tr>
* <tr><td>{@link #seek(int)}</td> <td>{@link State#Paused Paused}, {@link State#Playing Playing}</td> <td>{@link State#Paused Paused}, {@link State#Playing Playing}</td> <td>none</td></tr>
- * <tr><td>{@link #getNextTexture(GL)}</td> <td>{@link State#Paused Paused}, {@link State#Playing Playing}</td> <td>{@link State#Paused Paused}, {@link State#Playing Playing}</td> <td>none</td></tr>
- * <tr><td>{@link #getLastTexture()}</td> <td>{@link State#Paused Paused}, {@link State#Playing Playing}</td> <td>{@link State#Paused Paused}, {@link State#Playing Playing}</td> <td>none</td></tr>
- * <tr><td>{@link TextureFrame#END_OF_STREAM_PTS END_OF_STREAM}</td> <td>{@link State#Playing Playing}</td> <td>{@link State#Paused Paused}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_EOS EVENT_CHANGE_EOS} + {@link GLMediaEventListener#EVENT_CHANGE_PAUSE EVENT_CHANGE_PAUSE}</td></tr>
- * <tr><td>{@link StreamException}</td> <td>ANY</td> <td>{@link State#Paused Paused}, {@link State#Uninitialized Uninitialized}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_ERR EVENT_CHANGE_ERR} + ( {@link GLMediaEventListener#EVENT_CHANGE_PAUSE EVENT_CHANGE_PAUSE} or {@link GLMediaEventListener#EVENT_CHANGE_UNINIT EVENT_CHANGE_UNINIT} )</td></tr>
- * <tr><td>{@link #destroy(GL)}</td> <td>ANY</td> <td>{@link State#Uninitialized Uninitialized}</td> <td>{@link GLMediaEventListener#EVENT_CHANGE_UNINIT EVENT_CHANGE_UNINIT}</td></tr>
+ * <tr><td>{@link #getNextTexture(GL)}</td> <td><i>any</i></td> <td><i>same</i></td> <td>none</td></tr>
+ * <tr><td>{@link #getLastTexture()}</td> <td><i>any</i></td> <td><i>same</i></td> <td>none</td></tr>
+ * <tr><td>{@link TextureFrame#END_OF_STREAM_PTS END_OF_STREAM}</td> <td>{@link State#Playing Playing}</td> <td>{@link State#Paused Paused}</td> <td>{@link EventMask.Bit#EOS EOS} + {@link EventMask.Bit#Pause Pause}</td></tr>
+ * <tr><td>{@link StreamException}</td> <td><i>any</i></td> <td>{@link State#Paused Paused}, {@link State#Uninitialized Uninitialized}</td> <td>{@link EventMask.Bit#Error Error} + ( {@link EventMask.Bit#Pause Pause} or {@link EventMask.Bit#Uninit Uninit} )</td></tr>
+ * <tr><td>{@link #destroy(GL)}</td> <td><i>any</i></td> <td>{@link State#Uninitialized Uninitialized}</td> <td>{@link EventMask.Bit#Uninit Uninit}</td></tr>
* </table>
* </p>
*
@@ -188,6 +193,7 @@ import com.jogamp.opengl.util.TimeFrameI;
*/
public interface GLMediaPlayer extends TextureSequence {
public static final boolean DEBUG = Debug.debug("GLMediaPlayer");
+ public static final boolean DEBUG_AVSYNC = Debug.debug("GLMediaPlayer.AVSync");
public static final boolean DEBUG_NATIVE = Debug.debug("GLMediaPlayer.Native");
/** Default texture count, value {@value}. */
@@ -275,41 +281,112 @@ public interface GLMediaPlayer extends TextureSequence {
* </p>
*/
public interface GLMediaEventListener extends TexSeqEventListener<GLMediaPlayer> {
-
- /** State changed to {@link State#Initialized}. See <a href="#lifecycle">Lifecycle</a>.*/
- static final int EVENT_CHANGE_INIT = 1<<0;
- /** State changed to {@link State#Uninitialized}. See <a href="#lifecycle">Lifecycle</a>.*/
- static final int EVENT_CHANGE_UNINIT = 1<<1;
- /** State changed to {@link State#Playing}. See <a href="#lifecycle">Lifecycle</a>.*/
- static final int EVENT_CHANGE_PLAY = 1<<2;
- /** State changed to {@link State#Paused}. See <a href="#lifecycle">Lifecycle</a>.*/
- static final int EVENT_CHANGE_PAUSE = 1<<3;
- /** End of stream reached. See <a href="#lifecycle">Lifecycle</a>.*/
- static final int EVENT_CHANGE_EOS = 1<<4;
- /** An error occurred, e.g. during off-thread initialization. See {@link StreamException} and <a href="#lifecycle">Lifecycle</a>. */
- static final int EVENT_CHANGE_ERR = 1<<5;
-
- /** Stream video id change. */
- static final int EVENT_CHANGE_VID = 1<<16;
- /** Stream audio id change. */
- static final int EVENT_CHANGE_AID = 1<<17;
- /** TextureFrame size or vertical flip change. */
- static final int EVENT_CHANGE_SIZE = 1<<18;
- /** Stream fps change. */
- static final int EVENT_CHANGE_FPS = 1<<19;
- /** Stream bps change. */
- static final int EVENT_CHANGE_BPS = 1<<20;
- /** Stream length change. */
- static final int EVENT_CHANGE_LENGTH = 1<<21;
- /** Stream codec change. */
- static final int EVENT_CHANGE_CODEC = 1<<22;
-
/**
* @param mp the event source
* @param event_mask the changes attributes
* @param when system time in msec.
*/
- public void attributesChanged(GLMediaPlayer mp, int event_mask, long when);
+ public void attributesChanged(GLMediaPlayer mp, EventMask event_mask, long when);
+ }
+
+ /** Changes attributes event mask */
+ public static final class EventMask {
+
+ /** Attribute change bits */
+ public static enum Bit {
+ /** State changed to {@link State#Initialized}. See <a href="#lifecycle">Lifecycle</a>.*/
+ Init ( 1<<0 ),
+ /** State changed to {@link State#Uninitialized}. See <a href="#lifecycle">Lifecycle</a>.*/
+ Uninit ( 1<<1 ),
+ /** State changed to {@link State#Playing}. See <a href="#lifecycle">Lifecycle</a>.*/
+ Play ( 1<<2 ),
+ /** State changed to {@link State#Paused}. See <a href="#lifecycle">Lifecycle</a>.*/
+ Pause ( 1<<3 ),
+ /** End of stream reached. See <a href("#lifecycle">Lifecycle</a>.*/
+ EOS ( 1<<4 ),
+ /** An error occurred, e.g. during off-thread initialization. See {@link StreamException} and <a href("#lifecycle">Lifecycle</a>. */
+ Error ( 1<<5 ),
+
+ /** Stream video id change. */
+ VID ( 1<<16 ),
+ /** Stream audio id change. */
+ AID ( 1<<17 ),
+ /** TextureFrame size or vertical flip change. */
+ Size ( 1<<18 ),
+ /** Stream fps change. */
+ FPS ( 1<<19 ),
+ /** Stream bps change. */
+ BPS ( 1<<20 ),
+ /** Stream length change. */
+ Length ( 1<<21 ),
+ /** Stream codec change. */
+ Codec ( 1<<22 );
+
+ Bit(final int v) { value = v; }
+ public final int value;
+ }
+ public int mask;
+
+ public static int getBits(final List<Bit> v) {
+ int res = 0;
+ for(final Bit b : v) {
+ res |= b.value;
+ }
+ return res;
+ }
+ public EventMask(final List<Bit> v) {
+ mask = getBits(v);
+ }
+ public EventMask(final Bit v) {
+ mask = v.value;
+ }
+ public EventMask(final int v) {
+ mask = v;
+ }
+ public EventMask() {
+ mask = 0;
+ }
+
+ public boolean isSet(final Bit bit) { return bit.value == ( mask & bit.value ); }
+ public boolean isSet(final List<Bit> bits) { final int bits_i = getBits(bits); return bits_i == ( mask & bits_i ); }
+ public boolean isSet(final int bits) { return bits == ( mask & bits ); }
+ public boolean isZero() { return 0 == mask; }
+
+ public EventMask setBit(final Bit v) { mask |= v.value; return this; }
+ public EventMask setBits(final List<Bit> v) {
+ for(final Bit b : v) {
+ mask |= b.value;
+ }
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ int count = 0;
+ final StringBuilder out = new StringBuilder();
+ for (final Bit dt : Bit.values()) {
+ if( isSet(dt) ) {
+ if( 0 < count ) { out.append(", "); }
+ out.append(dt.name()); count++;
+ }
+ }
+ if( 0 == count ) {
+ out.append("None");
+ } else if( 1 < count ) {
+ out.insert(0, "[");
+ out.append("]");
+ }
+ return out.toString();
+ }
+
+ @Override
+ public boolean equals(final Object other) {
+ if (this == other) {
+ return true;
+ }
+ return (other instanceof EventMask) &&
+ this.mask == ((EventMask)other).mask;
+ }
}
/**
@@ -343,6 +420,20 @@ public interface GLMediaPlayer extends TextureSequence {
public void setTextureWrapST(int[] wrapST);
/**
+ * Limit maximum supported audio channels by user.
+ * <p>
+ * Must be set before {@link #playStream(Uri, int, int, int)}
+ * </p>
+ * <p>
+ * May be utilized to enforce 1 channel (mono) downsampling
+ * in combination with JOAL/OpenAL to experience spatial 3D position effects.
+ * </p>
+ * @param cc maximum supported audio channels, will be clipped [1..x], with x being the underlying audio subsystem's maximum
+ * @see #playStream(Uri, int, int, int)
+ */
+ public void setAudioChannelLimit(final int cc);
+
+ /**
* Issues asynchronous stream initialization.
* <p>
* <a href="#lifecycle">Lifecycle</a>: {@link State#Uninitialized} -> {@link State#Initialized}<sup><a href="#streamworker">1</a></sup> or {@link State#Uninitialized}
@@ -372,7 +463,7 @@ public interface GLMediaPlayer extends TextureSequence {
* @throws IllegalArgumentException if arguments are invalid
* @since 2.3.0
*/
- public void initStream(Uri streamLoc, int vid, int aid, int textureCount) throws IllegalStateException, IllegalArgumentException;
+ public void playStream(Uri streamLoc, int vid, int aid, int textureCount) throws IllegalStateException, IllegalArgumentException;
/**
* Returns the {@link StreamException} caught in the decoder thread, or <code>null</code> if none occured.
@@ -389,7 +480,7 @@ public interface GLMediaPlayer extends TextureSequence {
* <p>
* <a href="#lifecycle">Lifecycle</a>: {@link State#Initialized} -> {@link State#Paused} or {@link State#Initialized}
* </p>
- * Argument <code>gl</code> is ignored if video is muted, see {@link #initStream(Uri, int, int, int)}.
+ * Argument <code>gl</code> is ignored if video is muted, see {@link #playStream(Uri, int, int, int)}.
*
* @param gl current GL object. Maybe <code>null</code>, for audio only.
* @throws IllegalStateException if not invoked in {@link State#Initialized}.
@@ -401,7 +492,7 @@ public interface GLMediaPlayer extends TextureSequence {
/**
* If implementation uses a {@link AudioSink}, it's instance will be returned.
* <p>
- * The {@link AudioSink} instance is available after {@link #initStream(Uri, int, int, int)},
+ * The {@link AudioSink} instance is available after {@link #playStream(Uri, int, int, int)},
* if used by implementation.
* </p>
*/
@@ -416,6 +507,14 @@ public interface GLMediaPlayer extends TextureSequence {
public State destroy(GL gl);
/**
+ * Stops streaming and releases the GL, stream and other resources, but keeps {@link #attachObject(String, Object) attached user objects}.
+ * <p>
+ * <a href="#lifecycle">Lifecycle</a>: <code>ANY</code> -> {@link State#Uninitialized}
+ * </p>
+ */
+ public State stop();
+
+ /**
* Sets the playback speed.
* <p>
* To simplify test, play speed is <i>normalized</i>, i.e.
@@ -452,7 +551,7 @@ public interface GLMediaPlayer extends TextureSequence {
* <a href="#lifecycle">Lifecycle</a>: {@link State#Paused} -> {@link State#Playing}
* </p>
*/
- public State play();
+ public State resume();
/**
* Pauses the <i>StreamWorker</i> decoding thread.
@@ -460,7 +559,7 @@ public interface GLMediaPlayer extends TextureSequence {
* <a href="#lifecycle">Lifecycle</a>: {@link State#Playing} -> {@link State#Paused}
* </p>
* <p>
- * If a <i>new</i> frame is desired after the next {@link #play()} call,
+ * If a <i>new</i> frame is desired after the next {@link #resume()} call,
* e.g. to make a snapshot of a camera input stream,
* <code>flush</code> shall be set to <code>true</code>.
* </p>
@@ -498,13 +597,13 @@ public interface GLMediaPlayer extends TextureSequence {
public int getAID();
/**
- * @return the current decoded frame count since {@link #play()} and {@link #seek(int)}
+ * @return the current decoded frame count since {@link #resume()} and {@link #seek(int)}
* as increased by {@link #getNextTexture(GL)} or the decoding thread.
*/
public int getDecodedFrameCount();
/**
- * @return the current presented frame count since {@link #play()} and {@link #seek(int)}
+ * @return the current presented frame count since {@link #resume()} and {@link #seek(int)}
* as increased by {@link #getNextTexture(GL)} for new frames.
*/
public int getPresentedFrameCount();
@@ -547,7 +646,7 @@ public interface GLMediaPlayer extends TextureSequence {
public TextureSequence.TextureFrame getNextTexture(GL gl) throws IllegalStateException;
/**
- * Return the stream location, as set by {@link #initStream(Uri, int, int, int)}.
+ * Return the stream location, as set by {@link #playStream(Uri, int, int, int)}.
* @since 2.3.0
*/
public Uri getUri();
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java
index 532db3a7a..163e00c7a 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java
@@ -72,7 +72,7 @@ import com.jogamp.common.util.VersionNumber;
* was added since 2.2.1.
* </p>
*/
-public class ShaderCode {
+public final class ShaderCode {
public static final boolean DEBUG_CODE = Debug.isPropertyDefined("jogl.debug.GLSLCode", true);
/** Unique resource suffix for {@link GL2ES2#GL_VERTEX_SHADER} in source code: <code>{@value}</code> */
@@ -815,7 +815,7 @@ public class ShaderCode {
if(null!=shaderSource) {
if(DEBUG_CODE) {
System.err.println("ShaderCode.compile:");
- dumpShaderSource(System.err);
+ dumpSource(System.err);
}
valid=ShaderUtil.createAndCompileShader(gl, shader, shaderType,
shaderSource, verboseOut);
@@ -859,7 +859,7 @@ public class ShaderCode {
}
@Override
public String toString() {
- final StringBuilder buf = new StringBuilder("ShaderCode[id="+id+", type="+shaderTypeStr()+", valid="+valid+", shader: ");
+ final StringBuilder buf = new StringBuilder("ShaderCode[id="+id()+", type="+shaderTypeStr()+", valid="+valid+", "+shader.remaining()+"/"+shader.capacity()+" shader: ");
for(int i=0; i<shader.remaining(); i++) {
buf.append(" "+shader.get(i));
}
@@ -871,15 +871,20 @@ public class ShaderCode {
return buf.toString();
}
- public void dumpShaderSource(final PrintStream out) {
+ public void dumpSource(final PrintStream out) {
if(null==shaderSource) {
out.println("<no shader source>");
return;
}
final int sourceCount = shaderSource.length;
- final int shaderCount = (null!=shader)?shader.capacity():0;
+ final int shaderCount = shader.capacity();
+ out.println();
+ out.print("ShaderCode[id="+id()+", type="+shaderTypeStr()+", valid="+valid+", "+shader.remaining()+"/"+shaderCount+" shader: ");
+ if( 0 == shaderCount ) {
+ out.println("none]");
+ }
for(int i=0; i<shaderCount; i++) {
- out.println("");
+ out.println();
out.println("Shader #"+i+"/"+shaderCount+" name "+shader.get(i));
out.println("--------------------------------------------------------------");
if(i>=sourceCount) {
@@ -902,6 +907,7 @@ public class ShaderCode {
}
out.println("--------------------------------------------------------------");
}
+ out.println("]");
}
/**
@@ -922,7 +928,7 @@ public class ShaderCode {
if(null==shaderSource) {
throw new IllegalStateException("no shader source");
}
- final int shaderCount = (null!=shader)?shader.capacity():0;
+ final int shaderCount = shader.capacity();
if(0>shaderIdx || shaderIdx>=shaderCount) {
throw new IndexOutOfBoundsException("shaderIdx not within shader bounds [0.."+(shaderCount-1)+"]: "+shaderIdx);
}
@@ -1027,7 +1033,7 @@ public class ShaderCode {
if(null==shaderSource) {
throw new IllegalStateException("no shader source");
}
- final int shaderCount = (null!=shader)?shader.capacity():0;
+ final int shaderCount = shader.capacity();
if(0>shaderIdx || shaderIdx>=shaderCount) {
throw new IndexOutOfBoundsException("shaderIdx not within shader bounds [0.."+(shaderCount-1)+"]: "+shaderIdx);
}
@@ -1437,18 +1443,18 @@ public class ShaderCode {
// Internals only below this point
//
- protected CharSequence[][] shaderSource = null;
- protected Buffer shaderBinary = null;
- protected int shaderBinaryFormat = -1;
- protected IntBuffer shader = null;
- protected int shaderType = -1;
- protected int id = -1;
+ private CharSequence[][] shaderSource;
+ private Buffer shaderBinary;
+ private int shaderBinaryFormat = -1;
+ private final IntBuffer shader;
+ private int shaderType = -1;
+ private int id = -1;
- protected boolean valid=false;
+ private boolean valid=false;
private static synchronized int getNextID() {
return nextID++;
}
- protected static int nextID = 1;
+ private static int nextID = 1;
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java
index 63455ba51..fcc1cadd0 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java
@@ -36,7 +36,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.io.PrintStream;
-public class ShaderProgram {
+public final class ShaderProgram {
public ShaderProgram() {
id = getNextID();
@@ -103,6 +103,7 @@ public class ShaderProgram {
gl.glDeleteProgram(shaderProgram);
shaderProgram=0;
}
+ programLinked=false;
}
//
@@ -282,9 +283,13 @@ public class ShaderProgram {
sb = new StringBuilder();
}
sb.append("ShaderProgram[id=").append(id);
- sb.append(", linked="+programLinked+", inUse="+programInUse+", program: "+shaderProgram+",");
- for(final Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) {
- sb.append(Platform.getNewline()).append(" ").append(iter.next());
+ sb.append(", linked="+programLinked+", inUse="+programInUse+", program: "+shaderProgram+", "+allShaderCode.size()+" code: ");
+ if( 0 < allShaderCode.size() ) {
+ for(final Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) {
+ sb.append(Platform.getNewline()).append(" ").append(iter.next());
+ }
+ } else {
+ sb.append("none");
}
sb.append("]");
return sb;
@@ -304,7 +309,10 @@ public class ShaderProgram {
}
public synchronized void useProgram(final GL2ES2 gl, boolean on) {
- if(!programLinked) { throw new GLException("Program is not linked"); }
+ if(on && !programLinked) {
+ System.err.println("Error: ShaderProgram.useProgram(on "+on+") not linked: "+this);
+ throw new GLException("Program is not linked");
+ }
if(programInUse==on) { return; }
if( 0 == shaderProgram ) {
on = false;
@@ -316,6 +324,15 @@ public class ShaderProgram {
programInUse = false;
}
+ public void dumpSource(final PrintStream out) {
+ out.println();
+ out.println(toString());
+ for(final Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) {
+ iter.next().dumpSource(out);
+ }
+ out.println();
+ }
+
private boolean programLinked = false;
private boolean programInUse = false;
private int shaderProgram = 0; // non zero is valid!
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java
index e06f7be00..f13c2f743 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java
@@ -57,7 +57,7 @@ import com.jogamp.opengl.util.GLArrayDataEditable;
* and can be retrieved via {@link #getShaderState(GL)}.
* </p>
*/
-public class ShaderState {
+public final class ShaderState {
public static final boolean DEBUG;
static {
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java
index 165a5167a..5ad1d49d9 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java
@@ -42,7 +42,7 @@ import com.jogamp.opengl.*;
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.GLExtensions;
-public class ShaderUtil {
+public final class ShaderUtil {
public static String getShaderInfoLog(final GL _gl, final int shaderObj) {
final GL2ES2 gl = _gl.getGL2ES2();
final int[] infoLogLength=new int[1];
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java
index 43a6cfc58..e0f465da7 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -28,6 +28,7 @@
package com.jogamp.opengl.util.stereo;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Vec3f;
/**
* Constant single eye parameter of the viewer, relative to its {@link ViewerPose}.
@@ -36,8 +37,8 @@ public final class EyeParameter {
/** Eye number, <code>0</code> for the left eye and <code>1</code> for the right eye. */
public final int number;
- /** float[3] eye position vector used to define eye height in meter relative to <i>actor</i>. */
- public final float[] positionOffset;
+ /** eye position vector used to define eye height in meter relative to <i>actor</i>. */
+ public final Vec3f positionOffset;
/** Field of view in both directions, may not be centered, either {@link FovHVHalves#inTangents} or radians. */
public final FovHVHalves fovhv;
@@ -51,18 +52,18 @@ public final class EyeParameter {
/** Z-axis eye relief in meter. */
public final float eyeReliefZ;
- public EyeParameter(final int number, final float[] positionOffset, final FovHVHalves fovhv,
+ public EyeParameter(final int number, final Vec3f positionOffset, final FovHVHalves fovhv,
final float distNoseToPupil, final float verticalDelta, final float eyeRelief) {
this.number = number;
- this.positionOffset = new float[3];
- System.arraycopy(positionOffset, 0, this.positionOffset, 0, 3);
+ this.positionOffset = new Vec3f(positionOffset);
this.fovhv = fovhv;
this.distNoseToPupilX = distNoseToPupil;
this.distMiddleToPupilY = verticalDelta;
this.eyeReliefZ = eyeRelief;
}
+ @Override
public final String toString() {
- return "EyeParam[num "+number+", posOff["+positionOffset[0]+", "+positionOffset[1]+", "+positionOffset[2]+"], "+fovhv+
- ", distPupil[noseX "+distNoseToPupilX+", middleY "+distMiddleToPupilY+", reliefZ "+eyeReliefZ+"]]";
+ return "EyeParam[num "+number+", posOff["+positionOffset+"], "+fovhv+
+ ", distPupil[noseX "+distNoseToPupilX+", middleY "+distMiddleToPupilY+", reliefZ "+eyeReliefZ+"]]";
}
} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java
index b795927cd..6294adee1 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2015 JogAmp Community. All rights reserved.
+ * Copyright 2015-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -27,6 +27,7 @@
*/
package com.jogamp.opengl.util.stereo;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.geom.Frustum;
/**
@@ -38,13 +39,15 @@ public final class LocationSensorParameter {
/** The {@link Frustum}'s {@link Frustum.FovDesc} description of the location sensor. */
public final Frustum.FovDesc frustumDesc;
/** The {@link Frustum}'s float[16] projection matrix of the location sensor. */
- public final float[] frustumProjMat;
+ public final Matrix4f frustumProjMat;
public LocationSensorParameter(final Frustum.FovDesc fovDesc) {
this.frustumDesc = fovDesc;
this.frustum = new Frustum();
- this.frustumProjMat = frustum.updateByFovDesc(new float[16], 0, true, fovDesc);
+ this.frustumProjMat = frustum.updateByFovDesc(new Matrix4f(), fovDesc);
}
+
+ @Override
public final String toString() {
return "LocationSensor["+frustumDesc+"]";
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
index b6112650a..85e752302 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -33,6 +33,7 @@ import com.jogamp.nativewindow.util.PointImmutable;
import jogamp.opengl.Debug;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Vec3f;
/**
* Interface describing a native stereoscopic device
@@ -94,7 +95,7 @@ public interface StereoDevice {
public int getRequiredRotation();
/**
- * Return the device default eye position offset for {@link #createRenderer(int, int, float[], FovHVHalves[], float)}.
+ * Return the device default eye position offset for {@link #createRenderer(int, int, Vec3f, FovHVHalves[], float)}.
* <p>
* Result is an array of float values for
* <ul>
@@ -105,7 +106,7 @@ public interface StereoDevice {
* </p>
* @return
*/
- public float[] getDefaultEyePositionOffset();
+ public Vec3f getDefaultEyePositionOffset();
/**
* Returns the device default {@link FovHVHalves} for all supported eyes
@@ -198,7 +199,7 @@ public interface StereoDevice {
* Returns the supported distortion compensation of the {@link StereoDeviceRenderer},
* e.g. {@link StereoDeviceRenderer#DISTORTION_BARREL}, {@link StereoDeviceRenderer#DISTORTION_CHROMATIC}, etc.
* @see StereoDeviceRenderer#getDistortionBits()
- * @see #createRenderer(int, int, float[], FovHVHalves[], float, int)
+ * @see #createRenderer(int, int, Vec3f, FovHVHalves[], float, int)
* @see #getRecommendedDistortionBits()
* @see #getMinimumDistortionBits()
*/
@@ -212,7 +213,7 @@ public interface StereoDevice {
* User shall use the recommended distortion compensation to achieve a distortion free view.
* </p>
* @see StereoDeviceRenderer#getDistortionBits()
- * @see #createRenderer(int, int, float[], FovHVHalves[], float, int)
+ * @see #createRenderer(int, int, Vec3f, FovHVHalves[], float, int)
* @see #getSupportedDistortionBits()
* @see #getMinimumDistortionBits()
*/
@@ -227,7 +228,7 @@ public interface StereoDevice {
* @see #getSupportedDistortionBits()
* @see #getRecommendedDistortionBits()
* @see StereoDeviceRenderer#getDistortionBits()
- * @see #createRenderer(int, int, float[], FovHVHalves[], float, int)
+ * @see #createRenderer(int, int, Vec3f, FovHVHalves[], float, int)
*/
public int getMinimumDistortionBits();
@@ -245,6 +246,6 @@ public interface StereoDevice {
* @return
*/
public StereoDeviceRenderer createRenderer(final int distortionBits,
- final int textureCount, final float[] eyePositionOffset,
+ final int textureCount, final Vec3f eyePositionOffset,
final FovHVHalves[] eyeFov, final float pixelsPerDisplayPixel, final int textureUnit);
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java
index b6f76a343..63cb3e1e7 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -27,9 +27,9 @@
*/
package com.jogamp.opengl.util.stereo;
-import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.Quaternion;
-import com.jogamp.opengl.math.VectorUtil;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.util.CustomGLEventListener;
import com.jogamp.opengl.util.stereo.StereoDeviceRenderer.Eye;
@@ -137,24 +137,24 @@ public class StereoUtil {
* @param eye
* @param zNear frustum near value
* @param zFar frustum far value
- * @param mat4Projection float[16] projection matrix result
- * @param mat4Modelview float[16] modelview matrix result
+ * @param mat4Projection projection matrix result
+ * @param mat4Modelview modelview matrix result
*/
public static void getSBSUpstreamPMV(final ViewerPose viewerPose, final Eye eye,
final float zNear, final float zFar,
- final float[] mat4Projection, final float[] mat4Modelview) {
- final float[] mat4Tmp1 = new float[16];
- final float[] mat4Tmp2 = new float[16];
- final float[] vec3Tmp1 = new float[3];
- final float[] vec3Tmp2 = new float[3];
- final float[] vec3Tmp3 = new float[3];
+ final Matrix4f mat4Projection, final Matrix4f mat4Modelview) {
+ final Matrix4f mat4Tmp1 = new Matrix4f();
+ final Matrix4f mat4Tmp2 = new Matrix4f();
+ final Vec3f vec3Tmp1 = new Vec3f();
+ final Vec3f vec3Tmp2 = new Vec3f();
+ final Vec3f vec3Tmp3 = new Vec3f();
final EyeParameter eyeParam = eye.getEyeParameter();
//
// Projection
//
- FloatUtil.makePerspective(mat4Projection, 0, true, eyeParam.fovhv, zNear, zFar);
+ mat4Projection.setToPerspective(eyeParam.fovhv, zNear, zFar);
//
// Modelview
@@ -162,21 +162,17 @@ public class StereoUtil {
final Quaternion rollPitchYaw = new Quaternion();
// private final float eyeYaw = FloatUtil.PI; // 180 degrees in radians
// rollPitchYaw.rotateByAngleY(eyeYaw);
- final float[] shiftedEyePos = rollPitchYaw.rotateVector(vec3Tmp1, 0, viewerPose.position, 0);
- VectorUtil.addVec3(shiftedEyePos, shiftedEyePos, eyeParam.positionOffset);
+ final Vec3f shiftedEyePos = rollPitchYaw.rotateVector(viewerPose.position, vec3Tmp1).add(eyeParam.positionOffset);
rollPitchYaw.mult(viewerPose.orientation);
- final float[] up = rollPitchYaw.rotateVector(vec3Tmp2, 0, VectorUtil.VEC3_UNIT_Y, 0);
- final float[] forward = rollPitchYaw.rotateVector(vec3Tmp3, 0, VectorUtil.VEC3_UNIT_Z_NEG, 0);
- final float[] center = VectorUtil.addVec3(forward, shiftedEyePos, forward);
+ final Vec3f up = rollPitchYaw.rotateVector(Vec3f.UNIT_Y, vec3Tmp2);
+ final Vec3f forward = rollPitchYaw.rotateVector(Vec3f.UNIT_Z_NEG, vec3Tmp3); // -> center
+ final Vec3f center = forward.add(shiftedEyePos);
- final float[] mLookAt = FloatUtil.makeLookAt(mat4Tmp2, 0, shiftedEyePos, 0, center, 0, up, 0, mat4Tmp1);
- final float[] mViewAdjust = FloatUtil.makeTranslation(mat4Modelview, true,
- eyeParam.distNoseToPupilX,
- eyeParam.distMiddleToPupilY,
- eyeParam.eyeReliefZ);
-
- /* mat4Modelview = */ FloatUtil.multMatrix(mViewAdjust, mLookAt);
+ final Matrix4f mLookAt = mat4Tmp2.setToLookAt(shiftedEyePos, center, up, mat4Tmp1);
+ mat4Modelview.mul( mat4Tmp1.setToTranslation( eyeParam.distNoseToPupilX,
+ eyeParam.distMiddleToPupilY,
+ eyeParam.eyeReliefZ ), mLookAt);
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java
index 10ee4c994..5d2cf925c 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -28,13 +28,14 @@
package com.jogamp.opengl.util.stereo;
import com.jogamp.opengl.math.Quaternion;
+import com.jogamp.opengl.math.Vec3f;
/**
* {@link #position} and {@link #orientation} of viewer.
*/
public final class ViewerPose {
/**
- * float[3] position of viewer in meter.
+ * position of viewer in meter.
* <p>
* Apply the following to resolve the actual eye position:
* <ul>
@@ -43,13 +44,13 @@ public final class ViewerPose {
* </ul>
* </p>
*/
- public final float[] position;
+ public final Vec3f position;
/** Orientation of viewer. */
public final Quaternion orientation;
public ViewerPose() {
- this.position = new float[3];
+ this.position = new Vec3f();
this.orientation = new Quaternion();
}
public ViewerPose(final float[] position, final Quaternion orientation) {
@@ -64,11 +65,14 @@ public final class ViewerPose {
}
/** Set position and orientation of this instance. */
public final void setPosition(final float posX, final float posY, final float posZ) {
- position[0] = posX;
- position[1] = posY;
- position[2] = posZ;
+ position.set( posX, posY, posZ );
}
+ /** Set position and orientation of this instance. */
+ public final void setPosition(final Vec3f pos) {
+ position.set( pos );
+ }
+ @Override
public final String toString() {
- return "ViewerPose[pos["+position[0]+", "+position[1]+", "+position[2]+"], "+orientation+"]";
+ return "ViewerPose[pos["+position+"], "+orientation+"]";
}
} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java
index 957758e78..0cdef8770 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java
@@ -35,6 +35,7 @@ import com.jogamp.nativewindow.util.Dimension;
import com.jogamp.nativewindow.util.DimensionImmutable;
import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.util.stereo.EyeParameter;
import com.jogamp.opengl.util.stereo.StereoDevice;
import com.jogamp.opengl.util.stereo.StereoDeviceConfig;
@@ -53,7 +54,7 @@ public class GenericStereoDeviceFactory extends StereoDeviceFactory {
*/
public static GenericStereoDeviceConfig createMono(final String name,
final DimensionImmutable surfaceSizeInPixel, final float[] screenSizeInMeters,
- final float[] defaultEyePositionOffset) {
+ final Vec3f defaultEyePositionOffset) {
final float pupilCenterFromScreenTopInMeters = screenSizeInMeters[1] / 2f;
final float d2r = FloatUtil.PI / 180.0f;
return new GenericStereoDeviceConfig(
@@ -90,7 +91,7 @@ public class GenericStereoDeviceFactory extends StereoDeviceFactory {
public static GenericStereoDeviceConfig createStereoSBS(final String name,
final DimensionImmutable surfaceSizeInPixel, final float[] screenSizeInMeters,
final float interpupillaryDistanceInMeters, final float fovy,
- final float[] defaultEyePositionOffset) {
+ final Vec3f defaultEyePositionOffset) {
final float pupilCenterFromScreenTopInMeters = screenSizeInMeters[1] / 2f;
final float d2r = FloatUtil.PI / 180.0f;
@@ -138,7 +139,7 @@ public class GenericStereoDeviceFactory extends StereoDeviceFactory {
final DimensionImmutable surfaceSizeInPixel, final float[] screenSizeInMeters,
final float interpupillaryDistanceInMeters, final float fovy,
final DimensionImmutable eyeTextureSize,
- final float[] defaultEyePositionOffset) {
+ final Vec3f defaultEyePositionOffset) {
DistortionMesh.Producer lenseDistMeshProduce = null;
try {
lenseDistMeshProduce =
diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/ImageSequence.java b/src/jogl/classes/com/jogamp/opengl/util/texture/ImageSequence.java
index e485e5452..2da2dcbfc 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/texture/ImageSequence.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/texture/ImageSequence.java
@@ -153,17 +153,21 @@ public class ImageSequence implements TextureSequence {
private String textureLookupFunctionName = "myTexture2D";
@Override
- public String getTextureLookupFunctionName(final String desiredFuncName) throws IllegalStateException {
+ public String setTextureLookupFunctionName(final String texLookupFuncName) throws IllegalStateException {
if(useBuildInTexLookup) {
- return "texture2D";
- }
- if(null != desiredFuncName && desiredFuncName.length()>0) {
- textureLookupFunctionName = desiredFuncName;
+ textureLookupFunctionName = "texture2D";
+ } else if(null != texLookupFuncName && texLookupFuncName.length()>0) {
+ textureLookupFunctionName = texLookupFuncName;
}
return textureLookupFunctionName;
}
@Override
+ public String getTextureLookupFunctionName() throws IllegalStateException {
+ return textureLookupFunctionName;
+ }
+
+ @Override
public String getTextureLookupFragmentShaderImpl() throws IllegalStateException {
if(useBuildInTexLookup) {
return "";
diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureSequence.java b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureSequence.java
index 7147fd61b..1e308b215 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureSequence.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureSequence.java
@@ -32,7 +32,7 @@ import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLRunnable;
import com.jogamp.opengl.GLEventListener;
-import com.jogamp.opengl.util.TimeFrameI;
+import com.jogamp.common.av.TimeFrameI;
/**
* Protocol for texture sequences, like animations, movies, etc.
@@ -226,15 +226,28 @@ public interface TextureSequence {
public String getTextureSampler2DType() throws IllegalStateException ;
/**
- * @param desiredFuncName desired lookup function name. If <code>null</code> or ignored by the implementation,
- * a build-in name is returned.
- * @return the final lookup function name
+ * Set the desired shader code's texture lookup function name.
*
- * @see {@link #getTextureLookupFragmentShaderImpl()}
+ * @param texLookupFuncName desired lookup function name. If <code>null</code> or ignored by the implementation,
+ * a build-in name is returned.
+ * @return the chosen lookup function name
*
* @throws IllegalStateException if instance is not initialized
+ * @see #getTextureLookupFunctionName()
+ * @see #getTextureFragmentShaderHashCode()
+ * @see #getTextureLookupFragmentShaderImpl()
*/
- public String getTextureLookupFunctionName(String desiredFuncName) throws IllegalStateException ;
+ public String setTextureLookupFunctionName(String texLookupFuncName) throws IllegalStateException ;
+
+ /**
+ * Returns the chosen lookup function name, which can be set via {@link #setTextureLookupFunctionName(String)}.
+ *
+ * @throws IllegalStateException if instance is not initialized
+ * @see #setTextureLookupFunctionName(String)
+ * @see #getTextureFragmentShaderHashCode()
+ * @see #getTextureLookupFragmentShaderImpl()
+ */
+ public String getTextureLookupFunctionName() throws IllegalStateException ;
/**
* Returns the complete texture2D lookup function code of type
@@ -245,36 +258,49 @@ public interface TextureSequence {
* }
* </pre>
* <p>
- * <i>funcName</i> can be negotiated and queried via {@link #getTextureLookupFunctionName(String)}.
+ * <i>funcName</i> is set via {@link #setTextureLookupFunctionName(String)}
+ * and queried via {@link #getTextureLookupFunctionName()}.
+ * </p>
+ * <p>
+ * User shall call {@link #setTextureLookupFunctionName(String)} first if intended.
* </p>
+ * <p>
* Note: This function may return an empty string in case a build-in lookup
* function is being chosen. If the implementation desires so,
- * {@link #getTextureLookupFunctionName(String)} will ignore the desired function name
+ * {@link #getTextureLookupFunctionName()} will ignore the desired function name
* and returns the build-in lookup function name.
* </p>
- * @see #getTextureLookupFunctionName(String)
- * @see #getTextureSampler2DType()
- *
* @throws IllegalStateException if instance is not initialized
+ * @see #getTextureLookupFunctionName()
+ * @see #setTextureLookupFunctionName(String)
+ * @see #getTextureFragmentShaderHashCode()
+ * @see #getTextureSampler2DType()
*/
public String getTextureLookupFragmentShaderImpl() throws IllegalStateException;
/**
* Returns the hash code of the strings:
* <ul>
+ * <li>{@link #getTextureLookupFunctionName()}</li>
* <li>{@link #getTextureLookupFragmentShaderImpl()}</li>
* <li>{@link #getTextureSampler2DType()}</li>
* </ul>
* <p>
+ * User shall call {@link #setTextureLookupFunctionName(String)} first if intended.
+ * </p>
+ * <p>
* Returns zero if {@link #isTextureAvailable() texture is not available}.
* </p>
* The returned hash code allows selection of a matching shader program for this {@link TextureSequence} instance.
* <p>
* </p>
* <p>
- * Implementation shall cache the resulting hash code,
+ * Implementation caches the resulting hash code,
* which must be reset to zero if {@link #isTextureAvailable() texture is not available}.
* </p>
+ * @see #setTextureLookupFunctionName(String)
+ * @see #getTextureLookupFunctionName()
+ * @see #getTextureLookupFragmentShaderImpl()
*/
public int getTextureFragmentShaderHashCode();
}