summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--turtle2d/LICENSE.txt112
-rw-r--r--turtle2d/doc/alt-algorithm-rsantina-01.pdfbin0 -> 52435 bytes
-rwxr-xr-xturtle2d/src/com/jogamp/graph/curve/OutlineShape.java307
-rwxr-xr-xturtle2d/src/com/jogamp/graph/curve/Region.java128
-rwxr-xr-xturtle2d/src/com/jogamp/graph/curve/RegionFactory.java62
-rw-r--r--turtle2d/src/com/jogamp/graph/curve/opengl/RegionRenderer.java113
-rw-r--r--turtle2d/src/com/jogamp/graph/curve/opengl/Renderer.java167
-rw-r--r--turtle2d/src/com/jogamp/graph/curve/opengl/TextRenderer.java103
-rw-r--r--turtle2d/src/com/jogamp/graph/curve/tess/CDTriangulator2D.java216
-rw-r--r--turtle2d/src/com/jogamp/graph/font/Font.java82
-rw-r--r--turtle2d/src/com/jogamp/graph/font/FontFactory.java80
-rw-r--r--turtle2d/src/com/jogamp/graph/font/FontSet.java60
-rw-r--r--turtle2d/src/com/jogamp/graph/geom/AABBox.java299
-rw-r--r--turtle2d/src/com/jogamp/graph/geom/Outline.java176
-rw-r--r--turtle2d/src/com/jogamp/graph/geom/Triangle.java79
-rw-r--r--turtle2d/src/com/jogamp/graph/geom/Vertex.java80
-rw-r--r--turtle2d/src/com/jogamp/graph/geom/opengl/SVertex.java178
-rwxr-xr-xturtle2d/src/com/jogamp/graph/math/Quaternion.java382
-rwxr-xr-xturtle2d/src/com/jogamp/graph/math/VectorUtil.java295
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/TestRegionRenderer01.java156
-rwxr-xr-xturtle2d/src/com/jogamp/opengl/test/junit/graph/TestTextRenderer01.java169
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java124
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java120
-rwxr-xr-xturtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java75
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java75
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionRendererListenerBase01.java52
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java264
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java61
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java67
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java76
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java229
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/MSAATool.java69
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/ReadBufferUtil.java109
-rw-r--r--turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/Screenshot.java39
-rwxr-xr-xturtle2d/src/jogamp/graph/curve/opengl/RegionRendererImpl01.java206
-rw-r--r--turtle2d/src/jogamp/graph/curve/opengl/TextRendererImpl01.java188
-rw-r--r--turtle2d/src/jogamp/graph/curve/opengl/VBORegion2PES2.java385
-rw-r--r--turtle2d/src/jogamp/graph/curve/opengl/VBORegionSPES2.java185
-rw-r--r--turtle2d/src/jogamp/graph/curve/opengl/shader/curverenderer01.fp99
-rw-r--r--turtle2d/src/jogamp/graph/curve/opengl/shader/curverenderer01.vp13
-rw-r--r--turtle2d/src/jogamp/graph/curve/tess/GraphOutline.java81
-rw-r--r--turtle2d/src/jogamp/graph/curve/tess/GraphVertex.java120
-rw-r--r--turtle2d/src/jogamp/graph/curve/tess/HEdge.java130
-rw-r--r--turtle2d/src/jogamp/graph/curve/tess/Loop.java373
-rw-r--r--turtle2d/src/jogamp/graph/curve/text/GlyphShape.java161
-rw-r--r--turtle2d/src/jogamp/graph/curve/text/GlyphString.java163
-rw-r--r--turtle2d/src/jogamp/graph/font/FontConstructor.java34
-rw-r--r--turtle2d/src/jogamp/graph/font/FontInt.java50
-rw-r--r--turtle2d/src/jogamp/graph/font/JavaFontLoader.java129
-rw-r--r--turtle2d/src/jogamp/graph/font/UbuntuFontLoader.java132
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/CONTRIBUTING.txt21
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/FONTLOG.txt211
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/LICENCE-FAQ.txt177
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/LICENCE.txt96
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/README.txt15
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/TRADEMARKS.txt4
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-B.ttfbin0 -> 339320 bytes
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-BI.ttfbin0 -> 362784 bytes
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-L.ttfbin0 -> 421172 bytes
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-LI.ttfbin0 -> 415424 bytes
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-M.ttfbin0 -> 346940 bytes
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-MI.ttfbin0 -> 372728 bytes
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-R.ttfbin0 -> 359668 bytes
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-RI.ttfbin0 -> 389744 bytes
-rw-r--r--turtle2d/src/jogamp/graph/font/fonts/ubuntu/copyright.txt5
-rw-r--r--turtle2d/src/jogamp/graph/font/typecast/TypecastFont.java268
-rw-r--r--turtle2d/src/jogamp/graph/font/typecast/TypecastFontConstructor.java53
-rw-r--r--turtle2d/src/jogamp/graph/font/typecast/TypecastGlyph.java232
-rw-r--r--turtle2d/src/jogamp/graph/font/typecast/TypecastHMetrics.java83
-rw-r--r--turtle2d/src/jogamp/graph/font/typecast/TypecastRenderer.java163
-rw-r--r--turtle2d/src/jogamp/graph/geom/plane/AffineTransform.java580
-rw-r--r--turtle2d/src/jogamp/graph/geom/plane/IllegalPathStateException.java34
-rw-r--r--turtle2d/src/jogamp/graph/geom/plane/NoninvertibleTransformException.java31
-rw-r--r--turtle2d/src/jogamp/graph/geom/plane/Path2D.java428
-rw-r--r--turtle2d/src/jogamp/graph/geom/plane/PathIterator.java42
-rw-r--r--turtle2d/src/jogamp/graph/math/MathFloat.java45
-rw-r--r--turtle2d/src/jogamp/graph/math/plane/Crossing.java897
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/Disassembler.java109
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/Fixed.java852
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/Mnemonic.java397
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/OTFont.java274
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/OTFontCollection.java169
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/OTGlyph.java168
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/Point.java29
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/mac/ResourceData.java45
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/mac/ResourceFile.java77
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/mac/ResourceHeader.java61
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/mac/ResourceMap.java83
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/mac/ResourceReference.java81
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/mac/ResourceType.java82
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/BaseTable.java435
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CffStandardStrings.java424
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CffTable.java620
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/Charstring.java33
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CharstringType2.java235
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/ClassDef.java33
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/ClassDefFormat1.java39
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/ClassDefFormat2.java37
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat.java134
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat0.java92
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat2.java173
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat4.java165
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat6.java87
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CmapFormatUnknown.java54
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CmapIndexEntry.java117
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CmapTable.java161
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/Coverage.java83
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CoverageFormat1.java88
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CoverageFormat2.java89
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/CvtTable.java61
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/Device.java50
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/DirectoryEntry.java115
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/DsigEntry.java43
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/DsigTable.java69
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/Feature.java85
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/FeatureList.java118
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/FeatureRecord.java88
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/FeatureTags.java63
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/FpgmTable.java46
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/GaspRange.java45
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/GaspTable.java63
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/GlyfCompositeComp.java200
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/GlyfCompositeDescript.java202
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/GlyfDescript.java124
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/GlyfSimpleDescript.java245
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/GlyfTable.java132
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/GlyphDescription.java86
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/GposTable.java66
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/GsubTable.java181
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/HdmxTable.java130
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/HeadTable.java205
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/HheaTable.java135
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/HmtxTable.java141
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/ID.java399
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/KernSubtable.java49
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/KernSubtableFormat0.java47
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/KernSubtableFormat2.java42
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/KernTable.java62
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/KerningPair.java44
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/LangSys.java105
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/LangSysRecord.java88
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/Ligature.java85
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/LigatureSet.java85
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/LigatureSubst.java73
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/LigatureSubstFormat1.java95
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/LocaTable.java77
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/Lookup.java110
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/LookupList.java108
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/LookupSubtable.java60
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/LookupSubtableFactory.java64
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/LtshTable.java68
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/MaxpTable.java162
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/NameRecord.java145
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/NameTable.java131
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/Os2Table.java357
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/Panose.java96
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/PcltTable.java105
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/PostTable.java422
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/PrepTable.java46
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/Program.java40
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/RangeRecord.java87
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/Script.java118
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/ScriptList.java115
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/ScriptRecord.java88
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/ScriptTags.java61
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/SignatureBlock.java46
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/SingleSubst.java81
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/SingleSubstFormat1.java92
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/SingleSubstFormat2.java97
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/TTCHeader.java59
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/Table.java67
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/TableDirectory.java129
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/TableException.java46
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/TableFactory.java184
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/VdmxTable.java197
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/VheaTable.java147
-rw-r--r--turtle2d/src/net/java/dev/typecast/ot/table/VmtxTable.java112
-rw-r--r--turtle2d/src/net/java/dev/typecast/t2/T2Interpreter.java1043
-rw-r--r--turtle2d/src/net/java/dev/typecast/t2/T2Mnemonic.java86
-rw-r--r--turtle2d/src/net/java/dev/typecast/tt/engine/GraphicsState.java50
-rw-r--r--turtle2d/src/net/java/dev/typecast/tt/engine/Interpreter.java1357
-rw-r--r--turtle2d/src/net/java/dev/typecast/tt/engine/Parser.java192
-rw-r--r--turtle2d/src/org/apache/harmony/misc/HashCode.java203
183 files changed, 26479 insertions, 0 deletions
diff --git a/turtle2d/LICENSE.txt b/turtle2d/LICENSE.txt
new file mode 100644
index 0000000..4b5accb
--- /dev/null
+++ b/turtle2d/LICENSE.txt
@@ -0,0 +1,112 @@
+
+L.1) The JOGL source tree contains code from the JogAmp Community
+ which is covered by the Simplified BSD 2-clause license:
+
+ Copyright 2010 JogAmp Community. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are
+ permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this list of
+ conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ of conditions and the following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ The views and conclusions contained in the software and documentation are those of the
+ authors and should not be interpreted as representing official policies, either expressed
+ or implied, of JogAmp Community.
+
+ You can address the JogAmp Community via:
+ Web http://jogamp.org/
+ Forum/Mailinglist http://jogamp.762907.n3.nabble.com/
+ JogAmp Channel server: conference.jabber.org room: jogamp
+ Repository http://jogamp.org/git/
+ Email mediastream _at_ jogamp _dot_ org
+
+
+++++
+
+L.2) The JOGL source tree contains code from The Apache Software Foundation
+ which is covered by the Apache License Version 2.0
+
+Apache Harmony - Open Source Java SE
+=====================================
+
+<http://harmony.apache.org/>
+
+Author: The Apache Software Foundation (http://www.apache.org/).
+
+Copyright 2006, 2010 The Apache Software Foundation.
+
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+Files:
+ src/jogamp/graph/geom/plane/AffineTransform.java
+ src/jogamp/graph/geom/plane/IllegalPathStateException.java
+ src/jogamp/graph/geom/plane/NoninvertibleTransformException.java
+ src/jogamp/graph/geom/plane/PathIterator.java
+ src/jogamp/graph/geom/plane/Path2D.java
+ src/jogamp/graph/math/plane/Crossing.java
+ src/org/apache/harmony/misc/HashCode.java
+
+++++
+
+L.3) The JOGL source tree contains code from David Schweinsberg
+ which is covered by the Apache License Version 2.0
+
+Typecast
+========
+
+Typecast is a font development environment for OpenType font technology.
+
+<http://typecast.dev.java.net/>
+
+Author: David Schweinsberg
+
+Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+Files:
+ src/net/java/dev/typecast/**
+
+++++
+
+L.4) The JOGL source tree contains fonts from Ubuntu
+ which is covered by the UBUNTU FONT LICENCE Version 1.0
+
+Ubunut Font Family
+==================
+
+The Ubuntu Font Family are libre fonts funded by Canonical Ltd on behalf of the Ubuntu project.
+
+<http://font.ubuntu.com/>
+
+Copyright 2010 Canonical Ltd.
+Licensed under the Ubuntu Font Licence 1.0
+
+Author: Canonical Ltd., Dalton Maag
+
+UBUNTU FONT LICENCE
+Version 1.0
+http://font.ubuntu.com/ufl/ubuntu-font-licence-1.0.txt
+
+Files:
+ src/jogamp/graph/font/fonts/ubuntu/
+
diff --git a/turtle2d/doc/alt-algorithm-rsantina-01.pdf b/turtle2d/doc/alt-algorithm-rsantina-01.pdf
new file mode 100644
index 0000000..969b3a7
--- /dev/null
+++ b/turtle2d/doc/alt-algorithm-rsantina-01.pdf
Binary files differ
diff --git a/turtle2d/src/com/jogamp/graph/curve/OutlineShape.java b/turtle2d/src/com/jogamp/graph/curve/OutlineShape.java
new file mode 100755
index 0000000..827717a
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/curve/OutlineShape.java
@@ -0,0 +1,307 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.curve;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import com.jogamp.graph.geom.Outline;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.math.VectorUtil;
+
+import com.jogamp.graph.curve.tess.CDTriangulator2D;
+
+/** A Generic shape objects which is defined by a list of Outlines.
+ * This Shape can be transformed to Triangulations.
+ * The list of triangles generated are render-able by a Region object.
+ * The triangulation produced by this Shape will define the
+ * closed region defined by the outlines.
+ *
+ * One or more OutlineShape Object can be associated to a region
+ * this is left as a high-level representation of the Objects. For
+ * optimizations, flexibility requirements for future features.
+ *
+ * <br><br>
+ * Example to creating an Outline Shape:
+ * <pre>
+ addVertex(...)
+ addVertex(...)
+ addVertex(...)
+ addEnptyOutline()
+ addVertex(...)
+ addVertex(...)
+ addVertex(...)
+ * </pre>
+ *
+ * The above will create two outlines each with three vertices. By adding these two outlines to
+ * the OutlineShape, we are stating that the combination of the two outlines represent the shape.
+ * <br>
+ *
+ * To specify that the shape is curved at a region, the on-curve flag should be set to false
+ * for the vertex that is in the middle of the curved region (if the curved region is defined by 3
+ * vertices (quadratic curve).
+ * <br>
+ * In case the curved region is defined by 4 or more vertices the middle vertices should both have
+ * the on-curve flag set to false.
+ *
+ * <br>Example: <br>
+ * <pre>
+ addVertex(0,0, true);
+ addVertex(0,1, false);
+ addVertex(1,1, false);
+ addVertex(1,0, true);
+ * </pre>
+ *
+ * The above snippet defines a cubic nurbs curve where (0,1 and 1,1)
+ * do not belong to the final rendered shape.
+ *
+ * <i>Implementation Notes:</i><br>
+ * <ul>
+ * <li> The first vertex of any outline belonging to the shape should be on-curve</li>
+ * <li> Intersections between off-curved parts of the outline is not handled</li>
+ * </ul>
+ *
+ * @see Outline
+ * @see Region
+ */
+public class OutlineShape {
+
+ public static final int QUADRATIC_NURBS = 10;
+ private final Vertex.Factory<? extends Vertex> vertexFactory;
+
+ /** The list of {@link Outline}s that are part of this
+ * outline shape.
+ */
+ private ArrayList<Outline> outlines = new ArrayList<Outline>(3);
+
+ /** Create a new Outline based Shape
+ */
+ public OutlineShape(Vertex.Factory<? extends Vertex> factory) {
+ vertexFactory = factory;
+ outlines.add(new Outline());
+ }
+
+ /** Returns the associated vertex factory of this outline shape
+ * @return Vertex.Factory object
+ */
+ public final Vertex.Factory<? extends Vertex> vertexFactory() { return vertexFactory; }
+
+ /** Add a new empty {@link Outline}
+ * to the shape, this new outline will
+ * be placed at the end of the outline list.
+ *
+ * After a call to this function all new vertices added
+ * will belong to the new outline
+ */
+ public void addEmptyOutline(){
+ outlines.add(new Outline());
+ }
+
+ /** Adds an {@link Outline} to the OutlineShape object
+ * if last outline of the shape is empty, it will replace
+ * that last Outline with the new one. If outline is empty,
+ * it will do nothing.
+ * @param outline an Outline object
+ */
+ public void addOutline(Outline outline){
+ if(outline.isEmpty()){
+ return;
+ }
+ if(getLastOutline().isEmpty()){
+ outlines.remove(getLastOutline());
+ }
+ outlines.add(outline);
+ }
+
+ /** Adds a vertex to the last open outline in the
+ * shape.
+ * @param v the vertex to be added to the OutlineShape
+ */
+ public final void addVertex(Vertex v){
+ getLastOutline().addVertex(v);
+ }
+
+ /** Add a 2D {@link Vertex} to the last outline by defining the coordniate attribute
+ * of the vertex. The 2D vertex will be represented as Z=0.
+ *
+ * @param x the x coordinate
+ * @param y the y coordniate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float x, float y, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, x, y, onCurve);
+ }
+
+ /** Add a 3D {@link Vertex} to the last outline by defining the coordniate attribute
+ * of the vertex.
+ * @param x the x coordinate
+ * @param y the y coordniate
+ * @param z the z coordniate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float x, float y, float z, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, x, y, z, onCurve);
+ }
+
+ /** Add a vertex to the last outline by passing a float array and specifying the
+ * offset and length in which. The attributes of the vertex are located.
+ * The attributes should be continuous (stride = 0).
+ * Attributes which value are not set (when length less than 3)
+ * are set implicitly to zero.
+ * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from
+ * @param offset the offset in the buffer to the x coordinate
+ * @param length the number of attributes to pick from the buffer (maximum 3)
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float[] coordsBuffer, int offset, int length, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, coordsBuffer, offset, length, onCurve);
+ }
+
+ /** Closes the last outline in the shape
+ * if last vertex is not equal to first vertex.
+ * A new temp vertex is added at the end which
+ * is equal to the first.
+ */
+ public void closeLastOutline(){
+ getLastOutline().setClosed(true);
+ }
+
+ /** Get the last added outline to the list
+ * of outlines that define the shape
+ * @return the last outline
+ */
+ public final Outline getLastOutline(){
+ return outlines.get(outlines.size()-1);
+ }
+ /** Make sure that the outlines represent
+ * the specified destinationType, if not
+ * transform outlines to destination type.
+ * @param destinationType The curve type needed
+ */
+ public void transformOutlines(int destinationType){
+ if(destinationType == QUADRATIC_NURBS){
+ transformOutlinesQuadratic();
+ }
+ }
+
+ private void transformOutlinesQuadratic(){
+ ArrayList<Outline> newOutlines = new ArrayList<Outline>(3);
+
+ /**loop over the outlines and make sure no
+ * adj off-curve vertices
+ */
+ for(Outline outline:outlines){
+ Outline newOutline = new Outline();
+
+ ArrayList<Vertex> vertices = outline.getVertices();
+ int size =vertices.size()-1;
+ for(int i=0;i<size;i++){
+ Vertex currentVertex = vertices.get(i);
+ Vertex nextVertex = vertices.get((i+1)%size);
+ if(!(currentVertex.isOnCurve()) && !(nextVertex.isOnCurve())) {
+ newOutline.addVertex(currentVertex);
+
+ float[] newCoords = VectorUtil.mid(currentVertex.getCoord(), nextVertex.getCoord());
+ newOutline.addVertex(vertexFactory, newCoords, 0, 3, true);
+ }
+ else {
+ newOutline.addVertex(currentVertex);
+ }
+ }
+ newOutlines.add(newOutline);
+ }
+ outlines = newOutlines;
+ }
+
+ private void generateVertexIds(){
+ int maxVertexId = 0;
+ for(Outline outline:outlines){
+ ArrayList<Vertex> vertices = outline.getVertices();
+ for(Vertex vert:vertices){
+ vert.setId(maxVertexId);
+ maxVertexId++;
+ }
+ }
+ }
+
+ /** @return the list of vertices associated with the
+ * {@code Outline} list of this object
+ */
+ public ArrayList<Vertex> getVertices(){
+ ArrayList<Vertex> vertices = new ArrayList<Vertex>();
+ for(Outline polyline:outlines){
+ vertices.addAll(polyline.getVertices());
+ }
+ return vertices;
+ }
+
+ /** Triangulate the outline shape generating a list of triangles
+ * @return an arraylist of triangles representing the filled region
+ * which is produced by the combination of the outlines
+ */
+ public ArrayList<Triangle> triangulate(){
+ return triangulate(0.5f);
+ }
+
+ /**Triangulate the {@link OutlineShape} generating a list of triangles
+ * @param sharpness defines the curvature strength around the off-curve vertices.
+ * defaults to 0.5f
+ * @return an arraylist of triangles representing the filled region
+ * which is produced by the combination of the outlines
+ */
+ public ArrayList<Triangle> triangulate(float sharpness){
+ if(outlines.size() == 0){
+ return null;
+ }
+ sortOutlines();
+ generateVertexIds();
+
+ CDTriangulator2D triangulator2d = new CDTriangulator2D(sharpness);
+ for(int index = 0; index< outlines.size();index++){
+ Outline outline = outlines.get(index);
+ triangulator2d.addCurve(outline);
+ }
+
+ ArrayList<Triangle> triangles = triangulator2d.generateTriangulation();
+ triangulator2d.reset();
+
+ return triangles;
+ }
+
+ /** Sort the outlines from large
+ * to small depending on the AABox
+ */
+ private void sortOutlines() {
+ Collections.sort(outlines);
+ Collections.reverse(outlines);
+ }
+}
diff --git a/turtle2d/src/com/jogamp/graph/curve/Region.java b/turtle2d/src/com/jogamp/graph/curve/Region.java
new file mode 100755
index 0000000..051cb1c
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/curve/Region.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.curve;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.opengl.util.PMVMatrix;
+
+/** A Region is the OGL binding of one or more OutlineShapes
+ * Defined by its vertices and generated triangles. The Region
+ * defines the final shape of the OutlineShape(s), which shall produced a shaded
+ * region on the screen.
+ *
+ * Implementations of the Region shall take care of the OGL
+ * binding of the depending on its context, profile.
+ *
+ * @see RegionFactory, OutlineShape
+ */
+public interface Region {
+ /** The vertices index in an OGL object
+ */
+ public static int VERTEX_ATTR_IDX = 0;
+
+ /** The Texture Coord index in an OGL object
+ */
+ public static int TEXCOORD_ATTR_IDX = 1;
+
+ /** single pass rendering, fast, but AA might not be perfect */
+ public static int SINGLE_PASS = 1;
+
+ /** two pass rendering, slower and more resource hungry (FBO), but AA is perfect */
+ public static int TWO_PASS = 2;
+
+ /** Updates a graph region by updating the ogl related
+ * objects for use in rendering. if called for the first time
+ * it initialize the objects.
+ */
+ public void update();
+
+ /** Renders the associated OGL objects specifying
+ * current width/hight of window for multi pass rendering
+ * of the region.
+ * @param matrix current {@link PMVMatrix}.
+ * @param vp_width current screen width
+ * @param vp_height current screen height
+ * @param width texture width for mp rendering
+ *
+ * @see update()
+ */
+ public void render(PMVMatrix matrix, int vp_width, int vp_height, int width);
+
+ /** Adds a list of {@link Triangle} objects to the Region
+ * These triangles are to be binded to OGL objects
+ * on the next call to {@code update}
+ * @param tris an arraylist of triangle objects
+ *
+ * @see update()
+ */
+ public void addTriangles(ArrayList<Triangle> tris);
+
+ /** Get the current number of vertices associated
+ * with this region. This number is not necessary equal to
+ * the OGL binded number of vertices.
+ * @return vertices count
+ *
+ * @see isDirty()
+ */
+ public int getNumVertices();
+
+ /** Adds a list of {@link Vertex} objects to the Region
+ * These vertices are to be binded to OGL objects
+ * on the next call to {@code update}
+ * @param verts an arraylist of vertex objects
+ *
+ * @see update()
+ */
+ public void addVertices(ArrayList<Vertex> verts);
+
+ /** Check if this region is dirty. A region is marked dirty
+ * when new Vertices, Triangles, and or Lines are added after a
+ * call to update()
+ * @return true if region is Dirty, false otherwise
+ *
+ * @see update();
+ */
+ public boolean isDirty();
+
+ /** Delete and clean the associated OGL
+ * objects
+ */
+ public void destroy();
+
+ public boolean isFlipped();
+
+ /** Set if the y coordinate of the region should be flipped
+ * {@code y=-y} used mainly for fonts since they use opposite vertex
+ * as origion
+ * @param flipped flag if the coordinate is flipped defaults to false.
+ */
+ public void setFlipped(boolean flipped);
+}
diff --git a/turtle2d/src/com/jogamp/graph/curve/RegionFactory.java b/turtle2d/src/com/jogamp/graph/curve/RegionFactory.java
new file mode 100755
index 0000000..d3b978b
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/curve/RegionFactory.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.curve;
+
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLException;
+
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+import jogamp.graph.curve.opengl.VBORegionSPES2;
+import jogamp.graph.curve.opengl.VBORegion2PES2;
+
+
+/** RegionFactory to create a Context specific Region implementation.
+ *
+ * @see Region
+ */
+public class RegionFactory {
+
+ /**Create a Region based on the GLContext attached
+ * @param context the current {@link GLContext}
+ * @param st the {@link ShaderState} object
+ * @param type can be one of Region.SINGLE_PASS or Region.TWO_PASS
+ * @return region
+ */
+ public static Region create(GLContext context, ShaderState st, int type){
+ if( !context.isGL2ES2() ) {
+ throw new GLException("At least a GL2ES2 GL context is required. Given: " + context);
+ }
+ if( Region.TWO_PASS == type ){
+ return new VBORegion2PES2(context, st);
+ }
+ else{
+ return new VBORegionSPES2(context);
+ }
+ }
+}
diff --git a/turtle2d/src/com/jogamp/graph/curve/opengl/RegionRenderer.java b/turtle2d/src/com/jogamp/graph/curve/opengl/RegionRenderer.java
new file mode 100644
index 0000000..c1fec10
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/curve/opengl/RegionRenderer.java
@@ -0,0 +1,113 @@
+package com.jogamp.graph.curve.opengl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.media.opengl.GL2ES2;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.curve.RegionFactory;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Vertex;
+
+public abstract class RegionRenderer extends Renderer {
+
+ /** Create a Hardware accelerated Curve Region Renderer
+ */
+ public static RegionRenderer create(Vertex.Factory<? extends Vertex> factory, int type) {
+ return new jogamp.graph.curve.opengl.RegionRendererImpl01(factory, type);
+ }
+
+ public RegionRenderer(Vertex.Factory<? extends Vertex> factory, int type) {
+ super(factory, type);
+ }
+
+ /** Render an array of {@link OutlineShape}s combined in one region
+ * at the position provided the triangles of the
+ * shapes will be generated, if not yet generated
+ * @param outlineShapes array of OutlineShapes to Render.
+ * @param position the initial translation of the outlineShapes.
+ * @param texSize texture size for multipass render *
+ * @throws Exception if HwRegionRenderer not initialized
+ */
+ public abstract void renderOutlineShapes(GL2ES2 gl, OutlineShape[] outlineShapes, float[] position, int texSize);
+
+ /** Render an {@link OutlineShape} in 3D space at the position provided
+ * the triangles of the shapes will be generated, if not yet generated
+ * @param outlineShape the OutlineShape to Render.
+ * @param position the initial translation of the outlineShape.
+ * @param texSize texture size for multipass render
+ * @throws Exception if HwRegionRenderer not initialized
+ */
+ public abstract void renderOutlineShape(GL2ES2 gl, OutlineShape outlineShape, float[] position, int texSize);
+
+ protected HashMap<Integer, Region> regions = new HashMap<Integer, Region>();
+
+ public void flushCache() {
+ Iterator<Region> iterator = regions.values().iterator();
+ while(iterator.hasNext()){
+ Region region = iterator.next();
+ region.destroy();
+ }
+ regions.clear();
+ }
+
+ /** Create an ogl {@link Region} defining this {@link OutlineShape}
+ * @param sharpness parameter for Region generation
+ * @return the resulting Region.
+ */
+ protected Region createRegion(GL2ES2 gl, OutlineShape outlineShape, float sharpness) {
+ Region region = RegionFactory.create(gl.getContext(), st, renderType);
+
+ outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS);
+
+ ArrayList<Triangle> triangles = (ArrayList<Triangle>) outlineShape.triangulate(sharpness);
+ ArrayList<Vertex> vertices = (ArrayList<Vertex>) outlineShape.getVertices();
+ region.addVertices(vertices);
+ region.addTriangles(triangles);
+
+ region.update();
+ return region;
+ }
+
+ /** Create an ogl {@link Region} defining the list of {@link OutlineShape}.
+ * Combining the Shapes into single buffers.
+ * @param sharpness parameter for Region generation
+ * @return the resulting Region inclusive the generated region
+ */
+ protected Region createRegion(GL2ES2 gl, OutlineShape[] outlineShapes, float sharpness) {
+ Region region = RegionFactory.create(gl.getContext(), st, renderType);
+
+ int numVertices = region.getNumVertices();
+
+ for(OutlineShape outlineShape:outlineShapes){
+ outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS);
+
+ ArrayList<Triangle> triangles = outlineShape.triangulate(sharpness);
+ region.addTriangles(triangles);
+
+ ArrayList<Vertex> vertices = outlineShape.getVertices();
+ for(Vertex vert:vertices){
+ vert.setId(numVertices++);
+ }
+ region.addVertices(vertices);
+ }
+
+ region.update();
+ return region;
+ }
+
+ protected static int getHashCode(OutlineShape outlineShape){
+ return outlineShape.hashCode();
+ }
+
+ protected static int getHashCode(OutlineShape[] outlineShapes){
+ int hashcode = 0;
+ for(OutlineShape outlineShape:outlineShapes){
+ hashcode += getHashCode(outlineShape);
+ }
+ return hashcode;
+ }
+} \ No newline at end of file
diff --git a/turtle2d/src/com/jogamp/graph/curve/opengl/Renderer.java b/turtle2d/src/com/jogamp/graph/curve/opengl/Renderer.java
new file mode 100644
index 0000000..863928e
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/curve/opengl/Renderer.java
@@ -0,0 +1,167 @@
+package com.jogamp.graph.curve.opengl;
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLUniformData;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+
+import jogamp.opengl.Debug;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.opengl.SVertex;
+import com.jogamp.opengl.util.PMVMatrix;
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+public abstract class Renderer {
+ protected static final boolean DEBUG = Debug.debug("CurveRenderer");
+
+ protected abstract boolean initImpl(GL2ES2 gl);
+
+ protected abstract void disposeImpl(GL2ES2 gl);
+
+ /**
+ * Flushes all cached data
+ */
+ public abstract void flushCache();
+
+ public abstract float getAlpha();
+
+ public abstract void setAlpha(GL2ES2 gl, float alpha_t);
+
+ public abstract void setColor(GL2ES2 gl, float r, float g, float b);
+
+ protected final Vertex.Factory<? extends Vertex> pointFactory;
+ protected ShaderState st = new ShaderState();
+ protected PMVMatrix pmvMatrix = new PMVMatrix();
+ protected GLUniformData mgl_PMVMatrix;
+ protected int renderType;
+ protected int vp_width = 0;
+ protected int vp_height = 0;
+
+ private boolean vboSupported = false;
+ private boolean initialized = false;
+
+ /**
+ *
+ * @param factory
+ * @param renderType either {@link com.jogamp.graph.curve.Region#SINGLE_PASS} or {@link com.jogamp.graph.curve.Region#TWO_PASS}
+ */
+ protected Renderer(Vertex.Factory<? extends Vertex> factory, int renderType) {
+ this.renderType = renderType;
+ this.pointFactory = (null != factory) ? factory : SVertex.factory();
+ }
+
+ public Vertex.Factory<? extends Vertex> getFactory() { return pointFactory; }
+
+ public final boolean isInitialized() { return initialized; }
+
+ public final boolean isVBOSupported() { return vboSupported; }
+
+ public final int getRenderType() { return renderType; }
+
+ public final int getWidth() { return vp_width; }
+ public final int getHeight() { return vp_height; }
+
+ /**
+ * Initialize shaders and bindings for GPU based rendering.
+ * Leaves the renderer enabled, ie ShaderState on.
+ *
+ * @param gl the current GL state
+ * @return true if succeeded, false otherwise
+ */
+ public boolean init(GL2ES2 gl) {
+ if(initialized){
+ if(DEBUG) {
+ System.err.println("TextRenderer: Already initialized!");
+ }
+ return true;
+ }
+ vboSupported = gl.isFunctionAvailable("glGenBuffers") &&
+ gl.isFunctionAvailable("glBindBuffer") &&
+ gl.isFunctionAvailable("glBufferData") &&
+ gl.isFunctionAvailable("glDrawElements") &&
+ gl.isFunctionAvailable("glVertexAttribPointer") &&
+ gl.isFunctionAvailable("glDeleteBuffers");
+
+ if(DEBUG) {
+ System.err.println("TextRendererImpl01: VBO Supported = " + isVBOSupported());
+ }
+
+ initialized = initImpl(gl);
+ return initialized;
+ }
+
+ public void dispose(GL2ES2 gl) {
+ if(!initialized){
+ if(DEBUG) {
+ System.err.println("TextRenderer: Not initialized!");
+ }
+ return;
+ }
+ disposeImpl(gl);
+ st.destroy(gl);
+ flushCache();
+ initialized = false;
+ }
+
+ public final ShaderState getShaderState() { return st; }
+
+ public final PMVMatrix getMatrix() { return pmvMatrix; }
+
+ public void rotate(GL2ES2 gl, float angle, float x, float y, float z) {
+ pmvMatrix.glRotatef(angle, x, y, z);
+ if(initialized && null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+ }
+
+ public void translate(GL2ES2 gl, float x, float y, float z) {
+ pmvMatrix.glTranslatef(x, y, z);
+ if(initialized && null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+ }
+
+ public void resetModelview(GL2ES2 gl) {
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmvMatrix.glLoadIdentity();
+ if(initialized && null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+ }
+
+ public void updateMatrix(GL2ES2 gl) {
+ if(initialized && null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+ }
+
+ public boolean reshapePerspective(GL2ES2 gl, float angle, int width, int height, float near, float far) {
+ this.vp_width = width;
+ this.vp_height = height;
+ float ratio = (float)width/(float)height;
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.gluPerspective(angle, ratio, near, far);
+
+ if(initialized && null != gl) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+
+ return true;
+ }
+
+ public boolean reshapeOrtho(GL2ES2 gl, int width, int height, float near, float far) {
+ this.vp_width = width;
+ this.vp_height = height;
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.glOrthof(0, width, 0, height, near, far);
+
+ if(initialized && null != gl) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/turtle2d/src/com/jogamp/graph/curve/opengl/TextRenderer.java b/turtle2d/src/com/jogamp/graph/curve/opengl/TextRenderer.java
new file mode 100644
index 0000000..2bb99d2
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/curve/opengl/TextRenderer.java
@@ -0,0 +1,103 @@
+package com.jogamp.graph.curve.opengl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.media.opengl.GL2ES2;
+
+import jogamp.graph.curve.text.GlyphString;
+import jogamp.graph.font.FontInt;
+import jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.geom.Vertex;
+
+public abstract class TextRenderer extends Renderer {
+
+ /**
+ * Create a Hardware accelerated Text Renderer.
+ * @param factory optional Point.Factory for Vertex construction. Default is Vertex.Factory.
+ */
+ public static TextRenderer create(Vertex.Factory<? extends Vertex> factory, int type) {
+ return new jogamp.graph.curve.opengl.TextRendererImpl01(factory, type);
+ }
+
+ protected TextRenderer(Vertex.Factory<? extends Vertex> factory, int type) {
+ super(factory, type);
+ }
+
+ /** Render the String in 3D space wrt to the font provided at the position provided
+ * the outlines will be generated, if not yet generated
+ * @param gl the current GL state
+ * @param font {@link Font} to be used
+ * @param str text to be rendered
+ * @param position the lower left corner of the string
+ * @param fontSize font size
+ * @param texSize texture size for multipass render
+ * @throws Exception if TextRenderer not initialized
+ */
+ public abstract void renderString3D(GL2ES2 gl, Font font,
+ String str, float[] position, int fontSize, int texSize);
+
+ /**Create the resulting {@link GlyphString} that represents
+ * the String wrt to the font.
+ * @param font {@link Font} to be used
+ * @param size font size
+ * @param str {@link String} to be created
+ * @param sharpness parameter for Region generation of the resulting GlyphString
+ * @return the resulting GlyphString inclusive the generated region
+ */
+ protected GlyphString createString(GL2ES2 gl, Font font, int size, String str, float sharpness) {
+ AffineTransform affineTransform = new AffineTransform(pointFactory);
+
+ Path2D[] paths = new Path2D[str.length()];
+ ((FontInt)font).getOutline(str, size, affineTransform, paths);
+
+ GlyphString glyphString = new GlyphString(pointFactory, font.getName(), str);
+ glyphString.createfromFontPath(paths, affineTransform);
+ glyphString.generateRegion(gl.getContext(), sharpness, st, renderType);
+
+ return glyphString;
+ }
+
+ public void flushCache() {
+ Iterator<GlyphString> iterator = stringCacheMap.values().iterator();
+ while(iterator.hasNext()){
+ GlyphString glyphString = iterator.next();
+ glyphString.destroy();
+ }
+ stringCacheMap.clear();
+ stringCacheArray.clear();
+ }
+
+ public final void setCacheMaxSize(int newSize ) { stringCacheMaxSize = newSize; validateCache(0); }
+ public final int getCacheMaxSize() { return stringCacheMaxSize; }
+ public final int getCacheSize() { return stringCacheArray.size(); }
+
+ protected void validateCache(int space) {
+ while ( getCacheSize() + space > getCacheMaxSize() ) {
+ String key = stringCacheArray.remove(0);
+ stringCacheMap.remove(key);
+ }
+ }
+
+ protected GlyphString getCachedGlyphString(Font font, String str, int fontSize) {
+ final String key = font.getName() + "." + str.hashCode() + "." + fontSize;
+ return stringCacheMap.get(key);
+ }
+
+ protected void addCachedGlyphString(Font font, String str, int fontSize, GlyphString glyphString) {
+ final String key = font.getName() + "." + str.hashCode() + "." + fontSize;
+ validateCache(1);
+ stringCacheMap.put(key, glyphString);
+ stringCacheArray.add(stringCacheArray.size(), key);
+ }
+
+ // Cache is adding at the end of the array
+ public static final int DEFAULT_CACHE_SIZE = 32;
+ private HashMap<String, GlyphString> stringCacheMap = new HashMap<String, GlyphString>(DEFAULT_CACHE_SIZE);
+ private ArrayList<String> stringCacheArray = new ArrayList<String>(DEFAULT_CACHE_SIZE);
+ private int stringCacheMaxSize = DEFAULT_CACHE_SIZE; // -1 unlimited, 0 off, >0 limited
+} \ No newline at end of file
diff --git a/turtle2d/src/com/jogamp/graph/curve/tess/CDTriangulator2D.java b/turtle2d/src/com/jogamp/graph/curve/tess/CDTriangulator2D.java
new file mode 100644
index 0000000..a2e4ca5
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/curve/tess/CDTriangulator2D.java
@@ -0,0 +1,216 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.graph.curve.tess;
+
+import java.util.ArrayList;
+
+import jogamp.graph.curve.tess.GraphOutline;
+import jogamp.graph.curve.tess.GraphVertex;
+import jogamp.graph.curve.tess.Loop;
+
+import com.jogamp.graph.geom.Outline;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.math.VectorUtil;
+
+import jogamp.opengl.Debug;
+
+/** Constrained Delaunay Triangulation
+ * implementation of a list of Outlines that define a set of
+ * Closed Regions with optional n holes.
+ *
+ */
+public class CDTriangulator2D {
+
+ protected static final boolean DEBUG = Debug.debug("Triangulation");
+
+ private float sharpness = 0.5f;
+ private ArrayList<Loop> loops;
+ private ArrayList<Vertex> vertices;
+
+ private ArrayList<Triangle> triangles;
+ private int maxTriID = 0;
+
+
+ public CDTriangulator2D() {
+ this(0.5f);
+ }
+
+ /** Constructor for a new Delaunay triangulator
+ * @param curveSharpness the curvature around
+ * the off-curve vertices
+ */
+ public CDTriangulator2D(float curveSharpness) {
+ this.sharpness = curveSharpness;
+ reset();
+ }
+
+ /** Reset the triangulation to initial state
+ * Clearing cached data
+ */
+ public void reset() {
+ maxTriID = 0;
+ vertices = new ArrayList<Vertex>();
+ triangles = new ArrayList<Triangle>(3);
+ loops = new ArrayList<Loop>();
+ }
+
+ /** Add a curve to the list of profiles provided
+ * @param polyline a bounding {@link Outline}
+ */
+ public void addCurve(Outline polyline){
+ Loop loop = null;
+
+ if(!loops.isEmpty()){
+ loop = getContainerLoop(polyline);
+ }
+
+ if(loop == null) {
+ GraphOutline outline = new GraphOutline(polyline);
+ GraphOutline innerPoly = extractBoundaryTriangles(outline, false);
+ vertices.addAll(polyline.getVertices());
+ loop = new Loop(innerPoly, VectorUtil.CCW);
+ loops.add(loop);
+ }
+ else {
+ GraphOutline outline = new GraphOutline(polyline);
+ GraphOutline innerPoly = extractBoundaryTriangles(outline, true);
+ vertices.addAll(innerPoly.getPoints());
+ loop.addConstraintCurve(innerPoly);
+ }
+ }
+
+ /** Generate the triangulation of the provided
+ * List of {@link Outline}s
+ */
+ public ArrayList<Triangle> generateTriangulation(){
+ for(int i=0;i<loops.size();i++) {
+ Loop loop = loops.get(i);
+ int numTries = 0;
+ int size = loop.computeLoopSize();
+ while(!loop.isSimplex()){
+ Triangle tri = null;
+ if(numTries > size){
+ tri = loop.cut(false);
+ }
+ else{
+ tri = loop.cut(true);
+ }
+ numTries++;
+
+ if(tri != null) {
+ numTries = 0;
+ size--;
+ tri.setId(maxTriID++);
+ triangles.add(tri);
+ if(DEBUG){
+ System.err.println(tri);
+ }
+ }
+ if(numTries > size*2){
+ if(DEBUG){
+ System.err.println("Triangulation not complete!");
+ }
+ break;
+ }
+ }
+ Triangle tri = loop.cut(true);
+ if(tri != null)
+ triangles.add(tri);
+ }
+ return triangles;
+ }
+
+ private GraphOutline extractBoundaryTriangles(GraphOutline outline, boolean hole){
+ GraphOutline innerOutline = new GraphOutline();
+ ArrayList<GraphVertex> outVertices = outline.getGraphPoint();
+ int size = outVertices.size();
+ for(int i=0; i < size; i++) {
+ GraphVertex currentVertex = outVertices.get(i);
+ GraphVertex gv0 = outVertices.get((i+size-1)%size);
+ GraphVertex gv2 = outVertices.get((i+1)%size);
+ GraphVertex gv1 = currentVertex;
+
+ if(!currentVertex.getPoint().isOnCurve()) {
+ Vertex v0 = gv0.getPoint().clone();
+ Vertex v2 = gv2.getPoint().clone();
+ Vertex v1 = gv1.getPoint().clone();
+
+ gv0.setBoundaryContained(true);
+ gv1.setBoundaryContained(true);
+ gv2.setBoundaryContained(true);
+
+ Triangle t= null;
+ boolean holeLike = false;
+ if(VectorUtil.ccw(v0,v1,v2)){
+ t = new Triangle(v0, v1, v2);
+ }
+ else {
+ holeLike = true;
+ t = new Triangle(v2, v1, v0);
+ }
+ t.setId(maxTriID++);
+ triangles.add(t);
+ if(DEBUG){
+ System.err.println(t);
+ }
+ if(hole || holeLike) {
+ v0.setTexCoord(0, -0.1f);
+ v2.setTexCoord(1, -0.1f);
+ v1.setTexCoord(0.5f, -1*sharpness -0.1f);
+ innerOutline.addVertex(currentVertex);
+ }
+ else {
+ v0.setTexCoord(0, 0.1f);
+ v2.setTexCoord(1, 0.1f);
+ v1.setTexCoord(0.5f, sharpness+0.1f);
+ }
+ }
+ else {
+ if(!gv2.getPoint().isOnCurve() || !gv0.getPoint().isOnCurve()){
+ currentVertex.setBoundaryContained(true);
+ }
+ innerOutline.addVertex(currentVertex);
+ }
+ }
+ return innerOutline;
+ }
+
+ private Loop getContainerLoop(Outline polyline){
+ ArrayList<Vertex> vertices = polyline.getVertices();
+ for(Vertex vert: vertices){
+ for (Loop loop:loops){
+ if(loop.checkInside(vert)){
+ return loop;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/turtle2d/src/com/jogamp/graph/font/Font.java b/turtle2d/src/com/jogamp/graph/font/Font.java
new file mode 100644
index 0000000..a4ab527
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/font/Font.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.font;
+
+import com.jogamp.graph.geom.AABBox;
+
+/**
+ * Interface wrapper for font implementation.
+ *
+ * TrueType Font Specification:
+ * http://developer.apple.com/fonts/ttrefman/rm06/Chap6.html
+ *
+ * TrueType Font Table Introduction:
+ * http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08
+ */
+
+public interface Font {
+
+ /**
+ * Metrics for font
+ *
+ * Depending on the font's direction, horizontal or vertical,
+ * the following tables shall be used:
+ *
+ * Vertical http://developer.apple.com/fonts/TTRefMan/RM06/Chap6vhea.html
+ * Horizontal http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html
+ */
+ public interface Metrics {
+ float getAscent(float pixelSize);
+ float getDescent(float pixelSize);
+ float getLineGap(float pixelSize);
+ float getMaxExtend(float pixelSize);
+ float getScale(float pixelSize);
+ AABBox getBBox(float pixelSize);
+ }
+
+ /**
+ * Glyph for font
+ */
+ public interface Glyph {
+ public Font getFont();
+ public char getSymbol();
+ public AABBox getBBox(float pixelSize);
+ public float getAdvance(float pixelSize, boolean useFrationalMetrics);
+ }
+
+
+ public String getName();
+
+ public Metrics getMetrics();
+ public Glyph getGlyph(char symbol);
+ public int getNumGlyphs();
+
+ public float getStringWidth(String string, float pixelSize);
+ public float getStringHeight(String string, float pixelSize);
+ public AABBox getStringBounds(CharSequence string, float pixelSize);
+} \ No newline at end of file
diff --git a/turtle2d/src/com/jogamp/graph/font/FontFactory.java b/turtle2d/src/com/jogamp/graph/font/FontFactory.java
new file mode 100644
index 0000000..1752a69
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/font/FontFactory.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.font;
+
+import java.security.AccessController;
+
+import com.jogamp.common.util.ReflectionUtil;
+
+import jogamp.graph.font.FontConstructor;
+import jogamp.graph.font.JavaFontLoader;
+import jogamp.graph.font.UbuntuFontLoader;
+import jogamp.opengl.Debug;
+
+public class FontFactory {
+ /** Ubuntu is the default font family */
+ public static final int UBUNTU = 0;
+
+ /** Java fonts are optional */
+ public static final int JAVA = 1;
+
+ private static final FontConstructor fontConstr;
+
+ static {
+ /**
+ * For example:
+ * "jogamp.graph.font.typecast.TypecastFontFactory" (default)
+ * "jogamp.graph.font.ttf.TTFFontImpl"
+ */
+ String fontImplName = Debug.getProperty("FontImpl", true, AccessController.getContext());
+ if(null == fontImplName) {
+ fontImplName = "jogamp.graph.font.typecast.TypecastFontConstructor";
+ }
+ fontConstr = (FontConstructor) ReflectionUtil.createInstance(fontImplName, FontFactory.class.getClassLoader());
+ }
+
+ public static final FontConstructor getFontConstr() { return fontConstr; }
+
+ public static final FontSet getDefault() {
+ return get(UBUNTU);
+ }
+
+ public static final FontSet get(int font) {
+ switch (font) {
+ case JAVA:
+ return JavaFontLoader.get();
+ default:
+ return UbuntuFontLoader.get();
+ }
+ }
+
+ public static final Font get(String path) {
+ return fontConstr.create(path);
+ }
+
+}
diff --git a/turtle2d/src/com/jogamp/graph/font/FontSet.java b/turtle2d/src/com/jogamp/graph/font/FontSet.java
new file mode 100644
index 0000000..0cee811
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/font/FontSet.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.font;
+
+
+public interface FontSet {
+
+ /** Font family REGULAR **/
+ public static final int FAMILY_REGULAR = 0;
+
+ /** Font family LIGHT **/
+ public static final int FAMILY_LIGHT = 1;
+
+ /** Font family MEDIUM **/
+ public static final int FAMILY_MEDIUM = 2;
+
+ /** Font family CONDENSED **/
+ public static final int FAMILY_CONDENSED = 3;
+
+ /** Font family MONO **/
+ public static final int FAMILY_MONOSPACED = 4;
+
+ /** SERIF style/family bit flag. Fallback to Sans Serif. */
+ public static final int STYLE_SERIF = 1 << 1;
+
+ /** BOLD style bit flag */
+ public static final int STYLE_BOLD = 1 << 2;
+
+ /** ITALIC style bit flag */
+ public static final int STYLE_ITALIC = 1 << 3;
+
+ Font getDefault();
+
+ Font get(int family, int stylebits);
+}
diff --git a/turtle2d/src/com/jogamp/graph/geom/AABBox.java b/turtle2d/src/com/jogamp/graph/geom/AABBox.java
new file mode 100644
index 0000000..8cd0632
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/geom/AABBox.java
@@ -0,0 +1,299 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.geom;
+
+import com.jogamp.graph.math.VectorUtil;
+
+/**
+ * Axis Aligned Bounding Box. Defined by two 3D coordinates (low and high)
+ * The low being the the lower left corner of the box, and the high being the upper
+ * right corner of the box.
+ *
+ */
+public class AABBox {
+ private float[] low = {Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE};
+ private float[] high = {-1*Float.MAX_VALUE,-1*Float.MAX_VALUE,-1*Float.MAX_VALUE};
+ private float[] center = new float[3];
+
+ /** Create a Axis Aligned bounding box (AABBox)
+ * where the low and and high MAX float Values.
+ */
+ public AABBox() {}
+
+ /** Create an AABBox specifying the coordinates
+ * of the low and high
+ * @param lx min x-coordinate
+ * @param ly min y-coordnate
+ * @param lz min z-coordinate
+ * @param hx max x-coordinate
+ * @param hy max y-coordinate
+ * @param hz max z-coordinate
+ */
+ public AABBox(float lx, float ly, float lz,
+ float hx, float hy, float hz)
+ {
+ setLow(lx, ly, lz);
+ setHigh(hx, hy, hz);
+
+ computeCenter();
+ }
+
+ /** Create a AABBox defining the low and high
+ * @param low min xyz-coordinates
+ * @param high max xyz-coordinates
+ */
+ public AABBox(float[] low, float[] high)
+ {
+ this.low = low;
+ this.high = high;
+
+ computeCenter();
+ }
+
+ /** Get the max xyz-coordinates
+ * @return a float array containing the max xyz coordinates
+ */
+ public float[] getHigh()
+ {
+ return high;
+ }
+
+ private void setHigh(float hx, float hy, float hz)
+ {
+ this.high[0] = hx;
+ this.high[1] = hy;
+ this.high[2] = hz;
+ }
+
+ /** Get the min xyz-coordinates
+ * @return a float array containing the min xyz coordinates
+ */
+ public float[] getLow()
+ {
+ return low;
+ }
+
+ private void setLow(float lx, float ly, float lz)
+ {
+ this.low[0] = lx;
+ this.low[1] = ly;
+ this.low[2] = lz;
+ }
+
+ /** Resize the AABBox to encapsulate another AABox
+ * @param newBox AABBox to be encapsulated in
+ */
+ public void resize(AABBox newBox)
+ {
+ float[] newLow = newBox.getLow();
+ float[] newHigh = newBox.getHigh();
+
+ /** test low */
+ if (newLow[0] < low[0])
+ low[0] = newLow[0];
+ if (newLow[1] < low[1])
+ low[1] = newLow[1];
+ if (newLow[2] < low[2])
+ low[2] = newLow[2];
+
+ /** test high */
+ if (newHigh[0] > high[0])
+ high[0] = newHigh[0];
+ if (newHigh[1] > high[1])
+ high[1] = newHigh[1];
+ if (newHigh[2] > high[2])
+ high[2] = newHigh[2];
+
+ computeCenter();
+ }
+
+ private void computeCenter()
+ {
+ center[0] = (high[0] + low[0])/2;
+ center[1] = (high[1] + low[1])/2;
+ center[2] = (high[2] + low[2])/2;
+ }
+
+ /** Resize the AABBox to encapsulate the passed
+ * xyz-coordinates.
+ * @param x x-axis coordinate value
+ * @param y y-axis coordinate value
+ * @param z z-axis coordinate value
+ */
+ public void resize(float x, float y, float z)
+ {
+ /** test low */
+ if (x < low[0])
+ low[0] = x;
+ if (y < low[1])
+ low[1] = y;
+ if (z < low[2])
+ low[2] = z;
+
+ /** test high */
+ if (x > high[0])
+ high[0] = x;
+ if (y > high[1])
+ high[1] = y;
+ if (z > high[2])
+ high[2] = z;
+
+ computeCenter();
+ }
+
+ /** Check if the x & y coordinates are bounded/contained
+ * by this AABBox
+ * @param x x-axis coordinate value
+ * @param y y-axis coordinate value
+ * @return true if x belong to (low.x, high.x) and
+ * y belong to (low.y, high.y)
+ */
+ public boolean contains(float x, float y){
+ if(x<low[0] || x>high[0]){
+ return false;
+ }
+ if(y<low[1]|| y>high[1]){
+ return false;
+ }
+ return true;
+ }
+
+ /** Check if the xyz coordinates are bounded/contained
+ * by this AABBox.
+ * @param x x-axis coordinate value
+ * @param y y-axis coordinate value
+ * @param z z-axis coordinate value
+ * @return true if x belong to (low.x, high.x) and
+ * y belong to (low.y, high.y) and z belong to (low.z, high.z)
+ */
+ public boolean contains(float x, float y, float z){
+ if(x<low[0] || x>high[0]){
+ return false;
+ }
+ if(y<low[1]|| y>high[1]){
+ return false;
+ }
+ if(z<low[2] || z>high[2]){
+ return false;
+ }
+ return true;
+ }
+
+ /** Check if there is a common region between this AABBox and the passed
+ * 2D region irrespective of z range
+ * @param x lower left x-coord
+ * @param y lower left y-coord
+ * @param w width
+ * @param h hight
+ * @return true if this AABBox might have a common region with this 2D region
+ */
+ public boolean intersects(float x, float y, float w, float h) {
+ if (w <= 0 || h <= 0) {
+ return false;
+ }
+
+ final float _w = getWidth();
+ final float _h = getHeight();
+ if (_w <= 0 || _h <= 0) {
+ return false;
+ }
+
+ final float x0 = getMinX();
+ final float y0 = getMinY();
+ return (x + w > x0 &&
+ y + h > y0 &&
+ x < x0 + _w &&
+ y < y0 + _h);
+ }
+
+
+ /** Get the size of the Box where the size is represented by the
+ * length of the vector between low and high.
+ * @return a float representing the size of the AABBox
+ */
+ public float getSize(){
+ return VectorUtil.computeLength(low, high);
+ }
+
+ /**Get the Center of the AABBox
+ * @return the xyz-coordinates of the center of the AABBox
+ */
+ public float[] getCenter() {
+ return center;
+ }
+
+ /** Scale the AABBox by a constant
+ * @param size a constant float value
+ */
+ public void scale(float size) {
+ float[] diffH = new float[3];
+ diffH[0] = high[0] - center[0];
+ diffH[1] = high[1] - center[1];
+ diffH[2] = high[2] - center[2];
+
+ diffH = VectorUtil.scale(diffH, size);
+
+ float[] diffL = new float[3];
+ diffL[0] = low[0] - center[0];
+ diffL[1] = low[1] - center[1];
+ diffL[2] = low[2] - center[2];
+
+ diffL = VectorUtil.scale(diffL, size);
+
+ high = VectorUtil.vectorAdd(center, diffH);
+ low = VectorUtil.vectorAdd(center, diffL);
+ }
+
+ public float getMinX() {
+ return low[0];
+ }
+
+ public float getMinY() {
+ return low[1];
+ }
+
+ public float getWidth(){
+ return high[0] - low[0];
+ }
+
+ public float getHeight() {
+ return high[1] - low[1];
+ }
+
+ public float getDepth() {
+ return high[2] - low[2];
+ }
+ public AABBox clone(){
+ return new AABBox(this.low, this.high);
+ }
+
+ public String toString() {
+ return "[ "+low[0]+"/"+low[1]+"/"+low[1]+" .. "+high[0]+"/"+high[0]+"/"+high[0]+", ctr "+
+ center[0]+"/"+center[1]+"/"+center[1]+" ]";
+ }
+}
diff --git a/turtle2d/src/com/jogamp/graph/geom/Outline.java b/turtle2d/src/com/jogamp/graph/geom/Outline.java
new file mode 100644
index 0000000..a805adf
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/geom/Outline.java
@@ -0,0 +1,176 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.geom;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.math.VectorUtil;
+
+
+
+/** Define a single continuous stroke by control vertices.
+ * The vertices define the shape of the region defined by this
+ * outline. The Outline can contain a list of off-curve and on-curve
+ * vertices which define curved regions.
+ *
+ * Note: An outline should be closed to be rendered as a region.
+ *
+ * @see OutlineShape, Region
+ */
+public class Outline implements Comparable<Outline> {
+
+ private ArrayList<Vertex> vertices = new ArrayList<Vertex>(3);
+ private boolean closed = false;
+ private AABBox box = new AABBox();
+
+ /**Create an outline defined by control vertices.
+ * An outline can contain off Curve vertices which define curved
+ * regions in the outline.
+ */
+ public Outline(){
+
+ }
+
+ /** Add a vertex to the outline. The {@link Vertex} is added at the
+ * end of the outline loop/strip.
+ * @param vertex Vertex to be added
+ */
+ public final void addVertex(Vertex vertex) {
+ vertices.add(vertex);
+ box.resize(vertex.getX(), vertex.getY(), vertex.getZ());
+ }
+
+ /** Add a {@link Vertex} by specifying its 2D attributes to the outline.
+ * The {@link Vertex} is added at the
+ * end of the outline loop/strip.
+ * @param factory a {@link Factory} to get the required Vertex impl
+ * @param x the x coordinate
+ * @param y the y coordinate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(Vertex.Factory<? extends Vertex> factory, float x, float y, boolean onCurve) {
+ addVertex(factory, x, y, 0f, onCurve);
+ }
+
+ /** Add a {@link Vertex} by specifying its 3D attributes to the outline.
+ * The {@link Vertex} is added at the
+ * end of the outline loop/strip.
+ * @param factory a {@link Factory} to get the required Vertex impl
+ * @param x the x coordinate
+ * @param y the y coordinate
+ * @param z the z coordinate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(Vertex.Factory<? extends Vertex> factory, float x, float y, float z, boolean onCurve) {
+ Vertex v = factory.create(x, y, z);
+ v.setOnCurve(onCurve);
+ addVertex(v);
+ }
+
+ /** Add a vertex to the outline by passing a float array and specifying the
+ * offset and length in which. The attributes of the vertex are located.
+ * The attributes should be continuous (stride = 0).
+ * Attributes which value are not set (when length less than 3)
+ * are set implicitly to zero.
+ * @param factory a {@link Factory} to get the required Vertex impl
+ * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from
+ * @param offset the offset in the buffer to the x coordinate
+ * @param length the number of attributes to pick from the buffer (maximum 3)
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(Vertex.Factory<? extends Vertex> factory, float[] coordsBuffer, int offset, int length, boolean onCurve) {
+ Vertex v = factory.create(coordsBuffer, offset, length);
+ v.setOnCurve(onCurve);
+ addVertex(v);
+ }
+
+ public Vertex getVertex(int index){
+ return vertices.get(index);
+ }
+
+ public boolean isEmpty(){
+ return (vertices.size() == 0);
+ }
+ public Vertex getLastVertex(){
+ if(isEmpty()){
+ return null;
+ }
+ return vertices.get(vertices.size()-1);
+ }
+
+ public ArrayList<Vertex> getVertices() {
+ return vertices;
+ }
+ public void setVertices(ArrayList<Vertex> vertices) {
+ this.vertices = vertices;
+ }
+ public AABBox getBox() {
+ return box;
+ }
+ public boolean isClosed() {
+ return closed;
+ }
+
+ /** define if this outline is closed or not.
+ * if set to closed, checks if the last vertex is
+ * equal to the first vertex. If not Equal adds a
+ * vertex at the end to the list.
+ * @param closed
+ */
+ public void setClosed(boolean closed) {
+ this.closed = closed;
+ if(closed){
+ Vertex first = vertices.get(0);
+ Vertex last = getLastVertex();
+ if(!VectorUtil.checkEquality(first.getCoord(), last.getCoord())){
+ Vertex v = first.clone();
+ vertices.add(v);
+ }
+ }
+ }
+
+ /** Compare two outlines with Bounding Box area
+ * as criteria.
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(Outline outline) {
+ float size = box.getSize();
+ float newSize = outline.getBox().getSize();
+ if(size < newSize){
+ return -1;
+ }
+ else if(size > newSize){
+ return 1;
+ }
+ return 0;
+ }
+}
diff --git a/turtle2d/src/com/jogamp/graph/geom/Triangle.java b/turtle2d/src/com/jogamp/graph/geom/Triangle.java
new file mode 100644
index 0000000..d13e8dd
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/geom/Triangle.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.geom;
+
+public class Triangle {
+ private int id = Integer.MAX_VALUE;
+ final private Vertex[] vertices;
+ private boolean[] boundaryEdges = new boolean[3];
+ private boolean[] boundaryVertices = null;
+
+ public Triangle(Vertex ... v123){
+ vertices = v123;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public Vertex[] getVertices() {
+ return vertices;
+ }
+
+ public boolean isEdgesBoundary() {
+ return boundaryEdges[0] || boundaryEdges[1] || boundaryEdges[2];
+ }
+
+ public boolean isVerticesBoundary() {
+ return boundaryVertices[0] || boundaryVertices[1] || boundaryVertices[2];
+ }
+
+ public void setEdgesBoundary(boolean[] boundary) {
+ this.boundaryEdges = boundary;
+ }
+
+ public boolean[] getEdgeBoundary() {
+ return boundaryEdges;
+ }
+
+ public boolean[] getVerticesBoundary() {
+ return boundaryVertices;
+ }
+
+ public void setVerticesBoundary(boolean[] boundaryVertices) {
+ this.boundaryVertices = boundaryVertices;
+ }
+
+ public String toString() {
+ return "Tri ID: " + id + "\n" + vertices[0] + "\n" + vertices[1] + "\n" + vertices[2];
+ }
+}
diff --git a/turtle2d/src/com/jogamp/graph/geom/Vertex.java b/turtle2d/src/com/jogamp/graph/geom/Vertex.java
new file mode 100644
index 0000000..0e4e5e8
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/geom/Vertex.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.geom;
+
+/**
+ * A Vertex with custom memory layout using custom factory.
+ */
+public interface Vertex extends Comparable<Vertex>, Cloneable {
+
+ public static interface Factory <T extends Vertex> {
+ T create();
+
+ T create(float x, float y);
+
+ T create(float x, float y, float z);
+
+ T create(float[] coordsBuffer, int offset, int length);
+ }
+
+ void setCoord(float x, float y);
+
+ void setCoord(float x, float y, float z);
+
+ void setCoord(float[] coordsBuffer, int offset, int length);
+
+ float[] getCoord();
+
+ void setX(float x);
+
+ void setY(float y);
+
+ void setZ(float z);
+
+ float getX();
+
+ float getY();
+
+ float getZ();
+
+ boolean isOnCurve();
+
+ void setOnCurve(boolean onCurve);
+
+ int getId();
+
+ void setId(int id);
+
+ int compareTo(Vertex p);
+
+ float[] getTexCoord();
+
+ void setTexCoord(float s, float t);
+
+ Vertex clone();
+}
diff --git a/turtle2d/src/com/jogamp/graph/geom/opengl/SVertex.java b/turtle2d/src/com/jogamp/graph/geom/opengl/SVertex.java
new file mode 100644
index 0000000..681067e
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/geom/opengl/SVertex.java
@@ -0,0 +1,178 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.geom.opengl;
+
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.math.VectorUtil;
+
+/** A Simple Vertex Implementation. Where the coordinates, and other attributes are
+ * float based, and the coordinates and texture coordinates are saved in two float arrays.
+ *
+ */
+public class SVertex implements Vertex {
+ private int id = Integer.MAX_VALUE;
+ protected float[] coord = new float[3];
+ protected boolean onCurve = true;
+ private float[] texCoord = new float[2];
+
+ static final Factory factory = new Factory();
+
+ public static Factory factory() { return factory; }
+
+ public static class Factory implements Vertex.Factory<SVertex> {
+ @Override
+ public SVertex create() {
+ return new SVertex();
+ }
+
+ @Override
+ public SVertex create(float x, float y) {
+ return new SVertex(x, y);
+ }
+
+ @Override
+ public SVertex create(float x, float y, float z) {
+ return new SVertex(x, y, z);
+ }
+
+ @Override
+ public SVertex create(float[] coordsBuffer, int offset, int length) {
+ return new SVertex(coordsBuffer, offset, length);
+ }
+ }
+
+ public SVertex() {
+ }
+
+ public SVertex(float x, float y) {
+ setCoord(x, y);
+ }
+ public SVertex(float x, float y, float z) {
+ setCoord(x, y, z);
+ }
+ public SVertex(float[] coordsBuffer, int offset, int length) {
+ setCoord(coordsBuffer, offset, length);
+ }
+
+ public void setCoord(float x, float y) {
+ this.coord[0] = x;
+ this.coord[1] = y;
+ this.coord[2] = 0f;
+ }
+
+ public void setCoord(float x, float y, float z) {
+ this.coord[0] = x;
+ this.coord[1] = y;
+ this.coord[2] = z;
+ }
+
+ public void setCoord(float[] coordsBuffer, int offset, int length) {
+ if(length > coordsBuffer.length - offset) {
+ throw new IndexOutOfBoundsException("coordsBuffer too small: "+coordsBuffer.length+" - "+offset+" < "+length);
+ }
+ if(length > 3) {
+ throw new IndexOutOfBoundsException("length too big: "+length+" > "+3);
+ }
+ int i=0;
+ while(i<length) {
+ this.coord[i++] = coordsBuffer[offset++];
+ }
+ }
+
+ public float[] getCoord() {
+ return coord;
+ }
+
+ public void setX(float x) {
+ this.coord[0] = x;
+ }
+
+ public void setY(float y) {
+ this.coord[1] = y;
+ }
+
+ public void setZ(float z) {
+ this.coord[2] = z;
+ }
+
+ public float getX() {
+ return this.coord[0];
+ }
+
+ public float getY() {
+ return this.coord[1];
+ }
+
+ public float getZ() {
+ return this.coord[2];
+ }
+
+ public boolean isOnCurve() {
+ return onCurve;
+ }
+
+ public void setOnCurve(boolean onCurve) {
+ this.onCurve = onCurve;
+ }
+
+ public int getId(){
+ return id;
+ }
+
+ public void setId(int id){
+ this.id = id;
+ }
+
+ public int compareTo(Vertex p) {
+ if(VectorUtil.checkEquality(coord, p.getCoord())) {
+ return 0;
+ }
+ return -1;
+ }
+
+ public float[] getTexCoord() {
+ return texCoord;
+ }
+
+ public void setTexCoord(float s, float t) {
+ this.texCoord[0] = s;
+ this.texCoord[1] = t;
+ }
+
+ public SVertex clone(){
+ SVertex v = new SVertex(this.coord, 0, 3);
+ v.setOnCurve(this.onCurve);
+ return v;
+ }
+
+ public String toString() {
+ return "[ID: " + id + " X: " + coord[0]
+ + " Y: " + coord[1] + " Z: " + coord[2] + "]";
+ }
+}
diff --git a/turtle2d/src/com/jogamp/graph/math/Quaternion.java b/turtle2d/src/com/jogamp/graph/math/Quaternion.java
new file mode 100755
index 0000000..b77a5fa
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/math/Quaternion.java
@@ -0,0 +1,382 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.math;
+
+import jogamp.graph.math.MathFloat;
+
+public class Quaternion {
+ protected float x,y,z,w;
+
+ public Quaternion(){
+
+ }
+
+ public Quaternion(float x, float y, float z, float w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /** Constructor to create a rotation based quaternion from two vectors
+ * @param vector1
+ * @param vector2
+ */
+ public Quaternion(float[] vector1, float[] vector2)
+ {
+ float theta = (float)MathFloat.acos(dot(vector1, vector2));
+ float[] cross = cross(vector1,vector2);
+ cross = normalizeVec(cross);
+
+ this.x = (float)MathFloat.sin(theta/2)*cross[0];
+ this.y = (float)MathFloat.sin(theta/2)*cross[1];
+ this.z = (float)MathFloat.sin(theta/2)*cross[2];
+ this.w = (float)MathFloat.cos(theta/2);
+ this.normalize();
+ }
+
+ /** Transform the rotational quaternion to axis based rotation angles
+ * @return new float[4] with ,theta,Rx,Ry,Rz
+ */
+ public float[] toAxis()
+ {
+ float[] vec = new float[4];
+ float scale = (float)MathFloat.sqrt(x * x + y * y + z * z);
+ vec[0] =(float) MathFloat.acos(w) * 2.0f;
+ vec[1] = x / scale;
+ vec[2] = y / scale;
+ vec[3] = z / scale;
+ return vec;
+ }
+
+ /** Normalize a vector
+ * @param vector input vector
+ * @return normalized vector
+ */
+ private float[] normalizeVec(float[] vector)
+ {
+ float[] newVector = new float[3];
+
+ float d = MathFloat.sqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]);
+ if(d> 0.0f)
+ {
+ newVector[0] = vector[0]/d;
+ newVector[1] = vector[1]/d;
+ newVector[2] = vector[2]/d;
+ }
+ return newVector;
+ }
+ /** compute the dot product of two points
+ * @param vec1 vector 1
+ * @param vec2 vector 2
+ * @return the dot product as float
+ */
+ private float dot(float[] vec1, float[] vec2)
+ {
+ return (vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2]);
+ }
+ /** cross product vec1 x vec2
+ * @param vec1 vector 1
+ * @param vec2 vecttor 2
+ * @return the resulting vector
+ */
+ private float[] cross(float[] vec1, float[] vec2)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec2[2]*vec1[1] - vec2[1]*vec1[2];
+ out[1] = vec2[0]*vec1[2] - vec2[2]*vec1[0];
+ out[2] = vec2[1]*vec1[0] - vec2[0]*vec1[1];
+
+ return out;
+ }
+ public float getW() {
+ return w;
+ }
+ public void setW(float w) {
+ this.w = w;
+ }
+ public float getX() {
+ return x;
+ }
+ public void setX(float x) {
+ this.x = x;
+ }
+ public float getY() {
+ return y;
+ }
+ public void setY(float y) {
+ this.y = y;
+ }
+ public float getZ() {
+ return z;
+ }
+ public void setZ(float z) {
+ this.z = z;
+ }
+
+ /** Add a quaternion
+ * @param q quaternion
+ */
+ public void add(Quaternion q)
+ {
+ x+=q.x;
+ y+=q.y;
+ z+=q.z;
+ }
+
+ /** Subtract a quaternion
+ * @param q quaternion
+ */
+ public void subtract(Quaternion q)
+ {
+ x-=q.x;
+ y-=q.y;
+ z-=q.z;
+ }
+
+ /** Divide a quaternion by a constant
+ * @param n a float to divide by
+ */
+ public void divide(float n)
+ {
+ x/=n;
+ y/=n;
+ z/=n;
+ }
+
+ /** Multiply this quaternion by
+ * the param quaternion
+ * @param q a quaternion to multiply with
+ */
+ public void mult(Quaternion q)
+ {
+ float w1 = w*q.w - (x*q.x + y*q.y + z*q.z);
+
+ float x1 = w*q.z + q.w*z + y*q.z - z*q.y;
+ float y1 = w*q.x + q.w*x + z*q.x - x*q.z;
+ float z1 = w*q.y + q.w*y + x*q.y - y*q.x;
+
+ w = w1;
+ x = x1;
+ y = y1;
+ z = z1;
+ }
+
+ /** Multiply a quaternion by a constant
+ * @param n a float constant
+ */
+ public void mult(float n)
+ {
+ x*=n;
+ y*=n;
+ z*=n;
+ }
+
+ /** Normalize a quaternion required if
+ * to be used as a rotational quaternion
+ */
+ public void normalize()
+ {
+ float norme = (float)MathFloat.sqrt(w*w + x*x + y*y + z*z);
+ if (norme == 0.0f)
+ {
+ w = 1.0f;
+ x = y = z = 0.0f;
+ }
+ else
+ {
+ float recip = 1.0f/norme;
+
+ w *= recip;
+ x *= recip;
+ y *= recip;
+ z *= recip;
+ }
+ }
+
+ /** Invert the quaternion If rotational,
+ * will produce a the inverse rotation
+ */
+ public void inverse()
+ {
+ float norm = w*w + x*x + y*y + z*z;
+
+ float recip = 1.0f/norm;
+
+ w *= recip;
+ x = -1*x*recip;
+ y = -1*y*recip;
+ z = -1*z*recip;
+ }
+
+ /** Transform this quaternion to a
+ * 4x4 column matrix representing the rotation
+ * @return new float[16] column matrix 4x4
+ */
+ public float[] toMatrix()
+ {
+ float[] matrix = new float[16];
+ matrix[0] = 1.0f - 2*y*y - 2*z*z;
+ matrix[1] = 2*x*y + 2*w*z;
+ matrix[2] = 2*x*z - 2*w*y;
+ matrix[3] = 0;
+
+ matrix[4] = 2*x*y - 2*w*z;
+ matrix[5] = 1.0f - 2*x*x - 2*z*z;
+ matrix[6] = 2*y*z + 2*w*x;
+ matrix[7] = 0;
+
+ matrix[8] = 2*x*z + 2*w*y;
+ matrix[9] = 2*y*z - 2*w*x;
+ matrix[10] = 1.0f - 2*x*x - 2*y*y;
+ matrix[11] = 0;
+
+ matrix[12] = 0;
+ matrix[13] = 0;
+ matrix[14] = 0;
+ matrix[15] = 1;
+ return matrix;
+ }
+
+ /** Set this quaternion from a Sphereical interpolation
+ * of two param quaternion, used mostly for rotational animation
+ * @param a initial quaternion
+ * @param b target quaternion
+ * @param t float between 0 and 1 representing interp.
+ */
+ public void slerp(Quaternion a,Quaternion b, float t)
+ {
+ float omega, cosom, sinom, sclp, sclq;
+ cosom = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
+ if ((1.0f+cosom) > MathFloat.E) {
+ if ((1.0f-cosom) > MathFloat.E) {
+ omega = (float)MathFloat.acos(cosom);
+ sinom = (float)MathFloat.sin(omega);
+ sclp = (float)MathFloat.sin((1.0f-t)*omega) / sinom;
+ sclq = (float)MathFloat.sin(t*omega) / sinom;
+ }
+ else {
+ sclp = 1.0f - t;
+ sclq = t;
+ }
+ x = sclp*a.x + sclq*b.x;
+ y = sclp*a.y + sclq*b.y;
+ z = sclp*a.z + sclq*b.z;
+ w = sclp*a.w + sclq*b.w;
+ }
+ else {
+ x =-a.y;
+ y = a.x;
+ z =-a.w;
+ w = a.z;
+ sclp = MathFloat.sin((1.0f-t) * MathFloat.PI * 0.5f);
+ sclq = MathFloat.sin(t * MathFloat.PI * 0.5f);
+ x = sclp*a.x + sclq*b.x;
+ y = sclp*a.y + sclq*b.y;
+ z = sclp*a.z + sclq*b.z;
+ }
+ }
+
+ /** Check if this quaternion is empty, ie (0,0,0,1)
+ * @return true if empty, false otherwise
+ */
+ public boolean isEmpty()
+ {
+ if (w==1 && x==0 && y==0 && z==0)
+ return true;
+ return false;
+ }
+
+ /** Check if this quaternion represents an identity
+ * matrix, for rotation.
+ * @return true if it is an identity rep., false otherwise
+ */
+ public boolean isIdentity()
+ {
+ if (w==0 && x==0 && y==0 && z==0)
+ return true;
+ return false;
+ }
+
+ /** compute the quaternion from a 3x3 column matrix
+ * @param m 3x3 column matrix
+ */
+ public void setFromMatrix(float[] m) {
+ float T= m[0] + m[4] + m[8] + 1;
+ if (T>0){
+ float S = 0.5f / (float)MathFloat.sqrt(T);
+ w = 0.25f / S;
+ x = ( m[5] - m[7]) * S;
+ y = ( m[6] - m[2]) * S;
+ z = ( m[1] - m[3] ) * S;
+ }
+ else{
+ if ((m[0] > m[4])&(m[0] > m[8])) {
+ float S = MathFloat.sqrt( 1.0f + m[0] - m[4] - m[8] ) * 2f; // S=4*qx
+ w = (m[7] - m[5]) / S;
+ x = 0.25f * S;
+ y = (m[3] + m[1]) / S;
+ z = (m[6] + m[2]) / S;
+ }
+ else if (m[4] > m[8]) {
+ float S = MathFloat.sqrt( 1.0f + m[4] - m[0] - m[8] ) * 2f; // S=4*qy
+ w = (m[6] - m[2]) / S;
+ x = (m[3] + m[1]) / S;
+ y = 0.25f * S;
+ z = (m[7] + m[5]) / S;
+ }
+ else {
+ float S = MathFloat.sqrt( 1.0f + m[8] - m[0] - m[4] ) * 2f; // S=4*qz
+ w = (m[3] - m[1]) / S;
+ x = (m[6] + m[2]) / S;
+ y = (m[7] + m[5]) / S;
+ z = 0.25f * S;
+ }
+ }
+ }
+
+ /** Check if the the 3x3 matrix (param) is in fact
+ * an affine rotational matrix
+ * @param m 3x3 column matrix
+ * @return true if representing a rotational matrix, false otherwise
+ */
+ public boolean isRotationMatrix(float[] m) {
+ double epsilon = 0.01; // margin to allow for rounding errors
+ if (MathFloat.abs(m[0]*m[3] + m[3]*m[4] + m[6]*m[7]) > epsilon) return false;
+ if (MathFloat.abs(m[0]*m[2] + m[3]*m[5] + m[6]*m[8]) > epsilon) return false;
+ if (MathFloat.abs(m[1]*m[2] + m[4]*m[5] + m[7]*m[8]) > epsilon) return false;
+ if (MathFloat.abs(m[0]*m[0] + m[3]*m[3] + m[6]*m[6] - 1) > epsilon) return false;
+ if (MathFloat.abs(m[1]*m[1] + m[4]*m[4] + m[7]*m[7] - 1) > epsilon) return false;
+ if (MathFloat.abs(m[2]*m[2] + m[5]*m[5] + m[8]*m[8] - 1) > epsilon) return false;
+ return (MathFloat.abs(determinant(m)-1) < epsilon);
+ }
+ private float determinant(float[] m) {
+ return m[0]*m[4]*m[8] + m[3]*m[7]*m[2] + m[6]*m[1]*m[5] - m[0]*m[7]*m[5] - m[3]*m[1]*m[8] - m[6]*m[4]*m[2];
+ }
+}
diff --git a/turtle2d/src/com/jogamp/graph/math/VectorUtil.java b/turtle2d/src/com/jogamp/graph/math/VectorUtil.java
new file mode 100755
index 0000000..cca9a45
--- /dev/null
+++ b/turtle2d/src/com/jogamp/graph/math/VectorUtil.java
@@ -0,0 +1,295 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.graph.math;
+
+import java.util.ArrayList;
+
+import jogamp.graph.math.MathFloat;
+
+import com.jogamp.graph.geom.Vertex;
+
+public class VectorUtil {
+
+ public static final int CW = -1;
+ public static final int CCW = 1;
+ public static final int COLLINEAR = 0;
+
+ /** compute the dot product of two points
+ * @param vec1 vector 1
+ * @param vec2 vector 2
+ * @return the dot product as float
+ */
+ public static float dot(float[] vec1, float[] vec2)
+ {
+ return (vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2]);
+ }
+ /** Normalize a vector
+ * @param vector input vector
+ * @return normalized vector
+ */
+ public static float[] normalize(float[] vector)
+ {
+ float[] newVector = new float[3];
+
+ float d = MathFloat.sqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]);
+ if(d> 0.0f)
+ {
+ newVector[0] = vector[0]/d;
+ newVector[1] = vector[1]/d;
+ newVector[2] = vector[2]/d;
+ }
+ return newVector;
+ }
+
+ /** Scales a vector by param
+ * @param vector input vector
+ * @param scale constant to scale by
+ * @return scaled vector
+ */
+ public static float[] scale(float[] vector, float scale)
+ {
+ float[] newVector = new float[3];
+
+ newVector[0] = vector[0]*scale;
+ newVector[1] = vector[1]*scale;
+ newVector[2] = vector[2]*scale;
+ return newVector;
+ }
+
+ /** Adds to vectors
+ * @param v1 vector 1
+ * @param v2 vector 2
+ * @return v1 + v2
+ */
+ public static float[] vectorAdd(float[] v1, float[] v2)
+ {
+ float[] newVector = new float[3];
+
+ newVector[0] = v1[0] + v2[0];
+ newVector[1] = v1[1] + v2[1];
+ newVector[2] = v1[2] + v2[2];
+ return newVector;
+ }
+
+ /** cross product vec1 x vec2
+ * @param vec1 vector 1
+ * @param vec2 vecttor 2
+ * @return the resulting vector
+ */
+ public static float[] cross(float[] vec1, float[] vec2)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec2[2]*vec1[1] - vec2[1]*vec1[2];
+ out[1] = vec2[0]*vec1[2] - vec2[2]*vec1[0];
+ out[2] = vec2[1]*vec1[0] - vec2[0]*vec1[1];
+
+ return out;
+ }
+
+ /** Column Matrix Vector multiplication
+ * @param colMatrix column matrix (4x4)
+ * @param vec vector(x,y,z)
+ * @return result new float[3]
+ */
+ public static float[] colMatrixVectorMult(float[] colMatrix, float[] vec)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec[0]*colMatrix[0] + vec[1]*colMatrix[4] + vec[2]*colMatrix[8] + colMatrix[12];
+ out[1] = vec[0]*colMatrix[1] + vec[1]*colMatrix[5] + vec[2]*colMatrix[9] + colMatrix[13];
+ out[2] = vec[0]*colMatrix[2] + vec[1]*colMatrix[6] + vec[2]*colMatrix[10] + colMatrix[14];
+
+ return out;
+ }
+
+ /** Matrix Vector multiplication
+ * @param rawMatrix column matrix (4x4)
+ * @param vec vector(x,y,z)
+ * @return result new float[3]
+ */
+ public static float[] rowMatrixVectorMult(float[] rawMatrix, float[] vec)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec[0]*rawMatrix[0] + vec[1]*rawMatrix[1] + vec[2]*rawMatrix[2] + rawMatrix[3];
+ out[1] = vec[0]*rawMatrix[4] + vec[1]*rawMatrix[5] + vec[2]*rawMatrix[6] + rawMatrix[7];
+ out[2] = vec[0]*rawMatrix[8] + vec[1]*rawMatrix[9] + vec[2]*rawMatrix[10] + rawMatrix[11];
+
+ return out;
+ }
+
+ /** Calculate the midpoint of two values
+ * @param p1 first value
+ * @param p2 second vale
+ * @return midpoint
+ */
+ public static float mid(float p1, float p2)
+ {
+ return (p1+p2)/2.0f;
+ }
+ /** Calculate the midpoint of two points
+ * @param p1 first point
+ * @param p2 second point
+ * @return midpoint
+ */
+ public static float[] mid(float[] p1, float[] p2)
+ {
+ float[] midPoint = new float[3];
+ midPoint[0] = (p1[0] + p2[0])/2.0f;
+ midPoint[1] = (p1[1] + p2[1])/2.0f;
+ midPoint[2] = (p1[2] + p2[2])/2.0f;
+
+ return midPoint;
+ }
+ /** Compute the norm of a vector
+ * @param vec vector
+ * @return vorm
+ */
+ public static float norm(float[] vec)
+ {
+ return MathFloat.sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
+ }
+ /** Compute distance between 2 points
+ * @param p0 a ref point on the line
+ * @param vec vector representing the direction of the line
+ * @param point the point to compute the relative distance of
+ * @return distance float
+ */
+ public static float computeLength(float[] p0, float[] point)
+ {
+ float[] w = new float[]{point[0]-p0[0],point[1]-p0[1],point[2]-p0[2]};
+
+ float distance = MathFloat.sqrt(w[0]*w[0] + w[1]*w[1] + w[2]*w[2]);
+
+ return distance;
+ }
+
+ /**Check equality of 2 vec3 vectors
+ * @param v1 vertex 1
+ * @param v2 vertex 2
+ * @return
+ */
+ public static boolean checkEquality(float[] v1, float[] v2)
+ {
+ if(Float.compare(v1[0], v2[0]) == 0
+ && Float.compare(v1[1] , v2[1]) == 0
+ && Float.compare(v1[2], v2[2]) == 0 )
+ return true;
+ return false;
+ }
+
+ /** Compute the determinant of 3 vectors
+ * @param a vector 1
+ * @param b vector 2
+ * @param c vector 3
+ * @return the determinant value
+ */
+ public static float computeDeterminant(float[] a, float[] b, float[] c)
+ {
+ float area = a[0]*b[1]*c[2] + a[1]*b[2]*c[0] + a[2]*b[0]*c[1] - a[0]*b[2]*c[1] - a[1]*b[0]*c[2] - a[2]*b[1]*c[0];
+ return area;
+ }
+
+ /** Check if three vertices are colliniear
+ * @param v1 vertex 1
+ * @param v2 vertex 2
+ * @param v3 vertex 3
+ * @return true if collinear, false otherwise
+ */
+ public static boolean checkCollinear(float[] v1, float[] v2, float[] v3)
+ {
+ return (computeDeterminant(v1, v2, v3) == VectorUtil.COLLINEAR);
+ }
+
+ /** Compute Vector
+ * @param v1 vertex 1
+ * @param v2 vertex2 2
+ * @return Vector V1V2
+ */
+ public static float[] computeVector(float[] v1, float[] v2)
+ {
+ float[] vector = new float[3];
+ vector[0] = v2[0] - v1[0];
+ vector[1] = v2[1] - v1[1];
+ vector[2] = v2[2] - v1[2];
+ return vector;
+ }
+
+ /** Check if vertices in triangle circumcircle
+ * @param a triangle vertex 1
+ * @param b triangle vertex 2
+ * @param c triangle vertex 3
+ * @param d vertex in question
+ * @return true if the vertex d is inside the circle defined by the
+ * vertices a, b, c. from paper by Guibas and Stolfi (1985).
+ */
+ public static boolean inCircle(Vertex a, Vertex b, Vertex c, Vertex d){
+ return (a.getX() * a.getX() + a.getY() * a.getY()) * triArea(b, c, d) -
+ (b.getX() * b.getX() + b.getY() * b.getY()) * triArea(a, c, d) +
+ (c.getX() * c.getX() + c.getY() * c.getY()) * triArea(a, b, d) -
+ (d.getX() * d.getX() + d.getY() * d.getY()) * triArea(a, b, c) > 0;
+ }
+
+ /** Computes oriented area of a triangle
+ * @param a first vertex
+ * @param b second vertex
+ * @param c third vertex
+ * @return compute twice the area of the oriented triangle (a,b,c), the area
+ * is positive if the triangle is oriented counterclockwise.
+ */
+ public static float triArea(Vertex a, Vertex b, Vertex c){
+ return (b.getX() - a.getX()) * (c.getY() - a.getY()) - (b.getY() - a.getY())*(c.getX() - a.getX());
+ }
+
+ /** Check if points are in ccw order
+ * @param a first vertex
+ * @param b second vertex
+ * @param c third vertex
+ * @return true if the points a,b,c are in a ccw order
+ */
+ public static boolean ccw(Vertex a, Vertex b, Vertex c){
+ return triArea(a,b,c) > 0;
+ }
+
+ /** Computes the area of a list of vertices to check if ccw
+ * @param vertices
+ * @return positve area if ccw else negative area value
+ */
+ public static float area(ArrayList<Vertex> vertices) {
+ int n = vertices.size();
+ float area = 0.0f;
+ for (int p = n - 1, q = 0; q < n; p = q++)
+ {
+ float[] pCoord = vertices.get(p).getCoord();
+ float[] qCoord = vertices.get(q).getCoord();
+ area += pCoord[0] * qCoord[1] - qCoord[0] * pCoord[1];
+ }
+ return area;
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/TestRegionRenderer01.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/TestRegionRenderer01.java
new file mode 100644
index 0000000..9ad4eb4
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/TestRegionRenderer01.java
@@ -0,0 +1,156 @@
+package com.jogamp.opengl.test.junit.graph;
+
+import java.io.IOException;
+
+import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLProfile;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.test.junit.graph.demos.GPURegionGLListener01;
+import com.jogamp.opengl.test.junit.graph.demos.GPURegionGLListener02;
+import com.jogamp.opengl.test.junit.graph.demos.GPURegionRendererListenerBase01;
+
+
+public class TestRegionRenderer01 {
+
+ public static void main(String args[]) throws IOException {
+ String tstname = TestRegionRenderer01.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+
+ @BeforeClass
+ public static void initClass() {
+ GLProfile.initSingleton(true);
+ NativeWindowFactory.initSingleton(true);
+ }
+
+ static void destroyWindow(GLWindow window) {
+ if(null!=window) {
+ window.destroy();
+ }
+ }
+
+ static GLWindow createWindow(String title, GLCapabilitiesImmutable caps, int width, int height) {
+ Assert.assertNotNull(caps);
+
+ GLWindow window = GLWindow.create(caps);
+ window.setSize(width, height);
+ window.setPosition(10, 10);
+ window.setTitle(title);
+ Assert.assertNotNull(window);
+ window.setVisible(true);
+
+ return window;
+ }
+
+ @Test
+ public void testRegionRendererR2T01() throws InterruptedException {
+ GLProfile glp = GLProfile.getGL2ES2();
+
+ GLCapabilities caps = new GLCapabilities(glp);
+ //caps.setOnscreen(false);
+ caps.setAlphaBits(4);
+
+ GLWindow window = createWindow("shape-r2t1-msaa0", caps, 800,400);
+
+ GPURegionGLListener02 demo02Listener = new GPURegionGLListener02 (Region.TWO_PASS, 1140, false, false);
+ demo02Listener.attachInputListenerTo(window);
+ window.addGLEventListener(demo02Listener);
+
+ RegionGLListener listener = new RegionGLListener(demo02Listener, window.getTitle(), "GPURegionNewtDemo02");
+ window.addGLEventListener(listener);
+
+ listener.setTech(-20, 00, 0f, -300, 400);
+ window.display();
+
+ listener.setTech(-20, 00, 0f, -150, 800);
+ window.display();
+
+ listener.setTech(-20, 00, 0f, -50, 1000);
+ window.display();
+
+ destroyWindow(window);
+ }
+
+ @Test
+ public void testRegionRendererMSAA01() throws InterruptedException {
+ GLProfile glp = GLProfile.get(GLProfile.GL2ES2);
+ GLCapabilities caps = new GLCapabilities(glp);
+ // caps.setOnscreen(false);
+ caps.setAlphaBits(4);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4);
+
+ GLWindow window = createWindow("shape-r2t0-msaa1", caps, 800, 400);
+
+ GPURegionGLListener01 demo01Listener = new GPURegionGLListener01 (Region.SINGLE_PASS, 0, false, false);
+ demo01Listener.attachInputListenerTo(window);
+ window.addGLEventListener(demo01Listener);
+
+ RegionGLListener listener = new RegionGLListener(demo01Listener, window.getTitle(), "GPURegion01");
+ window.addGLEventListener(listener);
+
+ listener.setTech(-20, 00, 0f, -300, 400);
+ window.display();
+
+ listener.setTech(-20, 00, 0f, -150, 800);
+ window.display();
+
+ listener.setTech(-20, 00, 0f, -50, 1000);
+ window.display();
+
+ destroyWindow(window);
+ }
+
+ private class RegionGLListener implements GLEventListener {
+ String winTitle;
+ String name;
+ GPURegionRendererListenerBase01 impl;
+
+ public RegionGLListener(GPURegionRendererListenerBase01 impl, String title, String name) {
+ this.impl = impl;
+ this.winTitle = title;
+ this.name = name;
+ }
+
+ public void setTech(float xt, float yt, float angle, int zoom, int fboSize){
+ impl.setMatrix(xt, yt, angle, zoom, fboSize);
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ impl.init(drawable);
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ impl.display(drawable);
+
+ try {
+ impl.printScreen(drawable, "./", winTitle, name, false);
+ } catch (GLException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ impl.dispose(drawable);
+
+ }
+
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+ impl.reshape(drawable, x, y, width, height);
+
+ }
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/TestTextRenderer01.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/TestTextRenderer01.java
new file mode 100755
index 0000000..c954c6a
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/TestTextRenderer01.java
@@ -0,0 +1,169 @@
+package com.jogamp.opengl.test.junit.graph;
+
+import java.io.IOException;
+
+import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLProfile;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.curve.opengl.TextRenderer;
+import com.jogamp.graph.font.FontFactory;
+import com.jogamp.graph.geom.opengl.SVertex;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.test.junit.graph.demos.GPUTextRendererListenerBase01;
+
+
+public class TestTextRenderer01 {
+
+ public static void main(String args[]) throws IOException {
+ String tstname = TestTextRenderer01.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+
+ @BeforeClass
+ public static void initClass() {
+ GLProfile.initSingleton(true);
+ NativeWindowFactory.initSingleton(true);
+ }
+
+ static void destroyWindow(GLWindow window) {
+ if(null!=window) {
+ window.destroy();
+ }
+ }
+
+ static GLWindow createWindow(String title, GLCapabilitiesImmutable caps, int width, int height) {
+ Assert.assertNotNull(caps);
+
+ GLWindow window = GLWindow.create(caps);
+ window.setSize(width, height);
+ window.setPosition(10, 10);
+ window.setTitle(title);
+ Assert.assertNotNull(window);
+ window.setVisible(true);
+
+ return window;
+ }
+
+ @Test
+ public void testTextRendererR2T01() throws InterruptedException {
+ GLProfile glp = GLProfile.getGL2ES2();
+
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+
+ GLWindow window = createWindow("text-r2t1-msaa0", caps, 800,400);
+ TextGLListener textGLListener = new TextGLListener(Region.TWO_PASS);
+ textGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(textGLListener);
+
+ textGLListener.setFontSet(FontFactory.UBUNTU, 0, 0);
+ textGLListener.setTech(-400, -30, 0f, -1000, window.getWidth()*2);
+ window.display();
+
+ textGLListener.setTech(-400, -30, 0, -380, window.getWidth()*3);
+ window.display();
+
+ textGLListener.setTech(-400, -20, 0, -80, window.getWidth()*4);
+ window.display();
+
+ textGLListener.setFontSet(FontFactory.JAVA, 0, 0);
+ textGLListener.setTech(-400, -30, 0f, -1000, window.getWidth()*2);
+ window.display();
+
+ textGLListener.setTech(-400, -30, 0, -380, window.getWidth()*3);
+ window.display();
+
+ textGLListener.setTech(-400, -20, 0, -80, window.getWidth()*4);
+ window.display();
+
+ destroyWindow(window);
+ }
+
+ @Test
+ public void testTextRendererMSAA01() throws InterruptedException {
+ GLProfile glp = GLProfile.get(GLProfile.GL2ES2);
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4);
+
+ GLWindow window = createWindow("text-r2t0-msaa1", caps, 800, 400);
+ TextGLListener textGLListener = new TextGLListener(Region.SINGLE_PASS);
+ textGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(textGLListener);
+
+ textGLListener.setFontSet(FontFactory.UBUNTU, 0, 0);
+ textGLListener.setTech(-400, -30, 0f, -1000, 0);
+ window.display();
+
+ textGLListener.setTech(-400, -30, 0, -380, 0);
+ window.display();
+
+ textGLListener.setTech(-400, -20, 0, -80, 0);
+ window.display();
+
+ textGLListener.setFontSet(FontFactory.JAVA, 0, 0);
+ textGLListener.setTech(-400, -30, 0f, -1000, 0);
+ window.display();
+
+ textGLListener.setTech(-400, -30, 0, -380, 0);
+ window.display();
+
+ textGLListener.setTech(-400, -20, 0, -80, 0);
+ window.display();
+
+ destroyWindow(window);
+ }
+
+ private class TextGLListener extends GPUTextRendererListenerBase01 {
+ String winTitle;
+
+ public TextGLListener(int type) {
+ super(SVertex.factory(), type, false, false);
+ }
+
+ public void attachInputListenerTo(GLWindow window) {
+ super.attachInputListenerTo(window);
+ winTitle = window.getTitle();
+ }
+ public void setTech(float xt, float yt, float angle, int zoom, int fboSize){
+ setMatrix(xt, yt, angle, zoom, fboSize);
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ super.init(drawable);
+ gl.setSwapInterval(1);
+ gl.glEnable(GL.GL_DEPTH_TEST);
+
+ final TextRenderer textRenderer = (TextRenderer) getRenderer();
+
+ textRenderer.init(gl);
+ textRenderer.setAlpha(gl, 1.0f);
+ textRenderer.setColor(gl, 0.0f, 0.0f, 0.0f);
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ super.display(drawable);
+
+ try {
+ printScreen(drawable, "./", winTitle, false);
+ } catch (GLException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java
new file mode 100644
index 0000000..bf4bfab
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.graph.geom.opengl.SVertex;
+
+/** Demonstrate the rendering of multiple outlines into one region/OutlineShape
+ * These Outlines are not necessary connected or contained.
+ * The output of this demo shows two identical shapes but the left one
+ * has some vertices with off-curve flag set to true, and the right allt he vertices
+ * are on the curve. Demos the Res. Independent Nurbs based Curve rendering
+ *
+ */
+public class GPURegionGLListener01 extends GPURegionRendererListenerBase01 {
+ OutlineShape outlineShape = null;
+
+ public GPURegionGLListener01 (int numpass, int fbosize, boolean debug, boolean trace) {
+ super(SVertex.factory(), numpass, debug, trace);
+ setMatrix(-20, 00, 0f, -50, fbosize);
+ }
+
+ private void createTestOutline(){
+ float offset = 0;
+ outlineShape = new OutlineShape(getRenderer().getFactory());
+ outlineShape.addVertex(0.0f,-10.0f, true);
+ outlineShape.addVertex(15.0f,-10.0f, true);
+ outlineShape.addVertex(10.0f,5.0f, false);
+ outlineShape.addVertex(15.0f,10.0f, true);
+ outlineShape.addVertex(6.0f,15.0f, false);
+ outlineShape.addVertex(5.0f,8.0f, false);
+ outlineShape.addVertex(0.0f,10.0f,true);
+ outlineShape.closeLastOutline();
+ outlineShape.addEmptyOutline();
+ outlineShape.addVertex(5.0f,-5.0f,true);
+ outlineShape.addVertex(10.0f,-5.0f, false);
+ outlineShape.addVertex(10.0f,0.0f, true);
+ outlineShape.addVertex(5.0f,0.0f, false);
+ outlineShape.closeLastOutline();
+
+ /** Same shape as above but without any off-curve vertices */
+ outlineShape.addEmptyOutline();
+ offset = 30;
+ outlineShape.addVertex(offset+0.0f,-10.0f, true);
+ outlineShape.addVertex(offset+17.0f,-10.0f, true);
+ outlineShape.addVertex(offset+11.0f,5.0f, true);
+ outlineShape.addVertex(offset+16.0f,10.0f, true);
+ outlineShape.addVertex(offset+7.0f,15.0f, true);
+ outlineShape.addVertex(offset+6.0f,8.0f, true);
+ outlineShape.addVertex(offset+0.0f,10.0f, true);
+ outlineShape.closeLastOutline();
+ outlineShape.addEmptyOutline();
+ outlineShape.addVertex(offset+5.0f,0.0f, true);
+ outlineShape.addVertex(offset+5.0f,-5.0f, true);
+ outlineShape.addVertex(offset+10.0f,-5.0f, true);
+ outlineShape.addVertex(offset+10.0f,0.0f, true);
+ outlineShape.closeLastOutline();
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ super.init(drawable);
+
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ final RegionRenderer regionRenderer = (RegionRenderer) getRenderer();
+
+ gl.setSwapInterval(1);
+ gl.glEnable(GL2ES2.GL_DEPTH_TEST);
+ regionRenderer.init(gl);
+ regionRenderer.setAlpha(gl, 1.0f);
+ regionRenderer.setColor(gl, 0.0f, 0.0f, 0.0f);
+ //gl.glSampleCoverage(0.95f, false);
+ //gl.glEnable(GL2GL3.GL_SAMPLE_COVERAGE); // sample coverage doesn't really make a difference to lines
+ //gl.glEnable(GL2GL3.GL_SAMPLE_ALPHA_TO_ONE);
+ MSAATool.dump(drawable);
+
+ createTestOutline();
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ final RegionRenderer regionRenderer = (RegionRenderer) getRenderer();
+
+ regionRenderer.resetModelview(null);
+ regionRenderer.translate(null, getXTran(), getYTran(), getZoom());
+ regionRenderer.rotate(gl, getAngle(), 0, 1, 0);
+
+ regionRenderer.renderOutlineShape(gl, outlineShape, getPosition(), getTexSize());
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java
new file mode 100644
index 0000000..56db37e
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.graph.geom.opengl.SVertex;
+
+/** Demonstrate the rendering of multiple OutlineShapes
+ * into one region
+ *
+ */
+public class GPURegionGLListener02 extends GPURegionRendererListenerBase01 {
+ OutlineShape[] outlineShapes = new OutlineShape[2];
+
+ public GPURegionGLListener02 (int numpass, int fbosize, boolean debug, boolean trace) {
+ super(SVertex.factory(), numpass, debug, trace);
+ setMatrix(-20, 00, 0f, -50, fbosize);
+ }
+
+ private void createTestOutline(){
+ float offset = 0;
+ outlineShapes[0] = new OutlineShape(SVertex.factory());
+ outlineShapes[0].addVertex(0.0f,-10.0f,true);
+ outlineShapes[0].addVertex(15.0f,-10.0f, true);
+ outlineShapes[0].addVertex(10.0f,5.0f, false);
+ outlineShapes[0].addVertex(15.0f,10.0f, true);
+ outlineShapes[0].addVertex(6.0f,15.0f, false);
+ outlineShapes[0].addVertex(5.0f,8.0f, false);
+ outlineShapes[0].addVertex(0.0f,10.0f,true);
+ outlineShapes[0].closeLastOutline();
+ outlineShapes[0].addEmptyOutline();
+ outlineShapes[0].addVertex(5.0f,-5.0f,true);
+ outlineShapes[0].addVertex(10.0f,-5.0f, false);
+ outlineShapes[0].addVertex(10.0f,0.0f, true);
+ outlineShapes[0].addVertex(5.0f,0.0f, false);
+ outlineShapes[0].closeLastOutline();
+
+ /** Same shape as above but without any off-curve vertices */
+ outlineShapes[1] = new OutlineShape(SVertex.factory());
+ offset = 30;
+ outlineShapes[1].addVertex(offset+0.0f,-10.0f, true);
+ outlineShapes[1].addVertex(offset+17.0f,-10.0f, true);
+ outlineShapes[1].addVertex(offset+11.0f,5.0f, true);
+ outlineShapes[1].addVertex(offset+16.0f,10.0f, true);
+ outlineShapes[1].addVertex(offset+7.0f,15.0f, true);
+ outlineShapes[1].addVertex(offset+6.0f,8.0f, true);
+ outlineShapes[1].addVertex(offset+0.0f,10.0f, true);
+ outlineShapes[1].closeLastOutline();
+ outlineShapes[1].addEmptyOutline();
+ outlineShapes[1].addVertex(offset+5.0f,0.0f, true);
+ outlineShapes[1].addVertex(offset+5.0f,-5.0f, true);
+ outlineShapes[1].addVertex(offset+10.0f,-5.0f, true);
+ outlineShapes[1].addVertex(offset+10.0f,0.0f, true);
+ outlineShapes[1].closeLastOutline();
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ super.init(drawable);
+
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ final RegionRenderer regionRenderer = (RegionRenderer) getRenderer();
+
+ gl.setSwapInterval(1);
+ gl.glEnable(GL2ES2.GL_DEPTH_TEST);
+ regionRenderer.init(gl);
+ regionRenderer.setAlpha(gl, 1.0f);
+ regionRenderer.setColor(gl, 0.0f, 0.0f, 0.0f);
+ MSAATool.dump(drawable);
+
+ createTestOutline();
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ final RegionRenderer regionRenderer = (RegionRenderer) getRenderer();
+
+ regionRenderer.resetModelview(null);
+ regionRenderer.translate(null, getXTran(), getYTran(), getZoom());
+ regionRenderer.rotate(gl, getAngle(), 0, 1, 0);
+
+ regionRenderer.renderOutlineShapes(gl, outlineShapes, getPosition(), getTexSize());
+
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java
new file mode 100755
index 0000000..dbd5fe1
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.Animator;
+
+/** Demonstrate the rendering of multiple outlines into one region/OutlineShape
+ * These Outlines are not necessary connected or contained.
+ * The output of this demo shows two identical shapes but the left one
+ * has some vertices with off-curve flag set to true, and the right allt he vertices
+ * are on the curve. Demos the Res. Independent Nurbs based Curve rendering
+ *
+ */
+public class GPURegionNewtDemo01 {
+ static final boolean DEBUG = false;
+ static final boolean TRACE = false;
+
+ public static void main(String[] args) {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.getGL2ES2();
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4); // 2 samples is not enough ..
+ System.out.println("Requested: " + caps);
+
+ GLWindow window = GLWindow.create(caps);
+ window.setPosition(10, 10);
+ window.setSize(800, 400);
+ window.setTitle("GPU Curve Region Newt Demo 01 - r2t0 msaa1");
+
+ GPURegionGLListener01 regionGLListener = new GPURegionGLListener01 (Region.SINGLE_PASS, 0, DEBUG, TRACE);
+ regionGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(regionGLListener);
+
+ window.enablePerfLog(true);
+ window.setVisible(true);
+
+ //FPSAnimator animator = new FPSAnimator(60);
+ Animator animator = new Animator();
+ animator.add(window);
+ animator.start();
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java
new file mode 100644
index 0000000..7ffab59
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.Animator;
+
+/** Demonstrate the rendering of multiple OutlineShapes
+ * into one region
+ *
+ */
+public class GPURegionNewtDemo02 {
+ static final boolean DEBUG = false;
+ static final boolean TRACE = false;
+
+ public static void main(String[] args) {
+ GPURegionNewtDemo02 test = new GPURegionNewtDemo02();
+ test.testMe();
+ }
+
+ public void testMe() {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.getGL2ES2();
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ System.out.println("Requested: " + caps);
+
+ GLWindow window = GLWindow.create(caps);
+ window.setPosition(10, 10);
+ window.setSize(800, 400);
+ window.setTitle("GPU Curve Region Newt Demo 02 - r2t1 msaa0");
+
+ GPURegionGLListener02 regionGLListener = new GPURegionGLListener02 (Region.TWO_PASS, 1140, DEBUG, TRACE);
+ regionGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(regionGLListener);
+
+ window.enablePerfLog(true);
+ window.setVisible(true);
+
+ //FPSAnimator animator = new FPSAnimator(60);
+ Animator animator = new Animator();
+ animator.add(window);
+ animator.start();
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionRendererListenerBase01.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionRendererListenerBase01.java
new file mode 100644
index 0000000..eab5fc8
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURegionRendererListenerBase01.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.graph.geom.Vertex;
+
+/**
+ *
+ * Action Keys:
+ * - 1/2: zoom in/out
+ * - 3/4: font +/-
+ * - 6/7: 2nd pass texture size
+ * - 0/9: rotate
+ * - s: toogle draw 'font set'
+ * - f: toggle draw fps
+ * - v: toggle v-sync
+ * - space: toggle font (ubuntu/java)
+ */
+public abstract class GPURegionRendererListenerBase01 extends GPURendererListenerBase01 {
+ OutlineShape outlineShape = null;
+
+ public GPURegionRendererListenerBase01(Vertex.Factory<? extends Vertex> factory, int mode, boolean debug, boolean trace) {
+ super(RegionRenderer.create(factory, mode), debug, trace);
+ }
+} \ No newline at end of file
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java
new file mode 100644
index 0000000..622178b
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java
@@ -0,0 +1,264 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLPipelineFactory;
+import javax.media.opengl.GLRunnable;
+
+import com.jogamp.graph.curve.opengl.Renderer;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.opengl.GLWindow;
+
+/**
+ *
+ * Action Keys:
+ * - 1/2: zoom in/out
+ * - 6/7: 2nd pass texture size
+ * - 0/9: rotate
+ * - v: toggle v-sync
+ * - s: screenshot
+ */
+public abstract class GPURendererListenerBase01 implements GLEventListener {
+ private Screenshot screenshot;
+ private Renderer renderer;
+ private boolean debug;
+ private boolean trace;
+
+ private KeyAction keyAction;
+
+ private volatile GLAutoDrawable autoDrawable = null;
+
+ private final float[] position = new float[] {0,0,0};
+
+ private float xTran = -10;
+ private float yTran = 10;
+ private float ang = 0f;
+ private float zoom = -70f;
+ private int texSize = 400;
+
+ boolean updateMatrix = true;
+ boolean ignoreInput = false;
+
+ public GPURendererListenerBase01(Renderer renderer, boolean debug, boolean trace) {
+ this.renderer = renderer;
+ this.debug = debug;
+ this.trace = trace;
+ this.screenshot = new Screenshot();
+ }
+
+ public final Renderer getRenderer() { return renderer; }
+ public final float getZoom() { return zoom; }
+ public final float getXTran() { return xTran; }
+ public final float getYTran() { return yTran; }
+ public final float getAngle() { return ang; }
+ public final int getTexSize() { return texSize; }
+ public final float[] getPosition() { return position; }
+
+ public void setMatrix(float xtrans, float ytrans, float angle, int zoom, int fbosize) {
+ this.xTran = xtrans;
+ this.yTran = ytrans;
+ this.ang = angle;
+ this.zoom = zoom;
+ this.texSize = fbosize;
+ updateMatrix = true;
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ autoDrawable = drawable;
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ if(debug) {
+ gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Debug", null, gl, null) ).getGL2ES2();
+ }
+ if(trace) {
+ gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) ).getGL2ES2();
+ }
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ }
+
+ public void reshape(GLAutoDrawable drawable, int xstart, int ystart, int width, int height) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glViewport(xstart, ystart, width, height);
+ renderer.reshapePerspective(gl, 45.0f, width, height, 0.1f, 7000.0f);
+
+ dumpMatrix();
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ autoDrawable = null;
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ screenshot.dispose();
+ renderer.dispose(gl);
+ }
+
+ public void zoom(int v){
+ zoom += v;
+ updateMatrix = true;
+ dumpMatrix();
+ }
+
+ public void move(float x, float y){
+ xTran += x;
+ yTran += y;
+ updateMatrix = true;
+ dumpMatrix();
+ }
+ public void rotate(float delta){
+ ang += delta;
+ ang %= 360.0f;
+ updateMatrix = true;
+ dumpMatrix();
+ }
+
+ void dumpMatrix() {
+ System.err.println("Matrix: " + xTran + "/" + yTran + " x"+zoom + " @"+ang);
+ }
+
+ /** Attach the input listener to the window */
+ public void attachInputListenerTo(GLWindow window) {
+ if ( null == keyAction ) {
+ keyAction = new KeyAction();
+ window.addKeyListener(keyAction);
+ }
+ }
+
+ public void detachFrom(GLWindow window) {
+ if ( null == keyAction ) {
+ return;
+ }
+ window.removeGLEventListener(this);
+ window.removeKeyListener(keyAction);
+ }
+
+ public void printScreen(GLAutoDrawable drawable, String dir, String tech, String objName, boolean exportAlpha) throws GLException, IOException {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ pw.printf("-%03dx%03d-Z%04d-T%04d-%s", drawable.getWidth(), drawable.getHeight(), (int)Math.abs(zoom), texSize, objName);
+
+ String filename = dir + tech + sw +".tga";
+ screenshot.surface2File(drawable, filename /*, exportAlpha */);
+ }
+
+ int screenshot_num = 0;
+
+ public void setIgnoreInput(boolean v) {
+ ignoreInput = v;
+ }
+ public boolean getIgnoreInput() {
+ return ignoreInput;
+ }
+
+ public class KeyAction implements KeyListener {
+ public void keyPressed(KeyEvent arg0) {
+ if(ignoreInput) {
+ return;
+ }
+
+ if(arg0.getKeyCode() == KeyEvent.VK_1){
+ zoom(10);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_2){
+ zoom(-10);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_UP){
+ move(0, -1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_DOWN){
+ move(0, 1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_LEFT){
+ move(1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){
+ move(-1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_6){
+ texSize -= 10;
+ System.err.println("Tex Size: " + texSize);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_7){
+ texSize += 10;
+ System.err.println("Tex Size: " + texSize);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_0){
+ rotate(1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_9){
+ rotate(-1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_V) {
+ if(null != autoDrawable) {
+ autoDrawable.invoke(false, new GLRunnable() {
+ public void run(GLAutoDrawable drawable) {
+ GL gl = drawable.getGL();
+ int i = gl.getSwapInterval();
+ i = i==0 ? 1 : 0;
+ gl.setSwapInterval(i);
+ final GLAnimatorControl a = drawable.getAnimator();
+ if( null != a ) {
+ a.resetCounter();
+ }
+ System.err.println("Swap Interval: "+i);
+ }
+ });
+ }
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_S){
+ rotate(-1);
+ if(null != autoDrawable) {
+ autoDrawable.invoke(false, new GLRunnable() {
+ public void run(GLAutoDrawable drawable) {
+ try {
+ final String type = ( 1 == renderer.getRenderType() ) ? "r2t0-msaa1" : "r2t1-msaa0" ;
+ printScreen(drawable, "./", "demo-"+type, "snap"+screenshot_num, false);
+ screenshot_num++;
+ } catch (GLException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ }
+ }
+ public void keyTyped(KeyEvent arg0) {}
+ public void keyReleased(KeyEvent arg0) {}
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java
new file mode 100644
index 0000000..7290246
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.test.junit.graph.demos;
+
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+
+import com.jogamp.graph.curve.opengl.TextRenderer;
+import com.jogamp.graph.geom.opengl.SVertex;
+
+public class GPUTextGLListener0A extends GPUTextRendererListenerBase01 {
+ public GPUTextGLListener0A(int numpass, int fbosize, boolean debug, boolean trace) {
+ super(SVertex.factory(), numpass, debug, trace);
+ setMatrix(-400, -30, 0f, -500, fbosize);
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ super.init(drawable);
+
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ final TextRenderer textRenderer = (TextRenderer) getRenderer();
+
+ gl.setSwapInterval(1);
+ gl.glEnable(GL2ES2.GL_DEPTH_TEST);
+ textRenderer.init(gl);
+ textRenderer.setAlpha(gl, 1.0f);
+ textRenderer.setColor(gl, 0.0f, 0.0f, 0.0f);
+ //gl.glSampleCoverage(0.95f, false);
+ //gl.glEnable(GL2GL3.GL_SAMPLE_COVERAGE); // sample coverage doesn't really make a difference to lines
+ //gl.glEnable(GL2GL3.GL_SAMPLE_ALPHA_TO_COVERAGE);
+ //gl.glEnable(GL2GL3.GL_SAMPLE_ALPHA_TO_ONE);
+ MSAATool.dump(drawable);
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java
new file mode 100644
index 0000000..3739f28
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.test.junit.graph.demos;
+
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.Animator;
+
+public class GPUTextNewtDemo01 {
+ static final boolean DEBUG = false;
+ static final boolean TRACE = false;
+
+ public static void main(String[] args) {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.getGL2ES2();
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4); // 2 samples is not enough ..
+ System.out.println("Requested: "+caps);
+
+ GLWindow window = GLWindow.create(caps);
+ window.setPosition(10, 10);
+ window.setSize(800, 400);
+ window.setTitle("GPU Text Newt Demo 01 - r2t0 msaa1");
+
+ GPUTextGLListener0A textGLListener = new GPUTextGLListener0A(Region.SINGLE_PASS, 0, DEBUG, TRACE);
+ textGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(textGLListener);
+
+ window.enablePerfLog(true);
+ window.setVisible(true);
+ // FPSAnimator animator = new FPSAnimator(10);
+ Animator animator = new Animator();
+ animator.add(window);
+ animator.start();
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java
new file mode 100644
index 0000000..40c7d6a
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.Animator;
+
+public class GPUTextNewtDemo02 {
+ /**
+ * FIXME:
+ *
+ * If DEBUG is enabled:
+ *
+ * Caused by: javax.media.opengl.GLException: Thread[main-Display-X11_:0.0-1-EDT-1,5,main] glGetError() returned the following error codes after a call to glFramebufferRenderbuffer(<int> 0x8D40, <int> 0x1902, <int> 0x8D41, <int> 0x1): GL_INVALID_ENUM ( 1280 0x500),
+ * at javax.media.opengl.DebugGL4bc.checkGLGetError(DebugGL4bc.java:33961)
+ * at javax.media.opengl.DebugGL4bc.glFramebufferRenderbuffer(DebugGL4bc.java:33077)
+ * at jogamp.graph.curve.opengl.VBORegion2PGL3.initFBOTexture(VBORegion2PGL3.java:295)
+ */
+ static final boolean DEBUG = false;
+ static final boolean TRACE = false;
+
+ public static void main(String[] args) {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.getGL2ES2();
+
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ System.out.println("Requested: "+caps);
+
+ GLWindow window = GLWindow.create(caps);
+
+ window.setPosition(10, 10);
+ window.setSize(800, 400);
+ window.setTitle("GPU Text Newt Demo 02 - r2t1 msaa0");
+
+ GPUTextGLListener0A textGLListener = new GPUTextGLListener0A(Region.TWO_PASS, window.getWidth()*3, DEBUG, TRACE);
+ textGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(textGLListener);
+
+ window.enablePerfLog(true);
+ window.setVisible(true);
+ // FPSAnimator animator = new FPSAnimator(60);
+ Animator animator = new Animator();
+ animator.add(window);
+ animator.start();
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java
new file mode 100644
index 0000000..909f68b
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java
@@ -0,0 +1,229 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import java.io.IOException;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLException;
+import com.jogamp.graph.curve.opengl.TextRenderer;
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.font.FontFactory;
+import com.jogamp.graph.geom.AABBox;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.opengl.GLWindow;
+
+/**
+ *
+ * GPURendererListenerBase01 Keys:
+ * - 1/2: zoom in/out
+ * - 6/7: 2nd pass texture size
+ * - 0/9: rotate
+ * - v: toggle v-sync
+ * - s: screenshot
+ *
+ * Additional Keys:
+ * - 3/4: font +/-
+ * - h: toogle draw 'font set'
+ * - f: toggle draw fps
+ * - space: toggle font (ubuntu/java)
+ * - i: live input text input (CR ends it, backspace supported)
+ */
+public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerBase01 {
+ int fontSet = FontFactory.UBUNTU;
+ Font font;
+
+ boolean drawFontSet = true;
+ boolean drawFPS = true;
+ boolean updateFont = true;
+ int fontSize = 40;
+ final int fontSizeModulo = 100;
+
+ static final String text1 = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ\n0123456789.:,;(*!?/\\\")$%^&-+@~#<>{}[]";
+ static final String text2 = "The quick brown fox jumps over the lazy dog";
+
+ StringBuffer userString = new StringBuffer();
+ boolean userInput = false;
+
+ public GPUTextRendererListenerBase01(Vertex.Factory<? extends Vertex> factory, int mode, boolean debug, boolean trace) {
+ super(TextRenderer.create(factory, mode), debug, trace);
+ this.font = FontFactory.get(fontSet).getDefault();
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Demo02 needs to have this set here as well .. hmm ?
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ final TextRenderer textRenderer = (TextRenderer) getRenderer();
+
+ if(drawFPS || drawFontSet || updateMatrix) {
+ final int width = drawable.getWidth();
+ final int height = drawable.getHeight();
+ final GLAnimatorControl animator = drawable.getAnimator();
+ final boolean _drawFPS = drawFPS && null != animator && animator.getTotalFrames()>10;
+
+ if(_drawFPS || drawFontSet) {
+ textRenderer.reshapeOrtho(null, width, height, 0.1f, 7000.0f);
+ }
+ if(_drawFPS) {
+ final float fps = ( animator.getTotalFrames() * 1000.0f ) / (float) animator.getDuration() ;
+ final String fpsS = String.valueOf(fps);
+ final int fpsSp = fpsS.indexOf('.');
+ textRenderer.resetModelview(null);
+ textRenderer.translate(gl, 0, 0, -6000);
+ textRenderer.renderString3D(gl, font, fpsS.substring(0, fpsSp+2), getPosition(), fontSize, getTexSize());
+ }
+ if(drawFontSet) {
+ textRenderer.resetModelview(null);
+ final AABBox box = font.getStringBounds(font.getName(), fontSize/4);
+ final int dx = width-(int)box.getWidth()-2;
+ final int dy = height-(int)box.getHeight()-2;
+ textRenderer.translate(gl, dx, dy, -6000);
+ textRenderer.renderString3D(gl, font, font.getName(), getPosition(), fontSize/4, getTexSize());
+ textRenderer.translate(gl, -dx, -20, 0);
+ textRenderer.renderString3D(gl, font, text1, getPosition(), fontSize, getTexSize());
+ }
+ if(_drawFPS || drawFontSet) {
+ textRenderer.reshapePerspective(null, 45.0f, width, height, 0.1f, 7000.0f);
+ }
+
+ textRenderer.resetModelview(null);
+ textRenderer.translate(null, getXTran(), getYTran(), getZoom());
+ textRenderer.rotate(gl, getAngle(), 0, 1, 0);
+ updateMatrix = false;
+ }
+
+ if(!userInput) {
+ textRenderer.renderString3D(gl, font, text2, getPosition(), fontSize, getTexSize());
+ } else {
+ textRenderer.renderString3D(gl, font, userString.toString(), getPosition(), fontSize, getTexSize());
+ }
+ }
+
+ public void fontIncr(int v) {
+ fontSize = Math.abs((fontSize + v) % fontSizeModulo) ;
+ updateFont = true;
+ dumpMatrix(true);
+ }
+
+ public void nextFontSet() {
+ fontSet = ( fontSet == FontFactory.UBUNTU ) ? FontFactory.JAVA : FontFactory.UBUNTU ;
+ font = FontFactory.get(fontSet).getDefault();
+ }
+
+ public void setFontSet(int set, int family, int stylebits) {
+ fontSet = set;
+ font = FontFactory.get(fontSet).get(family, stylebits);
+ }
+
+ public boolean isUserInputMode() { return userInput; }
+
+ void dumpMatrix(boolean bbox) {
+ System.err.println("Matrix: " + getXTran() + "/" + getYTran() + " x"+getZoom() + " @"+getAngle() +" fontSize "+fontSize);
+ if(bbox) {
+ System.err.println("bbox: "+font.getStringBounds(text2, fontSize));
+ }
+ }
+
+ KeyAction keyAction = null;
+
+ @Override
+ public void attachInputListenerTo(GLWindow window) {
+ if ( null == keyAction ) {
+ keyAction = new KeyAction();
+ window.addKeyListener(keyAction);
+ super.attachInputListenerTo(window);
+ }
+
+ }
+
+ @Override
+ public void detachFrom(GLWindow window) {
+ super.detachFrom(window);
+ if ( null == keyAction ) {
+ return;
+ }
+ window.removeKeyListener(keyAction);
+ }
+
+ public void printScreen(GLAutoDrawable drawable, String dir, String tech, boolean exportAlpha) throws GLException, IOException {
+ printScreen(drawable, dir, tech, font.getName(), exportAlpha);
+ }
+
+ public class KeyAction implements KeyListener {
+ public void keyPressed(KeyEvent arg0) {
+ if(userInput) {
+ return;
+ }
+
+ if(arg0.getKeyCode() == KeyEvent.VK_3){
+ fontIncr(10);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_4){
+ fontIncr(-10);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_H) {
+ drawFontSet = !drawFontSet;
+ System.err.println("Draw font set: "+drawFontSet);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_F){
+ drawFPS = !drawFPS;
+ System.err.println("Draw FPS: "+drawFPS);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_SPACE) {
+ nextFontSet();
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_I){
+ userInput = true;
+ setIgnoreInput(true);
+ }
+ }
+ public void keyTyped(KeyEvent arg0) {
+ if(userInput) {
+ char c = arg0.getKeyChar();
+
+ System.err.println(arg0);
+ if(c == 0x08) {
+ userString.deleteCharAt(userString.length()-1);
+ } else if(c == 0x0d) {
+ userInput = false;
+ setIgnoreInput(true);
+ } else {
+ userString.append(c);
+ }
+ }
+ }
+ public void keyReleased(KeyEvent arg0) {}
+ }
+} \ No newline at end of file
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/MSAATool.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/MSAATool.java
new file mode 100644
index 0000000..5975e09
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/MSAATool.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilitiesImmutable;
+
+public class MSAATool {
+ public static void dump(GLAutoDrawable drawable) {
+ float[] vf = new float[] { 0f };
+ byte[] vb = new byte[] { 0 };
+ int[] vi = new int[] { 0, 0 };
+
+ System.out.println("GL MSAA SETUP:");
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ GLCapabilitiesImmutable caps = drawable.getChosenGLCapabilities();
+ System.out.println(" Caps realised "+caps);
+ System.out.println(" Caps sample buffers "+caps.getSampleBuffers()+", samples "+caps.getNumSamples());
+
+ // default TRUE
+ System.out.println(" GL MULTISAMPLE "+gl.glIsEnabled(GL2ES2.GL_MULTISAMPLE));
+ // sample buffers min 0, same as GLX_SAMPLE_BUFFERS_ARB or WGL_SAMPLE_BUFFERS_ARB
+ gl.glGetIntegerv(GL2GL3.GL_SAMPLE_BUFFERS, vi, 0);
+ // samples min 0
+ gl.glGetIntegerv(GL2GL3.GL_SAMPLES, vi, 1);
+ System.out.println(" GL SAMPLE_BUFFERS "+vi[0]+", SAMPLES "+vi[1]);
+
+ System.out.println("GL CSAA SETUP:");
+ // default FALSE
+ System.out.println(" GL SAMPLE COVERAGE "+gl.glIsEnabled(GL2GL3.GL_SAMPLE_COVERAGE));
+ // default FALSE
+ System.out.println(" GL SAMPLE_ALPHA_TO_COVERAGE "+gl.glIsEnabled(GL2GL3.GL_SAMPLE_ALPHA_TO_COVERAGE));
+ // default FALSE
+ System.out.println(" GL SAMPLE_ALPHA_TO_ONE "+gl.glIsEnabled(GL2GL3.GL_SAMPLE_ALPHA_TO_ONE));
+ // default FALSE, value 1, invert false
+ gl.glGetFloatv(GL2GL3.GL_SAMPLE_COVERAGE_VALUE, vf, 0);
+ gl.glGetBooleanv(GL2GL3.GL_SAMPLE_COVERAGE_INVERT, vb, 0);
+ System.out.println(" GL SAMPLE_COVERAGE "+gl.glIsEnabled(GL2GL3.GL_SAMPLE_COVERAGE) +
+ ": SAMPLE_COVERAGE_VALUE "+vf[0]+
+ ", SAMPLE_COVERAGE_INVERT "+vb[0]);
+ }
+}
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/ReadBufferUtil.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/ReadBufferUtil.java
new file mode 100644
index 0000000..172eef4
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/ReadBufferUtil.java
@@ -0,0 +1,109 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import com.jogamp.opengl.util.GLBuffers;
+import java.nio.*;
+import javax.media.opengl.*;
+
+import com.jogamp.opengl.util.texture.Texture;
+import com.jogamp.opengl.util.texture.TextureData;
+
+public class ReadBufferUtil {
+ protected int readPixelSizeLast = 0;
+ protected Buffer readPixelBuffer = null;
+ protected TextureData readTextureData = null;
+ protected Texture readTexture = new Texture(GL.GL_TEXTURE_2D);
+
+ public Buffer getPixelBuffer() { return readPixelBuffer; }
+ public void rewindPixelBuffer() { readPixelBuffer.rewind(); }
+
+ public TextureData getTextureData() { return readTextureData; }
+ public Texture getTexture() { return readTexture; }
+
+ public boolean isValid() {
+ return null!=readTexture && null!=readTextureData && null!=readPixelBuffer ;
+ }
+
+ public void fetchOffscreenTexture(GLDrawable drawable, GL gl) {
+ int readPixelSize = drawable.getWidth() * drawable.getHeight() * 3 ; // RGB
+ boolean newData = false;
+ if(readPixelSize>readPixelSizeLast) {
+ readPixelBuffer = GLBuffers.newDirectGLBuffer(GL.GL_UNSIGNED_BYTE, readPixelSize);
+ readPixelSizeLast = readPixelSize ;
+ try {
+ readTextureData = new TextureData(
+ gl.getGLProfile(),
+ // gl.isGL2GL3()?gl.GL_RGBA:gl.GL_RGB,
+ GL.GL_RGB,
+ drawable.getWidth(), drawable.getHeight(),
+ 0,
+ GL.GL_RGB,
+ GL.GL_UNSIGNED_BYTE,
+ false, false,
+ false /* flip */,
+ readPixelBuffer,
+ null /* Flusher */);
+ newData = true;
+ } catch (Exception e) {
+ readTextureData = null;
+ readPixelBuffer = null;
+ readPixelSizeLast = 0;
+ throw new RuntimeException("can not fetch offscreen texture", e);
+ }
+ }
+ if(null!=readPixelBuffer) {
+ readPixelBuffer.clear();
+ gl.glReadPixels(0, 0, drawable.getWidth(), drawable.getHeight(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE, readPixelBuffer);
+ readPixelBuffer.rewind();
+ if(newData) {
+ readTexture.updateImage(readTextureData);
+ } else {
+ readTexture.updateSubImage(readTextureData, 0,
+ 0, 0, // src offset
+ 0, 0, // dst offset
+ drawable.getWidth(), drawable.getHeight());
+ }
+ readPixelBuffer.rewind();
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void dispose() {
+ readTexture.dispose();
+ readTextureData = null;
+ if(null != readPixelBuffer) {
+ readPixelBuffer.clear();
+ readPixelBuffer = null;
+ }
+ readPixelSizeLast = 0;
+ }
+
+}
+
diff --git a/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/Screenshot.java b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/Screenshot.java
new file mode 100644
index 0000000..e0c304e
--- /dev/null
+++ b/turtle2d/src/com/jogamp/opengl/test/junit/graph/demos/Screenshot.java
@@ -0,0 +1,39 @@
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GLAutoDrawable;
+
+import com.jogamp.opengl.util.texture.TextureIO;
+
+public class Screenshot {
+
+ ReadBufferUtil readBufferUtil = new ReadBufferUtil();
+
+ public void dispose() {
+ readBufferUtil.dispose();
+ }
+
+ public void surface2File(GLAutoDrawable drawable, String filename) {
+ GL gl = drawable.getGL();
+ // FIXME glFinish() is an expensive paranoia sync, should not be necessary due to spec
+ gl.glFinish();
+ readBufferUtil.fetchOffscreenTexture(drawable, gl);
+ gl.glFinish();
+ try {
+ surface2File(filename);
+ } catch (IOException ex) {
+ throw new RuntimeException("can not write survace to file", ex);
+ }
+ }
+
+ void surface2File(String filename) throws IOException {
+ File file = new File(filename);
+ TextureIO.write(readBufferUtil.getTextureData(), file);
+ System.err.println("Wrote: " + file.getAbsolutePath() + ", ...");
+ readBufferUtil.rewindPixelBuffer();
+ }
+
+}
diff --git a/turtle2d/src/jogamp/graph/curve/opengl/RegionRendererImpl01.java b/turtle2d/src/jogamp/graph/curve/opengl/RegionRendererImpl01.java
new file mode 100755
index 0000000..c1f293f
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/opengl/RegionRendererImpl01.java
@@ -0,0 +1,206 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.curve.opengl;
+
+import java.nio.FloatBuffer;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLUniformData;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.opengl.util.glsl.ShaderCode;
+import com.jogamp.opengl.util.glsl.ShaderProgram;
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+
+public class RegionRendererImpl01 extends RegionRenderer {
+ /**Sharpness is equivalent to the value of t value of texture coord
+ * on the off-curve vertex. The high value of sharpness will
+ * result in high curvature.
+ */
+ private GLUniformData mgl_sharpness = new GLUniformData("p1y", 0.5f);
+ GLUniformData mgl_alpha = new GLUniformData("g_alpha", 1.0f);
+ private GLUniformData mgl_color = new GLUniformData("g_color", 3, FloatBuffer.allocate(3));
+ private GLUniformData mgl_strength = new GLUniformData("a_strength", 3.0f);
+
+ public RegionRendererImpl01(Vertex.Factory<? extends Vertex> factory, int type) {
+ super(factory, type);
+ }
+
+ protected boolean initImpl(GL2ES2 gl) {
+ boolean VBOsupported = gl.isFunctionAvailable("glGenBuffers") &&
+ gl.isFunctionAvailable("glBindBuffer") &&
+ gl.isFunctionAvailable("glBufferData") &&
+ gl.isFunctionAvailable("glDrawElements") &&
+ gl.isFunctionAvailable("glVertexAttribPointer") &&
+ gl.isFunctionAvailable("glDeleteBuffers");
+
+ if(DEBUG) {
+ System.err.println("RegionRenderer: VBO Supported = " + VBOsupported);
+ }
+
+ if(!VBOsupported){
+ return false;
+ }
+
+ gl.glEnable(GL2ES2.GL_BLEND);
+ gl.glBlendFunc(GL2ES2.GL_SRC_ALPHA, GL2ES2.GL_ONE_MINUS_SRC_ALPHA);
+
+ ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, RegionRendererImpl01.class,
+ "shader", "shader/bin", "curverenderer01");
+ ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, RegionRendererImpl01.class,
+ "shader", "shader/bin", "curverenderer01");
+
+ ShaderProgram sp = new ShaderProgram();
+ sp.add(rsVp);
+ sp.add(rsFp);
+
+ if(!sp.link(gl, System.err)) {
+ throw new GLException("RegionRenderer: Couldn't link program: "+sp);
+ }
+
+ st = new ShaderState();
+ st.attachShaderProgram(gl, sp);
+ gl.glBindAttribLocation(sp.id(), 0, "v_position");
+ gl.glBindAttribLocation(sp.id(), 1, "texCoord");
+
+ st.glUseProgram(gl, true);
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmvMatrix.glLoadIdentity();
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ resetModelview(null);
+
+ mgl_PMVMatrix = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf());
+ if(!st.glUniform(gl, mgl_PMVMatrix)) {
+ if(DEBUG){
+ System.err.println("Error setting PMVMatrix in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_sharpness)) {
+ if(DEBUG){
+ System.err.println("Error setting sharpness in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_alpha)) {
+ if(DEBUG){
+ System.err.println("Error setting global alpha in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_color)) {
+ if(DEBUG){
+ System.err.println("Error setting global color in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_strength)) {
+ System.err.println("Error setting antialias strength in shader: "+st);
+ }
+
+ if(DEBUG) {
+ System.err.println("RegionRendererImpl01 initialized: " + Thread.currentThread()+" "+st);
+ }
+ return true;
+ }
+
+ @Override
+ protected void disposeImpl(GL2ES2 gl) {
+ }
+
+
+ @Override
+ public float getAlpha() {
+ return mgl_alpha.floatValue();
+ }
+
+ @Override
+ public void setAlpha(GL2ES2 gl, float alpha_t) {
+ mgl_alpha.setData(alpha_t);
+ if(null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_alpha);
+ }
+ }
+
+ @Override
+ public void setColor(GL2ES2 gl, float r, float g, float b){
+ FloatBuffer fb = (FloatBuffer) mgl_color.getBuffer();
+ fb.put(0, r);
+ fb.put(1, r);
+ fb.put(2, r);
+ if(null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_color);
+ }
+ }
+
+
+ @Override
+ public void renderOutlineShape(GL2ES2 gl, OutlineShape outlineShape, float[] position, int texSize) {
+ if(!isInitialized()){
+ throw new GLException("RegionRendererImpl01: not initialized!");
+ }
+ int hashCode = getHashCode(outlineShape);
+ Region region = regions.get(hashCode);
+
+ if(null == region) {
+ region = createRegion(gl, outlineShape, mgl_sharpness.floatValue());
+ regions.put(hashCode, region);
+ }
+ region.render(pmvMatrix, vp_width, vp_height, texSize);
+ }
+
+ @Override
+ public void renderOutlineShapes(GL2ES2 gl, OutlineShape[] outlineShapes, float[] position, int texSize) {
+ if(!isInitialized()){
+ throw new GLException("RegionRendererImpl01: not initialized!");
+ }
+
+ int hashCode = getHashCode(outlineShapes);
+ Region region = regions.get(hashCode);
+
+ if(null == region) {
+ region = createRegion(gl, outlineShapes, mgl_sharpness.floatValue());
+ regions.put(hashCode, region);
+ }
+ region.render(pmvMatrix, vp_width, vp_height, texSize);
+ }
+}
diff --git a/turtle2d/src/jogamp/graph/curve/opengl/TextRendererImpl01.java b/turtle2d/src/jogamp/graph/curve/opengl/TextRendererImpl01.java
new file mode 100644
index 0000000..cebe7a1
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/opengl/TextRendererImpl01.java
@@ -0,0 +1,188 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.curve.opengl;
+
+import java.nio.FloatBuffer;
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLUniformData;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+
+import jogamp.graph.curve.text.GlyphString;
+
+import com.jogamp.graph.curve.opengl.TextRenderer;
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.opengl.util.glsl.ShaderCode;
+import com.jogamp.opengl.util.glsl.ShaderProgram;
+
+public class TextRendererImpl01 extends TextRenderer {
+ /**Sharpness is equivalent to the value of t value of texture coord
+ * on the off-curve vertex. The high value of sharpness will
+ * result in high curvature.
+ */
+ private GLUniformData mgl_sharpness = new GLUniformData("p1y", 0.5f);
+ GLUniformData mgl_alpha = new GLUniformData("g_alpha", 1.0f);
+ private GLUniformData mgl_color = new GLUniformData("g_color", 3, FloatBuffer.allocate(3));
+ private GLUniformData mgl_strength = new GLUniformData("a_strength", 1.8f);
+
+ public TextRendererImpl01(Vertex.Factory<? extends Vertex> factory, int type) {
+ super(factory, type);
+ }
+
+ @Override
+ protected boolean initImpl(GL2ES2 gl){
+ boolean VBOsupported = gl.isFunctionAvailable("glGenBuffers") &&
+ gl.isFunctionAvailable("glBindBuffer") &&
+ gl.isFunctionAvailable("glBufferData") &&
+ gl.isFunctionAvailable("glDrawElements") &&
+ gl.isFunctionAvailable("glVertexAttribPointer") &&
+ gl.isFunctionAvailable("glDeleteBuffers");
+
+ if(DEBUG) {
+ System.err.println("TextRendererImpl01: VBO Supported = " + VBOsupported);
+ }
+
+ if(!VBOsupported){
+ return false;
+ }
+
+ gl.glEnable(GL2ES2.GL_BLEND);
+ gl.glBlendFunc(GL2ES2.GL_SRC_ALPHA, GL2ES2.GL_ONE_MINUS_SRC_ALPHA);
+
+ ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, TextRendererImpl01.class,
+ "shader", "shader/bin", "curverenderer01");
+ ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, TextRendererImpl01.class,
+ "shader", "shader/bin", "curverenderer01");
+
+ ShaderProgram sp = new ShaderProgram();
+ sp.add(rsVp);
+ sp.add(rsFp);
+
+ if(!sp.link(gl, System.err)) {
+ throw new GLException("TextRendererImpl01: Couldn't link program: "+sp);
+ }
+
+ st.attachShaderProgram(gl, sp);
+ gl.glBindAttribLocation(sp.id(), 0, "v_position");
+ gl.glBindAttribLocation(sp.id(), 1, "texCoord");
+
+ st.glUseProgram(gl, true);
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmvMatrix.glLoadIdentity();
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ resetModelview(null);
+
+ mgl_PMVMatrix = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf());
+ if(!st.glUniform(gl, mgl_PMVMatrix)) {
+ if(DEBUG){
+ System.err.println("Error setting PMVMatrix in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_sharpness)) {
+ if(DEBUG){
+ System.err.println("Error setting sharpness in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_alpha)) {
+ if(DEBUG){
+ System.err.println("Error setting global alpha in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_color)) {
+ if(DEBUG){
+ System.err.println("Error setting global color in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_strength)) {
+ System.err.println("Error setting antialias strength in shader: "+st);
+ }
+
+ if(DEBUG) {
+ System.err.println("TextRendererImpl01 initialized: " + Thread.currentThread()+" "+st);
+ }
+ return true;
+ }
+
+ @Override
+ protected void disposeImpl(GL2ES2 gl) {
+ }
+
+ @Override
+ public float getAlpha() {
+ return mgl_alpha.floatValue();
+ }
+
+ @Override
+ public void setAlpha(GL2ES2 gl, float alpha_t) {
+ mgl_alpha.setData(alpha_t);
+ if(null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_alpha);
+ }
+ }
+
+ @Override
+ public void setColor(GL2ES2 gl, float r, float g, float b){
+ FloatBuffer fb = (FloatBuffer) mgl_color.getBuffer();
+ fb.put(0, r);
+ fb.put(1, r);
+ fb.put(2, r);
+ if(null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_color);
+ }
+ }
+
+ @Override
+ public void renderString3D(GL2ES2 gl, Font font, String str, float[] position, int fontSize, int texSize) {
+ if(!isInitialized()){
+ throw new GLException("TextRendererImpl01: not initialized!");
+ }
+ GlyphString glyphString = getCachedGlyphString(font, str, fontSize);
+ if(null == glyphString) {
+ glyphString = createString(gl, font, fontSize, str, mgl_sharpness.floatValue());
+ addCachedGlyphString(font, str, fontSize, glyphString);
+ }
+
+ glyphString.renderString3D(pmvMatrix, vp_width, vp_height, texSize);
+ }
+
+}
diff --git a/turtle2d/src/jogamp/graph/curve/opengl/VBORegion2PES2.java b/turtle2d/src/jogamp/graph/curve/opengl/VBORegion2PES2.java
new file mode 100644
index 0000000..c7c370f
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/opengl/VBORegion2PES2.java
@@ -0,0 +1,385 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.curve.opengl;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
+
+import javax.media.opengl.GL2ES2;
+// FIXME: Subsume GL2GL3.GL_DRAW_FRAMEBUFFER -> GL2ES2.GL_DRAW_FRAMEBUFFER !
+import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLUniformData;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+
+import com.jogamp.common.nio.Buffers;
+
+import com.jogamp.graph.geom.AABBox;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Vertex;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.opengl.util.PMVMatrix;
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+public class VBORegion2PES2 implements Region{
+ private int numVertices = 0;
+ private IntBuffer vboIds;
+
+ private IntBuffer t_vboIds;
+
+ private ArrayList<Triangle> triangles = new ArrayList<Triangle>();
+ private ArrayList<Vertex> vertices = new ArrayList<Vertex>();
+ private GLContext context;
+
+ private int numBuffers = 3;
+
+ private boolean flipped = false;
+
+ private boolean dirty = false;
+
+ private AABBox box = null;
+ private int[] texture = { 0 } ;
+ private int[] fbo = { 0 } ;
+ private int[] rbo_depth = { 0 } ;
+ private boolean texInitialized = false;
+
+ private int tex_width_c = 0;
+ private int tex_height_c = 0;
+
+ private ShaderState st;
+
+ public VBORegion2PES2(GLContext context, ShaderState st){
+ this.context =context;
+ this.st = st;
+ }
+
+ public void update(){
+ box = new AABBox();
+
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ ShortBuffer indicies = Buffers.newDirectShortBuffer(triangles.size() * 3);
+
+ for(Triangle t:triangles){
+ if(t.getVertices()[0].getId() == Integer.MAX_VALUE){
+ t.getVertices()[0].setId(numVertices++);
+ t.getVertices()[1].setId(numVertices++);
+ t.getVertices()[2].setId(numVertices++);
+
+ vertices.add(t.getVertices()[0]);
+ vertices.add(t.getVertices()[1]);
+ vertices.add(t.getVertices()[2]);
+
+ indicies.put((short) t.getVertices()[0].getId());
+ indicies.put((short) t.getVertices()[1].getId());
+ indicies.put((short) t.getVertices()[2].getId());
+ }
+ else{
+ Vertex v1 = t.getVertices()[0];
+ Vertex v2 = t.getVertices()[1];
+ Vertex v3 = t.getVertices()[2];
+
+ indicies.put((short) v1.getId());
+ indicies.put((short) v2.getId());
+ indicies.put((short) v3.getId());
+ }
+ }
+ indicies.rewind();
+
+ FloatBuffer verticesBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 3);
+ for(Vertex v:vertices){
+ verticesBuffer.put(v.getX());
+ if(flipped){
+ verticesBuffer.put(-1*v.getY());
+ }
+ else{
+ verticesBuffer.put(v.getY());
+ }
+ verticesBuffer.put(v.getZ());
+ if(flipped){
+ box.resize(v.getX(), -1*v.getY(), v.getZ());
+ }
+ else{
+ box.resize(v.getX(), v.getY(), v.getZ());
+ }
+ }
+ verticesBuffer.rewind();
+
+ FloatBuffer texCoordBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 2);
+ for(Vertex v:vertices){
+ float[] tex = v.getTexCoord();
+ texCoordBuffer.put(tex[0]);
+ texCoordBuffer.put(tex[1]);
+ }
+ texCoordBuffer.rewind();
+
+ vboIds = IntBuffer.allocate(numBuffers);
+ gl.glGenBuffers(numBuffers, vboIds);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(0)); // vertices
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, numVertices * 3 * Buffers.SIZEOF_FLOAT, verticesBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(1)); //texture
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, numVertices * 2 * Buffers.SIZEOF_FLOAT, texCoordBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2)); //triangles
+ gl.glBufferData(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, triangles.size()* 3 * Buffers.SIZEOF_SHORT, indicies, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ dirty = false;
+ }
+
+ public void render(PMVMatrix matrix, int vp_width, int vp_height, int width){
+ if(null == matrix || vp_width <=0 || vp_height <= 0 || width <= 0){
+ renderRegion();
+ }
+ else {
+ if(width != tex_width_c){
+ texInitialized = false;
+ tex_width_c = width;
+ }
+ if(!texInitialized){
+ initFBOTexture(matrix,vp_width, vp_height);
+ texInitialized = true;
+ }
+// System.out.println("Scale: " + matrix.glGetMatrixf().get(1+4*3) +" " + matrix.glGetMatrixf().get(2+4*3));
+ renderTexture(matrix, vp_width, vp_height);
+ }
+ }
+
+ private void renderTexture(PMVMatrix matrix, int width, int hight){
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ gl.glViewport(0, 0, width, hight);
+ if(!st.glUniform(gl, new GLUniformData("mgl_PMVMatrix", 4, 4, matrix.glGetPMvMatrixf()))){
+ System.out.println("Cnt set tex based mat");
+ }
+ gl.glEnable(GL2ES2.GL_TEXTURE_2D);
+ gl.glActiveTexture(GL2ES2.GL_TEXTURE0);
+ gl.glBindTexture(GL2ES2.GL_TEXTURE_2D, texture[0]);
+
+ st.glUniform(gl, new GLUniformData("texture", texture[0]));
+ int loc = gl.glGetUniformLocation(st.shaderProgram().id(), "texture");
+ gl.glUniform1i(loc, 0);
+
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, t_vboIds.get(0));
+ gl.glEnableVertexAttribArray(VERTEX_ATTR_IDX);
+ gl.glVertexAttribPointer(VERTEX_ATTR_IDX, 3, GL2ES2.GL_FLOAT, false, 3 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, t_vboIds.get(1));
+ gl.glEnableVertexAttribArray(TEXCOORD_ATTR_IDX);
+ gl.glVertexAttribPointer(TEXCOORD_ATTR_IDX, 2, GL2ES2.GL_FLOAT, false, 2 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, t_vboIds.get(2));
+ gl.glDrawElements(GL2ES2.GL_TRIANGLES, 2 * 3, GL2ES2.GL_UNSIGNED_SHORT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+ }
+
+ private void setupBoundingBuffers(){
+ GL2ES2 gl = context.getGL().getGL2ES2();
+
+ ShortBuffer indicies = Buffers.newDirectShortBuffer(6);
+ indicies.put((short) 0); indicies.put((short) 1); indicies.put((short) 3);
+ indicies.put((short) 1); indicies.put((short) 2); indicies.put((short) 3);
+ indicies.rewind();
+
+ FloatBuffer verticesBuffer = Buffers.newDirectFloatBuffer(4 * 3);
+ FloatBuffer texCoordBuffer = Buffers.newDirectFloatBuffer(4 * 2);
+
+ verticesBuffer.put(box.getLow()[0]);
+ verticesBuffer.put(box.getLow()[1]);
+ verticesBuffer.put(box.getLow()[2]);
+ texCoordBuffer.put(5);
+ texCoordBuffer.put(5);
+
+ verticesBuffer.put(box.getLow()[0]);
+ verticesBuffer.put(box.getHigh()[1]);
+ verticesBuffer.put(box.getLow()[2]);
+
+ texCoordBuffer.put(5);
+ texCoordBuffer.put(6);
+
+ verticesBuffer.put(box.getHigh()[0]);
+ verticesBuffer.put(box.getHigh()[1]);
+ verticesBuffer.put(box.getLow()[2]);
+
+ texCoordBuffer.put(6);
+ texCoordBuffer.put(6);
+
+ verticesBuffer.put(box.getHigh()[0]);
+ verticesBuffer.put(box.getLow()[1]);
+ verticesBuffer.put(box.getLow()[2]);
+
+ texCoordBuffer.put(6);
+ texCoordBuffer.put(5);
+
+ verticesBuffer.rewind();
+ texCoordBuffer.rewind();
+
+ t_vboIds = IntBuffer.allocate(3);
+ gl.glGenBuffers(numBuffers, t_vboIds);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, t_vboIds.get(0)); // vertices
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, 4 * 3 * Buffers.SIZEOF_FLOAT, verticesBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, t_vboIds.get(1)); //texture
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, 4 * 2 * Buffers.SIZEOF_FLOAT, texCoordBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, t_vboIds.get(2)); //triangles
+ gl.glBufferData(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, 4 * 3 * Buffers.SIZEOF_SHORT, indicies, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ private void initFBOTexture(PMVMatrix m, int width, int hight){
+ tex_height_c = (int)(tex_width_c*box.getHeight()/box.getWidth());
+ // tex_height_c = tex_width_c;
+ System.out.println("FBO Size: "+tex_height_c+"x"+tex_width_c);
+ System.out.println("FBO Scale: " + m.glGetMatrixf().get(0) +" " + m.glGetMatrixf().get(5));
+ GL2ES2 gl = context.getGL().getGL2ES2();
+
+ if(fbo[0] > 0) {
+ gl.glDeleteFramebuffers(1, fbo, 0);
+ fbo[0] = 0;
+ }
+ if(texture[0]>0) {
+ gl.glDeleteTextures(1, texture, 0);
+ texture[0] = 0;
+ }
+
+ gl.glGenFramebuffers(1, fbo, 0);
+ gl.glGenTextures(1, texture, 0);
+ gl.glGenRenderbuffers(1,rbo_depth, 0);
+ System.out.println("FBO: fbo " + fbo[0] + ", tex " + texture[0] + ", depth " + rbo_depth[0]);
+
+ gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, fbo[0]);
+ gl.glBindTexture(GL2ES2.GL_TEXTURE_2D, texture[0]);
+ gl.glTexImage2D(GL2ES2.GL_TEXTURE_2D, 0, GL2ES2.GL_RGBA, tex_width_c,
+ tex_height_c, 0, GL2ES2.GL_RGBA, GL2ES2.GL_UNSIGNED_BYTE, null);
+
+ gl.glTexParameterf(GL2ES2.GL_TEXTURE_2D, GL2ES2.GL_TEXTURE_MIN_FILTER, GL2ES2.GL_LINEAR);
+ gl.glTexParameterf(GL2ES2.GL_TEXTURE_2D, GL2ES2.GL_TEXTURE_MAG_FILTER, GL2ES2.GL_LINEAR);
+ gl.glTexParameterf(GL2ES2.GL_TEXTURE_2D, GL2ES2.GL_TEXTURE_WRAP_S, GL2ES2.GL_CLAMP_TO_EDGE);
+ gl.glTexParameterf(GL2ES2.GL_TEXTURE_2D, GL2ES2.GL_TEXTURE_WRAP_T, GL2ES2.GL_CLAMP_TO_EDGE);
+
+ gl.glFramebufferTexture2D(GL2GL3.GL_DRAW_FRAMEBUFFER, GL2ES2.GL_COLOR_ATTACHMENT0,
+ GL2ES2.GL_TEXTURE_2D, texture[0], 0);
+
+ // Set up the depth buffer
+ gl.glBindRenderbuffer(GL2ES2.GL_RENDERBUFFER, rbo_depth[0]);
+ gl.glRenderbufferStorage(GL2ES2.GL_RENDERBUFFER, GL2ES2.GL_DEPTH_COMPONENT, tex_width_c, tex_height_c);
+ gl.glFramebufferRenderbuffer(GL2ES2.GL_FRAMEBUFFER, GL2ES2.GL_DEPTH_COMPONENT, GL2ES2.GL_RENDERBUFFER, rbo_depth[0]);
+
+ int status = gl.glCheckFramebufferStatus(GL2ES2.GL_FRAMEBUFFER);
+ if(status != GL2ES2.GL_FRAMEBUFFER_COMPLETE){
+ System.err.println("Cant Create R2T pass!");
+ }
+
+ //render texture
+ PMVMatrix tex_matrix = new PMVMatrix();
+ gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, fbo[0]);
+ gl.glViewport(0, 0, tex_width_c, tex_height_c);
+ tex_matrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ tex_matrix.glLoadIdentity();
+ tex_matrix.glOrthof(box.getLow()[0], box.getHigh()[0], box.getLow()[1], box.getHigh()[1], -1, 1);
+
+ if(!st.glUniform(gl, new GLUniformData("mgl_PMVMatrix", 4, 4, tex_matrix.glGetPMvMatrixf()))){
+ System.out.println("Cnt set tex based mat");
+ }
+
+ gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ gl.glClear(GL2ES2.GL_COLOR_BUFFER_BIT | GL2ES2.GL_DEPTH_BUFFER_BIT);
+ renderRegion();
+
+ gl.glBindFramebuffer(GL2ES2.GL_FRAMEBUFFER, 0);
+ gl.glBindTexture(GL2ES2.GL_TEXTURE_2D, 0);
+
+ setupBoundingBuffers();
+ }
+
+ private void renderRegion(){
+ GL2ES2 gl = context.getGL().getGL2ES2();
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(0));
+ gl.glEnableVertexAttribArray(VERTEX_ATTR_IDX);
+ gl.glVertexAttribPointer(VERTEX_ATTR_IDX, 3, GL2ES2.GL_FLOAT, false, 3 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(1));
+ gl.glEnableVertexAttribArray(TEXCOORD_ATTR_IDX);
+ gl.glVertexAttribPointer(TEXCOORD_ATTR_IDX, 2, GL2ES2.GL_FLOAT, false, 2 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2));
+ gl.glDrawElements(GL2ES2.GL_TRIANGLES, triangles.size() * 3, GL2ES2.GL_UNSIGNED_SHORT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+ }
+
+ public void addTriangles(ArrayList<Triangle> tris) {
+ triangles.addAll(tris);
+ dirty = true;
+ }
+
+ public int getNumVertices(){
+ return numVertices;
+ }
+
+ public void addVertices(ArrayList<Vertex> verts){
+ vertices.addAll(verts);
+ numVertices = vertices.size();
+ dirty = true;
+ }
+
+ public boolean isDirty(){
+ return dirty;
+ }
+
+ public void destroy() {
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ gl.glDeleteBuffers(numBuffers, vboIds);
+ gl.glDeleteFramebuffers(1, fbo, 0);
+ fbo[0] = 0;
+ gl.glDeleteTextures(1, texture, 0);
+ texture[0] = 0;
+ gl.glDeleteRenderbuffers(1, rbo_depth, 0);
+ rbo_depth[0] = 0;
+ }
+
+ public boolean isFlipped() {
+ return flipped;
+ }
+
+ public void setFlipped(boolean flipped) {
+ this.flipped = flipped;
+ }
+}
diff --git a/turtle2d/src/jogamp/graph/curve/opengl/VBORegionSPES2.java b/turtle2d/src/jogamp/graph/curve/opengl/VBORegionSPES2.java
new file mode 100644
index 0000000..701549d
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/opengl/VBORegionSPES2.java
@@ -0,0 +1,185 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.curve.opengl;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLContext;
+
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.opengl.util.PMVMatrix;
+
+public class VBORegionSPES2 implements Region{
+ private int numVertices = 0;
+ private IntBuffer vboIds;
+
+ private ArrayList<Triangle> triangles = new ArrayList<Triangle>();
+ private ArrayList<Vertex> vertices = new ArrayList<Vertex>();
+
+ private GLContext context;
+
+ private int numBuffers = 3;
+
+ private boolean flipped = false;
+ private boolean dirty = false;
+
+ public VBORegionSPES2(GLContext context){
+ this.context =context;
+ }
+
+ public void update(){
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ ShortBuffer indicies = Buffers.newDirectShortBuffer(triangles.size() * 3);
+
+ for(Triangle t:triangles){
+ final Vertex[] t_vertices = t.getVertices();
+
+ if(t_vertices[0].getId() == Integer.MAX_VALUE){
+ t_vertices[0].setId(numVertices++);
+ t_vertices[1].setId(numVertices++);
+ t_vertices[2].setId(numVertices++);
+
+ vertices.add(t.getVertices()[0]);
+ vertices.add(t.getVertices()[1]);
+ vertices.add(t.getVertices()[2]);
+
+ indicies.put((short) t.getVertices()[0].getId());
+ indicies.put((short) t.getVertices()[1].getId());
+ indicies.put((short) t.getVertices()[2].getId());
+ }
+ else{
+ Vertex v1 = t_vertices[0];
+ Vertex v2 = t_vertices[1];
+ Vertex v3 = t_vertices[2];
+
+ indicies.put((short) v1.getId());
+ indicies.put((short) v2.getId());
+ indicies.put((short) v3.getId());
+ }
+ }
+ indicies.rewind();
+
+ FloatBuffer verticesBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 3);
+ for(Vertex v:vertices){
+ verticesBuffer.put(v.getX());
+ if(flipped){
+ verticesBuffer.put(-1*v.getY());
+ }
+ else{
+ verticesBuffer.put(v.getY());
+ }
+ verticesBuffer.put(v.getZ());
+ }
+ verticesBuffer.rewind();
+
+ FloatBuffer texCoordBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 2);
+ for(Vertex v:vertices){
+ float[] tex = v.getTexCoord();
+ texCoordBuffer.put(tex[0]);
+ texCoordBuffer.put(tex[1]);
+ }
+ texCoordBuffer.rewind();
+
+ vboIds = IntBuffer.allocate(numBuffers);
+ gl.glGenBuffers(numBuffers, vboIds);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(0)); // vertices
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, numVertices * 3 * Buffers.SIZEOF_FLOAT, verticesBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(1)); //texture
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, numVertices * 2 * Buffers.SIZEOF_FLOAT, texCoordBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2)); //triangles
+ gl.glBufferData(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, triangles.size()* 3 * Buffers.SIZEOF_SHORT, indicies, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ dirty = false;
+ }
+
+ private void render() {
+ GL2ES2 gl = context.getGL().getGL2ES2();
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(0));
+ gl.glEnableVertexAttribArray(VERTEX_ATTR_IDX);
+ gl.glVertexAttribPointer(VERTEX_ATTR_IDX, 3, GL2ES2.GL_FLOAT, false, 3 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(1));
+ gl.glEnableVertexAttribArray(TEXCOORD_ATTR_IDX);
+ gl.glVertexAttribPointer(TEXCOORD_ATTR_IDX, 2, GL2ES2.GL_FLOAT, false, 2 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2));
+ gl.glDrawElements(GL2ES2.GL_TRIANGLES, triangles.size() * 3, GL2ES2.GL_UNSIGNED_SHORT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+ }
+
+ public void render(PMVMatrix matrix, int vp_width, int vp_height, int width){
+ render();
+ }
+
+ public void addTriangles(ArrayList<Triangle> tris) {
+ triangles.addAll(tris);
+ dirty = true;
+ }
+
+ public int getNumVertices(){
+ return numVertices;
+ }
+
+ public void addVertices(ArrayList<Vertex> verts){
+ vertices.addAll(verts);
+ numVertices = vertices.size();
+ dirty = true;
+ }
+
+ public boolean isDirty(){
+ return dirty;
+ }
+
+ public void destroy() {
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ gl.glDeleteBuffers(numBuffers, vboIds);
+ }
+
+ public boolean isFlipped() {
+ return flipped;
+ }
+
+ public void setFlipped(boolean flipped) {
+ this.flipped = flipped;
+ }
+}
diff --git a/turtle2d/src/jogamp/graph/curve/opengl/shader/curverenderer01.fp b/turtle2d/src/jogamp/graph/curve/opengl/shader/curverenderer01.fp
new file mode 100644
index 0000000..2b3a0ce
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/opengl/shader/curverenderer01.fp
@@ -0,0 +1,99 @@
+//#version 100
+
+uniform float p1y;
+uniform float g_alpha;
+uniform vec3 g_color;
+uniform float a_strength;
+
+varying vec2 v_texCoord;
+
+vec3 b_color = vec3(0.0, 0.0, 0.0);
+
+uniform sampler2D texture;
+vec4 weights = vec4(0.075, 0.06, 0.045, 0.025);
+
+void main (void)
+{
+ vec2 rtex = vec2(abs(v_texCoord.x),abs(v_texCoord.y));
+ vec3 c = g_color;
+
+ float alpha = 0.0;
+
+ if((v_texCoord.x == 0.0) && (v_texCoord.y == 0.0)){
+ alpha = g_alpha;
+ }
+ else if((v_texCoord.x >= 5.0)){
+ vec2 dfx = dFdx(v_texCoord);
+ vec2 dfy = dFdy(v_texCoord);
+
+ vec2 size = 1.0/textureSize(texture,0); //version 130
+ rtex -= 5.0;
+ vec4 t = texture2D(texture, rtex)* 0.18;
+
+ t += texture2D(texture, rtex + size*(vec2(1, 0)))*weights.x;
+ t += texture2D(texture, rtex - size*(vec2(1, 0)))*weights.x;
+ t += texture2D(texture, rtex + size*(vec2(0, 1)))*weights.x;
+ t += texture2D(texture, rtex - size*(vec2(0, 1)))*weights.x;
+
+ t += texture2D(texture, rtex + 2.0*size*(vec2(1, 0))) *weights.y;
+ t += texture2D(texture, rtex - 2.0*size*(vec2(1, 0)))*weights.y;
+ t += texture2D(texture, rtex + 2.0*size*(vec2(0, 1)))*weights.y;
+ t += texture2D(texture, rtex - 2.0*size*(vec2(0, 1)))*weights.y;
+
+ t += texture2D(texture, rtex + 3.0*size*(vec2(1, 0))) *weights.z;
+ t += texture2D(texture, rtex - 3.0*size*(vec2(1, 0)))*weights.z;
+ t += texture2D(texture, rtex + 3.0*size*(vec2(0, 1)))*weights.z;
+ t += texture2D(texture, rtex - 3.0*size*(vec2(0, 1)))*weights.z;
+
+ t += texture2D(texture, rtex + 4.0*size*(vec2(1, 0))) *weights.w;
+ t += texture2D(texture, rtex - 4.0*size*(vec2(1, 0)))*weights.w;
+ t += texture2D(texture, rtex + 4.0*size*(vec2(0, 1)))*weights.w;
+ t += texture2D(texture, rtex - 4.0*size*(vec2(0, 1)))*weights.w;
+
+ if(t.w == 0.0){
+ discard;
+ }
+
+ c = t.xyz;
+ alpha = g_alpha* t.w;
+ }
+ ///////////////////////////////////////////////////////////
+ else if ((v_texCoord.x > 0.0) && (rtex.y > 0.0 || rtex.x == 1.0)){
+ vec2 dtx = dFdx(rtex);
+ vec2 dty = dFdy(rtex);
+
+ rtex.y -= 0.1;
+ if(rtex.y < 0.0) {
+ if(v_texCoord.y < 0.0)
+ discard;
+ else{
+ rtex.y = 0.0;
+ }
+ }
+
+ vec2 f = vec2((dtx.y - 2.0*p1y*dtx.x + 4.0*p1y*rtex.x*dtx.x), (dty.y - 2.0*p1y*dty.x + 4.0*p1y*rtex.x*dty.x));
+
+ float position = rtex.y - ((2.0 * rtex.x * p1y) * (1.0 - rtex.x));
+ float d = position/(length(f));
+
+ float a = (0.5 - d * sign(v_texCoord.y));
+
+
+ if (a >= 1.0) {
+ alpha = g_alpha;
+ // c = vec3(1.0,1.0,1.0);
+ }
+ else if (a <= 0.0) {
+ alpha = 0.0;//discard;
+ // c = vec3(0.0,0.0,0.0);
+
+ }
+ else {
+ alpha = g_alpha*a;
+ // c = vec3(a,a,a);
+ mix(b_color,g_color, a);
+ }
+ }
+
+ gl_FragColor = vec4(c, alpha);
+}
diff --git a/turtle2d/src/jogamp/graph/curve/opengl/shader/curverenderer01.vp b/turtle2d/src/jogamp/graph/curve/opengl/shader/curverenderer01.vp
new file mode 100644
index 0000000..bc9ecb4
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/opengl/shader/curverenderer01.vp
@@ -0,0 +1,13 @@
+//#version 100
+
+uniform mat4 mgl_PMVMatrix[2];
+attribute vec4 v_position;
+attribute vec2 texCoord;
+
+varying vec2 v_texCoord;
+
+void main(void)
+{
+ gl_Position = mgl_PMVMatrix[0] * mgl_PMVMatrix[1] * v_position;
+ v_texCoord = texCoord.st;
+} \ No newline at end of file
diff --git a/turtle2d/src/jogamp/graph/curve/tess/GraphOutline.java b/turtle2d/src/jogamp/graph/curve/tess/GraphOutline.java
new file mode 100644
index 0000000..5dae296
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/tess/GraphOutline.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.curve.tess;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Outline;
+import com.jogamp.graph.geom.Vertex;
+
+public class GraphOutline {
+ final private Outline outline;
+ final private ArrayList<GraphVertex> controlpoints = new ArrayList<GraphVertex>(3);
+
+ public GraphOutline(){
+ this.outline = new Outline();
+ }
+
+ /**Create a control polyline of control vertices
+ * the curve pieces can be identified by onCurve flag
+ * of each cp the control polyline is open by default
+ */
+ public GraphOutline(Outline ol){
+ this.outline = ol;
+ ArrayList<Vertex> vertices = this.outline.getVertices();
+ for(Vertex v:vertices){
+ this.controlpoints.add(new GraphVertex(v));
+ }
+ }
+
+ public Outline getOutline() {
+ return outline;
+ }
+
+ /*public void setOutline(Outline<T> outline) {
+ this.outline = outline;
+ }*/
+
+
+ public ArrayList<GraphVertex> getGraphPoint() {
+ return controlpoints;
+ }
+
+ public ArrayList<Vertex> getPoints() {
+ return outline.getVertices();
+ }
+
+ /*public void setControlpoints(ArrayList<GraphPoint<T>> controlpoints) {
+ this.controlpoints = controlpoints;
+ }*/
+
+ public void addVertex(GraphVertex v) {
+ controlpoints.add(v);
+ outline.addVertex(v.getPoint());
+ }
+
+}
diff --git a/turtle2d/src/jogamp/graph/curve/tess/GraphVertex.java b/turtle2d/src/jogamp/graph/curve/tess/GraphVertex.java
new file mode 100644
index 0000000..b9f95a0
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/tess/GraphVertex.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.curve.tess;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Vertex;
+
+public class GraphVertex {
+ private Vertex point;
+ private ArrayList<HEdge> edges = null;
+ private boolean boundaryContained = false;
+
+ public GraphVertex(Vertex point) {
+ this.point = point;
+ }
+
+ public Vertex getPoint() {
+ return point;
+ }
+
+ public float getX(){
+ return point.getX();
+ }
+
+ public float getY(){
+ return point.getY();
+ }
+
+ public float getZ(){
+ return point.getZ();
+ }
+ public float[] getCoord() {
+ return point.getCoord();
+ }
+
+ public void setPoint(Vertex point) {
+ this.point = point;
+ }
+
+ public ArrayList<HEdge> getEdges() {
+ return edges;
+ }
+
+ public void setEdges(ArrayList<HEdge> edges) {
+ this.edges = edges;
+ }
+
+ public void addEdge(HEdge edge){
+ if(edges == null){
+ edges = new ArrayList<HEdge>();
+ }
+ edges.add(edge);
+ }
+ public void removeEdge(HEdge edge){
+ if(edges == null)
+ return;
+ edges.remove(edge);
+ if(edges.size() == 0){
+ edges = null;
+ }
+ }
+ public HEdge findNextEdge(GraphVertex nextVert){
+ for(HEdge e:edges){
+ if(e.getNext().getGraphPoint() == nextVert){
+ return e;
+ }
+ }
+ return null;
+ }
+ public HEdge findBoundEdge(){
+ for(HEdge e:edges){
+ if((e.getType() == HEdge.BOUNDARY) || (e.getType() == HEdge.HOLE)){
+ return e;
+ }
+ }
+ return null;
+ }
+ public HEdge findPrevEdge(GraphVertex prevVert){
+ for(HEdge e:edges){
+ if(e.getPrev().getGraphPoint() == prevVert){
+ return e;
+ }
+ }
+ return null;
+ }
+
+ public boolean isBoundaryContained() {
+ return boundaryContained;
+ }
+
+ public void setBoundaryContained(boolean boundaryContained) {
+ this.boundaryContained = boundaryContained;
+ }
+}
diff --git a/turtle2d/src/jogamp/graph/curve/tess/HEdge.java b/turtle2d/src/jogamp/graph/curve/tess/HEdge.java
new file mode 100644
index 0000000..d1bcc6e
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/tess/HEdge.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.curve.tess;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Triangle;
+
+
+public class HEdge {
+ public static int BOUNDARY = 3;
+ public static int INNER = 1;
+ public static int HOLE = 2;
+
+ private GraphVertex vert;
+ private HEdge prev = null;
+ private HEdge next = null;
+ private HEdge sibling = null;
+ private int type = BOUNDARY;
+ private Triangle triangle = null;
+
+ public HEdge(GraphVertex vert, int type) {
+ this.vert = vert;
+ this.type = type;
+ }
+
+ public HEdge(GraphVertex vert, HEdge prev, HEdge next, HEdge sibling, int type) {
+ this.vert = vert;
+ this.prev = prev;
+ this.next = next;
+ this.sibling = sibling;
+ this.type = type;
+ }
+
+ public HEdge(GraphVertex vert, HEdge prev, HEdge next, HEdge sibling, int type, Triangle triangle) {
+ this.vert = vert;
+ this.prev = prev;
+ this.next = next;
+ this.sibling = sibling;
+ this.type = type;
+ this.triangle = triangle;
+ }
+
+ public GraphVertex getGraphPoint() {
+ return vert;
+ }
+
+ public void setVert(GraphVertex vert) {
+ this.vert = vert;
+ }
+
+ public HEdge getPrev() {
+ return prev;
+ }
+
+ public void setPrev(HEdge prev) {
+ this.prev = prev;
+ }
+
+ public HEdge getNext() {
+ return next;
+ }
+
+ public void setNext(HEdge next) {
+ this.next = next;
+ }
+
+ public HEdge getSibling() {
+ return sibling;
+ }
+
+ public void setSibling(HEdge sibling) {
+ this.sibling = sibling;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public Triangle getTriangle() {
+ return triangle;
+ }
+
+ public void setTriangle(Triangle triangle) {
+ this.triangle = triangle;
+ }
+
+ public static <T extends Vertex> void connect(HEdge first, HEdge next){
+ first.setNext(next);
+ next.setPrev(first);
+ }
+
+ public static <T extends Vertex> void makeSiblings(HEdge first, HEdge second){
+ first.setSibling(second);
+ second.setSibling(first);
+ }
+
+ public boolean vertexOnCurveVertex(){
+ return vert.getPoint().isOnCurve();
+ }
+
+}
diff --git a/turtle2d/src/jogamp/graph/curve/tess/Loop.java b/turtle2d/src/jogamp/graph/curve/tess/Loop.java
new file mode 100644
index 0000000..fd7736a
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/tess/Loop.java
@@ -0,0 +1,373 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.curve.tess;
+
+import java.util.ArrayList;
+
+
+import com.jogamp.graph.geom.AABBox;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.math.VectorUtil;
+
+public class Loop {
+ private HEdge root = null;
+ private AABBox box = new AABBox();
+ private GraphOutline initialOutline = null;
+
+ public Loop(GraphOutline polyline, int direction){
+ initialOutline = polyline;
+ this.root = initFromPolyline(initialOutline, direction);
+ }
+
+ public HEdge getHEdge(){
+ return root;
+ }
+
+ public Triangle cut(boolean delaunay){
+ if(isSimplex()){
+ Triangle t = new Triangle(root.getGraphPoint().getPoint(), root.getNext().getGraphPoint().getPoint(),
+ root.getNext().getNext().getGraphPoint().getPoint());
+ t.setVerticesBoundary(checkVerticesBoundary(root));
+ return t;
+ }
+ HEdge prev = root.getPrev();
+ HEdge next1 = root.getNext();
+
+ HEdge next2 = findClosestValidNeighbor(next1.getNext(), delaunay);
+ if(next2 == null){
+ root = root.getNext();
+ return null;
+ }
+
+ GraphVertex v1 = root.getGraphPoint();
+ GraphVertex v2 = next1.getGraphPoint();
+ GraphVertex v3 = next2.getGraphPoint();
+
+ HEdge v3Edge = new HEdge(v3, HEdge.INNER);
+
+ HEdge.connect(v3Edge, root);
+ HEdge.connect(next1, v3Edge);
+
+ HEdge v3EdgeSib = v3Edge.getSibling();
+ if(v3EdgeSib == null){
+ v3EdgeSib = new HEdge(v3Edge.getNext().getGraphPoint(), HEdge.INNER);
+ HEdge.makeSiblings(v3Edge, v3EdgeSib);
+ }
+
+ HEdge.connect(prev, v3EdgeSib);
+ HEdge.connect(v3EdgeSib, next2);
+
+ Triangle t = createTriangle(v1.getPoint(), v2.getPoint(), v3.getPoint(), root);
+ this.root = next2;
+ return t;
+ }
+
+ public boolean isSimplex(){
+ return (root.getNext().getNext().getNext() == root);
+ }
+
+ /**Create a connected list of half edges (loop)
+ * from the boundary profile
+ * @param direction requested winding of edges (CCW or CW)
+ */
+ private HEdge initFromPolyline(GraphOutline outline, int direction){
+ ArrayList<GraphVertex> vertices = outline.getGraphPoint();
+
+ if(vertices.size()<3) {
+ throw new IllegalArgumentException("outline's vertices < 3: " + vertices.size());
+ }
+ boolean isCCW = VectorUtil.ccw(vertices.get(0).getPoint(), vertices.get(1).getPoint(),
+ vertices.get(2).getPoint());
+ boolean invert = isCCW && (direction == VectorUtil.CW);
+
+ HEdge firstEdge = null;
+ HEdge lastEdge = null;
+ int index =0;
+ int max = vertices.size();
+
+ int edgeType = HEdge.BOUNDARY;
+ if(invert){
+ index = vertices.size() -1;
+ max = -1;
+ edgeType = HEdge.HOLE;
+ }
+
+ while(index != max){
+ GraphVertex v1 = vertices.get(index);
+ box.resize(v1.getX(), v1.getY(), v1.getZ());
+
+ HEdge edge = new HEdge(v1, edgeType);
+
+ v1.addEdge(edge);
+ if(lastEdge != null){
+ lastEdge.setNext(edge);
+ edge.setPrev(lastEdge);
+ }
+ else{
+ firstEdge = edge;
+ }
+
+ if(!invert){
+ if(index == vertices.size()-1){
+ edge.setNext(firstEdge);
+ firstEdge.setPrev(edge);
+ }
+ }
+ else if (index == 0){
+ edge.setNext(firstEdge);
+ firstEdge.setPrev(edge);
+ }
+
+ lastEdge = edge;
+
+ if(!invert){
+ index++;
+ }
+ else{
+ index--;
+ }
+ }
+ return firstEdge;
+ }
+
+ public void addConstraintCurve(GraphOutline polyline) {
+ // GraphOutline outline = new GraphOutline(polyline);
+ /**needed to generate vertex references.*/
+ initFromPolyline(polyline, VectorUtil.CW);
+
+ GraphVertex v3 = locateClosestVertex(polyline);
+ HEdge v3Edge = v3.findBoundEdge();
+ HEdge v3EdgeP = v3Edge.getPrev();
+ HEdge crossEdge = new HEdge(root.getGraphPoint(), HEdge.INNER);
+
+ HEdge.connect(root.getPrev(), crossEdge);
+ HEdge.connect(crossEdge, v3Edge);
+
+ HEdge crossEdgeSib = crossEdge.getSibling();
+ if(crossEdgeSib == null) {
+ crossEdgeSib = new HEdge(crossEdge.getNext().getGraphPoint(), HEdge.INNER);
+ HEdge.makeSiblings(crossEdge, crossEdgeSib);
+ }
+
+ HEdge.connect(v3EdgeP, crossEdgeSib);
+ HEdge.connect(crossEdgeSib, root);
+ }
+
+ /** Locates the vertex and update the loops root
+ * to have (root + vertex) as closest pair
+ * @param polyline the control polyline
+ * to search for closestvertices
+ * @return the vertex that is closest to the newly set root Hedge.
+ */
+ private GraphVertex locateClosestVertex(GraphOutline polyline) {
+ HEdge closestE = null;
+ GraphVertex closestV = null;
+
+ float minDistance = Float.MAX_VALUE;
+ boolean inValid = false;
+ ArrayList<GraphVertex> initVertices = initialOutline.getGraphPoint();
+ ArrayList<GraphVertex> vertices = polyline.getGraphPoint();
+
+ for(int i=0; i< initVertices.size()-1; i++){
+ GraphVertex v = initVertices.get(i);
+ GraphVertex nextV = initVertices.get(i+1);
+ for(GraphVertex cand:vertices){
+ float distance = VectorUtil.computeLength(v.getCoord(), cand.getCoord());
+ if(distance < minDistance){
+ for (GraphVertex vert:vertices){
+ if(vert == v || vert == nextV || vert == cand)
+ continue;
+ inValid = VectorUtil.inCircle(v.getPoint(), nextV.getPoint(),
+ cand.getPoint(), vert.getPoint());
+ if(inValid){
+ break;
+ }
+ }
+ if(!inValid){
+ closestV = cand;
+ minDistance = distance;
+ closestE = v.findBoundEdge();
+ }
+ }
+
+ }
+ }
+
+ if(closestE != null){
+ root = closestE;
+ }
+
+ return closestV;
+ }
+
+ private HEdge findClosestValidNeighbor(HEdge edge, boolean delaunay) {
+ HEdge next = root.getNext();
+
+ if(!VectorUtil.ccw(root.getGraphPoint().getPoint(), next.getGraphPoint().getPoint(),
+ edge.getGraphPoint().getPoint())){
+ return null;
+ }
+
+ HEdge candEdge = edge;
+ boolean inValid = false;
+
+ if(delaunay){
+ Vertex cand = candEdge.getGraphPoint().getPoint();
+ HEdge e = candEdge.getNext();
+ while (e != candEdge){
+ if(e.getGraphPoint() == root.getGraphPoint()
+ || e.getGraphPoint() == next.getGraphPoint()
+ || e.getGraphPoint().getPoint() == cand){
+ e = e.getNext();
+ continue;
+ }
+ inValid = VectorUtil.inCircle(root.getGraphPoint().getPoint(), next.getGraphPoint().getPoint(),
+ cand, e.getGraphPoint().getPoint());
+ if(inValid){
+ break;
+ }
+ e = e.getNext();
+ }
+ }
+ if(!inValid){
+ return candEdge;
+ }
+ return null;
+ }
+
+ /** Create a triangle from the param vertices only if
+ * the triangle is valid. IE not outside region.
+ * @param v1 vertex 1
+ * @param v2 vertex 2
+ * @param v3 vertex 3
+ * @param root and edge of this triangle
+ * @return the triangle iff it satisfies, null otherwise
+ */
+ private Triangle createTriangle(Vertex v1, Vertex v2, Vertex v3, HEdge rootT){
+ Triangle t = new Triangle(v1, v2, v3);
+ t.setVerticesBoundary(checkVerticesBoundary(rootT));
+ return t;
+ }
+
+ private boolean[] checkVerticesBoundary(HEdge rootT) {
+ boolean[] boundary = new boolean[3];
+ HEdge e1 = rootT;
+ HEdge e2 = rootT.getNext();
+ HEdge e3 = rootT.getNext().getNext();
+
+ if(e1.getGraphPoint().isBoundaryContained()){
+ boundary[0] = true;
+ }
+ if(e2.getGraphPoint().isBoundaryContained()){
+ boundary[1] = true;
+ }
+ if(e3.getGraphPoint().isBoundaryContained()){
+ boundary[2] = true;
+ }
+ return boundary;
+ }
+
+
+ /** Check if vertex inside the Loop
+ * @param vertex the Vertex
+ * @return true if the vertex is inside, false otherwise
+ */
+ public boolean checkInside(Vertex vertex) {
+ if(!box.contains(vertex.getX(), vertex.getY(), vertex.getZ())){
+ return false;
+ }
+
+ float[] center = box.getCenter();
+
+ int hits = 0;
+ HEdge current = root;
+ HEdge next = root.getNext();
+ while(next!= root){
+ if(current.getType() == HEdge.INNER || next.getType() == HEdge.INNER){
+ current = next;
+ next = current.getNext();
+ continue;
+ }
+ Vertex vert1 = current.getGraphPoint().getPoint();
+ Vertex vert2 = next.getGraphPoint().getPoint();
+
+ /** The ray is P0+s*D0, where P0 is the ray origin, D0 is a direction vector and s >= 0.
+ * The segment is P1+t*D1, where P1 and P1+D1 are the endpoints, and 0 <= t <= 1.
+ * perp(x,y) = (y,-x).
+ * if Dot(perp(D1),D0) is not zero,
+ * s = Dot(perp(D1),P1-P0)/Dot(perp(D1),D0)
+ * t = Dot(perp(D0),P1-P0)/Dot(perp(D1),D0)
+ */
+
+ float[] d0 = new float[]{center[0] - vertex.getX(), center[1]-vertex.getY(),
+ center[2]-vertex.getZ()};
+ float[] d1 = {vert2.getX() - vert1.getX(), vert2.getY() - vert1.getY(),
+ vert2.getZ() - vert1.getZ()};
+
+ float[] prep_d1 = {d1[1],-1*d1[0], d1[2]};
+ float[] prep_d0 = {d0[1],-1*d0[0], d0[2]};
+
+ float[] p0p1 = new float[]{vert1.getX() - vertex.getX(), vert1.getY() - vertex.getY(),
+ vert1.getZ() - vertex.getZ()};
+
+ float dotD1D0 = VectorUtil.dot(prep_d1, d0);
+ if(dotD1D0 == 0){
+ /** ray parallel to segment */
+ current = next;
+ next = current.getNext();
+ continue;
+ }
+
+ float s = VectorUtil.dot(prep_d1,p0p1)/dotD1D0;
+ float t = VectorUtil.dot(prep_d0,p0p1)/dotD1D0;
+
+ if(s >= 0 && t >= 0 && t<= 1){
+ hits++;
+ }
+ current = next;
+ next = current.getNext();
+ }
+
+ if(hits % 2 != 0){
+ /** check if hit count is even */
+ return true;
+ }
+ return false;
+ }
+
+ public int computeLoopSize(){
+ int size = 0;
+ HEdge e = root;
+ do{
+ size++;
+ e = e.getNext();
+ }while(e != root);
+ return size;
+ }
+}
diff --git a/turtle2d/src/jogamp/graph/curve/text/GlyphShape.java b/turtle2d/src/jogamp/graph/curve/text/GlyphShape.java
new file mode 100644
index 0000000..36ba572
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/text/GlyphShape.java
@@ -0,0 +1,161 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.curve.text;
+
+import java.util.ArrayList;
+
+import jogamp.graph.geom.plane.PathIterator;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Triangle;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.math.Quaternion;
+
+public class GlyphShape {
+
+ private Quaternion quat= null;
+ private int numVertices = 0;
+ private OutlineShape shape = null;
+
+ /** Create a new Glyph shape
+ * based on Parametric curve control polyline
+ */
+ public GlyphShape(Vertex.Factory<? extends Vertex> factory){
+ shape = new OutlineShape(factory);
+ }
+
+ /** Create a GlyphShape from a font Path Iterator
+ * @param pathIterator the path iterator
+ *
+ * @see PathIterator
+ */
+ public GlyphShape(Vertex.Factory<? extends Vertex> factory, PathIterator pathIterator){
+ this(factory);
+
+ if(null != pathIterator){
+ while(!pathIterator.isDone()){
+ float[] coords = new float[6];
+ int segmentType = pathIterator.currentSegment(coords);
+ addOutlineVerticesFromGlyphVector(coords, segmentType);
+
+ pathIterator.next();
+ }
+ }
+ shape.transformOutlines(OutlineShape.QUADRATIC_NURBS);
+ }
+
+ public final Vertex.Factory<? extends Vertex> vertexFactory() { return shape.vertexFactory(); }
+
+ private void addVertexToLastOutline(Vertex vertex){
+ shape.addVertex(vertex);
+ }
+
+ private void addOutlineVerticesFromGlyphVector(float[] coords, int segmentType){
+ if(segmentType == PathIterator.SEG_MOVETO){
+ if(!shape.getLastOutline().isEmpty()){
+ shape.addEmptyOutline();
+ }
+ Vertex vert = vertexFactory().create(coords[0],coords[1]);
+ vert.setOnCurve(true);
+ addVertexToLastOutline(vert);
+
+ numVertices++;
+ }
+ else if(segmentType == PathIterator.SEG_LINETO){
+ Vertex vert1 = vertexFactory().create(coords[0],coords[1]);
+ vert1.setOnCurve(true);
+ addVertexToLastOutline(vert1);
+
+ numVertices++;
+ }
+ else if(segmentType == PathIterator.SEG_QUADTO){
+ Vertex vert1 = vertexFactory().create(coords[0],coords[1]);
+ vert1.setOnCurve(false);
+ addVertexToLastOutline(vert1);
+
+ Vertex vert2 = vertexFactory().create(coords[2],coords[3]);
+ vert2.setOnCurve(true);
+ addVertexToLastOutline(vert2);
+
+ numVertices+=2;
+ }
+ else if(segmentType == PathIterator.SEG_CUBICTO){
+ Vertex vert1 = vertexFactory().create(coords[0],coords[1]);
+ vert1.setOnCurve(false);
+ addVertexToLastOutline(vert1);
+
+ Vertex vert2 = vertexFactory().create(coords[2],coords[3]);
+ vert2.setOnCurve(false);
+ addVertexToLastOutline(vert2);
+
+ Vertex vert3 = vertexFactory().create(coords[4],coords[5]);
+ vert3.setOnCurve(true);
+ addVertexToLastOutline(vert3);
+
+ numVertices+=3;
+ }
+ else if(segmentType == PathIterator.SEG_CLOSE){
+ shape.closeLastOutline();
+ }
+ }
+
+ public int getNumVertices() {
+ return numVertices;
+ }
+
+ /** Get the rotational Quaternion attached to this Shape
+ * @return the Quaternion Object
+ */
+ public Quaternion getQuat() {
+ return quat;
+ }
+
+ /** Set the Quaternion that shall defien the rotation
+ * of this shape.
+ * @param quat
+ */
+ public void setQuat(Quaternion quat) {
+ this.quat = quat;
+ }
+
+ /** Triangluate the glyph shape
+ * @param sharpness sharpness of the curved regions default = 0.5
+ * @return ArrayList of triangles which define this shape
+ */
+ public ArrayList<Triangle> triangulate(float sharpness){
+ return shape.triangulate(sharpness);
+ }
+
+ /** Get the list of Vertices of this Object
+ * @return arrayList of Vertices
+ */
+ public ArrayList<Vertex> getVertices(){
+ return shape.getVertices();
+ }
+}
diff --git a/turtle2d/src/jogamp/graph/curve/text/GlyphString.java b/turtle2d/src/jogamp/graph/curve/text/GlyphString.java
new file mode 100644
index 0000000..808e3a4
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/curve/text/GlyphString.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.curve.text;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.opengl.SVertex;
+
+import javax.media.opengl.GLContext;
+
+import jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+import jogamp.graph.geom.plane.PathIterator;
+
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.curve.RegionFactory;
+import com.jogamp.opengl.util.PMVMatrix;
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+public class GlyphString {
+ private final Vertex.Factory<? extends Vertex> pointFactory;
+ private ArrayList<GlyphShape> glyphs = new ArrayList<GlyphShape>();
+ private String str = "";
+ private String fontname = "";
+ private Region region;
+
+ private SVertex origin = new SVertex();
+
+ /** Create a new GlyphString object
+ * @param fontname the name of the font that this String is
+ * associated with
+ * @param str the string object
+ */
+ public GlyphString(Vertex.Factory<? extends Vertex> factory, String fontname, String str){
+ pointFactory = factory;
+ this.fontname = fontname;
+ this.str = str;
+ }
+
+ public final Vertex.Factory<? extends Vertex> pointFactory() { return pointFactory; }
+
+ public void addGlyphShape(GlyphShape glyph){
+ glyphs.add(glyph);
+ }
+ public String getString(){
+ return str;
+ }
+
+ /** Creates the Curve based Glyphs from a Font
+ * @param paths a list of FontPath2D objects that define the outline
+ * @param affineTransform a global affine transformation applied to the paths.
+ */
+ public void createfromFontPath(Path2D[] paths, AffineTransform affineTransform){
+ final int numGlyps = paths.length;
+ for (int index=0;index<numGlyps;index++){
+ if(paths[index] == null){
+ continue;
+ }
+ PathIterator iterator = paths[index].iterator(affineTransform);
+ GlyphShape glyphShape = new GlyphShape(pointFactory, iterator);
+
+ if(glyphShape.getNumVertices() < 3) {
+ continue;
+ }
+ addGlyphShape(glyphShape);
+ }
+ }
+
+ private ArrayList<Triangle> initializeTriangles(float sharpness){
+ ArrayList<Triangle> triangles = new ArrayList<Triangle>();
+ for(GlyphShape glyph:glyphs){
+ ArrayList<Triangle> tris = glyph.triangulate(sharpness);
+ triangles.addAll(tris);
+ }
+ return triangles;
+ }
+
+ /** Generate a OGL Region to represent this Object.
+ * @param context the GLContext which the region is defined by.
+ * @param shaprness the curvature sharpness of the object.
+ * @param st shader state
+ */
+ public void generateRegion(GLContext context, float shaprness, ShaderState st, int type){
+ region = RegionFactory.create(context, st, type);
+ region.setFlipped(true);
+
+ ArrayList<Triangle> tris = initializeTriangles(shaprness);
+ region.addTriangles(tris);
+
+ int numVertices = region.getNumVertices();
+ for(GlyphShape glyph:glyphs){
+ ArrayList<Vertex> gVertices = glyph.getVertices();
+ for(Vertex vert:gVertices){
+ vert.setId(numVertices++);
+ }
+ region.addVertices(gVertices);
+ }
+
+ /** initialize the region */
+ region.update();
+ }
+
+ /** Generate a Hashcode for this object
+ * @return a string defining the hashcode
+ */
+ public String getTextHashCode(){
+ return "" + fontname.hashCode() + str.hashCode();
+ }
+
+ /** Render the Object based using the associated Region
+ * previously generated.
+ */
+ public void renderString3D() {
+ region.render(null, 0, 0, 0);
+ }
+ /** Render the Object based using the associated Region
+ * previously generated.
+ */
+ public void renderString3D(PMVMatrix matrix, int vp_width, int vp_height, int size) {
+ region.render(matrix, vp_width, vp_height, size);
+ }
+
+ /** Get the Origion of this GlyphString
+ * @return
+ */
+ public Vertex getOrigin() {
+ return origin;
+ }
+
+ /** Destroy the associated OGL objects
+ */
+ public void destroy(){
+ region.destroy();
+ }
+}
diff --git a/turtle2d/src/jogamp/graph/font/FontConstructor.java b/turtle2d/src/jogamp/graph/font/FontConstructor.java
new file mode 100644
index 0000000..a382d29
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/FontConstructor.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.font;
+
+import com.jogamp.graph.font.Font;
+
+public interface FontConstructor {
+ Font create(String name);
+}
diff --git a/turtle2d/src/jogamp/graph/font/FontInt.java b/turtle2d/src/jogamp/graph/font/FontInt.java
new file mode 100644
index 0000000..4d9390d
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/FontInt.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.font;
+
+import jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+
+import com.jogamp.graph.font.Font;
+
+public interface FontInt extends Font {
+
+ public interface Glyph extends Font.Glyph {
+ // reserved special glyph IDs
+ // http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#ba57949e
+ public static final int ID_UNKNOWN = 0;
+ public static final int ID_CR = 2;
+ public static final int ID_SPACE = 3;
+
+ public Path2D getPath(); // unscaled path
+ public Path2D getPath(float pixelSize);
+ }
+
+ public void getOutline(String string, float pixelSize,
+ AffineTransform transform, Path2D[] result);
+}
diff --git a/turtle2d/src/jogamp/graph/font/JavaFontLoader.java b/turtle2d/src/jogamp/graph/font/JavaFontLoader.java
new file mode 100644
index 0000000..33505e7
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/JavaFontLoader.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.font;
+
+import com.jogamp.common.util.IntObjectHashMap;
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.font.FontSet;
+import com.jogamp.graph.font.FontFactory;
+
+public class JavaFontLoader implements FontSet {
+
+ final static FontSet fontLoader = new JavaFontLoader();
+
+ public static FontSet get() {
+ return fontLoader;
+ }
+
+ final static String availableFontFileNames[] =
+ {
+ /* 00 */ "LucidaBrightRegular.ttf",
+ /* 01 */ "LucidaBrightItalic.ttf",
+ /* 02 */ "LucidaBrightDemiBold.ttf",
+ /* 03 */ "LucidaBrightDemiItalic.ttf",
+ /* 04 */ "LucidaSansRegular.ttf",
+ /* 05 */ "LucidaSansDemiBold.ttf",
+ /* 06 */ "LucidaTypewriterRegular.ttf",
+ /* 07 */ "LucidaTypewriterBold.ttf",
+ };
+
+ final String javaFontPath;
+
+ private JavaFontLoader() {
+ javaFontPath = System.getProperty("java.home") + "/lib/fonts/";
+ }
+
+ // FIXME: Add cache size to limit memory usage
+ static final IntObjectHashMap fontMap = new IntObjectHashMap();
+
+ static boolean is(int bits, int bit) {
+ return 0 != ( bits & bit ) ;
+ }
+
+ public Font getDefault() {
+ return get(FAMILY_REGULAR, 0) ; // Sans Serif Regular
+ }
+
+ public Font get(int family, int style) {
+ Font font = (Font)fontMap.get( ( family << 8 ) | style );
+ if (font != null) {
+ return font;
+ }
+
+ // 1st process Sans Serif (2 fonts)
+ if( is(style, STYLE_SERIF) ) {
+ if( is(style, STYLE_BOLD) ) {
+ font = abspath(availableFontFileNames[5], family, style);
+ } else {
+ font = abspath(availableFontFileNames[4], family, style);
+ }
+ fontMap.put( ( family << 8 ) | style, font );
+ return font;
+ }
+
+ // Serif Fonts ..
+ switch (family) {
+ case FAMILY_LIGHT:
+ case FAMILY_MEDIUM:
+ case FAMILY_CONDENSED:
+ case FAMILY_REGULAR:
+ if( is(style, STYLE_BOLD) ) {
+ if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[3], family, style);
+ } else {
+ font = abspath(availableFontFileNames[2], family, style);
+ }
+ } else if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[1], family, style);
+ } else {
+ font = abspath(availableFontFileNames[0], family, style);
+ }
+ break;
+
+ case FAMILY_MONOSPACED:
+ if( is(style, STYLE_BOLD) ) {
+ font = abspath(availableFontFileNames[7], family, style);
+ } else {
+ font = abspath(availableFontFileNames[6], family, style);
+ }
+ break;
+ }
+
+ return font;
+ }
+
+ Font abspath(String fname, int family, int style) {
+ final Font f = FontFactory.getFontConstr().create(javaFontPath+fname);
+ if(null != f) {
+ fontMap.put( ( family << 8 ) | style, f );
+ }
+ return f;
+
+ }
+
+}
diff --git a/turtle2d/src/jogamp/graph/font/UbuntuFontLoader.java b/turtle2d/src/jogamp/graph/font/UbuntuFontLoader.java
new file mode 100644
index 0000000..e09ea85
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/UbuntuFontLoader.java
@@ -0,0 +1,132 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.font;
+
+import com.jogamp.common.util.IntObjectHashMap;
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.font.FontSet;
+import com.jogamp.graph.font.FontFactory;
+import com.jogamp.opengl.util.Locator;
+
+public class UbuntuFontLoader implements FontSet {
+
+ final static FontSet fontLoader = new UbuntuFontLoader();
+
+ public static FontSet get() {
+ return fontLoader;
+ }
+
+ final static String availableFontFileNames[] =
+ {
+ /* 00 */ "Ubuntu-R.ttf", // regular
+ /* 01 */ "Ubuntu-RI.ttf", // regular italic
+ /* 02 */ "Ubuntu-B.ttf", // bold
+ /* 03 */ "Ubuntu-BI.ttf", // bold italic
+ /* 04 */ "Ubuntu-L.ttf", // light
+ /* 05 */ "Ubuntu-LI.ttf", // light italic
+ /* 06 */ "Ubuntu-M.ttf", // medium
+ /* 07 */ "Ubuntu-MI.ttf", // medium italic
+
+ };
+
+ final static String relPath = "fonts/ubuntu/" ;
+
+ private UbuntuFontLoader() {
+ }
+
+ // FIXME: Add cache size to limit memory usage
+ static final IntObjectHashMap fontMap = new IntObjectHashMap();
+
+ static boolean is(int bits, int bit) {
+ return 0 != ( bits & bit ) ;
+ }
+
+ public Font getDefault() {
+ return get(FAMILY_REGULAR, 0) ; // Sans Serif Regular
+ }
+
+ public Font get(int family, int style)
+ {
+ Font font = (Font)fontMap.get( ( family << 8 ) | style );
+ if (font != null) {
+ return font;
+ }
+
+ switch (family) {
+ case FAMILY_MONOSPACED:
+ case FAMILY_CONDENSED:
+ case FAMILY_REGULAR:
+ if( is(style, STYLE_BOLD) ) {
+ if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[3], family, style);
+ } else {
+ font = abspath(availableFontFileNames[2], family, style);
+ }
+ } else if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[1], family, style);
+ } else {
+ font = abspath(availableFontFileNames[0], family, style);
+ }
+ break;
+
+ case FAMILY_LIGHT:
+ if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[5], family, style);
+ } else {
+ font = abspath(availableFontFileNames[4], family, style);
+ }
+ break;
+
+ case FAMILY_MEDIUM:
+ if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[6], family, style);
+ } else {
+ font = abspath(availableFontFileNames[7], family, style);
+ }
+ break;
+ }
+
+ return font;
+ }
+
+ Font abspath(String fname) {
+ return FontFactory.getFontConstr().create(
+ Locator.getResource(UbuntuFontLoader.class, relPath+fname).getPath() );
+ }
+
+ Font abspath(String fname, int family, int style) {
+ final Font f = FontFactory.getFontConstr().create(
+ Locator.getResource(UbuntuFontLoader.class, relPath+fname).getPath() );
+ if(null != f) {
+ fontMap.put( ( family << 8 ) | style, f );
+ }
+ return f;
+ }
+
+
+}
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/CONTRIBUTING.txt b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/CONTRIBUTING.txt
new file mode 100644
index 0000000..15bdc0c
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/CONTRIBUTING.txt
@@ -0,0 +1,21 @@
+The Ubuntu Font Family is very long-term endeavour, and the first time
+that a professionally-designed font has been funded specifically with
+the intent of being an on-going community expanded project:
+
+ http://font.ubuntu.com/
+
+Development of the Ubuntu Font Family is undertaken on Launchpad:
+
+ http://launchpad.net/ubuntu-font-family/
+
+and this is where milestones, bug management and releases are handled.
+
+Contributions are welcomed. Your work will be used on millions of
+computers every single day! Following the initial bootstrapping of
+Latin, Cyrillic, Greek, Arabic and Hebrew expansion will be undertaken
+by font designers from the font design and Ubuntu communities.
+
+To ensure that the Ubuntu Font Family can be re-licensed to future
+widely-used libre font licences, copyright assignment is being required:
+
+ https://launchpad.net/~uff-contributors
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/FONTLOG.txt b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/FONTLOG.txt
new file mode 100644
index 0000000..cf0e4c1
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/FONTLOG.txt
@@ -0,0 +1,211 @@
+This is the FONTLOG file for the Ubuntu Font Family and attempts to follow
+the recommendations at: http://scripts.sil.org/OFL-FAQ_web#43cecb44
+
+
+Overview
+
+The new Ubuntu Font Family was started to enable the personality of
+Ubuntu to be seen and felt in every menu, button and dialog.
+The typeface is sans-serif, uses OpenType features and is manually
+hinted for clarity on desktop and mobile computing screens.
+
+The scope of the Ubuntu Font Family includes all the languages used by
+the various Ubuntu users around the world in tune with Ubuntu's
+philosophy which states that every user should be able to use their
+software in the language of their choice. So the Ubuntu Font Family
+project will be extended to cover many more written languages.
+
+
+History
+
+The Ubuntu Font Family has been creating during 2010. As of December 2010
+coverage is provided for Latin, Cyrillic and Greek across Regular, Italic,
+Bold and Bold-Italic.
+
+
+ChangeLog
+
+2010-03-08 (Paul Sladen) Ubuntu Font Family version 0.71.2
+
+ * (Production) Adjust Medium WeightClass to 500 (Md, MdIt) (LP: #730912)
+
+2010-03-07 (Paul Sladen) Ubuntu Font Family version 0.71.1
+
+ * (Design) Add Capitalised version of glyphs and kern. (Lt, LtIt,
+ Md, MdIt) DM (LP: #677446)
+ * (Design) Re-space and tighen Regular and Italic by amount specified
+ by Mark Shuttleworth (minus 4 FUnits). (Rg, It) (LP: #677149)
+ * (Design) Design: Latin (U+0192) made straight more like l/c f with
+ tail (LP: #670768)
+ * (Design) (U+01B3) should have hook on right, as the lowercase
+ (U+01B4) (LP: #681026)
+ * (Design) Tail of Light Italic germandbls, longs and lowercase 'f'
+ to match Italic/BoldItalic (LP: #623925)
+ * (Production) Update <case> feature (Lt, LtIt, Md, MdIt). DM
+ (LP: #676538, #676539)
+ * (Production) Remove Bulgarian locl feature for Italics. (LP: #708578)
+ * (Production) Update Description information with new string:
+ "The Ubuntu Font Family are libre fonts funded by Canonical Ltd
+ on behalf of the Ubuntu project. The font design work and
+ technical implementation is being undertaken by Dalton Maag. The
+ typeface is sans-serif, uses OpenType features and is manually
+ hinted for clarity on desktop and mobile computing screens. The
+ scope of the Ubuntu Font Family includes all the languages used
+ by the various Ubuntu users around the world in tune with
+ Ubuntu's philosophy which states that every user should be able
+ to use their software in the language of their choice. The
+ project is ongoing, and we expect the family will be extended to
+ cover many written languages in the coming years."
+ (Rg, It, Bd, BdIt, Lt, LtIt, Md, MdIt) (LP: #690590)
+ * (Production) Pixel per em indicator added at U+F000 (Lt, LtIt, Md,
+ MdIt) (LP: #615787)
+ * (Production) Version number indicator added at U+EFFD (Lt, LtIt, Md,
+ MdIt) (LP: #640623)
+ * (Production) fstype bit set to 0 - Editable (Lt, LtIt, Md, MdIt)
+ (LP: #648406)
+ * (Production) Localisation of name table has been removed because
+ of problems with Mac OS/X interpretation of localisation. DM
+ (LP: #730785)
+ * (Hinting) Regular '?' dot non-circular (has incorrect control
+ value). (LP: #654336)
+ * (Hinting) Too much space after latin capital 'G' in 13pt
+ regular. Now reduced. (LP: #683437)
+ * (Hinting) Balance Indian Rupee at 18,19pt (LP: #662177)
+ * (Hinting) Make Regular '£' less ambiguous at 13-15 ppm (LP: #685562)
+ * (Hinting) Regular capital 'W' made symmetrical at 31 ppem (LP: #686168)
+
+2010-12-14 (Paul Sladen) Ubuntu Font Family version 0.70.1
+
+ Packaging, rebuilt from '2010-12-08 UbuntuFontsSourceFiles_070.zip':
+ * (Midstream) Fstype bit != 0 (LP: #648406)
+ * (Midstream) Add unit test to validate fstype bits (LP: #648406)
+ * (Midstream) Add unit test to validate licence
+
+2010-12-14 (Paul Sladen) Ubuntu Font Family version 0.70
+
+ Release notes 0.70:
+ * (Design) Add Capitalised version of glyphs and kern. (Rg, It, Bd,
+ BdIt) DM (LP: #676538, #677446)
+ * (Design) Give acute and grave a slight upright move to more match
+ the Hungarian double acute angle. (Rg, It, Bd, BdIt) (LP: #656647)
+ * (Design) Shift Bold Italic accent glyphs to be consistent with the
+ Italic. (BdIt only) DM (LP: #677449)
+ * (Design) Check spacing and kerning of dcaron, lcaron and
+ tcaron. (Rg, It, Bd, BdIt) (LP: #664722)
+ * (Design) Add positive kerning to () {} [] to open out the
+ combinations so they are less like a closed box. (Rg, It, Bd,
+ BdIt) (LP: #671228)
+ * (Design) Change design of acute.asc and check highest points (Bd
+ and BdIt only) DM
+ * (Production) Update <case> feature. DM (LP: #676538, #676539)
+ * (Production) Remove Romanian locl feature. (Rg, It, Bd, BdIt)
+ (LP: #635615)
+ * (Production) Update Copyright information with new
+ strings. "Copyright 2010 Canonical Ltd. Licensed under the Ubuntu
+ Font Licence 1.0" Trademark string "Ubuntu and Canonical are
+ registered trademarks of Canonical Ltd." (Rg, It, Bd, BdIt) DM
+ (LP: #677450)
+ * (Design) Check aligning of hyphen, math signs em, en, check braces
+ and other brackets. 16/11 (LP: #676465)
+ * (Production) Pixel per em indicator added at U+F000 (Rg, It, Bd,
+ BdIt) (LP: #615787)
+ * (Production) Version number indicator added at U+EFFD (Rg, It, Bd,
+ BdIt) (LP: #640623)
+ * (Production) fstype bit set to 0 - Editable (Rg, It, Bd, BdIt)
+ (LP: #648406)
+
+2010-10-05 (Paul Sladen) Ubuntu Font Family version 0.69
+
+ [Dalton Maag]
+ * Italic,
+ - Hinting on lowercase Italic l amended 19ppm (LP: #632451)
+ - Hinting on lowercase Italic u amended 12ppm (LP: #626376)
+
+ * Regular, Italic, Bold, BoldItalic
+ - New Rupee Sign added @ U+20B9 (LP: #645987)
+ - Ubuntu Roundel added @ U+E0FF (LP: #651606)
+
+ [Paul Sladen]
+ * All
+ - Removed "!ubu" GSUB.calt ligature for U+E0FF (LP: #651606)
+
+
+Acknowledgements
+
+If you make modifications be sure to add your name (N), email (E),
+web-address (if you have one) (W) and description (D). This list is in
+alphabetical order.
+
+N: Amélie Bonet
+W: http://ameliebonet.com/
+D: Type design with Dalton Maag, particularly Ubuntu Mono
+
+N: Ron Carpenter
+N: Vincent Connare
+N: Lukas Paltram
+W: http://www.daltonmaag.com/
+D: Type design and engineering with Dalton Maag
+
+N: Dave Crossland
+E: dave@understandingfonts.com
+W: http://understandingfonts.com/
+D: Documentation and libre licensing guidance
+
+N: Iain Farrell
+W: http://www.flickr.com/photos/iain
+D: Ubuntu Font Family delivery for the Ubuntu UX team
+
+N: Shiraaz Gabru
+W: http://www.daltonmaag.com/
+D: Ubuntu Font Family project management at Dalton Maag
+
+N: Marcus Haslam
+W: http://design.canonical.com/author/marcus-haslam/
+D: Creative inspiration
+
+N: Ben Laenen
+D: Inspiration behind the pixels-per-em (PPEM) readout debugging glyph at U+F000
+ (for this font the concept was re-implemented from scratch by Dalton-Maag)
+
+N: Bruno Maag
+W: http://www.daltonmaag.com/
+D: Stylistic direction of the Ubuntu Font Family, as head of Dalton Maag
+
+N: Ivanka Majic
+W: http://www.ivankamajic.com/
+D: Guiding the UX team and Cyrillic feedback
+
+N: David Marshall
+N: Malcolm Wooden
+W: http://www.daltonmaag.com/
+D: Font Engineering and technical direction
+
+N: Rodrigo Rivas
+D: Indian Rupee Sign glyph
+
+N: Mark Shuttleworth
+E: mark@ubuntu.com
+W: http://www.markshuttleworth.com/
+D: Executive quality-control and funding
+
+N: Paul Sladen
+E: ubuntu@paul.sladen.org
+W: http://www.paul.sladen.org/
+D: Bug triaging, packaging
+
+N: Nicolas Spalinger
+W: http://planet.open-fonts.org
+D: Continuous guidance on libre/open font licensing, best practises in source
+ tree layout, release and packaging (pkg-fonts Debian team)
+
+N: Kenneth Wimer
+D: Initial PPA packaging
+
+* Canonical Ltd is the primary commercial sponsor of the Ubuntu and
+ Kubuntu operating systems
+* Dalton Maag are a custom type foundry headed by Bruno Maag
+
+For further documentation, information on contributors, source code
+downloads and those involved with the Ubuntu Font Family, visit:
+
+ http://font.ubuntu.com/
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/LICENCE-FAQ.txt b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/LICENCE-FAQ.txt
new file mode 100644
index 0000000..776a25e
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/LICENCE-FAQ.txt
@@ -0,0 +1,177 @@
+ Ubuntu Font Family Licensing FAQ
+
+ Stylistic Foundations
+
+ The Ubuntu Font Family is the first time that a libre typeface has been
+ designed professionally and explicitly with the intent of developing a
+ public and long-term community-based development process.
+
+ When developing an open project, it is generally necessary to have firm
+ foundations: a font needs to maintain harmony within itself even across
+ many type designers and writing systems. For the [1]Ubuntu Font Family,
+ the process has been guided with the type foundry Dalton Maag setting
+ the project up with firm stylistic foundation covering several
+ left-to-right scripts: Latin, Greek and Cyrillic; and right-to-left
+ scripts: Arabic and Hebrew (due in 2011).
+
+ With this starting point the community will, under the supervision of
+ [2]Canonical and [3]Dalton Maag, be able to build on the existing font
+ sources to expand their character coverage. Ultimately everybody will
+ be able to use the Ubuntu Font Family in their own written languages
+ across the whole of Unicode (and this will take some time!).
+
+ Licensing
+
+ The licence chosen by any free software project is one of the
+ foundational decisions that sets out how derivatives and contributions
+ can occur, and in turn what kind of community will form around the
+ project.
+
+ Using a licence that is compatible with other popular licences is a
+ powerful constraint because of the [4]network effects: the freedom to
+ share improvements between projects allows free software to reach
+ high-quality over time. Licence-proliferation leads to many
+ incompatible licences, undermining the network effect, the freedom to
+ share and ultimately making the libre movement that Ubuntu is a part of
+ less effective. For all kinds of software, writing a new licence is not
+ to be taken lightly and is a choice that needs to be thoroughly
+ justified if this path is taken.
+
+ Today it is not clear to Canonical what the best licence for a font
+ project like the Ubuntu Font Family is: one that starts life designed
+ by professionals and continues with the full range of community
+ development, from highly commercial work in new directions to curious
+ beginners' experimental contributions. The fast and steady pace of the
+ Ubuntu release cycle means that an interim libre licence has been
+ necessary to enable the consideration of the font family as part of
+ Ubuntu 10.10 operating system release.
+
+ Before taking any decision on licensing, Canonical as sponsor and
+ backer of the project has reviewed the many existing licenses used for
+ libre/open fonts and engaged the stewards of the most popular licenses
+ in detailed discussions. The current interim licence is the first step
+ in progressing the state-of-the-art in licensing for libre/open font
+ development.
+
+ The public discussion must now involve everyone in the (comparatively
+ new) area of the libre/open font community; including font users,
+ software freedom advocates, open source supporters and existing libre
+ font developers. Most importantly, the minds and wishes of professional
+ type designers considering entering the free software business
+ community must be taken on board.
+
+ Conversations and discussion has taken place, privately, with
+ individuals from the following groups (generally speaking personally on
+ behalf of themselves, rather than their affiliations):
+ * [5]SIL International
+ * [6]Open Font Library
+ * [7]Software Freedom Law Center
+ * [8]Google Font API
+
+ Document embedding
+
+ One issue highlighted early on in the survey of existing font licences
+ is that of document embedding. Almost all font licences, both free and
+ unfree, permit embedding a font into a document to a certain degree.
+ Embedding a font with other works that make up a document creates a
+ "combined work" and copyleft would normally require the whole document
+ to be distributed under the terms of the font licence. As beautiful as
+ the font might be, such a licence makes a font too restrictive for
+ useful general purpose digital publishing.
+
+ The situation is not entirely unique to fonts and is encountered also
+ with tools such as GNU Bison: a vanilla GNU GPL licence would require
+ anything generated with Bison to be made available under the terms of
+ the GPL as well. To avoid this, Bison is [9]published with an
+ additional permission to the GPL which allows the output of Bison to be
+ made available under any licence.
+
+ The conflict between licensing of fonts and licensing of documents, is
+ addressed in two popular libre font licences, the SIL OFL and GNU GPL:
+ * [10]SIL Open Font Licence: When OFL fonts are embedded in a
+ document, the OFL's terms do not apply to that document. (See
+ [11]OFL-FAQ for details.
+ * [12]GPL Font Exception: The situation is resolved by granting an
+ additional permission to allow documents to not be covered by the
+ GPL. (The exception is being reviewed).
+
+ The Ubuntu Font Family must also resolve this conflict, ensuring that
+ if the font is embedded and then extracted it is once again clearly
+ under the terms of its libre licence.
+
+ Long-term licensing
+
+ Those individuals involved, especially from Ubuntu and Canonical, are
+ interested in finding a long-term libre licence that finds broad favour
+ across the whole libre/open font community. The deliberation during the
+ past months has been on how to licence the Ubuntu Font Family in the
+ short-term, while knowingly encouraging everyone to pursue a long-term
+ goal.
+ * [13]Copyright assignment will be required so that the Ubuntu Font
+ Family's licensing can be progressively expanded to one (or more)
+ licences, as best practice continues to evolve within the
+ libre/open font community.
+ * Canonical will support and fund legal work on libre font licensing.
+ It is recognised that the cost and time commitments required are
+ likely to be significant. We invite other capable parties to join
+ in supporting this activity.
+
+ The GPL version 3 (GPLv3) will be used for Ubuntu Font Family build
+ scripts and the CC-BY-SA for associated documentation and non-font
+ content: all items which do not end up embedded in general works and
+ documents.
+
+Ubuntu Font Licence
+
+ For the short-term only, the initial licence is the [14]Ubuntu Font
+ License (UFL). This is loosely inspired from the work on the SIL
+ OFL 1.1, and seeks to clarify the issues that arose during discussions
+ and legal review, from the perspective of the backers, Canonical Ltd.
+ Those already using established licensing models such as the GPL, OFL
+ or Creative Commons licensing should have no worries about continuing
+ to use them. The Ubuntu Font Licence (UFL) and the SIL Open Font
+ Licence (SIL OFL) are not identical and should not be confused with
+ each other. Please read the terms precisely. The UFL is only intended
+ as an interim license, and the overriding aim is to support the
+ creation of a more suitable and generic libre font licence. As soon as
+ such a licence is developed, the Ubuntu Font Family will migrate to
+ it—made possible by copyright assignment in the interium. Between the
+ OFL 1.1, and the UFL 1.0, the following changes are made to produce the
+ Ubuntu Font Licence:
+ * Clarification:
+
+ 1. Document embedding (see [15]embedding section above).
+ 2. Apply at point of distribution, instead of receipt
+ 3. Author vs. copyright holder disambiguation (type designers are
+ authors, with the copyright holder normally being the funder)
+ 4. Define "Propagate" (for internationalisation, similar to the GPLv3)
+ 5. Define "Substantially Changed"
+ 6. Trademarks are explicitly not transferred
+ 7. Refine renaming requirement
+
+ Streamlining:
+ 8. Remove "not to be sold separately" clause
+ 9. Remove "Reserved Font Name(s)" declaration
+
+ A visual demonstration of how these points were implemented can be
+ found in the accompanying coloured diff between SIL OFL 1.1 and the
+ Ubuntu Font Licence 1.0: [16]ofl-1.1-ufl-1.0.diff.html
+
+References
+
+ 1. http://font.ubuntu.com/
+ 2. http://www.canonical.com/
+ 3. http://www.daltonmaag.com/
+ 4. http://en.wikipedia.org/wiki/Network_effect
+ 5. http://scripts.sil.org/
+ 6. http://openfontlibrary.org/
+ 7. http://www.softwarefreedom.org/
+ 8. http://code.google.com/webfonts
+ 9. http://www.gnu.org/licenses/gpl-faq.html#CanIUseGPLToolsForNF
+ 10. http://scripts.sil.org/OFL_web
+ 11. http://scripts.sil.org/OFL-FAQ_web
+ 12. http://www.gnu.org/licenses/gpl-faq.html#FontException
+ 13. https://launchpad.net/~uff-contributors
+ 14. http://font.ubuntu.com/ufl/ubuntu-font-licence-1.0.txt
+ 15. http://font.ubuntu.com/ufl/FAQ.html#embedding
+ 16. http://font.ubuntu.com/ufl/ofl-1.1-ufl-1.0.diff.html
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/LICENCE.txt b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/LICENCE.txt
new file mode 100644
index 0000000..ae78a8f
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/LICENCE.txt
@@ -0,0 +1,96 @@
+-------------------------------
+UBUNTU FONT LICENCE Version 1.0
+-------------------------------
+
+PREAMBLE
+This licence allows the licensed fonts to be used, studied, modified and
+redistributed freely. The fonts, including any derivative works, can be
+bundled, embedded, and redistributed provided the terms of this licence
+are met. The fonts and derivatives, however, cannot be released under
+any other licence. The requirement for fonts to remain under this
+licence does not require any document created using the fonts or their
+derivatives to be published under this licence, as long as the primary
+purpose of the document is not to be a vehicle for the distribution of
+the fonts.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this licence and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Original Version" refers to the collection of Font Software components
+as received under this licence.
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to
+a new environment.
+
+"Copyright Holder(s)" refers to all individuals and companies who have a
+copyright ownership of the Font Software.
+
+"Substantially Changed" refers to Modified Versions which can be easily
+identified as dissimilar to the Font Software by users of the Font
+Software comparing the Original Version with the Modified Version.
+
+To "Propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification and with or without charging
+a redistribution fee), making available to the public, and in some
+countries other activities as well.
+
+PERMISSION & CONDITIONS
+This licence does not grant any rights under trademark law and all such
+rights are reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of the Font Software, to propagate the Font Software, subject to
+the below conditions:
+
+1) Each copy of the Font Software must contain the above copyright
+notice and this licence. These can be included either as stand-alone
+text files, human-readable headers or in the appropriate machine-
+readable metadata fields within text or binary files as long as those
+fields can be easily viewed by the user.
+
+2) The font name complies with the following:
+(a) The Original Version must retain its name, unmodified.
+(b) Modified Versions which are Substantially Changed must be renamed to
+avoid use of the name of the Original Version or similar names entirely.
+(c) Modified Versions which are not Substantially Changed must be
+renamed to both (i) retain the name of the Original Version and (ii) add
+additional naming elements to distinguish the Modified Version from the
+Original Version. The name of such Modified Versions must be the name of
+the Original Version, with "derivative X" where X represents the name of
+the new work, appended to that name.
+
+3) The name(s) of the Copyright Holder(s) and any contributor to the
+Font Software shall not be used to promote, endorse or advertise any
+Modified Version, except (i) as required by this licence, (ii) to
+acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with
+their explicit written permission.
+
+4) The Font Software, modified or unmodified, in part or in whole, must
+be distributed entirely under this licence, and must not be distributed
+under any other licence. The requirement for fonts to remain under this
+licence does not affect any document created using the Font Software,
+except any version of the Font Software extracted from a document
+created using the Font Software may only be distributed under this
+licence.
+
+TERMINATION
+This licence becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
+COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
+DEALINGS IN THE FONT SOFTWARE.
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/README.txt b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/README.txt
new file mode 100644
index 0000000..292d4ad
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/README.txt
@@ -0,0 +1,15 @@
+ ----------------------
+ Ubuntu Font Family
+ ======================
+
+The Ubuntu Font Family are a set of matching new libre/open fonts in
+development during 2010--2011. The development is being funded by
+Canonical Ltd on behalf the wider Free Software community and the
+Ubuntu project. The technical font design work and implementation is
+being undertaken by Dalton Maag.
+
+Both the final font Truetype/OpenType files and the design files used
+to produce the font family are distributed under an open licence and
+you are expressly encouraged to experiment, modify, share and improve.
+
+ http://font.ubuntu.com/
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/TRADEMARKS.txt b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/TRADEMARKS.txt
new file mode 100644
index 0000000..d34265b
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/TRADEMARKS.txt
@@ -0,0 +1,4 @@
+Ubuntu and Canonical are registered trademarks of Canonical Ltd.
+
+The licence accompanying these works does not grant any rights
+under trademark law and all such rights are reserved.
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-B.ttf b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-B.ttf
new file mode 100644
index 0000000..7639344
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-B.ttf
Binary files differ
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-BI.ttf b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-BI.ttf
new file mode 100644
index 0000000..337b8a8
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-BI.ttf
Binary files differ
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-L.ttf b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-L.ttf
new file mode 100644
index 0000000..c3b0fa4
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-L.ttf
Binary files differ
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-LI.ttf b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-LI.ttf
new file mode 100644
index 0000000..d65e8ea
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-LI.ttf
Binary files differ
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-M.ttf b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-M.ttf
new file mode 100644
index 0000000..387ef03
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-M.ttf
Binary files differ
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-MI.ttf b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-MI.ttf
new file mode 100644
index 0000000..5b92fcb
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-MI.ttf
Binary files differ
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-R.ttf b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-R.ttf
new file mode 100644
index 0000000..a464464
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-R.ttf
Binary files differ
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-RI.ttf b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-RI.ttf
new file mode 100644
index 0000000..0e09559
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/Ubuntu-RI.ttf
Binary files differ
diff --git a/turtle2d/src/jogamp/graph/font/fonts/ubuntu/copyright.txt b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/copyright.txt
new file mode 100644
index 0000000..3a45d71
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/fonts/ubuntu/copyright.txt
@@ -0,0 +1,5 @@
+Copyright 2010 Canonical Ltd.
+
+This Font Software is licensed under the Ubuntu Font Licence, Version
+1.0. https://launchpad.net/ubuntu-font-licence
+
diff --git a/turtle2d/src/jogamp/graph/font/typecast/TypecastFont.java b/turtle2d/src/jogamp/graph/font/typecast/TypecastFont.java
new file mode 100644
index 0000000..0d018a3
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/typecast/TypecastFont.java
@@ -0,0 +1,268 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.font.typecast;
+
+import jogamp.graph.font.FontInt;
+import jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+import net.java.dev.typecast.ot.OTFont;
+import net.java.dev.typecast.ot.OTFontCollection;
+import net.java.dev.typecast.ot.table.CmapFormat;
+import net.java.dev.typecast.ot.table.CmapIndexEntry;
+import net.java.dev.typecast.ot.table.CmapTable;
+import net.java.dev.typecast.ot.table.HdmxTable;
+import net.java.dev.typecast.ot.table.ID;
+
+import com.jogamp.common.util.IntObjectHashMap;
+import com.jogamp.graph.geom.AABBox;
+
+class TypecastFont implements FontInt {
+ static final boolean DEBUG = false;
+
+ final OTFontCollection fontset;
+ final OTFont font;
+ TypecastHMetrics metrics;
+ final CmapFormat cmapFormat;
+ int cmapentries;
+
+ // FIXME: Add cache size to limit memory usage ??
+ IntObjectHashMap char2Glyph;
+
+ public TypecastFont(OTFontCollection fontset) {
+ this.fontset = fontset;
+ this.font = fontset.getFont(0);
+
+ // FIXME: Generic attempt to find the best CmapTable,
+ // which is assumed to be the one with the most entries (stupid 'eh?)
+ CmapTable cmapTable = font.getCmapTable();
+ CmapFormat[] _cmapFormatP = { null, null, null, null };
+ int platform = -1;
+ int platformLength = -1;
+ int encoding = -1;
+ for(int i=0; i<cmapTable.getNumTables(); i++) {
+ CmapIndexEntry cmapIdxEntry = cmapTable.getCmapIndexEntry(i);
+ int pidx = cmapIdxEntry.getPlatformId();
+ CmapFormat cf = cmapIdxEntry.getFormat();
+ if(DEBUG) {
+ System.err.println("CmapFormat["+i+"]: platform " + pidx +
+ ", encoding "+cmapIdxEntry.getEncodingId() + ": "+cf);
+ }
+ if( _cmapFormatP[pidx] == null ||
+ _cmapFormatP[pidx].getLength() < cf.getLength() ) {
+ _cmapFormatP[pidx] = cf;
+ if( cf.getLength() > platformLength ) {
+ platformLength = cf.getLength() ;
+ platform = pidx;
+ encoding = cmapIdxEntry.getEncodingId();
+ }
+ }
+ }
+ if(0 <= platform) {
+ cmapFormat = _cmapFormatP[platform];
+ if(DEBUG) {
+ System.err.println("Selected CmapFormat: platform " + platform +
+ ", encoding "+encoding + ": "+cmapFormat);
+ }
+ } else {
+ CmapFormat _cmapFormat = null;
+ /*if(null == _cmapFormat) {
+ platform = ID.platformMacintosh;
+ encoding = ID.encodingASCII;
+ _cmapFormat = cmapTable.getCmapFormat(platform, encoding);
+ } */
+ if(null == _cmapFormat) {
+ // default unicode
+ platform = ID.platformMicrosoft;
+ encoding = ID.encodingUnicode;
+ _cmapFormat = cmapTable.getCmapFormat((short)platform, (short)encoding);
+ }
+ if(null == _cmapFormat) {
+ // maybe a symbol font ?
+ platform = ID.platformMicrosoft;
+ encoding = ID.encodingSymbol;
+ _cmapFormat = cmapTable.getCmapFormat((short)platform, (short)encoding);
+ }
+ if(null == _cmapFormat) {
+ throw new RuntimeException("Cannot find a suitable cmap table for font "+font);
+ }
+ cmapFormat = _cmapFormat;
+ if(DEBUG) {
+ System.err.println("Selected CmapFormat (2): platform " + platform + ", encoding "+encoding + ": "+cmapFormat);
+ }
+ }
+
+ cmapentries = 0;
+ for (int i = 0; i < cmapFormat.getRangeCount(); ++i) {
+ CmapFormat.Range range = cmapFormat.getRange(i);
+ cmapentries += range.getEndCode() - range.getStartCode() + 1; // end included
+ }
+ if(DEBUG) {
+ System.err.println("num glyphs: "+font.getNumGlyphs());
+ System.err.println("num cmap entries: "+cmapentries);
+ System.err.println("num cmap ranges: "+cmapFormat.getRangeCount());
+
+ for (int i = 0; i < cmapFormat.getRangeCount(); ++i) {
+ CmapFormat.Range range = cmapFormat.getRange(i);
+ for (int j = range.getStartCode(); j <= range.getEndCode(); ++j) {
+ final int code = cmapFormat.mapCharCode(j);
+ if(code < 15) {
+ System.err.println(" char: " + (int)j + " ( " + (char)j +" ) -> " + code);
+ }
+ }
+ }
+ }
+ char2Glyph = new IntObjectHashMap(cmapentries + cmapentries/4);
+ }
+
+ public String getName() {
+ return fontset.getFileName();
+ }
+
+ public Metrics getMetrics() {
+ if (metrics == null) {
+ metrics = new TypecastHMetrics(this);
+ }
+ return metrics;
+ }
+
+ public Glyph getGlyph(char symbol) {
+ TypecastGlyph result = (TypecastGlyph) char2Glyph.get(symbol);
+ if (null == result) {
+ // final short code = (short) char2Code.get(symbol);
+ short code = (short) cmapFormat.mapCharCode(symbol);
+ if(0 == code && 0 != symbol) {
+ // reserved special glyph IDs by convention
+ switch(symbol) {
+ case ' ': code = Glyph.ID_SPACE; break;
+ case '\n': code = Glyph.ID_CR; break;
+ default: code = Glyph.ID_UNKNOWN;
+ }
+ }
+
+ net.java.dev.typecast.ot.OTGlyph glyph = font.getGlyph(code);
+ if(null == glyph) {
+ glyph = font.getGlyph(Glyph.ID_UNKNOWN);
+ }
+ if(null == glyph) {
+ throw new RuntimeException("Could not retrieve glyph for symbol: <"+symbol+"> "+(int)symbol+" -> glyph id "+code);
+ }
+ Path2D path = TypecastRenderer.buildPath(glyph);
+ result = new TypecastGlyph(this, symbol, code, glyph.getBBox(), glyph.getAdvanceWidth(), path);
+ if(DEBUG) {
+ System.err.println("New glyph: " + (int)symbol + " ( " + (char)symbol +" ) -> " + code + ", contours " + glyph.getPointCount() + ": " + path);
+ }
+ final HdmxTable hdmx = font.getHdmxTable();
+ if (null!= result && null != hdmx) {
+ /*if(DEBUG) {
+ System.err.println("hdmx "+hdmx);
+ }*/
+ for (int i=0; i<hdmx.getNumberOfRecords(); i++)
+ {
+ final HdmxTable.DeviceRecord dr = hdmx.getRecord(i);
+ result.addAdvance(dr.getWidth(code), dr.getPixelSize());
+ if(DEBUG) {
+ System.err.println("hdmx advance : pixelsize = "+dr.getWidth(code)+" : "+ dr.getPixelSize());
+ }
+ }
+ }
+ char2Glyph.put(symbol, result);
+ }
+ return result;
+ }
+
+ public void getOutline(String string, float pixelSize, AffineTransform transform, Path2D[] result) {
+ TypecastRenderer.getOutline(this, string, pixelSize, transform, result);
+ }
+
+ public float getStringWidth(String string, float pixelSize) {
+ float width = 0;
+ final int len = string.length();
+ for (int i=0; i< len; i++)
+ {
+ char character = string.charAt(i);
+ if (character == '\n') {
+ width = 0;
+ } else {
+ Glyph glyph = getGlyph(character);
+ width += glyph.getAdvance(pixelSize, false);
+ }
+ }
+
+ return (int)(width + 0.5f);
+ }
+
+ public float getStringHeight(String string, float pixelSize) {
+ int height = 0;
+
+ for (int i=0; i<string.length(); i++)
+ {
+ char character = string.charAt(i);
+ if (character != ' ')
+ {
+ Glyph glyph = getGlyph(character);
+ AABBox bbox = glyph.getBBox(pixelSize);
+ height = (int)Math.ceil(Math.max(bbox.getHeight(), height));
+ }
+ }
+ return height;
+ }
+
+ public AABBox getStringBounds(CharSequence string, float pixelSize) {
+ if (string == null) {
+ return new AABBox();
+ }
+ final Metrics metrics = getMetrics();
+ final float lineGap = metrics.getLineGap(pixelSize);
+ final float ascent = metrics.getAscent(pixelSize);
+ final float descent = metrics.getDescent(pixelSize);
+ final float advanceY = lineGap - descent + ascent;
+ float totalHeight = 0;
+ float totalWidth = 0;
+ float curLineWidth = 0;
+ for (int i=0; i<string.length(); i++) {
+ char character = string.charAt(i);
+ if (character == '\n') {
+ totalWidth = Math.max(curLineWidth, totalWidth);
+ curLineWidth = 0;
+ totalHeight -= advanceY;
+ continue;
+ }
+ Glyph glyph = getGlyph(character);
+ curLineWidth += glyph.getAdvance(pixelSize, true);
+ }
+ if (curLineWidth > 0) {
+ totalHeight -= advanceY;
+ totalWidth = Math.max(curLineWidth, totalWidth);
+ }
+ return new AABBox(0, 0, 0, totalWidth, totalHeight,0);
+ }
+
+ final public int getNumGlyphs() {
+ return font.getNumGlyphs();
+ }
+} \ No newline at end of file
diff --git a/turtle2d/src/jogamp/graph/font/typecast/TypecastFontConstructor.java b/turtle2d/src/jogamp/graph/font/typecast/TypecastFontConstructor.java
new file mode 100644
index 0000000..5fb9d32
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/typecast/TypecastFontConstructor.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.font.typecast;
+
+import java.io.File;
+import java.io.IOException;
+
+import jogamp.graph.font.FontConstructor;
+
+import net.java.dev.typecast.ot.OTFontCollection;
+
+import com.jogamp.graph.font.Font;
+
+
+public class TypecastFontConstructor implements FontConstructor {
+
+ public Font create(String path) {
+ OTFontCollection fontset;
+ try {
+ fontset = OTFontCollection.create(new File(path));
+ return new TypecastFont(fontset);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+} \ No newline at end of file
diff --git a/turtle2d/src/jogamp/graph/font/typecast/TypecastGlyph.java b/turtle2d/src/jogamp/graph/font/typecast/TypecastGlyph.java
new file mode 100644
index 0000000..88d865f
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/typecast/TypecastGlyph.java
@@ -0,0 +1,232 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.font.typecast;
+
+import java.util.HashMap;
+
+import jogamp.graph.font.FontInt;
+import jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.geom.AABBox;
+
+public class TypecastGlyph implements FontInt.Glyph {
+ public class Advance
+ {
+ final Font font;
+ final float advance;
+ HashMap<Float, Float> size2advance = new HashMap<Float, Float>();
+
+ public Advance(Font font, float advance)
+ {
+ this.font = font;
+ this.advance = advance;
+ }
+
+ public void reset() {
+ size2advance.clear();
+ }
+
+ public float getScale(float pixelSize)
+ {
+ return this.font.getMetrics().getScale(pixelSize);
+ }
+
+ public void add(float advance, float size)
+ {
+ size2advance.put(size, advance);
+ }
+
+ public float get(float size, boolean useFrationalMetrics)
+ {
+ Float fo = size2advance.get(size);
+ if(null == fo) {
+ float value = (this.advance * getScale(size));
+ if (useFrationalMetrics == false) {
+ //value = (float)Math.ceil(value);
+ // value = (int)value;
+ value = (int) ( value + 0.5f ) ; // TODO: check
+ }
+ size2advance.put(size, value);
+ return value;
+ }
+ return fo.floatValue();
+ }
+
+ public String toString()
+ {
+ return "\nAdvance:"+
+ "\n advance: "+this.advance+
+ "\n advances: \n"+size2advance;
+ }
+ }
+
+ public class Metrics
+ {
+ AABBox bbox;
+ Advance advance;
+
+ public Metrics(Font font, AABBox bbox, float advance)
+ {
+ this.bbox = bbox;
+ this.advance = new Advance(font, advance);
+ }
+
+ public void reset() {
+ advance.reset();
+ }
+
+ public float getScale(float pixelSize)
+ {
+ return this.advance.getScale(pixelSize);
+ }
+
+ public AABBox getBBox()
+ {
+ return this.bbox;
+ }
+
+ public void addAdvance(float advance, float size)
+ {
+ this.advance.add(advance, size);
+ }
+
+ public float getAdvance(float size, boolean useFrationalMetrics)
+ {
+ return this.advance.get(size, useFrationalMetrics);
+ }
+
+ public String toString()
+ {
+ return "\nMetrics:"+
+ "\n bbox: "+this.bbox+
+ this.advance;
+ }
+ }
+
+ public static final short INVALID_ID = (short)((1 << 16) - 1);
+ public static final short MAX_ID = (short)((1 << 16) - 2);
+
+ private final Font font;
+
+ char symbol;
+ short id;
+ int advance;
+ Metrics metrics;
+
+ protected Path2D path; // in EM units
+ protected Path2D pathSized;
+ protected float numberSized;
+
+ protected TypecastGlyph(Font font, char symbol) {
+ this.font = font;
+ this.symbol = symbol;
+ }
+
+ protected TypecastGlyph(Font font,
+ char symbol, short id, AABBox bbox, int advance, Path2D path) {
+ this.font = font;
+ this.symbol = symbol;
+ this.advance = advance;
+
+ init(id, bbox, advance);
+
+ this.path = path;
+ this.pathSized = null;
+ this.numberSized = 0.0f;
+ }
+
+ void init(short id, AABBox bbox, int advance) {
+ this.id = id;
+ this.advance = advance;
+ this.metrics = new Metrics(this.font, bbox, this.advance);
+ }
+
+ public void reset(Path2D path) {
+ this.path = path;
+ this.metrics.reset();
+ }
+
+ public Font getFont() {
+ return this.font;
+ }
+
+ public char getSymbol() {
+ return this.symbol;
+ }
+
+ AABBox getBBoxUnsized() {
+ return this.metrics.getBBox();
+ }
+
+ public AABBox getBBox() {
+ return this.metrics.getBBox();
+ }
+
+ public Metrics getMetrics() {
+ return this.metrics;
+ }
+
+ public short getID() {
+ return this.id;
+ }
+
+ public float getScale(float pixelSize) {
+ return this.metrics.getScale(pixelSize);
+ }
+
+ public AABBox getBBox(float pixelSize) {
+ final float size = getScale(pixelSize);
+ AABBox newBox = getBBox().clone();
+ newBox.scale(size);
+ return newBox;
+ }
+
+ protected void addAdvance(float advance, float size) {
+ this.metrics.addAdvance(advance, size);
+ }
+
+ public float getAdvance(float pixelSize, boolean useFrationalMetrics) {
+ return this.metrics.getAdvance(pixelSize, useFrationalMetrics);
+ }
+
+ public Path2D getPath() {
+ return this.path;
+ }
+
+ public Path2D getPath(float pixelSize) {
+ final float size = getScale(pixelSize);
+
+ if (this.numberSized != size) {
+ this.numberSized = size;
+ this.pathSized = AffineTransform.getScaleInstance(null, size, size).createTransformedShape(getPath());
+ }
+ return this.pathSized;
+ }
+}
diff --git a/turtle2d/src/jogamp/graph/font/typecast/TypecastHMetrics.java b/turtle2d/src/jogamp/graph/font/typecast/TypecastHMetrics.java
new file mode 100644
index 0000000..cd85954
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/typecast/TypecastHMetrics.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.font.typecast;
+
+import net.java.dev.typecast.ot.table.HeadTable;
+import net.java.dev.typecast.ot.table.HheaTable;
+import com.jogamp.graph.font.Font.Metrics;
+import com.jogamp.graph.geom.AABBox;
+
+class TypecastHMetrics implements Metrics {
+ private final TypecastFont fontImpl;
+
+ // HeadTable
+ private final HeadTable headTable;
+ private final float unitsPerEM_Inv;
+ private final AABBox bbox;
+ // HheaTable
+ private final HheaTable hheaTable;
+ // VheaTable (for horizontal fonts)
+ // private final VheaTable vheaTable;
+
+ public TypecastHMetrics(TypecastFont fontImpl) {
+ this.fontImpl = fontImpl;
+ headTable = this.fontImpl.font.getHeadTable();
+ hheaTable = this.fontImpl.font.getHheaTable();
+ // vheaTable = this.fontImpl.font.getVheaTable();
+ unitsPerEM_Inv = 1.0f / ( (float) headTable.getUnitsPerEm() );
+
+ int maxWidth = headTable.getXMax() - headTable.getXMin();
+ int maxHeight = headTable.getYMax() - headTable.getYMin();
+ float lowx= headTable.getXMin();
+ float lowy = -(headTable.getYMin()+maxHeight);
+ float highx = lowx + maxWidth;
+ float highy = lowy + maxHeight;
+ bbox = new AABBox(lowx, lowy, 0, highx, highy, 0); // invert
+ }
+
+ public final float getAscent(float pixelSize) {
+ return getScale(pixelSize) * -hheaTable.getAscender(); // invert
+ }
+ public final float getDescent(float pixelSize) {
+ return getScale(pixelSize) * -hheaTable.getDescender(); // invert
+ }
+ public final float getLineGap(float pixelSize) {
+ return getScale(pixelSize) * -hheaTable.getLineGap(); // invert
+ }
+ public final float getMaxExtend(float pixelSize) {
+ return getScale(pixelSize) * hheaTable.getXMaxExtent();
+ }
+ public final float getScale(float pixelSize) {
+ return pixelSize * unitsPerEM_Inv;
+ }
+ public final AABBox getBBox(float pixelSize) {
+ AABBox res = new AABBox(bbox.getLow(), bbox.getHigh());
+ res.scale(getScale(pixelSize));
+ return res;
+ }
+} \ No newline at end of file
diff --git a/turtle2d/src/jogamp/graph/font/typecast/TypecastRenderer.java b/turtle2d/src/jogamp/graph/font/typecast/TypecastRenderer.java
new file mode 100644
index 0000000..410f5b7
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/font/typecast/TypecastRenderer.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.font.typecast;
+
+import jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+
+import com.jogamp.graph.font.Font;
+import net.java.dev.typecast.ot.Point;
+import net.java.dev.typecast.ot.OTGlyph;
+
+/**
+ * Factory to build a {@link com.jogamp.graph.geom.Path2D Path2D} from
+ * {@link net.java.dev.typecast.ot.OTGlyph Glyph}s.
+ */
+public class TypecastRenderer {
+
+ public static void getOutline(TypecastFont font,
+ String string, float pixelSize, AffineTransform transform, Path2D[] p)
+ {
+ if (string == null) {
+ return;
+ }
+ Font.Metrics metrics = font.getMetrics();
+ float advanceTotal = 0;
+ float lineGap = metrics.getLineGap(pixelSize) ;
+ float ascent = metrics.getAscent(pixelSize) ;
+ float descent = metrics.getDescent(pixelSize) ;
+ if (transform == null) {
+ transform = new AffineTransform();
+ }
+ AffineTransform t = new AffineTransform();
+
+ float advanceY = lineGap - descent + ascent;
+ float y = 0;
+ for (int i=0; i<string.length(); i++)
+ {
+ p[i] = new Path2D();
+ p[i].reset();
+ t.setTransform(transform);
+ char character = string.charAt(i);
+ if (character == '\n') {
+ y -= advanceY;
+ advanceTotal = 0;
+ continue;
+ } else if (character == ' ') {
+ advanceTotal += font.font.getHmtxTable().getAdvanceWidth(TypecastGlyph.ID_SPACE) * metrics.getScale(pixelSize);
+ continue;
+ }
+ TypecastGlyph glyph = (TypecastGlyph) font.getGlyph(character);
+ Path2D gp = glyph.getPath();
+ float scale = metrics.getScale(pixelSize);
+ t.translate(advanceTotal, y);
+ t.scale(scale, scale);
+ p[i].append(gp.iterator(t), false);
+ advanceTotal += glyph.getAdvance(pixelSize, true);
+ }
+ }
+
+ /**
+ * Build a {@link com.jogamp.graph.geom.Path2D Path2D} from a
+ * {@link net.java.dev.typecast.ot.OTGlyph Glyph}. This glyph path can then
+ * be transformed and rendered.
+ */
+ public static Path2D buildPath(OTGlyph glyph) {
+
+ if (glyph == null) {
+ return null;
+ }
+
+ Path2D glyphPath = new Path2D();
+
+ // Iterate through all of the points in the glyph. Each time we find a
+ // contour end point, add the point range to the path.
+ int firstIndex = 0;
+ int count = 0;
+ for (int i = 0; i < glyph.getPointCount(); i++) {
+ count++;
+ if (glyph.getPoint(i).endOfContour) {
+ addContourToPath(glyphPath, glyph, firstIndex, count);
+ firstIndex = i + 1;
+ count = 0;
+ }
+ }
+ return glyphPath;
+ }
+
+ private static void addContourToPath(Path2D gp, OTGlyph glyph, int startIndex, int count) {
+ int offset = 0;
+ while (offset < count) {
+ Point point = glyph.getPoint(startIndex + offset%count);
+ Point point_plus1 = glyph.getPoint(startIndex + (offset+1)%count);
+ Point point_plus2 = glyph.getPoint(startIndex + (offset+2)%count);
+ if(offset == 0)
+ {
+ gp.moveTo(point.x, -point.y);
+ }
+
+ if (point.onCurve) {
+ if (point_plus1.onCurve) {
+ // s = new Line2D.Float(point.x, -point.y, point_plus1.x, -point_plus1.y);
+ gp.lineTo( point_plus1.x, -point_plus1.y );
+ offset++;
+ } else {
+ if (point_plus2.onCurve) {
+ // s = new QuadCurve2D.Float( point.x, -point.y, point_plus1.x, -point_plus1.y, point_plus2.x, -point_plus2.y);
+ gp.quadTo(point_plus1.x, -point_plus1.y, point_plus2.x, -point_plus2.y);
+ offset+=2;
+ } else {
+ // s = new QuadCurve2D.Float(point.x,-point.y,point_plus1.x,-point_plus1.y,
+ // midValue(point_plus1.x, point_plus2.x), -midValue(point_plus1.y, point_plus2.y));
+ gp.quadTo(point_plus1.x, -point_plus1.y, midValue(point_plus1.x, point_plus2.x), -midValue(point_plus1.y, point_plus2.y));
+ offset+=2;
+ }
+ }
+ } else {
+ if (point_plus1.onCurve) {
+ // s = new QuadCurve2D.Float(midValue(point_minus1.x, point.x), -midValue(point_minus1.y, point.y),
+ // point.x, -point.y, point_plus1.x, -point_plus1.y);
+ //gp.curve3(point_plus1.x, -point_plus1.y, point.x, -point.y);
+ gp.quadTo(point.x, -point.y, point_plus1.x, -point_plus1.y);
+ offset++;
+
+ } else {
+ // s = new QuadCurve2D.Float(midValue(point_minus1.x, point.x), -midValue(point_minus1.y, point.y), point.x, -point.y,
+ // midValue(point.x, point_plus1.x), -midValue(point.y, point_plus1.y));
+ //gp.curve3(midValue(point.x, point_plus1.x), -midValue(point.y, point_plus1.y), point.x, -point.y);
+ gp.quadTo(point.x, -point.y, midValue(point.x, point_plus1.x), -midValue(point.y, point_plus1.y));
+ offset++;
+ }
+ }
+ }
+ }
+
+ private static int midValue(int a, int b) {
+ return a + (b - a)/2;
+ }
+}
diff --git a/turtle2d/src/jogamp/graph/geom/plane/AffineTransform.java b/turtle2d/src/jogamp/graph/geom/plane/AffineTransform.java
new file mode 100644
index 0000000..2ba9f8d
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/geom/plane/AffineTransform.java
@@ -0,0 +1,580 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.geom.plane;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import jogamp.graph.math.MathFloat;
+import org.apache.harmony.misc.HashCode;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Vertex.Factory;
+
+public class AffineTransform implements Cloneable, Serializable {
+
+ private static final long serialVersionUID = 1330973210523860834L;
+
+ static final String determinantIsZero = "Determinant is zero";
+
+ public static final int TYPE_IDENTITY = 0;
+ public static final int TYPE_TRANSLATION = 1;
+ public static final int TYPE_UNIFORM_SCALE = 2;
+ public static final int TYPE_GENERAL_SCALE = 4;
+ public static final int TYPE_QUADRANT_ROTATION = 8;
+ public static final int TYPE_GENERAL_ROTATION = 16;
+ public static final int TYPE_GENERAL_TRANSFORM = 32;
+ public static final int TYPE_FLIP = 64;
+ public static final int TYPE_MASK_SCALE = TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE;
+ public static final int TYPE_MASK_ROTATION = TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION;
+
+ /**
+ * The <code>TYPE_UNKNOWN</code> is an initial type value
+ */
+ static final int TYPE_UNKNOWN = -1;
+
+ /**
+ * The min value equivalent to zero. If absolute value less then ZERO it considered as zero.
+ */
+ static final float ZERO = (float) 1E-10;
+
+ private final Vertex.Factory<? extends Vertex> pointFactory;
+
+ /**
+ * The values of transformation matrix
+ */
+ float m00;
+ float m10;
+ float m01;
+ float m11;
+ float m02;
+ float m12;
+
+ /**
+ * The transformation <code>type</code>
+ */
+ transient int type;
+
+ public AffineTransform() {
+ pointFactory = null;
+ type = TYPE_IDENTITY;
+ m00 = m11 = 1.0f;
+ m10 = m01 = m02 = m12 = 0.0f;
+ }
+
+ public AffineTransform(Factory<? extends Vertex> factory) {
+ pointFactory = factory;
+ type = TYPE_IDENTITY;
+ m00 = m11 = 1.0f;
+ m10 = m01 = m02 = m12 = 0.0f;
+ }
+
+ public AffineTransform(AffineTransform t) {
+ this.pointFactory = t.pointFactory;
+ this.type = t.type;
+ this.m00 = t.m00;
+ this.m10 = t.m10;
+ this.m01 = t.m01;
+ this.m11 = t.m11;
+ this.m02 = t.m02;
+ this.m12 = t.m12;
+ }
+
+ public AffineTransform(Vertex.Factory<? extends Vertex> factory, float m00, float m10, float m01, float m11, float m02, float m12) {
+ pointFactory = factory;
+ this.type = TYPE_UNKNOWN;
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m02 = m02;
+ this.m12 = m12;
+ }
+
+ public AffineTransform(Vertex.Factory<? extends Vertex> factory, float[] matrix) {
+ pointFactory = factory;
+ this.type = TYPE_UNKNOWN;
+ m00 = matrix[0];
+ m10 = matrix[1];
+ m01 = matrix[2];
+ m11 = matrix[3];
+ if (matrix.length > 4) {
+ m02 = matrix[4];
+ m12 = matrix[5];
+ }
+ }
+
+ /*
+ * Method returns type of affine transformation.
+ *
+ * Transform matrix is
+ * m00 m01 m02
+ * m10 m11 m12
+ *
+ * According analytic geometry new basis vectors are (m00, m01) and (m10, m11),
+ * translation vector is (m02, m12). Original basis vectors are (1, 0) and (0, 1).
+ * Type transformations classification:
+ * TYPE_IDENTITY - new basis equals original one and zero translation
+ * TYPE_TRANSLATION - translation vector isn't zero
+ * TYPE_UNIFORM_SCALE - vectors length of new basis equals
+ * TYPE_GENERAL_SCALE - vectors length of new basis doesn't equal
+ * TYPE_FLIP - new basis vector orientation differ from original one
+ * TYPE_QUADRANT_ROTATION - new basis is rotated by 90, 180, 270, or 360 degrees
+ * TYPE_GENERAL_ROTATION - new basis is rotated by arbitrary angle
+ * TYPE_GENERAL_TRANSFORM - transformation can't be inversed
+ */
+ public int getType() {
+ if (type != TYPE_UNKNOWN) {
+ return type;
+ }
+
+ int type = 0;
+
+ if (m00 * m01 + m10 * m11 != 0.0) {
+ type |= TYPE_GENERAL_TRANSFORM;
+ return type;
+ }
+
+ if (m02 != 0.0 || m12 != 0.0) {
+ type |= TYPE_TRANSLATION;
+ } else
+ if (m00 == 1.0 && m11 == 1.0 && m01 == 0.0 && m10 == 0.0) {
+ type = TYPE_IDENTITY;
+ return type;
+ }
+
+ if (m00 * m11 - m01 * m10 < 0.0) {
+ type |= TYPE_FLIP;
+ }
+
+ float dx = m00 * m00 + m10 * m10;
+ float dy = m01 * m01 + m11 * m11;
+ if (dx != dy) {
+ type |= TYPE_GENERAL_SCALE;
+ } else
+ if (dx != 1.0) {
+ type |= TYPE_UNIFORM_SCALE;
+ }
+
+ if ((m00 == 0.0 && m11 == 0.0) ||
+ (m10 == 0.0 && m01 == 0.0 && (m00 < 0.0 || m11 < 0.0)))
+ {
+ type |= TYPE_QUADRANT_ROTATION;
+ } else
+ if (m01 != 0.0 || m10 != 0.0) {
+ type |= TYPE_GENERAL_ROTATION;
+ }
+
+ return type;
+ }
+
+ public float getScaleX() {
+ return m00;
+ }
+
+ public float getScaleY() {
+ return m11;
+ }
+
+ public float getShearX() {
+ return m01;
+ }
+
+ public float getShearY() {
+ return m10;
+ }
+
+ public float getTranslateX() {
+ return m02;
+ }
+
+ public float getTranslateY() {
+ return m12;
+ }
+
+ public boolean isIdentity() {
+ return getType() == TYPE_IDENTITY;
+ }
+
+ public void getMatrix(float[] matrix) {
+ matrix[0] = m00;
+ matrix[1] = m10;
+ matrix[2] = m01;
+ matrix[3] = m11;
+ if (matrix.length > 4) {
+ matrix[4] = m02;
+ matrix[5] = m12;
+ }
+ }
+
+ public float getDeterminant() {
+ return m00 * m11 - m01 * m10;
+ }
+
+ public void setTransform(float m00, float m10, float m01, float m11, float m02, float m12) {
+ this.type = TYPE_UNKNOWN;
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m02 = m02;
+ this.m12 = m12;
+ }
+
+ public void setTransform(AffineTransform t) {
+ type = t.type;
+ setTransform(t.m00, t.m10, t.m01, t.m11, t.m02, t.m12);
+ }
+
+ public void setToIdentity() {
+ type = TYPE_IDENTITY;
+ m00 = m11 = 1.0f;
+ m10 = m01 = m02 = m12 = 0.0f;
+ }
+
+ public void setToTranslation(float mx, float my) {
+ m00 = m11 = 1.0f;
+ m01 = m10 = 0.0f;
+ m02 = mx;
+ m12 = my;
+ if (mx == 0.0f && my == 0.0f) {
+ type = TYPE_IDENTITY;
+ } else {
+ type = TYPE_TRANSLATION;
+ }
+ }
+
+ public void setToScale(float scx, float scy) {
+ m00 = scx;
+ m11 = scy;
+ m10 = m01 = m02 = m12 = 0.0f;
+ if (scx != 1.0f || scy != 1.0f) {
+ type = TYPE_UNKNOWN;
+ } else {
+ type = TYPE_IDENTITY;
+ }
+ }
+
+ public void setToShear(float shx, float shy) {
+ m00 = m11 = 1.0f;
+ m02 = m12 = 0.0f;
+ m01 = shx;
+ m10 = shy;
+ if (shx != 0.0f || shy != 0.0f) {
+ type = TYPE_UNKNOWN;
+ } else {
+ type = TYPE_IDENTITY;
+ }
+ }
+
+ public void setToRotation(float angle) {
+ float sin = MathFloat.sin(angle);
+ float cos = MathFloat.cos(angle);
+ if (MathFloat.abs(cos) < ZERO) {
+ cos = 0.0f;
+ sin = sin > 0.0f ? 1.0f : -1.0f;
+ } else
+ if (MathFloat.abs(sin) < ZERO) {
+ sin = 0.0f;
+ cos = cos > 0.0f ? 1.0f : -1.0f;
+ }
+ m00 = m11 = cos;
+ m01 = -sin;
+ m10 = sin;
+ m02 = m12 = 0.0f;
+ type = TYPE_UNKNOWN;
+ }
+
+ public void setToRotation(float angle, float px, float py) {
+ setToRotation(angle);
+ m02 = px * (1.0f - m00) + py * m10;
+ m12 = py * (1.0f - m00) - px * m10;
+ type = TYPE_UNKNOWN;
+ }
+
+ public static <T extends Vertex> AffineTransform getTranslateInstance(Vertex.Factory<? extends Vertex> factory, float mx, float my) {
+ AffineTransform t = new AffineTransform(factory);
+ t.setToTranslation(mx, my);
+ return t;
+ }
+
+ public static <T extends Vertex> AffineTransform getScaleInstance(Vertex.Factory<? extends Vertex> factory, float scx, float scY) {
+ AffineTransform t = new AffineTransform(factory);
+ t.setToScale(scx, scY);
+ return t;
+ }
+
+ public static <T extends Vertex> AffineTransform getShearInstance(Vertex.Factory<? extends Vertex> factory, float shx, float shy) {
+ AffineTransform t = new AffineTransform(factory);
+ t.setToShear(shx, shy);
+ return t;
+ }
+
+ public static <T extends Vertex> AffineTransform getRotateInstance(Vertex.Factory<? extends Vertex> factory, float angle) {
+ AffineTransform t = new AffineTransform(factory);
+ t.setToRotation(angle);
+ return t;
+ }
+
+ public static <T extends Vertex> AffineTransform getRotateInstance(Vertex.Factory<? extends Vertex> factory, float angle, float x, float y) {
+ AffineTransform t = new AffineTransform(factory);
+ t.setToRotation(angle, x, y);
+ return t;
+ }
+
+ public void translate(float mx, float my) {
+ concatenate(AffineTransform.getTranslateInstance(pointFactory, mx, my));
+ }
+
+ public void scale(float scx, float scy) {
+ concatenate(AffineTransform.getScaleInstance(pointFactory, scx, scy));
+ }
+
+ public void shear(float shx, float shy) {
+ concatenate(AffineTransform.getShearInstance(pointFactory, shx, shy));
+ }
+
+ public void rotate(float angle) {
+ concatenate(AffineTransform.getRotateInstance(pointFactory, angle));
+ }
+
+ public void rotate(float angle, float px, float py) {
+ concatenate(AffineTransform.getRotateInstance(pointFactory, angle, px, py));
+ }
+
+ /**
+ * Multiply matrix of two AffineTransform objects.
+ * The first argument's {@link Vertex.Factory} is being used.
+ *
+ * @param t1 - the AffineTransform object is a multiplicand
+ * @param t2 - the AffineTransform object is a multiplier
+ * @return an AffineTransform object that is a result of t1 multiplied by matrix t2.
+ */
+ AffineTransform multiply(AffineTransform t1, AffineTransform t2) {
+ return new AffineTransform(t1.pointFactory,
+ t1.m00 * t2.m00 + t1.m10 * t2.m01, // m00
+ t1.m00 * t2.m10 + t1.m10 * t2.m11, // m01
+ t1.m01 * t2.m00 + t1.m11 * t2.m01, // m10
+ t1.m01 * t2.m10 + t1.m11 * t2.m11, // m11
+ t1.m02 * t2.m00 + t1.m12 * t2.m01 + t2.m02, // m02
+ t1.m02 * t2.m10 + t1.m12 * t2.m11 + t2.m12);// m12
+ }
+
+ public void concatenate(AffineTransform t) {
+ setTransform(multiply(t, this));
+ }
+
+ public void preConcatenate(AffineTransform t) {
+ setTransform(multiply(this, t));
+ }
+
+ public AffineTransform createInverse() throws NoninvertibleTransformException {
+ float det = getDeterminant();
+ if (MathFloat.abs(det) < ZERO) {
+ throw new NoninvertibleTransformException(determinantIsZero);
+ }
+ return new AffineTransform(
+ this.pointFactory,
+ m11 / det, // m00
+ -m10 / det, // m10
+ -m01 / det, // m01
+ m00 / det, // m11
+ (m01 * m12 - m11 * m02) / det, // m02
+ (m10 * m02 - m00 * m12) / det // m12
+ );
+ }
+
+ public Vertex transform(Vertex src, Vertex dst) {
+ if (dst == null) {
+ dst = pointFactory.create();
+ }
+
+ float x = src.getX();
+ float y = src.getY();
+
+ dst.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
+ return dst;
+ }
+
+ public void transform(Vertex[] src, int srcOff, Vertex[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ Vertex srcPoint = src[srcOff++];
+ float x = srcPoint.getX();
+ float y = srcPoint.getY();
+ Vertex dstPoint = dst[dstOff];
+ if (dstPoint == null) {
+ throw new IllegalArgumentException("dst["+dstOff+"] is null");
+ }
+ dstPoint.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
+ dst[dstOff++] = dstPoint;
+ }
+ }
+
+ public void transform(float[] src, int srcOff, float[] dst, int dstOff, int length) {
+ int step = 2;
+ if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) {
+ srcOff = srcOff + length * 2 - 2;
+ dstOff = dstOff + length * 2 - 2;
+ step = -2;
+ }
+ while (--length >= 0) {
+ float x = src[srcOff + 0];
+ float y = src[srcOff + 1];
+ dst[dstOff + 0] = x * m00 + y * m01 + m02;
+ dst[dstOff + 1] = x * m10 + y * m11 + m12;
+ srcOff += step;
+ dstOff += step;
+ }
+ }
+
+ public Vertex deltaTransform(Vertex src, Vertex dst) {
+ if (dst == null) {
+ dst = pointFactory.create();
+ }
+
+ float x = src.getX();
+ float y = src.getY();
+
+ dst.setCoord(x * m00 + y * m01, x * m10 + y * m11);
+ return dst;
+ }
+
+ public void deltaTransform(float[] src, int srcOff, float[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ float x = src[srcOff++];
+ float y = src[srcOff++];
+ dst[dstOff++] = x * m00 + y * m01;
+ dst[dstOff++] = x * m10 + y * m11;
+ }
+ }
+
+ public Vertex inverseTransform(Vertex src, Vertex dst) throws NoninvertibleTransformException {
+ float det = getDeterminant();
+ if (MathFloat.abs(det) < ZERO) {
+ throw new NoninvertibleTransformException(determinantIsZero);
+ }
+ if (dst == null) {
+ dst = pointFactory.create();
+ }
+
+ float x = src.getX() - m02;
+ float y = src.getY() - m12;
+
+ dst.setCoord((x * m11 - y * m01) / det, (y * m00 - x * m10) / det);
+ return dst;
+ }
+
+ public void inverseTransform(float[] src, int srcOff, float[] dst, int dstOff, int length)
+ throws NoninvertibleTransformException
+ {
+ float det = getDeterminant();
+ if (MathFloat.abs(det) < ZERO) {
+ throw new NoninvertibleTransformException(determinantIsZero);
+ }
+
+ while (--length >= 0) {
+ float x = src[srcOff++] - m02;
+ float y = src[srcOff++] - m12;
+ dst[dstOff++] = (x * m11 - y * m01) / det;
+ dst[dstOff++] = (y * m00 - x * m10) / det;
+ }
+ }
+
+ public Path2D createTransformedShape(Path2D src) {
+ if (src == null) {
+ return null;
+ }
+ if (src instanceof Path2D) {
+ return ((Path2D)src).createTransformedShape(this);
+ }
+ PathIterator path = src.iterator(this);
+ Path2D dst = new Path2D(path.getWindingRule());
+ dst.append(path, false);
+ return dst;
+ }
+
+ @Override
+ public String toString() {
+ return
+ getClass().getName() +
+ "[[" + m00 + ", " + m01 + ", " + m02 + "], [" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ + m10 + ", " + m11 + ", " + m12 + "]]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(m00);
+ hash.append(m01);
+ hash.append(m02);
+ hash.append(m10);
+ hash.append(m11);
+ hash.append(m12);
+ return hash.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof AffineTransform) {
+ AffineTransform t = (AffineTransform)obj;
+ return
+ m00 == t.m00 && m01 == t.m01 &&
+ m02 == t.m02 && m10 == t.m10 &&
+ m11 == t.m11 && m12 == t.m12;
+ }
+ return false;
+ }
+
+
+ /**
+ * Write AffineTrasform object to the output steam.
+ * @param stream - the output stream
+ * @throws IOException - if there are I/O errors while writing to the output strem
+ */
+ private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ }
+
+
+ /**
+ * Read AffineTransform object from the input stream
+ * @param stream - the input steam
+ * @throws IOException - if there are I/O errors while reading from the input strem
+ * @throws ClassNotFoundException - if class could not be found
+ */
+ private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ type = TYPE_UNKNOWN;
+ }
+
+}
+
diff --git a/turtle2d/src/jogamp/graph/geom/plane/IllegalPathStateException.java b/turtle2d/src/jogamp/graph/geom/plane/IllegalPathStateException.java
new file mode 100644
index 0000000..55211b3
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/geom/plane/IllegalPathStateException.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.geom.plane;
+
+public class IllegalPathStateException extends RuntimeException {
+
+ private static final long serialVersionUID = -5158084205220481094L;
+
+ public IllegalPathStateException() {
+ }
+
+ public IllegalPathStateException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/turtle2d/src/jogamp/graph/geom/plane/NoninvertibleTransformException.java b/turtle2d/src/jogamp/graph/geom/plane/NoninvertibleTransformException.java
new file mode 100644
index 0000000..398a03f
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/geom/plane/NoninvertibleTransformException.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.geom.plane;
+
+public class NoninvertibleTransformException extends java.lang.Exception {
+
+ private static final long serialVersionUID = 6137225240503990466L;
+
+ public NoninvertibleTransformException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/turtle2d/src/jogamp/graph/geom/plane/Path2D.java b/turtle2d/src/jogamp/graph/geom/plane/Path2D.java
new file mode 100644
index 0000000..4318913
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/geom/plane/Path2D.java
@@ -0,0 +1,428 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.geom.plane;
+
+import java.util.NoSuchElementException;
+
+import com.jogamp.graph.geom.AABBox;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.opengl.SVertex;
+
+import jogamp.graph.math.plane.Crossing;
+
+public final class Path2D implements Cloneable {
+
+ public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
+ public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
+
+ static final String invalidWindingRuleValue = "Invalid winding rule value";
+ static final String iteratorOutOfBounds = "Iterator out of bounds";
+
+ /**
+ * The buffers size
+ */
+ private static final int BUFFER_SIZE = 10;
+
+ /**
+ * The buffers capacity
+ */
+ private static final int BUFFER_CAPACITY = 10;
+
+ /**
+ * The point's types buffer
+ */
+ byte[] types;
+
+ /**
+ * The points buffer
+ */
+ float[] points;
+
+ /**
+ * The point's type buffer size
+ */
+ int typeSize;
+
+ /**
+ * The points buffer size
+ */
+ int pointSize;
+
+ /**
+ * The path rule
+ */
+ int rule;
+
+ /**
+ * The space amount in points buffer for different segmenet's types
+ */
+ static int pointShift[] = {
+ 2, // MOVETO
+ 2, // LINETO
+ 4, // QUADTO
+ 6, // CUBICTO
+ 0}; // CLOSE
+
+ /*
+ * GeneralPath path iterator
+ */
+ class Iterator implements PathIterator {
+
+ /**
+ * The current cursor position in types buffer
+ */
+ int typeIndex;
+
+ /**
+ * The current cursor position in points buffer
+ */
+ int pointIndex;
+
+ /**
+ * The source GeneralPath object
+ */
+ Path2D p;
+
+ /**
+ * The path iterator transformation
+ */
+ AffineTransform t;
+
+ /**
+ * Constructs a new GeneralPath.Iterator for given general path
+ * @param path - the source GeneralPath object
+ */
+ Iterator(Path2D path) {
+ this(path, null);
+ }
+
+ /**
+ * Constructs a new GeneralPath.Iterator for given general path and transformation
+ * @param path - the source GeneralPath object
+ * @param at - the AffineTransform object to apply rectangle path
+ */
+ Iterator(Path2D path, AffineTransform at) {
+ this.p = path;
+ this.t = at;
+ }
+
+ public int getWindingRule() {
+ return p.getWindingRule();
+ }
+
+ public boolean isDone() {
+ return typeIndex >= p.typeSize;
+ }
+
+ public void next() {
+ typeIndex++;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException(iteratorOutOfBounds);
+ }
+ int type = p.types[typeIndex];
+ int count = Path2D.pointShift[type];
+ System.arraycopy(p.points, pointIndex, coords, 0, count);
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count / 2);
+ }
+ pointIndex += count;
+ return type;
+ }
+
+ }
+
+ public Path2D() {
+ this(WIND_NON_ZERO, BUFFER_SIZE);
+ }
+
+ public Path2D(int rule) {
+ this(rule, BUFFER_SIZE);
+ }
+
+ public Path2D(int rule, int initialCapacity) {
+ setWindingRule(rule);
+ types = new byte[initialCapacity];
+ points = new float[initialCapacity * 2];
+ }
+
+ public Path2D(Path2D path) {
+ this(WIND_NON_ZERO, BUFFER_SIZE);
+ PathIterator p = path.iterator(null);
+ setWindingRule(p.getWindingRule());
+ append(p, false);
+ }
+
+ public void setWindingRule(int rule) {
+ if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
+ throw new NoSuchElementException(invalidWindingRuleValue);
+ }
+ this.rule = rule;
+ }
+
+ public int getWindingRule() {
+ return rule;
+ }
+
+ /**
+ * Checks points and types buffer size to add pointCount points. If necessary realloc buffers to enlarge size.
+ * @param pointCount - the point count to be added in buffer
+ */
+ void checkBuf(int pointCount, boolean checkMove) {
+ if (checkMove && typeSize == 0) {
+ throw new IllegalPathStateException("First segment should be SEG_MOVETO type");
+ }
+ if (typeSize == types.length) {
+ byte tmp[] = new byte[typeSize + BUFFER_CAPACITY];
+ System.arraycopy(types, 0, tmp, 0, typeSize);
+ types = tmp;
+ }
+ if (pointSize + pointCount > points.length) {
+ float tmp[] = new float[pointSize + Math.max(BUFFER_CAPACITY * 2, pointCount)];
+ System.arraycopy(points, 0, tmp, 0, pointSize);
+ points = tmp;
+ }
+ }
+
+ public void moveTo(float x, float y) {
+ if (typeSize > 0 && types[typeSize - 1] == PathIterator.SEG_MOVETO) {
+ points[pointSize - 2] = x;
+ points[pointSize - 1] = y;
+ } else {
+ checkBuf(2, false);
+ types[typeSize++] = PathIterator.SEG_MOVETO;
+ points[pointSize++] = x;
+ points[pointSize++] = y;
+ }
+ }
+
+ public void lineTo(float x, float y) {
+ checkBuf(2, true);
+ types[typeSize++] = PathIterator.SEG_LINETO;
+ points[pointSize++] = x;
+ points[pointSize++] = y;
+ }
+
+ public void quadTo(float x1, float y1, float x2, float y2) {
+ checkBuf(4, true);
+ types[typeSize++] = PathIterator.SEG_QUADTO;
+ points[pointSize++] = x1;
+ points[pointSize++] = y1;
+ points[pointSize++] = x2;
+ points[pointSize++] = y2;
+ }
+
+ public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) {
+ checkBuf(6, true);
+ types[typeSize++] = PathIterator.SEG_CUBICTO;
+ points[pointSize++] = x1;
+ points[pointSize++] = y1;
+ points[pointSize++] = x2;
+ points[pointSize++] = y2;
+ points[pointSize++] = x3;
+ points[pointSize++] = y3;
+ }
+
+ final public int size() {
+ return typeSize;
+ }
+
+ final public boolean isClosed() {
+ return typeSize > 0 && types[typeSize - 1] == PathIterator.SEG_CLOSE ;
+ }
+
+ public void closePath() {
+ if (!isClosed()) {
+ checkBuf(0, true);
+ types[typeSize++] = PathIterator.SEG_CLOSE;
+ }
+ }
+
+ public String toString() {
+ return "[size "+size()+", closed "+isClosed()+"]";
+ }
+
+ public void append(Path2D path, boolean connect) {
+ PathIterator p = path.iterator(null);
+ append(p, connect);
+ }
+
+ public void append(PathIterator path, boolean connect) {
+ while (!path.isDone()) {
+ float coords[] = new float[6];
+ switch (path.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (!connect || typeSize == 0) {
+ moveTo(coords[0], coords[1]);
+ break;
+ }
+ if (types[typeSize - 1] != PathIterator.SEG_CLOSE &&
+ points[pointSize - 2] == coords[0] &&
+ points[pointSize - 1] == coords[1])
+ {
+ break;
+ }
+ // NO BREAK;
+ case PathIterator.SEG_LINETO:
+ lineTo(coords[0], coords[1]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ quadTo(coords[0], coords[1], coords[2], coords[3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ closePath();
+ break;
+ }
+ path.next();
+ connect = false;
+ }
+ }
+
+ public SVertex getCurrentPoint() {
+ if (typeSize == 0) {
+ return null;
+ }
+ int j = pointSize - 2;
+ if (types[typeSize - 1] == PathIterator.SEG_CLOSE) {
+
+ for (int i = typeSize - 2; i > 0; i--) {
+ int type = types[i];
+ if (type == PathIterator.SEG_MOVETO) {
+ break;
+ }
+ j -= pointShift[type];
+ }
+ }
+ return new SVertex(points[j], points[j + 1]);
+ }
+
+ public void reset() {
+ typeSize = 0;
+ pointSize = 0;
+ }
+
+ public void transform(AffineTransform t) {
+ t.transform(points, 0, points, 0, pointSize / 2);
+ }
+
+ public Path2D createTransformedShape(AffineTransform t) {
+ Path2D p = (Path2D)clone();
+ if (t != null) {
+ p.transform(t);
+ }
+ return p;
+ }
+
+ public final synchronized AABBox getBounds2D() {
+ float rx1, ry1, rx2, ry2;
+ if (pointSize == 0) {
+ rx1 = ry1 = rx2 = ry2 = 0.0f;
+ } else {
+ int i = pointSize - 1;
+ ry1 = ry2 = points[i--];
+ rx1 = rx2 = points[i--];
+ while (i > 0) {
+ float y = points[i--];
+ float x = points[i--];
+ if (x < rx1) {
+ rx1 = x;
+ } else
+ if (x > rx2) {
+ rx2 = x;
+ }
+ if (y < ry1) {
+ ry1 = y;
+ } else
+ if (y > ry2) {
+ ry2 = y;
+ }
+ }
+ }
+ return new AABBox(rx1, ry1, 0f, rx2, ry2, 0f);
+ }
+
+ /**
+ * Checks cross count according to path rule to define is it point inside shape or not.
+ * @param cross - the point cross count
+ * @return true if point is inside path, or false otherwise
+ */
+ boolean isInside(int cross) {
+ if (rule == WIND_NON_ZERO) {
+ return Crossing.isInsideNonZero(cross);
+ }
+ return Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean contains(float px, float py) {
+ return isInside(Crossing.crossShape(this, px, py));
+ }
+
+ public boolean contains(float rx, float ry, float rw, float rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross != Crossing.CROSSING && isInside(cross);
+ }
+
+ public boolean intersects(float rx, float ry, float rw, float rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross == Crossing.CROSSING || isInside(cross);
+ }
+
+ public boolean contains(Vertex p) {
+ return contains(p.getX(), p.getY());
+ }
+
+ public boolean contains(AABBox r) {
+ return contains(r);
+ }
+
+ public boolean intersects(AABBox r) {
+ return intersects(r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight());
+ }
+
+ public PathIterator iterator() {
+ return new Iterator(this);
+ }
+
+ public PathIterator iterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ /* public PathIterator getPathIterator(AffineTransform t, float flatness) {
+ return new FlatteningPathIterator(getPathIterator(t), flatness);
+ } */
+
+ @Override
+ public Object clone() {
+ try {
+ Path2D p = (Path2D) super.clone();
+ p.types = types.clone();
+ p.points = points.clone();
+ return p;
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+}
+
diff --git a/turtle2d/src/jogamp/graph/geom/plane/PathIterator.java b/turtle2d/src/jogamp/graph/geom/plane/PathIterator.java
new file mode 100644
index 0000000..8868a8c
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/geom/plane/PathIterator.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.geom.plane;
+
+public interface PathIterator {
+
+ public static final int WIND_EVEN_ODD = 0;
+ public static final int WIND_NON_ZERO = 1;
+
+ public static final int SEG_MOVETO = 0;
+ public static final int SEG_LINETO = 1;
+ public static final int SEG_QUADTO = 2;
+ public static final int SEG_CUBICTO = 3;
+ public static final int SEG_CLOSE = 4;
+
+ public int getWindingRule();
+
+ public boolean isDone();
+
+ public void next();
+
+ public int currentSegment(float[] coords);
+
+}
+
diff --git a/turtle2d/src/jogamp/graph/math/MathFloat.java b/turtle2d/src/jogamp/graph/math/MathFloat.java
new file mode 100644
index 0000000..0b8d69e
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/math/MathFloat.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.graph.math;
+
+public class MathFloat {
+
+ public static final float E = 2.7182818284590452354f;
+
+ public static final float PI = 3.14159265358979323846f;
+
+ public static float abs(float a) { return (float) java.lang.Math.abs(a); }
+ public static float pow(float a, float b) { return (float) java.lang.Math.pow(a, b); }
+
+ public static float sin(float a) { return (float) java.lang.Math.sin(a); }
+ public static float cos(float a) { return (float) java.lang.Math.cos(a); }
+ public static float acos(float a) { return (float) java.lang.Math.acos(a); }
+
+ public static float sqrt(float a) { return (float) java.lang.Math.sqrt(a); }
+
+}
diff --git a/turtle2d/src/jogamp/graph/math/plane/Crossing.java b/turtle2d/src/jogamp/graph/math/plane/Crossing.java
new file mode 100644
index 0000000..8f86386
--- /dev/null
+++ b/turtle2d/src/jogamp/graph/math/plane/Crossing.java
@@ -0,0 +1,897 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.math.plane;
+
+import jogamp.graph.geom.plane.Path2D;
+import jogamp.graph.geom.plane.PathIterator;
+import jogamp.graph.math.MathFloat;
+
+
+public class Crossing {
+
+ /**
+ * Allowable tolerance for bounds comparison
+ */
+ static final float DELTA = (float) 1E-5;
+
+ /**
+ * If roots have distance less then <code>ROOT_DELTA</code> they are double
+ */
+ static final float ROOT_DELTA = (float) 1E-10;
+
+ /**
+ * Rectangle cross segment
+ */
+ public static final int CROSSING = 255;
+
+ /**
+ * Unknown crossing result
+ */
+ static final int UNKNOWN = 254;
+
+ /**
+ * Solves quadratic equation
+ * @param eqn - the coefficients of the equation
+ * @param res - the roots of the equation
+ * @return a number of roots
+ */
+ public static int solveQuad(float eqn[], float res[]) {
+ float a = eqn[2];
+ float b = eqn[1];
+ float c = eqn[0];
+ int rc = 0;
+ if (a == 0.0) {
+ if (b == 0.0) {
+ return -1;
+ }
+ res[rc++] = -c / b;
+ } else {
+ float d = b * b - 4.0f * a * c;
+ // d < 0.0
+ if (d < 0.0) {
+ return 0;
+ }
+ d = MathFloat.sqrt(d);
+ res[rc++] = (- b + d) / (a * 2.0f);
+ // d != 0.0
+ if (d != 0.0) {
+ res[rc++] = (- b - d) / (a * 2.0f);
+ }
+ }
+ return fixRoots(res, rc);
+ }
+
+ /**
+ * Solves cubic equation
+ * @param eqn - the coefficients of the equation
+ * @param res - the roots of the equation
+ * @return a number of roots
+ */
+ public static int solveCubic(float eqn[], float res[]) {
+ float d = eqn[3];
+ if (d == 0) {
+ return solveQuad(eqn, res);
+ }
+ float a = eqn[2] / d;
+ float b = eqn[1] / d;
+ float c = eqn[0] / d;
+ int rc = 0;
+
+ float Q = (a * a - 3.0f * b) / 9.0f;
+ float R = (2.0f * a * a * a - 9.0f * a * b + 27.0f * c) / 54.0f;
+ float Q3 = Q * Q * Q;
+ float R2 = R * R;
+ float n = - a / 3.0f;
+
+ if (R2 < Q3) {
+ float t = MathFloat.acos(R / MathFloat.sqrt(Q3)) / 3.0f;
+ float p = 2.0f * MathFloat.PI / 3.0f;
+ float m = -2.0f * MathFloat.sqrt(Q);
+ res[rc++] = m * MathFloat.cos(t) + n;
+ res[rc++] = m * MathFloat.cos(t + p) + n;
+ res[rc++] = m * MathFloat.cos(t - p) + n;
+ } else {
+// Debug.println("R2 >= Q3 (" + R2 + "/" + Q3 + ")");
+ float A = MathFloat.pow(MathFloat.abs(R) + MathFloat.sqrt(R2 - Q3), 1.0f / 3.0f);
+ if (R > 0.0) {
+ A = -A;
+ }
+// if (A == 0.0) {
+ if (-ROOT_DELTA < A && A < ROOT_DELTA) {
+ res[rc++] = n;
+ } else {
+ float B = Q / A;
+ res[rc++] = A + B + n;
+// if (R2 == Q3) {
+ float delta = R2 - Q3;
+ if (-ROOT_DELTA < delta && delta < ROOT_DELTA) {
+ res[rc++] = - (A + B) / 2.0f + n;
+ }
+ }
+
+ }
+ return fixRoots(res, rc);
+ }
+
+ /**
+ * Excludes float roots. Roots are float if they lies enough close with each other.
+ * @param res - the roots
+ * @param rc - the roots count
+ * @return new roots count
+ */
+ static int fixRoots(float res[], int rc) {
+ int tc = 0;
+ for(int i = 0; i < rc; i++) {
+ out: {
+ for(int j = i + 1; j < rc; j++) {
+ if (isZero(res[i] - res[j])) {
+ break out;
+ }
+ }
+ res[tc++] = res[i];
+ }
+ }
+ return tc;
+ }
+
+ /**
+ * QuadCurve class provides basic functionality to find curve crossing and calculating bounds
+ */
+ public static class QuadCurve {
+
+ float ax, ay, bx, by;
+ float Ax, Ay, Bx, By;
+
+ public QuadCurve(float x1, float y1, float cx, float cy, float x2, float y2) {
+ ax = x2 - x1;
+ ay = y2 - y1;
+ bx = cx - x1;
+ by = cy - y1;
+
+ Bx = bx + bx; // Bx = 2.0 * bx
+ Ax = ax - Bx; // Ax = ax - 2.0 * bx
+
+ By = by + by; // By = 2.0 * by
+ Ay = ay - By; // Ay = ay - 2.0 * by
+ }
+
+ int cross(float res[], int rc, float py1, float py2) {
+ int cross = 0;
+
+ for (int i = 0; i < rc; i++) {
+ float t = res[i];
+
+ // CURVE-OUTSIDE
+ if (t < -DELTA || t > 1 + DELTA) {
+ continue;
+ }
+ // CURVE-START
+ if (t < DELTA) {
+ if (py1 < 0.0 && (bx != 0.0 ? bx : ax - bx) < 0.0) {
+ cross--;
+ }
+ continue;
+ }
+ // CURVE-END
+ if (t > 1 - DELTA) {
+ if (py1 < ay && (ax != bx ? ax - bx : bx) > 0.0) {
+ cross++;
+ }
+ continue;
+ }
+ // CURVE-INSIDE
+ float ry = t * (t * Ay + By);
+ // ry = t * t * Ay + t * By
+ if (ry > py2) {
+ float rxt = t * Ax + bx;
+ // rxt = 2.0 * t * Ax + Bx = 2.0 * t * Ax + 2.0 * bx
+ if (rxt > -DELTA && rxt < DELTA) {
+ continue;
+ }
+ cross += rxt > 0.0 ? 1 : -1;
+ }
+ } // for
+
+ return cross;
+ }
+
+ int solvePoint(float res[], float px) {
+ float eqn[] = {-px, Bx, Ax};
+ return solveQuad(eqn, res);
+ }
+
+ int solveExtrem(float res[]) {
+ int rc = 0;
+ if (Ax != 0.0) {
+ res[rc++] = - Bx / (Ax + Ax);
+ }
+ if (Ay != 0.0) {
+ res[rc++] = - By / (Ay + Ay);
+ }
+ return rc;
+ }
+
+ int addBound(float bound[], int bc, float res[], int rc, float minX, float maxX, boolean changeId, int id) {
+ for(int i = 0; i < rc; i++) {
+ float t = res[i];
+ if (t > -DELTA && t < 1 + DELTA) {
+ float rx = t * (t * Ax + Bx);
+ if (minX <= rx && rx <= maxX) {
+ bound[bc++] = t;
+ bound[bc++] = rx;
+ bound[bc++] = t * (t * Ay + By);
+ bound[bc++] = id;
+ if (changeId) {
+ id++;
+ }
+ }
+ }
+ }
+ return bc;
+ }
+
+ }
+
+ /**
+ * CubicCurve class provides basic functionality to find curve crossing and calculating bounds
+ */
+ public static class CubicCurve {
+
+ float ax, ay, bx, by, cx, cy;
+ float Ax, Ay, Bx, By, Cx, Cy;
+ float Ax3, Bx2;
+
+ public CubicCurve(float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2) {
+ ax = x2 - x1;
+ ay = y2 - y1;
+ bx = cx1 - x1;
+ by = cy1 - y1;
+ cx = cx2 - x1;
+ cy = cy2 - y1;
+
+ Cx = bx + bx + bx; // Cx = 3.0 * bx
+ Bx = cx + cx + cx - Cx - Cx; // Bx = 3.0 * cx - 6.0 * bx
+ Ax = ax - Bx - Cx; // Ax = ax - 3.0 * cx + 3.0 * bx
+
+ Cy = by + by + by; // Cy = 3.0 * by
+ By = cy + cy + cy - Cy - Cy; // By = 3.0 * cy - 6.0 * by
+ Ay = ay - By - Cy; // Ay = ay - 3.0 * cy + 3.0 * by
+
+ Ax3 = Ax + Ax + Ax;
+ Bx2 = Bx + Bx;
+ }
+
+ int cross(float res[], int rc, float py1, float py2) {
+ int cross = 0;
+ for (int i = 0; i < rc; i++) {
+ float t = res[i];
+
+ // CURVE-OUTSIDE
+ if (t < -DELTA || t > 1 + DELTA) {
+ continue;
+ }
+ // CURVE-START
+ if (t < DELTA) {
+ if (py1 < 0.0 && (bx != 0.0 ? bx : (cx != bx ? cx - bx : ax - cx)) < 0.0) {
+ cross--;
+ }
+ continue;
+ }
+ // CURVE-END
+ if (t > 1 - DELTA) {
+ if (py1 < ay && (ax != cx ? ax - cx : (cx != bx ? cx - bx : bx)) > 0.0) {
+ cross++;
+ }
+ continue;
+ }
+ // CURVE-INSIDE
+ float ry = t * (t * (t * Ay + By) + Cy);
+ // ry = t * t * t * Ay + t * t * By + t * Cy
+ if (ry > py2) {
+ float rxt = t * (t * Ax3 + Bx2) + Cx;
+ // rxt = 3.0 * t * t * Ax + 2.0 * t * Bx + Cx
+ if (rxt > -DELTA && rxt < DELTA) {
+ rxt = t * (Ax3 + Ax3) + Bx2;
+ // rxt = 6.0 * t * Ax + 2.0 * Bx
+ if (rxt < -DELTA || rxt > DELTA) {
+ // Inflection point
+ continue;
+ }
+ rxt = ax;
+ }
+ cross += rxt > 0.0 ? 1 : -1;
+ }
+ } //for
+
+ return cross;
+ }
+
+ int solvePoint(float res[], float px) {
+ float eqn[] = {-px, Cx, Bx, Ax};
+ return solveCubic(eqn, res);
+ }
+
+ int solveExtremX(float res[]) {
+ float eqn[] = {Cx, Bx2, Ax3};
+ return solveQuad(eqn, res);
+ }
+
+ int solveExtremY(float res[]) {
+ float eqn[] = {Cy, By + By, Ay + Ay + Ay};
+ return solveQuad(eqn, res);
+ }
+
+ int addBound(float bound[], int bc, float res[], int rc, float minX, float maxX, boolean changeId, int id) {
+ for(int i = 0; i < rc; i++) {
+ float t = res[i];
+ if (t > -DELTA && t < 1 + DELTA) {
+ float rx = t * (t * (t * Ax + Bx) + Cx);
+ if (minX <= rx && rx <= maxX) {
+ bound[bc++] = t;
+ bound[bc++] = rx;
+ bound[bc++] = t * (t * (t * Ay + By) + Cy);
+ bound[bc++] = id;
+ if (changeId) {
+ id++;
+ }
+ }
+ }
+ }
+ return bc;
+ }
+
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross line.
+ */
+ public static int crossLine(float x1, float y1, float x2, float y2, float x, float y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < x2) ||
+ (x > x1 && x > x2) ||
+ (y > y1 && y > y2) ||
+ (x1 == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < y2) {
+ } else {
+ // INSIDE
+ if ((y2 - y1) * (x - x1) / (x2 - x1) <= y - y1) {
+ // INSIDE-UP
+ return 0;
+ }
+ }
+
+ // START
+ if (x == x1) {
+ return x1 < x2 ? 0 : -1;
+ }
+
+ // END
+ if (x == x2) {
+ return x1 < x2 ? 1 : 0;
+ }
+
+ // INSIDE-DOWN
+ return x1 < x2 ? 1 : -1;
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross quard curve
+ */
+ public static int crossQuad(float x1, float y1, float cx, float cy, float x2, float y2, float x, float y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < cx && x < x2) ||
+ (x > x1 && x > cx && x > x2) ||
+ (y > y1 && y > cy && y > y2) ||
+ (x1 == cx && cx == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < cy && y < y2 && x != x1 && x != x2) {
+ if (x1 < x2) {
+ return x1 < x && x < x2 ? 1 : 0;
+ }
+ return x2 < x && x < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ QuadCurve c = new QuadCurve(x1, y1, cx, cy, x2, y2);
+ float px = x - x1;
+ float py = y - y1;
+ float res[] = new float[3];
+ int rc = c.solvePoint(res, px);
+
+ return c.cross(res, rc, py, py);
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross cubic curve
+ */
+ public static int crossCubic(float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2, float x, float y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < cx1 && x < cx2 && x < x2) ||
+ (x > x1 && x > cx1 && x > cx2 && x > x2) ||
+ (y > y1 && y > cy1 && y > cy2 && y > y2) ||
+ (x1 == cx1 && cx1 == cx2 && cx2 == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < cy1 && y < cy2 && y < y2 && x != x1 && x != x2) {
+ if (x1 < x2) {
+ return x1 < x && x < x2 ? 1 : 0;
+ }
+ return x2 < x && x < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
+ float px = x - x1;
+ float py = y - y1;
+ float res[] = new float[3];
+ int rc = c.solvePoint(res, px);
+ return c.cross(res, rc, py, py);
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross path
+ */
+ public static int crossPath(PathIterator p, float x, float y) {
+ int cross = 0;
+ float mx, my, cx, cy;
+ mx = my = cx = cy = 0.0f;
+ float coords[] = new float[6];
+
+ while (!p.isDone()) {
+ switch (p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (cx != mx || cy != my) {
+ cross += crossLine(cx, cy, mx, my, x, y);
+ }
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ break;
+ case PathIterator.SEG_LINETO:
+ cross += crossLine(cx, cy, cx = coords[0], cy = coords[1], x, y);
+ break;
+ case PathIterator.SEG_QUADTO:
+ cross += crossQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3], x, y);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ cross += crossCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5], x, y);
+ break;
+ case PathIterator.SEG_CLOSE:
+ if (cy != my || cx != mx) {
+ cross += crossLine(cx, cy, cx = mx, cy = my, x, y);
+ }
+ break;
+ }
+
+ // checks if the point (x,y) is the vertex of shape with PathIterator p
+ if (x == cx && y == cy) {
+ cross = 0;
+ cy = my;
+ break;
+ }
+ p.next();
+ }
+ if (cy != my) {
+ cross += crossLine(cx, cy, mx, my, x, y);
+ }
+ return cross;
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross shape
+ */
+ public static int crossShape(Path2D s, float x, float y) {
+ if (!s.getBounds2D().contains(x, y)) {
+ return 0;
+ }
+ return crossPath(s.iterator(null), x, y);
+ }
+
+ /**
+ * Returns true if value enough small
+ */
+ public static boolean isZero(float val) {
+ return -DELTA < val && val < DELTA;
+ }
+
+ /**
+ * Sort bound array
+ */
+ static void sortBound(float bound[], int bc) {
+ for(int i = 0; i < bc - 4; i += 4) {
+ int k = i;
+ for(int j = i + 4; j < bc; j += 4) {
+ if (bound[k] > bound[j]) {
+ k = j;
+ }
+ }
+ if (k != i) {
+ float tmp = bound[i];
+ bound[i] = bound[k];
+ bound[k] = tmp;
+ tmp = bound[i + 1];
+ bound[i + 1] = bound[k + 1];
+ bound[k + 1] = tmp;
+ tmp = bound[i + 2];
+ bound[i + 2] = bound[k + 2];
+ bound[k + 2] = tmp;
+ tmp = bound[i + 3];
+ bound[i + 3] = bound[k + 3];
+ bound[k + 3] = tmp;
+ }
+ }
+ }
+
+ /**
+ * Returns are bounds intersect or not intersect rectangle
+ */
+ static int crossBound(float bound[], int bc, float py1, float py2) {
+
+ // LEFT/RIGHT
+ if (bc == 0) {
+ return 0;
+ }
+
+ // Check Y coordinate
+ int up = 0;
+ int down = 0;
+ for(int i = 2; i < bc; i += 4) {
+ if (bound[i] < py1) {
+ up++;
+ continue;
+ }
+ if (bound[i] > py2) {
+ down++;
+ continue;
+ }
+ return CROSSING;
+ }
+
+ // UP
+ if (down == 0) {
+ return 0;
+ }
+
+ if (up != 0) {
+ // bc >= 2
+ sortBound(bound, bc);
+ boolean sign = bound[2] > py2;
+ for(int i = 6; i < bc; i += 4) {
+ boolean sign2 = bound[i] > py2;
+ if (sign != sign2 && bound[i + 1] != bound[i - 3]) {
+ return CROSSING;
+ }
+ sign = sign2;
+ }
+ }
+ return UNKNOWN;
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross line or the are intersect
+ */
+ public static int intersectLine(float x1, float y1, float x2, float y2, float rx1, float ry1, float rx2, float ry2) {
+
+ // LEFT/RIGHT/UP
+ if ((rx2 < x1 && rx2 < x2) ||
+ (rx1 > x1 && rx1 > x2) ||
+ (ry1 > y1 && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (ry2 < y1 && ry2 < y2) {
+ } else {
+
+ // INSIDE
+ if (x1 == x2) {
+ return CROSSING;
+ }
+
+ // Build bound
+ float bx1, bx2;
+ if (x1 < x2) {
+ bx1 = x1 < rx1 ? rx1 : x1;
+ bx2 = x2 < rx2 ? x2 : rx2;
+ } else {
+ bx1 = x2 < rx1 ? rx1 : x2;
+ bx2 = x1 < rx2 ? x1 : rx2;
+ }
+ float k = (y2 - y1) / (x2 - x1);
+ float by1 = k * (bx1 - x1) + y1;
+ float by2 = k * (bx2 - x1) + y1;
+
+ // BOUND-UP
+ if (by1 < ry1 && by2 < ry1) {
+ return 0;
+ }
+
+ // BOUND-DOWN
+ if (by1 > ry2 && by2 > ry2) {
+ } else {
+ return CROSSING;
+ }
+ }
+
+ // EMPTY
+ if (x1 == x2) {
+ return 0;
+ }
+
+ // CURVE-START
+ if (rx1 == x1) {
+ return x1 < x2 ? 0 : -1;
+ }
+
+ // CURVE-END
+ if (rx1 == x2) {
+ return x1 < x2 ? 1 : 0;
+ }
+
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross quad curve or the are intersect
+ */
+ public static int intersectQuad(float x1, float y1, float cx, float cy, float x2, float y2, float rx1, float ry1, float rx2, float ry2) {
+
+ // LEFT/RIGHT/UP ------------------------------------------------------
+ if ((rx2 < x1 && rx2 < cx && rx2 < x2) ||
+ (rx1 > x1 && rx1 > cx && rx1 > x2) ||
+ (ry1 > y1 && ry1 > cy && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN ---------------------------------------------------------------
+ if (ry2 < y1 && ry2 < cy && ry2 < y2 && rx1 != x1 && rx1 != x2) {
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+ }
+
+ // INSIDE -------------------------------------------------------------
+ QuadCurve c = new QuadCurve(x1, y1, cx, cy, x2, y2);
+ float px1 = rx1 - x1;
+ float py1 = ry1 - y1;
+ float px2 = rx2 - x1;
+ float py2 = ry2 - y1;
+
+ float res1[] = new float[3];
+ float res2[] = new float[3];
+ int rc1 = c.solvePoint(res1, px1);
+ int rc2 = c.solvePoint(res2, px2);
+
+ // INSIDE-LEFT/RIGHT
+ if (rc1 == 0 && rc2 == 0) {
+ return 0;
+ }
+
+ // Build bound --------------------------------------------------------
+ float minX = px1 - DELTA;
+ float maxX = px2 + DELTA;
+ float bound[] = new float[28];
+ int bc = 0;
+ // Add roots
+ bc = c.addBound(bound, bc, res1, rc1, minX, maxX, false, 0);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, false, 1);
+ // Add extremal points`
+ rc2 = c.solveExtrem(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 2);
+ // Add start and end
+ if (rx1 < x1 && x1 < rx2) {
+ bound[bc++] = 0.0f;
+ bound[bc++] = 0.0f;
+ bound[bc++] = 0.0f;
+ bound[bc++] = 4;
+ }
+ if (rx1 < x2 && x2 < rx2) {
+ bound[bc++] = 1.0f;
+ bound[bc++] = c.ax;
+ bound[bc++] = c.ay;
+ bound[bc++] = 5;
+ }
+ // End build bound ----------------------------------------------------
+
+ int cross = crossBound(bound, bc, py1, py2);
+ if (cross != UNKNOWN) {
+ return cross;
+ }
+ return c.cross(res1, rc1, py1, py2);
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross cubic curve or the are intersect
+ */
+ public static int intersectCubic(float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2, float rx1, float ry1, float rx2, float ry2) {
+
+ // LEFT/RIGHT/UP
+ if ((rx2 < x1 && rx2 < cx1 && rx2 < cx2 && rx2 < x2) ||
+ (rx1 > x1 && rx1 > cx1 && rx1 > cx2 && rx1 > x2) ||
+ (ry1 > y1 && ry1 > cy1 && ry1 > cy2 && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (ry2 < y1 && ry2 < cy1 && ry2 < cy2 && ry2 < y2 && rx1 != x1 && rx1 != x2) {
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
+ float px1 = rx1 - x1;
+ float py1 = ry1 - y1;
+ float px2 = rx2 - x1;
+ float py2 = ry2 - y1;
+
+ float res1[] = new float[3];
+ float res2[] = new float[3];
+ int rc1 = c.solvePoint(res1, px1);
+ int rc2 = c.solvePoint(res2, px2);
+
+ // LEFT/RIGHT
+ if (rc1 == 0 && rc2 == 0) {
+ return 0;
+ }
+
+ float minX = px1 - DELTA;
+ float maxX = px2 + DELTA;
+
+ // Build bound --------------------------------------------------------
+ float bound[] = new float[40];
+ int bc = 0;
+ // Add roots
+ bc = c.addBound(bound, bc, res1, rc1, minX, maxX, false, 0);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, false, 1);
+ // Add extrimal points
+ rc2 = c.solveExtremX(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 2);
+ rc2 = c.solveExtremY(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 4);
+ // Add start and end
+ if (rx1 < x1 && x1 < rx2) {
+ bound[bc++] = 0.0f;
+ bound[bc++] = 0.0f;
+ bound[bc++] = 0.0f;
+ bound[bc++] = 6;
+ }
+ if (rx1 < x2 && x2 < rx2) {
+ bound[bc++] = 1.0f;
+ bound[bc++] = c.ax;
+ bound[bc++] = c.ay;
+ bound[bc++] = 7;
+ }
+ // End build bound ----------------------------------------------------
+
+ int cross = crossBound(bound, bc, py1, py2);
+ if (cross != UNKNOWN) {
+ return cross;
+ }
+ return c.cross(res1, rc1, py1, py2);
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross path or the are intersect
+ */
+ public static int intersectPath(PathIterator p, float x, float y, float w, float h) {
+
+ int cross = 0;
+ int count;
+ float mx, my, cx, cy;
+ mx = my = cx = cy = 0.0f;
+ float coords[] = new float[6];
+
+ float rx1 = x;
+ float ry1 = y;
+ float rx2 = x + w;
+ float ry2 = y + h;
+
+ while (!p.isDone()) {
+ count = 0;
+ switch (p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (cx != mx || cy != my) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ }
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ break;
+ case PathIterator.SEG_LINETO:
+ count = intersectLine(cx, cy, cx = coords[0], cy = coords[1], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_QUADTO:
+ count = intersectQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ count = intersectCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_CLOSE:
+ if (cy != my || cx != mx) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ }
+ cx = mx;
+ cy = my;
+ break;
+ }
+ if (count == CROSSING) {
+ return CROSSING;
+ }
+ cross += count;
+ p.next();
+ }
+ if (cy != my) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ if (count == CROSSING) {
+ return CROSSING;
+ }
+ cross += count;
+ }
+ return cross;
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross shape or the are intersect
+ */
+ public static int intersectShape(Path2D s, float x, float y, float w, float h) {
+ if (!s.getBounds2D().intersects(x, y, w, h)) {
+ return 0;
+ }
+ return intersectPath(s.iterator(null), x, y, w, h);
+ }
+
+ /**
+ * Returns true if cross count correspond inside location for non zero path rule
+ */
+ public static boolean isInsideNonZero(int cross) {
+ return cross != 0;
+ }
+
+ /**
+ * Returns true if cross count correspond inside location for even-odd path rule
+ */
+ public static boolean isInsideEvenOdd(int cross) {
+ return (cross & 1) != 0;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/Disassembler.java b/turtle2d/src/net/java/dev/typecast/ot/Disassembler.java
new file mode 100644
index 0000000..73e75cc
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/Disassembler.java
@@ -0,0 +1,109 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot;
+
+/**
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Disassembler.java,v 1.1.1.1 2004-12-05 23:14:25 davidsch Exp $
+ */
+public class Disassembler {
+
+ /**
+ * Advance the instruction pointer to the next executable opcode.
+ * This will be the next byte, unless the current opcode is a push
+ * instruction, in which case it will be the byte immediately beyond
+ * the last data byte.
+ * @param ip The current instruction pointer
+ * @return The new instruction pointer
+ */
+ public static int advanceIP(short[] instructions, int ip) {
+
+ // The high word specifies font, cvt, or glyph program
+ int i = ip & 0xffff;
+ int dataCount;
+ ip++;
+ if (Mnemonic.NPUSHB == instructions[i]) {
+ // Next byte is the data byte count
+ dataCount = instructions[++i];
+ ip += dataCount + 1;
+ } else if (Mnemonic.NPUSHW == instructions[i]) {
+ // Next byte is the data word count
+ dataCount = instructions[++i];
+ ip += dataCount*2 + 1;
+ } else if (Mnemonic.PUSHB == (instructions[i] & 0xf8)) {
+ dataCount = (short)((instructions[i] & 0x07) + 1);
+ ip += dataCount;
+ } else if (Mnemonic.PUSHW == (instructions[i] & 0xf8)) {
+ dataCount = (short)((instructions[i] & 0x07) + 1);
+ ip += dataCount*2;
+ }
+ return ip;
+ }
+
+ public static short getPushCount(short[] instructions, int ip) {
+ short instr = instructions[ip & 0xffff];
+ if ((Mnemonic.NPUSHB == instr) || (Mnemonic.NPUSHW == instr)) {
+ return instructions[(ip & 0xffff) + 1];
+ } else if ((Mnemonic.PUSHB == (instr & 0xf8)) || (Mnemonic.PUSHW == (instr & 0xf8))) {
+ return (short)((instr & 0x07) + 1);
+ }
+ return 0;
+ }
+
+ public static int[] getPushData(short[] instructions, int ip) {
+ int count = getPushCount(instructions, ip);
+ int[] data = new int[count];
+ int i = ip & 0xffff;
+ short instr = instructions[i];
+ if (Mnemonic.NPUSHB == instr) {
+ for (int j = 0; j < count; j++) {
+ data[j] = instructions[i + j + 2];
+ }
+ } else if (Mnemonic.PUSHB == (instr & 0xf8)) {
+ for (int j = 0; j < count; j++) {
+ data[j] = instructions[i + j + 1];
+ }
+ } else if (Mnemonic.NPUSHW == instr) {
+ for (int j = 0; j < count; j++) {
+ data[j] = (instructions[i + j*2 + 2] << 8) | instructions[i + j*2 + 3];
+ }
+ } else if (Mnemonic.PUSHW == (instr & 0xf8)) {
+ for (int j = 0; j < count; j++) {
+ data[j] = (instructions[i + j*2 + 1] << 8) | instructions[i + j*2 + 2];
+ }
+ }
+ return data;
+ }
+
+ public static String disassemble(short[] instructions, int leadingSpaces) {
+ StringBuffer sb = new StringBuffer();
+ int ip = 0;
+ while (ip < instructions.length) {
+ for (int i = 0; i < leadingSpaces; i++) {
+ sb.append(" ");
+ }
+ sb.append(ip).append(": ");
+ sb.append(Mnemonic.getMnemonic(instructions[ip]));
+ if (getPushCount(instructions, ip) > 0) {
+ int[] data = getPushData(instructions, ip);
+ for(int j = 0; j < data.length; j++) {
+ if ((instructions[ip] == Mnemonic.PUSHW) ||
+ (instructions[ip] == Mnemonic.NPUSHW)) {
+ sb.append(" ").append((short) data[j]);
+ } else {
+ sb.append(" ").append(data[j]);
+ }
+ }
+ }
+ sb.append("\n");
+ ip = advanceIP(instructions, ip);
+ }
+ return sb.toString();
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/Fixed.java b/turtle2d/src/net/java/dev/typecast/ot/Fixed.java
new file mode 100644
index 0000000..6f83e92
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/Fixed.java
@@ -0,0 +1,852 @@
+/*
+ * $Id: Fixed.java,v 1.1.1.1 2004-12-05 23:14:26 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot;
+
+/**
+ * Functions for working with signed 16.16 fixed values
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Fixed.java,v 1.1.1.1 2004-12-05 23:14:26 davidsch Exp $
+ */
+public class Fixed {
+
+ // Tangent LUT
+ static private int[] t = {
+ 0x0,
+ 0x1,
+ 0x3,
+ 0x4,
+ 0x6,
+ 0x7,
+ 0x9,
+ 0xb,
+ 0xc,
+ 0xe,
+ 0xf,
+ 0x11,
+ 0x12,
+ 0x14,
+ 0x16,
+ 0x17,
+ 0x19,
+ 0x1a,
+ 0x1c,
+ 0x1d,
+ 0x1f,
+ 0x21,
+ 0x22,
+ 0x24,
+ 0x25,
+ 0x27,
+ 0x29,
+ 0x2a,
+ 0x2c,
+ 0x2e,
+ 0x2f,
+ 0x31,
+ 0x32,
+ 0x34,
+ 0x36,
+ 0x37,
+ 0x39,
+ 0x3b,
+ 0x3c,
+ 0x3e,
+ 0x40,
+ 0x41,
+ 0x43,
+ 0x45,
+ 0x46,
+ 0x48,
+ 0x4a,
+ 0x4b,
+ 0x4d,
+ 0x4f,
+ 0x51,
+ 0x52,
+ 0x54,
+ 0x56,
+ 0x58,
+ 0x59,
+ 0x5b,
+ 0x5d,
+ 0x5f,
+ 0x60,
+ 0x62,
+ 0x64,
+ 0x66,
+ 0x68,
+ 0x6a,
+ 0x6b,
+ 0x6d,
+ 0x6f,
+ 0x71,
+ 0x73,
+ 0x75,
+ 0x77,
+ 0x79,
+ 0x7b,
+ 0x7c,
+ 0x7e,
+ 0x80,
+ 0x82,
+ 0x84,
+ 0x86,
+ 0x88,
+ 0x8a,
+ 0x8c,
+ 0x8e,
+ 0x91,
+ 0x93,
+ 0x95,
+ 0x97,
+ 0x99,
+ 0x9b,
+ 0x9d,
+ 0x9f,
+ 0xa2,
+ 0xa4,
+ 0xa6,
+ 0xa8,
+ 0xab,
+ 0xad,
+ 0xaf,
+ 0xb1,
+ 0xb4,
+ 0xb6,
+ 0xb9,
+ 0xbb,
+ 0xbd,
+ 0xc0,
+ 0xc2,
+ 0xc5,
+ 0xc7,
+ 0xca,
+ 0xcc,
+ 0xcf,
+ 0xd2,
+ 0xd4,
+ 0xd7,
+ 0xda,
+ 0xdc,
+ 0xdf,
+ 0xe2,
+ 0xe5,
+ 0xe8,
+ 0xea,
+ 0xed,
+ 0xf0,
+ 0xf3,
+ 0xf6,
+ 0xf9,
+ 0xfc,
+ 0x100,
+ 0x103,
+ 0x106,
+ 0x109,
+ 0x10c,
+ 0x110,
+ 0x113,
+ 0x116,
+ 0x11a,
+ 0x11d,
+ 0x121,
+ 0x125,
+ 0x128,
+ 0x12c,
+ 0x130,
+ 0x134,
+ 0x137,
+ 0x13b,
+ 0x13f,
+ 0x143,
+ 0x148,
+ 0x14c,
+ 0x150,
+ 0x154,
+ 0x159,
+ 0x15d,
+ 0x162,
+ 0x166,
+ 0x16b,
+ 0x170,
+ 0x175,
+ 0x17a,
+ 0x17f,
+ 0x184,
+ 0x189,
+ 0x18e,
+ 0x194,
+ 0x199,
+ 0x19f,
+ 0x1a5,
+ 0x1ab,
+ 0x1b1,
+ 0x1b7,
+ 0x1bd,
+ 0x1c3,
+ 0x1ca,
+ 0x1d1,
+ 0x1d7,
+ 0x1de,
+ 0x1e6,
+ 0x1ed,
+ 0x1f4,
+ 0x1fc,
+ 0x204,
+ 0x20c,
+ 0x214,
+ 0x21d,
+ 0x225,
+ 0x22e,
+ 0x238,
+ 0x241,
+ 0x24b,
+ 0x255,
+ 0x25f,
+ 0x26a,
+ 0x274,
+ 0x280,
+ 0x28b,
+ 0x297,
+ 0x2a3,
+ 0x2b0,
+ 0x2bd,
+ 0x2cb,
+ 0x2d9,
+ 0x2e8,
+ 0x2f7,
+ 0x306,
+ 0x317,
+ 0x328,
+ 0x339,
+ 0x34b,
+ 0x35e,
+ 0x372,
+ 0x387,
+ 0x39d,
+ 0x3b3,
+ 0x3cb,
+ 0x3e4,
+ 0x3fe,
+ 0x419,
+ 0x435,
+ 0x454,
+ 0x474,
+ 0x495,
+ 0x4b9,
+ 0x4de,
+ 0x506,
+ 0x531,
+ 0x55e,
+ 0x58f,
+ 0x5c3,
+ 0x5fb,
+ 0x637,
+ 0x677,
+ 0x6bd,
+ 0x709,
+ 0x75c,
+ 0x7b7,
+ 0x81b,
+ 0x889,
+ 0x904,
+ 0x98d,
+ 0xa27,
+ 0xad5,
+ 0xb9c,
+ 0xc82,
+ 0xd8e,
+ 0xecb,
+ 0x1046,
+ 0x1217,
+ 0x145a,
+ 0x1744,
+ 0x1b26,
+ 0x2095,
+ 0x28bc,
+ 0x3651,
+ 0x517b,
+ 0xa2f8
+ };
+
+ // Sine LUT
+ static private int[] s = {
+ 0x0,
+ 0x1,
+ 0x3,
+ 0x4,
+ 0x6,
+ 0x7,
+ 0x9,
+ 0xa,
+ 0xc,
+ 0xe,
+ 0xf,
+ 0x11,
+ 0x12,
+ 0x14,
+ 0x15,
+ 0x17,
+ 0x19,
+ 0x1a,
+ 0x1c,
+ 0x1d,
+ 0x1f,
+ 0x20,
+ 0x22,
+ 0x24,
+ 0x25,
+ 0x27,
+ 0x28,
+ 0x2a,
+ 0x2b,
+ 0x2d,
+ 0x2e,
+ 0x30,
+ 0x31,
+ 0x33,
+ 0x35,
+ 0x36,
+ 0x38,
+ 0x39,
+ 0x3b,
+ 0x3c,
+ 0x3e,
+ 0x3f,
+ 0x41,
+ 0x42,
+ 0x44,
+ 0x45,
+ 0x47,
+ 0x48,
+ 0x4a,
+ 0x4b,
+ 0x4d,
+ 0x4e,
+ 0x50,
+ 0x51,
+ 0x53,
+ 0x54,
+ 0x56,
+ 0x57,
+ 0x59,
+ 0x5a,
+ 0x5c,
+ 0x5d,
+ 0x5f,
+ 0x60,
+ 0x61,
+ 0x63,
+ 0x64,
+ 0x66,
+ 0x67,
+ 0x69,
+ 0x6a,
+ 0x6c,
+ 0x6d,
+ 0x6e,
+ 0x70,
+ 0x71,
+ 0x73,
+ 0x74,
+ 0x75,
+ 0x77,
+ 0x78,
+ 0x7a,
+ 0x7b,
+ 0x7c,
+ 0x7e,
+ 0x7f,
+ 0x80,
+ 0x82,
+ 0x83,
+ 0x84,
+ 0x86,
+ 0x87,
+ 0x88,
+ 0x8a,
+ 0x8b,
+ 0x8c,
+ 0x8e,
+ 0x8f,
+ 0x90,
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9b,
+ 0x9c,
+ 0x9d,
+ 0x9e,
+ 0x9f,
+ 0xa1,
+ 0xa2,
+ 0xa3,
+ 0xa4,
+ 0xa6,
+ 0xa7,
+ 0xa8,
+ 0xa9,
+ 0xaa,
+ 0xab,
+ 0xad,
+ 0xae,
+ 0xaf,
+ 0xb0,
+ 0xb1,
+ 0xb2,
+ 0xb3,
+ 0xb5,
+ 0xb6,
+ 0xb7,
+ 0xb8,
+ 0xb9,
+ 0xba,
+ 0xbb,
+ 0xbc,
+ 0xbd,
+ 0xbe,
+ 0xbf,
+ 0xc0,
+ 0xc1,
+ 0xc2,
+ 0xc3,
+ 0xc4,
+ 0xc5,
+ 0xc6,
+ 0xc7,
+ 0xc8,
+ 0xc9,
+ 0xca,
+ 0xcb,
+ 0xcc,
+ 0xcd,
+ 0xce,
+ 0xcf,
+ 0xd0,
+ 0xd1,
+ 0xd2,
+ 0xd3,
+ 0xd3,
+ 0xd4,
+ 0xd5,
+ 0xd6,
+ 0xd7,
+ 0xd8,
+ 0xd9,
+ 0xd9,
+ 0xda,
+ 0xdb,
+ 0xdc,
+ 0xdd,
+ 0xdd,
+ 0xde,
+ 0xdf,
+ 0xe0,
+ 0xe1,
+ 0xe1,
+ 0xe2,
+ 0xe3,
+ 0xe3,
+ 0xe4,
+ 0xe5,
+ 0xe6,
+ 0xe6,
+ 0xe7,
+ 0xe8,
+ 0xe8,
+ 0xe9,
+ 0xea,
+ 0xea,
+ 0xeb,
+ 0xeb,
+ 0xec,
+ 0xed,
+ 0xed,
+ 0xee,
+ 0xee,
+ 0xef,
+ 0xef,
+ 0xf0,
+ 0xf1,
+ 0xf1,
+ 0xf2,
+ 0xf2,
+ 0xf3,
+ 0xf3,
+ 0xf4,
+ 0xf4,
+ 0xf4,
+ 0xf5,
+ 0xf5,
+ 0xf6,
+ 0xf6,
+ 0xf7,
+ 0xf7,
+ 0xf7,
+ 0xf8,
+ 0xf8,
+ 0xf9,
+ 0xf9,
+ 0xf9,
+ 0xfa,
+ 0xfa,
+ 0xfa,
+ 0xfb,
+ 0xfb,
+ 0xfb,
+ 0xfb,
+ 0xfc,
+ 0xfc,
+ 0xfc,
+ 0xfc,
+ 0xfd,
+ 0xfd,
+ 0xfd,
+ 0xfd,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff
+ };
+
+ // Cosine LUT
+ static private int[] c = {
+ 0x100,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfd,
+ 0xfd,
+ 0xfd,
+ 0xfd,
+ 0xfc,
+ 0xfc,
+ 0xfc,
+ 0xfc,
+ 0xfb,
+ 0xfb,
+ 0xfb,
+ 0xfb,
+ 0xfa,
+ 0xfa,
+ 0xfa,
+ 0xf9,
+ 0xf9,
+ 0xf9,
+ 0xf8,
+ 0xf8,
+ 0xf7,
+ 0xf7,
+ 0xf7,
+ 0xf6,
+ 0xf6,
+ 0xf5,
+ 0xf5,
+ 0xf4,
+ 0xf4,
+ 0xf4,
+ 0xf3,
+ 0xf3,
+ 0xf2,
+ 0xf2,
+ 0xf1,
+ 0xf1,
+ 0xf0,
+ 0xef,
+ 0xef,
+ 0xee,
+ 0xee,
+ 0xed,
+ 0xed,
+ 0xec,
+ 0xeb,
+ 0xeb,
+ 0xea,
+ 0xea,
+ 0xe9,
+ 0xe8,
+ 0xe8,
+ 0xe7,
+ 0xe6,
+ 0xe6,
+ 0xe5,
+ 0xe4,
+ 0xe3,
+ 0xe3,
+ 0xe2,
+ 0xe1,
+ 0xe1,
+ 0xe0,
+ 0xdf,
+ 0xde,
+ 0xdd,
+ 0xdd,
+ 0xdc,
+ 0xdb,
+ 0xda,
+ 0xd9,
+ 0xd9,
+ 0xd8,
+ 0xd7,
+ 0xd6,
+ 0xd5,
+ 0xd4,
+ 0xd3,
+ 0xd3,
+ 0xd2,
+ 0xd1,
+ 0xd0,
+ 0xcf,
+ 0xce,
+ 0xcd,
+ 0xcc,
+ 0xcb,
+ 0xca,
+ 0xc9,
+ 0xc8,
+ 0xc7,
+ 0xc6,
+ 0xc5,
+ 0xc4,
+ 0xc3,
+ 0xc2,
+ 0xc1,
+ 0xc0,
+ 0xbf,
+ 0xbe,
+ 0xbd,
+ 0xbc,
+ 0xbb,
+ 0xba,
+ 0xb9,
+ 0xb8,
+ 0xb7,
+ 0xb6,
+ 0xb5,
+ 0xb3,
+ 0xb2,
+ 0xb1,
+ 0xb0,
+ 0xaf,
+ 0xae,
+ 0xad,
+ 0xab,
+ 0xaa,
+ 0xa9,
+ 0xa8,
+ 0xa7,
+ 0xa6,
+ 0xa4,
+ 0xa3,
+ 0xa2,
+ 0xa1,
+ 0x9f,
+ 0x9e,
+ 0x9d,
+ 0x9c,
+ 0x9b,
+ 0x99,
+ 0x98,
+ 0x97,
+ 0x95,
+ 0x94,
+ 0x93,
+ 0x92,
+ 0x90,
+ 0x8f,
+ 0x8e,
+ 0x8c,
+ 0x8b,
+ 0x8a,
+ 0x88,
+ 0x87,
+ 0x86,
+ 0x84,
+ 0x83,
+ 0x82,
+ 0x80,
+ 0x7f,
+ 0x7e,
+ 0x7c,
+ 0x7b,
+ 0x7a,
+ 0x78,
+ 0x77,
+ 0x75,
+ 0x74,
+ 0x73,
+ 0x71,
+ 0x70,
+ 0x6e,
+ 0x6d,
+ 0x6c,
+ 0x6a,
+ 0x69,
+ 0x67,
+ 0x66,
+ 0x64,
+ 0x63,
+ 0x61,
+ 0x60,
+ 0x5f,
+ 0x5d,
+ 0x5c,
+ 0x5a,
+ 0x59,
+ 0x57,
+ 0x56,
+ 0x54,
+ 0x53,
+ 0x51,
+ 0x50,
+ 0x4e,
+ 0x4d,
+ 0x4b,
+ 0x4a,
+ 0x48,
+ 0x47,
+ 0x45,
+ 0x44,
+ 0x42,
+ 0x41,
+ 0x3f,
+ 0x3e,
+ 0x3c,
+ 0x3b,
+ 0x39,
+ 0x38,
+ 0x36,
+ 0x35,
+ 0x33,
+ 0x31,
+ 0x30,
+ 0x2e,
+ 0x2d,
+ 0x2b,
+ 0x2a,
+ 0x28,
+ 0x27,
+ 0x25,
+ 0x24,
+ 0x22,
+ 0x20,
+ 0x1f,
+ 0x1d,
+ 0x1c,
+ 0x1a,
+ 0x19,
+ 0x17,
+ 0x15,
+ 0x14,
+ 0x12,
+ 0x11,
+ 0xf,
+ 0xe,
+ 0xc,
+ 0xa,
+ 0x9,
+ 0x7,
+ 0x6,
+ 0x4,
+ 0x3,
+ 0x1
+ };
+
+ /**
+ * Yet to be implemented.
+ * @param num Input
+ * @return Output
+ */
+ public static int arctan( int num ) {
+ return 0;
+ }
+
+ /**
+ * 26.6 fixed number square root function.
+ * Simple (brain-dead) divide & conqure algorithm.
+ * @param num The 26.6 fixed number in question
+ * @return The resulting square root
+ */
+ public static int squareRoot(int num) {
+ int n = num;
+ int divisor = num;
+ int nSquared;
+
+ while (divisor != 0) {
+ divisor /= 2;
+ nSquared = (n * n) >> 6;
+ if (nSquared == num) {
+ break;
+ } else if (nSquared > num) {
+ n -= divisor;
+ } else {
+ n += divisor;
+ }
+ }
+ return n;
+ }
+
+ public static float floatValue(long fixed) {
+ return (fixed >> 16) + (float)(fixed & 0xffff) / 0x10000;
+ }
+
+ public static float roundedFloatValue(long fixed, int decimalPlaces) {
+ int factor = 10 * decimalPlaces;
+ return (float)((int)(floatValue(fixed) * factor)) / factor;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/Mnemonic.java b/turtle2d/src/net/java/dev/typecast/ot/Mnemonic.java
new file mode 100644
index 0000000..5655c1e
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/Mnemonic.java
@@ -0,0 +1,397 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot;
+
+/**
+ * The Mnemonic representations of the TrueType instruction set.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Mnemonic.java,v 1.1.1.1 2004-12-05 23:14:30 davidsch Exp $
+ */
+public class Mnemonic {
+
+ public static final short SVTCA = 0x00; // [a]
+ public static final short SPVTCA = 0x02; // [a]
+ public static final short SFVTCA = 0x04; // [a]
+ public static final short SPVTL = 0x06; // [a]
+ public static final short SFVTL = 0x08; // [a]
+ public static final short SPVFS = 0x0A;
+ public static final short SFVFS = 0x0B;
+ public static final short GPV = 0x0C;
+ public static final short GFV = 0x0D;
+ public static final short SFVTPV = 0x0E;
+ public static final short ISECT = 0x0F;
+ public static final short SRP0 = 0x10;
+ public static final short SRP1 = 0x11;
+ public static final short SRP2 = 0x12;
+ public static final short SZP0 = 0x13;
+ public static final short SZP1 = 0x14;
+ public static final short SZP2 = 0x15;
+ public static final short SZPS = 0x16;
+ public static final short SLOOP = 0x17;
+ public static final short RTG = 0x18;
+ public static final short RTHG = 0x19;
+ public static final short SMD = 0x1A;
+ public static final short ELSE = 0x1B;
+ public static final short JMPR = 0x1C;
+ public static final short SCVTCI = 0x1D;
+ public static final short SSWCI = 0x1E;
+ public static final short SSW = 0x1F;
+ public static final short DUP = 0x20;
+ public static final short POP = 0x21;
+ public static final short CLEAR = 0x22;
+ public static final short SWAP = 0x23;
+ public static final short DEPTH = 0x24;
+ public static final short CINDEX = 0x25;
+ public static final short MINDEX = 0x26;
+ public static final short ALIGNPTS = 0x27;
+ public static final short UTP = 0x29;
+ public static final short LOOPCALL = 0x2A;
+ public static final short CALL = 0x2B;
+ public static final short FDEF = 0x2C;
+ public static final short ENDF = 0x2D;
+ public static final short MDAP = 0x2E; // [a]
+ public static final short IUP = 0x30; // [a]
+ public static final short SHP = 0x32;
+ public static final short SHC = 0x34; // [a]
+ public static final short SHZ = 0x36; // [a]
+ public static final short SHPIX = 0x38;
+ public static final short IP = 0x39;
+ public static final short MSIRP = 0x3A; // [a]
+ public static final short ALIGNRP = 0x3C;
+ public static final short RTDG = 0x3D;
+ public static final short MIAP = 0x3E; // [a]
+ public static final short NPUSHB = 0x40;
+ public static final short NPUSHW = 0x41;
+ public static final short WS = 0x42;
+ public static final short RS = 0x43;
+ public static final short WCVTP = 0x44;
+ public static final short RCVT = 0x45;
+ public static final short GC = 0x46; // [a]
+ public static final short SCFS = 0x48;
+ public static final short MD = 0x49; // [a]
+ public static final short MPPEM = 0x4B;
+ public static final short MPS = 0x4C;
+ public static final short FLIPON = 0x4D;
+ public static final short FLIPOFF = 0x4E;
+ public static final short DEBUG = 0x4F;
+ public static final short LT = 0x50;
+ public static final short LTEQ = 0x51;
+ public static final short GT = 0x52;
+ public static final short GTEQ = 0x53;
+ public static final short EQ = 0x54;
+ public static final short NEQ = 0x55;
+ public static final short ODD = 0x56;
+ public static final short EVEN = 0x57;
+ public static final short IF = 0x58;
+ public static final short EIF = 0x59;
+ public static final short AND = 0x5A;
+ public static final short OR = 0x5B;
+ public static final short NOT = 0x5C;
+ public static final short DELTAP1 = 0x5D;
+ public static final short SDB = 0x5E;
+ public static final short SDS = 0x5F;
+ public static final short ADD = 0x60;
+ public static final short SUB = 0x61;
+ public static final short DIV = 0x62;
+ public static final short MUL = 0x63;
+ public static final short ABS = 0x64;
+ public static final short NEG = 0x65;
+ public static final short FLOOR = 0x66;
+ public static final short CEILING = 0x67;
+ public static final short ROUND = 0x68; // [ab]
+ public static final short NROUND = 0x6C; // [ab]
+ public static final short WCVTF = 0x70;
+ public static final short DELTAP2 = 0x71;
+ public static final short DELTAP3 = 0x72;
+ public static final short DELTAC1 = 0x73;
+ public static final short DELTAC2 = 0x74;
+ public static final short DELTAC3 = 0x75;
+ public static final short SROUND = 0x76;
+ public static final short S45ROUND = 0x77;
+ public static final short JROT = 0x78;
+ public static final short JROF = 0x79;
+ public static final short ROFF = 0x7A;
+ public static final short RUTG = 0x7C;
+ public static final short RDTG = 0x7D;
+ public static final short SANGW = 0x7E;
+ public static final short AA = 0x7F;
+ public static final short FLIPPT = 0x80;
+ public static final short FLIPRGON = 0x81;
+ public static final short FLIPRGOFF = 0x82;
+ public static final short SCANCTRL = 0x85;
+ public static final short SDPVTL = 0x86; // [a]
+ public static final short GETINFO = 0x88;
+ public static final short IDEF = 0x89;
+ public static final short ROLL = 0x8A;
+ public static final short MAX = 0x8B;
+ public static final short MIN = 0x8C;
+ public static final short SCANTYPE = 0x8D;
+ public static final short INSTCTRL = 0x8E;
+ public static final short PUSHB = 0xB0; // [abc]
+ public static final short PUSHW = 0xB8; // [abc]
+ public static final short MDRP = 0xC0; // [abcde]
+ public static final short MIRP = 0xE0; // [abcde]
+
+ /**
+ * Gets the mnemonic text for the specified opcode
+ * @param opcode The opcode for which the mnemonic is required
+ * @return The mnemonic, with a description
+ */
+ public static String getMnemonic(short opcode) {
+ if (opcode >= MIRP) return "MIRP["+((opcode&16)==0?"nrp0,":"srp0,")+((opcode&8)==0?"nmd,":"md,")+((opcode&4)==0?"nrd,":"rd,")+(opcode&3)+"]";
+ else if (opcode >= MDRP) return "MDRP["+((opcode&16)==0?"nrp0,":"srp0,")+((opcode&8)==0?"nmd,":"md,")+((opcode&4)==0?"nrd,":"rd,")+(opcode&3)+"]";
+ else if (opcode >= PUSHW) return "PUSHW["+((opcode&7)+1)+"]";
+ else if (opcode >= PUSHB) return "PUSHB["+((opcode&7)+1)+"]";
+ else if (opcode >= INSTCTRL) return "INSTCTRL";
+ else if (opcode >= SCANTYPE) return "SCANTYPE";
+ else if (opcode >= MIN) return "MIN";
+ else if (opcode >= MAX) return "MAX";
+ else if (opcode >= ROLL) return "ROLL";
+ else if (opcode >= IDEF) return "IDEF";
+ else if (opcode >= GETINFO) return "GETINFO";
+ else if (opcode >= SDPVTL) return "SDPVTL["+(opcode&1)+"]";
+ else if (opcode >= SCANCTRL) return "SCANCTRL";
+ else if (opcode >= FLIPRGOFF) return "FLIPRGOFF";
+ else if (opcode >= FLIPRGON) return "FLIPRGON";
+ else if (opcode >= FLIPPT) return "FLIPPT";
+ else if (opcode >= AA) return "AA";
+ else if (opcode >= SANGW) return "SANGW";
+ else if (opcode >= RDTG) return "RDTG";
+ else if (opcode >= RUTG) return "RUTG";
+ else if (opcode >= ROFF) return "ROFF";
+ else if (opcode >= JROF) return "JROF";
+ else if (opcode >= JROT) return "JROT";
+ else if (opcode >= S45ROUND) return "S45ROUND";
+ else if (opcode >= SROUND) return "SROUND";
+ else if (opcode >= DELTAC3) return "DELTAC3";
+ else if (opcode >= DELTAC2) return "DELTAC2";
+ else if (opcode >= DELTAC1) return "DELTAC1";
+ else if (opcode >= DELTAP3) return "DELTAP3";
+ else if (opcode >= DELTAP2) return "DELTAP2";
+ else if (opcode >= WCVTF) return "WCVTF";
+ else if (opcode >= NROUND) return "NROUND["+(opcode&3)+"]";
+ else if (opcode >= ROUND) return "ROUND["+(opcode&3)+"]";
+ else if (opcode >= CEILING) return "CEILING";
+ else if (opcode >= FLOOR) return "FLOOR";
+ else if (opcode >= NEG) return "NEG";
+ else if (opcode >= ABS) return "ABS";
+ else if (opcode >= MUL) return "MUL";
+ else if (opcode >= DIV) return "DIV";
+ else if (opcode >= SUB) return "SUB";
+ else if (opcode >= ADD) return "ADD";
+ else if (opcode >= SDS) return "SDS";
+ else if (opcode >= SDB) return "SDB";
+ else if (opcode >= DELTAP1) return "DELTAP1";
+ else if (opcode >= NOT) return "NOT";
+ else if (opcode >= OR) return "OR";
+ else if (opcode >= AND) return "AND";
+ else if (opcode >= EIF) return "EIF";
+ else if (opcode >= IF) return "IF";
+ else if (opcode >= EVEN) return "EVEN";
+ else if (opcode >= ODD) return "ODD";
+ else if (opcode >= NEQ) return "NEQ";
+ else if (opcode >= EQ) return "EQ";
+ else if (opcode >= GTEQ) return "GTEQ";
+ else if (opcode >= GT) return "GT";
+ else if (opcode >= LTEQ) return "LTEQ";
+ else if (opcode >= LT) return "LT";
+ else if (opcode >= DEBUG) return "DEBUG";
+ else if (opcode >= FLIPOFF) return "FLIPOFF";
+ else if (opcode >= FLIPON) return "FLIPON";
+ else if (opcode >= MPS) return "MPS";
+ else if (opcode >= MPPEM) return "MPPEM";
+ else if (opcode >= MD) return "MD["+(opcode&1)+"]";
+ else if (opcode >= SCFS) return "SCFS";
+ else if (opcode >= GC) return "GC["+(opcode&1)+"]";
+ else if (opcode >= RCVT) return "RCVT";
+ else if (opcode >= WCVTP) return "WCVTP";
+ else if (opcode >= RS) return "RS";
+ else if (opcode >= WS) return "WS";
+ else if (opcode >= NPUSHW) return "NPUSHW";
+ else if (opcode >= NPUSHB) return "NPUSHB";
+ else if (opcode >= MIAP) return "MIAP["+((opcode&1)==0?"nrd+nci":"rd+ci")+"]";
+ else if (opcode >= RTDG) return "RTDG";
+ else if (opcode >= ALIGNRP) return "ALIGNRP";
+ else if (opcode >= MSIRP) return "MSIRP["+(opcode&1)+"]";
+ else if (opcode >= IP) return "IP";
+ else if (opcode >= SHPIX) return "SHPIX";
+ else if (opcode >= SHZ) return "SHZ["+(opcode&1)+"]";
+ else if (opcode >= SHC) return "SHC["+(opcode&1)+"]";
+ else if (opcode >= SHP) return "SHP";
+ else if (opcode >= IUP) return "IUP["+((opcode&1)==0?"y":"x")+"]";
+ else if (opcode >= MDAP) return "MDAP["+((opcode&1)==0?"nrd":"rd")+"]";
+ else if (opcode >= ENDF) return "ENDF";
+ else if (opcode >= FDEF) return "FDEF";
+ else if (opcode >= CALL) return "CALL";
+ else if (opcode >= LOOPCALL) return "LOOPCALL";
+ else if (opcode >= UTP) return "UTP";
+ else if (opcode >= ALIGNPTS) return "ALIGNPTS";
+ else if (opcode >= MINDEX) return "MINDEX";
+ else if (opcode >= CINDEX) return "CINDEX";
+ else if (opcode >= DEPTH) return "DEPTH";
+ else if (opcode >= SWAP) return "SWAP";
+ else if (opcode >= CLEAR) return "CLEAR";
+ else if (opcode >= POP) return "POP";
+ else if (opcode >= DUP) return "DUP";
+ else if (opcode >= SSW) return "SSW";
+ else if (opcode >= SSWCI) return "SSWCI";
+ else if (opcode >= SCVTCI) return "SCVTCI";
+ else if (opcode >= JMPR) return "JMPR";
+ else if (opcode >= ELSE) return "ELSE";
+ else if (opcode >= SMD) return "SMD";
+ else if (opcode >= RTHG) return "RTHG";
+ else if (opcode >= RTG) return "RTG";
+ else if (opcode >= SLOOP) return "SLOOP";
+ else if (opcode >= SZPS) return "SZPS";
+ else if (opcode >= SZP2) return "SZP2";
+ else if (opcode >= SZP1) return "SZP1";
+ else if (opcode >= SZP0) return "SZP0";
+ else if (opcode >= SRP2) return "SRP2";
+ else if (opcode >= SRP1) return "SRP1";
+ else if (opcode >= SRP0) return "SRP0";
+ else if (opcode >= ISECT) return "ISECT";
+ else if (opcode >= SFVTPV) return "SFVTPV";
+ else if (opcode >= GFV) return "GFV";
+ else if (opcode >= GPV) return "GPV";
+ else if (opcode >= SFVFS) return "SFVFS";
+ else if (opcode >= SPVFS) return "SPVFS";
+ else if (opcode >= SFVTL) return "SFVTL["+((opcode&1)==0?"y-axis":"x-axis")+"]";
+ else if (opcode >= SPVTL) return "SPVTL["+((opcode&1)==0?"y-axis":"x-axis")+"]";
+ else if (opcode >= SFVTCA) return "SFVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]";
+ else if (opcode >= SPVTCA) return "SPVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]";
+ else if (opcode >= SVTCA) return "SVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]";
+ else return "????";
+ }
+
+ public static String getComment(short opcode) {
+ if (opcode >= MIRP) return "MIRP["+((opcode&16)==0?"nrp0,":"srp0,")+((opcode&8)==0?"nmd,":"md,")+((opcode&4)==0?"nrd,":"rd,")+(opcode&3)+"]\t\tMove Indirect Relative Point";
+ else if (opcode >= MDRP) return "MDRP["+((opcode&16)==0?"nrp0,":"srp0,")+((opcode&8)==0?"nmd,":"md,")+((opcode&4)==0?"nrd,":"rd,")+(opcode&3)+"]\t\tMove Direct Relative Point";
+ else if (opcode >= PUSHW) return "PUSHW["+((opcode&7)+1)+"]";
+ else if (opcode >= PUSHB) return "PUSHB["+((opcode&7)+1)+"]";
+ else if (opcode >= INSTCTRL) return "INSTCTRL\tINSTruction Execution ConTRol";
+ else if (opcode >= SCANTYPE) return "SCANTYPE\tSCANTYPE";
+ else if (opcode >= MIN) return "MIN\t\tMINimum of top two stack elements";
+ else if (opcode >= MAX) return "MAX\t\tMAXimum of top two stack elements";
+ else if (opcode >= ROLL) return "ROLL\t\tROLL the top three stack elements";
+ else if (opcode >= IDEF) return "IDEF\t\tInstruction DEFinition";
+ else if (opcode >= GETINFO) return "GETINFO\tGET INFOrmation";
+ else if (opcode >= SDPVTL) return "SDPVTL["+(opcode&1)+"]\tSet Dual Projection_Vector To Line";
+ else if (opcode >= SCANCTRL) return "SCANCTRL\tSCAN conversion ConTRoL";
+ else if (opcode >= FLIPRGOFF) return "FLIPRGOFF\tFLIP RanGe OFF";
+ else if (opcode >= FLIPRGON) return "FLIPRGON\tFLIP RanGe ON";
+ else if (opcode >= FLIPPT) return "FLIPPT\tFLIP PoinT";
+ else if (opcode >= AA) return "AA";
+ else if (opcode >= SANGW) return "SANGW\t\tSet Angle _Weight";
+ else if (opcode >= RDTG) return "RDTG\t\tRound Down To Grid";
+ else if (opcode >= RUTG) return "RUTG\t\tRound Up To Grid";
+ else if (opcode >= ROFF) return "ROFF\t\tRound OFF";
+ else if (opcode >= JROF) return "JROF\t\tJump Relative On False";
+ else if (opcode >= JROT) return "JROT\t\tJump Relative On True";
+ else if (opcode >= S45ROUND) return "S45ROUND\tSuper ROUND 45 degrees";
+ else if (opcode >= SROUND) return "SROUND\tSuper ROUND";
+ else if (opcode >= DELTAC3) return "DELTAC3\tDELTA exception C3";
+ else if (opcode >= DELTAC2) return "DELTAC2\tDELTA exception C2";
+ else if (opcode >= DELTAC1) return "DELTAC1\tDELTA exception C1";
+ else if (opcode >= DELTAP3) return "DELTAP3\tDELTA exception P3";
+ else if (opcode >= DELTAP2) return "DELTAP2\tDELTA exception P2";
+ else if (opcode >= WCVTF) return "WCVTF\t\tWrite Control Value Table in FUnits";
+ else if (opcode >= NROUND) return "NROUND["+(opcode&3)+"]";
+ else if (opcode >= ROUND) return "ROUND["+(opcode&3)+"]";
+ else if (opcode >= CEILING) return "CEILING\tCEILING";
+ else if (opcode >= FLOOR) return "FLOOR\t\tFLOOR";
+ else if (opcode >= NEG) return "NEG\t\tNEGate";
+ else if (opcode >= ABS) return "ABS\t\tABSolute value";
+ else if (opcode >= MUL) return "MUL\t\tMULtiply";
+ else if (opcode >= DIV) return "DIV\t\tDIVide";
+ else if (opcode >= SUB) return "SUB\t\tSUBtract";
+ else if (opcode >= ADD) return "ADD\t\tADD";
+ else if (opcode >= SDS) return "SDS\t\tSet Delta_Shift in the graphics state";
+ else if (opcode >= SDB) return "SDB\t\tSet Delta_Base in the graphics state";
+ else if (opcode >= DELTAP1) return "DELTAP1\tDELTA exception P1";
+ else if (opcode >= NOT) return "NOT\t\tlogical NOT";
+ else if (opcode >= OR) return "OR\t\t\tlogical OR";
+ else if (opcode >= AND) return "AND\t\tlogical AND";
+ else if (opcode >= EIF) return "EIF\t\tEnd IF";
+ else if (opcode >= IF) return "IF\t\t\tIF test";
+ else if (opcode >= EVEN) return "EVEN";
+ else if (opcode >= ODD) return "ODD";
+ else if (opcode >= NEQ) return "NEQ\t\tNot EQual";
+ else if (opcode >= EQ) return "EQ\t\t\tEQual";
+ else if (opcode >= GTEQ) return "GTEQ\t\tGreater Than or Equal";
+ else if (opcode >= GT) return "GT\t\t\tGreater Than";
+ else if (opcode >= LTEQ) return "LTEQ\t\tLess Than or Equal";
+ else if (opcode >= LT) return "LT\t\t\tLess Than";
+ else if (opcode >= DEBUG) return "DEBUG";
+ else if (opcode >= FLIPOFF) return "FLIPOFF\tSet the auto_flip Boolean to OFF";
+ else if (opcode >= FLIPON) return "FLIPON\tSet the auto_flip Boolean to ON";
+ else if (opcode >= MPS) return "MPS\t\tMeasure Point Size";
+ else if (opcode >= MPPEM) return "MPPEM\t\tMeasure Pixels Per EM";
+ else if (opcode >= MD) return "MD["+(opcode&1)+"]\t\t\tMeasure Distance";
+ else if (opcode >= SCFS) return "SCFS\t\tSets Coordinate From the Stack using projection_vector and freedom_vector";
+ else if (opcode >= GC) return "GC["+(opcode&1)+"]\t\t\tGet Coordinate projected onto the projection_vector";
+ else if (opcode >= RCVT) return "RCVT\t\tRead Control Value Table";
+ else if (opcode >= WCVTP) return "WCVTP\t\tWrite Control Value Table in Pixel units";
+ else if (opcode >= RS) return "RS\t\t\tRead Store";
+ else if (opcode >= WS) return "WS\t\t\tWrite Store";
+ else if (opcode >= NPUSHW) return "NPUSHW";
+ else if (opcode >= NPUSHB) return "NPUSHB";
+ else if (opcode >= MIAP) return "MIAP["+((opcode&1)==0?"nrd+nci":"rd+ci")+"]\t\tMove Indirect Absolute Point";
+ else if (opcode >= RTDG) return "RTDG\t\tRound To Double Grid";
+ else if (opcode >= ALIGNRP) return "ALIGNRP\tALIGN Relative Point";
+ else if (opcode >= MSIRP) return "MSIRP["+(opcode&1)+"]\t\tMove Stack Indirect Relative Point";
+ else if (opcode >= IP) return "IP\t\t\tInterpolate Point by the last relative stretch";
+ else if (opcode >= SHPIX) return "SHPIX\t\tSHift point by a PIXel amount";
+ else if (opcode >= SHZ) return "SHZ["+(opcode&1)+"]\t\tSHift Zone by the last pt";
+ else if (opcode >= SHC) return "SHC["+(opcode&1)+"]\t\tSHift Contour by the last point";
+ else if (opcode >= SHP) return "SHP\t\tSHift Point by the last point";
+ else if (opcode >= IUP) return "IUP["+((opcode&1)==0?"y":"x")+"]\t\tInterpolate Untouched Points through the outline";
+ else if (opcode >= MDAP) return "MDAP["+((opcode&1)==0?"nrd":"rd")+"]\t\tMove Direct Absolute Point";
+ else if (opcode >= ENDF) return "ENDF\t\tEND Function definition";
+ else if (opcode >= FDEF) return "FDEF\t\tFunction DEFinition ";
+ else if (opcode >= CALL) return "CALL\t\tCALL function";
+ else if (opcode >= LOOPCALL) return "LOOPCALL\tLOOP and CALL function";
+ else if (opcode >= UTP) return "UTP\t\tUnTouch Point";
+ else if (opcode >= ALIGNPTS) return "ALIGNPTS\tALIGN Points";
+ else if (opcode >= MINDEX) return "MINDEX\tMove the INDEXed element to the top of the stack";
+ else if (opcode >= CINDEX) return "CINDEX\tCopy the INDEXed element to the top of the stack";
+ else if (opcode >= DEPTH) return "DEPTH\t\tReturns the DEPTH of the stack";
+ else if (opcode >= SWAP) return "SWAP\t\tSWAP the top two elements on the stack";
+ else if (opcode >= CLEAR) return "CLEAR\t\tClear the entire stack";
+ else if (opcode >= POP) return "POP\t\tPOP top stack element";
+ else if (opcode >= DUP) return "DUP\t\tDuplicate top stack element";
+ else if (opcode >= SSW) return "SSW\t\tSet Single-width";
+ else if (opcode >= SSWCI) return "SSWCI\t\tSet Single_Width_Cut_In";
+ else if (opcode >= SCVTCI) return "SCVTCI\tSet Control Value Table Cut In";
+ else if (opcode >= JMPR) return "JMPR\t\tJuMP";
+ else if (opcode >= ELSE) return "ELSE";
+ else if (opcode >= SMD) return "SMD\t\tSet Minimum_ Distance";
+ else if (opcode >= RTHG) return "RTHG\t\tRound To Half Grid";
+ else if (opcode >= RTG) return "RTG\t\tRound To Grid";
+ else if (opcode >= SLOOP) return "SLOOP\t\tSet LOOP variable";
+ else if (opcode >= SZPS) return "SZPS\t\tSet Zone PointerS";
+ else if (opcode >= SZP2) return "SZP2\t\tSet Zone Pointer 2";
+ else if (opcode >= SZP1) return "SZP1\t\tSet Zone Pointer 1";
+ else if (opcode >= SZP0) return "SZP0\t\tSet Zone Pointer 0";
+ else if (opcode >= SRP2) return "SRP2\t\tSet Reference Point 2";
+ else if (opcode >= SRP1) return "SRP1\t\tSet Reference Point 1";
+ else if (opcode >= SRP0) return "SRP0\t\tSet Reference Point 0";
+ else if (opcode >= ISECT) return "ISECT\t\tmoves point p to the InterSECTion of two lines";
+ else if (opcode >= SFVTPV) return "SFVTPV\tSet Freedom_Vector To Projection Vector";
+ else if (opcode >= GFV) return "GFV\t\tGet Freedom_Vector";
+ else if (opcode >= GPV) return "GPV\t\tGet Projection_Vector";
+ else if (opcode >= SFVFS) return "SFVFS\t\tSet Freedom_Vector From Stack";
+ else if (opcode >= SPVFS) return "SPVFS\t\tSet Projection_Vector From Stack";
+ else if (opcode >= SFVTL) return "SFVTL["+((opcode&1)==0?"y-axis":"x-axis")+"]\t\tSet Freedom_Vector To Line";
+ else if (opcode >= SPVTL) return "SPVTL["+((opcode&1)==0?"y-axis":"x-axis")+"]\t\tSet Projection_Vector To Line";
+ else if (opcode >= SFVTCA) return "SFVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]\tSet Freedom_Vector to Coordinate Axis";
+ else if (opcode >= SPVTCA) return "SPVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]\tSet Projection_Vector To Coordinate Axis";
+ else if (opcode >= SVTCA) return "SVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]\t\tSet freedom and projection Vectors To Coordinate Axis";
+ else return "????";
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/OTFont.java b/turtle2d/src/net/java/dev/typecast/ot/OTFont.java
new file mode 100644
index 0000000..e58fc37
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/OTFont.java
@@ -0,0 +1,274 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import net.java.dev.typecast.ot.table.DirectoryEntry;
+import net.java.dev.typecast.ot.table.GlyfDescript;
+import net.java.dev.typecast.ot.table.HdmxTable;
+import net.java.dev.typecast.ot.table.TableDirectory;
+import net.java.dev.typecast.ot.table.Table;
+import net.java.dev.typecast.ot.table.Os2Table;
+import net.java.dev.typecast.ot.table.CmapTable;
+import net.java.dev.typecast.ot.table.GlyfTable;
+import net.java.dev.typecast.ot.table.HeadTable;
+import net.java.dev.typecast.ot.table.HheaTable;
+import net.java.dev.typecast.ot.table.HmtxTable;
+import net.java.dev.typecast.ot.table.LocaTable;
+import net.java.dev.typecast.ot.table.MaxpTable;
+import net.java.dev.typecast.ot.table.NameTable;
+import net.java.dev.typecast.ot.table.PostTable;
+import net.java.dev.typecast.ot.table.VheaTable;
+import net.java.dev.typecast.ot.table.TableFactory;
+
+/**
+ * The TrueType font.
+ * @version $Id: OTFont.java,v 1.6 2007-01-31 01:49:18 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>, Sven Gothel
+ */
+public class OTFont {
+
+ private OTFontCollection _fc;
+ private TableDirectory _tableDirectory = null;
+ private Table[] _tables;
+ private Os2Table _os2;
+ private CmapTable _cmap;
+ private GlyfTable _glyf;
+ private HeadTable _head;
+ private HheaTable _hhea;
+ private HdmxTable _hdmx;
+ private HmtxTable _hmtx;
+ private LocaTable _loca;
+ private MaxpTable _maxp;
+ private NameTable _name;
+ private PostTable _post;
+ private VheaTable _vhea;
+
+ /**
+ * Constructor
+ */
+ public OTFont(OTFontCollection fc) {
+ _fc = fc;
+ }
+
+ public Table getTable(int tableType) {
+ for (int i = 0; i < _tables.length; i++) {
+ if ((_tables[i] != null) && (_tables[i].getType() == tableType)) {
+ return _tables[i];
+ }
+ }
+ return null;
+ }
+
+ public Os2Table getOS2Table() {
+ return _os2;
+ }
+
+ public CmapTable getCmapTable() {
+ return _cmap;
+ }
+
+ public HeadTable getHeadTable() {
+ return _head;
+ }
+
+ public HheaTable getHheaTable() {
+ return _hhea;
+ }
+
+ public HdmxTable getHdmxTable() {
+ return _hdmx;
+ }
+
+ public HmtxTable getHmtxTable() {
+ return _hmtx;
+ }
+
+ public LocaTable getLocaTable() {
+ return _loca;
+ }
+
+ public MaxpTable getMaxpTable() {
+ return _maxp;
+ }
+
+ public NameTable getNameTable() {
+ return _name;
+ }
+
+ public PostTable getPostTable() {
+ return _post;
+ }
+
+ public VheaTable getVheaTable() {
+ return _vhea;
+ }
+
+ public int getAscent() {
+ return _hhea.getAscender();
+ }
+
+ public int getDescent() {
+ return _hhea.getDescender();
+ }
+
+ public int getNumGlyphs() {
+ return _maxp.getNumGlyphs();
+ }
+
+ public OTGlyph getGlyph(int i) {
+
+ final GlyfDescript _glyfDescr = _glyf.getDescription(i);
+ return (null != _glyfDescr)
+ ? new OTGlyph(
+ _glyfDescr,
+ _hmtx.getLeftSideBearing(i),
+ _hmtx.getAdvanceWidth(i))
+ : null;
+ }
+
+ public TableDirectory getTableDirectory() {
+ return _tableDirectory;
+ }
+
+ private Table readTable(
+ DataInputStream dis,
+ int tablesOrigin,
+ int tag) throws IOException {
+ dis.reset();
+ DirectoryEntry entry = _tableDirectory.getEntryByTag(tag);
+ if (entry == null) {
+ return null;
+ }
+ dis.skip(tablesOrigin + entry.getOffset());
+ return TableFactory.create(_fc, this, entry, dis);
+ }
+
+ /**
+ * @param dis OpenType/TrueType font file data.
+ * @param directoryOffset The Table Directory offset within the file. For a
+ * regular TTF/OTF file this will be zero, but for a TTC (Font Collection)
+ * the offset is retrieved from the TTC header. For a Mac font resource,
+ * offset is retrieved from the resource headers.
+ * @param tablesOrigin The point the table offsets are calculated from.
+ * Once again, in a regular TTF file, this will be zero. In a TTC is is
+ * also zero, but within a Mac resource, it is the beggining of the
+ * individual font resource data.
+ */
+ protected void read(
+ DataInputStream dis,
+ int directoryOffset,
+ int tablesOrigin) throws IOException {
+
+ // Load the table directory
+ dis.reset();
+ dis.skip(directoryOffset);
+ _tableDirectory = new TableDirectory(dis);
+ _tables = new Table[_tableDirectory.getNumTables()];
+
+ // Load some prerequisite tables
+ _head = (HeadTable) readTable(dis, tablesOrigin, Table.head);
+ _hhea = (HheaTable) readTable(dis, tablesOrigin, Table.hhea);
+ _maxp = (MaxpTable) readTable(dis, tablesOrigin, Table.maxp);
+ _loca = (LocaTable) readTable(dis, tablesOrigin, Table.loca);
+ _vhea = (VheaTable) readTable(dis, tablesOrigin, Table.vhea);
+
+ int index = 0;
+ _tables[index++] = _head;
+ _tables[index++] = _hhea;
+ _tables[index++] = _maxp;
+ if (_loca != null) {
+ _tables[index++] = _loca;
+ }
+ if (_vhea != null) {
+ _tables[index++] = _vhea;
+ }
+
+ // Load all other tables
+ for (int i = 0; i < _tableDirectory.getNumTables(); i++) {
+ DirectoryEntry entry = _tableDirectory.getEntry(i);
+ if (entry.getTag() == Table.head
+ || entry.getTag() == Table.hhea
+ || entry.getTag() == Table.maxp
+ || entry.getTag() == Table.loca
+ || entry.getTag() == Table.vhea) {
+ continue;
+ }
+ dis.reset();
+ dis.skip(tablesOrigin + entry.getOffset());
+ _tables[index] = TableFactory.create(_fc, this, entry, dis);
+ ++index;
+ }
+
+ // Get references to commonly used tables (these happen to be all the
+ // required tables)
+ _cmap = (CmapTable) getTable(Table.cmap);
+ _hdmx = (HdmxTable) getTable(Table.hdmx);
+ _hmtx = (HmtxTable) getTable(Table.hmtx);
+ _name = (NameTable) getTable(Table.name);
+ _os2 = (Os2Table) getTable(Table.OS_2);
+ _post = (PostTable) getTable(Table.post);
+
+ // If this is a TrueType outline, then we'll have at least the
+ // 'glyf' table (along with the 'loca' table)
+ _glyf = (GlyfTable) getTable(Table.glyf);
+ }
+
+ public String toString() {
+ if (_tableDirectory != null) {
+ return _tableDirectory.toString();
+ } else {
+ return "Empty font";
+ }
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/OTFontCollection.java b/turtle2d/src/net/java/dev/typecast/ot/OTFontCollection.java
new file mode 100644
index 0000000..6f8754f
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/OTFontCollection.java
@@ -0,0 +1,169 @@
+/*
+ * $Id: OTFontCollection.java,v 1.6 2010-08-10 11:38:11 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot;
+
+import java.io.File;
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import java.util.ArrayList;
+
+import net.java.dev.typecast.ot.mac.ResourceHeader;
+import net.java.dev.typecast.ot.mac.ResourceMap;
+import net.java.dev.typecast.ot.mac.ResourceReference;
+import net.java.dev.typecast.ot.mac.ResourceType;
+import net.java.dev.typecast.ot.table.DirectoryEntry;
+import net.java.dev.typecast.ot.table.Table;
+import net.java.dev.typecast.ot.table.TTCHeader;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: OTFontCollection.java,v 1.6 2010-08-10 11:38:11 davidsch Exp $
+ */
+public class OTFontCollection {
+
+ private String _pathName;
+ private String _fileName;
+ private TTCHeader _ttcHeader;
+ private OTFont[] _fonts;
+ private ArrayList<Table> _tables = new ArrayList<Table>();
+ private boolean _resourceFork = false;
+
+ /** Creates new FontCollection */
+ protected OTFontCollection() {
+ }
+
+ /**
+ * @param file The OpenType font file
+ */
+ public static OTFontCollection create(File file) throws IOException {
+ OTFontCollection fc = new OTFontCollection();
+ fc.read(file);
+ return fc;
+ }
+
+ public String getPathName() {
+ return _pathName;
+ }
+
+ public String getFileName() {
+ return _fileName;
+ }
+
+ public OTFont getFont(int i) {
+ return _fonts[i];
+ }
+
+ public int getFontCount() {
+ return _fonts.length;
+ }
+
+ public TTCHeader getTtcHeader() {
+ return _ttcHeader;
+ }
+
+ public Table getTable(DirectoryEntry de) {
+ for (int i = 0; i < _tables.size(); i++) {
+ Table table = _tables.get(i);
+ if ((table.getDirectoryEntry().getTag() == de.getTag()) &&
+ (table.getDirectoryEntry().getOffset() == de.getOffset())) {
+ return table;
+ }
+ }
+ return null;
+ }
+
+ public void addTable(Table table) {
+ _tables.add(table);
+ }
+
+ /**
+ * @param file The OpenType font file
+ */
+ protected void read(File file) throws IOException {
+ _pathName = file.getPath();
+ _fileName = file.getName();
+
+ if (!file.exists()) {
+ throw new IOException();
+ }
+
+ // Do we need to modify the path name to deal with font resources
+ // in a Mac resource fork?
+ if (file.length() == 0) {
+ file = new File(file, "..namedfork/rsrc");
+ if (!file.exists()) {
+ throw new IOException();
+ }
+ _resourceFork = true;
+ }
+
+ DataInputStream dis = new DataInputStream(
+ new BufferedInputStream(
+ new FileInputStream(file), (int) file.length()));
+ dis.mark((int) file.length());
+
+ if (_resourceFork || _pathName.endsWith(".dfont")) {
+
+ // This is a Macintosh font suitcase resource
+ ResourceHeader resourceHeader = new ResourceHeader(dis);
+
+ // Seek to the map offset and read the map
+ dis.reset();
+ dis.skip(resourceHeader.getMapOffset());
+ ResourceMap map = new ResourceMap(dis);
+
+ // Get the 'sfnt' resources
+ ResourceType resourceType = map.getResourceType("sfnt");
+
+ // Load the font data
+ _fonts = new OTFont[resourceType.getCount()];
+ for (int i = 0; i < resourceType.getCount(); i++) {
+ ResourceReference resourceReference = resourceType.getReference(i);
+ _fonts[i] = new OTFont(this);
+ int offset = resourceHeader.getDataOffset() +
+ resourceReference.getDataOffset() + 4;
+ _fonts[i].read(dis, offset, offset);
+ }
+
+ } else if (TTCHeader.isTTC(dis)) {
+
+ // This is a TrueType font collection
+ dis.reset();
+ _ttcHeader = new TTCHeader(dis);
+ _fonts = new OTFont[_ttcHeader.getDirectoryCount()];
+ for (int i = 0; i < _ttcHeader.getDirectoryCount(); i++) {
+ _fonts[i] = new OTFont(this);
+ _fonts[i].read(dis, _ttcHeader.getTableDirectory(i), 0);
+ }
+ } else {
+
+ // This is a standalone font file
+ _fonts = new OTFont[1];
+ _fonts[0] = new OTFont(this);
+ _fonts[0].read(dis, 0, 0);
+ }
+ dis.close();
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/OTGlyph.java b/turtle2d/src/net/java/dev/typecast/ot/OTGlyph.java
new file mode 100644
index 0000000..958dd22
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/OTGlyph.java
@@ -0,0 +1,168 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot;
+
+import com.jogamp.graph.geom.AABBox;
+
+import net.java.dev.typecast.ot.table.GlyphDescription;
+import net.java.dev.typecast.ot.table.GlyfDescript;
+import net.java.dev.typecast.ot.table.Charstring;
+import net.java.dev.typecast.ot.table.CharstringType2;
+
+import net.java.dev.typecast.t2.T2Interpreter;
+
+/**
+ * An individual glyph within a font.
+ * @version $Id: Glyph.java,v 1.3 2007-02-21 12:23:54 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>, Sven Gothel
+ */
+public class OTGlyph {
+
+ protected short _leftSideBearing;
+ protected int _advanceWidth;
+ private Point[] _points;
+ AABBox _bbox;
+
+ /**
+ * Construct a Glyph from a TrueType outline described by
+ * a GlyphDescription.
+ * @param cs The Charstring describing the glyph.
+ * @param lsb The Left Side Bearing.
+ * @param advance The advance width.
+ */
+ public OTGlyph(GlyphDescription gd, short lsb, int advance) {
+ _leftSideBearing = lsb;
+ _advanceWidth = advance;
+ describe(gd);
+ }
+
+ /**
+ * Construct a Glyph from a PostScript outline described by a Charstring.
+ * @param cs The Charstring describing the glyph.
+ * @param lsb The Left Side Bearing.
+ * @param advance The advance width.
+ */
+ public OTGlyph(Charstring cs, short lsb, int advance) {
+ _leftSideBearing = lsb;
+ _advanceWidth = advance;
+ if (cs instanceof CharstringType2) {
+ T2Interpreter t2i = new T2Interpreter();
+ _points = t2i.execute((CharstringType2) cs);
+ } else {
+ //throw unsupported charstring type
+ }
+ }
+
+ public AABBox getBBox() {
+ return _bbox;
+ }
+
+ public int getAdvanceWidth() {
+ return _advanceWidth;
+ }
+
+ public short getLeftSideBearing() {
+ return _leftSideBearing;
+ }
+
+ public Point getPoint(int i) {
+ return _points[i];
+ }
+
+ public int getPointCount() {
+ return _points.length;
+ }
+
+ /**
+ * Resets the glyph to the TrueType table settings
+ */
+ public void reset() {
+ }
+
+ /**
+ * @param factor a 16.16 fixed value
+ */
+ public void scale(int factor) {
+ for (int i = 0; i < _points.length; i++) {
+ //points[i].x = ( points[i].x * factor ) >> 6;
+ //points[i].y = ( points[i].y * factor ) >> 6;
+ _points[i].x = ((_points[i].x<<10) * factor) >> 26;
+ _points[i].y = ((_points[i].y<<10) * factor) >> 26;
+ }
+ _leftSideBearing = (short)(( _leftSideBearing * factor) >> 6);
+ _advanceWidth = (_advanceWidth * factor) >> 6;
+ }
+
+ /**
+ * Set the points of a glyph from the GlyphDescription
+ */
+ private void describe(GlyphDescription gd) {
+ int endPtIndex = 0;
+ _points = new Point[gd.getPointCount() /* + 2 */ ];
+ for (int i = 0; i < gd.getPointCount(); i++) {
+ boolean endPt = gd.getEndPtOfContours(endPtIndex) == i;
+ if (endPt) {
+ endPtIndex++;
+ }
+ _points[i] = new Point(
+ gd.getXCoordinate(i),
+ gd.getYCoordinate(i),
+ (gd.getFlags(i) & GlyfDescript.onCurve) != 0,
+ endPt);
+ }
+
+ // Append the origin and advanceWidth points (n & n+1)
+ // _points[gd.getPointCount()] = new Point(0, 0, true, true);
+ // _points[gd.getPointCount()+1] = new Point(_advanceWidth, 0, true, true);
+
+ _bbox = new AABBox(gd.getXMinimum(), gd.getYMinimum(), 0, gd.getXMaximum(), gd.getYMaximum(), 0);
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/Point.java b/turtle2d/src/net/java/dev/typecast/ot/Point.java
new file mode 100644
index 0000000..fae13b0
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/Point.java
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot;
+
+/**
+ * @version $Id: Point.java,v 1.1.1.1 2004-12-05 23:14:31 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class Point {
+
+ public int x = 0;
+ public int y = 0;
+ public boolean onCurve = true;
+ public boolean endOfContour = false;
+ public boolean touched = false;
+
+ public Point(int x, int y, boolean onCurve, boolean endOfContour) {
+ this.x = x;
+ this.y = y;
+ this.onCurve = onCurve;
+ this.endOfContour = endOfContour;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceData.java b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceData.java
new file mode 100644
index 0000000..a1c12ff
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceData.java
@@ -0,0 +1,45 @@
+/*
+ * $Id: ResourceData.java,v 1.1.1.1 2004-12-05 23:14:31 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceData.java,v 1.1.1.1 2004-12-05 23:14:31 davidsch Exp $
+ */
+public class ResourceData {
+
+ private byte[] data;
+
+ /** Creates new ResourceData */
+ public ResourceData(DataInput di) throws IOException {
+ int dataLen = di.readInt();
+ data = new byte[dataLen];
+ di.readFully(data);
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceFile.java b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceFile.java
new file mode 100644
index 0000000..e9499d9
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceFile.java
@@ -0,0 +1,77 @@
+/*
+ * $Id: ResourceFile.java,v 1.2 2007-01-29 04:01:53 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Mac resource loading test.
+ * TODO: incorporate this into the test suite.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceFile.java,v 1.2 2007-01-29 04:01:53 davidsch Exp $
+ */
+public class ResourceFile {
+
+ private ResourceHeader header;
+ private ResourceMap map;
+
+ /** Creates new Resource */
+ public ResourceFile(RandomAccessFile raf) throws IOException {
+
+ // Read header at the beginning of the file
+ raf.seek(0);
+ header = new ResourceHeader(raf);
+
+ // Seek to the map offset and read the map
+ raf.seek(header.getMapOffset());
+ map = new ResourceMap(raf);
+ }
+
+ public ResourceMap getResourceMap() {
+ return map;
+ }
+
+ public static void main(String[] args) {
+ try {
+ //RandomAccessFile raf = new RandomAccessFile("/Library/Fonts/GillSans.dfont", "r");
+
+ // Tests loading a font from a resource fork on Mac OS X
+ RandomAccessFile raf = new RandomAccessFile("/Library/Fonts/Georgia/..namedfork/rsrc", "r");
+ ResourceFile resource = new ResourceFile(raf);
+ for (int i = 0; i < resource.getResourceMap().getResourceTypeCount(); i++) {
+ System.out.println(resource.getResourceMap().getResourceType(i).getTypeAsString());
+ }
+
+ // Get the first 'sfnt' resource
+ ResourceType type = resource.getResourceMap().getResourceType("sfnt");
+ ResourceReference reference = type.getReference(0);
+
+ type = resource.getResourceMap().getResourceType("FOND");
+ for (int i = 0; i < type.getCount(); ++i) {
+ reference = type.getReference(i);
+ System.out.println(reference.getName());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceHeader.java b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceHeader.java
new file mode 100644
index 0000000..bdfe15a
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceHeader.java
@@ -0,0 +1,61 @@
+/*
+ * $Id: ResourceHeader.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceHeader.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ */
+public class ResourceHeader {
+
+ private int dataOffset;
+ private int mapOffset;
+ private int dataLen;
+ private int mapLen;
+
+ /** Creates new ResourceHeader */
+ public ResourceHeader(DataInput di) throws IOException {
+ dataOffset = di.readInt();
+ mapOffset = di.readInt();
+ dataLen = di.readInt();
+ mapLen = di.readInt();
+ }
+
+ public int getDataOffset() {
+ return dataOffset;
+ }
+
+ public int getMapOffset() {
+ return mapOffset;
+ }
+
+ public int getDataLength() {
+ return dataLen;
+ }
+
+ public int getMapLength() {
+ return mapLen;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceMap.java b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceMap.java
new file mode 100644
index 0000000..ee98fd8
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceMap.java
@@ -0,0 +1,83 @@
+/*
+ * $Id: ResourceMap.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceMap.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ */
+public class ResourceMap {
+
+ private byte[] headerCopy = new byte[16];
+ private int nextResourceMap;
+ private int fileReferenceNumber;
+ private int attributes;
+ private ResourceType[] types;
+
+ /** Creates new ResourceMap */
+ public ResourceMap(DataInput di) throws IOException {
+ di.readFully(headerCopy);
+ nextResourceMap = di.readInt();
+ fileReferenceNumber = di.readUnsignedShort();
+ attributes = di.readUnsignedShort();
+ int typeOffset = di.readUnsignedShort();
+ int nameOffset = di.readUnsignedShort();
+ int typeCount = di.readUnsignedShort() + 1;
+
+ // Read types
+ types = new ResourceType[typeCount];
+ for (int i = 0; i < typeCount; i++) {
+ types[i] = new ResourceType(di);
+ }
+
+ // Read the references
+ for (int i = 0; i < typeCount; i++) {
+ types[i].readRefs(di);
+ }
+
+ // Read the names
+ for (int i = 0; i < typeCount; i++) {
+ types[i].readNames(di);
+ }
+ }
+
+ public ResourceType getResourceType(String typeName) {
+ for (int i = 0; i < types.length; i++) {
+ String s = types[i].getTypeAsString();
+ if (types[i].getTypeAsString().equals(typeName)) {
+ return types[i];
+ }
+ }
+ return null;
+ }
+
+ public ResourceType getResourceType(int i) {
+ return types[i];
+ }
+
+ public int getResourceTypeCount() {
+ return types.length;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceReference.java b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceReference.java
new file mode 100644
index 0000000..f7f6e0f
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceReference.java
@@ -0,0 +1,81 @@
+/*
+ * $Id: ResourceReference.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceReference.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ */
+public class ResourceReference {
+
+ private int id;
+ private short nameOffset;
+ private short attributes;
+ private int dataOffset;
+ private int handle;
+ private String name;
+
+ /** Creates new ResourceReference */
+ protected ResourceReference(DataInput di) throws IOException {
+ id = di.readUnsignedShort();
+ nameOffset = di.readShort();
+ attributes = (short) di.readUnsignedByte();
+ dataOffset = (di.readUnsignedByte()<<16) | di.readUnsignedShort();
+ handle = di.readInt();
+ }
+
+ protected void readName(DataInput di) throws IOException {
+ if (nameOffset > -1) {
+ int len = di.readUnsignedByte();
+ byte[] buf = new byte[len];
+ di.readFully(buf);
+ name = new String(buf);
+ }
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public short getNameOffset() {
+ return nameOffset;
+ }
+
+ public short getAttributes() {
+ return attributes;
+ }
+
+ public int getDataOffset() {
+ return dataOffset;
+ }
+
+ public int getHandle() {
+ return handle;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceType.java b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceType.java
new file mode 100644
index 0000000..2c21e7a
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/mac/ResourceType.java
@@ -0,0 +1,82 @@
+/*
+ * $Id: ResourceType.java,v 1.1.1.1 2004-12-05 23:14:33 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceType.java,v 1.1.1.1 2004-12-05 23:14:33 davidsch Exp $
+ */
+public class ResourceType {
+
+ private int type;
+ private int count;
+ private int offset;
+ private ResourceReference[] references;
+
+ /** Creates new ResourceType */
+ protected ResourceType(DataInput di) throws IOException {
+ type = di.readInt();
+ count = di.readUnsignedShort() + 1;
+ offset = di.readUnsignedShort();
+ references = new ResourceReference[count];
+ }
+
+ protected void readRefs(DataInput di) throws IOException {
+ for (int i = 0; i < count; i++) {
+ references[i] = new ResourceReference(di);
+ }
+ }
+
+ protected void readNames(DataInput di) throws IOException {
+ for (int i = 0; i < count; i++) {
+ references[i].readName(di);
+ }
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public String getTypeAsString() {
+ return new StringBuffer()
+ .append((char)((type>>24)&0xff))
+ .append((char)((type>>16)&0xff))
+ .append((char)((type>>8)&0xff))
+ .append((char)((type)&0xff))
+ .toString();
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public ResourceReference getReference(int i) {
+ return references[i];
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/BaseTable.java b/turtle2d/src/net/java/dev/typecast/ot/table/BaseTable.java
new file mode 100644
index 0000000..f92de71
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/BaseTable.java
@@ -0,0 +1,435 @@
+/*
+ * $Id: BaseTable.java,v 1.3 2007-02-08 04:31:31 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Baseline Table
+ * @version $Id: BaseTable.java,v 1.3 2007-02-08 04:31:31 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class BaseTable implements Table {
+
+ private abstract class BaseCoord {
+
+ public abstract int getBaseCoordFormat();
+
+ public abstract short getCoordinate();
+ }
+
+ private class BaseCoordFormat1 extends BaseCoord {
+
+ private short _coordinate;
+
+ protected BaseCoordFormat1(DataInput di) throws IOException {
+ _coordinate = di.readShort();
+ }
+
+ public int getBaseCoordFormat() {
+ return 1;
+ }
+
+ public short getCoordinate() {
+ return _coordinate;
+ }
+
+ }
+
+ private class BaseCoordFormat2 extends BaseCoord {
+
+ private short _coordinate;
+ private int _referenceGlyph;
+ private int _baseCoordPoint;
+
+ protected BaseCoordFormat2(DataInput di) throws IOException {
+ _coordinate = di.readShort();
+ _referenceGlyph = di.readUnsignedShort();
+ _baseCoordPoint = di.readUnsignedShort();
+ }
+
+ public int getBaseCoordFormat() {
+ return 2;
+ }
+
+ public short getCoordinate() {
+ return _coordinate;
+ }
+
+ }
+
+ private class BaseCoordFormat3 extends BaseCoord {
+
+ private short _coordinate;
+ private int _deviceTableOffset;
+
+ protected BaseCoordFormat3(DataInput di) throws IOException {
+ _coordinate = di.readShort();
+ _deviceTableOffset = di.readUnsignedShort();
+ }
+
+ public int getBaseCoordFormat() {
+ return 2;
+ }
+
+ public short getCoordinate() {
+ return _coordinate;
+ }
+
+ }
+
+ private class FeatMinMaxRecord {
+
+ private int _tag;
+ private int _minCoordOffset;
+ private int _maxCoordOffset;
+
+ protected FeatMinMaxRecord(DataInput di) throws IOException {
+ _tag = di.readInt();
+ _minCoordOffset = di.readUnsignedShort();
+ _maxCoordOffset = di.readUnsignedShort();
+ }
+ }
+
+ private class MinMax {
+
+ private int _minCoordOffset;
+ private int _maxCoordOffset;
+ private int _featMinMaxCount;
+ private FeatMinMaxRecord[] _featMinMaxRecord;
+
+ protected MinMax(int minMaxOffset) throws IOException {
+ DataInput di = getDataInputForOffset(minMaxOffset);
+ _minCoordOffset = di.readUnsignedShort();
+ _maxCoordOffset = di.readUnsignedShort();
+ _featMinMaxCount = di.readUnsignedShort();
+ _featMinMaxRecord = new FeatMinMaxRecord[_featMinMaxCount];
+ for (int i = 0; i < _featMinMaxCount; ++i) {
+ _featMinMaxRecord[i] = new FeatMinMaxRecord(di);
+ }
+ }
+ }
+
+ private class BaseValues {
+
+ private int _defaultIndex;
+ private int _baseCoordCount;
+ private int[] _baseCoordOffset;
+ private BaseCoord[] _baseCoords;
+
+ protected BaseValues(int baseValuesOffset) throws IOException {
+ DataInput di = getDataInputForOffset(baseValuesOffset);
+ _defaultIndex = di.readUnsignedShort();
+ _baseCoordCount = di.readUnsignedShort();
+ _baseCoordOffset = new int[_baseCoordCount];
+ for (int i = 0; i < _baseCoordCount; ++i) {
+ _baseCoordOffset[i] = di.readUnsignedShort();
+ }
+ _baseCoords = new BaseCoord[_baseCoordCount];
+ for (int i = 0; i < _baseCoordCount; ++i) {
+ int format = di.readUnsignedShort();
+ switch (format) {
+ case 1:
+ _baseCoords[i] = new BaseCoordFormat1(di);
+ break;
+ case 2:
+ _baseCoords[i] = new BaseCoordFormat2(di);
+ break;
+ case 3:
+ _baseCoords[i] = new BaseCoordFormat3(di);
+ break;
+ }
+ }
+ }
+ }
+
+ private class BaseLangSysRecord {
+
+ private int _baseLangSysTag;
+ private int _minMaxOffset;
+
+ protected BaseLangSysRecord(DataInput di) throws IOException {
+ _baseLangSysTag = di.readInt();
+ _minMaxOffset = di.readUnsignedShort();
+ }
+
+ public int getBaseLangSysTag() {
+ return _baseLangSysTag;
+ }
+
+ public int getMinMaxOffset() {
+ return _minMaxOffset;
+ }
+ }
+
+ private class BaseScript {
+
+ private int _thisOffset;
+ private int _baseValuesOffset;
+ private int _defaultMinMaxOffset;
+ private int _baseLangSysCount;
+ private BaseLangSysRecord[] _baseLangSysRecord;
+ private BaseValues _baseValues;
+ private MinMax[] _minMax;
+
+ protected BaseScript(int baseScriptOffset) throws IOException {
+ _thisOffset = baseScriptOffset;
+ DataInput di = getDataInputForOffset(baseScriptOffset);
+ _baseValuesOffset = di.readUnsignedShort();
+ _defaultMinMaxOffset = di.readUnsignedShort();
+ _baseLangSysCount = di.readUnsignedShort();
+ _baseLangSysRecord = new BaseLangSysRecord[_baseLangSysCount];
+ for (int i = 0; i < _baseLangSysCount; ++i) {
+ _baseLangSysRecord[i] = new BaseLangSysRecord(di);
+ }
+ if (_baseValuesOffset > 0) {
+ _baseValues = new BaseValues(baseScriptOffset + _baseValuesOffset);
+ }
+ for (int i = 0; i < _baseLangSysCount; ++i) {
+ _minMax[i] = new MinMax(baseScriptOffset + _baseLangSysRecord[i].getMinMaxOffset());
+ }
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer()
+ .append("\nBaseScript BaseScriptT").append(Integer.toHexString(_thisOffset))
+ .append("\nBaseValuesT").append(Integer.toHexString(_thisOffset + _baseValuesOffset))
+ .append("\nMinMaxT").append(Integer.toHexString(_thisOffset + _defaultMinMaxOffset))
+ .append("\n").append(Integer.toHexString(_baseLangSysCount));
+// for (int i = 0; i < _baseLangSysCount; ++i) {
+// sb.append("\n ; BaseScriptRecord[").append(i);
+// sb.append("]\n'").append(tagAsString(_baseScriptRecord[i].getBaseScriptTag())).append("'");
+// sb.append("\nBaseScriptT").append(Integer.toHexString(_thisOffset + _baseScriptRecord[i].getBaseScriptOffset()));
+// }
+// for (int i = 0; i < _baseScriptCount; ++i) {
+// sb.append("\n").append(_baseScripts[i].toString());
+// }
+ if (_baseValues != null) {
+ sb.append("\n").append(_baseValues.toString());
+ }
+ return sb.toString();
+ }
+ }
+
+ private class BaseScriptRecord {
+
+ private int _baseScriptTag;
+ private int _baseScriptOffset;
+
+ protected BaseScriptRecord(DataInput di) throws IOException {
+ _baseScriptTag = di.readInt();
+ _baseScriptOffset = di.readUnsignedShort();
+ }
+
+ public int getBaseScriptTag() {
+ return _baseScriptTag;
+ }
+
+ public int getBaseScriptOffset() {
+ return _baseScriptOffset;
+ }
+ }
+
+ private class BaseScriptList {
+
+ private int _thisOffset;
+ private int _baseScriptCount;
+ private BaseScriptRecord[] _baseScriptRecord;
+ private BaseScript[] _baseScripts;
+
+ protected BaseScriptList(int baseScriptListOffset) throws IOException {
+ _thisOffset = baseScriptListOffset;
+ DataInput di = getDataInputForOffset(baseScriptListOffset);
+ _baseScriptCount = di.readUnsignedShort();
+ _baseScriptRecord = new BaseScriptRecord[_baseScriptCount];
+ for (int i = 0; i < _baseScriptCount; ++i) {
+ _baseScriptRecord[i] = new BaseScriptRecord(di);
+ }
+ _baseScripts = new BaseScript[_baseScriptCount];
+ for (int i = 0; i < _baseScriptCount; ++i) {
+ _baseScripts[i] = new BaseScript(
+ baseScriptListOffset + _baseScriptRecord[i].getBaseScriptOffset());
+ }
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer()
+ .append("\nBaseScriptList BaseScriptListT").append(Integer.toHexString(_thisOffset))
+ .append("\n").append(Integer.toHexString(_baseScriptCount));
+ for (int i = 0; i < _baseScriptCount; ++i) {
+ sb.append("\n ; BaseScriptRecord[").append(i);
+ sb.append("]\n'").append(tagAsString(_baseScriptRecord[i].getBaseScriptTag())).append("'");
+ sb.append("\nBaseScriptT").append(Integer.toHexString(_thisOffset + _baseScriptRecord[i].getBaseScriptOffset()));
+ }
+ for (int i = 0; i < _baseScriptCount; ++i) {
+ sb.append("\n").append(_baseScripts[i].toString());
+ }
+ return sb.toString();
+ }
+ }
+
+ private class BaseTagList {
+
+ private int _thisOffset;
+ private int _baseTagCount;
+ private int[] _baselineTag;
+
+ protected BaseTagList(int baseTagListOffset) throws IOException {
+ _thisOffset = baseTagListOffset;
+ DataInput di = getDataInputForOffset(baseTagListOffset);
+ _baseTagCount = di.readUnsignedShort();
+ _baselineTag = new int[_baseTagCount];
+ for (int i = 0; i < _baseTagCount; ++i) {
+ _baselineTag[i] = di.readInt();
+ }
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer()
+ .append("\nBaseTagList BaseTagListT").append(Integer.toHexString(_thisOffset))
+ .append("\n").append(Integer.toHexString(_baseTagCount));
+ for (int i = 0; i < _baseTagCount; ++i) {
+ sb.append("\n'").append(tagAsString(_baselineTag[i])).append("'");
+ }
+ return sb.toString();
+ }
+ }
+
+ private class Axis {
+
+ private int _thisOffset;
+ private int _baseTagListOffset;
+ private int _baseScriptListOffset;
+ private BaseTagList _baseTagList;
+ private BaseScriptList _baseScriptList;
+
+ protected Axis(int axisOffset) throws IOException {
+ _thisOffset = axisOffset;
+ DataInput di = getDataInputForOffset(axisOffset);
+ _baseTagListOffset = di.readUnsignedShort();
+ _baseScriptListOffset = di.readUnsignedShort();
+ if (_baseTagListOffset != 0) {
+ _baseTagList = new BaseTagList(axisOffset + _baseTagListOffset);
+ }
+ if (_baseScriptListOffset != 0) {
+ _baseScriptList = new BaseScriptList(
+ axisOffset + _baseScriptListOffset);
+ }
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("\nAxis AxisT").append(Integer.toHexString(_thisOffset))
+ .append("\nBaseTagListT").append(Integer.toHexString(_thisOffset + _baseTagListOffset))
+ .append("\nBaseScriptListT").append(Integer.toHexString(_thisOffset + _baseScriptListOffset))
+ .append("\n").append(_baseTagList)
+ .append("\n").append(_baseScriptList)
+ .toString();
+ }
+ }
+
+ private DirectoryEntry _de;
+ private int _version;
+ private int _horizAxisOffset;
+ private int _vertAxisOffset;
+ private Axis _horizAxis;
+ private Axis _vertAxis;
+ private byte[] _buf;
+
+ /** Creates a new instance of BaseTable */
+ protected BaseTable(DirectoryEntry de, DataInput di) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+
+ // Load entire table into a buffer, and create another input stream
+ _buf = new byte[de.getLength()];
+ di.readFully(_buf);
+ DataInput di2 = getDataInputForOffset(0);
+
+ _version = di2.readInt();
+ _horizAxisOffset = di2.readUnsignedShort();
+ _vertAxisOffset = di2.readUnsignedShort();
+ if (_horizAxisOffset != 0) {
+ _horizAxis = new Axis(_horizAxisOffset);
+ }
+ if (_vertAxisOffset != 0) {
+ _vertAxis = new Axis(_vertAxisOffset);
+ }
+
+ // Let go of the buffer
+ _buf = null;
+ }
+
+ private DataInput getDataInputForOffset(int offset) {
+ return new DataInputStream(new ByteArrayInputStream(
+ _buf, offset,
+ _de.getLength() - offset));
+ }
+
+// private String valueAsShortHex(int value) {
+// return String.format("%1$4x", value);
+// }
+//
+// private String valueAsLongHex(int value) {
+// return String.format("%1$8x", value);
+// }
+
+ static protected String tagAsString(int tag) {
+ char[] c = new char[4];
+ c[0] = (char)((tag >> 24) & 0xff);
+ c[1] = (char)((tag >> 16) & 0xff);
+ c[2] = (char)((tag >> 8) & 0xff);
+ c[3] = (char)(tag & 0xff);
+ return String.valueOf(c);
+ }
+
+ public int getType() {
+ return BASE;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer()
+ .append("; 'BASE' Table - Baseline\n;-------------------------------------\n\n")
+ .append("BASEHeader BASEHeaderT").append(Integer.toHexString(0))
+ .append("\n").append(Integer.toHexString(_version))
+ .append("\nAxisT").append(Integer.toHexString(_horizAxisOffset))
+ .append("\nAxisT").append(Integer.toHexString(_vertAxisOffset));
+ if (_horizAxis != null) {
+ sb.append("\n").append(_horizAxis.toString());
+ }
+ if (_vertAxis != null) {
+ sb.append("\n").append(_vertAxis.toString());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CffStandardStrings.java b/turtle2d/src/net/java/dev/typecast/ot/table/CffStandardStrings.java
new file mode 100644
index 0000000..987ea88
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CffStandardStrings.java
@@ -0,0 +1,424 @@
+/*
+ * $Id: CffStandardStrings.java,v 1.1 2007-02-05 12:41:52 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ * Compact Font Format Standard Strings. As per Appendix A of the Adobe
+ * CFF specification.
+ * @version $Id: CffStandardStrings.java,v 1.1 2007-02-05 12:41:52 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CffStandardStrings {
+
+ public static final String[] standardStrings = {
+ ".notdef",
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quoteright",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "quoteleft",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ "questiondown",
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ "AE",
+ "ordfeminine",
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ "ae",
+ "dotlessi",
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ "onesuperior",
+ "logicalnot",
+ "mu",
+ "trademark",
+ "Eth",
+ "onehalf",
+ "plusminus",
+ "Thorn",
+ "onequarter",
+ "divide",
+ "brokenbar",
+ "degree",
+ "thorn",
+ "threequarters",
+ "twosuperior",
+ "registered",
+ "minus",
+ "eth",
+ "multiply",
+ "threesuperior",
+ "copyright",
+ "Aacute",
+ "Acircumflex",
+ "Adieresis",
+ "Agrave",
+ "Aring",
+ "Atilde",
+ "Ccedilla",
+ "Eacute",
+ "Ecircumflex",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Ntilde",
+ "Oacute",
+ "Ocircumflex",
+ "Odieresis",
+ "Ograve",
+ "Otilde",
+ "Scaron",
+ "Uacute",
+ "Ucircumflex",
+ "Udieresis",
+ "Ugrave",
+ "Yacute",
+ "Ydieresis",
+ "Zcaron",
+ "aacute",
+ "acircumflex",
+ "adieresis",
+ "agrave",
+ "aring",
+ "atilde",
+ "ccedilla",
+ "eacute",
+ "ecircumflex",
+ "edieresis",
+ "egrave",
+ "iacute",
+ "icircumflex",
+ "idieresis",
+ "igrave",
+ "ntilde",
+ "oacute",
+ "ocircumflex",
+ "odieresis",
+ "ograve",
+ "otilde",
+ "scaron",
+ "uacute",
+ "ucircumflex",
+ "udieresis",
+ "ugrave",
+ "yacute",
+ "ydieresis",
+ "zcaron",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "commasuperior",
+ "threequartersemdash",
+ "periodsuperior",
+ "questionsmall",
+ "asuperior",
+ "bsuperior",
+ "centsuperior",
+ "dsuperior",
+ "esuperior",
+ "isuperior",
+ "lsuperior",
+ "msuperior",
+ "nsuperior",
+ "osuperior",
+ "rsuperior",
+ "ssuperior",
+ "tsuperior",
+ "ff",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hyphensuperior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ "exclamdownsmall",
+ "centoldstyle",
+ "Lslashsmall",
+ "Scaronsmall",
+ "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall",
+ "Caronsmall",
+ "Dotaccentsmall",
+ "Macronsmall",
+ "figuredash",
+ "hypheninferior",
+ "Ogoneksmall",
+ "Ringsmall",
+ "Cedillasmall",
+ "questiondownsmall",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ "zerosuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "eightsuperior",
+ "ninesuperior",
+ "zeroinferior",
+ "oneinferior",
+ "twoinferior",
+ "threeinferior",
+ "fourinferior",
+ "fiveinferior",
+ "sixinferior",
+ "seveninferior",
+ "eightinferior",
+ "nineinferior",
+ "centinferior",
+ "dollarinferior",
+ "periodinferior",
+ "commainferior",
+ "Agravesmall",
+ "Aacutesmall",
+ "Acircumflexsmall",
+ "Atildesmall",
+ "Adieresissmall",
+ "Aringsmall",
+ "AEsmall",
+ "Ccedillasmall",
+ "Egravesmall",
+ "Eacutesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Igravesmall",
+ "Iacutesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ethsmall",
+ "Ntildesmall",
+ "Ogravesmall",
+ "Oacutesmall",
+ "Ocircumflexsmall",
+ "Otildesmall",
+ "Odieresissmall",
+ "OEsmall",
+ "Oslashsmall",
+ "Ugravesmall",
+ "Uacutesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ "Yacutesmall",
+ "Thornsmall",
+ "Ydieresissmall",
+ "001.000",
+ "001.001",
+ "001.002",
+ "001.003",
+ "Black",
+ "Bold",
+ "Book",
+ "Light",
+ "Medium",
+ "Regular",
+ "Roman",
+ "Semibold"
+ };
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CffTable.java b/turtle2d/src/net/java/dev/typecast/ot/table/CffTable.java
new file mode 100644
index 0000000..2bd0cec
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CffTable.java
@@ -0,0 +1,620 @@
+/*
+ * $Id: CffTable.java,v 1.4 2007-07-26 11:15:06 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * Compact Font Format Table
+ * @version $Id: CffTable.java,v 1.4 2007-07-26 11:15:06 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CffTable implements Table {
+
+ public class Dict {
+
+ private Dictionary<Integer, Object> _entries = new Hashtable<Integer, Object>();
+ private int[] _data;
+ private int _index;
+
+ protected Dict(int[] data, int offset, int length) {
+ _data = data;
+ _index = offset;
+ while (_index < offset + length) {
+ addKeyAndValueEntry();
+ }
+ }
+
+ public Object getValue(int key) {
+ return _entries.get(key);
+ }
+
+ private boolean addKeyAndValueEntry() {
+ ArrayList<Object> operands = new ArrayList<Object>();
+ Object operand = null;
+ while (isOperandAtIndex()) {
+ operand = nextOperand();
+ operands.add(operand);
+ }
+ int operator = _data[_index++];
+ if (operator == 12) {
+ operator <<= 8;
+ operator |= _data[_index++];
+ }
+ if (operands.size() == 1) {
+ _entries.put(operator, operand);
+ } else {
+ _entries.put(operator, operands);
+ }
+ return true;
+ }
+
+ private boolean isOperandAtIndex() {
+ int b0 = _data[_index];
+ if ((32 <= b0 && b0 <= 254)
+ || b0 == 28
+ || b0 == 29
+ || b0 == 30) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isOperatorAtIndex() {
+ int b0 = _data[_index];
+ if (0 <= b0 && b0 <= 21) {
+ return true;
+ }
+ return false;
+ }
+
+ private Object nextOperand() {
+ int b0 = _data[_index];
+ if (32 <= b0 && b0 <= 246) {
+
+ // 1 byte integer
+ ++_index;
+ return new Integer(b0 - 139);
+ } else if (247 <= b0 && b0 <= 250) {
+
+ // 2 byte integer
+ int b1 = _data[_index + 1];
+ _index += 2;
+ return new Integer((b0 - 247) * 256 + b1 + 108);
+ } else if (251 <= b0 && b0 <= 254) {
+
+ // 2 byte integer
+ int b1 = _data[_index + 1];
+ _index += 2;
+ return new Integer(-(b0 - 251) * 256 - b1 - 108);
+ } else if (b0 == 28) {
+
+ // 3 byte integer
+ int b1 = _data[_index + 1];
+ int b2 = _data[_index + 2];
+ _index += 3;
+ return new Integer(b1 << 8 | b2);
+ } else if (b0 == 29) {
+
+ // 5 byte integer
+ int b1 = _data[_index + 1];
+ int b2 = _data[_index + 2];
+ int b3 = _data[_index + 3];
+ int b4 = _data[_index + 4];
+ _index += 5;
+ return new Integer(b1 << 24 | b2 << 16 | b3 << 8 | b4);
+ } else if (b0 == 30) {
+
+ // Real number
+ StringBuffer fString = new StringBuffer();
+ int nibble1 = 0;
+ int nibble2 = 0;
+ ++_index;
+ while ((nibble1 != 0xf) && (nibble2 != 0xf)) {
+ nibble1 = _data[_index] >> 4;
+ nibble2 = _data[_index] & 0xf;
+ ++_index;
+ fString.append(decodeRealNibble(nibble1));
+ fString.append(decodeRealNibble(nibble2));
+ }
+ return new Float(fString.toString());
+ } else {
+ return null;
+ }
+ }
+
+ private String decodeRealNibble(int nibble) {
+ if (nibble < 0xa) {
+ return Integer.toString(nibble);
+ } else if (nibble == 0xa) {
+ return ".";
+ } else if (nibble == 0xb) {
+ return "E";
+ } else if (nibble == 0xc) {
+ return "E-";
+ } else if (nibble == 0xe) {
+ return "-";
+ }
+ return "";
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ Enumeration<Integer> keys = _entries.keys();
+ while (keys.hasMoreElements()) {
+ Integer key = keys.nextElement();
+ if ((key.intValue() & 0xc00) == 0xc00) {
+ sb.append("12 ").append(key.intValue() & 0xff).append(": ");
+ } else {
+ sb.append(key.toString()).append(": ");
+ }
+ sb.append(_entries.get(key).toString()).append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ public class Index {
+
+ private int _count;
+ private int _offSize;
+ private int[] _offset;
+ private int[] _data;
+
+ protected Index(DataInput di) throws IOException {
+ _count = di.readUnsignedShort();
+ _offset = new int[_count + 1];
+ _offSize = di.readUnsignedByte();
+ for (int i = 0; i < _count + 1; ++i) {
+ int thisOffset = 0;
+ for (int j = 0; j < _offSize; ++j) {
+ thisOffset |= di.readUnsignedByte() << ((_offSize - j - 1) * 8);
+ }
+ _offset[i] = thisOffset;
+ }
+ _data = new int[getDataLength()];
+ for (int i = 0; i < getDataLength(); ++i) {
+ _data[i] = di.readUnsignedByte();
+ }
+ }
+
+ public int getCount() {
+ return _count;
+ }
+
+ public int getOffset(int index) {
+ return _offset[index];
+ }
+
+ public int getDataLength() {
+ return _offset[_offset.length - 1] - 1;
+ }
+
+ public int[] getData() {
+ return _data;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("DICT\n");
+ sb.append("count: ").append(_count).append("\n");
+ sb.append("offSize: ").append(_offSize).append("\n");
+ for (int i = 0; i < _count + 1; ++i) {
+ sb.append("offset[").append(i).append("]: ").append(_offset[i]).append("\n");
+ }
+ sb.append("data:");
+ for (int i = 0; i < _data.length; ++i) {
+ if (i % 8 == 0) {
+ sb.append("\n");
+ } else {
+ sb.append(" ");
+ }
+ sb.append(_data[i]);
+ }
+ sb.append("\n");
+ return sb.toString();
+ }
+ }
+
+ public class TopDictIndex extends Index {
+
+ protected TopDictIndex(DataInput di) throws IOException {
+ super(di);
+ }
+
+ public Dict getTopDict(int index) {
+ int offset = getOffset(index) - 1;
+ int len = getOffset(index + 1) - offset - 1;
+ return new Dict(getData(), offset, len);
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < getCount(); ++i) {
+ sb.append(getTopDict(i).toString()).append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ public class NameIndex extends Index {
+
+ protected NameIndex(DataInput di) throws IOException {
+ super(di);
+ }
+
+ public String getName(int index) {
+ String name = null;
+ int offset = getOffset(index) - 1;
+ int len = getOffset(index + 1) - offset - 1;
+
+ // Ensure the name hasn't been deleted
+ if (getData()[offset] != 0) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = offset; i < offset + len; ++i) {
+ sb.append((char) getData()[i]);
+ }
+ name = sb.toString();
+ } else {
+ name = "DELETED NAME";
+ }
+ return name;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < getCount(); ++i) {
+ sb.append(getName(i)).append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ public class StringIndex extends Index {
+
+ protected StringIndex(DataInput di) throws IOException {
+ super(di);
+ }
+
+ public String getString(int index) {
+ if (index < CffStandardStrings.standardStrings.length) {
+ return CffStandardStrings.standardStrings[index];
+ } else {
+ index -= CffStandardStrings.standardStrings.length;
+ if (index >= getCount()) {
+ return null;
+ }
+ int offset = getOffset(index) - 1;
+ int len = getOffset(index + 1) - offset - 1;
+
+ StringBuffer sb = new StringBuffer();
+ for (int i = offset; i < offset + len; ++i) {
+ sb.append((char) getData()[i]);
+ }
+ return sb.toString();
+ }
+ }
+
+ public String toString() {
+ int nonStandardBase = CffStandardStrings.standardStrings.length;
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < getCount(); ++i) {
+ sb.append(nonStandardBase + i).append(": ");
+ sb.append(getString(nonStandardBase + i)).append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ private class CharsetRange {
+
+ private int _first;
+ private int _left;
+
+ public int getFirst() {
+ return _first;
+ }
+
+ protected void setFirst(int first) {
+ _first = first;
+ }
+
+ public int getLeft() {
+ return _left;
+ }
+
+ protected void setLeft(int left) {
+ _left = left;
+ }
+ }
+
+ private class CharsetRange1 extends CharsetRange {
+
+ protected CharsetRange1(DataInput di) throws IOException {
+ setFirst(di.readUnsignedShort());
+ setLeft(di.readUnsignedByte());
+ }
+ }
+
+ private class CharsetRange2 extends CharsetRange {
+
+ protected CharsetRange2(DataInput di) throws IOException {
+ setFirst(di.readUnsignedShort());
+ setLeft(di.readUnsignedShort());
+ }
+ }
+
+ private abstract class Charset {
+
+ public abstract int getFormat();
+
+ public abstract int getSID(int gid);
+ }
+
+ private class CharsetFormat0 extends Charset {
+
+ private int[] _glyph;
+
+ protected CharsetFormat0(DataInput di, int glyphCount) throws IOException {
+ _glyph = new int[glyphCount - 1]; // minus 1 because .notdef is omitted
+ for (int i = 0; i < glyphCount - 1; ++i) {
+ _glyph[i] = di.readUnsignedShort();
+ }
+ }
+
+ public int getFormat() {
+ return 0;
+ }
+
+ public int getSID(int gid) {
+ if (gid == 0) {
+ return 0;
+ }
+ return _glyph[gid - 1];
+ }
+ }
+
+ private class CharsetFormat1 extends Charset {
+
+ private ArrayList<CharsetRange> _charsetRanges = new ArrayList<CharsetRange>();
+
+ protected CharsetFormat1(DataInput di, int glyphCount) throws IOException {
+ int glyphsCovered = glyphCount - 1; // minus 1 because .notdef is omitted
+ while (glyphsCovered > 0) {
+ CharsetRange range = new CharsetRange1(di);
+ _charsetRanges.add(range);
+ glyphsCovered -= range.getLeft() + 1;
+ }
+ }
+
+ public int getFormat() {
+ return 1;
+ }
+
+ public int getSID(int gid) {
+ if (gid == 0) {
+ return 0;
+ }
+
+ // Count through the ranges to find the one of interest
+ int count = 0;
+ for (CharsetRange range : _charsetRanges) {
+ count += range.getLeft();
+ if (gid < count) {
+ int sid = gid - count + range.getFirst();
+ return sid;
+ }
+ }
+ return 0;
+ }
+ }
+
+ private class CharsetFormat2 extends Charset {
+
+ private ArrayList<CharsetRange> _charsetRanges = new ArrayList<CharsetRange>();
+
+ protected CharsetFormat2(DataInput di, int glyphCount) throws IOException {
+ int glyphsCovered = glyphCount - 1; // minus 1 because .notdef is omitted
+ while (glyphsCovered > 0) {
+ CharsetRange range = new CharsetRange2(di);
+ _charsetRanges.add(range);
+ glyphsCovered -= range.getLeft() + 1;
+ }
+ }
+
+ public int getFormat() {
+ return 2;
+ }
+
+ public int getSID(int gid) {
+ if (gid == 0) {
+ return 0;
+ }
+
+ // Count through the ranges to find the one of interest
+ int count = 0;
+ for (CharsetRange range : _charsetRanges) {
+ if (gid < range.getLeft() + count) {
+ int sid = gid - count + range.getFirst() - 1;
+ return sid;
+ }
+ count += range.getLeft();
+ }
+ return 0;
+ }
+ }
+
+ private DirectoryEntry _de;
+ private int _major;
+ private int _minor;
+ private int _hdrSize;
+ private int _offSize;
+ private NameIndex _nameIndex;
+ private TopDictIndex _topDictIndex;
+ private StringIndex _stringIndex;
+ private Index _globalSubrIndex;
+ private Index _charStringsIndexArray[];
+ private Charset[] _charsets;
+ private Charstring[][] _charstringsArray;
+
+ private byte[] _buf;
+
+ /** Creates a new instance of CffTable */
+ protected CffTable(DirectoryEntry de, DataInput di) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+
+ // Load entire table into a buffer, and create another input stream
+ _buf = new byte[de.getLength()];
+ di.readFully(_buf);
+ DataInput di2 = getDataInputForOffset(0);
+
+ // Header
+ _major = di2.readUnsignedByte();
+ _minor = di2.readUnsignedByte();
+ _hdrSize = di2.readUnsignedByte();
+ _offSize = di2.readUnsignedByte();
+
+ // Name INDEX
+ di2 = getDataInputForOffset(_hdrSize);
+ _nameIndex = new NameIndex(di2);
+
+ // Top DICT INDEX
+ _topDictIndex = new TopDictIndex(di2);
+
+ // String INDEX
+ _stringIndex = new StringIndex(di2);
+
+ // Global Subr INDEX
+ _globalSubrIndex = new Index(di2);
+
+ // Encodings go here -- but since this is an OpenType font will this
+ // not always be a CIDFont? In which case there are no encodings
+ // within the CFF data.
+
+ // Load each of the fonts
+ _charStringsIndexArray = new Index[_topDictIndex.getCount()];
+ _charsets = new Charset[_topDictIndex.getCount()];
+ _charstringsArray = new Charstring[_topDictIndex.getCount()][];
+ for (int i = 0; i < _topDictIndex.getCount(); ++i) {
+
+ // Charstrings INDEX
+ // We load this before Charsets because we may need to know the number
+ // of glyphs
+ Integer charStringsOffset = (Integer) _topDictIndex.getTopDict(i).getValue(17);
+ di2 = getDataInputForOffset(charStringsOffset);
+ _charStringsIndexArray[i] = new Index(di2);
+ int glyphCount = _charStringsIndexArray[i].getCount();
+
+ // Charsets
+ Integer charsetOffset = (Integer) _topDictIndex.getTopDict(i).getValue(15);
+ di2 = getDataInputForOffset(charsetOffset);
+ int format = di2.readUnsignedByte();
+ switch (format) {
+ case 0:
+ _charsets[i] = new CharsetFormat0(di2, glyphCount);
+ break;
+ case 1:
+ _charsets[i] = new CharsetFormat1(di2, glyphCount);
+ break;
+ case 2:
+ _charsets[i] = new CharsetFormat2(di2, glyphCount);
+ break;
+ }
+
+ // Create the charstrings
+ _charstringsArray[i] = new Charstring[glyphCount];
+ for (int j = 0; j < glyphCount; ++j) {
+ int offset = _charStringsIndexArray[i].getOffset(j) - 1;
+ int len = _charStringsIndexArray[i].getOffset(j + 1) - offset - 1;
+ _charstringsArray[i][j] = new CharstringType2(
+ i,
+ _stringIndex.getString(_charsets[i].getSID(j)),
+ _charStringsIndexArray[i].getData(),
+ offset,
+ len,
+ null,
+ null);
+ }
+ }
+ }
+
+ private DataInput getDataInputForOffset(int offset) {
+ return new DataInputStream(new ByteArrayInputStream(
+ _buf, offset,
+ _de.getLength() - offset));
+ }
+
+ public NameIndex getNameIndex() {
+ return _nameIndex;
+ }
+
+ public Charset getCharset(int fontIndex) {
+ return _charsets[fontIndex];
+ }
+
+ public Charstring getCharstring(int fontIndex, int gid) {
+ return _charstringsArray[fontIndex][gid];
+ }
+
+ public int getCharstringCount(int fontIndex) {
+ return _charstringsArray[fontIndex].length;
+ }
+
+ public int getType() {
+ return CFF;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'CFF' Table - Compact Font Format\n---------------------------------\n");
+ sb.append("\nName INDEX\n");
+ sb.append(_nameIndex.toString());
+ sb.append("\nTop DICT INDEX\n");
+ sb.append(_topDictIndex.toString());
+ sb.append("\nString INDEX\n");
+ sb.append(_stringIndex.toString());
+ sb.append("\nGlobal Subr INDEX\n");
+ sb.append(_globalSubrIndex.toString());
+ for (int i = 0; i < _charStringsIndexArray.length; ++i) {
+ sb.append("\nCharStrings INDEX ").append(i).append("\n");
+ sb.append(_charStringsIndexArray[i].toString());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/Charstring.java b/turtle2d/src/net/java/dev/typecast/ot/table/Charstring.java
new file mode 100644
index 0000000..2439d6b
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/Charstring.java
@@ -0,0 +1,33 @@
+/*
+ * $Id: Charstring.java,v 1.2 2007-02-21 12:25:19 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ * CFF Charstring
+ * @version $Id: Charstring.java,v 1.2 2007-02-21 12:25:19 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public abstract class Charstring {
+
+ public abstract int getIndex();
+
+ public abstract String getName();
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CharstringType2.java b/turtle2d/src/net/java/dev/typecast/ot/table/CharstringType2.java
new file mode 100644
index 0000000..e47825c
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CharstringType2.java
@@ -0,0 +1,235 @@
+/*
+ * $Id: CharstringType2.java,v 1.4 2007-07-26 11:13:44 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import net.java.dev.typecast.ot.table.CffTable;
+
+/**
+ * CFF Type 2 Charstring
+ * @version $Id: CharstringType2.java,v 1.4 2007-07-26 11:13:44 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CharstringType2 extends Charstring {
+
+ private static final String[] _oneByteOperators = {
+ "-Reserved-",
+ "hstem",
+ "-Reserved-",
+ "vstem",
+ "vmoveto",
+ "rlineto",
+ "hlineto",
+ "vlineto",
+ "rrcurveto",
+ "-Reserved-",
+ "callsubr",
+ "return",
+ "escape",
+ "-Reserved-",
+ "endchar",
+ "-Reserved-",
+ "-Reserved-",
+ "-Reserved-",
+ "hstemhm",
+ "hintmask",
+ "cntrmask",
+ "rmoveto",
+ "hmoveto",
+ "vstemhm",
+ "rcurveline",
+ "rlinecurve",
+ "vvcurveto",
+ "hhcurveto",
+ "shortint",
+ "callgsubr",
+ "vhcurveto",
+ "hvcurveto"
+ };
+
+ private static final String[] _twoByteOperators = {
+ "-Reserved- (dotsection)",
+ "-Reserved-",
+ "-Reserved-",
+ "and",
+ "or",
+ "not",
+ "-Reserved-",
+ "-Reserved-",
+ "-Reserved-",
+ "abs",
+ "add",
+ "sub",
+ "div",
+ "-Reserved-",
+ "neg",
+ "eq",
+ "-Reserved-",
+ "-Reserved-",
+ "drop",
+ "-Reserved-",
+ "put",
+ "get",
+ "ifelse",
+ "random",
+ "mul",
+ "-Reserved-",
+ "sqrt",
+ "dup",
+ "exch",
+ "index",
+ "roll",
+ "-Reserved-",
+ "-Reserved-",
+ "-Reserved-",
+ "hflex",
+ "flex",
+ "hflex1",
+ "flex1",
+ "-Reserved-"
+ };
+
+ private int _index;
+ private String _name;
+ private int[] _data;
+ private int _offset;
+ private int _length;
+ private CffTable.Index _localSubrIndex;
+ private CffTable.Index _globalSubrIndex;
+ private int _ip;
+
+ /** Creates a new instance of CharstringType2 */
+ protected CharstringType2(
+ int index,
+ String name,
+ int[] data,
+ int offset,
+ int length,
+ CffTable.Index localSubrIndex,
+ CffTable.Index globalSubrIndex) {
+ _index = index;
+ _name = name;
+ _data = data;
+ _offset = offset;
+ _length = length;
+ _localSubrIndex = localSubrIndex;
+ _globalSubrIndex = globalSubrIndex;
+ }
+
+ public int getIndex() {
+ return _index;
+ }
+
+ public String getName() {
+ return _name;
+ }
+
+ private void disassemble(StringBuffer sb) {
+ Number operand = null;
+ while (isOperandAtIndex()) {
+ operand = nextOperand();
+ sb.append(operand).append(" ");
+ }
+ int operator = nextByte();
+ String mnemonic;
+ if (operator == 12) {
+ operator = nextByte();
+
+ // Check we're not exceeding the upper limit of our mnemonics
+ if (operator > 38) {
+ operator = 38;
+ }
+ mnemonic = _twoByteOperators[operator];
+ } else {
+ mnemonic = _oneByteOperators[operator];
+ }
+ sb.append(mnemonic);
+ }
+
+ public void resetIP() {
+ _ip = _offset;
+ }
+
+ public boolean isOperandAtIndex() {
+ int b0 = _data[_ip];
+ if ((32 <= b0 && b0 <= 255) || b0 == 28) {
+ return true;
+ }
+ return false;
+ }
+
+ public Number nextOperand() {
+ int b0 = _data[_ip];
+ if (32 <= b0 && b0 <= 246) {
+
+ // 1 byte integer
+ ++_ip;
+ return new Integer(b0 - 139);
+ } else if (247 <= b0 && b0 <= 250) {
+
+ // 2 byte integer
+ int b1 = _data[_ip + 1];
+ _ip += 2;
+ return new Integer((b0 - 247) * 256 + b1 + 108);
+ } else if (251 <= b0 && b0 <= 254) {
+
+ // 2 byte integer
+ int b1 = _data[_ip + 1];
+ _ip += 2;
+ return new Integer(-(b0 - 251) * 256 - b1 - 108);
+ } else if (b0 == 28) {
+
+ // 3 byte integer
+ int b1 = _data[_ip + 1];
+ int b2 = _data[_ip + 2];
+ _ip += 3;
+ return new Integer(b1 << 8 | b2);
+ } else if (b0 == 255) {
+
+ // 16-bit signed integer with 16 bits of fraction
+ int b1 = (byte) _data[_ip + 1];
+ int b2 = _data[_ip + 2];
+ int b3 = _data[_ip + 3];
+ int b4 = _data[_ip + 4];
+ _ip += 5;
+ return new Float((b1 << 8 | b2) + ((b3 << 8 | b4) / 65536.0));
+ } else {
+ return null;
+ }
+ }
+
+ public int nextByte() {
+ return _data[_ip++];
+ }
+
+ public boolean moreBytes() {
+ return _ip < _offset + _length;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ resetIP();
+ while (moreBytes()) {
+ disassemble(sb);
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/ClassDef.java b/turtle2d/src/net/java/dev/typecast/ot/table/ClassDef.java
new file mode 100644
index 0000000..9fa45c3
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/ClassDef.java
@@ -0,0 +1,33 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ClassDef.java,v 1.1.1.1 2004-12-05 23:14:33 davidsch Exp $
+ */
+public abstract class ClassDef {
+
+ public abstract int getFormat();
+
+ protected static ClassDef read(RandomAccessFile raf) throws IOException {
+ ClassDef c = null;
+ int format = raf.readUnsignedShort();
+ if (format == 1) {
+ c = new ClassDefFormat1(raf);
+ } else if (format == 2) {
+ c = new ClassDefFormat2(raf);
+ }
+ return c;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/ClassDefFormat1.java b/turtle2d/src/net/java/dev/typecast/ot/table/ClassDefFormat1.java
new file mode 100644
index 0000000..07b85dd
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/ClassDefFormat1.java
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ClassDefFormat1.java,v 1.1.1.1 2004-12-05 23:14:33 davidsch Exp $
+ */
+public class ClassDefFormat1 extends ClassDef {
+
+ private int startGlyph;
+ private int glyphCount;
+ private int[] classValues;
+
+ /** Creates new ClassDefFormat1 */
+ public ClassDefFormat1(RandomAccessFile raf) throws IOException {
+ startGlyph = raf.readUnsignedShort();
+ glyphCount = raf.readUnsignedShort();
+ classValues = new int[glyphCount];
+ for (int i = 0; i < glyphCount; i++) {
+ classValues[i] = raf.readUnsignedShort();
+ }
+ }
+
+ public int getFormat() {
+ return 1;
+ }
+
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/ClassDefFormat2.java b/turtle2d/src/net/java/dev/typecast/ot/table/ClassDefFormat2.java
new file mode 100644
index 0000000..f8b883c
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/ClassDefFormat2.java
@@ -0,0 +1,37 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ClassDefFormat2.java,v 1.1.1.1 2004-12-05 23:14:33 davidsch Exp $
+ */
+public class ClassDefFormat2 extends ClassDef {
+
+ private int classRangeCount;
+ private RangeRecord[] classRangeRecords;
+
+ /** Creates new ClassDefFormat2 */
+ public ClassDefFormat2(RandomAccessFile raf) throws IOException {
+ classRangeCount = raf.readUnsignedShort();
+ classRangeRecords = new RangeRecord[classRangeCount];
+ for (int i = 0; i < classRangeCount; i++) {
+ classRangeRecords[i] = new RangeRecord(raf);
+ }
+ }
+
+ public int getFormat() {
+ return 2;
+ }
+
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat.java b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat.java
new file mode 100644
index 0000000..be88af1
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat.java
@@ -0,0 +1,134 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: CmapFormat.java,v 1.3 2004-12-21 16:56:35 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public abstract class CmapFormat {
+
+ public class Range {
+
+ private int _startCode;
+ private int _endCode;
+
+ protected Range(int startCode, int endCode) {
+ _startCode = startCode;
+ _endCode = endCode;
+ }
+
+ public int getStartCode() {
+ return _startCode;
+ }
+
+ public int getEndCode() {
+ return _endCode;
+ }
+ }
+
+ protected int _format;
+ protected int _length;
+ protected int _language;
+
+ protected CmapFormat(DataInput di) throws IOException {
+ _length = di.readUnsignedShort();
+ _language = di.readUnsignedShort();
+ }
+
+ protected static CmapFormat create(int format, DataInput di)
+ throws IOException {
+ switch(format) {
+ case 0:
+ return new CmapFormat0(di);
+ case 2:
+ return new CmapFormat2(di);
+ case 4:
+ return new CmapFormat4(di);
+ case 6:
+ return new CmapFormat6(di);
+ default:
+ return new CmapFormatUnknown(format, di);
+ }
+ }
+
+ public int getFormat() {
+ return _format;
+ }
+
+ public int getLength() {
+ return _length;
+ }
+
+ public int getLanguage() {
+ return _language;
+ }
+
+ public abstract int getRangeCount();
+
+ public abstract Range getRange(int index)
+ throws ArrayIndexOutOfBoundsException;
+
+ public abstract int mapCharCode(int charCode);
+
+ public String toString() {
+ return new StringBuffer()
+ .append("format: ")
+ .append(_format)
+ .append(", length: ")
+ .append(_length)
+ .append(", language: ")
+ .append(_language).toString();
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat0.java b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat0.java
new file mode 100644
index 0000000..80f42b2
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat0.java
@@ -0,0 +1,92 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * Simple Macintosh cmap table, mapping only the ASCII character set to glyphs.
+ *
+ * @version $Id: CmapFormat0.java,v 1.2 2004-12-21 10:22:55 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapFormat0 extends CmapFormat {
+
+ private int[] _glyphIdArray = new int[256];
+
+ protected CmapFormat0(DataInput di) throws IOException {
+ super(di);
+ _format = 0;
+ for (int i = 0; i < 256; i++) {
+ _glyphIdArray[i] = di.readUnsignedByte();
+ }
+ }
+
+ public int getRangeCount() {
+ return 1;
+ }
+
+ public Range getRange(int index) throws ArrayIndexOutOfBoundsException {
+ if (index != 0) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return new Range(0, 255);
+ }
+
+ public int mapCharCode(int charCode) {
+ if (0 <= charCode && charCode < 256) {
+ return _glyphIdArray[charCode];
+ } else {
+ return 0;
+ }
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat2.java b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat2.java
new file mode 100644
index 0000000..4eeaf42
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat2.java
@@ -0,0 +1,173 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * High-byte mapping through table cmap format.
+ * @version $Id: CmapFormat2.java,v 1.3 2004-12-21 16:56:54 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapFormat2 extends CmapFormat {
+
+ private class SubHeader {
+ int _firstCode;
+ int _entryCount;
+ short _idDelta;
+ int _idRangeOffset;
+ int _arrayIndex;
+ }
+
+ private int[] _subHeaderKeys = new int[256];
+ private SubHeader[] _subHeaders;
+ private int[] _glyphIndexArray;
+
+ protected CmapFormat2(DataInput di) throws IOException {
+ super(di);
+ _format = 2;
+
+ int pos = 6;
+
+ // Read the subheader keys, noting the highest value, as this will
+ // determine the number of subheaders to read.
+ int highest = 0;
+ for (int i = 0; i < 256; ++i) {
+ _subHeaderKeys[i] = di.readUnsignedShort();
+ highest = Math.max(highest, _subHeaderKeys[i]);
+ pos += 2;
+ }
+ int subHeaderCount = highest / 8 + 1;
+ _subHeaders = new SubHeader[subHeaderCount];
+
+ // Read the subheaders, once again noting the highest glyphIndexArray
+ // index range.
+ int indexArrayOffset = 8 * subHeaderCount + 518;
+ highest = 0;
+ for (int i = 0; i < _subHeaders.length; ++i) {
+ SubHeader sh = new SubHeader();
+ sh._firstCode = di.readUnsignedShort();
+ sh._entryCount = di.readUnsignedShort();
+ sh._idDelta = di.readShort();
+ sh._idRangeOffset = di.readUnsignedShort();
+
+ // Calculate the offset into the _glyphIndexArray
+ pos += 8;
+ sh._arrayIndex =
+ (pos - 2 + sh._idRangeOffset - indexArrayOffset) / 2;
+
+ // What is the highest range within the glyphIndexArray?
+ highest = Math.max(highest, sh._arrayIndex + sh._entryCount);
+
+ _subHeaders[i] = sh;
+ }
+
+ // Read the glyphIndexArray
+ _glyphIndexArray = new int[highest];
+ for (int i = 0; i < _glyphIndexArray.length; ++i) {
+ _glyphIndexArray[i] = di.readUnsignedShort();
+ }
+ }
+
+ public int getRangeCount() {
+ return _subHeaders.length;
+ }
+
+ public Range getRange(int index) throws ArrayIndexOutOfBoundsException {
+ if (index < 0 || index >= _subHeaders.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ // Find the high-byte (if any)
+ int highByte = 0;
+ if (index != 0) {
+ for (int i = 0; i < 256; ++i) {
+ if (_subHeaderKeys[i] / 8 == index) {
+ highByte = i << 8;
+ break;
+ }
+ }
+ }
+
+ return new Range(
+ highByte | _subHeaders[index]._firstCode,
+ highByte | (_subHeaders[index]._firstCode +
+ _subHeaders[index]._entryCount - 1));
+ }
+
+ public int mapCharCode(int charCode) {
+
+ // Get the appropriate subheader
+ int index = 0;
+ int highByte = charCode >> 8;
+ if (highByte != 0) {
+ index = _subHeaderKeys[highByte] / 8;
+ }
+ SubHeader sh = _subHeaders[index];
+
+ // Is the charCode out-of-range?
+ int lowByte = charCode & 0xff;
+ if (lowByte < sh._firstCode ||
+ lowByte >= (sh._firstCode + sh._entryCount)) {
+ return 0;
+ }
+
+ // Now calculate the glyph index
+ int glyphIndex =
+ _glyphIndexArray[sh._arrayIndex + (lowByte - sh._firstCode)];
+ if (glyphIndex != 0) {
+ glyphIndex += sh._idDelta;
+ glyphIndex %= 65536;
+ }
+ return glyphIndex;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat4.java b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat4.java
new file mode 100644
index 0000000..3748a8f
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat4.java
@@ -0,0 +1,165 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: CmapFormat4.java,v 1.3 2004-12-21 16:57:23 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapFormat4 extends CmapFormat {
+
+ private int _segCountX2;
+ private int _searchRange;
+ private int _entrySelector;
+ private int _rangeShift;
+ private int[] _endCode;
+ private int[] _startCode;
+ private int[] _idDelta;
+ private int[] _idRangeOffset;
+ private int[] _glyphIdArray;
+ private int _segCount;
+
+ protected CmapFormat4(DataInput di) throws IOException {
+ super(di); // 6
+ _format = 4;
+ _segCountX2 = di.readUnsignedShort(); // +2 (8)
+ _segCount = _segCountX2 / 2;
+ _endCode = new int[_segCount];
+ _startCode = new int[_segCount];
+ _idDelta = new int[_segCount];
+ _idRangeOffset = new int[_segCount];
+ _searchRange = di.readUnsignedShort(); // +2 (10)
+ _entrySelector = di.readUnsignedShort(); // +2 (12)
+ _rangeShift = di.readUnsignedShort(); // +2 (14)
+ for (int i = 0; i < _segCount; i++) {
+ _endCode[i] = di.readUnsignedShort();
+ } // + 2*segCount (2*segCount + 14)
+ di.readUnsignedShort(); // reservePad +2 (2*segCount + 16)
+ for (int i = 0; i < _segCount; i++) {
+ _startCode[i] = di.readUnsignedShort();
+ } // + 2*segCount (4*segCount + 16)
+ for (int i = 0; i < _segCount; i++) {
+ _idDelta[i] = di.readUnsignedShort();
+ } // + 2*segCount (6*segCount + 16)
+ for (int i = 0; i < _segCount; i++) {
+ _idRangeOffset[i] = di.readUnsignedShort();
+ } // + 2*segCount (8*segCount + 16)
+
+ // Whatever remains of this header belongs in glyphIdArray
+ int count = (_length - (8*_segCount + 16)) / 2;
+ _glyphIdArray = new int[count];
+ for (int i = 0; i < count; i++) {
+ _glyphIdArray[i] = di.readUnsignedShort();
+ } // + 2*count (8*segCount + 2*count + 18)
+
+ // Are there any padding bytes we need to consume?
+// int leftover = length - (8*segCount + 2*count + 18);
+// if (leftover > 0) {
+// di.skipBytes(leftover);
+// }
+ }
+
+ public int getRangeCount() {
+ return _segCount;
+ }
+
+ public Range getRange(int index) throws ArrayIndexOutOfBoundsException {
+ if (index < 0 || index >= _segCount) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return new Range(_startCode[index], _endCode[index]);
+ }
+
+ public int mapCharCode(int charCode) {
+ try {
+ for (int i = 0; i < _segCount; i++) {
+ if (_endCode[i] >= charCode) {
+ if (_startCode[i] <= charCode) {
+ if (_idRangeOffset[i] > 0) {
+ return _glyphIdArray[_idRangeOffset[i]/2 + (charCode - _startCode[i]) - (_segCount - i)];
+ } else {
+ return (_idDelta[i] + charCode) % 65536;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ System.err.println("error: Array out of bounds - " + e.getMessage());
+ }
+ return 0;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append(super.toString())
+ .append(", segCountX2: ")
+ .append(_segCountX2)
+ .append(", searchRange: ")
+ .append(_searchRange)
+ .append(", entrySelector: ")
+ .append(_entrySelector)
+ .append(", rangeShift: ")
+ .append(_rangeShift)
+ .append(", endCode: ")
+ .append(_endCode)
+ .append(", startCode: ")
+ .append(_endCode)
+ .append(", idDelta: ")
+ .append(_idDelta)
+ .append(", idRangeOffset: ")
+ .append(_idRangeOffset).toString();
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat6.java b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat6.java
new file mode 100644
index 0000000..f9b398a
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormat6.java
@@ -0,0 +1,87 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * TODO: To be implemented
+ * @version $Id: CmapFormat6.java,v 1.2 2004-12-21 10:22:56 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapFormat6 extends CmapFormat {
+
+ private short _firstCode;
+ private short _entryCount;
+ private short[] _glyphIdArray;
+
+ protected CmapFormat6(DataInput di) throws IOException {
+ super(di);
+ _format = 6;
+
+ // HACK: As this is not yet implemented, we need to skip over the bytes
+ // we should be consuming
+ //di.skipBytes(_length - 4);
+ }
+
+ public int getRangeCount() {
+ return 0;
+ }
+
+ public Range getRange(int index) throws ArrayIndexOutOfBoundsException {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ public int mapCharCode(int charCode) {
+ return 0;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormatUnknown.java b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormatUnknown.java
new file mode 100644
index 0000000..01ca600
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CmapFormatUnknown.java
@@ -0,0 +1,54 @@
+/*
+ * $Id: CmapFormatUnknown.java,v 1.1 2004-12-21 10:21:23 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * When we encounter a cmap format we don't understand, we can use this class
+ * to hold the bare minimum information about it.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: CmapFormatUnknown.java,v 1.1 2004-12-21 10:21:23 davidsch Exp $
+ */
+public class CmapFormatUnknown extends CmapFormat {
+
+ /** Creates a new instance of CmapFormatUnknown */
+ protected CmapFormatUnknown(int format, DataInput di) throws IOException {
+ super(di);
+ _format = format;
+
+ // We don't know how to handle this data, so we'll just skip over it
+ di.skipBytes(_length - 4);
+ }
+
+ public int getRangeCount() {
+ return 0;
+ }
+
+ public Range getRange(int index) throws ArrayIndexOutOfBoundsException {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ public int mapCharCode(int charCode) {
+ return 0;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CmapIndexEntry.java b/turtle2d/src/net/java/dev/typecast/ot/table/CmapIndexEntry.java
new file mode 100644
index 0000000..c82e270
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CmapIndexEntry.java
@@ -0,0 +1,117 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: CmapIndexEntry.java,v 1.2 2004-12-21 10:22:56 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapIndexEntry implements Comparable {
+
+ private int _platformId;
+ private int _encodingId;
+ private int _offset;
+ private CmapFormat _format;
+
+ protected CmapIndexEntry(DataInput di) throws IOException {
+ _platformId = di.readUnsignedShort();
+ _encodingId = di.readUnsignedShort();
+ _offset = di.readInt();
+ }
+
+ public int getPlatformId() {
+ return _platformId;
+ }
+
+ public int getEncodingId() {
+ return _encodingId;
+ }
+
+ public int getOffset() {
+ return _offset;
+ }
+
+ public CmapFormat getFormat() {
+ return _format;
+ }
+
+ public void setFormat(CmapFormat format) {
+ _format = format;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("platform id: ")
+ .append(_platformId)
+ .append(" (")
+ .append(ID.getPlatformName((short) _platformId))
+ .append("), encoding id: ")
+ .append(_encodingId)
+ .append(" (")
+ .append(ID.getEncodingName((short) _platformId, (short) _encodingId))
+ .append("), offset: ")
+ .append(_offset).toString();
+ }
+
+ public int compareTo(java.lang.Object obj) {
+ CmapIndexEntry entry = (CmapIndexEntry) obj;
+ if (getOffset() < entry.getOffset()) {
+ return -1;
+ } else if (getOffset() > entry.getOffset()) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CmapTable.java b/turtle2d/src/net/java/dev/typecast/ot/table/CmapTable.java
new file mode 100644
index 0000000..de69cc1
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CmapTable.java
@@ -0,0 +1,161 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import java.util.Arrays;
+
+/**
+ * @version $Id: CmapTable.java,v 1.3 2004-12-21 10:22:56 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapTable implements Table {
+
+ private DirectoryEntry _de;
+ private int _version;
+ private int _numTables;
+ private CmapIndexEntry[] _entries;
+
+ protected CmapTable(DirectoryEntry de, DataInput di) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+ _version = di.readUnsignedShort();
+ _numTables = di.readUnsignedShort();
+ long bytesRead = 4;
+ _entries = new CmapIndexEntry[_numTables];
+
+ // Get each of the index entries
+ for (int i = 0; i < _numTables; i++) {
+ _entries[i] = new CmapIndexEntry(di);
+ bytesRead += 8;
+ }
+
+ // Sort into their order of offset
+ Arrays.sort(_entries);
+
+ // Get each of the tables
+ int lastOffset = 0;
+ CmapFormat lastFormat = null;
+ for (int i = 0; i < _numTables; i++) {
+ if (_entries[i].getOffset() == lastOffset) {
+
+ // This is a multiple entry
+ _entries[i].setFormat(lastFormat);
+ continue;
+ } else if (_entries[i].getOffset() > bytesRead) {
+ di.skipBytes(_entries[i].getOffset() - (int) bytesRead);
+ } else if (_entries[i].getOffset() != bytesRead) {
+
+ // Something is amiss
+ throw new IOException();
+ }
+ int formatType = di.readUnsignedShort();
+ lastFormat = CmapFormat.create(formatType, di);
+ lastOffset = _entries[i].getOffset();
+ _entries[i].setFormat(lastFormat);
+ bytesRead += lastFormat.getLength();
+ }
+ }
+
+ public int getVersion() {
+ return _version;
+ }
+
+ public int getNumTables() {
+ return _numTables;
+ }
+
+ public CmapIndexEntry getCmapIndexEntry(int i) {
+ return _entries[i];
+ }
+
+ public CmapFormat getCmapFormat(short platformId, short encodingId) {
+
+ // Find the requested format
+ for (int i = 0; i < _numTables; i++) {
+ if (_entries[i].getPlatformId() == platformId
+ && _entries[i].getEncodingId() == encodingId) {
+ return _entries[i].getFormat();
+ }
+ }
+ return null;
+ }
+
+ public int getType() {
+ return cmap;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer().append("cmap\n");
+
+ // Get each of the index entries
+ for (int i = 0; i < _numTables; i++) {
+ sb.append("\t").append(_entries[i].toString()).append("\n");
+ }
+
+ // Get each of the tables
+// for (int i = 0; i < numTables; i++) {
+// sb.append("\t").append(formats[i].toString()).append("\n");
+// }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/Coverage.java b/turtle2d/src/net/java/dev/typecast/ot/table/Coverage.java
new file mode 100644
index 0000000..3c6cf04
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/Coverage.java
@@ -0,0 +1,83 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Coverage.java,v 1.3 2007-01-24 09:43:30 davidsch Exp $
+ */
+public abstract class Coverage {
+
+ public abstract int getFormat();
+
+ /**
+ * @param glyphId The ID of the glyph to find.
+ * @return The index of the glyph within the coverage, or -1 if the glyph
+ * can't be found.
+ */
+ public abstract int findGlyph(int glyphId);
+
+ protected static Coverage read(DataInput di) throws IOException {
+ Coverage c = null;
+ int format = di.readUnsignedShort();
+ if (format == 1) {
+ c = new CoverageFormat1(di);
+ } else if (format == 2) {
+ c = new CoverageFormat2(di);
+ }
+ return c;
+ }
+
+}
diff --git a/turtle2d/src/net/java/dev/typecast/ot/table/CoverageFormat1.java b/turtle2d/src/net/java/dev/typecast/ot/table/CoverageFormat1.java
new file mode 100644
index 0000000..a81eb0f
--- /dev/null
+++ b/turtle2d/src/net/java/dev/typecast/ot/table/CoverageFormat1.java
@@ -0,0 +1,88 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DAT