├── .gitattributes ├── .gitignore ├── src ├── test │ ├── resources │ │ ├── x.png │ │ ├── duke.gif │ │ ├── plus.png │ │ ├── check.png │ │ └── instrumentation.snip │ └── java │ │ └── org │ │ └── jogamp │ │ └── glg2d │ │ ├── util │ │ ├── Painter.java │ │ ├── CustomPainter.java │ │ ├── Tester.java │ │ ├── Timer.java │ │ ├── AutoTester.java │ │ └── TestWindow.java │ │ ├── examples │ │ ├── shaders │ │ │ ├── CellShader.v │ │ │ ├── CellShader.f │ │ │ ├── CellTextureShader.f │ │ │ ├── CellShaderExample.java.tmprename │ │ │ └── DepthSimExample.java │ │ ├── AWTExample.java │ │ ├── FBOExample.java │ │ └── Example.java │ │ ├── WWSD.java │ │ ├── MovePanelTest.java │ │ ├── ImageTest.java │ │ └── StressTest.java └── main │ └── java │ └── org │ └── jogamp │ └── glg2d │ ├── impl │ ├── shader │ │ ├── FixedFuncShader.f │ │ ├── StrokeShader.f │ │ ├── FixedFuncShader.v │ │ ├── TextShader.v │ │ ├── TextureShader.f │ │ ├── TextureShader.v │ │ ├── StrokeShader.v │ │ ├── ShaderPathVisitor.java │ │ ├── ShaderPipeline.java │ │ ├── ShaderException.java │ │ ├── UniformBufferObject.java │ │ ├── text │ │ │ ├── TextPipeline.java │ │ │ ├── CollectingTesselator.java │ │ │ ├── TriangleStripTesselator.java │ │ │ └── GL2ES2TextDrawer.java │ │ ├── GLShaderGraphics2D.java │ │ ├── GL2ES2TesselatingVisitor.java │ │ ├── GL2ES2StrokeLineVisitor.java │ │ ├── GL2ES2ShapeDrawer.java │ │ ├── AnyModePipeline.java │ │ ├── GL2ES2ImagePipeline.java │ │ ├── GL2ES2SimpleConvexFillVisitor.java │ │ ├── GL2GL3StrokeLineVisitor.java │ │ ├── GL2ES2TransformHelper.java │ │ ├── GL2ES2ImageDrawer.java │ │ ├── GL2ES2ColorHelper.java │ │ ├── GeometryShaderStrokePipeline.java │ │ └── AbstractShaderPipeline.java │ ├── gl2 │ │ ├── GL2TesselatorVisitor.java │ │ ├── LineDrawingVisitor.java │ │ ├── FillSimpleConvexPolygonVisitor.java │ │ ├── GL2Transformhelper.java │ │ ├── GL2ImageDrawer.java │ │ ├── GL2ShapeDrawer.java │ │ ├── GL2ColorHelper.java │ │ ├── GL2StringDrawer.java │ │ └── FastLineVisitor.java │ ├── GLG2DNotImplemented.java │ ├── GLGraphicsDevice.java │ ├── GLGraphicsConfiguration.java │ ├── AbstractMatrixHelper.java │ ├── AbstractTextDrawer.java │ ├── SimplePathVisitor.java │ ├── AbstractColorHelper.java │ ├── AbstractTesselatorVisitor.java │ └── AbstractShapeHelper.java │ ├── GLG2DTransformHelper.java │ ├── GLG2DTextHelper.java │ ├── GLG2DColorHelper.java │ ├── GLG2DShapeHelper.java │ ├── GLAwareRepaintManager.java │ ├── GLG2DImageHelper.java │ ├── GLG2DUtils.java │ ├── GLG2DHeadlessListener.java │ ├── GLG2DRenderingHints.java │ ├── event │ ├── AWTMouseEventTranslator.java │ └── NewtMouseEventTranslator.java │ ├── G2DDrawingHelper.java │ ├── GLG2DPanel.java │ ├── GLG2DSimpleEventListener.java │ ├── PathVisitor.java │ └── VertexBuffer.java ├── NOTICE.txt └── README.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .classpath 3 | .settings 4 | .nbproject 5 | target 6 | bin 7 | *.log 8 | -------------------------------------------------------------------------------- /src/test/resources/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonborkholder/glg2d/HEAD/src/test/resources/x.png -------------------------------------------------------------------------------- /src/test/resources/duke.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonborkholder/glg2d/HEAD/src/test/resources/duke.gif -------------------------------------------------------------------------------- /src/test/resources/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonborkholder/glg2d/HEAD/src/test/resources/plus.png -------------------------------------------------------------------------------- /src/test/resources/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonborkholder/glg2d/HEAD/src/test/resources/check.png -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/FixedFuncShader.f: -------------------------------------------------------------------------------- 1 | uniform vec4 u_color; 2 | 3 | void main() { 4 | gl_FragColor = u_color; 5 | } -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/StrokeShader.f: -------------------------------------------------------------------------------- 1 | uniform vec4 u_color; 2 | 3 | void main() { 4 | gl_FragColor = u_color; 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/util/Painter.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d.util; 2 | 3 | import java.awt.Graphics2D; 4 | 5 | public interface Painter { 6 | void paint(Graphics2D g2d); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/FixedFuncShader.v: -------------------------------------------------------------------------------- 1 | uniform mat4 u_transform; 2 | 3 | in vec2 a_vertCoord; 4 | 5 | void main() { 6 | gl_Position = u_transform * vec4(a_vertCoord, 0, 1); 7 | } -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/examples/shaders/CellShader.v: -------------------------------------------------------------------------------- 1 | void main() { 2 | gl_Position = ftransform(); 3 | gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; 4 | gl_FrontColor = gl_Color; 5 | } -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/util/CustomPainter.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d.util; 2 | 3 | import java.awt.Graphics2D; 4 | 5 | public interface CustomPainter { 6 | void paint(Graphics2D g2d, boolean jogl); 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/examples/shaders/CellShader.f: -------------------------------------------------------------------------------- 1 | void main() { 2 | int prec = 4; 3 | gl_FragColor = vec4(round(gl_Color.r * prec) / prec, round(gl_Color.g * prec) / prec, round(gl_Color.b * prec) / prec, gl_Color.a); 4 | } -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/util/Tester.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d.util; 2 | 3 | public interface Tester { 4 | void setPainter(Painter p); 5 | 6 | void assertSame() throws InterruptedException; 7 | 8 | void finish(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/TextShader.v: -------------------------------------------------------------------------------- 1 | uniform mat4 u_transform; 2 | uniform float u_xoffset; 3 | uniform float u_yoffset; 4 | 5 | in vec2 a_vertCoord; 6 | 7 | void main() { 8 | gl_Position = u_transform * vec4(a_vertCoord.x + u_xoffset, a_vertCoord.y + u_yoffset, 0, 1); 9 | } -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/TextureShader.f: -------------------------------------------------------------------------------- 1 | uniform sampler2D u_tex; 2 | uniform vec4 u_color; 3 | 4 | varying vec2 v_texCoord; 5 | 6 | void main() { 7 | vec4 texel; 8 | 9 | texel = texture2D(u_tex, v_texCoord); 10 | gl_FragColor = vec4(u_color.rgb * texel.rgb, texel.a); 11 | } -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/TextureShader.v: -------------------------------------------------------------------------------- 1 | uniform mat4 u_transform; 2 | 3 | attribute vec2 a_vertCoord; 4 | attribute vec2 a_texCoord; 5 | 6 | varying vec2 v_texCoord; 7 | 8 | void main() { 9 | gl_Position = u_transform * vec4(a_vertCoord.x, a_vertCoord.y, 0, 1); 10 | v_texCoord = a_texCoord; 11 | } -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/StrokeShader.v: -------------------------------------------------------------------------------- 1 | #version 130 2 | 3 | in vec2 a_vertCoord; 4 | in vec2 a_vertBefore; 5 | in vec2 a_vertAfter; 6 | 7 | out vec2 position; 8 | out vec2 posBefore; 9 | out vec2 posAfter; 10 | 11 | void main() { 12 | position = a_vertCoord; 13 | posBefore = a_vertBefore; 14 | posAfter = a_vertAfter; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/examples/shaders/CellTextureShader.f: -------------------------------------------------------------------------------- 1 | uniform sampler2D tex; 2 | 3 | void main() { 4 | vec4 texel; 5 | vec4 color = gl_Color; 6 | int prec = 4; 7 | 8 | texel = texture2D(tex, gl_TexCoord[0].st); 9 | color = vec4(color.rgb * texel.rgb, texel.a); 10 | gl_FragColor = vec4(round(color.r * prec) / prec, round(color.g * prec) / prec, round(color.b * prec) / prec, color.a); 11 | } -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2015 Brandon Borkholder 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/examples/AWTExample.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d.examples; 2 | 3 | import java.awt.Dimension; 4 | 5 | import javax.swing.JComponent; 6 | import javax.swing.JFrame; 7 | 8 | import org.jogamp.glg2d.GLG2DPanel; 9 | 10 | public class AWTExample { 11 | public static void main(String[] args) { 12 | JFrame frame = new JFrame("GLG2D AWT Example"); 13 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 14 | frame.setPreferredSize(new Dimension(300, 300)); 15 | 16 | JComponent comp = Example.createComponent(); 17 | 18 | frame.setContentPane(new GLG2DPanel(comp)); 19 | 20 | frame.pack(); 21 | frame.setVisible(true); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/util/Timer.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d.util; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | public class Timer { 7 | private static final Timer instance = new Timer(); 8 | 9 | private long started; 10 | 11 | private Queue times = new LinkedList(); 12 | 13 | public static Timer getInstance() { 14 | return instance; 15 | } 16 | 17 | public void start() { 18 | started = System.nanoTime(); 19 | } 20 | 21 | public void stop() { 22 | times.add(System.nanoTime() - started); 23 | 24 | if (times.size() > 10) { 25 | times.poll(); 26 | } 27 | } 28 | 29 | public void stopAndPrint() { 30 | stop(); 31 | 32 | double total = 0; 33 | for (Long val : times) { 34 | total += val; 35 | } 36 | 37 | System.out.println(String.format("Moving avg: %.3f ms", total / 1e6)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/resources/instrumentation.snip: -------------------------------------------------------------------------------- 1 | if ($1.getClass().getName().startsWith("glg2d.")) { 2 | /* good */ 3 | } else { 4 | /* need to check that this component is under a JOGL canvas. */ 5 | boolean glg2dDescendent = false; 6 | java.awt.Component comp = this.getParent(); 7 | while (comp != null) { 8 | if (comp.getClass().getName().startsWith("com.jogamp.opengl.")) { 9 | glg2dDescendent = true; 10 | break; 11 | } 12 | comp = comp.getParent(); 13 | } 14 | 15 | /* it should be painted in glg2d and it's not. print a message. */ 16 | if (glg2dDescendent) { 17 | System.err.print("Graphics object passed to "); 18 | System.err.print(getClass().getName()); 19 | System.err.println(" is not a GLG2D graphics object:"); 20 | StackTraceElement[] elements = new Throwable().getStackTrace(); 21 | for (int i = 0;i < elements.length; i++){ 22 | System.err.print("\t"); 23 | System.err.println(elements[i]); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/ShaderPathVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | 19 | import com.jogamp.opengl.GL; 20 | 21 | import org.jogamp.glg2d.PathVisitor; 22 | 23 | public interface ShaderPathVisitor extends PathVisitor { 24 | void setGLContext(GL glContext, UniformBufferObject uniforms); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/ShaderPipeline.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | import com.jogamp.opengl.GL2ES2; 19 | 20 | public interface ShaderPipeline { 21 | void setup(GL2ES2 gl); 22 | 23 | boolean isSetup(); 24 | 25 | void use(GL2ES2 gl, boolean use); 26 | 27 | void delete(GL2ES2 gl); 28 | } 29 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | GLG2D is an effort to translate Graphics2D calls directly into OpenGL calls 2 | and accelerate the Java2D drawing functionality. The existing OpenGL pipeline 3 | in the Oracle JVM is minimal at best and doesn't use higher-level OpenGL 4 | primitives, like GL_POLYGON and GLU tesselation that make drawing in OpenGL so 5 | fast. 6 | 7 | Find more information on http://brandonborkholder.github.com/glg2d/ 8 | 9 | Use cases: 10 | * use as a drop-in replacement for a JPanel and all Swing children will be 11 | accelerated 12 | * draw Swing components in an GLCanvas in your existing application 13 | 14 | This library is licensed under the Apache 2.0 license and JOGL is licensed and 15 | distributed separately. 16 | 17 | How to build 18 | 19 | This project uses maven, run mvn package to build the jar in the ./target/ dir 20 | or add the following to your pom.xml 21 | 22 | org.jogamp.glg2d 23 | glg2d 24 | ${glg2d.version} 25 | 26 | 27 | Make sure you also add the GLG2D repository at 28 | http://brandonborkholder.github.com/glg2d/maven2/ 29 | 30 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/gl2/GL2TesselatorVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.gl2; 17 | 18 | 19 | import com.jogamp.opengl.GL; 20 | import com.jogamp.opengl.GL2; 21 | 22 | import org.jogamp.glg2d.impl.AbstractTesselatorVisitor; 23 | 24 | public class GL2TesselatorVisitor extends AbstractTesselatorVisitor { 25 | protected GL2 gl; 26 | 27 | @Override 28 | public void setGLContext(GL context) { 29 | gl = context.getGL2(); 30 | } 31 | 32 | @Override 33 | protected void endTess() { 34 | vBuffer.drawBuffer(gl, drawMode); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/ShaderException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | public class ShaderException extends RuntimeException { 19 | private static final long serialVersionUID = 829519650852350876L; 20 | 21 | public ShaderException() { 22 | super(); 23 | } 24 | 25 | public ShaderException(String message, Throwable cause) { 26 | super(message, cause); 27 | } 28 | 29 | public ShaderException(String message) { 30 | super(message); 31 | } 32 | 33 | public ShaderException(Throwable cause) { 34 | super(cause); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/GLG2DTransformHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.awt.geom.AffineTransform; 19 | 20 | public interface GLG2DTransformHelper extends G2DDrawingHelper { 21 | void translate(int x, int y); 22 | 23 | void translate(double tx, double ty); 24 | 25 | void rotate(double theta); 26 | 27 | void rotate(double theta, double x, double y); 28 | 29 | void scale(double sx, double sy); 30 | 31 | void shear(double shx, double shy); 32 | 33 | void transform(AffineTransform Tx); 34 | 35 | void setTransform(AffineTransform transform); 36 | 37 | AffineTransform getTransform(); 38 | } -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/GLG2DNotImplemented.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl; 17 | 18 | import java.util.Set; 19 | import java.util.TreeSet; 20 | import java.util.logging.Level; 21 | import java.util.logging.Logger; 22 | 23 | public class GLG2DNotImplemented { 24 | private static final Logger LOGGER = Logger.getLogger(GLG2DNotImplemented.class.getName()); 25 | 26 | private static final Set tags = new TreeSet(); 27 | 28 | public static void notImplemented(String tag) { 29 | if (tags.add(tag)) { 30 | LOGGER.log(Level.WARNING, tag + " has not been implemented yet ..."); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/UniformBufferObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | import java.awt.geom.AffineTransform; 19 | 20 | /** 21 | * This class implements a Uniform Buffer Object on OpenGL ES 2.0 compatible 22 | * hardware. 23 | */ 24 | public class UniformBufferObject { 25 | public ColorHook colorHook; 26 | public TransformHook transformHook; 27 | 28 | public interface ColorHook { 29 | float[] getRGBA(); 30 | 31 | float getAlpha(); 32 | } 33 | 34 | public interface TransformHook { 35 | float[] getGLMatrixData(); 36 | 37 | float[] getGLMatrixData(AffineTransform concat); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/GLG2DTextHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.awt.Font; 19 | import java.awt.FontMetrics; 20 | import java.awt.font.FontRenderContext; 21 | import java.text.AttributedCharacterIterator; 22 | 23 | public interface GLG2DTextHelper extends G2DDrawingHelper { 24 | void setFont(Font font); 25 | 26 | Font getFont(); 27 | 28 | FontMetrics getFontMetrics(Font font); 29 | 30 | FontRenderContext getFontRenderContext(); 31 | 32 | void drawString(AttributedCharacterIterator iterator, int x, int y); 33 | 34 | void drawString(AttributedCharacterIterator iterator, float x, float y); 35 | 36 | void drawString(String string, float x, float y); 37 | 38 | void drawString(String string, int x, int y); 39 | } -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/examples/FBOExample.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d.examples; 2 | 3 | import static com.jogamp.opengl.GLDrawableFactory.getFactory; 4 | 5 | import com.jogamp.opengl.GLAutoDrawable; 6 | import com.jogamp.opengl.GLCapabilities; 7 | import com.jogamp.opengl.GLProfile; 8 | import javax.swing.JComponent; 9 | import javax.swing.JRootPane; 10 | 11 | import org.jogamp.glg2d.GLG2DCanvas; 12 | import org.jogamp.glg2d.GLG2DHeadlessListener; 13 | import org.jogamp.glg2d.GLG2DSimpleEventListener; 14 | 15 | public class FBOExample { 16 | public static void main(String[] args) throws InterruptedException { 17 | int size = 250; 18 | 19 | GLCapabilities caps = GLG2DCanvas.getDefaultCapabalities(); 20 | caps.setFBO(true); 21 | caps.setOnscreen(false); 22 | GLAutoDrawable offscreen = getFactory(GLProfile.getGL2ES1()).createOffscreenAutoDrawable(null, caps, null, size, size); 23 | 24 | JComponent comp = Example.createComponent(); 25 | 26 | // Put into a JRootPane if the component has no Window ancestor 27 | JRootPane root = new JRootPane(); 28 | root.setContentPane(comp); 29 | 30 | // Add the painting listener 31 | offscreen.addGLEventListener(new GLG2DSimpleEventListener(comp)); 32 | 33 | // Add the headless listener 34 | offscreen.addGLEventListener(new GLG2DHeadlessListener(comp)); 35 | 36 | offscreen.display(); 37 | 38 | System.exit(0); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/GLG2DColorHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.awt.Color; 19 | import java.awt.Composite; 20 | import java.awt.Paint; 21 | 22 | public interface GLG2DColorHelper extends G2DDrawingHelper { 23 | void setComposite(Composite comp); 24 | 25 | Composite getComposite(); 26 | 27 | void setPaint(Paint paint); 28 | 29 | Paint getPaint(); 30 | 31 | void setColor(Color c); 32 | 33 | Color getColor(); 34 | 35 | void setColorNoRespectComposite(Color c); 36 | 37 | void setColorRespectComposite(Color c); 38 | 39 | void setBackground(Color color); 40 | 41 | Color getBackground(); 42 | 43 | void setPaintMode(); 44 | 45 | void setXORMode(Color c); 46 | 47 | void copyArea(int x, int y, int width, int height, int dx, int dy); 48 | } -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/WWSD.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d; 2 | 3 | import java.awt.Dimension; 4 | import java.awt.Graphics; 5 | import java.awt.Graphics2D; 6 | import java.awt.image.BufferedImage; 7 | import java.net.URL; 8 | 9 | import javax.imageio.ImageIO; 10 | import javax.swing.JFrame; 11 | import javax.swing.JPanel; 12 | 13 | import org.jogamp.glg2d.util.Painter; 14 | 15 | 16 | public class WWSD { 17 | public static void main(String[] args) throws Exception { 18 | drawImage(); 19 | } 20 | 21 | static void drawImage() throws Exception { 22 | URL url = VisualTest.class.getClassLoader().getResource("duke.gif"); 23 | final BufferedImage image = ImageIO.read(url); 24 | paint(new Painter() { 25 | @Override 26 | public void paint(Graphics2D g2d) { 27 | g2d.drawImage(image, 200, 400, 20, 40, 5, 20, 200, 400, null, null); 28 | } 29 | }); 30 | } 31 | 32 | @SuppressWarnings("serial") 33 | static void paint(final Painter painter) { 34 | JFrame frame = new JFrame("What Would Swing Do?"); 35 | frame.setContentPane(new JPanel() { 36 | @Override 37 | protected void paintComponent(Graphics g) { 38 | painter.paint((Graphics2D) g); 39 | } 40 | }); 41 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 42 | frame.setPreferredSize(new Dimension(400, 400)); 43 | frame.pack(); 44 | frame.setLocationRelativeTo(null); 45 | frame.setVisible(true); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/MovePanelTest.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d; 2 | 3 | import java.awt.Color; 4 | import java.awt.Dimension; 5 | import java.awt.Graphics; 6 | 7 | import javax.swing.JFrame; 8 | import javax.swing.JPanel; 9 | 10 | import org.jogamp.glg2d.GLG2DCanvas; 11 | import org.junit.Test; 12 | 13 | public class MovePanelTest { 14 | @Test 15 | public void testMovePanel() throws Exception { 16 | JFrame frame = new JFrame(); 17 | JPanel painter = new JPanel() { 18 | protected void paintComponent(Graphics g) { 19 | g.setColor(Color.blue); 20 | g.drawRect(3, 4, 9, 18); 21 | g.setColor(Color.red); 22 | g.fillRect(30, 18, 99, 20); 23 | } 24 | }; 25 | GLG2DCanvas canvas = new GLG2DCanvas(painter); 26 | frame.setContentPane(canvas); 27 | frame.setPreferredSize(new Dimension(150, 150)); 28 | frame.setTitle("Frame 1"); 29 | frame.pack(); 30 | frame.setLocationRelativeTo(null); 31 | frame.setVisible(true); 32 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 33 | 34 | Thread.sleep(1 * 1000); 35 | frame.setVisible(false); 36 | frame.dispose(); 37 | 38 | frame = new JFrame(); 39 | frame.setContentPane(canvas); 40 | frame.setPreferredSize(new Dimension(150, 150)); 41 | frame.setTitle("Frame 2"); 42 | frame.pack(); 43 | frame.setLocationRelativeTo(null); 44 | frame.setVisible(true); 45 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 46 | 47 | Thread.sleep(2 * 1000); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/GLG2DShapeHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.awt.Shape; 19 | import java.awt.Stroke; 20 | 21 | public interface GLG2DShapeHelper extends G2DDrawingHelper { 22 | void setStroke(Stroke stroke); 23 | 24 | Stroke getStroke(); 25 | 26 | void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight, boolean fill); 27 | 28 | void drawRect(int x, int y, int width, int height, boolean fill); 29 | 30 | void drawLine(int x1, int y1, int x2, int y2); 31 | 32 | void drawOval(int x, int y, int width, int height, boolean fill); 33 | 34 | void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle, boolean fill); 35 | 36 | void drawPolyline(int[] xPoints, int[] yPoints, int nPoints); 37 | 38 | void drawPolygon(int[] xPoints, int[] yPoints, int nPoints, boolean fill); 39 | 40 | void draw(Shape shape); 41 | 42 | void fill(Shape shape); 43 | } -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/GLAwareRepaintManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.awt.Container; 19 | 20 | import com.jogamp.opengl.GLAutoDrawable; 21 | import javax.swing.JComponent; 22 | import javax.swing.RepaintManager; 23 | 24 | public class GLAwareRepaintManager extends RepaintManager { 25 | public static RepaintManager INSTANCE = new GLAwareRepaintManager(); 26 | 27 | @Override 28 | public void addDirtyRegion(JComponent c, int x, int y, int w, int h) { 29 | GLG2DCanvas canvas = getGLParent(c); 30 | if (canvas == null || c instanceof GLAutoDrawable) { 31 | super.addDirtyRegion(c, x, y, w, h); 32 | } else { 33 | canvas.repaint(); 34 | } 35 | } 36 | 37 | protected GLG2DCanvas getGLParent(JComponent component) { 38 | Container c = component.getParent(); 39 | while (true) { 40 | if (c == null) { 41 | return null; 42 | } else if (c instanceof GLG2DCanvas) { 43 | return (GLG2DCanvas) c; 44 | } else { 45 | c = c.getParent(); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/GLGraphicsDevice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl; 17 | 18 | import java.awt.GraphicsConfiguration; 19 | import java.awt.GraphicsDevice; 20 | 21 | /** 22 | * Fulfills the contract of a {@code GraphicsDevice}. 23 | */ 24 | public class GLGraphicsDevice extends GraphicsDevice { 25 | protected final GLGraphicsConfiguration config; 26 | 27 | public GLGraphicsDevice(GLGraphicsConfiguration config) { 28 | this.config = config; 29 | } 30 | 31 | @Override 32 | public int getType() { 33 | if (config.getTarget().getChosenGLCapabilities().isOnscreen()) { 34 | return TYPE_RASTER_SCREEN; 35 | } else { 36 | return TYPE_IMAGE_BUFFER; 37 | } 38 | } 39 | 40 | @Override 41 | public String getIDstring() { 42 | return "glg2d"; 43 | } 44 | 45 | @Override 46 | public GraphicsConfiguration[] getConfigurations() { 47 | return new GraphicsConfiguration[] { getDefaultConfiguration() }; 48 | } 49 | 50 | @Override 51 | public GraphicsConfiguration getDefaultConfiguration() { 52 | return config; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/GLG2DImageHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.awt.Color; 19 | import java.awt.Image; 20 | import java.awt.geom.AffineTransform; 21 | import java.awt.image.BufferedImage; 22 | import java.awt.image.BufferedImageOp; 23 | import java.awt.image.ImageObserver; 24 | import java.awt.image.RenderedImage; 25 | import java.awt.image.renderable.RenderableImage; 26 | 27 | public interface GLG2DImageHelper extends G2DDrawingHelper { 28 | boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer); 29 | 30 | boolean drawImage(Image img, AffineTransform xform, ImageObserver observer); 31 | 32 | boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer); 33 | 34 | boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer); 35 | 36 | void drawImage(BufferedImage img, BufferedImageOp op, int x, int y); 37 | 38 | void drawImage(RenderedImage img, AffineTransform xform); 39 | 40 | void drawImage(RenderableImage img, AffineTransform xform); 41 | } -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/text/TextPipeline.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader.text; 17 | 18 | import com.jogamp.opengl.GL2ES2; 19 | 20 | import org.jogamp.glg2d.impl.shader.AnyModePipeline; 21 | 22 | 23 | public class TextPipeline extends AnyModePipeline { 24 | protected int xOffsetLocation = -1; 25 | protected int yOffsetLocation = -1; 26 | 27 | public TextPipeline() { 28 | this("TextShader.v", "FixedFuncShader.f"); 29 | } 30 | 31 | public TextPipeline(String vertexShaderFilename, String fragmentShaderFilename) { 32 | super(vertexShaderFilename, fragmentShaderFilename); 33 | } 34 | 35 | public void setLocation(GL2ES2 gl, float x, float y) { 36 | if (xOffsetLocation >= 0) { 37 | gl.glUniform1f(xOffsetLocation, x); 38 | } 39 | 40 | if (yOffsetLocation >= 0) { 41 | gl.glUniform1f(yOffsetLocation, y); 42 | } 43 | } 44 | 45 | @Override 46 | protected void setupUniformsAndAttributes(GL2ES2 gl) { 47 | super.setupUniformsAndAttributes(gl); 48 | 49 | xOffsetLocation = gl.glGetUniformLocation(programId, "u_xoffset"); 50 | yOffsetLocation = gl.glGetUniformLocation(programId, "u_yoffset"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/examples/Example.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d.examples; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.GridLayout; 5 | 6 | import javax.swing.BorderFactory; 7 | import javax.swing.ButtonGroup; 8 | import javax.swing.JButton; 9 | import javax.swing.JComboBox; 10 | import javax.swing.JComponent; 11 | import javax.swing.JPanel; 12 | import javax.swing.JProgressBar; 13 | import javax.swing.JRadioButton; 14 | import javax.swing.JSlider; 15 | import javax.swing.SwingConstants; 16 | 17 | import org.jogamp.glg2d.GLGraphics2D; 18 | 19 | class Example { 20 | public static JComponent createComponent() { 21 | JPanel panel = new JPanel(new BorderLayout()); 22 | panel.setDoubleBuffered(false); 23 | 24 | panel.add(new JButton("Press me!"), BorderLayout.NORTH); 25 | 26 | JProgressBar bar = new JProgressBar() { 27 | protected void paintComponent(java.awt.Graphics g) { 28 | if (g instanceof GLGraphics2D 29 | ) { 30 | super.paintComponent(g); 31 | } else { 32 | System.out.println(g.getClass()); 33 | } 34 | } 35 | }; 36 | bar.setIndeterminate(true); 37 | panel.add(bar, BorderLayout.SOUTH); 38 | panel.add(new JSlider(SwingConstants.VERTICAL, 0, 10, 3), BorderLayout.EAST); 39 | 40 | ButtonGroup grp = new ButtonGroup(); 41 | JRadioButton radio1 = new JRadioButton("FM"); 42 | JRadioButton radio2 = new JRadioButton("AM"); 43 | grp.add(radio1); 44 | grp.add(radio2); 45 | 46 | JPanel panel2 = new JPanel(new GridLayout(0, 1)); 47 | panel2.add(radio1); 48 | panel2.add(radio2); 49 | 50 | JComboBox b = new JComboBox(new String[] {"3", "4"}); 51 | 52 | panel.add(b, BorderLayout.WEST); 53 | 54 | panel.setBorder(BorderFactory.createTitledBorder("Border")); 55 | 56 | return panel; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/GLShaderGraphics2D.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | 19 | import org.jogamp.glg2d.GLG2DColorHelper; 20 | import org.jogamp.glg2d.GLG2DImageHelper; 21 | import org.jogamp.glg2d.GLG2DShapeHelper; 22 | import org.jogamp.glg2d.GLG2DTextHelper; 23 | import org.jogamp.glg2d.GLG2DTransformHelper; 24 | import org.jogamp.glg2d.GLGraphics2D; 25 | import org.jogamp.glg2d.impl.shader.text.GL2ES2TextDrawer; 26 | 27 | public class GLShaderGraphics2D extends GLGraphics2D { 28 | protected UniformBufferObject uniforms = new UniformBufferObject(); 29 | 30 | public UniformBufferObject getUniformsObject() { 31 | return uniforms; 32 | } 33 | 34 | @Override 35 | protected GLG2DImageHelper createImageHelper() { 36 | return new GL2ES2ImageDrawer(); 37 | } 38 | 39 | @Override 40 | protected GLG2DColorHelper createColorHelper() { 41 | return new GL2ES2ColorHelper(); 42 | } 43 | 44 | @Override 45 | protected GLG2DTransformHelper createTransformHelper() { 46 | return new GL2ES2TransformHelper(); 47 | } 48 | 49 | @Override 50 | protected GLG2DShapeHelper createShapeHelper() { 51 | return new GL2ES2ShapeDrawer(); 52 | } 53 | 54 | @Override 55 | protected GLG2DTextHelper createTextHelper() { 56 | return new GL2ES2TextDrawer(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/gl2/LineDrawingVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.gl2; 17 | 18 | 19 | import java.awt.BasicStroke; 20 | 21 | import com.jogamp.opengl.GL; 22 | import com.jogamp.opengl.GL2; 23 | import com.jogamp.opengl.fixedfunc.GLMatrixFunc; 24 | 25 | import org.jogamp.glg2d.impl.BasicStrokeLineVisitor; 26 | 27 | /** 28 | * Draws a line, as outlined by a {@link BasicStroke}. The current 29 | * implementation supports everything except dashes. This class draws a series 30 | * of quads for each line segment, joins corners and endpoints as appropriate. 31 | */ 32 | public class LineDrawingVisitor extends BasicStrokeLineVisitor { 33 | protected GL2 gl; 34 | 35 | @Override 36 | public void setGLContext(GL context) { 37 | gl = context.getGL2(); 38 | } 39 | 40 | @Override 41 | public void beginPoly(int windingRule) { 42 | /* 43 | * pen hangs down and to the right. See java.awt.Graphics 44 | */ 45 | gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); 46 | gl.glPushMatrix(); 47 | gl.glTranslatef(0.5f, 0.5f, 0); 48 | 49 | super.beginPoly(windingRule); 50 | } 51 | 52 | @Override 53 | public void endPoly() { 54 | super.endPoly(); 55 | 56 | gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); 57 | gl.glPopMatrix(); 58 | } 59 | 60 | @Override 61 | protected void drawBuffer() { 62 | vBuffer.drawBuffer(gl, GL.GL_TRIANGLE_STRIP); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/gl2/FillSimpleConvexPolygonVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.gl2; 17 | 18 | 19 | import java.awt.BasicStroke; 20 | 21 | import com.jogamp.opengl.GL; 22 | import com.jogamp.opengl.GL2; 23 | 24 | import org.jogamp.glg2d.VertexBuffer; 25 | import org.jogamp.glg2d.impl.SimplePathVisitor; 26 | 27 | /** 28 | * Fills a simple convex polygon. This class does not test to determine if the 29 | * polygon is actually simple and convex. 30 | */ 31 | public class FillSimpleConvexPolygonVisitor extends SimplePathVisitor { 32 | protected GL2 gl; 33 | 34 | protected VertexBuffer vBuffer = VertexBuffer.getSharedBuffer(); 35 | 36 | @Override 37 | public void setGLContext(GL context) { 38 | gl = context.getGL2(); 39 | } 40 | 41 | @Override 42 | public void setStroke(BasicStroke stroke) { 43 | // nop 44 | } 45 | 46 | @Override 47 | public void beginPoly(int windingRule) { 48 | vBuffer.clear(); 49 | 50 | /* 51 | * We don't care what the winding rule is, we disable face culling. 52 | */ 53 | gl.glDisable(GL.GL_CULL_FACE); 54 | } 55 | 56 | @Override 57 | public void closeLine() { 58 | vBuffer.drawBuffer(gl, GL2.GL_POLYGON); 59 | } 60 | 61 | @Override 62 | public void endPoly() { 63 | } 64 | 65 | @Override 66 | public void lineTo(float[] vertex) { 67 | vBuffer.addVertex(vertex, 0, 1); 68 | } 69 | 70 | @Override 71 | public void moveTo(float[] vertex) { 72 | vBuffer.clear(); 73 | vBuffer.addVertex(vertex, 0, 1); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/GLG2DUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.awt.Color; 19 | import java.util.logging.Level; 20 | import java.util.logging.Logger; 21 | 22 | import com.jogamp.opengl.GL; 23 | import com.jogamp.opengl.GL2ES1; 24 | 25 | public class GLG2DUtils { 26 | private static final Logger LOGGER = Logger.getLogger(GLG2DUtils.class.getName()); 27 | 28 | public static void setColor(GL2ES1 gl, Color c, float preMultiplyAlpha) { 29 | int rgb = c.getRGB(); 30 | gl.glColor4ub((byte) (rgb >> 16 & 0xFF), (byte) (rgb >> 8 & 0xFF), (byte) (rgb & 0xFF), (byte) ((rgb >> 24 & 0xFF) * preMultiplyAlpha)); 31 | } 32 | 33 | public static float[] getGLColor(Color c) { 34 | return c.getComponents(null); 35 | } 36 | 37 | public static int getViewportHeight(GL gl) { 38 | int[] viewportDimensions = new int[4]; 39 | gl.glGetIntegerv(GL.GL_VIEWPORT, viewportDimensions, 0); 40 | int canvasHeight = viewportDimensions[3]; 41 | return canvasHeight; 42 | } 43 | 44 | public static void logGLError(GL gl) { 45 | int error = gl.glGetError(); 46 | if (error != GL.GL_NO_ERROR) { 47 | LOGGER.log(Level.SEVERE, "GL Error: code " + error); 48 | } 49 | } 50 | 51 | public static int ensureIsGLBuffer(GL gl, int bufferId) { 52 | if (gl.glIsBuffer(bufferId)) { 53 | return bufferId; 54 | } else { 55 | return genBufferId(gl); 56 | } 57 | } 58 | 59 | public static int genBufferId(GL gl) { 60 | int[] ids = new int[1]; 61 | gl.glGenBuffers(1, ids, 0); 62 | return ids[0]; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/GL2ES2TesselatingVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | 19 | import java.nio.FloatBuffer; 20 | 21 | import com.jogamp.opengl.GL; 22 | import com.jogamp.opengl.GL2ES2; 23 | 24 | import org.jogamp.glg2d.impl.AbstractTesselatorVisitor; 25 | 26 | public class GL2ES2TesselatingVisitor extends AbstractTesselatorVisitor implements ShaderPathVisitor { 27 | protected GL2ES2 gl; 28 | protected UniformBufferObject uniforms; 29 | 30 | protected AnyModePipeline pipeline; 31 | 32 | public GL2ES2TesselatingVisitor() { 33 | this(new AnyModePipeline()); 34 | } 35 | 36 | public GL2ES2TesselatingVisitor(AnyModePipeline pipeline) { 37 | this.pipeline = pipeline; 38 | } 39 | 40 | @Override 41 | public void setGLContext(GL context) { 42 | gl = context.getGL2ES2(); 43 | 44 | if (!pipeline.isSetup()) { 45 | pipeline.setup(gl); 46 | } 47 | } 48 | 49 | @Override 50 | public void setGLContext(GL glContext, UniformBufferObject uniforms) { 51 | setGLContext(glContext); 52 | this.uniforms = uniforms; 53 | } 54 | 55 | @Override 56 | public void beginPoly(int windingRule) { 57 | pipeline.use(gl, true); 58 | 59 | super.beginPoly(windingRule); 60 | 61 | pipeline.setColor(gl, uniforms.colorHook.getRGBA()); 62 | pipeline.setTransform(gl, uniforms.transformHook.getGLMatrixData()); 63 | } 64 | 65 | @Override 66 | public void endPoly() { 67 | super.endPoly(); 68 | 69 | pipeline.use(gl, false); 70 | } 71 | 72 | @Override 73 | protected void endTess() { 74 | FloatBuffer buf = vBuffer.getBuffer(); 75 | buf.flip(); 76 | 77 | pipeline.draw(gl, drawMode, buf); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/GLG2DHeadlessListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import com.jogamp.opengl.GLAutoDrawable; 19 | import com.jogamp.opengl.GLEventListener; 20 | import javax.swing.JComponent; 21 | 22 | /** 23 | * When the component being painting is not part of an existing Swing hierarchy 24 | * and therefore not receiving standard AWT events, the UI will not function as 25 | * expected. Reshape events will not be propagated and many features of Swing 26 | * components will not be available (e.g. indeterminate progress bars). 27 | * 28 | *

29 | * This will initialize the component as if it was part of a Swing hierarchy on 30 | * the first call to {@code init(GLDrawable)}. This will listen for reshape 31 | * events and ensure the component being painted fills the entire canvas. This 32 | * is useful when painting a Swing component into a NEWT window and the Swing 33 | * component takes up the entire NEWT frame. 34 | *

35 | */ 36 | public class GLG2DHeadlessListener implements GLEventListener { 37 | protected JComponent comp; 38 | 39 | public GLG2DHeadlessListener(JComponent component) { 40 | if (component == null) { 41 | throw new NullPointerException("component is null"); 42 | } 43 | 44 | comp = component; 45 | } 46 | 47 | @Override 48 | public void init(GLAutoDrawable drawable) { 49 | comp.addNotify(); 50 | } 51 | 52 | @Override 53 | public void dispose(GLAutoDrawable drawable) { 54 | } 55 | 56 | @Override 57 | public void display(GLAutoDrawable drawable) { 58 | } 59 | 60 | @Override 61 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 62 | comp.setSize(width, height); 63 | comp.validate(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/GLG2DRenderingHints.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.awt.RenderingHints; 19 | import java.awt.RenderingHints.Key; 20 | 21 | /** 22 | * Rendering hints for the GLG2D library that customize the behavior. 23 | */ 24 | public class GLG2DRenderingHints { 25 | private static int keyId = 384739478; 26 | 27 | /** 28 | * Never clear the texture cache. 29 | */ 30 | public static final Object VALUE_CLEAR_TEXTURES_CACHE_NEVER = new Object(); 31 | 32 | /** 33 | * Clear the texture cache before each paint. This allows images to be cached 34 | * within a paint cycle. 35 | */ 36 | public static final Object VALUE_CLEAR_TEXTURES_CACHE_EACH_PAINT = new Object(); 37 | 38 | /** 39 | * Use the default texture cache policy. 40 | */ 41 | public static final Object VALUE_CLEAR_TEXTURES_CACHE_DEFAULT = VALUE_CLEAR_TEXTURES_CACHE_NEVER; 42 | 43 | /** 44 | * Specifies when to clear the texture cache. Each image to be painted must be 45 | * turned into a texture and then the texture is re-used whenever that image 46 | * is seen. Values can be one of 47 | * 48 | *
    49 | *
  • {@link #VALUE_CLEAR_TEXTURES_CACHE_DEFAULT}
  • 50 | *
  • {@link #VALUE_CLEAR_TEXTURES_CACHE_NEVER}
  • 51 | *
  • {@link #VALUE_CLEAR_TEXTURES_CACHE_EACH_PAINT}
  • 52 | *
  • any integer for the maximum size of the cache
  • 53 | *
54 | */ 55 | public static final Key KEY_CLEAR_TEXTURES_CACHE = new RenderingHints.Key(keyId++) { 56 | public boolean isCompatibleValue(Object val) { 57 | return val == VALUE_CLEAR_TEXTURES_CACHE_DEFAULT || 58 | val == VALUE_CLEAR_TEXTURES_CACHE_EACH_PAINT || 59 | val == VALUE_CLEAR_TEXTURES_CACHE_NEVER || 60 | val instanceof Integer; 61 | } 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/event/AWTMouseEventTranslator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.event; 17 | 18 | import java.awt.Component; 19 | import java.awt.event.MouseEvent; 20 | import java.awt.event.MouseListener; 21 | import java.awt.event.MouseMotionListener; 22 | import java.awt.event.MouseWheelEvent; 23 | import java.awt.event.MouseWheelListener; 24 | 25 | public class AWTMouseEventTranslator extends MouseEventTranslator implements MouseListener, MouseMotionListener, MouseWheelListener { 26 | public AWTMouseEventTranslator(Component target) { 27 | super(target); 28 | } 29 | 30 | @Override 31 | public void mouseWheelMoved(MouseWheelEvent e) { 32 | translateMouseWheelEvent(e); 33 | } 34 | 35 | @Override 36 | public void mouseDragged(MouseEvent e) { 37 | translateMouseEvent(e); 38 | } 39 | 40 | @Override 41 | public void mouseMoved(MouseEvent e) { 42 | translateMouseEvent(e); 43 | } 44 | 45 | @Override 46 | public void mouseClicked(MouseEvent e) { 47 | translateMouseEvent(e); 48 | } 49 | 50 | @Override 51 | public void mousePressed(MouseEvent e) { 52 | translateMouseEvent(e); 53 | } 54 | 55 | @Override 56 | public void mouseReleased(MouseEvent e) { 57 | translateMouseEvent(e); 58 | } 59 | 60 | @Override 61 | public void mouseEntered(MouseEvent e) { 62 | translateMouseEvent(e); 63 | } 64 | 65 | @Override 66 | public void mouseExited(MouseEvent e) { 67 | translateMouseEvent(e); 68 | } 69 | 70 | protected void translateMouseEvent(MouseEvent e) { 71 | publishMouseEvent(e.getID(), e.getWhen(), e.getModifiers(), e.getClickCount(), e.getButton(), e.getPoint()); 72 | } 73 | 74 | protected void translateMouseWheelEvent(MouseWheelEvent e) { 75 | publishMouseWheelEvent(e.getID(), e.getWhen(), e.getModifiers(), e.getWheelRotation(), e.getPoint()); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/text/CollectingTesselator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader.text; 17 | 18 | 19 | import java.nio.FloatBuffer; 20 | 21 | import com.jogamp.opengl.GL; 22 | import com.jogamp.opengl.GL2ES2; 23 | import com.jogamp.opengl.glu.GLU; 24 | 25 | import org.jogamp.glg2d.impl.AbstractTesselatorVisitor; 26 | 27 | import com.jogamp.common.nio.Buffers; 28 | 29 | public class CollectingTesselator extends AbstractTesselatorVisitor { 30 | @Override 31 | public void setGLContext(GL context) { 32 | // nop 33 | } 34 | 35 | @Override 36 | public void beginPoly(int windingRule) { 37 | super.beginPoly(windingRule); 38 | 39 | vBuffer.clear(); 40 | } 41 | 42 | @Override 43 | protected void configureTesselator(int windingRule) { 44 | super.configureTesselator(windingRule); 45 | 46 | GLU.gluTessCallback(tesselator, GLU.GLU_TESS_EDGE_FLAG_DATA, callback); 47 | } 48 | 49 | @Override 50 | protected void beginTess(int type) { 51 | // don't clear the vertex buffer 52 | } 53 | 54 | @Override 55 | protected void endTess() { 56 | // nothing to do 57 | } 58 | 59 | public Triangles getTesselated() { 60 | FloatBuffer buf = vBuffer.getBuffer(); 61 | buf.flip(); 62 | return new Triangles(buf); 63 | } 64 | 65 | public static class Triangles { 66 | private FloatBuffer triangles; 67 | 68 | public Triangles(FloatBuffer vertexBuffer) { 69 | int numVertices = vertexBuffer.limit() - vertexBuffer.position(); 70 | 71 | triangles = Buffers.newDirectFloatBuffer(numVertices); 72 | triangles.put(vertexBuffer); 73 | 74 | triangles.flip(); 75 | } 76 | 77 | public void draw(GL2ES2 gl) { 78 | int numFloats = triangles.limit(); 79 | gl.glBufferData(GL.GL_ARRAY_BUFFER, Buffers.SIZEOF_FLOAT * numFloats, triangles, GL2ES2.GL_STREAM_DRAW); 80 | gl.glDrawArrays(GL.GL_TRIANGLES, 0, numFloats / 2); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/GL2ES2StrokeLineVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | 19 | import java.awt.BasicStroke; 20 | import java.nio.FloatBuffer; 21 | 22 | import com.jogamp.opengl.GL; 23 | import com.jogamp.opengl.GL2ES2; 24 | 25 | import org.jogamp.glg2d.impl.BasicStrokeLineVisitor; 26 | 27 | public class GL2ES2StrokeLineVisitor extends BasicStrokeLineVisitor implements ShaderPathVisitor { 28 | protected GL2ES2 gl; 29 | protected UniformBufferObject uniforms; 30 | 31 | protected AnyModePipeline pipeline; 32 | 33 | public GL2ES2StrokeLineVisitor() { 34 | this(new AnyModePipeline()); 35 | } 36 | 37 | public GL2ES2StrokeLineVisitor(AnyModePipeline pipeline) { 38 | this.pipeline = pipeline; 39 | } 40 | 41 | @Override 42 | public void setGLContext(GL context, UniformBufferObject uniforms) { 43 | setGLContext(context); 44 | 45 | this.uniforms = uniforms; 46 | } 47 | 48 | @Override 49 | public void setGLContext(GL context) { 50 | gl = context.getGL2ES2(); 51 | 52 | if (!pipeline.isSetup()) { 53 | pipeline.setup(gl); 54 | } 55 | } 56 | 57 | @Override 58 | public void setStroke(BasicStroke stroke) { 59 | super.setStroke(stroke); 60 | } 61 | 62 | @Override 63 | public void beginPoly(int windingRule) { 64 | pipeline.use(gl, true); 65 | pipeline.setTransform(gl, uniforms.transformHook.getGLMatrixData()); 66 | pipeline.setColor(gl, uniforms.colorHook.getRGBA()); 67 | 68 | super.beginPoly(windingRule); 69 | } 70 | 71 | @Override 72 | public void endPoly() { 73 | super.endPoly(); 74 | 75 | pipeline.use(gl, false); 76 | } 77 | 78 | @Override 79 | protected void drawBuffer() { 80 | FloatBuffer buf = vBuffer.getBuffer(); 81 | if (buf.position() == 0) { 82 | return; 83 | } 84 | 85 | buf.flip(); 86 | 87 | pipeline.draw(gl, GL.GL_TRIANGLE_STRIP, buf); 88 | 89 | vBuffer.clear(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/examples/shaders/CellShaderExample.java.tmprename: -------------------------------------------------------------------------------- 1 | package glg2d.examples.shaders; 2 | 3 | import glg2d.G2DGLEventListener; 4 | import glg2d.G2DGLPanel; 5 | import glg2d.GLGraphics2D; 6 | import glg2d.UIDemo; 7 | import glg2d.impl.gl2.GL2StringDrawer; 8 | import glg2d.impl.gl2.GL2Transformhelper; 9 | import glg2d.impl.gl2.GL2ColorHelper; 10 | import glg2d.impl.shader.G2DShaderImageDrawer; 11 | import glg2d.impl.shader.G2DShaderShapeDrawer; 12 | import glg2d.impl.shader.GLShaderGraphics2D; 13 | import glg2d.impl.shader.ResourceShader; 14 | import glg2d.impl.shader.Shader; 15 | 16 | import java.awt.Dimension; 17 | 18 | import com.jogamp.opengl.GLAutoDrawable; 19 | import javax.swing.JComponent; 20 | import javax.swing.JFrame; 21 | import javax.swing.UIManager; 22 | 23 | @SuppressWarnings("serial") 24 | public class CellShaderExample { 25 | public static void main(String[] args) throws Exception { 26 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 27 | 28 | JFrame frame = new JFrame("Cell Shader Example"); 29 | frame.setContentPane(new G2DGLPanel(new UIDemo()) { 30 | @Override 31 | protected G2DGLEventListener createG2DListener(JComponent drawingComponent) { 32 | return new G2DGLEventListener(drawingComponent) { 33 | @Override 34 | protected GLGraphics2D createGraphics2D(GLAutoDrawable drawable) { 35 | return new GLShaderGraphics2D() { 36 | @Override 37 | protected void createDrawingHelpers() { 38 | Shader s = new ResourceShader(CellShaderExample.class, "CellShader.v", "CellShader.f"); 39 | shapeHelper = new G2DShaderShapeDrawer(s); 40 | 41 | s = new ResourceShader(CellShaderExample.class, "CellShader.v", "CellTextureShader.f"); 42 | imageHelper = new G2DShaderImageDrawer(s); 43 | stringHelper = new GL2StringDrawer(); 44 | 45 | colorHelper = new GL2ColorHelper(); 46 | matrixHelper = new GL2Transformhelper(); 47 | 48 | addG2DDrawingHelper(shapeHelper); 49 | addG2DDrawingHelper(imageHelper); 50 | addG2DDrawingHelper(stringHelper); 51 | addG2DDrawingHelper(colorHelper); 52 | addG2DDrawingHelper(matrixHelper); 53 | } 54 | }; 55 | } 56 | }; 57 | } 58 | }); 59 | 60 | // frame.setContentPane(new UIDemo()); 61 | frame.setPreferredSize(new Dimension(1024, 768)); 62 | frame.pack(); 63 | frame.setLocationRelativeTo(null); 64 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 65 | frame.setVisible(true); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/GL2ES2ShapeDrawer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | 19 | import java.awt.BasicStroke; 20 | import java.awt.Shape; 21 | import java.awt.Stroke; 22 | 23 | import com.jogamp.opengl.GL; 24 | 25 | import org.jogamp.glg2d.GLGraphics2D; 26 | import org.jogamp.glg2d.PathVisitor; 27 | import org.jogamp.glg2d.impl.AbstractShapeHelper; 28 | import org.jogamp.glg2d.impl.SimpleOrTesselatingVisitor; 29 | 30 | public class GL2ES2ShapeDrawer extends AbstractShapeHelper { 31 | protected ShaderPathVisitor lineVisitor; 32 | protected ShaderPathVisitor simpleFillVisitor; 33 | protected ShaderPathVisitor tesselatingVisitor; 34 | protected PathVisitor complexFillVisitor; 35 | 36 | public GL2ES2ShapeDrawer() { 37 | lineVisitor = new GL2ES2StrokeLineVisitor(); 38 | simpleFillVisitor = new GL2ES2SimpleConvexFillVisitor(); 39 | tesselatingVisitor = new GL2ES2TesselatingVisitor(); 40 | complexFillVisitor = new SimpleOrTesselatingVisitor(simpleFillVisitor, tesselatingVisitor); 41 | } 42 | 43 | @Override 44 | public void setG2D(GLGraphics2D g2d) { 45 | super.setG2D(g2d); 46 | 47 | if (g2d instanceof GLShaderGraphics2D) { 48 | GL gl = g2d.getGLContext().getGL(); 49 | UniformBufferObject uniforms = ((GLShaderGraphics2D) g2d).getUniformsObject(); 50 | 51 | lineVisitor.setGLContext(gl, uniforms); 52 | simpleFillVisitor.setGLContext(gl, uniforms); 53 | tesselatingVisitor.setGLContext(gl, uniforms); 54 | complexFillVisitor.setGLContext(gl); 55 | } else { 56 | throw new IllegalArgumentException(GLGraphics2D.class.getName() + " implementation must be instance of " 57 | + GLShaderGraphics2D.class.getSimpleName()); 58 | } 59 | } 60 | 61 | public void draw(Shape shape) { 62 | Stroke stroke = getStroke(); 63 | if (stroke instanceof BasicStroke) { 64 | lineVisitor.setStroke((BasicStroke) stroke); 65 | traceShape(shape, lineVisitor); 66 | } else { 67 | fill(stroke.createStrokedShape(shape), false); 68 | } 69 | } 70 | 71 | @Override 72 | protected void fill(Shape shape, boolean isDefinitelySimpleConvex) { 73 | if (isDefinitelySimpleConvex) { 74 | traceShape(shape, simpleFillVisitor); 75 | } else { 76 | traceShape(shape, complexFillVisitor); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/AnyModePipeline.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | import static org.jogamp.glg2d.GLG2DUtils.ensureIsGLBuffer; 19 | 20 | import java.nio.FloatBuffer; 21 | 22 | import com.jogamp.opengl.GL; 23 | import com.jogamp.opengl.GL2ES2; 24 | 25 | import com.jogamp.common.nio.Buffers; 26 | 27 | public class AnyModePipeline extends AbstractShaderPipeline { 28 | protected int vertCoordBuffer = -1; 29 | protected int vertCoordLocation = -1; 30 | 31 | public AnyModePipeline() { 32 | this("FixedFuncShader.v", "FixedFuncShader.f"); 33 | } 34 | 35 | public AnyModePipeline(String vertexShaderFileName, String fragmentShaderFileName) { 36 | super(vertexShaderFileName, null, fragmentShaderFileName); 37 | } 38 | 39 | public void bindBuffer(GL2ES2 gl) { 40 | gl.glEnableVertexAttribArray(vertCoordLocation); 41 | vertCoordBuffer = ensureIsGLBuffer(gl, vertCoordBuffer); 42 | 43 | gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vertCoordBuffer); 44 | gl.glVertexAttribPointer(vertCoordLocation, 2, GL.GL_FLOAT, false, 0, 0); 45 | } 46 | 47 | public void bindBufferData(GL2ES2 gl, FloatBuffer vertexBuffer) { 48 | bindBuffer(gl); 49 | 50 | int count = vertexBuffer.limit() - vertexBuffer.position(); 51 | gl.glBufferData(GL.GL_ARRAY_BUFFER, Buffers.SIZEOF_FLOAT * count, vertexBuffer, GL2ES2.GL_STREAM_DRAW); 52 | } 53 | 54 | public void unbindBuffer(GL2ES2 gl) { 55 | gl.glDisableVertexAttribArray(vertCoordLocation); 56 | gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); 57 | } 58 | 59 | public void draw(GL2ES2 gl, int mode, FloatBuffer vertexBuffer) { 60 | bindBufferData(gl, vertexBuffer); 61 | 62 | int numPts = (vertexBuffer.limit() - vertexBuffer.position()) / 2; 63 | gl.glDrawArrays(mode, 0, numPts); 64 | 65 | unbindBuffer(gl); 66 | } 67 | 68 | @Override 69 | protected void setupUniformsAndAttributes(GL2ES2 gl) { 70 | super.setupUniformsAndAttributes(gl); 71 | 72 | transformLocation = gl.glGetUniformLocation(programId, "u_transform"); 73 | colorLocation = gl.glGetUniformLocation(programId, "u_color"); 74 | 75 | vertCoordLocation = gl.glGetAttribLocation(programId, "a_vertCoord"); 76 | } 77 | 78 | @Override 79 | public void delete(GL2ES2 gl) { 80 | super.delete(gl); 81 | 82 | if (gl.glIsBuffer(vertCoordBuffer)) { 83 | gl.glDeleteBuffers(1, new int[] { vertCoordBuffer }, 0); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/gl2/GL2Transformhelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.gl2; 17 | 18 | import java.awt.geom.AffineTransform; 19 | 20 | import com.jogamp.opengl.GL; 21 | import com.jogamp.opengl.GL2; 22 | import com.jogamp.opengl.fixedfunc.GLMatrixFunc; 23 | 24 | import org.jogamp.glg2d.GLGraphics2D; 25 | import org.jogamp.glg2d.impl.AbstractMatrixHelper; 26 | 27 | public class GL2Transformhelper extends AbstractMatrixHelper { 28 | protected GL2 gl; 29 | 30 | private float[] matrixBuf = new float[16]; 31 | 32 | @Override 33 | public void setG2D(GLGraphics2D g2d) { 34 | super.setG2D(g2d); 35 | gl = g2d.getGLContext().getGL().getGL2(); 36 | 37 | setupGLView(); 38 | flushTransformToOpenGL(); 39 | } 40 | 41 | protected void setupGLView() { 42 | int[] viewportDimensions = new int[4]; 43 | gl.glGetIntegerv(GL.GL_VIEWPORT, viewportDimensions, 0); 44 | int width = viewportDimensions[2]; 45 | int height = viewportDimensions[3]; 46 | 47 | // setup projection 48 | gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION); 49 | gl.glLoadIdentity(); 50 | gl.glOrtho(0, width, 0, height, -1, 1); 51 | 52 | // the MODELVIEW matrix will get adjusted later 53 | 54 | gl.glMatrixMode(GL.GL_TEXTURE); 55 | gl.glLoadIdentity(); 56 | } 57 | 58 | /** 59 | * Sends the {@code AffineTransform} that's on top of the stack to the video 60 | * card. 61 | */ 62 | protected void flushTransformToOpenGL() { 63 | float[] matrix = getGLMatrix(stack.peek()); 64 | 65 | gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); 66 | gl.glLoadMatrixf(matrix, 0); 67 | } 68 | 69 | /** 70 | * Gets the GL matrix for the {@code AffineTransform} with the change of 71 | * coordinates inlined. Since Java2D uses the upper-left as 0,0 and OpenGL 72 | * uses the lower-left as 0,0, we have to pre-multiply the matrix before 73 | * loading it onto the video card. 74 | */ 75 | protected float[] getGLMatrix(AffineTransform transform) { 76 | matrixBuf[0] = (float) transform.getScaleX(); 77 | matrixBuf[1] = -(float) transform.getShearY(); 78 | matrixBuf[4] = (float) transform.getShearX(); 79 | matrixBuf[5] = -(float) transform.getScaleY(); 80 | matrixBuf[10] = 1; 81 | matrixBuf[12] = (float) transform.getTranslateX(); 82 | matrixBuf[13] = g2d.getCanvasHeight() - (float) transform.getTranslateY(); 83 | matrixBuf[15] = 1; 84 | 85 | return matrixBuf; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/gl2/GL2ImageDrawer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.gl2; 17 | 18 | import java.awt.Color; 19 | import java.awt.geom.AffineTransform; 20 | 21 | import com.jogamp.opengl.GL; 22 | import com.jogamp.opengl.GL2; 23 | import com.jogamp.opengl.GL2ES1; 24 | 25 | import org.jogamp.glg2d.GLGraphics2D; 26 | import org.jogamp.glg2d.impl.AbstractImageHelper; 27 | 28 | import com.jogamp.opengl.util.texture.Texture; 29 | 30 | public class GL2ImageDrawer extends AbstractImageHelper { 31 | protected GL2 gl; 32 | 33 | protected AffineTransform savedTransform; 34 | 35 | @Override 36 | public void setG2D(GLGraphics2D g2d) { 37 | super.setG2D(g2d); 38 | gl = g2d.getGLContext().getGL().getGL2(); 39 | } 40 | 41 | @Override 42 | protected void begin(Texture texture, AffineTransform xform, Color bgcolor) { 43 | gl.glTexEnvi(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_TEXTURE_ENV_MODE, GL2ES1.GL_MODULATE); 44 | gl.glTexParameterf(GL2ES1.GL_TEXTURE_ENV, GL2ES1.GL_TEXTURE_ENV_MODE, GL.GL_BLEND); 45 | 46 | /* 47 | * FIXME This is unexpected since we never disable blending, but in some 48 | * cases it interacts poorly with multiple split panes, scroll panes and the 49 | * text renderer to disable blending. 50 | */ 51 | g2d.setComposite(g2d.getComposite()); 52 | 53 | texture.enable(gl); 54 | texture.bind(gl); 55 | 56 | savedTransform = null; 57 | if (xform != null && !xform.isIdentity()) { 58 | savedTransform = g2d.getTransform(); 59 | g2d.transform(xform); 60 | } 61 | 62 | g2d.getColorHelper().setColorRespectComposite(bgcolor == null ? Color.white : bgcolor); 63 | } 64 | 65 | @Override 66 | protected void end(Texture texture) { 67 | if (savedTransform != null) { 68 | g2d.setTransform(savedTransform); 69 | } 70 | 71 | texture.disable(gl); 72 | g2d.getColorHelper().setColorRespectComposite(g2d.getColor()); 73 | } 74 | 75 | @Override 76 | protected void applyTexture(Texture texture, int dx1, int dy1, int dx2, int dy2, float sx1, float sy1, float sx2, float sy2) { 77 | gl.glBegin(GL2.GL_QUADS); 78 | 79 | // SW 80 | gl.glTexCoord2f(sx1, sy2); 81 | gl.glVertex2i(dx1, dy2); 82 | // SE 83 | gl.glTexCoord2f(sx2, sy2); 84 | gl.glVertex2i(dx2, dy2); 85 | // NE 86 | gl.glTexCoord2f(sx2, sy1); 87 | gl.glVertex2i(dx2, dy1); 88 | // NW 89 | gl.glTexCoord2f(sx1, sy1); 90 | gl.glVertex2i(dx1, dy1); 91 | 92 | gl.glEnd(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/GLGraphicsConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl; 17 | 18 | import java.awt.GraphicsConfiguration; 19 | import java.awt.GraphicsDevice; 20 | import java.awt.Rectangle; 21 | import java.awt.Transparency; 22 | import java.awt.geom.AffineTransform; 23 | import java.awt.image.BufferedImage; 24 | import java.awt.image.ColorModel; 25 | import java.awt.image.DirectColorModel; 26 | 27 | import com.jogamp.opengl.GLDrawable; 28 | 29 | /** 30 | * Fulfills the contract of a {@code GraphicsConfiguration}. 31 | * 32 | *

33 | * Implementation note: this object is intended primarily to allow callers to 34 | * create compatible images. The transforms and bounds should be thought out 35 | * before being used. 36 | *

37 | */ 38 | public class GLGraphicsConfiguration extends GraphicsConfiguration { 39 | private final GLDrawable target; 40 | 41 | private final GLGraphicsDevice device; 42 | 43 | public GLGraphicsConfiguration(GLDrawable drawable) { 44 | target = drawable; 45 | device = new GLGraphicsDevice(this); 46 | } 47 | 48 | @Override 49 | public GraphicsDevice getDevice() { 50 | return device; 51 | } 52 | 53 | @Override 54 | public BufferedImage createCompatibleImage(int width, int height) { 55 | return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 56 | } 57 | 58 | /* 59 | * Any reasonable {@code ColorModel} can be transformed into a texture we can 60 | * render in OpenGL. I'm not worried about creating an exactly correct one 61 | * right now. 62 | */ 63 | @Override 64 | public ColorModel getColorModel() { 65 | return ColorModel.getRGBdefault(); 66 | } 67 | 68 | @Override 69 | public ColorModel getColorModel(int transparency) { 70 | switch (transparency) { 71 | case Transparency.OPAQUE: 72 | case Transparency.TRANSLUCENT: 73 | return getColorModel(); 74 | case Transparency.BITMASK: 75 | return new DirectColorModel(25, 0xff0000, 0xff00, 0xff, 0x1000000); 76 | default: 77 | return null; 78 | } 79 | } 80 | 81 | @Override 82 | public AffineTransform getDefaultTransform() { 83 | return new AffineTransform(); 84 | } 85 | 86 | @Override 87 | public AffineTransform getNormalizingTransform() { 88 | return new AffineTransform(); 89 | } 90 | 91 | @Override 92 | public Rectangle getBounds() { 93 | return new Rectangle(target.getSurfaceWidth(), target.getSurfaceHeight()); 94 | } 95 | 96 | public GLDrawable getTarget() { 97 | return target; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/util/AutoTester.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d.util; 2 | 3 | import java.awt.Graphics2D; 4 | import java.awt.image.BufferedImage; 5 | import java.awt.image.Raster; 6 | 7 | import com.jogamp.opengl.GLDrawableFactory; 8 | import com.jogamp.opengl.GLOffscreenAutoDrawable; 9 | import com.jogamp.opengl.GLProfile; 10 | import javax.swing.ImageIcon; 11 | import javax.swing.JLabel; 12 | import javax.swing.JPanel; 13 | import javax.swing.JSplitPane; 14 | 15 | import org.jogamp.glg2d.GLG2DCanvas; 16 | import org.jogamp.glg2d.GLG2DSimpleEventListener; 17 | import org.jogamp.glg2d.GLGraphics2D; 18 | import org.junit.Assert; 19 | 20 | import com.jogamp.opengl.util.awt.AWTGLReadBufferUtil; 21 | 22 | public class AutoTester implements Tester { 23 | static final int pixels = 500; 24 | 25 | 26 | static GLOffscreenAutoDrawable buffer = GLDrawableFactory.getFactory(GLProfile.getMaxFixedFunc(true)) 27 | .createOffscreenAutoDrawable(null, GLG2DCanvas.getDefaultCapabalities(), null, pixels, pixels); 28 | 29 | private Painter p; 30 | 31 | @Override 32 | public void assertSame() throws InterruptedException { 33 | Assert.assertEquals(1, getSimilarityScore(p), 0.05); 34 | } 35 | 36 | @Override 37 | public void setPainter(Painter p) { 38 | this.p = p; 39 | } 40 | 41 | @Override 42 | public void finish() { 43 | } 44 | 45 | public double getSimilarityScore(Painter painter) { 46 | BufferedImage gl = drawGL(painter); 47 | Raster rasterGl = gl.getData(); 48 | BufferedImage g2d = drawG2D(painter); 49 | Raster rasterG2d = g2d.getData(); 50 | 51 | // very naive for now 52 | for (int band = 0; band < rasterGl.getNumBands(); band++) { 53 | for (int row = 0; row < gl.getWidth(); row++) { 54 | for (int col = 0; col < gl.getHeight(); col++) { 55 | if (rasterGl.getSample(row, col, band) != rasterG2d.getSample(row, col, band)) { 56 | return 0; 57 | } 58 | } 59 | } 60 | } 61 | 62 | return 1; 63 | } 64 | 65 | public JSplitPane getComparison(Painter painter) { 66 | JSplitPane split = new JSplitPane(); 67 | split.setLeftComponent(new JLabel(new ImageIcon(drawGL(painter)))); 68 | split.setRightComponent(new JLabel(new ImageIcon(drawG2D(painter)))); 69 | return split; 70 | } 71 | 72 | public static BufferedImage drawG2D(Painter painter) { 73 | BufferedImage img = new BufferedImage(pixels, pixels, BufferedImage.TYPE_INT_RGB); 74 | Graphics2D g2d = (Graphics2D) img.getGraphics(); 75 | g2d.setColor(new JPanel().getBackground()); 76 | g2d.fillRect(0, 0, pixels, pixels); 77 | painter.paint(g2d); 78 | return img; 79 | } 80 | 81 | public static BufferedImage drawGL(final Painter painter) { 82 | JPanel panel = new JPanel(); 83 | panel.setSize(pixels, pixels); 84 | buffer.addGLEventListener(new GLG2DSimpleEventListener(panel) { 85 | @Override 86 | protected void paintGL(GLGraphics2D g2d) { 87 | painter.paint(g2d); 88 | } 89 | }); 90 | 91 | buffer.display(); 92 | buffer.getContext().makeCurrent(); 93 | AWTGLReadBufferUtil util = new AWTGLReadBufferUtil(GLG2DCanvas.getDefaultCapabalities().getGLProfile(), false); 94 | return util.readPixelsToBufferedImage( buffer.getContext().getGL( ), true ); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/G2DDrawingHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.awt.RenderingHints; 19 | 20 | /** 21 | * Assists in the drawing of a particular aspect of the Graphics2D object. This 22 | * allows the drawing to be segregated into certain aspects, such as image, text 23 | * or shape drawing. 24 | */ 25 | public interface G2DDrawingHelper { 26 | /** 27 | * Sets the current {@code GLGraphics2D} parent. The current {@code GL} and 28 | * {@code GLContext} objects can be accessed from this. This should clear all 29 | * internal stacks in the helper object because previous painting iterations 30 | * may not have called dispose() for each time they called create(). 31 | * 32 | * @param g2d 33 | * The parent context for subsequent drawing operations. 34 | */ 35 | void setG2D(GLGraphics2D g2d); 36 | 37 | /** 38 | * Sets the new {@code GLGraphics2D} context in a stack. This is called when 39 | * {@code Graphics2D.create()} is called and each helper is given notice to 40 | * push any necessary information onto the stack. This is used in conjunction 41 | * with {@link #pop(GLGraphics2D)}. 42 | * 43 | * @param newG2d 44 | * The new context, top of the stack. 45 | */ 46 | void push(GLGraphics2D newG2d); 47 | 48 | /** 49 | * Sets the new {@code GLGraphics2D} context in a stack after a pop. This is 50 | * called when {@code Graphics2D.dispose()} is called and each helper is given 51 | * notice to pop any necessary information off the stack. This is used in 52 | * conjunction with {@link #push(GLGraphics2D)}. 53 | * 54 | * @param parentG2d 55 | * The new context, top of the stack - which is actually the parent 56 | * of what was popped. 57 | */ 58 | void pop(GLGraphics2D parentG2d); 59 | 60 | /** 61 | * Sets a new rendering hint. The state of all rendering hints is kept by the 62 | * {@code GLGraphics2D} object, but all new state changes are propagated to 63 | * all listeners. 64 | * 65 | * @param key 66 | * The rendering hint key. 67 | * @param value 68 | * The new hint value. 69 | */ 70 | void setHint(RenderingHints.Key key, Object value); 71 | 72 | /** 73 | * Clears all hints back to their default states. 74 | */ 75 | void resetHints(); 76 | 77 | /** 78 | * Disposes the helper object. This is not called during the dispose operation 79 | * of the {@code Graphics2D} object. This should dispose all GL resources when 80 | * all drawing is finished and no more calls will be executing on this OpenGL 81 | * context and these resources. 82 | */ 83 | void dispose(); 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/GLG2DPanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.awt.Component; 19 | import java.awt.Graphics; 20 | 21 | import com.jogamp.opengl.GLAutoDrawable; 22 | import com.jogamp.opengl.GLCapabilities; 23 | import com.jogamp.opengl.GLCapabilitiesImmutable; 24 | import com.jogamp.opengl.GLContext; 25 | import com.jogamp.opengl.awt.GLCanvas; 26 | import javax.swing.JComponent; 27 | 28 | import org.jogamp.glg2d.event.AWTMouseEventTranslator; 29 | 30 | /** 31 | * This wraps an AWT component hierarchy and paints it using OpenGL. The 32 | * drawable component can be any JComponent. 33 | * 34 | *

35 | * If painting a simple scene using the 36 | * {@link JComponent#paintComponents(Graphics)}, then use {@link GLG2DCanvas}. 37 | *

38 | * 39 | *

40 | * GL drawing can be enabled or disabled using the {@code setGLDrawing(boolean)} 41 | * method. If GL drawing is enabled, all full paint requests are intercepted and 42 | * the drawable component is drawn to the OpenGL canvas. 43 | *

44 | */ 45 | public class GLG2DPanel extends GLG2DCanvas { 46 | private static final long serialVersionUID = 83442176852921790L; 47 | 48 | private AWTMouseEventTranslator mouseListener; 49 | 50 | public GLG2DPanel(GLCapabilities capabilities, JComponent drawableComponent) { 51 | super(capabilities, drawableComponent); 52 | } 53 | 54 | public GLG2DPanel(JComponent drawableComponent) { 55 | super(drawableComponent); 56 | } 57 | 58 | @Override 59 | public void setDrawableComponent(JComponent component) { 60 | if (mouseListener != null) { 61 | mouseListener = null; 62 | 63 | Component c = (Component) canvas; 64 | c.removeMouseListener(mouseListener); 65 | c.removeMouseMotionListener(mouseListener); 66 | c.removeMouseWheelListener(mouseListener); 67 | } 68 | 69 | super.setDrawableComponent(component); 70 | 71 | if (getDrawableComponent() != null && canvas instanceof Component) { 72 | mouseListener = new AWTMouseEventTranslator(getDrawableComponent()); 73 | 74 | Component c = (Component) canvas; 75 | c.addMouseListener(mouseListener); 76 | c.addMouseMotionListener(mouseListener); 77 | c.addMouseWheelListener(mouseListener); 78 | } 79 | } 80 | 81 | @Override 82 | protected GLAutoDrawable createGLComponent(GLCapabilitiesImmutable capabilities, GLContext shareWith) { 83 | GLAutoDrawable canvas = super.createGLComponent(capabilities, shareWith); 84 | if (canvas instanceof GLCanvas) { 85 | ((GLCanvas) canvas).setEnabled(true); 86 | } 87 | 88 | return canvas; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/examples/shaders/DepthSimExample.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d.examples.shaders; 2 | 3 | import java.awt.Dimension; 4 | import java.awt.RenderingHints.Key; 5 | import java.awt.event.ActionEvent; 6 | import java.awt.event.ActionListener; 7 | 8 | import com.jogamp.opengl.GL2; 9 | import com.jogamp.opengl.GLAutoDrawable; 10 | import javax.swing.JComponent; 11 | import javax.swing.JFrame; 12 | import javax.swing.Timer; 13 | import javax.swing.UIManager; 14 | 15 | import org.jogamp.glg2d.G2DDrawingHelper; 16 | import org.jogamp.glg2d.GLG2DCanvas; 17 | import org.jogamp.glg2d.GLG2DSimpleEventListener; 18 | import org.jogamp.glg2d.GLGraphics2D; 19 | import org.jogamp.glg2d.UIDemo; 20 | 21 | @SuppressWarnings("serial") 22 | public class DepthSimExample { 23 | public static void main(String[] args) throws Exception { 24 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 25 | 26 | final JFrame frame = new JFrame("Depth Shaker Example"); 27 | frame.setContentPane(new GLG2DCanvas(new UIDemo()) { 28 | @Override 29 | protected GLG2DSimpleEventListener createG2DListener(JComponent drawingComponent) { 30 | return new GLG2DSimpleEventListener(drawingComponent) { 31 | @Override 32 | protected GLGraphics2D createGraphics2D(GLAutoDrawable drawable) { 33 | return new GLGraphics2D() { 34 | @Override 35 | protected void createDrawingHelpers() { 36 | super.createDrawingHelpers(); 37 | 38 | addG2DDrawingHelper(new DepthShaker()); 39 | } 40 | 41 | @Override 42 | protected void scissor(boolean enable) { 43 | // nop 44 | } 45 | }; 46 | } 47 | }; 48 | } 49 | }); 50 | 51 | Timer timer = new Timer(100, new ActionListener() { 52 | @Override 53 | public void actionPerformed(ActionEvent e) { 54 | frame.getContentPane().repaint(); 55 | } 56 | }); 57 | timer.setRepeats(true); 58 | timer.start(); 59 | 60 | // frame.setContentPane(new UIDemo()); 61 | frame.setPreferredSize(new Dimension(1024, 768)); 62 | frame.pack(); 63 | frame.setLocationRelativeTo(null); 64 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 65 | frame.setVisible(true); 66 | } 67 | 68 | static class DepthShaker implements G2DDrawingHelper { 69 | double shiftX; 70 | double shiftY; 71 | 72 | double theta = 0; 73 | 74 | GL2 gl; 75 | 76 | @Override 77 | public void dispose() { 78 | } 79 | 80 | @Override 81 | public void pop(GLGraphics2D parentG2d) { 82 | gl.glTranslated(-shiftX, -shiftY, 0); 83 | } 84 | 85 | @Override 86 | public void push(GLGraphics2D newG2d) { 87 | gl.glTranslated(shiftX, shiftY, 0); 88 | } 89 | 90 | @Override 91 | public void resetHints() { 92 | } 93 | 94 | @Override 95 | public void setHint(Key key, Object value) { 96 | } 97 | 98 | @Override 99 | public void setG2D(GLGraphics2D g2d) { 100 | theta += 0.2; 101 | shiftX = Math.round(Math.sin(theta) * 100) / 100d * 1; 102 | shiftY = Math.round(Math.cos(theta) * 100) / 100d * 1; 103 | 104 | gl = g2d.getGLContext().getGL().getGL2(); 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/GL2ES2ImagePipeline.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | import static org.jogamp.glg2d.GLG2DUtils.ensureIsGLBuffer; 19 | 20 | import java.nio.FloatBuffer; 21 | 22 | import com.jogamp.opengl.GL; 23 | import com.jogamp.opengl.GL2ES2; 24 | 25 | import com.jogamp.common.nio.Buffers; 26 | 27 | public class GL2ES2ImagePipeline extends AbstractShaderPipeline { 28 | protected int vertexBufferId = -1; 29 | 30 | protected int textureLocation = -1; 31 | protected int vertCoordLocation = -1; 32 | protected int texCoordLocation = -1; 33 | 34 | public GL2ES2ImagePipeline() { 35 | this("TextureShader.v", "TextureShader.f"); 36 | } 37 | 38 | public GL2ES2ImagePipeline(String vertexShaderFileName, String fragmentShaderFileName) { 39 | super(vertexShaderFileName, null, fragmentShaderFileName); 40 | } 41 | 42 | public void setTextureUnit(GL2ES2 gl, int unit) { 43 | if (textureLocation >= 0) { 44 | gl.glUniform1i(textureLocation, unit); 45 | } 46 | } 47 | 48 | protected void bufferData(GL2ES2 gl, FloatBuffer buffer) { 49 | vertexBufferId = ensureIsGLBuffer(gl, vertexBufferId); 50 | 51 | gl.glEnableVertexAttribArray(vertCoordLocation); 52 | gl.glEnableVertexAttribArray(texCoordLocation); 53 | 54 | gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vertexBufferId); 55 | gl.glBufferData(GL.GL_ARRAY_BUFFER, Buffers.SIZEOF_FLOAT * 16, buffer, GL.GL_STATIC_DRAW); 56 | 57 | gl.glVertexAttribPointer(vertCoordLocation, 2, GL.GL_FLOAT, false, 4 * Buffers.SIZEOF_FLOAT, 0); 58 | gl.glVertexAttribPointer(texCoordLocation, 2, GL.GL_FLOAT, false, 4 * Buffers.SIZEOF_FLOAT, 2 * Buffers.SIZEOF_FLOAT); 59 | } 60 | 61 | public void draw(GL2ES2 gl, FloatBuffer interleavedVertTexBuffer) { 62 | bufferData(gl, interleavedVertTexBuffer); 63 | 64 | gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); 65 | 66 | gl.glDisableVertexAttribArray(vertCoordLocation); 67 | gl.glDisableVertexAttribArray(texCoordLocation); 68 | gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); 69 | } 70 | 71 | @Override 72 | protected void setupUniformsAndAttributes(GL2ES2 gl) { 73 | super.setupUniformsAndAttributes(gl); 74 | 75 | transformLocation = gl.glGetUniformLocation(programId, "u_transform"); 76 | colorLocation = gl.glGetUniformLocation(programId, "u_color"); 77 | textureLocation = gl.glGetUniformLocation(programId, "u_tex"); 78 | 79 | vertCoordLocation = gl.glGetAttribLocation(programId, "a_vertCoord"); 80 | texCoordLocation = gl.glGetAttribLocation(programId, "a_texCoord"); 81 | } 82 | 83 | @Override 84 | public void delete(GL2ES2 gl) { 85 | super.delete(gl); 86 | 87 | if (gl.glIsBuffer(vertexBufferId)) { 88 | gl.glDeleteBuffers(1, new int[] { vertexBufferId }, 0); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/gl2/GL2ShapeDrawer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.gl2; 17 | 18 | 19 | import java.awt.BasicStroke; 20 | import java.awt.RenderingHints; 21 | import java.awt.RenderingHints.Key; 22 | import java.awt.Shape; 23 | import java.awt.Stroke; 24 | 25 | import com.jogamp.opengl.GL; 26 | import com.jogamp.opengl.GL2; 27 | 28 | import org.jogamp.glg2d.GLGraphics2D; 29 | import org.jogamp.glg2d.impl.AbstractShapeHelper; 30 | import org.jogamp.glg2d.impl.SimpleOrTesselatingVisitor; 31 | 32 | public class GL2ShapeDrawer extends AbstractShapeHelper { 33 | protected GL2 gl; 34 | 35 | protected FillSimpleConvexPolygonVisitor simpleFillVisitor; 36 | protected SimpleOrTesselatingVisitor complexFillVisitor; 37 | protected LineDrawingVisitor simpleStrokeVisitor; 38 | protected FastLineVisitor fastLineVisitor; 39 | 40 | public GL2ShapeDrawer() { 41 | simpleFillVisitor = new FillSimpleConvexPolygonVisitor(); 42 | complexFillVisitor = new SimpleOrTesselatingVisitor(simpleFillVisitor, new GL2TesselatorVisitor()); 43 | simpleStrokeVisitor = new LineDrawingVisitor(); 44 | fastLineVisitor = new FastLineVisitor(); 45 | } 46 | 47 | @Override 48 | public void setG2D(GLGraphics2D g2d) { 49 | super.setG2D(g2d); 50 | GL gl = g2d.getGLContext().getGL(); 51 | simpleFillVisitor.setGLContext(gl); 52 | complexFillVisitor.setGLContext(gl); 53 | simpleStrokeVisitor.setGLContext(gl); 54 | fastLineVisitor.setGLContext(gl); 55 | 56 | this.gl = gl.getGL2(); 57 | } 58 | 59 | @Override 60 | public void setHint(Key key, Object value) { 61 | super.setHint(key, value); 62 | 63 | if (key == RenderingHints.KEY_ANTIALIASING) { 64 | if (value == RenderingHints.VALUE_ANTIALIAS_ON) { 65 | gl.glEnable(GL.GL_MULTISAMPLE); 66 | } else { 67 | gl.glDisable(GL.GL_MULTISAMPLE); 68 | } 69 | } 70 | } 71 | 72 | @Override 73 | public void draw(Shape shape) { 74 | Stroke stroke = getStroke(); 75 | if (stroke instanceof BasicStroke) { 76 | BasicStroke basicStroke = (BasicStroke) stroke; 77 | if (fastLineVisitor.isValid(basicStroke)) { 78 | fastLineVisitor.setStroke(basicStroke); 79 | traceShape(shape, fastLineVisitor); 80 | return; 81 | } else if (basicStroke.getDashArray() == null) { 82 | simpleStrokeVisitor.setStroke(basicStroke); 83 | traceShape(shape, simpleStrokeVisitor); 84 | return; 85 | } 86 | } 87 | 88 | // can fall through for various reasons 89 | fill(stroke.createStrokedShape(shape)); 90 | } 91 | 92 | @Override 93 | protected void fill(Shape shape, boolean forceSimple) { 94 | if (forceSimple) { 95 | traceShape(shape, simpleFillVisitor); 96 | } else { 97 | traceShape(shape, complexFillVisitor); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/text/TriangleStripTesselator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader.text; 17 | 18 | import static java.lang.Math.ceil; 19 | 20 | import java.nio.FloatBuffer; 21 | import java.util.ArrayList; 22 | import java.util.Collection; 23 | 24 | import com.jogamp.opengl.GL; 25 | 26 | import org.jogamp.glg2d.impl.AbstractTesselatorVisitor; 27 | 28 | public class TriangleStripTesselator extends AbstractTesselatorVisitor { 29 | protected Collection triangleStrips; 30 | 31 | @Override 32 | public void setGLContext(GL context) { 33 | // nop 34 | } 35 | 36 | @Override 37 | public void beginPoly(int windingRule) { 38 | super.beginPoly(windingRule); 39 | 40 | vBuffer.clear(); 41 | triangleStrips = new ArrayList(); 42 | } 43 | 44 | @Override 45 | protected void configureTesselator(int windingRule) { 46 | super.configureTesselator(windingRule); 47 | } 48 | 49 | @Override 50 | protected void endTess() { 51 | FloatBuffer buf = vBuffer.getBuffer(); 52 | buf.flip(); 53 | 54 | triangleStrips.addAll(getStrips(drawMode, buf)); 55 | vBuffer.clear(); 56 | } 57 | 58 | public Collection getTesselated() { 59 | return triangleStrips; 60 | } 61 | 62 | protected Collection getStrips(int drawMode, FloatBuffer vertexBuffer) { 63 | int size = vertexBuffer.limit() - vertexBuffer.position(); 64 | Collection strips = new ArrayList(); 65 | 66 | if (drawMode == GL.GL_TRIANGLE_STRIP) { 67 | float[] v = new float[size]; 68 | vertexBuffer.get(v); 69 | strips.add(new TriangleStrip(v)); 70 | } else if (drawMode == GL.GL_TRIANGLES) { 71 | float[] v = new float[6]; 72 | while (vertexBuffer.remaining() >= 6) { 73 | vertexBuffer.get(v); 74 | strips.add(new TriangleStrip(v.clone())); 75 | } 76 | } else if (drawMode == GL.GL_TRIANGLE_FAN) { 77 | int newSize = (int) ceil((size - 2) / 4.0) + size; 78 | float[] v = new float[newSize]; 79 | 80 | float origX = vertexBuffer.get(); 81 | float origY = vertexBuffer.get(); 82 | v[0] = origX; 83 | v[1] = origY; 84 | 85 | int index = 2; 86 | while (vertexBuffer.remaining() >= 4) { 87 | vertexBuffer.get(v, index, 4); 88 | index += 4; 89 | v[index++] = origX; 90 | v[index++] = origY; 91 | } 92 | 93 | if (vertexBuffer.remaining() >= 2) { 94 | vertexBuffer.get(v, index, 2); 95 | index += 2; 96 | v[index++] = origX; 97 | v[index++] = origY; 98 | } 99 | 100 | strips.add(new TriangleStrip(v)); 101 | } 102 | 103 | return strips; 104 | } 105 | 106 | public static class TriangleStrip { 107 | public final float[] vertices; 108 | 109 | public TriangleStrip(float[] vertices) { 110 | this.vertices = vertices; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/AbstractMatrixHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl; 17 | 18 | import java.awt.RenderingHints.Key; 19 | import java.awt.geom.AffineTransform; 20 | import java.util.ArrayDeque; 21 | import java.util.Deque; 22 | 23 | import org.jogamp.glg2d.GLG2DTransformHelper; 24 | import org.jogamp.glg2d.GLGraphics2D; 25 | 26 | public abstract class AbstractMatrixHelper implements GLG2DTransformHelper { 27 | protected GLGraphics2D g2d; 28 | 29 | protected Deque stack = new ArrayDeque(); 30 | 31 | @Override 32 | public void setG2D(GLGraphics2D g2d) { 33 | this.g2d = g2d; 34 | 35 | stack.clear(); 36 | stack.push(new AffineTransform()); 37 | } 38 | 39 | @Override 40 | public void push(GLGraphics2D newG2d) { 41 | stack.push(getTransform()); 42 | } 43 | 44 | @Override 45 | public void pop(GLGraphics2D parentG2d) { 46 | stack.pop(); 47 | flushTransformToOpenGL(); 48 | } 49 | 50 | @Override 51 | public void setHint(Key key, Object value) { 52 | // nop 53 | } 54 | 55 | @Override 56 | public void resetHints() { 57 | // nop 58 | } 59 | 60 | @Override 61 | public void dispose() { 62 | // nop 63 | } 64 | 65 | @Override 66 | public void translate(int x, int y) { 67 | translate((double) x, (double) y); 68 | flushTransformToOpenGL(); 69 | } 70 | 71 | @Override 72 | public void translate(double tx, double ty) { 73 | getTransform0().translate(tx, ty); 74 | flushTransformToOpenGL(); 75 | } 76 | 77 | @Override 78 | public void rotate(double theta) { 79 | getTransform0().rotate(theta); 80 | flushTransformToOpenGL(); 81 | } 82 | 83 | @Override 84 | public void rotate(double theta, double x, double y) { 85 | getTransform0().rotate(theta, x, y); 86 | flushTransformToOpenGL(); 87 | } 88 | 89 | @Override 90 | public void scale(double sx, double sy) { 91 | getTransform0().scale(sx, sy); 92 | flushTransformToOpenGL(); 93 | } 94 | 95 | @Override 96 | public void shear(double shx, double shy) { 97 | getTransform0().shear(shx, shy); 98 | flushTransformToOpenGL(); 99 | } 100 | 101 | @Override 102 | public void transform(AffineTransform Tx) { 103 | getTransform0().concatenate(Tx); 104 | flushTransformToOpenGL(); 105 | } 106 | 107 | @Override 108 | public void setTransform(AffineTransform transform) { 109 | getTransform0().setTransform(transform); 110 | flushTransformToOpenGL(); 111 | } 112 | 113 | @Override 114 | public AffineTransform getTransform() { 115 | return (AffineTransform) getTransform0().clone(); 116 | } 117 | 118 | /** 119 | * Returns the {@code AffineTransform} at the top of the stack, not a 120 | * copy. 121 | */ 122 | protected AffineTransform getTransform0() { 123 | return stack.peek(); 124 | } 125 | 126 | /** 127 | * Sends the {@code AffineTransform} that's on top of the stack to the video 128 | * card. 129 | */ 130 | protected abstract void flushTransformToOpenGL(); 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/GL2ES2SimpleConvexFillVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | 19 | import java.awt.BasicStroke; 20 | import java.nio.FloatBuffer; 21 | 22 | import com.jogamp.opengl.GL; 23 | import com.jogamp.opengl.GL2ES2; 24 | 25 | import org.jogamp.glg2d.VertexBuffer; 26 | import org.jogamp.glg2d.impl.SimplePathVisitor; 27 | 28 | public class GL2ES2SimpleConvexFillVisitor extends SimplePathVisitor implements ShaderPathVisitor { 29 | protected GL2ES2 gl; 30 | protected UniformBufferObject uniforms; 31 | 32 | protected VertexBuffer vBuffer = new VertexBuffer(1024); 33 | 34 | protected AnyModePipeline pipeline; 35 | 36 | public GL2ES2SimpleConvexFillVisitor() { 37 | this(new AnyModePipeline()); 38 | } 39 | 40 | public GL2ES2SimpleConvexFillVisitor(AnyModePipeline pipeline) { 41 | this.pipeline = pipeline; 42 | } 43 | 44 | @Override 45 | public void setGLContext(GL glContext, UniformBufferObject uniforms) { 46 | setGLContext(glContext); 47 | 48 | this.uniforms = uniforms; 49 | } 50 | 51 | @Override 52 | public void setGLContext(GL context) { 53 | gl = context.getGL2ES2(); 54 | 55 | if (!pipeline.isSetup()) { 56 | pipeline.setup(gl); 57 | } 58 | } 59 | 60 | @Override 61 | public void setStroke(BasicStroke stroke) { 62 | // nop 63 | } 64 | 65 | @Override 66 | public void beginPoly(int windingRule) { 67 | // do we need to care about winding rule? 68 | pipeline.use(gl, true); 69 | 70 | pipeline.setColor(gl, uniforms.colorHook.getRGBA()); 71 | pipeline.setTransform(gl, uniforms.transformHook.getGLMatrixData()); 72 | 73 | vBuffer.clear(); 74 | vBuffer.addVertex(0, 0); 75 | } 76 | 77 | @Override 78 | public void moveTo(float[] vertex) { 79 | draw(); 80 | 81 | vBuffer.addVertex(vertex[0], vertex[1]); 82 | } 83 | 84 | @Override 85 | public void lineTo(float[] vertex) { 86 | vBuffer.addVertex(vertex[0], vertex[1]); 87 | } 88 | 89 | @Override 90 | public void closeLine() { 91 | FloatBuffer buf = vBuffer.getBuffer(); 92 | float x = buf.get(2); 93 | float y = buf.get(3); 94 | vBuffer.addVertex(x, y); 95 | } 96 | 97 | @Override 98 | public void endPoly() { 99 | draw(); 100 | pipeline.use(gl, false); 101 | } 102 | 103 | protected void draw() { 104 | FloatBuffer buf = vBuffer.getBuffer(); 105 | if (buf.position() <= 2) { 106 | buf.position(2); 107 | return; 108 | } 109 | 110 | buf.flip(); 111 | 112 | setupCentroid(buf); 113 | 114 | pipeline.draw(gl, GL.GL_TRIANGLE_FAN, buf); 115 | 116 | vBuffer.clear(); 117 | vBuffer.addVertex(0, 0); 118 | } 119 | 120 | protected void setupCentroid(FloatBuffer vertexBuffer) { 121 | float x = 0; 122 | float y = 0; 123 | 124 | vertexBuffer.position(2); 125 | int numPts = 0; 126 | while (vertexBuffer.position() < vertexBuffer.limit()) { 127 | x += vertexBuffer.get(); 128 | y += vertexBuffer.get(); 129 | numPts++; 130 | } 131 | 132 | vertexBuffer.rewind(); 133 | vertexBuffer.put(x / numPts); 134 | vertexBuffer.put(y / numPts); 135 | 136 | vertexBuffer.rewind(); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/GL2GL3StrokeLineVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | 19 | import java.awt.BasicStroke; 20 | import java.nio.FloatBuffer; 21 | 22 | import com.jogamp.opengl.GL; 23 | import com.jogamp.opengl.GL2ES2; 24 | 25 | import org.jogamp.glg2d.VertexBuffer; 26 | import org.jogamp.glg2d.impl.SimplePathVisitor; 27 | 28 | public class GL2GL3StrokeLineVisitor extends SimplePathVisitor implements ShaderPathVisitor { 29 | protected VertexBuffer buffer = new VertexBuffer(1024); 30 | 31 | protected BasicStroke stroke; 32 | 33 | protected float[] lastV = new float[2]; 34 | 35 | protected GL2ES2 gl; 36 | protected UniformBufferObject uniforms; 37 | 38 | protected GeometryShaderStrokePipeline pipeline; 39 | 40 | public GL2GL3StrokeLineVisitor() { 41 | this(new GeometryShaderStrokePipeline()); 42 | } 43 | 44 | public GL2GL3StrokeLineVisitor(GeometryShaderStrokePipeline pipeline) { 45 | this.pipeline = pipeline; 46 | } 47 | 48 | @Override 49 | public void setGLContext(GL context) { 50 | gl = context.getGL2ES2(); 51 | 52 | if (!pipeline.isSetup()) { 53 | pipeline.setup(gl); 54 | } 55 | } 56 | 57 | @Override 58 | public void setGLContext(GL glContext, UniformBufferObject uniforms) { 59 | setGLContext(glContext); 60 | this.uniforms = uniforms; 61 | } 62 | 63 | @Override 64 | public void setStroke(BasicStroke stroke) { 65 | this.stroke = stroke; 66 | } 67 | 68 | @Override 69 | public void moveTo(float[] vertex) { 70 | draw(false); 71 | 72 | lastV[0] = vertex[0]; 73 | lastV[1] = vertex[1]; 74 | buffer.addVertex(vertex[0], vertex[1]); 75 | } 76 | 77 | @Override 78 | public void lineTo(float[] vertex) { 79 | // no 0-length lines 80 | if (vertex[0] == lastV[0] && vertex[1] == lastV[1]) { 81 | return; 82 | } 83 | 84 | buffer.addVertex(vertex, 0, 1); 85 | lastV[0] = vertex[0]; 86 | lastV[1] = vertex[1]; 87 | } 88 | 89 | @Override 90 | public void closeLine() { 91 | /* 92 | * Sometimes shapes will set the last point to be the same as the first and 93 | * then close the line. That can be confusing. So we discard the last point 94 | * if it's the same as the first. Now no 2 consecutive points are the same. 95 | */ 96 | FloatBuffer buf = buffer.getBuffer(); 97 | if (buf.get(0) == lastV[0] && buf.get(1) == lastV[1]) { 98 | buf.position(buf.position() - 2); 99 | } 100 | 101 | draw(true); 102 | } 103 | 104 | @Override 105 | public void beginPoly(int windingRule) { 106 | pipeline.use(gl, true); 107 | 108 | pipeline.setColor(gl, uniforms.colorHook.getRGBA()); 109 | pipeline.setTransform(gl, uniforms.transformHook.getGLMatrixData()); 110 | pipeline.setStroke(gl, stroke); 111 | 112 | buffer.clear(); 113 | } 114 | 115 | @Override 116 | public void endPoly() { 117 | draw(false); 118 | pipeline.use(gl, false); 119 | } 120 | 121 | protected void draw(boolean close) { 122 | FloatBuffer buf = buffer.getBuffer(); 123 | if (buf.position() == 0) { 124 | return; 125 | } 126 | 127 | buf.flip(); 128 | pipeline.draw(gl, buf, close); 129 | 130 | buffer.clear(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/AbstractTextDrawer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl; 17 | 18 | 19 | import static java.lang.Math.ceil; 20 | 21 | import java.awt.Font; 22 | import java.awt.FontMetrics; 23 | import java.awt.RenderingHints; 24 | import java.awt.RenderingHints.Key; 25 | import java.awt.font.FontRenderContext; 26 | import java.awt.geom.Rectangle2D; 27 | import java.util.ArrayDeque; 28 | import java.util.Deque; 29 | 30 | import org.jogamp.glg2d.GLG2DTextHelper; 31 | import org.jogamp.glg2d.GLGraphics2D; 32 | 33 | public abstract class AbstractTextDrawer implements GLG2DTextHelper { 34 | protected GLGraphics2D g2d; 35 | 36 | protected Deque stack = new ArrayDeque(); 37 | 38 | @Override 39 | public void setG2D(GLGraphics2D g2d) { 40 | this.g2d = g2d; 41 | 42 | stack.clear(); 43 | stack.push(new FontState()); 44 | } 45 | 46 | @Override 47 | public void push(GLGraphics2D newG2d) { 48 | stack.push(stack.peek().clone()); 49 | } 50 | 51 | @Override 52 | public void pop(GLGraphics2D parentG2d) { 53 | stack.pop(); 54 | } 55 | 56 | @Override 57 | public void setHint(Key key, Object value) { 58 | if (key == RenderingHints.KEY_TEXT_ANTIALIASING) { 59 | stack.peek().antiAlias = value == RenderingHints.VALUE_TEXT_ANTIALIAS_ON; 60 | } 61 | } 62 | 63 | @Override 64 | public void resetHints() { 65 | setHint(RenderingHints.KEY_TEXT_ANTIALIASING, null); 66 | } 67 | 68 | @Override 69 | public void setFont(Font font) { 70 | stack.peek().font = font; 71 | } 72 | 73 | @Override 74 | public Font getFont() { 75 | return stack.peek().font; 76 | } 77 | 78 | @Override 79 | public FontMetrics getFontMetrics(Font font) { 80 | return new GLFontMetrics(font, getFontRenderContext()); 81 | } 82 | 83 | @Override 84 | public FontRenderContext getFontRenderContext() { 85 | return new FontRenderContext(g2d.getTransform(), stack.peek().antiAlias, false); 86 | } 87 | 88 | /** 89 | * The default implementation is good enough for now. 90 | */ 91 | public static class GLFontMetrics extends FontMetrics { 92 | private static final long serialVersionUID = 3676850359220061793L; 93 | 94 | protected FontRenderContext fontRenderContext; 95 | 96 | public GLFontMetrics(Font font, FontRenderContext frc) { 97 | super(font); 98 | fontRenderContext = frc; 99 | } 100 | 101 | @Override 102 | public FontRenderContext getFontRenderContext() { 103 | return fontRenderContext; 104 | } 105 | 106 | @Override 107 | public int charsWidth(char[] data, int off, int len) { 108 | if (len <= 0) { 109 | return 0; 110 | } 111 | 112 | Rectangle2D bounds = font.getStringBounds(data, off, len, getFontRenderContext()); 113 | return (int) ceil(bounds.getWidth()); 114 | } 115 | } 116 | 117 | protected static class FontState implements Cloneable { 118 | public Font font; 119 | public boolean antiAlias; 120 | 121 | @Override 122 | public FontState clone() { 123 | try { 124 | return (FontState) super.clone(); 125 | } catch (CloneNotSupportedException e) { 126 | throw new AssertionError(e); 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/GL2ES2TransformHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | import java.awt.geom.AffineTransform; 19 | 20 | import com.jogamp.opengl.GL; 21 | 22 | import org.jogamp.glg2d.GLGraphics2D; 23 | import org.jogamp.glg2d.impl.AbstractMatrixHelper; 24 | import org.jogamp.glg2d.impl.shader.UniformBufferObject.TransformHook; 25 | 26 | public class GL2ES2TransformHelper extends AbstractMatrixHelper implements TransformHook { 27 | protected float[] glMatrix; 28 | protected boolean dirtyMatrix; 29 | 30 | protected int[] viewportDimensions; 31 | 32 | @Override 33 | public void setG2D(GLGraphics2D g2d) { 34 | super.setG2D(g2d); 35 | 36 | dirtyMatrix = true; 37 | glMatrix = new float[16]; 38 | viewportDimensions = new int[4]; 39 | 40 | GL gl = g2d.getGLContext().getGL(); 41 | gl.glGetIntegerv(GL.GL_VIEWPORT, viewportDimensions, 0); 42 | 43 | if (g2d instanceof GLShaderGraphics2D) { 44 | ((GLShaderGraphics2D) g2d).getUniformsObject().transformHook = this; 45 | } else { 46 | throw new IllegalArgumentException(GLGraphics2D.class.getName() + " implementation must be instance of " 47 | + GLShaderGraphics2D.class.getSimpleName()); 48 | } 49 | } 50 | 51 | @Override 52 | public float[] getGLMatrixData() { 53 | return getGLMatrixData(null); 54 | } 55 | 56 | @Override 57 | protected void flushTransformToOpenGL() { 58 | // only set dirty, we'll update lazily 59 | dirtyMatrix = true; 60 | } 61 | 62 | @Override 63 | public float[] getGLMatrixData(AffineTransform concat) { 64 | if (concat == null || concat.isIdentity()) { 65 | if (dirtyMatrix) { 66 | updateGLMatrix(getTransform0()); 67 | dirtyMatrix = false; 68 | } 69 | } else { 70 | AffineTransform tmp = getTransform(); 71 | tmp.concatenate(concat); 72 | updateGLMatrix(tmp); 73 | dirtyMatrix = true; 74 | } 75 | 76 | return glMatrix; 77 | } 78 | 79 | protected void updateGLMatrix(AffineTransform xform) { 80 | // add the GL->G2D coordinate transform and perspective inline here 81 | 82 | // Note this isn't quite the same as the GL2 implementation because GL2 has 83 | // an orthographic projection matrix 84 | 85 | float x1 = viewportDimensions[0]; 86 | float y1 = viewportDimensions[1]; 87 | float x2 = viewportDimensions[2]; 88 | float y2 = viewportDimensions[3]; 89 | 90 | float invWidth = 1f / (x2 - x1); 91 | float invHeight = 1f / (y2 - y1); 92 | 93 | glMatrix[0] = ((float) (2 * xform.getScaleX() * invWidth)); 94 | glMatrix[1] = ((float) (-2 * xform.getShearY() * invHeight)); 95 | // glMatrix[2] = 0; 96 | // glMatrix[3] = 0; 97 | 98 | glMatrix[4] = ((float) (2 * xform.getShearX() * invWidth)); 99 | glMatrix[5] = ((float) (-2 * xform.getScaleY() * invHeight)); 100 | // glMatrix[6] = 0; 101 | // glMatrix[7] = 0; 102 | 103 | // glMatrix[8] = 0; 104 | // glMatrix[9] = 0; 105 | glMatrix[10] = -1; 106 | // glMatrix[11] = 0; 107 | 108 | glMatrix[12] = ((float) (2 * xform.getTranslateX() * invWidth - 1)); 109 | glMatrix[13] = ((float) (1 - 2 * xform.getTranslateY() * invHeight)); 110 | // glMatrix[14] = 0; 111 | glMatrix[15] = 1; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/gl2/GL2ColorHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.gl2; 17 | 18 | import static org.jogamp.glg2d.impl.GLG2DNotImplemented.notImplemented; 19 | 20 | import java.awt.AlphaComposite; 21 | import java.awt.Color; 22 | import java.awt.Composite; 23 | import java.awt.GradientPaint; 24 | import java.awt.MultipleGradientPaint; 25 | import java.awt.Paint; 26 | 27 | import com.jogamp.opengl.GL2; 28 | import com.jogamp.opengl.GL2GL3; 29 | 30 | import org.jogamp.glg2d.GLGraphics2D; 31 | import org.jogamp.glg2d.impl.AbstractColorHelper; 32 | 33 | public class GL2ColorHelper extends AbstractColorHelper { 34 | protected GL2 gl; 35 | 36 | @Override 37 | public void setG2D(GLGraphics2D g2d) { 38 | super.setG2D(g2d); 39 | gl = g2d.getGLContext().getGL().getGL2(); 40 | } 41 | 42 | @Override 43 | public void setPaint(Paint paint) { 44 | if (paint instanceof Color) { 45 | setColor((Color) paint); 46 | } else if (paint instanceof GradientPaint) { 47 | setColor(((GradientPaint) paint).getColor1()); 48 | notImplemented("setPaint(Paint) with GradientPaint"); 49 | } else if (paint instanceof MultipleGradientPaint) { 50 | setColor(((MultipleGradientPaint) paint).getColors()[0]); 51 | notImplemented("setPaint(Paint) with MultipleGradientPaint"); 52 | } else { 53 | notImplemented("setPaint(Paint) with " + paint.getClass().getSimpleName()); 54 | // This will probably be easier to handle with a fragment shader 55 | // in the shader pipeline, not sure how to handle it in the fixed- 56 | // function pipeline. 57 | } 58 | } 59 | 60 | @Override 61 | public Paint getPaint() { 62 | return getColor(); 63 | } 64 | 65 | @Override 66 | public void setColorNoRespectComposite(Color c) { 67 | setColor(gl, c, 1); 68 | } 69 | 70 | /** 71 | * Sets the current color with a call to glColor4*. But it respects the 72 | * AlphaComposite if any. If the AlphaComposite wants to pre-multiply an 73 | * alpha, pre-multiply it. 74 | */ 75 | @Override 76 | public void setColorRespectComposite(Color c) { 77 | float alpha = 1; 78 | Composite composite = getComposite(); 79 | if (composite instanceof AlphaComposite) { 80 | alpha = ((AlphaComposite) composite).getAlpha(); 81 | } 82 | 83 | setColor(gl, c, alpha); 84 | } 85 | 86 | private void setColor(GL2 gl, Color c, float preMultiplyAlpha) { 87 | int rgb = c.getRGB(); 88 | gl.glColor4ub((byte) (rgb >> 16 & 0xFF), (byte) (rgb >> 8 & 0xFF), (byte) (rgb & 0xFF), (byte) ((rgb >> 24 & 0xFF) * preMultiplyAlpha)); 89 | } 90 | 91 | @Override 92 | public void setPaintMode() { 93 | notImplemented("setPaintMode()"); 94 | // TODO Auto-generated method stub 95 | } 96 | 97 | @Override 98 | public void setXORMode(Color c) { 99 | notImplemented("setXORMode(Color)"); 100 | // TODO Auto-generated method stub 101 | } 102 | 103 | @Override 104 | public void copyArea(int x, int y, int width, int height, int dx, int dy) { 105 | // glRasterPos* is transformed, but CopyPixels is not 106 | int x2 = x + dx; 107 | int y2 = y + dy + height; 108 | gl.glRasterPos2i(x2, y2); 109 | 110 | int x1 = x; 111 | int y1 = g2d.getCanvasHeight() - (y + height); 112 | gl.glCopyPixels(x1, y1, width, height, GL2GL3.GL_COLOR); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/GLG2DSimpleEventListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import com.jogamp.opengl.GLAutoDrawable; 19 | import com.jogamp.opengl.GLEventListener; 20 | import javax.swing.JComponent; 21 | 22 | /** 23 | * Wraps a {@code JComponent} and paints it using a {@code GLGraphics2D}. This 24 | * object will paint the entire component fully for each frame. 25 | * 26 | *

27 | * {@link GLG2DHeadlessListener} may also be used to listen for reshapes and 28 | * update the size and layout of the painted Swing component. 29 | *

30 | */ 31 | public class GLG2DSimpleEventListener implements GLEventListener { 32 | /** 33 | * The cached object. 34 | */ 35 | protected GLGraphics2D g2d; 36 | 37 | /** 38 | * The component to paint. 39 | */ 40 | protected JComponent comp; 41 | 42 | public GLG2DSimpleEventListener(JComponent component) { 43 | if (component == null) { 44 | throw new NullPointerException("component is null"); 45 | } 46 | 47 | this.comp = component; 48 | } 49 | 50 | @Override 51 | public void display(GLAutoDrawable drawable) { 52 | prePaint(drawable); 53 | paintGL(g2d); 54 | postPaint(drawable); 55 | } 56 | 57 | /** 58 | * Called before any painting is done. This should setup the matrices and ask 59 | * the {@code GLGraphics2D} object to setup any client state. 60 | */ 61 | protected void prePaint(GLAutoDrawable drawable) { 62 | setupViewport(drawable); 63 | g2d.prePaint(drawable.getContext()); 64 | 65 | // clip to only the component we're painting 66 | g2d.translate(comp.getX(), comp.getY()); 67 | g2d.clipRect(0, 0, comp.getWidth(), comp.getHeight()); 68 | } 69 | 70 | /** 71 | * Defines the viewport to paint into. 72 | */ 73 | protected void setupViewport(GLAutoDrawable drawable) { 74 | drawable.getGL().glViewport(0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); 75 | } 76 | 77 | /** 78 | * Called after all Java2D painting is complete. 79 | */ 80 | protected void postPaint(GLAutoDrawable drawable) { 81 | g2d.postPaint(); 82 | } 83 | 84 | /** 85 | * Paints using the {@code GLGraphics2D} object. This could be forwarded to 86 | * any code that expects to draw using the Java2D framework. 87 | *

88 | * Currently is paints the component provided, turning off double-buffering in 89 | * the {@code RepaintManager} to force drawing directly to the 90 | * {@code Graphics2D} object. 91 | *

92 | */ 93 | protected void paintGL(GLGraphics2D g2d) { 94 | boolean wasDoubleBuffered = comp.isDoubleBuffered(); 95 | comp.setDoubleBuffered(false); 96 | 97 | comp.paint(g2d); 98 | 99 | comp.setDoubleBuffered(wasDoubleBuffered); 100 | } 101 | 102 | @Override 103 | public void init(GLAutoDrawable drawable) { 104 | g2d = createGraphics2D(drawable); 105 | } 106 | 107 | @Override 108 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 109 | } 110 | 111 | /** 112 | * Creates the {@code Graphics2D} object that forwards Java2D calls to OpenGL 113 | * calls. 114 | */ 115 | protected GLGraphics2D createGraphics2D(GLAutoDrawable drawable) { 116 | return new GLGraphics2D(); 117 | } 118 | 119 | @Override 120 | public void dispose(GLAutoDrawable arg0) { 121 | if (g2d != null) { 122 | g2d.glDispose(); 123 | g2d = null; 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/util/TestWindow.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d.util; 2 | 3 | 4 | import java.awt.BorderLayout; 5 | import java.awt.FlowLayout; 6 | import java.awt.Graphics; 7 | import java.awt.Graphics2D; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | import java.awt.event.WindowAdapter; 11 | import java.awt.event.WindowEvent; 12 | 13 | import javax.swing.JButton; 14 | import javax.swing.JComponent; 15 | import javax.swing.JFrame; 16 | import javax.swing.JPanel; 17 | import javax.swing.JSplitPane; 18 | import javax.swing.Timer; 19 | 20 | import org.jogamp.glg2d.GLG2DCanvas; 21 | import org.junit.Assert; 22 | 23 | @SuppressWarnings("serial") 24 | public class TestWindow extends JFrame implements Tester { 25 | public static final int SAME = 0; 26 | 27 | public static final int DIFFERENT = 1; 28 | 29 | private CustomPainter painter; 30 | 31 | private volatile int result = -1; 32 | 33 | public TestWindow() { 34 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 35 | setSize(640, 480); 36 | setLocationRelativeTo(null); 37 | initialize(); 38 | setVisible(true); 39 | } 40 | 41 | private void initialize() { 42 | JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); 43 | final JComponent java2d = new JPanel() { 44 | @Override 45 | public void paint(Graphics g) { 46 | super.paint(g); 47 | if (painter != null) { 48 | painter.paint((Graphics2D) g, false); 49 | } 50 | } 51 | }; 52 | 53 | final JComponent jogl = new JPanel() { 54 | @Override 55 | public void paint(Graphics g) { 56 | super.paint(g); 57 | if (painter != null) { 58 | painter.paint((Graphics2D) g, true); 59 | } 60 | } 61 | }; 62 | 63 | GLG2DCanvas canvas = new GLG2DCanvas(jogl); 64 | canvas.setGLDrawing(true); 65 | splitPane.setLeftComponent(canvas); 66 | splitPane.setRightComponent(java2d); 67 | splitPane.setResizeWeight(0.5); 68 | 69 | JButton sameButton = new JButton("Same"); 70 | sameButton.addActionListener(new ActionListener() { 71 | @Override 72 | public void actionPerformed(ActionEvent e) { 73 | result = SAME; 74 | } 75 | }); 76 | 77 | JButton differentButton = new JButton("Different"); 78 | differentButton.addActionListener(new ActionListener() { 79 | @Override 80 | public void actionPerformed(ActionEvent e) { 81 | result = DIFFERENT; 82 | } 83 | }); 84 | 85 | JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); 86 | buttonPanel.add(sameButton); 87 | buttonPanel.add(differentButton); 88 | 89 | setLayout(new BorderLayout()); 90 | add(splitPane, BorderLayout.CENTER); 91 | add(buttonPanel, BorderLayout.SOUTH); 92 | 93 | addWindowListener(new WindowAdapter() { 94 | @Override 95 | public void windowClosing(WindowEvent e) { 96 | result = DIFFERENT; 97 | System.exit(-1); 98 | } 99 | }); 100 | 101 | new Timer(20, new ActionListener() { 102 | @Override 103 | public void actionPerformed(ActionEvent e) { 104 | repaint(); 105 | } 106 | }).start(); 107 | } 108 | 109 | @Override 110 | public void setPainter(final Painter painter) { 111 | this.painter = new CustomPainter() { 112 | @Override 113 | public void paint(Graphics2D g2d, boolean jogl) { 114 | painter.paint(g2d); 115 | } 116 | }; 117 | } 118 | 119 | public void setPainter(CustomPainter painter) { 120 | this.painter = painter; 121 | } 122 | 123 | @Override 124 | public void finish() { 125 | setVisible(false); 126 | } 127 | 128 | @Override 129 | public void assertSame() throws InterruptedException { 130 | int result = waitForInput(); 131 | Assert.assertEquals("User did not consider the two to be the same.", SAME, result); 132 | } 133 | 134 | public int waitForInput() throws InterruptedException { 135 | result = -1; 136 | while (result == -1) { 137 | Thread.sleep(100); 138 | } 139 | 140 | int value = result; 141 | result = -1; 142 | return value; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/text/GL2ES2TextDrawer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader.text; 17 | 18 | import static org.jogamp.glg2d.impl.AbstractShapeHelper.visitShape; 19 | 20 | import java.awt.Shape; 21 | import java.awt.font.GlyphVector; 22 | import java.awt.geom.Point2D; 23 | import java.text.AttributedCharacterIterator; 24 | 25 | import com.jogamp.opengl.GL2ES2; 26 | 27 | import org.jogamp.glg2d.GLGraphics2D; 28 | import org.jogamp.glg2d.impl.AbstractTextDrawer; 29 | import org.jogamp.glg2d.impl.shader.GLShaderGraphics2D; 30 | import org.jogamp.glg2d.impl.shader.text.CollectingTesselator.Triangles; 31 | 32 | public class GL2ES2TextDrawer extends AbstractTextDrawer { 33 | protected GLShaderGraphics2D g2d; 34 | protected GL2ES2 gl; 35 | 36 | protected TextPipeline pipeline; 37 | 38 | public GL2ES2TextDrawer() { 39 | this(new TextPipeline()); 40 | } 41 | 42 | public GL2ES2TextDrawer(TextPipeline pipeline) { 43 | this.pipeline = pipeline; 44 | } 45 | 46 | @Override 47 | public void setG2D(GLGraphics2D g2d) { 48 | if (g2d instanceof GLShaderGraphics2D) { 49 | this.g2d = (GLShaderGraphics2D) g2d; 50 | } else { 51 | throw new IllegalArgumentException(GLGraphics2D.class.getName() + " implementation must be instance of " 52 | + GLShaderGraphics2D.class.getSimpleName()); 53 | } 54 | 55 | gl = g2d.getGLContext().getGL().getGL2ES2(); 56 | if (!pipeline.isSetup()) { 57 | pipeline.setup(gl); 58 | } 59 | 60 | super.setG2D(g2d); 61 | } 62 | 63 | @Override 64 | public void dispose() { 65 | pipeline.delete(gl); 66 | } 67 | 68 | @Override 69 | public void drawString(String string, int x, int y) { 70 | drawString(string, (float) x, (float) y); 71 | } 72 | 73 | @Override 74 | public void drawString(AttributedCharacterIterator iterator, int x, int y) { 75 | drawString(iterator, (float) x, (float) y); 76 | } 77 | 78 | @Override 79 | public void drawString(AttributedCharacterIterator iterator, float x, float y) { 80 | char[] chars = new char[iterator.getEndIndex() - iterator.getBeginIndex()]; 81 | for (int i = 0; i < chars.length; i++) { 82 | chars[i] = iterator.next(); 83 | } 84 | 85 | drawChars(chars, x, y); 86 | } 87 | 88 | @Override 89 | public void drawString(String string, float x, float y) { 90 | drawChars(string.toCharArray(), x, y); 91 | } 92 | 93 | protected void drawChars(char[] string, float x, float y) { 94 | pipeline.use(gl, true); 95 | pipeline.setColor(gl, g2d.getUniformsObject().colorHook.getRGBA()); 96 | pipeline.setTransform(gl, g2d.getUniformsObject().transformHook.getGLMatrixData()); 97 | 98 | pipeline.bindBuffer(gl); 99 | 100 | GlyphVector glyphs = getFont().createGlyphVector(getFontRenderContext(), string); 101 | for (int i = 0; i < string.length; i++) { 102 | Triangles triangles = getTesselatedGlyph(string[i]); 103 | 104 | Point2D pt = glyphs.getGlyphPosition(i); 105 | pipeline.setLocation(gl, (float) pt.getX() + x, (float) pt.getY() + y); 106 | 107 | triangles.draw(gl); 108 | } 109 | 110 | pipeline.unbindBuffer(gl); 111 | pipeline.use(gl, false); 112 | } 113 | 114 | protected Triangles getTesselatedGlyph(char c) { 115 | GlyphVector glyphVect = getFont().createGlyphVector(getFontRenderContext(), new char[] { c }); 116 | Shape s = glyphVect.getGlyphOutline(0); 117 | 118 | CollectingTesselator tess = new CollectingTesselator(); 119 | visitShape(s, tess); 120 | Triangles triangles = tess.getTesselated(); 121 | 122 | return triangles; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/GL2ES2ImageDrawer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | 19 | import java.awt.Color; 20 | import java.awt.geom.AffineTransform; 21 | import java.nio.FloatBuffer; 22 | 23 | import com.jogamp.opengl.GL; 24 | import com.jogamp.opengl.GL2ES2; 25 | 26 | import org.jogamp.glg2d.GLGraphics2D; 27 | import org.jogamp.glg2d.impl.AbstractImageHelper; 28 | 29 | import com.jogamp.common.nio.Buffers; 30 | import com.jogamp.opengl.util.texture.Texture; 31 | 32 | public class GL2ES2ImageDrawer extends AbstractImageHelper { 33 | protected GLShaderGraphics2D g2d; 34 | protected GL2ES2 gl; 35 | 36 | protected FloatBuffer vertTexCoords = Buffers.newDirectFloatBuffer(16); 37 | protected GL2ES2ImagePipeline shader; 38 | 39 | private float[] white = new float[] { 1, 1, 1, 1 }; 40 | 41 | public GL2ES2ImageDrawer() { 42 | this(new GL2ES2ImagePipeline()); 43 | } 44 | 45 | public GL2ES2ImageDrawer(GL2ES2ImagePipeline shader) { 46 | this.shader = shader; 47 | } 48 | 49 | @Override 50 | public void setG2D(GLGraphics2D g2d) { 51 | super.setG2D(g2d); 52 | 53 | if (g2d instanceof GLShaderGraphics2D) { 54 | this.g2d = (GLShaderGraphics2D) g2d; 55 | } else { 56 | throw new IllegalArgumentException(GLGraphics2D.class.getName() + " implementation must be instance of " 57 | + GLShaderGraphics2D.class.getSimpleName()); 58 | } 59 | 60 | gl = g2d.getGLContext().getGL().getGL2ES2(); 61 | if (!shader.isSetup()) { 62 | shader.setup(gl); 63 | } 64 | } 65 | 66 | @Override 67 | public void dispose() { 68 | super.dispose(); 69 | shader.delete(gl); 70 | } 71 | 72 | @Override 73 | protected void begin(Texture texture, AffineTransform xform, Color bgcolor) { 74 | /* 75 | * FIXME This is unexpected since we never disable blending, but in some 76 | * cases it interacts poorly with multiple split panes, scroll panes and the 77 | * text renderer to disable blending. 78 | */ 79 | g2d.setComposite(g2d.getComposite()); 80 | 81 | gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); 82 | gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); 83 | 84 | gl.glActiveTexture(GL.GL_TEXTURE0); 85 | texture.enable(gl); 86 | texture.bind(gl); 87 | 88 | shader.use(gl, true); 89 | 90 | if (bgcolor == null) { 91 | white[3] = g2d.getUniformsObject().colorHook.getAlpha(); 92 | shader.setColor(gl, white); 93 | } else { 94 | float[] rgba = g2d.getUniformsObject().colorHook.getRGBA(); 95 | shader.setColor(gl, rgba); 96 | } 97 | 98 | if (xform == null) { 99 | shader.setTransform(gl, g2d.getUniformsObject().transformHook.getGLMatrixData()); 100 | } else { 101 | shader.setTransform(gl, g2d.getUniformsObject().transformHook.getGLMatrixData(xform)); 102 | } 103 | 104 | shader.setTextureUnit(gl, 0); 105 | } 106 | 107 | @Override 108 | protected void applyTexture(Texture texture, int dx1, int dy1, int dx2, int dy2, float sx1, float sy1, float sx2, float sy2) { 109 | vertTexCoords.rewind(); 110 | 111 | // interleave vertex and texture coordinates 112 | vertTexCoords.put(dx1); 113 | vertTexCoords.put(dy1); 114 | vertTexCoords.put(sx1); 115 | vertTexCoords.put(sy1); 116 | 117 | vertTexCoords.put(dx1); 118 | vertTexCoords.put(dy2); 119 | vertTexCoords.put(sx1); 120 | vertTexCoords.put(sy2); 121 | 122 | vertTexCoords.put(dx2); 123 | vertTexCoords.put(dy1); 124 | vertTexCoords.put(sx2); 125 | vertTexCoords.put(sy1); 126 | 127 | vertTexCoords.put(dx2); 128 | vertTexCoords.put(dy2); 129 | vertTexCoords.put(sx2); 130 | vertTexCoords.put(sy2); 131 | 132 | vertTexCoords.flip(); 133 | shader.draw(gl, vertTexCoords); 134 | } 135 | 136 | @Override 137 | protected void end(Texture texture) { 138 | shader.use(gl, false); 139 | texture.disable(gl); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/gl2/GL2StringDrawer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.gl2; 17 | 18 | 19 | import java.awt.AlphaComposite; 20 | import java.awt.Color; 21 | import java.awt.Font; 22 | import java.text.AttributedCharacterIterator; 23 | import java.util.HashMap; 24 | 25 | import com.jogamp.opengl.GL2; 26 | import com.jogamp.opengl.fixedfunc.GLMatrixFunc; 27 | 28 | import org.jogamp.glg2d.impl.AbstractTextDrawer; 29 | 30 | import com.jogamp.opengl.util.awt.TextRenderer; 31 | 32 | /** 33 | * Draws text for the {@code GLGraphics2D} class. 34 | */ 35 | public class GL2StringDrawer extends AbstractTextDrawer { 36 | protected FontRenderCache cache = new FontRenderCache(); 37 | 38 | @Override 39 | public void dispose() { 40 | cache.dispose(); 41 | } 42 | 43 | @Override 44 | public void drawString(AttributedCharacterIterator iterator, float x, float y) { 45 | drawString(iterator, (int) x, (int) y); 46 | } 47 | 48 | @Override 49 | public void drawString(AttributedCharacterIterator iterator, int x, int y) { 50 | StringBuilder builder = new StringBuilder(iterator.getEndIndex() - iterator.getBeginIndex()); 51 | while (iterator.next() != AttributedCharacterIterator.DONE) { 52 | builder.append(iterator.current()); 53 | } 54 | 55 | drawString(builder.toString(), x, y); 56 | } 57 | 58 | @Override 59 | public void drawString(String string, float x, float y) { 60 | drawString(string, (int) x, (int) y); 61 | } 62 | 63 | @Override 64 | public void drawString(String string, int x, int y) { 65 | TextRenderer renderer = getRenderer(getFont()); 66 | 67 | begin(renderer); 68 | renderer.draw3D(string, x, g2d.getCanvasHeight() - y, 0, 1); 69 | end(renderer); 70 | } 71 | 72 | protected TextRenderer getRenderer(Font font) { 73 | return cache.getRenderer(font, stack.peek().antiAlias); 74 | } 75 | 76 | /** 77 | * Sets the font color, respecting the AlphaComposite if it wants to 78 | * pre-multiply an alpha. 79 | */ 80 | protected void setTextColorRespectComposite(TextRenderer renderer) { 81 | Color color = g2d.getColor(); 82 | if (g2d.getComposite() instanceof AlphaComposite) { 83 | float alpha = ((AlphaComposite) g2d.getComposite()).getAlpha(); 84 | if (alpha < 1) { 85 | float[] rgba = color.getRGBComponents(null); 86 | color = new Color(rgba[0], rgba[1], rgba[2], alpha * rgba[3]); 87 | } 88 | } 89 | 90 | renderer.setColor(color); 91 | } 92 | 93 | protected void begin(TextRenderer renderer) { 94 | setTextColorRespectComposite(renderer); 95 | 96 | GL2 gl = g2d.getGLContext().getGL().getGL2(); 97 | gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); 98 | gl.glPushMatrix(); 99 | gl.glScalef(1, -1, 1); 100 | gl.glTranslatef(0, -g2d.getCanvasHeight(), 0); 101 | 102 | renderer.begin3DRendering(); 103 | } 104 | 105 | protected void end(TextRenderer renderer) { 106 | renderer.end3DRendering(); 107 | 108 | GL2 gl = g2d.getGLContext().getGL().getGL2(); 109 | gl.glPopMatrix(); 110 | } 111 | 112 | @SuppressWarnings("serial") 113 | public static class FontRenderCache extends HashMap { 114 | public TextRenderer getRenderer(Font font, boolean antiAlias) { 115 | TextRenderer[] renderers = get(font); 116 | if (renderers == null) { 117 | renderers = new TextRenderer[2]; 118 | put(font, renderers); 119 | } 120 | 121 | TextRenderer renderer = renderers[antiAlias ? 1 : 0]; 122 | 123 | if (renderer == null) { 124 | renderer = new TextRenderer(font, antiAlias, false); 125 | renderers[antiAlias ? 1 : 0] = renderer; 126 | } 127 | 128 | return renderer; 129 | } 130 | 131 | public void dispose() { 132 | for (TextRenderer[] value : values()) { 133 | if (value[0] != null) { 134 | value[0].dispose(); 135 | } 136 | if (value[1] != null) { 137 | value[1].dispose(); 138 | } 139 | } 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/SimplePathVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl; 17 | 18 | import org.jogamp.glg2d.PathVisitor; 19 | 20 | /** 21 | * This is a fast Bézier curve implementation. I can't use OpenGL's 22 | * built-in evaluators because subclasses need to do something with the points, 23 | * not just pass them directly to glVertex2f. This algorithm uses forward 24 | * differencing. Most of this is taken from http://www.niksula.hut.fi/~hkankaan/Homepages/bezierfast.html. I derived 27 | * the implementation for the quadratic on my own, but it's simple. 28 | */ 29 | public abstract class SimplePathVisitor implements PathVisitor { 30 | /** 31 | * Just a guess. Would be nice to make a better guess based on what's visually 32 | * acceptable. 33 | */ 34 | public static final int CURVE_STEPS = 30; 35 | 36 | protected int steps = CURVE_STEPS; 37 | 38 | /** 39 | * Sets the number of steps to take in a quadratic or cubic curve spline. 40 | */ 41 | public void setNumCurveSteps(int steps) { 42 | this.steps = steps; 43 | } 44 | 45 | /** 46 | * Gets the number of steps to take in a quadratic or cubic curve spline. 47 | */ 48 | public int getNumCurveSteps() { 49 | return steps; 50 | } 51 | 52 | @Override 53 | public void quadTo(float[] previousVertex, float[] control) { 54 | float[] p = new float[2]; 55 | 56 | float xd, xdd, xdd_per_2; 57 | float yd, ydd, ydd_per_2; 58 | float t = 1F / steps; 59 | float tt = t * t; 60 | 61 | // x 62 | p[0] = previousVertex[0]; 63 | xd = 2 * (control[0] - previousVertex[0]) * t; 64 | xdd_per_2 = 1 * (previousVertex[0] - 2 * control[0] + control[2]) * tt; 65 | xdd = xdd_per_2 + xdd_per_2; 66 | 67 | // y 68 | p[1] = previousVertex[1]; 69 | yd = 2 * (control[1] - previousVertex[1]) * t; 70 | ydd_per_2 = 1 * (previousVertex[1] - 2 * control[1] + control[3]) * tt; 71 | ydd = ydd_per_2 + ydd_per_2; 72 | 73 | for (int loop = 0; loop < steps; loop++) { 74 | lineTo(p); 75 | 76 | p[0] = p[0] + xd + xdd_per_2; 77 | xd = xd + xdd; 78 | 79 | p[1] = p[1] + yd + ydd_per_2; 80 | yd = yd + ydd; 81 | } 82 | 83 | // use exactly the last point 84 | p[0] = control[2]; 85 | p[1] = control[3]; 86 | lineTo(p); 87 | } 88 | 89 | @Override 90 | public void cubicTo(float[] previousVertex, float[] control) { 91 | float[] p = new float[2]; 92 | 93 | float xd, xdd, xddd, xdd_per_2, xddd_per_2, xddd_per_6; 94 | float yd, ydd, yddd, ydd_per_2, yddd_per_2, yddd_per_6; 95 | float t = 1F / steps; 96 | float tt = t * t; 97 | 98 | // x 99 | p[0] = previousVertex[0]; 100 | xd = 3 * (control[0] - previousVertex[0]) * t; 101 | xdd_per_2 = 3 * (previousVertex[0] - 2 * control[0] + control[2]) * tt; 102 | xddd_per_2 = 3 * (3 * (control[0] - control[2]) + control[4] - previousVertex[0]) * tt * t; 103 | 104 | xddd = xddd_per_2 + xddd_per_2; 105 | xdd = xdd_per_2 + xdd_per_2; 106 | xddd_per_6 = xddd_per_2 / 3; 107 | 108 | // y 109 | p[1] = previousVertex[1]; 110 | yd = 3 * (control[1] - previousVertex[1]) * t; 111 | ydd_per_2 = 3 * (previousVertex[1] - 2 * control[1] + control[3]) * tt; 112 | yddd_per_2 = 3 * (3 * (control[1] - control[3]) + control[5] - previousVertex[1]) * tt * t; 113 | 114 | yddd = yddd_per_2 + yddd_per_2; 115 | ydd = ydd_per_2 + ydd_per_2; 116 | yddd_per_6 = yddd_per_2 / 3; 117 | 118 | for (int loop = 0; loop < steps; loop++) { 119 | lineTo(p); 120 | 121 | p[0] = p[0] + xd + xdd_per_2 + xddd_per_6; 122 | xd = xd + xdd + xddd_per_2; 123 | xdd = xdd + xddd; 124 | xdd_per_2 = xdd_per_2 + xddd_per_2; 125 | 126 | p[1] = p[1] + yd + ydd_per_2 + yddd_per_6; 127 | yd = yd + ydd + yddd_per_2; 128 | ydd = ydd + yddd; 129 | ydd_per_2 = ydd_per_2 + yddd_per_2; 130 | } 131 | 132 | // use exactly the last point 133 | p[0] = control[4]; 134 | p[1] = control[5]; 135 | lineTo(p); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/event/NewtMouseEventTranslator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.event; 17 | 18 | import java.awt.Component; 19 | import java.awt.Point; 20 | 21 | import com.jogamp.newt.event.InputEvent; 22 | import com.jogamp.newt.event.MouseEvent; 23 | import com.jogamp.newt.event.MouseListener; 24 | 25 | public class NewtMouseEventTranslator extends MouseEventTranslator implements MouseListener { 26 | public NewtMouseEventTranslator(Component target) { 27 | super(target); 28 | } 29 | 30 | @Override 31 | public void mouseClicked(MouseEvent e) { 32 | translateMouseEvent(e); 33 | } 34 | 35 | @Override 36 | public void mouseEntered(MouseEvent e) { 37 | translateMouseEvent(e); 38 | } 39 | 40 | @Override 41 | public void mouseExited(MouseEvent e) { 42 | translateMouseEvent(e); 43 | } 44 | 45 | @Override 46 | public void mousePressed(MouseEvent e) { 47 | translateMouseEvent(e); 48 | } 49 | 50 | @Override 51 | public void mouseReleased(MouseEvent e) { 52 | translateMouseEvent(e); 53 | } 54 | 55 | @Override 56 | public void mouseMoved(MouseEvent e) { 57 | translateMouseEvent(e); 58 | } 59 | 60 | @Override 61 | public void mouseDragged(MouseEvent e) { 62 | translateMouseEvent(e); 63 | } 64 | 65 | @Override 66 | public void mouseWheelMoved(MouseEvent e) { 67 | translateMouseWheelEvent(e); 68 | } 69 | 70 | protected void translateMouseWheelEvent(MouseEvent e) { 71 | int id = newtType2Awt(e.getEventType()); 72 | int modifiers = newtModifiers2Awt(e.getModifiers()); 73 | long when = e.getWhen(); 74 | int wheelRotation = Math.round(-e.getRotation()[0]); 75 | publishMouseWheelEvent(id, when, modifiers, wheelRotation, new Point(e.getX(), e.getY())); 76 | } 77 | 78 | protected void translateMouseEvent(MouseEvent e) { 79 | int button = newtButton2Awt(e.getButton()); 80 | int id = newtType2Awt(e.getEventType()); 81 | int modifiers = newtModifiers2Awt(e.getModifiers()); 82 | long when = e.getWhen(); 83 | int clickCount = e.getClickCount(); 84 | 85 | publishMouseEvent(id, when, modifiers, clickCount, button, new Point(e.getX(), e.getY())); 86 | } 87 | 88 | public static int newtModifiers2Awt(int newtMods) { 89 | int awtMods = 0; 90 | 91 | if ((newtMods & InputEvent.SHIFT_MASK) != 0) { 92 | awtMods |= java.awt.event.InputEvent.SHIFT_MASK; 93 | } 94 | 95 | if ((newtMods & InputEvent.CTRL_MASK) != 0) { 96 | awtMods |= java.awt.event.InputEvent.CTRL_MASK; 97 | } 98 | 99 | if ((newtMods & InputEvent.META_MASK) != 0) { 100 | awtMods |= java.awt.event.InputEvent.META_MASK; 101 | } 102 | 103 | if ((newtMods & InputEvent.ALT_MASK) != 0) { 104 | awtMods |= java.awt.event.InputEvent.ALT_MASK; 105 | } 106 | 107 | if ((newtMods & InputEvent.ALT_GRAPH_MASK) != 0) { 108 | awtMods |= java.awt.event.InputEvent.ALT_GRAPH_MASK; 109 | } 110 | 111 | return awtMods; 112 | } 113 | 114 | public static int newtButton2Awt(int newtButton) { 115 | switch (newtButton) { 116 | case MouseEvent.BUTTON1: 117 | return java.awt.event.MouseEvent.BUTTON1; 118 | case MouseEvent.BUTTON2: 119 | return java.awt.event.MouseEvent.BUTTON2; 120 | case MouseEvent.BUTTON3: 121 | return java.awt.event.MouseEvent.BUTTON3; 122 | default: 123 | return 0; 124 | } 125 | } 126 | 127 | public static int newtType2Awt(int newtMouseType) { 128 | switch (newtMouseType) { 129 | case MouseEvent.EVENT_MOUSE_CLICKED: 130 | return java.awt.event.MouseEvent.MOUSE_CLICKED; 131 | case MouseEvent.EVENT_MOUSE_ENTERED: 132 | return java.awt.event.MouseEvent.MOUSE_ENTERED; 133 | case MouseEvent.EVENT_MOUSE_EXITED: 134 | return java.awt.event.MouseEvent.MOUSE_EXITED; 135 | case MouseEvent.EVENT_MOUSE_MOVED: 136 | return java.awt.event.MouseEvent.MOUSE_MOVED; 137 | case MouseEvent.EVENT_MOUSE_PRESSED: 138 | return java.awt.event.MouseEvent.MOUSE_PRESSED; 139 | case MouseEvent.EVENT_MOUSE_RELEASED: 140 | return java.awt.event.MouseEvent.MOUSE_RELEASED; 141 | case MouseEvent.EVENT_MOUSE_DRAGGED: 142 | return java.awt.event.MouseEvent.MOUSE_DRAGGED; 143 | case MouseEvent.EVENT_MOUSE_WHEEL_MOVED: 144 | return java.awt.event.MouseEvent.MOUSE_WHEEL; 145 | default: 146 | return 0; 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/ImageTest.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d; 2 | 3 | import static java.lang.Math.max; 4 | 5 | import java.awt.BorderLayout; 6 | import java.awt.Dimension; 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | import java.awt.geom.AffineTransform; 10 | import java.awt.image.BufferedImage; 11 | import java.util.Random; 12 | 13 | import com.jogamp.opengl.GLAutoDrawable; 14 | import com.jogamp.opengl.GLCapabilities; 15 | import com.jogamp.opengl.GLDrawableFactory; 16 | import com.jogamp.opengl.GLEventListener; 17 | import com.jogamp.opengl.GLProfile; 18 | import javax.swing.BorderFactory; 19 | import javax.swing.ImageIcon; 20 | import javax.swing.JButton; 21 | import javax.swing.JComponent; 22 | import javax.swing.JFrame; 23 | import javax.swing.JLabel; 24 | import javax.swing.JPanel; 25 | import javax.swing.JProgressBar; 26 | import javax.swing.JRootPane; 27 | import javax.swing.JSlider; 28 | import javax.swing.SwingConstants; 29 | import javax.swing.SwingUtilities; 30 | import javax.swing.Timer; 31 | 32 | import org.jogamp.glg2d.event.AWTMouseEventTranslator; 33 | 34 | import com.jogamp.opengl.util.FPSAnimator; 35 | import com.jogamp.opengl.util.awt.AWTGLReadBufferUtil; 36 | 37 | public class ImageTest { 38 | static JLabel icon; 39 | static int size = 250; 40 | 41 | public static void main(String[] args) throws InterruptedException { 42 | GLCapabilities caps = GLG2DCanvas.getDefaultCapabalities(); 43 | caps.setFBO(true); 44 | caps.setOnscreen(false); 45 | GLAutoDrawable offscreen = GLDrawableFactory.getFactory(GLProfile.getGL2ES1()).createOffscreenAutoDrawable(null, caps, null, size, size); 46 | 47 | JComponent comp = createComponent(); 48 | 49 | JRootPane p = new JRootPane(); 50 | p.setContentPane(comp); 51 | 52 | offscreen.addGLEventListener(new GLG2DSimpleEventListener(comp)); 53 | offscreen.addGLEventListener(new GLG2DHeadlessListener(comp)); 54 | offscreen.addGLEventListener(new ImageCopier()); 55 | 56 | icon = new JLabel(); 57 | 58 | final JFrame frame = new JFrame("Image test"); 59 | JPanel panel = new JPanel(null); 60 | panel.add(icon); 61 | icon.setBounds(0, 0, size, size); 62 | frame.setContentPane(panel); 63 | frame.setPreferredSize(new Dimension(size * 5, size * 3)); 64 | frame.pack(); 65 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 66 | frame.setVisible(true); 67 | 68 | final AWTMouseEventTranslator translator = new AWTMouseEventTranslator(comp); 69 | panel.addMouseListener(translator); 70 | panel.addMouseMotionListener(translator); 71 | panel.addMouseWheelListener(translator); 72 | 73 | Timer t = new Timer(5000, new ActionListener() { 74 | Random r = new Random(); 75 | 76 | @Override 77 | public void actionPerformed(ActionEvent e) { 78 | icon.setBounds(r.nextInt(max(1, frame.getWidth() - size)), 79 | r.nextInt(max(1, frame.getHeight() - size)), size, size); 80 | 81 | translator.setOriginToTargetTransform(AffineTransform.getTranslateInstance(-icon.getX(), -icon.getY())); 82 | } 83 | }); 84 | t.setRepeats(true); 85 | t.start(); 86 | 87 | FPSAnimator animator = new FPSAnimator(5); 88 | animator.add(offscreen); 89 | animator.start(); 90 | } 91 | 92 | private static JComponent createComponent() { 93 | JPanel panel = new JPanel(new BorderLayout()); 94 | panel.setDoubleBuffered(false); 95 | 96 | panel.add(new JButton("Press me!"), BorderLayout.NORTH); 97 | 98 | JLabel txt = new JLabel("This is an image being painted at 5Hz. The source component is offscreen and not visible anywhere. " + 99 | "The mouse events are being registered with the visible frame, translated and then re-sent to the offscreen " + 100 | "component. The offscreen component handles them, paints itself to the an FBO, which is captured into a " + 101 | "BufferedImage, which is then painted here"); 102 | 103 | panel.add(txt, BorderLayout.CENTER); 104 | 105 | JProgressBar bar = new JProgressBar(); 106 | bar.setIndeterminate(true); 107 | panel.add(bar, BorderLayout.SOUTH); 108 | panel.add(new JSlider(SwingConstants.VERTICAL, 0, 10, 3), BorderLayout.EAST); 109 | 110 | panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 111 | 112 | return panel; 113 | } 114 | 115 | static class ImageCopier implements GLEventListener { 116 | @Override 117 | public void init(GLAutoDrawable drawable) { 118 | } 119 | 120 | @Override 121 | public void dispose(GLAutoDrawable drawable) { 122 | } 123 | 124 | @Override 125 | public void display(GLAutoDrawable drawable) { 126 | AWTGLReadBufferUtil util = new AWTGLReadBufferUtil(GLG2DCanvas.getDefaultCapabalities().getGLProfile(), false); 127 | final BufferedImage img = util.readPixelsToBufferedImage(drawable.getContext().getGL(), true); 128 | SwingUtilities.invokeLater(new Runnable() { 129 | @Override 130 | public void run() { 131 | icon.setIcon(new ImageIcon(img)); 132 | } 133 | }); 134 | } 135 | 136 | @Override 137 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/PathVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.awt.BasicStroke; 19 | 20 | import com.jogamp.opengl.GL; 21 | 22 | /** 23 | * Receives the calls from a {@link java.awt.geom.PathIterator} and draws the 24 | * shape as it is visited. The form of this interface and the documentation 25 | * closely mirror that class. 26 | *

27 | * Note: The implementation should assume that the array being passed into each 28 | * of these calls is being modified when the call returns, the vertex array is 29 | * recycled and any storage of the points should guard against external 30 | * mutation. 31 | *

32 | * 33 | * @see java.awt.geom.PathIterator 34 | */ 35 | public interface PathVisitor { 36 | /** 37 | * Sets the GL context to be used for the next drawing session. 38 | * 39 | * @param context 40 | * The GL context 41 | */ 42 | void setGLContext(GL context); 43 | 44 | /** 45 | * Sets the stroke to be used when drawing a path. It's not needed for 46 | * visitors that fill. 47 | */ 48 | void setStroke(BasicStroke stroke); 49 | 50 | /** 51 | * Specifies the starting location for a new subpath. 52 | * 53 | * @param vertex 54 | * An array where the first two values are the x,y coordinates of the 55 | * start of the subpath. 56 | */ 57 | void moveTo(float[] vertex); 58 | 59 | /** 60 | * Specifies the end point of a line to be drawn from the most recently 61 | * specified point. 62 | * 63 | * @param vertex 64 | * An array where the first two values are the x,y coordinates of the 65 | * next point in the subpath. 66 | */ 67 | void lineTo(float[] vertex); 68 | 69 | /** 70 | * Specifies a quadratic parametric curve is to be drawn. The curve is 71 | * interpolated by solving the parametric control equation in the range 72 | * (t=[0..1]) using the previous point (CP), the first control 73 | * point (P1), and the final interpolated control point (P2). The parametric 74 | * control equation for this curve is: 75 | * 76 | *
 77 |    *          P(t) = B(2,0)*CP + B(2,1)*P1 + B(2,2)*P2
 78 |    *          0 <= t <= 1
 79 |    * 
 80 |    *        B(n,m) = mth coefficient of nth degree Bernstein polynomial
 81 |    *               = C(n,m) * t^(m) * (1 - t)^(n-m)
 82 |    *        C(n,m) = Combinations of n things, taken m at a time
 83 |    *               = n! / (m! * (n-m)!)
 84 |    * 
85 | * 86 | * @param previousVertex 87 | * The first control point. The same as the most recent specified 88 | * vertex. 89 | * @param control 90 | * The control point and the second vertex, in order. 91 | */ 92 | void quadTo(float[] previousVertex, float[] control); 93 | 94 | /** 95 | * Specifies a cubic parametric curve to be drawn. The curve is interpolated 96 | * by solving the parametric control equation in the range 97 | * (t=[0..1]) using the previous point (CP), the first control 98 | * point (P1), the second control point (P2), and the final interpolated 99 | * control point (P3). The parametric control equation for this curve is: 100 | * 101 | *
102 |    *          P(t) = B(3,0)*CP + B(3,1)*P1 + B(3,2)*P2 + B(3,3)*P3
103 |    *          0 <= t <= 1
104 |    * 
105 |    *        B(n,m) = mth coefficient of nth degree Bernstein polynomial
106 |    *               = C(n,m) * t^(m) * (1 - t)^(n-m)
107 |    *        C(n,m) = Combinations of n things, taken m at a time
108 |    *               = n! / (m! * (n-m)!)
109 |    * 
110 | * 111 | * This form of curve is commonly known as a Bézier curve. 112 | * 113 | * @param previousVertex 114 | * The first control point. The same as the most recent specified 115 | * vertex. 116 | * @param control 117 | * The two control points and the second vertex, in order. 118 | */ 119 | void cubicTo(float[] previousVertex, float[] control); 120 | 121 | /** 122 | * Specifies that the preceding subpath should be closed by appending a line 123 | * segment back to the point corresponding to the most recent call to 124 | * {@code #moveTo(float[])}. 125 | */ 126 | void closeLine(); 127 | 128 | /** 129 | * Starts the polygon or polyline. 130 | * 131 | * @param windingRule 132 | * The winding rule for the polygon. 133 | */ 134 | void beginPoly(int windingRule); 135 | 136 | /** 137 | * Signifies that the polygon or polyline has ended. All cleanup should occur 138 | * and there will be no more calls for this shape. 139 | */ 140 | void endPoly(); 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/VertexBuffer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d; 17 | 18 | import java.nio.FloatBuffer; 19 | 20 | import com.jogamp.opengl.GL; 21 | import com.jogamp.opengl.GL2; 22 | import com.jogamp.opengl.fixedfunc.GLPointerFunc; 23 | 24 | import com.jogamp.common.nio.Buffers; 25 | 26 | /** 27 | * Wraps a simple {@code FloatBuffer} and makes it easier to push 2-D vertices 28 | * into the buffer and then draw them using any mode desired. The default 29 | * constructor uses a global buffer since drawing in OpenGL is not 30 | * multi-threaded. 31 | */ 32 | public class VertexBuffer { 33 | protected static VertexBuffer shared = new VertexBuffer(1024); 34 | 35 | protected FloatBuffer buffer; 36 | 37 | protected int deviceBufferId; 38 | 39 | /** 40 | * Creates a buffer that uses the shared global buffer. This is faster than 41 | * allocating multiple float buffers. Since OpenGL is single-threaded, we can 42 | * assume this won't be accessed outside the OpenGL thread and typically one 43 | * object is drawn completely before another one. If this is not true, one of 44 | * the objects being drawn simultaneously must use a private buffer. See 45 | * {@code #VertexBuffer(int)}. 46 | */ 47 | public static VertexBuffer getSharedBuffer() { 48 | shared.clear(); 49 | return shared; 50 | } 51 | 52 | protected VertexBuffer(FloatBuffer buffer) { 53 | this.buffer = buffer; 54 | } 55 | 56 | /** 57 | * Creates a private buffer. This can be used without fear of clobbering the 58 | * global buffer. This should only be used if you have a need to create two 59 | * parallel shapes at the same time. 60 | * 61 | * @param capacity 62 | * The size of the buffer in number of vertices 63 | */ 64 | public VertexBuffer(int capacity) { 65 | this(Buffers.newDirectFloatBuffer(capacity * 2)); 66 | } 67 | 68 | /** 69 | * Adds multiple vertices to the buffer. 70 | * 71 | * @param array 72 | * The array containing vertices in the form (x,y),(x,y) 73 | * @param offset 74 | * The starting index 75 | * @param numVertices 76 | * The number of vertices, pairs of floats 77 | */ 78 | public void addVertex(float[] array, int offset, int numVertices) { 79 | int numFloats = numVertices * 2; 80 | ensureCapacity(numFloats); 81 | buffer.put(array, offset, numFloats); 82 | } 83 | 84 | /** 85 | * Adds a vertex to the buffer. 86 | * 87 | * @param x 88 | * The x coordinate 89 | * @param y 90 | * The y coordinate 91 | */ 92 | public void addVertex(float x, float y) { 93 | ensureCapacity(2); 94 | buffer.put(x); 95 | buffer.put(y); 96 | } 97 | 98 | /** 99 | * Adds multiple vertices to the buffer. 100 | * 101 | * @param vertices 102 | * The buffer of new vertices to add. 103 | */ 104 | public void addVertices(FloatBuffer vertices) { 105 | int size = vertices.limit() - vertices.position(); 106 | ensureCapacity(size); 107 | 108 | buffer.put(vertices); 109 | } 110 | 111 | protected void ensureCapacity(int numNewFloats) { 112 | if (buffer.capacity() <= buffer.position() + numNewFloats) { 113 | FloatBuffer larger = Buffers.newDirectFloatBuffer(Math.max(buffer.position() * 2, buffer.position() + numNewFloats)); 114 | deviceBufferId = -deviceBufferId; 115 | int position = buffer.position(); 116 | buffer.rewind(); 117 | larger.put(buffer); 118 | buffer = larger; 119 | buffer.position(position); 120 | } 121 | } 122 | 123 | /** 124 | * Discard all existing points. This method is not necessary unless the points 125 | * already added are not needed anymore and the buffer will be reused. 126 | */ 127 | public void clear() { 128 | buffer.clear(); 129 | } 130 | 131 | public FloatBuffer getBuffer() { 132 | return buffer; 133 | } 134 | 135 | /** 136 | * Draws the vertices and rewinds the buffer to be ready to draw next time. 137 | * 138 | * @param gl 139 | * The graphics context to use to draw 140 | * @param mode 141 | * The mode, e.g. {@code GL#GL_LINE_STRIP} 142 | */ 143 | public void drawBuffer(GL2 gl, int mode) { 144 | if (buffer.position() == 0) { 145 | return; 146 | } 147 | 148 | int count = buffer.position(); 149 | buffer.rewind(); 150 | 151 | gl.glVertexPointer(2, GL.GL_FLOAT, 0, buffer); 152 | 153 | gl.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY); 154 | gl.glDrawArrays(mode, 0, count / 2); 155 | gl.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY); 156 | 157 | buffer.position(count); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/AbstractColorHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl; 17 | 18 | import static org.jogamp.glg2d.impl.GLG2DNotImplemented.notImplemented; 19 | 20 | import java.awt.AlphaComposite; 21 | import java.awt.Color; 22 | import java.awt.Composite; 23 | import java.awt.Paint; 24 | import java.awt.RenderingHints.Key; 25 | import java.util.ArrayDeque; 26 | import java.util.Deque; 27 | 28 | import com.jogamp.opengl.GL; 29 | 30 | import org.jogamp.glg2d.GLG2DColorHelper; 31 | import org.jogamp.glg2d.GLGraphics2D; 32 | 33 | public abstract class AbstractColorHelper implements GLG2DColorHelper { 34 | protected GLGraphics2D g2d; 35 | 36 | protected Deque stack = new ArrayDeque(); 37 | 38 | @Override 39 | public void setG2D(GLGraphics2D g2d) { 40 | this.g2d = g2d; 41 | 42 | stack.clear(); 43 | stack.push(new ColorState()); 44 | } 45 | 46 | @Override 47 | public void push(GLGraphics2D newG2d) { 48 | stack.push(stack.peek().clone()); 49 | } 50 | 51 | @Override 52 | public void pop(GLGraphics2D parentG2d) { 53 | stack.pop(); 54 | 55 | // set all the states 56 | setComposite(getComposite()); 57 | setColor(getColor()); 58 | setBackground(getBackground()); 59 | } 60 | 61 | @Override 62 | public void setHint(Key key, Object value) { 63 | // nop 64 | } 65 | 66 | @Override 67 | public void resetHints() { 68 | // nop 69 | } 70 | 71 | @Override 72 | public void dispose() { 73 | } 74 | 75 | @Override 76 | public void setComposite(Composite comp) { 77 | GL gl = g2d.getGLContext().getGL(); 78 | gl.glEnable(GL.GL_BLEND); 79 | if (comp instanceof AlphaComposite) { 80 | switch (((AlphaComposite) comp).getRule()) { 81 | /* 82 | * Since the destination _always_ covers the entire canvas (i.e. there are 83 | * always color components for every pixel), some of these composites can 84 | * be collapsed into each other. They matter when Java2D is drawing into 85 | * an image and the destination may not take up the entire canvas. 86 | */ 87 | case AlphaComposite.SRC: 88 | case AlphaComposite.SRC_IN: 89 | gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ZERO); 90 | break; 91 | 92 | case AlphaComposite.SRC_OVER: 93 | case AlphaComposite.SRC_ATOP: 94 | gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); 95 | break; 96 | 97 | case AlphaComposite.SRC_OUT: 98 | case AlphaComposite.CLEAR: 99 | gl.glBlendFunc(GL.GL_ZERO, GL.GL_ZERO); 100 | break; 101 | 102 | case AlphaComposite.DST: 103 | case AlphaComposite.DST_OVER: 104 | gl.glBlendFunc(GL.GL_ZERO, GL.GL_ONE); 105 | break; 106 | 107 | case AlphaComposite.DST_IN: 108 | case AlphaComposite.DST_ATOP: 109 | gl.glBlendFunc(GL.GL_ZERO, GL.GL_SRC_ALPHA); 110 | break; 111 | 112 | case AlphaComposite.DST_OUT: 113 | case AlphaComposite.XOR: 114 | gl.glBlendFunc(GL.GL_ZERO, GL.GL_ONE_MINUS_SRC_ALPHA); 115 | break; 116 | } 117 | 118 | stack.peek().composite = comp; 119 | // need to pre-multiply the alpha 120 | setColor(getColor()); 121 | } else { 122 | notImplemented("setComposite(Composite) with " + comp == null ? "null Composite" : comp.getClass().getSimpleName()); 123 | } 124 | } 125 | 126 | @Override 127 | public Composite getComposite() { 128 | return stack.peek().composite; 129 | } 130 | 131 | @Override 132 | public void setColor(Color c) { 133 | if (c == null) { 134 | return; 135 | } 136 | 137 | stack.peek().color = c; 138 | setColorRespectComposite(c); 139 | } 140 | 141 | @Override 142 | public Color getColor() { 143 | return stack.peek().color; 144 | } 145 | 146 | @Override 147 | public void setBackground(Color color) { 148 | stack.peek().background = color; 149 | } 150 | 151 | @Override 152 | public Color getBackground() { 153 | return stack.peek().background; 154 | } 155 | 156 | @Override 157 | public void setPaint(Paint paint) { 158 | stack.peek().paint = paint; 159 | } 160 | 161 | @Override 162 | public Paint getPaint() { 163 | return stack.peek().paint; 164 | } 165 | 166 | protected static class ColorState implements Cloneable { 167 | public Composite composite; 168 | public Color color; 169 | public Paint paint; 170 | public Color background; 171 | 172 | @Override 173 | public ColorState clone() { 174 | try { 175 | return (ColorState) super.clone(); 176 | } catch (CloneNotSupportedException e) { 177 | throw new AssertionError(e); 178 | } 179 | } 180 | } 181 | } -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/AbstractTesselatorVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl; 17 | 18 | 19 | import java.awt.BasicStroke; 20 | import java.awt.geom.PathIterator; 21 | 22 | import com.jogamp.opengl.GLException; 23 | import com.jogamp.opengl.glu.GLU; 24 | import com.jogamp.opengl.glu.GLUtessellator; 25 | import com.jogamp.opengl.glu.GLUtessellatorCallback; 26 | import com.jogamp.opengl.glu.GLUtessellatorCallbackAdapter; 27 | 28 | import org.jogamp.glg2d.VertexBuffer; 29 | 30 | /** 31 | * Fills a shape by tesselating it with the GLU library. This is a slower 32 | * implementation and {@code FillNonintersectingPolygonVisitor} should be used 33 | * when possible. 34 | */ 35 | public abstract class AbstractTesselatorVisitor extends SimplePathVisitor { 36 | protected GLUtessellator tesselator; 37 | 38 | protected GLUtessellatorCallback callback; 39 | 40 | /** 41 | * Last command was a move to. This is where drawing starts. 42 | */ 43 | protected float[] drawStart = new float[2]; 44 | protected boolean drawing = false; 45 | 46 | protected int drawMode; 47 | protected VertexBuffer vBuffer = new VertexBuffer(1024); 48 | 49 | public AbstractTesselatorVisitor() { 50 | callback = new TessellatorCallback(); 51 | } 52 | 53 | @Override 54 | public void setStroke(BasicStroke stroke) { 55 | // nop 56 | } 57 | 58 | @Override 59 | public void beginPoly(int windingRule) { 60 | tesselator = GLU.gluNewTess(); 61 | configureTesselator(windingRule); 62 | 63 | GLU.gluTessBeginPolygon(tesselator, null); 64 | } 65 | 66 | protected void configureTesselator(int windingRule) { 67 | switch (windingRule) { 68 | case PathIterator.WIND_EVEN_ODD: 69 | GLU.gluTessProperty(tesselator, GLU.GLU_TESS_WINDING_RULE, GLU.GLU_TESS_WINDING_ODD); 70 | break; 71 | 72 | case PathIterator.WIND_NON_ZERO: 73 | GLU.gluTessProperty(tesselator, GLU.GLU_TESS_WINDING_RULE, GLU.GLU_TESS_WINDING_NONZERO); 74 | break; 75 | } 76 | 77 | GLU.gluTessCallback(tesselator, GLU.GLU_TESS_VERTEX, callback); 78 | GLU.gluTessCallback(tesselator, GLU.GLU_TESS_BEGIN, callback); 79 | GLU.gluTessCallback(tesselator, GLU.GLU_TESS_END, callback); 80 | GLU.gluTessCallback(tesselator, GLU.GLU_TESS_ERROR, callback); 81 | GLU.gluTessCallback(tesselator, GLU.GLU_TESS_COMBINE, callback); 82 | GLU.gluTessNormal(tesselator, 0, 0, -1); 83 | 84 | } 85 | 86 | @Override 87 | public void moveTo(float[] vertex) { 88 | endIfRequired(); 89 | drawStart[0] = vertex[0]; 90 | drawStart[1] = vertex[1]; 91 | } 92 | 93 | @Override 94 | public void lineTo(float[] vertex) { 95 | startIfRequired(); 96 | addVertex(vertex); 97 | } 98 | 99 | private void addVertex(float[] vertex) { 100 | double[] v = new double[3]; 101 | v[0] = vertex[0]; 102 | v[1] = vertex[1]; 103 | GLU.gluTessVertex(tesselator, v, 0, v); 104 | } 105 | 106 | @Override 107 | public void closeLine() { 108 | endIfRequired(); 109 | } 110 | 111 | @Override 112 | public void endPoly() { 113 | // shapes may just end on the starting point without calling closeLine 114 | endIfRequired(); 115 | 116 | GLU.gluTessEndPolygon(tesselator); 117 | GLU.gluDeleteTess(tesselator); 118 | } 119 | 120 | private void startIfRequired() { 121 | if (!drawing) { 122 | GLU.gluTessBeginContour(tesselator); 123 | addVertex(drawStart); 124 | drawing = true; 125 | } 126 | } 127 | 128 | private void endIfRequired() { 129 | if (drawing) { 130 | GLU.gluTessEndContour(tesselator); 131 | drawing = false; 132 | } 133 | } 134 | 135 | protected void beginTess(int type) { 136 | drawMode = type; 137 | vBuffer.clear(); 138 | } 139 | 140 | protected void addTessVertex(double[] vertex) { 141 | vBuffer.addVertex((float) vertex[0], (float) vertex[1]); 142 | } 143 | 144 | protected abstract void endTess(); 145 | 146 | protected class TessellatorCallback extends GLUtessellatorCallbackAdapter { 147 | @Override 148 | public void begin(int type) { 149 | beginTess(type); 150 | } 151 | 152 | @Override 153 | public void end() { 154 | endTess(); 155 | } 156 | 157 | @Override 158 | public void vertex(Object vertexData) { 159 | assert vertexData instanceof double[] : "Invalid assumption"; 160 | addTessVertex((double[]) vertexData); 161 | } 162 | 163 | @Override 164 | public void combine(double[] coords, Object[] data, float[] weight, Object[] outData) { 165 | outData[0] = coords; 166 | } 167 | 168 | @Override 169 | public void error(int errnum) { 170 | throw new GLException("Tesselation Error: " + new GLU().gluErrorString(errnum)); 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/GL2ES2ColorHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | 19 | import java.awt.AlphaComposite; 20 | import java.awt.Color; 21 | import java.awt.Composite; 22 | 23 | import org.jogamp.glg2d.GLGraphics2D; 24 | import org.jogamp.glg2d.impl.AbstractColorHelper; 25 | import org.jogamp.glg2d.impl.shader.UniformBufferObject.ColorHook; 26 | 27 | public class GL2ES2ColorHelper extends AbstractColorHelper implements ColorHook { 28 | protected float[] foregroundRGBA = new float[4]; 29 | 30 | protected GL2ES2ImagePipeline pipeline; 31 | 32 | public GL2ES2ColorHelper() { 33 | this(new GL2ES2ImagePipeline()); 34 | } 35 | 36 | public GL2ES2ColorHelper(GL2ES2ImagePipeline pipeline) { 37 | this.pipeline = pipeline; 38 | } 39 | 40 | @Override 41 | public void setG2D(GLGraphics2D g2d) { 42 | if (g2d instanceof GLShaderGraphics2D) { 43 | ((GLShaderGraphics2D) g2d).getUniformsObject().colorHook = this; 44 | } else { 45 | throw new IllegalArgumentException(GLGraphics2D.class.getName() + " implementation must be instance of " 46 | + GLShaderGraphics2D.class.getSimpleName()); 47 | } 48 | 49 | super.setG2D(g2d); 50 | } 51 | 52 | @Override 53 | public void setColorNoRespectComposite(Color c) { 54 | foregroundRGBA[0] = c.getRed() / 255f; 55 | foregroundRGBA[1] = c.getGreen() / 255f; 56 | foregroundRGBA[2] = c.getBlue() / 255f; 57 | foregroundRGBA[3] = c.getAlpha() / 255f; 58 | } 59 | 60 | @Override 61 | public void setColorRespectComposite(Color c) { 62 | float alpha = getAlpha(); 63 | foregroundRGBA[0] = c.getRed() / 255f; 64 | foregroundRGBA[1] = c.getGreen() / 255f; 65 | foregroundRGBA[2] = c.getBlue() / 255f; 66 | foregroundRGBA[3] = (c.getAlpha() / 255f) * alpha; 67 | } 68 | 69 | @Override 70 | public void setPaintMode() { 71 | // not implemented yet 72 | } 73 | 74 | @Override 75 | public void setXORMode(Color c) { 76 | // not implemented yet 77 | } 78 | 79 | @Override 80 | public void copyArea(int x, int y, int width, int height, int dx, int dy) { 81 | // GL2ES2 gl = g2d.getGLContext().getGL().getGL2ES2(); 82 | // 83 | // if (!pipeline.isSetup()) { 84 | // pipeline.setup(gl); 85 | // } 86 | // 87 | // pipeline.use(gl, true); 88 | // 89 | // float[] glMatrix = new float[16]; 90 | // glMatrix[0] = 1; 91 | // // glMatrix[1] = 0; 92 | // // glMatrix[2] = 0; 93 | // // glMatrix[3] = 0; 94 | // 95 | // // glMatrix[4] = 0; 96 | // glMatrix[5] = 1; 97 | // // glMatrix[6] = 0; 98 | // // glMatrix[7] = 0; 99 | // 100 | // // glMatrix[8] = 0; 101 | // // glMatrix[9] = 0; 102 | // glMatrix[10] = 1; 103 | // // glMatrix[11] = 0; 104 | // 105 | // // glMatrix[12] = 0; 106 | // // glMatrix[13] = 0; 107 | // // glMatrix[14] = 0; 108 | // glMatrix[15] = 1; 109 | // 110 | // pipeline.setColor(gl, new float[] { 1, 1, 1, 1 }); 111 | // pipeline.setTextureUnit(gl, GL.GL_TEXTURE0); 112 | // pipeline.setTransform(gl, glMatrix); 113 | // 114 | // int numPixels = width * height; 115 | // FloatBuffer data = Buffers.newDirectFloatBuffer(numPixels); 116 | // 117 | // int glX = x; 118 | // int glY = g2d.getCanvasHeight() - (y + height); 119 | // 120 | // gl.glReadPixels(glX, glY, width, height, GL.GL_RGBA, GL.GL_FLOAT, data); 121 | // 122 | // gl.glEnable(GL.GL_TEXTURE_2D); 123 | // gl.glActiveTexture(GL.GL_TEXTURE0); 124 | // 125 | // int[] ids = new int[1]; 126 | // gl.glGenTextures(1, ids, 0); 127 | // 128 | // gl.glBindTexture(GL.GL_TEXTURE_2D, ids[0]); 129 | // 130 | // gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); 131 | // gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); 132 | // 133 | // /* 134 | // * TODO This will need to be power-of-2 135 | // */ 136 | // gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, width, height, 0, GL.GL_RGBA, GL.GL_FLOAT, data); 137 | // 138 | // data.clear(); 139 | // 140 | // // translate to new location 141 | // glX += dx; 142 | // glY -= dy; 143 | // 144 | // // interleave vertex and texture coordinates 145 | // data.put(glX); 146 | // data.put(glY); 147 | // data.put(0); 148 | // data.put(0); 149 | // 150 | // data.put(glX + width); 151 | // data.put(glY); 152 | // data.put(1); 153 | // data.put(0); 154 | // 155 | // data.put(glX + width); 156 | // data.put(glY + height); 157 | // data.put(1); 158 | // data.put(1); 159 | // 160 | // data.put(glX); 161 | // data.put(glY + height); 162 | // data.put(0); 163 | // data.put(1); 164 | // 165 | // data.flip(); 166 | // 167 | // pipeline.draw(gl, data); 168 | // 169 | // gl.glDeleteTextures(1, ids, 0); 170 | // 171 | // gl.glDisable(GL.GL_TEXTURE_2D); 172 | // 173 | // pipeline.use(gl, false); 174 | } 175 | 176 | @Override 177 | public float getAlpha() { 178 | Composite composite = getComposite(); 179 | float alpha = 1; 180 | if (composite instanceof AlphaComposite) { 181 | alpha = ((AlphaComposite) composite).getAlpha(); 182 | } 183 | 184 | return alpha; 185 | } 186 | 187 | @Override 188 | public float[] getRGBA() { 189 | return foregroundRGBA; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/gl2/FastLineVisitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.gl2; 17 | 18 | 19 | import java.awt.BasicStroke; 20 | import java.nio.FloatBuffer; 21 | 22 | import com.jogamp.opengl.GL; 23 | import com.jogamp.opengl.GL2; 24 | 25 | import org.jogamp.glg2d.VertexBuffer; 26 | import org.jogamp.glg2d.impl.SimplePathVisitor; 27 | 28 | /** 29 | * Draws a line using the native GL implementation of a line. This is only 30 | * appropriate if the width of the line is less than a certain number of pixels 31 | * (not coordinate units) so that the user cannot see that the join and 32 | * endpoints are different. See {@link #isValid(BasicStroke)} for a set of 33 | * useful criteria. 34 | */ 35 | public class FastLineVisitor extends SimplePathVisitor { 36 | protected float[] testMatrix = new float[16]; 37 | 38 | protected VertexBuffer buffer = VertexBuffer.getSharedBuffer(); 39 | 40 | protected GL2 gl; 41 | 42 | protected BasicStroke stroke; 43 | 44 | protected float glLineWidth; 45 | 46 | @Override 47 | public void setGLContext(GL context) { 48 | gl = context.getGL2(); 49 | } 50 | 51 | @Override 52 | public void setStroke(BasicStroke stroke) { 53 | gl.glLineWidth(glLineWidth); 54 | gl.glPointSize(glLineWidth); 55 | 56 | /* 57 | * Not perfect copy of the BasicStroke implementation, but it does get 58 | * decently close. The pattern is pretty much the same. I think it's pretty 59 | * much impossible to do with out a fragment shader and only the fixed 60 | * function pipeline. 61 | */ 62 | float[] dash = stroke.getDashArray(); 63 | if (dash != null) { 64 | float totalLength = 0; 65 | for (float f : dash) { 66 | totalLength += f; 67 | } 68 | 69 | float lengthSoFar = 0; 70 | int prevIndex = 0; 71 | int mask = 0; 72 | for (int i = 0; i < dash.length; i++) { 73 | lengthSoFar += dash[i]; 74 | 75 | int nextIndex = (int) (lengthSoFar / totalLength * 16); 76 | for (int j = prevIndex; j < nextIndex; j++) { 77 | mask |= (~i & 1) << j; 78 | } 79 | 80 | prevIndex = nextIndex; 81 | } 82 | 83 | /* 84 | * XXX Should actually use the stroke phase, but not sure how yet. 85 | */ 86 | 87 | gl.glEnable(GL2.GL_LINE_STIPPLE); 88 | int factor = (int) totalLength; 89 | gl.glLineStipple(factor >> 4, (short) mask); 90 | } else { 91 | gl.glDisable(GL2.GL_LINE_STIPPLE); 92 | } 93 | 94 | this.stroke = stroke; 95 | } 96 | 97 | /** 98 | * Returns {@code true} if this class can reasonably render the line. This 99 | * takes into account whether or not the transform will blow the line width 100 | * out of scale and it obvious that we aren't drawing correct corners and line 101 | * endings. 102 | * 103 | *

104 | * Note: This must be called before {@link #setStroke(BasicStroke)}. If this 105 | * returns {@code false} then this renderer should not be used. 106 | *

107 | */ 108 | public boolean isValid(BasicStroke stroke) { 109 | // if the dash length is odd, I don't know how to handle that yet 110 | float[] dash = stroke.getDashArray(); 111 | if (dash != null && (dash.length & 1) == 1) { 112 | return false; 113 | } 114 | 115 | gl.glGetFloatv(GL2.GL_MODELVIEW_MATRIX, testMatrix, 0); 116 | 117 | float scaleX = Math.abs(testMatrix[0]); 118 | float scaleY = Math.abs(testMatrix[5]); 119 | 120 | // scales are different, we can't get a good line width 121 | if (Math.abs(scaleX - scaleY) > 1e-6) { 122 | return false; 123 | } 124 | 125 | float strokeWidth = stroke.getLineWidth(); 126 | 127 | // gl line width is in pixels, convert to pixel width 128 | glLineWidth = strokeWidth * scaleX; 129 | 130 | // we'll only try if it's a thin line 131 | return glLineWidth <= 2; 132 | } 133 | 134 | @Override 135 | public void moveTo(float[] vertex) { 136 | drawLine(false); 137 | buffer.addVertex(vertex, 0, 1); 138 | } 139 | 140 | @Override 141 | public void lineTo(float[] vertex) { 142 | buffer.addVertex(vertex, 0, 1); 143 | } 144 | 145 | @Override 146 | public void closeLine() { 147 | drawLine(true); 148 | } 149 | 150 | protected void drawLine(boolean close) { 151 | FloatBuffer buf = buffer.getBuffer(); 152 | int p = buf.position(); 153 | buffer.drawBuffer(gl, close ? GL2.GL_LINE_LOOP : GL2.GL_LINE_STRIP); 154 | 155 | /* 156 | * We'll ignore butt endcaps, but we'll pretend like we're drawing round, 157 | * bevel or miter corners as well as round or square corners by just putting 158 | * a point there. Since our line should be very thin, pixel-wise, it 159 | * shouldn't be noticeable. 160 | */ 161 | if (stroke.getDashArray() == null) { 162 | buf.position(p); 163 | buffer.drawBuffer(gl, GL2.GL_POINTS); 164 | } 165 | 166 | buffer.clear(); 167 | } 168 | 169 | @Override 170 | public void beginPoly(int windingRule) { 171 | buffer.clear(); 172 | 173 | /* 174 | * pen hangs down and to the right. See java.awt.Graphics 175 | */ 176 | gl.glMatrixMode(GL2.GL_MODELVIEW); 177 | gl.glPushMatrix(); 178 | gl.glTranslatef(0.5f, 0.5f, 0); 179 | 180 | gl.glPushAttrib(GL2.GL_LINE_BIT | GL2.GL_POINT_BIT); 181 | } 182 | 183 | @Override 184 | public void endPoly() { 185 | drawLine(false); 186 | gl.glDisable(GL2.GL_LINE_STIPPLE); 187 | gl.glPopMatrix(); 188 | 189 | gl.glPopAttrib(); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/AbstractShapeHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl; 17 | 18 | 19 | import java.awt.BasicStroke; 20 | import java.awt.RenderingHints; 21 | import java.awt.RenderingHints.Key; 22 | import java.awt.Shape; 23 | import java.awt.Stroke; 24 | import java.awt.geom.Arc2D; 25 | import java.awt.geom.Ellipse2D; 26 | import java.awt.geom.Line2D; 27 | import java.awt.geom.Path2D; 28 | import java.awt.geom.PathIterator; 29 | import java.awt.geom.Rectangle2D; 30 | import java.awt.geom.RoundRectangle2D; 31 | import java.util.ArrayDeque; 32 | import java.util.Deque; 33 | 34 | import org.jogamp.glg2d.GLG2DShapeHelper; 35 | import org.jogamp.glg2d.GLGraphics2D; 36 | import org.jogamp.glg2d.PathVisitor; 37 | 38 | public abstract class AbstractShapeHelper implements GLG2DShapeHelper { 39 | /** 40 | * We know this is single-threaded, so we can use these as archetypes. 41 | */ 42 | protected static final Ellipse2D.Float ELLIPSE = new Ellipse2D.Float(); 43 | protected static final RoundRectangle2D.Float ROUND_RECT = new RoundRectangle2D.Float(); 44 | protected static final Arc2D.Float ARC = new Arc2D.Float(); 45 | protected static final Rectangle2D.Float RECT = new Rectangle2D.Float(); 46 | protected static final Line2D.Float LINE = new Line2D.Float(); 47 | 48 | protected Deque strokeStack = new ArrayDeque(); 49 | 50 | public AbstractShapeHelper() { 51 | strokeStack.push(new BasicStroke()); 52 | } 53 | 54 | @Override 55 | public void setG2D(GLGraphics2D g2d) { 56 | strokeStack.clear(); 57 | strokeStack.push(new BasicStroke()); 58 | } 59 | 60 | @Override 61 | public void push(GLGraphics2D newG2d) { 62 | strokeStack.push(newG2d.getStroke()); 63 | } 64 | 65 | @Override 66 | public void pop(GLGraphics2D parentG2d) { 67 | strokeStack.pop(); 68 | } 69 | 70 | @Override 71 | public void setHint(Key key, Object value) { 72 | // nop 73 | } 74 | 75 | @Override 76 | public void resetHints() { 77 | setHint(RenderingHints.KEY_ANTIALIASING, null); 78 | } 79 | 80 | @Override 81 | public void dispose() { 82 | // nop 83 | } 84 | 85 | @Override 86 | public void setStroke(Stroke stroke) { 87 | strokeStack.pop(); 88 | strokeStack.push(stroke); 89 | } 90 | 91 | @Override 92 | public Stroke getStroke() { 93 | return strokeStack.peek(); 94 | } 95 | 96 | @Override 97 | public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight, boolean fill) { 98 | ROUND_RECT.setRoundRect(x, y, width, height, arcWidth, arcHeight); 99 | if (fill) { 100 | fill(ROUND_RECT, true); 101 | } else { 102 | draw(ROUND_RECT); 103 | } 104 | } 105 | 106 | @Override 107 | public void drawRect(int x, int y, int width, int height, boolean fill) { 108 | RECT.setRect(x, y, width, height); 109 | if (fill) { 110 | fill(RECT, true); 111 | } else { 112 | draw(RECT); 113 | } 114 | } 115 | 116 | @Override 117 | public void drawLine(int x1, int y1, int x2, int y2) { 118 | LINE.setLine(x1, y1, x2, y2); 119 | draw(LINE); 120 | } 121 | 122 | @Override 123 | public void drawOval(int x, int y, int width, int height, boolean fill) { 124 | ELLIPSE.setFrame(x, y, width, height); 125 | if (fill) { 126 | fill(ELLIPSE, true); 127 | } else { 128 | draw(ELLIPSE); 129 | } 130 | } 131 | 132 | @Override 133 | public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle, boolean fill) { 134 | ARC.setArc(x, y, width, height, startAngle, arcAngle, fill ? Arc2D.PIE : Arc2D.OPEN); 135 | if (fill) { 136 | fill(ARC, true); 137 | } else { 138 | draw(ARC); 139 | } 140 | } 141 | 142 | @Override 143 | public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { 144 | drawPoly(xPoints, yPoints, nPoints, false, false); 145 | } 146 | 147 | @Override 148 | public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints, boolean fill) { 149 | drawPoly(xPoints, yPoints, nPoints, fill, true); 150 | } 151 | 152 | protected void drawPoly(int[] xPoints, int[] yPoints, int nPoints, boolean fill, boolean close) { 153 | Path2D.Float path = new Path2D.Float(PathIterator.WIND_NON_ZERO, nPoints); 154 | path.moveTo(xPoints[0], yPoints[0]); 155 | for (int i = 1; i < nPoints; i++) { 156 | path.lineTo(xPoints[i], yPoints[i]); 157 | } 158 | 159 | if (close) { 160 | path.closePath(); 161 | } 162 | 163 | if (fill) { 164 | fill(path); 165 | } else { 166 | draw(path); 167 | } 168 | } 169 | 170 | @Override 171 | public void fill(Shape shape) { 172 | if (shape instanceof Rectangle2D || 173 | shape instanceof Ellipse2D || 174 | shape instanceof Arc2D || 175 | shape instanceof RoundRectangle2D) { 176 | fill(shape, true); 177 | } else { 178 | fill(shape, false); 179 | } 180 | } 181 | 182 | protected abstract void fill(Shape shape, boolean isDefinitelySimpleConvex); 183 | 184 | protected void traceShape(Shape shape, PathVisitor visitor) { 185 | visitShape(shape, visitor); 186 | } 187 | 188 | public static void visitShape(Shape shape, PathVisitor visitor) { 189 | PathIterator iterator = shape.getPathIterator(null); 190 | visitor.beginPoly(iterator.getWindingRule()); 191 | 192 | float[] coords = new float[10]; 193 | float[] previousVertex = new float[2]; 194 | for (; !iterator.isDone(); iterator.next()) { 195 | int type = iterator.currentSegment(coords); 196 | switch (type) { 197 | case PathIterator.SEG_MOVETO: 198 | visitor.moveTo(coords); 199 | break; 200 | 201 | case PathIterator.SEG_LINETO: 202 | visitor.lineTo(coords); 203 | break; 204 | 205 | case PathIterator.SEG_QUADTO: 206 | visitor.quadTo(previousVertex, coords); 207 | break; 208 | 209 | case PathIterator.SEG_CUBICTO: 210 | visitor.cubicTo(previousVertex, coords); 211 | break; 212 | 213 | case PathIterator.SEG_CLOSE: 214 | visitor.closeLine(); 215 | break; 216 | } 217 | 218 | switch (type) { 219 | case PathIterator.SEG_LINETO: 220 | case PathIterator.SEG_MOVETO: 221 | previousVertex[0] = coords[0]; 222 | previousVertex[1] = coords[1]; 223 | break; 224 | 225 | case PathIterator.SEG_QUADTO: 226 | previousVertex[0] = coords[2]; 227 | previousVertex[1] = coords[3]; 228 | break; 229 | 230 | case PathIterator.SEG_CUBICTO: 231 | previousVertex[0] = coords[4]; 232 | previousVertex[1] = coords[5]; 233 | break; 234 | } 235 | } 236 | 237 | visitor.endPoly(); 238 | } 239 | } -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/GeometryShaderStrokePipeline.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | 19 | import java.awt.BasicStroke; 20 | import java.nio.FloatBuffer; 21 | 22 | import com.jogamp.opengl.GL; 23 | import com.jogamp.opengl.GL2ES2; 24 | import com.jogamp.opengl.GL3ES3; 25 | 26 | import org.jogamp.glg2d.GLG2DUtils; 27 | 28 | import com.jogamp.common.nio.Buffers; 29 | 30 | public class GeometryShaderStrokePipeline extends AbstractShaderPipeline { 31 | public static final int DRAW_END_NONE = 0; 32 | public static final int DRAW_END_FIRST = -1; 33 | public static final int DRAW_END_LAST = 1; 34 | public static final int DRAW_END_BOTH = 2; 35 | 36 | protected FloatBuffer vBuffer = Buffers.newDirectFloatBuffer(500); 37 | 38 | protected int maxVerticesOut = 32; 39 | 40 | protected int vertCoordLocation; 41 | protected int vertBeforeLocation; 42 | protected int vertAfterLocation; 43 | protected int vertCoordBuffer; 44 | 45 | protected int lineWidthLocation; 46 | protected int miterLimitLocation; 47 | protected int joinTypeLocation; 48 | protected int capTypeLocation; 49 | protected int drawEndLocation; 50 | 51 | public GeometryShaderStrokePipeline() { 52 | this("StrokeShader.v", "StrokeShader.g", "StrokeShader.f"); 53 | } 54 | 55 | public GeometryShaderStrokePipeline(String vertexShaderFileName, String geometryShaderFileName, String fragmentShaderFileName) { 56 | super(vertexShaderFileName, geometryShaderFileName, fragmentShaderFileName); 57 | } 58 | 59 | public void setStroke(GL2ES2 gl, BasicStroke stroke) { 60 | if (lineWidthLocation >= 0) { 61 | gl.glUniform1f(lineWidthLocation, stroke.getLineWidth()); 62 | } 63 | 64 | if (miterLimitLocation >= 0) { 65 | gl.glUniform1f(miterLimitLocation, stroke.getMiterLimit()); 66 | } 67 | 68 | if (joinTypeLocation >= 0) { 69 | gl.glUniform1i(joinTypeLocation, stroke.getLineJoin()); 70 | } 71 | 72 | if (capTypeLocation >= 0) { 73 | gl.glUniform1i(capTypeLocation, stroke.getEndCap()); 74 | } 75 | } 76 | 77 | protected void setDrawEnd(GL2ES2 gl, int drawType) { 78 | if (drawEndLocation >= 0) { 79 | gl.glUniform1i(drawEndLocation, drawType); 80 | } 81 | } 82 | 83 | protected void bindBuffer(GL2ES2 gl, FloatBuffer vertexBuffer) { 84 | gl.glEnableVertexAttribArray(vertCoordLocation); 85 | gl.glEnableVertexAttribArray(vertBeforeLocation); 86 | gl.glEnableVertexAttribArray(vertAfterLocation); 87 | 88 | if (gl.glIsBuffer(vertCoordBuffer)) { 89 | gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vertCoordBuffer); 90 | gl.glBufferSubData(GL.GL_ARRAY_BUFFER, 0, Buffers.SIZEOF_FLOAT * vertexBuffer.limit(), vertexBuffer); 91 | } else { 92 | vertCoordBuffer = GLG2DUtils.genBufferId(gl); 93 | 94 | gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vertCoordBuffer); 95 | gl.glBufferData(GL.GL_ARRAY_BUFFER, Buffers.SIZEOF_FLOAT * vertexBuffer.capacity(), vertexBuffer, GL2ES2.GL_STREAM_DRAW); 96 | } 97 | 98 | gl.glVertexAttribPointer(vertCoordLocation, 2, GL.GL_FLOAT, false, 0, 2 * Buffers.SIZEOF_FLOAT); 99 | gl.glVertexAttribPointer(vertBeforeLocation, 2, GL.GL_FLOAT, false, 0, 0); 100 | gl.glVertexAttribPointer(vertAfterLocation, 2, GL.GL_FLOAT, false, 0, 4 * Buffers.SIZEOF_FLOAT); 101 | } 102 | 103 | public void draw(GL2ES2 gl, FloatBuffer vertexBuffer, boolean close) { 104 | int pos = vertexBuffer.position(); 105 | int lim = vertexBuffer.limit(); 106 | int numPts = (lim - pos) / 2; 107 | 108 | if (numPts * 2 + 6 > vBuffer.capacity()) { 109 | vBuffer = Buffers.newDirectFloatBuffer(numPts * 2 + 4); 110 | } 111 | 112 | vBuffer.clear(); 113 | 114 | if (close) { 115 | vBuffer.put(vertexBuffer.get(lim - 2)); 116 | vBuffer.put(vertexBuffer.get(lim - 1)); 117 | vBuffer.put(vertexBuffer); 118 | vBuffer.put(vertexBuffer.get(pos)); 119 | vBuffer.put(vertexBuffer.get(pos + 1)); 120 | vBuffer.put(vertexBuffer.get(pos + 2)); 121 | vBuffer.put(vertexBuffer.get(pos + 3)); 122 | } else { 123 | vBuffer.put(0); 124 | vBuffer.put(0); 125 | vBuffer.put(vertexBuffer); 126 | vBuffer.put(0); 127 | vBuffer.put(0); 128 | } 129 | 130 | vBuffer.flip(); 131 | 132 | bindBuffer(gl, vBuffer); 133 | 134 | if (close) { 135 | setDrawEnd(gl, DRAW_END_NONE); 136 | gl.glDrawArrays(GL.GL_LINES, 0, numPts + 1); 137 | gl.glDrawArrays(GL.GL_LINES, 1, numPts); 138 | } else if (numPts == 2) { 139 | setDrawEnd(gl, DRAW_END_BOTH); 140 | gl.glDrawArrays(GL.GL_LINES, 0, 2); 141 | } else { 142 | setDrawEnd(gl, DRAW_END_NONE); 143 | gl.glDrawArrays(GL.GL_LINES, 1, numPts - 2); 144 | gl.glDrawArrays(GL.GL_LINES, 2, numPts - 3); 145 | 146 | setDrawEnd(gl, DRAW_END_FIRST); 147 | gl.glDrawArrays(GL.GL_LINES, 0, 2); 148 | 149 | setDrawEnd(gl, DRAW_END_LAST); 150 | gl.glDrawArrays(GL.GL_LINES, numPts - 2, 2); 151 | } 152 | 153 | gl.glDisableVertexAttribArray(vertCoordLocation); 154 | gl.glDisableVertexAttribArray(vertBeforeLocation); 155 | gl.glDisableVertexAttribArray(vertAfterLocation); 156 | 157 | gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); 158 | } 159 | 160 | @Override 161 | protected void setupUniformsAndAttributes(GL2ES2 gl) { 162 | super.setupUniformsAndAttributes(gl); 163 | 164 | transformLocation = gl.glGetUniformLocation(programId, "u_transform"); 165 | colorLocation = gl.glGetUniformLocation(programId, "u_color"); 166 | lineWidthLocation = gl.glGetUniformLocation(programId, "u_lineWidth"); 167 | miterLimitLocation = gl.glGetUniformLocation(programId, "u_miterLimit"); 168 | joinTypeLocation = gl.glGetUniformLocation(programId, "u_joinType"); 169 | drawEndLocation = gl.glGetUniformLocation(programId, "u_drawEnd"); 170 | capTypeLocation = gl.glGetUniformLocation(programId, "u_capType"); 171 | 172 | vertCoordLocation = gl.glGetAttribLocation(programId, "a_vertCoord"); 173 | vertBeforeLocation = gl.glGetAttribLocation(programId, "a_vertBefore"); 174 | vertAfterLocation = gl.glGetAttribLocation(programId, "a_vertAfter"); 175 | } 176 | 177 | @Override 178 | protected void attachShaders(GL2ES2 gl) { 179 | super.attachShaders(gl); 180 | 181 | GL3ES3 gl3 = gl.getGL3ES3(); 182 | gl3.glProgramParameteri(programId, GL3ES3.GL_GEOMETRY_INPUT_TYPE, GL.GL_LINES); 183 | gl3.glProgramParameteri(programId, GL3ES3.GL_GEOMETRY_OUTPUT_TYPE, GL.GL_TRIANGLE_STRIP); 184 | gl3.glProgramParameteri(programId, GL3ES3.GL_GEOMETRY_VERTICES_OUT, maxVerticesOut); 185 | } 186 | 187 | @Override 188 | public void delete(GL2ES2 gl) { 189 | super.delete(gl); 190 | 191 | gl.glDeleteBuffers(1, new int[] { vertCoordBuffer }, 0); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/main/java/org/jogamp/glg2d/impl/shader/AbstractShaderPipeline.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Brandon Borkholder 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.jogamp.glg2d.impl.shader; 17 | 18 | import java.io.BufferedReader; 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import java.io.InputStreamReader; 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | import com.jogamp.opengl.GL; 26 | import com.jogamp.opengl.GL2ES2; 27 | import com.jogamp.opengl.GL2GL3; 28 | import com.jogamp.opengl.GL3ES3; 29 | 30 | public abstract class AbstractShaderPipeline implements ShaderPipeline { 31 | protected int vertexShaderId = 0; 32 | protected int geometryShaderId = 0; 33 | protected int fragmentShaderId = 0; 34 | 35 | protected String vertexShaderFileName; 36 | protected String geometryShaderFileName; 37 | protected String fragmentShaderFileName; 38 | 39 | protected int programId = 0; 40 | protected int transformLocation = -1; 41 | protected int colorLocation = -1; 42 | 43 | public AbstractShaderPipeline(String vertexShaderFileName, String geometryShaderFileName, String fragmentShaderFileName) { 44 | this.vertexShaderFileName = vertexShaderFileName; 45 | this.geometryShaderFileName = geometryShaderFileName; 46 | this.fragmentShaderFileName = fragmentShaderFileName; 47 | } 48 | 49 | @Override 50 | public void setup(GL2ES2 gl) { 51 | createProgramAndAttach(gl); 52 | setupUniformsAndAttributes(gl); 53 | } 54 | 55 | @Override 56 | public boolean isSetup() { 57 | return programId > 0; 58 | } 59 | 60 | public void setColor(GL2ES2 gl, float[] rgba) { 61 | if (colorLocation >= 0) { 62 | gl.glUniform4fv(colorLocation, 1, rgba, 0); 63 | } 64 | } 65 | 66 | public void setTransform(GL2ES2 gl, float[] glMatrixData) { 67 | if (transformLocation >= 0) { 68 | gl.glUniformMatrix4fv(transformLocation, 1, false, glMatrixData, 0); 69 | } 70 | } 71 | 72 | protected void createProgramAndAttach(GL2ES2 gl) { 73 | if (gl.glIsProgram(programId)) { 74 | delete(gl); 75 | } 76 | 77 | programId = gl.glCreateProgram(); 78 | 79 | attachShaders(gl); 80 | 81 | gl.glLinkProgram(programId); 82 | checkProgramThrowException(gl, programId, GL2ES2.GL_LINK_STATUS); 83 | } 84 | 85 | protected void setupUniformsAndAttributes(GL2ES2 gl) { 86 | // nop 87 | } 88 | 89 | protected void attachShaders(GL2ES2 gl) { 90 | if (vertexShaderFileName != null) { 91 | vertexShaderId = compileShader(gl, GL2ES2.GL_VERTEX_SHADER, getClass(), vertexShaderFileName); 92 | gl.glAttachShader(programId, vertexShaderId); 93 | } 94 | 95 | if (geometryShaderFileName != null) { 96 | geometryShaderId = compileShader(gl, GL3ES3.GL_GEOMETRY_SHADER, getClass(), geometryShaderFileName); 97 | gl.glAttachShader(programId, geometryShaderId); 98 | } 99 | 100 | if (fragmentShaderFileName != null) { 101 | fragmentShaderId = compileShader(gl, GL2ES2.GL_FRAGMENT_SHADER, getClass(), fragmentShaderFileName); 102 | gl.glAttachShader(programId, fragmentShaderId); 103 | } 104 | } 105 | 106 | @Override 107 | public void use(GL2ES2 gl, boolean use) { 108 | gl.glUseProgram(use ? programId : 0); 109 | } 110 | 111 | @Override 112 | public void delete(GL2ES2 gl) { 113 | gl.glDeleteProgram(programId); 114 | deleteShaders(gl); 115 | 116 | programId = 0; 117 | } 118 | 119 | protected void deleteShaders(GL2ES2 gl) { 120 | if (gl.glIsShader(vertexShaderId)) { 121 | gl.glDeleteShader(vertexShaderId); 122 | vertexShaderId = 0; 123 | } 124 | if (gl.glIsShader(geometryShaderId)) { 125 | gl.glDeleteShader(geometryShaderId); 126 | geometryShaderId = 0; 127 | } 128 | if (gl.glIsShader(fragmentShaderId)) { 129 | gl.glDeleteShader(fragmentShaderId); 130 | fragmentShaderId = 0; 131 | } 132 | } 133 | 134 | protected int compileShader(GL2ES2 gl, int type, Class context, String name) throws ShaderException { 135 | String[] source = readShader(context, name); 136 | int id = compileShader(gl, type, source); 137 | checkShaderThrowException(gl, id); 138 | return id; 139 | } 140 | 141 | protected int compileShader(GL2ES2 gl, int type, String[] source) throws ShaderException { 142 | int id = gl.glCreateShader(type); 143 | 144 | int[] lineLengths = new int[source.length]; 145 | for (int i = 0; i < source.length; i++) { 146 | lineLengths[i] = source[i].length(); 147 | } 148 | 149 | gl.glShaderSource(id, source.length, source, lineLengths, 0); 150 | int err = gl.glGetError(); 151 | if (err != GL.GL_NO_ERROR) { 152 | throw new ShaderException("Shader source failed, GL Error: 0x" + Integer.toHexString(err)); 153 | } 154 | 155 | gl.glCompileShader(id); 156 | if (err != GL.GL_NO_ERROR) { 157 | throw new ShaderException("Compile failed, GL Error: 0x" + Integer.toHexString(err)); 158 | } 159 | 160 | return id; 161 | } 162 | 163 | protected String[] readShader(Class context, String name) throws ShaderException { 164 | try { 165 | InputStream stream = null; 166 | if (context != null) { 167 | stream = context.getResourceAsStream(name); 168 | } 169 | 170 | if (stream == null) { 171 | stream = AbstractShaderPipeline.class.getResourceAsStream(name); 172 | } 173 | 174 | if (stream == null) { 175 | stream = AbstractShaderPipeline.class.getClassLoader().getResourceAsStream(name); 176 | } 177 | 178 | if (stream == null) { 179 | throw new NullPointerException("InputStream for " + name + " is null"); 180 | } 181 | 182 | BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); 183 | String line = null; 184 | List lines = new ArrayList(); 185 | while ((line = reader.readLine()) != null) { 186 | lines.add(line + "\n"); 187 | } 188 | 189 | stream.close(); 190 | return lines.toArray(new String[lines.size()]); 191 | } catch (IOException e) { 192 | throw new ShaderException("Error reading from stream", e); 193 | } 194 | } 195 | 196 | protected void checkShaderThrowException(GL2ES2 gl, int shaderId) { 197 | int[] result = new int[1]; 198 | gl.glGetShaderiv(shaderId, GL2ES2.GL_COMPILE_STATUS, result, 0); 199 | if (result[0] == GL.GL_TRUE) { 200 | return; 201 | } 202 | 203 | gl.glGetShaderiv(shaderId, GL2ES2.GL_INFO_LOG_LENGTH, result, 0); 204 | int size = result[0]; 205 | byte[] data = new byte[size]; 206 | gl.glGetShaderInfoLog(shaderId, size, result, 0, data, 0); 207 | 208 | String error = new String(data, 0, result[0]); 209 | throw new ShaderException(error); 210 | } 211 | 212 | protected void checkProgramThrowException(GL2ES2 gl, int programId, int statusFlag) { 213 | int[] result = new int[1]; 214 | gl.glGetProgramiv(programId, statusFlag, result, 0); 215 | if (result[0] == GL.GL_TRUE) { 216 | return; 217 | } 218 | 219 | gl.glGetProgramiv(programId, GL2ES2.GL_INFO_LOG_LENGTH, result, 0); 220 | int size = result[0]; 221 | byte[] data = new byte[size]; 222 | gl.glGetProgramInfoLog(programId, size, result, 0, data, 0); 223 | 224 | String error = new String(data, 0, result[0]); 225 | throw new ShaderException(error); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/test/java/org/jogamp/glg2d/StressTest.java: -------------------------------------------------------------------------------- 1 | package org.jogamp.glg2d; 2 | 3 | import java.awt.BasicStroke; 4 | import java.awt.Color; 5 | import java.awt.Graphics2D; 6 | import java.awt.Image; 7 | import java.awt.RenderingHints; 8 | import java.awt.geom.CubicCurve2D; 9 | import java.awt.geom.QuadCurve2D; 10 | import java.awt.geom.Rectangle2D; 11 | import java.awt.image.BufferedImage; 12 | import java.util.Random; 13 | 14 | import javax.imageio.ImageIO; 15 | 16 | import org.jogamp.glg2d.util.CustomPainter; 17 | import org.jogamp.glg2d.util.TestWindow; 18 | import org.junit.AfterClass; 19 | import org.junit.BeforeClass; 20 | import org.junit.Ignore; 21 | import org.junit.Test; 22 | 23 | public class StressTest { 24 | static final long TESTINGTIME = 10000; 25 | static final boolean USE_ANTIALIAS = true; 26 | 27 | static TestWindow tester; 28 | 29 | static Random rand = new Random(); 30 | 31 | @BeforeClass 32 | public static void initialize() { 33 | tester = new TestWindow(); 34 | } 35 | 36 | @AfterClass 37 | public static void close() { 38 | tester.finish(); 39 | } 40 | 41 | @Test 42 | public void shapeTest() throws Exception { 43 | final int numshapes = 1000; 44 | TimedPainter painter = new TimedPainter() { 45 | @Override 46 | protected void paint(Graphics2D g2d) { 47 | g2d.setColor(Color.red); 48 | Rectangle2D.Float rect = new Rectangle2D.Float(); 49 | float w = 20; 50 | float h = 40; 51 | float x = 300; 52 | float y = 400; 53 | for (int i = 0; i < numshapes; i++) { 54 | rect.setRect(rand.nextFloat() * x, rand.nextFloat() * y, rand.nextFloat() * w, rand.nextFloat() * h); 55 | g2d.fill(rect); 56 | } 57 | } 58 | }; 59 | 60 | tester.setPainter(painter); 61 | painter.waitAndLogTimes("shapes"); 62 | } 63 | 64 | @Test 65 | public void lineTest() throws Exception { 66 | final int numlines = 100; 67 | TimedPainter painter = new TimedPainter() { 68 | @Override 69 | protected void paint(Graphics2D g2d) { 70 | g2d.setColor(Color.BLACK); 71 | g2d.setStroke(new BasicStroke(3)); 72 | int x = 300; 73 | int y = 400; 74 | int numpoints = 5; 75 | int[] xarray = new int[numpoints]; 76 | int[] yarray = new int[numpoints]; 77 | for (int i = 0; i < numlines; i++) { 78 | for (int j = 0; j < numpoints; j++) { 79 | xarray[j] = rand.nextInt(x); 80 | yarray[j] = rand.nextInt(y); 81 | } 82 | 83 | g2d.drawPolyline(xarray, yarray, numpoints); 84 | } 85 | } 86 | }; 87 | 88 | tester.setPainter(painter); 89 | painter.waitAndLogTimes("lines"); 90 | } 91 | 92 | @Test 93 | public void quadCurvedLineTest() throws Exception { 94 | final int numcurves = 100; 95 | TimedPainter painter = new TimedPainter() { 96 | @Override 97 | protected void paint(Graphics2D g2d) { 98 | g2d.setColor(Color.BLACK); 99 | g2d.setStroke(new BasicStroke(3)); 100 | int x = 300; 101 | int y = 400; 102 | for (int i = 0; i < numcurves; i++) { 103 | g2d.draw(new QuadCurve2D.Double( 104 | rand.nextDouble() * x, rand.nextDouble() * y, 105 | rand.nextDouble() * x, rand.nextDouble() * y, 106 | rand.nextDouble() * x, rand.nextDouble() * y)); 107 | } 108 | } 109 | }; 110 | 111 | tester.setPainter(painter); 112 | painter.waitAndLogTimes("quad curves"); 113 | } 114 | 115 | @Test 116 | public void arcTest() throws Exception { 117 | final int numarcs = 1000; 118 | TimedPainter painter = new TimedPainter() { 119 | @Override 120 | protected void paint(Graphics2D g2d) { 121 | g2d.setColor(Color.BLACK); 122 | g2d.setStroke(new BasicStroke(3)); 123 | int x = 300; 124 | int y = 400; 125 | for (int i = 0; i < numarcs; i++) { 126 | g2d.drawArc(rand.nextInt(x), rand.nextInt(y), 127 | rand.nextInt(x / 2), rand.nextInt(y / 2), 128 | rand.nextInt(180), rand.nextInt(360)); 129 | } 130 | } 131 | }; 132 | 133 | tester.setPainter(painter); 134 | painter.waitAndLogTimes("arcs"); 135 | } 136 | 137 | @Test 138 | public void cubicCurvedLineTest() throws Exception { 139 | final int numcurves = 100; 140 | TimedPainter painter = new TimedPainter() { 141 | @Override 142 | protected void paint(Graphics2D g2d) { 143 | g2d.setColor(Color.BLACK); 144 | g2d.setStroke(new BasicStroke(3)); 145 | int x = 300; 146 | int y = 400; 147 | for (int i = 0; i < numcurves; i++) { 148 | g2d.draw(new CubicCurve2D.Double( 149 | rand.nextDouble() * x, rand.nextDouble() * y, 150 | rand.nextDouble() * x, rand.nextDouble() * y, 151 | rand.nextDouble() * x, rand.nextDouble() * y, 152 | rand.nextDouble() * x, rand.nextDouble() * y)); 153 | } 154 | } 155 | }; 156 | 157 | tester.setPainter(painter); 158 | painter.waitAndLogTimes("cubic curves"); 159 | } 160 | 161 | @Test 162 | public void imageTest() throws Exception { 163 | final int numimages = 100; 164 | final Image image = ImageIO.read(StressTest.class.getClassLoader().getResource("duke.gif")); 165 | TimedPainter painter = new TimedPainter() { 166 | @Override 167 | protected void paint(Graphics2D g2d) { 168 | int x = 300; 169 | int y = 400; 170 | for (int i = 0; i < numimages; i++) { 171 | g2d.drawImage(image, rand.nextInt(x), rand.nextInt(y), rand.nextInt(x), rand.nextInt(y), null); 172 | } 173 | } 174 | }; 175 | 176 | tester.setPainter(painter); 177 | painter.waitAndLogTimes("images"); 178 | } 179 | 180 | @Test 181 | @Ignore 182 | public void newImageMemoryTest() throws Exception { 183 | TimedPainter painter = new TimedPainter() { 184 | Random r = new Random(); 185 | 186 | @Override 187 | public void paint(Graphics2D g2d) { 188 | int w = 500; 189 | int h = 500; 190 | BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR); 191 | 192 | Graphics2D ig2d = img.createGraphics(); 193 | ig2d.setStroke(new BasicStroke(5)); 194 | ig2d.setColor(Color.white); 195 | for (int i = 0; i < 10; i++) { 196 | ig2d.drawArc(r.nextInt(w), r.nextInt(h), r.nextInt(w / 2), r.nextInt(h / 2), r.nextInt(360), r.nextInt(360)); 197 | } 198 | ig2d.dispose(); 199 | 200 | g2d.drawImage(img, null, null); 201 | } 202 | }; 203 | 204 | tester.setPainter(painter); 205 | painter.waitIndefinitely("icon memory"); 206 | } 207 | 208 | static abstract class TimedPainter implements CustomPainter { 209 | long[] times = new long[2]; 210 | 211 | int[] calls = new int[2]; 212 | 213 | @Override 214 | public void paint(Graphics2D g2d, boolean jogl) { 215 | if (USE_ANTIALIAS) { 216 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 217 | } 218 | 219 | long start = System.nanoTime(); 220 | paint(g2d); 221 | long end = System.nanoTime(); 222 | 223 | int index = jogl ? 0 : 1; 224 | times[index] += end - start; 225 | calls[index]++; 226 | } 227 | 228 | protected abstract void paint(Graphics2D g2d); 229 | 230 | public void waitAndLogTimes(String type) throws InterruptedException { 231 | Thread.sleep(TESTINGTIME); 232 | 233 | System.out.println(String.format("JOGL for %s took an average of %.3f ms", type, times[0] / 1e6 / calls[0])); 234 | System.out.println(String.format("Java2D for %s took an average of %.3f ms", type, times[1] / 1e6 / calls[1])); 235 | } 236 | 237 | public void waitIndefinitely(String type) throws InterruptedException { 238 | while (true) { 239 | waitAndLogTimes(type); 240 | } 241 | } 242 | } 243 | } 244 | --------------------------------------------------------------------------------