package org.jzy3d.plot3d.primitives.vbo.drawable;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.apache.log4j.Logger;
import org.jzy3d.colors.Color;
import org.jzy3d.io.IGLLoader;
import org.jzy3d.maths.BoundingBox3d;
import org.jzy3d.maths.Coord3d;
import org.jzy3d.plot3d.primitives.AbstractDrawable;
import org.jzy3d.plot3d.primitives.IGLBindedResource;
import org.jzy3d.plot3d.primitives.vbo.buffers.FloatVBO;
import org.jzy3d.plot3d.rendering.canvas.Quality;
import org.jzy3d.plot3d.rendering.compat.GLES2CompatUtils;
import org.jzy3d.plot3d.rendering.view.Camera;
import org.jzy3d.plot3d.transform.Rotate;
import org.jzy3d.plot3d.transform.Rotator;
import org.jzy3d.plot3d.transform.Transform;
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GL2ES1;
import com.jogamp.opengl.GL2GL3;
import com.jogamp.opengl.fixedfunc.GLPointerFunc;
import com.jogamp.opengl.glu.GLU;
/**
* A {@link DrawableVBO} is able to efficiently draw a large collection of
* geometries.
*
* The user must provide a loader that will be later called when the GL context
* requires loading the VBO data in GPU memory.
*
* The loader might freely make settings on the drawable as it is called with a
* reference to the {@link DrawableVBO} is will be loading data into.
*
* One can separate data and appearance by setting geometry settings out of
* loading process.
*
* DrawableVBO shape1 = new DrawableVBO(new MemoryVBOLoader(getScatter(size)));
* shape1.setGeometry(GL.GL_POINTS); shape1.setColor(Color.WHITE);
*
* @author Martin Pernollet
*/
public class DrawableVBO extends AbstractDrawable implements IGLBindedResource {
protected int geometry = GL.GL_TRIANGLES;
protected float width = 1;
protected Quality quality = Quality.Nicest;
protected int colorChannelNumber = 3;
public DrawableVBO(IGLLoader loader) {
this.loader = loader;
}
@Override
public boolean hasMountedOnce() {
return hasMountedOnce;
}
@Override
public void mount(GL gl) {
try {
loader.load(gl, this);
hasMountedOnce = true;
} catch (Exception e) {
e.printStackTrace();
Logger.getLogger(DrawableVBO.class).error(e, e);
}
}
// element array buffer is an index:
// @see
// http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-9-vbo-indexing/
@Override
public void draw(GL gl, GLU glu, Camera cam) {
if (hasMountedOnce) {
doTransform(gl, glu, cam);
configure(gl);
doDrawElements(gl);
doDrawBounds(gl, glu, cam);
}
}
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public Quality getQuality() {
return quality;
}
public void setQuality(Quality quality) {
this.quality = quality;
}
protected void doDrawElements(GL gl) {
if (gl.isGL2()) {
doBindGL2(gl);
pointers(gl);
color(gl);
enable(gl);
applyWidth(gl);
applyQuality(gl);
applyVertices(gl);
disable(gl);
disableColor(gl);
} else {
GLES2CompatUtils.glBindBuffer(GL.GL_ARRAY_BUFFER, arrayName[0]);
GLES2CompatUtils.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, elementName[0]);
GLES2CompatUtils.glVertexPointer(dimensions, GL.GL_FLOAT, byteOffset, pointer);
GLES2CompatUtils.glNormalPointer(GL.GL_FLOAT, byteOffset, normalOffset);
GLES2CompatUtils.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
GLES2CompatUtils.glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
GLES2CompatUtils.glDrawElements(getGeometry(), size, GL.GL_UNSIGNED_INT, pointer);
GLES2CompatUtils.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, elementName[0]);
GLES2CompatUtils.glBindBuffer(GL.GL_ARRAY_BUFFER, arrayName[0]);
GLES2CompatUtils.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
GLES2CompatUtils.glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
}
}
private void disableColor(GL gl) {
if (hasColorBuffer) {
gl.getGL2().glDisableClientState(GL2.GL_COLOR_ARRAY);
}
}
private void pointers(GL gl) {
gl.getGL2().glVertexPointer(dimensions, GL.GL_FLOAT, byteOffset, pointer);
gl.getGL2().glNormalPointer(GL.GL_FLOAT, byteOffset, normalOffset);
}
private void color(GL gl) {
if (hasColorBuffer) {
// int bo = 6 * Buffers.SIZEOF_FLOAT;
int p = 3 * Buffers.SIZEOF_FLOAT;
gl.getGL2().glEnableClientState(GL2.GL_COLOR_ARRAY);
gl.getGL2().glColorPointer(colorChannelNumber, GL.GL_FLOAT, byteOffset, p);
}
}
private void enable(GL gl) {
gl.getGL2().glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
gl.getGL2().glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
}
private void disable(GL gl) {
gl.getGL2().glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
gl.getGL2().glDisableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
}
private void applyVertices(GL gl) {
gl.getGL2().glDrawElements(getGeometry(), size, GL.GL_UNSIGNED_INT, pointer);
doBindGL2(gl);
}
private void applyWidth(GL gl) {
if(geometry==GL.GL_POINTS){
gl.getGL2().glPointSize(width);
} else if(geometry==GL.GL_LINES){
gl.getGL2().glLineWidth(width);
}
}
private void applyQuality(GL gl) {
if (quality.isSmoothPolygon()) {
gl.glEnable(GL2GL3.GL_POLYGON_SMOOTH);
gl.glHint(GL2GL3.GL_POLYGON_SMOOTH_HINT, GL.GL_NICEST);
} else
gl.glDisable(GL2GL3.GL_POLYGON_SMOOTH);
if (quality.isSmoothLine()) {
gl.glEnable(GL.GL_LINE_SMOOTH);
gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST);
} else
gl.glDisable(GL.GL_LINE_SMOOTH);
if (quality.isSmoothPoint()) {
gl.glEnable(GL2ES1.GL_POINT_SMOOTH);
gl.glHint(GL2ES1.GL_POINT_SMOOTH_HINT, GL.GL_NICEST);
// gl.glDisable(GL2.GL_BLEND);
// gl.glHint(GL2.GL_POINT_SMOOTH_HINT, GL2.GL_NICEST);
} else
gl.glDisable(GL2ES1.GL_POINT_SMOOTH);
}
protected void doBindGL2(GL gl) {
gl.getGL2().glBindBuffer(GL.GL_ARRAY_BUFFER, arrayName[0]);
gl.getGL2().glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, elementName[0]);
}
/**
* Returns a {@link Rotator} that can let the VBO turn around Z axis centered at X=0,Y=0.
* Must be started by {@link Rotator.start()} if not started explicitely.
*/
public Rotator rotator(boolean start) {
final Rotate r = new Rotate(25, new Coord3d(0, 0, 1));
Transform t = new Transform();
t.add(r);
setTransformBefore(t);
Rotator rotator = new Rotator(10, r);
if(start)
rotator.start();
return rotator;
}
public Rotator rotator() {
return rotator(false);
}
/*
* An OBJ file appears to be really really slow to render without a
* FRONT_AND_BACK spec, probably because such a big polygon set has huge
* cost to have culling status computed (culling enabled by depth peeling).
*/
protected void configure(GL gl) {
// gl.glPolygonMode(GL2.GL_FRONT, GL2.GL_FILL);
// gl.glPolygonMode(GL2.GL_FRONT, GL2.GL_LINE);
// gl.glColor4f(1f,0f,1f,0.6f);
// gl.glLineWidth(0.00001f);
if (gl.isGL2()) {
gl.getGL2().glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL);
} else {
GLES2CompatUtils.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL);
}
call(gl, color);
}
boolean hasColorBuffer = false;
public boolean isHasColorBuffer() {
return hasColorBuffer;
}
public void setHasColorBuffer(boolean hasColorBuffer) {
this.hasColorBuffer = hasColorBuffer;
}
public int getGeometry() {
return geometry;
}
/**
* Set geometry, use: GL.GL_TRIANGLES (default) ...
*
* @param geometry
*/
public void setGeometry(int geometry) {
this.geometry = geometry;
}
@Override
public void applyGeometryTransform(Transform transform) {
/*
* Coord3d c = transform.compute(new Coord3d(x,y, z)); x = c.x; y = c.y;
* z = c.z;
*/
Logger.getLogger(DrawableVBO.class).warn("not implemented");
}
@Override
public void updateBounds() { // requires smart reload
Logger.getLogger(DrawableVBO.class).warn("not implemented");
}
/** To be called by the VBOBuilder */
public void setData(GL gl, FloatVBO vbo) {
setData(gl.getGL2(), vbo.getIndices(), vbo.getVertices(), vbo.getBounds(), 0);
}
public void setData(GL gl, IntBuffer indices, FloatBuffer vertices, BoundingBox3d bounds) {
setData(gl.getGL2(), indices, vertices, bounds, 0);
}
public void setData(GL2 gl, IntBuffer indices, FloatBuffer vertices, BoundingBox3d bounds, int pointer) {
doConfigure(pointer, indices.capacity());
doLoadArrayFloatBuffer(gl, vertices);
doLoadElementIntBuffer(gl, indices);
doSetBoundingBox(bounds);
}
public void doConfigure(int pointer, int size) {
int dimensions = 3;
int byteOffset = (dimensions * 2) * Buffers.SIZEOF_FLOAT; // (coord+normal)
int normalOffset = dimensions * Buffers.SIZEOF_FLOAT;
doConfigure(pointer, size, byteOffset, normalOffset, dimensions);
}
public void doConfigure(int pointer, int size, int byteOffset, int normalOffset, int dimensions) {
this.byteOffset = byteOffset;
this.normalOffset = normalOffset;
this.dimensions = dimensions;
this.size = size;
this.pointer = pointer;
}
public void doLoadArrayFloatBuffer(GL gl, FloatBuffer vertices) {
doLoadArrayFloatBuffer(gl, vertices.capacity() * Buffers.SIZEOF_FLOAT, vertices);
}
public void doLoadArrayFloatBuffer(GL gl, int vertexSize, FloatBuffer vertices) {
gl.glGenBuffers(1, arrayName, 0);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, arrayName[0]);
gl.glBufferData(GL.GL_ARRAY_BUFFER, vertexSize, vertices, GL.GL_STATIC_DRAW);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, pointer);
}
public void doLoadElementIntBuffer(GL gl, IntBuffer indices) {
doLoadElementIntBuffer(gl, indices.capacity() * Buffers.SIZEOF_INT, indices);
}
public void doLoadElementIntBuffer(GL gl, int indexSize, IntBuffer indices) {
gl.glGenBuffers(1, elementName, 0);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, elementName[0]);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, indexSize, indices, GL.GL_STATIC_DRAW);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, pointer);
}
public void doSetBoundingBox(BoundingBox3d bounds) {
bbox = bounds;
}
/* */
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
protected IGLLoader loader;
protected int byteOffset;
protected int normalOffset;
protected int dimensions;
protected int size;
protected int pointer;
protected int arrayName[] = new int[1];
protected int elementName[] = new int[1];
protected boolean hasMountedOnce = false;
protected Color color = new Color(1f, 0f, 1f, 0.75f);
}
Ads help maintain this website.