aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java')
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java284
1 files changed, 260 insertions, 24 deletions
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 faaf72a99..a9e258f36 100644
--- a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
@@ -27,13 +27,32 @@
*/
package com.jogamp.graph.curve.opengl;
+import java.nio.FloatBuffer;
+
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLException;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+import com.jogamp.opengl.util.glsl.ShaderCode;
+import com.jogamp.opengl.util.glsl.ShaderState;
+import com.jogamp.opengl.util.PMVMatrix;
import com.jogamp.graph.curve.OutlineShape;
import com.jogamp.graph.curve.Region;
-public abstract class RegionRenderer extends Renderer {
+/**
+ * OpenGL {@link Region} renderer
+ * <p>
+ * All OpenGL related operations regarding {@link Region}s
+ * are passed through an instance of this class.
+ * </p>
+ */
+public abstract class RegionRenderer {
+ protected static final boolean DEBUG = Region.DEBUG;
+ protected static final boolean DEBUG_INSTANCE = Region.DEBUG_INSTANCE;
+
+ public static boolean isWeightValid(float v) {
+ return 0.0f <= v && v <= 1.9f ;
+ }
/**
* Create a Hardware accelerated Region Renderer.
@@ -45,39 +64,256 @@ public abstract class RegionRenderer extends Renderer {
return new jogamp.graph.curve.opengl.RegionRendererImpl01(rs, renderModes);
}
+ protected final int renderModes;
+ protected final RenderState rs;
+
+ protected int vp_width;
+ protected int vp_height;
+ protected boolean initialized;
+ private boolean vboSupported = false;
+
+ public final boolean isInitialized() { return initialized; }
+
+ public final int getWidth() { return vp_width; }
+ public final int getHeight() { return vp_height; }
+
+ public final float getWeight() { return rs.getWeight().floatValue(); }
+ public final float getAlpha() { return rs.getAlpha().floatValue(); }
+ public final PMVMatrix getMatrix() { return rs.pmvMatrix(); }
+
+ /**
+ * Implementation shall load, compile and link the shader program and leave it active.
+ * @param gl referencing the current GLContext to which the ShaderState is bound to
+ * @return
+ */
+ protected abstract boolean initImpl(GL2ES2 gl);
+
+ /** Delete and clean the associated OGL objects */
+ protected abstract void destroyImpl(GL2ES2 gl);
+
+ //////////////////////////////////////
+
+ /**
+ * @param rs the used {@link RenderState}
+ * @param renderModes bit-field of modes
+ */
protected RegionRenderer(RenderState rs, int renderModes) {
- super(rs, renderModes);
+ this.rs = rs;
+ this.renderModes = renderModes;
+ }
+
+ public final int getRenderModes() {
+ return renderModes;
}
+ public final boolean usesVariableCurveWeight() { return Region.isNonUniformWeight(renderModes); }
- /** Render an {@link OutlineShape} in 3D space at the position provided
- * the triangles of the shapes will be generated, if not yet generated
- * @param region the OutlineShape to Render.
- * @param texWidth desired texture width for multipass-rendering.
- * The actual used texture-width is written back when mp rendering is enabled, otherwise the store is untouched.
- * @throws Exception if HwRegionRenderer not initialized
+ /**
+ * @return true if Region's renderModes contains all bits as this Renderer's renderModes
+ * except {@link Region#VARIABLE_CURVE_WEIGHT_BIT}, otherwise false.
*/
- public final void draw(GL2ES2 gl, Region region, int[/*1*/] texWidth) {
- if(!isInitialized()) {
- throw new GLException("RegionRenderer: not initialized!");
- }
- if( !areRenderModesCompatible(region) ) {
- throw new GLException("Incompatible render modes, : region modes "+region.getRenderModes()+
- " doesn't contain renderer modes "+this.getRenderModes());
- }
- drawImpl(gl, region, texWidth);
+ public final boolean areRenderModesCompatible(final Region region) {
+ final int cleanRenderModes = getRenderModes() & ( Region.VARIABLE_CURVE_WEIGHT_BIT );
+ return cleanRenderModes == ( region.getRenderModes() & cleanRenderModes );
}
+ public final boolean isVBOSupported() { return vboSupported; }
+
/**
- * Usually just dispatched the draw call to the Region's draw implementation,
- * e.g. {@link com.jogamp.graph.curve.opengl.GLRegion#draw(GL2ES2, RenderState, int, int, int[]) GLRegion#draw(GL2ES2, RenderState, int, int, int[])}.
+ * Initialize shader and bindings for GPU based rendering bound to the given GL object's GLContext
+ * if not initialized yet.
+ * <p>Leaves the renderer enabled, ie ShaderState.</p>
+ * <p>Shall be called by a {@code draw()} method, e.g. {@link RegionRenderer#draw(GL2ES2, Region, int)}</p>
+ *
+ * @param gl referencing the current GLContext to which the ShaderState is bound to
+ * @throws GLException if initialization failed
*/
- protected abstract void drawImpl(GL2ES2 gl, Region region, int[] texWidth);
+ public final void init(GL2ES2 gl) throws GLException {
+ if(initialized){
+ return;
+ }
+ vboSupported = gl.isFunctionAvailable("glGenBuffers") &&
+ gl.isFunctionAvailable("glBindBuffer") &&
+ gl.isFunctionAvailable("glBufferData") &&
+ gl.isFunctionAvailable("glDrawElements") &&
+ gl.isFunctionAvailable("glVertexAttribPointer") &&
+ gl.isFunctionAvailable("glDeleteBuffers");
+
+ if(DEBUG) {
+ System.err.println("TextRendererImpl01: VBO Supported = " + isVBOSupported());
+ }
+
+ if(!vboSupported){
+ throw new GLException("VBO not supported");
+ }
+
+ rs.attachTo(gl);
+
+ gl.glEnable(GL2ES2.GL_BLEND);
+ gl.glBlendFunc(GL2ES2.GL_SRC_ALPHA, GL2ES2.GL_ONE_MINUS_SRC_ALPHA); // FIXME: alpha blending stage ?
+
+ initialized = initImpl(gl);
+ if(!initialized) {
+ throw new GLException("Shader initialization failed");
+ }
- @Override
- protected void destroyImpl(GL2ES2 gl) {
- // nop
+ if(!rs.getShaderState().uniform(gl, rs.getPMVMatrix())) {
+ throw new GLException("Error setting PMVMatrix in shader: "+rs.getShaderState());
+ }
+
+ if( Region.isNonUniformWeight( getRenderModes() ) ) {
+ if(!rs.getShaderState().uniform(gl, rs.getWeight())) {
+ throw new GLException("Error setting weight in shader: "+rs.getShaderState());
+ }
+ }
+
+ if(!rs.getShaderState().uniform(gl, rs.getAlpha())) {
+ throw new GLException("Error setting global alpha in shader: "+rs.getShaderState());
+ }
+
+ if(!rs.getShaderState().uniform(gl, rs.getColorStatic())) {
+ throw new GLException("Error setting global color in shader: "+rs.getShaderState());
+ }
+ }
+
+ public final void destroy(GL2ES2 gl) {
+ if(!initialized){
+ if(DEBUG_INSTANCE) {
+ System.err.println("TextRenderer: Not initialized!");
+ }
+ return;
+ }
+ rs.getShaderState().useProgram(gl, false);
+ destroyImpl(gl);
+ rs.destroy(gl);
+ initialized = false;
}
+ public final RenderState getRenderState() { return rs; }
+ public final ShaderState getShaderState() { return rs.getShaderState(); }
-}
+ public final void enable(GL2ES2 gl, boolean enable) {
+ rs.getShaderState().useProgram(gl, enable);
+ }
+
+ public final void setWeight(GL2ES2 gl, float v) {
+ if( !isWeightValid(v) ) {
+ throw new IllegalArgumentException("Weight out of range");
+ }
+ rs.getWeight().setData(v);
+ if(null != gl && rs.getShaderState().inUse() && Region.isNonUniformWeight( getRenderModes() ) ) {
+ rs.getShaderState().uniform(gl, rs.getWeight());
+ }
+ }
+
+ public final void setAlpha(GL2ES2 gl, float alpha_t) {
+ rs.getAlpha().setData(alpha_t);
+ if(null != gl && rs.getShaderState().inUse()) {
+ rs.getShaderState().uniform(gl, rs.getAlpha());
+ }
+
+ }
+
+ public final void getColorStatic(GL2ES2 gl, float[] rgb) {
+ FloatBuffer fb = (FloatBuffer) rs.getColorStatic().getBuffer();
+ rgb[0] = fb.get(0);
+ rgb[1] = fb.get(1);
+ rgb[2] = fb.get(2);
+ }
+
+ public final void setColorStatic(GL2ES2 gl, float r, float g, float b){
+ FloatBuffer fb = (FloatBuffer) rs.getColorStatic().getBuffer();
+ fb.put(0, r);
+ fb.put(1, g);
+ fb.put(2, b);
+ if(null != gl && rs.getShaderState().inUse()) {
+ rs.getShaderState().uniform(gl, rs.getColorStatic());
+ }
+ }
+
+ public final void rotate(GL2ES2 gl, float angle, float x, float y, float z) {
+ rs.pmvMatrix().glRotatef(angle, x, y, z);
+ updateMatrix(gl);
+ }
+
+ public final void translate(GL2ES2 gl, float x, float y, float z) {
+ rs.pmvMatrix().glTranslatef(x, y, z);
+ updateMatrix(gl);
+ }
+
+ public final void scale(GL2ES2 gl, float x, float y, float z) {
+ rs.pmvMatrix().glScalef(x, y, z);
+ updateMatrix(gl);
+ }
+
+ public final void resetModelview(GL2ES2 gl) {
+ rs.pmvMatrix().glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ rs.pmvMatrix().glLoadIdentity();
+ updateMatrix(gl);
+ }
+
+ public final void updateMatrix(GL2ES2 gl) {
+ if(initialized && null != gl && rs.getShaderState().inUse()) {
+ rs.getShaderState().uniform(gl, rs.getPMVMatrix());
+ }
+ }
+
+ /** No PMVMatrix operation is performed here. PMVMatrix will be updated if gl is not null. */
+ public final boolean reshapeNotify(GL2ES2 gl, int width, int height) {
+ this.vp_width = width;
+ this.vp_height = height;
+ updateMatrix(gl);
+ return true;
+ }
+
+ public final boolean reshapePerspective(GL2ES2 gl, float angle, int width, int height, float near, float far) {
+ this.vp_width = width;
+ this.vp_height = height;
+ final float ratio = (float)width/(float)height;
+ final PMVMatrix p = rs.pmvMatrix();
+ p.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ p.glLoadIdentity();
+ p.gluPerspective(angle, ratio, near, far);
+ updateMatrix(gl);
+ return true;
+ }
+
+ public final boolean reshapeOrtho(GL2ES2 gl, int width, int height, float near, float far) {
+ this.vp_width = width;
+ this.vp_height = height;
+ final PMVMatrix p = rs.pmvMatrix();
+ p.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ p.glLoadIdentity();
+ p.glOrthof(0, width, 0, height, near, far);
+ updateMatrix(gl);
+ return true;
+ }
+
+ protected String getVertexShaderName() {
+ return "curverenderer" + getImplVersion();
+ }
+
+ protected String getFragmentShaderName() {
+ final String version = getImplVersion();
+ final String pass = Region.isVBAA(renderModes) ? "-2pass" : "-1pass" ;
+ final String weight = Region.isNonUniformWeight(renderModes) ? "-weight" : "" ;
+ return "curverenderer" + version + pass + weight;
+ }
+
+ // FIXME: Really required to have sampler2D def. precision ? If not, we can drop getFragmentShaderPrecision(..) and use default ShaderCode ..
+ public static final String es2_precision_fp = "\nprecision mediump float;\nprecision mediump int;\nprecision mediump sampler2D;\n";
+
+ protected String getFragmentShaderPrecision(GL2ES2 gl) {
+ if( gl.isGLES() ) {
+ return es2_precision_fp;
+ }
+ if( ShaderCode.requiresGL3DefaultPrecision(gl) ) {
+ return ShaderCode.gl3_default_precision_fp;
+ }
+ return null;
+ }
+
+ protected String getImplVersion() {
+ return "01";
+ }
+} \ No newline at end of file