From 2ce80c3f677edefc5e5b2cfe7fa24d5a876a0495 Mon Sep 17 00:00:00 2001 From: Amnon Owed Date: Fri, 26 Jul 2013 12:57:14 +0200 Subject: [PATCH 001/556] Adding set(boolean) methods + fix w in set(int) method --- core/src/processing/opengl/PShader.java | 36 ++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShader.java index 03eca7517..e7655a5c5 100644 --- a/core/src/processing/opengl/PShader.java +++ b/core/src/processing/opengl/PShader.java @@ -264,7 +264,7 @@ public class PShader { * @param w fourth component of the variable to modify. The variable has to be declared with an array/vector type in the shader (i.e.: int[4], vec4) */ public void set(String name, int x, int y, int z, int w) { - setUniformImpl(name, UniformValue.INT4, new int[] { x, y, z }); + setUniformImpl(name, UniformValue.INT4, new int[] { x, y, z, w }); } @@ -296,6 +296,26 @@ public class PShader { } + public void set(String name, boolean x) { + setUniformImpl(name, UniformValue.INT1, new int[] { (x)?1:0 }); + } + + + public void set(String name, boolean x, boolean y) { + setUniformImpl(name, UniformValue.INT2, new int[] { (x)?1:0, (y)?1:0 }); + } + + + public void set(String name, boolean x, boolean y, boolean z) { + setUniformImpl(name, UniformValue.INT3, new int[] { (x)?1:0, (y)?1:0, (z)?1:0 }); + } + + + public void set(String name, boolean x, boolean y, boolean z, boolean w) { + setUniformImpl(name, UniformValue.INT4, new int[] { (x)?1:0, (y)?1:0, (z)?1:0, (w)?1:0 }); + } + + public void set(String name, int[] vec) { set(name, vec, 1); } @@ -343,6 +363,20 @@ public class PShader { } } + public void set(String name, boolean[] vec) { + set(name, vec, 1); + } + + + public void set(String name, boolean[] boolvec, int ncoords) { + int[] vec = new int[boolvec.length]; + for (int i=0; i Date: Fri, 26 Jul 2013 20:25:41 +0200 Subject: [PATCH 002/556] Fix for issue processing/processing#1994 --- core/src/processing/opengl/PShader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShader.java index e7655a5c5..7443ec811 100644 --- a/core/src/processing/opengl/PShader.java +++ b/core/src/processing/opengl/PShader.java @@ -597,7 +597,7 @@ public class PShader { pgl.uniform3i(loc, v[0], v[1], v[2]); } else if (val.type == UniformValue.INT4) { int[] v = ((int[])val.value); - pgl.uniform4i(loc, v[0], v[1], v[2], v[4]); + pgl.uniform4i(loc, v[0], v[1], v[2], v[3]); } else if (val.type == UniformValue.FLOAT1) { float[] v = ((float[])val.value); pgl.uniform1f(loc, v[0]); From fb898b752739c40eabb342acf08f908b17da008a Mon Sep 17 00:00:00 2001 From: AmnonOwed Date: Fri, 23 Aug 2013 17:53:22 +0200 Subject: [PATCH 003/556] Open new PDE maximized when current PDE is maximized --- app/src/processing/app/EditorState.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/processing/app/EditorState.java b/app/src/processing/app/EditorState.java index a55491af1..ffd43584f 100644 --- a/app/src/processing/app/EditorState.java +++ b/app/src/processing/app/EditorState.java @@ -53,6 +53,7 @@ public class EditorState { // int displayW, displayH; // String deviceName; // not really useful b/c it's more about bounds anyway Rectangle deviceBounds; + boolean isMaximized; /** @@ -173,6 +174,7 @@ public class EditorState { synchronized (editors) { final int OVER = 50; Editor lastOpened = editors.get(editors.size() - 1); + isMaximized = (lastOpened.getExtendedState() == Editor.MAXIMIZED_BOTH); editorBounds = lastOpened.getBounds(); editorBounds.x += OVER; editorBounds.y += OVER; @@ -183,6 +185,10 @@ public class EditorState { editorBounds.x = deviceBounds.x + (int) (Math.random() * (deviceBounds.width - defaultWidth)); editorBounds.y = deviceBounds.y + (int) (Math.random() * (deviceBounds.height - defaultHeight)); } + if (isMaximized) { + editorBounds.width = defaultWidth; + editorBounds.height = defaultHeight; + } } } } @@ -204,6 +210,9 @@ public class EditorState { if (dividerLocation != 0) { editor.setDividerLocation(dividerLocation); } + if (isMaximized) { + editor.setExtendedState(Editor.MAXIMIZED_BOTH); + } } From 50e3631fa907337476d377af88ac7515550cc737 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sun, 1 Sep 2013 20:01:42 -0400 Subject: [PATCH 004/556] made the description of loadTexture() more accurate --- core/src/processing/opengl/PGraphicsOpenGL.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index a0db323c3..56e8cb26a 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -5344,8 +5344,8 @@ public class PGraphicsOpenGL extends PGraphics { // LOAD/UPDATE TEXTURE - // Copies the contents of the color buffer into the pixels - // array, and then the pixels array into the screen texture. + // Loads the current contents of the renderer's drawing surface into the + // its texture. public void loadTexture() { boolean needEndDraw = false; if (!drawing) { @@ -5382,12 +5382,10 @@ public class PGraphicsOpenGL extends PGraphics { texture.setNative(nativePixelBuffer, 0, 0, width, height); } - } else { - // We need to copy the contents of the multisampled buffer to the - // color buffer, so the later is up-to-date with the last drawing. - if (offscreenMultisample) { - multisampleFramebuffer.copy(offscreenFramebuffer, currentFramebuffer); - } + } else if (offscreenMultisample) { + // We need to copy the contents of the multisampled buffer to the color + // buffer, so the later is up-to-date with the last drawing. + multisampleFramebuffer.copy(offscreenFramebuffer, currentFramebuffer); } if (needEndDraw) { From 4eb844598ee80618a9b4d92733dbf53d7a361ae9 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Mon, 2 Sep 2013 18:10:59 -0400 Subject: [PATCH 005/556] added missing TEXTURE_WRAP_R constant to PGL --- core/src/processing/opengl/PGL.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index 942ad20f0..3a9d255e6 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -2919,6 +2919,7 @@ public class PGL { public static final int TEXTURE_MAG_FILTER = GL.GL_TEXTURE_MAG_FILTER; public static final int TEXTURE_WRAP_S = GL.GL_TEXTURE_WRAP_S; public static final int TEXTURE_WRAP_T = GL.GL_TEXTURE_WRAP_T; + public static final int TEXTURE_WRAP_R = GL2.GL_TEXTURE_WRAP_R; public static final int TEXTURE_CUBE_MAP = GL.GL_TEXTURE_CUBE_MAP; public static final int TEXTURE_CUBE_MAP_POSITIVE_X = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X; From 39d2287f12d762d42e51c52287eb7b5b74ef5706 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 3 Sep 2013 10:32:18 -0400 Subject: [PATCH 006/556] removed some commented out code --- .../processing/opengl/PGraphicsOpenGL.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 56e8cb26a..b3f6e2d28 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -5416,26 +5416,6 @@ public class PGraphicsOpenGL extends PGraphics { } - /* - public void drawTexture(int target, int id, int width, int height, - int X0, int Y0, int X1, int Y1) { - beginPGL(); - pgl.drawTexture(target, id, width, height, X0, Y0, X1, Y1); - endPGL(); - } - - - public void drawTexture(int target, int id, int texW, int texH, - int texX0, int texY0, int texX1, int texY1, - int scrX0, int scrY0, int scrX1, int scrY1) { - beginPGL(); - pgl.drawTexture(target, id, texW, texH, width, height, - texX0, texY0, texX1, texY1, - scrX0, scrY0, scrX1, scrY1); - endPGL(); - } -*/ - protected void loadTextureImpl(int sampling, boolean mipmap) { if (width == 0 || height == 0) return; if (texture == null || texture.contextIsOutdated()) { From bb518933b09bfcddc59375d78bc484ab9c4e6980 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 3 Sep 2013 11:51:04 -0400 Subject: [PATCH 007/556] PShapeOpenGL uses close field from parent PShape, this takes care of #2035 --- core/src/processing/opengl/PGraphics2D.java | 29 ------------------ core/src/processing/opengl/PGraphics3D.java | 32 -------------------- core/src/processing/opengl/PShapeOpenGL.java | 19 +++++------- 3 files changed, 8 insertions(+), 72 deletions(-) diff --git a/core/src/processing/opengl/PGraphics2D.java b/core/src/processing/opengl/PGraphics2D.java index dd4089dca..f1149ab65 100644 --- a/core/src/processing/opengl/PGraphics2D.java +++ b/core/src/processing/opengl/PGraphics2D.java @@ -307,35 +307,6 @@ public class PGraphics2D extends PGraphicsOpenGL { } else if (type == PShape.GEOMETRY) { shape = new PShapeOpenGL(parent, PShape.GEOMETRY); } - - /* - if (type == POINTS) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(POINTS); - } else if (type == LINES) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(LINES); - } else if (type == TRIANGLE || type == TRIANGLES) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(TRIANGLES); - } else if (type == TRIANGLE_FAN) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(TRIANGLE_FAN); - } else if (type == TRIANGLE_STRIP) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(TRIANGLE_STRIP); - } else if (type == QUAD || type == QUADS) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(QUADS); - } else if (type == QUAD_STRIP) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(QUAD_STRIP); - } else if (type == POLYGON) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(POLYGON); - } - */ - shape.is3D(false); return shape; } diff --git a/core/src/processing/opengl/PGraphics3D.java b/core/src/processing/opengl/PGraphics3D.java index a60641dac..c2d78474a 100644 --- a/core/src/processing/opengl/PGraphics3D.java +++ b/core/src/processing/opengl/PGraphics3D.java @@ -178,38 +178,6 @@ public class PGraphics3D extends PGraphicsOpenGL { } else if (type == PShape.GEOMETRY) { shape = new PShapeOpenGL(parent, PShape.GEOMETRY); } - - /* - (type == POINTS) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - - shape.setKind(POINTS); - } else if (type == LINES) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - - shape.setKind(LINES); - } else if (type == TRIANGLE || type == TRIANGLES) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - - shape.setKind(TRIANGLES); - } else if (type == TRIANGLE_FAN) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(TRIANGLE_FAN); - } else if (type == TRIANGLE_STRIP) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(TRIANGLE_STRIP); - } else if (type == QUAD || type == QUADS) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(QUADS); - } else if (type == QUAD_STRIP) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(QUAD_STRIP); - } else if (type == POLYGON) { - shape = new PShapeOpenGL(parent, PShape.GEOMETRY); - shape.setKind(POLYGON); - } - */ - shape.is3D(true); return shape; } diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index e0fde4a2c..3d666cf28 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -162,12 +162,9 @@ public class PShapeOpenGL extends PShape { protected boolean tessellated; protected boolean needBufferInit = false; -// protected boolean polyBuffersCreated = false; -// protected boolean lineBuffersCreated = false; -// protected boolean pointBuffersCreated = false; - protected boolean isSolid; - protected boolean isClosed; + // Flag to indicate if the shape can have holes or not. + protected boolean solid; protected boolean breakShape = false; protected boolean shapeCreated = false; @@ -951,7 +948,7 @@ public class PShapeOpenGL extends PShape { child.solid(solid); } } else { - isSolid = solid; + this.solid = solid; } } @@ -1090,7 +1087,7 @@ public class PShapeOpenGL extends PShape { // size, which might lead to arrays larger than the vertex counts. inGeo.trim(); - isClosed = mode == CLOSE; + close = mode == CLOSE; markForTessellation(); shapeCreated = true; } @@ -2531,8 +2528,8 @@ public class PShapeOpenGL extends PShape { if (normalMode == NORMAL_MODE_AUTO) inGeo.calcQuadStripNormals(); tessellator.tessellateQuadStrip(); } else if (kind == POLYGON) { - if (stroke) inGeo.addPolygonEdges(isClosed); - tessellator.tessellatePolygon(isSolid, isClosed, + if (stroke) inGeo.addPolygonEdges(close); + tessellator.tessellatePolygon(solid, close, normalMode == NORMAL_MODE_AUTO); } } else if (family == PRIMITIVE) { @@ -2924,8 +2921,8 @@ public class PShapeOpenGL extends PShape { } } - if (stroke) inGeo.addPolygonEdges(isClosed); - tessellator.tessellatePolygon(false, isClosed, true); + if (stroke) inGeo.addPolygonEdges(close); + tessellator.tessellatePolygon(false, close, true); } From 8d2b69b0c5b6f0996f33e37ed8aa433e9de525e1 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 3 Sep 2013 12:07:54 -0400 Subject: [PATCH 008/556] fix #2061 --- core/src/processing/opengl/PShapeOpenGL.java | 77 ++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index 3d666cf28..d1dd3fe72 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -258,6 +258,30 @@ public class PShapeOpenGL extends PShape { protected int firstModifiedPointAttribute; protected int lastModifiedPointAttribute; + // ........................................................ + + // Saved style variables to style can be re-enabled after disableStyle, + // although it won't work if properties are defined on a per-vertex basis. + + protected boolean savedStroke; + protected int savedStrokeColor; + protected float savedStrokeWeight; + protected int savedStrokeCap; + protected int savedStrokeJoin; + + protected boolean savedFill; + protected int savedFillColor; + + protected boolean savedTint; + protected int savedTintColor; + + protected int savedAmbientColor; + protected int savedSpecularColor; + protected int savedEmissiveColor; + protected float savedShininess; + + protected int savedTextureMode; + PShapeOpenGL() { } @@ -4052,10 +4076,63 @@ public class PShapeOpenGL extends PShape { return; } + // Saving the current values to use if the style is re-enabled later + savedStroke = stroke; + savedStrokeColor = strokeColor; + savedStrokeWeight = strokeWeight; + savedStrokeCap = strokeCap; + savedStrokeJoin = strokeJoin; + savedFill = fill; + savedFillColor = fillColor; + savedTint = tint; + savedTintColor = tintColor; + savedAmbientColor = ambientColor; + savedSpecularColor = specularColor; + savedEmissiveColor = emissiveColor; + savedShininess = shininess; + savedTextureMode = textureMode; + super.disableStyle(); } + @Override + public void enableStyle() { + if (savedStroke) { + setStroke(true); + setStroke(savedStrokeColor); + setStrokeWeight(savedStrokeWeight); + setStrokeCap(savedStrokeCap); + setStrokeJoin(savedStrokeJoin); + } else { + setStroke(false); + } + + if (savedFill) { + setFill(true); + setFill(savedFillColor); + } else { + setFill(false); + } + + if (savedTint) { + setTint(true); + setTint(savedTintColor); + } + + setAmbient(savedAmbientColor); + setSpecular(savedSpecularColor); + setEmissive(savedEmissiveColor); + setShininess(savedShininess); + + if (image != null) { + setTextureMode(savedTextureMode); + } + + super.enableStyle(); + } + + // Applies the styles of g. @Override protected void styles(PGraphics g) { From 7fd145506194e266baa23b619bffb005b7bde285 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 3 Sep 2013 14:40:34 -0400 Subject: [PATCH 009/556] fix #1990 --- core/src/processing/core/PShape.java | 2 + core/src/processing/opengl/PGraphics2D.java | 2 +- core/src/processing/opengl/PGraphics3D.java | 2 +- .../processing/opengl/PGraphicsOpenGL.java | 44 ++------ core/src/processing/opengl/PShapeOpenGL.java | 102 +++++++++++++++--- 5 files changed, 98 insertions(+), 54 deletions(-) diff --git a/core/src/processing/core/PShape.java b/core/src/processing/core/PShape.java index 40ec381f5..8420f72f6 100644 --- a/core/src/processing/core/PShape.java +++ b/core/src/processing/core/PShape.java @@ -167,6 +167,8 @@ public class PShape implements PConstants { protected float shininess; protected int sphereDetailU, sphereDetailV; + protected int rectMode; + protected int ellipseMode; /** Temporary toggle for whether styles should be honored. */ protected boolean style = true; diff --git a/core/src/processing/opengl/PGraphics2D.java b/core/src/processing/opengl/PGraphics2D.java index f1149ab65..d8adced31 100644 --- a/core/src/processing/opengl/PGraphics2D.java +++ b/core/src/processing/opengl/PGraphics2D.java @@ -353,7 +353,7 @@ public class PGraphics2D extends PGraphicsOpenGL { shape = new PShapeOpenGL(parent, PShape.PRIMITIVE); shape.setKind(RECT); } else if (kind == ELLIPSE) { - if (len != 4) { + if (len != 4 && len != 5) { showWarning("Wrong number of parameters"); return null; } diff --git a/core/src/processing/opengl/PGraphics3D.java b/core/src/processing/opengl/PGraphics3D.java index c2d78474a..318b32df2 100644 --- a/core/src/processing/opengl/PGraphics3D.java +++ b/core/src/processing/opengl/PGraphics3D.java @@ -224,7 +224,7 @@ public class PGraphics3D extends PGraphicsOpenGL { shape = new PShapeOpenGL(parent, PShape.PRIMITIVE); shape.setKind(RECT); } else if (kind == ELLIPSE) { - if (len != 4) { + if (len != 4 && len != 5) { showWarning("Wrong number of parameters"); return null; } diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index b3f6e2d28..318d33556 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -2922,8 +2922,7 @@ public class PGraphicsOpenGL extends PGraphics { inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); - inGeo.addRect(a, b, c, d, - fill, stroke, rectMode); + inGeo.addRect(a, b, c, d, fill, stroke, rectMode); endShape(); } @@ -2937,8 +2936,7 @@ public class PGraphicsOpenGL extends PGraphics { inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); - inGeo.addRect(a, b, c, d, - tl, tr, br, bl, + inGeo.addRect(a, b, c, d, tl, tr, br, bl, fill, stroke, bezierDetail, rectMode); endShape(CLOSE); } @@ -2953,14 +2951,14 @@ public class PGraphicsOpenGL extends PGraphics { @Override - public void ellipse(float a, float b, float c, float d) { + public void ellipseImpl(float a, float b, float c, float d) { beginShape(TRIANGLE_FAN); defaultEdges = false; normalMode = NORMAL_MODE_SHAPE; inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); - inGeo.addEllipse(a, b, c, d, fill, stroke, ellipseMode); + inGeo.addEllipse(a, b, c, d, fill, stroke); endShape(); } @@ -8749,38 +8747,8 @@ public class PGraphicsOpenGL extends PGraphics { if (stroke) addPolygonEdges(true); } - void addEllipse(float a, float b, float c, float d, - boolean fill, boolean stroke, int ellipseMode) { - float x = a; - float y = b; - float w = c; - float h = d; - - if (ellipseMode == CORNERS) { - w = c - a; - h = d - b; - - } else if (ellipseMode == RADIUS) { - x = a - c; - y = b - d; - w = c * 2; - h = d * 2; - - } else if (ellipseMode == DIAMETER) { - x = a - c/2f; - y = b - d/2f; - } - - if (w < 0) { // undo negative width - x += w; - w = -w; - } - - if (h < 0) { // undo negative height - y += h; - h = -h; - } - + void addEllipse(float x, float y, float w, float h, + boolean fill, boolean stroke) { float radiusH = w / 2; float radiusV = h / 2; diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index d1dd3fe72..c218f4b3a 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -354,6 +354,9 @@ public class PShapeOpenGL extends PShape { sphereDetailU = pg.sphereDetailU; sphereDetailV = pg.sphereDetailV; + rectMode = pg.rectMode; + ellipseMode = pg.ellipseMode; + normalX = normalY = 0; normalZ = 1; @@ -2711,11 +2714,11 @@ public class PShapeOpenGL extends PShape { float tl = 0, tr = 0, br = 0, bl = 0; boolean rounded = false; if (params.length == 4) { - rounded = false; a = params[0]; b = params[1]; c = params[2]; d = params[3]; + rounded = false; } else if (params.length == 5) { a = params[0]; b = params[1]; @@ -2753,17 +2756,52 @@ public class PShapeOpenGL extends PShape { protected void tessellateEllipse() { float a = 0, b = 0, c = 0, d = 0; - if (params.length == 4) { + int mode = ellipseMode; + + if (4 <= params.length) { a = params[0]; b = params[1]; c = params[2]; d = params[3]; + if (params.length == 5) { + mode = (int)(params[4]); + } + } + + float x = a; + float y = b; + float w = c; + float h = d; + + if (mode == CORNERS) { + w = c - a; + h = d - b; + + } else if (mode == RADIUS) { + x = a - c; + y = b - d; + w = c * 2; + h = d * 2; + + } else if (mode == DIAMETER) { + x = a - c/2f; + y = b - d/2f; + } + + if (w < 0) { // undo negative width + x += w; + w = -w; + } + + if (h < 0) { // undo negative height + y += h; + h = -h; } inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); - inGeo.addEllipse(a, b, c, d, fill, stroke, CORNER); + inGeo.addEllipse(x, y, w, h, fill, stroke); tessellator.tessellateTriangleFan(); } @@ -2771,25 +2809,61 @@ public class PShapeOpenGL extends PShape { protected void tessellateArc() { float a = 0, b = 0, c = 0, d = 0; float start = 0, stop = 0; -// int mode = 0; - if (params.length == 6 || params.length == 7) { + int mode = ellipseMode; + + if (6 <= params.length) { a = params[0]; b = params[1]; c = params[2]; d = params[3]; start = params[4]; stop = params[5]; - // Not using arc mode since PShape only uses CORNER -// if (params.length == 7) { -// mode = (int)(params[6]); -// } + if (params.length == 7) { + mode = (int)(params[6]); + } } - inGeo.setMaterial(fillColor, strokeColor, strokeWeight, - ambientColor, specularColor, emissiveColor, shininess); - inGeo.setNormal(normalX, normalY, normalZ); - inGeo.addArc(a, b, c, d, start, stop, fill, stroke, CORNER); - tessellator.tessellateTriangleFan(); + float x = a; + float y = b; + float w = c; + float h = d; + + if (mode == CORNERS) { + w = c - a; + h = d - b; + + } else if (mode == RADIUS) { + x = a - c; + y = b - d; + w = c * 2; + h = d * 2; + + } else if (mode == CENTER) { + x = a - c/2f; + y = b - d/2f; + } + + // make sure the loop will exit before starting while + if (!Float.isInfinite(start) && !Float.isInfinite(stop)) { + // ignore equal and degenerate cases + if (stop > start) { + // make sure that we're starting at a useful point + while (start < 0) { + start += TWO_PI; + stop += TWO_PI; + } + + if (stop - start > TWO_PI) { + start = 0; + stop = TWO_PI; + } + inGeo.setMaterial(fillColor, strokeColor, strokeWeight, + ambientColor, specularColor, emissiveColor, shininess); + inGeo.setNormal(normalX, normalY, normalZ); + inGeo.addArc(x, y, w, h, start, stop, fill, stroke, mode); + tessellator.tessellateTriangleFan(); + } + } } From 2b2789641b03b98564a7f7e905448dc522fe1af9 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 3 Sep 2013 14:40:57 -0400 Subject: [PATCH 010/556] updated PrimitiveShape example --- .../Topics/Create Shapes/PrimitivePShape/PrimitivePShape.pde | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/java/examples/Topics/Create Shapes/PrimitivePShape/PrimitivePShape.pde b/java/examples/Topics/Create Shapes/PrimitivePShape/PrimitivePShape.pde index 9ae00c12a..6e24680ec 100644 --- a/java/examples/Topics/Create Shapes/PrimitivePShape/PrimitivePShape.pde +++ b/java/examples/Topics/Create Shapes/PrimitivePShape/PrimitivePShape.pde @@ -12,8 +12,7 @@ void setup() { size(640, 360, P2D); smooth(); // Creating the PShape as an ellipse - // The corner is -50,-50 so that the center is at 0,0 - circle = createShape(ELLIPSE, -50, -25, 100, 50); + circle = createShape(ELLIPSE, 0, 0, 100, 50); } void draw() { @@ -27,4 +26,3 @@ void draw() { // Drawing the PShape shape(circle); } - From c34696353d6733a4a66525101be5048696d624a9 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 3 Sep 2013 15:12:39 -0400 Subject: [PATCH 011/556] fixed handling of rect parametrers in PShape --- core/src/processing/opengl/PGraphics2D.java | 2 +- core/src/processing/opengl/PGraphics3D.java | 2 +- .../processing/opengl/PGraphicsOpenGL.java | 108 +----------------- core/src/processing/opengl/PShapeOpenGL.java | 65 ++++++++--- 4 files changed, 55 insertions(+), 122 deletions(-) diff --git a/core/src/processing/opengl/PGraphics2D.java b/core/src/processing/opengl/PGraphics2D.java index d8adced31..0f35b711c 100644 --- a/core/src/processing/opengl/PGraphics2D.java +++ b/core/src/processing/opengl/PGraphics2D.java @@ -346,7 +346,7 @@ public class PGraphics2D extends PGraphicsOpenGL { shape = new PShapeOpenGL(parent, PShape.PRIMITIVE); shape.setKind(QUAD); } else if (kind == RECT) { - if (len != 4 && len != 5 && len != 8) { + if (len != 4 && len != 5 && len != 8 && len != 9) { showWarning("Wrong number of parameters"); return null; } diff --git a/core/src/processing/opengl/PGraphics3D.java b/core/src/processing/opengl/PGraphics3D.java index 318b32df2..43aa52251 100644 --- a/core/src/processing/opengl/PGraphics3D.java +++ b/core/src/processing/opengl/PGraphics3D.java @@ -217,7 +217,7 @@ public class PGraphics3D extends PGraphicsOpenGL { shape = new PShapeOpenGL(parent, PShape.PRIMITIVE); shape.setKind(QUAD); } else if (kind == RECT) { - if (len != 4 && len != 5 && len != 8) { + if (len != 4 && len != 5 && len != 8 && len != 9) { showWarning("Wrong number of parameters"); return null; } diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 318d33556..c58992416 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -2908,40 +2908,6 @@ public class PGraphicsOpenGL extends PGraphics { endShape(); } - ////////////////////////////////////////////////////////////// - - // RECT - - // public void rectMode(int mode) - - @Override - public void rect(float a, float b, float c, float d) { - beginShape(QUADS); - defaultEdges = false; - normalMode = NORMAL_MODE_SHAPE; - inGeo.setMaterial(fillColor, strokeColor, strokeWeight, - ambientColor, specularColor, emissiveColor, shininess); - inGeo.setNormal(normalX, normalY, normalZ); - inGeo.addRect(a, b, c, d, fill, stroke, rectMode); - endShape(); - } - - - @Override - public void rect(float a, float b, float c, float d, - float tl, float tr, float br, float bl) { - beginShape(POLYGON); - defaultEdges = false; - normalMode = NORMAL_MODE_SHAPE; - inGeo.setMaterial(fillColor, strokeColor, strokeWeight, - ambientColor, specularColor, emissiveColor, shininess); - inGeo.setNormal(normalX, normalY, normalZ); - inGeo.addRect(a, b, c, d, tl, tr, br, bl, - fill, stroke, bezierDetail, rectMode); - endShape(CLOSE); - } - - // protected void rectImpl(float x1, float y1, float x2, float y2) ////////////////////////////////////////////////////////////// @@ -8634,39 +8600,7 @@ public class PGraphicsOpenGL extends PGraphics { } void addRect(float a, float b, float c, float d, - boolean fill, boolean stroke, int rectMode) { - float hradius, vradius; - switch (rectMode) { - case CORNERS: - break; - case CORNER: - c += a; d += b; - break; - case RADIUS: - hradius = c; - vradius = d; - c = a + hradius; - d = b + vradius; - a -= hradius; - b -= vradius; - break; - case CENTER: - hradius = c / 2.0f; - vradius = d / 2.0f; - c = a + hradius; - d = b + vradius; - a -= hradius; - b -= vradius; - } - - if (a > c) { - float temp = a; a = c; c = temp; - } - - if (b > d) { - float temp = b; b = d; d = temp; - } - + boolean fill, boolean stroke) { addQuad(a, b, 0, c, b, 0, c, d, 0, @@ -8676,45 +8610,7 @@ public class PGraphicsOpenGL extends PGraphics { void addRect(float a, float b, float c, float d, float tl, float tr, float br, float bl, - boolean fill, boolean stroke, int detail, int rectMode) { - float hradius, vradius; - switch (rectMode) { - case CORNERS: - break; - case CORNER: - c += a; d += b; - break; - case RADIUS: - hradius = c; - vradius = d; - c = a + hradius; - d = b + vradius; - a -= hradius; - b -= vradius; - break; - case CENTER: - hradius = c / 2.0f; - vradius = d / 2.0f; - c = a + hradius; - d = b + vradius; - a -= hradius; - b -= vradius; - } - - if (a > c) { - float temp = a; a = c; c = temp; - } - - if (b > d) { - float temp = b; b = d; d = temp; - } - - float maxRounding = PApplet.min((c - a) / 2, (d - b) / 2); - if (tl > maxRounding) tl = maxRounding; - if (tr > maxRounding) tr = maxRounding; - if (br > maxRounding) br = maxRounding; - if (bl > maxRounding) bl = maxRounding; - + boolean fill, boolean stroke, int detail) { if (nonZero(tr)) { addVertex(c-tr, b, VERTEX); addQuadraticVertex(c, b, 0, c, b+tr, 0, diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index c218f4b3a..43e172384 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -2713,20 +2713,18 @@ public class PShapeOpenGL extends PShape { float a = 0, b = 0, c = 0, d = 0; float tl = 0, tr = 0, br = 0, bl = 0; boolean rounded = false; - if (params.length == 4) { + int mode = rectMode; + + if (params.length == 4 || params.length == 5) { a = params[0]; b = params[1]; c = params[2]; d = params[3]; + if (params.length == 5) { + mode = (int)(params[4]); + } rounded = false; - } else if (params.length == 5) { - a = params[0]; - b = params[1]; - c = params[2]; - d = params[3]; - tl = tr = br = bl = params[4]; - rounded = true; - } else if (params.length == 8) { + } else if (params.length == 8 || params.length == 9) { a = params[0]; b = params[1]; c = params[2]; @@ -2735,20 +2733,59 @@ public class PShapeOpenGL extends PShape { tr = params[5]; br = params[6]; bl = params[7]; + if (params.length == 9) { + mode = (int)(params[8]); + } rounded = true; } + float hradius, vradius; + switch (mode) { + case CORNERS: + break; + case CORNER: + c += a; d += b; + break; + case RADIUS: + hradius = c; + vradius = d; + c = a + hradius; + d = b + vradius; + a -= hradius; + b -= vradius; + break; + case CENTER: + hradius = c / 2.0f; + vradius = d / 2.0f; + c = a + hradius; + d = b + vradius; + a -= hradius; + b -= vradius; + } + + if (a > c) { + float temp = a; a = c; c = temp; + } + + if (b > d) { + float temp = b; b = d; d = temp; + } + + float maxRounding = PApplet.min((c - a) / 2, (d - b) / 2); + if (tl > maxRounding) tl = maxRounding; + if (tr > maxRounding) tr = maxRounding; + if (br > maxRounding) br = maxRounding; + if (bl > maxRounding) bl = maxRounding; + inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); if (rounded) { - inGeo.addRect(a, b, c, d, - tl, tr, br, bl, - fill, stroke, bezierDetail, CORNER); + inGeo.addRect(a, b, c, d, tl, tr, br, bl, + fill, stroke, bezierDetail); tessellator.tessellatePolygon(false, true, true); } else { - inGeo.addRect(a, b, c, d, - fill, stroke, CORNER); + inGeo.addRect(a, b, c, d, fill, stroke); tessellator.tessellateQuads(); } } From 659be8ed8d5e2d9ce99111b2e66c0d1747d8c289 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 3 Sep 2013 15:57:45 -0400 Subject: [PATCH 012/556] Texture releases auxiliary arrays/buffers when the free memory is low, this should help in situations like #1975 --- core/src/processing/opengl/Texture.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/src/processing/opengl/Texture.java b/core/src/processing/opengl/Texture.java index 323d6f818..7f131c7e3 100644 --- a/core/src/processing/opengl/Texture.java +++ b/core/src/processing/opengl/Texture.java @@ -413,6 +413,8 @@ public class Texture implements PConstants { pgl.disableTexturing(glTarget); } + releaseMemory(); + updateTexels(x, y, w, h); } @@ -430,6 +432,7 @@ public class Texture implements PConstants { public void setNative(int[] pixels, int x, int y, int w, int h) { updatePixelBuffer(pixels); setNative(pixelBuffer, x, y, w, h); + releaseMemory(); } @@ -1322,6 +1325,14 @@ public class Texture implements PConstants { } + protected void releaseMemory() { + if (Runtime.getRuntime().freeMemory() / 1E6 < 5) { + pixelBuffer = null; + rgbaPixels = null; + } + } + + /////////////////////////////////////////////////////////// // Parameter handling From 8888372cbeb5b1375511506512eadcbf0ea5f20a Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 3 Sep 2013 16:24:00 -0400 Subject: [PATCH 013/556] some additional logic to keep the use of memory in Texture low --- core/src/processing/opengl/Texture.java | 109 ++++++++++++++---------- 1 file changed, 66 insertions(+), 43 deletions(-) diff --git a/core/src/processing/opengl/Texture.java b/core/src/processing/opengl/Texture.java index 7f131c7e3..69ed17895 100644 --- a/core/src/processing/opengl/Texture.java +++ b/core/src/processing/opengl/Texture.java @@ -1,5 +1,3 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - /* Part of the Processing project - http://processing.org @@ -65,6 +63,16 @@ public class Texture implements PConstants { * interpolates linearly between these two value. */ protected static final int TRILINEAR = 5; + + // This constant controls how many times pixelBuffer and rgbaPixels can be + // accessed before they are not released anymore. The idea is that if they + // have been used only a few times, it doesn't make sense to keep them around. + protected static final int MAX_UPDATES = 10; + + // The minimum amount of free JVM's memory (in MB) before pixelBuffer and + // rgbaPixels are released every time after they are used. + protected static final int MIN_MEMORY = 5; + public int width, height; public int glName; @@ -94,6 +102,8 @@ public class Texture implements PConstants { protected int[] rgbaPixels = null; protected IntBuffer pixelBuffer = null; protected FrameBuffer tempFbo = null; + protected int pixBufUpdateCount = 0; + protected int rgbaPixUpdateCount = 0; /** Modified portion of the texture */ protected boolean modified; @@ -334,7 +344,7 @@ public class Texture implements PConstants { if (PGraphicsOpenGL.autoMipmapGenSupported) { // Automatic mipmap generation. loadPixels(w * h); - convertToRGBA(pixels, rgbaPixels, format, w, h); + convertToRGBA(pixels, format, w, h); updatePixelBuffer(rgbaPixels); pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE, pixelBuffer); @@ -395,14 +405,14 @@ public class Texture implements PConstants { */ loadPixels(w * h); - convertToRGBA(pixels, rgbaPixels, format, w, h); + convertToRGBA(pixels, format, w, h); updatePixelBuffer(rgbaPixels); pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE, pixelBuffer); } } else { loadPixels(w * h); - convertToRGBA(pixels, rgbaPixels, format, w, h); + convertToRGBA(pixels, format, w, h); updatePixelBuffer(rgbaPixels); pgl.texSubImage2D(glTarget, 0, x, y, w, h, PGL.RGBA, PGL.UNSIGNED_BYTE, pixelBuffer); @@ -413,7 +423,8 @@ public class Texture implements PConstants { pgl.disableTexturing(glTarget); } - releaseMemory(); + releasePixelBuffer(); + releaseRGBAPixels(); updateTexels(x, y, w, h); } @@ -432,7 +443,7 @@ public class Texture implements PConstants { public void setNative(int[] pixels, int x, int y, int w, int h) { updatePixelBuffer(pixels); setNative(pixelBuffer, x, y, w, h); - releaseMemory(); + releasePixelBuffer(); } @@ -818,6 +829,7 @@ public class Texture implements PConstants { protected void updatePixelBuffer(int[] pixels) { pixelBuffer = PGL.updateIntBuffer(pixelBuffer, pixels, true); + pixBufUpdateCount++; } @@ -996,38 +1008,36 @@ public class Texture implements PConstants { /** * Reorders a pixel array in the given format into the order required by - * OpenGL (RGBA). Both arrays are assumed to be of the same length. The width - * and height parameters are used in the YUV420 to RBGBA conversion. - * @param intArray int[] - * @param tIntArray int[] - * @param arrayFormat int + * OpenGL (RGBA) and stores it into rgbaPixels. The width and height + * parameters are used in the YUV420 to RBGBA conversion. + * @param pixels int[] + * @param format int * @param w int * @param h int */ - protected void convertToRGBA(int[] intArray, int[] tIntArray, int arrayFormat, - int w, int h) { + protected void convertToRGBA(int[] pixels, int format, int w, int h) { if (PGL.BIG_ENDIAN) { - switch (arrayFormat) { + switch (format) { case ALPHA: // Converting from xxxA into RGBA. RGB is set to white // (0xFFFFFF, i.e.: (255, 255, 255)) - for (int i = 0; i< intArray.length; i++) { - tIntArray[i] = 0xFFFFFF00 | intArray[i]; + for (int i = 0; i< pixels.length; i++) { + rgbaPixels[i] = 0xFFFFFF00 | pixels[i]; } break; case RGB: // Converting xRGB into RGBA. A is set to 0xFF (255, full opacity). - for (int i = 0; i< intArray.length; i++) { - int pixel = intArray[i]; - tIntArray[i] = (pixel << 8) | 0xFF; + for (int i = 0; i< pixels.length; i++) { + int pixel = pixels[i]; + rgbaPixels[i] = (pixel << 8) | 0xFF; } break; case ARGB: // Converting ARGB into RGBA. Shifting RGB to 8 bits to the left, // and bringing A to the first byte. - for (int i = 0; i< intArray.length; i++) { - int pixel = intArray[i]; - tIntArray[i] = (pixel << 8) | ((pixel >> 24) & 0xFF); + for (int i = 0; i< pixels.length; i++) { + int pixel = pixels[i]; + rgbaPixels[i] = (pixel << 8) | ((pixel >> 24) & 0xFF); } break; } @@ -1037,43 +1047,44 @@ public class Texture implements PConstants { // for the most part just need to swap two components here // the sun.cpu.endian here might be "false", oddly enough.. // (that's why just using an "else", rather than check for "little") - switch (arrayFormat) { + switch (format) { case ALPHA: // Converting xxxA into ARGB, with RGB set to white. - for (int i = 0; i< intArray.length; i++) { - tIntArray[i] = (intArray[i] << 24) | 0x00FFFFFF; + for (int i = 0; i< pixels.length; i++) { + rgbaPixels[i] = (pixels[i] << 24) | 0x00FFFFFF; } break; case RGB: // We need to convert xRGB into ABGR, // so R and B must be swapped, and the x just made 0xFF. - for (int i = 0; i< intArray.length; i++) { - int pixel = intArray[i]; - tIntArray[i] = 0xFF000000 | - ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) | - (pixel & 0x0000FF00); + for (int i = 0; i< pixels.length; i++) { + int pixel = pixels[i]; + rgbaPixels[i] = 0xFF000000 | + ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) | + (pixel & 0x0000FF00); } break; case ARGB: // We need to convert ARGB into ABGR, // so R and B must be swapped, A and G just brought back in. - for (int i = 0; i < intArray.length; i++) { - int pixel = intArray[i]; - tIntArray[i] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) | - (pixel & 0xFF00FF00); + for (int i = 0; i < pixels.length; i++) { + int pixel = pixels[i]; + rgbaPixels[i] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) | + (pixel & 0xFF00FF00); } break; } } + rgbaPixUpdateCount++; } /** * Reorders an OpenGL pixel array (RGBA) into ARGB. The array must be * of size width * height. - * @param intArray int[] + * @param pixels int[] */ - protected void convertToARGB(int[] intArray) { + protected void convertToARGB(int[] pixels) { int t = 0; int p = 0; if (PGL.BIG_ENDIAN) { @@ -1081,8 +1092,8 @@ public class Texture implements PConstants { // and placing A 24 bits to the left. for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - int pixel = intArray[p++]; - intArray[t++] = (pixel >>> 8) | ((pixel << 24) & 0xFF000000); + int pixel = pixels[p++]; + pixels[t++] = (pixel >>> 8) | ((pixel << 24) & 0xFF000000); } } } else { @@ -1090,8 +1101,8 @@ public class Texture implements PConstants { // A and G just brought back in. for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - int pixel = intArray[p++]; - intArray[t++] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) | + int pixel = pixels[p++]; + pixels[t++] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) | (pixel & 0xFF00FF00); } } @@ -1325,9 +1336,21 @@ public class Texture implements PConstants { } - protected void releaseMemory() { - if (Runtime.getRuntime().freeMemory() / 1E6 < 5) { + // Releases the memory used by pixelBuffer either if the buffer hasn't been + // used many times yet, or if the JVM is running low in free memory. + protected void releasePixelBuffer() { + double freeMB = Runtime.getRuntime().freeMemory() / 1E6; + if (pixBufUpdateCount < MAX_UPDATES || freeMB < MIN_MEMORY) { pixelBuffer = null; + } + } + + + // Releases the memory used by rgbaPixels either if the array hasn't been + // used many times yet, or if the JVM is running low in free memory. + protected void releaseRGBAPixels() { + double freeMB = Runtime.getRuntime().freeMemory() / 1E6; + if (rgbaPixUpdateCount < MAX_UPDATES || freeMB < MIN_MEMORY) { rgbaPixels = null; } } From 3441ea7fa48576c2a9fe10aeb70d200e5229f74b Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 3 Sep 2013 19:41:10 -0400 Subject: [PATCH 014/556] GL implementations of copy() methods, fix #1924 --- .../processing/opengl/PGraphicsOpenGL.java | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index c58992416..5cf259b5d 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -5585,53 +5585,53 @@ public class PGraphicsOpenGL extends PGraphics { ////////////////////////////////////////////////////////////// - /** - * Extremely slow and not optimized, should use GL methods instead. Currently - * calls a beginPixels() on the whole canvas, then does the copy, then it - * calls endPixels(). - */ - // public void copy(int sx1, int sy1, int sx2, int sy2, - // int dx1, int dy1, int dx2, int dy2) + // COPY - // public void copy(PImage src, - // int sx1, int sy1, int sx2, int sy2, - // int dx1, int dy1, int dx2, int dy2) + + @Override + public void copy(int sx, int sy, int sw, int sh, + int dx, int dy, int dw, int dh) { + if (primarySurface) pgl.requestFBOLayer(); + loadTexture(); + if (filterTexture == null || filterTexture.contextIsOutdated()) { + filterTexture = new Texture(texture.width, texture.height, + texture.getParameters()); + filterTexture.invertedY(true); + filterImage = wrapTexture(filterTexture); + } + filterTexture.put(texture, sx, height - (sy + sh), sw, height - sy); + copy(filterImage, sx, sy, sw, sh, dx, dy, dw, dh); + } + + + @Override + public void copy(PImage src, + int sx, int sy, int sw, int sh, + int dx, int dy, int dw, int dh) { + boolean needEndDraw = false; + if (!drawing) { + beginDraw(); + needEndDraw = true; + } + + Texture tex = getTexture(src); + pgl.drawTexture(tex.glTarget, tex.glName, + tex.glWidth, tex.glHeight, width, height, + sx, tex.height - (sy + sh), + sx + sw, tex.height - sy, + dx, height - (dy + dh), + dx + dw, height - dy); + + if (needEndDraw) { + endDraw(); + } + } ////////////////////////////////////////////////////////////// // BLEND - // static public int blendColor(int c1, int c2, int mode) - - // public void blend(PImage src, - // int sx, int sy, int dx, int dy, int mode) { - // set(dx, dy, PImage.blendColor(src.get(sx, sy), get(dx, dy), mode)); - // } - - - /** - * Extremely slow and not optimized, should use GL methods instead. Currently - * calls a beginPixels() on the whole canvas, then does the copy, then it - * calls endPixels(). Please help fix: Bug 941, Bug 942. - */ - // public void blend(int sx1, int sy1, int sx2, int sy2, - // int dx1, int dy1, int dx2, int dy2, int mode) { - // loadPixels(); - // super.blend(sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2, mode); - // updatePixels(); - // } - - // public void blend(PImage src, - // int sx1, int sy1, int sx2, int sy2, - // int dx1, int dy1, int dx2, int dy2, int mode) { - // loadPixels(); - // super.blend(src, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2, mode); - // updatePixels(); - // } - /** * Allows to set custom blend modes for the entire scene, using openGL. From 55a23cb5fbea185d5aa4543d8301182711fd8d45 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 3 Sep 2013 20:31:40 -0400 Subject: [PATCH 015/556] removed FishEye example --- .../Topics/Shaders/FishEye/FishEye.pde | 52 ---------------- .../Topics/Shaders/FishEye/data/FishEye.glsl | 59 ------------------- 2 files changed, 111 deletions(-) delete mode 100644 java/examples/Topics/Shaders/FishEye/FishEye.pde delete mode 100644 java/examples/Topics/Shaders/FishEye/data/FishEye.glsl diff --git a/java/examples/Topics/Shaders/FishEye/FishEye.pde b/java/examples/Topics/Shaders/FishEye/FishEye.pde deleted file mode 100644 index 1453cc278..000000000 --- a/java/examples/Topics/Shaders/FishEye/FishEye.pde +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Fish Eye - * - * This fish-eye shader is useful for dome projection. - */ - -PShader fisheye; -PGraphics canvas; -PImage img; - -boolean useFishEye = true; - -void setup() { - size(640, 640, P3D); - canvas = createGraphics(width, height, P3D); - - fisheye = loadShader("FishEye.glsl"); - fisheye.set("aperture", 180.0); -} - -void draw() { - canvas.beginDraw(); - canvas.background(0); - canvas.stroke(255, 0, 0); - for (int i = 0; i < width; i += 10) { - canvas.line(i, 0, i, height); - } - for (int i = 0; i < height; i += 10) { - canvas.line(0, i, width, i); - } - canvas.lights(); - canvas.noStroke(); - canvas.translate(mouseX, mouseY, 100); - canvas.rotateX(frameCount * 0.01); - canvas.rotateY(frameCount * 0.01); - canvas.box(100); - canvas.endDraw(); - - if (useFishEye == true) { - shader(fisheye); - } - image(canvas, 0, 0, width, height); -} - -void mousePressed() { - if (useFishEye) { - useFishEye = false; - resetShader(); - } else { - useFishEye = true; - } -} diff --git a/java/examples/Topics/Shaders/FishEye/data/FishEye.glsl b/java/examples/Topics/Shaders/FishEye/data/FishEye.glsl deleted file mode 100644 index 9865603e6..000000000 --- a/java/examples/Topics/Shaders/FishEye/data/FishEye.glsl +++ /dev/null @@ -1,59 +0,0 @@ -// Inspired by the "Angular Fisheye à la Bourke" sketch from -// Jonathan Cremieux, as shown in the OpenProcessing website: -// http://openprocessing.org/visuals/?visualID=12140 -// Using the inverse transform of the angular fisheye as -// explained in Paul Bourke's website: -// http://paulbourke.net/miscellaneous/domefisheye/fisheye/ - -#ifdef GL_ES -precision mediump float; -precision mediump int; -#endif - -#define PROCESSING_TEXTURE_SHADER - -uniform sampler2D texture; -uniform mat4 texMatrix; - -varying vec4 vertColor; -varying vec4 vertTexCoord; - -uniform float aperture; - -const float PI = 3.1415926535; - -void main(void) { - float apertureHalf = 0.5 * aperture * (PI / 180.0); - - // This factor ajusts the coordinates in the case that - // the aperture angle is less than 180 degrees, in which - // case the area displayed is not the entire half-sphere. - float maxFactor = sin(apertureHalf); - - // The st factor takes into account the situation when non-pot - // textures are not supported, so that the maximum texture - // coordinate to cover the entire image might not be 1. - vec2 stFactor = vec2(1.0 / abs(texMatrix[0][0]), 1.0 / abs(texMatrix[1][1])); - vec2 pos = (2.0 * vertTexCoord.st * stFactor - 1.0); - - float l = length(pos); - if (l > 1.0) { - gl_FragColor = vec4(0, 0, 0, 1); - } else { - float x = maxFactor * pos.x; - float y = maxFactor * pos.y; - - float n = length(vec2(x, y)); - - float z = sqrt(1.0 - n * n); - - float r = atan(n, z) / PI; - - float phi = atan(y, x); - - float u = r * cos(phi) + 0.5; - float v = r * sin(phi) + 0.5; - - gl_FragColor = texture2D(texture, vec2(u, v) / stFactor) * vertColor; - } -} \ No newline at end of file From 4392af45f3a266c08f3e68c9719485ff6a564f0f Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 3 Sep 2013 20:34:02 -0400 Subject: [PATCH 016/556] Added new DomeProjection example --- .../Shaders/DomeProjection/CubeMapUtils.pde | 99 +++++++++++++++++++ .../Shaders/DomeProjection/DomeProjection.pde | 52 ++++++++++ .../DomeProjection/data/cubemapfrag.glsl | 1 + .../DomeProjection/data/cubemapvert.glsl | 1 + 4 files changed, 153 insertions(+) create mode 100644 java/examples/Topics/Shaders/DomeProjection/CubeMapUtils.pde create mode 100644 java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde create mode 100644 java/examples/Topics/Shaders/DomeProjection/data/cubemapfrag.glsl create mode 100644 java/examples/Topics/Shaders/DomeProjection/data/cubemapvert.glsl diff --git a/java/examples/Topics/Shaders/DomeProjection/CubeMapUtils.pde b/java/examples/Topics/Shaders/DomeProjection/CubeMapUtils.pde new file mode 100644 index 000000000..95a862184 --- /dev/null +++ b/java/examples/Topics/Shaders/DomeProjection/CubeMapUtils.pde @@ -0,0 +1,99 @@ +void initCubeMap() { + gridTex = loadImage("grid.png"); + sphereDetail(50); + domeSphere = createShape(SPHERE, height/2.0f); + domeSphere.setTexture(gridTex); + domeSphere.rotateX(HALF_PI); + domeSphere.setStroke(false); + + PGL pgl = beginPGL(); + + envMapTextureID = IntBuffer.allocate(1); + pgl.genTextures(1, envMapTextureID); + pgl.bindTexture(PGL.TEXTURE_CUBE_MAP, envMapTextureID.get(0)); + pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_S, PGL.CLAMP_TO_EDGE); + pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_T, PGL.CLAMP_TO_EDGE); + pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_R, PGL.CLAMP_TO_EDGE); + pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_MIN_FILTER, PGL.NEAREST); + pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_MAG_FILTER, PGL.NEAREST); + for (int i = PGL.TEXTURE_CUBE_MAP_POSITIVE_X; i < PGL.TEXTURE_CUBE_MAP_POSITIVE_X + 6; i++) { + pgl.texImage2D(i, 0, PGL.RGBA8, envMapSize, envMapSize, 0, PGL.RGBA, PGL.UNSIGNED_BYTE, null); + } + + // Init fbo, rbo + fbo = IntBuffer.allocate(1); + rbo = IntBuffer.allocate(1); + pgl.genFramebuffers(1, fbo); + pgl.bindFramebuffer(PGL.FRAMEBUFFER, fbo.get(0)); + pgl.framebufferTexture2D(PGL.FRAMEBUFFER, PGL.COLOR_ATTACHMENT0, PGL.TEXTURE_CUBE_MAP_POSITIVE_X, envMapTextureID.get(0), 0); + + pgl.genRenderbuffers(1, rbo); + pgl.bindRenderbuffer(PGL.RENDERBUFFER, rbo.get(0)); + pgl.renderbufferStorage(PGL.RENDERBUFFER, PGL.DEPTH_COMPONENT24, envMapSize, envMapSize); + + // Attach depth buffer to FBO + pgl.framebufferRenderbuffer(PGL.FRAMEBUFFER, PGL.DEPTH_ATTACHMENT, PGL.RENDERBUFFER, rbo.get(0)); + + pgl.enable(PGL.TEXTURE_CUBE_MAP); + pgl.activeTexture(PGL.TEXTURE1); + pgl.bindTexture(PGL.TEXTURE_CUBE_MAP, envMapTextureID.get(0)); + + endPGL(); + + // Load cubemap shader. + cubemapShader = loadShader("cubemapfrag.glsl", "cubemapvert.glsl"); + cubemapShader.set("EnvMap", 1); +} + +void drawCubeMap() { + regenerateEnvMap(); + drawDomeMaster(); +} + +void drawDomeMaster() { + ortho(); + resetMatrix(); + shader(cubemapShader); + shape(domeSphere); + resetShader(); +} + +// Called to regenerate the envmap +void regenerateEnvMap() { + PGL pgl = beginPGL(); + + // bind fbo + pgl.bindFramebuffer(PGL.FRAMEBUFFER, fbo.get(0)); + + // generate 6 views from origin(0, 0, 0) + pgl.viewport(0, 0, envMapSize, envMapSize); + perspective(90.0f * DEG_TO_RAD, 1.0f, 1.0f, 1025.0f); + for (int face = PGL.TEXTURE_CUBE_MAP_POSITIVE_X; face < + PGL.TEXTURE_CUBE_MAP_NEGATIVE_Z; face++) { + resetMatrix(); + + if (face == PGL.TEXTURE_CUBE_MAP_POSITIVE_X) { + camera(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f); + } else if (face == PGL.TEXTURE_CUBE_MAP_NEGATIVE_X) { + camera(0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f); + } else if (face == PGL.TEXTURE_CUBE_MAP_POSITIVE_Y) { + camera(0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, -1.0f); + } else if (face == PGL.TEXTURE_CUBE_MAP_NEGATIVE_Y) { + camera(0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f); + } else if (face == PGL.TEXTURE_CUBE_MAP_POSITIVE_Z) { + camera(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f); + } + + scale(-1, 1, -1); + translate(-width * 0.5f, -height * 0.5f, -500); + + pgl.framebufferTexture2D(PGL.FRAMEBUFFER, PGL.COLOR_ATTACHMENT0, face, envMapTextureID.get(0), 0); + + drawScene(); // Draw objects in the scene + flush(); // Make sure that the geometry in the scene is pushed to the GPU + noLights(); // Disabling lights to avoid adding many times + pgl.framebufferTexture2D(PGL.FRAMEBUFFER, PGL.COLOR_ATTACHMENT0, face, 0, 0); + } + + endPGL(); +} diff --git a/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde b/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde new file mode 100644 index 000000000..6c869eab7 --- /dev/null +++ b/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde @@ -0,0 +1,52 @@ +/** + * DomeProjection + * + * This sketch uses use environmental mapping to render the output + * on a full spherical come. + * + * Based on the FullDomeTemplate code from Christopher Warnow: + * https://github.com/mphasize/FullDome + * + */ + +import java.nio.IntBuffer; + +PShader cubemapShader; +PShape domeSphere; +PImage gridTex; + +IntBuffer fbo; +IntBuffer rbo; +IntBuffer envMapTextureID; + +int envMapSize = 1024; + +void setup() { + size(640, 640, P3D); + initCubeMap(); +} + +void draw() { + background(0); + drawCubeMap(); +} + +void drawScene() { + background(0); + stroke(255, 0, 0); + strokeWeight(2); + for (int i = -width; i < 2 * width; i += 50) { + line(i, -height, -100, i, 2 *height, -100); + } + for (int i = -height; i < 2 * height; i += 50) { + line(-width, i, -100, 2 * width, i, -100); + } + + lights(); + noStroke(); + translate(mouseX, mouseY, 200); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + box(100); +} + diff --git a/java/examples/Topics/Shaders/DomeProjection/data/cubemapfrag.glsl b/java/examples/Topics/Shaders/DomeProjection/data/cubemapfrag.glsl new file mode 100644 index 000000000..9eea974a4 --- /dev/null +++ b/java/examples/Topics/Shaders/DomeProjection/data/cubemapfrag.glsl @@ -0,0 +1 @@ +uniform sampler2D texture; uniform samplerCube EnvMap; varying vec3 reflectDir; uniform vec2 texOffset; varying vec4 vertColor; varying vec4 vertTexCoord; void main() { // gl_FragColor = texture2D(texture, vertTexCoord.st) * vertColor; vec3 envColor = vec3(textureCube(EnvMap, reflectDir)); gl_FragColor = vec4(envColor, 1.0); } /* void main() { // Look up environment map value in cube map vec3 envColor = vec3(textureCube(EnvMap, ReflectDir)); gl_FragColor = vec4(envColor, 1.0); } */ \ No newline at end of file diff --git a/java/examples/Topics/Shaders/DomeProjection/data/cubemapvert.glsl b/java/examples/Topics/Shaders/DomeProjection/data/cubemapvert.glsl new file mode 100644 index 000000000..f52f94419 --- /dev/null +++ b/java/examples/Topics/Shaders/DomeProjection/data/cubemapvert.glsl @@ -0,0 +1 @@ +#define PROCESSING_TEXTURE_SHADER uniform mat4 transform; uniform mat4 modelview; uniform mat4 texMatrix; attribute vec4 vertex; attribute vec4 color; attribute vec2 texCoord; attribute vec3 normal; varying vec4 vertColor; varying vec4 vertTexCoord; uniform mat3 normalMatrix; varying vec3 reflectDir; void main() { gl_Position = transform * vertex; vec3 ecNormal = normalize(normalMatrix * normal); // Vertex in eye coordinates vec3 ecVertex = vec3(modelview * vertex); // Normal vector in eye coordinates vec3 eyeDir = ecVertex.xyz; reflectDir = reflect(eyeDir, ecNormal); vertColor = color; vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); } /* varying vec3 ReflectDir; void main() { gl_Position = ftransform(); vec3 normal = normalize(gl_NormalMatrix * gl_Normal); vec4 pos = gl_ModelViewMatrix * gl_Vertex; vec3 eyeDir = pos.xyz; ReflectDir = reflect(eyeDir, normal); } */ \ No newline at end of file From e4afbd715136d5999a69febceb511d6d297c860c Mon Sep 17 00:00:00 2001 From: codeanticode Date: Wed, 4 Sep 2013 07:02:57 -0400 Subject: [PATCH 017/556] added flush() call in copy(PImage, ...) --- core/src/processing/opengl/PGraphicsOpenGL.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 5cf259b5d..9d5a2635a 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -5614,6 +5614,8 @@ public class PGraphicsOpenGL extends PGraphics { needEndDraw = true; } + flush(); // make sure that the screen contents are up to date. + Texture tex = getTexture(src); pgl.drawTexture(tex.glTarget, tex.glName, tex.glWidth, tex.glHeight, width, height, From 6cf649a0ce78fbd6e511ee6e8fd390543e869cd5 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Wed, 4 Sep 2013 19:04:43 -0400 Subject: [PATCH 018/556] cleanup inner shader classes, and minor tweaks --- .../processing/opengl/PGraphicsOpenGL.java | 194 +++++------------- core/src/processing/opengl/PShapeOpenGL.java | 6 +- 2 files changed, 57 insertions(+), 143 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 9d5a2635a..dc63067fc 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -80,8 +80,8 @@ public class PGraphicsOpenGL extends PGraphics { "Unsupported shape format"; static final String INVALID_FILTER_SHADER_ERROR = "Your shader needs to be of TEXTURE type to be used as a filter"; - static final String INVALID_PROCESSING_SHADER_ERROR = - "The GLSL code doesn't seem to contain a valid shader to use in Processing"; + static final String INCONSISTENT_SHADER_TYPES = + "The vertex and fragment shaders have different types"; static final String WRONG_SHADER_TYPE_ERROR = "shader() called with a wrong shader"; static final String UNKNOWN_SHADER_KIND_ERROR = @@ -2400,16 +2400,15 @@ public class PGraphicsOpenGL extends PGraphics { 4 * voffset * PGL.SIZEOF_BYTE); shader.setShininessAttribute(glPolyShininess, 1, PGL.FLOAT, 0, voffset * PGL.SIZEOF_FLOAT); - } - - if (tex != null) { + } else { shader.setNormalAttribute(glPolyNormal, 3, PGL.FLOAT, 0, 3 * voffset * PGL.SIZEOF_FLOAT); shader.setTexcoordAttribute(glPolyTexcoord, 2, PGL.FLOAT, 0, 2 * voffset * PGL.SIZEOF_FLOAT); - shader.setTexture(tex); + if (tex != null) shader.setTexture(tex); } + pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPolyIndex); pgl.drawElements(PGL.TRIANGLES, icount, PGL.INDEX_TYPE, ioffset * PGL.SIZEOF_INDEX); @@ -6255,10 +6254,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public PShader loadShader(String fragFilename) { int shaderType = getShaderType(fragFilename); - if (shaderType == -1) { - PGraphics.showWarning(INVALID_PROCESSING_SHADER_ERROR); - return null; - } + if (shaderType == -1) shaderType = PShader.COLOR; PShader shader = null; if (shaderType == PShader.POINT) { shader = new PointShader(parent); @@ -6286,12 +6282,20 @@ public class PGraphicsOpenGL extends PGraphics { @Override public PShader loadShader(String fragFilename, String vertFilename) { - int shaderType = getShaderType(vertFilename); - if (shaderType == -1) { - shaderType = getShaderType(fragFilename); - } - if (shaderType == -1) { - PGraphics.showWarning(INVALID_PROCESSING_SHADER_ERROR); + int vertType = getShaderType(vertFilename); + int fragType = getShaderType(fragFilename); + + int shaderType = -1; + if (vertType == -1 && fragType == -1) { + shaderType = PShader.COLOR; + } else if (vertType == -1) { + shaderType = fragType; + } else if (fragType == -1) { + shaderType = vertType; + } else if (fragType == vertType) { + shaderType = vertType; + } else { + PGraphics.showWarning(INCONSISTENT_SHADER_TYPES); return null; } @@ -6349,14 +6353,14 @@ public class PGraphicsOpenGL extends PGraphics { flush(); // Flushing geometry drawn with a different shader. if (kind == TRIANGLES || kind == QUADS || kind == POLYGON) { - if (shader instanceof TextureShader) { - textureShader = (TextureShader) shader; - } else if (shader instanceof ColorShader) { - colorShader = (ColorShader) shader; - } else if (shader instanceof TexlightShader) { + if (shader instanceof TexlightShader) { texlightShader = (TexlightShader) shader; + } else if (shader instanceof TextureShader) { + textureShader = (TextureShader) shader; } else if (shader instanceof LightShader) { lightShader = (LightShader) shader; + } else if (shader instanceof ColorShader) { + colorShader = (ColorShader) shader; } else { PGraphics.showWarning(WRONG_SHADER_TYPE_ERROR); } @@ -6684,6 +6688,9 @@ public class PGraphicsOpenGL extends PGraphics { protected class ColorShader extends BaseShader { protected int vertexLoc; protected int colorLoc; + protected int normalLoc; + protected int texCoordLoc; + protected int normalMatrixLoc; public ColorShader(PApplet parent) { super(parent); @@ -6702,11 +6709,15 @@ public class PGraphicsOpenGL extends PGraphics { public void loadAttributes() { vertexLoc = getAttributeLoc("vertex"); colorLoc = getAttributeLoc("color"); + texCoordLoc = getAttributeLoc("texCoord"); + normalLoc = getAttributeLoc("normal"); } @Override public void loadUniforms() { super.loadUniforms(); + + normalMatrixLoc = getUniformLoc("normalMatrix"); } @Override @@ -6721,6 +6732,18 @@ public class PGraphicsOpenGL extends PGraphics { setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset); } + @Override + public void setNormalAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(normalLoc, vboId, size, type, false, stride, offset); + } + + @Override + public void setTexcoordAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset); + } + @Override public void bind() { super.bind(); @@ -6729,26 +6752,32 @@ public class PGraphicsOpenGL extends PGraphics { loadAttributes(); loadUniforms(); } + setCommonUniforms(); if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc); if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc); + if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc); + if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc); - setCommonUniforms(); + if (-1 < normalMatrixLoc) { + pgCurrent.updateGLNormal(); + setUniformMatrix(normalMatrixLoc, pgCurrent.glNormal); + } } @Override public void unbind() { if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc); if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc); + if (-1 < texCoordLoc) pgl.disableVertexAttribArray(texCoordLoc); + if (-1 < normalLoc) pgl.disableVertexAttribArray(normalLoc); super.unbind(); } } - protected class LightShader extends BaseShader { - protected int normalMatrixLoc; - + protected class LightShader extends ColorShader { protected int lightCountLoc; protected int lightPositionLoc; protected int lightNormalLoc; @@ -6758,10 +6787,6 @@ public class PGraphicsOpenGL extends PGraphics { protected int lightFalloffLoc; protected int lightSpotLoc; - protected int vertexLoc; - protected int colorLoc; - protected int normalLoc; - protected int ambientLoc; protected int specularLoc; protected int emissiveLoc; @@ -6782,10 +6807,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void loadAttributes() { - vertexLoc = getAttributeLoc("vertex"); - colorLoc = getAttributeLoc("color"); - normalLoc = getAttributeLoc("normal"); - + super.loadAttributes(); ambientLoc = getAttributeLoc("ambient"); specularLoc = getAttributeLoc("specular"); emissiveLoc = getAttributeLoc("emissive"); @@ -6796,8 +6818,6 @@ public class PGraphicsOpenGL extends PGraphics { public void loadUniforms() { super.loadUniforms(); - normalMatrixLoc = getUniformLoc("normalMatrix"); - lightCountLoc = getUniformLoc("lightCount"); lightPositionLoc = getUniformLoc("lightPosition"); lightNormalLoc = getUniformLoc("lightNormal"); @@ -6808,24 +6828,6 @@ public class PGraphicsOpenGL extends PGraphics { lightSpotLoc = getUniformLoc("lightSpot"); } - @Override - public void setVertexAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void setColorAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset); - } - - @Override - public void setNormalAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(normalLoc, vboId, size, type, false, stride, offset); - } - @Override public void setAmbientAttribute(int vboId, int size, int type, int stride, int offset) { @@ -6853,26 +6855,12 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void bind() { super.bind(); - if (pgCurrent == null) { - setRenderer(PGraphicsOpenGL.pgCurrent); - loadAttributes(); - loadUniforms(); - } - - if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc); - if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc); - if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc); if (-1 < ambientLoc) pgl.enableVertexAttribArray(ambientLoc); if (-1 < specularLoc) pgl.enableVertexAttribArray(specularLoc); if (-1 < emissiveLoc) pgl.enableVertexAttribArray(emissiveLoc); if (-1 < shininessLoc) pgl.enableVertexAttribArray(shininessLoc); - if (-1 < normalMatrixLoc) { - pgCurrent.updateGLNormal(); - setUniformMatrix(normalMatrixLoc, pgCurrent.glNormal); - } - int count = pgCurrent.lightCount; setUniformValue(lightCountLoc, count); setUniformVector(lightPositionLoc, pgCurrent.lightPosition, 4, count); @@ -6883,16 +6871,10 @@ public class PGraphicsOpenGL extends PGraphics { setUniformVector(lightFalloffLoc, pgCurrent.lightFalloffCoefficients, 3, count); setUniformVector(lightSpotLoc, pgCurrent.lightSpotParameters, 2, count); - - setCommonUniforms(); } @Override public void unbind() { - if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc); - if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc); - if (-1 < normalLoc) pgl.disableVertexAttribArray(normalLoc); - if (-1 < ambientLoc) pgl.disableVertexAttribArray(ambientLoc); if (-1 < specularLoc) pgl.disableVertexAttribArray(specularLoc); if (-1 < emissiveLoc) pgl.disableVertexAttribArray(emissiveLoc); @@ -6906,15 +6888,11 @@ public class PGraphicsOpenGL extends PGraphics { protected class TextureShader extends ColorShader { protected Texture texture; protected int texUnit; - protected int texCoordLoc; protected int textureLoc; protected int texMatrixLoc; protected int texOffsetLoc; - protected int normalMatrixLoc; - protected int normalLoc; - protected float[] tcmat; public TextureShader(PApplet parent) { @@ -6937,29 +6915,6 @@ public class PGraphicsOpenGL extends PGraphics { textureLoc = getUniformLoc("texture"); texMatrixLoc = getUniformLoc("texMatrix"); texOffsetLoc = getUniformLoc("texOffset"); - - normalMatrixLoc = getUniformLoc("normalMatrix"); - } - - @Override - public void loadAttributes() { - super.loadAttributes(); - - texCoordLoc = getAttributeLoc("texCoord"); - - normalLoc = getAttributeLoc("normal"); - } - - @Override - public void setNormalAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(normalLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void setTexcoordAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset); } @Override @@ -7011,24 +6966,8 @@ public class PGraphicsOpenGL extends PGraphics { } } - @Override - public void bind() { - super.bind(); - - if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc); - - if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc); - if (-1 < normalMatrixLoc) { - pgCurrent.updateGLNormal(); - setUniformMatrix(normalMatrixLoc, pgCurrent.glNormal); - } - } - @Override public void unbind() { - if (-1 < texCoordLoc) pgl.disableVertexAttribArray(texCoordLoc); - if (-1 < normalLoc) pgl.disableVertexAttribArray(normalLoc); - if (-1 < textureLoc && texture != null) { pgl.activeTexture(PGL.TEXTURE0 + texUnit); texture.unbind(); @@ -7044,7 +6983,6 @@ public class PGraphicsOpenGL extends PGraphics { protected class TexlightShader extends LightShader { protected Texture texture; protected int texUnit; - protected int texCoordLoc; protected int textureLoc; protected int texMatrixLoc; @@ -7074,19 +7012,6 @@ public class PGraphicsOpenGL extends PGraphics { texOffsetLoc = getUniformLoc("texOffset"); } - @Override - public void loadAttributes() { - super.loadAttributes(); - - texCoordLoc = getAttributeLoc("texCoord"); - } - - @Override - public void setTexcoordAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset); - } - @Override public int getLastTexUnit() { return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit(); @@ -7136,17 +7061,8 @@ public class PGraphicsOpenGL extends PGraphics { } } - @Override - public void bind() { - super.bind(); - - if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc); - } - @Override public void unbind() { - if (-1 < texCoordLoc) pgl.disableVertexAttribArray(texCoordLoc); - if (-1 < textureLoc && texture != null) { pgl.activeTexture(PGL.TEXTURE0 + texUnit); texture.unbind(); diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index 43e172384..9dcfd90cf 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -4475,14 +4475,12 @@ public class PShapeOpenGL extends PShape { 0, 4 * voffset * PGL.SIZEOF_BYTE); shader.setShininessAttribute(root.glPolyShininess, 1, PGL.FLOAT, 0, voffset * PGL.SIZEOF_FLOAT); - } - - if (tex != null) { + } else { shader.setNormalAttribute(root.glPolyNormal, 3, PGL.FLOAT, 0, 3 * voffset * PGL.SIZEOF_FLOAT); shader.setTexcoordAttribute(root.glPolyTexcoord, 2, PGL.FLOAT, 0, 2 * voffset * PGL.SIZEOF_FLOAT); - shader.setTexture(tex); + if (tex != null) shader.setTexture(tex); } pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, root.glPolyIndex); From a4c1cd25b5f68da0e34077714e395915fb8758f4 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Wed, 4 Sep 2013 19:06:09 -0400 Subject: [PATCH 019/556] updated DomeProjection example with simplified shader use --- java/examples/Topics/Shaders/DomeProjection/CubeMapUtils.pde | 4 +--- .../examples/Topics/Shaders/DomeProjection/DomeProjection.pde | 1 - .../Topics/Shaders/DomeProjection/data/cubemapfrag.glsl | 2 +- .../Topics/Shaders/DomeProjection/data/cubemapvert.glsl | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/java/examples/Topics/Shaders/DomeProjection/CubeMapUtils.pde b/java/examples/Topics/Shaders/DomeProjection/CubeMapUtils.pde index 95a862184..679874c07 100644 --- a/java/examples/Topics/Shaders/DomeProjection/CubeMapUtils.pde +++ b/java/examples/Topics/Shaders/DomeProjection/CubeMapUtils.pde @@ -1,8 +1,6 @@ void initCubeMap() { - gridTex = loadImage("grid.png"); sphereDetail(50); domeSphere = createShape(SPHERE, height/2.0f); - domeSphere.setTexture(gridTex); domeSphere.rotateX(HALF_PI); domeSphere.setStroke(false); @@ -42,7 +40,7 @@ void initCubeMap() { // Load cubemap shader. cubemapShader = loadShader("cubemapfrag.glsl", "cubemapvert.glsl"); - cubemapShader.set("EnvMap", 1); + cubemapShader.set("cubemap", 1); } void drawCubeMap() { diff --git a/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde b/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde index 6c869eab7..6816e5fbb 100644 --- a/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde +++ b/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde @@ -13,7 +13,6 @@ import java.nio.IntBuffer; PShader cubemapShader; PShape domeSphere; -PImage gridTex; IntBuffer fbo; IntBuffer rbo; diff --git a/java/examples/Topics/Shaders/DomeProjection/data/cubemapfrag.glsl b/java/examples/Topics/Shaders/DomeProjection/data/cubemapfrag.glsl index 9eea974a4..0d47ce133 100644 --- a/java/examples/Topics/Shaders/DomeProjection/data/cubemapfrag.glsl +++ b/java/examples/Topics/Shaders/DomeProjection/data/cubemapfrag.glsl @@ -1 +1 @@ -uniform sampler2D texture; uniform samplerCube EnvMap; varying vec3 reflectDir; uniform vec2 texOffset; varying vec4 vertColor; varying vec4 vertTexCoord; void main() { // gl_FragColor = texture2D(texture, vertTexCoord.st) * vertColor; vec3 envColor = vec3(textureCube(EnvMap, reflectDir)); gl_FragColor = vec4(envColor, 1.0); } /* void main() { // Look up environment map value in cube map vec3 envColor = vec3(textureCube(EnvMap, ReflectDir)); gl_FragColor = vec4(envColor, 1.0); } */ \ No newline at end of file +uniform samplerCube cubemap; varying vec3 reflectDir; void main() { vec3 color = vec3(textureCube(cubemap, reflectDir)); gl_FragColor = vec4(color, 1.0); } \ No newline at end of file diff --git a/java/examples/Topics/Shaders/DomeProjection/data/cubemapvert.glsl b/java/examples/Topics/Shaders/DomeProjection/data/cubemapvert.glsl index f52f94419..1d96e9b52 100644 --- a/java/examples/Topics/Shaders/DomeProjection/data/cubemapvert.glsl +++ b/java/examples/Topics/Shaders/DomeProjection/data/cubemapvert.glsl @@ -1 +1 @@ -#define PROCESSING_TEXTURE_SHADER uniform mat4 transform; uniform mat4 modelview; uniform mat4 texMatrix; attribute vec4 vertex; attribute vec4 color; attribute vec2 texCoord; attribute vec3 normal; varying vec4 vertColor; varying vec4 vertTexCoord; uniform mat3 normalMatrix; varying vec3 reflectDir; void main() { gl_Position = transform * vertex; vec3 ecNormal = normalize(normalMatrix * normal); // Vertex in eye coordinates vec3 ecVertex = vec3(modelview * vertex); // Normal vector in eye coordinates vec3 eyeDir = ecVertex.xyz; reflectDir = reflect(eyeDir, ecNormal); vertColor = color; vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); } /* varying vec3 ReflectDir; void main() { gl_Position = ftransform(); vec3 normal = normalize(gl_NormalMatrix * gl_Normal); vec4 pos = gl_ModelViewMatrix * gl_Vertex; vec3 eyeDir = pos.xyz; ReflectDir = reflect(eyeDir, normal); } */ \ No newline at end of file +uniform mat4 transform; uniform mat4 modelview; uniform mat3 normalMatrix; attribute vec4 vertex; attribute vec3 normal; varying vec3 reflectDir; void main() { gl_Position = transform * vertex; vec3 ecNormal = normalize(normalMatrix * normal); // Vertex in eye coordinates vec3 ecVertex = vec3(modelview * vertex); // Normal vector in eye coordinates vec3 eyeDir = ecVertex.xyz; reflectDir = reflect(eyeDir, ecNormal); } \ No newline at end of file From cae8269fbd505fbf0ba14dcc1536c040a83915a4 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Wed, 4 Sep 2013 20:13:42 -0400 Subject: [PATCH 020/556] fixed error in flushPolys()/renderPolys() --- core/src/processing/opengl/PGraphicsOpenGL.java | 13 +++++++------ core/src/processing/opengl/PShapeOpenGL.java | 14 ++++++++------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index dc63067fc..3db04c14c 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -2388,6 +2388,10 @@ public class PGraphicsOpenGL extends PGraphics { 4 * voffset * PGL.SIZEOF_FLOAT); shader.setColorAttribute(glPolyColor, 4, PGL.UNSIGNED_BYTE, 0, 4 * voffset * PGL.SIZEOF_BYTE); + shader.setNormalAttribute(glPolyNormal, 3, PGL.FLOAT, 0, + 3 * voffset * PGL.SIZEOF_FLOAT); + shader.setTexcoordAttribute(glPolyTexcoord, 2, PGL.FLOAT, 0, + 2 * voffset * PGL.SIZEOF_FLOAT); if (lights) { shader.setNormalAttribute(glPolyNormal, 3, PGL.FLOAT, 0, @@ -2400,14 +2404,11 @@ public class PGraphicsOpenGL extends PGraphics { 4 * voffset * PGL.SIZEOF_BYTE); shader.setShininessAttribute(glPolyShininess, 1, PGL.FLOAT, 0, voffset * PGL.SIZEOF_FLOAT); - } else { - shader.setNormalAttribute(glPolyNormal, 3, PGL.FLOAT, 0, - 3 * voffset * PGL.SIZEOF_FLOAT); - shader.setTexcoordAttribute(glPolyTexcoord, 2, PGL.FLOAT, 0, - 2 * voffset * PGL.SIZEOF_FLOAT); - if (tex != null) shader.setTexture(tex); } + if (tex != null) { + shader.setTexture(tex); + } pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPolyIndex); pgl.drawElements(PGL.TRIANGLES, icount, PGL.INDEX_TYPE, diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index 9dcfd90cf..38e39d719 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -4463,6 +4463,10 @@ public class PShapeOpenGL extends PShape { 0, 4 * voffset * PGL.SIZEOF_FLOAT); shader.setColorAttribute(root.glPolyColor, 4, PGL.UNSIGNED_BYTE, 0, 4 * voffset * PGL.SIZEOF_BYTE); + shader.setNormalAttribute(root.glPolyNormal, 3, PGL.FLOAT, + 0, 3 * voffset * PGL.SIZEOF_FLOAT); + shader.setTexcoordAttribute(root.glPolyTexcoord, 2, PGL.FLOAT, + 0, 2 * voffset * PGL.SIZEOF_FLOAT); if (g.lights) { shader.setNormalAttribute(root.glPolyNormal, 3, PGL.FLOAT, @@ -4475,12 +4479,10 @@ public class PShapeOpenGL extends PShape { 0, 4 * voffset * PGL.SIZEOF_BYTE); shader.setShininessAttribute(root.glPolyShininess, 1, PGL.FLOAT, 0, voffset * PGL.SIZEOF_FLOAT); - } else { - shader.setNormalAttribute(root.glPolyNormal, 3, PGL.FLOAT, - 0, 3 * voffset * PGL.SIZEOF_FLOAT); - shader.setTexcoordAttribute(root.glPolyTexcoord, 2, PGL.FLOAT, - 0, 2 * voffset * PGL.SIZEOF_FLOAT); - if (tex != null) shader.setTexture(tex); + } + + if (tex != null) { + shader.setTexture(tex); } pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, root.glPolyIndex); From c90d7ce0f3d8ea99a1b3594c64a74535469c8bbd Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 5 Sep 2013 00:02:09 -0400 Subject: [PATCH 021/556] fix for indices with alternate constructor --- core/src/processing/data/IntDict.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/processing/data/IntDict.java b/core/src/processing/data/IntDict.java index 4cc3d927f..4d1aff090 100644 --- a/core/src/processing/data/IntDict.java +++ b/core/src/processing/data/IntDict.java @@ -88,6 +88,7 @@ public class IntDict { if (pieces.length == 2) { keys[count] = pieces[0]; values[count] = PApplet.parseInt(pieces[1]); + indices.put(pieces[0], count); count++; } } From e640decc81f40c6dde99066486c95466779eade3 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 5 Sep 2013 00:02:30 -0400 Subject: [PATCH 022/556] todo notes and attempting to wrap revisions --- build/shared/revisions.txt | 9 +++++++++ core/src/processing/core/PApplet.java | 4 ++-- core/todo.txt | 6 ++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/build/shared/revisions.txt b/build/shared/revisions.txt index fc4a21195..f97ebdab2 100644 --- a/build/shared/revisions.txt +++ b/build/shared/revisions.txt @@ -47,6 +47,15 @@ Several OpenGL fixes. https://github.com/processing/processing/pull/2022 https://github.com/processing/processing/issues/2021 ++ Copy doesn't produce a true copy with P2D and P3D renderers + https://github.com/processing/processing/issues/1924 + ++ Additional improvements to memory handling with images + https://github.com/processing/processing/issues/1975 + ++ PShape does not draw arc properly + https://github.com/processing/processing/issues/1990 + [ other bug fixes ] diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 2f4610242..46838ec3c 100755 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -6198,7 +6198,7 @@ public class PApplet extends Applet return new JSONArray(new StringReader(input)); } - + /** * @webref input:files * @param filename name of a file in the data folder or a URL @@ -6212,7 +6212,7 @@ public class PApplet extends Applet return new JSONArray(createReader(filename)); } - + static public JSONArray loadJSONArray(File file) { return new JSONArray(createReader(file)); } diff --git a/core/todo.txt b/core/todo.txt index de76d6a2e..6e2fcdae3 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -28,6 +28,12 @@ X Corrupted text with large font and OpenGL X https://github.com/processing/processing/issues/1869 X loadFont hangs on Processing 2.0 with any OpenGL renderer X https://github.com/processing/processing/issues/1854 +X copy doesn't produce a true copy with P2D and P3D renderers +X https://github.com/processing/processing/issues/1924 +X Additional improvements to memory handling with images +X https://github.com/processing/processing/issues/1975 +X PShape does not draw arc properly +X https://github.com/processing/processing/issues/1990 video X problem with bit shifting From 4cd280a19a510fa50b60b4fcd171d1d6c457e4eb Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 5 Sep 2013 00:34:19 -0400 Subject: [PATCH 023/556] wrapping up revisions list --- build/shared/revisions.txt | 12 +++++++++++- core/todo.txt | 8 ++++++++ todo.txt | 5 ++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/build/shared/revisions.txt b/build/shared/revisions.txt index f97ebdab2..28d937070 100644 --- a/build/shared/revisions.txt +++ b/build/shared/revisions.txt @@ -1,6 +1,6 @@ PROCESSING 2.0.3 (REV 0221) - 23 August 2013 -Several OpenGL fixes. +Lots of bug fixes. [ andres vs the volcano ] @@ -53,14 +53,24 @@ Several OpenGL fixes. + Additional improvements to memory handling with images https://github.com/processing/processing/issues/1975 ++ Additional memory handling changes for render buffers + https://github.com/processing/processing/issues/1776 + + PShape does not draw arc properly https://github.com/processing/processing/issues/1990 ++ PShape style is not restored after calling enableStyle in P2D/P3D + https://github.com/processing/processing/issues/2061 + [ other bug fixes ] + Fix options parsing on loadTable() to handle spaces. ++ PVector.angleBetween() returns 0 for 3D vectors whenever x and y are both 0 + https://github.com/processing/processing/issues/2045 + https://github.com/processing/processing/pull/2046 + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . diff --git a/core/todo.txt b/core/todo.txt index 6e2fcdae3..08570d88c 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -1,6 +1,9 @@ 0221 core X fix options parsing on loadTable() to handle spaces X add static versions of loadJSONObject and loadJSONArray that take File inputs +X PVector.angleBetween() returns 0 for 3D vectors whenever x and y are both 0 +X https://github.com/processing/processing/issues/2045 +X https://github.com/processing/processing/pull/2046 andres X blendMode() change causes OpenGL renderer to be very slow @@ -35,6 +38,11 @@ X https://github.com/processing/processing/issues/1975 X PShape does not draw arc properly X https://github.com/processing/processing/issues/1990 +X Additional memory handling changes for render buffers +X https://github.com/processing/processing/issues/1776 +X PShape style is not restored after calling enableStyle in P2D/P3D +X https://github.com/processing/processing/issues/2061 + video X problem with bit shifting X https://github.com/processing/processing/pull/2023 diff --git a/todo.txt b/todo.txt index 9312d89df..d4b1739c0 100644 --- a/todo.txt +++ b/todo.txt @@ -3,9 +3,6 @@ X add double quotes to readlink call, fixes issue w/ paths and spaces X https://github.com/processing/processing/pull/2027 X fix submitted by hamoid -_ changing modes brings the PDE back on the second screen -_ the Find window (also the save windows) also have the same problem - high _ MovieMaker needs to be compiling as 1.6 @@ -27,6 +24,8 @@ _ and doesn't just look for .Trash _ getCoreLibrary() is breaking OpenGL _ "new Library()" constructor needs to go back to private _ add .bat file to lib on windows so that we can get better debugging info +_ changing modes brings the PDE back on the second screen +_ the Find window (also the save windows) also have the same problem 7u40 switch _ change how export is handled From 71d70175a8162af327efb98f5133751b54e68757 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 5 Sep 2013 10:47:46 -0400 Subject: [PATCH 024/556] corrected typo in example comments --- java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde b/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde index 6816e5fbb..226f18275 100644 --- a/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde +++ b/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde @@ -2,7 +2,7 @@ * DomeProjection * * This sketch uses use environmental mapping to render the output - * on a full spherical come. + * on a full spherical dome. * * Based on the FullDomeTemplate code from Christopher Warnow: * https://github.com/mphasize/FullDome From ac814c326ee8772d3b537bddd08c59b33eeee0bb Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 5 Sep 2013 16:19:51 -0400 Subject: [PATCH 025/556] finalizing release notes --- build/shared/revisions.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build/shared/revisions.txt b/build/shared/revisions.txt index 28d937070..53d874efb 100644 --- a/build/shared/revisions.txt +++ b/build/shared/revisions.txt @@ -1,6 +1,7 @@ -PROCESSING 2.0.3 (REV 0221) - 23 August 2013 +PROCESSING 2.0.3 (REV 0221) - 5 September 2013 -Lots of bug fixes. +Lots of bug fixes, primarily a ton of work by Andres to improve +OpenGL rendering with P2D and P3D. [ andres vs the volcano ] From e2b9f2f552e4d198c6c7e59fa5f8d23f8b0c273e Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 5 Sep 2013 17:17:41 -0400 Subject: [PATCH 026/556] starting the next release --- app/src/processing/app/Base.java | 6 ++-- core/done.txt | 52 ++++++++++++++++++++++++++++++++ core/todo.txt | 51 +------------------------------ done.txt | 6 ++++ todo.txt | 11 ++++--- 5 files changed, 69 insertions(+), 57 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index ed3cdfa84..8a0052502 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -45,10 +45,10 @@ import processing.core.*; */ public class Base { // Added accessors for 0218 because the UpdateCheck class was not properly - // updating the values, because javac was inlining the static final values. - static private final int REVISION = 221; + // updating the values, due to javac inlining the static final values. + static private final int REVISION = 222; /** This might be replaced by main() if there's a lib/version.txt file. */ - static private String VERSION_NAME = "0221"; //$NON-NLS-1$ + static private String VERSION_NAME = "0222"; //$NON-NLS-1$ /** Set true if this a proper release rather than a numbered revision. */ // static private boolean RELEASE = false; diff --git a/core/done.txt b/core/done.txt index cb279de84..da51f76f4 100644 --- a/core/done.txt +++ b/core/done.txt @@ -1,3 +1,55 @@ +0221 core (2.0.3) +X fix options parsing on loadTable() to handle spaces +X add static versions of loadJSONObject and loadJSONArray that take File inputs +X PVector.angleBetween() returns 0 for 3D vectors whenever x and y are both 0 +X https://github.com/processing/processing/issues/2045 +X https://github.com/processing/processing/pull/2046 + +andres +X blendMode() change causes OpenGL renderer to be very slow +X https://github.com/processing/processing/issues/2021 +X serious OpenGL performance issues on OS X (fixed earlier?) +X https://github.com/processing/processing/issues/1714 +X fixed with a recent JOGL update +X P2D low quality text rendering +X https://github.com/processing/processing/issues/1972 +X Rendering artifacts on the diagonal line (topleft to bottomright) in P2D +X https://github.com/processing/processing/issues/1964 +X Fix issues with slow text rendering and OpenGL +X https://github.com/processing/processing/issues/2025 +X loadShape doesn't load OBJ files in subdirectories properly +X https://github.com/processing/processing/issues/2003 +X more OpenGL issues fixed by JOGL or newer drivers +X https://github.com/processing/processing/issues/1986 +X Vertical offset when sketch height is indivisible by 2 +X https://github.com/processing/processing/issues/1985 +X ellipse() causes RuntimeException: java.lang.OutOfMemoryError +X https://github.com/processing/processing/issues/1941 +X beginShape()..endShape() lines look wrong at joins/caps with P2D +X https://github.com/processing/processing/issues/1927 +X Corrupted text with large font and OpenGL +X https://github.com/processing/processing/issues/1869 +X loadFont hangs on Processing 2.0 with any OpenGL renderer +X https://github.com/processing/processing/issues/1854 +X copy doesn't produce a true copy with P2D and P3D renderers +X https://github.com/processing/processing/issues/1924 +X Additional improvements to memory handling with images +X https://github.com/processing/processing/issues/1975 +X PShape does not draw arc properly +X https://github.com/processing/processing/issues/1990 + +X Additional memory handling changes for render buffers +X https://github.com/processing/processing/issues/1776 +X PShape style is not restored after calling enableStyle in P2D/P3D +X https://github.com/processing/processing/issues/2061 + +video +X problem with bit shifting +X https://github.com/processing/processing/pull/2023 +X https://github.com/processing/processing/pull/2022 +X https://github.com/processing/processing/issues/2021 + + 0220 core (2.0.2) X basic getShape(ch) implementation for font glyph shapes X change QUAD_BEZIER_VERTEX to QUADRATIC_VERTEX to match the API call diff --git a/core/todo.txt b/core/todo.txt index 08570d88c..19c1f4511 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -1,53 +1,4 @@ -0221 core -X fix options parsing on loadTable() to handle spaces -X add static versions of loadJSONObject and loadJSONArray that take File inputs -X PVector.angleBetween() returns 0 for 3D vectors whenever x and y are both 0 -X https://github.com/processing/processing/issues/2045 -X https://github.com/processing/processing/pull/2046 - -andres -X blendMode() change causes OpenGL renderer to be very slow -X https://github.com/processing/processing/issues/2021 -X serious OpenGL performance issues on OS X (fixed earlier?) -X https://github.com/processing/processing/issues/1714 -X fixed with a recent JOGL update -X P2D low quality text rendering -X https://github.com/processing/processing/issues/1972 -X Rendering artifacts on the diagonal line (topleft to bottomright) in P2D -X https://github.com/processing/processing/issues/1964 -X Fix issues with slow text rendering and OpenGL -X https://github.com/processing/processing/issues/2025 -X loadShape doesn't load OBJ files in subdirectories properly -X https://github.com/processing/processing/issues/2003 -X more OpenGL issues fixed by JOGL or newer drivers -X https://github.com/processing/processing/issues/1986 -X Vertical offset when sketch height is indivisible by 2 -X https://github.com/processing/processing/issues/1985 -X ellipse() causes RuntimeException: java.lang.OutOfMemoryError -X https://github.com/processing/processing/issues/1941 -X beginShape()..endShape() lines look wrong at joins/caps with P2D -X https://github.com/processing/processing/issues/1927 -X Corrupted text with large font and OpenGL -X https://github.com/processing/processing/issues/1869 -X loadFont hangs on Processing 2.0 with any OpenGL renderer -X https://github.com/processing/processing/issues/1854 -X copy doesn't produce a true copy with P2D and P3D renderers -X https://github.com/processing/processing/issues/1924 -X Additional improvements to memory handling with images -X https://github.com/processing/processing/issues/1975 -X PShape does not draw arc properly -X https://github.com/processing/processing/issues/1990 - -X Additional memory handling changes for render buffers -X https://github.com/processing/processing/issues/1776 -X PShape style is not restored after calling enableStyle in P2D/P3D -X https://github.com/processing/processing/issues/2061 - -video -X problem with bit shifting -X https://github.com/processing/processing/pull/2023 -X https://github.com/processing/processing/pull/2022 -X https://github.com/processing/processing/issues/2021 +0222 core critical diff --git a/done.txt b/done.txt index 51ff8262d..0eba2223c 100644 --- a/done.txt +++ b/done.txt @@ -1,3 +1,9 @@ +0221 pde (2.0.3) +X add double quotes to readlink call, fixes issue w/ paths and spaces +X https://github.com/processing/processing/pull/2027 +X fix submitted by hamoid + + 0220 pde (2.0.2) X fix "less less" typo X https://github.com/processing/processing/issues/1928 diff --git a/todo.txt b/todo.txt index d4b1739c0..760ef19ec 100644 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,4 @@ -0221 pde -X add double quotes to readlink call, fixes issue w/ paths and spaces -X https://github.com/processing/processing/pull/2027 -X fix submitted by hamoid +0222 pde high @@ -45,6 +42,12 @@ _ appears to be line 138 of main.m _ maybe this is a holdover from OS X Java? _ bring back the splash screen? +no good installer, will need JDK anyway for the export +require that this folder exists: +/Library/Java/JavaVirtualMachines/jdk1.7.0_40.jdk +could also require that it's b40, but probably more trouble than it's worth +that would be 'java -version' for string 'build 1.7.0_40-b40' + direct link for download (replace .md5 with .dmg on that page) http://www.java.net/download/jdk7u40/archive/b38/binaries/jre-7u40-ea-bin-b38-macosx-x86_64-07_aug_2013.dmg http://www.java.net/download/jdk7u40/archive/b40/binaries/jre-7u40-fcs-bin-b40-macosx-x86_64-16_aug_2013.dmg From 764616c9e1bda65666d748b83a9e5328cfc264ae Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sun, 8 Sep 2013 14:07:47 -0400 Subject: [PATCH 027/556] starting the refactoring of PGL --- core/src/processing/opengl/PGL.java | 33 +- .../processing/opengl/PGraphicsOpenGL.java | 15 +- .../src/processing/lwjgl/PGraphics2D.java | 22 - .../src/processing/lwjgl/PGraphics3D.java | 22 - .../src/processing/lwjgl/PGraphicsLWJGL.java | 26 +- .../lwjgl/{PGL.java => PLWJGL.java} | 1434 ++++++++++------- 6 files changed, 875 insertions(+), 677 deletions(-) delete mode 100644 java/libraries/lwjgl/src/processing/lwjgl/PGraphics2D.java delete mode 100644 java/libraries/lwjgl/src/processing/lwjgl/PGraphics3D.java rename java/libraries/lwjgl/src/processing/lwjgl/{PGL.java => PLWJGL.java} (75%) diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index 3a9d255e6..417814c40 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -2969,6 +2969,7 @@ public class PGL { public static final int VERTEX_ATTRIB_ARRAY_STRIDE = GL2.GL_VERTEX_ATTRIB_ARRAY_STRIDE; public static final int VERTEX_ATTRIB_ARRAY_TYPE = GL2.GL_VERTEX_ATTRIB_ARRAY_TYPE; public static final int VERTEX_ATTRIB_ARRAY_NORMALIZED = GL2.GL_VERTEX_ATTRIB_ARRAY_NORMALIZED; + public static final int VERTEX_ATTRIB_ARRAY_POINTER = GL2.GL_VERTEX_ATTRIB_ARRAY_POINTER; public static final int BLEND = GL.GL_BLEND; public static final int ONE = GL.GL_ONE; @@ -3226,15 +3227,11 @@ public class PGL { // Reading Pixels public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer) { - boolean needBeginOp = format != STENCIL_INDEX && - format != DEPTH_COMPONENT && format != DEPTH_STENCIL; - if (needBeginOp) { - PGraphicsOpenGL.pgCurrent.beginPixelsOp(PGraphicsOpenGL.OP_READ); - } + boolean needEndBegin = format != STENCIL_INDEX && + format != DEPTH_COMPONENT && format != DEPTH_STENCIL; + if (needEndBegin) pg.beginReadPixels(); readPixelsImpl(x, y, width, height, format, type, buffer); - if (needBeginOp) { - PGraphicsOpenGL.pgCurrent.endPixelsOp(); - } + if (needEndBegin) pg.endReadPixels(); } protected void readPixelsImpl(int x, int y, int width, int height, int format, int type, Buffer buffer) { @@ -3477,13 +3474,14 @@ public class PGL { gl2.glDeleteProgram(program); } - public void getActiveAttrib(int program, int index, int[] size, int[] type, String[] name) { + public String glGetActiveAttrib (int program, int index, IntBuffer size, IntBuffer type) { int[] tmp = {0, 0, 0}; byte[] namebuf = new byte[1024]; gl2.glGetActiveAttrib(program, index, 1024, tmp, 0, tmp, 1, tmp, 2, namebuf, 0); - if (size != null && size.length != 0) size[0] = tmp[1]; - if (type != null && type.length != 0) type[0] = tmp[2]; - if (name != null && name.length != 0) name[0] = new String(namebuf, 0, tmp[0]); + size.put(tmp[1]); + type.put(tmp[2]); + String name = new String(namebuf, 0, tmp[0]); + return name; } public int getAttribLocation(int program, String name) { @@ -3498,13 +3496,14 @@ public class PGL { return gl2.glGetUniformLocation(program, name); } - public void getActiveUniform(int program, int index, int[] size,int[] type, String[] name) { + public String getActiveUniform(int program, int index, IntBuffer size, IntBuffer type) { int[] tmp= {0, 0, 0}; byte[] namebuf = new byte[1024]; gl2.glGetActiveUniform(program, index, 1024, tmp, 0, tmp, 1, tmp, 2, namebuf, 0); - if (size != null && size.length != 0) size[0] = tmp[1]; - if (type != null && type.length != 0) type[0] = tmp[2]; - if (name != null && name.length != 0) name[0] = new String(namebuf, 0, tmp[0]); + size.put(tmp[1]); + type.put(tmp[2]); + String name = new String(namebuf, 0, tmp[0]); + return name; } public void uniform1i(int location, int value) { @@ -3628,7 +3627,7 @@ public class PGL { gl2.glGetVertexAttribiv(index, pname, params); } - public void getVertexAttribPointerv() { + public void getVertexAttribPointerv(int index, int pname, ByteBuffer data) { throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glGetVertexAttribPointerv()")); } diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 3db04c14c..efb436ad8 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -532,7 +532,7 @@ public class PGraphicsOpenGL extends PGraphics { public PGraphicsOpenGL() { if (pgl == null) { - pgl = new PGL(this); + pgl = createPGL(this); } if (tessellator == null) { @@ -1699,6 +1699,12 @@ public class PGraphicsOpenGL extends PGraphics { } + // Factory method + static public PGL createPGL(PGraphicsOpenGL pg) { + return new PGL(pg); + } + + @Override public PGL beginPGL() { flush(); @@ -1768,6 +1774,13 @@ public class PGraphicsOpenGL extends PGraphics { pgl.drawBuffer(currentFramebuffer.getDefaultDrawBuffer()); } + public void beginReadPixels() { + pgCurrent.beginPixelsOp(OP_READ); + } + + public void endReadPixels() { + pgCurrent.endPixelsOp(); + } protected void beginPixelsOp(int op) { FrameBuffer pixfb = null; diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGraphics2D.java b/java/libraries/lwjgl/src/processing/lwjgl/PGraphics2D.java deleted file mode 100644 index d1f41c691..000000000 --- a/java/libraries/lwjgl/src/processing/lwjgl/PGraphics2D.java +++ /dev/null @@ -1,22 +0,0 @@ -package processing.lwjgl; - -public class PGraphics2D extends processing.opengl.PGraphics2D { - - public PGraphics2D() { - pgl = new PGL(this); - - if (tessellator == null) { - tessellator = new Tessellator(); - } - - intBuffer = PGL.allocateIntBuffer(2); - floatBuffer = PGL.allocateFloatBuffer(2); - viewport = PGL.allocateIntBuffer(4); - - inGeo = newInGeometry(IMMEDIATE); - tessGeo = newTessGeometry(IMMEDIATE); - texCache = newTexCache(); - - initialized = false; - } -} diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGraphics3D.java b/java/libraries/lwjgl/src/processing/lwjgl/PGraphics3D.java deleted file mode 100644 index 6efd89237..000000000 --- a/java/libraries/lwjgl/src/processing/lwjgl/PGraphics3D.java +++ /dev/null @@ -1,22 +0,0 @@ -package processing.lwjgl; - -public class PGraphics3D extends processing.opengl.PGraphics3D { - - public PGraphics3D() { - pgl = new PGL(this); - - if (tessellator == null) { - tessellator = new Tessellator(); - } - - intBuffer = PGL.allocateIntBuffer(2); - floatBuffer = PGL.allocateFloatBuffer(2); - viewport = PGL.allocateIntBuffer(4); - - inGeo = newInGeometry(IMMEDIATE); - tessGeo = newTessGeometry(IMMEDIATE); - texCache = newTexCache(); - - initialized = false; - } -} diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java index 8c79ec133..baf0f1f0e 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java @@ -22,6 +22,7 @@ package processing.lwjgl; +import processing.opengl.PGL; import processing.opengl.PGraphicsOpenGL; /** @@ -29,27 +30,8 @@ import processing.opengl.PGraphicsOpenGL; * */ public class PGraphicsLWJGL extends PGraphicsOpenGL { - - ////////////////////////////////////////////////////////////// - - // INIT/ALLOCATE/FINISH - - - public PGraphicsLWJGL() { - pgl = new PGL(this); - - if (tessellator == null) { - tessellator = new Tessellator(); - } - - intBuffer = PGL.allocateIntBuffer(2); - floatBuffer = PGL.allocateFloatBuffer(2); - viewport = PGL.allocateIntBuffer(4); - - inGeo = newInGeometry(IMMEDIATE); - tessGeo = newTessGeometry(IMMEDIATE); - texCache = newTexCache(); - - initialized = false; + + static public PGL createPGL(PGraphicsOpenGL pg) { + return new PLWJGL(pg); } } diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java similarity index 75% rename from java/libraries/lwjgl/src/processing/lwjgl/PGL.java rename to java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java index f42c1e754..f1d63d138 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java @@ -39,6 +39,7 @@ import org.lwjgl.BufferUtils; import org.lwjgl.LWJGLException; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.ARBES2Compatibility; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.DisplayMode; import org.lwjgl.opengl.EXTFramebufferObject; @@ -61,6 +62,7 @@ import processing.core.PConstants; import processing.event.Event; import processing.event.KeyEvent; import processing.event.MouseEvent; +import processing.opengl.PGL; import processing.opengl.PGraphicsOpenGL; import processing.opengl.Texture; @@ -76,7 +78,7 @@ import processing.opengl.Texture; * */ @SuppressWarnings("static-access") -public class PGL extends processing.opengl.PGL { +public class PLWJGL extends PGL { /////////////////////////////////////////////////////////// // Public members to access the underlying GL objects and context @@ -206,8 +208,10 @@ public class PGL extends processing.opengl.PGL { /** Which texturing targets are enabled */ protected static boolean[] texturingTargets = { false, false }; - /** Which textures are bound to each target */ - protected static int[] boundTextures = { 0, 0 }; + /** Used to keep track of which textures are bound to each target */ + protected static int maxTexUnits; + protected static int activeTexUnit = 0; + protected static int[][] boundTextures; /////////////////////////////////////////////////////////// @@ -316,7 +320,7 @@ public class PGL extends processing.opengl.PGL { // Initialization, finalization - public PGL(PGraphicsOpenGL pg) { + public PLWJGL(PGraphicsOpenGL pg) { this.pg = pg; if (glu == null) { glu = new GLU(); @@ -1023,13 +1027,16 @@ public class PGL extends processing.opengl.PGL { protected boolean textureIsBound(int target, int id) { + if (boundTextures == null) return false; + if (target == TEXTURE_2D) { - return boundTextures[0] == id; + return boundTextures[activeTexUnit][0] == id; } else if (target == TEXTURE_RECTANGLE) { - return boundTextures[1] == id; + return boundTextures[activeTexUnit][1] == id; } else { return false; } + } @@ -1042,7 +1049,7 @@ public class PGL extends processing.opengl.PGL { int initColor) { int[] glcolor = new int[16 * 16]; Arrays.fill(glcolor, javaToNativeARGB(initColor)); - IntBuffer texels = PGL.allocateDirectIntBuffer(16 * 16); + IntBuffer texels = PLWJGL.allocateDirectIntBuffer(16 * 16); texels.put(glcolor); texels.rewind(); for (int y = 0; y < height; y += 16) { @@ -1784,7 +1791,7 @@ public class PGL extends processing.opengl.PGL { protected static ByteBuffer allocateByteBuffer(byte[] arr) { if (USE_DIRECT_BUFFERS) { - return PGL.allocateDirectByteBuffer(arr.length); + return PLWJGL.allocateDirectByteBuffer(arr.length); } else { return ByteBuffer.wrap(arr); } @@ -1795,7 +1802,7 @@ public class PGL extends processing.opengl.PGL { boolean wrap) { if (USE_DIRECT_BUFFERS) { if (buf == null || buf.capacity() < arr.length) { - buf = PGL.allocateDirectByteBuffer(arr.length); + buf = PLWJGL.allocateDirectByteBuffer(arr.length); } buf.position(0); buf.put(arr); @@ -1863,7 +1870,7 @@ public class PGL extends processing.opengl.PGL { protected static ShortBuffer allocateShortBuffer(short[] arr) { if (USE_DIRECT_BUFFERS) { - return PGL.allocateDirectShortBuffer(arr.length); + return PLWJGL.allocateDirectShortBuffer(arr.length); } else { return ShortBuffer.wrap(arr); } @@ -1874,7 +1881,7 @@ public class PGL extends processing.opengl.PGL { boolean wrap) { if (USE_DIRECT_BUFFERS) { if (buf == null || buf.capacity() < arr.length) { - buf = PGL.allocateDirectShortBuffer(arr.length); + buf = PLWJGL.allocateDirectShortBuffer(arr.length); } buf.position(0); buf.put(arr); @@ -1942,7 +1949,7 @@ public class PGL extends processing.opengl.PGL { protected static IntBuffer allocateIntBuffer(int[] arr) { if (USE_DIRECT_BUFFERS) { - return PGL.allocateDirectIntBuffer(arr.length); + return PLWJGL.allocateDirectIntBuffer(arr.length); } else { return IntBuffer.wrap(arr); } @@ -1953,7 +1960,7 @@ public class PGL extends processing.opengl.PGL { boolean wrap) { if (USE_DIRECT_BUFFERS) { if (buf == null || buf.capacity() < arr.length) { - buf = PGL.allocateDirectIntBuffer(arr.length); + buf = PLWJGL.allocateDirectIntBuffer(arr.length); } buf.position(0); buf.put(arr); @@ -2020,7 +2027,7 @@ public class PGL extends processing.opengl.PGL { protected static FloatBuffer allocateFloatBuffer(float[] arr) { if (USE_DIRECT_BUFFERS) { - return PGL.allocateDirectFloatBuffer(arr.length); + return PLWJGL.allocateDirectFloatBuffer(arr.length); } else { return FloatBuffer.wrap(arr); } @@ -2031,7 +2038,7 @@ public class PGL extends processing.opengl.PGL { boolean wrap) { if (USE_DIRECT_BUFFERS) { if (buf == null || buf.capacity() < arr.length) { - buf = PGL.allocateDirectFloatBuffer(arr.length); + buf = PLWJGL.allocateDirectFloatBuffer(arr.length); } buf.position(0); buf.put(arr); @@ -2523,70 +2530,262 @@ public class PGL extends processing.opengl.PGL { - // OPENGL API: Still need to add all the missing functions to expose the entire - // GLES 2.0 API - + ////////////////////////////////////////////////////////////////////////////// + // + // OpenGL ES 2.0 API, with a few additional functions for multisampling and + // and buffer mapping from OpenGL 2.1+. + // + // The functions are organized following the groups in the GLES 2.0 reference + // card: + // http://www.khronos.org/opengles/sdk/docs/reference_cards/OpenGL-ES-2_0-Reference-card.pdf + // + // The entire GLES 2.0 specification is available below: + // http://www.khronos.org/opengles/2_X/ + // + ////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////// - // OpenGL constants + // Constants public static final int FALSE = GL11.GL_FALSE; public static final int TRUE = GL11.GL_TRUE; - public static final int LESS = GL11.GL_LESS; - public static final int LEQUAL = GL11.GL_LEQUAL; + public static final int INT = GL11.GL_INT; + public static final int BYTE = GL11.GL_BYTE; + public static final int SHORT = GL11.GL_SHORT; + public static final int FLOAT = GL11.GL_FLOAT; + public static final int BOOL = GL20.GL_BOOL; + public static final int UNSIGNED_INT = GL11.GL_UNSIGNED_INT; + public static final int UNSIGNED_BYTE = GL11.GL_UNSIGNED_BYTE; + public static final int UNSIGNED_SHORT = GL11.GL_UNSIGNED_SHORT; - public static final int CCW = GL11.GL_CCW; - public static final int CW = GL11.GL_CW; + public static final int RGB = GL11.GL_RGB; + public static final int RGBA = GL11.GL_RGBA; + public static final int ALPHA = GL11.GL_ALPHA; + public static final int LUMINANCE = GL11.GL_LUMINANCE; + public static final int LUMINANCE_ALPHA = GL11.GL_LUMINANCE_ALPHA; + + public static final int UNSIGNED_SHORT_5_6_5 = GL12.GL_UNSIGNED_SHORT_5_6_5; + public static final int UNSIGNED_SHORT_4_4_4_4 = GL12.GL_UNSIGNED_SHORT_4_4_4_4; + public static final int UNSIGNED_SHORT_5_5_5_1 = GL12.GL_UNSIGNED_SHORT_5_5_5_1; + + public static final int RGBA4 = GL11.GL_RGBA4; + public static final int RGB5_A1 = GL11.GL_RGB5_A1; + public static final int RGB565 = ARBES2Compatibility.GL_RGB565; + + public static final int READ_ONLY = GL15.GL_READ_ONLY; + public static final int WRITE_ONLY = GL15.GL_WRITE_ONLY; + public static final int READ_WRITE = GL15.GL_READ_WRITE; + + public static final int TESS_WINDING_NONZERO = GLU.GLU_TESS_WINDING_NONZERO; + public static final int TESS_WINDING_ODD = GLU.GLU_TESS_WINDING_ODD; + + public static final int GENERATE_MIPMAP_HINT = GL14.GL_GENERATE_MIPMAP_HINT; + public static final int FASTEST = GL11.GL_FASTEST; + public static final int NICEST = GL11.GL_NICEST; + public static final int DONT_CARE = GL11.GL_DONT_CARE; + + public static final int VENDOR = GL11.GL_VENDOR; + public static final int RENDERER = GL11.GL_RENDERER; + public static final int VERSION = GL11.GL_VERSION; + public static final int EXTENSIONS = GL11.GL_EXTENSIONS; + public static final int SHADING_LANGUAGE_VERSION = GL20.GL_SHADING_LANGUAGE_VERSION; + + public static final int MAX_SAMPLES = GL30.GL_MAX_SAMPLES; + public static final int SAMPLES = GL13.GL_SAMPLES; + + public static final int ALIASED_LINE_WIDTH_RANGE = GL12.GL_ALIASED_LINE_WIDTH_RANGE; + public static final int ALIASED_POINT_SIZE_RANGE = GL12.GL_ALIASED_POINT_SIZE_RANGE; + + public static final int DEPTH_BITS = GL11.GL_DEPTH_BITS; + public static final int STENCIL_BITS = GL11.GL_STENCIL_BITS; + + public static final int CCW = GL11.GL_CCW; + public static final int CW = GL11.GL_CW; + + public static final int VIEWPORT = GL11.GL_VIEWPORT; + + public static final int ARRAY_BUFFER = GL15.GL_ARRAY_BUFFER; + public static final int ELEMENT_ARRAY_BUFFER = GL15.GL_ELEMENT_ARRAY_BUFFER; + + public static final int MAX_VERTEX_ATTRIBS = GL20.GL_MAX_VERTEX_ATTRIBS; + + public static final int STATIC_DRAW = GL15.GL_STATIC_DRAW; + public static final int DYNAMIC_DRAW = GL15.GL_DYNAMIC_DRAW; + public static final int STREAM_DRAW = GL15.GL_STREAM_DRAW; + + public static final int BUFFER_SIZE = GL15.GL_BUFFER_SIZE; + public static final int BUFFER_USAGE = GL15.GL_BUFFER_USAGE; + + public static final int POINTS = GL11.GL_POINTS; + public static final int LINE_STRIP = GL11.GL_LINE_STRIP; + public static final int LINE_LOOP = GL11.GL_LINE_LOOP; + public static final int LINES = GL11.GL_LINES; + public static final int TRIANGLE_FAN = GL11.GL_TRIANGLE_FAN; + public static final int TRIANGLE_STRIP = GL11.GL_TRIANGLE_STRIP; + public static final int TRIANGLES = GL11.GL_TRIANGLES; public static final int CULL_FACE = GL11.GL_CULL_FACE; public static final int FRONT = GL11.GL_FRONT; public static final int BACK = GL11.GL_BACK; public static final int FRONT_AND_BACK = GL11.GL_FRONT_AND_BACK; - public static final int VIEWPORT = GL11.GL_VIEWPORT; + public static final int POLYGON_OFFSET_FILL = GL11.GL_POLYGON_OFFSET_FILL; - public static final int SCISSOR_TEST = GL11.GL_SCISSOR_TEST; - public static final int DEPTH_TEST = GL11.GL_DEPTH_TEST; - public static final int DEPTH_WRITEMASK = GL11.GL_DEPTH_WRITEMASK; - - public static final int COLOR_BUFFER_BIT = GL11.GL_COLOR_BUFFER_BIT; - public static final int DEPTH_BUFFER_BIT = GL11.GL_DEPTH_BUFFER_BIT; - public static final int STENCIL_BUFFER_BIT = GL11.GL_STENCIL_BUFFER_BIT; - - public static final int FUNC_ADD = GL14.GL_FUNC_ADD; - public static final int FUNC_MIN = GL14.GL_MIN; - public static final int FUNC_MAX = GL14.GL_MAX; - public static final int FUNC_REVERSE_SUBTRACT = GL14.GL_FUNC_REVERSE_SUBTRACT; + public static final int UNPACK_ALIGNMENT = GL11.GL_UNPACK_ALIGNMENT; + public static final int PACK_ALIGNMENT = GL11.GL_PACK_ALIGNMENT; public static final int TEXTURE_2D = GL11.GL_TEXTURE_2D; public static final int TEXTURE_RECTANGLE = GL31.GL_TEXTURE_RECTANGLE; public static final int TEXTURE_BINDING_2D = GL11.GL_TEXTURE_BINDING_2D; - public static final int TEXTURE_BINDING_RECTANGLE = - GL31.GL_TEXTURE_BINDING_RECTANGLE; + public static final int TEXTURE_BINDING_RECTANGLE = GL31.GL_TEXTURE_BINDING_RECTANGLE; - public static final int RGB = GL11.GL_RGB; - public static final int RGBA = GL11.GL_RGBA; - public static final int ALPHA = GL11.GL_ALPHA; - public static final int UNSIGNED_INT = GL11.GL_UNSIGNED_INT; - public static final int UNSIGNED_BYTE = GL11.GL_UNSIGNED_BYTE; - public static final int UNSIGNED_SHORT = GL11.GL_UNSIGNED_SHORT; - public static final int FLOAT = GL11.GL_FLOAT; + public static final int MAX_TEXTURE_SIZE = GL11.GL_MAX_TEXTURE_SIZE; + public static final int TEXTURE_MAX_ANISOTROPY = EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT; + public static final int MAX_TEXTURE_MAX_ANISOTROPY = EXTTextureFilterAnisotropic.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT; + + public static final int MAX_VERTEX_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS; + public static final int MAX_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_TEXTURE_IMAGE_UNITS; + public static final int MAX_COMBINED_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS; + + public static final int NUM_COMPRESSED_TEXTURE_FORMATS = GL13.GL_NUM_COMPRESSED_TEXTURE_FORMATS; + public static final int COMPRESSED_TEXTURE_FORMATS = GL13.GL_COMPRESSED_TEXTURE_FORMATS; public static final int NEAREST = GL11.GL_NEAREST; public static final int LINEAR = GL11.GL_LINEAR; public static final int LINEAR_MIPMAP_NEAREST = GL11.GL_LINEAR_MIPMAP_NEAREST; public static final int LINEAR_MIPMAP_LINEAR = GL11.GL_LINEAR_MIPMAP_LINEAR; - public static final int TEXTURE_MAX_ANISOTROPY = - EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT; - public static final int MAX_TEXTURE_MAX_ANISOTROPY = - EXTTextureFilterAnisotropic.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT; - public static final int CLAMP_TO_EDGE = GL12.GL_CLAMP_TO_EDGE; public static final int REPEAT = GL11.GL_REPEAT; + public static final int TEXTURE0 = GL13.GL_TEXTURE0; + public static final int TEXTURE1 = GL13.GL_TEXTURE1; + public static final int TEXTURE2 = GL13.GL_TEXTURE2; + public static final int TEXTURE3 = GL13.GL_TEXTURE3; + public static final int TEXTURE_MIN_FILTER = GL11.GL_TEXTURE_MIN_FILTER; + public static final int TEXTURE_MAG_FILTER = GL11.GL_TEXTURE_MAG_FILTER; + public static final int TEXTURE_WRAP_S = GL11.GL_TEXTURE_WRAP_S; + public static final int TEXTURE_WRAP_T = GL11.GL_TEXTURE_WRAP_T; + public static final int TEXTURE_WRAP_R = GL12.GL_TEXTURE_WRAP_R; + + public static final int TEXTURE_CUBE_MAP = GL13.GL_TEXTURE_CUBE_MAP; + public static final int TEXTURE_CUBE_MAP_POSITIVE_X = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X; + public static final int TEXTURE_CUBE_MAP_POSITIVE_Y = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; + public static final int TEXTURE_CUBE_MAP_POSITIVE_Z = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; + public static final int TEXTURE_CUBE_MAP_NEGATIVE_X = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; + public static final int TEXTURE_CUBE_MAP_NEGATIVE_Y = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; + public static final int TEXTURE_CUBE_MAP_NEGATIVE_Z = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; + + public static final int VERTEX_SHADER = GL20.GL_VERTEX_SHADER; + public static final int FRAGMENT_SHADER = GL20.GL_FRAGMENT_SHADER; + public static final int INFO_LOG_LENGTH = GL20.GL_INFO_LOG_LENGTH; + public static final int SHADER_SOURCE_LENGTH = GL20.GL_SHADER_SOURCE_LENGTH; + public static final int COMPILE_STATUS = GL20.GL_COMPILE_STATUS; + public static final int LINK_STATUS = GL20.GL_LINK_STATUS; + public static final int VALIDATE_STATUS = GL20.GL_VALIDATE_STATUS; + public static final int SHADER_TYPE = GL20.GL_SHADER_TYPE; + public static final int DELETE_STATUS = GL20.GL_DELETE_STATUS; + + public static final int FLOAT_VEC2 = GL20.GL_FLOAT_VEC2; + public static final int FLOAT_VEC3 = GL20.GL_FLOAT_VEC3; + public static final int FLOAT_VEC4 = GL20.GL_FLOAT_VEC4; + public static final int FLOAT_MAT2 = GL20.GL_FLOAT_MAT2; + public static final int FLOAT_MAT3 = GL20.GL_FLOAT_MAT3; + public static final int FLOAT_MAT4 = GL20.GL_FLOAT_MAT4; + public static final int INT_VEC2 = GL20.GL_INT_VEC2; + public static final int INT_VEC3 = GL20.GL_INT_VEC3; + public static final int INT_VEC4 = GL20.GL_INT_VEC4; + public static final int BOOL_VEC2 = GL20.GL_BOOL_VEC2; + public static final int BOOL_VEC3 = GL20.GL_BOOL_VEC3; + public static final int BOOL_VEC4 = GL20.GL_BOOL_VEC4; + public static final int SAMPLER_2D = GL20.GL_SAMPLER_2D; + public static final int SAMPLER_CUBE = GL20.GL_SAMPLER_CUBE; + + public static final int LOW_FLOAT = ARBES2Compatibility.GL_LOW_FLOAT; + public static final int MEDIUM_FLOAT = ARBES2Compatibility.GL_MEDIUM_FLOAT; + public static final int HIGH_FLOAT = ARBES2Compatibility.GL_HIGH_FLOAT; + public static final int LOW_INT = ARBES2Compatibility.GL_LOW_INT; + public static final int MEDIUM_INT = ARBES2Compatibility.GL_MEDIUM_INT; + public static final int HIGH_INT = ARBES2Compatibility.GL_HIGH_INT; + + public static final int CURRENT_VERTEX_ATTRIB = GL20.GL_CURRENT_VERTEX_ATTRIB; + + public static final int VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = GL15.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING; + public static final int VERTEX_ATTRIB_ARRAY_ENABLED = GL20.GL_VERTEX_ATTRIB_ARRAY_ENABLED; + public static final int VERTEX_ATTRIB_ARRAY_SIZE = GL20.GL_VERTEX_ATTRIB_ARRAY_SIZE; + public static final int VERTEX_ATTRIB_ARRAY_STRIDE = GL20.GL_VERTEX_ATTRIB_ARRAY_STRIDE; + public static final int VERTEX_ATTRIB_ARRAY_TYPE = GL20.GL_VERTEX_ATTRIB_ARRAY_TYPE; + public static final int VERTEX_ATTRIB_ARRAY_NORMALIZED = GL20.GL_VERTEX_ATTRIB_ARRAY_NORMALIZED; + public static final int VERTEX_ATTRIB_ARRAY_POINTER = GL20.GL_VERTEX_ATTRIB_ARRAY_POINTER; + + public static final int BLEND = GL11.GL_BLEND; + public static final int ONE = GL11.GL_ONE; + public static final int ZERO = GL11.GL_ZERO; + public static final int SRC_ALPHA = GL11.GL_SRC_ALPHA; + public static final int DST_ALPHA = GL11.GL_DST_ALPHA; + public static final int ONE_MINUS_SRC_ALPHA = GL11.GL_ONE_MINUS_SRC_ALPHA; + public static final int ONE_MINUS_DST_COLOR = GL11.GL_ONE_MINUS_DST_COLOR; + public static final int ONE_MINUS_SRC_COLOR = GL11.GL_ONE_MINUS_SRC_COLOR; + public static final int DST_COLOR = GL11.GL_DST_COLOR; + public static final int SRC_COLOR = GL11.GL_SRC_COLOR; + + public static final int SAMPLE_ALPHA_TO_COVERAGE = GL13.GL_SAMPLE_ALPHA_TO_COVERAGE; + public static final int SAMPLE_COVERAGE = GL13.GL_SAMPLE_COVERAGE; + + public static final int KEEP = GL11.GL_KEEP; + public static final int REPLACE = GL11.GL_REPLACE; + public static final int INCR = GL11.GL_INCR; + public static final int DECR = GL11.GL_DECR; + public static final int INVERT = GL11.GL_INVERT; + public static final int INCR_WRAP = GL14.GL_INCR_WRAP; + public static final int DECR_WRAP = GL14.GL_DECR_WRAP; + public static final int NEVER = GL11.GL_NEVER; + public static final int ALWAYS = GL11.GL_ALWAYS; + + public static final int EQUAL = GL11.GL_EQUAL; + public static final int LESS = GL11.GL_LESS; + public static final int LEQUAL = GL11.GL_LEQUAL; + public static final int GREATER = GL11.GL_GREATER; + public static final int GEQUAL = GL11.GL_GEQUAL; + public static final int NOTEQUAL = GL11.GL_NOTEQUAL; + + public static final int FUNC_ADD = GL14.GL_FUNC_ADD; + public static final int FUNC_MIN = GL14.GL_MIN; + public static final int FUNC_MAX = GL14.GL_MAX; + public static final int FUNC_REVERSE_SUBTRACT = GL14.GL_FUNC_REVERSE_SUBTRACT; + public static final int FUNC_SUBTRACT = GL14.GL_FUNC_SUBTRACT; + + public static final int DITHER = GL11.GL_DITHER; + + public static final int CONSTANT_COLOR = GL11.GL_CONSTANT_COLOR; + public static final int CONSTANT_ALPHA = GL11.GL_CONSTANT_ALPHA; + public static final int ONE_MINUS_CONSTANT_COLOR = GL11.GL_ONE_MINUS_CONSTANT_COLOR; + public static final int ONE_MINUS_CONSTANT_ALPHA = GL11.GL_ONE_MINUS_CONSTANT_ALPHA; + public static final int SRC_ALPHA_SATURATE = GL11.GL_SRC_ALPHA_SATURATE; + + public static final int SCISSOR_TEST = GL11.GL_SCISSOR_TEST; + public static final int DEPTH_TEST = GL11.GL_DEPTH_TEST; + public static final int DEPTH_WRITEMASK = GL11.GL_DEPTH_WRITEMASK; + public static final int ALPHA_TEST = GL11.GL_ALPHA_TEST; + + public static final int COLOR_BUFFER_BIT = GL11.GL_COLOR_BUFFER_BIT; + public static final int DEPTH_BUFFER_BIT = GL11.GL_DEPTH_BUFFER_BIT; + public static final int STENCIL_BUFFER_BIT = GL11.GL_STENCIL_BUFFER_BIT; + + public static final int FRAMEBUFFER = GL30.GL_FRAMEBUFFER; + public static final int COLOR_ATTACHMENT0 = GL30.GL_COLOR_ATTACHMENT0; + public static final int COLOR_ATTACHMENT1 = GL30.GL_COLOR_ATTACHMENT1; + public static final int COLOR_ATTACHMENT2 = GL30.GL_COLOR_ATTACHMENT2; + public static final int COLOR_ATTACHMENT3 = GL30.GL_COLOR_ATTACHMENT3; + public static final int RENDERBUFFER = GL30.GL_RENDERBUFFER; + public static final int DEPTH_ATTACHMENT = GL30.GL_DEPTH_ATTACHMENT; + public static final int STENCIL_ATTACHMENT = GL30.GL_STENCIL_ATTACHMENT; + public static final int READ_FRAMEBUFFER = GL30.GL_READ_FRAMEBUFFER; + public static final int DRAW_FRAMEBUFFER = GL30.GL_DRAW_FRAMEBUFFER; + public static final int RGBA8 = GL11.GL_RGBA8; public static final int DEPTH24_STENCIL8 = GL30.GL_DEPTH24_STENCIL8; @@ -2600,97 +2799,31 @@ public class PGL extends processing.opengl.PGL { public static final int STENCIL_INDEX4 = GL30.GL_STENCIL_INDEX4; public static final int STENCIL_INDEX8 = GL30.GL_STENCIL_INDEX8; - public static final int ARRAY_BUFFER = GL15.GL_ARRAY_BUFFER; - public static final int ELEMENT_ARRAY_BUFFER = GL15.GL_ELEMENT_ARRAY_BUFFER; + public static final int DEPTH_STENCIL = GL30.GL_DEPTH_STENCIL; - public static final int SAMPLES = GL13.GL_SAMPLES; + public static final int FRAMEBUFFER_COMPLETE = GL30.GL_FRAMEBUFFER_COMPLETE; + public static final int FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL30.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + public static final int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL30.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + public static final int FRAMEBUFFER_INCOMPLETE_DIMENSIONS = EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; + public static final int FRAMEBUFFER_INCOMPLETE_FORMATS = EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; + public static final int FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = GL30.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER; + public static final int FRAMEBUFFER_INCOMPLETE_READ_BUFFER = GL30.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER; + public static final int FRAMEBUFFER_UNSUPPORTED = GL30.GL_FRAMEBUFFER_UNSUPPORTED; - public static final int FRAMEBUFFER_COMPLETE = - GL30.GL_FRAMEBUFFER_COMPLETE; - public static final int FRAMEBUFFER_INCOMPLETE_ATTACHMENT = - GL30.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - public static final int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = - GL30.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; - public static final int FRAMEBUFFER_INCOMPLETE_DIMENSIONS = - EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; - public static final int FRAMEBUFFER_INCOMPLETE_FORMATS = - EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; - public static final int FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = - GL30.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER; - public static final int FRAMEBUFFER_INCOMPLETE_READ_BUFFER = - GL30.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER; - public static final int FRAMEBUFFER_UNSUPPORTED = - GL30.GL_FRAMEBUFFER_UNSUPPORTED; + public static final int FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE; + public static final int FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME; + public static final int FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = GL30.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL; + public static final int FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = GL30.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE; - public static final int STATIC_DRAW = GL15.GL_STATIC_DRAW; - public static final int DYNAMIC_DRAW = GL15.GL_DYNAMIC_DRAW; - public static final int STREAM_DRAW = GL15.GL_STREAM_DRAW; - - public static final int READ_ONLY = GL15.GL_READ_ONLY; - public static final int WRITE_ONLY = GL15.GL_WRITE_ONLY; - public static final int READ_WRITE = GL15.GL_READ_WRITE; - - public static final int TRIANGLE_FAN = GL11.GL_TRIANGLE_FAN; - public static final int TRIANGLE_STRIP = GL11.GL_TRIANGLE_STRIP; - public static final int TRIANGLES = GL11.GL_TRIANGLES; - - public static final int VENDOR = GL11.GL_VENDOR; - public static final int RENDERER = GL11.GL_RENDERER; - public static final int VERSION = GL11.GL_VERSION; - public static final int EXTENSIONS = GL11.GL_EXTENSIONS; - public static final int SHADING_LANGUAGE_VERSION = - GL20.GL_SHADING_LANGUAGE_VERSION; - - public static final int MAX_TEXTURE_SIZE = GL11.GL_MAX_TEXTURE_SIZE; - public static final int MAX_SAMPLES = GL30.GL_MAX_SAMPLES; - public static final int ALIASED_LINE_WIDTH_RANGE = - GL12.GL_ALIASED_LINE_WIDTH_RANGE; - public static final int ALIASED_POINT_SIZE_RANGE = - GL12.GL_ALIASED_POINT_SIZE_RANGE; - public static final int DEPTH_BITS = GL11.GL_DEPTH_BITS; - public static final int STENCIL_BITS = GL11.GL_STENCIL_BITS; - - public static final int TESS_WINDING_NONZERO = GLU.GLU_TESS_WINDING_NONZERO; - public static final int TESS_WINDING_ODD = GLU.GLU_TESS_WINDING_ODD; - - public static final int TEXTURE0 = GL13.GL_TEXTURE0; - public static final int TEXTURE1 = GL13.GL_TEXTURE1; - public static final int TEXTURE2 = GL13.GL_TEXTURE2; - public static final int TEXTURE3 = GL13.GL_TEXTURE3; - public static final int TEXTURE_MIN_FILTER = GL11.GL_TEXTURE_MIN_FILTER; - public static final int TEXTURE_MAG_FILTER = GL11.GL_TEXTURE_MAG_FILTER; - public static final int TEXTURE_WRAP_S = GL11.GL_TEXTURE_WRAP_S; - public static final int TEXTURE_WRAP_T = GL11.GL_TEXTURE_WRAP_T; - - public static final int BLEND = GL11.GL_BLEND; - public static final int ONE = GL11.GL_ONE; - public static final int ZERO = GL11.GL_ZERO; - public static final int SRC_ALPHA = GL11.GL_SRC_ALPHA; - public static final int DST_ALPHA = GL11.GL_DST_ALPHA; - public static final int ONE_MINUS_SRC_ALPHA = GL11.GL_ONE_MINUS_SRC_ALPHA; - public static final int ONE_MINUS_DST_COLOR = GL11.GL_ONE_MINUS_DST_COLOR; - public static final int ONE_MINUS_SRC_COLOR = GL11.GL_ONE_MINUS_SRC_COLOR; - public static final int DST_COLOR = GL11.GL_DST_COLOR; - public static final int SRC_COLOR = GL11.GL_SRC_COLOR; - - public static final int FRAMEBUFFER = GL30.GL_FRAMEBUFFER; - public static final int COLOR_ATTACHMENT0 = GL30.GL_COLOR_ATTACHMENT0; - public static final int COLOR_ATTACHMENT1 = GL30.GL_COLOR_ATTACHMENT1; - public static final int COLOR_ATTACHMENT2 = GL30.GL_COLOR_ATTACHMENT2; - public static final int COLOR_ATTACHMENT3 = GL30.GL_COLOR_ATTACHMENT3; - public static final int RENDERBUFFER = GL30.GL_RENDERBUFFER; - public static final int DEPTH_ATTACHMENT = GL30.GL_DEPTH_ATTACHMENT; - public static final int STENCIL_ATTACHMENT = GL30.GL_STENCIL_ATTACHMENT; - public static final int READ_FRAMEBUFFER = GL30.GL_READ_FRAMEBUFFER; - public static final int DRAW_FRAMEBUFFER = GL30.GL_DRAW_FRAMEBUFFER; - - public static final int VERTEX_SHADER = GL20.GL_VERTEX_SHADER; - public static final int FRAGMENT_SHADER = GL20.GL_FRAGMENT_SHADER; - public static final int INFO_LOG_LENGTH = GL20.GL_INFO_LOG_LENGTH; - public static final int SHADER_SOURCE_LENGTH = GL20.GL_SHADER_SOURCE_LENGTH; - public static final int COMPILE_STATUS = GL20.GL_COMPILE_STATUS; - public static final int LINK_STATUS = GL20.GL_LINK_STATUS; - public static final int VALIDATE_STATUS = GL20.GL_VALIDATE_STATUS; + public static final int RENDERBUFFER_WIDTH = GL30.GL_RENDERBUFFER_WIDTH; + public static final int RENDERBUFFER_HEIGHT = GL30.GL_RENDERBUFFER_HEIGHT; + public static final int RENDERBUFFER_RED_SIZE = GL30.GL_RENDERBUFFER_RED_SIZE; + public static final int RENDERBUFFER_GREEN_SIZE = GL30.GL_RENDERBUFFER_GREEN_SIZE; + public static final int RENDERBUFFER_BLUE_SIZE = GL30.GL_RENDERBUFFER_BLUE_SIZE; + public static final int RENDERBUFFER_ALPHA_SIZE = GL30.GL_RENDERBUFFER_ALPHA_SIZE; + public static final int RENDERBUFFER_DEPTH_SIZE = GL30.GL_RENDERBUFFER_DEPTH_SIZE; + public static final int RENDERBUFFER_STENCIL_SIZE = GL30.GL_RENDERBUFFER_STENCIL_SIZE; + public static final int RENDERBUFFER_INTERNAL_FORMAT = GL30.GL_RENDERBUFFER_INTERNAL_FORMAT; public static final int MULTISAMPLE = GL13.GL_MULTISAMPLE; public static final int POINT_SMOOTH = GL11.GL_POINT_SMOOTH; @@ -2698,209 +2831,105 @@ public class PGL extends processing.opengl.PGL { public static final int POLYGON_SMOOTH = GL11.GL_POLYGON_SMOOTH; - ////////////////////////////////////////////////////////////////////////////// - - // Caps query - - - public String getString(int name) { - return GL11.glGetString(name); - } - - - public void getIntegerv(int name, IntBuffer values) { - if (-1 < name) { - GL11.glGetInteger(name, values); - } else { - fillIntBuffer(values, 0, values.capacity() - 1, 0); - } - } - - - public void getFloatv(int name, FloatBuffer values) { - if (-1 < name) { - GL11.glGetFloat(name, values); - } else { - fillFloatBuffer(values, 0, values.capacity() - 1, 0); - } - } - - - public void getBooleanv(int name, IntBuffer values) { - if (-1 < name) { - if (byteBuffer.capacity() < values.capacity()) { - byteBuffer = allocateDirectByteBuffer(values.capacity()); - } - GL11.glGetBoolean(name, byteBuffer); - for (int i = 0; i < values.capacity(); i++) { - values.put(i, byteBuffer.get(i)); - } - } else { - fillIntBuffer(values, 0, values.capacity() - 1, 0); - } - } - - + /////////////////////////////////////////////////////////// - // Enable/disable caps - - - public void enable(int cap) { - if (-1 < cap) { - GL11.glEnable(cap); - } - } - - - public void disable(int cap) { - if (-1 < cap) { - GL11.glDisable(cap); - } - } - - - /////////////////////////////////////////////////////////// - - // Render control - + // Special Functions public void flush() { GL11.glFlush(); } - public void finish() { GL11.glFinish(); } + public void hint(int target, int hint) { + GL11.glHint(target, hint); + } /////////////////////////////////////////////////////////// - // Error handling + // State and State Requests + public void enable(int value) { + if (-1 < value) { + GL11.glEnable(value); + } + } + + public void disable(int value) { + if (-1 < value) { + GL11.glDisable(value); + } + } + + public void getBooleanv(int value, IntBuffer data) { + if (-1 < value) { + if (byteBuffer.capacity() < data.capacity()) { + byteBuffer = allocateDirectByteBuffer(data.capacity()); + } + GL11.glGetBoolean(value, byteBuffer); + for (int i = 0; i < data.capacity(); i++) { + data.put(i, byteBuffer.get(i)); + } + } else { + fillIntBuffer(data, 0, data.capacity() - 1, 0); + } + } + + public void getIntegerv(int value, IntBuffer data) { + if (-1 < value) { + GL11.glGetInteger(value, data); + } else { + fillIntBuffer(data, 0, data.capacity() - 1, 0); + } + } + + public void getFloatv(int value, FloatBuffer data) { + if (-1 < value) { + GL11.glGetFloat(value, data); + } else { + fillFloatBuffer(data, 0, data.capacity() - 1, 0); + } + } + + public boolean isEnabled(int value) { + return GL11.glIsEnabled(value); + } + + public String getString(int name) { + return GL11.glGetString(name); + } + + /////////////////////////////////////////////////////////// + + // Error Handling public int getError() { return GL11.glGetError(); } - public String errorString(int err) { return glu.gluErrorString(err); } + ////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////// + // Buffer Objects - // Rendering options - - - public void frontFace(int mode) { - GL11.glFrontFace(mode); + public void genBuffers(int n, IntBuffer buffers) { + GL15.glGenBuffers(buffers); } - - public void cullFace(int mode) { - GL11.glCullFace(mode); + public void deleteBuffers(int n, IntBuffer buffers) { + GL15.glDeleteBuffers(buffers); } - - public void depthMask(boolean flag) { - GL11.glDepthMask(flag); + public void bindBuffer(int target, int buffer) { + GL15.glBindBuffer(target, buffer); } - - public void depthFunc(int func) { - GL11.glDepthFunc(func); - } - - - /////////////////////////////////////////////////////////// - - // Textures - - - public void genTextures(int n, IntBuffer ids) { - GL11.glGenTextures(ids); - } - - - public void deleteTextures(int n, IntBuffer ids) { - GL11.glDeleteTextures(ids); - } - - - public void activeTexture(int unit) { - GL13.glActiveTexture(unit); - } - - - public void bindTexture(int target, int id) { - GL11.glBindTexture(target, id); - if (target == TEXTURE_2D) { - boundTextures[0] = id; - } else if (target == TEXTURE_RECTANGLE) { - boundTextures[1] = id; - } - } - - - public void texImage2D(int target, int level, int internalFormat, - int width, int height, int border, int format, - int type, Buffer data) { - GL11.glTexImage2D(target, level, internalFormat, - width, height, border, format, type, (IntBuffer)data); - } - - - public void texSubImage2D(int target, int level, int xOffset, int yOffset, - int width, int height, int format, - int type, Buffer data) { - GL11.glTexSubImage2D(target, level, xOffset, yOffset, - width, height, format, type, (IntBuffer)data); - } - - - public void texParameteri(int target, int param, int value) { - GL11.glTexParameteri(target, param, value); - } - - - public void texParameterf(int target, int param, float value) { - GL11.glTexParameterf(target, param, value); - } - - - public void getTexParameteriv(int target, int param, IntBuffer values) { - GL11.glGetTexParameter(target, param, values); - } - - - public void generateMipmap(int target) { - GL30.glGenerateMipmap(target); - } - - - /////////////////////////////////////////////////////////// - - // Vertex Buffers - - - public void genBuffers(int n, IntBuffer ids) { - GL15.glGenBuffers(ids); - } - - - public void deleteBuffers(int n, IntBuffer ids) { - GL15.glDeleteBuffers(ids); - } - - - public void bindBuffer(int target, int id) { - GL15.glBindBuffer(target, id); - } - - public void bufferData(int target, int size, Buffer data, int usage) { if (data == null) { FloatBuffer empty = BufferUtils.createFloatBuffer(size); @@ -2918,7 +2947,6 @@ public class PGL extends processing.opengl.PGL { } } - public void bufferSubData(int target, int offset, int size, Buffer data) { if (data instanceof ByteBuffer) { GL15.glBufferSubData(target, offset, (ByteBuffer)data); @@ -2931,444 +2959,664 @@ public class PGL extends processing.opengl.PGL { } } - - public void drawArrays(int mode, int first, int count) { - GL11.glDrawArrays(mode, first, count); + public void isBuffer(int buffer) { + GL15.glIsBuffer(buffer); } - - public void drawElements(int mode, int count, int type, int offset) { - GL11.glDrawElements(mode, count, type, offset); - } - - - public void enableVertexAttribArray(int loc) { - GL20.glEnableVertexAttribArray(loc); - } - - - public void disableVertexAttribArray(int loc) { - GL20.glDisableVertexAttribArray(loc); - } - - - public void vertexAttribPointer(int loc, int size, int type, - boolean normalized, int stride, int offset) { - GL20.glVertexAttribPointer(loc, size, type, normalized, stride, offset); - } - - - public void vertexAttribPointer(int loc, int size, int type, - boolean normalized, int stride, Buffer data) { - if (type == UNSIGNED_INT) { - GL20.glVertexAttribPointer(loc, size, true, normalized, stride, (IntBuffer)data); - } else if (type == UNSIGNED_BYTE) { - GL20.glVertexAttribPointer(loc, size, true, normalized, stride, (ByteBuffer)data); - } else if (type == UNSIGNED_SHORT) { - GL20.glVertexAttribPointer(loc, size, true, normalized, stride, (ShortBuffer)data); - } else if (type == FLOAT) { - GL20.glVertexAttribPointer(loc, size, normalized, stride, (FloatBuffer)data); + public void getBufferParameteriv(int target, int value, IntBuffer data) { + if (-1 < value) { + int res = GL15.glGetBufferParameteri(target, value); + data.put(0, res); + } else { + data.put(0, 0); } } - public ByteBuffer mapBuffer(int target, int access) { return GL15.glMapBuffer(target, access, null); } - - public ByteBuffer mapBufferRange(int target, int offset, int length, - int access) { + public ByteBuffer mapBufferRange(int target, int offset, int length, int access) { return GL30.glMapBufferRange(target, offset, length, access, null); } - public void unmapBuffer(int target) { GL15.glUnmapBuffer(target); } + ////////////////////////////////////////////////////////////////////////////// + + // Viewport and Clipping + + public void depthRangef(float n, float f) { + GL11.glDepthRange(n, f); + } + + public void viewport(int x, int y, int w, int h) { + GL11.glViewport(x, y, w, h); + } + + ////////////////////////////////////////////////////////////////////////////// + + // Reading Pixels + + public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer) { + boolean needEndBegin = format != STENCIL_INDEX && + format != DEPTH_COMPONENT && format != DEPTH_STENCIL; + if (needEndBegin) pg.beginReadPixels(); + readPixelsImpl(x, y, width, height, format, type, buffer); + if (needEndBegin) pg.endReadPixels(); + } + + protected void readPixelsImpl(int x, int y, int width, int height, int format, int type, Buffer buffer) { + GL11.glReadPixels(x, y, width, height, format, type, (IntBuffer)buffer); + } + + ////////////////////////////////////////////////////////////////////////////// + + // Vertices + + public void vertexAttrib1f(int index, float value) { + GL20.glVertexAttrib1f(index, value); + } + + public void vertexAttrib2f(int index, float value0, float value1) { + GL20.glVertexAttrib2f(index, value0, value1); + } + + public void vertexAttrib3f(int index, float value0, float value1, float value2) { + GL20.glVertexAttrib3f(index, value0, value1, value2); + } + + public void vertexAttrib4f(int index, float value0, float value1, float value2, float value3) { + GL20.glVertexAttrib4f(index, value0, value1, value2, value3); + } + + public void vertexAttrib1fv(int index, FloatBuffer values) { + GL20.glVertexAttrib1f(index, values.get()); + } + + public void vertexAttrib2fv(int index, FloatBuffer values) { + GL20.glVertexAttrib2f(index, values.get(), values.get()); + } + + public void vertexAttrib3fv(int index, FloatBuffer values) { + GL20.glVertexAttrib3f(index, values.get(), values.get(), values.get()); + } + + public void vertexAttri4fv(int index, FloatBuffer values) { + GL20.glVertexAttrib4f(index, values.get(), values.get(), values.get(), values.get()); + } + + public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, int offset) { + GL20.glVertexAttribPointer(index, size, type, normalized, stride, offset); + } + + public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer data) { + if (type == UNSIGNED_INT) { + GL20.glVertexAttribPointer(index, size, true, normalized, stride, (IntBuffer)data); + } else if (type == UNSIGNED_BYTE) { + GL20.glVertexAttribPointer(index, size, true, normalized, stride, (ByteBuffer)data); + } else if (type == UNSIGNED_SHORT) { + GL20.glVertexAttribPointer(index, size, true, normalized, stride, (ShortBuffer)data); + } else if (type == FLOAT) { + GL20.glVertexAttribPointer(index, size, normalized, stride, (FloatBuffer)data); + } + } + + public void enableVertexAttribArray(int index) { + GL20.glEnableVertexAttribArray(index); + } + + public void disableVertexAttribArray(int index) { + GL20.glDisableVertexAttribArray(index); + } + + public void drawArrays(int mode, int first, int count) { + GL11.glDrawArrays(mode, first, count); + } + + public void drawElements(int mode, int count, int type, int offset) { + GL11.glDrawElements(mode, count, type, offset); + } + + public void drawElements(int mode, int count, int type, Buffer indices) { + if (type == UNSIGNED_INT) { + GL11.glDrawElements(mode, (IntBuffer)indices); + } else if (type == UNSIGNED_BYTE) { + GL11.glDrawElements(mode, (ByteBuffer)indices); + } else if (type == UNSIGNED_SHORT) { + GL11.glDrawElements(mode, (ShortBuffer)indices); + } + } + + ////////////////////////////////////////////////////////////////////////////// + + // Rasterization + + public void lineWidth(float width) { + GL11.glLineWidth(width); + } + + public void frontFace(int dir) { + GL11.glFrontFace(dir); + } + + public void cullFace(int mode) { + GL11.glCullFace(mode); + } + + public void polygonOffset(float factor, float units) { + GL11.glPolygonOffset(factor, units); + } + + ////////////////////////////////////////////////////////////////////////////// + + // Pixel Rectangles + + public void pixelStorei(int pname, int param) { + GL11.glPixelStorei(pname, param); + } /////////////////////////////////////////////////////////// - // Framebuffers, renderbuffers + // Texturing - - public void genFramebuffers(int n, IntBuffer ids) { - GL30.glGenFramebuffers(ids); + public void activeTexture(int texture) { + GL13.glActiveTexture(texture); + activeTexUnit = texture - TEXTURE0; } - - public void deleteFramebuffers(int n, IntBuffer ids) { - GL30.glDeleteFramebuffers(ids); + public void texImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, Buffer data) { + GL11.glTexImage2D(target, level, internalFormat, width, height, border, format, type, (IntBuffer)data); } - - public void genRenderbuffers(int n, IntBuffer ids) { - GL30.glGenRenderbuffers(ids); + public void copyTexImage2D(int target, int level, int internalFormat, int x, int y, int width, int height, int border) { + GL11.glCopyTexImage2D(target, level, internalFormat, x, y, width, height, border); } - - public void deleteRenderbuffers(int n, IntBuffer ids) { - GL30.glDeleteRenderbuffers(ids); + public void texSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int type, Buffer data) { + GL11.glTexSubImage2D(target, level, xOffset, yOffset, width, height, format, type, (IntBuffer)data); } - - public void bindFramebuffer(int target, int id) { - GL30.glBindFramebuffer(target, id); + public void copyTexSubImage2D(int target, int level, int xOffset, int yOffset, int x, int y, int width, int height) { + GL11.glCopyTexSubImage2D(target, level, x, y, xOffset, xOffset, width, height); } - - public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, - int dstX0, int dstY0, int dstX1, int dstY1, - int mask, int filter) { - GL30.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, filter); + public void compressedTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int imageSize, Buffer data) { + GL13.glCompressedTexImage2D(target, level, internalFormat, width, height, border, (ByteBuffer)data); } - - public void framebufferTexture2D(int target, int attachment, int texTarget, - int texId, int level) { - GL30.glFramebufferTexture2D(target, attachment, texTarget, texId, level); + public void compressedTexSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int imageSize, Buffer data) { + GL13.glCompressedTexSubImage2D(target, level, xOffset, yOffset, width, height, format, (ByteBuffer)data); } - - public void bindRenderbuffer(int target, int id) { - GL30.glBindRenderbuffer(target, id); + public void texParameteri(int target, int pname, int param) { + GL11.glTexParameteri(target, pname, param); } - - public void renderbufferStorageMultisample(int target, int samples, - int format, int width, int height){ - GL30.glRenderbufferStorageMultisample(target, samples, format, - width, height); + public void texParameterf(int target, int pname, float param) { + GL11.glTexParameterf(target, pname, param); } - - public void renderbufferStorage(int target, int format, - int width, int height) { - GL30.glRenderbufferStorage(target, format, width, height); + public void texParameteriv(int target, int pname, IntBuffer params) { + GL11.glTexParameteri(target, pname, params.get()); } - - public void framebufferRenderbuffer(int target, int attachment, - int rendbufTarget, int rendbufId) { - GL30.glFramebufferRenderbuffer(target, attachment, rendbufTarget, rendbufId); + public void texParameterfv(int target, int pname, FloatBuffer params) { + GL11.glTexParameterf(target, pname, params.get()); } - - public int checkFramebufferStatus(int target) { - return GL30.glCheckFramebufferStatus(target); + public void generateMipmap(int target) { + GL30.glGenerateMipmap(target); } + public void bindTexture(int target, int texture) { + GL11.glBindTexture(target, texture); + + if (boundTextures == null) { + maxTexUnits = getMaxTexUnits(); + boundTextures = new int[maxTexUnits][2]; + } + + if (maxTexUnits <= activeTexUnit) { + throw new RuntimeException(TEXUNIT_ERROR); + } + + if (target == TEXTURE_2D) { + boundTextures[activeTexUnit][0] = texture; + } else if (target == TEXTURE_RECTANGLE) { + boundTextures[activeTexUnit][1] = texture; + } + } + + public void genTextures(int n, IntBuffer textures) { + GL11.glGenTextures(textures); + } + + public void deleteTextures(int n, IntBuffer textures) { + GL11.glDeleteTextures(textures); + } + + public void getTexParameteriv(int target, int pname, IntBuffer params) { + GL11.glGetTexParameter(target, pname, params); + } + + public void getTexParameterfv(int target, int pname, FloatBuffer params) { + GL11.glGetTexParameter(target, pname, params); + } + + public boolean isTexture(int texture) { + return GL11.glIsTexture(texture); + } /////////////////////////////////////////////////////////// - // Shaders - - - public int createProgram() { - return GL20.glCreateProgram(); - } - - - public void deleteProgram(int id) { - GL20.glDeleteProgram(id); - } - + // Shaders and Programs public int createShader(int type) { return GL20.glCreateShader(type); } - - public void deleteShader(int id) { - GL20.glDeleteShader(id); + public void shaderSource(int shader, String source) { + GL20.glShaderSource(shader, source); } - - public void linkProgram(int prog) { - GL20.glLinkProgram(prog); + public void compileShader(int shader) { + GL20.glCompileShader(shader); } - - public void validateProgram(int prog) { - GL20.glValidateProgram(prog); + public void releaseShaderCompiler() { + throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glReleaseShaderCompiler()")); } - - public void useProgram(int prog) { - GL20.glUseProgram(prog); + public void deleteShader(int shader) { + GL20.glDeleteShader(shader); } - - public int getAttribLocation(int prog, String name) { - return GL20.glGetAttribLocation(prog, name); + public void shaderBinary(int count, IntBuffer shaders, int binaryFormat, Buffer binary, int length) { + throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glShaderBinary()")); } - - public int getUniformLocation(int prog, String name) { - return GL20.glGetUniformLocation(prog, name); + public int createProgram() { + return GL20.glCreateProgram(); } - - public void uniform1i(int loc, int value) { - GL20.glUniform1i(loc, value); + public void attachShader(int program, int shader) { + GL20.glAttachShader(program, shader); } - - public void uniform2i(int loc, int value0, int value1) { - GL20.glUniform2i(loc, value0, value1); + public void detachShader(int program, int shader) { + GL20.glDetachShader(program, shader); } - - public void uniform3i(int loc, int value0, int value1, int value2) { - GL20.glUniform3i(loc, value0, value1, value2); + public void linkProgram(int program) { + GL20.glLinkProgram(program); } - - public void uniform4i(int loc, int value0, int value1, int value2, - int value3) { - GL20.glUniform4i(loc, value0, value1, value2, value3); + public void useProgram(int program) { + GL20.glUseProgram(program); } - - public void uniform1f(int loc, float value) { - GL20.glUniform1f(loc, value); + public void deleteProgram(int program) { + GL20.glDeleteProgram(program); } - - public void uniform2f(int loc, float value0, float value1) { - GL20.glUniform2f(loc, value0, value1); + public String glGetActiveAttrib (int program, int index, IntBuffer size, IntBuffer type) { + IntBuffer typeTmp = BufferUtils.createIntBuffer(2); + String name = GL20.glGetActiveAttrib(program, index, 256, typeTmp); + size.put(typeTmp.get(0)); + type.put(typeTmp.get(1)); + return name; } - - public void uniform3f(int loc, float value0, float value1, float value2) { - GL20.glUniform3f(loc, value0, value1, value2); + public int getAttribLocation(int program, String name) { + return GL20.glGetAttribLocation(program, name); } - - public void uniform4f(int loc, float value0, float value1, float value2, - float value3) { - GL20.glUniform4f(loc, value0, value1, value2, value3); + public void bindAttribLocation(int program, int index, String name) { + GL20.glBindAttribLocation(program, index, name); } + public int getUniformLocation(int program, String name) { + return GL20.glGetUniformLocation(program, name); + } - public void uniform1iv(int loc, int count, IntBuffer v) { + public String getActiveUniform(int program, int index, IntBuffer size, IntBuffer type) { + IntBuffer typeTmp = BufferUtils.createIntBuffer(2); + String name = GL20.glGetActiveUniform(program, index, 256, typeTmp); + type.put(typeTmp.get(0)); + return name; + } + + public void uniform1i(int location, int value) { + GL20.glUniform1i(location, value); + } + + public void uniform2i(int location, int value0, int value1) { + GL20.glUniform2i(location, value0, value1); + } + + public void uniform3i(int location, int value0, int value1, int value2) { + GL20.glUniform3i(location, value0, value1, value2); + } + + public void uniform4i(int location, int value0, int value1, int value2, int value3) { + GL20.glUniform4i(location, value0, value1, value2, value3); + } + + public void uniform1f(int location, float value) { + GL20.glUniform1f(location, value); + } + + public void uniform2f(int location, float value0, float value1) { + GL20.glUniform2f(location, value0, value1); + } + + public void uniform3f(int location, float value0, float value1, float value2) { + GL20.glUniform3f(location, value0, value1, value2); + } + + public void uniform4f(int location, float value0, float value1, float value2, float value3) { + GL20.glUniform4f(location, value0, value1, value2, value3); + } + + public void uniform1iv(int location, int count, IntBuffer v) { v.limit(count); - GL20.glUniform1(loc, v); + GL20.glUniform1(location, v); v.clear(); } - - public void uniform2iv(int loc, int count, IntBuffer v) { - v.limit(2 * count); - GL20.glUniform2(loc, v); - v.clear(); - } - - - public void uniform3iv(int loc, int count, IntBuffer v) { - v.limit(3 * count); - GL20.glUniform3(loc, v); - v.clear(); - } - - - public void uniform4iv(int loc, int count, IntBuffer v) { - v.limit(4 * count); - GL20.glUniform4(loc, v); - v.clear(); - } - - - public void uniform1fv(int loc, int count, FloatBuffer v) { + public void uniform2iv(int location, int count, IntBuffer v) { v.limit(count); - GL20.glUniform1(loc, v); + GL20.glUniform2(location, v); v.clear(); } - - public void uniform2fv(int loc, int count, FloatBuffer v) { - v.limit(2 * count); - GL20.glUniform2(loc, v); + public void uniform3iv(int location, int count, IntBuffer v) { + v.limit(count); + GL20.glUniform3(location, v); v.clear(); } - - public void uniform3fv(int loc, int count, FloatBuffer v) { - v.limit(3 * count); - GL20.glUniform3(loc, v); + public void uniform4iv(int location, int count, IntBuffer v) { + v.limit(count); + GL20.glUniform4(location, v); v.clear(); } - - public void uniform4fv(int loc, int count, FloatBuffer v) { - v.limit(4 * count); - GL20.glUniform4(loc, v); + public void uniform1fv(int location, int count, FloatBuffer v) { + v.limit(count); + GL20.glUniform1(location, v); v.clear(); } + public void uniform2fv(int location, int count, FloatBuffer v) { + v.limit(count); + GL20.glUniform2(location, v); + v.clear(); + } - public void uniformMatrix2fv(int loc, int count, boolean transpose, - FloatBuffer mat) { + public void uniform3fv(int location, int count, FloatBuffer v) { + v.limit(count); + GL20.glUniform3(location, v); + v.clear(); + } + + public void uniform4fv(int location, int count, FloatBuffer v) { + v.limit(count); + GL20.glUniform4(location, v); + v.clear(); + } + + public void uniformMatrix2fv(int location, int count, boolean transpose, FloatBuffer mat) { mat.limit(4); - GL20.glUniformMatrix2(loc, transpose, mat); + GL20.glUniformMatrix2(location, transpose, mat); mat.clear(); } - - public void uniformMatrix3fv(int loc, int count, boolean transpose, - FloatBuffer mat) { + public void uniformMatrix3fv(int location, int count, boolean transpose, FloatBuffer mat) { mat.limit(9); - GL20.glUniformMatrix3(loc, transpose, mat); + GL20.glUniformMatrix3(location, transpose, mat); mat.clear(); } - - public void uniformMatrix4fv(int loc, int count, boolean transpose, - FloatBuffer mat) { + public void uniformMatrix4fv(int location, int count, boolean transpose, FloatBuffer mat) { mat.limit(16); - GL20.glUniformMatrix4(loc, transpose, mat); + GL20.glUniformMatrix4(location, transpose, mat); mat.clear(); } - - public void vertexAttrib1f(int loc, float value) { - GL20.glVertexAttrib1f(loc, value); + public void validateProgram(int program) { + GL20.glValidateProgram(program); } - - public void vertexAttrib2f(int loc, float value0, float value1) { - GL20.glVertexAttrib2f(loc, value0, value1); + public boolean isShader(int shader) { + return GL20.glIsShader(shader); } - - public void vertexAttrib3f(int loc, float value0, float value1, float value2){ - GL20.glVertexAttrib3f(loc, value0, value1, value2); - } - - - public void vertexAttrib4f(int loc, float value0, float value1, float value2, - float value3) { - GL20.glVertexAttrib4f(loc, value0, value1, value2, value3); - } - - - public void shaderSource(int id, String source) { - GL20.glShaderSource(id, source); - } - - - public void compileShader(int id) { - GL20.glCompileShader(id); - } - - - public void attachShader(int prog, int shader) { - GL20.glAttachShader(prog, shader); - } - - public void getShaderiv(int shader, int pname, IntBuffer params) { GL20.glGetShader(shader, pname, params); } + public void getAttachedShaders(int program, int maxCount, IntBuffer count, IntBuffer shaders) { + GL20.glGetAttachedShaders(program, count, shaders); + } public String getShaderInfoLog(int shader) { int len = GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH); return GL20.glGetShaderInfoLog(shader, len); } - - public void getProgramiv(int prog, int pname, IntBuffer params) { - GL20.glGetProgram(prog, pname, params); + public String getShaderSource(int shader) { + int len = GL20.glGetShaderi(shader, GL20.GL_SHADER_SOURCE_LENGTH); + return GL20.glGetShaderSource(shader, len); } - - public String getProgramInfoLog(int prog) { - int len = GL20.glGetProgrami(prog, GL20.GL_INFO_LOG_LENGTH); - return GL20.glGetProgramInfoLog(prog, len); + public void getShaderPrecisionFormat(int shaderType, int precisionType, IntBuffer range, IntBuffer precision) { + throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glGetShaderPrecisionFormat()")); } + public void getVertexAttribfv(int index, int pname, FloatBuffer params) { + GL20.glGetVertexAttrib(index, pname, params); + } + + public void getVertexAttribiv(int index, int pname, IntBuffer params) { + GL20.glGetVertexAttrib(index, pname, params); + } + + public void getVertexAttribPointerv(int index, int pname, ByteBuffer data) { + int len = data.capacity(); + ByteBuffer res = GL20.glGetVertexAttribPointer(index, pname, len); + data.put(res); + } + + public void getUniformfv(int program, int location, FloatBuffer params) { + GL20.glGetUniform(program, location, params); + } + + public void getUniformiv(int program, int location, IntBuffer params) { + GL20.glGetUniform(program, location, params); + } + + public boolean isProgram(int program) { + return GL20.glIsProgram(program); + } + + public void getProgramiv(int program, int pname, IntBuffer params) { + GL20.glGetProgram(program, pname, params); + } + + public String getProgramInfoLog(int program) { + int len = GL20.glGetProgrami(program, GL20.GL_INFO_LOG_LENGTH); + return GL20.glGetProgramInfoLog(program, len); + } /////////////////////////////////////////////////////////// - // Viewport - - - public void viewport(int x, int y, int width, int height) { - GL11.glViewport(x, y, width, height); - } - - - /////////////////////////////////////////////////////////// - - // Clipping (scissor test) - + // Per-Fragment Operations public void scissor(int x, int y, int w, int h) { GL11.glScissor(x, y, w, h); } + public void sampleCoverage(float value, boolean invert) { + GL13.glSampleCoverage(value, invert); + } + + public void stencilFunc(int func, int ref, int mask) { + GL11.glStencilFunc(func, ref, mask); + } + + public void stencilFuncSeparate(int face, int func, int ref, int mask) { + GL20.glStencilFuncSeparate(face, func, ref, mask); + } + + public void stencilOp(int sfail, int dpfail, int dppass) { + GL11.glStencilOp(sfail, dpfail, dppass); + } + + public void stencilOpSeparate(int face, int sfail, int dpfail, int dppass) { + GL20.glStencilOpSeparate(face, sfail, dpfail, dppass); + } + + public void depthFunc(int func) { + GL11.glDepthFunc(func); + } + + public void blendEquation(int mode) { + GL14.glBlendEquation(mode); + } + + public void blendEquationSeparate(int modeRGB, int modeAlpha) { + GL20.glBlendEquationSeparate(modeRGB, modeAlpha); + } + + public void blendFunc(int src, int dst) { + GL11.glBlendFunc(src, dst); + } + + public void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) { + GL14.glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); + } + + public void blendColor(float red, float green, float blue, float alpha) { + GL14.glBlendColor(red, green, blue, alpha); + } + + public void alphaFunc(int func, float ref) { + GL11.glAlphaFunc(func, ref); + } /////////////////////////////////////////////////////////// - // Blending + // Whole Framebuffer Operations - - public void blendEquation(int eq) { - GL14.glBlendEquation(eq); + public void colorMask(boolean r, boolean g, boolean b, boolean a) { + GL11.glColorMask(r, g, b, a); } - - public void blendFunc(int srcFactor, int dstFactor) { - GL11.glBlendFunc(srcFactor, dstFactor); + public void depthMask(boolean mask) { + GL11.glDepthMask(mask); } - - /////////////////////////////////////////////////////////// - - // Pixels - - - public void readBuffer(int buf) { - GL11.glReadBuffer(buf); + public void stencilMask(int mask) { + GL11.glStencilMask(mask); } - - public void readPixels(int x, int y, int width, int height, int format, - int type, Buffer buffer) { - - GL11.glReadPixels(x, y, width, height, format, type, (IntBuffer)buffer); + public void stencilMaskSeparate(int face, int mask) { + GL20.glStencilMaskSeparate(face, mask); } - - public void drawBuffer(int buf) { - GL11.glDrawBuffer(buf); + public void clear(int buf) { + GL11.glClear(buf); } - - public void clearDepth(float d) { - GL11.glClearDepth(d); - } - - - public void clearStencil(int s) { - GL11.glClearStencil(s); - } - - - public void colorMask(boolean wr, boolean wg, boolean wb, boolean wa) { - GL11.glColorMask(wr, wg, wb, wa); - } - - public void clearColor(float r, float g, float b, float a) { GL11.glClearColor(r, g, b, a); } + public void clearDepth(float d) { + GL11.glClearDepth(d); + } - public void clear(int mask) { - GL11.glClear(mask); + public void clearStencil(int s) { + GL11.glClearStencil(s); + } + + /////////////////////////////////////////////////////////// + + // Framebuffers Objects + + public void bindFramebuffer(int target, int framebuffer) { + GL30.glBindFramebuffer(target, framebuffer); + } + + public void deleteFramebuffers(int n, IntBuffer framebuffers) { + GL30.glDeleteFramebuffers(framebuffers); + } + + public void genFramebuffers(int n, IntBuffer framebuffers) { + GL30.glGenFramebuffers(framebuffers); + } + + public void bindRenderbuffer(int target, int renderbuffer) { + GL30.glBindRenderbuffer(target, renderbuffer); + } + + public void deleteRenderbuffers(int n, IntBuffer renderbuffers) { + GL30.glDeleteRenderbuffers(renderbuffers); + } + + public void genRenderbuffers(int n, IntBuffer renderbuffers) { + GL30.glGenRenderbuffers(renderbuffers); + } + + public void renderbufferStorage(int target, int internalFormat, int width, int height) { + GL30.glRenderbufferStorage(target, internalFormat, width, height); + } + + public void framebufferRenderbuffer(int target, int attachment, int rendbuferfTarget, int renderbuffer) { + GL30.glFramebufferRenderbuffer(target, attachment, rendbuferfTarget, renderbuffer); + } + + public void framebufferTexture2D(int target, int attachment, int texTarget, int texture, int level) { + GL30.glFramebufferTexture2D(target, attachment, texTarget, texture, level); + } + + public int checkFramebufferStatus(int target) { + return GL30.glCheckFramebufferStatus(target); + } + + public boolean isFramebuffer(int framebuffer) { + return GL30.glIsFramebuffer(framebuffer); + } + + public void getFramebufferAttachmentParameteriv(int target, int attachment, int pname, IntBuffer params) { + GL30.glGetFramebufferAttachmentParameter(target, attachment, pname, params); + } + + public boolean isRenderbuffer(int renderbuffer) { + return GL30.glIsRenderbuffer(renderbuffer); + } + + public void getRenderbufferParameteriv(int target, int pname, IntBuffer params) { + GL30.glGetRenderbufferParameter(target, pname, params); + } + + public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) { + GL30.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + } + + public void renderbufferStorageMultisample(int target, int samples, int format, int width, int height) { + GL30.glRenderbufferStorageMultisample(target, samples, format, width, height); + } + + public void readBuffer(int buf) { + GL11.glReadBuffer(buf); + } + + public void drawBuffer(int buf) { + GL11.glDrawBuffer(buf); } } From 53a72e4318bfe742bfa95bfef766accdc3d6fc8c Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 10 Sep 2013 15:05:48 -0400 Subject: [PATCH 028/556] Added PJOGL class --- core/src/processing/opengl/PGraphicsOpenGL.java | 2 +- core/src/processing/opengl/PJOGL.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 core/src/processing/opengl/PJOGL.java diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index efb436ad8..f29a62fb4 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -1701,7 +1701,7 @@ public class PGraphicsOpenGL extends PGraphics { // Factory method static public PGL createPGL(PGraphicsOpenGL pg) { - return new PGL(pg); + return new PJOGL(pg); } diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java new file mode 100644 index 000000000..007532759 --- /dev/null +++ b/core/src/processing/opengl/PJOGL.java @@ -0,0 +1,7 @@ +package processing.opengl; + +public class PJOGL extends PGL { + public PJOGL(PGraphicsOpenGL pg) { + super(pg); + } +} From 69c59cfdf9f3fdb6e09c1b5de8fbb8700dc0d3e4 Mon Sep 17 00:00:00 2001 From: gohai Date: Tue, 10 Sep 2013 15:15:12 -0700 Subject: [PATCH 029/556] Image transparency for PDF output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before, drawing an image with transparency would result in black, opaque pixels in the PDF file. This change, figured out together with Jürg Lehni, fixes this. At its core, switching from drawImage(img, int, int, int, int, int, int, int, int, null) to drawImage(img, int, int, null) seems to do the trick - so this might have been a bug in iText all along. Signed-off-by: Jürg Lehni Signed-off-by: Gottfried Haider --- .../pdf/src/processing/pdf/PGraphicsPDF.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java b/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java index 2c6e8ae88..45b020710 100644 --- a/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java +++ b/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java @@ -404,22 +404,18 @@ public class PGraphicsPDF extends PGraphicsJava2D { ////////////////////////////////////////////////////////////// - /* - protected void imageImplAWT(java.awt.Image awtImage, + protected void imageImpl(PImage image, float x1, float y1, float x2, float y2, int u1, int v1, int u2, int v2) { pushMatrix(); translate(x1, y1); - int awtImageWidth = awtImage.getWidth(null); - int awtImageHeight = awtImage.getHeight(null); - scale((x2 - x1) / (float)awtImageWidth, - (y2 - y1) / (float)awtImageHeight); - g2.drawImage(awtImage, - 0, 0, awtImageWidth, awtImageHeight, - u1, v1, u2, v2, null); + int imageWidth = image.width; + int imageHeight = image.height; + scale((x2 - x1) / (float)imageWidth, + (y2 - y1) / (float)imageHeight); + g2.drawImage(image.getImage(), u1, v1, null); popMatrix(); } - */ ////////////////////////////////////////////////////////////// From b1ebdd6ed6d48ead73f7f7cb81cf81a9e6cdfb22 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 10 Sep 2013 18:55:55 -0400 Subject: [PATCH 030/556] removed use of switch/case --- .../processing/opengl/PGraphicsOpenGL.java | 33 +++++-------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index f29a62fb4..be369e530 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -3446,17 +3446,13 @@ public class PGraphicsOpenGL extends PGraphics { beginShape(); while (!outline.isDone()) { int type = outline.currentSegment(textPoints); - switch (type) { - case PGL.SEG_MOVETO: // 1 point (2 vars) in textPoints - case PGL.SEG_LINETO: // 1 point - if (type == PGL.SEG_MOVETO) { - beginContour(); - } + if (type == PGL.SEG_MOVETO) { // 1 point (2 vars) in textPoints + } else if (type == PGL.SEG_LINETO) { // 1 point + if (type == PGL.SEG_MOVETO) beginContour(); vertex(x + textPoints[0], y + textPoints[1]); lastX = textPoints[0]; lastY = textPoints[1]; - break; - case PGL.SEG_QUADTO: // 2 points + } else if (type == PGL.SEG_QUADTO) { // 2 points for (int i = 1; i < bezierDetail; i++) { float t = (float)i / (float)bezierDetail; vertex(x + bezierPoint(lastX, @@ -3470,8 +3466,7 @@ public class PGraphicsOpenGL extends PGraphics { } lastX = textPoints[2]; lastY = textPoints[3]; - break; - case PGL.SEG_CUBICTO: // 3 points + } else if (type == PGL.SEG_CUBICTO) { // 3 points for (int i = 1; i < bezierDetail; i++) { float t = (float)i / (float)bezierDetail; vertex(x + bezierPoint(lastX, textPoints[0], @@ -3481,10 +3476,8 @@ public class PGraphicsOpenGL extends PGraphics { } lastX = textPoints[4]; lastY = textPoints[5]; - break; - case PGL.SEG_CLOSE: + } else if (type == PGL.SEG_CLOSE) { endContour(); - break; } outline.next(); } @@ -12045,17 +12038,9 @@ public class PGraphicsOpenGL extends PGraphics { vertFirst = cache.vertexCount[cacheIndex]; vertCount = 0; - switch (type) { - case PGL.TRIANGLE_FAN: - primitive = TRIANGLE_FAN; - break; - case PGL.TRIANGLE_STRIP: - primitive = TRIANGLE_STRIP; - break; - case PGL.TRIANGLES: - primitive = TRIANGLES; - break; - } + if (type == PGL.TRIANGLE_FAN) primitive = TRIANGLE_FAN; + else if (type == PGL.TRIANGLE_STRIP) primitive = TRIANGLE_STRIP; + else if (type == PGL.TRIANGLES) primitive = TRIANGLES; } public void end() { From 748d331f8584eca3a5e8df3d054fb1e64bef6af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laureano=20L=C3=B3pez?= Date: Thu, 12 Sep 2013 15:12:27 -0300 Subject: [PATCH 031/556] setBackground for (JFrame)frame frame.setBackground >> ((JFrame)frame).getContentPane().setBackground --- core/src/processing/core/PApplet.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 46838ec3c..dd06ff605 100755 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -10445,7 +10445,7 @@ public class PApplet extends Applet Frame frame = new JFrame(displayDevice.getDefaultConfiguration()); // Default Processing gray, which will be replaced below if another // color is specified on the command line (i.e. in the prefs). - frame.setBackground(new Color(0xCC, 0xCC, 0xCC)); + ((JFrame)frame).getContentPane().setBackground(new Color(0xCC, 0xCC, 0xCC)); // Cannot call setResizable(false) until later due to OS X (issue #467) final PApplet applet; @@ -10557,7 +10557,7 @@ public class PApplet extends Applet //frame.setExtendedState(Frame.MAXIMIZED_BOTH); frame.setUndecorated(true); if (backgroundColor != null) { - frame.setBackground(backgroundColor); + ((JFrame)frame).getContentPane().setBackground(backgroundColor); } // if (exclusive) { // displayDevice.setFullScreenWindow(frame); @@ -10714,7 +10714,7 @@ public class PApplet extends Applet // // this means no bg color unless specified // backgroundColor = SystemColor.control; // } - frame.setBackground(backgroundColor); + ((JFrame)frame).getContentPane().setBackground(backgroundColor); } // int usableWindowH = windowH - insets.top - insets.bottom; From be08ef7c23792689cd1d5bfba0fa0dc767e20a99 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 12 Sep 2013 18:00:58 -0400 Subject: [PATCH 032/556] misc fixes, todo updates --- build/shared/tools/Mangler/make.sh | 2 +- build/shared/tools/MovieMaker/build.xml | 4 ++-- core/src/processing/core/PApplet.java | 4 ++-- core/todo.txt | 8 ++++---- todo.txt | 18 ++++++++++++++++-- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/build/shared/tools/Mangler/make.sh b/build/shared/tools/Mangler/make.sh index e1c1ce37b..8b2b2b5dc 100755 --- a/build/shared/tools/Mangler/make.sh +++ b/build/shared/tools/Mangler/make.sh @@ -3,7 +3,7 @@ # The pde.jar file may be buried inside the .app file on Mac OS X. PDE=`find ../.. -name pde.jar` -javac -target 1.5 \ +javac -target 1.6 \ -cp "../../lib/core.jar:$PDE" \ -d bin \ src/Mangler.java diff --git a/build/shared/tools/MovieMaker/build.xml b/build/shared/tools/MovieMaker/build.xml index a30d993fe..fa0902b8e 100644 --- a/build/shared/tools/MovieMaker/build.xml +++ b/build/shared/tools/MovieMaker/build.xml @@ -18,8 +18,8 @@ --> - Date: Thu, 12 Sep 2013 18:01:15 -0400 Subject: [PATCH 033/556] misc fixes, todo updates --- core/todo.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/core/todo.txt b/core/todo.txt index 51bcfe422..43a27d0e7 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -1,6 +1,7 @@ 0222 core X background color for present mode has no effect X https://github.com/processing/processing/issues/2071 +X https://github.com/processing/processing/pull/2072 high From d21b911a13f194fcac2fdf5a96bc53dc0a1bc8b8 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 12 Sep 2013 18:03:10 -0400 Subject: [PATCH 034/556] fix formatting --- core/src/processing/core/PApplet.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 58f6f3b41..2eb3e3dd6 100755 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -10445,7 +10445,8 @@ public class PApplet extends Applet Frame frame = new JFrame(displayDevice.getDefaultConfiguration()); // Default Processing gray, which will be replaced below if another // color is specified on the command line (i.e. in the prefs). - ((JFrame)frame).getContentPane().setBackground(new Color(0xCC, 0xCC, 0xCC)); + final Color defaultGray = new Color(0xCC, 0xCC, 0xCC); + ((JFrame) frame).getContentPane().setBackground(defaultGray); // Cannot call setResizable(false) until later due to OS X (issue #467) final PApplet applet; @@ -10557,7 +10558,7 @@ public class PApplet extends Applet //frame.setExtendedState(Frame.MAXIMIZED_BOTH); frame.setUndecorated(true); if (backgroundColor != null) { - ((JFrame)frame).getContentPane().setBackground(backgroundColor); + ((JFrame) frame).getContentPane().setBackground(backgroundColor); } // if (exclusive) { // displayDevice.setFullScreenWindow(frame); @@ -10714,7 +10715,7 @@ public class PApplet extends Applet // // this means no bg color unless specified // backgroundColor = SystemColor.control; // } - ((JFrame)frame).getContentPane().setBackground(backgroundColor); + ((JFrame) frame).getContentPane().setBackground(backgroundColor); } // int usableWindowH = windowH - insets.top - insets.bottom; From d334a8a8f9d6fbb409915b8742da51fed53e258d Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 12 Sep 2013 19:12:53 -0400 Subject: [PATCH 035/556] continue with the refactoring of PGL --- core/src/processing/opengl/PGL.java | 2592 ++++------------- core/src/processing/opengl/PJOGL.java | 2287 +++++++++++++++ .../lwjgl/src/processing/lwjgl/PLWJGL.java | 519 ++-- 3 files changed, 3135 insertions(+), 2263 deletions(-) diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index 417814c40..bdf3f3bb8 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2011-12 Ben Fry and Casey Reas + Copyright (c) 2011-13 Ben Fry and Casey Reas This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -23,52 +23,15 @@ package processing.opengl; -import java.awt.BorderLayout; -import java.awt.Canvas; -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Shape; -import java.awt.font.FontRenderContext; -import java.awt.font.GlyphVector; -import java.awt.geom.PathIterator; +import processing.core.PApplet; import java.nio.Buffer; - import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; import java.util.Arrays; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import javax.media.opengl.GL; -import javax.media.opengl.GL2; -import javax.media.opengl.GL2ES2; -import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLCapabilities; -import javax.media.opengl.GLCapabilitiesImmutable; -import javax.media.opengl.GLContext; -import javax.media.opengl.GLDrawable; -import javax.media.opengl.GLEventListener; -import javax.media.opengl.GLException; -import javax.media.opengl.GLFBODrawable; -import javax.media.opengl.GLProfile; -import javax.media.opengl.awt.GLCanvas; -import javax.media.opengl.glu.GLU; -import javax.media.opengl.glu.GLUtessellator; -import javax.media.opengl.glu.GLUtessellatorCallbackAdapter; - -import processing.core.PApplet; -import processing.core.PConstants; -import processing.event.KeyEvent; -import processing.event.MouseEvent; - -import com.jogamp.newt.awt.NewtCanvasAWT; -import com.jogamp.newt.event.InputEvent; -import com.jogamp.newt.opengl.GLWindow; -import com.jogamp.opengl.FBObject; /** * Processing-OpenGL abstraction layer. @@ -76,62 +39,51 @@ import com.jogamp.opengl.FBObject; * Warnings are suppressed for static access because presumably on Android, * the GL2 vs GL distinctions are necessary, whereas on desktop they are not. */ -@SuppressWarnings("static-access") -public class PGL { - /////////////////////////////////////////////////////////// +public abstract class PGL { - // Public members to access the underlying GL objects and context - /** Basic GL functionality, common to all profiles */ - public static GL gl; - /** GLU interface **/ - public static GLU glu; - /** The rendering context (holds rendering state info) */ - public static GLContext context; + /** The PGraphics object using this interface */ + protected PGraphicsOpenGL pg; + protected static int contextID; - /** The canvas where OpenGL rendering takes place */ - public static Canvas canvas; - - /** Selected GL profile */ - public static GLProfile profile; /////////////////////////////////////////////////////////// // Parameters /** Switches between the use of regular and direct buffers. */ - protected static final boolean USE_DIRECT_BUFFERS = true; - protected static final int MIN_DIRECT_BUFFER_SIZE = 1; + protected static boolean USE_DIRECT_BUFFERS = true; + protected static int MIN_DIRECT_BUFFER_SIZE = 1; /** This flag enables/disables a hack to make sure that anything drawn * in setup will be maintained even a renderer restart (e.g.: smooth change). * See the code and comments involving this constant in * PGraphicsOpenGL.endDraw(). */ - protected static final boolean SAVE_SURFACE_TO_PIXELS_HACK = true; + protected static boolean SAVE_SURFACE_TO_PIXELS_HACK = true; /** Enables/disables mipmap use. */ - protected static final boolean MIPMAPS_ENABLED = true; + protected static boolean MIPMAPS_ENABLED = true; /** Initial sizes for arrays of input and tessellated data. */ - protected static final int DEFAULT_IN_VERTICES = 64; - protected static final int DEFAULT_IN_EDGES = 128; - protected static final int DEFAULT_IN_TEXTURES = 64; - protected static final int DEFAULT_TESS_VERTICES = 64; - protected static final int DEFAULT_TESS_INDICES = 128; + protected static int DEFAULT_IN_VERTICES = 64; + protected static int DEFAULT_IN_EDGES = 128; + protected static int DEFAULT_IN_TEXTURES = 64; + protected static int DEFAULT_TESS_VERTICES = 64; + protected static int DEFAULT_TESS_INDICES = 128; /** Maximum lights by default is 8, the minimum defined by OpenGL. */ - protected static final int MAX_LIGHTS = 8; + protected static int MAX_LIGHTS = 8; /** Maximum index value of a tessellated vertex. GLES restricts the vertex * indices to be of type unsigned short. Since Java only supports signed * shorts as primitive type we have 2^15 = 32768 as the maximum number of * vertices that can be referred to within a single VBO. */ - protected static final int MAX_VERTEX_INDEX = 32767; - protected static final int MAX_VERTEX_INDEX1 = MAX_VERTEX_INDEX + 1; + protected static int MAX_VERTEX_INDEX = 32767; + protected static int MAX_VERTEX_INDEX1 = MAX_VERTEX_INDEX + 1; /** Count of tessellated fill, line or point vertices that will * trigger a flush in the immediate mode. It doesn't necessarily @@ -139,98 +91,39 @@ public class PGL { * be effectively much large since the renderer uses offsets to * refer to vertices beyond the MAX_VERTEX_INDEX limit. */ - protected static final int FLUSH_VERTEX_COUNT = MAX_VERTEX_INDEX1; + protected static int FLUSH_VERTEX_COUNT = MAX_VERTEX_INDEX1; /** Minimum/maximum dimensions of a texture used to hold font data. */ - protected static final int MIN_FONT_TEX_SIZE = 256; - protected static final int MAX_FONT_TEX_SIZE = 1024; + protected static int MIN_FONT_TEX_SIZE = 256; + protected static int MAX_FONT_TEX_SIZE = 1024; /** Minimum stroke weight needed to apply the full path stroking * algorithm that properly generates caps and joins. */ - protected static final float MIN_CAPS_JOINS_WEIGHT = 2f; + protected static float MIN_CAPS_JOINS_WEIGHT = 2f; /** Maximum length of linear paths to be stroked with the * full algorithm that generates accurate caps and joins. */ - protected static final int MAX_CAPS_JOINS_LENGTH = 5000; + protected static int MAX_CAPS_JOINS_LENGTH = 5000; /** Minimum array size to use arrayCopy method(). */ - protected static final int MIN_ARRAYCOPY_SIZE = 2; + protected static int MIN_ARRAYCOPY_SIZE = 2; /** Factor used to displace the stroke vertices towards the camera in * order to make sure the lines are always on top of the fill geometry */ - protected static final float STROKE_DISPLACEMENT = 0.999f; + protected static float STROKE_DISPLACEMENT = 0.999f; - /** Time that the Processing's animation thread will wait for JOGL's rendering - * thread to be done with a single frame. - */ - protected static final int DRAW_TIMEOUT_MILLIS = 500; - /** JOGL's windowing toolkit */ - // The two windowing toolkits available to use in JOGL: - protected static final int AWT = 0; // http://jogamp.org/wiki/index.php/Using_JOGL_in_AWT_SWT_and_Swing - protected static final int NEWT = 1; // http://jogamp.org/jogl/doc/NEWT-Overview.html - /** OS-specific configuration */ - protected static int WINDOW_TOOLKIT; - protected static int EVENTS_TOOLKIT; - protected static boolean USE_FBOLAYER_BY_DEFAULT; - protected static boolean USE_JOGL_FBOLAYER; - protected static int REQUESTED_DEPTH_BITS = 24; - protected static int REQUESTED_STENCIL_BITS = 8; - protected static int REQUESTED_ALPHA_BITS = 8; - static { - if (PApplet.platform == PConstants.WINDOWS) { - // Using AWT on Windows because NEWT displays a black background while - // initializing, and the cursor functions don't work. GLWindow has some - // functions for basic cursor handling (hide/show): - // GLWindow.setPointerVisible(false); - // but apparently nothing to set the cursor icon: - // https://jogamp.org/bugzilla/show_bug.cgi?id=409 - WINDOW_TOOLKIT = AWT; - EVENTS_TOOLKIT = AWT; - USE_FBOLAYER_BY_DEFAULT = false; - USE_JOGL_FBOLAYER = false; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; - } else if (PApplet.platform == PConstants.MACOSX) { - // Note: with the JOGL jars included in the 2.0 release (jogl-2.0-b993, - // gluegen-1.0-b671), the JOGL FBO layer seems incompatible with NEWT. - WINDOW_TOOLKIT = AWT; - EVENTS_TOOLKIT = AWT; - USE_FBOLAYER_BY_DEFAULT = true; - USE_JOGL_FBOLAYER = true; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; - } else if (PApplet.platform == PConstants.LINUX) { - WINDOW_TOOLKIT = AWT; - EVENTS_TOOLKIT = AWT; - USE_FBOLAYER_BY_DEFAULT = false; - USE_JOGL_FBOLAYER = false; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; - } else if (PApplet.platform == PConstants.OTHER) { - WINDOW_TOOLKIT = NEWT; // NEWT works on the Raspberry pi? - EVENTS_TOOLKIT = NEWT; - USE_FBOLAYER_BY_DEFAULT = false; - USE_JOGL_FBOLAYER = false; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; - } - } /** Size of different types in bytes */ - protected static final int SIZEOF_SHORT = Short.SIZE / 8; - protected static final int SIZEOF_INT = Integer.SIZE / 8; - protected static final int SIZEOF_FLOAT = Float.SIZE / 8; - protected static final int SIZEOF_BYTE = Byte.SIZE / 8; - protected static final int SIZEOF_INDEX = SIZEOF_SHORT; - protected static final int INDEX_TYPE = GL.GL_UNSIGNED_SHORT; + protected static int SIZEOF_SHORT = Short.SIZE / 8; + protected static int SIZEOF_INT = Integer.SIZE / 8; + protected static int SIZEOF_FLOAT = Float.SIZE / 8; + protected static int SIZEOF_BYTE = Byte.SIZE / 8; + protected static int SIZEOF_INDEX = SIZEOF_SHORT; + protected static int INDEX_TYPE = 0x1403; // GL_UNSIGNED_SHORT /** Machine Epsilon for float precision. */ protected static float FLOAT_EPS = Float.MIN_VALUE; @@ -246,6 +139,8 @@ public class PGL { FLOAT_EPS = eps; } + + /** * Set to true if the host system is big endian (PowerPC, MIPS, SPARC), false * if little endian (x86 Intel for Mac or PC). @@ -259,93 +154,8 @@ public class PGL { "precision mediump int;\n" + "#endif\n"; - /** OpenGL thread */ - protected static Thread glThread; - /** The PGraphics object using this interface */ - protected PGraphicsOpenGL pg; - /** The capabilities of the OpenGL rendering surface */ - protected static GLCapabilitiesImmutable capabilities; - - /** The rendering surface */ - protected static GLDrawable drawable; - - /** GLES2 functionality (shaders, etc) */ - protected static GL2ES2 gl2; - - /** GL2 desktop functionality (blit framebuffer, map buffer range, - * multisampled renerbuffers) */ - protected static GL2 gl2x; - - /** The AWT-OpenGL canvas */ - protected static GLCanvas canvasAWT; - - /** The NEWT-OpenGL canvas */ - protected static NewtCanvasAWT canvasNEWT; - - /** The NEWT window */ - protected static GLWindow window; - - /** The listener that fires the frame rendering in Processing */ - protected static PGLListener listener; - - /** This countdown latch is used to maintain the synchronization between - * Processing's drawing thread and JOGL's rendering thread */ - protected CountDownLatch drawLatch; - - /** Desired target framerate */ - protected float targetFps = 60; - protected float currentFps = 60; - protected boolean setFps = false; - protected int fcount, lastm; - protected int fint = 3; - - /** Which texturing targets are enabled */ - protected static boolean[] texturingTargets = { false, false }; - - /** Used to keep track of which textures are bound to each target */ - protected static int maxTexUnits; - protected static int activeTexUnit = 0; - protected static int[][] boundTextures; - - /////////////////////////////////////////////////////////// - - // FBO layer - - protected static boolean fboLayerRequested = false; - protected static boolean fboLayerCreated = false; - protected static boolean fboLayerInUse = false; - protected static boolean firstFrame = true; - protected static int reqNumSamples; - protected static int numSamples; - protected static IntBuffer glColorFbo; - protected static IntBuffer glMultiFbo; - protected static IntBuffer glColorBuf; - protected static IntBuffer glColorTex; - protected static IntBuffer glDepthStencil; - protected static IntBuffer glDepth; - protected static IntBuffer glStencil; - protected static int fboWidth, fboHeight; - protected static int backTex, frontTex; - - /** Back (== draw, current frame) buffer */ - protected static FBObject backFBO; - /** Sink buffer, used in the multisampled case */ - protected static FBObject sinkFBO; - /** Front (== read, previous frame) buffer */ - protected static FBObject frontFBO; - protected static FBObject.TextureAttachment backTexAttach; - protected static FBObject.TextureAttachment frontTexAttach; - - /** Flags used to handle the creation of a separte front texture */ - protected boolean usingFrontTex = false; - protected boolean needSepFrontTex = false; - - /** Flag used to do request final display() call to make sure that the - * buffers are properly swapped. - */ - protected boolean prevCanDraw = false; /////////////////////////////////////////////////////////// @@ -355,7 +165,7 @@ public class PGL { protected static int tex2DShaderProgram; protected static int tex2DVertShader; protected static int tex2DFragShader; - protected static GLContext tex2DShaderContext; + protected static int tex2DShaderContext; protected static int tex2DVertLoc; protected static int tex2DTCoordLoc; @@ -363,7 +173,7 @@ public class PGL { protected static int texRectShaderProgram; protected static int texRectVertShader; protected static int texRectFragShader; - protected static GLContext texRectShaderContext; + protected static int texRectShaderContext; protected static int texRectVertLoc; protected static int texRectTCoordLoc; @@ -413,9 +223,6 @@ public class PGL { protected FloatBuffer depthBuffer; protected ByteBuffer stencilBuffer; - protected float[] projMatrix; - protected float[] mvMatrix; - /////////////////////////////////////////////////////////// // Error messages @@ -439,20 +246,70 @@ public class PGL { "Number of texture units not supported by this hardware (or driver)" + WIKI; + + + + protected static boolean USE_FBOLAYER_BY_DEFAULT; + + + + + + + + + + + + /** Which texturing targets are enabled */ + protected static boolean[] texturingTargets = { false, false }; + + /** Used to keep track of which textures are bound to each target */ + protected static int maxTexUnits; + protected static int activeTexUnit = 0; + protected static int[][] boundTextures; + + /////////////////////////////////////////////////////////// + + // FBO layer + + protected static boolean fboLayerRequested = false; + protected static boolean fboLayerCreated = false; + protected static boolean fboLayerInUse = false; + protected static boolean firstFrame = true; + protected static int reqNumSamples; + protected static int numSamples; + protected static IntBuffer glColorFbo; + protected static IntBuffer glMultiFbo; + protected static IntBuffer glColorBuf; + protected static IntBuffer glColorTex; + protected static IntBuffer glDepthStencil; + protected static IntBuffer glDepth; + protected static IntBuffer glStencil; + protected static int fboWidth, fboHeight; + protected static int backTex, frontTex; + + + + /** Flags used to handle the creation of a separate front texture */ + protected boolean usingFrontTex = false; + protected boolean needSepFrontTex = false; + + /** Flag used to do request final display() call to make sure that the + * buffers are properly swapped. + */ + protected boolean prevCanDraw = false; + + + /////////////////////////////////////////////////////////// // Initialization, finalization - - public PGL() { - } - + public PGL() { } public PGL(PGraphicsOpenGL pg) { this.pg = pg; - if (glu == null) { - glu = new GLU(); - } if (glColorTex == null) { glColorTex = allocateIntBuffer(2); glColorFbo = allocateIntBuffer(1); @@ -472,152 +329,9 @@ public class PGL { viewBuffer = allocateIntBuffer(4); } + protected void setFps(float fps) { } - protected void setFps(float fps) { - if (!setFps || targetFps != fps) { - if (60 < fps) { - // Disables v-sync - gl.setSwapInterval(0); - } else if (30 < fps) { - gl.setSwapInterval(1); - } else { - gl.setSwapInterval(2); - } - targetFps = currentFps = fps; - setFps = true; - } - } - - - protected void initSurface(int antialias) { - if (profile == null) { - profile = GLProfile.getDefault(); - } - GLCapabilities reqCaps = new GLCapabilities(profile); - reqCaps.setDepthBits(REQUESTED_DEPTH_BITS); - reqCaps.setStencilBits(REQUESTED_STENCIL_BITS); - reqCaps.setAlphaBits(REQUESTED_ALPHA_BITS); - initSurface(antialias, reqCaps, null); - } - - - protected void initSurface(int antialias, GLCapabilities reqCaps, - GLContext sharedCtx) { - if (profile == null) { - profile = GLProfile.getDefault(); - } else { - // Restarting... - if (canvasAWT != null) { - canvasAWT.removeGLEventListener(listener); - pg.parent.removeListeners(canvasAWT); - pg.parent.remove(canvasAWT); - } else if (canvasNEWT != null) { - window.removeGLEventListener(listener); - pg.parent.remove(canvasNEWT); - } - sinkFBO = backFBO = frontFBO = null; - } - - // Setting up the desired capabilities; - GLCapabilities caps = reqCaps == null ? new GLCapabilities(profile) : - reqCaps; - caps.setBackgroundOpaque(true); - caps.setOnscreen(true); - if (USE_FBOLAYER_BY_DEFAULT) { - if (USE_JOGL_FBOLAYER) { - caps.setPBuffer(false); - caps.setFBO(true); - if (1 < antialias) { - caps.setSampleBuffers(true); - caps.setNumSamples(antialias); - } else { - caps.setSampleBuffers(false); - } - fboLayerRequested = false; - } else { - caps.setPBuffer(false); - caps.setFBO(false); - caps.setSampleBuffers(false); - fboLayerRequested = 1 < antialias; - } - } else { - if (1 < antialias) { - caps.setSampleBuffers(true); - caps.setNumSamples(antialias); - } else { - caps.setSampleBuffers(false); - } - fboLayerRequested = false; - } - caps.setDepthBits(REQUESTED_DEPTH_BITS); - caps.setStencilBits(REQUESTED_STENCIL_BITS); - caps.setAlphaBits(REQUESTED_ALPHA_BITS); - reqNumSamples = qualityToSamples(antialias); - - if (WINDOW_TOOLKIT == AWT) { - if (sharedCtx == null) { - canvasAWT = new GLCanvas(caps); - } else { - canvasAWT = new GLCanvas(caps, sharedCtx); - } - canvasAWT.setBounds(0, 0, pg.width, pg.height); - canvasAWT.setBackground(new Color(pg.backgroundColor, true)); - canvasAWT.setFocusable(true); - - pg.parent.setLayout(new BorderLayout()); - pg.parent.add(canvasAWT, BorderLayout.CENTER); - canvasAWT.requestFocusInWindow(); - - pg.parent.removeListeners(pg.parent); - pg.parent.addListeners(canvasAWT); - - canvas = canvasAWT; - canvasNEWT = null; - - listener = new PGLListener(); - canvasAWT.addGLEventListener(listener); - } else if (WINDOW_TOOLKIT == NEWT) { - window = GLWindow.create(caps); - if (sharedCtx != null) { - window.setSharedContext(sharedCtx); - } - canvasNEWT = new NewtCanvasAWT(window); - canvasNEWT.setBounds(0, 0, pg.width, pg.height); - canvasNEWT.setBackground(new Color(pg.backgroundColor, true)); - canvasNEWT.setFocusable(true); - - pg.parent.setLayout(new BorderLayout()); - pg.parent.add(canvasNEWT, BorderLayout.CENTER); - canvasNEWT.requestFocusInWindow(); - - if (EVENTS_TOOLKIT == NEWT) { - NEWTMouseListener mouseListener = new NEWTMouseListener(); - window.addMouseListener(mouseListener); - NEWTKeyListener keyListener = new NEWTKeyListener(); - window.addKeyListener(keyListener); - NEWTWindowListener winListener = new NEWTWindowListener(); - window.addWindowListener(winListener); - } else if (EVENTS_TOOLKIT == AWT) { - pg.parent.removeListeners(canvasNEWT); - pg.parent.addListeners(canvasNEWT); - } - - canvas = canvasNEWT; - canvasAWT = null; - - listener = new PGLListener(); - window.addGLEventListener(listener); - } - - canvas.setFocusTraversalKeysEnabled(false); - - fboLayerCreated = false; - fboLayerInUse = false; - firstFrame = true; - - setFps = false; - } - + protected void initSurface(int antialias) { } protected void deleteSurface() { if (threadIsCurrent() && fboLayerCreated) { @@ -630,109 +344,34 @@ public class PGL { deleteRenderbuffers(1, glStencil); } - if (canvasAWT != null) { - canvasAWT.removeGLEventListener(listener); - pg.parent.removeListeners(canvasAWT); - } else if (canvasNEWT != null) { - window.removeGLEventListener(listener); - } - fboLayerCreated = false; fboLayerInUse = false; firstFrame = false; - - GLProfile.shutdown(); } + protected int getReadFramebuffer() { return 0; } - protected int getReadFramebuffer() { - if (fboLayerInUse) { - return glColorFbo.get(0); - } else if (capabilities.isFBO()) { - return context.getDefaultReadFramebuffer(); - } else { - return 0; - } - } + protected int getDrawFramebuffer() { return 0; } + + protected int getDefaultDrawBuffer() { return 0; } + + protected int getDefaultReadBuffer() { return 0; } - protected int getDrawFramebuffer() { - if (fboLayerInUse) { - if (1 < numSamples) { - return glMultiFbo.get(0); - } else { - return glColorFbo.get(0); - } - } else if (capabilities.isFBO()) { - return context.getDefaultDrawFramebuffer(); - } else { - return 0; - } - } - - - protected int getDefaultDrawBuffer() { - if (fboLayerInUse) { - return COLOR_ATTACHMENT0; - } else if (capabilities.isFBO()) { - return GL.GL_COLOR_ATTACHMENT0; - } else if (capabilities.getDoubleBuffered()) { - return GL.GL_BACK; - } else { - return GL.GL_FRONT; - } - } - - - protected int getDefaultReadBuffer() { - if (fboLayerInUse) { - return COLOR_ATTACHMENT0; - } else if (capabilities.isFBO()) { - return GL.GL_COLOR_ATTACHMENT0; - } else if (capabilities.getDoubleBuffered()) { - return GL.GL_BACK; - } else { - return GL.GL_FRONT; - } - } - - - protected boolean isFBOBacked() { - return fboLayerInUse || capabilities.isFBO(); - } + protected boolean isFBOBacked() { return false; } protected void requestFBOLayer() { fboLayerRequested = true; } - protected boolean isMultisampled() { return 1 < numSamples; } + protected int getDepthBits() { return 0; } - protected int getDepthBits() { - if (USE_JOGL_FBOLAYER) { - return capabilities.getDepthBits(); - } else { - intBuffer.rewind(); - getIntegerv(DEPTH_BITS, intBuffer); - return intBuffer.get(0); - } - } - - - protected int getStencilBits() { - if (USE_JOGL_FBOLAYER) { - return capabilities.getStencilBits(); - } else { - intBuffer.rewind(); - getIntegerv(STENCIL_BITS, intBuffer); - return intBuffer.get(0); - } - } - + protected int getStencilBits() { return 0; } protected boolean getDepthTest() { intBuffer.rewind(); @@ -740,141 +379,21 @@ public class PGL { return intBuffer.get(0) == 0 ? false : true; } - protected boolean getDepthWriteMask() { intBuffer.rewind(); getBooleanv(DEPTH_WRITEMASK, intBuffer); return intBuffer.get(0) == 0 ? false : true; } + protected Texture wrapBackTexture(Texture texture) { return null; } - protected Texture wrapBackTexture(Texture texture) { - if (texture == null || changedBackTex) { - if (USE_JOGL_FBOLAYER) { - texture = new Texture(); - texture.init(pg.width, pg.height, - backTexAttach.getName(), TEXTURE_2D, RGBA, - backTexAttach.getWidth(), backTexAttach.getHeight(), - backTexAttach.minFilter, backTexAttach.magFilter, - backTexAttach.wrapS, backTexAttach.wrapT); - texture.invertedY(true); - texture.colorBuffer(true); - pg.setCache(pg, texture); - } else { - texture = new Texture(); - texture.init(pg.width, pg.height, - glColorTex.get(backTex), TEXTURE_2D, RGBA, - fboWidth, fboHeight, NEAREST, NEAREST, - CLAMP_TO_EDGE, CLAMP_TO_EDGE); - texture.invertedY(true); - texture.colorBuffer(true); - pg.setCache(pg, texture); - } - } else { - if (USE_JOGL_FBOLAYER) { - texture.glName = backTexAttach.getName(); - } else { - texture.glName = glColorTex.get(backTex); - } - } - return texture; - } + protected Texture wrapFrontTexture(Texture texture) { return null; } + protected void bindFrontTexture() { } - protected Texture wrapFrontTexture(Texture texture) { - if (texture == null || changedFrontTex) { - if (USE_JOGL_FBOLAYER) { - texture = new Texture(); - texture.init(pg.width, pg.height, - backTexAttach.getName(), TEXTURE_2D, RGBA, - frontTexAttach.getWidth(), frontTexAttach.getHeight(), - frontTexAttach.minFilter, frontTexAttach.magFilter, - frontTexAttach.wrapS, frontTexAttach.wrapT); - texture.invertedY(true); - texture.colorBuffer(true); - } else { - texture = new Texture(); - texture.init(pg.width, pg.height, - glColorTex.get(frontTex), TEXTURE_2D, RGBA, - fboWidth, fboHeight, NEAREST, NEAREST, - CLAMP_TO_EDGE, CLAMP_TO_EDGE); - texture.invertedY(true); - texture.colorBuffer(true); - } - } else { - if (USE_JOGL_FBOLAYER) { - texture.glName = frontTexAttach.getName(); - } else { - texture.glName = glColorTex.get(frontTex); - } - } - return texture; - } - - - protected void bindFrontTexture() { - usingFrontTex = true; - if (USE_JOGL_FBOLAYER) { - if (!texturingIsEnabled(TEXTURE_2D)) { - enableTexturing(TEXTURE_2D); - } - bindTexture(TEXTURE_2D, frontTexAttach.getName()); - } else { - if (!texturingIsEnabled(TEXTURE_2D)) { - enableTexturing(TEXTURE_2D); - } - bindTexture(TEXTURE_2D, glColorTex.get(frontTex)); - } - } - - - protected void unbindFrontTexture() { - if (USE_JOGL_FBOLAYER) { - if (textureIsBound(TEXTURE_2D, frontTexAttach.getName())) { - // We don't want to unbind another texture - // that might be bound instead of this one. - if (!texturingIsEnabled(TEXTURE_2D)) { - enableTexturing(TEXTURE_2D); - bindTexture(TEXTURE_2D, 0); - disableTexturing(TEXTURE_2D); - } else { - bindTexture(TEXTURE_2D, 0); - } - } - } else { - if (textureIsBound(TEXTURE_2D, glColorTex.get(frontTex))) { - // We don't want to unbind another texture - // that might be bound instead of this one. - if (!texturingIsEnabled(TEXTURE_2D)) { - enableTexturing(TEXTURE_2D); - bindTexture(TEXTURE_2D, 0); - disableTexturing(TEXTURE_2D); - } else { - bindTexture(TEXTURE_2D, 0); - } - } - } - } - - - protected void syncBackTexture() { - if (usingFrontTex) needSepFrontTex = true; - if (USE_JOGL_FBOLAYER) { - if (1 < numSamples) { - backFBO.syncSamplingSink(gl); - backFBO.bind(gl); - } - } else { - if (1 < numSamples) { - bindFramebuffer(READ_FRAMEBUFFER, glMultiFbo.get(0)); - bindFramebuffer(DRAW_FRAMEBUFFER, glColorFbo.get(0)); - blitFramebuffer(0, 0, fboWidth, fboHeight, - 0, 0, fboWidth, fboHeight, - COLOR_BUFFER_BIT, NEAREST); - } - } - } + protected void unbindFrontTexture() { } + protected void syncBackTexture() { } protected int qualityToSamples(int quality) { if (quality <= 1) { @@ -1034,10 +553,6 @@ public class PGL { protected void beginDraw(boolean clear0) { - if (!setFps) setFps(targetFps); - - if (USE_JOGL_FBOLAYER) return; - if (needFBOLayer(clear0)) { if (!fboLayerCreated) createFBOLayer(); @@ -1088,51 +603,33 @@ public class PGL { protected void endDraw(boolean clear0) { - if (isFBOBacked()) { - if (USE_JOGL_FBOLAYER) { - if (!clear0 && isFBOBacked() && !isMultisampled()) { - // Draw the back texture into the front texture, which will be used as - // back texture in the next frame. Otherwise flickering will occur if - // the sketch uses "incremental drawing" (background() not called). - frontFBO.bind(gl); - gl.glDisable(GL.GL_BLEND); - drawTexture(TEXTURE_2D, backTexAttach.getName(), - backTexAttach.getWidth(), backTexAttach.getHeight(), - pg.width, pg.height, - 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height); - backFBO.bind(gl); - } - } else if (fboLayerInUse) { - syncBackTexture(); + if (fboLayerInUse) { + syncBackTexture(); - // Draw the contents of the back texture to the screen framebuffer. - bindFramebuffer(FRAMEBUFFER, 0); + // Draw the contents of the back texture to the screen framebuffer. + bindFramebuffer(FRAMEBUFFER, 0); - clearDepth(1); - clearColor(0, 0, 0, 0); - clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT); + clearDepth(1); + clearColor(0, 0, 0, 0); + clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT); - // Render current back texture to screen, without blending. - disable(BLEND); - drawTexture(TEXTURE_2D, glColorTex.get(backTex), - fboWidth, fboHeight, pg.width, pg.height, - 0, 0, pg.width, pg.height, - 0, 0, pg.width, pg.height); + // Render current back texture to screen, without blending. + disable(BLEND); + drawTexture(TEXTURE_2D, glColorTex.get(backTex), + fboWidth, fboHeight, pg.width, pg.height, + 0, 0, pg.width, pg.height, + 0, 0, pg.width, pg.height); - // Swapping front and back textures. - int temp = frontTex; - frontTex = backTex; - backTex = temp; - } + // Swapping front and back textures. + int temp = frontTex; + frontTex = backTex; + backTex = temp; } } - protected void requestFocus() { - if (canvas != null) { - canvas.requestFocus(); - } - } + + protected void requestFocus() { } protected boolean canDraw() { @@ -1140,49 +637,12 @@ public class PGL { } - protected void requestDraw() { - boolean canDraw = pg.parent.canDraw(); - if (pg.initialized && (canDraw || prevCanDraw)) { - try { - drawLatch = new CountDownLatch(1); - if (WINDOW_TOOLKIT == AWT) { - canvasAWT.display(); - } else if (WINDOW_TOOLKIT == NEWT) { - window.display(); - } - try { - drawLatch.await(DRAW_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } + protected void requestDraw() { } - if (canDraw) prevCanDraw = true; - else prevCanDraw = false; - } catch (GLException e) { - // Unwrap GLException so that only the causing exception is shown. - Throwable tr = e.getCause(); - if (tr instanceof RuntimeException) { - throw (RuntimeException)tr; - } else { - throw new RuntimeException(tr); - } - } - } - } + protected void swapBuffers() { } - protected void swapBuffers() { - if (WINDOW_TOOLKIT == AWT) { - canvasAWT.swapBuffers(); - } else if (WINDOW_TOOLKIT == NEWT) { - window.swapBuffers(); - } - } - - - protected boolean threadIsCurrent() { - return Thread.currentThread() == glThread; - } + protected boolean threadIsCurrent() { return false; } protected boolean needFBOLayer(boolean clear0) { @@ -1190,55 +650,10 @@ public class PGL { } - protected void beginGL() { - if (projMatrix == null) { - projMatrix = new float[16]; - } - gl2x.glMatrixMode(GL2.GL_PROJECTION); - projMatrix[ 0] = pg.projection.m00; - projMatrix[ 1] = pg.projection.m10; - projMatrix[ 2] = pg.projection.m20; - projMatrix[ 3] = pg.projection.m30; - projMatrix[ 4] = pg.projection.m01; - projMatrix[ 5] = pg.projection.m11; - projMatrix[ 6] = pg.projection.m21; - projMatrix[ 7] = pg.projection.m31; - projMatrix[ 8] = pg.projection.m02; - projMatrix[ 9] = pg.projection.m12; - projMatrix[10] = pg.projection.m22; - projMatrix[11] = pg.projection.m32; - projMatrix[12] = pg.projection.m03; - projMatrix[13] = pg.projection.m13; - projMatrix[14] = pg.projection.m23; - projMatrix[15] = pg.projection.m33; - gl2x.glLoadMatrixf(projMatrix, 0); - - if (mvMatrix == null) { - mvMatrix = new float[16]; - } - gl2x.glMatrixMode(GL2.GL_MODELVIEW); - mvMatrix[ 0] = pg.modelview.m00; - mvMatrix[ 1] = pg.modelview.m10; - mvMatrix[ 2] = pg.modelview.m20; - mvMatrix[ 3] = pg.modelview.m30; - mvMatrix[ 4] = pg.modelview.m01; - mvMatrix[ 5] = pg.modelview.m11; - mvMatrix[ 6] = pg.modelview.m21; - mvMatrix[ 7] = pg.modelview.m31; - mvMatrix[ 8] = pg.modelview.m02; - mvMatrix[ 9] = pg.modelview.m12; - mvMatrix[10] = pg.modelview.m22; - mvMatrix[11] = pg.modelview.m32; - mvMatrix[12] = pg.modelview.m03; - mvMatrix[13] = pg.modelview.m13; - mvMatrix[14] = pg.modelview.m23; - mvMatrix[15] = pg.modelview.m33; - gl2x.glLoadMatrixf(mvMatrix, 0); - } + protected void beginGL() { } - protected void endGL() { - } + protected void endGL() { } /////////////////////////////////////////////////////////// @@ -1252,92 +667,36 @@ public class PGL { protected int getCurrentContext() { - return context.hashCode(); + return contextID; } + + + + + + + + + + /////////////////////////////////////////////////////////// // Tessellator interface protected Tessellator createTessellator(TessellatorCallback callback) { - return new Tessellator(callback); + return null; } - - protected class Tessellator { - protected GLUtessellator tess; - protected TessellatorCallback callback; - protected GLUCallback gluCallback; - - public Tessellator(TessellatorCallback callback) { - this.callback = callback; - tess = GLU.gluNewTess(); - gluCallback = new GLUCallback(); - - GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_END, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR, gluCallback); - } - - public void beginPolygon() { - GLU.gluTessBeginPolygon(tess, null); - } - - public void endPolygon() { - GLU.gluTessEndPolygon(tess); - } - - public void setWindingRule(int rule) { - GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, rule); - } - - public void beginContour() { - GLU.gluTessBeginContour(tess); - } - - public void endContour() { - GLU.gluTessEndContour(tess); - } - - public void addVertex(double[] v) { - GLU.gluTessVertex(tess, v, 0, v); - } - - protected class GLUCallback extends GLUtessellatorCallbackAdapter { - @Override - public void begin(int type) { - callback.begin(type); - } - - @Override - public void end() { - callback.end(); - } - - @Override - public void vertex(Object data) { - callback.vertex(data); - } - - @Override - public void combine(double[] coords, Object[] data, - float[] weight, Object[] outData) { - callback.combine(coords, data, weight, outData); - } - - @Override - public void error(int errnum) { - callback.error(errnum); - } - } - } - - protected String tessError(int err) { - return glu.gluErrorString(err); + protected interface Tessellator { + public void beginPolygon(); + public void endPolygon(); + public void setWindingRule(int rule); + public void beginContour(); + public void endContour(); + public void addVertex(double[] v); } protected interface TessellatorCallback { @@ -1349,57 +708,54 @@ public class PGL { public void error(int errnum); } + protected String tessError(int err) { + return ""; + } + /////////////////////////////////////////////////////////// // FontOutline interface - protected final static boolean SHAPE_TEXT_SUPPORTED = true; + protected static boolean SHAPE_TEXT_SUPPORTED; - protected final static int SEG_MOVETO = PathIterator.SEG_MOVETO; - protected final static int SEG_LINETO = PathIterator.SEG_LINETO; - protected final static int SEG_QUADTO = PathIterator.SEG_QUADTO; - protected final static int SEG_CUBICTO = PathIterator.SEG_CUBICTO; - protected final static int SEG_CLOSE = PathIterator.SEG_CLOSE; + protected static int SEG_MOVETO; + protected static int SEG_LINETO; + protected static int SEG_QUADTO; + protected static int SEG_CUBICTO; + protected static int SEG_CLOSE; protected FontOutline createFontOutline(char ch, Object font) { - return new FontOutline(ch, font); + return null; } - protected class FontOutline { - PathIterator iter; - - public FontOutline(char ch, Object font) { - char textArray[] = new char[] { ch }; - Graphics2D graphics = (Graphics2D) pg.parent.getGraphics(); - FontRenderContext frc = graphics.getFontRenderContext(); - GlyphVector gv = ((Font)font).createGlyphVector(frc, textArray); - Shape shp = gv.getOutline(); - iter = shp.getPathIterator(null); - } - - public boolean isDone() { - return iter.isDone(); - } - - public int currentSegment(float coords[]) { - return iter.currentSegment(coords); - } - - public void next() { - iter.next(); - } + protected interface FontOutline { + public boolean isDone(); + public int currentSegment(float coords[]); + public void next(); } + + + + + + + + + + + + /////////////////////////////////////////////////////////// // Utility functions protected boolean contextIsCurrent(int other) { - return other == -1 || other == context.hashCode(); + return other == -1 || other == contextID; } @@ -1518,8 +874,7 @@ public class PGL { protected void drawTexture2D(int id, int texW, int texH, int scrW, int scrH, int texX0, int texY0, int texX1, int texY1, int scrX0, int scrY0, int scrX1, int scrY1) { - if (!loadedTex2DShader || - tex2DShaderContext.hashCode() != context.hashCode()) { + if (!loadedTex2DShader || tex2DShaderContext != contextID) { tex2DVertShader = createShader(VERTEX_SHADER, texVertShaderSource); tex2DFragShader = createShader(FRAGMENT_SHADER, tex2DFragShaderSource); if (0 < tex2DVertShader && 0 < tex2DFragShader) { @@ -1530,7 +885,7 @@ public class PGL { tex2DTCoordLoc = getAttribLocation(tex2DShaderProgram, "inTexcoord"); } loadedTex2DShader = true; - tex2DShaderContext = context; + tex2DShaderContext = contextID; } if (texData == null) { @@ -1630,8 +985,7 @@ public class PGL { protected void drawTextureRect(int id, int texW, int texH, int scrW, int scrH, int texX0, int texY0, int texX1, int texY1, int scrX0, int scrY0, int scrX1, int scrY1) { - if (!loadedTexRectShader || - texRectShaderContext.hashCode() != context.hashCode()) { + if (!loadedTexRectShader || texRectShaderContext != contextID) { texRectVertShader = createShader(VERTEX_SHADER, texVertShaderSource); texRectFragShader = createShader(FRAGMENT_SHADER, texRectFragShaderSource); if (0 < texRectVertShader && 0 < texRectFragShader) { @@ -1643,7 +997,7 @@ public class PGL { texRectTCoordLoc = getAttribLocation(texRectShaderProgram, "inTexcoord"); } loadedTexRectShader = true; - texRectShaderContext = context; + texRectShaderContext = contextID; } if (texData == null) { @@ -2121,13 +1475,21 @@ public class PGL { protected boolean hasFBOs() { - return context.hasBasicFBOSupport(); + // FBOs might still be available through extensions. + int major = getGLVersion()[0]; + if (major < 2) { + String ext = getString(EXTENSIONS); + return ext.indexOf("_framebuffer_object") != -1 && + ext.indexOf("_vertex_shader") != -1 && + ext.indexOf("_shader_objects") != -1 && + ext.indexOf("_shading_language") != -1; + } else { + return true; + } } protected boolean hasShaders() { - if (context.hasGLSL()) return true; - // GLSL might still be available through extensions. For instance, // GLContext.hasGLSL() gives false for older intel integrated chipsets on // OSX, where OpenGL is 1.4 but shaders are available. @@ -2138,9 +1500,9 @@ public class PGL { ext.indexOf("_vertex_shader") != -1 && ext.indexOf("_shader_objects") != -1 && ext.indexOf("_shading_language") != -1; + } else { + return true; } - - return false; } @@ -2512,272 +1874,7 @@ public class PGL { } - /////////////////////////////////////////////////////////// - // Event listeners - protected boolean changedFrontTex = false; - protected boolean changedBackTex = false; - - protected class PGLListener implements GLEventListener { - public PGLListener() {} - - @Override - public void display(GLAutoDrawable glDrawable) { - drawable = glDrawable; - context = glDrawable.getContext(); - - glThread = Thread.currentThread(); - - gl = context.getGL(); - gl2 = gl.getGL2ES2(); - try { - gl2x = gl.getGL2(); - } catch (javax.media.opengl.GLException e) { - gl2x = null; - } - - if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { - // The onscreen drawing surface is backed by an FBO layer. - GLFBODrawable fboDrawable = null; - - if (WINDOW_TOOLKIT == AWT) { - GLCanvas glCanvas = (GLCanvas)glDrawable; - fboDrawable = (GLFBODrawable)glCanvas.getDelegatedDrawable(); - } else { - GLWindow glWindow = (GLWindow)glDrawable; - fboDrawable = (GLFBODrawable)glWindow.getDelegatedDrawable(); - } - - if (fboDrawable != null) { - backFBO = fboDrawable.getFBObject(GL.GL_BACK); - if (1 < numSamples) { - if (needSepFrontTex) { - // When using multisampled FBO, the back buffer is the MSAA - // surface so it cannot be read from. The sink buffer contains - // the readable 2D texture. - // In this case, we create an auxiliary "front" buffer that it is - // swapped with the sink buffer at the beginning of each frame. - // In this way, we always have a readable copy of the previous - // frame in the front texture, while the back is synchronized - // with the contents of the MSAA back buffer when requested. - if (frontFBO == null) { - // init - frontFBO = new FBObject(); - frontFBO.reset(gl, pg.width, pg.height); - frontFBO.attachTexture2D(gl, 0, true); - sinkFBO = backFBO.getSamplingSinkFBO(); - changedFrontTex = changedBackTex = true; - } else { - // swap - FBObject temp = sinkFBO; - sinkFBO = frontFBO; - frontFBO = temp; - backFBO.setSamplingSink(sinkFBO); - changedFrontTex = changedBackTex = false; - } - backTexAttach = (FBObject.TextureAttachment) sinkFBO. - getColorbuffer(0); - frontTexAttach = (FBObject.TextureAttachment)frontFBO. - getColorbuffer(0); - } else { - // Default setting (to save resources): the front and back - // textures are the same. - sinkFBO = backFBO.getSamplingSinkFBO(); - backTexAttach = (FBObject.TextureAttachment) sinkFBO. - getColorbuffer(0); - frontTexAttach = backTexAttach; - } - - } else { - // w/out multisampling, rendering is done on the back buffer. - frontFBO = fboDrawable.getFBObject(GL.GL_FRONT); - - backTexAttach = fboDrawable.getTextureBuffer(GL.GL_BACK); - frontTexAttach = fboDrawable.getTextureBuffer(GL.GL_FRONT); - } - } - } - - pg.parent.handleDraw(); - drawLatch.countDown(); - } - - @Override - public void dispose(GLAutoDrawable adrawable) { - } - - @Override - public void init(GLAutoDrawable adrawable) { - drawable = adrawable; - context = adrawable.getContext(); - capabilities = adrawable.getChosenGLCapabilities(); - gl = context.getGL(); - - if (!hasFBOs()) { - throw new RuntimeException(MISSING_FBO_ERROR); - } - if (!hasShaders()) { - throw new RuntimeException(MISSING_GLSL_ERROR); - } - if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { - int maxs = maxSamples(); - numSamples = PApplet.min(capabilities.getNumSamples(), maxs); - } - } - - @Override - public void reshape(GLAutoDrawable adrawable, int x, int y, int w, int h) { - drawable = adrawable; - context = adrawable.getContext(); - } - } - - protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent, - int peAction) { - int modifiers = nativeEvent.getModifiers(); - int peModifiers = modifiers & - (InputEvent.SHIFT_MASK | - InputEvent.CTRL_MASK | - InputEvent.META_MASK | - InputEvent.ALT_MASK); - - int peButton = 0; - if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { - peButton = PConstants.LEFT; - } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { - peButton = PConstants.CENTER; - } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { - peButton = PConstants.RIGHT; - } - - if (PApplet.platform == PConstants.MACOSX) { - //if (nativeEvent.isPopupTrigger()) { - if ((modifiers & InputEvent.CTRL_MASK) != 0) { - peButton = PConstants.RIGHT; - } - } - - int peCount = 0; - if (peAction == MouseEvent.WHEEL) { - peCount = nativeEvent.isShiftDown() ? (int)nativeEvent.getRotation()[0] : - (int)nativeEvent.getRotation()[1]; - } else { - peCount = nativeEvent.getClickCount(); - } - - MouseEvent me = new MouseEvent(nativeEvent, nativeEvent.getWhen(), - peAction, peModifiers, - nativeEvent.getX(), nativeEvent.getY(), - peButton, - peCount); - - pg.parent.postEvent(me); - } - - protected void nativeKeyEvent(com.jogamp.newt.event.KeyEvent nativeEvent, - int peAction) { - int peModifiers = nativeEvent.getModifiers() & - (InputEvent.SHIFT_MASK | - InputEvent.CTRL_MASK | - InputEvent.META_MASK | - InputEvent.ALT_MASK); - - char keyChar; - if ((int)nativeEvent.getKeyChar() == 0) { - keyChar = PConstants.CODED; - } else { - keyChar = nativeEvent.getKeyChar(); - } - - KeyEvent ke = new KeyEvent(nativeEvent, nativeEvent.getWhen(), - peAction, peModifiers, - keyChar, - nativeEvent.getKeyCode()); - - pg.parent.postEvent(ke); - } - - class NEWTWindowListener implements com.jogamp.newt.event.WindowListener { - @Override - public void windowGainedFocus(com.jogamp.newt.event.WindowEvent arg0) { - pg.parent.focusGained(null); - } - - @Override - public void windowLostFocus(com.jogamp.newt.event.WindowEvent arg0) { - pg.parent.focusLost(null); - } - - @Override - public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) { - } - - @Override - public void windowDestroyed(com.jogamp.newt.event.WindowEvent arg0) { - } - - @Override - public void windowMoved(com.jogamp.newt.event.WindowEvent arg0) { - } - - @Override - public void windowRepaint(com.jogamp.newt.event.WindowUpdateEvent arg0) { - } - - @Override - public void windowResized(com.jogamp.newt.event.WindowEvent arg0) { } - } - - // NEWT mouse listener - class NEWTMouseListener extends com.jogamp.newt.event.MouseAdapter { - @Override - public void mousePressed(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.PRESS); - } - @Override - public void mouseReleased(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.RELEASE); - } - @Override - public void mouseClicked(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.CLICK); - } - @Override - public void mouseDragged(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.DRAG); - } - @Override - public void mouseMoved(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.MOVE); - } - @Override - public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.WHEEL); - } - @Override - public void mouseEntered(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.ENTER); - } - @Override - public void mouseExited(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.EXIT); - } - } - - // NEWT key listener - class NEWTKeyListener extends com.jogamp.newt.event.KeyAdapter { - @Override - public void keyPressed(com.jogamp.newt.event.KeyEvent e) { - nativeKeyEvent(e, KeyEvent.PRESS); - } - @Override - public void keyReleased(com.jogamp.newt.event.KeyEvent e) { - nativeKeyEvent(e, KeyEvent.RELEASE); - } - public void keyTyped(com.jogamp.newt.event.KeyEvent e) { - nativeKeyEvent(e, KeyEvent.TYPE); - } - } ////////////////////////////////////////////////////////////////////////////// @@ -2792,441 +1889,369 @@ public class PGL { // The entire GLES 2.0 specification is available below: // http://www.khronos.org/opengles/2_X/ // + // Implementations of the PGL functions for specific OpenGL bindings (JOGL, + // LWJGL) should simply call the corresponding GL function in the bindings. + // readPixels(), activeTexture() and bindTexture() are special cases, please + // read their comments. + // Also, keep in mind the note about the PGL constants below. + // ////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// // Constants + // Very important note: set the GL constants in your PGL subclass by using an + // initialization block as follows: + // static { + // FALSE = SUPER_DUPER_JAVA_OPENGL_BINDINGS.GL_FALSE; + // TRUE = SUPER_DUPER_JAVA_OPENGL_BINDINGS.GL_TRUE; + // ... + // } + // and not by re-declaring the constants, because doing so will lead to + // errors when the constants are accessed through PGL because they are not + // overridden but hidden by the new declarations, and hence they keep their + // initial values (all zeroes) when accessed through the superclass. - public static final int FALSE = GL.GL_FALSE; - public static final int TRUE = GL.GL_TRUE; + public static int FALSE; + public static int TRUE; - public static final int INT = GL2.GL_INT; - public static final int BYTE = GL.GL_BYTE; - public static final int SHORT = GL.GL_SHORT; - public static final int FLOAT = GL.GL_FLOAT; - public static final int BOOL = GL2.GL_BOOL; - public static final int UNSIGNED_INT = GL.GL_UNSIGNED_INT; - public static final int UNSIGNED_BYTE = GL.GL_UNSIGNED_BYTE; - public static final int UNSIGNED_SHORT = GL.GL_UNSIGNED_SHORT; + public static int INT; + public static int BYTE; + public static int SHORT; + public static int FLOAT; + public static int BOOL; + public static int UNSIGNED_INT; + public static int UNSIGNED_BYTE; + public static int UNSIGNED_SHORT; - public static final int RGB = GL.GL_RGB; - public static final int RGBA = GL.GL_RGBA; - public static final int ALPHA = GL.GL_ALPHA; - public static final int LUMINANCE = GL.GL_LUMINANCE; - public static final int LUMINANCE_ALPHA = GL.GL_LUMINANCE_ALPHA; + public static int RGB; + public static int RGBA; + public static int ALPHA; + public static int LUMINANCE; + public static int LUMINANCE_ALPHA; - public static final int UNSIGNED_SHORT_5_6_5 = GL.GL_UNSIGNED_SHORT_5_6_5; - public static final int UNSIGNED_SHORT_4_4_4_4 = GL.GL_UNSIGNED_SHORT_4_4_4_4; - public static final int UNSIGNED_SHORT_5_5_5_1 = GL.GL_UNSIGNED_SHORT_5_5_5_1; + public static int UNSIGNED_SHORT_5_6_5; + public static int UNSIGNED_SHORT_4_4_4_4; + public static int UNSIGNED_SHORT_5_5_5_1; - public static final int RGBA4 = GL2.GL_RGBA4; - public static final int RGB5_A1 = GL2.GL_RGB5_A1; - public static final int RGB565 = GL2.GL_RGB565; + public static int RGBA4; + public static int RGB5_A1; + public static int RGB565; - public static final int READ_ONLY = GL2.GL_READ_ONLY; - public static final int WRITE_ONLY = GL2.GL_WRITE_ONLY; - public static final int READ_WRITE = GL2.GL_READ_WRITE; + public static int READ_ONLY; + public static int WRITE_ONLY; + public static int READ_WRITE; - public static final int TESS_WINDING_NONZERO = GLU.GLU_TESS_WINDING_NONZERO; - public static final int TESS_WINDING_ODD = GLU.GLU_TESS_WINDING_ODD; + public static int TESS_WINDING_NONZERO; + public static int TESS_WINDING_ODD; - public static final int GENERATE_MIPMAP_HINT = GL.GL_GENERATE_MIPMAP_HINT; - public static final int FASTEST = GL.GL_FASTEST; - public static final int NICEST = GL.GL_NICEST; - public static final int DONT_CARE = GL.GL_DONT_CARE; + public static int GENERATE_MIPMAP_HINT; + public static int FASTEST; + public static int NICEST; + public static int DONT_CARE; - public static final int VENDOR = GL.GL_VENDOR; - public static final int RENDERER = GL.GL_RENDERER; - public static final int VERSION = GL.GL_VERSION; - public static final int EXTENSIONS = GL.GL_EXTENSIONS; - public static final int SHADING_LANGUAGE_VERSION = GL2ES2.GL_SHADING_LANGUAGE_VERSION; + public static int VENDOR; + public static int RENDERER; + public static int VERSION; + public static int EXTENSIONS; + public static int SHADING_LANGUAGE_VERSION; - public static final int MAX_SAMPLES = GL2.GL_MAX_SAMPLES; - public static final int SAMPLES = GL.GL_SAMPLES; + public static int MAX_SAMPLES; + public static int SAMPLES; - public static final int ALIASED_LINE_WIDTH_RANGE = GL.GL_ALIASED_LINE_WIDTH_RANGE; - public static final int ALIASED_POINT_SIZE_RANGE = GL.GL_ALIASED_POINT_SIZE_RANGE; + public static int ALIASED_LINE_WIDTH_RANGE; + public static int ALIASED_POINT_SIZE_RANGE; - public static final int DEPTH_BITS = GL.GL_DEPTH_BITS; - public static final int STENCIL_BITS = GL.GL_STENCIL_BITS; + public static int DEPTH_BITS; + public static int STENCIL_BITS; - public static final int CCW = GL.GL_CCW; - public static final int CW = GL.GL_CW; + public static int CCW; + public static int CW; - public static final int VIEWPORT = GL.GL_VIEWPORT; + public static int VIEWPORT; - public static final int ARRAY_BUFFER = GL.GL_ARRAY_BUFFER; - public static final int ELEMENT_ARRAY_BUFFER = GL.GL_ELEMENT_ARRAY_BUFFER; + public static int ARRAY_BUFFER; + public static int ELEMENT_ARRAY_BUFFER; - public static final int MAX_VERTEX_ATTRIBS = GL2.GL_MAX_VERTEX_ATTRIBS; + public static int MAX_VERTEX_ATTRIBS; - public static final int STATIC_DRAW = GL.GL_STATIC_DRAW; - public static final int DYNAMIC_DRAW = GL.GL_DYNAMIC_DRAW; - public static final int STREAM_DRAW = GL2.GL_STREAM_DRAW; + public static int STATIC_DRAW; + public static int DYNAMIC_DRAW; + public static int STREAM_DRAW; - public static final int BUFFER_SIZE = GL.GL_BUFFER_SIZE; - public static final int BUFFER_USAGE = GL.GL_BUFFER_USAGE; + public static int BUFFER_SIZE; + public static int BUFFER_USAGE; - public static final int POINTS = GL.GL_POINTS; - public static final int LINE_STRIP = GL.GL_LINE_STRIP; - public static final int LINE_LOOP = GL.GL_LINE_LOOP; - public static final int LINES = GL.GL_LINES; - public static final int TRIANGLE_FAN = GL.GL_TRIANGLE_FAN; - public static final int TRIANGLE_STRIP = GL.GL_TRIANGLE_STRIP; - public static final int TRIANGLES = GL.GL_TRIANGLES; + public static int POINTS; + public static int LINE_STRIP; + public static int LINE_LOOP; + public static int LINES; + public static int TRIANGLE_FAN; + public static int TRIANGLE_STRIP; + public static int TRIANGLES; - public static final int CULL_FACE = GL.GL_CULL_FACE; - public static final int FRONT = GL.GL_FRONT; - public static final int BACK = GL.GL_BACK; - public static final int FRONT_AND_BACK = GL.GL_FRONT_AND_BACK; + public static int CULL_FACE; + public static int FRONT; + public static int BACK; + public static int FRONT_AND_BACK; - public static final int POLYGON_OFFSET_FILL = GL.GL_POLYGON_OFFSET_FILL; + public static int POLYGON_OFFSET_FILL; - public static final int UNPACK_ALIGNMENT = GL.GL_UNPACK_ALIGNMENT; - public static final int PACK_ALIGNMENT = GL.GL_PACK_ALIGNMENT; + public static int UNPACK_ALIGNMENT; + public static int PACK_ALIGNMENT; - public static final int TEXTURE_2D = GL.GL_TEXTURE_2D; - public static final int TEXTURE_RECTANGLE = GL2.GL_TEXTURE_RECTANGLE; + public static int TEXTURE_2D; + public static int TEXTURE_RECTANGLE; - public static final int TEXTURE_BINDING_2D = GL.GL_TEXTURE_BINDING_2D; - public static final int TEXTURE_BINDING_RECTANGLE = GL2.GL_TEXTURE_BINDING_RECTANGLE; + public static int TEXTURE_BINDING_2D; + public static int TEXTURE_BINDING_RECTANGLE; - public static final int MAX_TEXTURE_SIZE = GL.GL_MAX_TEXTURE_SIZE; - public static final int TEXTURE_MAX_ANISOTROPY = GL.GL_TEXTURE_MAX_ANISOTROPY_EXT; - public static final int MAX_TEXTURE_MAX_ANISOTROPY = GL.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT; + public static int MAX_TEXTURE_SIZE; + public static int TEXTURE_MAX_ANISOTROPY; + public static int MAX_TEXTURE_MAX_ANISOTROPY; - public static final int MAX_VERTEX_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS; - public static final int MAX_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_TEXTURE_IMAGE_UNITS; - public static final int MAX_COMBINED_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS; + public static int MAX_VERTEX_TEXTURE_IMAGE_UNITS; + public static int MAX_TEXTURE_IMAGE_UNITS; + public static int MAX_COMBINED_TEXTURE_IMAGE_UNITS; - public static final int NUM_COMPRESSED_TEXTURE_FORMATS = GL2ES2.GL_NUM_COMPRESSED_TEXTURE_FORMATS; - public static final int COMPRESSED_TEXTURE_FORMATS = GL2ES2.GL_COMPRESSED_TEXTURE_FORMATS; + public static int NUM_COMPRESSED_TEXTURE_FORMATS; + public static int COMPRESSED_TEXTURE_FORMATS; - public static final int NEAREST = GL.GL_NEAREST; - public static final int LINEAR = GL.GL_LINEAR; - public static final int LINEAR_MIPMAP_NEAREST = GL.GL_LINEAR_MIPMAP_NEAREST; - public static final int LINEAR_MIPMAP_LINEAR = GL.GL_LINEAR_MIPMAP_LINEAR; + public static int NEAREST; + public static int LINEAR; + public static int LINEAR_MIPMAP_NEAREST; + public static int LINEAR_MIPMAP_LINEAR; - public static final int CLAMP_TO_EDGE = GL.GL_CLAMP_TO_EDGE; - public static final int REPEAT = GL.GL_REPEAT; + public static int CLAMP_TO_EDGE; + public static int REPEAT; - public static final int TEXTURE0 = GL.GL_TEXTURE0; - public static final int TEXTURE1 = GL.GL_TEXTURE1; - public static final int TEXTURE2 = GL.GL_TEXTURE2; - public static final int TEXTURE3 = GL.GL_TEXTURE3; - public static final int TEXTURE_MIN_FILTER = GL.GL_TEXTURE_MIN_FILTER; - public static final int TEXTURE_MAG_FILTER = GL.GL_TEXTURE_MAG_FILTER; - public static final int TEXTURE_WRAP_S = GL.GL_TEXTURE_WRAP_S; - public static final int TEXTURE_WRAP_T = GL.GL_TEXTURE_WRAP_T; - public static final int TEXTURE_WRAP_R = GL2.GL_TEXTURE_WRAP_R; + public static int TEXTURE0; + public static int TEXTURE1; + public static int TEXTURE2; + public static int TEXTURE3; + public static int TEXTURE_MIN_FILTER; + public static int TEXTURE_MAG_FILTER; + public static int TEXTURE_WRAP_S; + public static int TEXTURE_WRAP_T; + public static int TEXTURE_WRAP_R; - public static final int TEXTURE_CUBE_MAP = GL.GL_TEXTURE_CUBE_MAP; - public static final int TEXTURE_CUBE_MAP_POSITIVE_X = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X; - public static final int TEXTURE_CUBE_MAP_POSITIVE_Y = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; - public static final int TEXTURE_CUBE_MAP_POSITIVE_Z = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; - public static final int TEXTURE_CUBE_MAP_NEGATIVE_X = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; - public static final int TEXTURE_CUBE_MAP_NEGATIVE_Y = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; - public static final int TEXTURE_CUBE_MAP_NEGATIVE_Z = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; + public static int TEXTURE_CUBE_MAP; + public static int TEXTURE_CUBE_MAP_POSITIVE_X; + public static int TEXTURE_CUBE_MAP_POSITIVE_Y; + public static int TEXTURE_CUBE_MAP_POSITIVE_Z; + public static int TEXTURE_CUBE_MAP_NEGATIVE_X; + public static int TEXTURE_CUBE_MAP_NEGATIVE_Y; + public static int TEXTURE_CUBE_MAP_NEGATIVE_Z; - public static final int VERTEX_SHADER = GL2.GL_VERTEX_SHADER; - public static final int FRAGMENT_SHADER = GL2.GL_FRAGMENT_SHADER; - public static final int INFO_LOG_LENGTH = GL2.GL_INFO_LOG_LENGTH; - public static final int SHADER_SOURCE_LENGTH = GL2.GL_SHADER_SOURCE_LENGTH; - public static final int COMPILE_STATUS = GL2.GL_COMPILE_STATUS; - public static final int LINK_STATUS = GL2.GL_LINK_STATUS; - public static final int VALIDATE_STATUS = GL2.GL_VALIDATE_STATUS; - public static final int SHADER_TYPE = GL2.GL_SHADER_TYPE; - public static final int DELETE_STATUS = GL2.GL_DELETE_STATUS; + public static int VERTEX_SHADER; + public static int FRAGMENT_SHADER; + public static int INFO_LOG_LENGTH; + public static int SHADER_SOURCE_LENGTH; + public static int COMPILE_STATUS; + public static int LINK_STATUS; + public static int VALIDATE_STATUS; + public static int SHADER_TYPE; + public static int DELETE_STATUS; - public static final int FLOAT_VEC2 = GL2.GL_FLOAT_VEC2; - public static final int FLOAT_VEC3 = GL2.GL_FLOAT_VEC3; - public static final int FLOAT_VEC4 = GL2.GL_FLOAT_VEC4; - public static final int FLOAT_MAT2 = GL2.GL_FLOAT_MAT2; - public static final int FLOAT_MAT3 = GL2.GL_FLOAT_MAT3; - public static final int FLOAT_MAT4 = GL2.GL_FLOAT_MAT4; - public static final int INT_VEC2 = GL2.GL_INT_VEC2; - public static final int INT_VEC3 = GL2.GL_INT_VEC3; - public static final int INT_VEC4 = GL2.GL_INT_VEC4; - public static final int BOOL_VEC2 = GL2.GL_BOOL_VEC2; - public static final int BOOL_VEC3 = GL2.GL_BOOL_VEC3; - public static final int BOOL_VEC4 = GL2.GL_BOOL_VEC4; - public static final int SAMPLER_2D = GL2.GL_SAMPLER_2D; - public static final int SAMPLER_CUBE = GL2.GL_SAMPLER_CUBE; + public static int FLOAT_VEC2; + public static int FLOAT_VEC3; + public static int FLOAT_VEC4; + public static int FLOAT_MAT2; + public static int FLOAT_MAT3; + public static int FLOAT_MAT4; + public static int INT_VEC2; + public static int INT_VEC3; + public static int INT_VEC4; + public static int BOOL_VEC2; + public static int BOOL_VEC3; + public static int BOOL_VEC4; + public static int SAMPLER_2D; + public static int SAMPLER_CUBE; - public static final int LOW_FLOAT = GL2.GL_LOW_FLOAT; - public static final int MEDIUM_FLOAT = GL2.GL_MEDIUM_FLOAT; - public static final int HIGH_FLOAT = GL2.GL_HIGH_FLOAT; - public static final int LOW_INT = GL2.GL_LOW_INT; - public static final int MEDIUM_INT = GL2.GL_MEDIUM_INT; - public static final int HIGH_INT = GL2.GL_HIGH_INT; + public static int LOW_FLOAT; + public static int MEDIUM_FLOAT; + public static int HIGH_FLOAT; + public static int LOW_INT; + public static int MEDIUM_INT; + public static int HIGH_INT; - public static final int CURRENT_VERTEX_ATTRIB = GL2.GL_CURRENT_VERTEX_ATTRIB; + public static int CURRENT_VERTEX_ATTRIB; - public static final int VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = GL2.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING; - public static final int VERTEX_ATTRIB_ARRAY_ENABLED = GL2.GL_VERTEX_ATTRIB_ARRAY_ENABLED; - public static final int VERTEX_ATTRIB_ARRAY_SIZE = GL2.GL_VERTEX_ATTRIB_ARRAY_SIZE; - public static final int VERTEX_ATTRIB_ARRAY_STRIDE = GL2.GL_VERTEX_ATTRIB_ARRAY_STRIDE; - public static final int VERTEX_ATTRIB_ARRAY_TYPE = GL2.GL_VERTEX_ATTRIB_ARRAY_TYPE; - public static final int VERTEX_ATTRIB_ARRAY_NORMALIZED = GL2.GL_VERTEX_ATTRIB_ARRAY_NORMALIZED; - public static final int VERTEX_ATTRIB_ARRAY_POINTER = GL2.GL_VERTEX_ATTRIB_ARRAY_POINTER; + public static int VERTEX_ATTRIB_ARRAY_BUFFER_BINDING; + public static int VERTEX_ATTRIB_ARRAY_ENABLED; + public static int VERTEX_ATTRIB_ARRAY_SIZE; + public static int VERTEX_ATTRIB_ARRAY_STRIDE; + public static int VERTEX_ATTRIB_ARRAY_TYPE; + public static int VERTEX_ATTRIB_ARRAY_NORMALIZED; + public static int VERTEX_ATTRIB_ARRAY_POINTER; - public static final int BLEND = GL.GL_BLEND; - public static final int ONE = GL.GL_ONE; - public static final int ZERO = GL.GL_ZERO; - public static final int SRC_ALPHA = GL.GL_SRC_ALPHA; - public static final int DST_ALPHA = GL.GL_DST_ALPHA; - public static final int ONE_MINUS_SRC_ALPHA = GL.GL_ONE_MINUS_SRC_ALPHA; - public static final int ONE_MINUS_DST_COLOR = GL.GL_ONE_MINUS_DST_COLOR; - public static final int ONE_MINUS_SRC_COLOR = GL.GL_ONE_MINUS_SRC_COLOR; - public static final int DST_COLOR = GL.GL_DST_COLOR; - public static final int SRC_COLOR = GL.GL_SRC_COLOR; + public static int BLEND; + public static int ONE; + public static int ZERO; + public static int SRC_ALPHA; + public static int DST_ALPHA; + public static int ONE_MINUS_SRC_ALPHA; + public static int ONE_MINUS_DST_COLOR; + public static int ONE_MINUS_SRC_COLOR; + public static int DST_COLOR; + public static int SRC_COLOR; - public static final int SAMPLE_ALPHA_TO_COVERAGE = GL.GL_SAMPLE_ALPHA_TO_COVERAGE; - public static final int SAMPLE_COVERAGE = GL.GL_SAMPLE_COVERAGE; + public static int SAMPLE_ALPHA_TO_COVERAGE; + public static int SAMPLE_COVERAGE; - public static final int KEEP = GL.GL_KEEP; - public static final int REPLACE = GL.GL_REPLACE; - public static final int INCR = GL.GL_INCR; - public static final int DECR = GL.GL_DECR; - public static final int INVERT = GL.GL_INVERT; - public static final int INCR_WRAP = GL.GL_INCR_WRAP; - public static final int DECR_WRAP = GL.GL_DECR_WRAP; - public static final int NEVER = GL.GL_NEVER; - public static final int ALWAYS = GL.GL_ALWAYS; + public static int KEEP; + public static int REPLACE; + public static int INCR; + public static int DECR; + public static int INVERT; + public static int INCR_WRAP; + public static int DECR_WRAP; + public static int NEVER; + public static int ALWAYS; - public static final int EQUAL = GL.GL_EQUAL; - public static final int LESS = GL.GL_LESS; - public static final int LEQUAL = GL.GL_LEQUAL; - public static final int GREATER = GL.GL_GREATER; - public static final int GEQUAL = GL.GL_GEQUAL; - public static final int NOTEQUAL = GL.GL_NOTEQUAL; + public static int EQUAL; + public static int LESS; + public static int LEQUAL; + public static int GREATER; + public static int GEQUAL; + public static int NOTEQUAL; - public static final int FUNC_ADD = GL.GL_FUNC_ADD; - public static final int FUNC_MIN = GL2.GL_MIN; - public static final int FUNC_MAX = GL2.GL_MAX; - public static final int FUNC_REVERSE_SUBTRACT = GL.GL_FUNC_REVERSE_SUBTRACT; - public static final int FUNC_SUBTRACT = GL.GL_FUNC_SUBTRACT; + public static int FUNC_ADD; + public static int FUNC_MIN; + public static int FUNC_MAX; + public static int FUNC_REVERSE_SUBTRACT; + public static int FUNC_SUBTRACT; - public static final int DITHER = GL.GL_DITHER; + public static int DITHER; - public static final int CONSTANT_COLOR = GL2.GL_CONSTANT_COLOR; - public static final int CONSTANT_ALPHA = GL2.GL_CONSTANT_ALPHA; - public static final int ONE_MINUS_CONSTANT_COLOR = GL2.GL_ONE_MINUS_CONSTANT_COLOR; - public static final int ONE_MINUS_CONSTANT_ALPHA = GL2.GL_ONE_MINUS_CONSTANT_ALPHA; - public static final int SRC_ALPHA_SATURATE = GL.GL_SRC_ALPHA_SATURATE; + public static int CONSTANT_COLOR; + public static int CONSTANT_ALPHA; + public static int ONE_MINUS_CONSTANT_COLOR; + public static int ONE_MINUS_CONSTANT_ALPHA; + public static int SRC_ALPHA_SATURATE; - public static final int SCISSOR_TEST = GL.GL_SCISSOR_TEST; - public static final int DEPTH_TEST = GL.GL_DEPTH_TEST; - public static final int DEPTH_WRITEMASK = GL.GL_DEPTH_WRITEMASK; - public static final int ALPHA_TEST = GL2.GL_ALPHA_TEST; + public static int SCISSOR_TEST; + public static int DEPTH_TEST; + public static int DEPTH_WRITEMASK; + public static int ALPHA_TEST; - public static final int COLOR_BUFFER_BIT = GL.GL_COLOR_BUFFER_BIT; - public static final int DEPTH_BUFFER_BIT = GL.GL_DEPTH_BUFFER_BIT; - public static final int STENCIL_BUFFER_BIT = GL.GL_STENCIL_BUFFER_BIT; + public static int COLOR_BUFFER_BIT; + public static int DEPTH_BUFFER_BIT; + public static int STENCIL_BUFFER_BIT; - public static final int FRAMEBUFFER = GL.GL_FRAMEBUFFER; - public static final int COLOR_ATTACHMENT0 = GL.GL_COLOR_ATTACHMENT0; - public static final int COLOR_ATTACHMENT1 = GL2.GL_COLOR_ATTACHMENT1; - public static final int COLOR_ATTACHMENT2 = GL2.GL_COLOR_ATTACHMENT2; - public static final int COLOR_ATTACHMENT3 = GL2.GL_COLOR_ATTACHMENT3; - public static final int RENDERBUFFER = GL.GL_RENDERBUFFER; - public static final int DEPTH_ATTACHMENT = GL.GL_DEPTH_ATTACHMENT; - public static final int STENCIL_ATTACHMENT = GL.GL_STENCIL_ATTACHMENT; - public static final int READ_FRAMEBUFFER = GL2.GL_READ_FRAMEBUFFER; - public static final int DRAW_FRAMEBUFFER = GL2.GL_DRAW_FRAMEBUFFER; + public static int FRAMEBUFFER; + public static int COLOR_ATTACHMENT0; + public static int COLOR_ATTACHMENT1; + public static int COLOR_ATTACHMENT2; + public static int COLOR_ATTACHMENT3; + public static int RENDERBUFFER; + public static int DEPTH_ATTACHMENT; + public static int STENCIL_ATTACHMENT; + public static int READ_FRAMEBUFFER; + public static int DRAW_FRAMEBUFFER; - public static final int RGBA8 = GL.GL_RGBA8; - public static final int DEPTH24_STENCIL8 = GL.GL_DEPTH24_STENCIL8; + public static int RGBA8; + public static int DEPTH24_STENCIL8; - public static final int DEPTH_COMPONENT = GL2.GL_DEPTH_COMPONENT; - public static final int DEPTH_COMPONENT16 = GL.GL_DEPTH_COMPONENT16; - public static final int DEPTH_COMPONENT24 = GL.GL_DEPTH_COMPONENT24; - public static final int DEPTH_COMPONENT32 = GL.GL_DEPTH_COMPONENT32; + public static int DEPTH_COMPONENT; + public static int DEPTH_COMPONENT16; + public static int DEPTH_COMPONENT24; + public static int DEPTH_COMPONENT32; - public static final int STENCIL_INDEX = GL2.GL_STENCIL_INDEX; - public static final int STENCIL_INDEX1 = GL.GL_STENCIL_INDEX1; - public static final int STENCIL_INDEX4 = GL.GL_STENCIL_INDEX4; - public static final int STENCIL_INDEX8 = GL.GL_STENCIL_INDEX8; + public static int STENCIL_INDEX; + public static int STENCIL_INDEX1; + public static int STENCIL_INDEX4; + public static int STENCIL_INDEX8; - public static final int DEPTH_STENCIL = GL.GL_DEPTH_STENCIL; + public static int DEPTH_STENCIL; - public static final int FRAMEBUFFER_COMPLETE = GL.GL_FRAMEBUFFER_COMPLETE; - public static final int FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - public static final int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; - public static final int FRAMEBUFFER_INCOMPLETE_DIMENSIONS = GL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; - public static final int FRAMEBUFFER_INCOMPLETE_FORMATS = GL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS; - public static final int FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = GL2.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER; - public static final int FRAMEBUFFER_INCOMPLETE_READ_BUFFER = GL2.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER; - public static final int FRAMEBUFFER_UNSUPPORTED = GL.GL_FRAMEBUFFER_UNSUPPORTED; + public static int FRAMEBUFFER_COMPLETE; + public static int FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + public static int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + public static int FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + public static int FRAMEBUFFER_INCOMPLETE_FORMATS; + public static int FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER; + public static int FRAMEBUFFER_INCOMPLETE_READ_BUFFER; + public static int FRAMEBUFFER_UNSUPPORTED; - public static final int FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = GL2.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE; - public static final int FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = GL2.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME; - public static final int FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = GL2.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL; - public static final int FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = GL2.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE; + public static int FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE; + public static int FRAMEBUFFER_ATTACHMENT_OBJECT_NAME; + public static int FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL; + public static int FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE; - public static final int RENDERBUFFER_WIDTH = GL2.GL_RENDERBUFFER_WIDTH; - public static final int RENDERBUFFER_HEIGHT = GL2.GL_RENDERBUFFER_HEIGHT; - public static final int RENDERBUFFER_RED_SIZE = GL2.GL_RENDERBUFFER_RED_SIZE; - public static final int RENDERBUFFER_GREEN_SIZE = GL2.GL_RENDERBUFFER_GREEN_SIZE; - public static final int RENDERBUFFER_BLUE_SIZE = GL2.GL_RENDERBUFFER_BLUE_SIZE; - public static final int RENDERBUFFER_ALPHA_SIZE = GL2.GL_RENDERBUFFER_ALPHA_SIZE; - public static final int RENDERBUFFER_DEPTH_SIZE = GL2.GL_RENDERBUFFER_DEPTH_SIZE; - public static final int RENDERBUFFER_STENCIL_SIZE = GL2.GL_RENDERBUFFER_STENCIL_SIZE; - public static final int RENDERBUFFER_INTERNAL_FORMAT = GL2.GL_RENDERBUFFER_INTERNAL_FORMAT; + public static int RENDERBUFFER_WIDTH; + public static int RENDERBUFFER_HEIGHT; + public static int RENDERBUFFER_RED_SIZE; + public static int RENDERBUFFER_GREEN_SIZE; + public static int RENDERBUFFER_BLUE_SIZE; + public static int RENDERBUFFER_ALPHA_SIZE; + public static int RENDERBUFFER_DEPTH_SIZE; + public static int RENDERBUFFER_STENCIL_SIZE; + public static int RENDERBUFFER_INTERNAL_FORMAT; - public static final int MULTISAMPLE = GL.GL_MULTISAMPLE; - public static final int POINT_SMOOTH = GL2.GL_POINT_SMOOTH; - public static final int LINE_SMOOTH = GL.GL_LINE_SMOOTH; - public static final int POLYGON_SMOOTH = GL2.GL_POLYGON_SMOOTH; + public static int MULTISAMPLE; + public static int POINT_SMOOTH; + public static int LINE_SMOOTH; + public static int POLYGON_SMOOTH; /////////////////////////////////////////////////////////// // Special Functions - public void flush() { - gl.glFlush(); - } - - public void finish() { - gl.glFinish(); - } - - public void hint(int target, int hint) { - gl.glHint(target, hint); - } + public abstract void flush(); + public abstract void finish(); + public abstract void hint(int target, int hint); /////////////////////////////////////////////////////////// // State and State Requests - public void enable(int value) { - if (-1 < value) { - gl.glEnable(value); - } - } - - public void disable(int value) { - if (-1 < value) { - gl.glDisable(value); - } - } - - public void getBooleanv(int value, IntBuffer data) { - if (-1 < value) { - if (byteBuffer.capacity() < data.capacity()) { - byteBuffer = allocateDirectByteBuffer(data.capacity()); - } - gl.glGetBooleanv(value, byteBuffer); - for (int i = 0; i < data.capacity(); i++) { - data.put(i, byteBuffer.get(i)); - } - } else { - fillIntBuffer(data, 0, data.capacity() - 1, 0); - } - } - - public void getIntegerv(int value, IntBuffer data) { - if (-1 < value) { - gl.glGetIntegerv(value, data); - } else { - fillIntBuffer(data, 0, data.capacity() - 1, 0); - } - } - - public void getFloatv(int value, FloatBuffer data) { - if (-1 < value) { - gl.glGetFloatv(value, data); - } else { - fillFloatBuffer(data, 0, data.capacity() - 1, 0); - } - } - - public boolean isEnabled(int value) { - return gl.glIsEnabled(value); - } - - public String getString(int name) { - return gl.glGetString(name); - } + public abstract void enable(int value); + public abstract void disable(int value); + public abstract void getBooleanv(int value, IntBuffer data); + public abstract void getIntegerv(int value, IntBuffer data); + public abstract void getFloatv(int value, FloatBuffer data); + public abstract boolean isEnabled(int value); + public abstract String getString(int name); /////////////////////////////////////////////////////////// // Error Handling - public int getError() { - return gl.glGetError(); - } - - public String errorString(int err) { - return glu.gluErrorString(err); - } + public abstract int getError(); + public abstract String errorString(int err); ////////////////////////////////////////////////////////////////////////////// // Buffer Objects - public void genBuffers(int n, IntBuffer buffers) { - gl.glGenBuffers(n, buffers); - } - - public void deleteBuffers(int n, IntBuffer buffers) { - gl.glDeleteBuffers(n, buffers); - } - - public void bindBuffer(int target, int buffer) { - gl.glBindBuffer(target, buffer); - } - - public void bufferData(int target, int size, Buffer data, int usage) { - gl.glBufferData(target, size, data, usage); - } - - public void bufferSubData(int target, int offset, int size, Buffer data) { - gl.glBufferSubData(target, offset, size, data); - } - - public void isBuffer(int buffer) { - gl.glIsBuffer(buffer); - } - - public void getBufferParameteriv(int target, int value, IntBuffer data) { - gl.glGetBufferParameteriv(target, value, data); - } - - public ByteBuffer mapBuffer(int target, int access) { - return gl2.glMapBuffer(target, access); - } - - public ByteBuffer mapBufferRange(int target, int offset, int length, int access) { - if (gl2x != null) { - return gl2x.glMapBufferRange(target, offset, length, access); - } else { - return null; - } - } - - public void unmapBuffer(int target) { - gl2.glUnmapBuffer(target); - } + public abstract void genBuffers(int n, IntBuffer buffers); + public abstract void deleteBuffers(int n, IntBuffer buffers); + public abstract void bindBuffer(int target, int buffer); + public abstract void bufferData(int target, int size, Buffer data, int usage); + public abstract void bufferSubData(int target, int offset, int size, Buffer data); + public abstract void isBuffer(int buffer); + public abstract void getBufferParameteriv(int target, int value, IntBuffer data); + public abstract ByteBuffer mapBuffer(int target, int access); + public abstract ByteBuffer mapBufferRange(int target, int offset, int length, int access); + public abstract void unmapBuffer(int target); ////////////////////////////////////////////////////////////////////////////// // Viewport and Clipping - public void depthRangef(float n, float f) { - gl.glDepthRangef(n, f); - } - - public void viewport(int x, int y, int w, int h) { - gl.glViewport(x, y, w, h); - } + public abstract void depthRangef(float n, float f); + public abstract void viewport(int x, int y, int w, int h); ////////////////////////////////////////////////////////////////////////////// // Reading Pixels + // This is a special case: because the renderer might be using an FBO even on + // the main surface, some extra handling might be needed before and after + // reading the pixels. To make this transparent to the user, the actual call + // to glReadPixels() should be done in readPixelsImpl(). - public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer) { + public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer){ boolean needEndBegin = format != STENCIL_INDEX && format != DEPTH_COMPONENT && format != DEPTH_STENCIL; if (needEndBegin) pg.beginReadPixels(); @@ -3234,157 +2259,76 @@ public class PGL { if (needEndBegin) pg.endReadPixels(); } - protected void readPixelsImpl(int x, int y, int width, int height, int format, int type, Buffer buffer) { - gl.glReadPixels(x, y, width, height, format, type, buffer); - } + protected abstract void readPixelsImpl(int x, int y, int width, int height, int format, int type, Buffer buffer); ////////////////////////////////////////////////////////////////////////////// // Vertices - public void vertexAttrib1f(int index, float value) { - gl2.glVertexAttrib1f(index, value); - } - - public void vertexAttrib2f(int index, float value0, float value1) { - gl2.glVertexAttrib2f(index, value0, value1); - } - - public void vertexAttrib3f(int index, float value0, float value1, float value2) { - gl2.glVertexAttrib3f(index, value0, value1, value2); - } - - public void vertexAttrib4f(int index, float value0, float value1, float value2, float value3) { - gl2.glVertexAttrib4f(index, value0, value1, value2, value3); - } - - public void vertexAttrib1fv(int index, FloatBuffer values) { - gl2.glVertexAttrib1fv(index, values); - } - - public void vertexAttrib2fv(int index, FloatBuffer values) { - gl2.glVertexAttrib2fv(index, values); - } - - public void vertexAttrib3fv(int index, FloatBuffer values) { - gl2.glVertexAttrib3fv(index, values); - } - - public void vertexAttri4fv(int index, FloatBuffer values) { - gl2.glVertexAttrib4fv(index, values); - } - - public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, int offset) { - gl2.glVertexAttribPointer(index, size, type, normalized, stride, offset); - } - - public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer data) { - gl2.glVertexAttribPointer(index, size, type, normalized, stride, data); - } - - public void enableVertexAttribArray(int index) { - gl2.glEnableVertexAttribArray(index); - } - - public void disableVertexAttribArray(int index) { - gl2.glDisableVertexAttribArray(index); - } - - public void drawArrays(int mode, int first, int count) { - gl.glDrawArrays(mode, first, count); - } - - public void drawElements(int mode, int count, int type, int offset) { - gl.glDrawElements(mode, count, type, offset); - } - - public void drawElements(int mode, int count, int type, Buffer indices) { - gl.glDrawElements(mode, count, type, indices); - } + public abstract void vertexAttrib1f(int index, float value); + public abstract void vertexAttrib2f(int index, float value0, float value1); + public abstract void vertexAttrib3f(int index, float value0, float value1, float value2); + public abstract void vertexAttrib4f(int index, float value0, float value1, float value2, float value3); + public abstract void vertexAttrib1fv(int index, FloatBuffer values); + public abstract void vertexAttrib2fv(int index, FloatBuffer values); + public abstract void vertexAttrib3fv(int index, FloatBuffer values); + public abstract void vertexAttri4fv(int index, FloatBuffer values); + public abstract void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, int offset); + public abstract void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer data); + public abstract void enableVertexAttribArray(int index); + public abstract void disableVertexAttribArray(int index); + public abstract void drawArrays(int mode, int first, int count); + public abstract void drawElements(int mode, int count, int type, int offset); + public abstract void drawElements(int mode, int count, int type, Buffer indices); ////////////////////////////////////////////////////////////////////////////// // Rasterization - public void lineWidth(float width) { - gl.glLineWidth(width); - } - - public void frontFace(int dir) { - gl.glFrontFace(dir); - } - - public void cullFace(int mode) { - gl.glCullFace(mode); - } - - public void polygonOffset(float factor, float units) { - gl.glPolygonOffset(factor, units); - } + public abstract void lineWidth(float width); + public abstract void frontFace(int dir); + public abstract void cullFace(int mode); + public abstract void polygonOffset(float factor, float units); ////////////////////////////////////////////////////////////////////////////// // Pixel Rectangles - public void pixelStorei(int pname, int param) { - gl.glPixelStorei(pname, param); - } + public abstract void pixelStorei(int pname, int param); /////////////////////////////////////////////////////////// // Texturing + public abstract void texImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, Buffer data); + public abstract void copyTexImage2D(int target, int level, int internalFormat, int x, int y, int width, int height, int border); + public abstract void texSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int type, Buffer data); + public abstract void copyTexSubImage2D(int target, int level, int xOffset, int yOffset, int x, int y, int width, int height); + public abstract void compressedTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int imageSize, Buffer data); + public abstract void compressedTexSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int imageSize, Buffer data); + public abstract void texParameteri(int target, int pname, int param); + public abstract void texParameterf(int target, int pname, float param); + public abstract void texParameteriv(int target, int pname, IntBuffer params); + public abstract void texParameterfv(int target, int pname, FloatBuffer params); + public abstract void generateMipmap(int target); + public abstract void genTextures(int n, IntBuffer textures); + public abstract void deleteTextures(int n, IntBuffer textures); + public abstract void getTexParameteriv(int target, int pname, IntBuffer params); + public abstract void getTexParameterfv(int target, int pname, FloatBuffer params); + public abstract boolean isTexture(int texture); + + // activeTexture() and bindTexture() have some extra logic to keep track of + // the bound textures, so the actual GL call should go in activeTextureImpl() + // and bindTextureImpl(). public void activeTexture(int texture) { - gl.glActiveTexture(texture); activeTexUnit = texture - TEXTURE0; + activeTextureImpl(texture); } - public void texImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, Buffer data) { - gl.glTexImage2D(target, level, internalFormat, width, height, border, format, type, data); - } - - public void copyTexImage2D(int target, int level, int internalFormat, int x, int y, int width, int height, int border) { - gl.glCopyTexImage2D(target, level, internalFormat, x, y, width, height, border); - } - - public void texSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int type, Buffer data) { - gl.glTexSubImage2D(target, level, xOffset, yOffset, width, height, format, type, data); - } - - public void copyTexSubImage2D(int target, int level, int xOffset, int yOffset, int x, int y, int width, int height) { - gl.glCopyTexSubImage2D(target, level, x, y, xOffset, xOffset, width, height); - } - - public void compressedTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int imageSize, Buffer data) { - gl.glCompressedTexImage2D(target, level, internalFormat, width, height, border, imageSize, data); - } - - public void compressedTexSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int imageSize, Buffer data) { - gl.glCompressedTexSubImage2D(target, level, xOffset, yOffset, width, height, format, imageSize, data); - } - - public void texParameteri(int target, int pname, int param) { - gl.glTexParameteri(target, pname, param); - } - - public void texParameterf(int target, int pname, float param) { - gl.glTexParameterf(target, pname, param); - } - - public void texParameteriv(int target, int pname, IntBuffer params) { - gl.glTexParameteriv(target, pname, params); - } - - public void texParameterfv(int target, int pname, FloatBuffer params) { - gl.glTexParameterfv(target, pname, params); - } - - public void generateMipmap(int target) { - gl.glGenerateMipmap(target); - } + protected abstract void activeTextureImpl(int texture); public void bindTexture(int target, int texture) { - gl.glBindTexture(target, texture); + bindTextureImpl(target, texture); if (boundTextures == null) { maxTexUnits = getMaxTexUnits(); @@ -3401,441 +2345,115 @@ public class PGL { boundTextures[activeTexUnit][1] = texture; } } - - public void genTextures(int n, IntBuffer textures) { - gl.glGenTextures(n, textures); - } - - public void deleteTextures(int n, IntBuffer textures) { - gl.glDeleteTextures(n, textures); - } - - public void getTexParameteriv(int target, int pname, IntBuffer params) { - gl.glGetTexParameteriv(target, pname, params); - } - - public void getTexParameterfv(int target, int pname, FloatBuffer params) { - gl.glGetTexParameterfv(target, pname, params); - } - - public boolean isTexture(int texture) { - return gl.glIsTexture(texture); - } + protected abstract void bindTextureImpl(int target, int texture); /////////////////////////////////////////////////////////// // Shaders and Programs - public int createShader(int type) { - return gl2.glCreateShader(type); - } - - public void shaderSource(int shader, String source) { - gl2.glShaderSource(shader, 1, new String[] { source }, (int[]) null, 0); - } - - public void compileShader(int shader) { - gl2.glCompileShader(shader); - } - - public void releaseShaderCompiler() { - gl2.glReleaseShaderCompiler(); - } - - public void deleteShader(int shader) { - gl2.glDeleteShader(shader); - } - - public void shaderBinary(int count, IntBuffer shaders, int binaryFormat, Buffer binary, int length) { - gl2.glShaderBinary(count, shaders, binaryFormat, binary, length); - } - - public int createProgram() { - return gl2.glCreateProgram(); - } - - public void attachShader(int program, int shader) { - gl2.glAttachShader(program, shader); - } - - public void detachShader(int program, int shader) { - gl2.glDetachShader(program, shader); - } - - public void linkProgram(int program) { - gl2.glLinkProgram(program); - } - - public void useProgram(int program) { - gl2.glUseProgram(program); - } - - public void deleteProgram(int program) { - gl2.glDeleteProgram(program); - } - - public String glGetActiveAttrib (int program, int index, IntBuffer size, IntBuffer type) { - int[] tmp = {0, 0, 0}; - byte[] namebuf = new byte[1024]; - gl2.glGetActiveAttrib(program, index, 1024, tmp, 0, tmp, 1, tmp, 2, namebuf, 0); - size.put(tmp[1]); - type.put(tmp[2]); - String name = new String(namebuf, 0, tmp[0]); - return name; - } - - public int getAttribLocation(int program, String name) { - return gl2.glGetAttribLocation(program, name); - } - - public void bindAttribLocation(int program, int index, String name) { - gl2.glBindAttribLocation(program, index, name); - } - - public int getUniformLocation(int program, String name) { - return gl2.glGetUniformLocation(program, name); - } - - public String getActiveUniform(int program, int index, IntBuffer size, IntBuffer type) { - int[] tmp= {0, 0, 0}; - byte[] namebuf = new byte[1024]; - gl2.glGetActiveUniform(program, index, 1024, tmp, 0, tmp, 1, tmp, 2, namebuf, 0); - size.put(tmp[1]); - type.put(tmp[2]); - String name = new String(namebuf, 0, tmp[0]); - return name; - } - - public void uniform1i(int location, int value) { - gl2.glUniform1i(location, value); - } - - public void uniform2i(int location, int value0, int value1) { - gl2.glUniform2i(location, value0, value1); - } - - public void uniform3i(int location, int value0, int value1, int value2) { - gl2.glUniform3i(location, value0, value1, value2); - } - - public void uniform4i(int location, int value0, int value1, int value2, int value3) { - gl2.glUniform4i(location, value0, value1, value2, value3); - } - - public void uniform1f(int location, float value) { - gl2.glUniform1f(location, value); - } - - public void uniform2f(int location, float value0, float value1) { - gl2.glUniform2f(location, value0, value1); - } - - public void uniform3f(int location, float value0, float value1, float value2) { - gl2.glUniform3f(location, value0, value1, value2); - } - - public void uniform4f(int location, float value0, float value1, float value2, float value3) { - gl2.glUniform4f(location, value0, value1, value2, value3); - } - - public void uniform1iv(int location, int count, IntBuffer v) { - gl2.glUniform1iv(location, count, v); - } - - public void uniform2iv(int location, int count, IntBuffer v) { - gl2.glUniform2iv(location, count, v); - } - - public void uniform3iv(int location, int count, IntBuffer v) { - gl2.glUniform3iv(location, count, v); - } - - public void uniform4iv(int location, int count, IntBuffer v) { - gl2.glUniform4iv(location, count, v); - } - - public void uniform1fv(int location, int count, FloatBuffer v) { - gl2.glUniform1fv(location, count, v); - } - - public void uniform2fv(int location, int count, FloatBuffer v) { - gl2.glUniform2fv(location, count, v); - } - - public void uniform3fv(int location, int count, FloatBuffer v) { - gl2.glUniform3fv(location, count, v); - } - - public void uniform4fv(int location, int count, FloatBuffer v) { - gl2.glUniform4fv(location, count, v); - } - - public void uniformMatrix2fv(int location, int count, boolean transpose, FloatBuffer mat) { - gl2.glUniformMatrix2fv(location, count, transpose, mat); - } - - public void uniformMatrix3fv(int location, int count, boolean transpose, FloatBuffer mat) { - gl2.glUniformMatrix3fv(location, count, transpose, mat); - } - - public void uniformMatrix4fv(int location, int count, boolean transpose, FloatBuffer mat) { - gl2.glUniformMatrix4fv(location, count, transpose, mat); - } - - public void validateProgram(int program) { - gl2.glValidateProgram(program); - } - - public boolean isShader(int shader) { - return gl2.glIsShader(shader); - } - - public void getShaderiv(int shader, int pname, IntBuffer params) { - gl2.glGetShaderiv(shader, pname, params); - } - - public void getAttachedShaders(int program, int maxCount, IntBuffer count, IntBuffer shaders) { - gl2.glGetAttachedShaders(program, maxCount, count, shaders); - } - - public String getShaderInfoLog(int shader) { - int[] val = { 0 }; - gl2.glGetShaderiv(shader, GL2.GL_INFO_LOG_LENGTH, val, 0); - int length = val[0]; - - byte[] log = new byte[length]; - gl2.glGetShaderInfoLog(shader, length, val, 0, log, 0); - return new String(log); - } - - public String getShaderSource(int shader) { - int[] len = {0}; - byte[] buf = new byte[1024]; - gl2.glGetShaderSource(shader, 1024, len, 0, buf, 0); - return new String(buf, 0, len[0]); - } - - public void getShaderPrecisionFormat(int shaderType, int precisionType, IntBuffer range, IntBuffer precision) { - gl2.glGetShaderPrecisionFormat(shaderType, precisionType, range, precision); - } - - public void getVertexAttribfv(int index, int pname, FloatBuffer params) { - gl2.glGetVertexAttribfv(index, pname, params); - } - - public void getVertexAttribiv(int index, int pname, IntBuffer params) { - gl2.glGetVertexAttribiv(index, pname, params); - } - - public void getVertexAttribPointerv(int index, int pname, ByteBuffer data) { - throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glGetVertexAttribPointerv()")); - } - - public void getUniformfv(int program, int location, FloatBuffer params) { - gl2.glGetUniformfv(program, location, params); - } - - public void getUniformiv(int program, int location, IntBuffer params) { - gl2.glGetUniformiv(program, location, params); - } - - public boolean isProgram(int program) { - return gl2.glIsProgram(program); - } - - public void getProgramiv(int program, int pname, IntBuffer params) { - gl2.glGetProgramiv(program, pname, params); - } - - public String getProgramInfoLog(int program) { - int[] val = { 0 }; - gl2.glGetShaderiv(program, GL2.GL_INFO_LOG_LENGTH, val, 0); - int length = val[0]; - - if (0 < length) { - byte[] log = new byte[length]; - gl2.glGetProgramInfoLog(program, length, val, 0, log, 0); - return new String(log); - } else { - return "Unknow error"; - } - } + public abstract int createShader(int type); + public abstract void shaderSource(int shader, String source); + public abstract void compileShader(int shader); + public abstract void releaseShaderCompiler(); + public abstract void deleteShader(int shader); + public abstract void shaderBinary(int count, IntBuffer shaders, int binaryFormat, Buffer binary, int length); + public abstract int createProgram(); + public abstract void attachShader(int program, int shader); + public abstract void detachShader(int program, int shader); + public abstract void linkProgram(int program); + public abstract void useProgram(int program); + public abstract void deleteProgram(int program); + public abstract String glGetActiveAttrib (int program, int index, IntBuffer size, IntBuffer type); + public abstract int getAttribLocation(int program, String name); + public abstract void bindAttribLocation(int program, int index, String name); + public abstract int getUniformLocation(int program, String name); + public abstract String getActiveUniform(int program, int index, IntBuffer size, IntBuffer type); + public abstract void uniform1i(int location, int value); + public abstract void uniform2i(int location, int value0, int value1); + public abstract void uniform3i(int location, int value0, int value1, int value2); + public abstract void uniform4i(int location, int value0, int value1, int value2, int value3); + public abstract void uniform1f(int location, float value); + public abstract void uniform2f(int location, float value0, float value1); + public abstract void uniform3f(int location, float value0, float value1, float value2); + public abstract void uniform4f(int location, float value0, float value1, float value2, float value3); + public abstract void uniform1iv(int location, int count, IntBuffer v); + public abstract void uniform2iv(int location, int count, IntBuffer v); + public abstract void uniform3iv(int location, int count, IntBuffer v); + public abstract void uniform4iv(int location, int count, IntBuffer v); + public abstract void uniform1fv(int location, int count, FloatBuffer v); + public abstract void uniform2fv(int location, int count, FloatBuffer v); + public abstract void uniform3fv(int location, int count, FloatBuffer v); + public abstract void uniform4fv(int location, int count, FloatBuffer v); + public abstract void uniformMatrix2fv(int location, int count, boolean transpose, FloatBuffer mat); + public abstract void uniformMatrix3fv(int location, int count, boolean transpose, FloatBuffer mat); + public abstract void uniformMatrix4fv(int location, int count, boolean transpose, FloatBuffer mat); + public abstract void validateProgram(int program); + public abstract boolean isShader(int shader); + public abstract void getShaderiv(int shader, int pname, IntBuffer params); + public abstract void getAttachedShaders(int program, int maxCount, IntBuffer count, IntBuffer shaders); + public abstract String getShaderInfoLog(int shader); + public abstract String getShaderSource(int shader); + public abstract void getShaderPrecisionFormat(int shaderType, int precisionType, IntBuffer range, IntBuffer precision); + public abstract void getVertexAttribfv(int index, int pname, FloatBuffer params); + public abstract void getVertexAttribiv(int index, int pname, IntBuffer params); + public abstract void getVertexAttribPointerv(int index, int pname, ByteBuffer data); + public abstract void getUniformfv(int program, int location, FloatBuffer params); + public abstract void getUniformiv(int program, int location, IntBuffer params); + public abstract boolean isProgram(int program); + public abstract void getProgramiv(int program, int pname, IntBuffer params); + public abstract String getProgramInfoLog(int program); /////////////////////////////////////////////////////////// // Per-Fragment Operations - public void scissor(int x, int y, int w, int h) { - gl.glScissor(x, y, w, h); - } - - public void sampleCoverage(float value, boolean invert) { - gl2.glSampleCoverage(value, invert); - } - - public void stencilFunc(int func, int ref, int mask) { - gl2.glStencilFunc(func, ref, mask); - } - - public void stencilFuncSeparate(int face, int func, int ref, int mask) { - gl2.glStencilFuncSeparate(face, func, ref, mask); - } - - public void stencilOp(int sfail, int dpfail, int dppass) { - gl2.glStencilOp(sfail, dpfail, dppass); - } - - public void stencilOpSeparate(int face, int sfail, int dpfail, int dppass) { - gl2.glStencilOpSeparate(face, sfail, dpfail, dppass); - } - - public void depthFunc(int func) { - gl.glDepthFunc(func); - } - - public void blendEquation(int mode) { - gl.glBlendEquation(mode); - } - - public void blendEquationSeparate(int modeRGB, int modeAlpha) { - gl.glBlendEquationSeparate(modeRGB, modeAlpha); - } - - public void blendFunc(int src, int dst) { - gl.glBlendFunc(src, dst); - } - - public void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) { - gl.glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); - } - - public void blendColor(float red, float green, float blue, float alpha) { - gl2.glBlendColor(red, green, blue, alpha); - } - - public void alphaFunc(int func, float ref) { - if (gl2x != null) { - gl2x.glAlphaFunc(func, ref); - } - } + public abstract void scissor(int x, int y, int w, int h); + public abstract void sampleCoverage(float value, boolean invert); + public abstract void stencilFunc(int func, int ref, int mask); + public abstract void stencilFuncSeparate(int face, int func, int ref, int mask); + public abstract void stencilOp(int sfail, int dpfail, int dppass); + public abstract void stencilOpSeparate(int face, int sfail, int dpfail, int dppass); + public abstract void depthFunc(int func); + public abstract void blendEquation(int mode); + public abstract void blendEquationSeparate(int modeRGB, int modeAlpha); + public abstract void blendFunc(int src, int dst); + public abstract void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha); + public abstract void blendColor(float red, float green, float blue, float alpha); + public abstract void alphaFunc(int func, float ref); /////////////////////////////////////////////////////////// // Whole Framebuffer Operations - public void colorMask(boolean r, boolean g, boolean b, boolean a) { - gl.glColorMask(r, g, b, a); - } - - public void depthMask(boolean mask) { - gl.glDepthMask(mask); - } - - public void stencilMask(int mask) { - gl.glStencilMask(mask); - } - - public void stencilMaskSeparate(int face, int mask) { - gl2.glStencilMaskSeparate(face, mask); - } - - public void clear(int buf) { - gl.glClear(buf); - } - - public void clearColor(float r, float g, float b, float a) { - gl.glClearColor(r, g, b, a); - } - - public void clearDepth(float d) { - gl.glClearDepthf(d); - } - - public void clearStencil(int s) { - gl.glClearStencil(s); - } + public abstract void colorMask(boolean r, boolean g, boolean b, boolean a); + public abstract void depthMask(boolean mask); + public abstract void stencilMask(int mask); + public abstract void stencilMaskSeparate(int face, int mask); + public abstract void clear(int buf); + public abstract void clearColor(float r, float g, float b, float a); + public abstract void clearDepth(float d); + public abstract void clearStencil(int s); /////////////////////////////////////////////////////////// // Framebuffers Objects - public void bindFramebuffer(int target, int framebuffer) { - gl.glBindFramebuffer(target, framebuffer); - } - - public void deleteFramebuffers(int n, IntBuffer framebuffers) { - gl.glDeleteFramebuffers(n, framebuffers); - } - - public void genFramebuffers(int n, IntBuffer framebuffers) { - gl.glGenFramebuffers(n, framebuffers); - } - - public void bindRenderbuffer(int target, int renderbuffer) { - gl.glBindRenderbuffer(target, renderbuffer); - } - - public void deleteRenderbuffers(int n, IntBuffer renderbuffers) { - gl.glDeleteRenderbuffers(n, renderbuffers); - } - - public void genRenderbuffers(int n, IntBuffer renderbuffers) { - gl.glGenRenderbuffers(n, renderbuffers); - } - - public void renderbufferStorage(int target, int internalFormat, int width, int height) { - gl.glRenderbufferStorage(target, internalFormat, width, height); - } - - public void framebufferRenderbuffer(int target, int attachment, int rendbuferfTarget, int renderbuffer) { - gl.glFramebufferRenderbuffer(target, attachment, rendbuferfTarget, renderbuffer); - } - - public void framebufferTexture2D(int target, int attachment, int texTarget, int texture, int level) { - gl.glFramebufferTexture2D(target, attachment, texTarget, texture, level); - } - - public int checkFramebufferStatus(int target) { - return gl.glCheckFramebufferStatus(target); - } - - public boolean isFramebuffer(int framebuffer) { - return gl2.glIsFramebuffer(framebuffer); - } - - public void getFramebufferAttachmentParameteriv(int target, int attachment, int pname, IntBuffer params) { - gl2.glGetFramebufferAttachmentParameteriv(target, attachment, pname, params); - } - - public boolean isRenderbuffer(int renderbuffer) { - return gl2.glIsRenderbuffer(renderbuffer); - } - - public void getRenderbufferParameteriv(int target, int pname, IntBuffer params) { - gl2.glGetRenderbufferParameteriv(target, pname, params); - } - - public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) { - if (gl2x != null) { - gl2x.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); - } - } - - public void renderbufferStorageMultisample(int target, int samples, int format, int width, int height) { - if (gl2x != null) { - gl2x.glRenderbufferStorageMultisample(target, samples, format, width, height); - } - } - - public void readBuffer(int buf) { - if (gl2x != null) { - gl2x.glReadBuffer(buf); - } - } - - public void drawBuffer(int buf) { - if (gl2x != null) { - gl2x.glDrawBuffer(buf); - } - } + public abstract void bindFramebuffer(int target, int framebuffer); + public abstract void deleteFramebuffers(int n, IntBuffer framebuffers); + public abstract void genFramebuffers(int n, IntBuffer framebuffers); + public abstract void bindRenderbuffer(int target, int renderbuffer); + public abstract void deleteRenderbuffers(int n, IntBuffer renderbuffers); + public abstract void genRenderbuffers(int n, IntBuffer renderbuffers); + public abstract void renderbufferStorage(int target, int internalFormat, int width, int height); + public abstract void framebufferRenderbuffer(int target, int attachment, int rendbuferfTarget, int renderbuffer); + public abstract void framebufferTexture2D(int target, int attachment, int texTarget, int texture, int level); + public abstract int checkFramebufferStatus(int target); + public abstract boolean isFramebuffer(int framebuffer); + public abstract void getFramebufferAttachmentParameteriv(int target, int attachment, int pname, IntBuffer params); + public abstract boolean isRenderbuffer(int renderbuffer); + public abstract void getRenderbufferParameteriv(int target, int pname, IntBuffer params); + public abstract void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter); + public abstract void renderbufferStorageMultisample(int target, int samples, int format, int width, int height); + public abstract void readBuffer(int buf); + public abstract void drawBuffer(int buf); } diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index 007532759..e4d7a413c 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -1,7 +1,2294 @@ package processing.opengl; +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES1; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLException; +import javax.media.opengl.GLFBODrawable; +import javax.media.opengl.GLProfile; +import javax.media.opengl.awt.GLCanvas; +import javax.media.opengl.fixedfunc.GLMatrixFunc; +import javax.media.opengl.glu.GLU; + +import processing.core.PApplet; +import processing.core.PConstants; +import processing.event.KeyEvent; +import processing.event.MouseEvent; + +import com.jogamp.newt.awt.NewtCanvasAWT; +import com.jogamp.newt.event.InputEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.FBObject; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.PathIterator; +import javax.media.opengl.glu.GLUtessellator; +import javax.media.opengl.glu.GLUtessellatorCallbackAdapter; + +@SuppressWarnings("static-access") public class PJOGL extends PGL { + static { + INDEX_TYPE = GL.GL_UNSIGNED_SHORT; + } + + + /////////////////////////////////////////////////////////// + + // Public members to access the underlying GL objects and context + + /** Basic GL functionality, common to all profiles */ + public static GL gl; + + /** GLU interface **/ + public static GLU glu; + + /** The rendering context (holds rendering state info) */ + public static GLContext context; + + /** The canvas where OpenGL rendering takes place */ + public static Canvas canvas; + + /** Selected GL profile */ + public static GLProfile profile; + + + /** JOGL's windowing toolkit */ + // The two windowing toolkits available to use in JOGL: + protected static final int AWT = 0; // http://jogamp.org/wiki/index.php/Using_JOGL_in_AWT_SWT_and_Swing + protected static final int NEWT = 1; // http://jogamp.org/jogl/doc/NEWT-Overview.html + + + /** OS-specific configuration */ + protected static int WINDOW_TOOLKIT; + protected static int EVENTS_TOOLKIT; + protected static boolean USE_JOGL_FBOLAYER; + protected static int REQUESTED_DEPTH_BITS = 24; + protected static int REQUESTED_STENCIL_BITS = 8; + protected static int REQUESTED_ALPHA_BITS = 8; + static { + if (PApplet.platform == PConstants.WINDOWS) { + // Using AWT on Windows because NEWT displays a black background while + // initializing, and the cursor functions don't work. GLWindow has some + // functions for basic cursor handling (hide/show): + // GLWindow.setPointerVisible(false); + // but apparently nothing to set the cursor icon: + // https://jogamp.org/bugzilla/show_bug.cgi?id=409 + WINDOW_TOOLKIT = AWT; + EVENTS_TOOLKIT = AWT; + USE_FBOLAYER_BY_DEFAULT = false; + USE_JOGL_FBOLAYER = false; + REQUESTED_DEPTH_BITS = 24; + REQUESTED_STENCIL_BITS = 8; + REQUESTED_ALPHA_BITS = 8; + } else if (PApplet.platform == PConstants.MACOSX) { + // Note: The JOGL FBO layer (in 2.0.2) seems incompatible with NEWT. + WINDOW_TOOLKIT = AWT; + EVENTS_TOOLKIT = AWT; + USE_FBOLAYER_BY_DEFAULT = true; + USE_JOGL_FBOLAYER = true; + REQUESTED_DEPTH_BITS = 24; + REQUESTED_STENCIL_BITS = 8; + REQUESTED_ALPHA_BITS = 8; + } else if (PApplet.platform == PConstants.LINUX) { + WINDOW_TOOLKIT = AWT; + EVENTS_TOOLKIT = AWT; + USE_FBOLAYER_BY_DEFAULT = false; + USE_JOGL_FBOLAYER = false; + REQUESTED_DEPTH_BITS = 24; + REQUESTED_STENCIL_BITS = 8; + REQUESTED_ALPHA_BITS = 8; + } else if (PApplet.platform == PConstants.OTHER) { + WINDOW_TOOLKIT = NEWT; // NEWT works on the Raspberry pi? + EVENTS_TOOLKIT = NEWT; + USE_FBOLAYER_BY_DEFAULT = false; + USE_JOGL_FBOLAYER = false; + REQUESTED_DEPTH_BITS = 24; + REQUESTED_STENCIL_BITS = 8; + REQUESTED_ALPHA_BITS = 8; + } + } + + /** Time that the Processing's animation thread will wait for JOGL's rendering + * thread to be done with a single frame. + */ + protected static int DRAW_TIMEOUT_MILLIS = 500; + + + + /** Desired target framerate */ + protected float targetFps = 60; + protected float currentFps = 60; + protected boolean setFps = false; + protected int fcount, lastm; + protected int fint = 3; + + + + + + /** OpenGL thread */ + protected static Thread glThread; + + /** The capabilities of the OpenGL rendering surface */ + protected static GLCapabilitiesImmutable capabilities; + + /** The rendering surface */ + protected static GLDrawable drawable; + + /** GLES2 functionality (shaders, etc) */ + protected static GL2ES2 gl2; + + /** GL2 desktop functionality (blit framebuffer, map buffer range, + * multisampled renerbuffers) */ + protected static GL2 gl2x; + + /** The AWT-OpenGL canvas */ + protected static GLCanvas canvasAWT; + + /** The NEWT-OpenGL canvas */ + protected static NewtCanvasAWT canvasNEWT; + + /** The NEWT window */ + protected static GLWindow window; + + /** The listener that fires the frame rendering in Processing */ + protected static PGLListener listener; + + /** This countdown latch is used to maintain the synchronization between + * Processing's drawing thread and JOGL's rendering thread */ + protected CountDownLatch drawLatch; + + + + protected float[] projMatrix; + protected float[] mvMatrix; + + + /** Back (== draw, current frame) buffer */ + protected static FBObject backFBO; + /** Sink buffer, used in the multisampled case */ + protected static FBObject sinkFBO; + /** Front (== read, previous frame) buffer */ + protected static FBObject frontFBO; + protected static FBObject.TextureAttachment backTexAttach; + protected static FBObject.TextureAttachment frontTexAttach; + + + public PJOGL(PGraphicsOpenGL pg) { super(pg); + if (glu == null) glu = new GLU(); } + + + @Override + protected void setFps(float fps) { + if (!setFps || targetFps != fps) { + if (60 < fps) { + // Disables v-sync + gl.setSwapInterval(0); + } else if (30 < fps) { + gl.setSwapInterval(1); + } else { + gl.setSwapInterval(2); + } + targetFps = currentFps = fps; + setFps = true; + } + } + + + @Override + protected void initSurface(int antialias) { + if (profile == null) { + profile = GLProfile.getDefault(); + } else { + // Restarting... + if (canvasAWT != null) { + canvasAWT.removeGLEventListener(listener); + pg.parent.removeListeners(canvasAWT); + pg.parent.remove(canvasAWT); + } else if (canvasNEWT != null) { + window.removeGLEventListener(listener); + pg.parent.remove(canvasNEWT); + } + sinkFBO = backFBO = frontFBO = null; + } + + // Setting up the desired capabilities; + GLCapabilities caps = new GLCapabilities(profile); + caps.setDepthBits(REQUESTED_DEPTH_BITS); + caps.setStencilBits(REQUESTED_STENCIL_BITS); + caps.setAlphaBits(REQUESTED_ALPHA_BITS); + + caps.setBackgroundOpaque(true); + caps.setOnscreen(true); + if (USE_FBOLAYER_BY_DEFAULT) { + if (USE_JOGL_FBOLAYER) { + caps.setPBuffer(false); + caps.setFBO(true); + if (1 < antialias) { + caps.setSampleBuffers(true); + caps.setNumSamples(antialias); + } else { + caps.setSampleBuffers(false); + } + fboLayerRequested = false; + } else { + caps.setPBuffer(false); + caps.setFBO(false); + caps.setSampleBuffers(false); + fboLayerRequested = 1 < antialias; + } + } else { + if (1 < antialias) { + caps.setSampleBuffers(true); + caps.setNumSamples(antialias); + } else { + caps.setSampleBuffers(false); + } + fboLayerRequested = false; + } + caps.setDepthBits(REQUESTED_DEPTH_BITS); + caps.setStencilBits(REQUESTED_STENCIL_BITS); + caps.setAlphaBits(REQUESTED_ALPHA_BITS); + reqNumSamples = qualityToSamples(antialias); + + if (WINDOW_TOOLKIT == AWT) { + canvasAWT = new GLCanvas(caps); + canvasAWT.setBounds(0, 0, pg.width, pg.height); + canvasAWT.setBackground(new Color(pg.backgroundColor, true)); + canvasAWT.setFocusable(true); + + pg.parent.setLayout(new BorderLayout()); + pg.parent.add(canvasAWT, BorderLayout.CENTER); + canvasAWT.requestFocusInWindow(); + + pg.parent.removeListeners(pg.parent); + pg.parent.addListeners(canvasAWT); + + canvas = canvasAWT; + canvasNEWT = null; + + listener = new PGLListener(); + canvasAWT.addGLEventListener(listener); + } else if (WINDOW_TOOLKIT == NEWT) { + window = GLWindow.create(caps); + canvasNEWT = new NewtCanvasAWT(window); + canvasNEWT.setBounds(0, 0, pg.width, pg.height); + canvasNEWT.setBackground(new Color(pg.backgroundColor, true)); + canvasNEWT.setFocusable(true); + + pg.parent.setLayout(new BorderLayout()); + pg.parent.add(canvasNEWT, BorderLayout.CENTER); + canvasNEWT.requestFocusInWindow(); + + if (EVENTS_TOOLKIT == NEWT) { + NEWTMouseListener mouseListener = new NEWTMouseListener(); + window.addMouseListener(mouseListener); + NEWTKeyListener keyListener = new NEWTKeyListener(); + window.addKeyListener(keyListener); + NEWTWindowListener winListener = new NEWTWindowListener(); + window.addWindowListener(winListener); + } else if (EVENTS_TOOLKIT == AWT) { + pg.parent.removeListeners(canvasNEWT); + pg.parent.addListeners(canvasNEWT); + } + + canvas = canvasNEWT; + canvasAWT = null; + + listener = new PGLListener(); + window.addGLEventListener(listener); + } + + canvas.setFocusTraversalKeysEnabled(false); + + fboLayerCreated = false; + fboLayerInUse = false; + firstFrame = true; + + setFps = false; + } + + + @Override + protected void deleteSurface() { + super.deleteSurface(); + + if (canvasAWT != null) { + canvasAWT.removeGLEventListener(listener); + pg.parent.removeListeners(canvasAWT); + } else if (canvasNEWT != null) { + window.removeGLEventListener(listener); + } + GLProfile.shutdown(); + } + + + @Override + protected int getReadFramebuffer() { + if (fboLayerInUse) { + return glColorFbo.get(0); + } else if (capabilities.isFBO()) { + return context.getDefaultReadFramebuffer(); + } else { + return 0; + } + } + + + @Override + protected int getDrawFramebuffer() { + if (fboLayerInUse) { + if (1 < numSamples) { + return glMultiFbo.get(0); + } else { + return glColorFbo.get(0); + } + } else if (capabilities.isFBO()) { + return context.getDefaultDrawFramebuffer(); + } else { + return 0; + } + } + + + @Override + protected int getDefaultDrawBuffer() { + if (fboLayerInUse) { + return COLOR_ATTACHMENT0; + } else if (capabilities.isFBO()) { + return GL.GL_COLOR_ATTACHMENT0; + } else if (capabilities.getDoubleBuffered()) { + return GL.GL_BACK; + } else { + return GL.GL_FRONT; + } + } + + + @Override + protected int getDefaultReadBuffer() { + if (fboLayerInUse) { + return COLOR_ATTACHMENT0; + } else if (capabilities.isFBO()) { + return GL.GL_COLOR_ATTACHMENT0; + } else if (capabilities.getDoubleBuffered()) { + return GL.GL_BACK; + } else { + return GL.GL_FRONT; + } + } + + + @Override + protected boolean isFBOBacked() { + return fboLayerInUse || capabilities.isFBO(); + } + + + @Override + protected int getDepthBits() { + if (USE_JOGL_FBOLAYER) { + return capabilities.getDepthBits(); + } else { + intBuffer.rewind(); + getIntegerv(DEPTH_BITS, intBuffer); + return intBuffer.get(0); + } + } + + + @Override + protected int getStencilBits() { + if (USE_JOGL_FBOLAYER) { + return capabilities.getStencilBits(); + } else { + intBuffer.rewind(); + getIntegerv(STENCIL_BITS, intBuffer); + return intBuffer.get(0); + } + } + + + @Override + protected Texture wrapBackTexture(Texture texture) { + if (texture == null || changedBackTex) { + if (USE_JOGL_FBOLAYER) { + texture = new Texture(); + texture.init(pg.width, pg.height, + backTexAttach.getName(), TEXTURE_2D, RGBA, + backTexAttach.getWidth(), backTexAttach.getHeight(), + backTexAttach.minFilter, backTexAttach.magFilter, + backTexAttach.wrapS, backTexAttach.wrapT); + texture.invertedY(true); + texture.colorBuffer(true); + pg.setCache(pg, texture); + } else { + texture = new Texture(); + texture.init(pg.width, pg.height, + glColorTex.get(backTex), TEXTURE_2D, RGBA, + fboWidth, fboHeight, NEAREST, NEAREST, + CLAMP_TO_EDGE, CLAMP_TO_EDGE); + texture.invertedY(true); + texture.colorBuffer(true); + pg.setCache(pg, texture); + } + } else { + if (USE_JOGL_FBOLAYER) { + texture.glName = backTexAttach.getName(); + } else { + texture.glName = glColorTex.get(backTex); + } + } + return texture; + } + + + @Override + protected Texture wrapFrontTexture(Texture texture) { + if (texture == null || changedFrontTex) { + if (USE_JOGL_FBOLAYER) { + texture = new Texture(); + texture.init(pg.width, pg.height, + backTexAttach.getName(), TEXTURE_2D, RGBA, + frontTexAttach.getWidth(), frontTexAttach.getHeight(), + frontTexAttach.minFilter, frontTexAttach.magFilter, + frontTexAttach.wrapS, frontTexAttach.wrapT); + texture.invertedY(true); + texture.colorBuffer(true); + } else { + texture = new Texture(); + texture.init(pg.width, pg.height, + glColorTex.get(frontTex), TEXTURE_2D, RGBA, + fboWidth, fboHeight, NEAREST, NEAREST, + CLAMP_TO_EDGE, CLAMP_TO_EDGE); + texture.invertedY(true); + texture.colorBuffer(true); + } + } else { + if (USE_JOGL_FBOLAYER) { + texture.glName = frontTexAttach.getName(); + } else { + texture.glName = glColorTex.get(frontTex); + } + } + return texture; + } + + + @Override + protected void bindFrontTexture() { + usingFrontTex = true; + if (USE_JOGL_FBOLAYER) { + if (!texturingIsEnabled(TEXTURE_2D)) { + enableTexturing(TEXTURE_2D); + } + bindTexture(TEXTURE_2D, frontTexAttach.getName()); + } else { + if (!texturingIsEnabled(TEXTURE_2D)) { + enableTexturing(TEXTURE_2D); + } + bindTexture(TEXTURE_2D, glColorTex.get(frontTex)); + } + } + + + @Override + protected void unbindFrontTexture() { + if (USE_JOGL_FBOLAYER) { + if (textureIsBound(TEXTURE_2D, frontTexAttach.getName())) { + // We don't want to unbind another texture + // that might be bound instead of this one. + if (!texturingIsEnabled(TEXTURE_2D)) { + enableTexturing(TEXTURE_2D); + bindTexture(TEXTURE_2D, 0); + disableTexturing(TEXTURE_2D); + } else { + bindTexture(TEXTURE_2D, 0); + } + } + } else { + if (textureIsBound(TEXTURE_2D, glColorTex.get(frontTex))) { + // We don't want to unbind another texture + // that might be bound instead of this one. + if (!texturingIsEnabled(TEXTURE_2D)) { + enableTexturing(TEXTURE_2D); + bindTexture(TEXTURE_2D, 0); + disableTexturing(TEXTURE_2D); + } else { + bindTexture(TEXTURE_2D, 0); + } + } + } + } + + + @Override + protected void syncBackTexture() { + if (usingFrontTex) needSepFrontTex = true; + if (USE_JOGL_FBOLAYER) { + if (1 < numSamples) { + backFBO.syncSamplingSink(gl); + backFBO.bind(gl); + } + } else { + if (1 < numSamples) { + bindFramebuffer(READ_FRAMEBUFFER, glMultiFbo.get(0)); + bindFramebuffer(DRAW_FRAMEBUFFER, glColorFbo.get(0)); + blitFramebuffer(0, 0, fboWidth, fboHeight, + 0, 0, fboWidth, fboHeight, + COLOR_BUFFER_BIT, NEAREST); + } + } + } + + + @Override + protected void beginDraw(boolean clear0) { + if (!setFps) setFps(targetFps); + if (USE_JOGL_FBOLAYER) return; + super.beginDraw(clear0); + } + + + @Override + protected void endDraw(boolean clear0) { + if (isFBOBacked()) { + if (USE_JOGL_FBOLAYER) { + if (!clear0 && isFBOBacked() && !isMultisampled()) { + // Draw the back texture into the front texture, which will be used as + // back texture in the next frame. Otherwise flickering will occur if + // the sketch uses "incremental drawing" (background() not called). + frontFBO.bind(gl); + gl.glDisable(GL.GL_BLEND); + drawTexture(TEXTURE_2D, backTexAttach.getName(), + backTexAttach.getWidth(), backTexAttach.getHeight(), + pg.width, pg.height, + 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height); + backFBO.bind(gl); + } + } else { + super.endDraw(clear0); + } + } + } + + @Override + protected void requestFocus() { + if (canvas != null) { + canvas.requestFocus(); + } + } + + @Override + protected void requestDraw() { + boolean canDraw = pg.parent.canDraw(); + if (pg.initialized && (canDraw || prevCanDraw)) { + try { + drawLatch = new CountDownLatch(1); + if (WINDOW_TOOLKIT == AWT) { + canvasAWT.display(); + } else if (WINDOW_TOOLKIT == NEWT) { + window.display(); + } + try { + drawLatch.await(DRAW_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + if (canDraw) prevCanDraw = true; + else prevCanDraw = false; + } catch (GLException e) { + // Unwrap GLException so that only the causing exception is shown. + Throwable tr = e.getCause(); + if (tr instanceof RuntimeException) { + throw (RuntimeException)tr; + } else { + throw new RuntimeException(tr); + } + } + } + } + + @Override + protected void swapBuffers() { + if (WINDOW_TOOLKIT == AWT) { + canvasAWT.swapBuffers(); + } else if (WINDOW_TOOLKIT == NEWT) { + window.swapBuffers(); + } + } + + @Override + protected boolean threadIsCurrent() { + return Thread.currentThread() == glThread; + } + + + @Override + protected void beginGL() { + if (projMatrix == null) { + projMatrix = new float[16]; + } + gl2x.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + projMatrix[ 0] = pg.projection.m00; + projMatrix[ 1] = pg.projection.m10; + projMatrix[ 2] = pg.projection.m20; + projMatrix[ 3] = pg.projection.m30; + projMatrix[ 4] = pg.projection.m01; + projMatrix[ 5] = pg.projection.m11; + projMatrix[ 6] = pg.projection.m21; + projMatrix[ 7] = pg.projection.m31; + projMatrix[ 8] = pg.projection.m02; + projMatrix[ 9] = pg.projection.m12; + projMatrix[10] = pg.projection.m22; + projMatrix[11] = pg.projection.m32; + projMatrix[12] = pg.projection.m03; + projMatrix[13] = pg.projection.m13; + projMatrix[14] = pg.projection.m23; + projMatrix[15] = pg.projection.m33; + gl2x.glLoadMatrixf(projMatrix, 0); + + if (mvMatrix == null) { + mvMatrix = new float[16]; + } + gl2x.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + mvMatrix[ 0] = pg.modelview.m00; + mvMatrix[ 1] = pg.modelview.m10; + mvMatrix[ 2] = pg.modelview.m20; + mvMatrix[ 3] = pg.modelview.m30; + mvMatrix[ 4] = pg.modelview.m01; + mvMatrix[ 5] = pg.modelview.m11; + mvMatrix[ 6] = pg.modelview.m21; + mvMatrix[ 7] = pg.modelview.m31; + mvMatrix[ 8] = pg.modelview.m02; + mvMatrix[ 9] = pg.modelview.m12; + mvMatrix[10] = pg.modelview.m22; + mvMatrix[11] = pg.modelview.m32; + mvMatrix[12] = pg.modelview.m03; + mvMatrix[13] = pg.modelview.m13; + mvMatrix[14] = pg.modelview.m23; + mvMatrix[15] = pg.modelview.m33; + gl2x.glLoadMatrixf(mvMatrix, 0); + } + + @Override + protected boolean hasFBOs() { + if (context.hasBasicFBOSupport()) return true; + else return super.hasFBOs(); + } + + @Override + protected boolean hasShaders() { + if (context.hasGLSL()) return true; + else return super.hasShaders(); + } + + /////////////////////////////////////////////////////////// + + // Constants + + static { + FALSE = GL.GL_FALSE; + TRUE = GL.GL_TRUE; + + INT = GL2ES2.GL_INT; + BYTE = GL.GL_BYTE; + SHORT = GL.GL_SHORT; + FLOAT = GL.GL_FLOAT; + BOOL = GL2ES2.GL_BOOL; + UNSIGNED_INT = GL.GL_UNSIGNED_INT; + UNSIGNED_BYTE = GL.GL_UNSIGNED_BYTE; + UNSIGNED_SHORT = GL.GL_UNSIGNED_SHORT; + + RGB = GL.GL_RGB; + RGBA = GL.GL_RGBA; + ALPHA = GL.GL_ALPHA; + LUMINANCE = GL.GL_LUMINANCE; + LUMINANCE_ALPHA = GL.GL_LUMINANCE_ALPHA; + + UNSIGNED_SHORT_5_6_5 = GL.GL_UNSIGNED_SHORT_5_6_5; + UNSIGNED_SHORT_4_4_4_4 = GL.GL_UNSIGNED_SHORT_4_4_4_4; + UNSIGNED_SHORT_5_5_5_1 = GL.GL_UNSIGNED_SHORT_5_5_5_1; + + RGBA4 = GL.GL_RGBA4; + RGB5_A1 = GL.GL_RGB5_A1; + RGB565 = GL.GL_RGB565; + + READ_ONLY = GL2GL3.GL_READ_ONLY; + WRITE_ONLY = GL.GL_WRITE_ONLY; + READ_WRITE = GL2GL3.GL_READ_WRITE; + + TESS_WINDING_NONZERO = GLU.GLU_TESS_WINDING_NONZERO; + TESS_WINDING_ODD = GLU.GLU_TESS_WINDING_ODD; + + GENERATE_MIPMAP_HINT = GL.GL_GENERATE_MIPMAP_HINT; + FASTEST = GL.GL_FASTEST; + NICEST = GL.GL_NICEST; + DONT_CARE = GL.GL_DONT_CARE; + + VENDOR = GL.GL_VENDOR; + RENDERER = GL.GL_RENDERER; + VERSION = GL.GL_VERSION; + EXTENSIONS = GL.GL_EXTENSIONS; + SHADING_LANGUAGE_VERSION = GL2ES2.GL_SHADING_LANGUAGE_VERSION; + + MAX_SAMPLES = GL2.GL_MAX_SAMPLES; + SAMPLES = GL.GL_SAMPLES; + + ALIASED_LINE_WIDTH_RANGE = GL.GL_ALIASED_LINE_WIDTH_RANGE; + ALIASED_POINT_SIZE_RANGE = GL.GL_ALIASED_POINT_SIZE_RANGE; + + DEPTH_BITS = GL.GL_DEPTH_BITS; + STENCIL_BITS = GL.GL_STENCIL_BITS; + + CCW = GL.GL_CCW; + CW = GL.GL_CW; + + VIEWPORT = GL.GL_VIEWPORT; + + ARRAY_BUFFER = GL.GL_ARRAY_BUFFER; + ELEMENT_ARRAY_BUFFER = GL.GL_ELEMENT_ARRAY_BUFFER; + + MAX_VERTEX_ATTRIBS = GL2ES2.GL_MAX_VERTEX_ATTRIBS; + + STATIC_DRAW = GL.GL_STATIC_DRAW; + DYNAMIC_DRAW = GL.GL_DYNAMIC_DRAW; + STREAM_DRAW = GL2ES2.GL_STREAM_DRAW; + + BUFFER_SIZE = GL.GL_BUFFER_SIZE; + BUFFER_USAGE = GL.GL_BUFFER_USAGE; + + POINTS = GL.GL_POINTS; + LINE_STRIP = GL.GL_LINE_STRIP; + LINE_LOOP = GL.GL_LINE_LOOP; + LINES = GL.GL_LINES; + TRIANGLE_FAN = GL.GL_TRIANGLE_FAN; + TRIANGLE_STRIP = GL.GL_TRIANGLE_STRIP; + TRIANGLES = GL.GL_TRIANGLES; + + CULL_FACE = GL.GL_CULL_FACE; + FRONT = GL.GL_FRONT; + BACK = GL.GL_BACK; + FRONT_AND_BACK = GL.GL_FRONT_AND_BACK; + + POLYGON_OFFSET_FILL = GL.GL_POLYGON_OFFSET_FILL; + + UNPACK_ALIGNMENT = GL.GL_UNPACK_ALIGNMENT; + PACK_ALIGNMENT = GL.GL_PACK_ALIGNMENT; + + TEXTURE_2D = GL.GL_TEXTURE_2D; + TEXTURE_RECTANGLE = GL2GL3.GL_TEXTURE_RECTANGLE; + + TEXTURE_BINDING_2D = GL.GL_TEXTURE_BINDING_2D; + TEXTURE_BINDING_RECTANGLE = GL2GL3.GL_TEXTURE_BINDING_RECTANGLE; + + MAX_TEXTURE_SIZE = GL.GL_MAX_TEXTURE_SIZE; + TEXTURE_MAX_ANISOTROPY = GL.GL_TEXTURE_MAX_ANISOTROPY_EXT; + MAX_TEXTURE_MAX_ANISOTROPY = GL.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT; + + MAX_VERTEX_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS; + MAX_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_TEXTURE_IMAGE_UNITS; + MAX_COMBINED_TEXTURE_IMAGE_UNITS = GL2ES2.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS; + + NUM_COMPRESSED_TEXTURE_FORMATS = GL.GL_NUM_COMPRESSED_TEXTURE_FORMATS; + COMPRESSED_TEXTURE_FORMATS = GL.GL_COMPRESSED_TEXTURE_FORMATS; + + NEAREST = GL.GL_NEAREST; + LINEAR = GL.GL_LINEAR; + LINEAR_MIPMAP_NEAREST = GL.GL_LINEAR_MIPMAP_NEAREST; + LINEAR_MIPMAP_LINEAR = GL.GL_LINEAR_MIPMAP_LINEAR; + + CLAMP_TO_EDGE = GL.GL_CLAMP_TO_EDGE; + REPEAT = GL.GL_REPEAT; + + TEXTURE0 = GL.GL_TEXTURE0; + TEXTURE1 = GL.GL_TEXTURE1; + TEXTURE2 = GL.GL_TEXTURE2; + TEXTURE3 = GL.GL_TEXTURE3; + TEXTURE_MIN_FILTER = GL.GL_TEXTURE_MIN_FILTER; + TEXTURE_MAG_FILTER = GL.GL_TEXTURE_MAG_FILTER; + TEXTURE_WRAP_S = GL.GL_TEXTURE_WRAP_S; + TEXTURE_WRAP_T = GL.GL_TEXTURE_WRAP_T; + TEXTURE_WRAP_R = GL2ES2.GL_TEXTURE_WRAP_R; + + TEXTURE_CUBE_MAP = GL.GL_TEXTURE_CUBE_MAP; + TEXTURE_CUBE_MAP_POSITIVE_X = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X; + TEXTURE_CUBE_MAP_POSITIVE_Y = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; + TEXTURE_CUBE_MAP_POSITIVE_Z = GL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; + TEXTURE_CUBE_MAP_NEGATIVE_X = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; + TEXTURE_CUBE_MAP_NEGATIVE_Y = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; + TEXTURE_CUBE_MAP_NEGATIVE_Z = GL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; + + VERTEX_SHADER = GL2ES2.GL_VERTEX_SHADER; + FRAGMENT_SHADER = GL2ES2.GL_FRAGMENT_SHADER; + INFO_LOG_LENGTH = GL2ES2.GL_INFO_LOG_LENGTH; + SHADER_SOURCE_LENGTH = GL2ES2.GL_SHADER_SOURCE_LENGTH; + COMPILE_STATUS = GL2ES2.GL_COMPILE_STATUS; + LINK_STATUS = GL2ES2.GL_LINK_STATUS; + VALIDATE_STATUS = GL2ES2.GL_VALIDATE_STATUS; + SHADER_TYPE = GL2ES2.GL_SHADER_TYPE; + DELETE_STATUS = GL2ES2.GL_DELETE_STATUS; + + FLOAT_VEC2 = GL2ES2.GL_FLOAT_VEC2; + FLOAT_VEC3 = GL2ES2.GL_FLOAT_VEC3; + FLOAT_VEC4 = GL2ES2.GL_FLOAT_VEC4; + FLOAT_MAT2 = GL2ES2.GL_FLOAT_MAT2; + FLOAT_MAT3 = GL2ES2.GL_FLOAT_MAT3; + FLOAT_MAT4 = GL2ES2.GL_FLOAT_MAT4; + INT_VEC2 = GL2ES2.GL_INT_VEC2; + INT_VEC3 = GL2ES2.GL_INT_VEC3; + INT_VEC4 = GL2ES2.GL_INT_VEC4; + BOOL_VEC2 = GL2ES2.GL_BOOL_VEC2; + BOOL_VEC3 = GL2ES2.GL_BOOL_VEC3; + BOOL_VEC4 = GL2ES2.GL_BOOL_VEC4; + SAMPLER_2D = GL2ES2.GL_SAMPLER_2D; + SAMPLER_CUBE = GL2ES2.GL_SAMPLER_CUBE; + + LOW_FLOAT = GL2ES2.GL_LOW_FLOAT; + MEDIUM_FLOAT = GL2ES2.GL_MEDIUM_FLOAT; + HIGH_FLOAT = GL2ES2.GL_HIGH_FLOAT; + LOW_INT = GL2ES2.GL_LOW_INT; + MEDIUM_INT = GL2ES2.GL_MEDIUM_INT; + HIGH_INT = GL2ES2.GL_HIGH_INT; + + CURRENT_VERTEX_ATTRIB = GL2ES2.GL_CURRENT_VERTEX_ATTRIB; + + VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING; + VERTEX_ATTRIB_ARRAY_ENABLED = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_ENABLED; + VERTEX_ATTRIB_ARRAY_SIZE = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_SIZE; + VERTEX_ATTRIB_ARRAY_STRIDE = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_STRIDE; + VERTEX_ATTRIB_ARRAY_TYPE = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_TYPE; + VERTEX_ATTRIB_ARRAY_NORMALIZED = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_NORMALIZED; + VERTEX_ATTRIB_ARRAY_POINTER = GL2ES2.GL_VERTEX_ATTRIB_ARRAY_POINTER; + + BLEND = GL.GL_BLEND; + ONE = GL.GL_ONE; + ZERO = GL.GL_ZERO; + SRC_ALPHA = GL.GL_SRC_ALPHA; + DST_ALPHA = GL.GL_DST_ALPHA; + ONE_MINUS_SRC_ALPHA = GL.GL_ONE_MINUS_SRC_ALPHA; + ONE_MINUS_DST_COLOR = GL.GL_ONE_MINUS_DST_COLOR; + ONE_MINUS_SRC_COLOR = GL.GL_ONE_MINUS_SRC_COLOR; + DST_COLOR = GL.GL_DST_COLOR; + SRC_COLOR = GL.GL_SRC_COLOR; + + SAMPLE_ALPHA_TO_COVERAGE = GL.GL_SAMPLE_ALPHA_TO_COVERAGE; + SAMPLE_COVERAGE = GL.GL_SAMPLE_COVERAGE; + + KEEP = GL.GL_KEEP; + REPLACE = GL.GL_REPLACE; + INCR = GL.GL_INCR; + DECR = GL.GL_DECR; + INVERT = GL.GL_INVERT; + INCR_WRAP = GL.GL_INCR_WRAP; + DECR_WRAP = GL.GL_DECR_WRAP; + NEVER = GL.GL_NEVER; + ALWAYS = GL.GL_ALWAYS; + + EQUAL = GL.GL_EQUAL; + LESS = GL.GL_LESS; + LEQUAL = GL.GL_LEQUAL; + GREATER = GL.GL_GREATER; + GEQUAL = GL.GL_GEQUAL; + NOTEQUAL = GL.GL_NOTEQUAL; + + FUNC_ADD = GL.GL_FUNC_ADD; + FUNC_MIN = GL2.GL_MIN; + FUNC_MAX = GL2.GL_MAX; + FUNC_REVERSE_SUBTRACT = GL.GL_FUNC_REVERSE_SUBTRACT; + FUNC_SUBTRACT = GL.GL_FUNC_SUBTRACT; + + DITHER = GL.GL_DITHER; + + CONSTANT_COLOR = GL2ES2.GL_CONSTANT_COLOR; + CONSTANT_ALPHA = GL2ES2.GL_CONSTANT_ALPHA; + ONE_MINUS_CONSTANT_COLOR = GL2ES2.GL_ONE_MINUS_CONSTANT_COLOR; + ONE_MINUS_CONSTANT_ALPHA = GL2ES2.GL_ONE_MINUS_CONSTANT_ALPHA; + SRC_ALPHA_SATURATE = GL.GL_SRC_ALPHA_SATURATE; + + SCISSOR_TEST = GL.GL_SCISSOR_TEST; + DEPTH_TEST = GL.GL_DEPTH_TEST; + DEPTH_WRITEMASK = GL.GL_DEPTH_WRITEMASK; + ALPHA_TEST = GL2ES1.GL_ALPHA_TEST; + + COLOR_BUFFER_BIT = GL.GL_COLOR_BUFFER_BIT; + DEPTH_BUFFER_BIT = GL.GL_DEPTH_BUFFER_BIT; + STENCIL_BUFFER_BIT = GL.GL_STENCIL_BUFFER_BIT; + + FRAMEBUFFER = GL.GL_FRAMEBUFFER; + COLOR_ATTACHMENT0 = GL.GL_COLOR_ATTACHMENT0; + COLOR_ATTACHMENT1 = GL2ES2.GL_COLOR_ATTACHMENT1; + COLOR_ATTACHMENT2 = GL2ES2.GL_COLOR_ATTACHMENT2; + COLOR_ATTACHMENT3 = GL2ES2.GL_COLOR_ATTACHMENT3; + RENDERBUFFER = GL.GL_RENDERBUFFER; + DEPTH_ATTACHMENT = GL.GL_DEPTH_ATTACHMENT; + STENCIL_ATTACHMENT = GL.GL_STENCIL_ATTACHMENT; + READ_FRAMEBUFFER = GL2.GL_READ_FRAMEBUFFER; + DRAW_FRAMEBUFFER = GL2.GL_DRAW_FRAMEBUFFER; + + RGBA8 = GL.GL_RGBA8; + DEPTH24_STENCIL8 = GL.GL_DEPTH24_STENCIL8; + + DEPTH_COMPONENT = GL2ES2.GL_DEPTH_COMPONENT; + DEPTH_COMPONENT16 = GL.GL_DEPTH_COMPONENT16; + DEPTH_COMPONENT24 = GL.GL_DEPTH_COMPONENT24; + DEPTH_COMPONENT32 = GL.GL_DEPTH_COMPONENT32; + + STENCIL_INDEX = GL2ES2.GL_STENCIL_INDEX; + STENCIL_INDEX1 = GL.GL_STENCIL_INDEX1; + STENCIL_INDEX4 = GL.GL_STENCIL_INDEX4; + STENCIL_INDEX8 = GL.GL_STENCIL_INDEX8; + + DEPTH_STENCIL = GL.GL_DEPTH_STENCIL; + + FRAMEBUFFER_COMPLETE = GL.GL_FRAMEBUFFER_COMPLETE; + FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + FRAMEBUFFER_INCOMPLETE_DIMENSIONS = GL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + FRAMEBUFFER_INCOMPLETE_FORMATS = GL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS; + FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER; + FRAMEBUFFER_INCOMPLETE_READ_BUFFER = GL2GL3.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER; + FRAMEBUFFER_UNSUPPORTED = GL.GL_FRAMEBUFFER_UNSUPPORTED; + + FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE; + FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME; + FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = GL.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL; + FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = GL.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE; + + RENDERBUFFER_WIDTH = GL.GL_RENDERBUFFER_WIDTH; + RENDERBUFFER_HEIGHT = GL.GL_RENDERBUFFER_HEIGHT; + RENDERBUFFER_RED_SIZE = GL.GL_RENDERBUFFER_RED_SIZE; + RENDERBUFFER_GREEN_SIZE = GL.GL_RENDERBUFFER_GREEN_SIZE; + RENDERBUFFER_BLUE_SIZE = GL.GL_RENDERBUFFER_BLUE_SIZE; + RENDERBUFFER_ALPHA_SIZE = GL.GL_RENDERBUFFER_ALPHA_SIZE; + RENDERBUFFER_DEPTH_SIZE = GL.GL_RENDERBUFFER_DEPTH_SIZE; + RENDERBUFFER_STENCIL_SIZE = GL.GL_RENDERBUFFER_STENCIL_SIZE; + RENDERBUFFER_INTERNAL_FORMAT = GL.GL_RENDERBUFFER_INTERNAL_FORMAT; + + MULTISAMPLE = GL.GL_MULTISAMPLE; + POINT_SMOOTH = GL2ES1.GL_POINT_SMOOTH; + LINE_SMOOTH = GL.GL_LINE_SMOOTH; + POLYGON_SMOOTH = GL2GL3.GL_POLYGON_SMOOTH; + } + + + /////////////////////////////////////////////////////////// + + // Special Functions + + @Override + public void flush() { + gl.glFlush(); + } + + @Override + public void finish() { + gl.glFinish(); + } + + @Override + public void hint(int target, int hint) { + gl.glHint(target, hint); + } + + /////////////////////////////////////////////////////////// + + // State and State Requests + + @Override + public void enable(int value) { + if (-1 < value) { + gl.glEnable(value); + } + } + + @Override + public void disable(int value) { + if (-1 < value) { + gl.glDisable(value); + } + } + + @Override + public void getBooleanv(int value, IntBuffer data) { + if (-1 < value) { + if (byteBuffer.capacity() < data.capacity()) { + byteBuffer = allocateDirectByteBuffer(data.capacity()); + } + gl.glGetBooleanv(value, byteBuffer); + for (int i = 0; i < data.capacity(); i++) { + data.put(i, byteBuffer.get(i)); + } + } else { + fillIntBuffer(data, 0, data.capacity() - 1, 0); + } + } + + @Override + public void getIntegerv(int value, IntBuffer data) { + if (-1 < value) { + gl.glGetIntegerv(value, data); + } else { + fillIntBuffer(data, 0, data.capacity() - 1, 0); + } + } + + @Override + public void getFloatv(int value, FloatBuffer data) { + if (-1 < value) { + gl.glGetFloatv(value, data); + } else { + fillFloatBuffer(data, 0, data.capacity() - 1, 0); + } + } + + @Override + public boolean isEnabled(int value) { + return gl.glIsEnabled(value); + } + + @Override + public String getString(int name) { + return gl.glGetString(name); + } + + /////////////////////////////////////////////////////////// + + // Error Handling + + @Override + public int getError() { + return gl.glGetError(); + } + + @Override + public String errorString(int err) { + return glu.gluErrorString(err); + } + + ////////////////////////////////////////////////////////////////////////////// + + // Buffer Objects + + @Override + public void genBuffers(int n, IntBuffer buffers) { + gl.glGenBuffers(n, buffers); + } + + @Override + public void deleteBuffers(int n, IntBuffer buffers) { + gl.glDeleteBuffers(n, buffers); + } + + @Override + public void bindBuffer(int target, int buffer) { + gl.glBindBuffer(target, buffer); + } + + @Override + public void bufferData(int target, int size, Buffer data, int usage) { + gl.glBufferData(target, size, data, usage); + } + + @Override + public void bufferSubData(int target, int offset, int size, Buffer data) { + gl.glBufferSubData(target, offset, size, data); + } + + @Override + public void isBuffer(int buffer) { + gl.glIsBuffer(buffer); + } + + @Override + public void getBufferParameteriv(int target, int value, IntBuffer data) { + gl.glGetBufferParameteriv(target, value, data); + } + + @Override + public ByteBuffer mapBuffer(int target, int access) { + return gl2.glMapBuffer(target, access); + } + + @Override + public ByteBuffer mapBufferRange(int target, int offset, int length, int access) { + if (gl2x != null) { + return gl2x.glMapBufferRange(target, offset, length, access); + } else { + return null; + } + } + + @Override + public void unmapBuffer(int target) { + gl2.glUnmapBuffer(target); + } + + ////////////////////////////////////////////////////////////////////////////// + + // Viewport and Clipping + + @Override + public void depthRangef(float n, float f) { + gl.glDepthRangef(n, f); + } + + @Override + public void viewport(int x, int y, int w, int h) { + gl.glViewport(x, y, w, h); + } + + ////////////////////////////////////////////////////////////////////////////// + + // Reading Pixels + + @Override + protected void readPixelsImpl(int x, int y, int width, int height, int format, int type, Buffer buffer) { + gl.glReadPixels(x, y, width, height, format, type, buffer); + } + + ////////////////////////////////////////////////////////////////////////////// + + // Vertices + + @Override + public void vertexAttrib1f(int index, float value) { + gl2.glVertexAttrib1f(index, value); + } + + @Override + public void vertexAttrib2f(int index, float value0, float value1) { + gl2.glVertexAttrib2f(index, value0, value1); + } + + @Override + public void vertexAttrib3f(int index, float value0, float value1, float value2) { + gl2.glVertexAttrib3f(index, value0, value1, value2); + } + + @Override + public void vertexAttrib4f(int index, float value0, float value1, float value2, float value3) { + gl2.glVertexAttrib4f(index, value0, value1, value2, value3); + } + + @Override + public void vertexAttrib1fv(int index, FloatBuffer values) { + gl2.glVertexAttrib1fv(index, values); + } + + @Override + public void vertexAttrib2fv(int index, FloatBuffer values) { + gl2.glVertexAttrib2fv(index, values); + } + + @Override + public void vertexAttrib3fv(int index, FloatBuffer values) { + gl2.glVertexAttrib3fv(index, values); + } + + @Override + public void vertexAttri4fv(int index, FloatBuffer values) { + gl2.glVertexAttrib4fv(index, values); + } + + @Override + public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, int offset) { + gl2.glVertexAttribPointer(index, size, type, normalized, stride, offset); + } + + @Override + public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer data) { + gl2.glVertexAttribPointer(index, size, type, normalized, stride, data); + } + + @Override + public void enableVertexAttribArray(int index) { + gl2.glEnableVertexAttribArray(index); + } + + @Override + public void disableVertexAttribArray(int index) { + gl2.glDisableVertexAttribArray(index); + } + + @Override + public void drawArrays(int mode, int first, int count) { + gl.glDrawArrays(mode, first, count); + } + + @Override + public void drawElements(int mode, int count, int type, int offset) { + gl.glDrawElements(mode, count, type, offset); + } + + @Override + public void drawElements(int mode, int count, int type, Buffer indices) { + gl.glDrawElements(mode, count, type, indices); + } + + ////////////////////////////////////////////////////////////////////////////// + + // Rasterization + + @Override + public void lineWidth(float width) { + gl.glLineWidth(width); + } + + @Override + public void frontFace(int dir) { + gl.glFrontFace(dir); + } + + @Override + public void cullFace(int mode) { + gl.glCullFace(mode); + } + + @Override + public void polygonOffset(float factor, float units) { + gl.glPolygonOffset(factor, units); + } + + ////////////////////////////////////////////////////////////////////////////// + + // Pixel Rectangles + + @Override + public void pixelStorei(int pname, int param) { + gl.glPixelStorei(pname, param); + } + + /////////////////////////////////////////////////////////// + + // Texturing + + @Override + public void texImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, Buffer data) { + gl.glTexImage2D(target, level, internalFormat, width, height, border, format, type, data); + } + + @Override + public void copyTexImage2D(int target, int level, int internalFormat, int x, int y, int width, int height, int border) { + gl.glCopyTexImage2D(target, level, internalFormat, x, y, width, height, border); + } + + @Override + public void texSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int type, Buffer data) { + gl.glTexSubImage2D(target, level, xOffset, yOffset, width, height, format, type, data); + } + + @Override + public void copyTexSubImage2D(int target, int level, int xOffset, int yOffset, int x, int y, int width, int height) { + gl.glCopyTexSubImage2D(target, level, x, y, xOffset, xOffset, width, height); + } + + @Override + public void compressedTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int imageSize, Buffer data) { + gl.glCompressedTexImage2D(target, level, internalFormat, width, height, border, imageSize, data); + } + + @Override + public void compressedTexSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int imageSize, Buffer data) { + gl.glCompressedTexSubImage2D(target, level, xOffset, yOffset, width, height, format, imageSize, data); + } + + @Override + public void texParameteri(int target, int pname, int param) { + gl.glTexParameteri(target, pname, param); + } + + @Override + public void texParameterf(int target, int pname, float param) { + gl.glTexParameterf(target, pname, param); + } + + @Override + public void texParameteriv(int target, int pname, IntBuffer params) { + gl.glTexParameteriv(target, pname, params); + } + + @Override + public void texParameterfv(int target, int pname, FloatBuffer params) { + gl.glTexParameterfv(target, pname, params); + } + + @Override + public void generateMipmap(int target) { + gl.glGenerateMipmap(target); + } + + @Override + public void genTextures(int n, IntBuffer textures) { + gl.glGenTextures(n, textures); + } + + @Override + public void deleteTextures(int n, IntBuffer textures) { + gl.glDeleteTextures(n, textures); + } + + @Override + public void getTexParameteriv(int target, int pname, IntBuffer params) { + gl.glGetTexParameteriv(target, pname, params); + } + + @Override + public void getTexParameterfv(int target, int pname, FloatBuffer params) { + gl.glGetTexParameterfv(target, pname, params); + } + + @Override + public boolean isTexture(int texture) { + return gl.glIsTexture(texture); + } + + @Override + protected void activeTextureImpl(int texture) { + gl.glActiveTexture(texture); + } + + @Override + protected void bindTextureImpl(int target, int texture) { + gl.glBindTexture(target, texture); + } + + /////////////////////////////////////////////////////////// + + // Shaders and Programs + + @Override + public int createShader(int type) { + return gl2.glCreateShader(type); + } + + @Override + public void shaderSource(int shader, String source) { + gl2.glShaderSource(shader, 1, new String[] { source }, (int[]) null, 0); + } + + @Override + public void compileShader(int shader) { + gl2.glCompileShader(shader); + } + + @Override + public void releaseShaderCompiler() { + gl2.glReleaseShaderCompiler(); + } + + @Override + public void deleteShader(int shader) { + gl2.glDeleteShader(shader); + } + + @Override + public void shaderBinary(int count, IntBuffer shaders, int binaryFormat, Buffer binary, int length) { + gl2.glShaderBinary(count, shaders, binaryFormat, binary, length); + } + + @Override + public int createProgram() { + return gl2.glCreateProgram(); + } + + @Override + public void attachShader(int program, int shader) { + gl2.glAttachShader(program, shader); + } + + @Override + public void detachShader(int program, int shader) { + gl2.glDetachShader(program, shader); + } + + @Override + public void linkProgram(int program) { + gl2.glLinkProgram(program); + } + + @Override + public void useProgram(int program) { + gl2.glUseProgram(program); + } + + @Override + public void deleteProgram(int program) { + gl2.glDeleteProgram(program); + } + + @Override + public String glGetActiveAttrib (int program, int index, IntBuffer size, IntBuffer type) { + int[] tmp = {0, 0, 0}; + byte[] namebuf = new byte[1024]; + gl2.glGetActiveAttrib(program, index, 1024, tmp, 0, tmp, 1, tmp, 2, namebuf, 0); + size.put(tmp[1]); + type.put(tmp[2]); + String name = new String(namebuf, 0, tmp[0]); + return name; + } + + @Override + public int getAttribLocation(int program, String name) { + return gl2.glGetAttribLocation(program, name); + } + + @Override + public void bindAttribLocation(int program, int index, String name) { + gl2.glBindAttribLocation(program, index, name); + } + + @Override + public int getUniformLocation(int program, String name) { + return gl2.glGetUniformLocation(program, name); + } + + @Override + public String getActiveUniform(int program, int index, IntBuffer size, IntBuffer type) { + int[] tmp= {0, 0, 0}; + byte[] namebuf = new byte[1024]; + gl2.glGetActiveUniform(program, index, 1024, tmp, 0, tmp, 1, tmp, 2, namebuf, 0); + size.put(tmp[1]); + type.put(tmp[2]); + String name = new String(namebuf, 0, tmp[0]); + return name; + } + + @Override + public void uniform1i(int location, int value) { + gl2.glUniform1i(location, value); + } + + @Override + public void uniform2i(int location, int value0, int value1) { + gl2.glUniform2i(location, value0, value1); + } + + @Override + public void uniform3i(int location, int value0, int value1, int value2) { + gl2.glUniform3i(location, value0, value1, value2); + } + + @Override + public void uniform4i(int location, int value0, int value1, int value2, int value3) { + gl2.glUniform4i(location, value0, value1, value2, value3); + } + + @Override + public void uniform1f(int location, float value) { + gl2.glUniform1f(location, value); + } + + @Override + public void uniform2f(int location, float value0, float value1) { + gl2.glUniform2f(location, value0, value1); + } + + @Override + public void uniform3f(int location, float value0, float value1, float value2) { + gl2.glUniform3f(location, value0, value1, value2); + } + + @Override + public void uniform4f(int location, float value0, float value1, float value2, float value3) { + gl2.glUniform4f(location, value0, value1, value2, value3); + } + + @Override + public void uniform1iv(int location, int count, IntBuffer v) { + gl2.glUniform1iv(location, count, v); + } + + @Override + public void uniform2iv(int location, int count, IntBuffer v) { + gl2.glUniform2iv(location, count, v); + } + + @Override + public void uniform3iv(int location, int count, IntBuffer v) { + gl2.glUniform3iv(location, count, v); + } + + @Override + public void uniform4iv(int location, int count, IntBuffer v) { + gl2.glUniform4iv(location, count, v); + } + + @Override + public void uniform1fv(int location, int count, FloatBuffer v) { + gl2.glUniform1fv(location, count, v); + } + + @Override + public void uniform2fv(int location, int count, FloatBuffer v) { + gl2.glUniform2fv(location, count, v); + } + + @Override + public void uniform3fv(int location, int count, FloatBuffer v) { + gl2.glUniform3fv(location, count, v); + } + + @Override + public void uniform4fv(int location, int count, FloatBuffer v) { + gl2.glUniform4fv(location, count, v); + } + + @Override + public void uniformMatrix2fv(int location, int count, boolean transpose, FloatBuffer mat) { + gl2.glUniformMatrix2fv(location, count, transpose, mat); + } + + @Override + public void uniformMatrix3fv(int location, int count, boolean transpose, FloatBuffer mat) { + gl2.glUniformMatrix3fv(location, count, transpose, mat); + } + + @Override + public void uniformMatrix4fv(int location, int count, boolean transpose, FloatBuffer mat) { + gl2.glUniformMatrix4fv(location, count, transpose, mat); + } + + @Override + public void validateProgram(int program) { + gl2.glValidateProgram(program); + } + + @Override + public boolean isShader(int shader) { + return gl2.glIsShader(shader); + } + + @Override + public void getShaderiv(int shader, int pname, IntBuffer params) { + gl2.glGetShaderiv(shader, pname, params); + } + + @Override + public void getAttachedShaders(int program, int maxCount, IntBuffer count, IntBuffer shaders) { + gl2.glGetAttachedShaders(program, maxCount, count, shaders); + } + + @Override + public String getShaderInfoLog(int shader) { + int[] val = { 0 }; + gl2.glGetShaderiv(shader, GL2ES2.GL_INFO_LOG_LENGTH, val, 0); + int length = val[0]; + + byte[] log = new byte[length]; + gl2.glGetShaderInfoLog(shader, length, val, 0, log, 0); + return new String(log); + } + + @Override + public String getShaderSource(int shader) { + int[] len = {0}; + byte[] buf = new byte[1024]; + gl2.glGetShaderSource(shader, 1024, len, 0, buf, 0); + return new String(buf, 0, len[0]); + } + + @Override + public void getShaderPrecisionFormat(int shaderType, int precisionType, IntBuffer range, IntBuffer precision) { + gl2.glGetShaderPrecisionFormat(shaderType, precisionType, range, precision); + } + + @Override + public void getVertexAttribfv(int index, int pname, FloatBuffer params) { + gl2.glGetVertexAttribfv(index, pname, params); + } + + @Override + public void getVertexAttribiv(int index, int pname, IntBuffer params) { + gl2.glGetVertexAttribiv(index, pname, params); + } + + @Override + public void getVertexAttribPointerv(int index, int pname, ByteBuffer data) { + throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glGetVertexAttribPointerv()")); + } + + @Override + public void getUniformfv(int program, int location, FloatBuffer params) { + gl2.glGetUniformfv(program, location, params); + } + + @Override + public void getUniformiv(int program, int location, IntBuffer params) { + gl2.glGetUniformiv(program, location, params); + } + + @Override + public boolean isProgram(int program) { + return gl2.glIsProgram(program); + } + + @Override + public void getProgramiv(int program, int pname, IntBuffer params) { + gl2.glGetProgramiv(program, pname, params); + } + + @Override + public String getProgramInfoLog(int program) { + int[] val = { 0 }; + gl2.glGetShaderiv(program, GL2.GL_INFO_LOG_LENGTH, val, 0); + int length = val[0]; + + if (0 < length) { + byte[] log = new byte[length]; + gl2.glGetProgramInfoLog(program, length, val, 0, log, 0); + return new String(log); + } else { + return "Unknow error"; + } + } + + /////////////////////////////////////////////////////////// + + // Per-Fragment Operations + + @Override + public void scissor(int x, int y, int w, int h) { + gl.glScissor(x, y, w, h); + } + + @Override + public void sampleCoverage(float value, boolean invert) { + gl2.glSampleCoverage(value, invert); + } + + @Override + public void stencilFunc(int func, int ref, int mask) { + gl2.glStencilFunc(func, ref, mask); + } + + @Override + public void stencilFuncSeparate(int face, int func, int ref, int mask) { + gl2.glStencilFuncSeparate(face, func, ref, mask); + } + + @Override + public void stencilOp(int sfail, int dpfail, int dppass) { + gl2.glStencilOp(sfail, dpfail, dppass); + } + + @Override + public void stencilOpSeparate(int face, int sfail, int dpfail, int dppass) { + gl2.glStencilOpSeparate(face, sfail, dpfail, dppass); + } + + @Override + public void depthFunc(int func) { + gl.glDepthFunc(func); + } + + @Override + public void blendEquation(int mode) { + gl.glBlendEquation(mode); + } + + @Override + public void blendEquationSeparate(int modeRGB, int modeAlpha) { + gl.glBlendEquationSeparate(modeRGB, modeAlpha); + } + + @Override + public void blendFunc(int src, int dst) { + gl.glBlendFunc(src, dst); + } + + @Override + public void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) { + gl.glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); + } + + @Override + public void blendColor(float red, float green, float blue, float alpha) { + gl2.glBlendColor(red, green, blue, alpha); + } + + @Override + public void alphaFunc(int func, float ref) { + if (gl2x != null) { + gl2x.glAlphaFunc(func, ref); + } + } + + /////////////////////////////////////////////////////////// + + // Whole Framebuffer Operations + + @Override + public void colorMask(boolean r, boolean g, boolean b, boolean a) { + gl.glColorMask(r, g, b, a); + } + + @Override + public void depthMask(boolean mask) { + gl.glDepthMask(mask); + } + + @Override + public void stencilMask(int mask) { + gl.glStencilMask(mask); + } + + @Override + public void stencilMaskSeparate(int face, int mask) { + gl2.glStencilMaskSeparate(face, mask); + } + + @Override + public void clear(int buf) { + gl.glClear(buf); + } + + @Override + public void clearColor(float r, float g, float b, float a) { + gl.glClearColor(r, g, b, a); + } + + @Override + public void clearDepth(float d) { + gl.glClearDepthf(d); + } + + @Override + public void clearStencil(int s) { + gl.glClearStencil(s); + } + + /////////////////////////////////////////////////////////// + + // Framebuffers Objects + + @Override + public void bindFramebuffer(int target, int framebuffer) { + gl.glBindFramebuffer(target, framebuffer); + } + + @Override + public void deleteFramebuffers(int n, IntBuffer framebuffers) { + gl.glDeleteFramebuffers(n, framebuffers); + } + + @Override + public void genFramebuffers(int n, IntBuffer framebuffers) { + gl.glGenFramebuffers(n, framebuffers); + } + + @Override + public void bindRenderbuffer(int target, int renderbuffer) { + gl.glBindRenderbuffer(target, renderbuffer); + } + + @Override + public void deleteRenderbuffers(int n, IntBuffer renderbuffers) { + gl.glDeleteRenderbuffers(n, renderbuffers); + } + + @Override + public void genRenderbuffers(int n, IntBuffer renderbuffers) { + gl.glGenRenderbuffers(n, renderbuffers); + } + + @Override + public void renderbufferStorage(int target, int internalFormat, int width, int height) { + gl.glRenderbufferStorage(target, internalFormat, width, height); + } + + @Override + public void framebufferRenderbuffer(int target, int attachment, int rendbuferfTarget, int renderbuffer) { + gl.glFramebufferRenderbuffer(target, attachment, rendbuferfTarget, renderbuffer); + } + + @Override + public void framebufferTexture2D(int target, int attachment, int texTarget, int texture, int level) { + gl.glFramebufferTexture2D(target, attachment, texTarget, texture, level); + } + + @Override + public int checkFramebufferStatus(int target) { + return gl.glCheckFramebufferStatus(target); + } + + @Override + public boolean isFramebuffer(int framebuffer) { + return gl2.glIsFramebuffer(framebuffer); + } + + @Override + public void getFramebufferAttachmentParameteriv(int target, int attachment, int pname, IntBuffer params) { + gl2.glGetFramebufferAttachmentParameteriv(target, attachment, pname, params); + } + + @Override + public boolean isRenderbuffer(int renderbuffer) { + return gl2.glIsRenderbuffer(renderbuffer); + } + + @Override + public void getRenderbufferParameteriv(int target, int pname, IntBuffer params) { + gl2.glGetRenderbufferParameteriv(target, pname, params); + } + + @Override + public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) { + if (gl2x != null) { + gl2x.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + } + } + + @Override + public void renderbufferStorageMultisample(int target, int samples, int format, int width, int height) { + if (gl2x != null) { + gl2x.glRenderbufferStorageMultisample(target, samples, format, width, height); + } + } + + @Override + public void readBuffer(int buf) { + if (gl2x != null) { + gl2x.glReadBuffer(buf); + } + } + + @Override + public void drawBuffer(int buf) { + if (gl2x != null) { + gl2x.glDrawBuffer(buf); + } + } + + + + + + /////////////////////////////////////////////////////////// + + // JOGL Event listeners + + protected boolean changedFrontTex = false; + protected boolean changedBackTex = false; + + protected class PGLListener implements GLEventListener { + public PGLListener() {} + + @Override + public void display(GLAutoDrawable glDrawable) { + drawable = glDrawable; + context = glDrawable.getContext(); + contextID = context.hashCode(); + + glThread = Thread.currentThread(); + + gl = context.getGL(); + gl2 = gl.getGL2ES2(); + try { + gl2x = gl.getGL2(); + } catch (javax.media.opengl.GLException e) { + gl2x = null; + } + + if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { + // The onscreen drawing surface is backed by an FBO layer. + GLFBODrawable fboDrawable = null; + + if (WINDOW_TOOLKIT == AWT) { + GLCanvas glCanvas = (GLCanvas)glDrawable; + fboDrawable = (GLFBODrawable)glCanvas.getDelegatedDrawable(); + } else { + GLWindow glWindow = (GLWindow)glDrawable; + fboDrawable = (GLFBODrawable)glWindow.getDelegatedDrawable(); + } + + if (fboDrawable != null) { + backFBO = fboDrawable.getFBObject(GL.GL_BACK); + if (1 < numSamples) { + if (needSepFrontTex) { + // When using multisampled FBO, the back buffer is the MSAA + // surface so it cannot be read from. The sink buffer contains + // the readable 2D texture. + // In this case, we create an auxiliary "front" buffer that it is + // swapped with the sink buffer at the beginning of each frame. + // In this way, we always have a readable copy of the previous + // frame in the front texture, while the back is synchronized + // with the contents of the MSAA back buffer when requested. + if (frontFBO == null) { + // init + frontFBO = new FBObject(); + frontFBO.reset(gl, pg.width, pg.height); + frontFBO.attachTexture2D(gl, 0, true); + sinkFBO = backFBO.getSamplingSinkFBO(); + changedFrontTex = changedBackTex = true; + } else { + // swap + FBObject temp = sinkFBO; + sinkFBO = frontFBO; + frontFBO = temp; + backFBO.setSamplingSink(sinkFBO); + changedFrontTex = changedBackTex = false; + } + backTexAttach = (FBObject.TextureAttachment) sinkFBO. + getColorbuffer(0); + frontTexAttach = (FBObject.TextureAttachment)frontFBO. + getColorbuffer(0); + } else { + // Default setting (to save resources): the front and back + // textures are the same. + sinkFBO = backFBO.getSamplingSinkFBO(); + backTexAttach = (FBObject.TextureAttachment) sinkFBO. + getColorbuffer(0); + frontTexAttach = backTexAttach; + } + + } else { + // w/out multisampling, rendering is done on the back buffer. + frontFBO = fboDrawable.getFBObject(GL.GL_FRONT); + + backTexAttach = fboDrawable.getTextureBuffer(GL.GL_BACK); + frontTexAttach = fboDrawable.getTextureBuffer(GL.GL_FRONT); + } + } + } + + pg.parent.handleDraw(); +// clearColor(1, 0, 0, 1); +// clear(COLOR_BUFFER_BIT); + drawLatch.countDown(); + } + + @Override + public void dispose(GLAutoDrawable adrawable) { + } + + @Override + public void init(GLAutoDrawable adrawable) { + drawable = adrawable; + context = adrawable.getContext(); + contextID = context.hashCode(); + capabilities = adrawable.getChosenGLCapabilities(); + gl = context.getGL(); + + if (!hasFBOs()) { + throw new RuntimeException(MISSING_FBO_ERROR); + } + if (!hasShaders()) { + throw new RuntimeException(MISSING_GLSL_ERROR); + } + if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { + int maxs = maxSamples(); + numSamples = PApplet.min(capabilities.getNumSamples(), maxs); + } + } + + @Override + public void reshape(GLAutoDrawable adrawable, int x, int y, int w, int h) { + drawable = adrawable; + context = adrawable.getContext(); + contextID = context.hashCode(); + } + } + + protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent, + int peAction) { + int modifiers = nativeEvent.getModifiers(); + int peModifiers = modifiers & + (InputEvent.SHIFT_MASK | + InputEvent.CTRL_MASK | + InputEvent.META_MASK | + InputEvent.ALT_MASK); + + int peButton = 0; + if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { + peButton = PConstants.LEFT; + } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { + peButton = PConstants.CENTER; + } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { + peButton = PConstants.RIGHT; + } + + if (PApplet.platform == PConstants.MACOSX) { + //if (nativeEvent.isPopupTrigger()) { + if ((modifiers & InputEvent.CTRL_MASK) != 0) { + peButton = PConstants.RIGHT; + } + } + + int peCount = 0; + if (peAction == MouseEvent.WHEEL) { + peCount = nativeEvent.isShiftDown() ? (int)nativeEvent.getRotation()[0] : + (int)nativeEvent.getRotation()[1]; + } else { + peCount = nativeEvent.getClickCount(); + } + + MouseEvent me = new MouseEvent(nativeEvent, nativeEvent.getWhen(), + peAction, peModifiers, + nativeEvent.getX(), nativeEvent.getY(), + peButton, + peCount); + + pg.parent.postEvent(me); + } + + protected void nativeKeyEvent(com.jogamp.newt.event.KeyEvent nativeEvent, + int peAction) { + int peModifiers = nativeEvent.getModifiers() & + (InputEvent.SHIFT_MASK | + InputEvent.CTRL_MASK | + InputEvent.META_MASK | + InputEvent.ALT_MASK); + + char keyChar; + if ((int)nativeEvent.getKeyChar() == 0) { + keyChar = PConstants.CODED; + } else { + keyChar = nativeEvent.getKeyChar(); + } + + KeyEvent ke = new KeyEvent(nativeEvent, nativeEvent.getWhen(), + peAction, peModifiers, + keyChar, + nativeEvent.getKeyCode()); + + pg.parent.postEvent(ke); + } + + class NEWTWindowListener implements com.jogamp.newt.event.WindowListener { + @Override + public void windowGainedFocus(com.jogamp.newt.event.WindowEvent arg0) { + pg.parent.focusGained(null); + } + + @Override + public void windowLostFocus(com.jogamp.newt.event.WindowEvent arg0) { + pg.parent.focusLost(null); + } + + @Override + public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) { + } + + @Override + public void windowDestroyed(com.jogamp.newt.event.WindowEvent arg0) { + } + + @Override + public void windowMoved(com.jogamp.newt.event.WindowEvent arg0) { + } + + @Override + public void windowRepaint(com.jogamp.newt.event.WindowUpdateEvent arg0) { + } + + @Override + public void windowResized(com.jogamp.newt.event.WindowEvent arg0) { } + } + + // NEWT mouse listener + class NEWTMouseListener extends com.jogamp.newt.event.MouseAdapter { + @Override + public void mousePressed(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.PRESS); + } + @Override + public void mouseReleased(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.RELEASE); + } + @Override + public void mouseClicked(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.CLICK); + } + @Override + public void mouseDragged(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.DRAG); + } + @Override + public void mouseMoved(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.MOVE); + } + @Override + public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.WHEEL); + } + @Override + public void mouseEntered(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.ENTER); + } + @Override + public void mouseExited(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.EXIT); + } + } + + // NEWT key listener + class NEWTKeyListener extends com.jogamp.newt.event.KeyAdapter { + @Override + public void keyPressed(com.jogamp.newt.event.KeyEvent e) { + nativeKeyEvent(e, KeyEvent.PRESS); + } + @Override + public void keyReleased(com.jogamp.newt.event.KeyEvent e) { + nativeKeyEvent(e, KeyEvent.RELEASE); + } + public void keyTyped(com.jogamp.newt.event.KeyEvent e) { + nativeKeyEvent(e, KeyEvent.TYPE); + } + } + + + + + @Override + protected Tessellator createTessellator(TessellatorCallback callback) { + return new Tessellator(callback); + } + + protected class Tessellator implements PGL.Tessellator { + protected GLUtessellator tess; + protected TessellatorCallback callback; + protected GLUCallback gluCallback; + + public Tessellator(TessellatorCallback callback) { + this.callback = callback; + tess = GLU.gluNewTess(); + gluCallback = new GLUCallback(); + + GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_END, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR, gluCallback); + } + + @Override + public void beginPolygon() { + GLU.gluTessBeginPolygon(tess, null); + } + + @Override + public void endPolygon() { + GLU.gluTessEndPolygon(tess); + } + + @Override + public void setWindingRule(int rule) { + GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, rule); + } + + @Override + public void beginContour() { + GLU.gluTessBeginContour(tess); + } + + @Override + public void endContour() { + GLU.gluTessEndContour(tess); + } + + @Override + public void addVertex(double[] v) { + GLU.gluTessVertex(tess, v, 0, v); + } + + protected class GLUCallback extends GLUtessellatorCallbackAdapter { + @Override + public void begin(int type) { + callback.begin(type); + } + + @Override + public void end() { + callback.end(); + } + + @Override + public void vertex(Object data) { + callback.vertex(data); + } + + @Override + public void combine(double[] coords, Object[] data, + float[] weight, Object[] outData) { + callback.combine(coords, data, weight, outData); + } + + @Override + public void error(int errnum) { + callback.error(errnum); + } + } + } + + @Override + protected String tessError(int err) { + return glu.gluErrorString(err); + } + + static { + SHAPE_TEXT_SUPPORTED = true; + SEG_MOVETO = PathIterator.SEG_MOVETO; + SEG_LINETO = PathIterator.SEG_LINETO; + SEG_QUADTO = PathIterator.SEG_QUADTO; + SEG_CUBICTO = PathIterator.SEG_CUBICTO; + SEG_CLOSE = PathIterator.SEG_CLOSE; + } + + @Override + protected FontOutline createFontOutline(char ch, Object font) { + return new FontOutline(ch, font); + } + + protected class FontOutline implements PGL.FontOutline { + PathIterator iter; + + public FontOutline(char ch, Object font) { + char textArray[] = new char[] { ch }; + Graphics2D graphics = (Graphics2D) pg.parent.getGraphics(); + FontRenderContext frc = graphics.getFontRenderContext(); + GlyphVector gv = ((Font)font).createGlyphVector(frc, textArray); + Shape shp = gv.getOutline(); + iter = shp.getPathIterator(null); + } + + public boolean isDone() { + return iter.isDone(); + } + + public int currentSegment(float coords[]) { + return iter.currentSegment(coords); + } + + public void next() { + iter.next(); + } + } + } diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java index f1d63d138..5fe122c86 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java @@ -2529,308 +2529,299 @@ public class PLWJGL extends PGL { - - ////////////////////////////////////////////////////////////////////////////// - // - // OpenGL ES 2.0 API, with a few additional functions for multisampling and - // and buffer mapping from OpenGL 2.1+. - // - // The functions are organized following the groups in the GLES 2.0 reference - // card: - // http://www.khronos.org/opengles/sdk/docs/reference_cards/OpenGL-ES-2_0-Reference-card.pdf - // - // The entire GLES 2.0 specification is available below: - // http://www.khronos.org/opengles/2_X/ - // - ////////////////////////////////////////////////////////////////////////////// + + + + + /////////////////////////////////////////////////////////// // Constants - public static final int FALSE = GL11.GL_FALSE; - public static final int TRUE = GL11.GL_TRUE; + static { + FALSE = GL11.GL_FALSE; + TRUE = GL11.GL_TRUE; - public static final int INT = GL11.GL_INT; - public static final int BYTE = GL11.GL_BYTE; - public static final int SHORT = GL11.GL_SHORT; - public static final int FLOAT = GL11.GL_FLOAT; - public static final int BOOL = GL20.GL_BOOL; - public static final int UNSIGNED_INT = GL11.GL_UNSIGNED_INT; - public static final int UNSIGNED_BYTE = GL11.GL_UNSIGNED_BYTE; - public static final int UNSIGNED_SHORT = GL11.GL_UNSIGNED_SHORT; + INT = GL11.GL_INT; + BYTE = GL11.GL_BYTE; + SHORT = GL11.GL_SHORT; + FLOAT = GL11.GL_FLOAT; + BOOL = GL20.GL_BOOL; + UNSIGNED_INT = GL11.GL_UNSIGNED_INT; + UNSIGNED_BYTE = GL11.GL_UNSIGNED_BYTE; + UNSIGNED_SHORT = GL11.GL_UNSIGNED_SHORT; - public static final int RGB = GL11.GL_RGB; - public static final int RGBA = GL11.GL_RGBA; - public static final int ALPHA = GL11.GL_ALPHA; - public static final int LUMINANCE = GL11.GL_LUMINANCE; - public static final int LUMINANCE_ALPHA = GL11.GL_LUMINANCE_ALPHA; + RGB = GL11.GL_RGB; + RGBA = GL11.GL_RGBA; + ALPHA = GL11.GL_ALPHA; + LUMINANCE = GL11.GL_LUMINANCE; + LUMINANCE_ALPHA = GL11.GL_LUMINANCE_ALPHA; - public static final int UNSIGNED_SHORT_5_6_5 = GL12.GL_UNSIGNED_SHORT_5_6_5; - public static final int UNSIGNED_SHORT_4_4_4_4 = GL12.GL_UNSIGNED_SHORT_4_4_4_4; - public static final int UNSIGNED_SHORT_5_5_5_1 = GL12.GL_UNSIGNED_SHORT_5_5_5_1; + UNSIGNED_SHORT_5_6_5 = GL12.GL_UNSIGNED_SHORT_5_6_5; + UNSIGNED_SHORT_4_4_4_4 = GL12.GL_UNSIGNED_SHORT_4_4_4_4; + UNSIGNED_SHORT_5_5_5_1 = GL12.GL_UNSIGNED_SHORT_5_5_5_1; - public static final int RGBA4 = GL11.GL_RGBA4; - public static final int RGB5_A1 = GL11.GL_RGB5_A1; - public static final int RGB565 = ARBES2Compatibility.GL_RGB565; + RGBA4 = GL11.GL_RGBA4; + RGB5_A1 = GL11.GL_RGB5_A1; + RGB565 = ARBES2Compatibility.GL_RGB565; - public static final int READ_ONLY = GL15.GL_READ_ONLY; - public static final int WRITE_ONLY = GL15.GL_WRITE_ONLY; - public static final int READ_WRITE = GL15.GL_READ_WRITE; + READ_ONLY = GL15.GL_READ_ONLY; + WRITE_ONLY = GL15.GL_WRITE_ONLY; + READ_WRITE = GL15.GL_READ_WRITE; - public static final int TESS_WINDING_NONZERO = GLU.GLU_TESS_WINDING_NONZERO; - public static final int TESS_WINDING_ODD = GLU.GLU_TESS_WINDING_ODD; + TESS_WINDING_NONZERO = GLU.GLU_TESS_WINDING_NONZERO; + TESS_WINDING_ODD = GLU.GLU_TESS_WINDING_ODD; - public static final int GENERATE_MIPMAP_HINT = GL14.GL_GENERATE_MIPMAP_HINT; - public static final int FASTEST = GL11.GL_FASTEST; - public static final int NICEST = GL11.GL_NICEST; - public static final int DONT_CARE = GL11.GL_DONT_CARE; + GENERATE_MIPMAP_HINT = GL14.GL_GENERATE_MIPMAP_HINT; + FASTEST = GL11.GL_FASTEST; + NICEST = GL11.GL_NICEST; + DONT_CARE = GL11.GL_DONT_CARE; - public static final int VENDOR = GL11.GL_VENDOR; - public static final int RENDERER = GL11.GL_RENDERER; - public static final int VERSION = GL11.GL_VERSION; - public static final int EXTENSIONS = GL11.GL_EXTENSIONS; - public static final int SHADING_LANGUAGE_VERSION = GL20.GL_SHADING_LANGUAGE_VERSION; + VENDOR = GL11.GL_VENDOR; + RENDERER = GL11.GL_RENDERER; + VERSION = GL11.GL_VERSION; + EXTENSIONS = GL11.GL_EXTENSIONS; + SHADING_LANGUAGE_VERSION = GL20.GL_SHADING_LANGUAGE_VERSION; - public static final int MAX_SAMPLES = GL30.GL_MAX_SAMPLES; - public static final int SAMPLES = GL13.GL_SAMPLES; + MAX_SAMPLES = GL30.GL_MAX_SAMPLES; + SAMPLES = GL13.GL_SAMPLES; - public static final int ALIASED_LINE_WIDTH_RANGE = GL12.GL_ALIASED_LINE_WIDTH_RANGE; - public static final int ALIASED_POINT_SIZE_RANGE = GL12.GL_ALIASED_POINT_SIZE_RANGE; + ALIASED_LINE_WIDTH_RANGE = GL12.GL_ALIASED_LINE_WIDTH_RANGE; + ALIASED_POINT_SIZE_RANGE = GL12.GL_ALIASED_POINT_SIZE_RANGE; - public static final int DEPTH_BITS = GL11.GL_DEPTH_BITS; - public static final int STENCIL_BITS = GL11.GL_STENCIL_BITS; + DEPTH_BITS = GL11.GL_DEPTH_BITS; + STENCIL_BITS = GL11.GL_STENCIL_BITS; - public static final int CCW = GL11.GL_CCW; - public static final int CW = GL11.GL_CW; + CCW = GL11.GL_CCW; + CW = GL11.GL_CW; - public static final int VIEWPORT = GL11.GL_VIEWPORT; + VIEWPORT = GL11.GL_VIEWPORT; - public static final int ARRAY_BUFFER = GL15.GL_ARRAY_BUFFER; - public static final int ELEMENT_ARRAY_BUFFER = GL15.GL_ELEMENT_ARRAY_BUFFER; + ARRAY_BUFFER = GL15.GL_ARRAY_BUFFER; + ELEMENT_ARRAY_BUFFER = GL15.GL_ELEMENT_ARRAY_BUFFER; - public static final int MAX_VERTEX_ATTRIBS = GL20.GL_MAX_VERTEX_ATTRIBS; + MAX_VERTEX_ATTRIBS = GL20.GL_MAX_VERTEX_ATTRIBS; - public static final int STATIC_DRAW = GL15.GL_STATIC_DRAW; - public static final int DYNAMIC_DRAW = GL15.GL_DYNAMIC_DRAW; - public static final int STREAM_DRAW = GL15.GL_STREAM_DRAW; + STATIC_DRAW = GL15.GL_STATIC_DRAW; + DYNAMIC_DRAW = GL15.GL_DYNAMIC_DRAW; + STREAM_DRAW = GL15.GL_STREAM_DRAW; - public static final int BUFFER_SIZE = GL15.GL_BUFFER_SIZE; - public static final int BUFFER_USAGE = GL15.GL_BUFFER_USAGE; + BUFFER_SIZE = GL15.GL_BUFFER_SIZE; + BUFFER_USAGE = GL15.GL_BUFFER_USAGE; - public static final int POINTS = GL11.GL_POINTS; - public static final int LINE_STRIP = GL11.GL_LINE_STRIP; - public static final int LINE_LOOP = GL11.GL_LINE_LOOP; - public static final int LINES = GL11.GL_LINES; - public static final int TRIANGLE_FAN = GL11.GL_TRIANGLE_FAN; - public static final int TRIANGLE_STRIP = GL11.GL_TRIANGLE_STRIP; - public static final int TRIANGLES = GL11.GL_TRIANGLES; + POINTS = GL11.GL_POINTS; + LINE_STRIP = GL11.GL_LINE_STRIP; + LINE_LOOP = GL11.GL_LINE_LOOP; + LINES = GL11.GL_LINES; + TRIANGLE_FAN = GL11.GL_TRIANGLE_FAN; + TRIANGLE_STRIP = GL11.GL_TRIANGLE_STRIP; + TRIANGLES = GL11.GL_TRIANGLES; - public static final int CULL_FACE = GL11.GL_CULL_FACE; - public static final int FRONT = GL11.GL_FRONT; - public static final int BACK = GL11.GL_BACK; - public static final int FRONT_AND_BACK = GL11.GL_FRONT_AND_BACK; + CULL_FACE = GL11.GL_CULL_FACE; + FRONT = GL11.GL_FRONT; + BACK = GL11.GL_BACK; + FRONT_AND_BACK = GL11.GL_FRONT_AND_BACK; - public static final int POLYGON_OFFSET_FILL = GL11.GL_POLYGON_OFFSET_FILL; + POLYGON_OFFSET_FILL = GL11.GL_POLYGON_OFFSET_FILL; - public static final int UNPACK_ALIGNMENT = GL11.GL_UNPACK_ALIGNMENT; - public static final int PACK_ALIGNMENT = GL11.GL_PACK_ALIGNMENT; + UNPACK_ALIGNMENT = GL11.GL_UNPACK_ALIGNMENT; + PACK_ALIGNMENT = GL11.GL_PACK_ALIGNMENT; - public static final int TEXTURE_2D = GL11.GL_TEXTURE_2D; - public static final int TEXTURE_RECTANGLE = GL31.GL_TEXTURE_RECTANGLE; + TEXTURE_2D = GL11.GL_TEXTURE_2D; + TEXTURE_RECTANGLE = GL31.GL_TEXTURE_RECTANGLE; - public static final int TEXTURE_BINDING_2D = GL11.GL_TEXTURE_BINDING_2D; - public static final int TEXTURE_BINDING_RECTANGLE = GL31.GL_TEXTURE_BINDING_RECTANGLE; + TEXTURE_BINDING_2D = GL11.GL_TEXTURE_BINDING_2D; + TEXTURE_BINDING_RECTANGLE = GL31.GL_TEXTURE_BINDING_RECTANGLE; - public static final int MAX_TEXTURE_SIZE = GL11.GL_MAX_TEXTURE_SIZE; - public static final int TEXTURE_MAX_ANISOTROPY = EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT; - public static final int MAX_TEXTURE_MAX_ANISOTROPY = EXTTextureFilterAnisotropic.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT; + MAX_TEXTURE_SIZE = GL11.GL_MAX_TEXTURE_SIZE; + TEXTURE_MAX_ANISOTROPY = EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT; + MAX_TEXTURE_MAX_ANISOTROPY = EXTTextureFilterAnisotropic.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT; - public static final int MAX_VERTEX_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS; - public static final int MAX_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_TEXTURE_IMAGE_UNITS; - public static final int MAX_COMBINED_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS; + MAX_VERTEX_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS; + MAX_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_TEXTURE_IMAGE_UNITS; + MAX_COMBINED_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS; - public static final int NUM_COMPRESSED_TEXTURE_FORMATS = GL13.GL_NUM_COMPRESSED_TEXTURE_FORMATS; - public static final int COMPRESSED_TEXTURE_FORMATS = GL13.GL_COMPRESSED_TEXTURE_FORMATS; + NUM_COMPRESSED_TEXTURE_FORMATS = GL13.GL_NUM_COMPRESSED_TEXTURE_FORMATS; + COMPRESSED_TEXTURE_FORMATS = GL13.GL_COMPRESSED_TEXTURE_FORMATS; - public static final int NEAREST = GL11.GL_NEAREST; - public static final int LINEAR = GL11.GL_LINEAR; - public static final int LINEAR_MIPMAP_NEAREST = GL11.GL_LINEAR_MIPMAP_NEAREST; - public static final int LINEAR_MIPMAP_LINEAR = GL11.GL_LINEAR_MIPMAP_LINEAR; + NEAREST = GL11.GL_NEAREST; + LINEAR = GL11.GL_LINEAR; + LINEAR_MIPMAP_NEAREST = GL11.GL_LINEAR_MIPMAP_NEAREST; + LINEAR_MIPMAP_LINEAR = GL11.GL_LINEAR_MIPMAP_LINEAR; - public static final int CLAMP_TO_EDGE = GL12.GL_CLAMP_TO_EDGE; - public static final int REPEAT = GL11.GL_REPEAT; + CLAMP_TO_EDGE = GL12.GL_CLAMP_TO_EDGE; + REPEAT = GL11.GL_REPEAT; - public static final int TEXTURE0 = GL13.GL_TEXTURE0; - public static final int TEXTURE1 = GL13.GL_TEXTURE1; - public static final int TEXTURE2 = GL13.GL_TEXTURE2; - public static final int TEXTURE3 = GL13.GL_TEXTURE3; - public static final int TEXTURE_MIN_FILTER = GL11.GL_TEXTURE_MIN_FILTER; - public static final int TEXTURE_MAG_FILTER = GL11.GL_TEXTURE_MAG_FILTER; - public static final int TEXTURE_WRAP_S = GL11.GL_TEXTURE_WRAP_S; - public static final int TEXTURE_WRAP_T = GL11.GL_TEXTURE_WRAP_T; - public static final int TEXTURE_WRAP_R = GL12.GL_TEXTURE_WRAP_R; + TEXTURE0 = GL13.GL_TEXTURE0; + TEXTURE1 = GL13.GL_TEXTURE1; + TEXTURE2 = GL13.GL_TEXTURE2; + TEXTURE3 = GL13.GL_TEXTURE3; + TEXTURE_MIN_FILTER = GL11.GL_TEXTURE_MIN_FILTER; + TEXTURE_MAG_FILTER = GL11.GL_TEXTURE_MAG_FILTER; + TEXTURE_WRAP_S = GL11.GL_TEXTURE_WRAP_S; + TEXTURE_WRAP_T = GL11.GL_TEXTURE_WRAP_T; + TEXTURE_WRAP_R = GL12.GL_TEXTURE_WRAP_R; - public static final int TEXTURE_CUBE_MAP = GL13.GL_TEXTURE_CUBE_MAP; - public static final int TEXTURE_CUBE_MAP_POSITIVE_X = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X; - public static final int TEXTURE_CUBE_MAP_POSITIVE_Y = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; - public static final int TEXTURE_CUBE_MAP_POSITIVE_Z = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; - public static final int TEXTURE_CUBE_MAP_NEGATIVE_X = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; - public static final int TEXTURE_CUBE_MAP_NEGATIVE_Y = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; - public static final int TEXTURE_CUBE_MAP_NEGATIVE_Z = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; + TEXTURE_CUBE_MAP = GL13.GL_TEXTURE_CUBE_MAP; + TEXTURE_CUBE_MAP_POSITIVE_X = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X; + TEXTURE_CUBE_MAP_POSITIVE_Y = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Y; + TEXTURE_CUBE_MAP_POSITIVE_Z = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Z; + TEXTURE_CUBE_MAP_NEGATIVE_X = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_X; + TEXTURE_CUBE_MAP_NEGATIVE_Y = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; + TEXTURE_CUBE_MAP_NEGATIVE_Z = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; - public static final int VERTEX_SHADER = GL20.GL_VERTEX_SHADER; - public static final int FRAGMENT_SHADER = GL20.GL_FRAGMENT_SHADER; - public static final int INFO_LOG_LENGTH = GL20.GL_INFO_LOG_LENGTH; - public static final int SHADER_SOURCE_LENGTH = GL20.GL_SHADER_SOURCE_LENGTH; - public static final int COMPILE_STATUS = GL20.GL_COMPILE_STATUS; - public static final int LINK_STATUS = GL20.GL_LINK_STATUS; - public static final int VALIDATE_STATUS = GL20.GL_VALIDATE_STATUS; - public static final int SHADER_TYPE = GL20.GL_SHADER_TYPE; - public static final int DELETE_STATUS = GL20.GL_DELETE_STATUS; + VERTEX_SHADER = GL20.GL_VERTEX_SHADER; + FRAGMENT_SHADER = GL20.GL_FRAGMENT_SHADER; + INFO_LOG_LENGTH = GL20.GL_INFO_LOG_LENGTH; + SHADER_SOURCE_LENGTH = GL20.GL_SHADER_SOURCE_LENGTH; + COMPILE_STATUS = GL20.GL_COMPILE_STATUS; + LINK_STATUS = GL20.GL_LINK_STATUS; + VALIDATE_STATUS = GL20.GL_VALIDATE_STATUS; + SHADER_TYPE = GL20.GL_SHADER_TYPE; + DELETE_STATUS = GL20.GL_DELETE_STATUS; - public static final int FLOAT_VEC2 = GL20.GL_FLOAT_VEC2; - public static final int FLOAT_VEC3 = GL20.GL_FLOAT_VEC3; - public static final int FLOAT_VEC4 = GL20.GL_FLOAT_VEC4; - public static final int FLOAT_MAT2 = GL20.GL_FLOAT_MAT2; - public static final int FLOAT_MAT3 = GL20.GL_FLOAT_MAT3; - public static final int FLOAT_MAT4 = GL20.GL_FLOAT_MAT4; - public static final int INT_VEC2 = GL20.GL_INT_VEC2; - public static final int INT_VEC3 = GL20.GL_INT_VEC3; - public static final int INT_VEC4 = GL20.GL_INT_VEC4; - public static final int BOOL_VEC2 = GL20.GL_BOOL_VEC2; - public static final int BOOL_VEC3 = GL20.GL_BOOL_VEC3; - public static final int BOOL_VEC4 = GL20.GL_BOOL_VEC4; - public static final int SAMPLER_2D = GL20.GL_SAMPLER_2D; - public static final int SAMPLER_CUBE = GL20.GL_SAMPLER_CUBE; + FLOAT_VEC2 = GL20.GL_FLOAT_VEC2; + FLOAT_VEC3 = GL20.GL_FLOAT_VEC3; + FLOAT_VEC4 = GL20.GL_FLOAT_VEC4; + FLOAT_MAT2 = GL20.GL_FLOAT_MAT2; + FLOAT_MAT3 = GL20.GL_FLOAT_MAT3; + FLOAT_MAT4 = GL20.GL_FLOAT_MAT4; + INT_VEC2 = GL20.GL_INT_VEC2; + INT_VEC3 = GL20.GL_INT_VEC3; + INT_VEC4 = GL20.GL_INT_VEC4; + BOOL_VEC2 = GL20.GL_BOOL_VEC2; + BOOL_VEC3 = GL20.GL_BOOL_VEC3; + BOOL_VEC4 = GL20.GL_BOOL_VEC4; + SAMPLER_2D = GL20.GL_SAMPLER_2D; + SAMPLER_CUBE = GL20.GL_SAMPLER_CUBE; - public static final int LOW_FLOAT = ARBES2Compatibility.GL_LOW_FLOAT; - public static final int MEDIUM_FLOAT = ARBES2Compatibility.GL_MEDIUM_FLOAT; - public static final int HIGH_FLOAT = ARBES2Compatibility.GL_HIGH_FLOAT; - public static final int LOW_INT = ARBES2Compatibility.GL_LOW_INT; - public static final int MEDIUM_INT = ARBES2Compatibility.GL_MEDIUM_INT; - public static final int HIGH_INT = ARBES2Compatibility.GL_HIGH_INT; + LOW_FLOAT = ARBES2Compatibility.GL_LOW_FLOAT; + MEDIUM_FLOAT = ARBES2Compatibility.GL_MEDIUM_FLOAT; + HIGH_FLOAT = ARBES2Compatibility.GL_HIGH_FLOAT; + LOW_INT = ARBES2Compatibility.GL_LOW_INT; + MEDIUM_INT = ARBES2Compatibility.GL_MEDIUM_INT; + HIGH_INT = ARBES2Compatibility.GL_HIGH_INT; - public static final int CURRENT_VERTEX_ATTRIB = GL20.GL_CURRENT_VERTEX_ATTRIB; + CURRENT_VERTEX_ATTRIB = GL20.GL_CURRENT_VERTEX_ATTRIB; - public static final int VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = GL15.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING; - public static final int VERTEX_ATTRIB_ARRAY_ENABLED = GL20.GL_VERTEX_ATTRIB_ARRAY_ENABLED; - public static final int VERTEX_ATTRIB_ARRAY_SIZE = GL20.GL_VERTEX_ATTRIB_ARRAY_SIZE; - public static final int VERTEX_ATTRIB_ARRAY_STRIDE = GL20.GL_VERTEX_ATTRIB_ARRAY_STRIDE; - public static final int VERTEX_ATTRIB_ARRAY_TYPE = GL20.GL_VERTEX_ATTRIB_ARRAY_TYPE; - public static final int VERTEX_ATTRIB_ARRAY_NORMALIZED = GL20.GL_VERTEX_ATTRIB_ARRAY_NORMALIZED; - public static final int VERTEX_ATTRIB_ARRAY_POINTER = GL20.GL_VERTEX_ATTRIB_ARRAY_POINTER; + VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = GL15.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING; + VERTEX_ATTRIB_ARRAY_ENABLED = GL20.GL_VERTEX_ATTRIB_ARRAY_ENABLED; + VERTEX_ATTRIB_ARRAY_SIZE = GL20.GL_VERTEX_ATTRIB_ARRAY_SIZE; + VERTEX_ATTRIB_ARRAY_STRIDE = GL20.GL_VERTEX_ATTRIB_ARRAY_STRIDE; + VERTEX_ATTRIB_ARRAY_TYPE = GL20.GL_VERTEX_ATTRIB_ARRAY_TYPE; + VERTEX_ATTRIB_ARRAY_NORMALIZED = GL20.GL_VERTEX_ATTRIB_ARRAY_NORMALIZED; + VERTEX_ATTRIB_ARRAY_POINTER = GL20.GL_VERTEX_ATTRIB_ARRAY_POINTER; - public static final int BLEND = GL11.GL_BLEND; - public static final int ONE = GL11.GL_ONE; - public static final int ZERO = GL11.GL_ZERO; - public static final int SRC_ALPHA = GL11.GL_SRC_ALPHA; - public static final int DST_ALPHA = GL11.GL_DST_ALPHA; - public static final int ONE_MINUS_SRC_ALPHA = GL11.GL_ONE_MINUS_SRC_ALPHA; - public static final int ONE_MINUS_DST_COLOR = GL11.GL_ONE_MINUS_DST_COLOR; - public static final int ONE_MINUS_SRC_COLOR = GL11.GL_ONE_MINUS_SRC_COLOR; - public static final int DST_COLOR = GL11.GL_DST_COLOR; - public static final int SRC_COLOR = GL11.GL_SRC_COLOR; + BLEND = GL11.GL_BLEND; + ONE = GL11.GL_ONE; + ZERO = GL11.GL_ZERO; + SRC_ALPHA = GL11.GL_SRC_ALPHA; + DST_ALPHA = GL11.GL_DST_ALPHA; + ONE_MINUS_SRC_ALPHA = GL11.GL_ONE_MINUS_SRC_ALPHA; + ONE_MINUS_DST_COLOR = GL11.GL_ONE_MINUS_DST_COLOR; + ONE_MINUS_SRC_COLOR = GL11.GL_ONE_MINUS_SRC_COLOR; + DST_COLOR = GL11.GL_DST_COLOR; + SRC_COLOR = GL11.GL_SRC_COLOR; - public static final int SAMPLE_ALPHA_TO_COVERAGE = GL13.GL_SAMPLE_ALPHA_TO_COVERAGE; - public static final int SAMPLE_COVERAGE = GL13.GL_SAMPLE_COVERAGE; + SAMPLE_ALPHA_TO_COVERAGE = GL13.GL_SAMPLE_ALPHA_TO_COVERAGE; + SAMPLE_COVERAGE = GL13.GL_SAMPLE_COVERAGE; - public static final int KEEP = GL11.GL_KEEP; - public static final int REPLACE = GL11.GL_REPLACE; - public static final int INCR = GL11.GL_INCR; - public static final int DECR = GL11.GL_DECR; - public static final int INVERT = GL11.GL_INVERT; - public static final int INCR_WRAP = GL14.GL_INCR_WRAP; - public static final int DECR_WRAP = GL14.GL_DECR_WRAP; - public static final int NEVER = GL11.GL_NEVER; - public static final int ALWAYS = GL11.GL_ALWAYS; + KEEP = GL11.GL_KEEP; + REPLACE = GL11.GL_REPLACE; + INCR = GL11.GL_INCR; + DECR = GL11.GL_DECR; + INVERT = GL11.GL_INVERT; + INCR_WRAP = GL14.GL_INCR_WRAP; + DECR_WRAP = GL14.GL_DECR_WRAP; + NEVER = GL11.GL_NEVER; + ALWAYS = GL11.GL_ALWAYS; - public static final int EQUAL = GL11.GL_EQUAL; - public static final int LESS = GL11.GL_LESS; - public static final int LEQUAL = GL11.GL_LEQUAL; - public static final int GREATER = GL11.GL_GREATER; - public static final int GEQUAL = GL11.GL_GEQUAL; - public static final int NOTEQUAL = GL11.GL_NOTEQUAL; + EQUAL = GL11.GL_EQUAL; + LESS = GL11.GL_LESS; + LEQUAL = GL11.GL_LEQUAL; + GREATER = GL11.GL_GREATER; + GEQUAL = GL11.GL_GEQUAL; + NOTEQUAL = GL11.GL_NOTEQUAL; - public static final int FUNC_ADD = GL14.GL_FUNC_ADD; - public static final int FUNC_MIN = GL14.GL_MIN; - public static final int FUNC_MAX = GL14.GL_MAX; - public static final int FUNC_REVERSE_SUBTRACT = GL14.GL_FUNC_REVERSE_SUBTRACT; - public static final int FUNC_SUBTRACT = GL14.GL_FUNC_SUBTRACT; + FUNC_ADD = GL14.GL_FUNC_ADD; + FUNC_MIN = GL14.GL_MIN; + FUNC_MAX = GL14.GL_MAX; + FUNC_REVERSE_SUBTRACT = GL14.GL_FUNC_REVERSE_SUBTRACT; + FUNC_SUBTRACT = GL14.GL_FUNC_SUBTRACT; - public static final int DITHER = GL11.GL_DITHER; + DITHER = GL11.GL_DITHER; - public static final int CONSTANT_COLOR = GL11.GL_CONSTANT_COLOR; - public static final int CONSTANT_ALPHA = GL11.GL_CONSTANT_ALPHA; - public static final int ONE_MINUS_CONSTANT_COLOR = GL11.GL_ONE_MINUS_CONSTANT_COLOR; - public static final int ONE_MINUS_CONSTANT_ALPHA = GL11.GL_ONE_MINUS_CONSTANT_ALPHA; - public static final int SRC_ALPHA_SATURATE = GL11.GL_SRC_ALPHA_SATURATE; + CONSTANT_COLOR = GL11.GL_CONSTANT_COLOR; + CONSTANT_ALPHA = GL11.GL_CONSTANT_ALPHA; + ONE_MINUS_CONSTANT_COLOR = GL11.GL_ONE_MINUS_CONSTANT_COLOR; + ONE_MINUS_CONSTANT_ALPHA = GL11.GL_ONE_MINUS_CONSTANT_ALPHA; + SRC_ALPHA_SATURATE = GL11.GL_SRC_ALPHA_SATURATE; - public static final int SCISSOR_TEST = GL11.GL_SCISSOR_TEST; - public static final int DEPTH_TEST = GL11.GL_DEPTH_TEST; - public static final int DEPTH_WRITEMASK = GL11.GL_DEPTH_WRITEMASK; - public static final int ALPHA_TEST = GL11.GL_ALPHA_TEST; + SCISSOR_TEST = GL11.GL_SCISSOR_TEST; + DEPTH_TEST = GL11.GL_DEPTH_TEST; + DEPTH_WRITEMASK = GL11.GL_DEPTH_WRITEMASK; + ALPHA_TEST = GL11.GL_ALPHA_TEST; - public static final int COLOR_BUFFER_BIT = GL11.GL_COLOR_BUFFER_BIT; - public static final int DEPTH_BUFFER_BIT = GL11.GL_DEPTH_BUFFER_BIT; - public static final int STENCIL_BUFFER_BIT = GL11.GL_STENCIL_BUFFER_BIT; + COLOR_BUFFER_BIT = GL11.GL_COLOR_BUFFER_BIT; + DEPTH_BUFFER_BIT = GL11.GL_DEPTH_BUFFER_BIT; + STENCIL_BUFFER_BIT = GL11.GL_STENCIL_BUFFER_BIT; - public static final int FRAMEBUFFER = GL30.GL_FRAMEBUFFER; - public static final int COLOR_ATTACHMENT0 = GL30.GL_COLOR_ATTACHMENT0; - public static final int COLOR_ATTACHMENT1 = GL30.GL_COLOR_ATTACHMENT1; - public static final int COLOR_ATTACHMENT2 = GL30.GL_COLOR_ATTACHMENT2; - public static final int COLOR_ATTACHMENT3 = GL30.GL_COLOR_ATTACHMENT3; - public static final int RENDERBUFFER = GL30.GL_RENDERBUFFER; - public static final int DEPTH_ATTACHMENT = GL30.GL_DEPTH_ATTACHMENT; - public static final int STENCIL_ATTACHMENT = GL30.GL_STENCIL_ATTACHMENT; - public static final int READ_FRAMEBUFFER = GL30.GL_READ_FRAMEBUFFER; - public static final int DRAW_FRAMEBUFFER = GL30.GL_DRAW_FRAMEBUFFER; + FRAMEBUFFER = GL30.GL_FRAMEBUFFER; + COLOR_ATTACHMENT0 = GL30.GL_COLOR_ATTACHMENT0; + COLOR_ATTACHMENT1 = GL30.GL_COLOR_ATTACHMENT1; + COLOR_ATTACHMENT2 = GL30.GL_COLOR_ATTACHMENT2; + COLOR_ATTACHMENT3 = GL30.GL_COLOR_ATTACHMENT3; + RENDERBUFFER = GL30.GL_RENDERBUFFER; + DEPTH_ATTACHMENT = GL30.GL_DEPTH_ATTACHMENT; + STENCIL_ATTACHMENT = GL30.GL_STENCIL_ATTACHMENT; + READ_FRAMEBUFFER = GL30.GL_READ_FRAMEBUFFER; + DRAW_FRAMEBUFFER = GL30.GL_DRAW_FRAMEBUFFER; - public static final int RGBA8 = GL11.GL_RGBA8; - public static final int DEPTH24_STENCIL8 = GL30.GL_DEPTH24_STENCIL8; + RGBA8 = GL11.GL_RGBA8; + DEPTH24_STENCIL8 = GL30.GL_DEPTH24_STENCIL8; - public static final int DEPTH_COMPONENT = GL11.GL_DEPTH_COMPONENT; - public static final int DEPTH_COMPONENT16 = GL14.GL_DEPTH_COMPONENT16; - public static final int DEPTH_COMPONENT24 = GL14.GL_DEPTH_COMPONENT24; - public static final int DEPTH_COMPONENT32 = GL14.GL_DEPTH_COMPONENT32; + DEPTH_COMPONENT = GL11.GL_DEPTH_COMPONENT; + DEPTH_COMPONENT16 = GL14.GL_DEPTH_COMPONENT16; + DEPTH_COMPONENT24 = GL14.GL_DEPTH_COMPONENT24; + DEPTH_COMPONENT32 = GL14.GL_DEPTH_COMPONENT32; - public static final int STENCIL_INDEX = GL11.GL_STENCIL_INDEX; - public static final int STENCIL_INDEX1 = GL30.GL_STENCIL_INDEX1; - public static final int STENCIL_INDEX4 = GL30.GL_STENCIL_INDEX4; - public static final int STENCIL_INDEX8 = GL30.GL_STENCIL_INDEX8; + STENCIL_INDEX = GL11.GL_STENCIL_INDEX; + STENCIL_INDEX1 = GL30.GL_STENCIL_INDEX1; + STENCIL_INDEX4 = GL30.GL_STENCIL_INDEX4; + STENCIL_INDEX8 = GL30.GL_STENCIL_INDEX8; - public static final int DEPTH_STENCIL = GL30.GL_DEPTH_STENCIL; + DEPTH_STENCIL = GL30.GL_DEPTH_STENCIL; - public static final int FRAMEBUFFER_COMPLETE = GL30.GL_FRAMEBUFFER_COMPLETE; - public static final int FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL30.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - public static final int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL30.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; - public static final int FRAMEBUFFER_INCOMPLETE_DIMENSIONS = EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; - public static final int FRAMEBUFFER_INCOMPLETE_FORMATS = EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; - public static final int FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = GL30.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER; - public static final int FRAMEBUFFER_INCOMPLETE_READ_BUFFER = GL30.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER; - public static final int FRAMEBUFFER_UNSUPPORTED = GL30.GL_FRAMEBUFFER_UNSUPPORTED; + FRAMEBUFFER_COMPLETE = GL30.GL_FRAMEBUFFER_COMPLETE; + FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL30.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL30.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + FRAMEBUFFER_INCOMPLETE_DIMENSIONS = EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; + FRAMEBUFFER_INCOMPLETE_FORMATS = EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; + FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = GL30.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER; + FRAMEBUFFER_INCOMPLETE_READ_BUFFER = GL30.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER; + FRAMEBUFFER_UNSUPPORTED = GL30.GL_FRAMEBUFFER_UNSUPPORTED; - public static final int FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE; - public static final int FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME; - public static final int FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = GL30.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL; - public static final int FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = GL30.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE; + FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE; + FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME; + FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = GL30.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL; + FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = GL30.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE; - public static final int RENDERBUFFER_WIDTH = GL30.GL_RENDERBUFFER_WIDTH; - public static final int RENDERBUFFER_HEIGHT = GL30.GL_RENDERBUFFER_HEIGHT; - public static final int RENDERBUFFER_RED_SIZE = GL30.GL_RENDERBUFFER_RED_SIZE; - public static final int RENDERBUFFER_GREEN_SIZE = GL30.GL_RENDERBUFFER_GREEN_SIZE; - public static final int RENDERBUFFER_BLUE_SIZE = GL30.GL_RENDERBUFFER_BLUE_SIZE; - public static final int RENDERBUFFER_ALPHA_SIZE = GL30.GL_RENDERBUFFER_ALPHA_SIZE; - public static final int RENDERBUFFER_DEPTH_SIZE = GL30.GL_RENDERBUFFER_DEPTH_SIZE; - public static final int RENDERBUFFER_STENCIL_SIZE = GL30.GL_RENDERBUFFER_STENCIL_SIZE; - public static final int RENDERBUFFER_INTERNAL_FORMAT = GL30.GL_RENDERBUFFER_INTERNAL_FORMAT; + RENDERBUFFER_WIDTH = GL30.GL_RENDERBUFFER_WIDTH; + RENDERBUFFER_HEIGHT = GL30.GL_RENDERBUFFER_HEIGHT; + RENDERBUFFER_RED_SIZE = GL30.GL_RENDERBUFFER_RED_SIZE; + RENDERBUFFER_GREEN_SIZE = GL30.GL_RENDERBUFFER_GREEN_SIZE; + RENDERBUFFER_BLUE_SIZE = GL30.GL_RENDERBUFFER_BLUE_SIZE; + RENDERBUFFER_ALPHA_SIZE = GL30.GL_RENDERBUFFER_ALPHA_SIZE; + RENDERBUFFER_DEPTH_SIZE = GL30.GL_RENDERBUFFER_DEPTH_SIZE; + RENDERBUFFER_STENCIL_SIZE = GL30.GL_RENDERBUFFER_STENCIL_SIZE; + RENDERBUFFER_INTERNAL_FORMAT = GL30.GL_RENDERBUFFER_INTERNAL_FORMAT; - public static final int MULTISAMPLE = GL13.GL_MULTISAMPLE; - public static final int POINT_SMOOTH = GL11.GL_POINT_SMOOTH; - public static final int LINE_SMOOTH = GL11.GL_LINE_SMOOTH; - public static final int POLYGON_SMOOTH = GL11.GL_POLYGON_SMOOTH; - - + MULTISAMPLE = GL13.GL_MULTISAMPLE; + POINT_SMOOTH = GL11.GL_POINT_SMOOTH; + LINE_SMOOTH = GL11.GL_LINE_SMOOTH; + POLYGON_SMOOTH = GL11.GL_POLYGON_SMOOTH; + } /////////////////////////////////////////////////////////// @@ -3000,14 +2991,6 @@ public class PLWJGL extends PGL { // Reading Pixels - public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer) { - boolean needEndBegin = format != STENCIL_INDEX && - format != DEPTH_COMPONENT && format != DEPTH_STENCIL; - if (needEndBegin) pg.beginReadPixels(); - readPixelsImpl(x, y, width, height, format, type, buffer); - if (needEndBegin) pg.endReadPixels(); - } - protected void readPixelsImpl(int x, int y, int width, int height, int format, int type, Buffer buffer) { GL11.glReadPixels(x, y, width, height, format, type, (IntBuffer)buffer); } @@ -3122,11 +3105,6 @@ public class PLWJGL extends PGL { // Texturing - public void activeTexture(int texture) { - GL13.glActiveTexture(texture); - activeTexUnit = texture - TEXTURE0; - } - public void texImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, Buffer data) { GL11.glTexImage2D(target, level, internalFormat, width, height, border, format, type, (IntBuffer)data); } @@ -3171,25 +3149,6 @@ public class PLWJGL extends PGL { GL30.glGenerateMipmap(target); } - public void bindTexture(int target, int texture) { - GL11.glBindTexture(target, texture); - - if (boundTextures == null) { - maxTexUnits = getMaxTexUnits(); - boundTextures = new int[maxTexUnits][2]; - } - - if (maxTexUnits <= activeTexUnit) { - throw new RuntimeException(TEXUNIT_ERROR); - } - - if (target == TEXTURE_2D) { - boundTextures[activeTexUnit][0] = texture; - } else if (target == TEXTURE_RECTANGLE) { - boundTextures[activeTexUnit][1] = texture; - } - } - public void genTextures(int n, IntBuffer textures) { GL11.glGenTextures(textures); } @@ -3210,6 +3169,14 @@ public class PLWJGL extends PGL { return GL11.glIsTexture(texture); } + protected void activeTextureImpl(int texture) { + GL13.glActiveTexture(texture); + } + + protected void bindTextureImpl(int target, int texture) { + GL11.glBindTexture(target, texture); + } + /////////////////////////////////////////////////////////// // Shaders and Programs From 7eb0f19d6512b20908e00af4949e6d352d7ff245 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Thu, 12 Sep 2013 19:21:57 -0400 Subject: [PATCH 036/556] change build scripts to use built-in ecj (removes jdk req) --- app/build.xml | 5 ++++- build/build.xml | 6 +++++- build/shared/tools/MovieMaker/build.xml | 6 +++++- core/build.xml | 6 +++++- core/methods/build.xml | 6 +++++- experimental/build.xml | 5 ++++- java/libraries/dxf/build.xml | 6 +++++- java/libraries/lwjgl/build.xml | 6 +++++- java/libraries/net/build.xml | 6 +++++- java/libraries/pdf/build.xml | 6 +++++- java/libraries/serial/build.xml | 6 +++++- java/libraries/video/build.xml | 6 +++++- 12 files changed, 58 insertions(+), 12 deletions(-) mode change 100644 => 100755 app/build.xml mode change 100644 => 100755 build/shared/tools/MovieMaker/build.xml mode change 100644 => 100755 core/build.xml mode change 100644 => 100755 core/methods/build.xml mode change 100644 => 100755 experimental/build.xml mode change 100644 => 100755 java/libraries/dxf/build.xml mode change 100644 => 100755 java/libraries/lwjgl/build.xml mode change 100644 => 100755 java/libraries/net/build.xml mode change 100644 => 100755 java/libraries/pdf/build.xml mode change 100644 => 100755 java/libraries/serial/build.xml mode change 100644 => 100755 java/libraries/video/build.xml diff --git a/app/build.xml b/app/build.xml old mode 100644 new mode 100755 index c8d8ef937..ad89dbf8c --- a/app/build.xml +++ b/app/build.xml @@ -92,9 +92,12 @@ encoding="UTF-8" includeAntRuntime="false" classpath="../core/library/core.jar; lib/ant.jar; lib/ant-launcher.jar; lib/antlr.jar; lib/apple.jar; lib/jdt-core.jar; lib/jna.jar; lib/org-netbeans-swing-outline.jar;lib/com.ibm.icu_4.4.2.v20110823.jar;lib/jdi.jar;lib/jdimodel.jar;lib/org.eclipse.osgi_3.8.1.v20120830-144521.jar" - debug="on"> + debug="on" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> + diff --git a/build/build.xml b/build/build.xml index 0c09692db..9d055a8fb 100755 --- a/build/build.xml +++ b/build/build.xml @@ -1,6 +1,6 @@ - + @@ -36,15 +36,18 @@ + + + classpath="../../../../app/bin" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> + + diff --git a/core/build.xml b/core/build.xml old mode 100644 new mode 100755 index 00d1cbbd6..833acaa4e --- a/core/build.xml +++ b/core/build.xml @@ -19,7 +19,11 @@ includeAntRuntime="false" debug="true" srcdir="src" destdir="bin" - classpath="library/jogl-all.jar; library/gluegen-rt.jar" /> + classpath="library/jogl-all.jar; library/gluegen-rt.jar" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> + + + includeantruntime="true" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> + + diff --git a/experimental/build.xml b/experimental/build.xml old mode 100644 new mode 100755 index 2e0f18baa..283510aed --- a/experimental/build.xml +++ b/experimental/build.xml @@ -48,7 +48,10 @@ encoding="UTF-8" includeAntRuntime="false" classpath="../core/library/core.jar; ${env.JAVA_HOME}/lib/tools.jar; ../app/lib/ant.jar; ../app/lib/ant-launcher.jar; ../app/lib/antlr.jar; ../app/lib/apple.jar; ../app/lib/jdt-core.jar; ../app/lib/jna.jar; ../app/lib/org-netbeans-swing-outline.jar; ../app/pde.jar; mode/CompilationChecker.jar; mode/com.ibm.icu_4.4.2.v20110823.jar; mode/jdi.jar; mode/jdimodel.jar; mode/org.eclipse.core.contenttype_3.4.200.v20120523-2004.jar; mode/org.eclipse.core.jobs_3.5.300.v20120622-204750.jar; mode/org.eclipse.core.resources_3.8.1.v20120802-154922.jar; mode/org.eclipse.core.runtime_3.8.0.v20120521-2346.jar; mode/org.eclipse.equinox.common_3.6.100.v20120522-1841.jar; mode/org.eclipse.equinox.preferences_3.5.0.v20120522-1841.jar; mode/org.eclipse.jdt.core_3.8.2.v20120814-155456.jar; mode/org.eclipse.jdt.debug_3.7.101.v20120725-115645.jar; mode/org.eclipse.osgi_3.8.1.v20120830-144521.jar; mode/org.eclipse.text_3.5.200.v20120523-1310.jar" - debug="on"> + debug="on" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> + diff --git a/java/libraries/dxf/build.xml b/java/libraries/dxf/build.xml old mode 100644 new mode 100755 index f059571e3..5f4719dac --- a/java/libraries/dxf/build.xml +++ b/java/libraries/dxf/build.xml @@ -18,7 +18,11 @@ srcdir="src" destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../../../core/library/core.jar" /> + classpath="../../../core/library/core.jar" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> + + diff --git a/java/libraries/lwjgl/build.xml b/java/libraries/lwjgl/build.xml old mode 100644 new mode 100755 index f9e186a30..280c0ca07 --- a/java/libraries/lwjgl/build.xml +++ b/java/libraries/lwjgl/build.xml @@ -18,7 +18,11 @@ srcdir="src" destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../../../core/library/core.jar; library/lwjgl.jar; library/lwjgl_util.jar" /> + classpath="../../../core/library/core.jar; library/lwjgl.jar; library/lwjgl_util.jar" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> + + diff --git a/java/libraries/net/build.xml b/java/libraries/net/build.xml old mode 100644 new mode 100755 index 1766599ed..61adc6a05 --- a/java/libraries/net/build.xml +++ b/java/libraries/net/build.xml @@ -18,7 +18,11 @@ srcdir="src" destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../../../core/library/core.jar" /> + classpath="../../../core/library/core.jar" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> + + diff --git a/java/libraries/pdf/build.xml b/java/libraries/pdf/build.xml old mode 100644 new mode 100755 index 322002993..c122c2876 --- a/java/libraries/pdf/build.xml +++ b/java/libraries/pdf/build.xml @@ -18,7 +18,11 @@ srcdir="src" destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../../../core/library/core.jar; library/itext.jar" /> + classpath="../../../core/library/core.jar; library/itext.jar" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> + + diff --git a/java/libraries/serial/build.xml b/java/libraries/serial/build.xml old mode 100644 new mode 100755 index 887db84a0..d04e8a66a --- a/java/libraries/serial/build.xml +++ b/java/libraries/serial/build.xml @@ -18,7 +18,11 @@ srcdir="src" destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../../../core/library/core.jar; library/RXTXcomm.jar" /> + classpath="../../../core/library/core.jar; library/RXTXcomm.jar" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> + + diff --git a/java/libraries/video/build.xml b/java/libraries/video/build.xml old mode 100644 new mode 100755 index 1bf2e5899..202242085 --- a/java/libraries/video/build.xml +++ b/java/libraries/video/build.xml @@ -18,7 +18,11 @@ srcdir="src" destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../../../core/library/core.jar; library/gstreamer-java.jar; library/jna.jar" /> + classpath="../../../core/library/core.jar; library/gstreamer-java.jar; library/jna.jar" + nowarn="true" + compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> + + From da0b526f683951ba4023dafdebec097a6753639d Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Fri, 13 Sep 2013 02:19:56 -0400 Subject: [PATCH 037/556] making swap public --- core/src/processing/data/FloatDict.java | 2 +- core/src/processing/data/IntDict.java | 2 +- core/src/processing/data/StringDict.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/processing/data/FloatDict.java b/core/src/processing/data/FloatDict.java index 91b2b7538..794ca2713 100644 --- a/core/src/processing/data/FloatDict.java +++ b/core/src/processing/data/FloatDict.java @@ -518,7 +518,7 @@ public class FloatDict { } - protected void swap(int a, int b) { + public void swap(int a, int b) { String tkey = keys[a]; float tvalue = values[a]; keys[a] = keys[b]; diff --git a/core/src/processing/data/IntDict.java b/core/src/processing/data/IntDict.java index 4d1aff090..44efea215 100644 --- a/core/src/processing/data/IntDict.java +++ b/core/src/processing/data/IntDict.java @@ -527,7 +527,7 @@ public class IntDict { } - protected void swap(int a, int b) { + public void swap(int a, int b) { String tkey = keys[a]; int tvalue = values[a]; keys[a] = keys[b]; diff --git a/core/src/processing/data/StringDict.java b/core/src/processing/data/StringDict.java index 5fb533616..ed284b10b 100644 --- a/core/src/processing/data/StringDict.java +++ b/core/src/processing/data/StringDict.java @@ -316,7 +316,7 @@ public class StringDict { } - protected void swap(int a, int b) { + public void swap(int a, int b) { String tkey = keys[a]; String tvalue = values[a]; keys[a] = keys[b]; From b4827a92ce3cedcf4150f5163367c1f72922ded2 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Fri, 13 Sep 2013 02:20:26 -0400 Subject: [PATCH 038/556] adding tweak to avoid crash when tools or modes folders are inaccessible --- .../app/contrib/ModeContribution.java | 20 +++++++++++-------- .../app/contrib/ToolContribution.java | 18 ++++++++++------- todo.txt | 3 +++ 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/app/src/processing/app/contrib/ModeContribution.java b/app/src/processing/app/contrib/ModeContribution.java index 4a927c895..18a1b2a4a 100644 --- a/app/src/processing/app/contrib/ModeContribution.java +++ b/app/src/processing/app/contrib/ModeContribution.java @@ -95,14 +95,18 @@ public class ModeContribution extends LocalContribution { existing.put(contrib.getFolder(), contrib); } File[] potential = ContributionType.MODE.listCandidates(modesFolder); - for (File folder : potential) { - if (!existing.containsKey(folder)) { - try { - contribModes.add(new ModeContribution(base, folder, null)); - } catch (IgnorableException ig) { - Base.log(ig.getMessage()); - } catch (Exception e) { - e.printStackTrace(); + // If modesFolder does not exist or is inaccessible (folks might like to + // mess with folders then report it as a bug) 'potential' will be null. + if (potential != null) { + for (File folder : potential) { + if (!existing.containsKey(folder)) { + try { + contribModes.add(new ModeContribution(base, folder, null)); + } catch (IgnorableException ig) { + Base.log(ig.getMessage()); + } catch (Exception e) { + e.printStackTrace(); + } } } } diff --git a/app/src/processing/app/contrib/ToolContribution.java b/app/src/processing/app/contrib/ToolContribution.java index 978e95f49..aec572f7c 100644 --- a/app/src/processing/app/contrib/ToolContribution.java +++ b/app/src/processing/app/contrib/ToolContribution.java @@ -74,14 +74,18 @@ public class ToolContribution extends LocalContribution implements Tool { static public ArrayList loadAll(File toolsFolder) { File[] list = ContributionType.TOOL.listCandidates(toolsFolder); ArrayList outgoing = new ArrayList(); - for (File folder : list) { - try { - ToolContribution tc = load(folder); - if (tc != null) { - outgoing.add(tc); + // If toolsFolder does not exist or is inaccessible (stranger things have + // happened, and are reported as bugs) list will come back null. + if (list != null) { + for (File folder : list) { + try { + ToolContribution tc = load(folder); + if (tc != null) { + outgoing.add(tc); + } + } catch (Exception e) { + e.printStackTrace(); } - } catch (Exception e) { - e.printStackTrace(); } } return outgoing; diff --git a/todo.txt b/todo.txt index 0d3b6add6..e54351ac4 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,7 @@ 0222 pde X MovieMaker needs to be compiling as 1.6 +X deal with null/missing folders for Tools and Modes +X https://github.com/processing/processing/issues/2068 high @@ -791,6 +793,7 @@ _ https://github.com/processing/processing/issues/1840 _ need to have ecj.jar accessible to ant, then modify build.xml to use this: _ +_ http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Ftasks%2Ftask-ant_javac_adapter.htm _ line ending issues _ doesn't really help on Windows since we use Cygwin _ but it would be helpful for people not using it (ant/other LF issues) From 51947ae116d24149d9842c88c27c8dedb830c426 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 13 Sep 2013 15:02:36 -0400 Subject: [PATCH 039/556] done with the PGL refactoring --- core/src/processing/opengl/PGL.java | 486 ++-- .../processing/opengl/PGraphicsOpenGL.java | 4 +- core/src/processing/opengl/PJOGL.java | 1010 ++++---- .../src/processing/lwjgl/PGraphics2D.java | 10 + .../src/processing/lwjgl/PGraphics3D.java | 10 + .../src/processing/lwjgl/PGraphicsLWJGL.java | 3 +- .../lwjgl/src/processing/lwjgl/PLWJGL.java | 2138 ++--------------- 7 files changed, 1025 insertions(+), 2636 deletions(-) create mode 100644 java/libraries/lwjgl/src/processing/lwjgl/PGraphics2D.java create mode 100644 java/libraries/lwjgl/src/processing/lwjgl/PGraphics3D.java diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index bdf3f3bb8..cc8962534 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -32,27 +32,36 @@ import java.nio.IntBuffer; import java.nio.ShortBuffer; import java.util.Arrays; - /** - * Processing-OpenGL abstraction layer. + * Processing-OpenGL abstraction layer. Needs to be implemented by subclasses + * using specific OpenGL-Java bindings. + * + * It includes a full GLES 2.0 interface. * - * Warnings are suppressed for static access because presumably on Android, - * the GL2 vs GL distinctions are necessary, whereas on desktop they are not. */ public abstract class PGL { + // ........................................................ - - + // Basic fields /** The PGraphics object using this interface */ protected PGraphicsOpenGL pg; - protected static int contextID; + /** OpenGL thread */ + protected static Thread glThread; - /////////////////////////////////////////////////////////// + /** ID of the GL context associated to the surface **/ + protected static int glContext; + + // ........................................................ // Parameters + protected static boolean USE_FBOLAYER_BY_DEFAULT = false; + protected static int REQUESTED_DEPTH_BITS = 24; + protected static int REQUESTED_STENCIL_BITS = 8; + protected static int REQUESTED_ALPHA_BITS = 8; + /** Switches between the use of regular and direct buffers. */ protected static boolean USE_DIRECT_BUFFERS = true; protected static int MIN_DIRECT_BUFFER_SIZE = 1; @@ -114,50 +123,31 @@ public abstract class PGL { * order to make sure the lines are always on top of the fill geometry */ protected static float STROKE_DISPLACEMENT = 0.999f; + // ........................................................ + // FBO layer + protected static boolean fboLayerRequested = false; + protected static boolean fboLayerCreated = false; + protected static boolean fboLayerInUse = false; + protected static boolean firstFrame = true; + protected static int reqNumSamples; + protected static int numSamples; + protected static IntBuffer glColorFbo; + protected static IntBuffer glMultiFbo; + protected static IntBuffer glColorBuf; + protected static IntBuffer glColorTex; + protected static IntBuffer glDepthStencil; + protected static IntBuffer glDepth; + protected static IntBuffer glStencil; + protected static int fboWidth, fboHeight; + protected static int backTex, frontTex; - /** Size of different types in bytes */ - protected static int SIZEOF_SHORT = Short.SIZE / 8; - protected static int SIZEOF_INT = Integer.SIZE / 8; - protected static int SIZEOF_FLOAT = Float.SIZE / 8; - protected static int SIZEOF_BYTE = Byte.SIZE / 8; - protected static int SIZEOF_INDEX = SIZEOF_SHORT; - protected static int INDEX_TYPE = 0x1403; // GL_UNSIGNED_SHORT + /** Flags used to handle the creation of a separate front texture */ + protected boolean usingFrontTex = false; + protected boolean needSepFrontTex = false; - /** Machine Epsilon for float precision. */ - protected static float FLOAT_EPS = Float.MIN_VALUE; - // Calculation of the Machine Epsilon for float precision. From: - // http://en.wikipedia.org/wiki/Machine_epsilon#Approximation_using_Java - static { - float eps = 1.0f; - - do { - eps /= 2.0f; - } while ((float)(1.0 + (eps / 2.0)) != 1.0); - - FLOAT_EPS = eps; - } - - - - /** - * Set to true if the host system is big endian (PowerPC, MIPS, SPARC), false - * if little endian (x86 Intel for Mac or PC). - */ - protected static boolean BIG_ENDIAN = - ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; - - protected static final String SHADER_PREPROCESSOR_DIRECTIVE = - "#ifdef GL_ES\n" + - "precision mediump float;\n" + - "precision mediump int;\n" + - "#endif\n"; - - - - - /////////////////////////////////////////////////////////// + // ........................................................ // Texture rendering @@ -186,6 +176,12 @@ public abstract class PGL { }; protected static FloatBuffer texData; + protected static final String SHADER_PREPROCESSOR_DIRECTIVE = + "#ifdef GL_ES\n" + + "precision mediump float;\n" + + "precision mediump int;\n" + + "#endif\n"; + protected static String texVertShaderSource = "attribute vec2 inVertex;" + "attribute vec2 inTexcoord;" + @@ -211,9 +207,25 @@ public abstract class PGL { " gl_FragColor = texture2DRect(textureSampler, vertTexcoord.st);" + "}"; - /////////////////////////////////////////////////////////// + /** Which texturing targets are enabled */ + protected static boolean[] texturingTargets = { false, false }; - // Utilities + /** Used to keep track of which textures are bound to each target */ + protected static int maxTexUnits; + protected static int activeTexUnit = 0; + protected static int[][] boundTextures; + + // ........................................................ + + // Framerate handling + + protected float targetFps = 60; + protected float currentFps = 60; + protected boolean setFps = false; + + // ........................................................ + + // Utility buffers protected ByteBuffer byteBuffer; protected IntBuffer intBuffer; @@ -223,7 +235,7 @@ public abstract class PGL { protected FloatBuffer depthBuffer; protected ByteBuffer stencilBuffer; - /////////////////////////////////////////////////////////// + // ........................................................ // Error messages @@ -245,69 +257,48 @@ public abstract class PGL { protected static final String TEXUNIT_ERROR = "Number of texture units not supported by this hardware (or driver)" + WIKI; + // ........................................................ + // Constants + /** Size of different types in bytes */ + protected static int SIZEOF_SHORT = Short.SIZE / 8; + protected static int SIZEOF_INT = Integer.SIZE / 8; + protected static int SIZEOF_FLOAT = Float.SIZE / 8; + protected static int SIZEOF_BYTE = Byte.SIZE / 8; + protected static int SIZEOF_INDEX = SIZEOF_SHORT; + protected static int INDEX_TYPE = 0x1403; // GL_UNSIGNED_SHORT + /** Machine Epsilon for float precision. */ + protected static float FLOAT_EPS = Float.MIN_VALUE; + // Calculation of the Machine Epsilon for float precision. From: + // http://en.wikipedia.org/wiki/Machine_epsilon#Approximation_using_Java + static { + float eps = 1.0f; - protected static boolean USE_FBOLAYER_BY_DEFAULT; + do { + eps /= 2.0f; + } while ((float)(1.0 + (eps / 2.0)) != 1.0); + FLOAT_EPS = eps; + } - - - - - - - - - - /** Which texturing targets are enabled */ - protected static boolean[] texturingTargets = { false, false }; - - /** Used to keep track of which textures are bound to each target */ - protected static int maxTexUnits; - protected static int activeTexUnit = 0; - protected static int[][] boundTextures; - - /////////////////////////////////////////////////////////// - - // FBO layer - - protected static boolean fboLayerRequested = false; - protected static boolean fboLayerCreated = false; - protected static boolean fboLayerInUse = false; - protected static boolean firstFrame = true; - protected static int reqNumSamples; - protected static int numSamples; - protected static IntBuffer glColorFbo; - protected static IntBuffer glMultiFbo; - protected static IntBuffer glColorBuf; - protected static IntBuffer glColorTex; - protected static IntBuffer glDepthStencil; - protected static IntBuffer glDepth; - protected static IntBuffer glStencil; - protected static int fboWidth, fboHeight; - protected static int backTex, frontTex; - - - - /** Flags used to handle the creation of a separate front texture */ - protected boolean usingFrontTex = false; - protected boolean needSepFrontTex = false; - - /** Flag used to do request final display() call to make sure that the - * buffers are properly swapped. + /** + * Set to true if the host system is big endian (PowerPC, MIPS, SPARC), false + * if little endian (x86 Intel for Mac or PC). */ - protected boolean prevCanDraw = false; + protected static boolean BIG_ENDIAN = + ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; - - /////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////// // Initialization, finalization + public PGL() { } + public PGL(PGraphicsOpenGL pg) { this.pg = pg; if (glColorTex == null) { @@ -329,9 +320,12 @@ public abstract class PGL { viewBuffer = allocateIntBuffer(4); } - protected void setFps(float fps) { } - protected void initSurface(int antialias) { } + protected abstract void setFps(float fps); + + + protected abstract void initSurface(int antialias); + protected void deleteSurface() { if (threadIsCurrent() && fboLayerCreated) { @@ -349,29 +343,57 @@ public abstract class PGL { firstFrame = false; } - protected int getReadFramebuffer() { return 0; } - protected int getDrawFramebuffer() { return 0; } - - protected int getDefaultDrawBuffer() { return 0; } - - protected int getDefaultReadBuffer() { return 0; } + protected int getReadFramebuffer() { + return fboLayerInUse ? glColorFbo.get(0) : 0; + } - protected boolean isFBOBacked() { return false; } + protected int getDrawFramebuffer() { + if (fboLayerInUse) return 1 < numSamples ? glMultiFbo.get(0) : + glColorFbo.get(0); + else return 0; + } + + + protected int getDefaultDrawBuffer() { + return fboLayerInUse ? COLOR_ATTACHMENT0 : FRONT; + } + + + protected int getDefaultReadBuffer() { + return fboLayerInUse ? COLOR_ATTACHMENT0 : FRONT; + } + + + protected boolean isFBOBacked() { + return fboLayerInUse; + } protected void requestFBOLayer() { fboLayerRequested = true; } + protected boolean isMultisampled() { return 1 < numSamples; } - protected int getDepthBits() { return 0; } - protected int getStencilBits() { return 0; } + protected int getDepthBits() { + intBuffer.rewind(); + getIntegerv(DEPTH_BITS, intBuffer); + return intBuffer.get(0); + } + + + protected int getStencilBits() { + intBuffer.rewind(); + getIntegerv(STENCIL_BITS, intBuffer); + return intBuffer.get(0); + } + protected boolean getDepthTest() { intBuffer.rewind(); @@ -379,21 +401,82 @@ public abstract class PGL { return intBuffer.get(0) == 0 ? false : true; } + protected boolean getDepthWriteMask() { intBuffer.rewind(); getBooleanv(DEPTH_WRITEMASK, intBuffer); return intBuffer.get(0) == 0 ? false : true; } - protected Texture wrapBackTexture(Texture texture) { return null; } - protected Texture wrapFrontTexture(Texture texture) { return null; } + protected Texture wrapBackTexture(Texture texture) { + if (texture == null) { + texture = new Texture(); + texture.init(pg.width, pg.height, + glColorTex.get(backTex), TEXTURE_2D, RGBA, + fboWidth, fboHeight, NEAREST, NEAREST, + CLAMP_TO_EDGE, CLAMP_TO_EDGE); + texture.invertedY(true); + texture.colorBuffer(true); + pg.setCache(pg, texture); + } else { + texture.glName = glColorTex.get(backTex); + } + return texture; + } - protected void bindFrontTexture() { } - protected void unbindFrontTexture() { } + protected Texture wrapFrontTexture(Texture texture) { + if (texture == null) { + texture = new Texture(); + texture.init(pg.width, pg.height, + glColorTex.get(frontTex), TEXTURE_2D, RGBA, + fboWidth, fboHeight, NEAREST, NEAREST, + CLAMP_TO_EDGE, CLAMP_TO_EDGE); + texture.invertedY(true); + texture.colorBuffer(true); + } else { + texture.glName = glColorTex.get(frontTex); + } + return texture; + } + + + protected void bindFrontTexture() { + usingFrontTex = true; + if (!texturingIsEnabled(TEXTURE_2D)) { + enableTexturing(TEXTURE_2D); + } + bindTexture(TEXTURE_2D, glColorTex.get(frontTex)); + } + + + protected void unbindFrontTexture() { + if (textureIsBound(TEXTURE_2D, glColorTex.get(frontTex))) { + // We don't want to unbind another texture + // that might be bound instead of this one. + if (!texturingIsEnabled(TEXTURE_2D)) { + enableTexturing(TEXTURE_2D); + bindTexture(TEXTURE_2D, 0); + disableTexturing(TEXTURE_2D); + } else { + bindTexture(TEXTURE_2D, 0); + } + } + } + + + protected void syncBackTexture() { + if (usingFrontTex) needSepFrontTex = true; + if (1 < numSamples) { + bindFramebuffer(READ_FRAMEBUFFER, glMultiFbo.get(0)); + bindFramebuffer(DRAW_FRAMEBUFFER, glColorFbo.get(0)); + blitFramebuffer(0, 0, fboWidth, fboHeight, + 0, 0, fboWidth, fboHeight, + COLOR_BUFFER_BIT, NEAREST); + } + } - protected void syncBackTexture() { } protected int qualityToSamples(int quality) { if (quality <= 1) { @@ -628,21 +711,23 @@ public abstract class PGL { } - - protected void requestFocus() { } - - protected boolean canDraw() { return pg.initialized && pg.parent.isDisplayable(); } - protected void requestDraw() { } - - protected void swapBuffers() { } + protected abstract void requestFocus(); - protected boolean threadIsCurrent() { return false; } + protected abstract void requestDraw(); + + + protected abstract void swapBuffers(); + + + protected boolean threadIsCurrent() { + return Thread.currentThread() == glThread; + } protected boolean needFBOLayer(boolean clear0) { @@ -667,95 +752,17 @@ public abstract class PGL { protected int getCurrentContext() { - return contextID; + return glContext; } - - - - - - - - - - - /////////////////////////////////////////////////////////// - - // Tessellator interface - - - protected Tessellator createTessellator(TessellatorCallback callback) { - return null; - } - - protected interface Tessellator { - public void beginPolygon(); - public void endPolygon(); - public void setWindingRule(int rule); - public void beginContour(); - public void endContour(); - public void addVertex(double[] v); - } - - protected interface TessellatorCallback { - public void begin(int type); - public void end(); - public void vertex(Object data); - public void combine(double[] coords, Object[] data, - float[] weight, Object[] outData); - public void error(int errnum); - } - - protected String tessError(int err) { - return ""; - } - - - /////////////////////////////////////////////////////////// - - // FontOutline interface - - - protected static boolean SHAPE_TEXT_SUPPORTED; - - protected static int SEG_MOVETO; - protected static int SEG_LINETO; - protected static int SEG_QUADTO; - protected static int SEG_CUBICTO; - protected static int SEG_CLOSE; - - protected FontOutline createFontOutline(char ch, Object font) { - return null; - } - - protected interface FontOutline { - public boolean isDone(); - public int currentSegment(float coords[]); - public void next(); - } - - - - - - - - - - - - - - /////////////////////////////////////////////////////////// // Utility functions protected boolean contextIsCurrent(int other) { - return other == -1 || other == contextID; + return other == -1 || other == glContext; } @@ -874,7 +881,7 @@ public abstract class PGL { protected void drawTexture2D(int id, int texW, int texH, int scrW, int scrH, int texX0, int texY0, int texX1, int texY1, int scrX0, int scrY0, int scrX1, int scrY1) { - if (!loadedTex2DShader || tex2DShaderContext != contextID) { + if (!loadedTex2DShader || tex2DShaderContext != glContext) { tex2DVertShader = createShader(VERTEX_SHADER, texVertShaderSource); tex2DFragShader = createShader(FRAGMENT_SHADER, tex2DFragShaderSource); if (0 < tex2DVertShader && 0 < tex2DFragShader) { @@ -885,7 +892,7 @@ public abstract class PGL { tex2DTCoordLoc = getAttribLocation(tex2DShaderProgram, "inTexcoord"); } loadedTex2DShader = true; - tex2DShaderContext = contextID; + tex2DShaderContext = glContext; } if (texData == null) { @@ -985,7 +992,7 @@ public abstract class PGL { protected void drawTextureRect(int id, int texW, int texH, int scrW, int scrH, int texX0, int texY0, int texX1, int texY1, int scrX0, int scrY0, int scrX1, int scrY1) { - if (!loadedTexRectShader || texRectShaderContext != contextID) { + if (!loadedTexRectShader || texRectShaderContext != glContext) { texRectVertShader = createShader(VERTEX_SHADER, texVertShaderSource); texRectFragShader = createShader(FRAGMENT_SHADER, texRectFragShaderSource); if (0 < texRectVertShader && 0 < texRectFragShader) { @@ -997,7 +1004,7 @@ public abstract class PGL { texRectTCoordLoc = getAttribLocation(texRectShaderProgram, "inTexcoord"); } loadedTexRectShader = true; - texRectShaderContext = contextID; + texRectShaderContext = glContext; } if (texData == null) { @@ -1479,10 +1486,10 @@ public abstract class PGL { int major = getGLVersion()[0]; if (major < 2) { String ext = getString(EXTENSIONS); - return ext.indexOf("_framebuffer_object") != -1 && - ext.indexOf("_vertex_shader") != -1 && - ext.indexOf("_shader_objects") != -1 && - ext.indexOf("_shading_language") != -1; + return ext.indexOf("_framebuffer_object") != -1 && + ext.indexOf("_vertex_shader") != -1 && + ext.indexOf("_shader_objects") != -1 && + ext.indexOf("_shading_language") != -1; } else { return true; } @@ -1874,7 +1881,60 @@ public abstract class PGL { } + /////////////////////////////////////////////////////////// + // Tessellator interface + + + protected abstract Tessellator createTessellator(TessellatorCallback callback); + + + protected interface Tessellator { + public void beginPolygon(); + public void endPolygon(); + public void setWindingRule(int rule); + public void beginContour(); + public void endContour(); + public void addVertex(double[] v); + } + + + protected interface TessellatorCallback { + public void begin(int type); + public void end(); + public void vertex(Object data); + public void combine(double[] coords, Object[] data, + float[] weight, Object[] outData); + public void error(int errnum); + } + + + protected String tessError(int err) { + return ""; + } + + + /////////////////////////////////////////////////////////// + + // FontOutline interface + + + protected static boolean SHAPE_TEXT_SUPPORTED; + protected static int SEG_MOVETO; + protected static int SEG_LINETO; + protected static int SEG_QUADTO; + protected static int SEG_CUBICTO; + protected static int SEG_CLOSE; + + + protected abstract FontOutline createFontOutline(char ch, Object font); + + + protected interface FontOutline { + public boolean isDone(); + public int currentSegment(float coords[]); + public void next(); + } ////////////////////////////////////////////////////////////////////////////// @@ -1901,7 +1961,7 @@ public abstract class PGL { // Constants // Very important note: set the GL constants in your PGL subclass by using an - // initialization block as follows: + // static initialization block as follows: // static { // FALSE = SUPER_DUPER_JAVA_OPENGL_BINDINGS.GL_FALSE; // TRUE = SUPER_DUPER_JAVA_OPENGL_BINDINGS.GL_TRUE; diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index be369e530..592f12b71 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -1583,7 +1583,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void requestFocus() { // ignore - //pgl.requestFocus(); + pgl.requestFocus(); } @@ -1700,7 +1700,7 @@ public class PGraphicsOpenGL extends PGraphics { // Factory method - static public PGL createPGL(PGraphicsOpenGL pg) { + protected PGL createPGL(PGraphicsOpenGL pg) { return new PJOGL(pg); } diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index e4d7a413c..5aa314ff1 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -47,14 +47,12 @@ import java.awt.geom.PathIterator; import javax.media.opengl.glu.GLUtessellator; import javax.media.opengl.glu.GLUtessellatorCallbackAdapter; -@SuppressWarnings("static-access") public class PJOGL extends PGL { - static { - INDEX_TYPE = GL.GL_UNSIGNED_SHORT; - } + // The two windowing toolkits available to use in JOGL: + public static final int AWT = 0; // http://jogamp.org/wiki/index.php/Using_JOGL_in_AWT_SWT_and_Swing + public static final int NEWT = 1; // http://jogamp.org/jogl/doc/NEWT-Overview.html - - /////////////////////////////////////////////////////////// + // ........................................................ // Public members to access the underlying GL objects and context @@ -73,20 +71,22 @@ public class PJOGL extends PGL { /** Selected GL profile */ public static GLProfile profile; + // ........................................................ - /** JOGL's windowing toolkit */ - // The two windowing toolkits available to use in JOGL: - protected static final int AWT = 0; // http://jogamp.org/wiki/index.php/Using_JOGL_in_AWT_SWT_and_Swing - protected static final int NEWT = 1; // http://jogamp.org/jogl/doc/NEWT-Overview.html + // Additional parameters + /** Time that the Processing's animation thread will wait for JOGL's rendering + * thread to be done with a single frame. + */ + protected static int DRAW_TIMEOUT_MILLIS = 500; + + // ........................................................ + + // OS-specific configuration - /** OS-specific configuration */ protected static int WINDOW_TOOLKIT; protected static int EVENTS_TOOLKIT; protected static boolean USE_JOGL_FBOLAYER; - protected static int REQUESTED_DEPTH_BITS = 24; - protected static int REQUESTED_STENCIL_BITS = 8; - protected static int REQUESTED_ALPHA_BITS = 8; static { if (PApplet.platform == PConstants.WINDOWS) { // Using AWT on Windows because NEWT displays a black background while @@ -99,57 +99,28 @@ public class PJOGL extends PGL { EVENTS_TOOLKIT = AWT; USE_FBOLAYER_BY_DEFAULT = false; USE_JOGL_FBOLAYER = false; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; } else if (PApplet.platform == PConstants.MACOSX) { // Note: The JOGL FBO layer (in 2.0.2) seems incompatible with NEWT. WINDOW_TOOLKIT = AWT; EVENTS_TOOLKIT = AWT; USE_FBOLAYER_BY_DEFAULT = true; USE_JOGL_FBOLAYER = true; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; } else if (PApplet.platform == PConstants.LINUX) { WINDOW_TOOLKIT = AWT; EVENTS_TOOLKIT = AWT; USE_FBOLAYER_BY_DEFAULT = false; USE_JOGL_FBOLAYER = false; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; } else if (PApplet.platform == PConstants.OTHER) { WINDOW_TOOLKIT = NEWT; // NEWT works on the Raspberry pi? EVENTS_TOOLKIT = NEWT; USE_FBOLAYER_BY_DEFAULT = false; USE_JOGL_FBOLAYER = false; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; } } - /** Time that the Processing's animation thread will wait for JOGL's rendering - * thread to be done with a single frame. - */ - protected static int DRAW_TIMEOUT_MILLIS = 500; + // ........................................................ - - - /** Desired target framerate */ - protected float targetFps = 60; - protected float currentFps = 60; - protected boolean setFps = false; - protected int fcount, lastm; - protected int fint = 3; - - - - - - /** OpenGL thread */ - protected static Thread glThread; + // Protected JOGL-specific objects needed to access the GL profiles /** The capabilities of the OpenGL rendering surface */ protected static GLCapabilitiesImmutable capabilities; @@ -180,11 +151,14 @@ public class PJOGL extends PGL { * Processing's drawing thread and JOGL's rendering thread */ protected CountDownLatch drawLatch; + /** Flag used to do request final display() call to make sure that the + * buffers are properly swapped. + */ + protected boolean prevCanDraw = false; + // ........................................................ - protected float[] projMatrix; - protected float[] mvMatrix; - + // JOGL's FBO-layer /** Back (== draw, current frame) buffer */ protected static FBObject backFBO; @@ -195,6 +169,30 @@ public class PJOGL extends PGL { protected static FBObject.TextureAttachment backTexAttach; protected static FBObject.TextureAttachment frontTexAttach; + protected boolean changedFrontTex = false; + protected boolean changedBackTex = false; + + // ........................................................ + + // Utility arrays to copy projection/modelview matrices to GL + + protected float[] projMatrix; + protected float[] mvMatrix; + + // ........................................................ + + // Static initialization for some parameters that need to be different for + // JOGL + + static { + MIN_DIRECT_BUFFER_SIZE = 2; + INDEX_TYPE = GL.GL_UNSIGNED_SHORT; + } + + + /////////////////////////////////////////////////////////////// + + // Initialization, finalization public PJOGL(PGraphicsOpenGL pg) { @@ -239,9 +237,9 @@ public class PJOGL extends PGL { // Setting up the desired capabilities; GLCapabilities caps = new GLCapabilities(profile); + caps.setAlphaBits(REQUESTED_ALPHA_BITS); caps.setDepthBits(REQUESTED_DEPTH_BITS); caps.setStencilBits(REQUESTED_STENCIL_BITS); - caps.setAlphaBits(REQUESTED_ALPHA_BITS); caps.setBackgroundOpaque(true); caps.setOnscreen(true); @@ -329,7 +327,6 @@ public class PJOGL extends PGL { fboLayerCreated = false; fboLayerInUse = false; firstFrame = true; - setFps = false; } @@ -406,31 +403,21 @@ public class PJOGL extends PGL { @Override protected boolean isFBOBacked() { - return fboLayerInUse || capabilities.isFBO(); + return super.isFBOBacked() || capabilities.isFBO(); } @Override protected int getDepthBits() { - if (USE_JOGL_FBOLAYER) { - return capabilities.getDepthBits(); - } else { - intBuffer.rewind(); - getIntegerv(DEPTH_BITS, intBuffer); - return intBuffer.get(0); - } + if (USE_JOGL_FBOLAYER) return capabilities.getDepthBits(); + else return super.getDepthBits(); } @Override protected int getStencilBits() { - if (USE_JOGL_FBOLAYER) { - return capabilities.getStencilBits(); - } else { - intBuffer.rewind(); - getIntegerv(STENCIL_BITS, intBuffer); - return intBuffer.get(0); - } + if (USE_JOGL_FBOLAYER) return capabilities.getStencilBits(); + else return super.getStencilBits(); } @@ -448,20 +435,13 @@ public class PJOGL extends PGL { texture.colorBuffer(true); pg.setCache(pg, texture); } else { - texture = new Texture(); - texture.init(pg.width, pg.height, - glColorTex.get(backTex), TEXTURE_2D, RGBA, - fboWidth, fboHeight, NEAREST, NEAREST, - CLAMP_TO_EDGE, CLAMP_TO_EDGE); - texture.invertedY(true); - texture.colorBuffer(true); - pg.setCache(pg, texture); + texture = super.wrapBackTexture(null); } } else { if (USE_JOGL_FBOLAYER) { texture.glName = backTexAttach.getName(); } else { - texture.glName = glColorTex.get(backTex); + texture = super.wrapBackTexture(texture); } } return texture; @@ -481,19 +461,13 @@ public class PJOGL extends PGL { texture.invertedY(true); texture.colorBuffer(true); } else { - texture = new Texture(); - texture.init(pg.width, pg.height, - glColorTex.get(frontTex), TEXTURE_2D, RGBA, - fboWidth, fboHeight, NEAREST, NEAREST, - CLAMP_TO_EDGE, CLAMP_TO_EDGE); - texture.invertedY(true); - texture.colorBuffer(true); + texture = super.wrapFrontTexture(null); } } else { if (USE_JOGL_FBOLAYER) { texture.glName = frontTexAttach.getName(); } else { - texture.glName = glColorTex.get(frontTex); + texture = super.wrapFrontTexture(texture); } } return texture; @@ -502,18 +476,13 @@ public class PJOGL extends PGL { @Override protected void bindFrontTexture() { - usingFrontTex = true; if (USE_JOGL_FBOLAYER) { + usingFrontTex = true; if (!texturingIsEnabled(TEXTURE_2D)) { enableTexturing(TEXTURE_2D); } bindTexture(TEXTURE_2D, frontTexAttach.getName()); - } else { - if (!texturingIsEnabled(TEXTURE_2D)) { - enableTexturing(TEXTURE_2D); - } - bindTexture(TEXTURE_2D, glColorTex.get(frontTex)); - } + } else super.bindFrontTexture(); } @@ -531,39 +500,19 @@ public class PJOGL extends PGL { bindTexture(TEXTURE_2D, 0); } } - } else { - if (textureIsBound(TEXTURE_2D, glColorTex.get(frontTex))) { - // We don't want to unbind another texture - // that might be bound instead of this one. - if (!texturingIsEnabled(TEXTURE_2D)) { - enableTexturing(TEXTURE_2D); - bindTexture(TEXTURE_2D, 0); - disableTexturing(TEXTURE_2D); - } else { - bindTexture(TEXTURE_2D, 0); - } - } - } + } else super.unbindFrontTexture(); } @Override protected void syncBackTexture() { - if (usingFrontTex) needSepFrontTex = true; if (USE_JOGL_FBOLAYER) { + if (usingFrontTex) needSepFrontTex = true; if (1 < numSamples) { backFBO.syncSamplingSink(gl); backFBO.bind(gl); } - } else { - if (1 < numSamples) { - bindFramebuffer(READ_FRAMEBUFFER, glMultiFbo.get(0)); - bindFramebuffer(DRAW_FRAMEBUFFER, glColorFbo.get(0)); - blitFramebuffer(0, 0, fboWidth, fboHeight, - 0, 0, fboWidth, fboHeight, - COLOR_BUFFER_BIT, NEAREST); - } - } + } else super.syncBackTexture(); } @@ -597,12 +546,10 @@ public class PJOGL extends PGL { } } + @Override - protected void requestFocus() { - if (canvas != null) { - canvas.requestFocus(); - } - } + protected void requestFocus() { } + @Override protected void requestDraw() { @@ -635,6 +582,7 @@ public class PJOGL extends PGL { } } + @Override protected void swapBuffers() { if (WINDOW_TOOLKIT == AWT) { @@ -644,11 +592,6 @@ public class PJOGL extends PGL { } } - @Override - protected boolean threadIsCurrent() { - return Thread.currentThread() == glThread; - } - @Override protected void beginGL() { @@ -697,18 +640,432 @@ public class PJOGL extends PGL { gl2x.glLoadMatrixf(mvMatrix, 0); } + @Override protected boolean hasFBOs() { if (context.hasBasicFBOSupport()) return true; else return super.hasFBOs(); } + @Override protected boolean hasShaders() { if (context.hasGLSL()) return true; else return super.hasShaders(); } + + /////////////////////////////////////////////////////////// + + // JOGL event listeners + + + protected class PGLListener implements GLEventListener { + public PGLListener() {} + + @Override + public void display(GLAutoDrawable glDrawable) { + drawable = glDrawable; + context = glDrawable.getContext(); + glContext = context.hashCode(); + + glThread = Thread.currentThread(); + + gl = context.getGL(); + gl2 = gl.getGL2ES2(); + try { + gl2x = gl.getGL2(); + } catch (javax.media.opengl.GLException e) { + gl2x = null; + } + + if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { + // The onscreen drawing surface is backed by an FBO layer. + GLFBODrawable fboDrawable = null; + + if (WINDOW_TOOLKIT == AWT) { + GLCanvas glCanvas = (GLCanvas)glDrawable; + fboDrawable = (GLFBODrawable)glCanvas.getDelegatedDrawable(); + } else { + GLWindow glWindow = (GLWindow)glDrawable; + fboDrawable = (GLFBODrawable)glWindow.getDelegatedDrawable(); + } + + if (fboDrawable != null) { + backFBO = fboDrawable.getFBObject(GL.GL_BACK); + if (1 < numSamples) { + if (needSepFrontTex) { + // When using multisampled FBO, the back buffer is the MSAA + // surface so it cannot be read from. The sink buffer contains + // the readable 2D texture. + // In this case, we create an auxiliary "front" buffer that it is + // swapped with the sink buffer at the beginning of each frame. + // In this way, we always have a readable copy of the previous + // frame in the front texture, while the back is synchronized + // with the contents of the MSAA back buffer when requested. + if (frontFBO == null) { + // init + frontFBO = new FBObject(); + frontFBO.reset(gl, pg.width, pg.height); + frontFBO.attachTexture2D(gl, 0, true); + sinkFBO = backFBO.getSamplingSinkFBO(); + changedFrontTex = changedBackTex = true; + } else { + // swap + FBObject temp = sinkFBO; + sinkFBO = frontFBO; + frontFBO = temp; + backFBO.setSamplingSink(sinkFBO); + changedFrontTex = changedBackTex = false; + } + backTexAttach = (FBObject.TextureAttachment) sinkFBO. + getColorbuffer(0); + frontTexAttach = (FBObject.TextureAttachment)frontFBO. + getColorbuffer(0); + } else { + // Default setting (to save resources): the front and back + // textures are the same. + sinkFBO = backFBO.getSamplingSinkFBO(); + backTexAttach = (FBObject.TextureAttachment) sinkFBO. + getColorbuffer(0); + frontTexAttach = backTexAttach; + } + + } else { + // w/out multisampling, rendering is done on the back buffer. + frontFBO = fboDrawable.getFBObject(GL.GL_FRONT); + + backTexAttach = fboDrawable.getTextureBuffer(GL.GL_BACK); + frontTexAttach = fboDrawable.getTextureBuffer(GL.GL_FRONT); + } + } + } + + pg.parent.handleDraw(); + drawLatch.countDown(); + } + + @Override + public void dispose(GLAutoDrawable adrawable) { + } + + @Override + public void init(GLAutoDrawable adrawable) { + drawable = adrawable; + context = adrawable.getContext(); + glContext = context.hashCode(); + capabilities = adrawable.getChosenGLCapabilities(); + gl = context.getGL(); + + if (!hasFBOs()) { + throw new RuntimeException(MISSING_FBO_ERROR); + } + if (!hasShaders()) { + throw new RuntimeException(MISSING_GLSL_ERROR); + } + if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { + int maxs = maxSamples(); + numSamples = PApplet.min(capabilities.getNumSamples(), maxs); + } + } + + @Override + public void reshape(GLAutoDrawable adrawable, int x, int y, int w, int h) { + drawable = adrawable; + context = adrawable.getContext(); + glContext = context.hashCode(); + } + } + + protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent, + int peAction) { + int modifiers = nativeEvent.getModifiers(); + int peModifiers = modifiers & + (InputEvent.SHIFT_MASK | + InputEvent.CTRL_MASK | + InputEvent.META_MASK | + InputEvent.ALT_MASK); + + int peButton = 0; + if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { + peButton = PConstants.LEFT; + } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { + peButton = PConstants.CENTER; + } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { + peButton = PConstants.RIGHT; + } + + if (PApplet.platform == PConstants.MACOSX) { + //if (nativeEvent.isPopupTrigger()) { + if ((modifiers & InputEvent.CTRL_MASK) != 0) { + peButton = PConstants.RIGHT; + } + } + + int peCount = 0; + if (peAction == MouseEvent.WHEEL) { + peCount = nativeEvent.isShiftDown() ? (int)nativeEvent.getRotation()[0] : + (int)nativeEvent.getRotation()[1]; + } else { + peCount = nativeEvent.getClickCount(); + } + + MouseEvent me = new MouseEvent(nativeEvent, nativeEvent.getWhen(), + peAction, peModifiers, + nativeEvent.getX(), nativeEvent.getY(), + peButton, + peCount); + + pg.parent.postEvent(me); + } + + protected void nativeKeyEvent(com.jogamp.newt.event.KeyEvent nativeEvent, + int peAction) { + int peModifiers = nativeEvent.getModifiers() & + (InputEvent.SHIFT_MASK | + InputEvent.CTRL_MASK | + InputEvent.META_MASK | + InputEvent.ALT_MASK); + + char keyChar; + if ((int)nativeEvent.getKeyChar() == 0) { + keyChar = PConstants.CODED; + } else { + keyChar = nativeEvent.getKeyChar(); + } + + KeyEvent ke = new KeyEvent(nativeEvent, nativeEvent.getWhen(), + peAction, peModifiers, + keyChar, + nativeEvent.getKeyCode()); + + pg.parent.postEvent(ke); + } + + class NEWTWindowListener implements com.jogamp.newt.event.WindowListener { + @Override + public void windowGainedFocus(com.jogamp.newt.event.WindowEvent arg0) { + pg.parent.focusGained(null); + } + + @Override + public void windowLostFocus(com.jogamp.newt.event.WindowEvent arg0) { + pg.parent.focusLost(null); + } + + @Override + public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) { + } + + @Override + public void windowDestroyed(com.jogamp.newt.event.WindowEvent arg0) { + } + + @Override + public void windowMoved(com.jogamp.newt.event.WindowEvent arg0) { + } + + @Override + public void windowRepaint(com.jogamp.newt.event.WindowUpdateEvent arg0) { + } + + @Override + public void windowResized(com.jogamp.newt.event.WindowEvent arg0) { } + } + + // NEWT mouse listener + class NEWTMouseListener extends com.jogamp.newt.event.MouseAdapter { + @Override + public void mousePressed(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.PRESS); + } + @Override + public void mouseReleased(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.RELEASE); + } + @Override + public void mouseClicked(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.CLICK); + } + @Override + public void mouseDragged(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.DRAG); + } + @Override + public void mouseMoved(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.MOVE); + } + @Override + public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.WHEEL); + } + @Override + public void mouseEntered(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.ENTER); + } + @Override + public void mouseExited(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.EXIT); + } + } + + // NEWT key listener + class NEWTKeyListener extends com.jogamp.newt.event.KeyAdapter { + @Override + public void keyPressed(com.jogamp.newt.event.KeyEvent e) { + nativeKeyEvent(e, KeyEvent.PRESS); + } + @Override + public void keyReleased(com.jogamp.newt.event.KeyEvent e) { + nativeKeyEvent(e, KeyEvent.RELEASE); + } + public void keyTyped(com.jogamp.newt.event.KeyEvent e) { + nativeKeyEvent(e, KeyEvent.TYPE); + } + } + + + /////////////////////////////////////////////////////////// + + // Tessellator + + + @Override + protected Tessellator createTessellator(TessellatorCallback callback) { + return new Tessellator(callback); + } + + + protected class Tessellator implements PGL.Tessellator { + protected GLUtessellator tess; + protected TessellatorCallback callback; + protected GLUCallback gluCallback; + + public Tessellator(TessellatorCallback callback) { + this.callback = callback; + tess = GLU.gluNewTess(); + gluCallback = new GLUCallback(); + + GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_END, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR, gluCallback); + } + + @Override + public void beginPolygon() { + GLU.gluTessBeginPolygon(tess, null); + } + + @Override + public void endPolygon() { + GLU.gluTessEndPolygon(tess); + } + + @Override + public void setWindingRule(int rule) { + GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, rule); + } + + @Override + public void beginContour() { + GLU.gluTessBeginContour(tess); + } + + @Override + public void endContour() { + GLU.gluTessEndContour(tess); + } + + @Override + public void addVertex(double[] v) { + GLU.gluTessVertex(tess, v, 0, v); + } + + protected class GLUCallback extends GLUtessellatorCallbackAdapter { + @Override + public void begin(int type) { + callback.begin(type); + } + + @Override + public void end() { + callback.end(); + } + + @Override + public void vertex(Object data) { + callback.vertex(data); + } + + @Override + public void combine(double[] coords, Object[] data, + float[] weight, Object[] outData) { + callback.combine(coords, data, weight, outData); + } + + @Override + public void error(int errnum) { + callback.error(errnum); + } + } + } + + + @Override + protected String tessError(int err) { + return glu.gluErrorString(err); + } + + + /////////////////////////////////////////////////////////// + + // Font outline + + + static { + SHAPE_TEXT_SUPPORTED = true; + SEG_MOVETO = PathIterator.SEG_MOVETO; + SEG_LINETO = PathIterator.SEG_LINETO; + SEG_QUADTO = PathIterator.SEG_QUADTO; + SEG_CUBICTO = PathIterator.SEG_CUBICTO; + SEG_CLOSE = PathIterator.SEG_CLOSE; + } + + + @Override + protected FontOutline createFontOutline(char ch, Object font) { + return new FontOutline(ch, font); + } + + + protected class FontOutline implements PGL.FontOutline { + PathIterator iter; + + public FontOutline(char ch, Object font) { + char textArray[] = new char[] { ch }; + Graphics2D graphics = (Graphics2D) pg.parent.getGraphics(); + FontRenderContext frc = graphics.getFontRenderContext(); + GlyphVector gv = ((Font)font).createGlyphVector(frc, textArray); + Shape shp = gv.getOutline(); + iter = shp.getPathIterator(null); + } + + public boolean isDone() { + return iter.isDone(); + } + + public int currentSegment(float coords[]) { + return iter.currentSegment(coords); + } + + public void next() { + iter.next(); + } + } + + /////////////////////////////////////////////////////////// // Constants @@ -997,7 +1354,6 @@ public class PJOGL extends PGL { POLYGON_SMOOTH = GL2GL3.GL_POLYGON_SMOOTH; } - /////////////////////////////////////////////////////////// // Special Functions @@ -1657,7 +2013,7 @@ public class PJOGL extends PGL { @Override public String getProgramInfoLog(int program) { int[] val = { 0 }; - gl2.glGetShaderiv(program, GL2.GL_INFO_LOG_LENGTH, val, 0); + gl2.glGetShaderiv(program, GL2ES2.GL_INFO_LOG_LENGTH, val, 0); int length = val[0]; if (0 < length) { @@ -1885,410 +2241,4 @@ public class PJOGL extends PGL { gl2x.glDrawBuffer(buf); } } - - - - - - /////////////////////////////////////////////////////////// - - // JOGL Event listeners - - protected boolean changedFrontTex = false; - protected boolean changedBackTex = false; - - protected class PGLListener implements GLEventListener { - public PGLListener() {} - - @Override - public void display(GLAutoDrawable glDrawable) { - drawable = glDrawable; - context = glDrawable.getContext(); - contextID = context.hashCode(); - - glThread = Thread.currentThread(); - - gl = context.getGL(); - gl2 = gl.getGL2ES2(); - try { - gl2x = gl.getGL2(); - } catch (javax.media.opengl.GLException e) { - gl2x = null; - } - - if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { - // The onscreen drawing surface is backed by an FBO layer. - GLFBODrawable fboDrawable = null; - - if (WINDOW_TOOLKIT == AWT) { - GLCanvas glCanvas = (GLCanvas)glDrawable; - fboDrawable = (GLFBODrawable)glCanvas.getDelegatedDrawable(); - } else { - GLWindow glWindow = (GLWindow)glDrawable; - fboDrawable = (GLFBODrawable)glWindow.getDelegatedDrawable(); - } - - if (fboDrawable != null) { - backFBO = fboDrawable.getFBObject(GL.GL_BACK); - if (1 < numSamples) { - if (needSepFrontTex) { - // When using multisampled FBO, the back buffer is the MSAA - // surface so it cannot be read from. The sink buffer contains - // the readable 2D texture. - // In this case, we create an auxiliary "front" buffer that it is - // swapped with the sink buffer at the beginning of each frame. - // In this way, we always have a readable copy of the previous - // frame in the front texture, while the back is synchronized - // with the contents of the MSAA back buffer when requested. - if (frontFBO == null) { - // init - frontFBO = new FBObject(); - frontFBO.reset(gl, pg.width, pg.height); - frontFBO.attachTexture2D(gl, 0, true); - sinkFBO = backFBO.getSamplingSinkFBO(); - changedFrontTex = changedBackTex = true; - } else { - // swap - FBObject temp = sinkFBO; - sinkFBO = frontFBO; - frontFBO = temp; - backFBO.setSamplingSink(sinkFBO); - changedFrontTex = changedBackTex = false; - } - backTexAttach = (FBObject.TextureAttachment) sinkFBO. - getColorbuffer(0); - frontTexAttach = (FBObject.TextureAttachment)frontFBO. - getColorbuffer(0); - } else { - // Default setting (to save resources): the front and back - // textures are the same. - sinkFBO = backFBO.getSamplingSinkFBO(); - backTexAttach = (FBObject.TextureAttachment) sinkFBO. - getColorbuffer(0); - frontTexAttach = backTexAttach; - } - - } else { - // w/out multisampling, rendering is done on the back buffer. - frontFBO = fboDrawable.getFBObject(GL.GL_FRONT); - - backTexAttach = fboDrawable.getTextureBuffer(GL.GL_BACK); - frontTexAttach = fboDrawable.getTextureBuffer(GL.GL_FRONT); - } - } - } - - pg.parent.handleDraw(); -// clearColor(1, 0, 0, 1); -// clear(COLOR_BUFFER_BIT); - drawLatch.countDown(); - } - - @Override - public void dispose(GLAutoDrawable adrawable) { - } - - @Override - public void init(GLAutoDrawable adrawable) { - drawable = adrawable; - context = adrawable.getContext(); - contextID = context.hashCode(); - capabilities = adrawable.getChosenGLCapabilities(); - gl = context.getGL(); - - if (!hasFBOs()) { - throw new RuntimeException(MISSING_FBO_ERROR); - } - if (!hasShaders()) { - throw new RuntimeException(MISSING_GLSL_ERROR); - } - if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { - int maxs = maxSamples(); - numSamples = PApplet.min(capabilities.getNumSamples(), maxs); - } - } - - @Override - public void reshape(GLAutoDrawable adrawable, int x, int y, int w, int h) { - drawable = adrawable; - context = adrawable.getContext(); - contextID = context.hashCode(); - } - } - - protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent, - int peAction) { - int modifiers = nativeEvent.getModifiers(); - int peModifiers = modifiers & - (InputEvent.SHIFT_MASK | - InputEvent.CTRL_MASK | - InputEvent.META_MASK | - InputEvent.ALT_MASK); - - int peButton = 0; - if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { - peButton = PConstants.LEFT; - } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { - peButton = PConstants.CENTER; - } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { - peButton = PConstants.RIGHT; - } - - if (PApplet.platform == PConstants.MACOSX) { - //if (nativeEvent.isPopupTrigger()) { - if ((modifiers & InputEvent.CTRL_MASK) != 0) { - peButton = PConstants.RIGHT; - } - } - - int peCount = 0; - if (peAction == MouseEvent.WHEEL) { - peCount = nativeEvent.isShiftDown() ? (int)nativeEvent.getRotation()[0] : - (int)nativeEvent.getRotation()[1]; - } else { - peCount = nativeEvent.getClickCount(); - } - - MouseEvent me = new MouseEvent(nativeEvent, nativeEvent.getWhen(), - peAction, peModifiers, - nativeEvent.getX(), nativeEvent.getY(), - peButton, - peCount); - - pg.parent.postEvent(me); - } - - protected void nativeKeyEvent(com.jogamp.newt.event.KeyEvent nativeEvent, - int peAction) { - int peModifiers = nativeEvent.getModifiers() & - (InputEvent.SHIFT_MASK | - InputEvent.CTRL_MASK | - InputEvent.META_MASK | - InputEvent.ALT_MASK); - - char keyChar; - if ((int)nativeEvent.getKeyChar() == 0) { - keyChar = PConstants.CODED; - } else { - keyChar = nativeEvent.getKeyChar(); - } - - KeyEvent ke = new KeyEvent(nativeEvent, nativeEvent.getWhen(), - peAction, peModifiers, - keyChar, - nativeEvent.getKeyCode()); - - pg.parent.postEvent(ke); - } - - class NEWTWindowListener implements com.jogamp.newt.event.WindowListener { - @Override - public void windowGainedFocus(com.jogamp.newt.event.WindowEvent arg0) { - pg.parent.focusGained(null); - } - - @Override - public void windowLostFocus(com.jogamp.newt.event.WindowEvent arg0) { - pg.parent.focusLost(null); - } - - @Override - public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) { - } - - @Override - public void windowDestroyed(com.jogamp.newt.event.WindowEvent arg0) { - } - - @Override - public void windowMoved(com.jogamp.newt.event.WindowEvent arg0) { - } - - @Override - public void windowRepaint(com.jogamp.newt.event.WindowUpdateEvent arg0) { - } - - @Override - public void windowResized(com.jogamp.newt.event.WindowEvent arg0) { } - } - - // NEWT mouse listener - class NEWTMouseListener extends com.jogamp.newt.event.MouseAdapter { - @Override - public void mousePressed(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.PRESS); - } - @Override - public void mouseReleased(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.RELEASE); - } - @Override - public void mouseClicked(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.CLICK); - } - @Override - public void mouseDragged(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.DRAG); - } - @Override - public void mouseMoved(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.MOVE); - } - @Override - public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.WHEEL); - } - @Override - public void mouseEntered(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.ENTER); - } - @Override - public void mouseExited(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.EXIT); - } - } - - // NEWT key listener - class NEWTKeyListener extends com.jogamp.newt.event.KeyAdapter { - @Override - public void keyPressed(com.jogamp.newt.event.KeyEvent e) { - nativeKeyEvent(e, KeyEvent.PRESS); - } - @Override - public void keyReleased(com.jogamp.newt.event.KeyEvent e) { - nativeKeyEvent(e, KeyEvent.RELEASE); - } - public void keyTyped(com.jogamp.newt.event.KeyEvent e) { - nativeKeyEvent(e, KeyEvent.TYPE); - } - } - - - - - @Override - protected Tessellator createTessellator(TessellatorCallback callback) { - return new Tessellator(callback); - } - - protected class Tessellator implements PGL.Tessellator { - protected GLUtessellator tess; - protected TessellatorCallback callback; - protected GLUCallback gluCallback; - - public Tessellator(TessellatorCallback callback) { - this.callback = callback; - tess = GLU.gluNewTess(); - gluCallback = new GLUCallback(); - - GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_END, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR, gluCallback); - } - - @Override - public void beginPolygon() { - GLU.gluTessBeginPolygon(tess, null); - } - - @Override - public void endPolygon() { - GLU.gluTessEndPolygon(tess); - } - - @Override - public void setWindingRule(int rule) { - GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, rule); - } - - @Override - public void beginContour() { - GLU.gluTessBeginContour(tess); - } - - @Override - public void endContour() { - GLU.gluTessEndContour(tess); - } - - @Override - public void addVertex(double[] v) { - GLU.gluTessVertex(tess, v, 0, v); - } - - protected class GLUCallback extends GLUtessellatorCallbackAdapter { - @Override - public void begin(int type) { - callback.begin(type); - } - - @Override - public void end() { - callback.end(); - } - - @Override - public void vertex(Object data) { - callback.vertex(data); - } - - @Override - public void combine(double[] coords, Object[] data, - float[] weight, Object[] outData) { - callback.combine(coords, data, weight, outData); - } - - @Override - public void error(int errnum) { - callback.error(errnum); - } - } - } - - @Override - protected String tessError(int err) { - return glu.gluErrorString(err); - } - - static { - SHAPE_TEXT_SUPPORTED = true; - SEG_MOVETO = PathIterator.SEG_MOVETO; - SEG_LINETO = PathIterator.SEG_LINETO; - SEG_QUADTO = PathIterator.SEG_QUADTO; - SEG_CUBICTO = PathIterator.SEG_CUBICTO; - SEG_CLOSE = PathIterator.SEG_CLOSE; - } - - @Override - protected FontOutline createFontOutline(char ch, Object font) { - return new FontOutline(ch, font); - } - - protected class FontOutline implements PGL.FontOutline { - PathIterator iter; - - public FontOutline(char ch, Object font) { - char textArray[] = new char[] { ch }; - Graphics2D graphics = (Graphics2D) pg.parent.getGraphics(); - FontRenderContext frc = graphics.getFontRenderContext(); - GlyphVector gv = ((Font)font).createGlyphVector(frc, textArray); - Shape shp = gv.getOutline(); - iter = shp.getPathIterator(null); - } - - public boolean isDone() { - return iter.isDone(); - } - - public int currentSegment(float coords[]) { - return iter.currentSegment(coords); - } - - public void next() { - iter.next(); - } - } - } diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGraphics2D.java b/java/libraries/lwjgl/src/processing/lwjgl/PGraphics2D.java new file mode 100644 index 000000000..501de2ba0 --- /dev/null +++ b/java/libraries/lwjgl/src/processing/lwjgl/PGraphics2D.java @@ -0,0 +1,10 @@ +package processing.lwjgl; + +import processing.opengl.PGL; +import processing.opengl.PGraphicsOpenGL; + +public class PGraphics2D extends processing.opengl.PGraphics2D { + protected PGL createPGL(PGraphicsOpenGL pg) { + return new PLWJGL(pg); + } +} diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGraphics3D.java b/java/libraries/lwjgl/src/processing/lwjgl/PGraphics3D.java new file mode 100644 index 000000000..14bbc5c31 --- /dev/null +++ b/java/libraries/lwjgl/src/processing/lwjgl/PGraphics3D.java @@ -0,0 +1,10 @@ +package processing.lwjgl; + +import processing.opengl.PGL; +import processing.opengl.PGraphicsOpenGL; + +public class PGraphics3D extends processing.opengl.PGraphics3D { + protected PGL createPGL(PGraphicsOpenGL pg) { + return new PLWJGL(pg); + } +} diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java index baf0f1f0e..b34d4d2a3 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java @@ -30,8 +30,7 @@ import processing.opengl.PGraphicsOpenGL; * */ public class PGraphicsLWJGL extends PGraphicsOpenGL { - - static public PGL createPGL(PGraphicsOpenGL pg) { + protected PGL createPGL(PGraphicsOpenGL pg) { return new PLWJGL(pg); } } diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java index 5fe122c86..e3b54272e 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java @@ -26,14 +26,18 @@ package processing.lwjgl; import java.awt.BorderLayout; import java.awt.Canvas; import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.PathIterator; import java.nio.Buffer; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; -import java.util.Arrays; import org.lwjgl.BufferUtils; import org.lwjgl.LWJGLException; @@ -64,24 +68,19 @@ import processing.event.KeyEvent; import processing.event.MouseEvent; import processing.opengl.PGL; import processing.opengl.PGraphicsOpenGL; -import processing.opengl.Texture; /** - * Processing-OpenGL abstraction layer. + * Processing-OpenGL abstraction layer. LWJGL implementation. * - * Warnings are suppressed for static access because presumably on Android, - * the GL2 vs GL distinctions are necessary, whereas on desktop they are not. - * - * This version of PGL uses LWJGL, see some issues with it: + * Some issues: * http://lwjgl.org/forum/index.php/topic,4711.0.html * http://www.java-gaming.org/topics/cannot-add-mouselistener-to-java-awt-canvas-with-lwjgl-on-windows/24650/view.html * */ -@SuppressWarnings("static-access") public class PLWJGL extends PGL { - /////////////////////////////////////////////////////////// + // ........................................................ - // Public members to access the underlying GL objects and context + // Public members to access the underlying GL objects and canvas /** GLU interface **/ public static GLU glu; @@ -89,230 +88,30 @@ public class PLWJGL extends PGL { /** The canvas where OpenGL rendering takes place */ public static Canvas canvas; - /////////////////////////////////////////////////////////// - - // Parameters - - protected static boolean FORCE_SCREEN_FBO = false; - protected static final boolean USE_DIRECT_BUFFERS = true; - protected static final int MIN_DIRECT_BUFFER_SIZE = 16; - protected static final boolean SAVE_SURFACE_TO_PIXELS = true; - - /** Enables/disables mipmap use. **/ - protected static final boolean MIPMAPS_ENABLED = true; - - /** Initial sizes for arrays of input and tessellated data. */ - protected static final int DEFAULT_IN_VERTICES = 64; - protected static final int DEFAULT_IN_EDGES = 128; - protected static final int DEFAULT_IN_TEXTURES = 64; - protected static final int DEFAULT_TESS_VERTICES = 64; - protected static final int DEFAULT_TESS_INDICES = 128; - - /** Maximum lights by default is 8, the minimum defined by OpenGL. */ - protected static final int MAX_LIGHTS = 8; - - /** Maximum index value of a tessellated vertex. GLES restricts the vertex - * indices to be of type unsigned short. Since Java only supports signed - * shorts as primitive type we have 2^15 = 32768 as the maximum number of - * vertices that can be referred to within a single VBO. */ - protected static final int MAX_VERTEX_INDEX = 32767; - protected static final int MAX_VERTEX_INDEX1 = MAX_VERTEX_INDEX + 1; - - /** Count of tessellated fill, line or point vertices that will - * trigger a flush in the immediate mode. It doesn't necessarily - * be equal to MAX_VERTEX_INDEX1, since the number of vertices can - * be effectively much large since the renderer uses offsets to - * refer to vertices beyond the MAX_VERTEX_INDEX limit. - */ - protected static final int FLUSH_VERTEX_COUNT = MAX_VERTEX_INDEX1; - - /** Minimum/maximum dimensions of a texture used to hold font data. **/ - protected static final int MIN_FONT_TEX_SIZE = 256; - protected static final int MAX_FONT_TEX_SIZE = 1024; - - /** Minimum stroke weight needed to apply the full path stroking - * algorithm that properly generates caps and joins. - */ - protected static final float MIN_CAPS_JOINS_WEIGHT = 2f; - - /** Maximum length of linear paths to be stroked with the - * full algorithm that generates accurate caps and joins. - */ - protected static final int MAX_CAPS_JOINS_LENGTH = 5000; - - /** Minimum array size to use arrayCopy method(). **/ - protected static final int MIN_ARRAYCOPY_SIZE = 2; - - /** Factor used to displace the stroke vertices towards the camera in - * order to make sure the lines are always on top of the fill geometry **/ - protected static final float STROKE_DISPLACEMENT = 0.999f; + // ........................................................ + + // Event handling - protected static int request_depth_bits = 24; - protected static int request_stencil_bits = 8; - protected static int request_alpha_bits = 8; - - protected static final int SIZEOF_SHORT = Short.SIZE / 8; - protected static final int SIZEOF_INT = Integer.SIZE / 8; - protected static final int SIZEOF_FLOAT = Float.SIZE / 8; - protected static final int SIZEOF_BYTE = Byte.SIZE / 8; - protected static final int SIZEOF_INDEX = SIZEOF_SHORT; - protected static final int INDEX_TYPE = GL11.GL_UNSIGNED_SHORT; - - /** Machine Epsilon for float precision. **/ - protected static float FLOAT_EPS = Float.MIN_VALUE; - // Calculation of the Machine Epsilon for float precision. From: - // http://en.wikipedia.org/wiki/Machine_epsilon#Approximation_using_Java - static { - float eps = 1.0f; - - do { - eps /= 2.0f; - } while ((float)(1.0 + (eps / 2.0)) != 1.0); - - FLOAT_EPS = eps; - } - - /** - * Set to true if the host system is big endian (PowerPC, MIPS, SPARC), false - * if little endian (x86 Intel for Mac or PC). - */ - protected static boolean BIG_ENDIAN = - ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; - - protected static final String SHADER_PREPROCESSOR_DIRECTIVE = - "#ifdef GL_ES\n" + - "precision mediump float;\n" + - "precision mediump int;\n" + - "#endif\n"; - - /** OpenGL thread */ - protected static Thread glThread; - - /** Just holds a unique ID */ - protected static int context; - - /** The PGraphics object using this interface */ - protected PGraphicsOpenGL pg; - /** Poller threads to get the keyboard/mouse events from LWJGL */ protected static KeyPoller keyPoller; protected static MousePoller mousePoller; - /** Desired target framerate */ - protected float targetFps = 60; - protected float currentFps = 60; - protected boolean setFps = false; - protected int fcount, lastm; - protected int fint = 3; + // ........................................................ - /** Which texturing targets are enabled */ - protected static boolean[] texturingTargets = { false, false }; - - /** Used to keep track of which textures are bound to each target */ - protected static int maxTexUnits; - protected static int activeTexUnit = 0; - protected static int[][] boundTextures; - - /////////////////////////////////////////////////////////// - - // FBO layer - - protected static boolean fboLayerByDefault = FORCE_SCREEN_FBO; - protected static boolean fboLayerCreated = false; - protected static boolean fboLayerInUse = false; - protected static boolean firstFrame = true; - protected static int reqNumSamples; - protected static int numSamples; - protected static IntBuffer glColorFbo; - protected static IntBuffer glMultiFbo; - protected static IntBuffer glColorBuf; - protected static IntBuffer glColorTex; - protected static IntBuffer glDepthStencil; - protected static IntBuffer glDepth; - protected static IntBuffer glStencil; - protected static int fboWidth, fboHeight; - protected static int backTex, frontTex; - - protected static boolean needToClearBuffers; - - /////////////////////////////////////////////////////////// - - // Texture rendering - - protected static boolean loadedTex2DShader = false; - protected static int tex2DShaderProgram; - protected static int tex2DVertShader; - protected static int tex2DFragShader; - protected static int tex2DShaderContext; - protected static int tex2DVertLoc; - protected static int tex2DTCoordLoc; - - protected static boolean loadedTexRectShader = false; - protected static int texRectShaderProgram; - protected static int texRectVertShader; - protected static int texRectFragShader; - protected static int texRectShaderContext; - protected static int texRectVertLoc; - protected static int texRectTCoordLoc; - - protected static float[] texCoords = { - // X, Y, U, V - -1.0f, -1.0f, 0.0f, 0.0f, - +1.0f, -1.0f, 1.0f, 0.0f, - -1.0f, +1.0f, 0.0f, 1.0f, - +1.0f, +1.0f, 1.0f, 1.0f - }; - protected static FloatBuffer texData; - - protected static String texVertShaderSource = - "attribute vec2 inVertex;" + - "attribute vec2 inTexcoord;" + - "varying vec2 vertTexcoord;" + - "void main() {" + - " gl_Position = vec4(inVertex, 0, 1);" + - " vertTexcoord = inTexcoord;" + - "}"; - - protected static String tex2DFragShaderSource = - SHADER_PREPROCESSOR_DIRECTIVE + - "uniform sampler2D textureSampler;" + - "varying vec2 vertTexcoord;" + - "void main() {" + - " gl_FragColor = texture2D(textureSampler, vertTexcoord.st);" + - "}"; - - protected static String texRectFragShaderSource = - SHADER_PREPROCESSOR_DIRECTIVE + - "uniform sampler2DRect textureSampler;" + - "varying vec2 vertTexcoord;" + - "void main() {" + - " gl_FragColor = texture2DRect(textureSampler, vertTexcoord.st);" + - "}"; - - /////////////////////////////////////////////////////////// - - // Utilities - - protected ByteBuffer byteBuffer; - protected IntBuffer intBuffer; - - protected IntBuffer colorBuffer; - protected FloatBuffer depthBuffer; - protected ByteBuffer stencilBuffer; - - - /////////////////////////////////////////////////////////// - - // Error messages - - protected static final String MISSING_FBO_ERROR = - "Framebuffer objects are not supported by this hardware (or driver)"; - - protected static final String MISSING_GLSL_ERROR = - "GLSL shaders are not supported by this hardware (or driver)"; - - protected static final String MISSING_GLFUNC_ERROR = - "GL function %1$s is not available on this hardware (or driver)"; + // Utility buffers to copy projection/modelview matrices to GL + + protected FloatBuffer projMatrix; + protected FloatBuffer mvMatrix; + + // ........................................................ + + // Static initialization for some parameters that need to be different for + // LWJGL + + static { + MIN_DIRECT_BUFFER_SIZE = 16; + INDEX_TYPE = GL11.GL_UNSIGNED_SHORT; + } /////////////////////////////////////////////////////////// @@ -321,27 +120,8 @@ public class PLWJGL extends PGL { public PLWJGL(PGraphicsOpenGL pg) { - this.pg = pg; - if (glu == null) { - glu = new GLU(); - } - if (glColorTex == null) { - glColorTex = allocateIntBuffer(2); - glColorFbo = allocateIntBuffer(1); - glMultiFbo = allocateIntBuffer(1); - glColorBuf = allocateIntBuffer(1); - glDepthStencil = allocateIntBuffer(1); - glDepth = allocateIntBuffer(1); - glStencil = allocateIntBuffer(1); - - fboLayerCreated = false; - fboLayerInUse = false; - firstFrame = false; - needToClearBuffers = false; - } - - byteBuffer = allocateByteBuffer(1); - intBuffer = allocateIntBuffer(1); + super(pg); + if (glu == null) glu = new GLU(); } @@ -390,9 +170,21 @@ public class PLWJGL extends PGL { for (int i = 0; i < modes.length; i++) { bpp = PApplet.max(modes[i].getBitsPerPixel(), bpp); } - PixelFormat format = new PixelFormat(bpp, request_alpha_bits, - request_depth_bits, - request_stencil_bits, 1); + + PixelFormat format; + if (USE_FBOLAYER_BY_DEFAULT) { + format = new PixelFormat(bpp, REQUESTED_ALPHA_BITS, + REQUESTED_DEPTH_BITS, + REQUESTED_STENCIL_BITS, 1); + reqNumSamples = qualityToSamples(antialias); + fboLayerRequested = true; + } else { + format = new PixelFormat(bpp, REQUESTED_ALPHA_BITS, + REQUESTED_DEPTH_BITS, + REQUESTED_STENCIL_BITS, antialias); + fboLayerRequested = false; + } + Display.setDisplayMode(new DisplayMode(pg.parent.width, pg.parent.height)); int argb = pg.backgroundColor; float r = ((argb >> 16) & 0xff) / 255.0f; @@ -412,7 +204,7 @@ public class PLWJGL extends PGL { e.printStackTrace(); } - context = Display.getDrawable().hashCode(); + glContext = Display.getDrawable().hashCode(); keyPoller = new KeyPoller(pg.parent); keyPoller.start(); @@ -420,440 +212,21 @@ public class PLWJGL extends PGL { mousePoller = new MousePoller(pg.parent); mousePoller.start(); - reqNumSamples = qualityToSamples(antialias); + fboLayerCreated = false; fboLayerInUse = false; firstFrame = true; - needToClearBuffers = true; - setFps = false; } - protected void deleteSurface() { - if (glColorTex != null) { - deleteTextures(2, glColorTex); - deleteFramebuffers(1, glColorFbo); - deleteFramebuffers(1, glMultiFbo); - deleteRenderbuffers(1, glColorBuf); - deleteRenderbuffers(1, glDepthStencil); - deleteRenderbuffers(1, glDepth); - deleteRenderbuffers(1, glStencil); - } - fboLayerCreated = false; - fboLayerInUse = false; - firstFrame = false; - needToClearBuffers = false; - } - - - protected void update() { - if (!setFps) setFps(targetFps); - - if (!fboLayerCreated) { - if (!hasFBOs()) { - throw new RuntimeException("Framebuffer objects are not supported by this hardware (or driver)"); - } - if (!hasShaders()) { - throw new RuntimeException("GLSL shaders are not supported by this hardware (or driver)"); - } - - String ext = getString(EXTENSIONS); - if (-1 < ext.indexOf("texture_non_power_of_two")) { - fboWidth = pg.width; - fboHeight = pg.height; - } else { - fboWidth = nextPowerOfTwo(pg.width); - fboHeight = nextPowerOfTwo(pg.height); - } - - if (-1 < ext.indexOf("_framebuffer_multisample")) { - numSamples = reqNumSamples; - } else { - numSamples = 1; - } - boolean multisample = 1 < numSamples; - - boolean packed = ext.indexOf("packed_depth_stencil") != -1; - int depthBits = getDepthBits(); - int stencilBits = getStencilBits(); - - genTextures(2, glColorTex); - for (int i = 0; i < 2; i++) { - bindTexture(TEXTURE_2D, glColorTex.get(i)); - texParameteri(TEXTURE_2D, TEXTURE_MIN_FILTER, NEAREST); - texParameteri(TEXTURE_2D, TEXTURE_MAG_FILTER, NEAREST); - texParameteri(TEXTURE_2D, TEXTURE_WRAP_S, CLAMP_TO_EDGE); - texParameteri(TEXTURE_2D, TEXTURE_WRAP_T, CLAMP_TO_EDGE); - texImage2D(TEXTURE_2D, 0, RGBA, fboWidth, fboHeight, 0, - RGBA, UNSIGNED_BYTE, null); - initTexture(TEXTURE_2D, RGBA, fboWidth, fboHeight, pg.backgroundColor); - } - bindTexture(TEXTURE_2D, 0); - - backTex = 0; - frontTex = 1; - - genFramebuffers(1, glColorFbo); - bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0)); - framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_2D, - glColorTex.get(backTex), 0); - - if (multisample) { - // Creating multisampled FBO - genFramebuffers(1, glMultiFbo); - bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0)); - - // color render buffer... - genRenderbuffers(1, glColorBuf); - bindRenderbuffer(RENDERBUFFER, glColorBuf.get(0)); - renderbufferStorageMultisample(RENDERBUFFER, numSamples, - RGBA8, fboWidth, fboHeight); - framebufferRenderbuffer(FRAMEBUFFER, COLOR_ATTACHMENT0, - RENDERBUFFER, glColorBuf.get(0)); - } - - // Creating depth and stencil buffers - if (packed && depthBits == 24 && stencilBits == 8) { - // packed depth+stencil buffer - genRenderbuffers(1, glDepthStencil); - bindRenderbuffer(RENDERBUFFER, glDepthStencil.get(0)); - if (multisample) { - renderbufferStorageMultisample(RENDERBUFFER, numSamples, - DEPTH24_STENCIL8, fboWidth, fboHeight); - } else { - renderbufferStorage(RENDERBUFFER, DEPTH24_STENCIL8, - fboWidth, fboHeight); - } - framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER, - glDepthStencil.get(0)); - framebufferRenderbuffer(FRAMEBUFFER, STENCIL_ATTACHMENT, RENDERBUFFER, - glDepthStencil.get(0)); - } else { - // separate depth and stencil buffers - if (0 < depthBits) { - int depthComponent = DEPTH_COMPONENT16; - if (depthBits == 32) { - depthComponent = DEPTH_COMPONENT32; - } else if (depthBits == 24) { - depthComponent = DEPTH_COMPONENT24; - } else if (depthBits == 16) { - depthComponent = DEPTH_COMPONENT16; - } - - genRenderbuffers(1, glDepth); - bindRenderbuffer(RENDERBUFFER, glDepth.get(0)); - if (multisample) { - renderbufferStorageMultisample(RENDERBUFFER, numSamples, - depthComponent, fboWidth, fboHeight); - } else { - renderbufferStorage(RENDERBUFFER, depthComponent, - fboWidth, fboHeight); - } - framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, - RENDERBUFFER, glDepth.get(0)); - } - - if (0 < stencilBits) { - int stencilIndex = STENCIL_INDEX1; - if (stencilBits == 8) { - stencilIndex = STENCIL_INDEX8; - } else if (stencilBits == 4) { - stencilIndex = STENCIL_INDEX4; - } else if (stencilBits == 1) { - stencilIndex = STENCIL_INDEX1; - } - - genRenderbuffers(1, glStencil); - bindRenderbuffer(RENDERBUFFER, glStencil.get(0)); - if (multisample) { - renderbufferStorageMultisample(RENDERBUFFER, numSamples, - stencilIndex, fboWidth, fboHeight); - } else { - renderbufferStorage(RENDERBUFFER, stencilIndex, - fboWidth, fboHeight); - } - framebufferRenderbuffer(FRAMEBUFFER, STENCIL_ATTACHMENT, - RENDERBUFFER, glStencil.get(0)); - } - } - - validateFramebuffer(); - - // Clear all buffers. - clearDepth(1); - clearStencil(0); - int argb = pg.backgroundColor; - float a = ((argb >> 24) & 0xff) / 255.0f; - float r = ((argb >> 16) & 0xff) / 255.0f; - float g = ((argb >> 8) & 0xff) / 255.0f; - float b = ((argb) & 0xff) / 255.0f; - clearColor(r, g, b, a); - clear(DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT | COLOR_BUFFER_BIT); - - bindFramebuffer(FRAMEBUFFER, 0); - - fboLayerCreated = true; - } - } - - - protected int getReadFramebuffer() { - if (fboLayerInUse) { - return glColorFbo.get(0); - } else { - return 0; - } - } - - - protected int getDrawFramebuffer() { - if (fboLayerInUse) { - if (1 < numSamples) { - return glMultiFbo.get(0); - } else { - return glColorFbo.get(0); - } - } else { - return 0; - } - } - - - protected int getDefaultDrawBuffer() { - if (fboLayerInUse) { - return COLOR_ATTACHMENT0; - } else { - return BACK; - } - } - - - protected int getDefaultReadBuffer() { - if (fboLayerInUse) { - return COLOR_ATTACHMENT0; - } else { - return FRONT; - } - } - - - protected boolean isFBOBacked() { - return fboLayerInUse; - } - - - protected void requestFBOLayer() { - FORCE_SCREEN_FBO = true; - } - - - protected boolean isMultisampled() { - return 1 < numSamples; - } - - - protected int getDepthBits() { - intBuffer.rewind(); - getIntegerv(DEPTH_BITS, intBuffer); - return intBuffer.get(0); - } - - - protected int getStencilBits() { - intBuffer.rewind(); - getIntegerv(STENCIL_BITS, intBuffer); - return intBuffer.get(0); - } - - - protected boolean getDepthTest() { - intBuffer.rewind(); - getBooleanv(DEPTH_TEST, intBuffer); - return intBuffer.get(0) == 0 ? false : true; - } - - - protected boolean getDepthWriteMask() { - intBuffer.rewind(); - getBooleanv(DEPTH_WRITEMASK, intBuffer); - return intBuffer.get(0) == 0 ? false : true; - } - - - protected Texture wrapBackTexture() { - Texture tex = new Texture(); - tex.init(pg.width, pg.height, - glColorTex.get(backTex), TEXTURE_2D, RGBA, - fboWidth, fboHeight, NEAREST, NEAREST, - CLAMP_TO_EDGE, CLAMP_TO_EDGE); - tex.invertedY(true); - tex.colorBuffer(true); - pg.setCache(pg, tex); - return tex; - } - - - protected Texture wrapFrontTexture() { - Texture tex = new Texture(); - tex.init(pg.width, pg.height, - glColorTex.get(frontTex), TEXTURE_2D, RGBA, - fboWidth, fboHeight, NEAREST, NEAREST, - CLAMP_TO_EDGE, CLAMP_TO_EDGE); - tex.invertedY(true); - tex.colorBuffer(true); - return tex; - } - - - protected int getBackTextureName() { - return glColorTex.get(backTex); - } - - - protected int getFrontTextureName() { - return glColorTex.get(frontTex); - } - - - protected void bindFrontTexture() { - if (!texturingIsEnabled(TEXTURE_2D)) { - enableTexturing(TEXTURE_2D); - } - bindTexture(TEXTURE_2D, glColorTex.get(frontTex)); - } - - - protected void unbindFrontTexture() { - if (textureIsBound(TEXTURE_2D, glColorTex.get(frontTex))) { - // We don't want to unbind another texture - // that might be bound instead of this one. - if (!texturingIsEnabled(TEXTURE_2D)) { - enableTexturing(TEXTURE_2D); - bindTexture(TEXTURE_2D, 0); - disableTexturing(TEXTURE_2D); - } else { - bindTexture(TEXTURE_2D, 0); - } - } - } - - - protected void syncBackTexture() { - if (1 < numSamples) { - bindFramebuffer(READ_FRAMEBUFFER, glMultiFbo.get(0)); - bindFramebuffer(DRAW_FRAMEBUFFER, glColorFbo.get(0)); - blitFramebuffer(0, 0, fboWidth, fboHeight, - 0, 0, fboWidth, fboHeight, - COLOR_BUFFER_BIT, NEAREST); - } - } - - - protected int qualityToSamples(int quality) { - if (quality <= 1) { - return 1; - } else { - // Number of samples is always an even number: - int n = 2 * (quality / 2); - return n; - } - } - - /////////////////////////////////////////////////////////// // Frame rendering - protected void beginDraw(boolean clear0) { - if (needFBOLayer(clear0)) { - bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0)); - framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, - TEXTURE_2D, glColorTex.get(backTex), 0); - - if (1 < numSamples) { - bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0)); - } - - if (firstFrame) { - // No need to draw back color buffer because we are in the first frame. - int argb = pg.backgroundColor; - float a = ((argb >> 24) & 0xff) / 255.0f; - float r = ((argb >> 16) & 0xff) / 255.0f; - float g = ((argb >> 8) & 0xff) / 255.0f; - float b = ((argb) & 0xff) / 255.0f; - clearColor(r, g, b, a); - clear(COLOR_BUFFER_BIT); - } else if (!clear0) { - // Render previous back texture (now is the front) as background, - // because no background() is being used ("incremental drawing") - drawTexture(TEXTURE_2D, glColorTex.get(frontTex), - fboWidth, fboHeight, 0, 0, pg.width, pg.height, - 0, 0, pg.width, pg.height); - } - - fboLayerInUse = true; - } else { - fboLayerInUse = false; - } - - if (firstFrame) { - firstFrame = false; - } - - if (!fboLayerByDefault) { - // The result of this assignment is the following: if the user requested - // at some point the use of the FBO layer, but subsequently didn't do - // request it again, then the rendering won't use the FBO layer if not - // needed, since it is slower than simple onscreen rendering. - FORCE_SCREEN_FBO = false; - } - } - - - protected void endDraw(boolean clear0) { - if (fboLayerInUse) { - syncBackTexture(); - - // Draw the contents of the back texture to the screen framebuffer. - bindFramebuffer(FRAMEBUFFER, 0); - - clearDepth(1); - clearColor(0, 0, 0, 0); - clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT); - - // Render current back texture to screen, without blending. - disable(BLEND); - drawTexture(TEXTURE_2D, glColorTex.get(backTex), - fboWidth, fboHeight, 0, 0, pg.width, pg.height, - 0, 0, pg.width, pg.height); - - // Swapping front and back textures. - int temp = frontTex; - frontTex = backTex; - backTex = temp; - } - - // call (gl)finish() only if the rendering of each frame is taking too long, - // to make sure that commands are not accumulating in the GL command queue. - fcount += 1; - int m = pg.parent.millis(); - if (m - lastm > 1000 * fint) { - currentFps = (float)(fcount) / fint; - fcount = 0; - lastm = m; - } - if (currentFps < 0.5f * targetFps) { - finish(); - } - } - - - protected boolean canDraw() { - return pg.initialized && pg.parent.isDisplayable(); - } - + protected void requestFocus() { } + protected void requestDraw() { if (pg.initialized) { @@ -863,1234 +236,96 @@ public class PLWJGL extends PGL { } } - - protected boolean threadIsCurrent() { - return Thread.currentThread() == glThread; + + protected void swapBuffers() { + try { + Display.swapBuffers(); + } catch (LWJGLException e) { + e.printStackTrace(); + } } - protected boolean needFBOLayer(boolean clear0) { - boolean cond = !clear0 || FORCE_SCREEN_FBO || 1 < numSamples; - return cond && glColorFbo.get(0) != 0; + @Override + protected void beginGL() { + if (projMatrix == null) { + projMatrix = allocateFloatBuffer(16); + } + GL11.glMatrixMode(GL11.GL_PROJECTION); + projMatrix.rewind(); + projMatrix.put(pg.projection.m00); + projMatrix.put(pg.projection.m10); + projMatrix.put(pg.projection.m20); + projMatrix.put(pg.projection.m30); + projMatrix.put(pg.projection.m01); + projMatrix.put(pg.projection.m11); + projMatrix.put(pg.projection.m21); + projMatrix.put(pg.projection.m31); + projMatrix.put(pg.projection.m02); + projMatrix.put(pg.projection.m12); + projMatrix.put(pg.projection.m22); + projMatrix.put(pg.projection.m32); + projMatrix.put(pg.projection.m03); + projMatrix.put(pg.projection.m13); + projMatrix.put(pg.projection.m23); + projMatrix.put(pg.projection.m33); + projMatrix.rewind(); + GL11.glLoadMatrix(projMatrix); + + if (mvMatrix == null) { + mvMatrix = allocateFloatBuffer(16); + } + GL11.glMatrixMode(GL11.GL_MODELVIEW); + mvMatrix.rewind(); + mvMatrix.put(pg.modelview.m00); + mvMatrix.put(pg.modelview.m10); + mvMatrix.put(pg.modelview.m20); + mvMatrix.put(pg.modelview.m30); + mvMatrix.put(pg.modelview.m01); + mvMatrix.put(pg.modelview.m11); + mvMatrix.put(pg.modelview.m21); + mvMatrix.put(pg.modelview.m31); + mvMatrix.put(pg.modelview.m02); + mvMatrix.put(pg.modelview.m12); + mvMatrix.put(pg.modelview.m22); + mvMatrix.put(pg.modelview.m32); + mvMatrix.put(pg.modelview.m03); + mvMatrix.put(pg.modelview.m13); + mvMatrix.put(pg.modelview.m23); + mvMatrix.put(pg.modelview.m33); + mvMatrix.rewind(); + GL11.glLoadMatrix(mvMatrix); } - - - /////////////////////////////////////////////////////////// - - // Context interface - - - protected int createEmptyContext() { - return -1; - } - - - protected int getCurrentContext() { - return context; - } - - - /////////////////////////////////////////////////////////// - - // Tessellator interface - - - protected Tessellator createTessellator(TessellatorCallback callback) { - return new Tessellator(callback); - } - - - protected class Tessellator { - protected GLUtessellator tess; - protected TessellatorCallback callback; - protected GLUCallback gluCallback; - - public Tessellator(TessellatorCallback callback) { - this.callback = callback; - tess = GLU.gluNewTess(); - gluCallback = new GLUCallback(); - - tess.gluTessCallback(GLU.GLU_TESS_BEGIN, gluCallback); - tess.gluTessCallback(GLU.GLU_TESS_END, gluCallback); - tess.gluTessCallback(GLU.GLU_TESS_VERTEX, gluCallback); - tess.gluTessCallback(GLU.GLU_TESS_COMBINE, gluCallback); - tess.gluTessCallback(GLU.GLU_TESS_ERROR, gluCallback); - } - - public void beginPolygon() { - tess.gluTessBeginPolygon(null); - } - - public void endPolygon() { - tess.gluTessEndPolygon(); - } - - public void setWindingRule(int rule) { - tess.gluTessProperty(GLU.GLU_TESS_WINDING_RULE, rule); - } - - public void beginContour() { - tess.gluTessBeginContour(); - } - - public void endContour() { - tess.gluTessEndContour(); - } - - public void addVertex(double[] v) { - tess.gluTessVertex(v, 0, v); - } - - protected class GLUCallback extends GLUtessellatorCallbackAdapter { - @Override - public void begin(int type) { - callback.begin(type); - } - - @Override - public void end() { - callback.end(); - } - - @Override - public void vertex(Object data) { - callback.vertex(data); - } - - @Override - public void combine(double[] coords, Object[] data, - float[] weight, Object[] outData) { - callback.combine(coords, data, weight, outData); - } - - @Override - public void error(int errnum) { - callback.error(errnum); - } - } - } - - - protected String tessError(int err) { - return glu.gluErrorString(err); - } - - protected interface TessellatorCallback { - public void begin(int type); - public void end(); - public void vertex(Object data); - public void combine(double[] coords, Object[] data, - float[] weight, Object[] outData); - public void error(int errnum); - } - - + + /////////////////////////////////////////////////////////// // Utility functions - - protected boolean contextIsCurrent(int other) { - return other == -1 || other == context; - } - - - protected void enableTexturing(int target) { - enable(target); - if (target == TEXTURE_2D) { - texturingTargets[0] = true; - } else if (target == TEXTURE_RECTANGLE) { - texturingTargets[1] = true; - } - } - - - protected void disableTexturing(int target) { - disable(target); - if (target == TEXTURE_2D) { - texturingTargets[0] = false; - } else if (target == TEXTURE_RECTANGLE) { - texturingTargets[1] = false; - } - } - - - protected boolean texturingIsEnabled(int target) { - if (target == TEXTURE_2D) { - return texturingTargets[0]; - } else if (target == TEXTURE_RECTANGLE) { - return texturingTargets[1]; - } else { - return false; - } - } - - - protected boolean textureIsBound(int target, int id) { - if (boundTextures == null) return false; - - if (target == TEXTURE_2D) { - return boundTextures[activeTexUnit][0] == id; - } else if (target == TEXTURE_RECTANGLE) { - return boundTextures[activeTexUnit][1] == id; - } else { - return false; - } - - } - - - protected void initTexture(int target, int format, int width, int height) { - initTexture(target, format, width, height, 0); - } - - - protected void initTexture(int target, int format, int width, int height, - int initColor) { - int[] glcolor = new int[16 * 16]; - Arrays.fill(glcolor, javaToNativeARGB(initColor)); - IntBuffer texels = PLWJGL.allocateDirectIntBuffer(16 * 16); - texels.put(glcolor); - texels.rewind(); - for (int y = 0; y < height; y += 16) { - int h = PApplet.min(16, height - y); - for (int x = 0; x < width; x += 16) { - int w = PApplet.min(16, width - x); - texSubImage2D(target, 0, x, y, w, h, format, UNSIGNED_BYTE, texels); - } - } - } - - - protected void copyToTexture(int target, int format, int id, int x, int y, - int w, int h, IntBuffer buffer) { - activeTexture(TEXTURE0); - boolean enabledTex = false; - if (!texturingIsEnabled(target)) { - enableTexturing(target); - enabledTex = true; - } - bindTexture(target, id); - texSubImage2D(target, 0, x, y, w, h, format, UNSIGNED_BYTE, buffer); - bindTexture(target, 0); - if (enabledTex) { - disableTexturing(target); - } - } - - - public void drawTexture(int target, int id, int width, int height, - int X0, int Y0, int X1, int Y1) { - drawTexture(target, id, width, height, X0, Y0, X1, Y1, X0, Y0, X1, Y1); - } - - - public void drawTexture(int target, int id, int width, int height, - int texX0, int texY0, int texX1, int texY1, - int scrX0, int scrY0, int scrX1, int scrY1) { - if (target == TEXTURE_2D) { - drawTexture2D(id, width, height, - texX0, texY0, texX1, texY1, - scrX0, scrY0, scrX1, scrY1); - } else if (target == TEXTURE_RECTANGLE) { - drawTextureRect(id, width, height, - texX0, texY0, texX1, texY1, - scrX0, scrY0, scrX1, scrY1); - } - } - - - protected void drawTexture2D(int id, int width, int height, - int texX0, int texY0, int texX1, int texY1, - int scrX0, int scrY0, int scrX1, int scrY1) { - if (!loadedTex2DShader || tex2DShaderContext != context) { - tex2DVertShader = createShader(VERTEX_SHADER, texVertShaderSource); - tex2DFragShader = createShader(FRAGMENT_SHADER, tex2DFragShaderSource); - if (0 < tex2DVertShader && 0 < tex2DFragShader) { - tex2DShaderProgram = createProgram(tex2DVertShader, tex2DFragShader); - } - if (0 < tex2DShaderProgram) { - tex2DVertLoc = getAttribLocation(tex2DShaderProgram, "inVertex"); - tex2DTCoordLoc = getAttribLocation(tex2DShaderProgram, "inTexcoord"); - } - loadedTex2DShader = true; - tex2DShaderContext = context; - } - - if (texData == null) { - texData = allocateDirectFloatBuffer(texCoords.length); - } - - if (0 < tex2DShaderProgram) { - // The texture overwrites anything drawn earlier. - boolean depthTest = getDepthTest(); - disable(DEPTH_TEST); - - // When drawing the texture we don't write to the - // depth mask, so the texture remains in the background - // and can be occluded by anything drawn later, even if - // if it is behind it. - boolean depthMask = getDepthWriteMask(); - depthMask(false); - - useProgram(tex2DShaderProgram); - - enableVertexAttribArray(tex2DVertLoc); - enableVertexAttribArray(tex2DTCoordLoc); - - // Vertex coordinates of the textured quad are specified - // in normalized screen space (-1, 1): - // Corner 1 - texCoords[ 0] = 2 * (float)scrX0 / pg.width - 1; - texCoords[ 1] = 2 * (float)scrY0 / pg.height - 1; - texCoords[ 2] = (float)texX0 / width; - texCoords[ 3] = (float)texY0 / height; - // Corner 2 - texCoords[ 4] = 2 * (float)scrX1 / pg.width - 1; - texCoords[ 5] = 2 * (float)scrY0 / pg.height - 1; - texCoords[ 6] = (float)texX1 / width; - texCoords[ 7] = (float)texY0 / height; - // Corner 3 - texCoords[ 8] = 2 * (float)scrX0 / pg.width - 1; - texCoords[ 9] = 2 * (float)scrY1 / pg.height - 1; - texCoords[10] = (float)texX0 / width; - texCoords[11] = (float)texY1 / height; - // Corner 4 - texCoords[12] = 2 * (float)scrX1 / pg.width - 1; - texCoords[13] = 2 * (float)scrY1 / pg.height - 1; - texCoords[14] = (float)texX1 / width; - texCoords[15] = (float)texY1 / height; - - texData.rewind(); - texData.put(texCoords); - - activeTexture(TEXTURE0); - boolean enabledTex = false; - if (!texturingIsEnabled(TEXTURE_2D)) { - enableTexturing(TEXTURE_2D); - enabledTex = true; - } - bindTexture(TEXTURE_2D, id); - - bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point. - - texData.position(0); - vertexAttribPointer(tex2DVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, - texData); - texData.position(2); - vertexAttribPointer(tex2DTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, - texData); - - drawArrays(TRIANGLE_STRIP, 0, 4); - - bindTexture(TEXTURE_2D, 0); - if (enabledTex) { - disableTexturing(TEXTURE_2D); - } - - disableVertexAttribArray(tex2DVertLoc); - disableVertexAttribArray(tex2DTCoordLoc); - - useProgram(0); - - if (depthTest) { - enable(DEPTH_TEST); - } else { - disable(DEPTH_TEST); - } - depthMask(depthMask); - } - } - - - protected void drawTextureRect(int id, int width, int height, - int texX0, int texY0, int texX1, int texY1, - int scrX0, int scrY0, int scrX1, int scrY1) { - if (!loadedTexRectShader || texRectShaderContext != context) { - texRectVertShader = createShader(VERTEX_SHADER, texVertShaderSource); - texRectFragShader = createShader(FRAGMENT_SHADER, texRectFragShaderSource); - if (0 < texRectVertShader && 0 < texRectFragShader) { - texRectShaderProgram = createProgram(texRectVertShader, - texRectFragShader); - } - if (0 < texRectShaderProgram) { - texRectVertLoc = getAttribLocation(texRectShaderProgram, "inVertex"); - texRectTCoordLoc = getAttribLocation(texRectShaderProgram, "inTexcoord"); - } - loadedTexRectShader = true; - texRectShaderContext = context; - } - - if (texData == null) { - texData = allocateDirectFloatBuffer(texCoords.length); - } - - if (0 < texRectShaderProgram) { - // The texture overwrites anything drawn earlier. - boolean depthTest = getDepthTest(); - disable(DEPTH_TEST); - - // When drawing the texture we don't write to the - // depth mask, so the texture remains in the background - // and can be occluded by anything drawn later, even if - // if it is behind it. - boolean depthMask = getDepthWriteMask(); - depthMask(false); - - useProgram(texRectShaderProgram); - - enableVertexAttribArray(texRectVertLoc); - enableVertexAttribArray(texRectTCoordLoc); - - // Vertex coordinates of the textured quad are specified - // in normalized screen space (-1, 1): - // Corner 1 - texCoords[ 0] = 2 * (float)scrX0 / pg.width - 1; - texCoords[ 1] = 2 * (float)scrY0 / pg.height - 1; - texCoords[ 2] = texX0; - texCoords[ 3] = texY0; - // Corner 2 - texCoords[ 4] = 2 * (float)scrX1 / pg.width - 1; - texCoords[ 5] = 2 * (float)scrY0 / pg.height - 1; - texCoords[ 6] = texX1; - texCoords[ 7] = texY0; - // Corner 3 - texCoords[ 8] = 2 * (float)scrX0 / pg.width - 1; - texCoords[ 9] = 2 * (float)scrY1 / pg.height - 1; - texCoords[10] = texX0; - texCoords[11] = texY1; - // Corner 4 - texCoords[12] = 2 * (float)scrX1 / pg.width - 1; - texCoords[13] = 2 * (float)scrY1 / pg.height - 1; - texCoords[14] = texX1; - texCoords[15] = texY1; - - texData.rewind(); - texData.put(texCoords); - - activeTexture(TEXTURE0); - boolean enabledTex = false; - if (!texturingIsEnabled(TEXTURE_RECTANGLE)) { - enableTexturing(TEXTURE_RECTANGLE); - enabledTex = true; - } - bindTexture(TEXTURE_RECTANGLE, id); - - bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point. - - texData.position(0); - vertexAttribPointer(texRectVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, - texData); - texData.position(2); - vertexAttribPointer(texRectTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, - texData); - - drawArrays(TRIANGLE_STRIP, 0, 4); - - bindTexture(TEXTURE_RECTANGLE, 0); - if (enabledTex) { - disableTexturing(TEXTURE_RECTANGLE); - } - - disableVertexAttribArray(texRectVertLoc); - disableVertexAttribArray(texRectTCoordLoc); - - useProgram(0); - - if (depthTest) { - enable(DEPTH_TEST); - } else { - disable(DEPTH_TEST); - } - depthMask(depthMask); - } - } - - - protected int getColorValue(int scrX, int scrY) { - if (colorBuffer == null) { - colorBuffer = IntBuffer.allocate(1); - } - colorBuffer.rewind(); - readPixels(scrX, pg.height - scrY - 1, 1, 1, RGBA, UNSIGNED_BYTE, - colorBuffer); - return colorBuffer.get(); - } - - - protected float getDepthValue(int scrX, int scrY) { - if (depthBuffer == null) { - depthBuffer = FloatBuffer.allocate(1); - } - depthBuffer.rewind(); - readPixels(scrX, pg.height - scrY - 1, 1, 1, DEPTH_COMPONENT, FLOAT, - depthBuffer); - return depthBuffer.get(0); - } - - - protected byte getStencilValue(int scrX, int scrY) { - if (stencilBuffer == null) { - stencilBuffer = ByteBuffer.allocate(1); - } - readPixels(scrX, pg.height - scrY - 1, 1, 1, STENCIL_INDEX, - UNSIGNED_BYTE, stencilBuffer); - return stencilBuffer.get(0); - } - - - // bit shifting this might be more efficient - protected static int nextPowerOfTwo(int val) { - int ret = 1; - while (ret < val) { - ret <<= 1; - } - return ret; - } - - - /** - * Converts input native OpenGL value (RGBA on big endian, ABGR on little - * endian) to Java ARGB. - */ - protected static int nativeToJavaARGB(int color) { - if (BIG_ENDIAN) { // RGBA to ARGB - return (color & 0xff000000) | - ((color >> 8) & 0x00ffffff); - } else { // ABGR to ARGB - return (color & 0xff000000) | - ((color << 16) & 0xff0000) | - (color & 0xff00) | - ((color >> 16) & 0xff); - } - } - - - /** - * Converts input array of native OpenGL values (RGBA on big endian, ABGR on - * little endian) representing an image of width x height resolution to Java - * ARGB. It also rearranges the elements in the array so that the image is - * flipped vertically. - */ - protected static void nativeToJavaARGB(int[] pixels, int width, int height) { - int index = 0; - int yindex = (height - 1) * width; - for (int y = 0; y < height / 2; y++) { - if (BIG_ENDIAN) { // RGBA to ARGB - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - pixels[index] = (pixels[yindex] & 0xff000000) | - ((pixels[yindex] >> 8) & 0x00ffffff); - pixels[yindex] = (temp & 0xff000000) | - ((temp >> 8) & 0x00ffffff); - index++; - yindex++; - } - } else { // ABGR to ARGB - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - pixels[index] = (pixels[yindex] & 0xff000000) | - ((pixels[yindex] << 16) & 0xff0000) | - (pixels[yindex] & 0xff00) | - ((pixels[yindex] >> 16) & 0xff); - pixels[yindex] = (temp & 0xff000000) | - ((temp << 16) & 0xff0000) | - (temp & 0xff00) | - ((temp >> 16) & 0xff); - index++; - yindex++; - } - } - yindex -= width * 2; - } - - // Flips image - if ((height % 2) == 1) { - index = (height / 2) * width; - if (BIG_ENDIAN) { // RGBA to ARGB - for (int x = 0; x < width; x++) { - pixels[index] = (pixels[index] & 0xff000000) | - ((pixels[index] >> 8) & 0x00ffffff); - index++; - } - } else { // ABGR to ARGB - for (int x = 0; x < width; x++) { - pixels[index] = (pixels[index] & 0xff000000) | - ((pixels[index] << 16) & 0xff0000) | - (pixels[index] & 0xff00) | - ((pixels[index] >> 16) & 0xff); - index++; - } - } - } - } - - - /** - * Converts input native OpenGL value (RGBA on big endian, ABGR on little - * endian) to Java RGB, so that the alpha component of the result is set - * to opaque (255). - */ - protected static int nativeToJavaRGB(int color) { - if (BIG_ENDIAN) { // RGBA to ARGB - return ((color << 8) & 0xffffff00) | 0xff; - } else { // ABGR to ARGB - return 0xff000000 | ((color << 16) & 0xff0000) | - (color & 0xff00) | - ((color >> 16) & 0xff); - } - } - - - /** - * Converts input array of native OpenGL values (RGBA on big endian, ABGR on - * little endian) representing an image of width x height resolution to Java - * RGB, so that the alpha component of all pixels is set to opaque (255). It - * also rearranges the elements in the array so that the image is flipped - * vertically. - */ - protected static void nativeToJavaRGB(int[] pixels, int width, int height) { - int index = 0; - int yindex = (height - 1) * width; - for (int y = 0; y < height / 2; y++) { - if (BIG_ENDIAN) { // RGBA to ARGB - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - pixels[index] = 0xff000000 | ((pixels[yindex] >> 8) & 0x00ffffff); - pixels[yindex] = 0xff000000 | ((temp >> 8) & 0x00ffffff); - index++; - yindex++; - } - } else { // ABGR to ARGB - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) | - (pixels[yindex] & 0xff00) | - ((pixels[yindex] >> 16) & 0xff); - pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) | - (temp & 0xff00) | - ((temp >> 16) & 0xff); - index++; - yindex++; - } - } - yindex -= width * 2; - } - - // Flips image - if ((height % 2) == 1) { - index = (height / 2) * width; - if (BIG_ENDIAN) { // RGBA to ARGB - for (int x = 0; x < width; x++) { - pixels[index] = 0xff000000 | ((pixels[index] >> 8) & 0x00ffffff); - index++; - } - } else { // ABGR to ARGB - for (int x = 0; x < width; x++) { - pixels[index] = 0xff000000 | ((pixels[index] << 16) & 0xff0000) | - (pixels[index] & 0xff00) | - ((pixels[index] >> 16) & 0xff); - index++; - } - } - } - } - - - /** - * Converts input Java ARGB value to native OpenGL format (RGBA on big endian, - * BGRA on little endian). - */ - protected static int javaToNativeARGB(int color) { - if (BIG_ENDIAN) { // ARGB to RGBA - return ((color >> 24) & 0xff) | - ((color << 8) & 0xffffff00); - } else { // ARGB to ABGR - return (color & 0xff000000) | - ((color << 16) & 0xff0000) | - (color & 0xff00) | - ((color >> 16) & 0xff); - } - } - - - /** - * Converts input array of Java ARGB values representing an image of width x - * height resolution to native OpenGL format (RGBA on big endian, BGRA on - * little endian). It also rearranges the elements in the array so that the - * image is flipped vertically. - */ - protected static void javaToNativeARGB(int[] pixels, int width, int height) { - int index = 0; - int yindex = (height - 1) * width; - for (int y = 0; y < height / 2; y++) { - if (BIG_ENDIAN) { // ARGB to RGBA - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - pixels[index] = ((pixels[yindex] >> 24) & 0xff) | - ((pixels[yindex] << 8) & 0xffffff00); - pixels[yindex] = ((temp >> 24) & 0xff) | - ((temp << 8) & 0xffffff00); - index++; - yindex++; - } - - } else { // ARGB to ABGR - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - pixels[index] = (pixels[yindex] & 0xff000000) | - ((pixels[yindex] << 16) & 0xff0000) | - (pixels[yindex] & 0xff00) | - ((pixels[yindex] >> 16) & 0xff); - pixels[yindex] = (pixels[yindex] & 0xff000000) | - ((temp << 16) & 0xff0000) | - (temp & 0xff00) | - ((temp >> 16) & 0xff); - index++; - yindex++; - } - } - yindex -= width * 2; - } - - // Flips image - if ((height % 2) == 1) { - index = (height / 2) * width; - if (BIG_ENDIAN) { // ARGB to RGBA - for (int x = 0; x < width; x++) { - pixels[index] = ((pixels[index] >> 24) & 0xff) | - ((pixels[index] << 8) & 0xffffff00); - index++; - } - } else { // ARGB to ABGR - for (int x = 0; x < width; x++) { - pixels[index] = (pixels[index] & 0xff000000) | - ((pixels[index] << 16) & 0xff0000) | - (pixels[index] & 0xff00) | - ((pixels[index] >> 16) & 0xff); - index++; - } - } - } - } - - - /** - * Converts input Java ARGB value to native OpenGL format (RGBA on big endian, - * BGRA on little endian), setting alpha component to opaque (255). - */ - protected static int javaToNativeRGB(int color) { - if (BIG_ENDIAN) { // ARGB to RGBA - return ((color << 8) & 0xffffff00) | 0xff; - } else { // ARGB to ABGR - return 0xff000000 | ((color << 16) & 0xff0000) | - (color & 0xff00) | - ((color >> 16) & 0xff); - } - } - - - /** - * Converts input array of Java ARGB values representing an image of width x - * height resolution to native OpenGL format (RGBA on big endian, BGRA on - * little endian), while setting alpha component of all pixels to opaque - * (255). It also rearranges the elements in the array so that the image is - * flipped vertically. - */ - protected static void javaToNativeRGB(int[] pixels, int width, int height) { - int index = 0; - int yindex = (height - 1) * width; - for (int y = 0; y < height / 2; y++) { - if (BIG_ENDIAN) { // ARGB to RGBA - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - pixels[index] = ((pixels[yindex] << 8) & 0xffffff00) | 0xff; - pixels[yindex] = ((temp << 8) & 0xffffff00) | 0xff; - index++; - yindex++; - } - - } else { - for (int x = 0; x < width; x++) { // ARGB to ABGR - int temp = pixels[index]; - pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) | - (pixels[yindex] & 0xff00) | - ((pixels[yindex] >> 16) & 0xff); - pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) | - (temp & 0xff00) | - ((temp >> 16) & 0xff); - index++; - yindex++; - } - } - yindex -= width * 2; - } - - // Flips image - if ((height % 2) == 1) { // ARGB to RGBA - index = (height / 2) * width; - if (BIG_ENDIAN) { - for (int x = 0; x < width; x++) { - pixels[index] = ((pixels[index] << 8) & 0xffffff00) | 0xff; - index++; - } - } else { // ARGB to ABGR - for (int x = 0; x < width; x++) { - pixels[index] = 0xff000000 | ((pixels[index] << 16) & 0xff0000) | - (pixels[index] & 0xff00) | - ((pixels[index] >> 16) & 0xff); - index++; - } - } - } - } - - - protected int createShader(int shaderType, String source) { - int shader = createShader(shaderType); - if (shader != 0) { - shaderSource(shader, source); - compileShader(shader); - if (!compiled(shader)) { - System.err.println("Could not compile shader " + shaderType + ":"); - System.err.println(getShaderInfoLog(shader)); - deleteShader(shader); - shader = 0; - } - } - return shader; - } - - - protected int createProgram(int vertexShader, int fragmentShader) { - int program = createProgram(); - if (program != 0) { - attachShader(program, vertexShader); - attachShader(program, fragmentShader); - linkProgram(program); - if (!linked(program)) { - System.err.println("Could not link program: "); - System.err.println(getProgramInfoLog(program)); - deleteProgram(program); - program = 0; - } - } - return program; - } - - - protected boolean compiled(int shader) { - intBuffer.rewind(); - getShaderiv(shader, COMPILE_STATUS, intBuffer); - return intBuffer.get(0) == 0 ? false : true; - } - - - protected boolean linked(int program) { - intBuffer.rewind(); - getProgramiv(program, LINK_STATUS, intBuffer); - return intBuffer.get(0) == 0 ? false : true; - } - - - protected boolean validateFramebuffer() { - int status = checkFramebufferStatus(FRAMEBUFFER); - if (status == FRAMEBUFFER_COMPLETE) { - return true; - } else if (status == FRAMEBUFFER_INCOMPLETE_ATTACHMENT) { - throw new RuntimeException( - "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT (" + - Integer.toHexString(status) + ")"); - } else if (status == FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) { - throw new RuntimeException( - "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT (" + - Integer.toHexString(status) + ")"); - } else if (status == FRAMEBUFFER_INCOMPLETE_DIMENSIONS) { - throw new RuntimeException("GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS (" + - Integer.toHexString(status) + ")"); - } else if (status == FRAMEBUFFER_INCOMPLETE_FORMATS) { - throw new RuntimeException("GL_FRAMEBUFFER_INCOMPLETE_FORMATS (" + - Integer.toHexString(status) + ")"); - } else if (status == FRAMEBUFFER_UNSUPPORTED) { - throw new RuntimeException("GL_FRAMEBUFFER_UNSUPPORTED" + - Integer.toHexString(status)); - } else { - throw new RuntimeException("unknown framebuffer error (" + - Integer.toHexString(status) + ")"); - } - } - - - protected int[] getGLVersion() { - String version = getString(VERSION).trim(); - int[] res = {0, 0, 0}; - String[] parts = version.split(" "); - for (int i = 0; i < parts.length; i++) { - if (0 < parts[i].indexOf(".")) { - String nums[] = parts[i].split("\\."); - try { - res[0] = Integer.parseInt(nums[0]); - } catch (NumberFormatException e) { } - if (1 < nums.length) { - try { - res[1] = Integer.parseInt(nums[1]); - } catch (NumberFormatException e) { } - } - if (2 < nums.length) { - try { - res[2] = Integer.parseInt(nums[2]); - } catch (NumberFormatException e) { } - } - break; - } - } - return res; - } - - - protected boolean hasFBOs() { - int major = getGLVersion()[0]; - if (major < 2) { - String ext = getString(EXTENSIONS); - return ext.indexOf("_framebuffer_object") != -1; - } - return true; // Assuming FBOs are always available for OpenGL >= 2.0 - } - - - protected boolean hasShaders() { - // GLSL might still be available through extensions. For instance, - // GLContext.hasGLSL() gives false for older intel integrated chipsets on - // OSX, where OpenGL is 1.4 but shaders are available. - int major = getGLVersion()[0]; - if (major < 2) { - String ext = getString(EXTENSIONS); - return ext.indexOf("_fragment_shader") != -1 && - ext.indexOf("_vertex_shader") != -1 && - ext.indexOf("_shader_objects") != -1 && - ext.indexOf("_shading_language") != -1; - } - return true; // Assuming shaders are always available for OpenGL >= 2.0 - } - protected static ByteBuffer allocateDirectByteBuffer(int size) { - int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_BYTE; - return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()); + return BufferUtils.createByteBuffer(size); } - protected static ByteBuffer allocateByteBuffer(int size) { - if (USE_DIRECT_BUFFERS) { - return allocateDirectByteBuffer(size); - } else { - return ByteBuffer.allocate(size); - } + protected static ShortBuffer allocateDirectShortBuffer(int size) { + return BufferUtils.createShortBuffer(size); } - - protected static ByteBuffer allocateByteBuffer(byte[] arr) { - if (USE_DIRECT_BUFFERS) { - return PLWJGL.allocateDirectByteBuffer(arr.length); - } else { - return ByteBuffer.wrap(arr); - } - } - - - protected static ByteBuffer updateByteBuffer(ByteBuffer buf, byte[] arr, - boolean wrap) { - if (USE_DIRECT_BUFFERS) { - if (buf == null || buf.capacity() < arr.length) { - buf = PLWJGL.allocateDirectByteBuffer(arr.length); - } - buf.position(0); - buf.put(arr); - buf.rewind(); - } else { - if (wrap) { - buf = ByteBuffer.wrap(arr); - } else { - if (buf == null || buf.capacity() < arr.length) { - buf = ByteBuffer.allocate(arr.length); - } - buf.position(0); - buf.put(arr); - buf.rewind(); - } - } - return buf; - } - - - protected static void getByteArray(ByteBuffer buf, byte[] arr) { - if (!buf.hasArray() || buf.array() != arr) { - buf.position(0); - buf.get(arr); - buf.rewind(); - } - } - - - protected static void putByteArray(ByteBuffer buf, byte[] arr) { - if (!buf.hasArray() || buf.array() != arr) { - buf.position(0); - buf.put(arr); - buf.rewind(); - } - } - - - protected static void fillByteBuffer(ByteBuffer buf, int i0, int i1, - byte val) { - int n = i1 - i0; - byte[] temp = new byte[n]; - Arrays.fill(temp, 0, n, val); - buf.position(i0); - buf.put(temp, 0, n); - buf.rewind(); - } - - - protected static ShortBuffer allocateDirectShortBuffer(int size) { - int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_SHORT; - return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()). - asShortBuffer(); - } - - - protected static ShortBuffer allocateShortBuffer(int size) { - if (USE_DIRECT_BUFFERS) { - return allocateDirectShortBuffer(size); - } else { - return ShortBuffer.allocate(size); - } - } - - - protected static ShortBuffer allocateShortBuffer(short[] arr) { - if (USE_DIRECT_BUFFERS) { - return PLWJGL.allocateDirectShortBuffer(arr.length); - } else { - return ShortBuffer.wrap(arr); - } - } - - - protected static ShortBuffer updateShortBuffer(ShortBuffer buf, short[] arr, - boolean wrap) { - if (USE_DIRECT_BUFFERS) { - if (buf == null || buf.capacity() < arr.length) { - buf = PLWJGL.allocateDirectShortBuffer(arr.length); - } - buf.position(0); - buf.put(arr); - buf.rewind(); - } else { - if (wrap) { - buf = ShortBuffer.wrap(arr); - } else { - if (buf == null || buf.capacity() < arr.length) { - buf = ShortBuffer.allocate(arr.length); - } - buf.position(0); - buf.put(arr); - buf.rewind(); - } - } - return buf; - } - - - protected static void getShortArray(ShortBuffer buf, short[] arr) { - if (!buf.hasArray() || buf.array() != arr) { - buf.position(0); - buf.get(arr); - buf.rewind(); - } - } - - - protected static void putShortArray(ShortBuffer buf, short[] arr) { - if (!buf.hasArray() || buf.array() != arr) { - buf.position(0); - buf.put(arr); - buf.rewind(); - } - } - - - protected static void fillShortBuffer(ShortBuffer buf, int i0, int i1, - short val) { - int n = i1 - i0; - short[] temp = new short[n]; - Arrays.fill(temp, 0, n, val); - buf.position(i0); - buf.put(temp, 0, n); - buf.rewind(); - } - - + protected static IntBuffer allocateDirectIntBuffer(int size) { - int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_INT; - return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()). - asIntBuffer(); + return BufferUtils.createIntBuffer(size); } - - protected static IntBuffer allocateIntBuffer(int size) { - if (USE_DIRECT_BUFFERS) { - return allocateDirectIntBuffer(size); - } else { - return IntBuffer.allocate(size); - } - } - - - protected static IntBuffer allocateIntBuffer(int[] arr) { - if (USE_DIRECT_BUFFERS) { - return PLWJGL.allocateDirectIntBuffer(arr.length); - } else { - return IntBuffer.wrap(arr); - } - } - - - protected static IntBuffer updateIntBuffer(IntBuffer buf, int[] arr, - boolean wrap) { - if (USE_DIRECT_BUFFERS) { - if (buf == null || buf.capacity() < arr.length) { - buf = PLWJGL.allocateDirectIntBuffer(arr.length); - } - buf.position(0); - buf.put(arr); - buf.rewind(); - } else { - if (wrap) { - buf = IntBuffer.wrap(arr); - } else { - if (buf == null || buf.capacity() < arr.length) { - buf = IntBuffer.allocate(arr.length); - } - buf.position(0); - buf.put(arr); - buf.rewind(); - } - } - return buf; - } - - - protected static void getIntArray(IntBuffer buf, int[] arr) { - if (!buf.hasArray() || buf.array() != arr) { - buf.position(0); - buf.get(arr); - buf.rewind(); - } - } - - - protected static void putIntArray(IntBuffer buf, int[] arr) { - if (!buf.hasArray() || buf.array() != arr) { - buf.position(0); - buf.put(arr); - buf.rewind(); - } - } - - - protected static void fillIntBuffer(IntBuffer buf, int i0, int i1, int val) { - int n = i1 - i0; - int[] temp = new int[n]; - Arrays.fill(temp, 0, n, val); - buf.position(i0); - buf.put(temp, 0, n); - buf.rewind(); - } - - + protected static FloatBuffer allocateDirectFloatBuffer(int size) { - int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_FLOAT; - return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()). - asFloatBuffer(); + return BufferUtils.createFloatBuffer(size); } - - - protected static FloatBuffer allocateFloatBuffer(int size) { - if (USE_DIRECT_BUFFERS) { - return allocateDirectFloatBuffer(size); - } else { - return FloatBuffer.allocate(size); - } - } - - - protected static FloatBuffer allocateFloatBuffer(float[] arr) { - if (USE_DIRECT_BUFFERS) { - return PLWJGL.allocateDirectFloatBuffer(arr.length); - } else { - return FloatBuffer.wrap(arr); - } - } - - - protected static FloatBuffer updateFloatBuffer(FloatBuffer buf, float[] arr, - boolean wrap) { - if (USE_DIRECT_BUFFERS) { - if (buf == null || buf.capacity() < arr.length) { - buf = PLWJGL.allocateDirectFloatBuffer(arr.length); - } - buf.position(0); - buf.put(arr); - buf.rewind(); - } else { - if (wrap) { - buf = FloatBuffer.wrap(arr); - } else { - if (buf == null || buf.capacity() < arr.length) { - buf = FloatBuffer.allocate(arr.length); - } - buf.position(0); - buf.put(arr); - buf.rewind(); - } - } - return buf; - } - - - protected static void getFloatArray(FloatBuffer buf, float[] arr) { - if (!buf.hasArray() || buf.array() != arr) { - buf.position(0); - buf.get(arr); - buf.rewind(); - } - } - - - protected static void putFloatArray(FloatBuffer buf, float[] arr) { - if (!buf.hasArray() || buf.array() != arr) { - buf.position(0); - buf.put(arr); - buf.rewind(); - } - } - - - protected static void fillFloatBuffer(FloatBuffer buf, int i0, int i1, - float val) { - int n = i1 - i0; - float[] temp = new float[n]; - Arrays.fill(temp, 0, n, val); - buf.position(i0); - buf.put(temp, 0, n); - buf.rewind(); - } - - + + /////////////////////////////////////////////////////////// - // Java specific stuff + // LWJGL event handling protected class KeyPoller extends Thread { @@ -2526,14 +761,139 @@ public class PLWJGL extends PGL { return 0; } } - - - - - - + /////////////////////////////////////////////////////////// + + // Tessellator interface + + + protected Tessellator createTessellator(TessellatorCallback callback) { + return new Tessellator(callback); + } + + + protected class Tessellator implements PGL.Tessellator { + protected GLUtessellator tess; + protected TessellatorCallback callback; + protected GLUCallback gluCallback; + + public Tessellator(TessellatorCallback callback) { + this.callback = callback; + tess = GLU.gluNewTess(); + gluCallback = new GLUCallback(); + + tess.gluTessCallback(GLU.GLU_TESS_BEGIN, gluCallback); + tess.gluTessCallback(GLU.GLU_TESS_END, gluCallback); + tess.gluTessCallback(GLU.GLU_TESS_VERTEX, gluCallback); + tess.gluTessCallback(GLU.GLU_TESS_COMBINE, gluCallback); + tess.gluTessCallback(GLU.GLU_TESS_ERROR, gluCallback); + } + + public void beginPolygon() { + tess.gluTessBeginPolygon(null); + } + + public void endPolygon() { + tess.gluTessEndPolygon(); + } + + public void setWindingRule(int rule) { + tess.gluTessProperty(GLU.GLU_TESS_WINDING_RULE, rule); + } + + public void beginContour() { + tess.gluTessBeginContour(); + } + + public void endContour() { + tess.gluTessEndContour(); + } + + public void addVertex(double[] v) { + tess.gluTessVertex(v, 0, v); + } + + protected class GLUCallback extends GLUtessellatorCallbackAdapter { + @Override + public void begin(int type) { + callback.begin(type); + } + + @Override + public void end() { + callback.end(); + } + + @Override + public void vertex(Object data) { + callback.vertex(data); + } + + @Override + public void combine(double[] coords, Object[] data, + float[] weight, Object[] outData) { + callback.combine(coords, data, weight, outData); + } + + @Override + public void error(int errnum) { + callback.error(errnum); + } + } + } + + + protected String tessError(int err) { + return GLU.gluErrorString(err); + } + + + /////////////////////////////////////////////////////////// + + // Font outline + + + static { + SHAPE_TEXT_SUPPORTED = true; + SEG_MOVETO = PathIterator.SEG_MOVETO; + SEG_LINETO = PathIterator.SEG_LINETO; + SEG_QUADTO = PathIterator.SEG_QUADTO; + SEG_CUBICTO = PathIterator.SEG_CUBICTO; + SEG_CLOSE = PathIterator.SEG_CLOSE; + } + + + protected FontOutline createFontOutline(char ch, Object font) { + return new FontOutline(ch, font); + } + + + protected class FontOutline implements PGL.FontOutline { + PathIterator iter; + + public FontOutline(char ch, Object font) { + char textArray[] = new char[] { ch }; + Graphics2D graphics = (Graphics2D) pg.parent.getGraphics(); + FontRenderContext frc = graphics.getFontRenderContext(); + GlyphVector gv = ((Font)font).createGlyphVector(frc, textArray); + Shape shp = gv.getOutline(); + iter = shp.getPathIterator(null); + } + + public boolean isDone() { + return iter.isDone(); + } + + public int currentSegment(float coords[]) { + return iter.currentSegment(coords); + } + + public void next() { + iter.next(); + } + } + /////////////////////////////////////////////////////////// @@ -2902,7 +1262,7 @@ public class PLWJGL extends PGL { } public String errorString(int err) { - return glu.gluErrorString(err); + return GLU.gluErrorString(err); } ////////////////////////////////////////////////////////////////////////////// From ea82da68deb313e4dd57e9ff648a18945f6a527c Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 13 Sep 2013 19:04:55 -0400 Subject: [PATCH 040/556] added registerListeners() method to PGL --- core/src/processing/opengl/PGL.java | 3 ++ core/src/processing/opengl/PJOGL.java | 42 +++++++++++-------- .../lwjgl/src/processing/lwjgl/PLWJGL.java | 16 ++++--- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index cc8962534..e1310dbdd 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -327,6 +327,9 @@ public abstract class PGL { protected abstract void initSurface(int antialias); + protected abstract void registerListeners(); + + protected void deleteSurface() { if (threadIsCurrent() && fboLayerCreated) { deleteTextures(2, glColorTex); diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index 5aa314ff1..a293a850b 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -284,14 +284,8 @@ public class PJOGL extends PGL { pg.parent.add(canvasAWT, BorderLayout.CENTER); canvasAWT.requestFocusInWindow(); - pg.parent.removeListeners(pg.parent); - pg.parent.addListeners(canvasAWT); - canvas = canvasAWT; canvasNEWT = null; - - listener = new PGLListener(); - canvasAWT.addGLEventListener(listener); } else if (WINDOW_TOOLKIT == NEWT) { window = GLWindow.create(caps); canvasNEWT = new NewtCanvasAWT(window); @@ -303,6 +297,28 @@ public class PJOGL extends PGL { pg.parent.add(canvasNEWT, BorderLayout.CENTER); canvasNEWT.requestFocusInWindow(); + canvas = canvasNEWT; + canvasAWT = null; + } + + registerListeners(); + + fboLayerCreated = false; + fboLayerInUse = false; + firstFrame = true; + setFps = false; + } + + + @Override + protected void registerListeners() { + if (WINDOW_TOOLKIT == AWT) { + pg.parent.removeListeners(pg.parent); + pg.parent.addListeners(canvasAWT); + + listener = new PGLListener(); + canvasAWT.addGLEventListener(listener); + } else if (WINDOW_TOOLKIT == NEWT) { if (EVENTS_TOOLKIT == NEWT) { NEWTMouseListener mouseListener = new NEWTMouseListener(); window.addMouseListener(mouseListener); @@ -315,19 +331,11 @@ public class PJOGL extends PGL { pg.parent.addListeners(canvasNEWT); } - canvas = canvasNEWT; - canvasAWT = null; - listener = new PGLListener(); window.addGLEventListener(listener); } canvas.setFocusTraversalKeysEnabled(false); - - fboLayerCreated = false; - fboLayerInUse = false; - firstFrame = true; - setFps = false; } @@ -842,7 +850,7 @@ public class PJOGL extends PGL { pg.parent.postEvent(ke); } - class NEWTWindowListener implements com.jogamp.newt.event.WindowListener { + protected class NEWTWindowListener implements com.jogamp.newt.event.WindowListener { @Override public void windowGainedFocus(com.jogamp.newt.event.WindowEvent arg0) { pg.parent.focusGained(null); @@ -874,7 +882,7 @@ public class PJOGL extends PGL { } // NEWT mouse listener - class NEWTMouseListener extends com.jogamp.newt.event.MouseAdapter { + protected class NEWTMouseListener extends com.jogamp.newt.event.MouseAdapter { @Override public void mousePressed(com.jogamp.newt.event.MouseEvent e) { nativeMouseEvent(e, MouseEvent.PRESS); @@ -910,7 +918,7 @@ public class PJOGL extends PGL { } // NEWT key listener - class NEWTKeyListener extends com.jogamp.newt.event.KeyAdapter { + protected class NEWTKeyListener extends com.jogamp.newt.event.KeyAdapter { @Override public void keyPressed(com.jogamp.newt.event.KeyEvent e) { nativeKeyEvent(e, KeyEvent.PRESS); diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java index e3b54272e..795d5828f 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java @@ -206,12 +206,7 @@ public class PLWJGL extends PGL { glContext = Display.getDrawable().hashCode(); - keyPoller = new KeyPoller(pg.parent); - keyPoller.start(); - - mousePoller = new MousePoller(pg.parent); - mousePoller.start(); - + registerListeners(); fboLayerCreated = false; fboLayerInUse = false; @@ -219,6 +214,15 @@ public class PLWJGL extends PGL { setFps = false; } + + protected void registerListeners() { + keyPoller = new KeyPoller(pg.parent); + keyPoller.start(); + + mousePoller = new MousePoller(pg.parent); + mousePoller.start(); + } + /////////////////////////////////////////////////////////// From fab8555160b786ff07bc0e84921db88b761c6daa Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 13 Sep 2013 19:12:39 -0400 Subject: [PATCH 041/556] check for null canvas --- core/src/processing/opengl/PJOGL.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index a293a850b..f977f4319 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -335,7 +335,9 @@ public class PJOGL extends PGL { window.addGLEventListener(listener); } - canvas.setFocusTraversalKeysEnabled(false); + if (canvas != null) { + canvas.setFocusTraversalKeysEnabled(false); + } } From afd8a66df2483f6daa9840cb6e09e06d362cf800 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 13 Sep 2013 19:25:37 -0400 Subject: [PATCH 042/556] added GLW library for native window output using NEWT --- java/libraries/glw/.classpath | 8 ++ java/libraries/glw/.gitignore | 1 + java/libraries/glw/.project | 17 ++++ java/libraries/glw/build.xml | 31 +++++++ .../glw/examples/BigWindow/BigWindow.pde | 13 +++ .../libraries/glw/src/processing/glw/GLW.java | 6 ++ .../glw/src/processing/glw/PGraphics2D.java | 10 ++ .../glw/src/processing/glw/PGraphics3D.java | 10 ++ .../glw/src/processing/glw/PGraphicsGLW.java | 36 +++++++ .../glw/src/processing/glw/PNEWT.java | 93 +++++++++++++++++++ 10 files changed, 225 insertions(+) create mode 100644 java/libraries/glw/.classpath create mode 100644 java/libraries/glw/.gitignore create mode 100644 java/libraries/glw/.project create mode 100755 java/libraries/glw/build.xml create mode 100644 java/libraries/glw/examples/BigWindow/BigWindow.pde create mode 100644 java/libraries/glw/src/processing/glw/GLW.java create mode 100644 java/libraries/glw/src/processing/glw/PGraphics2D.java create mode 100644 java/libraries/glw/src/processing/glw/PGraphics3D.java create mode 100644 java/libraries/glw/src/processing/glw/PGraphicsGLW.java create mode 100644 java/libraries/glw/src/processing/glw/PNEWT.java diff --git a/java/libraries/glw/.classpath b/java/libraries/glw/.classpath new file mode 100644 index 000000000..614f216d5 --- /dev/null +++ b/java/libraries/glw/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/java/libraries/glw/.gitignore b/java/libraries/glw/.gitignore new file mode 100644 index 000000000..5e56e040e --- /dev/null +++ b/java/libraries/glw/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/java/libraries/glw/.project b/java/libraries/glw/.project new file mode 100644 index 000000000..2a1ccb06f --- /dev/null +++ b/java/libraries/glw/.project @@ -0,0 +1,17 @@ + + + processing-glw + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/java/libraries/glw/build.xml b/java/libraries/glw/build.xml new file mode 100755 index 000000000..d33336574 --- /dev/null +++ b/java/libraries/glw/build.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/libraries/glw/examples/BigWindow/BigWindow.pde b/java/libraries/glw/examples/BigWindow/BigWindow.pde new file mode 100644 index 000000000..8536365f2 --- /dev/null +++ b/java/libraries/glw/examples/BigWindow/BigWindow.pde @@ -0,0 +1,13 @@ +import processing.nwin.*; + +void setup() { + size(2560, 1440, NWin.P2D); + frameRate(180); +} + +void draw() { + background(255, 0, 0); + + fill(255); + text("FPS: " + frameRate, mouseX, mouseY); +} diff --git a/java/libraries/glw/src/processing/glw/GLW.java b/java/libraries/glw/src/processing/glw/GLW.java new file mode 100644 index 000000000..c45805cb6 --- /dev/null +++ b/java/libraries/glw/src/processing/glw/GLW.java @@ -0,0 +1,6 @@ +package processing.glw; + +public interface GLW { + static final String P2D = "processing.glw.PGraphics2D"; + static final String P3D = "processing.glw.PGraphics3D"; +} diff --git a/java/libraries/glw/src/processing/glw/PGraphics2D.java b/java/libraries/glw/src/processing/glw/PGraphics2D.java new file mode 100644 index 000000000..b28f93f31 --- /dev/null +++ b/java/libraries/glw/src/processing/glw/PGraphics2D.java @@ -0,0 +1,10 @@ +package processing.glw; + +import processing.opengl.PGL; +import processing.opengl.PGraphicsOpenGL; + +public class PGraphics2D extends processing.opengl.PGraphics2D { + protected PGL createPGL(PGraphicsOpenGL pg) { + return new PNEWT(pg); + } +} diff --git a/java/libraries/glw/src/processing/glw/PGraphics3D.java b/java/libraries/glw/src/processing/glw/PGraphics3D.java new file mode 100644 index 000000000..c4e011a98 --- /dev/null +++ b/java/libraries/glw/src/processing/glw/PGraphics3D.java @@ -0,0 +1,10 @@ +package processing.glw; + +import processing.opengl.PGL; +import processing.opengl.PGraphicsOpenGL; + +public class PGraphics3D extends processing.opengl.PGraphics3D { + protected PGL createPGL(PGraphicsOpenGL pg) { + return new PNEWT(pg); + } +} diff --git a/java/libraries/glw/src/processing/glw/PGraphicsGLW.java b/java/libraries/glw/src/processing/glw/PGraphicsGLW.java new file mode 100644 index 000000000..d436454c2 --- /dev/null +++ b/java/libraries/glw/src/processing/glw/PGraphicsGLW.java @@ -0,0 +1,36 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2004-12 Ben Fry and Casey Reas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + */ + +package processing.glw; + +import processing.opengl.PGL; +import processing.opengl.PGraphicsOpenGL; + +/** + * LWJGL renderer. + * + */ +public class PGraphicsGLW extends PGraphicsOpenGL { + protected PGL createPGL(PGraphicsOpenGL pg) { + return new PNEWT(pg); + } +} diff --git a/java/libraries/glw/src/processing/glw/PNEWT.java b/java/libraries/glw/src/processing/glw/PNEWT.java new file mode 100644 index 000000000..61922b288 --- /dev/null +++ b/java/libraries/glw/src/processing/glw/PNEWT.java @@ -0,0 +1,93 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2011-12 Ben Fry and Casey Reas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +package processing.glw; + + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; + +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; + +import processing.opengl.PGraphicsOpenGL; +import processing.opengl.PJOGL; + +public class PNEWT extends PJOGL { + + static { + WINDOW_TOOLKIT = NEWT; + EVENTS_TOOLKIT = NEWT; + USE_FBOLAYER_BY_DEFAULT = false; + USE_JOGL_FBOLAYER = false; + } + + + public PNEWT(PGraphicsOpenGL pg) { + super(pg); + } + + + protected void initSurface(int antialias) { + if (profile == null) { + profile = GLProfile.getDefault(); + } else { + window.removeGLEventListener(listener); + pg.parent.remove(canvasNEWT); + } + + // Setting up the desired capabilities; + GLCapabilities caps = new GLCapabilities(profile); + caps.setAlphaBits(REQUESTED_ALPHA_BITS); + caps.setDepthBits(REQUESTED_DEPTH_BITS); + caps.setStencilBits(REQUESTED_STENCIL_BITS); + + if (1 < antialias) { + caps.setSampleBuffers(true); + caps.setNumSamples(antialias); + } else { + caps.setSampleBuffers(false); + } + fboLayerRequested = false; + + window = GLWindow.create(caps); + window.setSize(pg.width, pg.height); + window.setVisible(true); + pg.parent.frame.setVisible(false); + + canvas = canvasNEWT; + canvasAWT = null; + + window.addWindowListener(new WindowAdapter() { + @Override + public void windowDestroyNotify(final WindowEvent e) { + System.exit(0); + } + }); + + registerListeners(); + } + + +} From 7e7a5c465ae3dea2df5ab3b9416bb3ee811704f6 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 13 Sep 2013 19:39:33 -0400 Subject: [PATCH 043/556] updated library name in example --- java/libraries/glw/examples/BigWindow/BigWindow.pde | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/libraries/glw/examples/BigWindow/BigWindow.pde b/java/libraries/glw/examples/BigWindow/BigWindow.pde index 8536365f2..3149b6996 100644 --- a/java/libraries/glw/examples/BigWindow/BigWindow.pde +++ b/java/libraries/glw/examples/BigWindow/BigWindow.pde @@ -1,7 +1,7 @@ -import processing.nwin.*; +import processing.glw.*; void setup() { - size(2560, 1440, NWin.P2D); + size(2560, 1440, GLW.P2D); frameRate(180); } From 3cf2194e8f96e110b859bf151d1a685ecadf1b15 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sun, 15 Sep 2013 17:06:53 -0400 Subject: [PATCH 044/556] fixed classpath in ant build script, ignore library jar --- java/libraries/glw/build.xml | 4 ++-- java/libraries/glw/library/.gitignore | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 java/libraries/glw/library/.gitignore diff --git a/java/libraries/glw/build.xml b/java/libraries/glw/build.xml index d33336574..0b161fe8f 100755 --- a/java/libraries/glw/build.xml +++ b/java/libraries/glw/build.xml @@ -8,7 +8,7 @@ - + @@ -18,7 +18,7 @@ srcdir="src" destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../../../core/library/core.jar" + classpath="../../../core/library/core.jar; ../../../core/library/jogl-all.jar; ../../../core/library/gluegen-rt.jar" nowarn="true" compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> diff --git a/java/libraries/glw/library/.gitignore b/java/libraries/glw/library/.gitignore new file mode 100644 index 000000000..f7094d12e --- /dev/null +++ b/java/libraries/glw/library/.gitignore @@ -0,0 +1 @@ +/glw.jar From 873637e7ae9ae25109fa53f6436c01cdc0677fd9 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 17 Sep 2013 19:34:11 -0400 Subject: [PATCH 045/556] adding a hacked version of appbundler --- build/macosx/appbundler/README.md | 85 ++ build/macosx/appbundler/TODO | 3 + .../oracle/appbundler/AppBundlerTask.class | Bin 0 -> 19734 bytes .../com/oracle/appbundler/Architecture.class | Bin 0 -> 636 bytes .../com/oracle/appbundler/Argument.class | Bin 0 -> 627 bytes .../oracle/appbundler/BundleDocument.class | Bin 0 -> 2801 bytes .../com/oracle/appbundler/GenericApp.icns | Bin 0 -> 142652 bytes .../com/oracle/appbundler/JavaAppLauncher | Bin 0 -> 51136 bytes .../com/oracle/appbundler/Option.class | Bin 0 -> 621 bytes build/macosx/appbundler/build.properties | 28 + build/macosx/appbundler/build.xml | 169 ++++ build/macosx/appbundler/native/main.m | 243 ++++++ .../res/en.lproj/Localizable.strings | 3 + .../com/oracle/appbundler/AppBundlerTask.java | 731 ++++++++++++++++++ .../com/oracle/appbundler/Architecture.java | 45 ++ .../src/com/oracle/appbundler/Argument.java | 48 ++ .../com/oracle/appbundler/BundleDocument.java | 111 +++ .../src/com/oracle/appbundler/GenericApp.icns | Bin 0 -> 142652 bytes .../src/com/oracle/appbundler/Option.java | 47 ++ 19 files changed, 1513 insertions(+) create mode 100644 build/macosx/appbundler/README.md create mode 100644 build/macosx/appbundler/TODO create mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/AppBundlerTask.class create mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/Architecture.class create mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/Argument.class create mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/BundleDocument.class create mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/GenericApp.icns create mode 100755 build/macosx/appbundler/bin/classes/com/oracle/appbundler/JavaAppLauncher create mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/Option.class create mode 100644 build/macosx/appbundler/build.properties create mode 100644 build/macosx/appbundler/build.xml create mode 100644 build/macosx/appbundler/native/main.m create mode 100644 build/macosx/appbundler/res/en.lproj/Localizable.strings create mode 100644 build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java create mode 100644 build/macosx/appbundler/src/com/oracle/appbundler/Architecture.java create mode 100644 build/macosx/appbundler/src/com/oracle/appbundler/Argument.java create mode 100644 build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java create mode 100644 build/macosx/appbundler/src/com/oracle/appbundler/GenericApp.icns create mode 100644 build/macosx/appbundler/src/com/oracle/appbundler/Option.java diff --git a/build/macosx/appbundler/README.md b/build/macosx/appbundler/README.md new file mode 100644 index 000000000..cd3eabc84 --- /dev/null +++ b/build/macosx/appbundler/README.md @@ -0,0 +1,85 @@ +appbundler +============= + +A fork of the [Java Application Bundler](https://svn.java.net/svn/appbundler~svn) +with the following changes: + +- The native binary is created as universal (32/64) +- Fixes [icon not showing bug](http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7159381) in `JavaAppLauncher` +- Adds `LC_CTYPE` environment variable to the `Info.plist` file in order to fix an [issue with `File.exists()` in OpenJDK 7](http://java.net/jira/browse/MACOSX_PORT-165) **(Contributed by Steve Hannah)** +- Allows to specify the name of the executable instead of using the default `"JavaAppLauncher"` **(contributed by Karl von Randow)** +- Adds `classpathref` support to the `bundleapp` task +- Adds support for `JVMArchs` and `LSArchitecturePriority` keys +- Allows to specify a custom value for `CFBundleVersion` +- Allows specifying registered file extensions using `CFBundleDocumentTypes` +- Passes to the Java application a set of environment variables with the paths of + the OSX special folders and whether the application is running in the + sandbox (see below). + +These are the environment variables passed to the JVM: + +- `LibraryDirectory` +- `DocumentsDirectory` +- `CachesDirectory` +- `ApplicationSupportDirectory` +- `SandboxEnabled` (the String `true` or `false`) + + +Example: + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/macosx/appbundler/TODO b/build/macosx/appbundler/TODO new file mode 100644 index 000000000..270d3e950 --- /dev/null +++ b/build/macosx/appbundler/TODO @@ -0,0 +1,3 @@ +- Architectures should be automatically inferred from the embedded JVM +- It makes more sense to take as input a JRE instead of taking a JDK and strip + it until it becomes a JRE... diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/AppBundlerTask.class b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/AppBundlerTask.class new file mode 100644 index 0000000000000000000000000000000000000000..aeeb36b758bffed48947702b7bfd7fad9871e771 GIT binary patch literal 19734 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 F{{yJnD02V+ literal 0 HcmV?d00001 diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Architecture.class b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Architecture.class new file mode 100644 index 0000000000000000000000000000000000000000..d6f39ccd3a9c830c1bea382fe2da20e39a2f453d GIT binary patch literal 636 zcma)&%}T>i5QWc8)1-~n{@7OCC>GH+1+#D?CF5z!zaskb}pSoGzWpwa&QU*Z*_ASGuohCv)U z;>MM9)zwv}@|h**D3p+g#?bm3kD>B&oLhTF&^V+Us&rEZMfy;tQckw?EmCz(eMZqR zU%*WE4CRq31%~WV1omm-02`E*QYFPrsu;FV&Ri^t(j{*`L3yAgHPDh~Yh^h9JzPOG n8}5->F4D~In)SzoeUdmdQ&r|b`s6`!aqWK~-L)Xw32yxpvK?;7 literal 0 HcmV?d00001 diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Argument.class b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Argument.class new file mode 100644 index 0000000000000000000000000000000000000000..586b79c340b7c9c5e3ad22497a7a84a204ebed52 GIT binary patch literal 627 zcma)&%}T>S6ot>ENt(vi*4kFxhzdd*p;@>Ql!6GZiY_YMPtqZ#q)ADWK9_@sLe9;AYyIh^t(w*ww}_9%({ z&^u?)FZ|F?1`MTcZ_J=xMH7`g{RP9p(2Ztx z6mvHaHlNR(G@Jw?wl8BZory4^HHIgWagNdI_SS(Ii`J zlCAc&s4qWQMHxmF8gz#Jzrh$9-zT|srov5dNT*ZjlnjdWpiHHlEa|OKbw+(g(X?K` zEcOiLktzkI>`??cs5rs~Wz}3su|^fcChCQYO;NgN))SNmN^%1|Yaag?)>gv}Y!$-; kQp-iUb+TrCkFc%Gp_8i$2hwLBl8c-F1L>~?+0JlVpF(?UWdHyG literal 0 HcmV?d00001 diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/BundleDocument.class b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/BundleDocument.class new file mode 100644 index 0000000000000000000000000000000000000000..1be4d79850f2356e969f0388accc607b5ffb4cec GIT binary patch literal 2801 zcma)7T~iZh6n-|@upulT1`x!mRINaQ#`;06SkNF^T0kp;MXK#4*@nerH*Pk5^?Rm& zqPM;ArWfr@37tA)@9IqdM?3uqUTL4R8v=$n)5*+x-uK;ep7ZsbH-EkO{V9Nx_%4P) zEJSg=6$h{w#gfPyvV1Jdattxtj9~?zXt*VZ+ZsNN;M4%}r$1k0; zmTk^giW$?rZe+wmeAdYtg(btaN7Lb*L5}RaVw`0^Wd&`)=7Q@Q4;6$~rWCZ7O>cTz z=Dp28nOtkVJWSMZ-NO_G)22{n2xW28QCBI?S`uLUg2!^r86`hu4M!AcbT{MITXyq) zb7XhTZ-p*jw`$y3uXoThn&&sodxo2)Dhf4J?gG?y?p{rCq-lG#Rihll#(uKBQP0`* ztFTjhc9b??w_+5^ zGkM!_&A?I9QIThXV{Fp~qX&CDdOSR#?!Ko2?7h?iznrnce5>ahuX0=#q`FGn=N8z4{O@!l$S|A4jxxu`ux zw9dq!FLA$?m&m%y=)ny3;KOZx2I_tW=wJLuja7ttRPOoEa24{WD24nH(xPRHhb{i) zybl=AI#L5vzLcTI>=f!@gj<>yrn&5=|!3l6O+iDodXYnZ3Jj-nr=OmUiDgDF1F*$JljBx3<>^D{ ZCFvZ|a7Dvaf0%*id=eCV#LppI`wtR(^3MPO literal 0 HcmV?d00001 diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/GenericApp.icns b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/GenericApp.icns new file mode 100644 index 0000000000000000000000000000000000000000..20d16f39ac790026befe19a7fb6789c98e7ca03b GIT binary patch literal 142652 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 literal 0 HcmV?d00001 diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Option.class b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Option.class new file mode 100644 index 0000000000000000000000000000000000000000..aa4a23818e34881c79f078922039f4c32df4f7a9 GIT binary patch literal 621 zcma)2T}#4H7=Dg!b52V$wStI*F6N?k(M?cz6LckcVR(Nw4|Zg3GB;;7< znhLPgjw*0Wj1DT)RdXcOEt(j%QKMI>xKx#j?mVOLNKGzaWXqEuWPMGpV`oL~5n34; h&glkwn__n}g?5fwDG)yUkTP!kFUZ-(AiG)I<`)a + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/macosx/appbundler/native/main.m b/build/macosx/appbundler/native/main.m new file mode 100644 index 000000000..55bcfa917 --- /dev/null +++ b/build/macosx/appbundler/native/main.m @@ -0,0 +1,243 @@ +/* + * Copyright 2012, Oracle and/or its affiliates. All rights reserved. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#import +#include +#include + +#define JAVA_LAUNCH_ERROR "JavaLaunchError" + +#define JVM_RUNTIME_KEY "JVMRuntime" +#define WORKING_DIR "WorkingDirectory" +#define JVM_MAIN_CLASS_NAME_KEY "JVMMainClassName" +#define JVM_OPTIONS_KEY "JVMOptions" +#define JVM_ARGUMENTS_KEY "JVMArguments" + +#define JVM_RUN_PRIVILEGED "JVMRunPrivileged" + +#define UNSPECIFIED_ERROR "An unknown error occurred." + +#define APP_ROOT_PREFIX "$APP_ROOT" + +#define LIBJLI_DYLIB "/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/jli/libjli.dylib" + +typedef int (JNICALL *JLI_Launch_t)(int argc, char ** argv, + int jargc, const char** jargv, + int appclassc, const char** appclassv, + const char* fullversion, + const char* dotversion, + const char* pname, + const char* lname, + jboolean javaargs, + jboolean cpwildcard, + jboolean javaw, + jint ergo); + +int launch(char *); + +int main(int argc, char *argv[]) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + int result; + @try { + launch(argv[0]); + result = 0; + } @catch (NSException *exception) { + NSAlert *alert = [[NSAlert alloc] init]; + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert setMessageText:[exception reason]]; + [alert runModal]; + + result = 1; + } + + [pool drain]; + + return result; +} + +int launch(char *commandName) { + // Get the main bundle + NSBundle *mainBundle = [NSBundle mainBundle]; + + // Get the main bundle's info dictionary + NSDictionary *infoDictionary = [mainBundle infoDictionary]; + + // Set the working directory based on config, defaulting to the user's home directory + NSString *workingDir = [infoDictionary objectForKey:@WORKING_DIR]; + if (workingDir != nil) { + workingDir = [workingDir stringByReplacingOccurrencesOfString:@APP_ROOT_PREFIX withString:[mainBundle bundlePath]]; + } else { + workingDir = NSHomeDirectory(); + } + + chdir([workingDir UTF8String]); + + // execute privileged + NSString *privileged = [infoDictionary objectForKey:@JVM_RUN_PRIVILEGED]; + if ( privileged != nil && getuid() != 0 ) { + NSDictionary *error = [NSDictionary new]; + NSString *script = [NSString stringWithFormat:@"do shell script \"\\\"%@\\\" > /dev/null 2>&1 &\" with administrator privileges", [NSString stringWithCString:commandName encoding:NSASCIIStringEncoding]]; + NSAppleScript *appleScript = [[NSAppleScript new] initWithSource:script]; + if ([appleScript executeAndReturnError:&error]) { + // This means we successfully elevated the application and can stop in here. + return; + } + } + + // Locate the JLI_Launch() function + NSString *runtime = [infoDictionary objectForKey:@JVM_RUNTIME_KEY]; + + const char *libjliPath = NULL; + if (runtime != nil) { + NSString *runtimePath = [[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:runtime]; + libjliPath = [[runtimePath stringByAppendingPathComponent:@"Contents/Home/jre/lib/jli/libjli.dylib"] fileSystemRepresentation]; + } else { + libjliPath = LIBJLI_DYLIB; + } + + void *libJLI = dlopen(libjliPath, RTLD_LAZY); + + JLI_Launch_t jli_LaunchFxnPtr = NULL; + if (libJLI != NULL) { + jli_LaunchFxnPtr = dlsym(libJLI, "JLI_Launch"); + } + + if (jli_LaunchFxnPtr == NULL) { + [[NSException exceptionWithName:@JAVA_LAUNCH_ERROR + reason:NSLocalizedString(@"JRELoadError", @UNSPECIFIED_ERROR) + userInfo:nil] raise]; + } + + // Get the main class name + NSString *mainClassName = [infoDictionary objectForKey:@JVM_MAIN_CLASS_NAME_KEY]; + if (mainClassName == nil) { + [[NSException exceptionWithName:@JAVA_LAUNCH_ERROR + reason:NSLocalizedString(@"MainClassNameRequired", @UNSPECIFIED_ERROR) + userInfo:nil] raise]; + } + + // Set the class path + NSString *mainBundlePath = [mainBundle bundlePath]; + NSString *javaPath = [mainBundlePath stringByAppendingString:@"/Contents/Java"]; + NSMutableString *classPath = [NSMutableString stringWithFormat:@"-Djava.class.path=%@/Classes", javaPath]; + + NSFileManager *defaultFileManager = [NSFileManager defaultManager]; + NSArray *javaDirectoryContents = [defaultFileManager contentsOfDirectoryAtPath:javaPath error:nil]; + if (javaDirectoryContents == nil) { + [[NSException exceptionWithName:@JAVA_LAUNCH_ERROR + reason:NSLocalizedString(@"JavaDirectoryNotFound", @UNSPECIFIED_ERROR) + userInfo:nil] raise]; + } + + for (NSString *file in javaDirectoryContents) { + if ([file hasSuffix:@".jar"]) { + [classPath appendFormat:@":%@/%@", javaPath, file]; + } + } + + // Set the library path + NSString *libraryPath = [NSString stringWithFormat:@"-Djava.library.path=%@/Contents/MacOS", mainBundlePath]; + + // Get the VM options + NSArray *options = [infoDictionary objectForKey:@JVM_OPTIONS_KEY]; + if (options == nil) { + options = [NSArray array]; + } + + // Get the application arguments + NSArray *arguments = [infoDictionary objectForKey:@JVM_ARGUMENTS_KEY]; + if (arguments == nil) { + arguments = [NSArray array]; + } + + // Set OSX special folders + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, + NSUserDomainMask, YES); + NSString *basePath = [paths objectAtIndex:0]; + NSString *libraryDirectory = [NSString stringWithFormat:@"-DLibraryDirectory=%@", basePath]; + + paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, + NSUserDomainMask, YES); + basePath = [paths objectAtIndex:0]; + NSString *documentsDirectory = [NSString stringWithFormat:@"-DDocumentsDirectory=%@", basePath]; + + paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, + NSUserDomainMask, YES); + basePath = [paths objectAtIndex:0]; + NSString *applicationSupportDirectory = [NSString stringWithFormat:@"-DApplicationSupportDirectory=%@", basePath]; + + paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, + NSUserDomainMask, YES); + basePath = [paths objectAtIndex:0]; + NSString *cachesDirectory = [NSString stringWithFormat:@"-DCachesDirectory=%@", basePath]; + + NSString *sandboxEnabled = @"true"; + if ([basePath rangeOfString:@"Containers"].location == NSNotFound) { + sandboxEnabled = @"false"; + } + NSString *sandboxEnabledVar = [NSString stringWithFormat:@"-DSandboxEnabled=%@", sandboxEnabled]; + + // Initialize the arguments to JLI_Launch() + // +5 due to the special directories and the sandbox enabled property + int argc = 1 + [options count] + 2 + [arguments count] + 1 + 5; + char *argv[argc]; + + int i = 0; + argv[i++] = commandName; + argv[i++] = strdup([classPath UTF8String]); + argv[i++] = strdup([libraryPath UTF8String]); + argv[i++] = strdup([libraryDirectory UTF8String]); + argv[i++] = strdup([documentsDirectory UTF8String]); + argv[i++] = strdup([applicationSupportDirectory UTF8String]); + argv[i++] = strdup([cachesDirectory UTF8String]); + argv[i++] = strdup([sandboxEnabledVar UTF8String]); + + for (NSString *option in options) { + option = [option stringByReplacingOccurrencesOfString:@APP_ROOT_PREFIX withString:[mainBundle bundlePath]]; + argv[i++] = strdup([option UTF8String]); + } + + argv[i++] = strdup([mainClassName UTF8String]); + + for (NSString *argument in arguments) { + argument = [argument stringByReplacingOccurrencesOfString:@APP_ROOT_PREFIX withString:[mainBundle bundlePath]]; + argv[i++] = strdup([argument UTF8String]); + } + + // Invoke JLI_Launch() + return jli_LaunchFxnPtr(argc, argv, + 0, NULL, + 0, NULL, + "", + "", + "java", + "java", + FALSE, + FALSE, + FALSE, + 0); +} diff --git a/build/macosx/appbundler/res/en.lproj/Localizable.strings b/build/macosx/appbundler/res/en.lproj/Localizable.strings new file mode 100644 index 000000000..0d306aaaf --- /dev/null +++ b/build/macosx/appbundler/res/en.lproj/Localizable.strings @@ -0,0 +1,3 @@ +"JRELoadError" = "Unable to load Java Runtime Environment."; +"MainClassNameRequired" = "Main class name is required."; +"JavaDirectoryNotFound" = "Unable to enumerate Java directory contents."; diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java new file mode 100644 index 000000000..ef9121223 --- /dev/null +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -0,0 +1,731 @@ +/* + * Copyright 2012, Oracle and/or its affiliates. All rights reserved. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.appbundler; + +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Writer; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.Reference; +import org.apache.tools.ant.types.resources.FileResource; + +/** + * App bundler Ant task. + */ +public class AppBundlerTask extends Task { + // Output folder for generated bundle + private File outputDirectory = null; + + // General bundle properties + private String name = null; + private String displayName = null; + private String identifier = null; + private File icon = null; + private String executableName = EXECUTABLE_NAME; + + private String shortVersion = "1.0"; + private String version = "1.0"; + private String signature = "????"; + private String copyright = ""; + private String privileged = null; + private String workingDirectory = null; + + private String applicationCategory = null; + + private boolean highResolutionCapable = true; + + // JVM info properties + private String mainClassName = null; + private FileSet runtime = null; + private ArrayList classPath = new ArrayList<>(); + private ArrayList libraryPath = new ArrayList<>(); + private ArrayList options = new ArrayList<>(); + private ArrayList arguments = new ArrayList<>(); + private ArrayList architectures = new ArrayList<>(); + private ArrayList bundleDocuments = new ArrayList<>(); + + private Reference classPathRef; + + private static final String EXECUTABLE_NAME = "JavaAppLauncher"; + private static final String DEFAULT_ICON_NAME = "GenericApp.icns"; + private static final String OS_TYPE_CODE = "APPL"; + + private static final String PLIST_DTD = ""; + private static final String PLIST_TAG = "plist"; + private static final String PLIST_VERSION_ATTRIBUTE = "version"; + private static final String DICT_TAG = "dict"; + private static final String KEY_TAG = "key"; + private static final String ARRAY_TAG = "array"; + private static final String STRING_TAG = "string"; + + private static final int BUFFER_SIZE = 2048; + + public void setOutputDirectory(File outputDirectory) { + this.outputDirectory = outputDirectory; + } + + public void setName(String name) { + this.name = name; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public void setIcon(File icon) { + this.icon = icon; + } + + public void setExecutableName(String executable) { + this.executableName = executable; + } + + public void setShortVersion(String shortVersion) { + this.shortVersion = shortVersion; + } + + public void setVersion(String version) { + this.version = version; + } + + public void setSignature(String signature) { + this.signature = signature; + } + + public void setCopyright(String copyright) { + this.copyright = copyright; + } + + public void setPrivileged(String privileged) { + this.privileged = privileged; + } + + public void setWorkingDirectory(String workingDirectory) { + this.workingDirectory = workingDirectory; + } + + public void setApplicationCategory(String applicationCategory) { + this.applicationCategory = applicationCategory; + } + + public void setHighResolutionCapable(boolean highResolutionCapable) { + this.highResolutionCapable = highResolutionCapable; + } + + public void setMainClassName(String mainClassName) { + this.mainClassName = mainClassName; + } + + public void addConfiguredRuntime(FileSet runtime) throws BuildException { + if (this.runtime != null) { + throw new BuildException("Runtime already specified."); + } + + this.runtime = runtime; + + runtime.appendIncludes(new String[] { + "jre/", + }); + + runtime.appendExcludes(new String[] { + "bin/", + "jre/bin/", + "jre/lib/deploy/", + "jre/lib/deploy.jar", + "jre/lib/javaws.jar", + "jre/lib/libdeploy.dylib", + "jre/lib/libnpjp2.dylib", + "jre/lib/plugin.jar", + "jre/lib/security/javaws.policy" + }); + } + + public void setClasspathRef(Reference ref) { + this.classPathRef = ref; + } + + public void addConfiguredClassPath(FileSet classPath) { + this.classPath.add(classPath); + } + + public void addConfiguredLibraryPath(FileSet libraryPath) { + this.libraryPath.add(libraryPath); + } + + public void addConfiguredBundleDocument(BundleDocument document) { + this.bundleDocuments.add(document); + } + + public void addConfiguredOption(Option option) throws BuildException { + String value = option.getValue(); + + if (value == null) { + throw new BuildException("Value is required."); + } + + options.add(value); + } + + public void addConfiguredArgument(Argument argument) throws BuildException { + String value = argument.getValue(); + + if (value == null) { + throw new BuildException("Value is required."); + } + + arguments.add(value); + } + + public void addConfiguredArch(Architecture architecture) throws BuildException { + String name = architecture.getName(); + + if (name == null) { + throw new BuildException("Name is required."); + } + + architectures.add(name); + } + + @Override + public void execute() throws BuildException { + // Validate required properties + if (outputDirectory == null) { + throw new IllegalStateException("Output directory is required."); + } + + if (!outputDirectory.exists()) { + throw new IllegalStateException("Output directory does not exist."); + } + + if (!outputDirectory.isDirectory()) { + throw new IllegalStateException("Invalid output directory."); + } + + if (name == null) { + throw new IllegalStateException("Name is required."); + } + + if (displayName == null) { + throw new IllegalStateException("Display name is required."); + } + + if (identifier == null) { + throw new IllegalStateException("Identifier is required."); + } + + if (icon != null) { + if (!icon.exists()) { + throw new IllegalStateException("Icon does not exist."); + } + + if (icon.isDirectory()) { + throw new IllegalStateException("Invalid icon."); + } + } + + if (shortVersion == null) { + throw new IllegalStateException("Short version is required."); + } + + if (signature == null) { + throw new IllegalStateException("Signature is required."); + } + + if (signature.length() != 4) { + throw new IllegalStateException("Invalid signature."); + } + + if (copyright == null) { + throw new IllegalStateException("Copyright is required."); + } + + if (mainClassName == null) { + throw new IllegalStateException("Main class name is required."); + } + + // Create the app bundle + try { + System.out.println("Creating app bundle: " + name); + + // Create directory structure + File rootDirectory = new File(outputDirectory, name + ".app"); + delete(rootDirectory); + rootDirectory.mkdir(); + + File contentsDirectory = new File(rootDirectory, "Contents"); + contentsDirectory.mkdir(); + + File macOSDirectory = new File(contentsDirectory, "MacOS"); + macOSDirectory.mkdir(); + + File javaDirectory = new File(contentsDirectory, "Java"); + javaDirectory.mkdir(); + + File plugInsDirectory = new File(contentsDirectory, "PlugIns"); + plugInsDirectory.mkdir(); + + File resourcesDirectory = new File(contentsDirectory, "Resources"); + resourcesDirectory.mkdir(); + + // Generate Info.plist + File infoPlistFile = new File(contentsDirectory, "Info.plist"); + infoPlistFile.createNewFile(); + writeInfoPlist(infoPlistFile); + + // Generate PkgInfo + File pkgInfoFile = new File(contentsDirectory, "PkgInfo"); + pkgInfoFile.createNewFile(); + writePkgInfo(pkgInfoFile); + + // Copy executable to MacOS folder + File executableFile = new File(macOSDirectory, executableName); + copy(getClass().getResource(EXECUTABLE_NAME), executableFile); + + executableFile.setExecutable(true, false); + + // Copy localized resources to Resources folder + copyResources(resourcesDirectory); + + // Copy runtime to PlugIns folder + copyRuntime(plugInsDirectory); + + // Copy class path entries to Java folder + copyClassPathEntries(javaDirectory); + + // Copy class path ref entries to Java folder + copyClassPathRefEntries(javaDirectory); + + // Copy library path entries to MacOS folder + copyLibraryPathEntries(macOSDirectory); + + // Copy icon to Resources folder + copyIcon(resourcesDirectory); + } catch (IOException exception) { + throw new BuildException(exception); + } + } + + private void copyResources(File resourcesDirectory) throws IOException { + // Unzip res.zip into resources directory + InputStream inputStream = getClass().getResourceAsStream("res.zip"); + ZipInputStream zipInputStream = new ZipInputStream(inputStream); + + try { + ZipEntry zipEntry = zipInputStream.getNextEntry(); + while (zipEntry != null) { + File file = new File(resourcesDirectory, zipEntry.getName()); + + if (zipEntry.isDirectory()) { + file.mkdir(); + } else { + OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE); + + try { + int b = zipInputStream.read(); + while (b != -1) { + outputStream.write(b); + b = zipInputStream.read(); + } + + outputStream.flush(); + } finally { + outputStream.close(); + } + + } + + zipEntry = zipInputStream.getNextEntry(); + } + } finally { + zipInputStream.close(); + } + } + + private void copyRuntime(File plugInsDirectory) throws IOException { + if (runtime != null) { + File runtimeHomeDirectory = runtime.getDir(); + File runtimeContentsDirectory = runtimeHomeDirectory.getParentFile(); + File runtimeDirectory = runtimeContentsDirectory.getParentFile(); + + // Create root plug-in directory + File pluginDirectory = new File(plugInsDirectory, runtimeDirectory.getName()); + pluginDirectory.mkdir(); + + // Create Contents directory + File pluginContentsDirectory = new File(pluginDirectory, runtimeContentsDirectory.getName()); + pluginContentsDirectory.mkdir(); + + // Copy MacOS directory + File runtimeMacOSDirectory = new File(runtimeContentsDirectory, "MacOS"); + copy(runtimeMacOSDirectory, new File(pluginContentsDirectory, runtimeMacOSDirectory.getName())); + + // Copy Info.plist file + File runtimeInfoPlistFile = new File(runtimeContentsDirectory, "Info.plist"); + copy(runtimeInfoPlistFile, new File(pluginContentsDirectory, runtimeInfoPlistFile.getName())); + + // Copy included contents of Home directory + File pluginHomeDirectory = new File(pluginContentsDirectory, runtimeHomeDirectory.getName()); + + DirectoryScanner directoryScanner = runtime.getDirectoryScanner(getProject()); + String[] includedFiles = directoryScanner.getIncludedFiles(); + + for (int i = 0; i < includedFiles.length; i++) { + String includedFile = includedFiles[i]; + File source = new File(runtimeHomeDirectory, includedFile); + File destination = new File(pluginHomeDirectory, includedFile); + copy(source, destination); + } + } + } + + private void copyClassPathRefEntries(File javaDirectory) throws IOException { + if(classPathRef != null) { + org.apache.tools.ant.types.Path classpath = + (org.apache.tools.ant.types.Path) classPathRef.getReferencedObject(getProject()); + + Iterator iter = (Iterator)(Object)classpath.iterator(); + while(iter.hasNext()) { + FileResource resource = iter.next(); + File source = resource.getFile(); + File destination = new File(javaDirectory, source.getName()); + copy(source, destination); + } + } + } + + private void copyClassPathEntries(File javaDirectory) throws IOException { + for (FileSet fileSet : classPath) { + File classPathDirectory = fileSet.getDir(); + DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject()); + String[] includedFiles = directoryScanner.getIncludedFiles(); + + for (int i = 0; i < includedFiles.length; i++) { + String includedFile = includedFiles[i]; + File source = new File(classPathDirectory, includedFile); + File destination = new File(javaDirectory, new File(includedFile).getName()); + copy(source, destination); + } + } + } + + private void copyLibraryPathEntries(File macOSDirectory) throws IOException { + for (FileSet fileSet : libraryPath) { + File libraryPathDirectory = fileSet.getDir(); + DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject()); + String[] includedFiles = directoryScanner.getIncludedFiles(); + + for (int i = 0; i < includedFiles.length; i++) { + String includedFile = includedFiles[i]; + File source = new File(libraryPathDirectory, includedFile); + File destination = new File(macOSDirectory, new File(includedFile).getName()); + copy(source, destination); + } + } + } + + private void copyIcon(File resourcesDirectory) throws IOException { + if (icon == null) { + copy(getClass().getResource(DEFAULT_ICON_NAME), new File(resourcesDirectory, DEFAULT_ICON_NAME)); + } else { + copy(icon, new File(resourcesDirectory, icon.getName())); + } + } + + private void writeInfoPlist(File file) throws IOException { + Writer out = new BufferedWriter(new FileWriter(file)); + XMLOutputFactory output = XMLOutputFactory.newInstance(); + + try { + XMLStreamWriter xout = output.createXMLStreamWriter(out); + + // Write XML declaration + xout.writeStartDocument(); + xout.writeCharacters("\n"); + + // Write plist DTD declaration + xout.writeDTD(PLIST_DTD); + xout.writeCharacters("\n"); + + // Begin root element + xout.writeStartElement(PLIST_TAG); + xout.writeAttribute(PLIST_VERSION_ATTRIBUTE, "1.0"); + xout.writeCharacters("\n"); + + // Begin root dictionary + xout.writeStartElement(DICT_TAG); + xout.writeCharacters("\n"); + + // Write bundle properties + writeProperty(xout, "CFBundleDevelopmentRegion", "English"); + writeProperty(xout, "CFBundleExecutable", executableName); + writeProperty(xout, "CFBundleIconFile", (icon == null) ? DEFAULT_ICON_NAME : icon.getName()); + writeProperty(xout, "CFBundleIdentifier", identifier); + writeProperty(xout, "CFBundleDisplayName", displayName); + writeProperty(xout, "CFBundleInfoDictionaryVersion", "6.0"); + writeProperty(xout, "CFBundleName", name); + writeProperty(xout, "CFBundlePackageType", OS_TYPE_CODE); + writeProperty(xout, "CFBundleShortVersionString", shortVersion); + writeProperty(xout, "CFBundleVersion", version); + writeProperty(xout, "CFBundleSignature", signature); + writeProperty(xout, "NSHumanReadableCopyright", copyright); + + if (applicationCategory != null) { + writeProperty(xout, "LSApplicationCategoryType", applicationCategory); + } + + if (highResolutionCapable) { + writeKey(xout, "NSHighResolutionCapable"); + writeBoolean(xout, true); + xout.writeCharacters("\n"); + } + + // Write runtime + if (runtime != null) { + writeProperty(xout, "JVMRuntime", runtime.getDir().getParentFile().getParentFile().getName()); + } + + if ( privileged != null ) { + writeProperty(xout, "JVMRunPrivileged", privileged); + } + + if ( workingDirectory != null ) { + writeProperty(xout, "WorkingDirectory", workingDirectory); + } + + // Write main class name + writeProperty(xout, "JVMMainClassName", mainClassName); + + + // Write CFBundleDocument entries + writeKey(xout, "CFBundleDocumentTypes"); + + xout.writeStartElement(ARRAY_TAG); + xout.writeCharacters("\n"); + + for(BundleDocument bundleDocument: bundleDocuments) { + xout.writeStartElement(DICT_TAG); + xout.writeCharacters("\n"); + + writeKey(xout, "CFBundleTypeExtensions"); + xout.writeStartElement(ARRAY_TAG); + xout.writeCharacters("\n"); + for(String extension : bundleDocument.getExtensions()) { + writeString(xout, extension); + } + xout.writeEndElement(); + xout.writeCharacters("\n"); + + if(bundleDocument.hasIcon()) { + writeKey(xout, "CFBundleTypeIconFile"); + writeString(xout, bundleDocument.getIcon()); + } + + writeKey(xout, "CFBundleTypeName"); + writeString(xout, bundleDocument.getName()); + + writeKey(xout, "CFBundleTypeRole"); + writeString(xout, bundleDocument.getRole()); + + writeKey(xout, "LSTypeIsPackage"); + writeBoolean(xout, bundleDocument.isPackage()); + + xout.writeEndElement(); + xout.writeCharacters("\n"); + } + + xout.writeEndElement(); + xout.writeCharacters("\n"); + + // Write architectures + writeKey(xout, "LSArchitecturePriority"); + + xout.writeStartElement(ARRAY_TAG); + xout.writeCharacters("\n"); + + for (String architecture : architectures) { + writeString(xout, architecture); + } + + xout.writeEndElement(); + xout.writeCharacters("\n"); + + // Write Environment + writeKey(xout, "LSEnvironment"); + xout.writeStartElement(DICT_TAG); + xout.writeCharacters("\n"); + writeKey(xout, "LC_CTYPE"); + writeString(xout, "UTF-8"); + xout.writeEndElement(); + xout.writeCharacters("\n"); + + // Write options + writeKey(xout, "JVMOptions"); + + xout.writeStartElement(ARRAY_TAG); + xout.writeCharacters("\n"); + + for (String option : options) { + writeString(xout, option); + } + + xout.writeEndElement(); + xout.writeCharacters("\n"); + + // Write arguments + writeKey(xout, "JVMArguments"); + + xout.writeStartElement(ARRAY_TAG); + xout.writeCharacters("\n"); + + for (String argument : arguments) { + writeString(xout, argument); + } + + xout.writeEndElement(); + xout.writeCharacters("\n"); + + // End root dictionary + xout.writeEndElement(); + xout.writeCharacters("\n"); + + // End root element + xout.writeEndElement(); + xout.writeCharacters("\n"); + + // Close document + xout.writeEndDocument(); + xout.writeCharacters("\n"); + + out.flush(); + } catch (XMLStreamException exception) { + throw new IOException(exception); + } finally { + out.close(); + } + } + + private void writeKey(XMLStreamWriter xout, String key) throws XMLStreamException { + xout.writeStartElement(KEY_TAG); + xout.writeCharacters(key); + xout.writeEndElement(); + xout.writeCharacters("\n"); + } + + private void writeString(XMLStreamWriter xout, String value) throws XMLStreamException { + xout.writeStartElement(STRING_TAG); + xout.writeCharacters(value); + xout.writeEndElement(); + xout.writeCharacters("\n"); + } + + private void writeBoolean(XMLStreamWriter xout, boolean value) throws XMLStreamException { + xout.writeEmptyElement(value ? "true" : "false"); + } + + private void writeProperty(XMLStreamWriter xout, String key, String value) throws XMLStreamException { + writeKey(xout, key); + writeString(xout, value); + } + + private void writePkgInfo(File file) throws IOException { + Writer out = new BufferedWriter(new FileWriter(file)); + + try { + out.write(OS_TYPE_CODE + signature); + out.flush(); + } finally { + out.close(); + } + } + + private static void delete(File file) throws IOException { + Path filePath = file.toPath(); + + if (Files.exists(filePath, LinkOption.NOFOLLOW_LINKS)) { + if (Files.isDirectory(filePath, LinkOption.NOFOLLOW_LINKS)) { + File[] files = file.listFiles(); + + for (int i = 0; i < files.length; i++) { + delete(files[i]); + } + } + + Files.delete(filePath); + } + } + + private static void copy(URL location, File file) throws IOException { + try (InputStream in = location.openStream()) { + Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + } + + private static void copy(File source, File destination) throws IOException { + Path sourcePath = source.toPath(); + Path destinationPath = destination.toPath(); + + destination.getParentFile().mkdirs(); + + Files.copy(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS); + + if (Files.isDirectory(sourcePath, LinkOption.NOFOLLOW_LINKS)) { + String[] files = source.list(); + + for (int i = 0; i < files.length; i++) { + String file = files[i]; + copy(new File(source, file), new File(destination, file)); + } + } + } +} diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/Architecture.java b/build/macosx/appbundler/src/com/oracle/appbundler/Architecture.java new file mode 100644 index 000000000..8c1d3d2b4 --- /dev/null +++ b/build/macosx/appbundler/src/com/oracle/appbundler/Architecture.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012, The Infinite Kind and/or its affiliates. All rights reserved. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. The Infinite Kind designates this + * particular file as subject to the "Classpath" exception as provided + * by The Infinite Kind in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package com.oracle.appbundler; + +/** + * Class representing an architecture that will be written in the Info.plist file + * to indicate which architectures the binary support. + */ +public class Architecture { + private String name = null; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/Argument.java b/build/macosx/appbundler/src/com/oracle/appbundler/Argument.java new file mode 100644 index 000000000..352c19c23 --- /dev/null +++ b/build/macosx/appbundler/src/com/oracle/appbundler/Argument.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012, Oracle and/or its affiliates. All rights reserved. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.appbundler; + +/** + * Class representing an argument that will be passed to the Java application + * at startup. + */ +public class Argument { + private String value = null; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } +} diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java b/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java new file mode 100644 index 000000000..1687ec397 --- /dev/null +++ b/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java @@ -0,0 +1,111 @@ +/* + * Copyright 2012, The Infinite Kind and/or its affiliates. All rights reserved. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. The Infinite Kind designates this + * particular file as subject to the "Classpath" exception as provided + * by The Infinite Kind in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package com.oracle.appbundler; + +import java.io.File; +import org.apache.tools.ant.BuildException; + + +/** + * Represent a CFBundleDocument. + */ +public class BundleDocument { + private String name = "editor"; + private String role = ""; + private String icon = null; + private String[] extensions; + private boolean isPackage = false; + + private String capitalizeFirst(String string) { + char[] stringArray = string.toCharArray(); + stringArray[0] = Character.toUpperCase(stringArray[0]); + return new String(stringArray); + } + + public void setExtensions(String extensionsList) { + if(extensionsList == null) { + throw new BuildException("Extensions can't be null"); + } + + extensions = extensionsList.split(","); + for (String extension : extensions) { + extension.trim().toLowerCase(); + } + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public void setName(String name) { + this.name = name; + } + + public void setRole(String role) { + this.role = capitalizeFirst(role); + } + + public void setIsPackage(String isPackageString) { + if(isPackageString.trim().equalsIgnoreCase("true")) { + this.isPackage = true; + } else { + this.isPackage = false; + } + } + + public String getIcon() { + return icon; + } + + public String getName() { + return name; + } + + public String getRole() { + return role; + } + + public String[] getExtensions() { + return extensions; + } + + public boolean hasIcon() { + return icon != null; + } + + public boolean isPackage() { + return isPackage; + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(getName()); + s.append(" ").append(getRole()).append(" ").append(getIcon()). append(" "); + for(String extension : extensions) { + s.append(extension).append(" "); + } + + return s.toString(); + } +} diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/GenericApp.icns b/build/macosx/appbundler/src/com/oracle/appbundler/GenericApp.icns new file mode 100644 index 0000000000000000000000000000000000000000..20d16f39ac790026befe19a7fb6789c98e7ca03b GIT binary patch literal 142652 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 Date: Tue, 17 Sep 2013 19:39:05 -0400 Subject: [PATCH 046/556] more tweaks to appbundler --- .../oracle/appbundler/AppBundlerTask.class | Bin 19734 -> 0 bytes .../com/oracle/appbundler/Architecture.class | Bin 636 -> 0 bytes .../com/oracle/appbundler/Argument.class | Bin 627 -> 0 bytes .../oracle/appbundler/BundleDocument.class | Bin 2801 -> 0 bytes .../com/oracle/appbundler/GenericApp.icns | Bin 142652 -> 0 bytes .../com/oracle/appbundler/JavaAppLauncher | Bin 51136 -> 0 bytes .../com/oracle/appbundler/Option.class | Bin 621 -> 0 bytes build/macosx/appbundler/build.properties | 28 ------------------ build/macosx/appbundler/build.xml | 13 ++++++-- core/todo.txt | 2 ++ 10 files changed, 12 insertions(+), 31 deletions(-) delete mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/AppBundlerTask.class delete mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/Architecture.class delete mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/Argument.class delete mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/BundleDocument.class delete mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/GenericApp.icns delete mode 100755 build/macosx/appbundler/bin/classes/com/oracle/appbundler/JavaAppLauncher delete mode 100644 build/macosx/appbundler/bin/classes/com/oracle/appbundler/Option.class delete mode 100644 build/macosx/appbundler/build.properties diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/AppBundlerTask.class b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/AppBundlerTask.class deleted file mode 100644 index aeeb36b758bffed48947702b7bfd7fad9871e771..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19734 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 F{{yJnD02V+ diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Architecture.class b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Architecture.class deleted file mode 100644 index d6f39ccd3a9c830c1bea382fe2da20e39a2f453d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 636 zcma)&%}T>i5QWc8)1-~n{@7OCC>GH+1+#D?CF5z!zaskb}pSoGzWpwa&QU*Z*_ASGuohCv)U z;>MM9)zwv}@|h**D3p+g#?bm3kD>B&oLhTF&^V+Us&rEZMfy;tQckw?EmCz(eMZqR zU%*WE4CRq31%~WV1omm-02`E*QYFPrsu;FV&Ri^t(j{*`L3yAgHPDh~Yh^h9JzPOG n8}5->F4D~In)SzoeUdmdQ&r|b`s6`!aqWK~-L)Xw32yxpvK?;7 diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Argument.class b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Argument.class deleted file mode 100644 index 586b79c340b7c9c5e3ad22497a7a84a204ebed52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 627 zcma)&%}T>S6ot>ENt(vi*4kFxhzdd*p;@>Ql!6GZiY_YMPtqZ#q)ADWK9_@sLe9;AYyIh^t(w*ww}_9%({ z&^u?)FZ|F?1`MTcZ_J=xMH7`g{RP9p(2Ztx z6mvHaHlNR(G@Jw?wl8BZory4^HHIgWagNdI_SS(Ii`J zlCAc&s4qWQMHxmF8gz#Jzrh$9-zT|srov5dNT*ZjlnjdWpiHHlEa|OKbw+(g(X?K` zEcOiLktzkI>`??cs5rs~Wz}3su|^fcChCQYO;NgN))SNmN^%1|Yaag?)>gv}Y!$-; kQp-iUb+TrCkFc%Gp_8i$2hwLBl8c-F1L>~?+0JlVpF(?UWdHyG diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/BundleDocument.class b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/BundleDocument.class deleted file mode 100644 index 1be4d79850f2356e969f0388accc607b5ffb4cec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2801 zcma)7T~iZh6n-|@upulT1`x!mRINaQ#`;06SkNF^T0kp;MXK#4*@nerH*Pk5^?Rm& zqPM;ArWfr@37tA)@9IqdM?3uqUTL4R8v=$n)5*+x-uK;ep7ZsbH-EkO{V9Nx_%4P) zEJSg=6$h{w#gfPyvV1Jdattxtj9~?zXt*VZ+ZsNN;M4%}r$1k0; zmTk^giW$?rZe+wmeAdYtg(btaN7Lb*L5}RaVw`0^Wd&`)=7Q@Q4;6$~rWCZ7O>cTz z=Dp28nOtkVJWSMZ-NO_G)22{n2xW28QCBI?S`uLUg2!^r86`hu4M!AcbT{MITXyq) zb7XhTZ-p*jw`$y3uXoThn&&sodxo2)Dhf4J?gG?y?p{rCq-lG#Rihll#(uKBQP0`* ztFTjhc9b??w_+5^ zGkM!_&A?I9QIThXV{Fp~qX&CDdOSR#?!Ko2?7h?iznrnce5>ahuX0=#q`FGn=N8z4{O@!l$S|A4jxxu`ux zw9dq!FLA$?m&m%y=)ny3;KOZx2I_tW=wJLuja7ttRPOoEa24{WD24nH(xPRHhb{i) zybl=AI#L5vzLcTI>=f!@gj<>yrn&5=|!3l6O+iDodXYnZ3Jj-nr=OmUiDgDF1F*$JljBx3<>^D{ ZCFvZ|a7Dvaf0%*id=eCV#LppI`wtR(^3MPO diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/GenericApp.icns b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/GenericApp.icns deleted file mode 100644 index 20d16f39ac790026befe19a7fb6789c98e7ca03b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 142652 zcmc$n2S8KT_xN8R2^$np#0}zB+*@naI%{jKwrX3oQ@g*dTCJ@k6L7D(_hdMbjqE)_ z$liOhhvFXa{^uqj0kKk*-~V+$^6tC)+J=Ju)xGgsb;%q6Tw zr^yKo`IRma%OE-BVdY6*4D0q~6t{jP1)KI>y*cl6SdQ>ojJ$5|0xt}!F|#;T#@w)Q zp6ZnQKnyE3a?)(s;}b*zSEC^Ib2}xT8g<2 z=(!Uktn5L@UTEX}N@-IYtMoE~P{eC&qgJjq*W7PHVNrInU(tWv2n_ka7rPf`K2(Vp_4><|?reiT{M*hE9-;q%$z$QapeYZG-W zeyuqlnkYYIX`;TVi4oRetjw_tV^nD4Fh0(UNlHnK&N+$G`*r>CK-tBMF$-f#%N*pEzQUtC~OKmqdkjlWUv5 zxQ8pTp_1m$c-?TU_br>xF`cl^yKO$_4#OOl+kC#e0V7PTZu+8vdub7d4Hm=ayYlkK z>&6f24mIw&mw*1psb5uZCKI527)I{ex0|zl$Pbne*bhG=(RG@;4e=H*kDajQ7DvX#1(2Z#FV~v$8Nbd595f)HmwWd= z_VG)S@w$n0%y$P{fY<6uS&O`Vyq(ET{k{$lr?WMwb@)CSww;65vG50agEV2=ici)C zMTrm8Ql z!b?q>#FS#0QX$Mwjtae$#}X9b4=#Fj?m8Iz-&2DUuhOvdV$utWIRzPUG1reIq2?epy zacSv^=l%$Z6Kko7sl$4A37}!Vr}$6sBB6+z9I+=jBxK*!A~XN*OBWY(?KXjdbxW$j z6_LeiabZqc7DrPmJNI|2>bjTTr1K2S_X{;%Q*`!n8doe67sValaap7<9x-xg*qw>+ zU?P66Oq&&U=EU*iXRc-`j7HV_(}srJ!S^yS`z`q6Qc9VpNv|`QO3Wsc_NRA7{Hm`XU~LrTz^M= zi-C15!ta!qmBEA6br10;)0a#SGvuE8pI;D0zK-9osJZ=shLawz{AkAHcXwfSA^2k| z?$~h8EQ}oX&b+>RF!$w;@JChhLXL>D1?x3=;9ktFZ_<&OdFGl2`Li&>jNXSZ$Aft7 zAq<-`dH7+Bkh+wD5n?{wg|$Z}>PlM4#N7&`QYup0$^_|Nl}RI)QY0j?SYnY1XCxK( zYf5!WImiS7CclIz7FQ#|AS1z0DU}q3om?)XNF3l9iCB*W!wv+4qUx+vsy47kipTZ%lQOPVFmj+Bdyw-+bu;Y$} zToUTowt`Wr$qGAt;@I&s5t#~uK?#BpY!M7!Bp5J>K``_tv&m@GfMEQhsIdr!BM3%0 z%U^tlYO1M)3g5hQ|m$ncMI}i;@S*Oy{@~S%z@F(vsZ7CX6 zx9?j-WATfkF@3=cqA_JaOVO~m5sgt30-HqR)SUK-#vM~D(Wooe$%H(Gt!TL4tuQFW zLZLvw=L;;N;etftUX@ublZeF>5k*LXdzDR+Q6ZPfC{lZn2q9HKg2%LtJH}lFNQ+Fa zP^it-x2yGXp+x>%FqCjls}So-6!}TXg%Yj4s0s;&E9@9Lr9z)~^Xzv+NK}mcZgP>p zA{P!KyhNqX4_XNO)aM6^wMmw}!V!r?waUmILC2hli$ZTO3*;$xnm3C3YOOS4&74_F z{)`Yy<6xsObIY6MA>j$G(+hK|pW^tlibi?JhQ4T$2X+;1)Tvr-6s_c;LfKj#;!12b z3O0U+(|V&g!fhcBY<|m)VtahrOXY$8*ZB+08-@I4vDUg#fIOVvd{Y+DEDzO%XD+3q zje-?_H0T0f%^ERsNYh4fw?vf@dg|EGqo=~sr8=D)$;0i&jpC7+QsQaQYP1HUL9bW+ z2=XAUvdDuk$U~XgTvB3&9RzM_kvypGS~rSrAP0vn={_l`^3O&ZQkemTa`zG$M!bw-=9ymX5g^o zNt+3RJgoQaMwPaCKLaV>aE5f7Uef0MiV2o3?D?y$x@?9 z=QX$x&Ofa#qN|JdA9%^%eH<6-3j4OmyD6o;@Ahe(?Fmam`ZRrG`T4^Jbe#HZ4*Gz@ zKSdaM>J^Uh&NJm5j6CuR*HHVgo{D4TRT$a-Lb1N)VSNxzxId``BYU1M(pNvIXW|YG zkL$`nyf5l8viC8TuKNBnChpqs1a?ZLM92m45vVcJ!2+%2MrXKDWrQ1Gco2(4Djctt zVWeGos>=J%f^f$tpn9sLBB3Z)Z2u6i4-sIb;2c%uy{AFA)6@IaCbbOii5U{Qm?)^i z@!VpJ#K=@up!;OFZ`Q~q6!9(zRZJ9Waok*hk^W9sSZ+H%g;SkYE`d@dbm=anr;4Oc z@WAn<3SnT>i5U6Y1ZipAW0a;IrBT7QZzq$>cgS{1Lm(?fJ$`poG)7(-CvHmi z=uU+}EvHB^Sr8=K0m+DBP@&FU$HusZc0`R3VUJhkPg0oGg)u zKnpU5VWbEge*}kQ^^V5dsQo0d40UuUbaVsWpjXk41SkOw844a$5 zQli)l-5Z7xK}4&SL2xfbxx>;zrj#U6*5mg^g<`})(7;q7Ha8hkq6E6~bSP$j1;?LI zG}fEeX49lZQ91M<6#08S-e6ES-$u=$z_S`C4Q>bA0g+VEG{KhUP!$w86%PGUnT%;k zhx(2Q#luXiQ86G@h>EFnQh@fRP-@^fNiA_O8MG=nJVAr*CP_tL`pAX{a^Wzg4zfHz zQ939TDxImks+Mw_P+Lo@ajLDoU0YqMkxIb;K|tywT}G7Xp?l%U^Em!g8v;)TshpK+ zovEbMY}D&?RDFQKpx0^C3aMBuRhuh~Vi{CJDphGUa?ueBB?^H)zb`qT8&C3=5q>jGV>JW5~*Bj0?~d_S0)!hCKBk6m@Ak= zZy2$1wboLRE-IDIsOIIQXXLOr0*OqaF_=rsD=3wHE6PjsN>OoMMoN5E8COz)KPwUB z=dgr)u3RR8T~h_^0r|hJrb0$c^<=$Xm>Lz8keZpt;)vvGjapKi5qI_CnNz1PTusQ~ zNhR!z#G9F#V*GAV?2Vf@uSKNhvE@<~2-YxYR|d>X4IOf#s;BDo#Wyd7-iS^}$;>b2 zvs16^TDS6pSyLxX7&mV0xbc%_EdFs{94jy3sv@%@Co+`>4a+(fm%)`wK@~X#c^!vd z)-fTkchpAFwG(G9gc#=q;V6bOrJGp?!5W)=gpft``t;SM!xg?m7FNi z_2gKV8qUWGef-X(Oqm3x82<`J`U+NdvnEK()O6Px(+>Z0^6aJX$oSaPn-)(VJ89

RUz`QCf)P6(XBOwt^>l&z-8ofWd3=To>cm|@kBmnYcyDmB4c zx~7}faBau_BT%)gVZonG9y4Xm`wM2jJ9)zRarCj+IO=$}iIb;Jn=)qT1__^Emh-f3TNy&aQOK7E4w}!HFnm*1+%7395Q(cm>EoArp z!%7|h4ZFQ7)Ke~bKHc96UUDkIeh5gK?4T#A24w6(7;gxKaj--(doGwn!-h{ ziQXBVE(dcOZiZ&=ha-nUOM?;UuG8(H1n)X{rZOXp1mtZ zOqf0Q9heDIr%xC*pr2pgz7#*YKc%00KtG@U2TP(4?B5kky~0yLwN%&7#HTCdQkeD8 z7cj@7stOh~xJtv+QMFw)Wmy}jAv-@AF=^(EiQ^_rnlf>?zn`B!(~sugsh^)ukMH=Z z%SZm%zh}qxa}p(0;i{BGL?mV_JvO+8KFre@ttNMftxGBuk0r!jX* zDNM75ySxG%f2`B%gLRI2;hnI*Hcc2ekurfaW=KE(e*LKa!G2!7x^@})C;y@N+Qsvy zj~_X>Z#OkuLzTNLl$oiS$zoX8Wgr8mPhkYjBd|(6)~3gUCTP@A^h}+LLBxG}eeuwV z6DE!uLhncMr}|O)`uFbU)phvSH)`rtiC4ofpFeZ*C^VXJMJ5u%>6TYel$j1QhA0Cq zl79jti0@Nz=Vz5FNnR8j7Rq!qJwxZJjZ@%>pN<|jxSxMO02MMG+_z6JUvJMY0ki*1 zsKOu0(&M6TM1)>E2VHP*UvQX&$K?t|0;MRS809U8wXy0LM$p}*;VyS{3Z=X#5`?c> zOV`tNuEvZQ-jk<=As>wBd@);GHn4fXi5Qhs(?azaex)v!zFPoFsY z&w(9R#oXeeJV|wJ;VmUy0ZaTdDg$%u6k8DN?!9Q5Z!kuXHc)W42PUOTtyXa3#b^YX zdaBOHSR9#>YpTcVD>yOd4(P8FQCCZxHC$? zE-ci6-6@8rgx#GegV~iy$6V%IIk9%6Pro7leFhH>!bm(AS(AdQCaZ)gIWWETjMNmjeLTuD^)Lo}f967W*fm0xY30x5!FO^ve0e!_t z$6PPd-Vf~M?nv_JH)>c9FyjpbJO2YUte%dNtOOWyv)&M_e@ACbj!MbQE#irlhSKuN zs;bKJ(h`$i3o3w2EZ`L7Lve{PI#Q74Zb-j^b&0(D*=8IzX{`wm4xlB+-#S5Yzd zOGiE*8Q@ODoO=e2=+kW^6T{9yKUSzTU^|!RN5M8zuBRA+^dn82Yq!#}@{0u$xk{@y zBI6TmZd$bpHaEVt$XjvIk=MenKogH2{zpc^J@2wE$FPgDa-d8lRILtgh@@a1XT#Ty z8{C!N>`%3@<2xwWQ6P!6I;w%GUt!Qj#Uy9s6cqEtV7k{CjOc)` zgI3C+Q;X5arQC{-j)Y#l1T*~bg)01kAmTzQhh5A|EfUF~OnGTTy#&K{ByXBHw5ua% z!b8Rk@+Nz{2Sxr4qIp{dMXLCTBG~zLbOT-QsWawWOH9qoDJdks7vyH8 zCnv^3iPyrRm8XxV-8gx(fXm_XDE!{Clzcusppe%+s@s}d_ppnv?L@2yOA7t=?4wOk!t|ug?L77Eh^cPEHG{p?q{e`?@R(?)qnx#PK zR+v3!&Rq^G67x7bKG@HA%G^|rNTyIo%y+Ab()R6K>E=Xm>NR0vfIF%46xSUX7EZxk zkqV+Hi~>ck(qLp5y6UwWDUZ*+5u2C-CFU2hxqP8WBB4mTOGH9G2X$&jYEoicOjP9c zt6?yEE`$~FDLg8_H;<=e$FTSyArfg#i7fO;h+l6K*=NkuA)aKHF}-$Soj_`y=rmdt zCmMdctv4EJ1|LwkWW^kgAme&MQfhiuPF`UV439ua5%qv3aM{pAU?52emIALugkHXM zJ~}hEkW$o_&Eax+YED=l7mVe?;u1q@#3?jWJp-qY^l@+;6u296-}Vfqr&_BP-a<;Z zfoh}}h&qj;sEERL=f*}QCa0ul=HwNy*u`85Z#tjHDTV@bvoq3?660f`i8roa4Zm{i zbVO8AdS+HmK8wTQ=?czdv4s*5x3D5PIeO_JAF}(PcgOd1BKMpGmQ*fU=`|WjMi$73 ziEbo<%&`lpMegi^8}XLnvUBqbSVc7Uw4%cNyqv6z)RbGOaW^9)Z(O@^djIh=S0dw~ z@3RZo#R7BOp>!5sz+;(HBeQn(@8#g^H+`DFE6IDR<6g{tHVoQ*jaHTm+e&M{ zX@t3SmK!_sM#8P+)bxz3oZS3;YJq!xUT#iSW_nukE!3`P%FUsX(czSkL&wiYL?@#*>59%J#C_b)$+7#CnS(q?ZWDa=V^|CYcPi7UilX3rQ3XYj^;%V4 zUO@q^(4{yn@>WuEY8sT5P0w-7%F0MjOR*LdLyaC1AG6_C=7Hnq!ef#%VQ|@ez4Z4} zX?cZ(QthSCl+{z*$X&+G9_dYX8aDU<)|Cv0vd20#HxAA!bq27QLz6_Ah4cc~!XjRJ zR8n$s3Mz@3>6!t>q^2Y%B__nj#Zh90#l|J2tY7x$jzcFdUQf)-FJiN~^6K+z!c%i{ zxs}mZqSh|#O!5evGXccA@AyO5z};ZlsZoiN`Ji_h!Qco3#mX&Wu?h+Yl`pwAA zA9f|X4wyZ?uQR#pRN_CF3oKXl21zEG5N3*rXwWLM3+Zf^A}B-1Pm4}TOG%-pI;KEV zl5X9CG7pb6c1`6dGUYF_a?ayTQI$s6WMnv;W*Y6Oic~CWDwOyXxvreRDqPoKu$fH!+;cF?-@f=Q3UQ+m;U%y!O+g941;};_$<6s)IiaC5~1)ei+ad3EC zqF$oRjauX3;1V!zPJk=PbBfzZ%u|6k)aAl?>RAaKE>+@;JRP6Pn~&CIZee;tbX0V7 z#E~sOe!J%9b$@JJ_w#pOez|4?C1~e?QhPFZA2GrbQc@1Gijog_ zVotqgzCYZ9@0LlsXEJ%m*DNCncT|JvB1o%znn! z&6_rE{PS;0(5}7v51+miZaLHC6cllI0=t~vPA(nL^dYM=zIj1!e+mT@^8DC0eDaX}VnEiutIuZNvKdF0T+gNF_uL+7&V zH)GCeXg)X2Foyq!kxuo7l5{x7#|lKeG?Yqh={A#BX35>#@|Xw&&thb6?0+o z0c5^=@%=f!9l4nTM`tc8{rdVIM7NpPZjEheI;f7T+D;su%VlIr8NOK2&lD_uc&*&H8(sJ26p|ChR zampsBB=4_n3=#Qf}pmRWLl8B0Pe{iw$UHs)lPm=Sn`CHO8jI)^k z`g^8A*v2Z&sQwa8cIaORrFScJav^k6F`JDREL#4!f&vx`?VQl(Lb1Yxmg&Sl=6~?N zePIddNcEJ;q(b)9f#goTXD{hPcJQ0`WvHws?;O@Mr-B8Rh}&kEr#hvGoppoy%Sq+K z2bFq-n9rqfXvHKLaLAS_94?k=D`25{AUL&V!IE|RL*r7j3pqlmTp<^6GZuI5G;-C< zE ztuL*8M8SvD39oEi`oWi5k3=NE76_dJI+{`@WUcSvK495*6P!uj6Bp7V3vNGsN;!vh zKPH8f!xMyzQ2wIg{Itk}zkc@pzEs0w3U1%<_`yBOUHf|v9)tOH#FI*4?Ee2PTfA!H z-U~OA(m`hwK;}qw6La?WbL;)V&+mCVV||xy2+a{zH8fC^4r+02z`^BtBxPj7+QS3R33+RgnTek?+rx9hkKYV(_L@9r&5Z2MKc_BU1uGB8 z6cSk>Sf5moxegRhg{W|qx5uz=ex2avHgVpDa|vvjN~4CU6$!QP4?_E(gjzb%()%cX zi$+?In++=IEwm}eCnSPifE28J7A$81ktJ)bmZIwgTAxzF`KyOpzvUa}c{vZA_tS-B zwoIwfs^N^QxPaN;f^lV(dLd^LWRnAhUM%Esi$R<~7w|4*6~TT5Vgwqv0?v@Ax^V94 zt<$Kayu$&mJr{0T(Zi|Fyp<=CIZ~xYqt(DU^{yY(dJ8Q5L07Mz#fC5jzQAa8f zi$n-WgItQl60kK|bEWDCdOa1CVo*{A*G9W`efN*=2f+mYcyD|$bOlvQ)POu3gM1e} zf_<@sSxU4(N{W#TS!*>KFc4CeBo&-;H5v*uoTxXzxyY*aD#ht@JUWm4<&O!j9#h|^ z+$@x;G?0X(RfC0-19=ib7pf}>E~S=`tw>-tL3H-ZJ0I zW#qiy!?Q(@15HQNfW5ck0!D^I??Z4u2ri|A8v$ktF=7Uak!A`uf|jqA^0xGF@%wc9 zXFZ$(=6!P}O`uY1nL7K&__HnNG5cuHR%q~KP)V>k#KbWAz~NCYI2PdIJ8$cc1D(3h z{q#^GN1@Sy>46A~Bo5+2+6jGIS!#VM#2jp*8oR<%O7YFnuHI8OZW{0EIpc$%XqHS3 zrdFt>7Mf>($KHpot0|?Ig)|n{4Y6O9G;5x_$Htjsy;OG`$l{OO0Cp z41WMKoCpSryQR#=2ZK#rjp!_~(#v(gm-OYn&O_$?a6Ur_CsB&t6&};-%@ubZf`Wu5 zuK@P`vhpBkU@$b0Vd@Kdrb2kWmwT^|Y2WvE?lbR;V@X`47W!DLGnUoff7(FDF)j2< z6zu5K=MU0MJ&ZcFwD7%7JwM#O0p`c-k9Wneq$-`EwEFHNz&v(Oss&IS19}GhoXUe6 z3-q<9M~Ppf}mAs2x#UWXs<6?+{x+PgOrKA{oecX zVv!ko;I8u4jt||VFyam9gUXP`7y*cJ+I zS6yCVO-zMZ*rlYjqPnK)Vh?iP^~aX<8?;~rW!twC$w?S#GMr}alv6BenWY${^)3aT z|K!=zhj$7FI(1on^4mduW_EMRz=&{qykAbUq$D8k8B%FQ?Y&1}BXVze_V}*(9ap#a zkNz>T$HX347!fw+$K{NQ;Bp%HnUTxN!JF(E45oWS{gaZc8E#G!_b?{+7&~V7>;!&H$KLO5@8U3M>;5^t`o3caDS^P?wILOR@^VTUsl2lG z?jsmB?}po|g1GR%dH~NQlY9Jlbg5tWsa`pl141%&6_u5=3Tip20?L2d03hz6u_*fT zm8-EgR#Gu1JCf%oN52{9Gjd3th0;6#)4yXyd3i;(wH9vAs>CT_#}8kK&0+~J4~8cQ zMDmP7>jHiHP07dX!BX*rQbDY~4HXH-J??4qBhMT?b?ItMjznu#{0*Mj4sQO7f0^Xl z{T=6g%;5?&^zH-HIsI#x1Ies=2wzph1Um`Dm`1DzIF!*{p`7EI=@WlMb7h;5fJ9OOlkumN3jVlph z*FZgB@g%TF7%Cn?kL8YGLe8D0{Pl5O(s-e`u- zzX!={n8BE%OaE_|`*#`VZC8ZZhlelqVqk86R@C0DFqJ~*l$X_jzbYYTbTH=N)NSFi zK|LpU$}ys>zM;N~QejtK`2g-#GeR&2`_7X-9ocW9y8?6i;V~?V6_w?;pP@%b>;PZa zfgem9I>}juVYx6{Ybqb2r|3H|vSaU=Q^rmv0eBq@Tj^8uKz86RjMRDjj46}swBT}1 z!wFTiJ(&Gr`pk(24AVi1tfBDvG;W+|#O(iUxJ}!K+3^JZ%^2b8y!{v<=L-agoBp}+ z2Dtc6DH!`&;o`@26?!??+F%K2jf*P{3K8F;9P$;gQ$5GUOxziOWhGE%0qDCy!q&jp z`6+_Q=%!Fe7tw`8aQACLj2)leuQI8nB7tzXh$|FooPPqZdqeKFn+M135r6L&L z5*u6avIRoZ)+trM zf1B?I1LlVVz;k%4ptiWpgxj#*HsNChT@?(-I=Hc&bjV!Z43O_Cm@RJ8;9=-iK*&T` zbe^b#;cio& zN-E@!T1EgDT4`swLal?<1nGHtjZy|43ruOSmBKgSV-?-<1YO|_v`b?wtE#EJeVbBC zt#P#CW3^b!kW$2S3DH94p`L(_p8#e>?QjJ)tkfDo-viy@1$bOx0Bu()6-$(0zXdfF zoEH(l2Y5_E@Ytvdf=n1n55U$&y+XumqQ?|NKV)Zq#yV( z*}{)iz@URc#q`n|R0tpETJSNdR#_uHE;Xpcjrf=&vf|@hz{eb^Lwv``8B7V%0S{yT)__3M>Sus>o zwYnyLoK?W#=Eol2^7Z>uMh*@@fX~0*z>)8MMv2Hn{5T8vaS9h2mWlYWR0MiJ6F=56 zATO%Q*C4!Z1<1EDGGmVX{^7U*{{H<34ILgBNFC89aM+-LKD~!6JDC-Y_;I1dS3nyJ z{8%am6|;#So77C`EMI*iKE4?rd2sE!gZc&x2^Y+cpkMc+(rrhIl{Cmqb$WMFu3Xwokne!~JxD`Sdzm5-K|XQr^ycY( z{f3MhHEe*tAGI&R53ni#%zn^k0Re!0yH6FK+qSD%L6(@`qXGv9`1SSkL(li~>)o@5uTNKsk6X9yJ$v`+Dt}@_k1U3}8Qq2VR-bGys6nO`IR__7BhV<{(Z{XkoJ-t0W zDPA;BDyo~OqwD8f^_51BEC%xKCX<*ns4GSc>6f8mx8K2>>Mj zIG|tu{sH~{e7jJ+DPF;z1Kb@*{=ab^Nt!uwm=bx$$mIwmBWDrhOz|8fKhmUurN7<) zheW2U13Gv1aIz=&ULIcEpl$(^rEvb1%DD(8!!AU$ zxK=d7WThzQCLA_O;rPhVI%@zXN6+ou&Bx0d(O!zzD9=vrPDDFWmr1`xR{~5%hOOv1Ouns=D`l)3Ac@r)I`|N{8q#BUPoL&&o9Wlt*?~eHMk12P&Ype~ zRxo0;&%oaDFElw3ym?46*-Ln`-F>41T!G}AIK-1J9tJ)JHt=LK@Z_?h8z*+tw$pYU zkI0ZzA)fs3(C+zA%fr&<++f60q(g7#XYMLrEH^qSWv$}Azwc5oE25apf8n}H}hy+D*}l@zsu zf|~${=AMoLMhQ=?A^Ww7atc=jT`N-|qC7Wu_mnn?vJq@S;DZ1(=t;2N+hWcTzcx`$ z&f`g-MClzM$~mFi+9t~P0Z}_jvJ=1t0saU~y%%@^NM9Q%Cl`akS1vXIQcgd(dzG6L zFo~8(*`*AOgz|!$u#Z=OQI4kX3O;ob?rSsUr~)3yh!~i%JmT0+|CUVI9h8_STD3-5 z90kAK22TWv-Um#V(l=ttp*h7uu~@)18#Aw+9XI4frd*@as04^9-v?_P39M=IH$%#& zGg&;5fKyPBmKOU-TS!^07N;YEXrv>6ttxsWq+H13aSF_7(Yd<^v_#5o2r1uFYos}_ z*ff;V41ljS!kpJ9$_G>O*~Nug_QhL?OI{?(&Sh#P%R-d(0OrYH=6!9X{M*UY+=2p$ z?n-!CE2QjZLCWBC5DUk}J9>%{4VUmukaB2JRt~o+E4X{*F(ym9FIv(D@}_{I{Ja1 z!wX3Ht}HJOOfh9BR!1#ujg$evw+AV|w>2y-QBxS69NQLBHnO5%BdkWCUnNd|1El=j ziJNf((be>%Rc#?YJpPYQCs5tFl8%S9i2h+G5;t|!ajg${g`-B;q zkd~2t?56|aZ6M`%u<9i%+_e}^NJ zvkQwkg=yFR1u2_gtczj}7W^lq{1_o++WFYjoFZV@fL#9_Da&|y;f(l-|A3S?9Jzig zBah7!i3P(5CnSQR7D)MuEmE!p zr$dA**jd*pznpp%Qa-t6{*rb3uEeHf6@b&COd%6;(ru9PlD(~vGSF}fQqGP)_RBXr zb87H^MaoMSuHJeiJRUqEp;LevDx`wKmPk3jHBv@cLm}eir`p*gjjxzx<@4grkt0aaP`#AO=}QS{t}q-kBBL+SiWNA zn)S4UXTzhx12(S^`4w8YuSTtu@@$#%cSmj&LtKNEDU&Qr*-R~2jFupeNUBt$AWxujL<>@8 zlq^CPHH3Vv9*$WV7PqyySOCh%JtGr&(1ELiKxFa1L?GM(tHqqnHaz)!QV~>JqXI_Q z#FHtdw36Xy-XNz`88~e6IEW{MzgK=f_hEdLuCzz>qiOBnI7l=2THI_EqO@k5ykL7|0b~fwnWRy* zz{!kKMu|P(MjrKt?9u;b5o&a{p|Bl|MO{ zP%H=3%YafrF959UV8zPT=Yq^Z@EpKssH`Z`hAT6p0G~tn1gb6Al$*IS70P1*It?;0 z(R1K-kl75D=WYtm5nGtK6L?doRXSU+j6k;aNjiXRokq%TftJ$+@E}Epfw{;LLXVoz zG7+KWQpWRVDaO8lvsO(-TRsq;U3g zw!C;(bfFZWbV-#BTP8CsY#E+I{TgIuntVVqWn6@oH#VZ>s|YRMN8x>~(K6-vb2Px` zuv!ZdT>k#VY6O>mzs_wFE>i(6TMO$3GXPvyEO>e8so!3XmmihUEf1mo?1A=u7U1O> z|4?6smn)c!$?4{9mX!wa<&nYrU&5D}mTqH|AQ%k*v57EmII+}*FgsWYa|IAy)LGpv zo*HIg%=aHRG3GB%w`9yzOIn%*F_+gsuiGHzg~wYUW;!Hglwm083ygWvKBg^WWGr5s5(_0~CRtv=Z>G5x^h}i*7LJxpQ zL*@XaTO#K3F*b;K=Hd1K1u=j8GQ@n@f|x-iX@Qu3{{1D0IRSj_Ac(*gF*6o={R?7N zw?fQYmiFvyLCn5wAZDEvF$1e@M9gbG>({kii1~vRLs}!|`v?{{BIXsN18fj;MGM6I z(d1!mBj)#}wS|~HC%!keC1T#XWkw6c{P*4PG0liM=elnbV$Pn`gqP9JH$cpfZkxgS z+!`_8Dbq-J#f4z5Y>Aj3*OhDG1{-oX8lIrnfbhXzF_>%rz&0eAiMyaE zXLxr97o42A3?7Y3WW%0q8ol)eoN`g}G=>n99$c9j%mW&xiKdU7Ia0V7ogu#MfelU+%4B=%hD6^9V zS4)N9mKbU?R7h-+KZQ6NVdboO(~jF7cbN)%w&X_fm8%F-Ve4kk-;bNgjUvU z2~$>sX}e_#I-kfv-421lXw5Q7X_f>`Nieht^%4~lz)`)CH&;p-awcGG>wVN_2R@%C zu_4Y7_uVo9iO;nnXA&Ui$4Wre*85HULFAy01+0vivlfm5C_!^0nF1nD4n5i!xonnE zpC`cJ)ihM_SS1LBG^i_6fY^N_eXf?#flQ;eLa#x(&SKEjQQ#G9kXoS60zO2v1PSQ^ zA{RQj5kTJq%8wqROI;)o)&oAUl~w{xu>>&RuB|dF1p-v49XP>LgcPWo8oD3qb{@>0 zDrJ!6aaW+iGPMCvH=MU#B++`l5WE}t0vQ|}c%qSkWkZ*FNWuL^ z_pdBkC=dzsprJmgE0yv@LID@f@xY=YJO4|sdb6H#oSX{-d}y9aWpQ2E#kvWYGTpqV93f#F4qYfS#(lX zdPLCY`IRT`W%xhLmn!s=v_$}LLQI|pwA8{df5P87fdBX;i1%~9X^Eo z<=~USg!orCrOry6 zLnDr?33NV;xe)B&1sTDzZAXfv;7j5x2fCas7Q(coLqsu52^Z2@nOa+kJFgrOl2w}!ZA|1*hLn3 zC?-XOd{IzXv4bV7*rb9Wd|-A)M1=Qm2|SItIMGTQ*)LlP1xc@-iBA=a1Te#F$ZrLJ z8;IUllmPkN`PX2KKsbT9F5+mKD6bHfKvxMrBH~ttM8t>9sztQ$9VJc8R5|Jt8)=kr z7{Trs*2#WB#_g;otb1K42ImwvX&!Lh0&r5d%&60tYh!>gHxKN)Dux=UoSF|@cew** zXLkhi^!~p1u?@?G@LgEZT{F@$llbsjD~lscQ%vw9RdOugJRRghRXJ(++-ISKpdy4r zSnp1YE?2>ZV-p8_83OXaNxm4+Z7PfxQGmP}8quxGvvL_f^E#kgvl<*zC@PXNR)L2P zJBax^2L2dX35#?qRx5>5FNcd*Z6V4`2rnNe(&iKB9j!w0CKB?w?Z(~J~|dcwBVUk zR(SO=^RG>RGY^NRiYr0a_G=T-?y`jZB19X_mVk#5dWVUX(4K4^@vD7Q}Bp zW`N6vlSU498i@EUd$0o^`BFanPjkR;EPBNXdh-})0Tw>XSZK>1aF+ zY6iG+%+V#iZoF>>c*&#U;H4@}boRw~U-wc7>I4Rta|4#*QVqChP}C!J?Ee(-d&nl> zH`7`uI2OGG&yo zt&u^QGIp#GQ7I~v>8a9YzAm3FPG<9=bH#ECpUv6THlNjlMj+=W0a|&?(9$%XU~&<@ zHlIz(;egkLSacil*(+OL;Io}j#P59+Z7s}*gLAwQ{A0Rkz!0Gji(fP5HzyHDqD0I$ zB0zg!SDP`vB~YR?_Xe=OGGuA#3gwAjpU+0-7K4lkM8Idmj_znH=2xXq%8DXk6|M!V z2Tkh(Mn=&a@!89OO9cWh%WTZJdZsNtTMaKT;KqX~=DvmsA>l+I-mEu@`8|;a5n9}$ z{EF1nm{x$+6{t_WUa1tMK)Bx%6c3@2v)+Ku?oY`pE-uP7r$yzo$!G5>RN^dHZ5qrd zh(fL8y*{5kygw<2#md#NFC-?k#b-+tviwMxq7_;_MMs8qf#vn}LVo{uJSi(TSNu{w ztCq8)K?A(4rRX65M#+DDK6~!F%ZV9T?8?}%Hu-FooS%s7m|)uVfe5GkmV6e%i`&g- zzt{pRQ8wbUe|_NdV#u#nm=5#dDflD6Ajz^`lg}`JMImm6&*SL0D4EM{R`s>I))4^{Uc=0aPJOdwo9p-nYlD$M8iFX-O-m zwGr}L90MEd9UU^23Q}I1&wjcmA}U{ZQjoZLUK=65np+%D-1HW6Y_jk*Lw@HjVqA%i z(@Rx(ZSvWybkKxR026f9Yli$r&s;>i9GjSUki|}Ilh4KgpDjb-U!uI2*9-YQICUxg zN*v7eBR}mAdkLSdHh}qA%)a?rA-_LOS-mq1g0XY6VrYwB7V>*n4~$vL%{cSl`Rs)S zvw!{PdSXUi5j#IMd|g{1zaZp~3<$Cb3ZoDFH$M9$ea-Y0l(W&vS@4z*6jS^%KKsmU zK<005PADzDy&=EZ8{hkI{XbX1#>s*ZV;(EhCggYC-z`FZ%PsW>fO@6fe0IaUg}>~% z46jD&__sZm;0-T%MOCl~mKm&^v&l1jXMi}q7qXx;JqU#<`*C;z(2W|lh_>cJNw&1@kJsjydLOz$nR~VHCPn9 zoD>oP2fcUaR`k`2Cl2hOZQHzQ)8@aoGj|<4em*=BUSpHd81oA*p@>cbwUqF3S3VE< zowNRQTmig6Mh+@KQ^@aq6V<%ff_)%=c(D)15<;H_FENRajg5(k1xA}s$aa zzwoLJbP$FUB*bk)oI!7Rw~(mVhRuF{Gy&cu1m!8THu1h?CWhG?y-EajNqFZH1oVi( zb_I4scx#Od1SUa*1!16$AhyDZaXS$pSuXa?z8yYd-ub5Tgg-Gob8$7%1dLC*z6*7d=D+K#GpkUuS zrV=2dR3NKRSERS@&=9oR9XcP#T_qD1G{f1szg^Dc%awE$Q3+a86PpDv&ot9b7&z0> z!I_n+$H1wTq3ep;!}+^8+V`uI$sC~l6tG~}#``khX$D}@Ab5ckRo4~9K*BxR9P#_f zfw&@x0%B&!DwP6`y})KIA;0BjI&epZDago#2Z3!vT?N;h+3Z3_WWGcZtR^bJ@Csm- zXbJd5tkU`nL+`6Y(dp?nT=tK!EFlU*htsqJ^eVU?pnzX8fPp%Q4@7*_`mDvdR3$EI zCbM(bo=fFIcsxbpifFmoPG?Qs*roRQ8%lPM>$NkRz>~I1^ zcB4N;q1KmF-)myCDDL+u-2$$ykM__(bbNku-0w#_qVvT7u1ytpTE+cVmNY*{2jH!R zcQ{a+;p~=(Y^kxjC7dOrxZm2+GRE@)DV7*?x!^pav&S3hET^oE&|mmF42yY%G01phuNrIsPAk9w71>|w#qA3^xIn&Z|I)toKjNayoS{p!nstM4N!6)H< zSvjCw)LbV3zb11T3c9vIwC}e-v}Gu6n^Edw;l3qh@a}vR)%`pWc+y^5NLxXN#1LFe zwFDR6f7~(@c-sM6N?XH(;9_bi5fS1SAZ?GIjyK&~oiHi}@S>l(4 z0@qmrolz)o;^pJV&WGJhOv~mPY(jy5ejyY%>)M%PXRh3cPlfGTBrCHC1*X5>MksLT z)tKb0LN2@(POC3NA^1(9z<)1k3GpGG-g?|f9OSXgp8%ro< z_NAq^p}-$3AKc7oD=Fo6W#zVG+cMe=05@%ZJ^!#1o?XCEmq$8lBojMKugb|~J)f~sKd6V8GzyI*8 zwP=sQA5){`psqAtra{jC2Lk}DCOf$gT(td$6xQ+<*Q(API{=oV-THs<_f;`qyBDvs z-8yUl2zK^lC)a)p{tOd<)7nceSzo6P7yxV0e)Be7;enmz->#?cyT9E5fTBr`u6<{3 zxX1x@@YPpHm)3s~<3CL5mPxHe_nP_JId(PdC+)j(d%cat)l#%ek9U7PU5MV&`X8=4 zlil8I0IWrKf9IzY`Q=~(`p?&TFYDi0XxW$T`eZG-+m!E*<)Xid@p@NGclcu$|M?;i zV4Au3O#1F{R>^A@ZK<$%h|7PJKs(sFoV!l=`e3^0+3U5r#Z#*~wSNMjUDLVCnAQ7I zjo?4%8?VxV=jt!DaZ3 zw_ZAUceQs3Bslj2zw5Vt-EQ|1=-BI<|F*ieudeN00*O8|!7}sKujuZLe>3S-%b>mI zD6m(&^~==WC6M4gq$4IE-rgk;CScH8Z#`sqy1h%FL$B3uw%fE_dr5njK%&od@DzOO z*OT^Yf%cvw0hhh~tG!Dg!EG@3n7;k1y-Og$*^l=2O9%VbB#oJZ?8e1c7=MqTlG6{^lZ~uC-pnV5nyH0_*Z@+ZNF{pi7Ai-_mxeh5myPaB~ zbHD8!QvU6U?OFou+`dzHNcs5h?N|cs$W!7wrgR*?`N}1bKkP%SE)e zYw8BVsH+{JceZTLllks;R+G-sb8EVGUA(9-32I;&2fH~Pvgo%gA7^wSfz8y}Ck?(g zft1%?9742Kz^>EoR%tupV^(i?OPWh(niU_iPx=!z-Wq zHT}6=vhQCVT)HLuCn!>{@v6`GbwXEiqj{9z+MnHYqXU16!FQ(Vl2B&(yV^IIXNlg+ zI(`*2ikb=sf6fCR!Jo-$Djp*^_34nqZ*zg*&%$dqu-&_~YE)N88$xT}X-bDG08o*q z&HBx=Ap0#lsZzi)qKhZ=U2y?Ar0Z5Q^DK3&iX@&v*sVeDktV4uzYh z_i-b>P&`I(=&|SRl<=>)s6*xr=+vfjgq_a#-fKy(4BaTj}bPupF`wrK0`q;Bgvu5^g3e#hIY z^SxNI^&3!zb2_pDUwglF@>wfj@AXkfD#IsVWr+Y~_(BJEfWYrnPBHc#6FPtdH#O<; zoLAZc$=y4I12oov=KU(C7&wr21PN>`Kcm+xeKLsM;YAT0bybgZeR1n;DUAfT(WxC( zJdXe3`O@XLsT!m{t2^#AaNYNnMA*)2Dnv7N(4`;vY8>J+bXNzJ4%seyZVPPc?-zcO zdVke%18~&mm41QtU8Z#iiLi94pwFw8K+LYwh>qKZ9=&=AB)ASd*>Mwq`pP8`bL`WB zHnH@cuUrC2z8}K7usY~!#}a7oJ+^~T2x`;MuUrD{Jcf0kCLZ-lAPEMce>$l5;f>8_ zeH#sLFDyLIzi{mRa|e`PUn7n`^y~bc$)?e(s#=O0==+jDG^z1hzLoahRi&QTyz1lm z?@kyouy1#74;M$oURt&G#gA|f*#D;GKQ1eZ2wMB;2k%W8Go)WnpU!Shj-{@@}(|&!p%7{^rAX#}4u9 z(WR3sgo3oA$6Hmy-fOg^&Ai+3WrOr2yzeWZ$7?kEc`fYRhx|8l*yHl&22|78)l>R< zx{`@ajPH4_?f(UAA^$-Kd!~y$e6^`(?u36cwz~`I4GKrq{4Wlfn)CEu{%EqCJWX9U z32ZF?eaKsOPWv4)@5cZ2^}^ZkH-M~{IAm6U2kA|V$G{woL;@a{(IqYw|x$o z#eaM-ws$AjPScwLkBYWU>E-(7y$=;=heKxVnHAFqc5!xa>5|acG5UYzzm361z0>TF z`N&kc*OG2~^|Rg~v{x$Hax+3*Kbh0*(e`|Pu|FP=wg zPOq3gz}wN@j_lf{$kO~r>S^cdzx~AKFPAKsF=^zmv46F;3>W>raCA?w zqZ5dZoz_^2e~`iWcx(@sw=(!pKEa{OpmCGN4h`t#549vZb=rceRvWu< z#sF{UHZA+@E3b7b2yi1cZJl5lKK{G|s!ugG9*T$N4?upymDkrz?dRq6_FCVnHg+DP zo9JobZ`P4VDZqE9(?KY{B=qM=eLFk8@v7gdRGW{aZtE=_P2R6mLgz_J;Rf z>d&to-`nHA>NqyJzxr2#OaFYRK;duikLvLp9}(FM5~#lw2!wYa|O zIBI+owzm%d6-6|C$;j?*Z=`O#y8ReT!Hr+c8P&tpW^+O9|6|Llse^o6$9>LQbyR*4pg|8G7(w4Obv_bq$n|EB21Qrhq+{68)K4Ga6>n~{?+0u}xoIp+G~ zM}7OcIR`t#@7`-RZ2s-X-$wUE**E@N1V6urk6nNG{@Zo1LBp@`AJM^T&G7it!{uz`S~@9iv4*kksVPw)j~_YJ-XUyO~04^7#jUoBT-_Dvs&4g|vU zfANnoSGYkWkcdQ#fPaB`_5Eo1@-J=w#lOYeF~a*_{q)the+(ZJI2zxNp>`1{b@0F; zZu%^W)4Z-VOSW%f@is5m-4GiPJ8thfUB8;3{FA@)W%@n2!3PYFmTw%s_Os|w!X@I5 z1n$g{ogL1~cUE#s(sp(laY~ufcZd1eq6>Z{yPY~uT)6l9Wh+m9GgofAZ&B+f-}L6{>Eg2Zvr{kMS515Z~+5L)rT- zRJo{jR+RiQq&G2iv3%OXpc!#T&u_Hv`A60x;Q_vM^0s528;06*j9>meEoh4G>Mfaf zr&71B4WEDNx0v1>^|_pk-)M{Fy9XS0*y_K2?b0obZ|i$&|D3n@&p-G4RS?sgwWWWJ z?^(yWCk|cAsGrEJ8qZBLb?&{MH%#Yq>)Qo!tDmJ3KQ8O?!BWaEPRo~#b~w84?4RdW zvCSKP-1+Q>ltsjnkgiP3(HKbXH$GtZt~)=jo&4Uu?4hGo1ns)nLUFErXl<_ncUC8# z`M`@XEo0Y)xf@O$*c!8S{Cw%u-}@e%{H{yTri0QCFP!?-??ATp*bME*gD-d4`Ry3i zqKn_IAGD=@*{uHu8$jg09`1$5*`gn=xr&RQlZgTTXlRZ?IQL!O_iM^dA*5rZD|rc+ z%$qRp>HM%#^Tq;-%ftdUX?piPTcjUaOwO5j3@a)6mcbEQ)bFCJvGzyJ>J$^?0gg4m z%g@T*pOw)cmCB5I`|P_c)!k*gJYMl`eKap^qw=H#Kx~N#i-+^kM_6Tn98RuKlXZ(#XJV1tObaTD>vaw4bHQ7^&Nzh;xF3WwQZj37p;BvrC1${XepSr* zs05@u?M&S~5iXOy$xDBDoDSWV z*xNeHPH(V$20=s>8^zwg0Q*4j7u&qDyo&@oX)-iKx)mo+#V z+egsbaJS^Tr^_?%H&=a--=M|`bRxQS{M0^nlKSUfGf=>+p)bywRzaedgFfLQ49tmm z36Y{m)o<51&FJ36K%d-`x$0MuQX_~-{t$%|4RE{(Hwlk4DbhojK@87Q<`emw&(3wA z{%AjbfEN$bx3dj!#l7?JSpRJ5K7mfie-tDz!1H4t&8G+ItqaYlcyb;mW6_tGp5wC% zg*IeREH8F^jksx0t3H#!J^ae*LKnPzWMb=$Um$c@`8h20S>kOa@sfR{gd5ni`I4wP z`+ry>1!EXcn5fgKiL=97cEEg&Ao`D>eJ+4{()k5RDmFV1mL3n2vf*0C3?gD&O7!-E zt#3X#_Q`vZyZZ^6>ezBwj2TZ?d`cn``Vc@17WaOG&iQ+geU)w#T*;P;p%*Ma2}M#@3I@Qp`FD&&OF7j3(OxOft)ta%GoCg(}M;Z7s>R(JM#v>e2n0H z?jSy9z@{|7c6=-e6g3N@B~2(El=No&lrzVJs}^e&1?sKVyRz33wzpzxE0vmnt!?Gq zyIU3teK?`BsYXb}gqEb;=|8_oWAYfrcMlxf-z3FoJUXuQOv#n~^Nx2ml@VDB?+dU^ z-=rZz3Pbb2rXD^Xnubd#WBsHt7^?+n9W4-AZzbP?6Jz`}y2A74?yT=~MQ8El_OG;w zPpO{+l%H}f(X7wPi;upIhu=m3i-_tFXmj~oNFMSavaLHZy`Rb)lS= z!wA`r`KpU7p5*lw!Se12Y7pGi4x}@#pE@94J_0aINyt2$q1_~yNxkzVrLL2peG!Dd zh79XOlTNiyE@qJO@nAU-e#^vk0Uu(u#?nq57>i?*JKm(YgBs&(-BQ$hD(gfn&l6BY zCr57{h(byT14)!aYSfT6_G7CJ9aa7pO-nB9%sqVGMm!i?Za zo9y0_lz`?|AnBqKBm3B`FKm?ivO-pJr($G7jM>C=hMixaDgvp7W@?o6%JkvF{9NQG z{2FVn#-)r|`;A7ew{oo!#{WIea)TCPF&a)rY>Se{D)y-49mV`*P_`8;5eoNVwl|&) zVS4Wxa(GV>a1<2~_@H}HTi2nKKDUrPAuD&1Ch}E-v94cC;)1XOG!HBl|2wB#IWq!O zEZQYW9^3?Q$H2U{rM20TINm)#%Uu07&(EsK`SpDd!>TZWR!gjTjd>^Bs*6=^Y!=kK zapzE+CbeLg`O4tDbv1R9X8ns9yj?{f)nBA#^Efi+fodskA0s};oVwU}j{VxiI7*ok zk{nBA`8V@y?k1#=xyI$PPbu?LlCxc}(|bn^OGKONbw4Q>t|m9K`H22ZYhWNeDx#$2 z-%_vgL0U#sNO~v;Q6+h&vOR*O*HsIh_YWzaXoVG2(1>^e+?8N!a=43!vC+o$aUs+G z&1MkM*7v`M1T(SuLQX~0zx;*2mH#%bTX0Xjpyt?Fd@Oxzx)B7b#To_NlNjCRi*6@G zc&OO1{Jk`adzXi0)C_{uEgnSmOLSZ`2Hjoj;esX|rkQJE)bGnYp5l5B-;=brD$Z(s zn>{sERYik9evUsu*b1blP1h%+mKpf4iNaARoC~F?nWR_wLZQKHt2kxmBr{1-{-Vui0VL`<+$BACVf1_Sh`fAzuErgU*ths98ylh*E3Zo#>1rjSGqZ+C7bZRd4y+& zb7A*~rL?#+G3>d=hcOX9Ss4-9Z&KU#Q^`=m)O!cXoy!$iQF_S&Ky0x-1mlL~RAyN! zj?3Q8v)|;`ybxE<0-Vj+eZiIz*@6&K)@nA(EqGwM61K32+V8rUjv5oUk+gjPMIssn*=49Dp)i)6KxAQ zBEOs)rY0!uPFV<=;YMIBLW9<0<23QQV~GJ*g-_O}?uyqjyaG8Zl1Gs=Da_8N!dD9HR?~Y?&Z6em$$xNH?2Aq0X$(*58yuyrFx3tBIZEBK4Xu zd-;R(E@;c=*#A9-O9NAqpH{EFNNg2J7a8K~w)MjrQ9cXGFg^n*6gR?Wjamb<9)U`I zLp3T)hNJwNxgU)e%w)v>Rt@)4t6LUt`tD)Nv>-DaFkg@bD(~OYO{uFKd%EQT$8c4{ zx0-uFY%%<#kezwQZ3My=9jXCrM3!&p#|GPTe%hsJ&;@gM*dZbcD| zsDZ5lf>Hh>i)Q59j-&dsTL#%|UNM>ngw<=Ja~8&>VoE4GVtWoc&lPwVm{W=BT0NfaAF zcwTn~l+RlB5xH3J{H56Jy+yaK&?}_u8yNl1qoR8gw)CLC7E3&YJ z(x1$QFr36lo7w9TfvZI_*{RCn8qNl`G=U}0#b=hr%967GIWHST7m#69Gzr91MwiGC zl0Wztd%f5l<+Gj(>^cNnm9Di&{^NsMwh1e>MJ3)5pg}%e*Z#4RI5R4=p4#C6B}-za zlW6}twmd%nfOJ9)VPsNsNs<41#l3ltZW3*KpwxoJ(Qj^rcmEwDYYTrlY{Zb(VTF() z>ojw>=mOlh<-GhNi2~!W)>&c%z22vvP=wkx{gOGasNf@l^;~`c1H%TKnP6aGK*^AF z{w^-m2{n;hvAMBi(WKre)61+xM3kc7lBi6e?r1HoJ0_a|CthxDO46wUJ!zdoY)+Ng>a zs8{jt{p&T7-@Xd}VaU=uF|y5fY-e;!IXtDj09m9i2IWCLo*Y{s?Z~?xvTw#T{!4K< zC3Uv;JLM5%!qO*E1>7;BpAweZZCHt+u2RlFMUXET?l*;^OJGPr28W1eVJFt#v|HcU zB1rfp=ptH~5*<70lQH~b^d-)R;qOD%BXIbaoG?2dIBuI!vtzF4egxeXkO4G?Dp_fO zb7HBXGfTJ4io(GT7-uGa!Sk_!^J;h>A%NnURzcuTdaBx=Y()0G)mXd&p3`+QADpgpn>1_E*leT&?aIy=4&xYVaAArw$6RR zZqZ5-ce2OGTzw_;ZV1E9tDW6p;bb;KfXuxX4;_3*BpH}tUqw&~vhM|Iq)#(U=N>~X zwl#rn!f+f2tGDOKPEyj{aU^YEL+iq~j^9DUD*UM)d3CkX7*hH43(Ku0!(m^DDunuV zT2zP4gijDo3P(cbY$m9?(*R$mrEZhNgyMEeE~96ISv;Uk^ymPz;Td-*Rts~|aHR?^oOho5Rpt=b#>m#awx>@! z?Is6S)1&xCqrhjt=Opkir|UxGnb>+z2i;6CE2x14)}DkFkBf_4fsRZ#lgURKhhW$J zuQb;RXvmU}Z7k;igMFwz%keKBPhKwg>VhXwN|oA? z&G}wVS=%&C&UJk-7r$EBSYs~`$%nf1ydNcVyXHyOO0ExXco9zB6)IUJ_^-alWXPDx z?eF%MlT#PFvcVC2hNhbu7&^fxgmb;uOwngK92+Jr$pMyM?LVbSl12u7n`HRhoszcy z7fr?_cxrb-K;%zlZVEvlJt>N}|15&J6evzNAL>d+VL&do#{uwE&*P^_{|po9GupDm z-6+JA@p*ven#NXE%U6QIgn#FC?&gTE@tk4rn=FEl++t@u^u@&A;toapg z(|unV$Ymum?cVSeC2NzqF{p`^6gF%G#be?o5i?DCC3x=1N4!XsZU zg>Zf(%*;toFzw%K+lNFMhMW3hnDQmmKM`yHOG4D!D2}DWrutLfqaC*bErq;-^Q#KI zhGzdU8(cI8JD0%T1wHZFy9HP$&Vx*9hjw?4h|x zn6le@kUN@_Mqi)Ar3amWn7BmE>!V8d)wTasV?KMN&{4(ThwcX3UhC}FHL9pDvC+B7 zwLB55uK#i))o}|dQT!Q5!DH#c6G#15tG07pqfE@*(XOZ32MMTh74k9RM*;l6YjRmtp%Z1husUB_6D4MV#Z_R5tV;3>4<~!ivBgA23F0`$xslyvBLUlxp$pMw zC*)hxLm^WFa|Wmt`{QtV#jI*t(Z#?VGVf%Z&Ql|*EDJ+moC~%@H%};iKE^R$!{AZ) zkMtP7D3BD=>tK~5Hx%C~f}El2&<%*H7da+c{o%HQ9Vn6dw)W{)WsbC@p~i$s|9+rx z#tJOso%Lx{Qn8?8;l zum*`AHxMfl!Cs31fN zhLd(i`*Ugu^DB5a?xX9TarBG(kbZD53-#qu?&eWQR`L zDFRg)KkS)P-zlz2E67}dgU%JN+0^0p+*ca($Ijyt4OR~Uayi&-J>fcyn+ecq!9gg? z9eoTAd2~xyrc(Eyuo(WmxgmLAPk?8y;^2zMAAM?XLm=KL z<)iLpOZoJ@43#|y7>n1Eds|+z-(K`e3}LazO6R4D3#j75et|g`}1s{{94?DQUT_H=7YLi{m11`fo!; z43^vDj}hg2)0fXSKho&#Mp`}DWj!}9{PC#cF@WSves+Wh3$5?W0x`zh*|+6=*anZk z&QwbaJ&SEJs@$#^<-3()Dmw(PbcS{}h{;H!^Xa{Dfazg8UPrD#|4k`(oSC{L;>Sap z!URi9{G%KxDX$zWoPBdm`mxl>Xl%*OC|8Zk$M6*O@OT+E<`PuMi z;dq7#p+iDY0Iwzi;FN0QiPD8LUkHMweLXK4RF!^5KLz5#ws8<$SP=cJh@~0@{Qfff zkyUN3D!9fcCRUAdb%AD)#z({$CP3cn;)RC9$tdiA8tvEkrGw=rj;CEfXXJbcq^C&r zW&an1F>44Nd9Q6BDQ|Mf4@Z+aTP{FC$R_FlvtK!99B6@p zpF-ga?miDxk13fIF#h{f__O@l2#HygFntROb>jw;bpzGNJ&*PDFkeA8?{B7sPy3PD z8P46e$W$baLtn*$?0Yf)& z_heM2ETxvaD`g+4ARQ0bS}?&ITQ- z@IZ^PS6Q_G9oY&9xMp#6I6r@lh$%WN7aAD1bms0gfTAou<+P5|Mzvr^R6RYlE7#sV z^O9MZ6mMMx8uCu6(cw@V&6lWSizMhK>Ke3Z3R&&SWKvVEx&&KmA;&SxyuZ|`aCz}W zWos>rmewRGtqDAIpKAqUY)*>jX&`>?H=)af2_d$);|WEHBjp2rOnxAmCMeI~)E1@4 z-hw>;GD8mBJ*N$^DDu9#iuYZ=kCf)_gr#n zSX>$R46i~6A8&BH?z)A#DxL^oAHODmtDa%$!<$wAY?>Z$tL8i?`9s-{861d)Yb-z8 zXeDtAJDM&xz6WS3ZoqP)s<@pEG8+(mP&~Qw)ooi8KbgHG60~LZ3_q7Qko|JOr(`@B zu)oi<;eU3}v;Q|xdXnScPr-qVSpiF+Gx>u`>dY9#b|&c5ic%@dF(2lANS<;)UW0IK zxMuM_0dNeSlerE;xO>H+^?&Jo?ROv%;6xbC2JTm=fig(M;E2R<0b@=`au`=%PFL;T z-`(Q8ARJIMhm}CqV%Qg@!@vf#EX_-<(OS!rz%O!_HP2-poYrUGlv&~3!z{sq+I=Z< zAzuq=PPZrD*S6dj4_bc}XjPdlWB(#xn!$N78%d?1YvIz}WW9IIf!g9Ppf7XUVGSIN+sRGp9D>8pd24s9Fn%^JmaMrTCYrM=wq?JqGu zOMumTNaik_CQ~-fLU=R$8P_B~F*aC`tD zfHLP-iKlB8Kfm&%4FMH#3#4E7;T`Tg$UeF=oML-RvO{6bbrt~ z$zQ2Rww!VX>x-q$e(TA@Ff%-;>I|Objp~&HWDEm!>uO`vscxg;78OF-diPsW^$$83 z38asjEkx{$0*DMBUmBMcHQ~wq8+mw69kgFT`-_1|2~zfFZBXMr9XOqtW2y>JRE$0t|u+7qrl(K9h0*^1)F@QiMfbpTT>4gVU%O z;G9?Gp-u9K9Yh!EwdEt$;L-Owj0)sbMXxSgo~bPL zJ(+ox)b$A7&$6RR@b2nuFYkFflB_%d(0hjbCeFfmEGwi-Uh}k1D;lao=Vzu@&Ln=u+oLhPOO;<1KwAGg@;6 z9eFJrp}(q2IcBz^+`y;;vR*2i5O8S;2PF2O7q3o*)d2cnoAkUyf{Q_uMtYz z&hdKhPXubY|JaJ&$k8Y)G}INJBPLM90lUR0{_E?DOG(z-D%niTM!taN!myqa3YsYWt* zfVzJfyG_*0{}vHW*r4c(MOnLHY1Ma)dlG2iD5{=%*G;*)tF2Q~77i)5EdFfD z@ZDc2dPjamrXsND5Pp`-l`sw+*lR+lN9xe_8+cJgwUViK!3D6?3t`=mMMy#0lNSS& z!WFwUw1>GmT=IDX(IBZGS_YP=XR4-emjqwq?cXbyC_2;<#>!=s=={46#v#F#eZDDk z>zr-kl;AJ;X_E)c!GkNvbuMAKxdN#&X0U@;=$6$?#;1*MZx||gXfw1-nmYw_xC(BC zKA0Q_IBf8X+72oX?>$*}^@|5(i#)-4#xII+FI&uI=gLE`ZPwxDxI672u_o_|ERYFR z6cid>%88ahRv6y4!mfA1yBo*C#rba;-mB}muQJ&L4Fk! zBqI6uyb4sQ{eLDyJlL{#5?kYV)FzTlJ6J*hIX3Kh`w|m2C1S4If@1QreQTp5k4OE0 z;9fksRX?E2NSGsK7MT3nq=*`VLT1HYPt%$2hSc)MeFZKCYb~R)ix**KvE$ZN4TiR5 z;4?qPnjGhaGLe7&p=omkqlQ?x{CoFqMRtMqK$eg~c|CRNNlP~yENp6j60W%rW2p)t zU@nF~Vr?u5mw&QGk)rbO)-o4V3J}xbXpC)uGa_`2f?s?QLGaLp4Q62&>q4zs)kNiJ z)k0eM#;1k7Ys5Y z=v!t5lyh|iLH^lDAFt)WO!gnJ%=IPq#6@otrgg-ZsZBtO!8BzlC}ZaS6tkGNS%>j{ zpHmtX!Q}lY8(BvSs35D$?39_^{C?KM2iJVPup;+YO(@hLF}#3{1E@b9(wYXnx!G0> zU!t|4^drWvt{PCkgnhljMp1OhMR@sHWj1w$cJRM;gWH3YVqj5luN^K131@|I`R=Z( zkE9#IhIR!((56d5E1ehyzBQ0PxGKKKMh9FunpIVkauv#*1{%MVHzICU{fe-s-8#dA zNnpyvt`JkLB`@!0-A_z%MVyWMQ%@eEM78sLKFBus(Ft2Yu=8t$<*Lm@0UQ5%$*o=f z*mn+8$`A7ilnXO44a`m=U%Me?%$LpPLl=K$eGz9-cuO@uO|1SV63eALm2*o+IG(v) zHJdkzuN#fg82iQGFc95#XU9Kmxn z9fw2c#U^2GvcuGwQ*}{);YRLQ6?gRXlp$k{buXXcN30s*wuQVZ^CZlgJm-C|M@D#L z?T^;_9wfOgmVLCZu$6C5-0v5U1};G0hUrq!)|p3fE?MYGf*2ZBydS$8X)ti1BfPa| zZMqUvD&6C9YKUAk%Y-RYq_ZUU2RmQup$1ED0O90rj~X2L@h(`~7{V813cqd;d>!9r z|1%*F@WJ1Cc3yHeZ6P5&X@u9eJU?LtZMw;kDTu0SgTEfC(zDla6fz^8NjA8D-0C>V z;HFmYPWLo*T1u3oe}e7sdO_DB(_ss%r?l`w$+P0o~_ zQ=ix6rls4K?;+r$qgKrL zlX&46Vmew2oki4I3lqDu`}E14Fr6E2RsnYDGi-xz24&s~k~FF@{$nXiizI030-9V? zrBXutj1D8j6xL4MZ+bGD{CjdOij3W3$(gG&IkqMcQuBzC-`vXiPIp|5GNIG`gLSI` z!`KQn-#XK|8ufN`IKP^uqSYvIFeVlsbRNcS1v&PObV?JQ_&jlxzNM!-aPrDe_rsE= zImX?WGqe8i>7&)=QM|0@!UrjErXE4w7k)6->Kc7^%zF`piJz8!e!SNJ_ z%|n6YfcPv^@@g<<7s!NWeax`k`j0t0AowkQ+=5m|9ySeq1-x3*0XM-Af#Dy%)|}P? z9ga#^y*Mm(&;jIV6XrZQJ9o{n)o|6r=m$5 z_$*gr4gR<20g;q4AaRA;$KTXEef>Z~>FfBJZzkoReDO6o^3hrTx3|=*E;MJ4Yrev8 zq1H>Xp&gYz)X##1<#HKm1oKejU4p++1UQ(Y8KUVn#U_+Sg)5XgQEwH3@V#;J)fzH9 z3EUQdGQ@9p&DAKOGiy_t4PuJW`^n{TDshGBHC^~SVmX^LRmp!d{i7RUYcD34uHf;O zyYpJMwoSghg05iIsP=dm<=lnNW#fyG7ch#jL~yX$91)I&mQL5A=9{j6f74P)u(=yW zg-7yq^-5(fs~u^3B`#-SvZk|+&?1Rj+w#ya3|18|a0w zqM`-M`~fX)Ep3kd#nhg}ITV_BX0k~seA*|BZrA{eUy~txFHu$AVp(Dd6m@B3wuVz{ z(+IpgZfTb}$AQwSF4V6P4APF(nUq^qih8+n%E{(|mtJ`R0snoDF;YJz@xU0FSIrQN zc-3CtyQ!|9;+T3poQP-5;oe<$w8s|h&1 z2mo1!aRz-9Ku=cHUXg-8Q;(&S9L#WKYM_NB!vO9Y5;Z5e(#XD-Nk}iVR`Iq5k+9fy zZ(qaI^<@E4^cAM9iHtR}vKU&aO^X@W9rdrqJC8=I_uLgwQ{+4}}lEZm~-ZG!q6p1RXF!|Z4Qgf0Tcw$AT7gg6tom%s>d`y%H$fF?GeE_2sT5ZO&hQ@yX%87jP$l2)W!E2 z|6lYhTP8w8Ru3-@TPu07A@r}v{{%H{vXZNi^evrTsjXl)tqP5Bv^Cp~If>#JMkf}@ zUcSiYoYK3|t#XwL0=j4(O66{6=f^H6c5vzhFHS0!d^yp%@Xl$7S?(LM8|f;Q)`WXZ zXR3vUyBj|^S`w*A&pfF-R&mJbqW-8E)6aoqf~5^@n;(WKF-@!2QP;zZZZ$7(s)7Z7 zCwdL#lYwI7C;PL8HSqUuzish#jdI%hQT84d-)gX%znEFh1pEmiBEw7x_l~X;O(rs` z%uPT_Tr9II``j{6u<@*xEI4qr=Z6+7n}g9R`=b9= z>b^KF_~vSnhVQaC)N>+FC^6`h({wfOnbCGM+Dt{Hw=Al;F5EGAtjsbX2Wf=R z^DNE1{q!{ILhYlHoKq4dKWTEcQBo=5;BwQQDuZyc~IIC|dSGO~pAHK%N2I4+e8c zu_yGJSD78Pl-}RDr9m{iub(MVI|iq;H&NWvmmuxQ&YR8G&xAF13npUZk0>0sbPVe8+kbuq^Ag7Fv``vph8G5F1QF1esz z@z>RGqY+ps7yX55F3G*aJAQvQr8c8#jJ(IIxPK3WJo>o$KHKqV`|9&2-wEnC`?4?N zWZg2|JYhrLhtURB+VxpUnYVq{9QqP@6D-Dr;BD^TbfBiHHLcb6vF>9N@M59LnrTkc)K72hj-6Y!n8kG_CGP`KTv*^WJmD#{5fModKl;0 zw>>-D7jS^xD2ofe=c0WGs(ED|fW4*PCtws&wnZF%ZpH1AwokK^xEn#}y@)zC^HfP9 zx?sUaP&!L2<7BgS3oJbpcQL;B;0;!2J2!_{tNXL4f#>h+GW$D}zRsy{v%k!K&g;K# zazD4R-`VI7hw1bm`nrJqJ-Gc{MgaEa4wyb|k#&is10@IMur|v6GObQ;ulD&I%#+ry zZXtL~rHx=rNyN%yUY32bU|OfXWw0-&S~SiCf3fti%)!m*Y+NA!Om{IO``=;|f~I<4 z&5JBS)2tm$LVC6Mk;q%CR)7r~Z46xK!-2{b{P(XyGqjF+6vxNS{cp9@ZWuFovxF*6 zz<>La35zULDHV%QcN%3?*$b=KcenWmN>v55Jz$PBXgO*2^^`;f_ZY_{@b5Q^txdvF z4{5ZtrCtHtl;lS4;8t5RvCdCT8k%f;0rtBy^)rW2SYMfZOv{e|m23Ss?m5q^Pr@(4 zuMVC#ep_&1p*C@E7x3UDxSM1@_`DVGEH>}S_aCoGz(are`I&wJse=dP)g>&_IuK}} zMkwS;q-_bJ6E3hB8T)5F#IIp0lpqbgPJ71WM`}j=EA?4yGwr)-7A(eT@O(iwBnZt9 z_U;*a-xf7Slr&E2WLQiNu5D{>L1CjaZ`Sf(X05XxM-R(?V#@66A#xu%_u2RQ6-oDp zzi?}_D6MRh^f-4j;1$#kK4DtUGQZLRYRnSxYz#?f1Z`2p2~XwkR2I9qf9gi2(%Z!p zg&T&A;eYF5CkKhohsF@M_>_oAK{9Txvr`X>kc*1Lq0Oz4@JDmhf|>*_nbJKY|3koL z5BdxJ>vL*1`AD|e8>>SovEMg%1|Pd4<}6%vXnkuVkBweMrOHwW72-L*1y*gHnX9zc z!m9FTMu@_)(x}e=2zLzYM{^@CH2DNTK$)%MjzsP9!Eu6yp@ao(5#iLvUdcnppAwK+ z{)}zVS5SC*aP;=TK8%dz8mQVpMW)J{nJosqTzv(&i{Pq*oR#O-3KMPiP^xKq7f!=Z zemiVqd=y1eoM4hL_o1)6o@CyHq9RACDB9#yuxTMw9;5}Y)0$L0oa^NjLlCTb{`+WE zXTwj{A%7W0sHBUH14@#!Tu)hI%2Nid8V>_b!iCspPZ;D$m6c<@M&LNA4C5(Mc{E!2 zdQ+fC;Q^b8i^@_6J^xGgdb`{4>zRZgazRs1H0AdcD(qE!0dQfKC-;<)$}!Nna6 z5(;pF{vb7%yCBHR>qvI3GFa;JCuLQcK*e~O=uD_Amsz~XZbsGWMIA0UX6`$Z6=lmA zGdQXXAYvBZZlmyz@mx)R>XOkJt8ku|r;D-ApC_g*#3E?$88X-vDJgP>7NM5t5xj-b zUy_$CVWeiLyfkr$b!%d0%IX;-j<&wIMsPv(gKaG>8S27*oFj62A2!RzIAM4;PCoxF zs;~h9fD-uVS3|Zn_xp8h5_h+Fq(vK^2{zV#TZS?MQ9g@MhOqvfPqo1mVJpKS!0U~J zSr(-@$-upBxlOg;L)4)?+iDcd2t|21?S34AjKj?XF%$nPM`PGPCq|@=a=ykT2rja9 zxuq61{LusdTUJD{Na%4|clI&@@-xM5#WtwK1+I-Mc&AYE)82@fPDLaYjEp9YAFoSH zwQS~GO!udbx}G@8p1;!b`~eZzR31{LryWBxz+heG&`V$t-Jyn(GqmGuQWRmWO{o*ema=Gm zK{tO(MLUc^Zk7y|r%}jBF^~^uNBQR&6?Cr*4wGAU`Sb9(1aNe^-SH2c5S((lpln6h zf9aC|=3r^q (*NLm#-3uBA1RSnnQc=qfwi2Tlz~-Y;{wL9jfF1VmXu}xII1_(p z-<%W|$%HT^VXkYbXO^+>gNW8Amy_i76+^D{VY&0}GB2p8l@U`;y+V1DgRvfR0|nr_zBFOe9~I{B$b+f_5!Ckvv0JT{J13B z#^R_1SW;q)DhBW=ajkgRz$t)9DD3O+Ay;|a25WX>itFzmC8akVTY$>>I^PX|>q-c4 zAP2xWSeq?a5`$durouPOq6hcsbFg?RTLHvyAF|0;;m2LxE!PL5&ywnA=!-SrOiIZX zN0LP$im8i&@RYCwt_y1I?udbf4B>|o7fcjL{b97LsQG;@HYso6 zo+R6>o64HOq>ubZOa;qK8b~W0zMrF(hCOWRQc`EcH>;*Jz06@I;XZGW3nB~2Izz|h zNqvM#fj0z*irs2w6{j8(Pp;6&yaNw<)E$$KFwK8FhA<+(*3fi+XLKrCl|{}jhS!KS zv{2#@B{=yYU2B`cT>)AbU@*`V4h`UtY!IBcj5f93F$=VFBYirJhg#;oiDM76JjnVPZOZOQ=WPBU>3t+2_9$fX`O@08DytUG)y+h^E zS~cHd%}4LFAZrdOLMPM|0Nsg%;fjyPd3aB!Fr1Nf}j0O@Y zLO8_O{Wl*Uj)331<4lSTO@H*WHRh-)>GKyh z!PrjFxOM1+O=ftOrGHh?l>s`3Ki6(m3n{0T!k^1?LSOx5Wn`_I5XDpm5$o4xxJBPW zC^Da*;f@3zRkjYdJNXm!L>t7sQ}?A84)I)!wdj0kYxx#A;F@b&mITbjMnI_m*s!?N zVnQGwhi7RfdEd8U%Izs8d<-4fOy@0&&FY=!EQFyDkT_?m;K@}e%))fkt*9Pq0{pPG z_@BFrSW=CtXE->i263eZ4eN)uN9_br@aB+z>dz!5MmJ3%vs0RhBr~kAvkSM|Jj3sv z9QqU{b@@imXNRug1D(Gw&O-+g|7YFt>RTa-3jqlmX?XF#z&q)YtAAkMTK;EcefR1j z_$|TB_tPpiirzLKDRiAM5@!RLRby9`eki7#UZhaw=;Q_@S%7BWR%Nm2; z`kq^?j8WKimmogrC{ToY@7&j$yRf)@#0cIFNa13 zot&8RJxJth{zbmbdDmg4WPWie0PTV#gRFg4j*^Sht&p{Li0ym_73!Zoh0O~;F{5Da zj>SK+-4wb2G_4eou=H6N&D2O1S&$k1__-OmSH>No5Cwp6&-38w+@V1r90PAYz=%)% zWos$G{2F>DCZIWwuwg^XQbY~W zOgMQJAX$s?3?V#)8&zz>gLhA-UZ|Yxx-Q!D40L!?M8m~hk(MVj(`9ITs~AIR)7_oW zI)N3h1lA&%tmR?^d~t`9TZ~hpc#`*t#CK?!!o!b zDwV7yr1~*sJY^h62v=a%U%KlQN@3RewsLpKSk!`#mm+lmRWXiHoH|`@j2CmweKWHM zILSblR&uk4Q6>}6?{lh`Xy+0RIndQ=T05Q z3!Y`SANUHtojaIF<=)t`%7y$6vMJ;Mzp{78*MIl}WBj@a>yf0j^uYF3(*8_z7P&i( znZd_ybf}1L5mK9h_mY zw(bhE=x(;*8)%&0nA4Zrg;Jf9uRJolDzp^7QR@^DNLXl5Oa~6#eRYGiKXqI*pCEtXLwh@S4O6@xL&ZVCtgd4RAgB<0*D) zx}Vfd@j>JNF}sZ_EF7P_3E_wm#oHLSj8gv6hhOW^z@SuR+MiHxjuo1wfDFUCv#HII z$X|%giJdK?HhS!6)XyMBhyQ64UH@Ftr0jcwuH#cNTnWVFWQoloUKrFg%#=;ud1j-j z#gJ?nLAXShf3L-XP2XXccAc_Ivl@`w9W@6?pGREUI1;@7^VPJOFtl+L+yQQ31nI+<`*_v;9EI$1cijb z`*rX5lVvx$nHBm{s;a80s;a7(j(6L_YFZ_y)HYH%Tz-lH?ub6-g{y7c`VPk3!Rti? zNO=l4Kc+a=TV7N`TSM(O(Q~3j?FsxLi-q8p)ggR+`)~g$;sl}T%o+i$_U;Nu8>cKV~_`eVK z&l}p8(~hI>Y=MOa(om*1+oA9It9le%WuyXNM^P$c11XVUlw3#Yoj#@_#>g z6%!B|8YcB6u47eOaMYO&7go=LG$AXBLODe0FnBmR0yrL5?M**H6(JaN2xJi4K{5w* zsC=^=PdF||9QI&&UAUW8%W4gb8`0`G<-$C~I%Yp~k@=U1|U^8E`5s~0#%QGftI71LLp z2(_;L#a_H|**;mV)IQT1j5`|y)ZPJT*@B=TylQ0{z)fP*ry94wQ~x!;YnmkJIssZ& z3zBFn(w^;lWqKm2adeuZo7;}Mh~(_K-h-*_>J@cwEYlFR0RbXhUF=^cvGE)s^|A9= z8pIh;@2~e=*f{}JMeRb5(|7IK93iIi#b)D!52(sRyvzSFvXHP*;D)7aHTamY%@*Ho z0ULp1p@lzypV2VrgP#m;H@t?2*%X5Q^Fz6ieG-yTF!Acpd63-A*oJ3%*&eke*|J>p zs0~CA1J-fgsnAF^X&C2*pb{ax)C7-{_+7}PJciS}x^}gsj#mJ6yja*^@X&WHQ6Bq| z69dhP7|558qmBVunFD(d1AsVQPkz~3C!~6G;~LyD%R{|}K}^pD!2EFjiKKa#vh1;DLPXl@ZBFKH2XR8aB_VL){f zF%*VVqMj^|2gUd^y-u6AWPSGo_o@!0z5-YnYi%7>?up3De_9_;UvfsLx}rKP5Ye+| zGjX{ex?tnH5Bb1y*oi7mH#~YM)H|T$7mPuPAZt(@E4fupnER5{wh7nz5Ll(^N2vzR z4j8j39%!_09LFo3I8B^b7Tao|oy2h(jvOf?nVdP90VE(ORupaiDPaWvV0^i*!L|7| zM;liht?k65lz4?%prR3%Qa2%MUgyJ|N89)isY^`Yf^}0{B~vu)P**!$9PnD$|7q^A z=Z=e_sVc1Jq72aRsXkA0k4)X{h0iS{(YIR$SrPP^nV*->H;p5HMGL5CCzttM&<|8g zgeWewg8Po<07=!Oqf;c&hLuW6F{l8g-n(Q%CM%+Y#y@+~pvw0ROz-dpz%E+DqNNoy znj4GhT%PXgrMw{RwY^Pq?#kuxQrJrO_#!?1`w-zQrV7#{{ zn{H~~LmPUvOuuTsas}|nqInr`#uSzPEtZt@lE%C#ipX<;3>BED*4Nj(oJH9RF`626 zXx*C+2g$XpAZHpUk(U*ACp3iD3z;g!r24FL2syoX9@yNWur=-?mhAHn*`@}-Bd6EI zdJVW?M1$bi#oo56 z6O=Je%lCCO5Cwan`T7g`#W@?U3OtGkukls3r__*-wneXS2yW*;oaaZ*q)#0WAlaWb zG98gC!1T(2z|LfXE{S~*FeR87XczPhJ+O;++l0Dk_2uSy_TWI7N+1vi2V|$eqta~| zMuQxp5WiUIknX9AJ-T5h_tuCN6DL>T7T}LUVi5!L`gEhxwPE2E_36t#U4=Flw zX<}Fomo;Exgc)2B?@pC(={Io7tvIPYjIKcqITlga1mjA^Zf3iQn>Y!} zV?NCzybct}yo1SdkEphhG6Sg-)AmzHO$pCwT9Tye1Qrqzaw)L;{#YAv1?65A;wul+ zb>ku`@46XF|kRy`6Zw`{_7ABJ$(As6Ji^e8Pt=I+ZewXj=vitdP- z4S5sm7rjy(UG00hhw33Z?~3pQ^N4YquYx?U(xp$6DJT?Kutp}aL2w*`o{l)Jc-%TZ zpLV+n#MfEf>^Xtv{5J6Gj^AE4lJ+YdgsYXw*_(fqs3gKo#WJJ-09zAEZm7li-a8aO9G-O??I@@9YrGO7b-`TV zP9rh2zmM@J0>G849uIAnEr5Q;kHt*2bf|-Z^RLmewF(*57B|=VBS&nopI`J(NA8gz zt#*Ts-LdbQDgPHHfu%Be{)v{oEL~b%CRTDk4p!kLp``(1jW`LA4i*e&c5@4^ZHRx; z)~i;w|00VhZuIJcj?LE)SL=uxn(7IGj9HZscJkIkce_(oN`o)$S4z!Q%)VT}!)uJt z1trTG+s0}}@(q|~eUR|b0hi@12?OSAf+xY-`2Kt-Jm7Z47Tj-#ZgQ6ZAdze6Imo%o z_7ZBd#b6lsOckrooC6VGU(mU{>5HmmMp(7_+~r%F^6FkwttI0NAQO>d?Bte>xUl!B z#y4kZ&Y+h4aHW;&9>mR_daO-Z4aNPf!9-Pu1$E~RlXQJ@3>000CT zH`S8IF;$d#zwJ%|l-60PPm(m&lc3#LjE;NVScEc+nk}ECc zH`^FhK?zk&?}x7k2~^H^z_^M4lV-PB1@JBZQlokF6|xhb*~ z)q@jH%d&CILvadO&ZcUxR``?or<;4nQNqFH_P87PjR4HCc=fGi+pJ{Z=8%70NobJ{M$75@FgkWX6Rt{Fy~pT_$&v?2 z#DkDJ5AZO>+2SDj%gyW?vuh@1&C`?8;wE$rO$o<4D*VjlF$-ircb#5B@-PDRDgXcj zHgRz!Pz_HE(FRZ^#q%R!NH(W_`7J4j{+oZ2_+8g34Rmj@RXuvuRz0+2Y|*Vfc{^X5 z;@xVZU~WPRd&e%X2@$qb;Qou3q%B1(`)mFub#)$=YXRBb!5DhjMQ1m9$VpN`5Ma{^(^+~jtI_Fy!?GYCsOQg6qeVH>rpuEh;hknW;ovH^V>DtgDwVnT^EMx4ABtC@X7Le#L5fea--B8r zPx1hj3G1GBW^kNxWf8GhwL_gJ4@gB1`sY>7cK$Z3zVF*DMjruo#+#{=U-WI4m>LHv zerr7qa=>1`Tp_P-6QCD1$7D0MKDjF;pMVD*~iQ%mWhibjW zDiFX;6NM!Z%>^Xd`Ea8C!SEUz4}ca9_a)T6)gD&QOU~2aTKQXcp!;&kzD2 z&_lRUJqc_fm*y3XvJplS%deqZz!zC*#3ROXcwzeR71HT;za)M*mcnCm0sULZO#02- zL!j+S3QDJ!E6&SYq!mWPVdFMvosig)`odui)_>^0)yw@&nyK_26eZI{rX}EIW&AA= zWlyTl)WeJOB#-;H8ZjYMNct@3q-zlIAn*ss#hozog)|*Xx`UZS8Z56GT?+FfhCec5 z??<1-i1%+7wkH&*-bt`#mSPL3|7`)AXs##Yg$_)9OKjv&%NYK~8T-{+Ys(>EOorB? znG*wza`#|=@EH)loraa)l_zrk<8Gq}y$uJwu%{xuMvVf&#_U!b6B~^{!oom&)-Cz( z$F9Kn5`UdkBDycRjm!wqZdMFDThkehCiIKswXBaJ9 zi;f_JCiddP&vHtZv`5^cL1AxL^{P{?u$SPX6?|0fRopV%xu~hU%&X#F#%3S8x{mem zvrSLQq_YhH-5tVCcbow>e~)##8EiQ7o-ti4F@z*x#vLbTG88|c$8>KrV~|;`K_wb- z&NhuMZ~V)?k+!mt%yk-BK^;}CS5~vFdJV-U9szb*v%w#>NVU&(XWll6d2V@rTsvwP;m-MoV>UVqO=iX;Hsrz|4(?P zVb$A@CZrv{=LYDb=w~yI&Jf!W2NDOmuT0Ruk~CTE*Ooi4ZaC0`3pCg>8hdXVlz#P( z??F=x#Q0aX{))1DmT2K7f+!yKP#bBB7I|lE6!Ykq|9g;HWxUcSRYD)2rxO?CRI9lkhZhSynnN!j8KFK|vxf1m;sg2ssNf z2-yBQJWJkpQo-zByGEDNHGk|ZIC!s-lE@ZCxE#uqKN(X82h37WusQ^8^Kj&qC@fm} z4&A2B+rD7`R?s<7U1oibZ0LClw)bMDg$Ja6{2L~0bD$b2+#T?u8T9PC!dt>uwg?c+ ziH_%blg-(%m$H=Sj^;1Qwq2#P7%7kFDBStrFX5(#34 z`REkrY@Vx21&8M8wd0`lxT4Zg(NFP0)HxU_LzX-FL!}K1?*n(eDy4_jWto!^C-ajb z>Z;yy{nq(k0jnA8R~yYEe%jrfjhJ};Q-SlfA%!N(W~Qro^kQssFV6*-+viF~^Kg7U zE`Y-h1p?{0_rra5Lgg}JZhb6Cb++kVYi6~l#UL)iq#t`X=6*8orDYgWxV2E3sQm$L zl7^{R(UhfJVQ*n3(e7#jnxD1yW=N4K?RT?USS>)1krq;pH=1`prf#mK@eXA1boTBt z_S(W*lp=m*hw_tWnm4|hV#AWh66{r&h+te)f>^@tC*ujby@W{Q-*LUqP=~ESqyHR-<)un^ZM2#APrT>}ho>aaha7%ZopsC{qrdU?Usc-)U;bF(ugF|qhgbvi5dNQ2l8x85jeHV@^ z^UlMU^%{>`O6=&QyRY+d)!uV~3=On@gHLc-;djpBv&83jg`CSK)rN zUw~rWTZM<}<#D0hc4cBBa#_e?znPak{EEb5{?_ayY<|r%1?UPJW%4e7YO->!9Q}FvqAy5)f#!B)1<$ zjiu>8nm6}(^?JG#97(qM_<82kNvRNew?C~pt&FF~(IZi#@h(Q+oRsxhQB)9M{Z>s| zsr3$7=n;3>KlX5w^>c5Cs#Th`aX~u;Q4?Ukb<}IFmFO7PpGmkQ);s!X_WT`4+X|bN zR&$C$`i&HVnA}#E3ynOPvJ!;GxAZg5!oo=y&|icxz$M%sUl8OtRjaBbCB=O!iY8wN z_<}sZL*&;dsO?co9%_A%+ABj!6!Pkngpo8KAMfgibhIWR>VQZ-KQw4@0`Y6BRD(d) z1?98(xo@C;x=MUB$lz3HhoJKZDNB5>XM>y*5tge7UzI#&7{&R#yed zZK|7ve)zs#IaTa+&D6~Z2gB(FOd&h(i_>``+LNTzBy{F~YlX{d&8%~m2$eR9zR26ue{=1TobB3-*AUPLD zSjix+57oL(k{hkr&~Y8!(^s%C)R>l?Z`SqI_Ef z>P1I4YW4Jo82@T--`&^fRD2E-rqvEvH*4cIH*eMmPl+ti*;{`h9Pu&_KRCYdXp6b! zlLTY}yDmj&yQo7GbNV6gd=6f-+-Na+E#DB`idNcdQVs~rZ!1O!$cwIWhs+0bFU&SS zkIfPv?2-(|9C)YgCY$l_-aU*}zzIWBC|wRPUK2#I;|<*n!;~d5p23}a+givDJ;^`* z4qSj>g48P0!on-B{CONmsR-%;?+?vcpO8kiPTaH3gOCs+2y&=d z(K^~S$82iPAIIp`nMXkAi56@;7=V3tC*B0$Po*9{V269R3W$Z;xAt_W{lU*VvVVyZ zro8;Q{1862<#ptdr1)#wQ0+u$vJvUyE!m&cW>tm@P9f^3q!?o1xFA2WwY$85e$m<` zV=U!enY6L}L$0Q0F*lJYjWSoFE)AE7cG$jtMvvIBJrn07SQkeG>h~#>B|5?|9eR9G z{{6%^0hwfw>g|lT{|HTL~{PWj04u)o`f-pOedm5A5ZQZn7P8MG>8?;lbUf z+3RM)LMrz;5Tv46-5?c_$ouXU@9-p|Kf$AX@?XFGRR?6iMrD**)f)c(QaZsyv&dD~||E*%h{a$Ald9L_?3xLlPrel-_&K1CXu7!kSI@ zW|~<&@U@PJRB$hVd~dvC6s(yXT%7+l7h7^QqvWCi!pMRZZwW4%WnA^<3oK1zy;C#1 z%cnCs?BCmF*RdAQfllwb^bjLXF8zbEQ zS#xecR`A_P&#Y`o>H_y%Ry}kuY(IWp@Liecq$Q?(-(+t9(_UtnSsHBM4rgNWqF@?Z zMbMbyM@Wgk&rs86s4{#&HmPzMFeD}}IbJkK(YXXlF8jRHMQpZrJ?K|y?0`lsNCwCU ze7m-AM9~GiJ)7$(Euod^1w+2mqA@gM72te8W=H}nWWVL-Zyb&oJ3ipX zsnFv93UpN@geg(P*LV=ir6}l^ZFl3XT$i(@8MS%i?Nf`z(@k4Dhy!CREMLO?0T2qz zx)o-+Q{9|$9pyxj+x% zUc~a8Y>776b0wP@`&!Li+xY5zim*1-2M9I!fySTn#tC2>$~l^=~5 zFHrA>NSR2`WwIAbeugb;8Lr&pWfVuDT&TyJz0V&Wj5U;Bsf(Fpm$}1zEJ%NB3EQ$P ztTI=IKT0Nf+#hq@vEc}`5lbLhhszkirGa@Ztddtl&F;c_z9^(AkoG$1Q7btTvrdQksmixQD38JZBYZ^+l42;dHD96q@q?E z+(NrH3uh-9-jjYej0;cXm6a1-gRmvS;(td;3 zl*(;r)*x=}*Roq!E$aG#Y60qMSfY_fF-&f*i5A-;Fp>rW8qurH>};SWn{~k92*(rc zn);AAFk#f5G|9JE+uMO>+NEAlFzc<2jffpFD* zL3)ihGGPNuVQ;bcRF`yqJE-ln#k(|CrhxG!ryN}I)*ojIM1R8jthY`^L+YJe05#<_P^$% z{;hzIhjhL@(fRtDzdu9ct7-7`Kj-NGb69^i(ER&r^Rwgm^*865#{4;A^MX6;tOed9w{>yO)4}dwy zrbBIgdq5{^?7%;9b@4P49c_G`8g^Eok_tfe#M)(~^@vS8^|RQJU&{jpG*%x9ha<3e z7M}$mHya^&3%W;ghhgiKVweHhP+&h|F=K3nZjHwW9aD!Y!INz*#Z^|VHr%i(&L|h# z>pO(o9MX}gU1uyqRgMio`~Y&ue@d-sFD{062>5M>T`4=jnV#vx$F+TL6R2q zejrLK!+|}aE#&l5SCkwElIhS2{Md+0lk_($t!6(e$dlC}{q(Op)vOoNb1i)#fM&wE zsou<6ifHmkujh4AUcVgfIz-{q@?L9BoE$}EOxks{m3$Ylo?zs_6#Gx}>(+Lm$iR$7 zN0PWz#xA{Q!ncGcXZ)qA$Fg7vOexE9kIE7 zGAxzBJK01G#9(ftG^5j9m?Ib8fIi$Jf(XVFiyC$gxw2`2O_SOV$SeOO-i1CKvyZo% zenIKK)3sY)QW88r*PS~@bsdl()$r0mqI(Eptz_R*k@|pL4TL8%=p;4GTZX=GrBT_e zf{u%U{TK6lX3%`0;teys&WsF+(rc2?wv7#r3I@MC&O9!9Q4iGle*n3RjHhr5eu&t5 zWAs*{8J0+);++afGPf}OdAGDF=!NMPQ`(k;Ej#c7j$2CP3pk0p%KscXv_Sy=lx$Dh z@07;eOg=6@AygIhBnh!4vpZGvig7KN&lK18IO_ao9k*ehB38(V>aPmuca#3?wOf-3 zfXt7|K8ebeHCz|;DYbO{vI}+ItlD~sn^vb)2A~?Q_>T&_C7y0Ojo`g((w=mURoq_Z zNPobD4Ew-l2Kv6|58}t_tl&yAvgZ`jBuy`BYZ|L#IX3qMumuitn_J%+G#Jhx%n_LA zEzGKL*fb>IlIf%04E8IEGt)?zfy3>Fi>hQCm8`Wu6bOsr%R3Z?Py;-BU*RfdT<+kn z=6b|@AS-s(yG0_FMW@;>bt8}O#sV=*Gsp1^j15mbAmFD%joQQ}vUFVY3*ZFxr*cwW zD8ZlecSaB-bK~TBi)Tewbolt_@~FE8o}J^;>T7t>?z?=rM=%Sxp*fpQ_dlekIf|u0 z+SnYeh6s#7WQ1eXNNgERko=faw-#-z`}|!yE>=o8O3;{qZVm@w<@&O;IV5`G}^qa^5U}Loal{6Kv zcWM>ZEvHImshSYcPsiGeqsID^Ajyu25F%alAN?UYLJhe;aPYkg%-$TarZu@b_gnj` zLa6x4x~twSl_t3nYj6=r>hMA5V-3}zjX$VzvgfyCV$$lcD2 zLD)~7-I=HMrBpP9Gfb?^58nGqh$IN-DQj)o$;wpWx@E@SV5*hj(84-PHI~=ev?G=6 zNhqc05Nf0y2Xr~ztE?cBo_N2}Te6=pYFpEEX|K)De|q+L$urq{z$s1w2^YS9oN;{^ z6lXbt2vZC3=@SNvF1JD00sEb!NC$7R;k+E~F?^j=72Iq$1u_UxMy419t`3T}ZTFRj z9VbhjJP%5j38L^iTp=%2wz4Y$n+Sy|T{vxiM4*;>JWcW<Yw<9 z=vz2=cUu`TzxmLVIMiw%@!Z&HaN=ZQB6LvbZ?^{>Et?$&gu%KQvscU9y77s#tH3Hu zWHLOUe#k!A#~o{4r3ReE;=F(}Yb&H1T~|U1M!@zR_5Lj*_naJ?@p@y)5~6fceztL= zFL6bQWS)(UvMU5i5wJleB%#5I^q7i3)77g?AnutI7%*6B8!w1_xTtZNLVRVa7olv_ zeQkG)lJ9E3e^AmYLOoZ(Ii)vw2HCwWx{VT&PF=@6Zvsf zB8(xIZ2xch@GNbDv~&t$NQ{LCzq)M9QMdsYyT@JED}S3p!P+3zSU4Kda$(DXAt1|c zASQW$(PvxzytQHQs^I$`i)y@?y|S!ko$J0efa56UzU|y1t)gK7 z5Vnd0#FfogYtvgGA_9SE0(8~$HKxSA9+O%>m(Mony(N*f%3B-VTyqAmx3p5j&)RTk z+pvVtirArG>kSNLmvLfjyL$}`KD-*9~K-PaJ<976N~ z5&T=><=4PCwmF`^we_RiG1a)Ab9+BRBL??bT)GQ9C{=q30_LfUeKV!OqXSzsVR1k( zc<1WMl4sCsVJU_s`}f-)QgVR}v)%>j?;|f(@V79@qQ@}Q2s;wg0i3E{#S!qz*$suB z{?65evl1*caC>q<|6uco=XLVBph?Nl*cYCT@8MP^g4JIqLKIug9ZcQ|Kg2kC(EQK07eA2i+K6zNEpntNml&l=Q@u5l#FH^DO?-G~E)U0Zlo(DmF#pC>o0v|#YQ1gxf(yLc<*-^&=$APt_ z?nNHjo92~dj!aCFKJr-c=K}jW=WNq21{na&KkJgFYCLQP=L} z==SB#QXOwO!V9=U)ej!W3lRaOkfX3y0_3Tth}6~qmx4BN)Tzj=&8VBHe+ zxhs7q5i09#OaTF7A6-^f8y{-6uL)6i$RXG)T)kqOqvL_JnXk{2Z-UBY+{L6f_U}&z z+hKzzQPjas<2n{|9f{&)Q3y)$RK~*>_~Y9I^^A{G{T!X5rCZ2_OS43@rd9@=MrKVA z&<0c*K^zAn?_hiQf_G8o3=YSYDxD&+5tlu00)q9N7nSwt9OW#1Y{=}u&XFX1jo43c zQkfJsy635G1t59Z4vBizbLa=GFEm!nRU4gh08q1!pv#9|x}J{RBB$eLL>LRd`SA{U zcmw>f=d?YlPeYj5V;Y%l^I9cp{@<)%q6zpFNiy9MqftT=FxhwVH9HZ08vOO9WW~1# zMF&k4V{2j_5sZrS1NEnWd*!EXLs2Jh*0Ii+d9`1%9c_0{T!B-$eASTot%u}okFr(i zym&AR=p!@ky-u_cVS62GohP{O9GXZk*Evd`cLMw8 z5?!S|G6mZK#2y5Ow4bYqrhmEh*H>PM3;*MoO_; zaw@DR5cK~j)O4!_f+`r`GXkCKzG8^wxC03ZeW|sL5sHU5jf$Cx^oA9vV&M&bp-)*9Nt(zTFgsU5LS8g> z6xhP81#Y_GAwoIm(lPMbE;BKFJZ*8T@vSfKKj=B^Ac~q@WO0W9?HJ8(Jimb|g|<96 z#9U9qAkiZ@`A9lPYvLaYIgnlgHPNRyuiCI{zd2-u99m{C=5Tvc#U)HbC-BwGB{-@#H zJw%V`mCOt%#L2PAd|v-hvUJ{)R@(PSH!^?R~BWL7{8n+gMOx6)6{5 ziU#xldg;crS58%XACT}(oCLI^gxJpUaGZN8&N_R|i zG*-dfCoG@se<+wzos{J?emfOWURzbFzQVYI#6J=^v{6%7g*tzL$m8wCuTJDyZ#7I$ z<18|iBtT?34Nj8eJM)PEm9T2x1AF=+-`D=~<^encFgE1w9bhzAAmz}ToGgSdW|e>U zM#cTfeh~f!O2>2x(h2U zqrPkTH&S6H4%G1Q}u%+T~lE)EPa?3!%@? z8!jSV>T_7?gH&z)o#p10G$U46i09#>d^!JQ|3idetoQ~1@II!gcsssO)}}C{+^=07 z7=AgE7lIhQEBDXsIP(#F@UZ=&7bB;Y1jH`0@+{Ww6L|I=3yuU$6?L?4+laf5-w(nd zbklxylAB$j@x}<(SL0zJ8VO+-NJv#wy~*>`kmmzQDb_q5yf?Z?<9dJ8zznKov<`HnRv*NR+|84OWHD?EPR);6P^j^Ev{%V$r8 zZO6i7426^&PQVTngxgT=`zmPdj_pAo-Xs@RCMLA$a&NAzTj%&}SDZz-1d2y z60}dAhi$mQRiE=KzU*r{pSaLO`!rvk6k{(aGL(jtlIPVWbgw^YA+ZJXR zex3C?$*TKfE{+fF1L!&sXVm`|!E#Fr=S#_}&|75Nl7w>QnJKHsj`Q|~FevBCKoc?~ zFu_d?o%HDDscla z3C+W4td8vRwZ)(etw)KDm;`; zgFbpzPUY!UGA_IqFj5_Dj!Q)YS=>As0dQ3twf|T_%hs}?>049S@>Nx%Qil^LoT(?} z27P8s&<@*s#yp&%3QNx<&@CbA&HT zTSAW4D`pJxms3frZBaq)(x2PjG?1ha=Zt6EkjksTX1MG+yMuPUb1fs-6Yjn<;jv3;0bTZ&WtGHBHujcczb1Ioore2P6=<=PFO zyqnEe-p^K}HGiGO-xYahI5RHCE?Es?5}!8iNA8QG9R`5ogLsWQ-Zx!-xnw*n0wGXHn#xEH@$YXH`y-&NXBZ;)d z*~7-*gX&)GGlj(Q;0n$*>cJtgJA%kp=zz?(PgVBb4VuSK9b}yhD?Jz(#Rb_yTlO|# zAe)gsj_72sYPq%754*-1KbsRx@ZCv7_~MI%r}QLySBS6awIdhblhO6^0BBXXI>rRl zVj~e&`uCF*k^F%{m$Y7}&T31PmI&v%eY#pM?xF>+kN!V{=(q%jf)i;5*5LJx+C>{< z6W3bMzdZaTG(tHQE(SLu^&>0ejG9wW3g0R|aZ_8fA_u%Ysna3-LbZmSBE90qOVexz zGWe44X@6CgGpwj6FG7OZ{b+=-Lea78KM-3+_<`&zg9)v^^kFn{q4_v7UJZM($~0SP z*<1gHQ*TYpUhLDmb0h);A2Mk8Qy2HL?E{Sqny+kWJ0EX%g}>eITASzLidzNqxLF?% z!+Uj1;$k#QDPuHJxZqHazN#|6Y4(yrTDY(m*+^fP%ZME}|8{K+qgqHFXopt-DsLs zuwjWPn$T9PL@1(fTEB_(Rm1e>Yqxzut4CYdLX|Y#W|%W=sa}Y1M4pJJBTK$?+U0Ta zJ5Uh%WsZZ3#|1VzipMBfPX474!}2B}?XAOMQGr7et*z5cvpbvrLx#e6pIP{lQ!Xz3-u0B!D6#VBESjrGkS_ejpA+F;!Y zm?-WZfn59W+hn)pUfjaQVGInljQE0fZh9Wsrx{vb2&*oLTN{(%4b~|Huwa|EInX41 z2eG@*y}&&;wl}wNzpIqZERd$ODG&p$tcy5dkdkh-HCR*+o|Y0W4*VAQ^aE%GCgUY( zz(4ueU2CIQ2;8=;S98uoac=^@C1j3_mWJsJqO?UUn&J^LCtpg!L4{OmsD2HwDK?^j z5B``aTpaMmMqY8Wu{Z=AO~R>iNa7&w459uR9g1YlLdQ18kA`}$wTE#cpcJH?0!Ar? z0GSw@jebhQeAc`0osUyl@!>HeW*F^l>NjEilZ0q}fO7J76l?W)~X0Gpm z3;`kd#q{PP;phc#6dn^11f;>SOC>z-Q%bOYr~2I7scP6O0j8ky8wIVB|i{o5nkl=+td-kjFG2M{l{ zqQ%Ay@%(6mIL}YGm^>jOVea$)Yhi;TZ154Wxmm=47(raWy;Kftt$G&9i1(qOk5JC< z=iqLlurH7z3Z7=QN%MdS+m?=@Y=Wrrm$H2AKg)c-If+b$RS<9=yhFqJj9-|cB zDuCC6%O8~8qQp^2iG3PB&{M=R4UZs&Rzh_xAu+V-$^mfdg*WSTZO)&P@^=tvK`ef& zV}t_xpcTQyU`#S%lpZy6d}Nh%O!6QiWP2IO;GREgQJXy?PL+}(vn?@OI`&XRNNhOd z>^Xn=gUaO$jzaOSbD}|**AF-=4Cw(V)h&M`Q&Y_)=3_h07 z5&muRrk7FLOu&C~rt~P_u63&f+CeLeVtRDQ z5}%!h`V~jkcxsga^zs=hgy-`L1I8HGH&QSEMvGD9t;H${+fhb;8#Bwz2xl5CQd)@JRaoBqVlwvfy4ST17#gLjwp$f?S zdY@4dP3d8Um5=j1Vp?5r8kIokQq5-5Dz?4z1EX=nGC5~oYXqJqbq=3|pAS>TV~EDj zu3@z_R7y*Lfbjl$6fK|gRev!b&7)7vw7<=BU(I0r&OaqP^J&Kq=B9pX|9tmo;r|xI zetl!FT(9S<{sTW9_W1SB=1;-C8kpMd_;e}KelTJSa&nxL(Oz!>*9*1G%!&0%#UI z17|*r*bf{3Evu3h-M`^yUJ6EL@ReGgc)VRe$@@=&I)do-(Ukq^knx0r&;uo-rmt1>`%J2(RrflADB22tH89=db7&4A%QR!g8Yg zLWC0_FturJ@s*~WgM4D2L<@inv}5{D)|n=MKl^6E7i_fS{vO1-Il5s2tD_NLaj1iS z>->5Q3#)1$?u(V^ott39%p$K$`U0b<3vQs1*;Xg@UCC_)R9NPYcWor6_pBc~2pX9e z&hoVGjsINybhj4w>mn_VX&wg~zAgFNYtO~Q${*k|5OehH5j#iteB3~e^EqjExfDn| zP3p#~BhQw^We$3(0qPp*k@{k{Y8lxV2fR7X$+XEda!eNo!)YL17a8*t?XK$MQ+vQO zRP3Q{4LKq-*ucvMuyWPr%cmlYjq+nr#Eh9=YA6tvA)C09rDg~@VsGa@$>08%;)3yD z&Y1Sw`i5M0Nb8ze93`z{qt#uQKdVq$JDB|DL_L3%Fta` zpnoh1#tms?*``%H45=Hn&>^>FnS&G`9u~hj4D69uOc;w-FWMm*E)i z7~pP4{%YtlgD3*Uj(B-ZxpbW)(Cez?z$gnqc&E8+x0+#*hA=D4%r4s9pg~I;y;ZOyARWKyCHk z;6XV#ltpmYTR=zw;QVAq$er@_H{xtUE?#D?4z{~zgjiyE@SlM*kq)#UhdUchW<>-+Q@}rd>Nb_*2{~6F#+1H=if8u-d;MDt( z=2q(ktQ})NNQxBZ8#L?)9n^-?=)?M}4>J-Ej@9au3j;~%&2a3+VQy5fr(YoWXODkL z3R>vG-_Hhon?;BhRe*G{EvO*1umXdfxJbd~k)?DDm_ZHRl0SZ+Fe#a&V)No%xaXPG z!2)kr+<==Y$2=|r`X|X?Sav=XS4nYvHZRy_)u0s>zA@Z$$^Ja!lO^&6zDMY(Fm=E? z!QaAkOSHwKp+?b>55w{extCu0Nig`=jw4{9VFwHXRlMQ4!Tmd2x8uJAB`T#kw&FO7 zNq6s~k3F4b834Z8T&;#^ZwO^5IjK)4rvHAjP9X+u<@09S2T@T;@TYX|52}A47IylH z2WT_cZgN-4pAp2{gr`DfnJ%P$S8WBJQMlsiE6N*LLEj4k&eZ)uCF?c_|1G%zInD?Fgz@)7LIQ}iZspPOc|JN~Ug z5)8omFwV_l8Daim;(K_;K%JT{tenjth4P0$x7H$lNL&(*_=WHF{4@V$ViHX5t)<=& zjgWw6ntOGUv(&+efh+^*)q`mV7@9`ctC}xsoPfUq0Fh|P>puaU0D7BC~+v9j5?xYv7VO zi2;9UEZV5cx!hmG02|-*VlLH?J8{M9&Z?2`56Ve*a0j_Y@dV)alCL{E&p6S!akQ1? z#E90|?9UxS6ldV5K114H{-=amoK9WjVupy9JZooW@wzoU_;KTLh7+l7UkV1bT^nqN zS|XRZNdSaFSaYhUs_M7os2axO*s-!Z0-7}|%?DEw;qm_jj!~Bjq__Kq8@zy|q!Jp5 zKbdxx!d{Z^nMXldduK%LA=OIYh9zr#i6}*PMJR6|B+VSEQ>i`}NPY_(y_poY zQfT;k^ZwVrIVMMnbJ7aKuqZnxm6S>LAN&vgSlwF3#8YU5*kO6vFE$tD-RyEVUi4LV zvw^!3P`MvjQ1Z4<%@r?nnG{b&8rTU`$QX9sOW0jo83Te(p`Ky}AChTq3Lkp^6Xmhb zC}m5JQ1CK;{^h z|97PmWyo{9ABrcd`9zeCm=?;BV!EiRtm0=iBGMNkNLA7?KiI|cJnLCHx8lX^GY+ut z)|@(T&;_4@iHwr%I)F35;teq-R=4^OiODjds!8B)9VKNdN_mO`xopKB07pQ$zmQHO z>B7LGs@uLg8AT|3T-x4w@VgDEZd{e!{q*#p+;YB__*zT;H^{xJY@LGEZ#U1?ZX6)V zR)k{5+)}qrWV~k84&vZOsBs@MgN;NH|DuINV=Y(>cwdAhqZYn3gF~GfC*~8+^Mx zqvcH{ZvzW9h$rR?$1uPpleS~orr5HP?tGD(jmCyzk9*XeY}ic)$4g4&-i<7-W`SiU z8#0>{-e=g!HpPPxGDMB)&MhZ~t5A}ntrG2hlS|g*lEDI2Pz@|WpPM2F0PAbwIf5LI zLgGEpz>kgGdu1^f5=$H?n{!4V{M#42+PC6oqup$;o>XQlb|6I|Tk(b7p@#Lwow1{W zWP>6zNP50DNkNB6h%zr#}yD2DlgCTOcuDLLIos#^OS9o~Q-O zeb%D|ygoe=sexl^pGxhOqjpQDWi^@?@dOkg_9$s%i3M%(w7*z>!lGj?!@!dx0KvZz z64CYLg`Hg7RRJQXFVf{VUwiey+Biy4=TBX^ls7uu1i^1RDrbcnJ~Idey<%eg_QTn= z_hYvdIqY`;YJ^#&v*@0t6~r9VjrSWq5sZ-n@$C!pWb)`p5}Ab1n}qtFd1zBZuEYG2 zF!iU=f&|P9P?XI<+uNV<1<@he(h)}dV=WZ`=>rPZNXm9QDnXlj_0kQCUmcYE6kdhf zLW;Xo*g6%_3O#+~% zDUL$OuFO~VLSRnW{HrPUmKGZO#oX8NKc4`9q~`~)23rV_AHw71K_%8ArM`GeUc~$( z-{4b4+$=xI6Z+ipIA8*!**nJfDiy-p7F+2%TIDL`>^kuOzZRfF! zeQI75jdkLC`|9Q)t_U|3y3FmIqBiK8MgE$H6_+ez)5S3OCkq-i+Tr>?0G#^ny{J3} zn_QGM?F;S1D=n-Rvu$w^-C9g_NMp}0lXM``X&)7se$_Q8)jg>l2<^=r4O^N8fPjF2 zfRKPOk$~P{41j?1tj2qxK={I=xQho+WgGq7Tu?F6wQKy*&v?lz_c}2pc6GoywwnUi zy#Gcq_0Vk?7J)s#L!w~NvtmqOHX@djO`v^tl5vN-<+65u@S3LqlR5_sNQ9;+J8^-8 z8WC}u#oodFs9^%QZP1SWndevd{ogDfvpJZGB?nbbP2?*w)Ivvb0tVzof%DR|A2gN9 zn5q@s5pu^m(0`iGnVPi!1BUvp2`@HyOR6Na$qR|g)40rniO>pLQC2P}z7#VinJw~S2;=R3qJYK&5 z4$w*F{k6BVN6-rig!FF30!%!ev~~(+>@KD&{-@bQzYe4Ubb>Of`oVv7MCEXX{c7=q zlOFWeAD3K2k(M?W)KpjnD(gAQWxlA>5fc2mdR7ad#GWI1^uOGmI`Jd7I56r_8}-xf zJTy&CHGUKM61@d5^*)m`dmRVp;KoF@juw=X32(LH!B)i34RdP#BnRPEQQ zfF;WZ&rpWm(af~6a~n&blHIGm@LGmTmHxdR{pdqQPU`Qz>6ECix8~c~&U9&CI(0xk zX3)3X(tG-mO5mk?%TnqfUEip-Z6>g|RB*rt5vwt)@uIasog&S_T8W6vGq3k3d?>$( zg2!2p_AEBh$ELpAzA0`K>{h%FZ(!g|ka0g+D+p*Rcuht?dg5O!_7RbALRB@aXjde1 zJzv;)&DIddT1;Wnz87YlMRtSle-{MSltJ?Y_CaWqzOiER1r>J-yPvHcyaJPFnWb)f zo5A5Aw`ecU*{?;Q(3)}k)30@3&j4UW;enJ*9p!8Dqc?DfJ5sQi!yv0*Cls)FKdXQ^ z_#h=#k5tT|;vQ*>D8hIde^Gi(V>u!PHryONHMaH+9MXQ8fRlsvf!|;#Fj87y;u)v? zTDmhs?o~kRXl3%7cI3CWDb=%Y{HPbgGU-D{|# z$(;^O)*vVe?=IdJGkFi?qqYq4)bi=cyVao4Dk>h1vxWR*`TuJ9%G<=CqhsVWvxqD$ zcM~Xfq<>C|#ETZ%Q6yWDz?H8NWEPZw92WGm#L4LD$ugm{H@yj!rG#66t%6V zuX&o1jaSXR8k?=O&gFjJO>s)iq43@iSuJS3JxXQqi_Z^{XWA|6dlwNG_3knYGD z6~M@?eUV6dB!uo-_4%+oTpY7md1J~OO8df-TI}8(2?s&A8-hR%q7}h?F}wH? zF9znDVt0!j)X4gg^?rZrHX<3N*TwR*q2-e~k~j$lHYDYW=D-zs37{PmMteLcgK>X= zX|^mXv4fuZwqsUd=Hcl`qC%x7*O0Zq-3KFQ0V^C6Inc*y)X!_T0M*`ghIABb2IPp^ z!3>Y0F*_iY(xl9A?Yv1^Lywh>WzOtViT8+hbc+{{jeHxYFawh}ahtLURkmCYEBpB3Hg`2x%s-t zy~gX7eScHW>KRslE%~jXf!v8-xyqRjwUN#q$O}*68tCH{^5oKH_je+swGq!$l&@2n zL&HM2sRzH1OW|6GE`rW`S?bSZihc^yR2 zA?EAXm7tK5$?$pF>d4q*km4Bud(!WNX>z7K4nd7lZPOYw5*ZxmRZZi_EePkh3`}_2 zm6|&ZIznCY^sp4EOdRaD+aKDBEuhGToI?9{pvN8lu79q=j}0Q`Si5XqoL>xE-kW9R zI#Qail zighD3=L=fYx@-g9LNp_^e9 zWK+9c-~UB-Z+K}VqzujbFORcCjZN&$XO<`cM2wS_mCZ5os6DI8`qL>4EH5uI#C*#m zWCRc2wyvvauBB`k7xQxm9o zINFGXK7I5L-)s|^m8J<6P@(}pP%BENoWg*JXfl-^2HWub}k?cDq~*w|#h8&! zME`x4fHuNS->m332Ivt3=@-*WD&qeh=}Kp#uw^e-SMFHsaBpR(<5pusH5f-`y6}>6 zWsOX}4s1wdT#naJ!z-ddeEQBrZAyH*xwtYeUV%<5UaG3_No!ND+Vj%I!G;3#kbRgq zlXrQA18hA=#X%lcQ|RO;;5KE_pxLkixYSIE*HT;Q#IE+dAu#3w^IT_=GSnzO*@A0J zjF?Xpsl&FT_jNng2bbr(cZSHQfH?pSVN9m!3CR4FkAYYcI18bvn$8pTJW+2AM)_hq z)C`zrc2loGa?6p!xW!5nb5r&(uFsM)+YM~RR4j}z*U8Yen$I>F&&p;`i&0gUX}2;9 z)Sn?Nw@HsD0{-+>N;E5&oF!;RMR0&{hp?=fYLmd8x`!$iC-J=PQD;F}F|1**!9`7* zJI~94=q@Fah7m}LYBq{l?wSNaQe|KUxWj!C$P%DW`jXFr8we2XGl zK>st)%z^A8mfyQ!$u_MmC<)2eHbQ+oF7;{qQCfVNARzKE)~`j}^Mq9;{5-%3k0TOC zz-q$7HThbah|)`@JgLK7h{rL#w!d&at>#9Eiq}$f<~H-r2D}U!e)((7 zxjym&Y+kb|jNa=OjgFSKl73#a&(5Hz5WW%majp64oU%$p@Fnrn5*l{)Xvc0dtCJ;Q zq{trH3o8(N&auDg3^L%yZls1L73*e|s;dl5Xcr^;sVtH$49pE2dYXU?V}*ZYVPNPS z*yb`B3xUl3W?7Sa2B>D&BHIi&%@Hrr@uvIcOWz8_I{#lZ3UFo=X%B-}&k z0;FOb`_<9-holiePK8zjwj*3*l98WwDDEW=<`8 zW?*+p5IZ`YsnrSSHbxQOrCEM2rpu9{+-TpE)D)cBGr#Adt~#nIfB%2np~-fWl4$2? z;{(OXH`VlR&3~xoffU=r^78N5=XZnHh*>fwT7XXJM!o^Ffrp2|nn#5GL~=a3O(c3V ztmU2laSK5&6i>kiOITWXyM=&W0MiScr(?4IGCH4n^3wWM=HDu3dB@655 zn)>4ulSl>-aT}9n3nDmnG4Y z^w@SR(0=X0YzH$_l*WmiuP#AY4h&DtrH3qcX@dDeg^+%arS??TiUh$wChNQHK>@7a z=r9t!USHF&mMQYe+egd5s#&wdvX8$mkQ{Pg>dC;g2E?crb!Ul2k10cn{=Rnwu}z5h zJua4yDc|^PJ1aP*3&$}G&TVI2Y}K*N{%O}}pOSD1Gb;gLkNP{94jVj8W= zPf9ALE?O4wz1KqUi5mtxtw$0gP;Lwbic31l=Cy$@PPZhINhFdk%0&%7#vpyY$EkBhZ)q)olrAS!1@z{8Tes zflHfxfN+?AilcYR8@vSwJUjt+Zf&<V$eVxJaF?n8{|vB$3hM`U=TY8g zS4_#3mHD+Ad=CFz$`M!_&+(|2G ziK(uJY1lOqFO9Enr)Q(Z;HtcPK;|8aST0EN+03OR0ZSh~Oe@>}hyB={L*kU;t zH^%NcCky?W?7GgcPjpgFztLidX$16+ecO{bR}NbDMl3DBC!AgoaTM6|eIve%GNj_5 zpGltX#M1h=I%cA!M^$Da?9jJ6Kqy9)&W_Ze@N)?)85=s6{T0pkYOpC zfQS+2O?$Hfw?0mMxZPOm_5NbW-x^z>`3P2R>cv*pe9`Gt>V5cTSk6D@=4sKV$ zd`J8dPkOMIy{l19^Jv4A*(SQ$0Fo9@>7T|>h&_>>okSq>Q)>2lsH!bil63lOF082% zGik0UcpEwXI@evCaYUA$m|U5(Dr{2-)b&yhx<1c}O}0yGX1Z&!y+)9;byK-%Ozqb_ ztUq?<)nTu^&*_^JO41E*2qT;$$dae%)B>IOfkFZv8&g$+ z?lPmfMHCQ0Z|fudPGpf}*#J_@8p?%=YdsyjxrDXJ2m1k;b!0ssr^mQ0 zxv^mL`^sDUMq#e>QmdX7@_6zPWp}!bgTuS_f&9M5d}?$IKu}A2QU4&wfUHIsiMR1} z*r9g{?hPUY1oq$VX_78H3i~v=+QWc!NyQfo%&_*YF-9(d4)~ir{O0=*m&)HGsC^sUp`3grm~pz_rl$gQ$nxfJtBqpqZ!POs>Q zkOzbz)`=Uol2%Lp<{D{QE>^Ob++%g?xZ^TlWWVQGM5G;hTjKnJR#% zu%R&!o7OHtz@khEMC_vkIv3dd+_{O2Xj}2d# zWx@EQ(f5ZI#IA|2qKDh6-adcxT!Wh2FxZJm18#}Nn`BMa%hz-wN3~W4!@l?*`_8DV z-C+EUkaUb?Qv4TW0AJ;;GbeEwBB3(d2QCvoWPXs2CEgiK7i#ybntuq;MAnzKhDJU; z^+sb5>BCgUJY2QHfUmHYr#J*zFjC$C;B_)Xfcx?o_ffmVmygpSRX<_z={CgBY0000y!0~C)F?jP*CYUcymg!?i zMX2e9SFa;KZoae?E4)%Wi_H$Z1`kXh<&_V`Zeu^}fwt7~*;n5O`nyE`K~|Ui zmC3Wii{WRhMR%sw8vYp1d!H=`2N?!>h`dV9NFw%@W;A#tjCh zw|sRTm>-@|@caJh%3gw!Vc2ncr0_X1IB`rU8Cn7xiv{?5U38y=z4&lO`E^YWp(Me6 zj*_njg6DuaH^x&3o{_5#h34&vI**Svq;`z6KV!#L5(~tm_DbLxR0JW%fqF;F(Ot&> zNg}yO28{z#n~V3RZpYVgbMCxI$(>XXu8N2u_4zjVW|-f}FL+0k_*)I-X(V`BVNu&H zJFn>t2|5-#GkNCq(pv^Zae*XqQP>|16$SL|X$Oo^GP+nNc3J1;oo_a)$&Qp@0dQ3PAp6=R7f-R4fUZT0!+CD2133l%Cv3k<*c)2ufsJ*YfH#!wHd<#vVet?oTI#0(0D`?$dZ^+iu@(?zvD>g zY+j{ns4=ewpXh*Ok`PGn*(2ZU{OH{ak5H< zb;OpB9aKSXQf~7^xM1fhv%$f*YdOMe@#ef^v=wUS&^+#}kq9BCT~9_;lKMhf`IsCC z@OU77!npmmTL(yTEp2mWbJBzedCE`;H(7V`m&{0oQ)~#~I1@#WWh(h{&`S11YBaW8 z`nzrVMmod$*4nf~0wW&z*Vg&6%+<9!LDbh6a5&^#_MFL z$aCr<>DBbth=SGKxgj0Ite1o0n|Q)J)Kl_@J6`Jb}izrIognFixxViC12j zBt=)xAvBGM5H2CCZleUkemt}+Su8SqrysF##{-<`hUUSOJ@y$H?CFOSuake_bBs#A zud`kCjqS>1z+z*M{s@*kP}I#2vR)oB+h(ND#zi#ppqp`P(M=laKttxDoKJ3ns~WTi zOl;fu18AQ~MN_o`EO1j~j$0xCd=UY|rY#zx9`BplYR;G%e4ilMk64?iYr*uY%QwPpXj!PhW{jp|9tI<4n>|nv1*NFs=b06TsSW&K5rIz}-p8zAh|6`fe$es~ za;S(1PBwG9>VFjw7-F{`h&P7S?%3Q#Ex`UY#hZPfBpP!&>eQ*PhSHkzk0coHUx(Sa zE26tpnaN81f&{D1E_(~=AM}rs%8D6N+bSm!PWf7L)IlRn4$RhydM(p`#4i%+d998a z+Zq2-Bfo^i&Z8d6$>zNAe3l8faYLTgA1W@(mzVNJ^nNF4$+;B=Y8c0}2qVb6Mot=N z&0C0H1{J-ZS_CKHa7#K}Q#q0^cl3S064NTTBL=ISoX<}t3n1@uymV>@weI#B9&jJT4_+lb$wJnMg^lYb5gBun(V zd^a*-x2!{Z(5&(*t9?fr%|ObZ^`$Wx|0g7@QPjc*RWZh0cZ1Zcv1~R;=<{1HqI;l9 zg1PZoKJFkBJq6FI2Ym?3(1ur|lBFTR9<1-vQ!%GB{mwP$TkUh%2t|+TSmzK_E|yn8@S(&#;(yR&nnSlOKNU0o(eM z>-VYuEw5;<=zmi_w7AcXI)lnUlE8@!-ctp=Eze;Nn;fCE=g6 z6bS4C;&g2n;c1nRXTFB(f){#Buo1PR6a*=^)#P*D>1se?CiMm%+AY79LnVQbSPp6i zF~wGrrzhlsLRJN)aXTtK=GxWlGh|0pV4wj|JssZ5JBYv;F0WgDj2yS)X;Khn+;1+A z{0xh2t|{g0Dqy&o@RHn%lz(7s_o1zFL+E?i=m4VA7Irsw8!|bT&XCZ?&v|7VUX@|y z^K5X|+t97-=6dA3;!2hMYtfJ^iT^4=Z7STN^P@BL0t{3xfmAsJp#sx2 z&|6c}5f@0~91h}8Z{)FMtvs-|Z+)`gp%2DwPE35_b!$rjU)+oXAMT168qb?3q$?SW zkKv$Z01Ck8|3=9$ zl^vRBuwqfp^S^U!T|}(a_ln^Z;sC01fd41@>~QsoXutHWM&yTbQf-T-`(>;3mqTS| z+$U`kCJ*Jxwf2ULF;V(tQy)i7W!xX~vlPP)!t~Rr(~t5GHr zhf7>Ak~MqbR60VB1Bcb~3or3CG!TJF&THmXl#jQd$O4~({~L6jQ_&+0)Hk&);UD=C zO|q|9clh2u)~GK3gYE~HI!_3eASTr8#mr?Bu7Ne&e!EeV##Kaen ztv115{%7;EWlG|}M(A&VQ5`DS*ShRAGorJ0^6?QV8beU>T2mi-Agcz)(4U<{_2Ty~ zTEr|!Eb_ImmiDM^vnA|vT)-|j9>Kf`mRsg!_za6wFt1Q+=jxi=IeZXb&uumwC2rHp zLJZ{-7Kvf+`tCqGAGKcB#7V(GiRODyOrpn5DXvV;whGWz#U3{J#*xOVQF&YqNrdVwn@+cg_RoQtu?3@|o&|XXBa0p1H=Cx}BFE-z!_d6`z7x)>OfQ?; z_Uz8RqjVm2UOb7nPoX|!!^-=OR{1Lm9M&UFU{@WOR^ZM!*o%mgR z?q;&-Bd3}ys4ds=Jd}__V=Z?&LJ@!EDacO!O=1oT0tB{Rk+*EB!f2St2+bk#iV>rx z__^JctN#?=!@7ulTS1nxg|Vfk_$(+1sgyjQIny_h7s(PXK?Rao4CY-A8FC=LVQu?Y zFEZF)c4Z6HbPT8lKTm%}6SbudIWjY^Yx%ln&4UT$*oeGa0+umNK6Y{*lThKb$^pCi zYXB?OuFlL^!}>n-m4KqJDg(mErGHCD)*vYk-TF}g>D8yAZYqhA($%IosG++}2>U6H z@S+59e*oq9UBovABVST_-|MuP5dQ=g^1U9Hh=~6HbUV&J6(M5(a7b9Pr8U_bh@*t_ z=FQs#~ z9n*Vr;|NYCuN3yn+7N+2<-rOCNvmY!biEDp$J~joH}aZ!O`a1_DOun<(J193 zrquZ-RT5uO1t%-8^70%kF?5nkfHGsu*B&Ag3#!ZUx0k~){q!x??5xjSh z#9?TTh_{?$hOCS2g?3Kt#@I5b{I9UVSBbMIYaj^C-^Lk5zLqkY%m{1-C_O>R_KZoh zi(Cp=E|q_`>!(zf!^m+w%0-x_l!nR@YmMtf%JF-#O3? zU7R(u1#GJ?uR@vG_XY_n)y96Yiq;P{ecXpc3i0=977&#Dx!iQ5A~UUnXvL-G8Iomt zsOKRFvhcgU=p}_6+}UGWg!fq+4=lK9g{OU*ve*>9J>2DD+739P190-J2i!W-M!xO) z)1LV3-i>>4%a`QcPCauJ7~u3g!8W)H{m{|eK^Q`~{^kyvm=+C04nweTn0N*BmR$n8 z#+S!+yKn$|VBl!GwOz@y0@s9>TN&+7zVA_vuq0%5L$}tR6Y!rTsomDr+Q82%^fTJLAgNc^F1Q|iE*63`x{D~joxD@tgQkeQ~&^s_}}1h2)W zJBh41a=|JMc+w4apGkgxU~pBKjjwKVKfmf6-Y5_uyu4j(jt40649A5}FQNpMRz4rj zxQ*NlTi%({7A(=39n@R|)(7u+!yCWH)+`w4GsGvih@m@3Zb2?EE|u*)4=MwQZve5j(%hrd==C3z0JdVq#{D5QkCV$W=h*Nh^u% z*wE!)?n_~n721LmO4c!x5vDN|vg>w!A%UEx13%!qNt~uC%(*DVje=0*r8X;sMZJfa z4EB*Kf9J%)$9r=E-DKMJNEx6XZR7Sc={UFtUlG8n-5Ys4M7<7yKj`MDt5hk%5~XzJ zlq9$^&A+jeBwOji^lYH#^fjZmRQ~sKp?otvi?&WARKIAzT!?!V|6aNI^OiY;sVJ9R zVdaPfPw0NkwB#J1qpMzgBYNzJ8sQheCDNBHJ~U8ivSPXF=5ul0X^o$6FmN>8Jpf7Ct%@w*ma&$a2aTw zUtfS`vxeSHYHkcDuLSly--F^rjp%moi^k#9HO- z1zE->0b>$4%vgRibYD7(mFDUS5JAlfREeUqjy28v<<1s-C*6^Nbec6cX}|lwg$uhJ zo1-T98E_HxOC0GLd>@45_)NKhKwBtvv?Qy!@uS#koWecd_`x8&P!S9(yTO}MV^IjB zTMqus|6*+N14A|Xcm1gl3f_eBwe~qx*|)vpSv3@}UG!xFFz6*%j)uS9+N8_jP4)jf zZJ|y{C<4<4-BFu?#1JU~j_~&t7N$!`5zV40U!hwG#hsDf$9PuC*SC4(Gj_wdvo zCCX{z7jmdMF)nR;pO}H3%?heVav9d1SrcJ7W7l)O4l|8e1x{pM=)|s{@UGptxUW@3FbRs?nt?{1J4{-&1?;w)A(I3 z`oec%Ko3q8-Vqjh?paVkDih*)kBPsSP7AJ?a5pqEAO)*Hlgwz+q`h9VTkm=*Gm3i< z#pW3+k6|4%*l~G{r@;r&NiGF_buVYPsKJ&>?7li{5c9OC)oDEUx@?2B`jHbox_G^s zj0>iq8x(EK?W1fI29)s48s5>dHB(xLIwU64`mqt;;~R9DzA-zE_w+_6E2DI(U%OlX zfbbc4nj;0OT32^F-w0`(86nUMo@?`x^|zuCvFV~y>ugWBDs>viTfMfG_b{Gl1XWr| z5eTn49T}?1zh4>jVD#X*>(a}@EV}AJR^crjeszHskDvrCcmYoFb65_suYc}eAdj&sWpsZE`k56(r7aeG?zz5EEU4$$%osVyyV7|JQ~u@u zCJ+IMjU14Fgw>I{pV|+{25iR#Rn6~e1TK?O93`nrzOY~#KEmEan&20g(F*)i z6w@|hj>U8NuHH4Ca`P8dlH6`y2*yXGE^~t?ri8NQue3?!lx26Q6rTz*iipdg<2$>V z!@T2yCgjnjU|mUhOM;yg&3vSu@h##qDK5(9fhiKky7H}K<853PoyST7Gys3nIZR+jMTj@~an5A_-cE5=OWNS4=y6yaic zDATq;$f)Q6M=A2$@<-UudQ&dm+x`|`N)AAp5CX%kJDS7X&Ned`QDwHm!{}n8c2$DA z9RnA~tJLIWW;kn^CyceK^1w*%?1Uqc-S5bEcnWTK2I>c$Js%%IH0{n%OT`kK{-kkV z5<)P*VLXl)ao=0IdH;51M*CKy_`h(KH-hyJy{NV9l>b@pQ6SrGN1#irT!y;KFxe}f zRSO<>3|I`HLgW8g!qTJ{9oCv*k(2*Y^m6d4L#o!ZG&7ofm3;{tq@-%ii%4O5B$l5! zK%&lo$KMgHKbO>(P})}Ud!3G)&~D(5tIA3bX@m3DIq}N)+cwm2&kemRVoZt)n&a$X zu`@koR%Sx_!~=9e#$5u3NNr7LQ8D3cD4ya##CnPILF)!Zd3})dlYhl#Z|-P`{-Q>} z(Q&)T8JC=12=%9SM0l|+MG|ku58Uo}bDX@Bl*XB)gZYl3WBKEw*5Qcw&AS&tCOX=cuAP-r^+Me(h$@aHH+bST6-~Sl)N=9(N>WC|t$tj~S*#%}>h^b&97W@Hi==~EPC=Tq?h@PJ5qO19@rT?B|8p}Wqg8H4 ztbWV{@~UQ0-iV=$@17J~91Ir%J?%_W4Ds0j+ngGQXzajh=zO76#4~tGTrjL2)Prfh zytiQWXNR023gK8%?@bsclU@KN?F@nTZW!S$ZLFpk2>t-firfps%;)oVv1P#KP&K4q z;$VVsdrxs4jST~Q5uKxAb&8w5fNl9i!f>G!`(oIK9vz3Q?;6pMTZ%uHfM>9NtO^pC zqN+h5ECyimHNs4{a$PIgy8fSe4?u87@i0#B#QnHD7OMM9uEWo;3f4;7Y`G0 zhWzpo+@_U>%)f7puae%rs2tMD&TFfXbB!hIt>juVI*tZC+?)<{bU!lNkHQQPWreNm zL|$nn#Hrn*N}7PWSA+OtJ^x@>aU$?|?xr$xP=^(Gt%3VGFW;3_=V@i7--ZGEEndnl zg#A56A~EIc*PyxzYq#ph1_lbTH zXXOmXp8ak1pNq{OIeG*}#vF=ZWqrHY@gc0)q|*u*VQuGyRi~LB<}A(V6rrgP@Q8=m zPm3|*CR^wgG*0?D2>5wl9eP!hDSg;+gwKltwht|H-2WDFg9{cw9=|r0gCo|*Y6&B5 zXeU^TP#-E~*@}G%2LE!j+pZ6d4FisvHq>_w_YU3_?waNp_hb*kjyQQY;^)wIFytrW0a=pI57ZSWZ>>Z z|2(s8eM6m@|63kNF@T1hrg~y0N9Md0kLHk)+J+N^!|vtkWd~qr$N9p7}`W-aQmJY-J#fEWp>e8RIl`&6RojrtEL7)jIlaOOxaZv(R{I= z#@8n6fu|`;t4IF;h1y}xL*0nikV&8zL*P?eW|WZnV@reLnz{g|-GBa@;N6dnApk9K z-QUwCS$S=$l+x?{UKC^r~O$We;21RJ&fesQCWYG+~x%tZm&vDFPAP4disL8WlZ56sx6)jAoa(=sk`t&D71Owo4 za`?$usSWX}hH~?0thQoYL?zc`&PoZoz$FvyU|kyrV+EcLI$~GQ84O1{qDS~Del2-{ zmIs=f+BNtFaK~U>ZByUCG1MIs#ZLH8U(<9{E|Uf53!9SL4tG6T%+#F5EMUZfDbJ)e z-8uhVjEY6qGY0Y0Fl>4LwDBel8IN8k07~nk$f;iCZHR9-Vk3%Cao~CuX74GD#kU`X zoI06^!Bc}_liWSOLfJ!ICuKqQeWYDRD9nntSE)1<5C2-Nik4$lNd1GSj4mSk!`*~N)H8|!x!NSF;$Rs5r{Qly!}^$r12%Z zL&I?rS+$E&%(moW&|=yIoMgoFFSPkGiu!=ZQM!=8tI6T!`a^%;2Zt7G((axh;L4k! z;YOYgtppMP_3Vn3awC=hIJXd;O4dN0aVh>2Q51*P0l!`pYCn zwar6bHc$bo&?Ac(SB!q;4llT0hO6l?eY2JZOzIFtz*hDnhuE^t2q{$jL6UbCK`cF} z(rP0H$02>W>P4|=Tdmt&e1t2gDbINmT4L(`I+}OQ^^!5)t5Nx<8(A%P@ex>Jm^en*#=b4`Mt0^{T~1z86V){4sMHPgLh5OCs`ERkF8f_Ew4lwZ}^q0A%JgxKRMB^cUY0TJUM2z|hWlH=OJ1+stdU32YFJ&0cI(N84!Jz|43*|u5o zUk!GIvsXU95q9RMjXTTcVSVHM0FxvLwEDjO~I_Y~R+$vU7 z?@D&S<>eViesO=7-JBgn-|QHGJgEkXNyVVF5hA_2u=uHg^(m>@Kmmrdc5tSEy5 z#Ar-ZG|Eeji_%Z)vNIC7-z2U|Ts+Ov@=<(_Qx^QwEP#N3fPjF2fPj$T{m_Jip&my~ zTS#x;u?T>Gfb*h!=>K5!*sy@~M*AK3X;Y|&U_Q*C%2vnxa@1QkByFLaC|M)l$5o4D zl>bouxG4R2o@ASQj2*o`LuhnV!AiC{H6}?w=x+t7O5=Y<)%-g^9*R3aGw&48E0Z?apoE zl^``hiz==6$yoEeUFSI2=bGkc+M#evy*7@Z$RzSm)i)H}XFqEeD{Hky@TBAD<1ohj zs3BfB-~e?o)SW0|k}mTcr7V)hxUmM!!AZ4cystg9;j-U=9uFA=E*5iwwrh`(%RCc+ zyGo0#%}N}+`A&8nl^{vp#}_d*McY!qG z1ssTqE8P-QAFO;Cdpmca1;o|nCiH`{_rS+7ybPfI?4x+@Q#xcX^Zzd!>6(?6s$kQE z-oTUhfOwUs12O?viujkV#40bjx{k+mZFfnndg^+v&1{o?%)5*LuZ)nO+;mfmWE2(UM`t3BtY1A1&7eYj#B+UH_NoG$h)4y1 zYt7%ABFrL@i8Xv;v7!H4(SfeXKTA=g#o7cvN{Cp7{Hg^X(ie>rGarM~|6vNCk-RL4 z=hu&!k{fhG8xV_wb#-GyzydPb$6P)%HoRA6Lt>sG$^TZFB+DASzgArFTqJlV@H8GX zsK!VTyDx4^G1o~+5D>^@`lk6G^f~&1nJs-SBOlNmEuk-|s?kSk^A4xpIE9S>8gjYG z)7|=bYNW?`Xx%`}fPF2t2agBFD+??sYAtrP4k1D;yVoc{bvIR5zRqP1MwBIVV-8=r z859z_LFFz^Bhkn1;vu0#^m#HkP=roMeP#TQ0j^Z0P#?>Nn2YI(uV`%2ub|`1XqId2 z7`1W!FW*{P7(g=*dTDjhHA&^jt%5O@^oMvaS&dhbzS*1EF_=I>NU&;H@b*qVoAqO# zm{2M_m;U`EO@z5MNAw__#SVHqUoXz6;yCh zH=LY^NGO$(Zyl@Rj7*vVxreghQ&EV&Np+%>KSc`iEIX_x5lUx1z-Q9zdTl*bTC>^) zR&I&Ss~}#ehr|)7K?+dRw&$i;sMZil7g;_5OnmCAqi1Jn8p)+8v$?wPl-=N0M#(=`3 zf;s7bWKsg~FGDbYU3j~KzF$v2UX(yy1fKy&!Az1q^B2XuU4QB2H|gfC<3E80%9uPa z6si+YDyN9x>WW*Nxd zxGgQ5d)mfhavnsF8Sr1%znNdn z2VK|8jsP%P>xugucTHQ=XYRfc3VpnkP*qCq2e+8^Z_00t2uSpJ5x*_t$LixCoFW}( z3+5{U^+wWRuk$5qza5Z8fFqRjYKx^2qMhpE0?TxvT~|V~ze>|L(lsTwVY}vkReUXh zHCJ}t6JH+++aiiWIygvbAR&r zw-f1j88=$kQl_}(r!-%D{u>*jN3z-J2X7}0pL$9^=U;z!Jg%`^9O)G6kAXCoE=qWM z*5p#j*10Gb%_@1z^C`4vGc3!^sd)?1Bt6lCpryc-jg}6RwT<@vSB69-gg$ zkT!UY>H4yc@2K=1cK#7|fHg*P=D9uRL`6SJ~1#^aN`xI59tuKu3uX@_DFvz66y!?(gxpr{35*SfiMEdS48ezWpD<^egDZ zkY*z_G*;_`L!Bdn#eYuOhok5!4fMX+=%2aSU}=ymdAl_deXI0ha+oA$?&QkS zFZE2RjI?t|QKvHq&{#-{BDQ3uTvsq(JTg16`N5CPmE=#q^V8gla+Hu!x*D&$QmT%8zcp$FE@Z0X8WSG;hN|!xn zDoyxn>ICT3+4UjJRFSIRV<>0j0+pPpc)1#UCXa7>Gt7ggZZsd;?~hOaF+%o-W;bpq z6d9PmQlcqw*zzSr%qQo@o+BYI#>~V#A<@_=M%qH8+gq>@3HC)HvM0;)(5T)~Kn9_^ zqRPOe{GUB=Y3Ur`Rk*`b+W8;&QG%T9<`C~+{ovk#A|+#Kx)fV}M_sp&h%L-?%u+HJ z>UdpzUrWRn^5e7=i-F?PKr0V>49mzA$;vbjn5K7}(l!YkxxnttXy_$0B}&8?vwLFh zIiSq`1{e$8BNdl|iH%q~s&&-jg=^gX)FfOTUoQ!3g@SfM{MyIE_u{l*z4Gl)J#pHn ziW^k*YKbTsKlw5Q%mlc?3;m~!`2gn-*K}A*jbau%8h;0dyaPU7cD^Pn+dTDmSzXb) zc3M}v6YCzdp_t>thTBgX9VTE8SA@d7aF?fcb&rl7`RuivD<5ovEHH!CT>fHREaiTm zaW5*(AI0+=HobW`!d||OhyBA4dZlZE@`-fuagLha;pV28wQ{-e4R7=zDW9~$pkUCL zOfDG{>W^D`*VOoFo)tlJ(PEE%fo+~smQf&o9F6!4-80vVl~r2K7qktnc$^-}yh2@A zV{Jp_tO7S8J9gy!E4GCVZl+RMALA zg*ChB5nRhen(6*dSWF>RX4S%H;T#X0lEGfG3l??}71Zs>A^V^ikDP@50Kb$4S9?k3 zfCs_wBdfYEf$m}7?{?A=_PTmxWV-$`ttSaD5+;Yum(^>}o`O-n9Ucc@6&>7cHSI66w-Z3yfKY`MKsDPGUWC^X5WBF`K)tn2 z)tAw!v@`@Et(KViASzfpro>bI<#%mBmByF9NM~1@Swh^}{+skQ5P1id6a|PSsEpsa zVrNK*0CScqZ=X*QGe*kX2dIA^91b7(vg$BUTxvpq|3b&#Uw%ykQ4_*SJrJbb(bc{e zE|t#JtSx`lU~4I`f)e};p0{~>!u|?_>#6W;uhwJWdi)zV;Msqulhj{mU#&Nh{O9l~ zz6Ynkx1YZSb^I1L>jUkr@M^Q*+s~fwJoPK{3GgfP{~qzjj`ROoOSPA)zk;diZqZ(> z{Y&sP`kC>7U8^ig+5=pcifW3dOJtHy1nxc%(o&>drU019c6T~@!r;;qqM*-xK-L(e->uK-U%zN>`MCmkHoC+#_w03l;{k~OG zsdi^G+#TtkNI8?F=Sm&f3NAOyKqUvVAkbU7kAascC}jx*q8Q!Ej;&{chU@Y4VBO?4 z-?!Q#x{<(B08ahAvgJh^Xt8OZVct={gt~!J!}Ex~su0=q85Ll>dP^e6qW>MW?ni4TX2;A{+liJi8v-yCDR~`p9qB*E$61D281)VFlWrPC?0GfHEH`UQOVT2JpHy1wlO<&4*TL!5OnR3Y>#Q`TYwyp+9r=gF`p3f*j|&j*VNoCO27pEM_epO!w^$>diV!Ho1H?~cKd9}o`L(%ZCNrIZ@;Anmbm zOZt7LPy$0sHU2t|G0x@8UIeh2(PVI|-HZDqRlcUN-I%-wxJCA0Uf+Z=1&1`fcjJA5 zykniA3*Xf=?1woag!ynF>LmUlt+3^=SRCT=Q|(1L384@2b>7cWrMfhcKa!dg9bt=H zh^>Y1&u~?GM3*OsFChOz%9o#4w~?PPMZMFzt`z?rpFFPjg(`!2rN&cHifSwJ=8@xo ziHRddc23_qP?7FbZzU&aZqIo6nW>?kkSS^G|1O0o*gY&1(b)@?-7_mlB7zr^lHtIa ze$U1z{Fxybwoqs90IOmsfPbjkyJDdC7(>CvAg74Q@L1Fs(6i_ee=t=%K%S-Mp3kAyhW2|`IAIpW>vMW7+xy@^9L__3|_bO$D;ex^<=rL zKN=;oNBG6V3;db*C5OfTeTgh;vbXeAT}w$r?O<4F*qumnwSt9wb*u?#uE&+7xO&Jb zJg1LdQm8^M>vO02_uU+hAuu9OY7}(dT#>QbsGeOXDE+kH$c7M?9`CW6$m+0e4LJ|e z{52A~P=+NeI|?KA$l%C{1xn5u%z1b(1T3od{95HM`#`%;$HM*gRY6iWWyKf9(hfeL zn0oPr5>cd3=nnTUJ}2(SB5NoJrRAdHE)ZsM;1QXQjClxJ3|>f5Kqv5J##{V4wnJ0z zvI{ybS&ay7ON9Scr6ZU~I(>O~xu2+R}4jEi&dH zyYaXxMptpXdf1%crPqKTgjl5{6msPm{LXZUDO$gJ3O~%yFdLsDk7qZJ@PTKuko1pa zfY@wbo^=>~O8Nw2PJh;1U5Uta)*KW=AV=|8~tkLm{VwfhERt>+)6pErbtI^Rk zXT;^|-f!uKQ}_s~xed!9#uS|TM|tuGqSz7r&As+yNlS`DohNMuvl^(lix1WF_^}bb zq-1?gAC%o!R4QB)k4p#70WMIET(_v0)bs1Ryitw3ex@CY4Zco@e<)+4zW67V6qmtJ zmA)$Za~aC}<&33k%UedS6h*E=Il$&12BIhOnZUXY9pS#3nTT_0f)EZ~GDiW#`BEGR zAEa98(MESLS~+n)b#B4NbN=w{mYJxDy1EgfP+7B){6^yPu zUuV%1!TaJNq0Hv^`W+@5<{$wFP6>bKrfCecTYaGvOiXVT&r=85AlSNVl)N!~sYGE% z53CgTHx~+}??sw;{q#Y?Z@IWJLQX7u^JKerM#^=l1}=yICcV7}hRlW1*shcJ(P3Ua&xv*Z{2fUy4d>aehMf_%JJ3u z1+JZ@y)oh>m|Nl>RU;seoImOs?@9&r*LyJ8j>W9-tdVFE?8nZyK^}cU z<l&!HVP-FDgWPVQsO;D0ts_ncAR|tmeA_PJ3*~ePdJoCC+u+68> z{MYN*9Chko&li|=sK)y6MtC&gl6UV)jxR?uz+dMhpkR)jB`kXi~& z-gp0IvX7<2NMH|gaFf$p=|h+{#ZjY59;du*11O%R*SInm8|~(SS9w zJYe5XO4rt;7+Exqu7z8$j|v*I?A<$wL}yXpb%#Mx)v|php}vRBA&i3-!HkF7 z7Y5^}NXs|jFL9(AUp?0l-&+cc{2tW?;QqMIgTrK8F;_-c;itj(U-^3O0}3iBdNRPR zq~f+;<+TjfnAH?CGl#-s`b`!UU11Q^UHS6u$y2o>oQ{^z-hxJ=2%??{XCx&6_8^dg z>2s|qH}LPa#OKm}>fQ;DTwLQ$@_eF2+huC+&K~(kL~z>b50ZCT8`0Ky7;>vBEprF; z+88+!KuFxX5lw1Zk@F*@A7f5bWW-X-cE~6&7zUV+8M~61{HZXi@rMlV6<+!f}lS+hA_2Lnq1bdj@kT5%Z=1Y!4c&d#ty?HvLBqsui@=25Y5frOX)E(eD~&Y|-behW{Z zhVR1&D=Ja0`b|!XI{}jP)wEy^F`!O|&J=XkF6nsw+W^=q_t zhY9+h;l(KwVSF0odQe{{!#R&ZZgHD%kCpRxvYMIb-yV%c&^dADg0ecZj5i$!z^oPr z$ZX$D5SDKVu0t)2Zzy$?CD!kufNgwH;QD>udsG`zDzoj&twtwA&kz^>2Y*|P%3E}i&BlPzs8^0Bc&LSZ0;#8 z&6kSxe>PN=i%fGJw1enne_EAp zxn2wUG; z>L(OhYYfcv*s(-w}kb1Ro;CI}HtpL9Org7FU+Q;V=+sU)!SCQ%Baa=l3N; zYQ^2#D&&;P9UxwFNZsYAU5Pf&<~b+|t=OP<)f`q{m{MP+)aYuvh0k3LtTF?l(Q{*B zlWY&%+70P5a6`GcjhEo0x=Wj=&R?cn(ci*DXa@F83IBn>xv63JpLuvDuN zWoxyA{mpn-+YO)A!0*xgjzFfFYwm*D{ z3{;%JFaIrlp7-{R+8%-yde71JjxT(Bv9m4((bR?RpU={!g83&9Yis6J;1zOJp1%7u z^bn-GLw`eH^(}Gy?+0tSA+JAfH|<7B%hbd+9&uRex2990&Srw&Du(RDNTtE-jH;sL zW+d&ufydRsj+5?e-m)kU@p<_dVI7uG33&Z}j_X&Jiu^su z^&tB(#}hojZ@Usvgt`fE$B3s-l8~m@Y)L=Y=zt+R?F+D&M1u{fwfMl<4i#9>dL#lt z<$2jvWaha%#oU)_A!S*4b2yvuC?mWw9A80(ZcJ_or?rfy1>JS~Sj5;fE$1Jv)>+bj1jyYT~vys3@g7$mF}(T;kmdhF9rpJugrX zY+9yMfU?y)ux?ueW@*N^^UjFW^eLX=U|mmZC|vb!)|ESU(VHi zXO1{hC>HMp+vNR85ldV#&cxEHda8-7EQ)WJDnVVO{Ri~aP*D~99M}x^H#*yauv;Aq zJ-Vn~)9gt`tiFMv{{|V}o5Mq6UsP+fFQKSkGY6ryJJsQ_J>)&_Vz+RL!tPWxN5i4b z8(KXBM~o*JfUpS6`DB802vI*EfF1fE_>iI{+q*1Z_w*~)xxnspggIe@|55t2)ujJ$ z`y-FhLlRSRMzd`cLwiE=p{duxrr%gK4e#G?W_Fxaz6c5EvdeVOCf=_hBSYi{K;$TJscQc*O_AmAG_sZ;zM3~Ki zx{Qn*X}8ow2i&$_l1pNYjBoLgE(fOT$hT#}!Yfk?{;1fzG2KO;l>8pfqd$etLs z@>`%m(_yO54+IWKOU8Ijj6r*3n}Xcy1;8F3?8h2sSLzuO^ofFz8Ny=Qpa*RfCG5CM z*i#BjTjVj!R-KUzHVr-X?U|rA6IE(Z$wSzyl=9m6LmRng&V zJKqGSQMkMcF(B#|2#8@rr;NWXpj@%t1y0g0(4Mm|Hem6dfr5{{lURjrjL{VOHBt*l{{}CPreIx{~`C&Cf zyQ?&z0HR$IJ5C5xhNWN+6fbpRX~nC&eLSM>m1m@ZZJ>|-GEPFjgb8#Y)+jDMBjLEZ zUEmnAfJUH=GxVp6qNl|lUU)3UBP>Mz& z{9IS%O7s>K!|<+u+p;j)gsQt>f~&mSp)Wr3U@4Q|t4KZRE?;xUZmR;@pZ@77z|yZ% zC}mnSsM5cuUH2%1?w%6Ua4$iRn%!_X>=)0@eAeqb$W{w|_VBgvLv=Y3j{Nx^Y7-lM z7rDcTAdtFj6-a%4n#0HV^Nu#7-*rM8xcTb6NntDdT}66sqo-m(7i=#|(#pZ?U*u^d zE@<5BzPY>x1ArfHVxtz(9m>l9Nx$8c$K?VYYz*$lqERqpv{Lo*u-hAH3Su&jBfDF+ zp9>32!Ch_ZlP^I~^CY6*z=mqJkD8_)eu%ALmTvC1o6Do~fq9CbQtdRQ1R$;nvoYnC zJ?x_ae$q6q-Z98@osD9B)CVj02kMYBhG35ZOl6W)Fs(1egbse9u}4_No0|sNf4Og3 z%h=V*j&f!O)?1J`yn2WW|4h|Rpoe0^wu&`%Rs1EQZkO5>F{{h~kXI$3araKvYuPiW z2;%a}eA>_jlfl0j9PdNw-UNof&4HcC74P`pqH$)ky>~`#yef zyLu5KkRlW`m0z~;;tD`2+qHJ<$^`p8kXb&JDTIQh>PC?`U!|{dK}jh0#^>C~=)dto z#cp;%$;HaxKVdXlZO*grxWm7d=#jZuZ31VVDXF_`8r=rutB%$O44z$R5puPFe++Yi zv3?<$e}HK27-`^KSLsdHz29s%TWlX-%-K#e+-Q|ESFK``NP9`@k3$wjmUTG0b=O1j z+c*35f0G_h8M$Z>q&W^vpov$L`0_bSMkh)Ceq+iM%!mjk&^zK~Gu#qOt!K{%x6YnIO+|kFW40$tHa^uf#aDxYj5${xPvM&rSht;V zE}92X_bmgY&nrX{Vdpnm#G?$c!RY)j*4)z+GhNhkCm!HlG zf{~T|bPOg2S0gnMeJLzkQ=q{nF`e`^PJgtuN}FNh483>U;@pQBMH`41aoZm+rBYaa zcA~YkL5jeUP_>i3k;xqf5|}Fcwmu#xkjxFwB^pU9mSZxq|LZ;!~Ebaa4JiX-xfbssT16rowT~%6B_;z z2!zEq3GF+YJM95sJVA85jj#}8NMmcyM3wejNm~Ltm7hlRAq0*;O2MC7<(wXWU~-6k zy%5Elp281E544j%+g4SI znC~|H2Y-1RFtcu5j~M$e786pz&)b3XM2LZCsM;vP{S?2o-#x9q!TH%2;I^t;a@NsG_G+y<)DBQ{e5Q zE00#H@Frxo;*uzu2vnxNFVQ4Eh>>y+Kd;+S`4%g*0@y$(C2d{Nsn#PK-cgIrOG1ra z0sW13ibgONSOzX#ju#uxA~sa>J%*R4UZpNe(#$>lrsklz=*@bE2bNe6qWJB^#bH$v zx*8Zx@?JLYw8cuahXm6l2j091adb3=>4B1<%{M$02}SUEtl;UYi%BgeD8*c|YPc}0 zqIp|Y`jf+yzH!^*i%h}vx7nZz6!i7|Reif#!+jz-oC}Nm&Ru&N6iEc5T`eDh1^p=gB1uG+Y!djZt;_T#j#qRn z=d#QR2`cO0h_x~xZ4HqaX)n4^p^iZ{Y0#MC$ML5!FJh)F-rk>^6_=*Bka0T@99ll%y*r_q-27Q?%DY+VpK?O0tFxK6F zc2#W6&WrwO8aSRqp>dlkmIAksi z8`dewd)~M`5^&YnE-7o$Dv{N}(nfd8^%Y+q?36?u;c3<7hJ);{4=kU_EtM z#{_=GO7<`yy`d_T23-5v=X6R#I&RXcWcJn(eZw4_N)E%~jy)ZAZnNLB0#BI3CpRs! zIyIOQ2{Qj+9=Kz9gttG>l~XxjBAyDL>pw=nD{^}(A&kEO5Ep)8lCaFl2`To`tUlwk z3N#jKy*(>EFus%-D)Vsa_%S+wI`VUey2!y{c(+N$+FzpPz34B`rFSx%g5Ar9XNKVg zb(HTz*x)yi26|Wy@)?QRs!KZ~@l=6#8O93hmuFSSwWbFK?l_<+?A$-cgB7D}28_S| zetvK8zMA~o@Ca0@+`EgE(%N|wex0o}kUay)Q)E%~nPmA}ENydzsUe*pk0>c?)oBoF z#{Wg$&)9P2hn<^u1USN_gd7-%D?Rw+!WrEwpOT8`o0Tnra))ZrtVQbJ%PL$kDtx)TGUQi3l z(B9=(M`$l4T&9sPvz0=?uDDPwgRznDP_6LQT@|OhNA`C~N5DD-OIfFAld>Zey;V|s zDl4MiIt?(Ez(Ya$4m^=EQ2nZaX~C4ueVz2a1dfgkM)$w-skbqL>p1AoIFy zFDI;8R1i=A)$L$dxF5>&Z>_P7{1K+8|46n-DTUCU%(xCSiu%Q{Kuu*G;pY_)*8D*_1p=; zs=Fj1qC+_tgPeq}A}L}GT3*>Gw-M>jDjR6j0Z{)b@tQy!-|)vGi_UY)VI%(FT#dVJ zSUU4Fv^b*WIfzfrV#d9Yi@SQjFGQ}I1h@sW)oRCHHDKT;j+*v%{l{;XWf19HS5||? z;8Dln*5d=h2;R&UzkV?QlC%>ydRiuiK0WNh>W2Oo_qKyTrVfce~3%beJfg z;JRVgi%gOI7Zwg@gFSA>TFrlnOr|9reRB=ZZ}X<%BC9V=n;6}yR5klmPW{<7+ExO0 zRLfWv#b{dHk&ufNX@$tjVI)o_hP|ZQjFdqRT?E1k z{8)&apoi&&x)T(Urle!}f@64e@{+Z|Du7q0J1A$gEfWm?Z16{0)zuTcnqquEO_|9Z zWs4T!;rF>Lfb$(C!jw;G3cP7#_0#kf$9 zYn}P0>8}@O;y4*1av<5(v&+yv%}a1XruD%Lj%_07*p6YAA~!ll)0loY;!enbW>)_= zZh%8}H9ekTIhXO6I6fq{~C)BD@M9VkES zbuu!MR(<;a2u2plE~nKwZI<^*<{=aeGkCwuiWNF&@V5ruIcuD9hOYO96m$73+#IOLB=8>>QT@ zy6*vYETuwMX0bXwP`$t9t#SaMn|TE~l}0tb0Dz>Va^K1LYyz|sXpnZrmT)<;6r zvF0(4;C#9K{6ABMaf}{8+n1Rx>*cq|6WPYXK6{4ao(5{F2`A^y#XD}h@O7lOhx&$Y z3EQx!O-V_|6rP&c>RLemH;aZ8R0kDlQS9emzvHo3cFPk1Oh7^MMqQS5pT8$YQ>Kse zMtPkiB`Ng-U9Zi(_6E>KBGFF$od7zLGP*dzh=&vk${G!uvb{n+2@fnYo1%FItPRUz z*=2Bb76`%fYoWm|E_Q9seT@~eAi(3wz`>sl!`KV}CKKlv0Vo6KD5SIAkQ%A>Ov9mA zx7y`u7saz3qUu6VgKkVhwC>H@V4riRk&R<@wEsVyQO$aa(3k?d6dI3N(%bG^v~m#| zkxT6te@B;@0ig10)?vm4v6Z8d17Tbw+rr*$UZ{NPZlr-Bys$Mz#*NgOF@r4?SG&zO z=JbKNIH1Q386`5vj;$49r)?@SVgFRGP%1}Es@4xv(LCWniE#QJbgz>Ca5S6}X}by( zUc}H-RX&!{QTsyA#-BPuk>L=glfup^wkFc4Zql*#XM;dtl`xX*YRAmbJAV8XH4M`R zwF!f$@5~<2eycgO>5WMCsOIT!Q~MdQl>W`qqtdIpGW|;OTa6lpngGIO;ZpJsFCYFT z{9g#Wc^sZVtc9m?XJkHC&P>_75$O-4E2j$MwoSF!`mu+S^dTSVyO`to>hJ-ysp9!Y zqaOJ)aQD7y6E-J%>aI3sG(TRZzLNII$+uNOtfex}>b4*Z-d6)Yl%UJ;97$`FEe?ac zUyd(it>XV+1;d8@z3NF93t<7c2e$N@7r6`+f!$1X-DK3ICBikYl?(2k-H#S!$hJ_~V|3q`D<7((6|Ogn;a zecy`iVjM?$&pmitH0SNEFQh=uI}i@bo?CBf1RJL=3k_u$2fB-UYDC@tC@B)JoAgyk zZk|y5tK3O32)9?+xC0(*sx6<`hXF=aiC#$@^Cp^%b5?I06re?S6vHsqZOQ-sy25(B;L4c`5*)+E)Ukx zG5TD)>J2s>bsd7s@P%!e3lI4M=?yF-w#IoacTm`;Hj|-8eOd*HF8$|7R?oc zHvny-W^EQW!x(t1wwk1<`~8zEFGX)QrV$>iX_y5i>pt??C-lc7H+LCJeuXY2SnFoe z6^{AF*=1_h4T?iHpV1|WN30T8?%H8*{N`NNZn{1pe+LkOXpT1TXYJHL+Y0_858WG- zq(EtCOS(vbw&n##q!w|7BP@hAp%AI6A!HoB6vKgGN3K$Gym?{%Q;OeM~rLf+q9z%HW~&{QBjpPyMc3`Ftn)ri3+MhUKy*rgqmqA5Q(oAqBbH$Dlr`>4Q1Brc?OS50 zEik89a3~=C)*e+8+Su*80ziMBw|P^fRk(2R5I+uny1(+;TIZ^$diis!r4L_l8%r2u zCZ8f8AUSFZ_ww;H4Mq3;*yQo)xPPvY{SVl0hnsl6euXpWpo2iv5{X@(TPmBNE~Etj znhZ9u9yrMKQmIt;BiIT~SS`4a(B>RX2-+MXra)NiqK&8^A5=9ehrCF(WOjilSSIr} zbdF^_UVO$U7qU6q7ok07_!-MZ8kwg{=BHTM&m|NG@=E9V+BsVK$mn_dx#5gFws)gJsv0^PN_$E1Rmz}iX|hH6 zQQWdeaYPq`a|JX45ZtKS($LFT(h@8sFf*Ys1jWu^J&v&l>Ys_V;Cdcoa;3RH9Nc@j zgndarcj2e4vxhu!>|QVTBtw}u2aNah%Si|zvbD^U(sp9%-jzL31<=tRwy=}N_VRN? zR35`Wz(X~4PD_i*1WR37z6aH^^;UDG^7yB4JxL4=EL4^#j{M33klp4%^_9sFo5y2_u{oL^~B*TV^K_+;9vy zL>f0HUrMT$#yhTNp90W~sgk;b?@R|hb!pCwsR!~_lkpnb&nc>YF)f-%ZlWdsFl662 zOpUO;b51B9GHUyi@}CYuxo#fp?mqut9AU!j(o=9mZLfDo^UoYG+x=OLWv;%Er0Y@4 z*rSB|Bve{a2`rF+Y+)%=@ab;NL#jlONNlR(CW{xB!}BMLl$PXgZTGkL{EMft^73K^ znp~(gSKIo-JwSj~GsC2$ys)cGIuUHibc(w-IOTD9i)f1{;1Lwhe3(f-K=oiGWh2-7WSV}squ z2KUS}S;w_QB}d>_gHGCX zI1c{d$~O9>^Dh*6^ZgTU#%`KnkA7*R^t&O`uIt?;2OF{85vdgyY!h~I; z8DOd8oh*Bs zkc8pzUrynAcUp>U2c%$r{+nO41(v=PZm}FvHMdhQ&{rQ#l*V<`pOO3RMKB9I`M9;_ z5=7u5emBG9N~Yd*4U)1B_|AqD6hjNA1uf7d;2qbJdatlq7krgp!Wo0Q5*1wKv~7?C zSAuTl5fd&JHc=+o7$F>U#Ti;=rs!(&7R0O2L|yP5Me!D|#+nO6flJG_gP#Ifnsq~7 z=?JjVfC|5qA#a3qTK`&HuE5ueU8uuW*3+9DNmZFHnK9>81n6C_$$?W=JD8JK<72{w z+LVbz(^*$zSsXJB{YMDTP?&)9=ruGEop1#|gT*j{@hSWV01|SXh)+oz_))On`KpY4 z4VqZh^uJ3K<#a@X>Lo75NNS{N1Ei#1he@8)hf73&@_^H=m&J2bxipjJl7{yUq)$NFB+iN&15; z+NsOUAAc46qEOg;i@;fY@np(>^u6Xb-+ovWg!1yg$DF+N?z5d^_Udzg?w`#m&VqBJ z^Hb~ovUT2U=UH6Z4$xfDyFhk_cS!AfsQqv2e-4p5V*C_A+HblabuVe}s~|0W_A$(9 zjMFaz&XXCK+O{`k#ybI|-ri(=4%g*QDe_+yGgqmUtG?eDEHSOym@$R;OH^(yq(FtN zJPY5gQ-)Z3C2X`-kTkH}BcYKZxiesjDTY84>Gg%U<*@8+MB>G44LcCGSG&C<||;+K}n;h4swmLt-Z(7nqohwE{iCzDrfOmzVF)BxSlEp zkteGZgh7Rsit)G|Ho&HQ!Lba0CdP!nS7pnkg=vz6?rb`-*hO6xYBNGe(2CrPP|c-( zL)U`7#a-r4U`>)Ft5TL0{f|BSY|UTK0;SGB5#r@!c>;vGtmP*jHQtIyInTBE1fte- zt>;o$2c z?8`q@&`TvpxAjmSMa#GC>>=j1%W3oC=v8H;ReD}^mJX)J&)?u!v8A1*$#tg?R)uB@ z8k)#mNYO%>(i6Oa@`C(W@%2o_$a)+T^wM2=Lw+_H0X|@2NMwQ1U=9Z%kvdg5lm0;1 z?1^jMw9#eZJ8i0_K5T+IYl4%4B}1=6EX_GpjQOr{d|pfsMfl9%=^Mv8?Yj^WpXHL6NJ7!SrYkU)7!fvWY;*$`$j!K)h92&kylC};|xUkUnd^4>n{c3AgX$&<0 zwGhl25u3yYmg$y$-%5PNuJbI0aq?JVShi7|xj(L{Q+0yqsL#k*?iVIHjwH_^yzaFC z(DIan6wJO<;v=bIj9SYk)kI;CD6+@@0>l&5nXK47D?j=u{0r|JJ<;%Kb>KRQmh*{;zC)}zyWas=Sttd{t`eu)NEPk(&zX7;JPLF@18c`%S2Vaf!FoNww`_~d zenB<>F@E&Zq%UF#44^~~8@R;>8WA}WX)Ye8X!WYd&dSQs3IoRq6OITxJDmpg%Uqgi zns(Ocsj8W0$*-*%+;UmTp9G=G85bM&?E~!QK$38?D8W_s@JU71BtmJn4g;mkZ=m93f?c@E_qAKl}{NToSJ-06jp$zd=kvbHE)?j6ng| zZ9xiBAL%4+2JB<8k0voSM;6&PQtmRoki4HhVy~A*Q1pA9@;|FeO*@H$aBu|ZG(d6d zEz8XtW4N_At;#Tt5CrtOS>Ts!@bknv7V7t=FH%hREwGU%O-|h#6R}DK$Y@W3{aB zlwoA~Q!w(5#KWR9ZI}^1Grj6q%!OEoC-;`^{wl2n;QOkj#EUwiLL-bJPryxHfoIU> zQC5;WN*X9^q$6$2|1*x$oFJ=JNk}GVmOQmAGlRIyNw{1z1f~7%_m;WuF?gOH&8NTV zE7d;NX6GouRH1HK(nXE4Xy9&^D(#0-(P^d`5(helFDF6S?Fs=YyR#WNXG zMxuP5w4Vd*xi4gZST0|%UjBF`m@?q&H|`74qj+u-vH*Mq2#w2o03kv@sYL3)Y0#z~ z-^PRGakg6`s{^CWlII?z<0H~(ZfK%{YWN4yf0m%?$g+NFrJEiXM#GQ^lHOojnOD5PbZWK(^z`Sybgu;Ltm;>ZSNdSN{%dlG|PXw#K zfP?4|+U1b$5+dqosXX%6_widH`9qtxGv`!+1O!CT4j;nWkXMcFv&ADCc{AK}eks22`VK`Id~=W89t9o@A4(;-( z4Ok%r(%WR-c8GgL&~!H`JrbY&;&n}g5|xF*Yt?o)QF~~1(ffPXd!)4 zX{m;g8-+gMv=x5WMuG}+uBGuAEGvyLwED+a`5WC5qPV z^;S;^D5+c9}J2BC-cjg-qz4 ziwEIcILCl}8X(!z3qKnN61-0&flE9ub|Lt9&e@b5oqa(4b6(*u=cRcXxN=s($wd z<7hdpmK6*%6t{2IYJQZC-Z6~^oTjNgLkNbSIn2mI%4t&`;7L#<7Tn3;`e$?nqxO^& zqsCQ2$T#$Xz29?6nNnQ!p4-mr_ET5j-NwK=V zx2I43dK(h0{$og@0|SJG#ECEAIkUu13a@04>Is|gad8n+2$0^4;_>;4Eq`&iBMy>u z*%21Niv2}D#Q$jYm}R$KW@qFxP)7X~0LDTC$PMp!llW;dJ8QC)apU=Te+KD; z5@0;#83h5}*DN~{VA-kAs6G&jl<#)EZx|}yQiYNUlyE{zX9z1}L^|?3K2)L&Lq6+; zZt=r|Jd!0kFkv}CTcuHqvU+znPiI}I>;*(m$hu-NkdGF#octQjwwL>hLe)ocO)bfb*ley{dha+<1Oy2^( zV85~Bb9{X{Oy;4#q@qDdd?$plgxC#oQ;s0CO&4=$ywW1ZwH|aDTa!++e*|aXaLB~K zmDe?hB@&$;rzg;@KhIw*J3A7Hrb*;PDw&qepeW^f0CFXo^` z6j8bVd^rUT4fP0Rl|IrWBBS2VB=|p=G_{&5vXgk5K2c_kV|45Iq#CBTSLEpQ>~zzI zcp1U^pqUrN_dC=@2-(fb5dyVCWn{34zg->S)$~yquY(2r{ada} zM2%N~f7kXyZpUn|;z!PipSaBq+C#(d66h&I-}~6Pi8|rnCQl1NC^=6EP&o>%X-E+@ z{VOCI>I66gK!s3ST(ZJ4u=~%k&Gtn|;y2hbUs)`#wJC#^>^3IW%Bo7xn%M4Ku1k%k zR(V%{8ugTE{|8v;P%%Vke+KXD!ayH{bAiD34ziYV@X&F__-;?>9ND{p3a#m(KB#Mz z+N^N%Os903S^qM07I|3za&++i+YW)sfy{n&n^oqJK^ZvTiB(@Hg;z0AyG+mi_61DRS;djjIz7i1d|C4wEDfLbxf(r?xFE5{o% z)!cBrVKsgZeHxrbiy3A@3xb}h@@Xi`$r|jW(^iytbUohY8w1J;qihBD9974xfO-dcXjHz`($P0DyqNfdGJjfWSaN0DzNF+~GMQ<%r*g zD)H~BW6K&}lS@w26O|J%r7Qpm7vOklC<#JtW8N3?ZKSM(HC` zi1W&Gy1@A=J3Owk&-U8s1;U2gV+TXiX*&hBCl|G?WC1^U$}Kh%NXm!72Ss4HYfibw zm;r_rv3@w-$^Sm5c!^E3dzp*G)sOyDHS6|`8fm81=}Hi4IUAeC2f`%>Wc6|S{lq8K z;2o7uAUFCs<(?}t6$kh$X<+{lLnW+QKUAp-2BN!cB~8<&5vx0QZ1-3I=5lS|q_EI= zGrohxfY%npqQB+3?q$Fo03xMHQEFBRy{qEf6dT~Jl4PrmB`eX$?%ZgcV{I09v@@_#*6SyyN zm&nF(+t-wzl&#!<^zX9IefA*2$NeFZejO%pXln0xaX_uh6~dUKp#J2|SJk8u=D!afqYE`?Sw0{h6}TZ^J$| z?=FN_r+Sy{|7cS~Q!1O`dazzwbm&nUR=SVu6fi#+X=KMvtK`$GTRkX$-k`@FJSqe; zK$fr6D5sH&cpwAdH=6yR(-q=Q*zJ;y5~!5y9c=!o*m#T4vwp9|X+Z%I_+`Mx(h0a{ zko8$x&}vwLHn>5P?zb9YbLY_$(>n(AIWZDPQ)Ut13RLvi;qAZ9g zmR@-}Uzy}yZ@Ox=)XLi!3Xv9frU2RkdVA)l8!=a$bI+3UgQwiH^Yh zRM>j%0evQ-r38~5Yge!OgLuF}Q6VAG{DAhUkBJRW3)a9-GtNFO0HTVR%}=8CJ0cFr zTBK%8#pz|>Cr1JM{$AV;zsqftozDz`#`BzJH7`6vf^3zY^ePCXUH}A?Co>N%*65?g zP(GD{&(O#*$pa8FC}ZVUR6F#}kPL+pR#5I#Em9T*o0P1+ZXGqY&ODwGtdl*{ChA~} z=QruP6Y_qA8byv>*?9jupK`KtsTcv&Jsbr<=s zh2^^tJp0U4w*oeW>>gcU@1cXgd{<=NjdLyYZDE?FWY6Gr0%$x?D*u0h05hrQVkPf? z%!#Av6!h8E3#E}@GIpxuEfukzLxm&GX(2sHbzYbf?Cjd_>0}>XsTk-TII9>3jl=Jt(O?8YT2&66x99$vHSLNVML!jAUw^#O zDxdoICicv`JMv+&8BgLvPr`vZY%DTe=}&IjLX|ByNw|I~%YVI~hjA-D=o>nYa*!Q? zHxo#ya9&|A-kguJKd>I@yjVL!Gc?(5yKEqUdrH}}egGO2jd<+AW;!EE>t&>aK8UJ1 z@$(&7`Pq~C2%CBy-fx~6mvF1!qSCo8DRsopV)#B zOj+NQ*JJiS`DcTFdF&ATHBa7Sr1h|Sf4snrai*c}upqZ}CdV@uWKG}YI#{~SE~|>H z^ZIwJ&|+H6L7|#GiM7b&ywHPx0J_ZipM{pE16+@URZ~AdR+q|eA-@g+Ne1bHZ+EZX zhye=7)^P$OH?m8$n>?~v%?n-tMepa254)z?DD(C;Mqpd>J?og5PE)6Z_3IRC-12d! zC&-V~{}6Z=J0F6`2b$jzE#fb5FK429Z(Bk10|V<6X)Pq;w>K?JxNf{Y1yN>JloPJ+ z1f>la^N$NE>M?eOjfwu{O}w_k=VDw(!|=#Q9ge!Sm^`tuN`c`9^XIwV+xOgWx~mTo z>Bw8bG%H~R_>jVCA;?~f1GK`EE#je+E1+*%E&O2?mZhYg^fjB)bIajCOjf&-;q-pN*ct6`eu1P$R|3zm^8)i5Pn+F zbwZWdEy``V=7$NF1$g>*TWPO>^a0RkA|2epX1*VLF@|_00tW)bs#u z^GTLV{4s>KFYuo+;7WqfA7{lM2dE!pVrE@EH;#-slsH#5ofkUX0)|+OVVbH_^qZjW zpEp&2)Rs2XxcI)#0QZA-A+f29m$fNSX$s+$Q1_G{MLMo_$hdTkEm9IgVJp+um~Ph? zA1>&zg)Zh*qP#4URy#Z>)~*%=f)dy)W3aW*Rt(+wv)#{iBv~k`AvQa{xops=KNW4~ zgg@<2xJVb(R$P)Kam7ieoh!=?h^_48Y=Se3w+2A~t|xy_PWfs)d*wAl2^3id6Pu0Q z4@TIKmUsh3%YTj4FpIb?-LHN&coqYd-~#qBB)b#=utMY|tdl~~KQ+gS@KiIsfY7&4 ziE3C<9bH1B-JaNJSy03u*nh28%BR_sNXtm`PT+f&5jigQ`z?l4me0mcwC`(iA%0tY zn&VrWiq}t=rNn*`RWCZFE_f?T-C>xUV+N@i$nqdl{)9!25i zy*;y?WSl8WLDyqTfp`(>ln#it*b3Nr5Iq~9R#)k7#*4b6yaKDP9m!>7uq8hm;;yJS z-{eR6ZA18`QC^1eXQhF3k7MNV=Bv|C6hzKAEPgu8u2E8Ebu|!0T>IK~?rV2VUV5T3 z6cl}2su)RKSoOPr25RCHD`R~Yf63x`FI75`czLWK1A2yh-mV$63f~BeSfkBweZ%m> za54OfqEUInlfrwzr`_)ds#WRWE55wnyuqf`E>^)xf88dPc#_rlCYP&Smxcp%9|p4enf~iff%V1kzuPW@1GC-{CyUs4j&Iw@MP4p}#fJ3f(6~ zUrAoFv}#}(Y6k(K(2zOplU3g8X(AQSajj+wf?%dwf}LiNmU_josG+^DP54TJ*^M7j zy1f%jFz=Imr$b6z5X>l;d!M7vKixBK*P?FOX-lN7`rAGpmwX-D2YVag?GRdeoYxOd zFQ9_Qjy3$f*>5(Lf$8);;c*SvTh7&Nlk}m*;$!SNqUpcodqCOtFy7RxK~> zq!_73R~y1`+)?YQ;oEQNZS>SAQg==m-*b!WZ2!ae0|q>u0fV!crYtJASF$mDyT_PH9=W78}@jH z>z>34J`FhkR`9mGZ>;>_Hg5jcY$#q2P|d~K4uQmq#Kex&U*Jd7#(=Ux@Y#&wu9PuH z;ip68#^C;%a5;Nl$!7hzFE$OK= zctg0eo425%8tcPHKBS=#)3f)Rv>FTxPMP2Je-Xby#e+NICzXm3M23F^E_Chf zL8pmdpZi%>D;lWAv5Y$H$}?wF(GLA85GZ9l+=YSg78ZA(Jj9?vra3Es5C$LtCcvfP zGr$)lZ9K1EJ`D8ACIKq6s9CZBhqKGMvAewVi1ALx+E23PDNO6KgLNDYyOx$lhgHhk z0$h&Ar{qSeg)@ra0$8v1gPVzIk;a{1AGlYsZZp{@DM3!b?(Ook5J+4Nt4XzwEK*Jn z+Hmz|TlKR8U(Q!hM6Jj7wd{h4-wDB?37H4-M4&!KWQ{Kqi+$rSkKN6um94d0ghFSoXjJoUYCjIpKc7wZ9uc7UpE!0)jt(Em*)N>NtQ+ zSj7Io#rBf2V(4o4)J8k-7p?dQ%LEzX285%JjomOBz$4&-KbSXp_E62qB{gZc^C`T5 z!LYCb#bAZ|?CqDCwwVt(x74(<&|=F zn;t~CmKIb-GBVTREXSkW;>awY^)*!$WBTOztS4^REERa_3Q2pmt!(zzOnj!ea$Q7~lJ-kjoAFao|rm9w%fLHn~nD7{% za$*%h^)0I+)Ww9s^aePBh4bGYNlOSp*}}pC>;t7;n2KmQ#b)2ltsTah*A?2PnK(u8 zKbnI1S%>D*l@hYELNmjM&D~tsbaF2wbd6u7Pci-7R?ufCyAt~k|3xzCfmAe97PZSw zBh!<+xHRE{JntUkHw|@`# zlsLe{O*fHMgd+e2Hy=ryvee=y0)g5WEFwQ_}8A)Ct=G0;7Mm zwxqFIl>LJGXBH8Y0%=Hv$EK_*u~-$%0gw#-o(H0dTfS*U>fb)r?7Ln@nbhyun$k(> zrMx?zP@W^|KZ3LcjsXGy}L%l9k+Kg-Bo z)`2k5(qV3ILA36DTXiw)U!)diCy+|d1|E5^SHq94dN>-}EFr;}cq<~P!pDK6%*-_M zCDzTC4}mmio@~ZADs_eM>Q}=S$MwDFN1xsz#gwyF{L4t#zP$@pdOUI*JhUM!gF*+t z`S-fey&V}2pA&?UoWBl`oJ>&)6d&mB zFaw>^=vghazyJW&w#QW9NcGx_sx8$-9e|Z0$U54mRTwP{NA*yRY7vZ26XDZ;4)XZx zhr(aOvEL5Dek*hMZI{ERUk|9?irs!45BxNbhh2UfY4E2zw@X=c$eOrxx5o@VH-V0m z_v9!GyOiGd$RyHN1lNKZBaK$T@&JcShy~#W#IrC~HZ+uAmU3y4Sz_Fw7K<)`tTE2H z-3#C7Qy-TFf4b#U`W%=DQyj=BTi{>VV^p-u1lP#hWroBX61juvx!>*w)#^vD@@t8ILS_GWW(jb11jxtTvq{XE(j zQAr$Bv<44K62+EItE66gCyb^gIfnL=neCmnwQs{?DI53kOJFhLGUK1V|wV zNzc$kfIozu*j6x`3*AX5wLK?R`divym764l`n1I5prKZpB7oI?Bz+Z92+;3>6fUr# zy;m`=7u@}fp>5a+V_{4igYv`=1GX?eiN51yhI5WaY6rXD#G1S+>vZReUI}iuv&-+E z`;_=J*X~I?Xu^LTWa<B}Q0gjM zy8fsH*l=eY(k8l)3xnO}OD1>Aj0NFj!OEMo-1~eZb?wHeWx_jkjpK_cy2VEjwLj!o zTbM}Tx!5t`0;wR`Wsd_7r=oHk97LJp&_p~!-@H00nQY7PH)tXbh{4=rmWRVT^QoDA zmX-byuZ12VG(c10xLPk)i40R`oQ1O^bIc<7hUYrYK8l`f*E3L~Af)Jz&?7enxf-%b z030OjArd5&taY!aixl^5BK`Y9Ip(HstV-aNhzsF&`Ow3nECuG3LRI)+)G*2vGeI&M z0A{N|lKkeDQiMAE{P7TqnjO0fF9STOn9@r8(mSu*IkMy-w#jaXD7TXo()c9D5|$;d zPMs^X`(hI+Tks%7wJN>rY-uD}0&wCMY>Y=Q&*@s4Z^ouLPDw{zLSm~WWdp|QErtuS z%q+pAK$LZ*$Xs623TDMW__lV#vqjTGTSVu^GbZpk&I>9q?R}E%VuoH@iEvx_lwmV4 zj$j9g-_=$8M_+t?UAsi{m!ypwG4U*$>~(kf4P#8Dyv;&wJuj4c4#U=XpR0bR>T!E; z^>ZWu!^-p?$?$}%R4gY%4o(;n7Yt}|cOFsc_oNr$0sP;^u^xh&O_5N~ zi4wMg+MoNrXv!n~%Az;+S`7AgG-=yM^tbtNm7bQ^zhvfX8gKYS@ys=z;}#{ULPTlF zFj#LF>}-Ltkpc+P>&m!?1*@S25bpNgV9Q zgK{&yzp}6u-GihGhQNBmU=w9Gi#OJ{1L{4)+KcJpifRqRq=PSvNIg#Xng^gBE_9X> z`aqePj*th24;(2{3r12XYos+Mq#sBXAJm7l9xCL-;#Kq)4x`VG1~NluqNm3NsYNCD zl%IlpH-sOIGyxSNmaZTZvUB`@*cM zY29o>UKrZ&aF@J8>|i{`lLE)Nn>ZFs0kd>9k~mqUzY!!&5S>ccA`Sfw#HX!gxS=8F zK41;jHg5O`1x zK-!iOZ2+q}Bwgwt|9?3%gv2J+x4f!{cbDV?TAFo1kmA}#FfxS+(1T1=?!s^JM+as! zjqY)G*EdwvHAww?n1apbDB59;9y8bRk7BOyQ)|BjUGy3!anP^zjNqnL;~%<^5+4J~ zTX23ws#>`f-s!d7 zyr986ue2gcXjzrT3hxy1;Hc=?#S1xGM~W3=?PU+g&>d4G+-OP)U?jU7VU_-E7u*GY z)#tGK|52<`;R$peyxWs^=8L)l8^0j*(J?^x>Z#t%R}9JJ#Gj-)J90h!8qv@ZzD|;b zj&(67O)l_0O4kuPSHg;t`KH(}V=Zy~dEhNxKBp8Ic%%<7wmT7g)6o?2&N}P(Z>qN0q&wtIJ^u|kz^>CU z)oBn01I(RzS@TAY{iLdRcnnV|ZHggOc4hhQHf-M@O?dKSA)j6>xJc8?oW3Eb#Ojs8 zco~(C)&^1lA0dYnl^`+w8UKCYI{OGK_DG2W^DHveXoKO_5n0!bHt-uAEiA5!hAQGSwk-N%y5G>AQv$J@GnyWmyFu zDn;Zdv%iXUDah{J`Q(PtHLJ2_{o-ZXEd(gWFM&rTB;tK$(7+vz3l$|GB75~+*86JR z#nOsk%S}#Z;!R-AfPhHDJ7VEYhBUMg2vc|m@!0dvBQq(}j{dj@tw7tj;&!{%G6Nc9 zl0!aJze%Zs)-B|bUG(wHkeN(XMqW6MEI z(lnJ%r?_x^cD6o@6-|2y8|;0-KqZqt5#!L-vs9^F*B6{5tPaAar#I| zVMYy^jic|Bz~WtVH@Ed%vlI1k$p@jdTR%i{I|Bl;Aah)oj|u1^xbmapRVR8O*52EE zAD&GA14w**1NcrWzT0>*oCMAm$FYQW-(d@-9oJrlkjCqJ`A-9N<$EWpse)rZ9AONt z;y1mlQwU=*##*3zk=_mX71Fk!<;&jH7HQN<(AmhTj!Q`qVYQ=i34ficVng)t{#hUz z=<`Xs`ECCQ9hPMCzIlCfCK?QLB2(cV<)-Sp^`*!u1+YAmi_sl*0rh?~MdxFzx%I&72r~$SC9X*96o;1j;}}k^afAa&nQv zM-A_9=N4=@$xfsHK|3RuOX5$zKIW6rysEw7elj@38rcVM2#!RqPay%%b~nm7Be6`~ z>7!-}4W@8Jdtf|DiX#+lhv5wVIOW#)L6$WtV#Fd}Bt`6}sJQO6GuRGx;p#Rv3PQYC z?c_QAJnA+UZRQ~W88dmPKvXUcN~dp9Ybh)`WVexW^xrZ4JY@US(RI5#)gdSNC^7`V ziQxiNdD9DnYH$w$iQ5p}W*j3fQO!7ko^eQ^NFTMGXc!mMo!-X*Zm+MXQKec%O@CcX zJYF)_e!sEw33EGT-#@(9&T`N8l1R&bUuTZ?_R@OUUqFiG@Wk;hJfocuPBoN7)~x~v z*c{YVfM_NTcvj=4T5)FoYO4eQj71Oq$Jq*lzGOJ$dUI-RM4*j&lu0ZKE|loICvru} z>+jKatdJAUZ`t8S@*Q1q@ye|)Vjo0=;1n?+)|M#gwf|Cww;F`)QC-kDPuCIb&!KX-ekzC_7O?q=@jYcTKKb zZA+gW2ee$uT1=3{-_?5|Ham7y9pI^^f^sH(;tHwKwF%~k%F;XZy?SJUQ&5k#=Oa4b z)v9dXqf!kleNRJQed+g-7&yibQDV=x5o31SyUkVU;o)!_P~21bQipKvwB92SI=L7w8A^IdekxoY3!yXJAC;t-a}k5;9lPJ zO5&MTJ9pBq1KbOcrjp4*QO^G28M6*U;6`AtezPq3DkDay$l5zPlhB~+cX(^2LeEI0 zqIe@+i@1SEgLU;gWz}2zc+a88xHMoyrRp05sxwa4$ve;%&M^ifvCy%Wa27{=rUT@~ zNTzg^vwWW}X3_ZP&HhAT{@$=LKtTBJNHR<^x_!WowBaf>OSu8XtWhPKZJ!oYY3Y1E zcH7dBdp!Jfw5NV(rq(b5)C+g?fC(_yT@QE&=PG9J!S*lrayX}jpIHeC-1b|qzC1b zC5zbAjCWiURtlk3G>5JaHA$}tMVyT_eOW<+CsqoaWX~fHIP-tVn=BmQW3&xab`g{F zE*=R}vrNiyHSKr05DzdJzCew`=RkT_GsPSBs@5W_;pE)OYWI1TyLh^wxq~OOUNti z2ojCG|2;(p&2lvBr&za}5{sFU`j|_<6OLUcd6l--Qj3axL7gTx1^6=w+A;V6>tpOe zV2er`?%}^!fP!?Alb7j-&y1SuAm2{ZVcE|`vzH}>rDyBe?2q`}Y_F;We3!A(!7B|R zX-&;;A<)u9c2&V_+NUspFs9Yl7rmDUK%11ve@?QVsX7 zmZqgMmDU&r`JN=u+vg0F z^%=RM1junCdzGo~>&bz}k>r3o81huw)0N*L%CHaH_T7vG6;JzAhmVzg!D6|2G@O~r zIBtwj8#ki-83tgwKj^T!7#kwbSOz5^gbgIMy4ItIZtU-FX68CNH$Wx<#zws9FYn1l zyPg@iqOy|QopMfr;a{6t*7{_|HZD9V3p`Z$^)v1~qI-_T7zj4u4dwNq35>wS4tE%7|C(9`^FVzWAg?Xj{arFN}P;4KYW%q7mUu5_#-M~xO6L)lTtPoqM}sepg#-xRSK<$=VIgM(6kVw zW116KBOeiO*y?L#M@|o~LWg8AQ!29_qv*RZih9QEV#a^Y&ElLL$AmAitUEKwTP)?0 zDw5HHN+!@oUL}?+50>{L+%v@Nhv7vhp6g(*&~a*k)99q9jyn;i=w&??##iJ15U()HZ1}u3#qaRjHDk$a?-;blk-Db(aR^9k0<_8ITwp z*a#&Y^(}W@k*>S%^%|#qR=6&&ik?dH>)Zbc4`21yCtYavF=M1buek|gKo0xj42y-C zQ03(c^3jO96y?P#BoiWNk*zBjAT?@#kNu=|PLml!1OWvS1_o!_d|fWkuESN^q}awU zA3mc@P`VK(@~%=s==EHoUT6umr_v)IF2$A|Vha`a#oL{zSim7|77DZ}(!+4W;R}Y2 zDG-*s@f&W?LB-+z&PM*PK!KRsAS9yt4ap7;x{k&x-&ttE{IS%^+!uiiX6RqV1z{gq zorp>H_omYXoNJHbrg^| zQ8OH^D#SQ}n+xYg! zJMy`FE)Mk4?ATIK!Pth2{9SJX5~d5_)Tp-1Gd@-TXTxfyBTHqe4m{h(!R|1@iYS6$ zXiEdf)i%UnS`F-VG)v+=b?9T)5JTO=aOihj#-}fbfM&nkj&D+dTowaBx1a-%wy0sK^eMm`u(`K%M%2*rV{e{D#O5L zaBzKlw81SmJuBYb>c~F zF)@NC2U1y8dAe}YMw~;wfz`v^cjMhfSI1Cy-vB&k+@d}pU(Z?PQD_|M|4SJPjrO3k zqeR{-Q8sw|luh?t9HYF7PlVdA-;*>~7($hJDEm$svf&5grlpZ2kC75gUUu+<^ffW@ zc5SZInnA9sA!&Y>lPsP#BhRNTz9Bhdd0K$H1_iClBXn&Y)dBRmWRW z9NcL3{Q2bshCcA(&|6+-{MK;BmOle0NQL_tl^b` z3dY?cxk*XGAPEU^K8$`(gVy?mK*QViO`?YQ=t9(UVzAqv#|YrCTkB`vsI}m}5i@k~ zacFJtN#55!8`go8%n^Q}C0-F*BW8%&E^fizIIV%t{p$>MM(_!LpvK8gm|)%41awmc zP%WD=^1>~VstS}7)vqg7(vnrn80_=Co2Y0#iqhH$W8vm3r96aMnZ2(%$S2GXBrPNo zmj}fZR*Y7T^!(>$Ma;pLm_dHvJXik#0H+t*fzuBOgx!p$(gN$+7xavGfc-eI3d#>4 zDq+Nv+{X7wu?+uQ7#UMTkSYx#m0hKbu5Y5Kd4W*PFs*FJf$l*TO+2L!3s`|TQg3w6 z>RN*v1M!Fpmg8r?1}~7WFyErrmB#fNCbH6Hs&wV3h02g!Ow`v5MU=zZV-g;m1u=^_ zc4s-%vyG%yrjO$z6dQ}M>i(ao*6|UjkU+c`e@Ou$+Z|E+ zj2(#3AX#Wc#(^DM$hUYlRlb^#fX2YG>ek!PB2yXOZA$qYqURt1^IH5}1i4s{!XFx! zsa=`HZpx3^;(A^)EUbP}kis_3#X+S*|5`0-tw-`zjV<}yjx7bw8$_;TA{b1t)b`F5 ze|F=@Lg+j(6$VeVMw;OHSUUMZ4-o;C>S;Gvf@C|&eJwLG1aRoZcK1Sj!=*2F6jGy* zN@(FIp2f|p$&}jJeklz$cV^ts9FE4CszPJJHpTo;IF zVUXVru*NZ@Pp=r+5V#}EnNAoZ5&_z3CEb?Bd<(3I#t1$x_(M|&LtMbL`H}G3BXcS! zB|l5Ep!YsiajbCN@>5bnuOENzMCK|ScLk>I`3bT~B~bga;Oi&|QYc*0*=&hpw_b-H zl0u9jZiX)=u<=n>;&t)Q=I{GNwauNGW@tZI6b7sGGLO=k3YCGtayY3rv*pO!>m!zur`s-Y zOO0Yig1b(hb5>}hzzoFnu+6Gm)~Y->P70)&&Hce46c+TnsoTA&an9tqZ%mpRZD1d zO0(NaP#u?B?Q0bKo_c?1e155?_qtK2o-WJ797wtEWEQ_}`l>gRaYQMaBvFbDRQudK zhaKpijMLoje#6{j|5+%KwP%^6DYy9-+7C-kc>iNEDq1*Q@`;;H3RTe^{JSh{%kZNd zPGt>vU-|>SW3M_Pca_XMmeJdLm2jJ}BSWRUlnB|4fa@h2DS-;RO3g;dARDZhq-UXZxNC=s)m|!;KY;X*VCGmC|O*WTdpp ztv;XY-%8aAT!Gp$a4}k1dE0=aIh>-wH=lAKfzcEb-WTGS_)`J>h>$I# z46xK+-f~AJYz$Fai8n$M$InrZl*#d>@5lFr0bC+lO6ryC1rWRtDxy}jFc(8A15GVu zkao8xR9jskB0=Lf;CFc1ao(*L_C+hm$e87QUIL~YZ5DL(_Z*mpON*ixcLxcM%%ssy zIF0qQ?~*ZucVLWn=}dY3Kka~PWL>mZt|FOh1LRKf`>*_=qJ$rCa+bbN;$sU_eNH<-f0w(}1`RQGFF%}Tsn z`pawQY&^=jp{GZ`zNAchnszHz{qelloKop34f_3N)Yc0NZU}GjQJY*tH9TVET=rab zDc^?eOqWhc3gxtYL=c-c5A>uux~bMu@WY{)ipqnT=Bfc#;0^mZq9pE#wDue#EuB2* z)3sb|Y%N7AVOX_tQ65U3GKj`bb2{Ti+%3MTSu9W=WL*9MIi$4j@{pAkEY)TB;wNAF zQkmjg)F1xcYKgd4Wzmj#&vmkhzrkLJFcfSlochR!?V8-HcUXnIH53CE7!7l~&u>M^`n;5I4SwFuxlFpQ8qUDjD@&aAa zcO`e(^#-~Zkb`vIFqg|R_R73U4Ujk}%M!NNoBw=FDS(8^(T9v>@n!_9w9h$sV(>5&lB?T8*HEl5<5}M8lFei0l<8(}$jbk0mBx;;(C)1{ z##YpwaUO4t@`$-Vte@aa z$ozX11o=8d?e#5eDy1V#@0`FZv;R7))*R~*-pXTzku7*T$;WRl0yX#m3H@Q5!*cN~sH)gA-*f9%dqd8zfO$y%B{-3N)g4crt2n!V zFnblt-FfhH;-IelrL~V3gpLLS62*&^| z5g?~=G#N`Tw3h_{jc@aI$%^c;s7&Kanm<4>hFtMDrG8>)TD%erdn&!Pf8Q7U*F}x` zk5wXG)cEM>!dmyf3E@9iR&NRTXo6&*Qc9H{R`8kHavGkUS&@H2Z)oAiSJVy+BFS0fJP7KPH0_Hl7Jvt3WO=jRe^n<%UbV6P3_ zLk%7ww2aPX(WttwEF*1w(2`OTLLInJpM4xM;c?^go^%PD8;WoEMTE8=r0zOo+GeaDNf z5IJ>*sK5g08Ook#+ZhG(*e=jeu$jHuPP_aGwI86Arn*iBm;-g{d9z&}Zo^!Sx>eB@ z*5B=Nq94L=j9@%HS#2V%5Bo?~hJg&%F`6q<;S)VU%#d2RzsbRYvIB+6ciSWEr$(;t zaESqpJ#xYkIGA76UBp-mo{d(b}mD-Qa}4)zUb`_}&xOt=y+R-NkXo$Msp#_10QDDIBBOp~{??G{h+j@-eqBd)qrq=(W}xe2nVBjB zJ{$H0?a;BRX~TE;I&VXIw%^Yob%$G-_pEhvN0bGz6YMIu_xwQp*sO~~96;-q>Vu?r zM}stTdei!X$xBRd!Y!8ED-uG9{T3V+Aok`=69!e423HKB%3YWN;Fp}&$mblir}kpA zqn_hG!+)=xtC6f8p+XHC1jsB<%R&6<2wjc;J%i$Z!3u4SX?Qnw z0tG)U*?XOwBKpy<+AhMv<<0)7Wn%JeS2;@~#z6WTR1R#Ta`6@U5rd7$0oqveDtggp10PEjVD-F43e3+wR~%(O%Z&|LMdk5NFOkx zx92O(A#dbxWQY-2Ea#!owcB8IA2F+=V@X}og}~!nX}#-A^*BbLvLip!IgXXV{zpLo z^bJW%e=0~HK~p}VilEpF{IbLN@G*kWDS0W_kbghO@Gbtu*e<0$#~(TbGSi1-Ie{5x zqswLw{mMJ-%)QLOAm`H2k6F6H78dtj=^$ToJYzi#t7~A!g7AaV&)f*q9|klft{l!N zs|ifP@>H&qe2}&GLO|f&Mg2SnufLetr)GQ_jAHXV^Ww|dS_UJBZl$=T*6|1{(V%6) zJb_Kfe~JG_U}fbQ7YgSIz_dX?#DuQI-hU>=2%u&7P_jBxJjD=b`grC?u~{cSs~?$! zv*281DOkKZ6{tEi6{f|pi}0@|08gNvxpxM?aP4+&Qk%VlGe(1Zag<4`-ZR+UCSWI#j^Qcfq@%APztea5s;>DfbSq^ld17}YxvsD>EhPNXYE=Pil56$|4PR2)La zl^TL~O(n06`GX6N9n`9H(aUjbZfR2(EzI%6zV!=v^;gRk{(BfDc+tyg++A_aq84K< zSSqMgLH%-q_d$|_U)L3UKi1-gjBbo}0$e6!&-0pFUkGi^$IwKCOe9!VtX|~Lmy2-~ z_9X|s`abY!l+s;cqU@Wzn>Y8%vak}zw-F|7Rb1)Op4SlOTVHFWcq1=0PbksKGS!59 z8lUGyBEGv~NlsyLjn=#VRNcgAY$U=NXA%j|L`0_x%{uq~(y|!VXiiE!QFY;~J}D)B zjJ~wGp=qsSrFL(JW943OuB*ol-0CRra-nUJ9D)@l7V%K=Knn@;;mCqXgy$X)0;R?} zK5Zx;evKDs=A7gU_w{(F=hC+!cjX#}ph22qo11HpX!rI-4MkRBw656p^=T z=LKf~Id2HN4U2o&9Z ze@&~MK3oCsEUze+yvFplBS#i*707xu5vQ35AasgnY`L%Cgu4UHQmW=<2E5xA2ZtTl!cS(`jF#q`1#xL`FZR5N1R1dImWV9^KbVIp$2xCmu0DP_ z&dOr*XyVO6Dx9>aPt|9$ZtUewX)k$m?uvg!LYb$qQvI%zFtJXb{g)hHofkWbYqGmC zN3#TKW!&z;Dd#EA`E*ar&X%lf1yD852ZHg@a6}|Kx8nS>1{A|2sC$irQz87D6FI>t z^4dw1SaM$!&Q=%z-sc3bZ;8;2yJ}HUKOEb={BQnWGfH2;VgRTj{T!ZQ;V4i)ZWbo+3;t4o>CPHgq z+OKL*woCYjpLJq>zNbE@(ooliY+ctaRaB-@lvo-F>L+PZ+)2t#1j>#KpB5oo`BM+V z0OD45wK2XIADg?F73<=UUuC{)JO>e%F@{KDG5OZqJU>neo z^g;|AO24k^pzoV8mi9y98kcKCAyeLis+(@-Q*0^&NHU9oypm&Wvrf<;CWOK^@O_K% zXPlck!DnjzG--NI41yOZE*>I0_V?fX0k#3?p|%$8;}G%>0Ws1ANL9ktt#{^uWcGBj zQF+-{+lOMeYr9N=By@Vi_hP4)Ov)CDYriT zxZvYnHVksJ$a6|n$@GTS-_fCDZM19Dju=KhhU5AX>L+*Bz;p*YHNgp z&b6B%Dx5=`Ucix&P7t+_Q3>LRh!~|CIj=F_5!=BilvG><{~$&Lj)i!Nhh~P6P9xbs zoSc`N>eGEq?U9KoGavKJgaQOT4-qd;9XJDF$(rc-1RsN+a*@*jpOt@E*Px`<#|CMz zxTG67=w7U&Sg;x1oh4{^63a@xX1XR>5lDJ5u*AXAb_-ui_POvR`J60TJ6&`A2A}zb znWh|As^U%Dd*IXnQ%x|=s;P>GXq!_h7AWn;U+m=j*WblLCVqJTOA!<-$Gzv__<=vB ziUufSVACH3!Kr&#wHI|71UK>lrf-f{B)|x5mWE0S`j2r44IHQe z-cOpvHCQ^NKqZ-KkR|aTZ$18;Wc1bG7L)*MQuq;+thDKwEIU`ST2CsDs91IMnYjzL zS%<`>d45`mRb`p4#nj|@js8bij6ZAJ0iQv0uhidt7$-Cb0D`$pFc@Fxd1}GScA0bp+g2n>1^t?TCPvpK@RpLu0@ugm zRBen>2mS2I_$@B0&&sQelrzuNC3z@#eio>Ta0ehEqdsQ!br#{Q5Qi9|C3X@87R5D- zf8;q84*a6a`j(ZhJq29cEz!Nb#e^QD3H`Rmv@~=7Akw#L1W9Zo>O^wlr%=g~$m|y* zg&oFL^o^(m6Pb7aHL)A8&vlByl?t~q47PzZFRrpb#rarq>{f0?kuJ`Mn@*!e27_(_ zq-#INmmVx>LW*!fuLE_P)Not$eyG~IG2iV;Q6z}X(U@}#SXdAh7S~W)+ ze)(bOI548ImmQLL14pqExnwSV$LlhcH-XH%{h9|zQ0q{sWE)0dUeN_!kJ3m=XV(6A?UNdB+%1EA(_E8HmA^BGU@FHKK_Lb~eABv4pHxJ{Da8DY2OsLOf*F_9Bw4JCB z#M}4Yp>XqkR*If&h@K^Y_^z>uvcsdBpKD1(4x=fxbNu>Q%qUD+ZzknhNPjk}q!CTP z_W)5~W6eWD&Wmvm>LuEMwtUn8y!-D;!>{+B+uT|iw8rsBsSS{I?z*Yby<}j`zjOmK z-FQ%YaFtR{u}dMr0X~nIm70+c`_!2)++?~?4Js~#N+40`f6h}4rAP3SoTGs|)NSU_ zOy*OgTJ^OtF=qT&k~owuK^Y;VVXs*je(vB1*PlSCJkG0sLcaDViNMS(Ol>on5oOD& zOv1S=t#FKWS^lQd3!8^dWv!oIHdwf$2qwt*Gv44htBAutY z-@S*$6!3;3fgi5RgDD*hewh}3Q+Xln$9G|<*rXg_xucM$r`uq>3FtPf)kzOL(qm`{ zGEdH7-F=Ksao8>kJGmiJebgeyf2e4@=aQoGiI!eTggvD`LgSu;?NdXn1cXj8CVN}Y z8HKlI5E;|r9sBKK;T@Ch7!l|5WMc`}5~heTU7pd|rS?&w=7~wbL%R+T>WECmQL)LC z+(mAI=~OHqqluDmx1sW0Jl4jf`^=U?%uE(%kV3o>T4e{IWT;8o5*dFDISfr^9Zt!v`Rbh3}5Tk7I z>BIv}9&&mWm`x{czom`TPa(nH+9Tt{hsv z4UhL45erGt1WvKSjz$!B6Z~np(62NK>RKvoM^)V5ir-W|q36rmu$>BZhoyq*s#Z|v zw%^WmN$-~Es&c7nqkNR9oh~tTLNP50ujw zo}2I$@7pA{@=k;ClGffvuGU_@8a$5rk*c8xeFAXoXgluhE1vHNL%hHzIwmD$#IB{n zT@L3e20*@kT1Dkg<|obJg_WeIg6<@YYg*dm!kY6cb*Eh+IRzlxhslT;NXf^?Y;&_< z5Yx#J>upx5_X?~FWZKe3dFkRE69}+;)q>=|9TrU--oMHOt`A(Qeln~lO?AcBjq&J@ z@B&Rq-vfrxG$wa}MHatD@nh;;v5_x1<;pgfxy3dHC?wn>_AcAiHpl|k34BP63l4B$ zrUlt!ju_eoP&ZC{$HS>QTyuc&XRsQ4hBOc1x_8v&AHDR3awPr3k*Rg;$#R$ARz2h4 zUL=^=L^(L*z7@e=tB){TUc%Sa+)-ytBYt>X?Ghjw!Ra+TnxF?I4Z;y~EF;i7DZ0Cs zhM-6YwD`V?j2!PB?tdq(sy6fV6OCJ~Ba?O@AeNE8a{HKh0DaJ=VILflW4-0D zP@|8Q3vK9HlV*V#@CpAKrq&94!(=>`T6RSS_pjf(OcIXgst)($c^Rs_c3U^9J9hw< ztuZp{M`kBMGx5VWHuWYb!hNHUc_9#2hfne3Zrx~}{i=R#jP1>g@t10oFGHHWe9E$- z7q(1=W5M2*qWbBY3g>?6c?Y$|>MbT2l%A2(HoJVgYhnETS?`Pfc8gGC8 zR*b4ghORy?@BQ73?mW`sejMxLFn@>)+Y#IQTS@TSG*HWEUFMEoQoq{bgFda}3^2Ov z?J_qjS?$MxH-B(l2W6K}G4JP9^JpifNm~geG zLRX=2ugo%skusXW=A9NqCRrY!JQNE*^A3GUnc zNGl&fC}u3m`>W#kOc=Pd14gEh-P0w*!F1e1f2v->LVY3h!S!K*oEI%Vc)2o~p(rNZ zBC}YJrl`rbL2*NdJ?~v@81)=L&XwGlg0p5>5A4JLTNuqwOPmWn&m6Gw3Te^o#NwD% zOouF-JV2tw;W$rPU}}#nWbQ+ZE}gX>=DlXYn>U=5{~X1^7oTOT%Kn+60whwtU_2?W1WrAg|)sRl#!7 z_20guJH7%zlxlzllw->!J}DvSZk|9Rt>JZ zBd~$hCNWqdQ%&3jREOA5B_X&)N?2aE#% z8%q}z?1bZS`P({Zv8B=3pe2z`I6+F|5dA5P*lijmd*+yHj&>gURLqPZtR7#HqcE)G+ z`EcLmWw*BLijity52jp2S=iY2+CVeYcYJ?Nk8c93a9|7wa%=x~*?<1v1)blSC>`8u zz1l&l>&Uk1sfaRZOP4dBhwh9xJZ*?$Z=(>C6m^Iruk^dj&1}uh!cz33n@Gk#GUUqM zyOu^!rXLwU)ZZrdd#uq4mvIng%PZ1cK)oKn%$-BY;KYj`i-#5n>O$o%(mmH?_r|Tv z4Y1rvE4nhMQ7*3XyyTZjGfO(@2oWS&&i{Bu;yWOAvO0s?x}08`LMzSfA0D~3G>rth zixj>%*idjVI;`u;kUQy`h$$ptDYqI8wLDyIKsH(4o7x4mi4|qMpE3LVXLE^xJMxYl zi|ey0Uk#GAk6<{(85}pn6$93aciLvI%P9&1;d6hGL|kn-rui3pQp|L>{PVh}SbXOZ zrvQHrNMBD^xssE8%3axPNY-K$415gJe(VjpxJ=03c3J2q!or`!Nr|icEeBzP>E}_* zKlIKu<9Dspme>dOkNqMxhl3VT5P7-cx7Tf`V;R@yu-<^4#>nVH^*Z>aKdHY{2xLTW zXc@$e$OIC21f)JQwFYc4qmtb)U|TnlFVlYTYx5O+JZfMH-*75hMXbVGC|;5Cj{bMr zDz1WLv4PW&{PBSK;1j0R*M|)W5yHq|4s{snN>H$&W>8@aJ>!Vvw?UMp!w8xz%H>3$r@?sFCGnbajH(u z)tU9 zzxvk7?K8MC!qV62E2ihzip1Q}A+4{5cjw>8@+17%V_!5~uS|e2*5MF_x0A;V>aJ&B z)68#)Y)8NjzDa(ltMR;~I!|`u&DuNK@OZyGyk@a=e_d;ad0nI3`B3qlUeP;0$g@JL z1M4h;3?lBu7?b#-I>LUj_nQuI9N?c+i|EEu(5d=U4Lm~N&oyT|MbNSRzkd?vtQAr9 zetLV%(E($j4kNE=oBwjcu=L=-@#F7&h5B*4nBb8${Zr}q8!KcxxEPT=xId)_7jGgo z=yGk%e4GmqHHUJbC0sF%{BKt-l6cTCBxFF1Yp0xZzC)zAJ#i zKNm*8?$t(2tppZnMun^wU%}b=a(5458Rb|lmR29S{fP;;jGb}silM^%oDfVp4ek|Ilu3+R+Z1A0;&h6=%!=`D$BkFt=83@XrDiOkGW)n~imqab7&xg1F zKpM<(yu|%cf)iTqNtB0a6*x_Y^-en;){N98Lt5e&bjuC92SKDzDTYXmiUo&8Mop; zg30_Zp4uf*U>ykWN1?uK8CE!VZ^i(!TM~9?2l_x;mtBpV*=dhszD;4JvcYE+;)rN~ z+d{1r+V!mMrSFL>!$Huj{rXTTHySAAdfz*#uUHc-J$K*ya6|U_+aP{<9ApU$DtZ`N zH(_}V_0&*BDx@|phhYFUEeQC}$dD}d9SwUx)sz=q$gJxfRhC@8&>lG*-f-QGg$BI0 zM)9!&rp+|LgGIyyiy~rZvXYMStVkjV63i2s+fNd>{!vcPn%ilCipBh;53F~4)4#XE z-5fT6?ib30W!-uDyWLbV+(nX*f~Q?Ls+NW^>L;#hOxc)DkIs+_4%a8oO&TiYLwa(dkhJkMQW` zwW?MwL6?yEmD0Bjg-dj^c*vbCgzE)jpD*XbmhGKL-{G1P;`}jp0)1#6ij^fORJ%#I zqNo`lD1aBf=FjzNL?S=O5jS~?%*qII7-O;X;$D_peODdk%NLklX47S(X$X=GHkjXA z?IesdHoL~EHNohT@sw)QO1%TYWv_mfuDOd5KFh6~j+*tXWQe;JBO&I@MV3klExCpe^@mDb4AcGRMH1ZLUJiQlyfI9ZibiyNgQh&&b3Ep^sx z(z}DMI|&?QFpT!`*rfOwy&{z(e*>4+473WnIG`V|7^kc(P%$#wOL2ie(9=2cZ6>>LAk2_v^@f($~23`^9}3I`_F;_o_x zQc+O1(#5oTAX$9jQH?|}VxI`(*;=+1D_cAVCsH_7$+zM8lkEavcqZdSZgbCrvMtwL zgF)M@GYf55^5N8ydTVJ2ZK)oV}B1@ZYTH99flMrep{eS5%DlD;SQTH&s7a$M_g06xPJ6I9C@1~T0 zF4D5YM zb*i&aK>ga&NnC}e$}AB!D87*)xuUh((HR^q=W+mizJB+WXBRDkoNTu{rtenp1LI7Q z$sUTc>()*qU~IX)JARAQmT83C>A4_^3oUm_753M0mzro@=f9P$t_9+hTECWZ%t!p#LM6oz(kwZRt(mRjg+-O$uIJ)R)DEe)kAgSf67!u>Q{S zUS(51c*eAOC7a9Q?d{#R??f*2x8d~P;N7=(%stor>o|A1q22PT_hI;V#CKGV^!)Et zqrE-wYOlf38Qz4$-Ot|bhkZzgdPCAZ-+msDXuU>vrn2u7hz5Kdx_;U1A#m7PH!XT^zJ}n7$M2Dfkq`xq1o2?aM>;k5oNcT7R%X?*J z(tMYelgR3+21meSY6q?zsc<@Z3hTWbmP~|H&qd+0+7*4hZi5a&^josg+a%;C?Txp6 z2TArRU+Ow}KNtQO=TsK}Z4A@&7178a&U4*HO=yln{3ymvZP5bgf(}WKnGQ7Cm)UDQ z2Y7P-TF*tkZlBCtL63|h$Qhm~q_tOhs#xSuU@(Hwrd;J=2v)s~fqw~UA(8zuNHe~2 zx{!|D_$*3|3NGUt)v-=O1v+}P`=#n?uyee^EyvBy>wbh;glj*mBlC8Jl^9ptvIWEZPt5`9#BL`emx7_YAi_jg?Cj8 zk0sp{yHw7_qcZNNsgo4xo$y+M+F7NVgT=7v+JsZ96T30#pTicL&6w)6XVbCwwcfHhZ39 z;MEsUll1=q-o@|n+82&XKmB4TY>^&Bs^nb0@!wHXsf@bV49KXZ_N`wvctVL;?;{9g z+G@EiTJzWVzR(cQzu#Ge-VaOklwj!~IjHK34szSnmju;T$^^8|{_oOzOuum>lV96} zY#tCf{+X@Vo&DNqM#I08poa^#*=)Vc#aVxJ^Y^k3C#vKxMs(yfvV7Mtk|_ftUv!BT zg1gV#d+0Ru2+`T>D9lwJ z&iXZCb!7hl;7wdWL~|!4B|e8JYz$@r=28{!s>J8NcadS}E4L0P)P8z@PhrLTP&%j; z9T~Qy?=!S`xLlxm=6=rS%dAk5d=`SGPTo-42lPyTXILTZFqh5e4~b+x{==yFR~939LkqO3EPr|*pGd-Z|bWh_lmATZ={6b zI`PHgD61`|aFQ6pHf6sbnU*)j!KXp97UyKwVy%3|A!us3=j#o0z zZW*(lLxf>D>h&)76NDuqBTRbHT{H-Vz!U{Y@FwIz)#xviPROGglX%T?eO$xnj@;hO zlB(&pHvkcQ?;V8vktmC(Wvvv_EO|LD?jFj@STQ7$esLH%M+XcKc!pAvWdPRPN{X-)S`I}S(1kZA~P z!TKJRyxTiOMRy$Ai=w}VGosiu+|4jPZxUH&5o7}RGu8Ux=zcrdRHJX*BQ-P?^D`Xt^+IEb??J;j9AJ{}jOY=1K4iQL~=9TN654#4FpE zp{V}{ay!~tE8Xu^*o4ES^e) zzJ-~5yFEbm!_3S!QQ4KsrmALLtM45xNwQak@Y;?-AFXo-MUw^qv0z6ltX46-K_@)1 zOK)&91)XY@AiQgv=N5TY*+OX~lj&)ZzLr+Xoa2Sio7>27@MxObpuM7MNM}JEe4!SH zeH}`F*~rNH@yD8PFB-#bBv*M*Bt$#=v2J>yrdmkwfrGT9Q8B0QX+LP&o^BT~1WL`r zqM-0o1Yh-W`s7$YMak1&V^9pNetv{OF082G0Rp}h>_P4Q7e3nCS_&x-$rG@x9<=qZ zZ71H>Z;3wb=CT52i&Bj-7Orrh^_eh%Aq0bZO(xAdI^)Mvj1hg)%hmPTxJjWX@cm1PL*2!N!)L+5!n z3O^fP3NX4u5nPh|5fx$dw9hrBpDcw4JydMd&$h;|-b>-j&E%m;Y;y_zVxCDK7(oIC z)E>&?BnHLO{&LsUY+?9nVT|<*)R-l27xpFc6Oh9`q51m+20P~g^eyycweg&}hNJ>s z%&%q&$|b$gr%DLUBFlz0^@R*Q=^Qf?ek427nQd}j;Yfwc)clQUwf{Wc&jlGuXa=zJ zrdRDYzaneu#wEf8_iwI(ND$_H`=^j7a&+uKb$-l#%(bbVSGIZiDUWR2KB6yokvBkL zki=;IHDv!C8=C6am*#D2^%>zXxTfS}-{eWgo+uT;ue;IW+S-Xy`;fpp$cvV~RW= zWTJ2dDEQg@cZxH0H=n0cq6I;*$RkCJ)5gJaayt{jYZz#WW8k(&r&$CY*i}R#aW)}& z)|G~rNden8{2?R*rI|J8n9~^A7^xz-LogM+OhAP!3!a<7oF#zE`P`#8*8>qD|A&3@dKP6j(B??dX72e@4?PfOLk z1|5ki@Gr1%QaV+b=NSeHot+OXad*DS2P)i>LJCRDQRyPWbMv;PGMcbUKKQ)$2TyZA z`lOH50`kW==e2)1twcSGhScYuDir?*GWfAIG4Fi1*v^YRALu3E4EVKjjx)(*^Je#KE$aTMgCUVDe)tr4D={a3ds@ zy#~K)D#dDE?}YGZ8-Ps074gC#phZb%O*+f#QOmni5BOJ%L$lDpMO2v>Vm>Eh$t$n+ z|1&6=mbe1v2E~n@l}feFxmnS7#WnEctKhZR(niE4OjxIBU8Ky6FAucYj)rgMLyDgy z-B{cqjc`BJ4VhHUHW=H(3AE%vEv+mG5Z6R z7ojrwxnVYu606`#Hl=N-c5U~0J0A2DL-x&+75b}TM$c|#ov8KB&J(HY==R&*WzcW2Df(m5GOH z#}=2zOBla|x!xOC$33u*PQ&As#PRbVOji8yk93$M)*_B!p4d@!&q9#{A>6blv0FF{ zV`oy&0Y-6(l%cCO6A}efc!}+57e5FNjXP1r{`^?f_G=XZ1ouDeDe>P^v(3{ARdEPk z^c(8d+OzK3Oy^HKZ1Vz`M%M4$6+*K4uXtJV!L1JYT@e>seHM!M^@!&WGWP~z+Hf5` zHI*N6FI>J7qWNHb5QR<554>&6SFw@uXRdFy6P;V&b&^%hz{p=F2HfppO6;A|5BFSj5b2d&Llm)V#KFXI=CARATrk!k&?BZ7 z-GFU{_2GeM9|6?`v4s4)9gz$+hau1sW1ww4l9drn6;A|`uXgfm)^=>w@E8Tm1o!ZT z?R8wcH;3Azb340xhrj#0IzmGZ;#&{Z1mOmNv!)GSW(!(jH3D3#kd12Sn`@ZD%0lv& z-t3b)@@I1^Gk9Kq=j_tD|45HG+m3R0V5cDg?y|Yb(uti^{|ZzB58cs?UeidiL&%rD z7S{3({|3VPl}ssadue5JMs;%sgf!1e%|+=zB=a>G`+SJaGO}c4%Td*b<12gLTRYC4 zI%=-?6#+r$FV}b}I`67>m;gRQ3|&7h^$mTo|3ZQ4wbPd-H@~wWPYh3gd(KUb>vIK= zLO?Rn9SM+nB_)}UBMMs!x?75CrF?J-f&{=n*P}*PH9mzo;qat+PiB8nEzX6o{gM({ zqcB|;8;)HB`P{@W3vop^rm>h`J;8jdm97bsja6LR&!7IR<^ttsc_T1?pV&|9gkjLw z2d5&A*g-ZiMGZ+Y6hX<)#o1~K<>U*ed^H|kP2^A|x0Dt0Y6)KF(d?eLhqijhWtgjw zt-V6&YmX22wDf?hYt8_f2?l;aQDj+p^d8z41zm$+md*{=Dw3Uw5mesQ*+jdfT$??K zABTRh{)WYdS)ejS=SZ=(L?4TJBd33b$u?AYgDDRAp>#n;^kmmtTe3EqNO!~*x{z2L>;Cp1cqC{unZ$)t=2FzK6N^F1Of)eDwi+%5x=ZBcoG zF}d0^zc}ewMaWjvWclBlJajMQck+V+0VznYJzgd@Z0gqu6 zREt|Ke%McyWO%Yx#SXoQ*9kt7Y}i_3Jku$X@9m_!yaB8z9Fm?>#j5|DviqbJ;;7JWxb zg;D4bloRWcjMsntcZ>itSjo3%}gXqbY)#*^*j5W^F0??{6 zq5+7t8Pp%mDfx~z%8J#o)t`qgOT=M#%mY!qzYs+r5J+A!F?fe5eAGY%K4{hL;31{~ z(sGm3UldgLAfJZ)D>bJI{gXtV)h7c&q_*jhw^BWhOzs<0I=F(I5mdYlEw{jU0=#a}PE8^Iiy2U?6+#a9&UcI)oo4*# zJG$4;w$g0F+Td?@vM_H)rp&$JDPLZ0Zph!)3TEZ5kCKSbab_O1H*QFIjsINILxAGE zfa3B|=M$@=0HroC>D}w9-dVnh%Ho%xvi7&0_hU2h zuhE{Q1^olA13J1Po0R05t>9x-WRYm%3R)51nTtR0fQ2Q_WM2iM9gqx;7(-cvNwsPV za;@T=r6SNogQ=}SL%-=ZIDQ)8p^e|RdtriRi{#2T)WEE1#|Ve1mP8DIjO?m(kZoP_ zX_re`8%RFt>L3elYzV>6gpm~iU@AmdWVcb55=%X_td5%EHvSB1iS#i05Bh!HlLInA z8=Aa_ng&fXGrD!S8(gzDg}<#h35XjFfxs#n5(R6kns^glB$!!EFJOP@D)a9R$oWuH z+3)%w?9HrrqWt3JX^OUg+mMr6^jn!z=^+Q;Ro@S;@z};^ISnm zO1@6n5Hd>!P7*BVyQ?}3TvVy~HK6^z0b z*y0|i)^Hi$J-X$tJ{jS4$X3;ZP!4iMs*qSv(;b+RQ2T^t@6J(SL5J%*|E5Er8!X}t>kYQlaL;Ov*0u< z&U+gIMFM{)*67egqjH5GTDT-65Cz!I_M`G$?=(^8shpT$7-T-}+hE(wylX8Gshq9Q~THq2*nkIsjJ;l@H%{2bfV&6VRa+GJc*aGa!UO22CMq1ssDAz;bKQa`N z{%w`t7s4=?DBmB!Q)BPS_oXpjcsE%5m_6=ua<_`5;7^!BTg&O2q8Kh-jFI-`0Z`Ho z2XkRCOC?XlUaDU67FB}T77ay{W%kPIfBuI9y|532?##`d8kLku1q#>DmeAM_#zAGl zt=inaH7NVZEmSfAINR-fx#^(42Ny+;9}%hXQge$hNiNOVE=2VBP=GygOj-rbTWPk7 zdqNvzi=$=2+QY7Q{~{?ff0;D(OK@JrD`{^4{VL!pNg}_|tN_~COl?Y77?l-zn(OMN zQ~6kQfc)_Dukr3C5cUFm*e|B=D;^IzloH@wRi@dhn$ef&N#glrw)&8;$7ZtKB+ts6 zyT6|u!v@~&Nst$Xkp8$LREUC>1>X9RUTmdv1mU~gA~O$q4kjt*>@NMX*~k7L8`b9^ zwt1sN9&mhGO2%aWEAzLH1}GO`KF!lg4l~&&*TEa)giR!bd~*bc^A6KjH&=ja{VUi}(CYUDKNm5!Y z7)-~_<@UNkiPn|f?JDbbU3NE5i5qxEQ(#SSStyE77u>BY>aFdr1uIlhy5H~bch1b6 znY3ZwbNB6gZ|*1Op5O1B-@o%afA5)lPrmi$qhEI%XG)RdoYLbsQyr%a=m%fMZ5qNU z2uSNdbjv7iOe1rHQFQ1C#(0|gHhJW%jJ!2<;k6g=>MnFpTv)xW-p zhx{Tu68c)WJWbkVJDik-WKvp7OHVolQ4!Jl@tC z@7%U|Lwjqyqbr#wZ!Y-Rj*U4E@o+iW-cCobS3JI{J=87omV^M;$eC8AIB1V#pCT8Zf}gYY;M?;U{lHU-)ObUD>V$nr*Vk56J z(V9$boS;6&!B6`F!%IADAI6k$aZz5eZ*%9SiRBHV?NDC5kw^UG^(*okTN^q%DKWRa zW!I{_S|g8m*ghoZ*w?r*+;MZ|)f;*BMhNj7c}9~)7zf%nZ*Fh1iMjGdqiSEo5+DxC zqc6f2`&kSj9W1jD6?VWx0fp9<#uWJFQWYk~R%}a{(9M;y4G8cp6}%N@z$|itu)XcOabT>bco*=1h>uz7|2? z2KfB$&gA^omJRcpwzW0^=XD+e?QpC9ZO-?rul|6)YtE%R*8DVDfwVFN=M-p0;9NG0 zz_#;lg#Xi*oi8V|gXLa_z%pueoB^oFnP0c9vn#QAeof1UWJ7Y>{N)_F?`ThcxO4u} z_Qv*x%VaEP!u*>P$4Uzy}PZcp$q1ps6b&FW8b>4p7}{s`K2e* zv!tWrhL*00tnS98-1cB}K82T6c%exHj*!~Q> za1}gI@Ib)>1rHQFQ1C#(0|gKK|Kow%otXQhSntb6V%}Y)F~7Ua{Z;Q{MSK5cYOLth znEULZ;#lwA(pc|er~5TR0iPS(vEUv&2OaIlbrad|IlPa_$K2?zV{SJ@m834k>%fKzjFksO6?TpozIp2ajJw@>I-H5>PE2ggjp&cjX{hZ&233uk)!& z_=l>6{OOoCKq%;jG%;4WqQkITtaYQK@W`1WVCAUs$aSiF5je?I@&=wV;m%>rhD_!J zb8=*kgYtVyIc@~Kd7<$mJm>^36ML_hY67<#4bm=+9tfU97W{tzC8nFbXy6Lj!5)^# zL*=;9eUN{T%12E~)%`Kpyyy-$`jQuY$&DWNqK9MmJi&%>>*Ge0(c;m;Y$v#0-82-EcoX+j+1VG*dKsN%kg+4%_e#*=H7KA=CTm6-;k|j z3jOM)Mt>#PQ$pzrruP36#36t8FHKV-0DM^JeTiIuT(Ie%7VZJTw2ACi?p>Cf0JsO0 zTO!xrr`+Y@xBNV3U;PC}?nuAzy?}ZpBn`CB$|Ru8ZjXwUsP~sn*WGZ7AZ}{E zWU1M1>VRM+|Aws;G*iK}v_~RR+8!gjD*aY#3jvgmN)OEr zc4%&g%_U%RGnNHvOHwrnrnWRGceCLhArMSQqVy8=UFwK(zoguP`LmuT<}dtnRtIGb z)r;ci;XXnfWm4;mSOL_1yG52S5!^Rp$J?f$OMK-5jA46Sf2}ZhDaO6WkQ)@ydnHd& znVUMMhJ59nO!NiQV*C;Kksq`A2&le*kT<!5>2r$b4^# zc<_(dN<$IK0gLYmXb}z&@}_^6@?F17js6?#F2Eqcv>SX@1(aC<1SnAHKcn=D4T(sy z4V4NN%SI?zt3n(rgn(MHpOEKELNQ$(*CEB_gDcMa`s@6*{7AnECb$vk1-*1HzP~nTz4c80HfM8k~)0AbO zWg(y})yi^#vM4qrCP{sa3n4v6D0pJFm^NzV5P+%sv@#@e{g{e;iW9OoAeg_fO$x=z z7*2~M6#Slw9JC?{sA;t-XQ#>$OiOc(vh1-e1YiYydg%0+U-FMyTH>fgMvrJG8p90! zci7Jb@ovjZ0C*pX$5K6rOua}7htw+|L=b=a^CEeSD}i2>v&+gMpmtLRSR~@8kvd=N z^)Jl|MT%8&mtysb$=vSwf@v*(Q04bq`2v{8d9tno`OW=*;y zeL_xu_Xxx)WLk~8w+6NW3SK`~Jh2t9j2KslKz|(ta>O`KB(Z6ChzO1t3Jo+%0*4H8 zLm(4^FRH+Lz|yY>sL35_^7mvtF(8;$WhYpKc92eUQ(J|w#8FcO^Jl$EHh-b|kM^t+ z!R%^;q^s3hr36&zR;dSHBK9v^4;N9mo9aw4hxzR05WI_)E2c_DMZ_N+ik1 zEh1#(7HA+Mkqq5{P!CK9-k}1^0gG=5sL8w3T8Kye~+qpRk#NP^B2yOV$c(%!b49G3ffhqV?`2x$Yv2a{Vv+- z`hzO+78R-35J{>lkHgzPLoHVKjU0cStkiKtpr>nGI)})zdsEC^);AiwdA5`x04ilB zp#G^>ooA@dVbyts>J&`9HKGCzSOElJ@j7*aM6N%o+`r+x>m&0Zj8tUQioopS0<3h$Ob@ z-6Dc*TA_hmlE7*sH`+84g6maaKVb0(0X6x6ntYdN7!XWr>1?oob}UtkWxs<9;JOT0 zp8=aQU`GbrngM$#@5J}lH zd7dwMi^sbz0*5puH+4h`AyMU%c%JSX51yTA#soSI$|x%472_!~H7*mr2#?9!Dk_SY zrBq6RC9?X);k=0@GBJPF$Jn~GC3Zqb-`+mIUCMWFit$zY6eE4nO*y}&){<{>&i8!9 z26Su~5;Od(*FavhaumL;7w^avArPCDrVZ3e0-KdU*dRc{vcA-6L@V6Udj$x7c$O)% z7DFApcznjkz9xk)xkJr3aV6g@Ym<>`(MCfS0n$n)6mthEC1NELLM4+{DtRsdsbm5Z zRB~#b)+vikhaWl(6>Jgss7lvGrRuSHTtIlfVgnqRt1G!qSfqPLO{q$Mv>J0-Gq?x!d`IH;O4RgGY3=XU(Wj{N;r z8UeMFVunjlxzep3MXv^-EI2EbXP@OE02!64ULx186phmla0TEE5R>tHpR5Q*#)XBB zS7>Nd5?De)QWL`fq=E^kO>;%X^cO{lzerX517~eKf(kZ75}k>oXoQ%F|5ms;N9+;E z%)~@66El}HaTkV0lwmhe(MdpcMj-H!Q&D0D)k(^7mVQ0(m~E zR)e2XgNcbxz9!3#kv?IePZS#Jkp%jLkoaUP0I`oimQTh+h#ylGk8sk)BTueRZbY+% zPwo(I`lMMP;}atA33KU_`WfPrdZ40{fa)x#Px!h@j!)JL1$;svC{_Mi%TFNBC$(zu zuo_HEe6mMY9V0Pep-&VVs+I)$gpl}T5dg7|K$cIwB0~Iis^ZT$abuyL>yum2Dd3a$ z3paf-S0LjPBJc@w>603i8fAz86`cfBXBmAmJ>Ms@g#tby5F7;s_{%ImfjpnotHBSd z!NkNT_shy-q*Pew6NQExNuW;%=_vLKW8X0VSw8s_5#l$iiu-1XPZSIFofh;k_~dor zrcVNaj8BNbC(NZ!7HOFd02QAQP@SdlNz9*qrS?~cnCD9;cKr^u;P=%6!Tg1n3ndlq z7a?5G5elB0CVtx|sRQGPpvq5e6(PPRmtx{z4*c08=>wAeb@+tWM`Md$?dDVYVd*L< zHK*hgGysoX!co$LWdLkcY=9&>SMAq6Ix6BhSA9bu&Q+Q=FenL}s|ekjB0+Gzn!N|G zxQ2kb=9unORMRJ}->=SiOtcRO<}ZAhn5(}C?6wjJ;Ku}vcfvWaOE_os3FnYt{?&I1 z=g2P6_Ik`4BINq_<9__xEGz)Ahk(1+8(@z6e9_ar-#pbFIttS~pLf@P5aPYOd+d=? zG<06xkWk1y*7#a%#^1c+zT!R^^H_5J|6-9L`K>*<(#6g9dBqQ+83%#s0qVnWQr zZ!?V}OpUnms%R{&UEFU1@h6xyqG?jPxaxiOaoBjozqaS#5-+od8q0JCf( z1cI$hR8`&p$zqN84XOAQPYmfDEy98m8Wja$OzUG<)J^{oXK`;xFsO5%c2ljCx?EM& zTU7*t>0wnQn?zMaRgJ2upK((4h6FRJ)>G<>n0ioSwN@2@;PXthr6SoRsyJSwm5r;a z9jZz&qpF5dJ5*J*RYf3pe^?dCCQ-#<5UTd6s&iD8U`Ewdlv<*yDy=F4!Bc2d=~9tw z5>+y~xc+`s_1Bz%y&=Jjs(F<9hm?vD+o~cEG=x==Y!X${TV4Nvs#>b51T(5;Q|f$G zRc2KY2wpoSR4S59tO^V0xmZ-QPXVmVfQvFxetU&l@ba(5USW=b&exXmL(tL^p3(2(*^SHLKRAN#FVn+14<#>{;WThB@TRq ziNGgK@E)ZPtXBwtpGtLb!_ci343vt_S-;@)=?w|S*7UsVzf4I#z~UR6`;DX#0>K_8 z+MZ9c6SOAd0aFirZX6IFS^Ks62ekT!Sp9Z$;2pBU8QDkKQv2h8^tq7`o*PFcVk01g z=SI>>TNnl)^9q3p+Cr*?MvRF!SoQMUNN*5HkHK4Y2q_cyOn;tJD1Ok9D#6MCWAMX} z9z0eo?%88hjt~f3CR+E9>;&!^OF1x^T47CT1}w{fY??+tGff=a4?rADASOS~uN;j@H+w_( zU04GBxp_P`7TqUB^inp}TRCofmoYRVhNc+V-nC(>>0NXTe%Hqj>$2A}EL{t~vuAI# z@Q3%5STnH^#~RTls(}h0q+^0sPH$t z)1Pa1I--_q1*lS}2+wSxX3EYupN|pMp2c+GJ5W3SkiCE2q(49ytwOtE9YMVe- zZR_UNn0SCyEFFm+F!jAh1~2;O z()2!2%^$KC06T=P&e%;YLuKKYPCio~THvJ~f}w8oWiSoWWH-7WV2l;&J^|^_m9bahul9d_ddDbEBBpp|AgH8 z<^D;z-!J!1W*Lh3+U=^X5zsg!-(cNgkB=Fn9#QgEhjWiXf2_y6KWvz zFrm$azC>s{q1}W$LZ2q|1wuOsJwxbYgaSfa39$u9;hQ6Ibkl?ne zE-K$1;>!o;7JS8lF9(;kBomEY?a6IU#gf|E_?p$L*E-kVymC!6>( zT)!q-)85b&O(xru4rOYF!EauxL7XoQzHia4ubTJEF_v zqp{068oHXVzPNh6$Vk8s$V$6@ReP6ww&7fMdqdKx0@=mYQe{R2tmo%A86mc8D;pYD z*U_h|JNPw=xOYi%Q}<>%6$aEOV_Fd`K{5AX>D(8Xl=PO(WIQP>4wC%sx1wz-H9rEv)h`eayFu0=yyzO5*^7zC)_PA z%hygzm$q;2Xm0~em9wF{rL}8C8=EQ`FEe3LqOrRxv81hOO`@wi*(Ob{%0c((qK$R! z-N{C%)N(P!Iw_N~)RZyN*4WM>S2=BoJDi)=E?=Y>X|rH$YeOR_RyQ_wCzGI0bf#;9 z9oGngoo!9639*mgcP?vbWcxxJbT*@sua#V<2`+7OlHF}9+nX9%oz6tp%0y=;YGExt z>aKFsu}oglnn-rlb#0^TST3ib8^c1P6`oHx4XtpvgRi?V3>jae(!1NbuH6=GLp#L~ z0)xdBaB`wbDLbo#rphobfm53j(p;`JupXyOhN-)Z6)HG0|V&G4Z&GA2spACjK)M+wwka?6UZyIrw-E{_`As$_G@h z<=>N&Z_|HU@i-Pxyyl^Qu)N&P2wyh;YLkyWsI1H8UpEQ=I+MR5i`#K5|L09UR{mL+ z%^x)Rmt^H;_@BBm+i#Z4@>iLBJSJsbHvc-4kG+Yk%jVx=@=xTSW|NPN@vO`8-)-`- zQIK`neBb2H&dSY{?@N=&A2s=SGReBE{J%5#c3iSVHh-VVzu0D&*yg`x@=sJhMW!E| z$iJtX{1f@7!sO%Er>x8BuQvIStlW%$8caTh{H)9JZ!!5N^3O+1{)x)>ag$$?B|W2m zr^&|~2!*TQfr1AL9w>OA;DLe%3LYqUpx}Z3um{e#(77pk+mib8m-LjBcGUNrTYjU+ zII}v=qwE?QKOApt{&0L#cSEwtxiJ~*ujZjga%f(B1I~TJ{#nm{-Eug7yr};yvdPI; zIQ|ZsWY`w#+7{nZ>GYKKSErBIs>4289D8-$9ZpX$WwfNUe`a-j^|jY8jW4ZPQdbwR zh_9+!BAa|YwP4H132iO)aGPDOqI|l{#U>%*U6r^(^H;r^peaz zS8aQHtJAa32!nI;gqdBnp3?lR<=Ahu8=O6J^Yd4B%f_VH?dv&m5-pbIK!(O~lC^9h zH|g1bYZ9Hyh5r+|-gJ(hQ`jwH+I;#5x4S zsdz-T0!eJe)*s-WA|RWv+1b)Ww2x?KSF#BW2xxy1{Jg4;zX+sve3`yW)9Vrq$;M{x zOk%Up60{^bSF|l_=iX!|X?GW)=}N=hkic&OacpQ~lOGv-(iv>D>Eyvsve|NMZ=+MW z>q)-hGy%?(V}nN`uPJe78roK}%c*lp;?8_p;H+!a9~Ew0wGNx{&W1$WmX;*sY;mS+ zZiW|RzZZu}Hn6{~mZJ#U_^ZNp?ha0M2It~-L~fTtL!)#17N?`w8TE>A&e*uz_sM-f z?s^T*t?uD7CIy_1hgExyB%f=Eb03qm+y|L~7lrKp;AIB4`-JZ^xZNkbmUxlwUXcH0 zlW+GE^yBh3a`InPJpDNSN>2V6 z5FVC4SMfCc(j5HO9QtiJ_-Ar({^W+gw7e%3H@muy^Kwo;zbr-)_jctvU-2~k{2ct+ z9DGF%eq#>4E(gCY2j8f8T0hTh4cpU~gMU5;AI!m@P#kx?p31?w4|6WUY=rX>-hprd zLIiuK#%gQg^1PJyI&tZn zjV9iLlMXZeFdonErg7VeagwI|Vi=dMu6;jmxI)6@<5ccUs1r_JYG{hd%ad6(FEwY< z$;~(OOm1>$BF@dqOs=^(;fX0XFMCqT%{B9oCQmq#pJYNpZA~(*pJ3sF+TpO0-y@8EL=gCjB(_W<| zP7h%|XiRp7Ki@(4D(D`94Eij685zVUJ7>QM&sVEZ@TPZX%LvPx>}>rn<2U>mbbWb# z+JZbFQy2N?->2&Xb;-KmqCZm?lb?4lzk#A2v+5#b!DMIL&#cz-m}f#pxZJD*JaWo4 z**Wx)YR6dy%1Dk3mPhPEjJi1K+38J?F$hOB<;VbQ`kL&#^qJRY-f0MzCEUg`b-}%; zv}ir3ybO3X0^$&vgipvt1khyC0>~r#mb)zmRRW3ZC=$lqXPOgl(kg*e# zbE{7#L;Dt=$$90q5u2ob&4IkwF6>V-yv^x(L_dg-+&t`UvtOpld>GuN}a5fT45^2$9J8 zC`afAehK2kYaQn~B=VUSq*)hjX5cgMi7x){l#3_GG^C-8xDN` zvnzId>zbtxUG&;_>$iNdxdLfr2;sBoX%ovU>CAfz7sus^F4_WfGiR+!um0aVGoCUR zgk`>k^WyV(-ojb&pSd_z5Hi6u-_}InBGN)V=ALyYi^lx8w>C%Q3KC zUkhMwK+db3SwS6obZ;;SLFS}dIm_4U+bopL_<74!%3!C^)FWjqx|4eRXg`c_Q#D8m zHXzp%kcPbtm>m20Y0R6JE=Ib!l!Ak8_LC2%*o^I#3+ z;KU_Rd3{lucGF>ZT7|o|qBwX-S!V1wn>5kGI8BUXhIoaPzEv2t^n`7hhABSP5u(>} zGsV)}FEnd~hIcpB6{7z=@e@-F{n)aKQZ8_U_29z+sKUW7mGod`H?=*)-7VZqvDz*n zmoEjqZyR%m$m=eUvbvBR6ldf{du%c9BI!*%R>}eVd@z<;4^FOI4xK@_M0XmWjv({U z* z?hkMp1ioPO`n*b1na@w=yuQZ)Q%!po2KGQ7ba%XO7-@s9Q_uyXyqa52Rn{2}bi@VZ^7n`X<;?>O-(A?|F=TNFfR zlVqCYrq&9qVxJMQOvwlg&QoEYFEsakhct35n*YepjcU^@wpWy*X-o?aVnr*3rs6}V z1%CnD6)UU(>q1Ij5T#5BDgB~~U<&GbnPOf_J+VH-t)5_tKR9(xo+oazrYsO1-rr&*EDu>uX(r-Z9XxD;*{_@70Bz}<&4 zLRd@aq0`tcf=BV=7~EwY{6n$~Q55Na;$An+zvnEJ%)PGEy`|WFe{iqTBJ;tyVg;^v4NP*M006%=EsdAL&?K1c;5mB?o!TP{z$ zu^m~qcM{Hs43=AQJ)|+-_?eW3DIv<)mU2gk^5;S+DMMmFrr)#w1$f0>I>5O2jdy&t zoyX4A8w@dxYRBY$|Qcq(E?Sa{mqUNH@&Dx>v5Qlvy|KRQnS zAzI)+(r7rd2dXsZBIR^b4}|njy&U`lObJ{-*@a_=3HejasgPr+x`rKK@=MmxI z{RB>XkOanQdjwXe5e}KsYXv?;8qx{#c5dB{$y_=dXl)Pg)4RM_!Rl^j2@KgD&Zn6C3A)e1kgZvs( z`ecY55O|0*)cq6pj%ohj7a+~Oqtsnp?4BLWv2tdH>0u(DQWGxxV6)QH0Li^In#uf_Y*XjaT1sY^OV5aU2Q;-;Pp>DLCsl#r!+gtE*}?ZR4XOzw2aSn2`b z3hhoq52m3#Y3QLeG?<1SHjwAjl{o*1R+vT2S*(&FruZW~D75!*B(&DGqYSKaf@!uC zzXqL`;+@s9qoat^56!}QR*p#-OBG|~Npo#FPRKzDj_H}>rNoHTOEg06EdCGNqM#3- zpP~79QdZBW2(P#gEl8#kqH_9{q)Q_HGlU4y#&tGJGQbpn@bUbvu}Y=)?d`$2=r?#N zwrn@`a!9~=B0y54b$TPzOo#l?{YaVHiB9qzc9PCg_l9Ektl-z!-bAf>QdrNYKX}f^ zskGa)G4bwzcz1~2^+#B*6lt107mi&zl8cY`s7zP9oAGh#OJEz5Ler~<-kyQ2DqVX8 zERX5s0uONvp@+4X|BwZ+z5Gg1h9!Ebc;PDC-PB=$)ulSHGsPeLdA>{Ez&S+H-;0HZ zcQlCZ_gRy^P|3OY2s8UG5a$vOwf0A|1*ic>MOfGXreKYGA+(_&nE@lX)ABpQ!}|mV z9Al<2fN(}gusAFL>0`we{H@6@7Z8^g0S|tH9ZMu%lbf{_ ze8+Mh6K>_u`f^aOw!Q=&A`N9|eVv6ur|ZkJa*iqutUYxiYZqI(u(ie1WSXT~%ajSM zz1VW+TU#2kR^S|KFA7`xeQc75&v*`(`j)>3@8jLSyp}LC&swHTVC|EZJKx&!khKEmSi3ZA?LAgb0Bf~Y z{k}R<_%AcXr+n9+Ei&IJZIdu9`msOUNW!~I-Brcz?*#8tQNGV3z1$-A#$v313Cf8< zSVRk4fjbUa#{FsxZy)VWueUohN=@U^hP{9cW*`!Hh=$PsZP>lx;(Qs+Se(iO@-UvF z8{w&0R1Pzx?>$lkrevHNY*#Kle9iT*BE6Z_gno!Aq&I8d)WeV!EVo?5iuU&IJ=OJJ z61BWzyF%3F-u>bf<`1X$z!CQc@7n7=g$)qUjivU32kDsShW;-FR$ zQZ0i|hrq)m?$akVrck&pKZ4`MrkMzh*&C#U6YdTEgK}6CSO+){5qH<`qBb*h$)?~C zQ>e`jUH5}7@KgfRu{C&|wLnIm0aCcd_v!c`WfKj$SMJljT%0~aO<9Xm)|WrTI`T)@ zI!>}UJxw&?F^1ASxyy6ehadt+G{OMZ5*McyR%`J87i5syO66I_WJ-nC*|G$S)?&b%se}a;FVrvdJ${v`3>I8ue+kQ=@*3?q_7@k?kQX_34Ny{$0E1 z8B-rv*=0Q%y)s3cadbZpos);6&$1ok=K=h9^3quJfG8m9t$axvE*GmfppeSsPB(De z|CoqE!`)6NuRI`+Kwm?t@y`rdttAXAb22nCp}NK)iiBns)R+|QQ! zG<9UPRH=sUUH%B``XtS?NfbqJ7@(<))JGs|OuWW=U;|}2q)v3+_A5{u-oQ&p)x(?p zum9}@7`y&>H9r5qL5TDswh--#9x)clvO44_##JJA$FQi{UQv!P8@~}o5V-9)*W}ML zG5jv{3m6}NmWLds`e|O2AKhSxyB~=A1WqiphZ8c_jRrWb(7IfIm%%yMi(l1a$h%L+ z|676We&XnD@!!4maXB9m=MF}ydG26^+~>-Dp4=!n2)&cg^MqLDgHI81x9M+kkK(Dw*!C-gd@B%!n5#e>a+<`cS&&}u^b9k98L(Di_v z!nuLYfA4bx|0~Z7{4Y5#P!4*_JvC5IflD9zriTdr2ab&^oHzL2^}Io?S$h)Tf6D2D za^hh43_=`?n)|6XQg~`%){&{J>dd!utLj2u%i&u;`LLWqLLcj`s>}WWZdG0QV>$at zJjPXd(-TovJOw!4jOWnLz&G4^5yrv}Z-y4(4Lx#aU6@t*?s7T8Y=j6x_!?g9IFBJb zh44JW0fe6-97T8&p|r|z&P14va0x;sLKVU?gjEPUkBt}4$KpHhGKm|!8#uNI%g~Ukf~J z&pP1vu{&ARusweXJgo1lz_|y@i~7C>9KW{}u7U>&9w>OA;DLe% z3LYqUpx}Xm2MQi2c%a~c{|7y=7|+ag2sa?a5t9RL&LYI`M))P*pCY`7@Lhy?&>g<;*ecKPeD;61Hk?y{3mzzVpx}Xm2MQi2c%a~c zf(Hs7D0raYfr1AL9w>OgdVuHuFRef0+MaW#-FT5xe`$2hnRCY1^ps8MDC(GUBcAuG zCphl*#^mgY{tv)WyzM1d5zq6V^uXPon$dHo^}~>4Bu9%qD!zj0_-~N6Zap`{^Ybz%>rarE+=la}@tut6@PndP^A3K-6Ym#&6w@raW97$h}+u%8b-T@7AE`9q{=l&+7?BeYK-gY;E_(*y6 zDBndO;|#o{z;{ykt^#4cn}V-o1?KxHkfmqLO_nsmOqg4ZqN?D&ogu#aS5p7z3b zNO-0^&ne?ekO1YijAn)96^P$gSYDUd9ZG*Z1b;t7^F|0Rhd}&^ocD*|bs;zzf_p>o z9)(5kw-lZN(auXD_-7&bSP15UC-@WkQ*gKN=^=P#2%fDlUj}mC7lK!X;HD6KX9&JO z1pieC{+|ltj(-{*g8AMG-&NtusplY^i*OzSszAATON7kHl!b92Z)bZ9&XP;;o mH>a}a4dA)yI&|lz>Y$yMnjWqv%;7+-8Fq-avsT{m?*9(tvbB5w diff --git a/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Option.class b/build/macosx/appbundler/bin/classes/com/oracle/appbundler/Option.class deleted file mode 100644 index aa4a23818e34881c79f078922039f4c32df4f7a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 621 zcma)2T}#4H7=Dg!b52V$wStI*F6N?k(M?cz6LckcVR(Nw4|Zg3GB;;7< znhLPgjw*0Wj1DT)RdXcOEt(j%QKMI>xKx#j?mVOLNKGzaWXqEuWPMGpV`oL~5n34; h&glkwn__n}g?5fwDG)yUkTP!kFUZ-(AiG)I<`)a + + + + + @@ -98,7 +105,7 @@ questions. - + @@ -116,7 +123,7 @@ questions. + classpath="${folder.bin}/${ant.project.name}.jar"/> + classpath="${folder.bin}/${ant.project.name}.jar"/> Date: Tue, 17 Sep 2013 19:41:21 -0400 Subject: [PATCH 047/556] add ignore file --- build/macosx/appbundler/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 build/macosx/appbundler/.gitignore diff --git a/build/macosx/appbundler/.gitignore b/build/macosx/appbundler/.gitignore new file mode 100644 index 000000000..fe99505dc --- /dev/null +++ b/build/macosx/appbundler/.gitignore @@ -0,0 +1,2 @@ +bin + From d04281fdc546a6404a86722a7dc8a92c8e7e2495 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 17 Sep 2013 21:19:40 -0400 Subject: [PATCH 048/556] working on 7u40 prep, remove dynamic loading code from ThinkDifferent --- .../app/platform/ThinkDifferent.java | 36 ++++++------------- build/build-7u40.xml | 3 ++ core/todo.txt | 1 + todo.txt | 3 ++ 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/app/src/processing/app/platform/ThinkDifferent.java b/app/src/processing/app/platform/ThinkDifferent.java index 79caaa338..69c94218d 100644 --- a/app/src/processing/app/platform/ThinkDifferent.java +++ b/app/src/processing/app/platform/ThinkDifferent.java @@ -22,13 +22,8 @@ package processing.app.platform; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; +import java.awt.event.*; +import javax.swing.*; import processing.app.About; import processing.app.Base; @@ -77,28 +72,19 @@ public class ThinkDifferent implements ApplicationListener { application.setEnabledPreferencesMenu(true); // Set the menubar to be used when nothing else is open. http://j.mp/dkZmka - // http://developer.apple.com/mac/library/documentation/Java/Reference/ - // JavaSE6_AppleExtensionsRef/api/com/apple/eawt/Application.html - // Only available since Java for Mac OS X 10.6 Update 1, and - // Java for Mac OS X 10.5 Update 6, so need to load this dynamically + // Only available since Java for Mac OS X 10.6 Update 1, but removed + // dynamic loading code because that should be installed in 10.6.8, and + // we may be dropped 10.6 really soon anyway. if (PApplet.javaVersion <= 1.6f) { // doesn't work on Oracle's Java // if (System.getProperty("java.vendor").contains("Apple") || // Base.isUsableOracleJava()) { try { - // com.apple.eawt.Application.setDefaultMenuBar(JMenuBar) - Class appClass = Application.class; - Method method = - appClass.getMethod("setDefaultMenuBar", new Class[] { JMenuBar.class }); - if (method != null) { - JMenuBar defaultMenuBar = new JMenuBar(); - JMenu fileMenu = buildFileMenu(base); - defaultMenuBar.add(fileMenu); - method.invoke(application, new Object[] { defaultMenuBar }); - // This is kind of a gross way to do this, but the alternatives? Hrm. - Base.defaultFileMenu = fileMenu; - } - } catch (InvocationTargetException ite) { - ite.getTargetException().printStackTrace(); + JMenuBar defaultMenuBar = new JMenuBar(); + JMenu fileMenu = buildFileMenu(base); + defaultMenuBar.add(fileMenu); + application.setDefaultMenuBar(new JMenuBar()); + // This is kind of a gross way to do this, but the alternatives? Hrm. + Base.defaultFileMenu = fileMenu; } catch (Exception e) { e.printStackTrace(); // oh well nevermind } diff --git a/build/build-7u40.xml b/build/build-7u40.xml index 814f1c4c8..6e894e2be 100755 --- a/build/build-7u40.xml +++ b/build/build-7u40.xml @@ -414,6 +414,9 @@ --> + + 0 for all, or 1, 2, 3... diff --git a/todo.txt b/todo.txt index e54351ac4..5d7a9ef13 100644 --- a/todo.txt +++ b/todo.txt @@ -3,6 +3,8 @@ X MovieMaker needs to be compiling as 1.6 X deal with null/missing folders for Tools and Modes X https://github.com/processing/processing/issues/2068 +_ add pref to select PDE font (so that CJKV languages work better) +_ https://github.com/processing/processing/issues/2078 high _ move old Google Code SVN back to processing.org @@ -31,6 +33,7 @@ _ change how export is handled _ remove ability to export cross-platform apps _ add ability to embed the current JRE _ appbundler fixes/changes +_ don't re-copy jre into work folder if already exists _ icon location uses path, even when embedded _ add indents to the Info.plist output file _ inside writeInfoPlist from AppBundlerTask.java From 6e2a0c98849313499232243b133cb10eb9576712 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 17 Sep 2013 21:25:28 -0400 Subject: [PATCH 049/556] remove /Classes from the classpath --- build/build-7u40.xml | 2 ++ build/macosx/appbundler/native/main.m | 8 +++++++- todo.txt | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/build/build-7u40.xml b/build/build-7u40.xml index 6e894e2be..0636e96dd 100755 --- a/build/build-7u40.xml +++ b/build/build-7u40.xml @@ -514,7 +514,9 @@ + diff --git a/build/macosx/appbundler/native/main.m b/build/macosx/appbundler/native/main.m index 55bcfa917..516efb08f 100644 --- a/build/macosx/appbundler/native/main.m +++ b/build/macosx/appbundler/native/main.m @@ -143,7 +143,13 @@ int launch(char *commandName) { // Set the class path NSString *mainBundlePath = [mainBundle bundlePath]; NSString *javaPath = [mainBundlePath stringByAppendingString:@"/Contents/Java"]; - NSMutableString *classPath = [NSMutableString stringWithFormat:@"-Djava.class.path=%@/Classes", javaPath]; + //NSMutableString *classPath = [NSMutableString stringWithFormat:@"-Djava.class.path=%@/Classes", javaPath]; + // Removed the /Classes, because the P5 compiler (ECJ?) will throw an + // error if it doesn't exist. But it's harmless to leave this as including + // the root dir, since it will always exist, and I guess if you wanted to + // put .class files in there, they'd work. If I knew more Cocoa, I'd just + // make this an empty string to start, to be appended a few lines later. + NSMutableString *classPath = [NSMutableString stringWithFormat:@"-Djava.class.path=%@", javaPath]; NSFileManager *defaultFileManager = [NSFileManager defaultManager]; NSArray *javaDirectoryContents = [defaultFileManager contentsOfDirectoryAtPath:javaPath error:nil]; diff --git a/todo.txt b/todo.txt index 5d7a9ef13..21928ef33 100644 --- a/todo.txt +++ b/todo.txt @@ -33,7 +33,6 @@ _ change how export is handled _ remove ability to export cross-platform apps _ add ability to embed the current JRE _ appbundler fixes/changes -_ don't re-copy jre into work folder if already exists _ icon location uses path, even when embedded _ add indents to the Info.plist output file _ inside writeInfoPlist from AppBundlerTask.java @@ -46,6 +45,7 @@ _ the "Classes" folder is included _ appears to be line 138 of main.m _ maybe this is a holdover from OS X Java? _ bring back the splash screen? +_ don't re-copy jre into work folder if already exists no good installer, will need JDK anyway for the export require that this folder exists: From 2d7b1041fedb53d3a40a28069a935986fc39423d Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 17 Sep 2013 21:30:52 -0400 Subject: [PATCH 050/556] add project for appbundler --- .../src/com/oracle/appbundler/BundleDocument.java | 1 - todo.txt | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java b/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java index 1687ec397..3e64dbb2c 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java @@ -23,7 +23,6 @@ package com.oracle.appbundler; -import java.io.File; import org.apache.tools.ant.BuildException; diff --git a/todo.txt b/todo.txt index 21928ef33..3901ae507 100644 --- a/todo.txt +++ b/todo.txt @@ -29,10 +29,10 @@ _ changing modes brings the PDE back on the second screen _ the Find window (also the save windows) also have the same problem 7u40 switch -_ change how export is handled -_ remove ability to export cross-platform apps -_ add ability to embed the current JRE _ appbundler fixes/changes +X the "Classes" folder is included +X appears to be line 138 of main.m +o maybe this is a holdover from OS X Java? don't know. _ icon location uses path, even when embedded _ add indents to the Info.plist output file _ inside writeInfoPlist from AppBundlerTask.java @@ -41,11 +41,11 @@ _ this is in main.m. why the change? _ any missing args from our app (copyrights/versions?) _ make sure it's only running on 64-bit machines? _ add MinimumSystemVersion? -_ the "Classes" folder is included -_ appears to be line 138 of main.m -_ maybe this is a holdover from OS X Java? _ bring back the splash screen? _ don't re-copy jre into work folder if already exists +_ change how export is handled +_ remove ability to export cross-platform apps +_ add ability to embed the current JRE no good installer, will need JDK anyway for the export require that this folder exists: From 5955f3bb99543597cfecc96e5ada9f287991a231 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 17 Sep 2013 23:42:36 -0400 Subject: [PATCH 051/556] further work on the new bundler and build script --- build/build-7u40.xml | 17 ++++++++++------- build/macosx/appbundler/.classpath | 7 +++++++ build/macosx/appbundler/.project | 17 +++++++++++++++++ .../.settings/org.eclipse.jdt.core.prefs | 11 +++++++++++ .../com/oracle/appbundler/AppBundlerTask.java | 13 ++++++++----- build/macosx/pde.icns | Bin 0 -> 42258 bytes build/macosx/processing.icns | Bin 0 -> 415779 bytes 7 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 build/macosx/appbundler/.classpath create mode 100644 build/macosx/appbundler/.project create mode 100644 build/macosx/appbundler/.settings/org.eclipse.jdt.core.prefs create mode 100644 build/macosx/pde.icns create mode 100644 build/macosx/processing.icns diff --git a/build/build-7u40.xml b/build/build-7u40.xml index 0636e96dd..73b45d858 100755 --- a/build/build-7u40.xml +++ b/build/build-7u40.xml @@ -414,9 +414,6 @@ --> - - - + + @@ -467,8 +468,8 @@ - diff --git a/build/macosx/appbundler/.classpath b/build/macosx/appbundler/.classpath new file mode 100644 index 000000000..74aba6a10 --- /dev/null +++ b/build/macosx/appbundler/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/build/macosx/appbundler/.project b/build/macosx/appbundler/.project new file mode 100644 index 000000000..9e6f7c6d4 --- /dev/null +++ b/build/macosx/appbundler/.project @@ -0,0 +1,17 @@ + + + processing-appbundler + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/build/macosx/appbundler/.settings/org.eclipse.jdt.core.prefs b/build/macosx/appbundler/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..7341ab168 --- /dev/null +++ b/build/macosx/appbundler/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index ef9121223..14f9e3022 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -48,6 +48,7 @@ import java.util.zip.ZipInputStream; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.OutputKeys; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; @@ -485,6 +486,8 @@ public class AppBundlerTask extends Task { private void writeInfoPlist(File file) throws IOException { Writer out = new BufferedWriter(new FileWriter(file)); XMLOutputFactory output = XMLOutputFactory.newInstance(); +// output.setProperty("indent-number", 2); + output.setProperty(OutputKeys.INDENT, "yes"); try { XMLStreamWriter xout = output.createXMLStreamWriter(out); @@ -535,11 +538,11 @@ public class AppBundlerTask extends Task { writeProperty(xout, "JVMRuntime", runtime.getDir().getParentFile().getParentFile().getName()); } - if ( privileged != null ) { + if (privileged != null) { writeProperty(xout, "JVMRunPrivileged", privileged); } - if ( workingDirectory != null ) { + if (workingDirectory != null) { writeProperty(xout, "WorkingDirectory", workingDirectory); } @@ -553,20 +556,20 @@ public class AppBundlerTask extends Task { xout.writeStartElement(ARRAY_TAG); xout.writeCharacters("\n"); - for(BundleDocument bundleDocument: bundleDocuments) { + for (BundleDocument bundleDocument: bundleDocuments) { xout.writeStartElement(DICT_TAG); xout.writeCharacters("\n"); writeKey(xout, "CFBundleTypeExtensions"); xout.writeStartElement(ARRAY_TAG); xout.writeCharacters("\n"); - for(String extension : bundleDocument.getExtensions()) { + for (String extension : bundleDocument.getExtensions()) { writeString(xout, extension); } xout.writeEndElement(); xout.writeCharacters("\n"); - if(bundleDocument.hasIcon()) { + if (bundleDocument.hasIcon()) { writeKey(xout, "CFBundleTypeIconFile"); writeString(xout, bundleDocument.getIcon()); } diff --git a/build/macosx/pde.icns b/build/macosx/pde.icns new file mode 100644 index 0000000000000000000000000000000000000000..214b19877ae38e580adf5e2466aceaa6f6b798a6 GIT binary patch literal 42258 zcmeHwcXS)qnePCknk8AbWI1tc$ zaZy%sx1>P_NP-~126l=C?7fp933h@MdnZ`H27)9i(F=+9-2o{UiB+IwXF1>qxO2a9 z%XbUrH$Uj|8}D7ku%y$M-?;jB7>4~+^0efX;HARUXs70d&&Be zbF&xN`2mKJjxM>(mJ1e(kHvDq^?q(yy*gQ#bU7%X_Lvv$L!-{wVE$jk-o_U8gOE!3&9W`<+>lSw%f`Ej^n!Urqn25e!}Al^k3m3hY>5)k zBE_LJ?K~2&m{$zwwJ2@1XK_*q14cbc+nsI$v%?l6cIr6hq&SY*?KT^JQ%i3mWm*vo`ktSh9Yd7#jcQ&UmOjk1qVvowQ5x z^!l_b`>}QTF4wm=q+i^S{>l3E(!~wwUqBiL>7CGO;lc%2E36iad7~gK2tiXC|wXWu)6$veRAcbB?23l%0AF_}~ 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 Ze8jT{SUj{dc036kWX~Uj-MhYd{C^CIlIj2e literal 0 HcmV?d00001 diff --git a/build/macosx/processing.icns b/build/macosx/processing.icns new file mode 100644 index 0000000000000000000000000000000000000000..901fc569e7e2f8de6a78df10fc9574c3319237ef GIT binary patch literal 415779 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

Z; zOJ0D(E1=R~)ZE*U!gGDS7hZ5KWdflY$pI7XozklB5sz2EzIPv3nJ8W_n~27WC9FDE zpPV6|hONX0|EuXGea)Zx`8i=H;8%YAH}eVhDJC)u6c&K`ur3NA9*Zc2`WDIG_J%Dp z)IU3e!_cAfS}X)(r+|C=OS>9rYi*LonoVf|@1=`(q!&ienqdU(y^9}|W(URE#uf|@ zt;yu%Jvsf%%kq0){VvvB)$6*z+|Ec@!k-|b3OfL-0(x0(O~8N+&#}LH>1s@U9ZfaT z*@j7PPk$d9e5RxgjcEX5N#{f~-|8pG6s&%b@8r|*k+TQoCK`Y9-h&wQ0Sq-w0~c^{ zN?>_;Mc%n|UGCvISu%$sCDJodO-%hP8YkS4;K!GjfO4J6CqH=f%3zNge3F5X@70(i zGn~pWzJnQ{McZG6hcFF?0vs#@6vc^wIj& zylJ_TWr*kYzxijsB#+xcLOd?`+4E=Yvl=Tdb)xq&L}bA%o{Rmuo3XEJ6D$A8ji35L zy{uzobEC-6zj=oQNgN&MmO^W%IaKY17f-_o+Kk-B)k2%WyKry6^PXJ);C<-_+dZ7H zD$U*KT+r?co!)aBtNx}nP+B%}Z-xi6m`!J~sMjwtFPEcmSOL2`McL7y*v_9f{VJPZRr*X8as zP7UC2hH|fHLsUqQa3UH~GHf4EOO$+Ale9iga^qCE#*6t%>zPaBErY(8 z_M(sc0SW-;*R|L)IZs5vTg z6arZ+60y}cx5L_=-N%HQyId%4FW8azj=SujCcUG|aJvjxyw0U#F%j75h;~G_MT+;+ukP>o3G{doc7(kZL zfC^0{M!H5X-I4`-)ng5cud}_deD&8q^P=1~r(ofQgHaK5j@_cbfG{(KFe{+-m6&{4 zE`+OW^+B(}kSq|xhF<>ya60JaAfWfd2q$Tda3e(-Gw75}eM2A8g}fe_4k($?RT{l- zArGj1O^ek=F{vq4Ea6I%=1y{@;vwsU3a1h+2M}gP>1~3Z9%?74#j9 z8=F~?(c5Y?E{iD*<5t2N>;||rwkTiz+IMmM{F*rqxDAV}YhiPl;14;=veu=rL6 z(ZdJvRSY9H3vPcqXM;GP)5v2YO(oMBqJB;WwUH_NrJl%3QfvyH0wg(nJfd_VvcRM07`tXX6B(m40t`8R${|m1?~7bG3MGRG9k3sexrh3axe z-ad0`mfhm_`a2ip+W4Z(ES9qL6Qvepp-3>KM>r8pGHOGweiEOGt2{3_MG*mlJ-zXa zL?m7e<;I*QltRR)ykQAnFG|qIx%X!*YJ=`u{^KIGvC9%q{T9O~c$8HA1o}gbYM$ut z%0-O7{A<7QSgi-x)hK{@)a>(Ci+TTpeQf;inlFAn?@buHuR~+I5!&7Nx-R~l-kXC7 zbl64V$KfYG`AIoE$n#=$WPXt!OX_lDB*0r(cd)UtC?}sjBQJjBJQgRiYa-Ixibkkv z5J;7o>sQR+z%%# z18RZupPyP-`#ac+7anv^H7+jUAhX6=85lkc13+xT!Ao``>GDMxG?xk-J~$}ju;Z_- z!W0_*i5dNrGGt}{EG{ibPhYPz!Wa>E1hlQ+ljcH`EG=_)f@Z30aZeoK9y?Rt)5hly2LmQy8PDtl)EB$Q77IjjGpRx}!$CfZ)xwCac!Qsn<}*h+Weo=$y+7r6 z9np)2TCs<UE{Y5e~7kkorR|S%&1KD6O;;8-=wb*`uQ%Rav_s9&=+TO1Q_l@ zr9XY3S$5Xab4#B%J0PuHz2+b!miyM!GUm24#r!-)7^QWY38M}a(K5^NzYrG-dpQWO zycOpu$V9G~5E0PFGL(q8`k_y2C?P@VqDsMNMj9bHTfn0W^)Jo6XEEKjWeHbhrKw{% zD1o+bdl1DMUdWC$(i!*4v=Sa!geEl!aPvE3IXWJAyJ9^@jjNTfJBv6kbV}!{JwYFg708PXv zKlyR=C+v{@-HGW8+VX^MV+}%QUmq3})=2%<0;=Dpv|}OQ7R}ICT~Q5G*a66pi5EK0 z1gLGaqX4aeWGoUjj`bw&c!TwdV@ym@z8<6i8BCExZ7Q`hQYRa38p+X~D-E;KXoY{nO7pCl@YW@m!`(sT^h3ctFKqEeypS8tjuz9D{Ba5dt>5 zuq-$4jAP`qoOh=an2-gN>`W-8h6D=LDE3fT~Ggr?hM@Xr{9Xa-p#o zdUQu7$0yO=!qO9tXH<6;rverlt@&8{5>iaUrn`O{Lr%pwp zK2n51Q6VkEfeTRq*aj7uLZksEKLmrvhtp&cMDtN3jTA}&${R`B7a@IN-iOS_Ma5%Q zyy_?m7i1t84Mb+6ue@XoFNHrWKTMlpbtt#*paAAO1By@hp_l;m*1PY^|MffnZvfe! zLGA|lvCn_HXy)r$>@a!(cKN5rZ{q8JU26Skx_#z&l(~7fgHD4HO0-wM);YdLt))O+ z=!Z62x_f$M4hI5tw5#EsqS-2n+*q2C!(G^xh++RVo>uE6xM=a0z;*t$ZuvF1hvOpHHa8tJGfbAhP2cO94{fyTX91bn0F zGO9GWzS61h2pQEY#;ZW}W5{&G=pVGsS1$Vbt^`#kT7mgepEQhr-7qW0p zTSTSM0Qd$IGQx(`rd5j5g%V2ABLHfI!WqoB$I?(1X zz}^B`mRI*aRKJapSdLR{)i%Mr@Di#mI|Jwda3rAWay3v{2Ow9RtpOXb@YK{4H~!Pt z*(wG?61{xD1ByzvRF2j+I8I&}oW*NskT1wCpwS<0XX75PoF~w?Id-bwq*jmK=AG$P zS%zKes8GnC7DxR=-ge*MQ@jeJUycju1D+gkJk#aK2aUf6R(>ctTS7=-d17>mCeWZ2 zkU<+`d~ze^yEmeKi*tzB~B;DAg|-h~abTAc8Tp?|caCr_P`ci+F1V`Crs^!3FFN<6Y0 z{_pQ@lhyTY>Fny1QzsA0sZ%HA!sQR--gL1Y00}{f{AzS{ZB4FDtw}h`CWGO&``N@uIlV-ILk6D=NPb)%(zA{k`nA`AY$k|t*q^_W+U33H< zhfx5Y4ba(vubYHxZ0nLELtR*}y=fltiK#_2qV>`5$UJTcx=J6mo+ zdO%wZMjEKF13>L3?tqio%RQrT&%A(PCPRV~q7b+=xh_Y08~ol+NA5k9sEwsIGDb#r zQl8f)q!I#fGN>flnaB`cKn11a$kFnW$e3B1Vi_Bo3erB%FE_{Mu-f14_0P$hmVduGCZj888~ zp&6_GpdQwUso6QKs!ulliCeGLCjn+d+}Yj&Q@ty)xw;_Tea-UPYu}f#sW}fWEz?nTaZu~j5xzILJAZ1WC&1p>gAT=z)IB`>Bf46H4Imb zo74NSegR}Z@YDfW-D#9DEQnF3gB*;94Svx^-)E!zJZXAS{wXAIUM65MR4yW54uXak zKd!+iCX^6R20_E*C_V&4`H-I245D-k^Q@eJcYXT!o573M-Mmo4v`TiH>8cddr-(-+7(G7L>XZ!Q4yu3S1HQT zK=5#Ra_Tq>?g+9_+VGo3Px-S5eImOEP)_1XM3d-}@mzvkWGk0cGe-jGBBvw39RXke z*8a8&V2%fNdT79^|Kr1W$H7FezWUgB)-<(B3)XUREkJSS>W$W=fS7at#4g}#oWt~U zFxvB}Pklsg-MlG-J)QFIdzZ@?0icBP+`?Lo^!N2hGY%?ZpRI8TPat{Q#M2;o?v3Tr={ ztD-|cMKEJwtQfxX^brGFS>KeK_m)gWF8YN}YAhcAB zDX02rPQ|DX3U?b*v?MW3X+1y@3BMFRL0&AHm#1Pp`wSNqF$zURpf0oE4xB;(z!$b} z_$etxL|~bYyurn1DTsQ}Vb!Q4%-kg9GM)kwR;e=r9WydX9Wk%I5F#`Vw4dE4aC|Py zQx8+Wbf&~8M#($m#0=bn95-oN<1 zoIj5p1@Byzd$aQx0q}ba4Qtsy=AJ~<{B&byWgZ`CbgLM}Z76V2V1m$Kt3TAh9y$PN z1)6(~o6eQ<+>-Is+4ENUK=4a?yQWbFJMwNexx*_h-#|PG0()riwy%YLZM;fq#~$`EO-uBztr>#*YM`>YZ940dE6BQ4TxDvUYRl~04C*X z@xwf5zA6xJSyY%4pt>@;t1%sb{eE1qod(#E<0E}CJ2x+r_h#&^<7z#)ZrBXCefy46 z06Yth;#nc8EuiB^RY!ZXtgLTIS9iC3`>)=VFaG3D%EfE9<>@oWvEaHM3k*xFEyzkI z1E$~kfByX|_~>txO`H?3$#n}nyS?f%HL&Ln0PnTE?C&)g#i46PJAdti3nt7T&Ya(# zT9uil4O7XKEAl;QJm3>RV6Tm2A(^p*M#G3KPpQjE($SJU~MoC2oky@(m0DVuTaXqy*E@ zx1gu8gma}0F-9*y#C;405BJD67QfJ4y)$LDFj{$`P=hY<6Vfy6Tn@NorjY`Hr%u}2iH-i_6Zc?0A12SS z)2Y4=y!^J-I33I=2LPRBLI9|^>lSP z0eO{3<(KF0?AUj9BRVoTcL=>2bPL?nZg~=(EUL;n0H&dVqH^xpG**nRVk^eWuYOc+ zPjkDRT}jW;n5Oz#*vwB1$xx2D@UyE%-!obPi70?6$4aSxotW#gZ!_4W1}}S%IP=G3 zg^brG7h&ob`(O8xCkj#*=1*b9&qc(je8lJ6juM>^a3=Xep>48Ai)cC zcZ^Rob-vbkUvjW1umk8Ywr|19RW12(IWJvToE*igU#|GQ(rJ3?hw`WYB8*w4fc{lsCTnntb$QPfI&G0xv#$#^_+03lHz3GxleY>D%L2sIAQmdmvSpse#Hm z0GXl)v`uRRPL1dv8kV)yRXNzl1A*-n0DEK|g*rhWKnhG*8#4b!F{CAa^oe#=GZ9TP zYh$l|5?_l7$|`84y^P2m86N4ByVJ`uZO*?;a%9DGG7*A}Y~{^GC_&s;J(bivkinDz;ydxfawgv&R^ksk-B8gico+}zk^(D0m8J23CpSo1T+Z`VDx_B& z{jyxhP)WFqL_)Dj9#(I~`+_M^xjqHZ?Z}tD{HHd!4}VXeI0jq)c7Y#HFx`YcdOEx0 z#*Le}=PaYvnOzpnsb?GStM;~5H2zzd0(u4(RT=EU6v0-x zHzkyha3Y#4l{WP1C-E9T(AO>782X=KEpeF~LB8r?ulgD+Rnd}EzRSr(4!C5dvl3#S z^kNo+D~sI1icp0phK&n>3WHzjSqw;b70i^I2`nMD5}pzwA2Bpb7?m;#*_sf>UB=@K zmfH-+>OD>o6e%%i`LL3OPDR+5g%=f2D`0K6s^wWo<9dXuOKD&aTFKBn#1ndJavoNg zR%9CsJnC_xl)gbW&^0^IStkux8<6iPA-IBIR;AR2Uj2Nzk=VX2oE44vee&3}L=JT~ zNkeM~&M>fR78bE@HF8R)zQbr#{fGe}1=26WX=CsFkULvK2?|9sX)i#59#BTcDk0&^ zvA8QuQJnvA#>RCM#(3YtxYI%kYi0cIm>I4QUK-KsBUbVv5p+Ch zP;DLWe{?70_|c>C!PRSMgB#=x*idN3M;39L;YZeed?jrJ77JH5@RsK~0KQkNE~SAz zbN~{v^g)86Uw!^5^B8SI@tysHo{-Pjjj1hI1l$y^y|d0UBI<5Z2vV}Z*T&v9-~l2T z^l}g|6~F?vFeJ4wvmiQqH`3QC8|HXR%=_P&#n(S4k34f+Y7RI~Poffz`3bI2Y(95L zl_5Wc4gvX6GbEJ<;tdU*X>j(Cj>;=ngwlt3c&x(70w&`qYzm|RRiegADTZ{o=qW2% z9GJnl3lU_{IDP9vNCZ`E<$h9bT()AFC(TzzT1uv<6nR{#l4bc{|JG|+;C%t>=;$!- zzP{dWv*nLxxm50`MCic`(0SSf&6lHQ1xgsywBB+Xz+9ym=v7?a9dWMpdB&HE2 zwbG^taaGXV(4cEqB7P>;O>1dZmlhfOD8vu>jDF0Q3#YQ^$r3 zeP4s)K?ONJfW?71BFb*?nY7BtXz;_FVP^~GxLQr)Z{e147>5^a?qJSnjZ*@lJQuda z#Soq%70|}sYh|z@Mq(P_Mx!uwilU|Oja%hUB@#x_4 zOA_4=pW76%0+d$co+Bp!I+F4VSu@#{h=j@%g)&)kQuXXArkI~6BL}XcELvk>;S!8W zqF|D05em(W9|$|^_}EXbBoh3caOt!D$Bk``qRi5Rx=DC7lZ2b3`MchdvV z1&JX)!zG-OTQZFmDQHqANj=O5QmKA@A9n!GojHjHyIwX{t@+$k;VJ;|HQ0&9e|~mW zPMageUFbjn)HMb$G4S()^@L~}tv%!yK?O^K(7xispQA(YR zP4Yx5Sg3+1Uh6pHdInaoreFrsI-eM#43}`bZty8DOd~^nh&EYB0Wz3MfD#Wx3FNvSRP0kWoG3uAj?-D6`a5(qLFn!Dk6!@Qx51zs?{rx%oCB=%8o+0OqSFWY9REB z@MfYyUKdVw3^MtmtXQoZn zTG!Xth5P(l@!fU(`ZekAfr&Nf@ug?Zp;NGlQG)nKU|LcVlAmTs$qiZiSnwi1Zm{2-W>lARBJd7U}0fFu3R6*!o%ImP9&8Z<##@J zz%IM~1#P@AwVLWyz?9A^?*LGv;T4FUoL!accPDV1WWlU3U0GQ*i~mTn!yAvAqYbpl zfS2O~fwW@5ke*@Z5adFX?tx)x+E~Q!zFM1td17R`8$gp( zsR9&(A&TKNfWZCbvfqgrWhk34gZJ?TMOukM<&_rnyJfKtpRIP9NJ<6)teo^MGDV`i z^gWpmgxH4|*7V_PFe7!MBFC7PHG-N@NNAo_Kn*NJSe_d6sB6?3Rw#P%T2^c$p2}?f-mm; zzd{@Hr;gqhjR9Qz7WlTivLq$5eB+^3Tzn~$RvJjbKQv!?NZ;FI` zbROvg7XC>5x;*7%KAvO7R4ECDFiH|$1{NYj_VYr(`*pkc(bbBhf9Dryh6juM7G|WW ztzB;3xg)Q<@}fzmv7uJ(jNilQgA4a7*_51hd}MMbcdeTOND)*4UIUeN033VR;M;Fw zi=f_b;SA~3*>UWt-;hO&0GI~{jqBtbj6+~dW}~JFh9JtB1Jb8XA5fpTlZkkMYQ%y+ z4nGxS6^;LnETE%7$2lPO1aZO->|6)E^<6jk6q1uCqUb`j$y*9w=|1$|_)9F7og%0h zU2Y^tKn^%pOew_umRBmh`;3pWABD555pT=VN^}mcM)u&D#k?yVz zX&*cyJ4<%m)y-RXWqNu_Zrzb5F>xABFXo|!!`!=SSeEr!}^m{tm5bc=g~e85+uTo zo?_Ld*a(QyO`&6a#O6{cWf5QbEAfkn%|*F%aCcw zx6dP=;6OzkfJ}YynK2iB(7?WT?T&1&%*cE1UzAm>_^ijUytwIh+>V%=V!#o~XE@<9(IGHFzb~U1 z%o-87WvL3+p>rMb)zC8xm0hpSx z>#c@{horf+RpzFr<>_;$jNV&tH1IX7z1p@L^Y@rqadvJ$Z*Q*itN*zdjMwh%niNlG zzhf)!0O)h6U(<;PnpU8;H`dV;q#b6fCi}g=18Yz-Fg{_QoP+&skq*7g2xLPc!U+pV zOwV&@L=H5rV}u_~KO1?MuX^~Ll2~0^PvkHVV1i*9NgU!SbO=c2DMP}(1?}#k;e8F> zie;60FZ$aHZ&{i95QvKCZ&ySAft*}5k%mZ18*oJBHbDMlVk5d(Na>X)nE}8J3E&(x z%DpI5WrPW+JR>BBCZyM}qt6lR$1Y5^Yq#uQ*l6DNE;o2fk{OAX|+%)Z8a;n4sOY`$` zcg)%q7#=(TQ@|^7{MZp`!(u=>8VH(OT9!?B_R3z;EXK=)fZUQegXV>e96tit381rM zz&8A(|L&m!P)v1vX!sS*rI@vX`yjPA5W+a1+PeB=V|`mzVJL#mZV9wJ_JK3t;y?JZ zFJOqNrjEB3XHL|$%IKB%&ErZ*bnPuoGK^LK*GIYNFO;tohRpt?&?!Jb{3HaU*Wj*7 zo1xk`e}!`6LLTE-G5rvy3NA)R^#C7|I}p7rmnqEvGcg$=NXJX_=c3B44Lv!Pv=ZMu zmMYZAG6E@BoeI`?p6}!Y;*>H1F~me8h@nYDiQlj5060B+Xn4RBtI({Q=S(#JC%n!0 z%3=p#-Whm1a{Qz$Z`Z>T?5tVvO(ByL6LN2M(X0)4(DVOHufg1(8X4-c<>4BzXcC$f zRYwinrw)L5Dj`mNF7$8<{MM|ANz)ggL4G(^2GZWRGl!D_MVcE^Pm`gG{kS204)2>G zeuq4Q^#n^>4KjZ9LX5l{#)rDPI?Y-Go39w!Ml`$hjY|O(QT0n{pp08sTtp=TD&Z-f zi-(I1^Y1HRJPVm5AuvvEV;T4qNCE06*#R179S|X1W#lqeq6Mv#VVWojfNU#=Zb%0(j^TO!1A4--UrV+8nTFvY5aF{J{n= ztUbeaz%~2b&(B1f1h$`x4=~|fFf>Jxs(hB$A!=duQOzn=5&9yiEJWAl9a|Jl-KZwj~7`&HpLb5nX>XFc@=K>5ixN_=;$kh0TlUhya|eko1sWvgBy9I zEt7_ZdYHa#$MLpym3u<=0eF2?;Ap>i{`7Jc@ z+k;j9e4p3iy{?T%J>YHF|G%}mVh({LLkH}=eCMqzGK6V>vuW2Ell7vDY6)cxuqfui#`Ty5>T& zC+R+XRF=lC&PB*H_FHu$e41!_w4EZuyJ3 zEQv9KYNQekB%diZ1V+{R(%hv`W!u&5N@il0X+DbNu_CEbV!(`C1Fxitjj<@w0%IuB z8$b%Gk^(=ZL6}i~@zW`a_mAN)u6Ttpz8j}?BIMU}D97M|B;MpFg)EX9`9N=EL}YCE z_?{}za2XsI6m!^|$Jw@FdmC9+ajwYptXdq6c=tnS${FREnwgaYgM+ezh1BQHp2b)D zIOgw$vb10db_J)t)F{rBE;80Uepx33@bKihJ5!Wy86G8*PD&Q^`(X<(N+ z+a-CFD(`8IGpHhX!&Y&^If*`OF!NucjFlEKB{oVcg)+s?hDI78o|nrITR%D#8=yRy zBQf!mc$JsuTk-x^$uvz(SL2HJa00>%cuAQ7V=ta8aBSo`mD$zaDnoeRu-rraeKLq^ zcxX@#!LA5NTU#6D)QQ7VhXu*|(XHeCd*%8qdF%Zv*r8=dQ#a7CAHYaz1LkNy`Kq1gke&wTP@a^mPA=%NSX>UJI1xzk6{s4vU8XI{XluATm!!WO`h;X%1}^}6(S zcN*0^3>yGu#psi@CqeTGg_!+u^HfPmT2ZcK16Y5ns0-)N`2TS8|pT-|*@Pgon zJr9PMx^>O0%p{<-s~_i2kIMAInhbU|%hmD4IJ1ex<=3Dm-aC9m3fpUP>7qM)BOvL+ z6hlMp79Mxr+yIdwxeD5y1~>~?*6LaFTvhULRqt2qj>J@mNGu+s3?hy$SCtfEk(uH$ zfr0o~CNwSQlZ>J%gI5?vG;&1l#%0mF0xHTyefBhM?<*nGWmp-q^U;Bo>TB4=G|<;8 zi;IhRU17m77RU8q^s&FcTUrVjUA#LZ-R*6d<8F}Vj&9IzOJ{dqw!lXmN{g&(_%f%P z!dAWc#$~g(dS`1BhTPiZgBv$-l3%ARF0II!)5qoZox8BBa#ZFPm!!3`N6sG~k>C63 zw=rsP-pDvS&?RqPxGG17`(+k9)cEw&w5(x@0E_b?e(W6ar;rcyu0EIw$ zzt>kV*lfFL4>2PTt;D-eXb&BL(h6kb-{iLbZJ{#tq7qHq88tWJ_UNeK&_L<$Xfh8N zGh!zKvgI~5x8iK+mwi_mDK;UZ~-1*hR{vU&mz%t1$gC zr9VKjGBQpQ^QBE~<+%)845XTl0V81soP#q|2^^y)UrvOE)sKQARAK)~(85z6fhFdY>qNtTH8TKpijQ@ z?qy^7PG(ok9`}<+My#NH_{;5j&CSimZ2J*daa~wlmqr}sHi}W)`nm>LaBI3YH`b&F zW`5^z%?gx(Fjje@7%o%OV%re(u zTG!Lriq)am5diq1ZX6%nuz)k7+y1cck5e9Q-Hp%f^I;ttIRx9! z%Q%Bz%B4{CQW^+fh$&2WLuNtM@O)Q4eOJZHl?L@!)Wj7#1i(BH%ikcMgnI<8n+o|1+VO^KO%%nXp~n_=2jT+;ea^}8nt15zZS#)>v-QnUDDLjhSB~N=&w__ zNRU&p?_RkMlkc7K!c#{u*KRvb%iDJNf2hAx-oJKN4s5Q;k%J@XDD}v{{_IUGd?(bYUS?qw)@!B%JPWZhz}tfm8}5?GfG7V7uBxU3Kq+3VUB-d z?6%<;LT{P}^pIkD4nzKhb}S@m$HI_xGdE+1l$kzU*MUK^*ha9Y^!E64s_|zJ=FssI zQoDtrCREC*+s_)>!Yo)`|*-0p&WzGqe;N^E1F`Y=s+*#?t9HZKyN3usvYQ)BO^m{1Y6&Fv9i6pyBq8^(%#lA-M!uBD|Th8 z&b(7@-&;hZu^@A^)3UQ{*B0HKn8H@KW*LW-yGe8!w$Xv8$CkJK=n7cjPdAAUOcQoA ztYb=mMs(R^b2Rdz%?V3h2YSQ1=B?DLwaQ4(udFI%F z{Cl5!1%o2na_aD)96LNLwT(@J0RVaRl~<&r_kc9C6gzy#Bzxa}KEN)p0v3zY6~ zQnnkrr3niIj|}d}2Y2S3D0gFOxD&Njj&;?^dv{l5b>1y1bX2DCf9kA>QTDB|dk*uY zdwh6zQ@M-K7eSTQGV@TO0A<@vF8Z%hw&kqgQFvWWf zU&d%Kw=un0%Ta}8-HsgQ?9mT5VI2cc@T2usPM`Lp1GKb^`F$E%!#nuYL3Et(_ubdt zkYRMBxI5s_3g{f+@7Pc`zVPvp1{tJnM#o^CqbqQyjtrY)e-8~GkPA2)hPx(C96lg# zyfq_rIFfw}rsC7?{?;FkY;>@5C$|O75Jn)j#aO3jgHd&r+eP4WpYJS|w~~e+R!|{2 z>bGSJb40V#lWr9zhGRxf;Do3#+1bJw(f8Q+M^YP`nx%huSO%MSLx6lj~?@KNN)S6Dv__tzycLQImM@9xP1l=r`uHAw~y94;@ zZ$P{e3-dPcj=<62Xp~MKJ1h&>y0&AMfYrzn8ubru&6(+dRm^uUFU?DH8w`gbo%#7W z%>QG%Sly;9Zs9WnuzE}{(zg667Pa+vwcu;n8aP{nP5X5;oOG+}$4Zsrk;H%VwKvTd ze>*x%1HD~xcXAr@{GBrDwo#vd>I6nPrsN#H@ZY<58D&7zzp)}e_JvQIDFAMhWT%KD zx!c=Yc;`3DGe-u@aqlq5izDFIS}{D{5}&c0xhf(X5Qy&X7AXiZkzyV2p_!Tb~MT;O=mpMK@za_7ohGKrCf zs(Vlx;Jva>7<>FW_Zd%(c+lC~>c~qxm5zmSqM!v4$3k*TlH9-|7YKP zT{X1uU@PMuIshdqyhGDU7AwRi_J8zX zOUc+G7XKk_y#dQ})3Sv|zR<8~8vmBA9@)X-8)JU5wHF2?-b_6gNKJvWw{h%QAB*)2NGFxG`YGa!t$mh z7(fad&xkJgBbka)-%#f9J24p^8-0uv;~B^NJPz=ptE+D?i_A7w>{oRIcKj^ki<2*> zjd?rg-h|UdyZaByb}hc{o$2spd_~d%Uw3=E+#H+0_Pi!aMJEl@i+?$b;s36y| zm$b11TWU7!JQ>FUu3Y{ATWeaR2gCfVaDzSVvWTw1V0W7=H1^B*`*wRtm{JRJ{M1W7 z0BcqD22P-NUv*Ut7!B;cJ$l3ymwKp*=Qmb-R*paWpDtj)FH5jScGB)WkFd*nR;Ae-8@-*W_u$-+t#^bi^=4 zjC$}OTuV!fNplc}Xt85crqKAex5Bz3?&S=2p*_j2@(w`iK}Z4YRvT!y7IShZj~~a% z+Iv_L+Ac?rAC`+(M`Z-I{8uqDFoC<$i9NQBu&8wuC-_~4QJ{{&_;8@!B&Je_m&xd* zw`F4L!Sx(9z5VO&_H9*!z6dI&AJT=+e2a zKwP_a6(b0kGF(|e}0{Qe)wkN?OgOo5a>j3!Y!v}Jea|TwTILvnY_ANO+GA!eF#$Xz9)X?9C zxn3I7SYMyVL)w7Vx-GJUH38de<1+dFcTzH2F${PXrY0}G^_uCOrUGdXigG1vN0=Z5n&X*xA7sBHov5==r5hw}Zx> zi|A|k5(RJ-Uxx)W66f# ze)Sm{$9v!g>~|a==|e-Xh(ly(;+qNC#4z}77UONLF3AoW_=X;g5^$^#jri6YR{Ue` zdU?t25Ng0XWNmd0L)2R)uYAF+BRwNa&!AV;c)z%w!0a68e5cle$VoADotTc;Z;qoh zZMYX3=uGh*b#=ALPkrKJ^8EA9K&Q*-G;Pb;cCFN7z1AYuL%er|@9r976|fGSJ}wv> z>}{709Pz$gn3RTg*ix7nlm5ac&PG^}Fa7B^j7om|v!68ni_e^uKmW^b8QTKSpF1U^ zcP8Y8Gsoo5zx}3k^$p0}JuC{(8-XzrD*M?&$Az;2bLiX*Km_}M8yG3#Boxd2q`JyF z0H(@owJ)x^TX(0>yC0BR?D-!Z$6}niW;uWUq`ZkCBcpgcLED%|+NsB|KPuS7^-(w1 z7MI)6)+A4zIqx5~IJO#luo}=e<^Rv#dw@B1TxX&OXk?&s?&;~tIgk@L!yH9YqG(B8 z%W{z9B-wgvt-a4-WxY@PeNS)K-d%fF_WFI2v-j;<@=6vZOBN|HhY946oEdUBId}JT z&Jo=}0}Z_YuZs&@02gQg-96JijhboPdn=r(I`>x9sZ%F#=qK2vS?g4Ds`|;AO;0pV zqfYUyhU7T_=V!(BfD+23yahUz3uO9`qb@Trgn#1Jv%nbUw!9UyuVH0vIL zz&Q%Z^RJBIlS;fp)sT7qkQ>#Zw9K@(4+fNyLz&{q2Vk#c9zcNvK<;nEgGnX?!5x_# zgwYKw{8xIwzMF_sT_JeU^49STFADuqb3OiwGB1b%=-T2VJ9q9h1W^{}tSI+h6?3Lz zAU0_l=RxCrdVvLwVg0vLSS;jO;gHJ-8|?w9E_Gnxgy#%Q%0Z~b@w}b_yB4aoaSiv? zDoq?>HH!0D{#o6nFaV=1#PP|4+bOj)qm0cdUN~T(&{aJw?CsyNR!*F2lhw682>%A; z)x*a?AXsF_rZwtF@N)O7Vnw}C9?T<@K$;&Ei8!YQr3AcMw;eLzY_HybzFXEKw)z^9bs-Wlz>LIV6-OKO@U~qU$_U_&)Pdxe%%p6ZDE(QrF z9^<@r_^{k}V6RLd{_s2R%eGaO^249JE(dmPk_rg&k+zE9-A6$fcEAQpN6&!l+qPag z;kgK$c6Qv5Zp3L{i^#E)XXT##yJQgl2G*`=flq;6vCfP^XcNahIHw;T56Q##ACxza zybT!(_6Px86J|b%5cD1YlICR{SvBvt!3LIr9N+6KHOj zb^Olf>V`|>mOJ;!OJK$8<>z1cNsR}Sge8jD0bda@ce0$ zV-^cVeT56w^&sR0m?RdOp*GeAc0Sd8PaHp?uyN%|L|TVurERzk_Vl5e2Up-c^o>m6 z2oU9bQAp?`=Opav*Eqm{h0~Z3Ov+p=__{}74+NEpf7Cc9XdTdgV;=<;9=%`sYnYo0 zpqE7n0^?&m7$0K!;%Rf=tZ8nVJJS-&5y25p73}#3A-nMog!1k`um_vAQF-RMmt_J5 zk%nQrr4+(}QEb|L@OC&hJR~7-bI)Fz2H`LbS&N`d<4E9%`}fHu82Z@@gFkPdzKq?r zUGCn!8E5lG`v@Asvy_F#K z>lzv$(F;z%NUKzryJc`pdog3<#(~aKT4-!)l=Usm*bz`CH45{TMb^KLo7}GXPGb4y zH)#by7(;xwlq>9100v+RM6PfQ<(AuR90l>4lpY}7h=!zWi3FbQW8kQ=o1Kd)1$ha%cOZzrF)78V-jvlN zXD?k>u=rzvP*{n(0!Il>Tw#A5lf2dG6-QtY1cYDQUK=*gv+CG^;sZV$6%4{kTm)^j zqbymoJvdL!EyVg+5D}1413R2R8y@tClzbT;wW1bjS%w5aZ*Q->0+zcSov4Bk-rxW4 z??D>BS3-_*i9iUjvT3c-`451FKHYH*7=YzN8fAk<2E(;$t+EOhTc3UHm^`?Dx3Y?O z|Gw=Y2D;_kwJy11^IFAK@HicE90rBDV6UMWuHjEZ8-SJviTDHeJ|Hjsff9TG*8^lBdXkjp;al`-)liLQ>!&#~ES!Hk% zAKwZLi%tOW2w*KJIxgT*n;X`k+|mu&e;NWJ5+eZ2@ZQkasG=!ReCFJFC3s?%uNZf; zFp!uO=iX(ZP4VoU9`g+>yn;d!ijp4YhXkOpx~fuHx+{qU;jg|@+WSYPZ$u-!3B1Ja zhVJ(W7XERWg*jY?hy|>FTrD^UrskX$DEx`(A5!)#VT=hL55`7D)q5?0ARXUPnD$q+ zSEk_y@42hHTfOfWkDibR_V0v!1_=5=vfl=Ff7bx){v*E)mS7L=*#<+*Q91U(MJ2@f z=J8W<-(7p4Sk|dg75@n6(=j0vjJ=sT}5Yt6^xTvwuWphBR(K64vnkl=oc72MCV_pus~q919kG z8jXpNw-me|T+FY>PGCeT@Lq8#L zKqDYXlkND+7-H{mYGO=|oHz?R4^y&x#|8*`u9wYgnqd8J5Hcb#2nAS92zegd8I}|0 zuSpM#1HJj~`}jUkyJe5G)R)T>ANi=f_>&)_Uc20J@Ih#n*yO=`@0LSH-$XvmxKvU* z%-&&A2JL~zSW_{pk{AY3ft9bKyhQxyR=LwEBd`*=62qbs07NR~b*#`corJ*$PidL> zG3MdmPeu@r)Bm)^zYbQWw!=Wgk++Vo#CLLY`pkio*W8=qNK0*f);jWTL@M;#^f@ci zvi6y5`*NQbuQmz^dHQd6$-s;QS~PxfR5eQp1o);gVOzkaPb~i0yR~8RkAh&J;GYew zdzg6>8w~7(C*ZXc#|Ks(oFZ_i)av()CHIJF8P8J&b>IGptlC=P?xhiT>h`zB1T zg?>tGX40pf^bqS?>LtChJ9jNVBS0UVIj?l%=_JQj-6#Q=We-CSKM1LOF8s=bJFEib zf)NcvFvAQYfQH{rpSvc0Xqt@RZ2zY}{0M9@gmC;j3$KgQ(z1RdI72RV#B})W)6xJ3 zPH#i-FuG?uzE`_E{=^e<=#AIq0t^csy#G;YsBlZ`nzg9H0)fP<8aGL+Fy~(jzTNWb zT3NGUM*Qd7!GaPTDZ{7{3`GSC;y&eE^^(p=I|z#&=pl-NMRYMq4Wl!MUl(i+qzpBu zp8nTVLd^)f3q2Hf|2ig?*)`W$BV#_3gu>Uw<%7I}`)Cn*(4=m*1Lv*W^;;Y;iyMY7 zj_FB^zjAdpPj>z6^q5>beOxxwxTKC0xC&7Tj}KvI54JzjL)iI8N7}_U(WO$$AqZBA zwcZ^KNI9Hw1h6B7G9K9bVHp^ofycLiQq!XW9!+JBB*@JQCf~|pS8b@W5>9hI@}Y+p zyT%2F-v$2&4j5@Falm*IcKmkiutPYSrD`9K2MP@lXa{f(zuMNNtU!L}+1C`PrdrsF zzydG{*@7yXd`5Wi;7%MhP2t;$KnU@iikr2&WOYl6)YaC?p%06+jqL_t)#+m$PNew;L9U zv+!9Tr8gdgYlGbT=>hrio_LN=>{dImTZ8nz7wr8isB?ApX{ut1U5goW7L&Xl$Zk&# z{N7UIl5;Hl)6K7wxY)dP8_tra;BI)$!gpzrA)YyZS!Q7SpMgg)0Sflb`?V2(HsA1= zhz6c$cJCj5@G7oR`TVCoEH@xTT3rS$lW4v23|Izp!dKwOp|R2-hu(S*>Z%U;&;th{ zI{>cn#DsXD!Z+(5kbC!R25gJGeE5WfU==c-P+M0kZ=bs^cWwfw=E_BICr~{I0RIH7 z&_WOpnrJr$Q@5k})UZ7BE;T1QtX2kYwTVPd@679WqD={oO0kCPqI&nc#I12U>0}TIxJt@+UBLKJoiHEIg>Sh1Iz0m*E)PU$5 zq8OGg2GS<}OifkeFnKU$%F6iMb7q5bJEs9dF(mQ4-3<$B4zNWdWlb^}fo?v|@44F# z^tVb70)AoW-qTWBXsk~Y#z{dc)2rJ!yp^0ib0zyWFahRRF(b>Hqbr*rmfdP*1#AYs**)(zvK*r=) zc_Uooy)mo0pKpC>0B_3(viZqUbwGG(2Ir_{Wnk?CuT~Ev^?||&JnHc}Gtz~8FxgAf zeAwpDY9EZO#fb(TIUH@A`um{rRfVi}mqq$0oofgjyJ6@7CdV2wEbH6Cd$ncrCaG^) zE!_h{%9+gGoy$)E@btNhiMMBp3Py5lrUa9ylpNZeqUSRKL#Dv@UW8OX{)M43`sgDM z$z40w%MGZgl9N?k^>L`@Ipm+d`(0^lY?hNBoRz!py-yJVCr`dB+jrh6JJ&VHFbozk z^z`-P*R&HVUH|##!ym{e?uX0)+ExqMml16GYh2J)fgdSfCDa_@9B8G5MI`{XZ(T19 ztJX=!we#Zg!LY=T#%37-!tY$|g)MNufS^->Dj$R0H{|Gh7r@$q)v&CT=}LP|OQpa1 zsLruHxn^fR)A5@zA;$(R_iPp^D=(9AxV5dTsS!JD<416QKMLKYFn0P>m5ty^z55W1 zYegwx3q;Ohr&X6bklQKv?GQt?l6z^Gv1i;~A$5Xqv@Xy5M9N*4!hduy4L8M}b|I~*cR~iTn zwUrPa49jo+#^>bE|K^);PizyHy%#Qu%i%*{jU0dHIP3_BJo3;Z^1|Vh;)UjbKd#1? zxk3+CyHlsnN=5x@X}i=RwU9!G*J<^AQ+07AhDAF9*tD)$8k*NBYKv^jj`kin1hL8R z5PXK?$Z>R3lK_Bk5xMK(k6`g{hh(uvffX13h5i(?%xd{oH7`(e%&^(oqSreQ5ZS;l znKTHNIbbV&_39QWhjcjwpsKM8qC>5Im@u0NVMktq0fdD=YK1eO!8QpGz&AUH01MRf zX7QIPl)?gv4}WyoOZI0?B~1RtGS}f)ZbL)Dovl8NF6s^;Q$q`l*Bf0(c^wf+Wi@~{ z$XRUJzEzsmZo)!Ez6ll%u(F51(Y$}pCTW7xqvaNoH~@O%O>kfmrRPq$=AJX9pd31J zMMeGSCod=tFx?5eFa{XD@;hIU&9EmhW+{`dz99+BmdL{o-K)}$zxf7C7w?wG9ylN# zn?*b&*(Zk^H#+38M;?TCLTpBnl^cHTZDK6c)QYdnt!yGF;49>3QO5V`=6Vf%K=RN) zx3t6P!z!G+gq0x>?L)EPg{`i$$#|$lTCZJ|#%idDSey{h&?xH_g8$pMoBDj9&7s&? z;YPpDsnY92i!N*O(*3BD(vTNsdC8YQp zKl`MzFY&{dkH~264QU^kkPm}fFflnP@4Wpc%vD%r2e>e&KR7Q=e6&GYvC0s5pfx(w zCtJ4E!du~hcp&|6g)aljLexO8vwx&BL&@7SdeJxl%`o;roy)e<7qo8z_yZ?XXw@02 z!*DSP3xP4oS(^RzmRHF8uuR3>PcbZI3?wFo`~?9s4@_f^6S)#~8Pjj4`zF{$uc)b) zpuJ2c!N%m|6^6-d`oFM-U^07Z9Fw0F=lz(vu;UMn!A|>F4~PJ}SYcz|f&*2u@v{X| z`E;~1G8S9lf!49f38kV{T~i@G*hJUEx*D(oVnN5g6U6$`4-4ByE6+Xm zt5>A8tyP8w`(Z#R0AEs8`Siygm%aP$f=l5$aeUkd<8oHnvuCeX!&tZM+_?!FXD#9) z<*Gt*A2)%M@cmcb7FT&4tAH26GFT|IiVqeu8Kz+hTiLBrPb=eR!3lr{u*24F*aQor z1LDS+B|{Z<|J-=!E*%0GLk$gHxcLmq#%-|o45}*{)9ajx9RsWk^e=&4CXbN?YLLk! zppQw@8WyDyrZp|4$P!>uMbE2e1ytfi^4MWHz!3=0it|?0=$SiHF31%Bi7wW>1GX zZvg2amq?5qy!Ge|obbT$Nf^>dT!*Io6Ceme(3qKo8(nzGwt;1k@cE| zG<$!B#ndeSqQ#}uo7S!zE4E-)=_@P8#$=bWM?VV!h<@pN1}EUbvYQDqd?YF!em<^F0 zGOw)p))(uHp-(){qKf4PsF>BjZMh2Iv{-Q@=_#$0&CS(71l2F;x=iH4#Y^(9f8`g{ z{c`%D{(n0b(X@~+3ey0jMC1i8bLL}bq1}QH@W(H{hU0(%SnivE{K929b@n2JWVMC= z>8GBA_rh|>Yg9>NL!D|!WV}zdZf=onTh@TP#TSiZoB(-TiNLi!Fv*n(@-NUN@W4P# z2(}Sc)g**r6S;5CJ9EBafqi`llvOX>eZGD2Y#c(*z${M6FoDEkhKFV#+_742w6)9r zyY5!8R!A;CfAqb0nc~f@#sCMTVRlSw4%4(j%ZW4NZc886iR>}3bHUdu%#u$fWl7gT zEa9sKEXpx(y&~|gr{j~jTB!mt($zN%H^0empPUAcU;2#C{fyMmuxyntL>j9qFi_BsLT8or zjZ%h948JHFh_Nzk565vtSq8yOBAjM_{Zj!s_1-Bw&cfT>R%vN&DzMgDS4?C7vzK#+ z+;R~PbK)hai=mX^Hnq06{7{xWdYNNq+SF}0{F=Ic45s4UAc~KjI3;)O0jCCpa#Ldi zILPD5G;`;Tb`S%b zzBHy`BUo|W^ggK?Z{Ht%U7lAD=??TGPkcz7Pr5NtF>I{`+YF1pMqg>*xyN6(sTrt+ zjd7gAT!kRVI3~ciLFM%+V-8xr;_vN%f!N3{aB|LJURd@>qHEp=*!@;o@8cirUyw~% zTURGT<8+)A#xVdS&(Tx20~`Vh31Y_{%&@kWIA9k5h#LZTAYZii#*Pw7-5?{#jpGZ5 z0b%_amXG02?hmyl8s2Ymo0-5r zvydsCc@5=aC^mzTe_W!@Q&)Rc@gF?6|WW$;m z%Z&w!;pSr?F~)MNJI?}o_N-${&t%qwY-wismq(no+lS#EOlDvMU`4Vkk7Z*}m!Zm@ z4{XU9*zd3O!s{N!i(oy<6u59tgOQLd31G;b758X~I+t_G>NV@2T9|ye5XNK(mFa}v zcmr7dHjM~if~qrX#d`5PuY@_jZ^G>>mD;u2RlTHlYT<(14%f$n(3F^lU?gQOToRDB z8?AEg{6*kLo6p#(a;R*6`e#3uXPa+*c3N09)&I|>X}O|1*L?9h^ZPzX1f03vFW>&& zj}(NOic)#@mBaG<8*jHSr%aA$$6PxhAUJ~Y<;8euY;IOC zC?Zo=T?uZ$436Q*jaxZk-UI+G{e1XCkI680EU&%xdJ^U+GfUYDn9EjweeeOiu6dPG z?Py-JUIH*N=D{TQ_K7n|<%$n06a)E89{J51OA?_xJh4Ntk3vXfF=PLZvwjc+QK31h8OSzI0h8Df!QBBL8CHi=SVfyZ>i#j&2(A8F!`tVvz|H8Q#xA0Z*>@a@UCb zuWx@}{{EZ)BrOe^Q=u0?1l)7aJ#yf{UDDXJN)@Q8s*;Y*P8@NSNeC{F17m}7;)8Q4 zjjFcv3g~cH@rdhpeHO6lgE*M>M^2}u!8XjiRVpwzx3Ti#-h~spn7*IO5Jd&t>Y3`vZqzhzKX>9N>Kh02nXUE9JkIa zGe*V*INqH2O>PZJ$`vb{0Yt{SV=$~Fu&`NS@YSuBav1oj#O{$E;usv@xKvcvLnv%m zu3b7Kef@nBgi3M%I_Qaj%JKi-eEzeEsAY7gvH#~9FB*d9%9ZH0NluffME=yfyfP;h zZtdeLBl7jX`Crlu_48&(`2XmYqbiO@wHQ{xqUOCI3Lbpm0hkQdj;F_92xzdsN152h ziJJ-#?~qx1{|>hor#=B`RDysRJ~pk$ZSk9BIA`yl(`lD`58e&7NksV|Km5jPYVq$J zh{UCnTk1=tvY`bOShw0t41n5-Lg1!vbV4dheQ+~6Dve;h6~l7GK%Rpm&+N$Vq4VVK+yaH87d&;ouXJW=Wk!Cd@ue7=e z^HDSAoEqqeYdCXb9^7UenT|@=sz-;=)e`&$czSDh~31Fg}E_xdMVl z66M)ZQqmzv8N0xK3`E@W(u*(22F)IcG-A%UiVgjymP(nm!MrIXEt=PDkj}PivKjV( zdwTk$Wy?+&CW*jMkV9U3^F*Gt7qc%l43K%9Z4!>RR}EZ!^v*p4G3VU5;?S4fO$3Mf z4tUC>Fd9SD?Ne%gQ3wXkLgkDLrbYQY2NrNH&trmeNUBd^Qk#w1U@IV|)25zOj%;3GJSVk_Z8Qkf_>g{DXVYB844D4;FdsL)s0dzi)|mwEn8-1;5BhtCU7=9 z2!k_bmC{(uEVeO!@Na*^q`gZ&DkJ+p=ceoL#H@fJjql6wXqG$oxZDBtjLpb@{|k)> z`2FAd4aM#G;KDVjg8U4_$reE)qosJkLAw+k8s(6oV_8XChKhFd@i5QbqA z+k%ZMWkY(P6FUvLfC_M~M{&%}BkQTS;~@odS^pG70Iy}K979^?#a)=Ox-S7t{CG#7z$ zumZ9Y0jyeeFMB&Ow~)o-A5z9_w2nx#uhzf_*t#&L1Y}njaMOo>OPMh1jOcog8J zndlNbj`2W9GECyTa`Gqv+@$Hb>~yOVx9+DP0${_MW^q)nQoDFIox6Wh+^tyr36PXG zohz(b)hurvds`8NF#QiNWHZt`I06^J!*b?okJN(|H&Q(RzjbeaUNxH!?u;OF&CYyD zlZXy6V}hPx*h6iEAPve|SU?(>< z(1!DVn2<#oW8m(P92)FtU@jT<0N_RO|N8A;H)dHj_eb775i|ZX*Y}{M&y_1{$61&k z#=L-Jts!e7i2#QG@@IdkuD|=mU&nDko3!=}$;Nf-Row8kU6=wQyL$U&7(z^| z)@_g*?Hy8%ntaqTMxgZnwoPm0$1fjJ&&8jciGh4RsX6k_k-TWV((9dT1zNNQEDT^f zc#M8bAPixTQzoH;mdaYEPZ~O-vBGkuvKfFa3p@wN>B~1jXh-GlJGRJsAOgIlWw4TF zBmxR;BP--2HI21DAf=d$CP4^TFd0QEH^65B*yg?0HHtq+{OgPMdhjXzOL$s*Rn_8!v$2kA7o`R!WEp(*IFjt>l#c6HVL?ti&nKZpE{xmlR@wkj3w$U9 zU{8VSnLx-_e)o5l<=H>`8`u5kgFbe6KkuLe#23Km=3)*c5~ho7a}hU~eC6Q>+ES074ac!|;>S+taI#A;u>BP+6>kQz}gW zavIt{Y-0%~3cU@iKi8n~wsOrK%U1%SpzlBPec4{G8Chg>J7kA8!^qDlC6zk56|kkFui^1f*ibas~o&z zDA83Ui#%2c zgh`l|rRP64y#CSS+!TbG!%)Md3ub-s-wn64zxivQR{59P4_*Hz5dZ~sAlvvtnm(TO z*OV=LLG>F79iex(s)9$|&Sd7&_bA zU~|JN13jJKDrl;`bjVfP&?r`L4eFclP2*bKuv#iAYo!s#f$KMIg3~Ik4GKseKLrs0 zG_art5Z%&-#ee-;90@>oX&Q~bbiGq{Y-~})fFnj>uW71~AiSDYcu7am@Ip*#PzO}J zE<+6HBc3#04kI(3J%_w$*oYTSOIfZFUKr6TwMU=^3w9qmk-$n+%D@p&3qImEu3HOZ zKrX4T#BNoWq{qOc?H>LeIdM)E-m_y97Hylnv1~arR1%iRQEyDwXKR z);sp&47g3EC&n=GhrxCQ8y6fH8U%8?z*WIw5P~Xml>QiCnp_1EXgGHHuV4LxT$-{Z z^L$gc{Abp>#0M8kHF=+Dc`^XXDW6%{OmPbbaL^x-|M0bM$RGXbU&<$*dK~L|R1rnH zcI}pjAAUr6!Gs*3+NEFV4hR(h8mb@!h=n(TO=@FPEi?z>;negDOn+-> zBZGr70O9!|sH6_`_NaWLAPi_BbbPQ!*$fGjQvqWJj4LF>x{zPd%a<-;_wSGy2+*{m zt?Zo7=alaLaT$c)U+x?F`iErS!Oe2v>{*3?D6E_@j6*=8vwu|1T)e8Di$6;U1ALJt zbHMys7z3)q<)aFEg#K)PU6dx7S9MEb!#GDICb*DuAh}!)u>Q0KXdLW48@3c9S6gK# z*w@22B517k$q3Zc$gYN|dQ3Xd7{K5^bR0wgb~$%$-vBVgngwoD`&FM}pw)dMA}uzN zuHTW^U_Cej@PZW?48kRGS)Ev>`eE41DNgK`gFGZx_34Ff&XtQkLlnC-Uqvk@bsSM( z(HDEOcwooB6fE7YD`#cb-h=9>q<;u5mZ8Zo+}RH%N>u54+p+TxVAH|{pKh1+KnFnN zcFx)f?U5@?i5?XOj#4+5!ruy9%wtvuYjNT;Y)St_>&xU<{{UF8r}3 ze>db|aOL^FUNbEZusj!iMKHwBY2|&>uDT-5>-Q;#@)84-Y^97a;%+ zf(n=id@g$YgtQ6>*Fr);9Dr(%Rg>OF2ieiRyVhgz2TK6{Kmor4i#|00A{d^Tm?bODS0*(O%sF=QOd)M8mRWKb&_De=8x|WF=A{aRX%1{j$BvIoU;#>>cB5E$ z#{F2`F*{L8o#BIX7sUpPf5Rx#R8y|vs!Kgs_^hxY;85&pvaC;?zYfAYELAwWuc@tz zaRXHLJbv^SgdGsZ^W@YNxV&MoHz5=U*ToS}jfA{#o&#em9uO?)J;a55{$@kCGCCD<IhnD_o=iN*bV0jJQ1#3vo zJsI+cW!OI}{}J4P{|rKaT(u$Wws#(Yksv_X*~rx_5q{?Jy-INX!*{KRtj$`vdrPfs zTIH5~+v=shxy!91UunZ;aX?(jKrx3+euo^|#NNNt5z2?fBly7XcUz#D zKRJlG1Un$?+FjVuceh;zF%*Gn7Mv{ks-^w{!H%ZsP zIBWw1rDrrK?Ke7Ap5o7PzyK$JEED@2$=Q22kHUJi;o25skUL%G?tl*eY7pDJkKlN~ zkA*KO5O-<<*I*~586H?R0=KClNFztEkBRt)rNmPqQ`S&#Dt<*wA41yED@YnzFLwVrfcBth!KvXu!6vp6BJ$R=) zd-#<2k$(Qlpg8S=@(aKCahVt$lxx)Rf}LjK@_L%9q$Z5||hU_X@d->{h#YtPUx>?z+Z>lMiz9D)# zb3zqY+j4Yt_DDlR6Ik1vM6h)LeE-N0uDIcV%^HmF7U$*DQ&6j`S271-o}0sw5jBEf zFaYD;hDFwJAR1p#a_mr+c2LF135P^s93#5Xk068*BhE5$LVKbdM-b7eaT!IQJTU!Q z-MmHmJKGerS?u=xen?}fezF}}e;r`)m(c$^c40oKg!!R=H)XN%Qt@lQUGm!=e_ev-eY(oDEs!_ zA&qcU_pctcLB%g3&mDSC9)`V*%NNeUN?^T|*~9YaV~>CcwaA$ZSEPGrRNOEn?e^KR zh@%|=66i2Dj5vE$xdiZS*1+KugC80Pv1X7k+3FfYw*?0v;HvnxQa50ihrQ07R1P+`UCkp1qVb zEpzu#0;;?phD{nlA(2vdpj}=V;aIn-R%r;7m4Y&YsnKG%{V>1*K9|bY{CcfT;PZpA zbV`Hs3<>oaNET-pylP(Kk9ogo2Y{iyqYIM^%xw4hWo^qU>{x8l+68qZENslt7n2}% zmExchrf@w_ADY5$CQbxoR4Mer`9MUg&8@JTg7nrwovlc{Nx)9oLlHQN!A;aGC_OtuS0f z9}7WDyt6SiD!u(as7g`ws}!;mY!>yYuYns$LLmU|f(6-}tXzowIFAIYaX9 zKi8J#^KO_||1M(i^{8B{TSEE9K`U3dt#a*pyU=@JbycNo-@QlPedld?;+|dd(lJeD z?Njv)IA*d*$GOw8VcQ+DYsVIudG7;go>=4xjsnWd-7*ICcN=!^1Jelxe-L{8BtkjN zbu1HmKBxo?4Ufe}7YPKcmr%JK9?^~sh@zl{X1_6psaAk61-Lu`&}9jEKM84I3%Kir zgn|fwn!2jE3EvpUU)9aQWdjvdS6d~QE?+ zfnPmCo|8qM*|j>B!7mN^&<$vbX z!fu9UQB^R$Yb^%9dSpBz;|<;Rl9;4Wp4|a1!{h)gvQ=a9gLO0z1xiH`s!+bl8YN#e z4!;PqXj^!4NLg4ja)g{dpW5kHQ%Va>m;}ed1tO^%ZeOEV{Jq$5h43Dn@Wt@8|M2By zeeO?$Chz_^dQw7K6yHlqqDXW&2rg|8ax*=QEHOZycZq+dk zX=4a;1&@Wq9lk>f`XcCYBoM-J!hy&H(V!=)oZ62Oyz$D0u50qU)$Dvn>eMlWN6n~`Q1F>pa3>GZj`kZ&1(B{`#YC1ot|ed?2kDXO%O-!$nq zid2h#>UiLQH=@*dpRwhQbYPb+)QxyS_XpRPl&&H6YPgK35 z%mG8ysts`111CL@(YC|RIvx4AYgXaBvk#mAa4-P35~%{fhr1}0B8u% zr#t19s$e#mvuqG@NOjp8mk5#hERAAC%+#_PPK4H?nK{76o^?{+RCmv*26% z*fe}+&1Q-alwcvPxM>d4$owlx9uuZO7bbEHYB|rp{090ImEa@zw$Ro`9{Z5IdFVBH z`u?5r|NY=KRncdE>OmQU#oOANYV6vbinBB}F$GiiDRMSho0Sc5+0wEC%`1_|ka>q5 zOeV7is)hiRH7-y~GqKt0%B9P&X>0+NQ~`FRroTuvn_^fh7${^EE!h$<~?r=v&$AvoZP4JiAR70E2ZMigVxp{9ReZPK}662N_cu4M*+A;TrD^c@#Zoj)+QClZe-{R&5P^7gCmCO zmdz5vVohm&c<+%}2tAco)yl{XsPjR9%8I$fT?LPRo=WlGI4v`y+Tve}4xhkk2bUQfLl*Ac%aKl9q_hg5Z^&RmrH9(q*ndEjB$ z57j@0Z$5ii)_@bfYs*?$w|CH_+o0btfA{XDW7rc1|hK3Ix5 zWIATWVCUx5^2(8uib^soTZ~&m7%&}wrjdz8&yk$SXm*#OaE9n42zs7u^GQ;HrS_nA zAf;WY{YiaJ$)52M6GDl5gpZ50=!izDG6cEVsYLbo4!yAp*NT^HDz zT#RW9CsUZk;>q2=4Ke__gOdQf?O8o=txI-2+si+8&)7vhKEu^&gJs0}7V$vJIWRT= zRYPzkVn+@^Ec&B8ZA#eC4x>aRWeqYt+zXcfuyX5a1@Tf|RV{9)O|`6QfU9w*w03lZ zmD{Cu_}5!+z@X6-tpB+naAi>rS!fW5;jjPn59QN8`!RLDoPW~v{*#a&>zVO=s3`qK zrS?26qag#zs3Rjo)GfQs*3QBkHG;Ez{=NMA5qSlFmoB#|V4wW?&&vMw6|xm(@c;H7 zpHp$QWp3GlV}ZSQ?0_szwX9pyQh3ETxnw~E04I&qpa}p*rLwM3s$hVFp|P$)8tdz% zt#=G|i#1t*)N;k=6@&rfSXG};`gc??HjJlAAhT$T%CjfV=VVo_`KvzFf;#NBP z+{Ke1h~oTz7AjN9HUgvsT^0y6!kzN^)lJGAD(4$kPzv2{945fiV!z^a@C?@tk8A-* zPfsatfM^t8{`J@X<886{)8_xb`@jDSF`OKX-$HT zi^}|)SLV!MZbHgP?417D7haJ|SK8#_mFx1!U-%_e^J-Z7`R2F2Bj5h^KS@b=O2s|( z_(LEtqq1xBx|`6t`Bza80bo`wj{s~CtYPSBy9hx*my&u61U2D`E7w}hiWTE-3k>M9 z0Ox@m26sGr4tbOClW+c{!b|jleTpL_(Z-}GJS06QvSqw8K^2Jr!l4Up2NuH;EP!-D zsaAnLNkH8c29YY1aL;r@-#6%3vYaM+=GLEb+%7f zj@or%bytFLaVe)P^e$QrgGe;;<8as@ywo(XkZr(mhFKuK7djB8{*A@q>k(Nh%OOiz=|ak+0VzC!L;(Mu zeg0(ybun5NN8eoiM|x@& z!?SX{gN1(#f^Q5FEcVnZw%{z^3L>74Qli++^GI*j52HA~S}f?W`|p9zG{CVy_g|a% zEpSNE4G08|^0-8Kq=1FrAGJvx1P^s@dT~kdSUVKA5DPkqMGJ%psU}Qqgb;T97PuQO zfey75Tm|c7uiCvwoe)$6C!oxU=_&~IzNul<7)8DkS-ol%IE^*Rf}ao4{EYAD>QQa1 z@WF*L)GVnwr3E%Jss#RCc;&*E}aCGw*u|DdT_y?m$Bo^#=3}1*zKGQfB zVqTQt%hrQgaXl?|<$F#9L)k=RJZDlOO%~6>00_w=eRmU-%-7^}s-t z$00{vd0yT*{3-}zaKykRJGg(ZY;0*ze@mzvNljTW0)VD~tHJ)KNlpfj+a)`8?v}Hc z+m(Tiq*{v)O9TVPfjOTh@i;TwXDd4%l zQvhxXCVrhU+oDnI>M4a!Zk|M-q6BN6v(Tq!pl*NzlKysY1vq^gtDoxtWd<~jfUsKd zgCH90AOb=qklY7H(CN_fDj@jbuAdwSvi&O>Rzn`4L?$7XA3@(rriXF0!k#~lC_+;( zZUPPhjwE1XMH(w$FlDq`_HSDQ_!VVge>jA?4H|NNup<^0t)xq!c4{k6}_&wu)}aQSLjq zADTC1vbv#Kc5L4!{^_99!6?vD3^5+v{F+8*9Q3Kp5P$_THwLw@tV%{>EGcEa^ya^- z`E{yTIt2rKf%=F~N#f%i$tES{5p`25n@2lyEvom2_~m^p=;+p?)Xq!Kt4HdYQ?Dqj zPt;5ztW@w=6uCQ_gta^$bmf^o4aH+c05C5i9M&+{=D5Y8P2oS~cn1Q5w80;NCQxX6 z0J&6V7JxiK2*P%Lu|q(xvZhXYyE;|8F6B=Pe7@>>RYzckfME*(XZ_Z4sw~2g7#4mS zL{S2I*h%@EurmM?rg5sN76GNQa%Q~XvV8anWU(s3gS@GcmL-3 z;ssJ~^30xEd@-JfVno2R&%LO?cK)vV?`E7{1Xs-0V*Lp zt}Z2|a0`sM0Q?S6Sdg~#NpR3wAX)!WoZSa-o?i;fpZp_HQCbD*dH0Q5;kurml>{QPI+trxz#?2Y_rz0rPefDN5&^v9Tr`;>Q`lByolzq<68 zL^-7C$vSNPIgzQry9EPOVEwrl)4M)6P7~NAa^&cnauJ+>^Ovv6m%j1`FoqYA|Ms=7 z$!=%{+`V_Z+;d?eVYw><{JXCmxCQ^!B;@26X<@1^@6pq<#{q&t@M$u4vJ}odk+= zE2-L$){xxFn&w(aSf&+Zjnuo}5BJYepW4<|PD2v4P#cMYdv75D$n~=C58~_^DUQqw(sCoeAk zH{mrdg(~zRvDj_7wF7@~dzVY!bUf#hS8pxKu$Zxk4o1&{D<>vyoJj;w7|`v6x*Znk zX)M5G-7^FN0Y&V)v30P+6-j-WLoMQA|0swByD}nVbCWPA0ZZQ{qY<}MLO*{NJ0KDc zJGce2eM%Iq;3=!g{>+^Ilu~#pyV6QlJmdwa zX*fFxZh=kd@<(8VXn@=RI4hyw0EP%S1U~5LPmGO;KWI_Hf{d@NsgmAF=>NmH%9#t7 z7$ps`tVWHZYwexNcYzf|1|X;%m48~Z*p}#sDx!A%U-{kNl;8Z^r?rUN>^C#(Kj}qk zy*7zT{@!v$jscMNiR1}JFJxAq0k&E45|1+y0WD26^2Xt#;AElEpr(KS_x?}0digTA zSQGH*R{`}{kL9mQJTBLK@d8C0}I*5heDsAm; zQdLoxL-q{Ncfz8S;MF6U*`S}pYvte1X&zk_CJ#n7R*)YOJF4_F-y0R zPbUJHi^Ukyit7oK3z)!;-K!S&37Fq4fzTd3p>Zc}x4@SGSo&TYjO{3QW)W#>Y{1c9 zk7DgdAVXlWd&C2le{dooql3LlAdrH>bjLdm_C1LO$^`Hr(Se1(9EO}KK z5}N#O7t58fezgF~`) z!&(r$UgemI1oF{iC&3*kmBCTU6WrV|Zy5kP{1<;-V1N_I9FvGP(=3}F<=xQa?k7LxG|R>jsL!yeFfug>`Sh%MQD)WSl8P~s zs)AGagL!(FOO8DPSy8U|pjMwL2gy!pi_f2C|@_p8YSx+>+@Z{oIpLC*8M}1yk^g?De zWB`;Q+6=-{iz5-hzbn_fl=H3Q@4l;=c=GIJp=KNnS3P!cr;6LTb(8GBbBAnLx8{~~ zV_qBp>IBb%eG!RxWn)vhboTa1AX*~b9qkbOsf1MS$SvtqvC_rD07qrE!Ms@Yu4K5x zw_!F+c~tL1pPUt%(lTT~9`c#(=#q*<1rR$FJ#f6!sEHf9c?QiAph!*gdMxxaGL5;Q z)Cqe5&=9~$0POgKX%Dr)X_TRWp~D3OK_CKX^oM~&0C)4dH?ESmp)qs}ehRREf^cD2 z#$%QW)o!1h4#T3)vMpHndCq@3IPqbB<_fg-N2!1FVE8`FGbF{Pryp$R}a7OOn} z$|2deYpa}u=fRs9=0yO|w)k2MM1lEEH!T10HJ3QBJAmZx&`|5m>_@S#rGNo`09-(B zO1P<&En1I~)?0-<<7AnkkI98FryxQR0Xp(iGh}LhET1tu?kTKCAwCsi3$GQD`cVE; zTs>OXBb$GCWE2w3(Blt`$rKy`RpWerWOxYL10}MysX;E^=vKyi+^_~{gM9%%O!AVT zaNxMGrKMRa-FA8F#Cviiw%FTY0yqF$0OJsl(u1-`pg-VBR{y{G+-FwI!q2YL(T};x zp8+wcpNjD_QrV0z*-&oITLT~+gdxhTcoO?R?VC0$kx$$lmFENMCgdd%!0^F^R=IQg z203*2Ek)BtpziwUJ$n@aaL1Ol7#B33A5liME?n!l2`$sAm=^(1g#kYW6(I&ESbhV2 z@DS#!mQ%2RR^@!F8=1{{w&0Im!+^uQZF=qmy}zTH3OiR!BzhxdDZWe zfMk0xgRSS!kd`4@FSQ)6Bm_=@2w>oFd*J?q^6Iho<%#?D;n^Zv*EP%GDGd3H zVE0NXe^3_^u{t5-XICasyL$VjXAt%Ua7-{d0?&iA@6V6I@Ck6Y&xQZ9pZdgYWx>z* z%I3PK(BHE!ygFC5B)laP1Sa3k+|XhKTD0cKGgorb#57mtrJ0_Lx#XveEjG($N(5lB zhpmn%t@o*gU)$x|aX$m0T^jtQ;<6pA`Y2fWHpG+dJOv@Wav0^IgRgt`-+?LL0<*jx z@xwCk7^L^F!T1S7_mE$zJXX1M4UWI;Br2>@3rYS>Ygfy;EA24q$NHTTfS-XnSO)zc z-+x6)%d5o_oDk(q6+{SS1GvIasPCsf{HR*^cWvLI;IGu5e|+X&vJ3rj5l&rXQ=bjU zOG{D_X|d`(#Ea?Qn0__O9?#6?7&GXF3>oHiYlJ;7K)0+gi2#PUK74FX%mQ(m$S4(!MSu)_~iUJ?XJ;B`CYk^2tF zz8xD;wMCAeI4iA#6B6ke6BieGR*lJQ7XUpSQDgb zF!DCxh`<641NJ`RNBtoX1r8h?-UIJxPd;+L(&49YUonVq@y{&uM+_Op0KWm#pbs)b zUekOTB6VVt$w{Dcg_mnSL;VF5F_d05w`B95Jbgu>)dg-kg9}cC9=vOhtZuB64?lD_ z#;XmMHz(xO*(*{?!&!dat@XlnvoHbx=NU608vAg9^0&a4K^Q*0>jnPAWHLA_mo8jc zxE2;6-5Lz&1HQo8xf96U8eoByEc0Ry-g5vRGslz8cazuief#a`M7z_IO zk3WSu;=9U3_Ss9gfNaE7kOGdt(w7fjxn{rtD1$z4*F*?rLj7uTSTS$0 z*wJ}nV9uFhp757$@fW`LKjV$#q(2IFABDY06dZZ$xJo;H?gFg7X-;$!v#~xSGYjxX z6yj`AndHVoZ-K6U1d|Il>N6oI)?wlGK+k?~bR2WJ6_WcivSaHOx!%?;8#ixJ{yMg- zUoG#Rz9a`WZjh5WqpU9X%7zA*_Xg}yjA>TkhCts1u=(M_N4k17!#t}RYor%D{vjOy zRpA^{3s&X-yazEQc`f-M{f0)j-bq8>`wpU)DtPBFi9l2IG`}C*MD-T5E$$%*P&oP%gk0 z#u!%)bw-*Ks6VvTErVDyq`gu1U*r@Qk$zW*zy}d(|3O;g-hDC@xiyV3PJ>^t~ zyRS3nFUSZMd8ZBRehTS=W$1LmW+4~}WS#7V z*S!aEWZ;HTpu4cEU)=;B0WkPe47p<<=fz(KX{~Yj> zYg_S86WH08LumH+d*_sZAQ4ht>V~>)Bh&{sVX^&)j86I?6EGpCFSRZhz6v4$f=~yl zUbj}P(*v;gt({9)W`i<0H4Rn3!3Aqv5zx)T00*maHYv2;n>pwgqP>Oo^X8Z1*|>f_ z9w!p!Xhs(n@Qxn1=*Ag7-Rzd&C?JG|oV$#RS0Jd1^M7UN2S<8T(?d38o7@YQ{!AFo zN)YFRx4w02R>y^UnV)KZ%{ZqlhK0jGZi|1czSQBGHtZ4^(vos%@~znY=hCj*JkJ=` zPljXfd;ns4uYB+MH{`QF{Sg&+=Z?+t#yjuJ(@#FE>DKi!iCJ(>#_QMuHF%&US#K0}bz$$R#_-7Ul?%iz`U5vX07|4C`$8tXB zimosI88WKq3~4&>Ja_*|D9Z|8&uLP>NtB*DhfXK5-UfFh1P&c0mk$g(XyE+Pzxs%B z!~M{KJ5?N|tERy*_~tXu$-v0CiYxR-6WuMK^blAP^%WjCHyD(43$M#}e)O{Z;}2d?vUOAmd>F@s8NEzflM@k% zyIipm1I|nAR+Y>fP~HXRXy8J_o1?lVluROEA{3DyJ^PZ9^LYkWEkxz%4?QSPJ@$b7 z>d!qruND_{1mJesRi#l-Bi%iNQd-}PZ)WAbsCm7CV&QpXfM?e+liTx#RRmDPz|FwG z+n)fL?Fy}g80?Q;SrC}@jaRLUk zUViPU!hsXUy67_d=_ejmel|W1nScNYg_H29aq9gK^2Sp^TPEr+Ql~cr>EKoC)~ZUw zks0_v?#{ab#R5ePWXHhVvjZ1@AEeNWR6ur27E_l72J&0{V{PUz;QGp7IwTT{Z(6d7 zNQ>2A#R0~EGh5br48_uJv(=H7xfqcL26{#&g?}%;{uZ2R+2o}+jw&A;^t18Fryq+8 z>E;1aWi5yUP!6j^7MK-f2u)AP_!Ni%uqr0v`pPP)_;Xugz&JxJfeym#Y$=S{OhR`) z)pOhuXkD=hMGPci;0wR|@8w(H{b5pE_6Ll&IoH+1n4B|fT4j0(Tn)EzPCz^|tsqkL z0!Ukw-M;~Tdi5(Z=5l+tJp0m7@xWk^3*3MQ?>!*o3haie;2AjK%QqB60I-r-m;s)K zCoeDcf`>K9f4cdk&TuglF>o_5V1d;;4|HcEy6g$h0*axCfhC9m`d0YVul<%BIi?wS z%B_j`p7l>Udg$pW>T)g;{GX~DW)8>8qcgjmg z-jy=1SG_A6RD25w1(gc;$H8(yQKwtg=|dx0Tic3@e<5$6Sf(Hhczk8BX%|(JvD4Fj z*uE_(o&Xet$zq|!#sG!=vb*$6Z9#1HgS@bxSoezmcHz`S_>-kMnVmS;jQjPwo9GS}|FaFG&Id7~o^Gkun%z>@U*a`UP zV0h!`32CgXJJ!l$%75rGTMn%n^ua~3hMh!~*XhM)V~Zzp+qoVz;Ao%-~daq%YQC{;tBADNcyiK>V*MkA*^NX%mIZjhcK=BY zDLyO&2BxMpKLYu}Du@HXU6Pn-HeObB{h612pQ zJ1sdaBB@~PA(koi+@H}2&}Ib-jLXod4AB`nU0~hCV!2?TAOgS+OGHuF0T>TPWHvM- zH#&QAsjHZ$h=IH@U~zh+rramPg9B>UukTna4zGCYH%RqtuXJ?uD!4^E0C}UgSYQD# z@Z5{9sl`8cK|fZiFUGM3%(?g{%4A$Wb(k@b$rqN2t@5eo{y8lE$-Dm?3S@0da?6TO zw+;gZ5dc#G_y(`7msj8ZKzxw=udS|Uu!}kK#y~*?fK91j z1?0fKeRA#EWw`|3;>A$Jz(Qi6#O_dfjTepI7|IrUyO6L7Z9}nKE*L0C2+(dTk=i<(`(HRO!$YIugIU62C}LnC zFkrFTrLLh~s;kPyhOcvc3?_ad^k;Q?)t?2nukYE`AQAtV*qts3M`JbsqO&+6Scn!B zVH7ct83RY&J|Wxhc~bre1VDa^KNm&(>1$)^x2ng-t7e3rDJ@aUrJ^&WsT_v1RG~j6 z>EPpy(!d&jlgJLjm`^Y?CmBq}gyd|+rv=AAK^y??#4fe>h{NrbRnY(M>@LaxEclyQ zDF6)DcSixq?bLzt$g!5xUqKnk|# z5^$w_H8;JVWcPmwdj0tc`RUD!EpYleXIw}1I6bSn>VrZ{%$Oz1!kr8b70&zIpAb!3 zl2lc0c~XiLA8#233gQ6J?|NmKPiXU@< zf9#u4lOW4LdIlsbEBNUd{x}F>!raJ5Sy!9C<=J!?UNFL z=83}&3xF{vKpsblIKdsDc1kf6F|ZIA;KKj)zx{^-&-vMc*uti-Z^nh+keu9BW@bjM zkX|$?kBT%+F=S(U0*>C4I1v&r9=|b^HMv!+{~Yt06pz<$mR5|rr5Gq^#w@QWlNlVi zMgsnr1;AU{hhpXP#z5-qR472hq*Dk8u<-4$>ep0NCfD1s+XtaJ-E&!F<9fM#_B|oz zi9}}!t_&@WwK9v@g#>BQ3uPe)FP2Hg!2B0}LX0hzyrd4Ttm|lE{Fr7_k)|nzZZJIo z$B>}i#*4>qOtKi#)UDw;Ew>(#OCCM1el4VoUbc8$2n-ZN0Qe`T6#KucThqT@h=vql ztP~6wW<<(&gO0WjtdiY*$H)vKE1 zYHMq8_qCXB=(dNgQ325iZTgG&D(Yl(d`v2F=HJ^3K~u2xXB4X+yM9mrK95^gH`K`R z$dH6)QP$y>(Xj~$j}1yFT$BO0?LU_V?jVKxzVUb8ly83bhj~i%r#2+Epy}(HzNYKh z^mzSQT^Xr;|9W)BY}ppsR9Hr^$>5RGv%%~;=LQxsTIjyxMAWm=& z!ZSgc4QpwO)5apy+X(|l-aanh!lKW=`7et2HuZHir-h%GWP!x$tQTiWQcwvQQ)5{T zunf0x@bPN0!%5!##|tGjC;cG{%q&UiaEdXv0s{pR03E$ULhpm4qlI}Ox)mKQ)|n>; zQYW&!i_ZbTBsnxSAtk;_?D8SdCo@t5TL7c*qs}A$*>G5$|64!=Oa*47vZ6u)p@_^t zAP|XA11uT>%JUVixa?%}Kl{RK(Bc1vw0Hdf?7at^B*|4L{Hm+E+I!#AKCR9p*TU;6QM2-0`~uKE69X?vuFVkl+wnAt4En1S@H^lGbU> z?9Ps#p7!2Wmp9$t|3zk`tIVvdHq+JJ5x?om$mb&RWlp>>FJ6q}`Po8k)JlP0ig13@ z5^mEp1DTNjGy+#L<`D=_EK?vc-jrozEudg>gfQ(Vu+yJU-F#4%l2mq^HL$J@z|jN! zw6ZXb06+~CPiSWnZ}W4g;wwS}>-b;KTa-krr9D6f+xu2m>nIlv)6mp1b$7MXU4_**$GdCp4XFRu>KZnw74zuqx%quU&qrM{aZP)S** z2G-R97{$6-Q*B5Y|8**T&$DsEWJ|KuLfeJC|Jh`Y8rr(37D4`^nBK<%0ha#}ehSL~ z91=K-BZ1SYG(rW}(>#0us-kcTJSjE+yzCqMl;`qXFs0i*pfhh8@Nt?2x2 zV%%WHDBZNku4G(G17Tzwb+-}OagxP$l{a=$>z&Q`Z~5rIbbYLKQ~9mcz`8mBRd|QB zXqb6h*6ONqyxQ7VwD+WkaP)6Fju5~N&6HY7(Li4}P0uY*9#j7Edz)QYpneV++}2Ku z%gaOv7{uSBN_$rWa|?^~@FU-%FZ|P2==1;l4P6n=-sVOOkj^VbSVc=%k@^{78h%Fm zl6qrx$rf%l)-uSCjphzad_a#nI)J57C!UYy`JZqYp}xR+7N0PzB#24XmpJkVE4;Gc~1V z0Ji9*RIXTO%jc+R3ABT{-q4%4Bj_^G7FuLjt!n2??w49Z>e)PnkOtCk_6ik39v$|0F$s>5A<^qBu61Q+;iO zTI#WP1iL|Eu^6@W4A6;W5>BE88XjA3z%qQK(r&qZs}g6_NPg6&F)bo7Xps>}UkaVt zLc>`p-gy<&7FwO#c_}jf+^aSo)JYxi-nUp^WWWLx*;Z&^eH{Qayxa(@v>PoXo;HMxeu3_J-~q&rsG{kyAsWX_WdnjoC6aO} zz{2dA)eDm4IloZ}xA8O3{(r!gjCl-%k+Dg#-&klkD~oVm1(Su=F2uN7zw!5x?SnE3 zR+);_z`8mB$#ez*SgNr7T8rLRkx!;7Re>6Cwxj{7h!g&nmgcDmy8>c`D(dU$5=@gb z3up^*9tHeS+FBa{<6Q#E2{3?0D~9BSOIKm&FN;0-Jgv`0-`u8Wsiv=i(U7yV^Hc*z z(B_63ni?CY#Jw zJzHn#Y?y;3NmrtwK%k!-)^xd{ox;BVgMA%nmf#7Xv-2*1YMdn?4+#oZ_V!b86uN`^ z_lb(U>SgzDe}%T720Vp-;o=qIkv#|BVIwcER>SF8wBM&8*TMDgZ4$FX`_G)9sp)CD ztGk<;n;PhPHO`kv#%W()uZSN}T#jCVEJuEll2F3sy>Vp(6Z2n@c{Qj+M#%6KWT$mA zxW;o@NXw8}RJ*`a{w3<{i}poY9zVj0B}?`m6QhT8VL9wUTZHkR&Lk=Cb2CL zz9)_CU6|et(Gdirx-l{-xOr<}4f_Y^h9IEGZ72KiFZ_B@9a^x=arUk|1e`ku2L`kb zLMwb7&YafZjMQ-bMf|rDz$5sjWyAzW`sQO#itEUzX6To&4*!C6`o74pNlP328xRGE zAMhC8k(7f$3BH5puH2#;1c>VH?xfoKBXs`$dny0ecMvK%N8{7r!;F!c^s;3YtSBau zaFam?G9mwI1g>PvV<3zSLp_qD(dEifzZJ}!^4`pN$kV{vWBh%qq>vS)fpv8N)OM>1 zdV{;7D$bVI{h_K6@F#=#0Asm2><)nQ7nTP^iwO2*93ZqCb^-7dI6J$oC!INcidu1q zl9mihVTfWpcQB0PAYo(C)YM2> z)dAQI4ehpSeMc7VY$Y8JQ3CCt*4oh`pabBLnagmze;obW(1PJ!mbyCHa3Ix^So>c? zXP}C=eC^@H)9Yp`)`e@wLMLPIiJtBbibNvR+0{v-W0N#DzaVS@lgQ;3Q+_$Q;<{+u zUT|PtQ2+}2YyB{a38!Y4s1^s7UA=abUiqq5(wXCj=+TKGN~P1(+tq<3fixwtLqH^} zCIX% z*3|*ny6Py&w^sw)!fZndRIE2qY+;HDI5wCl z?X^&t=HOAkxVRvU97`$J_)A$@$@V)9R-$fhELK-5@MEr75*S$x;ZvW?Jr!w zkMBYC?e&#VSqpJBfJVlKF21qSAu&k^;U@O(SUNB-X6X0vQn*$@@;xFH1ZL)OmOlFqut@A zXU(?0dzHzO&CiNJcsqk&$j8WwuC@e8=?b+^O{t+E1^VE0ucZ+Sogm^ zG)`^p?UYW$@QvUc2|VNJqx#0`o@+MyK zB5Pj-y0EI8gS`-zgsYl2@kcBzM^9Mn%j!^<)5@4mqns) z^Of5QYu6VGdX5Z4i#OUfdoq=)EB-I75f^)$;NG2s7eYZuA z!dZ~s>sAIch=Xj^UOJQWo|ds?U|xf;2qMuI&=xfjeGoK1k4=jBQXy5O ziG|z4A*j&0L+A2&3%NpE3Alk_QD;mp+`ZEljc=p~J*#M))TjVXwNAM&Y_h^NWMcUl zcdZcH<^zvUfGULrDM`B48NCd68Mv}?wPBK$bkq5OS=`2QD=jamTg@3nz!3$EH;O!&>NheGHV1oberafRQs=4MMw4^WtkulLo$T;F?-1xP$ z@GKpV4+5ps%-DjfjdN11UN0Tom)}$VP|~7oY8?GSlqjA}5O%Y3vmxdSL=3F&S^in0FV_L=}ES$ zO>8noS#|=?MyC(rfUfC4k;}K_CCM0cX9%ojM(qaFqKQnY!9)NpX^>R`ZWFKOe;WW!*EYVw+)*CLz07(u?iAzjT-%iOD#j z6udbI?x9F6(RmgOMgFtZ#1^zms0c$WJH#4i04&WQ`O#>QEVdt}cOa3W?(2mA2zy|d zy~;2h@dwgu0!r*h@=rZ+Yaurvn!A>*c$wenmL+Cs)RahGL?k8qR$Oj1bc}=UmDoU{ z)W9rpT*7rfK?&}l>T<`BchuF@+4{g7UhbA0sDDpW)iZInhsm3lC8dtCQWfm3PVUCE zeDZKb{Ef@r(8-P~voyg$C=E=AjZ@Z@<;MfFINAFB;d+f9p{$-Kyb|RAJ_VfNxw$M8 z!nZSFf#Q`u!ju6u zLC7`sJdhlh1P)~a&yj$7D_@GY_rBmVVqKtrUfwqrN@k#XPhQU5)?7|@4-IQdi2DA&pqGJ-$@;DrX42d{U)C>g5Tp72BIAM(J5pzFL8EqQaDE76a44? z%44C&;=1_sl)2a!2BEB*KM@=anz?kHH5oy3W@09G{M_WnHkp;tI^BX%quL}$lji6F z1CXC|axxf!8Lea4e=vBQzR2`WTc=8uwyzd$EuSw!Hy%up@18%}3%3!nS90FGr`F!5Cw#GoyP>YV3 z`B}fm$nsg6S{6t?Vd@H<3kh4a*7t}tF#JSR@D{l9c`(NHbYI;2@5^GKb{K5X zYeH(pLCuI12CbZfWK(8P&=R(S6+8h`CX zg{~6}{(>zbhmL?c`Wp{Iq@Opv6kQe=;P-5Jx_-Xh*oa)YAAv*1mtmQL9W?Nj`N^vl>(FE2QJ1|lI?FI`-T+U)3#lk<+l~Cp!LI;raq=GPX_Tq1Ums6v0Tq(7 z%I+S>k33ynq=HE4#jJ$Ux}N>p$i~m97()wfT~&vyd~1#LPT8W;iE7l#%vy0eecXeV z1Y#s-#hYaBAY8E*(}Ja`Azez$FYS6Tbqw;0h-+?FObRd1^~jR3=l*R6;&>dc=kT37 zHzu)ozRGJteOUz(0U_H^PXwPx9p>oO(ZE3bkz8f#`4bJ>zntUK0W6~g9VJizDC)(r zS6y>lzZjSuv|iTWhqz$4ZMzvLnMB~R&v1ct%Z+ai9Wz#7SlA^}t5;j2p8e7f|NGKw z8EHE%pyS>yMP z_y^|uf5Jc!$0XpICz1b%0ihF2<32lv@jf3@@k`q_!%<=d>beNixH!m6xxESeYl7%05Ipp4RFu&Pp-!qY%a2;!C@W9X(*^DM-_-j1o#$D=QUY}A)S zQ$kL6K1Kt|1>aHHU*GsN^#SOFrV zkkuZh$eFl=fv?04)W5}Pdm`?}2dbgxI-{~Dmow-&H^?5$@o+G1M}D##2Nv)!yr^p788g~Q9rhMZ?WWH>owbZrRsVKi$BE8jlsuuao_yTc4VTV@Wz z?GTVt>!PO4R#LzMhO;Y8LajFf7D8^rwA@++(9$|xJTcC(W3yDJJNOXKo8O)QCG^R_CCgU!N(IN{9rxKAR2yz@@ z0Y^C?BLFZJ$%V<|vLrZH_q~lsp&h>`=GV7bzx?p<@Ke8QKSJ0dZZH_0rA-mUTyEj% zX?YNH)>n|=f_{9W-$p$;=hk7mcfe9|XN{5a9BG@&-@#4)!y8l}x8)XoScM~mB5jjs z_Ky{!^!j~2y9TSD&pulIm*CVtkJWmTW?~L7(&?b zaaK6$7$fO!P$PeC`YWHew^P9QuY-rd5zNZkS_Q06bR!0XPO*c7A=iIX)Yeuu%Rh8@ zF@w8u341{N>EuuXZH4+t1`XnUoo2!UHn z+{h3Sqz9suN&=n{rQ06o^MDzbp-^-CJBr;0%WPa+BARvj6`Cfi{gc;Su#V}dZ0nN`e_`la z;j((cX$}qMzI{hnTQ_RHG7e~8r%ZN#Tv0*&c8ra^ZJ{eo9M_Y!3lDzy#kz4QRn!+z*35FDg~YF;wZ! zrwc3V+N$D+0?&LHtZ8SQ?97s^ENxA2FDbAZP6<@7Zam|RQZt0|Rj!dbc1EQ4UiLzG za&53VbW&?ABc zCSgs_)+*_%ha31@LsvUkvdK`*q%th--qvLcm-CAnnZOoIT)BPQp1~Ig$Ibhn^RKN9 zlHVNCeanGm0h45m^o|M2TOPC8XOeRT)l7Fxl@&}!WM!1K zaZqVk2Al)PE&9t5+*EZygLEn6Q-x>Z8f{->Gxm)TCh8$i;KDWv)FBH5+&~sTrHjsD zRvna8{pc^RuZu=sd4y+ygK~eTQn?UZOBa^`2~$|*NlBB{^|MA%a+9)Q*Cv0TGAz?` z8D0sWIqQh-3Ei)Fy1M(A7XR=e+WJC=9N&NY@@H44BMd=!`kk)Ic%)lf3nGMXi;4?) ztq^>-&!}w9_YiqJPGHN4k7=5c#51}Suu|2?5ESm|rB`VXq2GCtqAyhA@^)whJk5l3 z1s)Km@JpHa@Ls$7^PE2p9zogh-hedp`)`IW5mhA<8V8|^o|0a?n)u=1`pqyI;G?$ii$7jmQ4T%BdYp- z{EpPGZwX(-e*234IitraORKAr5uG`eWi4?cCKwVhckRw;GMcg$3^8jZLf{%WbN@LD z!1xWE)9Dp)r5E87GWp$b=O)5(ltVARZUp<`jeD~$_{LhZ~~aj|WdQPj5x`sC1swB_w4Cewt?ax-S@YtN$)b1#>eoCkHv zp~Ff2dyb(Hk``9h&Y^=`DlbK|{^<;Tp3u4wE;opoh1Wip+TKT5v=3AF87Dzq2#Y$z z2_}9MkHYIVqaJ3+m`${i3xT45s>7~QWM^7Ua}LG3BZ9Y$uGuv2cyoFuR3+#H)vW9= zLD1^*l2JB~q%3Xbr{pV7e3Rew$69)L%gJk}jxn#NVHbN=-N;l&FCuL=c;qU|!**cS z3weipdN(yomkv9)&VnV;TOIhZ`MX&bFdXG-VI_t$hcKfnye#m%C45;UxQ``3r{1TYhiXU#C3FH$WBd54zGJp+ul@R-4c{^KHnqOYerW2L zwco!02+{kFDYe$hLLTs$aZ1vVLe%}1q2&EvIusp!^*w>hhR~AlfahR7Rc$p%z0WOU zl>~2Jnn+Iti(6YD3ZDn0ww%N@7H2z;WzHkm#{R0U8_@NT3P?JR2BUqYa5ck#=EP4k zYSFqaXS(obAgfMp9{DV}V1*sO%+IT$*#*tMJ9K2SN*Lmhov)xL)oGn{gLXaYHJzNwU1oD@hS-WXJ+fTI$tBss7cS};cEyDu zG$AaU(EGhzl^S%BFuK z^Nl|;MS&aW)ryvAW(4b`u(p;#ryq)tcZIq!y+pF_jid)nb+-F&9df+Qxxx&|h>u(E zR^UQjqiZWkJrJ5OeVCSG@956peiA*w3#3nLnx`JG5_L*N?FT0(8I3zel!F#;zZl^pR9$tRyeK6hp`6!hq8PJ^X($1Qg*%g)Yzy{AG zY1(h3R6eM@Qsv9yzkZqPczjEQTmj)Y)`JgWb%F|REy{2_nx`v=eB13#O;lHXRT8Y4 z-r*3)Nhys zeV+1`Hh?IFVmY4NJmwJjo@Js*Nv8kOYBKBVtB!_f8Kjfzh65!ACwcK3hA}pZDSMZ3 zSiakZosdj2f6C=d9*r1+m3%;OY0nr@?qp>7f?*z1|WN*Wt3 zl5ka@W*~c?wy>iqRn^d87Q*zNd4)+cLUs2O-beDX4kdkq|Ft41Xp};Vdr8~ z9L6GM1}N<94prjq-fNtod2kyqRDlHrw?t-);L6_otW;szw5Wq;RL z{7z-RpnM1hd7Fff}*Yvu#>oYB*~k-*Fj(s>NAs zLW0*aZlcU1iB^2vT^Jtzy2@8XQfMwL!qpS5j_rP;Im_o3DdV)`&-cJ&GbBc@bMh>`nJcZ8T zmX@vNv9~8xl*)o?R=?drPdsfM*t$@LYSZHl)}5KG9gr_eeDJR}5(n_-$aQwAuK5Om z6=AGA)v*L6;G~na)7VAD&v9Mx-GZV$&?kBFuXSY624Ofk0lgeI;L(;o*|!$N*$Fs9fV36069hG z@jJ}%L=mfr#u$*I7Mgne5r&K>2ul#pG_fi^yr3eFU{qz}mhZcR6%+==zu3hr-g!Qe zd_>Tavc>)}K={&8P$m{ng=-k(a#UEEbw5s&0YjCz(4TJAKZ)-)38NP5Q4BE!vFP(* z$hjdmp}j72zFQM;wy80Mb~*`6;O0ruZQ zB-jca80zB}NwvegPAluen!L8PsUVcRgSZO#A2cEngpZlY@+(V9@_vj*?8qzf`w8=X zUVmMURW>vTi^2U6`TQDe03{HqFYNnRwK%cVMK5dGt$|&X%gzH+74W|IL;w(zHL`EZ zprCHN8}@7+B~Yi&_#+AzVkT;*6}k}Dtlc?qq1yjP;&$V%qsc=>QIZyKx|)f_u6&@v zpp?+}9QR}pK37|iJFF&&3M#CpdPBK(5u^QIPc2R^)>$89`<`W8y)<2Ugm}#0N@b7$u=mQNtehTgmz1Di5V5m)?s$Jx*j%~pBuE) zF{;%b|Iu)_tQCXw5K9Hp87z0JLR6ct5Wv794@@;5%xL_+p18`%Ie)Q4=SFO}xg?xY zvRVlv`!DGTBYNnWw3soEzp23g2LHMci|^|t=-?JCujk3Y+RnPvqQEcys_R-nM_<3J z;G-j94rytY_A~eD1SUps9a?Iy-Mm)6ltz3qMmAXDg9_d@;+qchHuvV4O@#9};`8A+ zGJdlB?iq$^|3%xD&T>6jpOc6INw9Zh38A`z6{$imvLx_v z0n2f~sJ%^JTLR}r8(XW^4wjufh36Rik9_$#rVLG#twW_S-eb$!eLF@|rhZp^#ko#X zKnK4J6qH{LYE^}&Rce~6lQRNg`G$O0VK>ZcSVd>l+i&Qd<%1aVJ}al9)gA8|R*gXQ zwa4%61nr&f^Pj_Kw!m`{A~b*ZU&(-Yt}~D~gT??s4^%Gcp}K8kr!Qbsa4v&(99j6a zMrbh}#x$y`C3P#K^KWLSTX%qO5WMc0-u9UQLBES3ium?Irf&BW1WlK==QKGu0n5+{p>IX@y^ ziJx2TEv7Uzh}5l0p~7zaawT6D_=dn;hI5Mzy9gv zduZBM*7BBhiKM_>J=u9*N;r|Eim;?kDhrp$1>xe1bNfPg9j^mS4_pm74%_wUy*{qO znb<9ybY7YrC1e0eR2NTS7PE9Fdk~}|%qctRr;di#cQRV8S?C8SEzW?p2>5r7RD5;K zGCEUbuZe?o71u3cQ7}bGwe@3~nPn$-HO+U>e}4#b)lcPlzKD*eLd9})Flk85Q+x*NIkmVfZaTOKl@_T@a7k$e52Usp_jj`6K5MmT^kWGhE3v27@R3D$Jj_)gy`#;4AFov zJ}-Q5iq#C+;?r_f04E2l!hzo{$l8$xA0yui5BW<1DMBC)sf8sAhuI~YrRJ%y^$$+n z08A>%Uvw^sm?skBm7m1JFiZFT&cY^XwD;s%TJ_t{2L$l|@q5gco+jeZw1OA0_2o(V z>14wE!ZTRwBl7f*`VqwLYu^t)*PWNQD#!=;%)Wr55u1lg$zF*#N2vEj#drJ|%;o)4 zzt4jlE`kQ2lD_1HVusP5fmH_R@qsV4!n!a*k-Lt~VS`#GyXxRqmX0Rad3pFGT1vQo zcC6XtsBbDu*&MsRf!(Hiz+27N7rymZc!G>Ey&vR(tZ4yCs{LA>kw(>UDOo{`9!1dgU#<`+acn92Swg=qpzVMpTq?=^|&SIu^ec$RjN5|%-5KMi4`5V zl(6~&7CJpOk&p-_r4lxoYKxf$i7j&91s2Qw=!fDHp6Ovg`UT+G=`yeN(B<^ zYlZQH%+0NN{_8bHan5CyPo5Caa498x8}F;IZ;qB;JNQMB+=!!O|+k3(4eCGJ_4Pc)E7TG&!f6eOgyt zT}C`Ux6n_l-?fANUyq`O#hl&y0?`%sOCUpr>gYw#o(%wHkcXGX`aeF}g#<`037@mg z1i?VP+E_H=I)cZ&%f#iiy4k3wD?&bBFw!fY=-D{ajA0n|WwrUT995IUo;vBor~<*) zZNu`(8?fSn|cPH>C&g4e%0B^YW>5Tgate6t8-w;9oF^E!6~}cY!yhSRV!OkSfKFf zhM85!%Yrsb0Xa;&d~~nhNa|)Rz~b-8!i^JIK5%^H<4YfsaNyKCD~+6KQmX^o@1cL) zx0zl(U-#aiPYl-cx$UvwbNfct!pAKv9k$!;^mXxQZ6d^8raMgdk`lagFr7C;^$RKR z40i4m2s5aoA3pC9@%wHu;C{_q*~jklQe|iruRXgF*Ohlh+s~MtI(mTm?Mm)YtYx}G zG?CF}#($0Myw;IXZu#t1dAK%Bi-O=i}5r%!Q<7Pl~b@GrYT)GDz~D7>DBCr^+!z>*G0N3=yedmj%&( z_cm-Bf<2m_3tRiwwd#C6c76&mwlCFIxFvz{zHTTPN>(W1ml%kBbot+7T%Mm|NPK}_ zd-G0@sW__S{K-9b=^bk<^M*pI8@t5UHhQ1FsX;R?jD>6E)`%I3KeHxT0tnLMlGv?l z66R{o8DUn?j#d=6oFe}rUX&DcU*`s1?yM^IJ#O~Na~|KX*;jyH?v3q310$sB?P7!G zmXDKu>XimLFGEk1YBDc^9KdN2NbJa&>&sdeOcl3@|OyqR;jz9?EA2BBvh z&>D0!=w_iPp5hMJXR9sjk3{dvmz1Q)lH?sBZ2#-vM%g5oF z+myd8apQ)dgLu<2-+S>RxXqDP8}Eis)SWg>-HD3~zCk>>wy9WK0vS;P zHkAYt0XbGqVKRr*NXG<`QX>N->p#Dfbv?f;W~)x}-B#sU9QgJM3bLYSn~WR_0WXbsPXrJtVy7mH&W<0IIw zL7Y9Y8Vz{;ov-^Dy>egYMU1$lm$l{AVB7N=e{gkjki0P~{?XGZm-c2gVm%@jk&>fS zk8v25FBf-s!m6Nvx7XHUSXz5$;~<%MqE7;I93c9u;p%b@r3&xOL)a?EG7ecW1saJL zv(-!E%<)-rNN1unZR4y>tqj>d02+_@v$WC21xAlh5`U?N+`F8hIh@elha$!wj8nZ& zgc#Y0`1E~nW5E_4i=22oj-j(N^-EvYhqcMwJ{Bye>kBNb;uXHP9- z@G257_vwyA$3#8tpY4T|mF%ZFsFgHG4p$p4Gb|H3aXf^AQK*A__scbw0&4E8MhR*n zJ05Bc8%-TsecE@|qGrjyZ2XVqrolfK$06)yrSf}A%dkilXFku#S{F0s8;mwN4oPs& zlqc8Lg%U+R$;r%r8CK@h!i$Rl;a%T;O+Yfu?(#9ZB}$>`j%GD9l{YGn5S^J(q&|6g z`&ws2Vz(s1gDPvRzl7Y*P#dv|JZ3>3Rr$z0)zs^X7kmN!oer|F1u*E-=St)ncw)q& z0fyv5ZH;j?J|$7D$-0sC%tKhB+p%4WcvWSiLUb~i0>tbaVEATF&qu15V9ihSbaVO? zMC@lsG?bX7HXVhqx5}QgqI{th^$cYf}vohq2Y@=gTP} zA|Oi@HDTWQ#-o5!H81q@eABFRwXG|2R$QU$$AF%BGnJXUf+-)Gv7bf%e%uJ3H2&xi zNaaO#+h0TGalZ+K;%Eve%n-P(nngy4FG1{mdkeiiw2&E2w_-MzNMhZ|&SEu;6^GSu zJYNMjyo_w+6cA95os>ljHpQ!8Gr=(mH;|nw?o%*; z*bM||jPbcVCC{zH62|YY2BHIQSU?jVd+n2 zC&9&-NC$aAt#vl2n+o|4%F%y;QNurfM-|`HrY5Cy405HB$+9P8YqnjLqZPK|TK4uh z@s9L9YN0n#JU*tt(|}*lrm34+xJ6$dr;L`mW3G=3zsRh7Z9^qSDL4#xCYv#@6QRit z^bPFz_m3!%?b{&!JZ|6!%=h;iU~%Vq7={({aJ3O7)VE`XJM4L}A%jDqZtiN8r^2p# zTsV}VPuZeX<5t!*K(;MH^Ig%?JSBv-fUP%4kr~6^Y~s+#UUgRsqElvXXXcvebV5suZq)lM>!J##?8>hk zutvTt&IST**dp?CVZGa3Z?O;F5K_y{Y)=wB*^4#zvH1|!ReZ_4cL}x_g#Nobma;t{ z&D>v%L*m35%|`A;4N&l;NXlRkod}X=2u5EYXeKL!+|H3YbJV|&G_3s1VIU8iK@$}E zr+>2bgjxlp&g)Ft`-p`caNQGVGJx~miCKrN`j=Lva4F63Nqk@tlAb6CPXSq?{WCm2 zG2Hx6dO&gy?f4_X1^W?3QX- z23!P)?@EM&JZy!y@b(d9AN5E2>N4u!usGWb`$;rmP8wR>!Fw7&t%35!To|Me{yNs zc=bof%gl{zKUP6r#Y9h?8Mv4{igAU~*}2TVdSmKilDxdszi~P#O@bzPw1NIihO#aE zFsvM1QbbTl{?1ohzVp?e?7q5(4*ij@OS6E2_y8H)?Pc?*?tOQBMW=jQ`K>YK4Xej? z6!kxZ>J=QfrdmX zJ~Mn2s)r|3h`mTXx~{Yecnrx9Kda==3Qz17?DJyYof0lL=77zb9sJs?;f~OKj1vyl z$$*@AWO{!{4~*lcN|DAa%%*VqdweA^ zSK#+y%XDuN_eJ>iH>Y^P4k}(%>!(ORVDH}`Yl8d@PDjpdGtICk^-&1uG(;M&d(E`G zR+j~7vqbkrJwya=`{g`~M5WyF${z{V6jQdQ*i$ckG+Yk_RoNpn_K>ri5Ot6N?9u#p9qUV*65In;k`4XlT8wx{E{WBSW%=jX7LmmElMM>YjbnK{`xefgTQ~vIg6r$zHf{(0D^(TXp*4K7E-7nJJLI&y1S%- zQT$4E%e@G~k>X>m6l3CPd@rOJr~9i9`~0}z<<5i6!Al60dfLnv8ghR)BOM8}pFnx0 z2>QUOy8ddaVmb22vd}_vHx5ln7>wRiHCnm7}2S^o1+Vq)He` zx<>~l3M5H7@xF(GQ^8jyyxU~kiSM3FTP!2f5C3O{b6*s zo@?p}2WZNln<8B;WMk?;99`t9JqmmSwL9b)RWfxI!zh6q}g)_hxb`tRnvr9u^MOe8qiqD z#&M(k>#qm#?hIP)xpyb8@%uS*_Us~v0*tM_O^FtQo*zayHS07rtTm(OHBa6zGOOqAs`biw+6s$7etyj;5kaFTb!7rF zU&XiqwTKC8n_WIu?gXk|E=@}apaR@6r*6C1IY^=!u2>sPA&JF2T#)XAPK?+I$~3*9 zNk3Q>P%p&zf{>U2W&}Wbz9W~+xliEiG z@p~0?i`A0LzP)@D@E~1mkapY-8mWwq7YdNRct$Z_>WRSXfXBMd=-tH79%G z7LG?#Mo{-iZC#XYm$*etK!Sp-aU1^5k_bd)B2IIGWErNgd}54LUi`lz0Fhejt(m&G z&OabIjRh5iz_K%v+bxcmZZOYf(9q4Dcpr5JruT_mHjwuR(^3OPZanm{@Iq9;syI_s zlY}pyfD=2D>>dJP&v1MA0Zk%lKwXjP5DVMHd^hO+X<_&ftfv2_?$?i9!8tjXOl2*- zUSLXo+2Gn(Xn&0waS#5Q$F=m8aD`9|%>wwZHM(4&<3+XpY=OmE43^0ASrochj9VPQ zuC)_aJVU&{x+Cq!ABQZG)ZJZ6GJ&H`wodfLgwDru`6vB5LL_Pl`q0y|@3W>~VLl}BMoyoRxofg97>_a~*51LHZDK3=y!FJhZZZMucm;ID)V{l7<<(6K zVRj-RB%43%f51DT0QOM9r!SN;py3|4Be!1?`4sT(hIkV?$%#tGZj3{~QL z4IeNsO@CQ=>D6W-r6^8@i8&&UGV7xWPHTx6T?ZgAPbq{oq;Zuwt7E+!BZmkoE=O`v z#b2S1J?Z?aApfcBWMS+LIUsRTIPc_}R1ihjafrbt3`H(lb#6XEqprck=K#IHe(VDD4333{jH!VK)y`m*{P6P2cB2ZfJpLWt(Ky5ss*f386VsQHygc1TnBT z;0Dnco!kg(0gw#+XO*`1q={47XIF`}_5$Jew~)8Du%u%?LRKG)@V<^H#O`(7Qy?Dh z_pvAow(bRwd{3A$;JUf6m@R3oBAZo)p-8el)_SUy8%-p4&akRa5q0=D<7mXLTcsl%pL_KuMMWT5m7$}*dONl zMVB6e(|A%zTr29|@~*Ifpcz&DY4@E%Zb_JFx+|CI=x+m!kLD7NW_$Q?#YIS7Lo!7N zEKkmulJz0J_cDJ{uxmD0j(UYg5%%Id^Zw1viLQ^X8xOi3$gyUW>!adxX#|lfPyQOpIRNsHAH(L!a&K6 zS8~22WDqYzce4@U#hbRh;6e2P8L#2Tc-cnqoRrSFTaT{>_GYT#kbw}wzto{uK|zQw z#lM!*kB?A~xf4oI7W|HpMu2Gy9J=44k#(Hysymqn#F>82n`VCAqg%CJmVdmD;yI7z zg0TJ-D}S-v#SUlsOHSY-X9i4nz(Zo(+<>!^AMpZIlV`?d1EqVY7r)Be@w0LaBb8lD z@t0SLDpe)kX0_7fmH1-=IELSN08vS@cMYbl`3y+y8J4EYn;gz-{jR?sV!uG}`tykJlZXd&hyB9ybj%pkLCYsjFIa{(q_{l z7jaH2;;0>A5{T9J4+tKx6UDF|O>Ci3>8Z__r7_L9_w5~`YqeY1M-$4jpFT!HqLK8abIG>= z=CUo6`A_V2Z?h>@B$K)jxX^DuANYL?==?Qo@3FhxQvX3PdF4`P>RO^j)fh0)PywoT zEJ%rdlyu3+LWnEaDI4QrAn<4GLcjTU<%mNxMkairpJ7GFv1u|jyk(UQCD#knhH0(j z_IE(mk6@e^AV~h{MouCXeKGdsY>K68b88_#^_;5dO^V6+ar<_?rU56+mi50K8O4QZ z6+tT$p2e8teb?aaiJv{=v!e-H6ueADzgrM6QabLOyYZRQr<6&9fqttcfZ`8k0z+x8 zN+ovEz}rTDGX~YA%1|o!3kCQaZeU2r&JjaDdXuHWU5#^OaQ=eK*$66@DRCfPAL!;h zuJP@1SU8oFa4Sc(5GmrAco#2v9;LK3`1(DPRG>0oQP2tKIi(T%nen1Edw+>XTiv1{ zy7!sUQS-{4j`TsU>Z6k&1LG~tWbMJzK{oEDO3ZT;N9^H(eAwu$=+!TNsH`>F$o|XP z0zDq-y(5N$B9$tT<)v^aN&bFJpuJqp<#ZrXZki_I@25oYRSp?UKR*W;ypnY9v25+l zO|5jK>*jaI*|zcW%gGQZt0lWPN+4e=u`PIV`Tg*WZM?$!Z<$}#U3J|+Q8(J%52m9D zAc=~9l7Xk~YY|;4BV!5y8iLacf!V-obn-OZGN4`hpiEK=-D9laGVyZJH*9fG1}V}b zr#C{B^uJ0gk?})vN>t~;o8%*pyGTQTSnm3Q(ca*WUUXw(ePkEh3=`WXeI{x-qm5E84USPF9;YieMlmyh zP5{#Rd+wyx_Ezfe>lXKA|Lk%bm`0DPo_#9xl*LIw8N>r_Y0$RP<>5}uqMVpw zftsqS(Z7PCc{hMcN&_3zfbs#@paO3{yKH4Qt7Mk9dm7En(u$H}YG8C?l4_z+8XO!F z*TY8-QWP=k`v>+@dutP>{qwXmKPSGU>B%W-#Jc|yjuqy{#qA{fWdypZ!Z$YrN5LrO zx+kV)XrQ-~a)}kX=iF(!j+uf6jC7}`XU$6Nu^e}(c&Wd+cONZJjfr_cp8rWqTfR}$(3r3U4X6ef1>*D#UV4-I9h;{w_eUwZj z>F#r9DN?mYlhZRaH9k#;j~u44p5O%4DhZ3J?(-1s&w%SM@&b+mE}dMt*fI(91yU=%PVR(fczrV zb)6azGk5FcRcuNFN&~xH13t!f6|w7=V=J`0vO<@yT%+O9F&c)khwVmZAWbLkJPB|0 z0v$SWN@(feL2doNf4_D$oCS0p#;~1$4d1PyQ3M#8r@^5S82@%aa&*V3Bh-M-MrT)t zPVIK_sjM4$g~M_=Z2D{Lq=u#@gaXzoTVG#C)%A^3hq;xiuo}Nr_$#dV>ZuMu#lIp| zL8XC8)PTjvJI89H_Q!16AYu9d3OG`6FqcwE+&>;%J`0X3mr;UPlsYBdyOw&OG-v4sf zUn09kk>*}3!9-|P9S`jK?I>Vy4X7?;a9!N_gmBM&7 z_5)l^E>UuN6~=!JnpmUNNDZy!H3!R`_i(Dl+pPiB0od+0pvqSo*vT4@2mi3GWt*?} z1>7EKad{c&5KW9vQXPWaJo3n+2p?Qa=}el=p1GT*(Fr(p`fi$l(_wvGJ(t)aMv>|e6>>26&|h|~ikiCmDL*+*seQ!2K1r6xabyN2WcGu9p>{WsdNh1kTCvCcH#LKL}y@XY7)+Whq3-YL{ z2hgcG5JK$dzy1V;G5w!Ou24@`C!IKafQ}t3P+MyY{rCU<5Os8Pic&jz`ltpw6*%xv z8p{bGOrvMxF?i93hF)i4}JMjig1hqI2ykF4KJl1d&isT!PmT$;)xVJ{H-VG zJI`OI`ucim#14dfE>CN1T{x>~l~ReAkcqwkrqV@`75%f8j!{kDNea(RVEg16r4}ct ztN$RiVo_jxa+>6E!4>@ws&W;n0o4Jh$k%e4E5&W`4rmB(vsP4bt{RXZ3$D`e^Ht_u zdCCQH8CuH1aC6EoVk$qRP3Jemmmszrqt=#IY?cRYRRl8wPl9Td{^1)>(3zv!E`xW! z`BgwgsI{qq+S{7xOJDsaJu^5<&A1Oo;Y|cR8`oClCOlE}w*N#T zI16xjf;zhUXl6o>2|(BiI5ni53>-$tU_K&PIR$R}yV_|LP#u7s_Qq6wl?Jw512DR5 zqpgOY^CFqXTSAJi0Z58?EPxn%2{In;oN8)VnT|pt+SS?7#8_5XwMdccy(P9ec+w1qpr4AdgAfN=;0S^$wew; z(^OU4NO|}jY+J%C#|oA%!V&m1q*Bz}v!C+e8j3BTQ@|kuIW#cO0;r@kP=*Fn2cQgP zRR*bSgg3J`>u8WSvv?(I2WbG`pY;=zdA0G&J{407jy zL+5gDC68DF(S~}_5qRR_P0C`#e0*OIz32NMq?g=#hQ8?n~w(U_Z18m7V*sVfU2Vl3p*>ye_kJQ9rBkSZ>Y`awh7E3Sti}G5+ zX4^*pC1}gnp1VM8W&nd?b{fP8IbX#^BF)SN2 zcT#p~RyZiG<~KJ=|15S!G&a>zLu)TBjt&VGMf1y)C{$Cfp&8o*J85}w5N89ZxNhZt zKYN>l|M&1$!&mt~$@SWP*Z2H;thfCJtE+%@r#$|OlVmN%7}Cv*3y}f^(*U=;9?28s ziO>XD(B2&Y5HX#6%_7e*E5M^(%*gb5(z0u!apqAJduoT_u(h(dh(_DugvFvk%-xc( z9uJkbLRmyfk&dgC0z&v!RMQG~u-w*Ly-r-FYrO=pWR2=DDr{@2quT0f>hEb6`{y&6 z6ip!(e+mc2MBwNag5D-3mnp*q;eJ(rUqvMdKoL~0gAV75p-XGti;o}Af9zbWHxeJ|yMG9Bfz?Wc-s%x7dZ*!In4xG4K z)M;V-8r3(n(9FyX4hlL%k#LB*8W3AyWQgK)q>H=%Xp|tD5Zj8Z)AWFaa$A3*n_kURk zfAFPuA#&jZ^yBaQF*;?Eq%uj6QGV>cJG~#a3_8Jxgkp91jSUemD<|cX=M^8GVao_ z$m>vQ#Q$w+v=#ku~~$3O=BBYID)NA zdg3YDDvV-yAhTM)d<3%!_VrZK%A;47LDJahqhWcg89Kcp>%NErG;XOM0m6+1Wr}wN znrP3Q#+OED+y)#HGqtb+ulQBb3Fz$XqKVX~2(A-P#DRw)%4ws~m0UT&aAe(Z<*fC2 zI4{tWrnsWE(ZB3O6qBtJ;$3bKfpVsaeFiw?^Q$7r5O)$dnqU>S-`yOWqcDOA{rTs< zP5<9#9~N})dCM#4d*AwIx)&!Oe((eD7qF+EdWue+Iz`+m_|^r7~Wk_jcNNFb|F-uQ;^61g&--P$r5jgY;5bMFFgDh{q(!PmlE^eq9)v@R;zG0 z5K#@>9Wn?IEP@-LQ>~KHKq(EV4nQdlDSWX8jD}xF@wBcqq{Y+%Qrpmo(MlZQS!*d% z6QvY9wv#dJzt&GQ6C*KD@+?2Eyz-#mSO}2i2?Hd4JWBBbTMY#ZpDZ(JJ;oam*N*kdBmT}ej^-C^SfIc%+z%sz6wRIGR!&Ds8(%Cp-!eiexQ?9ae7N#w$!!S|>Kw$ZC z)QMIJt0-BPfbkC}OIQT;R_PvjT^3&~)y-hr8b{3= zn?s0PY1e{G%@l8T`XD0Ac*!;8fGp3CF?} z_zvK(U%bN{ItC$Z|6`-i37!k$cx62{5<(#Fqpv-44YLUgRNdMIiYejH#peasJ`QG9 zNol}E1F8eyqLjS};zlE2awC-^L>3{oUJ;zCYB2?kP_3BWPo}XoE3qUDKa;G%!CVKpCCQXeO~9!jmkD5$IZzOvI#`A8n>#z7{@ROl2#%PKzc5J8Jo60gKYRim zgf)8mi4*jySG*0M>e?bs)l z5weLzv1BlM?IL6z6`g5brueV_^Rw9AxI)bx*pUGLn1*)DBH)muDmWponhs$?uKH0L zaMOV50Jv$T;$gBCE~laacytnO%!;OojiPiSX^buKYMkK4DU2gZ!x)XOp)pG$Xh}A) zY)tjD;b()wyR+FOMbJQ^O(os^4-jc-kd?_=b%|yeCu84fWtkv!j{c1@ zjf@Mo1y^$PZ=tnH@&H>&wj(c>2{K{qo@W~wm`$^T(NFf*P?X!$t$9I7cO3+ zTf>Xgg8v@1wN=8Iu)C+1e&k(0MEBlvj-t_OT9}`w|BU5=SDfskZ(W`eeEIotYUn*e zYpErwMx?_k{9kEk>7a$#N&5Uhe^trhUh0Y2hhME2!gvg>uwS zNe!rtqa{_e!w5FiXi5_j;F4j_t`bhg7w0j#^0!eOW~ecE{E1r zNW~$f6JZ{40rGJ6<3ElOz-#dA$ja;V;hF||ZY)D>ecg0R-w`-5vxp;+$LM!{@Av7u zPdzD~tEst}KJ<>)&kN2AkrZ^(>I>e=qKRufA5KX z=*-p8(&Vt9&teN>U6dU>u?P_6PKioN1O6Hi%`r&$f2jOl>Uyo~KKdF=cfFd$@m^E+ z*wd1gsT|2b85swGy4`*a1bjCz;8i$GrMA8SYt2!rk77L^4pY2lnu*87cD^-CL9X() zK1@~e8bA9b@c}H6s#S{OZzZ!z`f{pxY_nuDXMU2pW*B8fONH6swi`*YgRZjvxXP?y zboIxOaNAQcP)mH=EpM6Z=|F4+EXOorS%94?*;veAia3jy_c?5PgOj_MeQ}C63YH>e zc}yr_W=0lkT+3VgHv}5|BI5zph8Is|dGY^Ig$BOOFMk`0 z3-JI;A7r5#kNoONXBZ)Mr6D*J?%YzGurr*pnIs)Ma)h#Y4>i2q5)Oj3*omlH!}zVM)Lf5UHr&aB10i?7#otalH=1iio;X_hZ_4P*H?<{Q)JN^IM>s9HyT@cJlZZE{vP0e=zelX|^eC^_t@SWiZt5`%Ms%xZQ|1bZO z-f(t6L?UF+Ti^OtTEMZ$ygjj}yN9k`xkA0YJ&b~r;1b1nTP^bJAb9*>FOAN`C>~GP z{)-4=^`kVPYrxt82>4%I>8>&~AX{gb+W4Scs2w2tXV8F1eMzi8Ru@w6O76iaX*hZm z>-z;nIpee@qVs_V|JZ|>GhBQdb~dH47QLKec|OUdt|o|coTLmBqrvg(B#{U!ivg3w z62MnUXoYQ7-laSzh>Q2Cf|J&$79%91No3{>LYl*;8I7RLbOc^Jz9k8W=Ps$6? z;!**A0a03pvmg$?70WcjUa@Fdg!L-Kx|O1pXE*)~^QP4}Jbu^7<{_)vSiu^8JkIYUOkaC`lI}X#P79N>^k@I$(=;c%Horpu_Wf_8 z^XJbK2Oyf6nZ~k?`Iv=No?^)ioIvA{u}hU{KCa4bKm+<5ZD|SkjJ%qu(#(ot2WbFr z8Y7IRjxGcz>BLsPD7AL9Bf?k>Mv>Z7C6D&m@C%QAd=~6*6heTMDtP}l)rP6PzKRxC z{{QyAG&qvvI`8#`zJNyK1_n3go}HbYUGBjZ#pUu4Ez1`zg%x4RVbTBmM`8Jg<#2?h zSlgi=4o5iXAC7Q1e2}soj*t`dS$Vw7d{vb%^W{6XC9$n3Nx9*hlT(Q~ib?ro9jgFOSI|XuldPiu z>}7OZwW4q8d@Th|_eEcIKlRmKN2e8BS%8&wL3^yApt_+G93MC`bFqX>PELa8uVB~M z1A7b!u%qEwZX*fV0FU?pk{;$1S4M+j6Ab#Aj~M9{f7wSTl*Is9^9WivmU{m*Hk5`S zpCa1OmQgN^VHxYrY+M##BV!H3{PJMCsy977E#LXhcOc}sAkRPlyh>B>@Y6rg2_f5{ zoEh%L;=*|j7IK`(4h)o90POn41RC75iRFZ2i2-XiFYG-g7Z-%|A|U+XNDFq1UI_(! zAmSoxaL~g*$0n(@B^)Vg70~yN{K1$ONE#-XKYtHWgIn5stdq z@nhy1Wp)(G=N44d$@;1@`DPdY>Ad2ru3OEuxURl0ZmamqDg|5DEx59vJs5j!UEQ9e z;yOd^{@_0zoS04Q2+l3JeYnLzQz;x^cqx z!#6*I{r?u>LSS@sR3^cY>xG(OFGLEK;3%l4vt8~#nmTT%aQb`57^pTSm^FlSiYU$kH)etctV}DSiV+f1Vw><8umo3j5|iP9UL^;x0uDe18XHX@9GmM< zUt@R}KtB<9-ZAsg`H zcivS#AUJ5+5?sU-Oy$3qfBr?8nwf*wz@Wro9Lfm}2FhWe(gL7d9qDLqm9PHX6}fO` zQ08NC=>SV{5v$I@)8}Mt^iyf??v`uszA1ByYjXa~u-v=U_eUGH)$Sw% z+w){Et9729qwT~)iG&Y3v%|lRA?*tNgXM1zj?} zup+wjM!O|Qu3pB<3v59Z{1-}y7S3g6n(6A$I=#Y^(w-d&kp%6r1%&ck6AlzU9| zNvG*u>hCMIB0z>A0G7>qz@>pI(MBBX{RMHua7hk3`JD1&o}Z}I89#_aQ$to-;eS51 zhBJPc_uVjr{PP_orC~MuHJ@w7bb%ciwtPfOXbISB=-z3PS$Q$Qn)#A;IENe8y|(v9 zBg>vwIGU1uw2E7ilEv(an^*)yT0=6wvMxitUE;@gJioMxXYP?m1jhw23aIHCRzxQh zTnmVQLCzj-DmGOya}SLjlPc;62af~7fK#J4#RHR>ZT(=?AW+k0b}A<4&o|2tZ%(T; ztP5lYM*%JEUGiXJ3g7loc;8jmoS!3#foc~31#eOYQmP~plT!=Q+8R-l$kNh^41uk9 zexO4xjr6Eh>0oCR3xkZj_QF{?+y5KbZM49c#ghEhkKdEeeE!Sw@b)daeC1i0n3_@O z8NKzfEUzaO8_OotYN3tKXvv{9JPguw7u z?rN2UDE>|k0L=UWL zR-{CsQb{i5Qg#WeHZRWpXTT;N9PEd7z=+(ueHTW7G7^SifDNp~>8feRBesFuLHyNo zs-{2Hl(9ARlt%~7J_A9&S#W3!7g-r-5VSx}=SR1uyzvysXpYm6z;_!FDW~M-Lwv?SuFm)2H!Uiufx|LYaj@egUC}qbDO1o=!eiSN*tl zcG}$#hVAeuJeV2V^q^}?;+{r{!MA9}^g~WTqf!>bxZ|gEf1@WUU9ACGTu$LRZc8jt ziBDtpMR%$ATF^zES&&%bhUE~dSO}WMM@MZm88qFUoHp)CL|hZlqI|e(Y1AH!nerpbar+@yiHgfuHqP|6c{tD z?!;eruVkAQGfUPuDT)2VXJr-7#{>7l44u&492!0&fAQ{Z=;Vlu&ul6G0>eXH^2yws zDl@gbDZ|}S*?_xkhxjX$I6oCIpceqf%uu1AJ!=*${(BQM$`aKlW3zI)7ZRtF3v%V` z05*|0H^$1-9SXqiJIs&<{Aw~u;)QI4PxwZpZ-Xn4fL&`3cJy92jXB%bDwn}EU>NS} z0<1;(c&&$1AA3*?dMZ&=bNT5SU zoi$7q8%Fif0;ds!d%#p3>=U(4t8gu|u&7YuiDbE9gS-&}Krje~LBstnScq|0B8y}D zo=wfGKG9~mp(0d-1F#)kROj<$B;-v=96SES*gD+FLcp)8(I`xpUPkJsEY`kRwraR2 zsOW(SNW&{rUlq0G6&5efwH2&6x;w1hOH^pos%%9n6fVxP*FhZrsTmeq+mH}c#pV{5 zrM<01y1Tk$9cc-CyAep4uVT%}Z^!W9Pz=*{ufW^eu;n??{b2xTrAN)p@w-Ycqq93A zkKse0uUX{5sz^KbQ0LC{t2VeGpbMZ3tp9cO^r|$U?=j2+S6Z;EV$RP~i~;QnfGE&k zvA!0hh2RSS6!|qKM%p?dl{zB-b#lP zG4ITA^TLYut17_+dm`ht1hc*dQ)P8~@pAE6dZEjfgJnG z7Cp0&OfPg`>VUXxE3b{MEfHB*UWF$|7^yLzdDc9K)-4x2f5NFclqp;$*#KKHv+9nvxh6v8$kll!#Q?jcvwEZKcyCIIeg!pc#bJ> zOXn6S=;laFu9=~JyTh3&;qvqvVD z6Vm9-%GFD!QZIIFz>a2yMVCh6@l%wN*u z7VXQ2v6ETa*petz*?x9sQhxr*u-qPBkhed+C%^Kg7v#79^*7}6uYFFw`c`GeV4T6my)Y7X|K%Bd z2!lv@Leddw0EfjTu~iU!Oa_@0rVe|Di@{-Vieuo}mQ6?*H)7`>hEjM8cI4yMmLC9$ zr1{Ic3${04Hmnh(ueyktt#2!LG+(N8%m&OBEnW5qrWU_sJKnl#`>X-kkj*69trbTa z7Xi_*SNh?{J`jL(`QoCitZqme?;+O=)b7=vMgj3>ckGLbirv$FDk@YaIbUkm0{NmR zDAv#o@C|)a>B{#-F929he{uS1r8N(}@OwBz z|5cC2GZ=+4m>k&mKlhnu<>Pyk(h+vcQbV6~wnb!fbxpF^O-`?1=M94H!6cCd3z{C_ zw&1O*CE$`c^v#>xNeQH45^rdguoxX*nVl54F~_-ei!3iLux$vZCFT6tGjjLtJ@I3L zV))V*UX$KwI1{1QAa5w9MP$0y4 zB#t_{q6J{}#Gk#_jTVihOtMj`VrCJblXKhCH>d`~IWsZ;NY=J;Lfd~_guQsRUvAub zOhcVAi_i4SpBYwVx8Yyl?OQYIh^{?i%#ml#oR(|1M_~l2lsL7j=KP!>4D4qCz%NaI zZTd>o6vP|bhJFY0#P2X8(A+7Vea6|->7i4y2BP1Do%!taq`dmli}EKw`BXAZz0&AT z;p{jeewZBH+*p;=@+1t)(8O#9gwR%`3GC`ENVf+4K52qA@^vf>+TDf}x*sg)7#v?T zw?ttc(=b6hF*YW{XV1(1d!K@}&z?Ya9e;e~d6vOaytZQ(JhxW(;{Wr1{A=>x|M&lq zzy6gk$RGUipG#w-Uw-f3ydgI}`apj9Z+u1m!+-vL8Gz7Dw5tygM1Ju7AIR0KS7Ztv z(=Lwm%76K<{|&MRd4lSLp1kH*s0!u}+t(XsuB_|~I3iR}&w5^FHJ#2lL-DJ`Vt=bNtbzgC3+V!-I#Nqo2{peo;C{Wa&+<(hm6iV)O4F6AUHF>sm_x6BMI6-(aL&R>yCM_MgT1?aD~Aq;TXpH4zhd;1+lUhQps$$XU_DqsUM0 zEh#McVCiw7BLW6OgWP-Y_yl3b8A>G#)N292HuRULuc}=v0Df050K^xRoIeEO+zK@^ z=oLq>^9L*b;<+Jt7Ai&SFgrRoHzREz-aos38|TVCS$9Vz5$J-&Ils(6sD%Q6$(0!i zw)M-_>YVr+qpF>TaI-`LUfFWP-@MBp;%)w{ENsBc?BZkTiW;hHeLbDB2HW&&V0AAo z84|FoD+!ph_2K+-TN%WFEE7&QdB$n1p!GEf%3LhW{&&9es{F|hej=|tcUFFSeN^>@ zKVNm%z?vH*bSxCue;*iGKW6%o(jp(v8sraY> z>{+@M4N$<+<(K5@y!gT`Y5`ELD=v>;JfX0-DD{s(=RUOlw-|%{aopQX{iyuXKj>l6 zPO#=h009>hAw6&s77M<;kShMcz8~r(o-1>A{@lhKC4f5q6sBFVE z)frd-9O`M4B&1M#yIP=Q?3Q;vx+T3WjWUm=?R+{6YjRl`AD@ust^rw{8vZ1@HO=jne)pprJ zW(IfJ^*jQg%!4xS!ATe_LaOg^A;2A*5lVdQDCfcRqC9{n03l4sWi(;Sump}lQnM?5@SVUU4T1`EcwUuL3BVNC4I=k#bpa=$UpQ@k{RWxXgM<(kc8ox}l$9ZoR zQa9EQcl*rhX@&}@F96>Go8nHc!73p9LEsh3;kgu=VYaH4i0F=#$YN62?6MhU0G*6v zT2u7}A>NOpx!9wd7B_AL!hWRT10zH7*7Y&P?c_#=p{uKV0Iv}OGGI37^yPDyM1eWQdr{r9Jm#pHv ztEICa_N&*VrF%%$7A7Hyp1=-w0Yp0{iRD=suz|8m5W8I$mcfu(Prz&tISZYw&9Vez z7_DIK-xynvzQG}BXlfG|&cc0Q%J&SOk*@v$<+~u*-YuKUb8_kGRSEh$a_RCFX$NPa ztE)qC9TE^IeE#BqGLq8;Err;caRd>KGRbnk`?hQo&-v zT-g_@Hs*Ul!9aTR%fhjU2RL>^7_h&^@aVS$XFZr7N`!p<5}9Ta$`tJacL;}-txWi4 z8@$*Fla8x&TNz#6D$G3nSGJ)Ol%dDUt40!0fH>Y6E9hdnh`qQ~Oc%0h6-2hMa1Vj2 z#Oo=T2yTPL#|NxNCTiORuhuynDC*%dQO!#n1wtsPzBcDwMM1|;_Q zp2TgcdvM7iFFbcn9z1*qBVERkBGvsydcyK(c^h2TX3SwO*JH8R=-c>lv|>TK~(|NMv0Ifeis77zoFA&7um(ADjihxbPzecmFcJZq2<=z>l1 zK5@79OKW$(%slu6tK1G*#D~F+XJP|Z=r&>ovBYfT1}B0Ggyi-GS%37tG!0$_Yd#p_a$*s zdFV7B+Y|}QRwgGQ>@11biCjoRAU`-gQ|HpO3Q-=jx-%u(sgPCr`IUfi!jf9s+r<-% z;M-5*s6~JO#vm{E;YbFd4T70Jx;`$aa0{cVDs+Nl>1i8~KsEt0z?S-#Oi*ZfuuIk; z#7PURPIxLYke629W%!gsvxidOHPcF^+v}NeW5OtrVI^g-D~+uzt0RNkckW68!h;{( zx+~XVi~Iu!3^s%sA-(ztddVHC&c(q_Y1$l<=JdQ=J<|grz>u8oYE)9LeZ%J@0HHw= zRm}>|!pdNB{vl2sVBQ42>lx@;b7T50P7ETJ+<*s8Z`L7fLwSS5+(Rr9c-V&juo~n| zF2NV~7LF%C@!^X*y$7BBu&jrM)E_1A+1DIR^=LLecI)*2ZJ@bIRI8C0KlJR!kjrgL5O)5r^adrW z^dqqIUrWgS*`oKM;zVq~tnL?p6mcpntrr4?sip30?~9J=w@vrae$O;@Z)U1GOwfgO z8%$$R1&XdJ0n>{*sHKi@x7{}+t2`Zzw(*s=eCX`uQfP_ zdH~<^wA?w2qq=Rpzgu``^@O3Xg^=x?F3fT6c4D9jX1ceb8r={KV_sSi7&0vg3(Fgj zXF4O_ee;@}GDWVS=_?yhQEr8{QWA3~!)Ds8EH|o~bOOf-5ab*lQn${JgMmsIz*cle z;FMD0OLpa{2nd)FN)+1xu5!ZqI*$ur*LwUh*o;{?w^)!1XGi3n53b9Fkv_S3cT6sv z?pKB}SZ-;44y?(jv_5-AzWnktNO?|v@Atni8Cbe=f%Q#6!mP;-X&$^R$)(5QNy6J% zv{%xQ*!P2whgv$MDF}5qm$AZLUD=cdILZmPbgJDt+wo*!1~&y%G!BSo8x}VZlDOXn z@$VTJQY-cpEbM{TCLs?N2ktOd+;J=tpr!*AoD{t2(Mne?1!p^%Ep zjghv;U#kA)V79l{58Df{_0O;dIfh029eltbi#P#nlf8c=;(Jw9 zXPR)TylBF26-R$u;A(+1!St-5VM8NRf$a@tG;3Xd{#FG>c4@m}cE!wsR!-CnHUKTB zhGl*B0o*eibBrEeCq$gO;6nXJZ~s&!aj&p|>E_BXmiFGLN^64o^DQ{ivQysM(IRbNn=y>fEXe5i6xfoOuweh5hHWw%OVWoA#|^GPurVUz6BCH% zq_evVEH)e+xM3$BmhO_9s}cw`DdR-6f4&9lc?^xPDwxT+#hYG(iDKgjBLIH|8K}{v zVOS>>=SiFqmchy3E1Vrr5&*Yg zawR3FPoI%_SnKq;($WlVszhu-ZcH20|JAGK2uemD&qIZ?YFeP`I6ub|11?h|j=hH! zz^Xs0QXBw{fl^bD&I8fH48U{k0}N?MHa>#!ABJnU;QRXQX}LK%E*H=<9|%5)%j)u? zc+AC!7yW4rxFrf-1)cs3Ob%~Jps7_^BHVHXVYYZnVCG!5z%9U0zId@?Cjua5AVK%G z((9iby$(~yI1WJA#sZ)<8j-QbW9nZ0@VG%udS(*tH`Z~sj)ed<6&SKM0l>7WqL;IF z{>Gxh_%)_ZA{s)#md^sM4WN$*6wnesUT845FhMXt1i?o9OB61Z#MeYW zh(J*_O=N0Y2oQ)4=wQ*U$|;q`40}57%Mt#9a%GTEvMwrG#GDN&@wGIFX-CS!{V9)Gx)@I&(_zKbdIrSZJQ!n7ptqb_nUpM!0T|{nQLQX5!yIl> z!qFC$mV!(GeBjC2%91p3TuGTShS{>AA<+cSgsh29 zZ3_Wb)}uCYuWxma^&=^lZU>?36km(_TAaP(zEpX8`}Vl5toy02_A)xoyyASFr{EOa zXvkGx^)uK}!2)YVR1p&PZAhSdct(u{Y$x)D4ZQcENN3yaGBWTn>O40s1 z7GixP=fMHEt~N9ta2VrBH|(#p$>`XW9lR4ii5MuPKX27CMADdAf<xv&ZW=m?BV|f-~p?16F40${!j5f@5%t>k??dQ352j zi!2^n<*Sb5nHNQ=pvHz8 z8V0W#Zn>+yEaP@~rC{3O*vs4D6qni2347t{<7IKK+AG!BLfBhLSlhr(|KaQgjBY`X z7M!*;j+^+Fa)C-6_8p-_Qel~03ltVVA$MsU2X>!+MyBswFChNpM7FgxL83n^Q!~af z;YJfiM4!|qB3oPnA7MP;vng2jPgquifflIgKgg(1#bpNucUE=t59{wL&} z*=-m_wAiB2yVYa9S^$s>P)%W!xn`BCx{6h!E|DfUxsODem96q&SQ^Zk9t3l#xHP~% zeotE?oR}C=`m-}r5?h=#2)oI)SK0zxG3h_mD-K_yKws<9-Kv4`Fh$R!d>s0Z%o)XI zH6aCI>N6bh$u>+SyG-f-@{LqE$?jTg*8(NFVAk2eE;owqZ4qE^hVbowW}ZFC?1IYC zkGS~p7MIue_NGe3bvgUhUankwEK{ydK?V!$FO((x1ZzE)-P@s-O%mn+b6{6%8JIL& zZHHeWhUY#|gz4fFm{OJ$(_jO$<}NI-kV8o&-6j~a#}5}^dT#z zHgQ2KiE7jOiFGx>$I2S)qCns;1)D3EI(diyLBX@V5R`6J3ClCXLv^YmJFWil(()u6c=>-sYjbhKtK;?`V1bp%UXe{ zTb|1+LeInkg3pAb6R0h~pv|mm8f8D3@nZMi67(o*Y`R>US_m9hJ%XN9%EH>UK$)7T zS9fkesixS!;y+ut;w*h{D`G|M#JgPFDr}2rn8jCH5hGe$K;Q2uxTl0&2|t^&$Vhcf zaOb%VVcA7|Vy&S3Vb};rL%=l-{E!o%KvoUbDqUUUC!&-~PG5W$pF$R%Iva(mmJG1d zWrgLrML9j#Cg(_$MV=V=4h_s9w4R#EyX*g^g{ubPk@C+w;c8 zr@1L4vE_N`huic*+Mqx>KPL?Xg|v8Y3jpGTivWi5_{oh~d4*~RR`P*G_@Ur$V`D?k z4GqZKAK!xny;rgCv(VXRxBwHFK73qvAS)1{i>%`k)Ffbh%sY?|b}NrN{BWlXt4C@? zbXA;z`cHMiHpA>zVb`L&7AVt#S?^F50`@Mj-AaGJ`&O zza(cxbq8-2uX$2kbJICmm&Cs`js!MoQ4&V4NWen)s~)r}S##URzXI%wVCX9g)3O3p zW_vh);hZevShGFq2az|l0j^zppm5p(F{ka6A?VxK+^VdPvThpl?>V z&b2zax@8omE?XmTNCdrpC!=LeFab@F}vlxxWnM??t{DA;O_43Ft|H|yX!ExyUXAXgWJX3-IxFEd$qe& z+g0gQS31d;bahfW$#>2GZI1Vx3KPFK2BGpF_^_3=d6L7vS=}JYq-l%VOD3WDV};Ml zwV)&ctM7Xmbpz87w>(JlWd>34YGf7N*`1b_ILOx z>^(IJ`&Z~2Vi=quNzA6%$bPrFnj90v-9pHHDrCcm>+cjlp@eZwnhxUHCFtYDM}cl| znq{bcs3rJt!S7r>h7r5;wtm7g7etDZCjd-bpQx@h8f}ZV?|tptGQG@XwkRLy_(XOh zkkmGC>=#v@^1W(dS$PJvwMJEY|L+T!JFkwKJRlY=cJsy|09A?s>>`HW93Oe$*)a}eT39VtwUN~cy0mTE!A#> z>fy{zqT~pN>4Z7J-utvyi16q>3N8uW8&-ve%TV0su)s4G1s`B+s0%}UE|;TE?pvCK zeCBmI+ghBT<$t@0%`r@z7@w+8#U#!1psC+E1AnQ(Z56f^P=p`h$mIU+S~r&euk?-- z&_N}S%I#rrE5uA3Ve)GdpWqeb0R^A;9*#@7gByjb^6BSg!7(J0VFJeM%KP2)tvF=I zNezDuNw+M7C%=$Ipp0Aec4bsI_{j=~xr0J0?|Sk$lWiaenTI{^=5A2v$!PoE)C*^c za$s7IQ}zBAtpwYiCwR$tjc3VhC0r8Rx&K^hzTyA%VCY) zvC0iLSyvSoVFdW5eru@0);#wV8Dn9e!y->=CMJOL%7-kpB2Ig)y6x@CuqT_~C{-h` z!;otO*yk!-?_OG@L^xd&m~)X32Qob>g(A)3^}%r5w~q4XVGdt0>XC$HF|Vx|v#r|g z6!h=@Gfp_xRMMt%-;K1vf~N*L<6XVUm-#jo^|yhq6nvUyX{r3B1DuMo`ee=q(&wj? zX1-azx4d1Z7$#EXQOH;*25pEFtD(uCZLx7PLalRuqgL;qv0jnU(}DLr%vA6*Qga10 zfArc7CtaPbC48^)w`jBbuMfhJG07b^#P+^-epICr?+Lfsm8c8Lv=- zUIv5{WBF7cmW$cKh@UX z!wR;h)qs{QTt_Mc0*79q69BHae;8Y3DT-&kMEg{?0FGCGSqltd_uZKmnU z)o-f^7VWPy11g+$A!l~gQ!4O%77(rW)Rp?IaUt?7-Y=l;W7`XY#zEIm=M~^RJRR-VE$O-_y{7kOa*&1ELVD98b&NLTTFRAUP~fcbZ_4LnR+Rz)og^Lz*a$y zg0Y&xR5SP+940|;>1}@}H&Gr1!~jttH)Hr>G;S+w;`2#CkXjPQ65CiN7J%}O(~XXC zJhV!lJN@+TtTUUJm6~YN&-9E3Oq0swaXY9XM+RImBXCAnQs&MOw+39*OMSnk^z)3E z=4uJFuSM$%(@KHV17S7a9oVJ&zOyK+&p(p+b#%WVs(aaxr5v`1p$(3hH|k8H@#pv! zuyzrG9aB|#m!!`^7o4VbHqxzi5oYNmZq}6p@sAF3mE2{j6MmP`Wetn2-&6PUln601 z_(k?Rbv}}wfCTZ&t31wAFQ$*v5X#5tK-(K7eY96Cm)DaA)Oup0Vy{2AcPe&e5{o0$ zz-*7$Dku{lOkV&WNG^OP6T1DO&tAaR>^^#aP0gV`wKKi1-lMuw6P8MCYON$7F>T_}f4X%Im&~C<`vHGXhps9!Sf>wvd_+<*vun*a1aIm<=|v8`kXpRX~A)vvSC#Tw?zF z&IF(y^y(c3WL-0~@$$g=dh~SOZxeWYz(@6z>2+?a*LFAmhOgMy`AH;2`lD{I2*Yw? znkRf9`)lK+f4I#`W`yCcuHR`@lP6Rhd9V8HOuvm?y@KY*-MU&+g-*g~BUMXntDFwj z{+ehEBY9=q_q*&SR^Rsy6Wy~6NE~R7qP5EUNZRN_$AimI6Gpfi^OjPS2o3CuvND?Z zFv9jV|He?~ioX(agD+m*`4n}K+X5yU(_;kZN~I6%BO9-~aOzNtXuk0&M=>v^mX1P4 zZV9hGA2E$yri21%7DhKeTToy^lmE#*eq z=o`)N+N|-Y7-v_monm#O3Uj{OO=I~Ls%qIx?&>(djhqH2S+-miN|l7K_F^{+JIf2s z>lE`wUs^OAVnXT$knukF;)St#CK(uZz+cptTKXu`Q;6OMJEGnN*F_leE1!B1D=90h zs->yH?GU&mz288AYGx)TYEX`Q@eCaEwkeLJ!#LpLXP*ukY;6Z5YLBTYP_J@yI2{4O z>uuex_o)AjaQDs(nWm;?>!VmlWCptC@R5R^!uKD#B-MY$N{8%3ynS5t5VsO{*;c#f=1C#f zr=}zIN1568)zt}TeD$xz`r?CkwGc(^hURuZ?$06m^&_ZbOEdJ?nOVWWb3154SUi51 zQdrgwc3EBiIWtAN0WpT62pyuBvKPuH%Nuw*5!&Dk$IMmsN^DWvt^Y(X4d#RzM+8-h zC7+pvyfqOx;Ld89*!4$*=ZWq}Cklmw-PfvDoH`~1y% zU_0|^jSBcDC+s9s51q9pljfFx!0;KmgoblCO14y2NLm?PX;a3gwP~{-1cv z^IdhBKd(;*>da7*eVxsfzWG1M)qOglyOp&3SOj_T!2}Dz79t;w_Mbf-s7LCFMhZLa z4(y5(xqr^%EsF`UCuJeNn@$-H?1dzS12ssliMFEedWOdQdPX?eh_CjLL*RvmG0Dit zSonL$?HDEvi#(HEov@o(^tz#*K?nTOcv>4CiQoJ@8XxUy-{2qL%eT@2qc_M4X28`K{Jl$aYdYfu&dN4+)qjv_89Xk3@~bhaz;-0kyBD!d<|rMM zYfZsujetXBWs(DY?~`yXNx10ram+R!c|r;Ie-l zY+%YzSTl%3nCmgh0=?jj0eJpDj>`W~?|Ff#fj2G5<34NaYbt8SaDj1(m<$L-|=-@B7iCx5y$-$Ke-8wrd10aJ>0-d01LfmOZ^A2 zk2$`&4;};(O-zpMH;nHi!c8&5z$XC)lK^v!!E$#88Nk^^5;kc9rB)aT3xOreO5ARI z#-I=GE#H?IAXN0#*9vm|`A+57D)@zIu0wmH9?A#=*=t#<~Xw}&;%jA8PgtrYx&ahp$TBPs|ityw);y3WyVY!QsvR@$@BbBzkgO! zoiXQFWpQv_kvj^ii{;;1S$>PiR+D9dUbwmqcpvgI$`c*=C)*WTh?YTLxgXxCPwp#G zWnkXwi=N&wE!F2nfE9D+BKtCMZP(4NIJWo9mp*o>4kxHScni%EG5=*u6k-yes&HIQ9ZA6G8nF3G8E9Vi+Ns8q~=D3iRJdU!O zr6Ub5&tXPFkSYfXf15N^#loJ~K@anB4y8HR$pkh8!YOt|0WZf;Hf^avx-#$1W-@(MCYfC;{J{%C z4*P0vm?0wRkv^dq0k1yMI1}6TW zN`6ltRE|Q%KG@{Ne^zk^50S^Z!sBehv})jleYW2Ia?9p!XW$V;pLqmmr7;o1mL3)F z^8N(7KN;R0Sb=t;zNmyUlh+(vQFz$g4CGEWYE zChXQ>xsTcVAg^TO1v%Tp3Q=Ei*+6;-kGK%uB)dh3mV}c)s2fhLztLCku>(~p{odlQ zwzPH9rh}epsw-iBeU`DlK2%3MIkDBFu4zdwG5q{Z48m=N)%~SNk!ge|<=|jbF^sNT ztwr_D{2f5L%MxRoG1+Z4x9Sym-Kz^qwFMHOPHu9fn#&;UE?&?pBIhf>%STKw8G|~wbv_IG zFH|vx20v*i-1YsTl)i?rx&R*caK`}C1t;U#Jxt)+abSo81aB6(Euh4z0#pW@>2am~ z#}K+~*A2|KviGR&)JBiDCh$i4P{>Hn5m>JYvj@nX3TDfifE*BVB}I=FyPm}t1ltcs z5DliQ;=;kTDS%oQ3W(mM@Ytcl@}Om2Cm71`Z=lZ{1mj`>tv5G@Z}fB#*vBuXrkSBp z2H;ftI^uD_HusrsPwa*4Mgg%pB`_O4Of0*&y=@QHV0qK7NO5(|r&2+YMvZo1v`WVM2(Q;QZ$dJDi~a@Q;BF?pk)z=)YTp)U9X% zN~9CkTxfrB48R^>Wj!Ii+x{?BNB-hIB|--~n@o-(QtfE!Wmu@$Y19UtmsNK4@dHcS zP^SlIp2ifybXoWN=976Tv3ij?++5Ig0Z=}?!z79^KY6=>E4h59d4H00QEaU!-U4N+9f|Bu<(_!zZnye7pO7G_Vyr2FK_qTQ(Q(?65 zxGaBr4M6U&Yv8ZXuS2<-L1(^CpY#mS4Ip1$s2k+Ax(X+EMW}>m7OG_g2Od7De|W_8 z_gdk*6w_*M?DkVZ{M?_`J4&0K4Uc+4;}y0wUJsPes$W4~9#?_eISR~G)Vqou6RHZ5 zSf&^$AHWn_B#Erg`PD{Vl}AW`cX({<_6^SmLX;GZ1S42E z9}-NTs=bU%*18`vgYO?NK-k%5<(+VqnX$ci36j=*92k!-U{BB+)z4PDcD1DI7J{-q ziSA7DY>5>gSg1O^jZdTLzRuzY0R}7Z!D6*Lp=$-5-e1JF&!8{ZO;(imFO$2xprb>E zV<|O7y5^!t_-*#NGaz+}w)MuNwh6cjcDjxic(v=0&r417QzIKwaiJD@DXt)hQ%$3XbP#ffZ#h&VP{O^vabv%4nz=@spxS`&}g<%C9q?2?jzm zQBxAtTkXfbedW^iE#~e zGS>QB=n6DJQrs0ch#PgJ<{!Vzfx7BL9I@VJV}}+BCV+pdVh?s?4-q2xYE3iNA!uyL zU3S`vWHhFa@fJHg5f~6n_I|TjHC*_}d|Icb1##M=Ug002fln>S%+FqxxP~h#Vlpn~ zhV~)v)`Wre^CAux>I#V_Q@DcFU+Lx6(8+R|G6R%vVAP?Uf}46`B#zX6jZ zM+m@c1MK7p_vn?38I#E-XmH&y9dWA#8?>>JU;5uk{T78n!Hb~${ig?ZO0o+qj_lYv zTQ@TLaMct^JMH>kv+NY^F!;UoaG;6>0=0HTQGp1Ze{qTivh!h$q|=vE6-P+mumAi> z-JybHh8mzCmptQ&z=3!E8xM2+l#JZIa!e*ye+B5N=3ZXW^h_Ci7522ScCsZ~7&h(kCS#ScR?1fnH zt@$frZFVpl{W$=ncJU$n~q_ z?+KRWS-40FnFZs>dl|;H$WaZ3O({byJS}s9spwIB7XBFnDvhmwEdhEIwZNqE+)Lb&f*O^%K5@5srxgwz(Zv zSGy4}IjW$P^Wj9|r1CFpCLt=NP$u1OcYc!VJn*6<^9T_jpc@D9`a_LD&gj;*F)LdA zD+!Fsp-T(3S94G;{$3R?{y{Q|xx}A!OPzlUdxg-8A zfIv#K!*kuAqyxgS;0i%9R>yaf^&_tET<9|3;+O-+CRjERXK_#CdMDj-XVDj8Bo|LIPLA}~tR3}|? zRa$dMnYcvXG^T~TY#4=pZD;F(-&wgc&`=iOE-NJCPy%(QS96-v*8%lfSB+ZaU{U8IQAi6hSOZmXi{4 zD)>ufMqGGGh2ZOmcs+jF)Fw$AGkSv96rEK)V8qR-f7=Lf*)-?A_IH+pebXJ)AJwn^ zH9VL6no7iQ7m8`*8w?0aY&NE5`x5aDamT@eI4_=2f<|*7&N(hfBtc3n$Z>KM#Xvjt zo)q1+zvbc0_`MC07kaOl3){o%J1FQI@fcXE3rYUWXl8M< zpqK4=j)g;oIzrT3tGGhvpx{B}eo4PxMZPc?2o2t0)H^uHM=4XjG;0|9V*kufCmnr> z4G+!~!4wB$DbEQB?1M`>wf}+wk;4ZJ7bqzr30x?{o9kA3zYDzV2NmS0E@W96fTyBx z(ON=9OzU2x@%|)~;erDibLwSwn3+F-8q;5(C5i3$VKd6~+x*_YP0)FhZ`-Aa+dAXh z1Yi*PyJe8yNryqgtB(aLMl|uLT{#p0ojbNFs|yC`+{m#2UQZm=04(sD-5QQrL-vgH z8P)aQcfVXlTmQ<*=Vj0tr4z~T4*Y3AqT<4KWOkIo1_k8+LsAbvhjs{}!HVZQ-I353 zrnfdUK@LiC@kx$3qQOMj&?wJrcW9%KBim!uii{+ZZsJ1~>+h%ahtND`w#ND(Frha` zsKx}S@A4%`zfkDb3$kV@EeV9ej9d^ou#T+L`;(s}Cj%PQyDC{f&*^Gx@(Xiytz(9ZbX)J{PPu2Oc*vu4; zCor?XeZ$_qfd8oj-xGlg{);a>A{&Y4zfAm3THuRGuNL4R(H|tS|82>C_43|#(3f}Z z8<{iD(f=voBo1f+RP@j0K_U3>Hum=QCJcW;vRpTDBggswQ_t6QEC`hiDfI4iBINqj z6aQ_3Bq8_|7-&S0^iS~rW$FjEBPQT}xD0&u|1tE<->GnpA#Tn&74UWa5SJIL7BLL6 zGWpH|0HC=>D#}YD!r{VwB_aNh5>x()h5i#@puXmJ0xYN%5Zm{Gm*K z^_7$GKjXCra9_tNUT@G%z`?)aGBZJf3_Xw>lLS@ zXyk!KcY2l)_c$*J;2hZ|w&{u=nA6y5RUgX;$FrC+ZEK`b?{N81%)sHy7*$EPmF@>= z`curv6z>jW^GQFhet)BfMjJywUb8S@D2rh0yEo2n;TZJpXxVxv!8SpbX{~zl3=t(v=Mhf!aS=8K z3P?DLf?Vi+TG2`tTE7}a3Pq@!qTE}AitH7iAC#=($EQT`Tw|pB%9aAR==mV=!lA(k z%er2c*q@e}xrI5IQwn)GN$;I}C_f;z5=~X2 z|ISa&ZDz+)%HrV8jneJrE7`XvU4Wfg5qcGab(;*o<#`Aa zpegkSvz3phB87jhXQMD-`JR>*nV_*(!h4x!GW{kLr9y_I?$&n;kcq%nw1wyct87o5 z<)~t8jMbk1HOYkEDszBUpBP%gnlJd+V^Q4HVzB9XnSE!sPTS_AWPSk0!pB2XRAgek zF*JjJDcdhePzj;XP+?y(QP z?>5bR<0XzNAPNQrH)gIy_D>0xyU>#4fT5DOqG3Rf({29S>+Upd0L#sp*FdH__w|dF znFXW*kop#VWKmU-tWqGMr7Kb8RXHGRkam$);*=CI_~=SVK!MX#5 zNS*gk-oN}3@o?VuV|1Ri!FlK3TBd;aM`CB#oz0)kxy~rVVV+kNrn^;=XlK<|YOMU4 zM8m&og7Gzp77< zEldBhGIElF6~4UUKjVU(pHhlS3_5=!>LX#*s)&t9<{9;6PMMFIxtvh2$1o(o$_K%P zRipk6_=pwUq2>6-dj>nBF07pweucd{Djh5a67z#M|!8#V?IyV9+8rW_KzJ@BwAN4$&F(l!UWQKZh{J{Z59VSjFB^IkY>m6_Z-N(JF@tVv|JA*1%X-V&_b^k{{&#T^= zvGbOThm$9?Y`hEZtN3gWa0l!^5CDh3=hbWK5*{kam(9Z zW@-`xi8BtGG7oX*Hok{PbH*9*2qY}pfa)Jup~L?W@#SsvI`NI4%9u1vy}Ts4A00j! z9(`VJZx(tyHDNfgxj6aWnrbxbtrfZIzo=U#98Ti7zTr66T5tGB0hM6ByyAk2#C?NG z?Ao(;je;3eK$y&@mbsu4x&Vi7yA=4!^2&c@d4fs4bT*#!xUXi?PT{&P7xk8HY!`U$ z#O`PZ<~>JEofAWC7eK2u%JI%!)ZdE%)!>-~Fktm#`7?EzKjyF>xv7KH@8}gO8e*%_ zU?!*wOLUl2G^mq=fVxV)Vi-H9lY7!BMmgHyU5+_tM%BUgEmxwKE0I&B^~*6#X~&!$2M2485rlm#fIM zUiXs|0d<~VLO~}fyN9pJHdI$VYA{>LyekT*Ed^x2-a0M@R)YXhRJ1q&hsTHv=V8#Q zH5Zj@>U#9g!b`$vN1gT@AYvaAe7|R@2)ErZ60MO;m&O%a{q~O46smAFOUhj$sDg6# zud(33NoaO)5wNVu-Jm?vRg{}e1a9(j#*kAAYGIf1)K;6#yas<#ddy2KR$rFXCpP#T-hm$6lLRN0pz(G`W z=BnfNoLLGej3Mg^&NgMSnZxtoIZq1yTY(%tKO4G;D4+=Ugl^>NE@%c75i;nC1AKxF zGgBwCPC`K%_4J|SfU-#+YB$p&(gZDuB@lyP-~q21k=?`76n)t0$MZ!I^!^?VebmhP z%!?aK_<}t-X0uHxPzHu3pF1b{<}MlYOGiM*zpf;x7wa)zRi?vUmIWSOQx5mkoCRmp zyuLl9x}C{Me4ni49M7h7;nPKo^ck|vYCL~Ci%-rHgAb(>l^s`{tH)bBG)@T8gk@%n-D^RcqDoc3~k%W4EjWG4SXn7=T!~0pfe# zH8G4Fsqr_ixqEb#;xXzZ{#F4$Ys0ulS5;S7?Co96)!zh(+a(ODmfSEWo1a^asuPIY z70iY*DNS)rWY?WM-)LPK8wCmVyqz1o)m5AfTGT!BOmPNpoU{iGBV}|APwFg67dJ_o zH>8;XU4R#o#UVtl48m&R|5WA><3_Z$HgZpeOoEUgQAF=hgl(LVh5HV_xBYe^>IGnc zss`S@?w3E(YI)x}YCg;49mn>(eeO?@$qrXJ>n`9JrYjr}cXbUVs<*rlafe^f>AA#f z@I>I!MW189wLtv5WT@O zsx|-nXL10V58u1~lM6o^9P(50VE^~7!|0~o7du!;Y!rn&bx2sRT5wm;duTR~3(4P3 z+>ot)^~cyQ&hghnrkw~MFiB0VVH_LdW?JXqLn9VOI-`9d~g3;VzuFsZ1UmE}r$+(PtN` ze!0qckt;rE=5QKypgU5jS^%Aiq?)*|?UsEk6!(`{6gxC233B={4^KnDI2u2(c0nUb z=oYDTkP+AGY@S%mufUG(q*i3E`$e4R8X^G-v~|$a*GRQl5`6*y5t}nzQgl|g=D{k9!ZC+O z>gQlkL}_kN6qdESA^U72-{%kf*!)Ft1s0x-JRxLI<7dDesG-HKIm-^$PprYO-Sl8w zHe=)XedxuN7loTxZ;s`_<^HGRhkIcyW6PrOHd9>e>B{B-;_{6(fD1YA$3N{YOehcA zeTt%ZX!=nCTGKe-9^tgHYn<@nP6x34DO83`tx(+S*r z{hhRG8P26c2Sg}@c-pJM+se#BQPcTQz3zF+L80DHqURF(ezqszdLBrfh-f%U1~7%s2nJNA8qX?|(x+FUiN zhuxN)`TDuz+Cqydt@y>t=`mDnRkt01ZiB4GUY~*>F|ywYaD|y|d4_?B_j8m^a_>;n z^P^9rI}H5WmRG>;m&eF!@6MYBTz4l6!|k_De8h7ojq(7h&-=WPpYC+91b9C|bD`{! z)dC(2zvWbqb1|j#)nRD!b2IQPnW=@Cw}j9HQZ3n#4lVFnw}v(F8-4JHuPK+Cae$rM z4dN9j@5V{__VT~bsWw69F`0GMn)KKIAh6<2&7ukZjkpBKY|G~>(*JN!pc3fFO3Tf) z$2rvNnffq~_^S*{v$zgeIAqGmLG1Ay~ zc!u}L+pV&iFl0byUXypL2)7Z{pmLS9<=qF*j&f_Q&C}YwDZt4TopxNp!Q^i5jHEYi zSMRJ}wc6@!MHjW-)^}HUd04lqf82Qk3I+vl2L(qJj3ZZ9R~RfdJ)x;uO|HEwIjf->>k)WOs7uoZvzaBjcYazlJRllM>1UXg9VDzShhF;Ec^`Q7 zt!o4=TlV@VOyu%k-1l2=k}uEB_W2x-S{TH;6tUh+6bzvDQBffT<8l7rynst=oxO%` z$Qf+;{D?->)&@70yV-vAWMdI`WJpaU^x3lTXfg&BU?eXFdOEom6l)ldLlIdnnDHY! zhBOzPi$B#@OTBn^Ty49EnNw1dZ>*B6aBnW)MC1N6Th(5UwiUs<`=f{at0I3{9@Tur zyRv!0spw6K853@@K2qV1bU3_lP$Le7{GBa}P7EmMo`z>}#fS8<_=x>!c zqK7kgAYY`MTH-ZXzICnG@8|h21y5l{!`VRvz0T$?%Fd8t5_iI-dr#eK*W$5O@#;RM zbLTqraLPJJkr8ms&1OFx{hczgpFjU_r@^ZS>9z;mxq>LlvjtGMP@AHFIv811;IW!u zEXIyDr7SZ9ygC#5Mm`1f;ChoRd~Ls40DZd~+})blx65-teaFgkb z#(Ei4ad{&%c)1-t^O$OExPpNpM7iZ3#>0%1AH4x^e8%i|Cw}h-gH0o)a;MZs!AS+k8wyT3c+TnNT0v_`g+_EuvKB@0M|PD_tJo(VQ|>lIDhN8_RUiTq zv!i#jp@X%7^|^a#7UOf<$IpW z6uy){lc}iaq0ouQJhvdnot~a}Nw-dBK=ikp$9m^ZCJc}>OoujwXU_sQ)^C7~;LGJ@ z4aa|uK&!TcXx|F^yEJ!HPZHUPeuw(l7+JfniaR{r_xNnCq`l}Tf(d~L;M>j|7XK{@ zY9}h^BuncP6{_k6+$I)l%-_AQaf}I`anWkHElSDx2FuD#(E6wuq@4-)>7ToC+)u`k zqPZ*vVr8?$5qWpQKZ(mpOV^jk?RC+-Fe9pOi5!2oB8xLdx4%d86oFcVI0IH}Bcu0@ zU5R=q2@K6cAij!hl1Noa0b}1poVG_ZSKISKMSgkbMr-l`8H1=QE??I*Z07FcNbqdn zJ@@RX(J+g;xjs){PxssJyPV%ZBxN-W(xNI^rgNU2yL;Jp3=^;^ag^a(a(Lc*8$}kP zh56-;AdTqkOkjDRIxK*84(?21M0dsGxPERXt?o~iK6NM(z2KX(+#Z%&lDANxWQEl@>_+w1;p|;G`VVU1MCj2e$GfR@2ZwEaOQnZ?w1W@(= zkk>zxpq1H=hvD1WR!P~X$BW^z(`HYT1Re9BxLI`)Kiu&4h7k2oK05gv$Dxi-PDG?8 z5)#>Vmr|@!5%sDWuR2Y`oQ7(u$|O!?#NRYOuApDZ&yrj~df=nle3yv$7B#{#-GJky z64fBw?JB>h-F{L5_7J}kb<;^H+(ESu;dbWr?M%*jjEBbo7e297ULNvju3}6$<*~#3 zgR)Is8<-lJQJ(_K3jg6W2RJZ6I%+a5D47D*%)3AJr338*{KpX%=phd6_mUm2-ww_^ zD!{bcKV*|!8(T6wNGj3&D!f_dR@WU7;ZAJ~)n`>z0qU=bvZ-71W@6G8?X+ZB zoK;EQ_C5N+8RHBid3-+=Z>cSA%}&DzpHlXk>26gVvY(U zb?049$qdv&LL>{pYELY(dK3-E+m)e|%p03z8~PYVCv~dlCeFti$KUQ+eRebWp&+|Q zP`Tla++E#eB-^Rq`E%x$)Zl%n9O*(Vhk{smc_6GKDs6h{7EDS-hHfkcB9M)m0~AuZ zLk!^9Bow=eOR3GIfw}TPxlv@$ybQ*`B21r0=n*z+$rLS&6`Q>9X1A}NMewhfxF6oQ z%<0_8zqXS^m4mf;)l^NmM(g7t4e5#ZBovo zm6Fj@YM;Tf1Y;DBFE2~V6cJ7#FV^JnLHq|RWdl>>S^`x7I7WiYz6L~$?PfxS{O-)) zvH9tApAzXB)^gnt1(|u-S(k-i=J>8{b)?CVa|FH5#t5%Wzh@mC`n;tYlK$1Vj-?v( z&aQRJl=L3v%Fu*s&9;fxb+D7z92;b-u(!M#ye&PkVA}C=!4+no3A-h1Dl=zuYt7l` zt>*NQ3fS-0bp5#&5-~!sn9eL(SqaC+UFh7g5I)u2O47Glc3}93FfqjR$SPGyJ+I#p zqKh2RQopqlH7AnUAm$7z<;S7XIf6>9y|%GtH5Jt+Yf59PiVaS;7KVzuN!ZMU2|iRqe-V9p{a z$V4Tdt^9_6bfAP1j~r<9tQq<04oNxYFd0qu`f~zNPct4IGyJ+EP zZcy#+?#^{u=lsg$%72Qnd{lv)Ao|B4Wn?Rr+40&GV<5F4L&M9^#{INl+VrTvUSRaG zmQEsC)sHGsF<3B3id*s3TYEq)r(iCifGX0yNrG%ZYH(yQ?9l2$coYy`>O@iJd_$0Y zW8(<9iG6h0G!=Nfr{Po(FChr}XvG<*$0ddY4{R-6g`q!$|E_LlPLsbut}8=XE?aag zF1wDtPlmis<+6ek%Fgj`9Q<*UY!@xb`RT~X)9&@B>Cr^QKaM6DU%jfc)dmAfN=nnM zKvCzNyNFIsmf-RZYL`O=cx8wI5@lE%HKv$j+)*sd;%W|x7+*Y!wDP2|(8|3VZmo{; zADKG1#pyZ8V7n!P2lelP;ep>bpXx#y%9mO@8nN-!Y-h4s`jmJ*tyZ4T4s zx&q&QSjpMh!FMGDj%xA`{Vgl0&nFROODl2L&q7DFWbBas{dxOV4pe>W1)8w+AjAu1 zM$bY^%sDz?QZDy?5gtL}yOH)WXSbUjT=2TeHut>LpK%K?5G}7V>9p9U>ez46D!jkD zx80`#xjo+4P-L9v*=_bB9r&5L(kVyG8|LQqspLwZN*ZqGx~+xGsU&{?Df)2}Q&C*y zD1S0za#4x3;=dDuaA$66>5A_H*mXY9{o$IJ;k2#VJrs%D59x2_HdSKl(9PuI zIVk9(uuE?dp%=wchahTvCzwPj$sf(ShS3ZrK9-&pz(o0m%?44V|^#Qq7kF6!@P8UCr?9y|uQRUctKjGYlQEh%%CwxQ&NWwsN>= zoTZrax6bDP7Kq<_rkFkR*=Ko)w;b`?E(jImf5IlU!G>q?FT96_2F1s?uJ1sElsC&j z743O0A~kn6v7?9@7RsFQwSXYUJrIb{0dA`rXyy14A6VfKFKZ{?-1Cr%*i8O&%Ox*c z1hMVoKYa@`m*aKoNfB!;u4;4-e{Y8v5 zK_4+w&$CWftKI!%CGr=FCE~5lp4f{j`*t)Mi#S=3L{<+)!O3e7Z(>1J+*BsKimSZ5 zt(<&aKvp^>J_UHJJwbowQA%e{j@&mp3$!5Kj2)ANOx5Qe^VHg)o1FY??-CCh{(`frrT%`K*LOlJ4X0&2RiI@diP9}8qL_H=c!WOKOv z{yM{T@j=1}kvt}*diL{C%%rm_vBCV6iKsi8HVS@nZA6k{F*X+erG=sgEHviHD^qB@_9M8C`fsHRiR!OGz=`?%XmA4tZIUlidZYT8m< z)3Bo;PMdQD!~R_}WMPz8h*Xee2lDNk`10YBe&;i@+qE_ribi@{{-a(ZJRPve1qthw zH02`t1nzr7XwDzgoY3)oqr%H{_|yTgAPN=huvKRQT>_<-*QfM+SqjFS`Q(&60Q2+< zUAmoE)(L$ioV}P;ok>{og!mGYTzKEs)=EZr$W6gs{iks-=YS^~0E}h3RXd@7aOo4NO9*q2i z=PVPKhNGq3Li*x|@aJ2Mfr(D^FGnJX&ehD*;@?$z?&o6qpVf9$8UUZ8uq5UHr?IbCDI+zUDDFA=?-b7 zK@kO{L_k8irBPIn76g$>mz`W^q@_j|wkAJ6fu7vedeIcLt9HM3@|bM1A` zd}91uvSM^&m!`H2!w7n)J=Z7BJz*jdpAwROGkSo4j5DoL919-To>9lwl68kXAT);p-TqRZs>t=igMj}N~x z`=S*rdOj&z+BX-`ZSAng?>{Z>H4Eyw$3z&+%qdSxrc9;r`lO7~oxRJ2V}m|$QRZ2T zORP)a3tXw(d$?<4_$?E8g)bj^y-od@tecB*bvUJk5L*drd9p{fIT00p{6%~iI;8Uy z<2@pR((BBy#L86k4j(OR4+Tw)>E!S%rL5|%c@xbNl7dnxD!=haT?aPYQ7h4~kXFSs zFf9JtdEpW_tm>e$h>Kdc5su=V5_oQ&bxG2o|Y>luU&u zcu_!ys3t;!FHTP{s{70KvPXEk6<*OtYQ!j(FRPqI<9Y=Y^mo#BKxE|oC0O{67zKXy zRX=;M7(`~^Dk1bx$*Y^$Ogp;TN8De$;K*!DNDn%43~ybe*ZST-emIm~i)>7ihYSO!YzSfi6{BE%NYrS zYkMV9UPk!<`{>d6A@+O}ruTw4TDmYz+SZ0H z*0~fSPy5N+z+4j6sk^o>wP#&5@7pyF?>yStu(c{+(SsH=rnz8{5pbk46cQ+C3RjQ_ zHum; zDbakH`Qu({jYG~U3LPm41jez0wZOo*#FpTs=EmPO7BHn@s7okartZ@aTexHc28h;5 z>k%$NsOscV4$2u(CHQT1dM){;9iD&Gk*$6Bxae`-vyxz|l8CRRo8O#E#R$)`hLx!p zLbKqf<(i0sR9(%l&(@I7o*E&e@U(I_H=|+}Pm>}bU;P$>g1-~8n!DXW?fqpNt4Bd=(%n zA+gvmKQPDsaEWl7#M|{1(y~S36*Mit07D~q$@lrnFT3^USYh`p4t@Qduv?hjJ03r2 ztudo&%sPt@GK{yr_*j~?%okzMePJ!j=f8K{@Oe|=oBOBxZ@xJ-yV&ju;}`n>rfx>Q zD;63wwRSy9s_$5ZONsFS{2j{gz@L;dfEZ{0gS!aSHe1%LZoAl)bx>Ax9$6|FGo60n${ z#czZ3v-a}wMWeR*h+Us8!F}n}-0T|=raI*O)iEqYTa{mCB7OJU8lfdwNnv3=f|U zFmW!VkqFVBOtmM+bN#X%FVX{C#_)|FTn|M$vtG!(Lp3-ntm*;3QAgR^j(JL495HEg z(s{Sr5LUjuIq{3*(c?)wa8r4l$9-Q#!MnI5oSwQt58%Om9d;witG*`!4hkqO@mG1^g>-)gGF5EW>;gjN%XSl*Kh zi`05^M7f+LKj`2*i5CnH;Ag<-t27q&?6RW8F}Qvo+ibR`X$&pY+D)GSl%+W(NK(W7 z7`5jEr@q7TV_CDeRo1ex0->0K$3t}=I6t4c8~0D8o{@TkTd)mU^bO0NwD*KXr_|Qq zUS-vf55Jc{cHMC7@9|Z+J*n(aOV1!@mg;?O?HneFsUGso*HnJ&oh-kE@8&Od?Fy79 zdwZp}Y>eo?yhHN@;PY7K%f>seHXu=C0eIr<`W^=T3YwhBz1xWuc$dEyrJg?THT-%i zjaKhJz?9=jF}wQgMWweaJoO+{wn3}=%=v9ib&AaG)Eo8rIa%IAoNaJC`6IlM`TWa+ z4$QabKcpPIzawv?S5-`_(E=m)g$VJCk-v}Q)LCp2yxgkTWvZq17f%+y%raN{wJf6T z>FD>e_3?c)Q-`Js+qrxkXbzB%BFWgi=ck(5y3EnUYb<9QllN35*u(5G*wYKOM956^y?=o>q8(}i z^V7>udtz@?PeWUh^`6XuIn9KadfQi;_!3e@Le>bRqpW729DgT?{)M`diUI`whC+!39_-ZK7ZefYP)*o_;QfZPdjhQgyO^P$bBT!SM*hG*Q4ng{LQ zD&Tg3d+c~kvkr}bEm7A^gF}qB=(>~6*0Zg!+@Jbe131^ zO9MX_g0gQdZy5S}p0me)nK`;oI@V3gH^{`Z`r96IQU57Z8=Jdp`;_|-6HqD8r;H%Q z@%|7~n)M90X@3!e&v^62>&lmzW@yyLo7hUt;O>xj6!d3E^|u4JTr=*-ZGIG&Eiz}S z6fYWbKok6RSY@b@Dr?p8C--x-Rl#{|hPrSi z9>6=d$&dav;(jR&CDqyHatzPP)~vO@Hv7R2lOB}4n%H@$EZmgXM%a)&v5Xi`aE2IR zo4j#(;&5L||9xtW7(Z>ff4s11os{J9xhpOoaTOg#3_pJ*`^*#Oc1nyODV5`<`L(&y zA*11;mc^6Sn?s$gXL3MFN_p-tpl=)CvEkL+_-?U-c&_7aU>-kdpW`4?^~`z3+1J#O zn-51<4;sR+XaC6$13}W(NL?<`E0Aq#cn9Nsw9o!?^(AvCMWhwB^O&?P)t4bHZ(W6v zgs`Ye*iPQtamx7CY6d`@m?UT#kwA@a4$&kKSgJ64!xX$==PrfoQ#hAF! zR5%pwd=&fKr6=N!h`PF9w?+sn7bLp2rat>iItEQ{mF@_6hKsrp#oE_lSw(7_NAOoc zI7(2K)M@k}H1wC@)@32WV}+iTx(zNgnie))6iUWp2Ys;z(N1qy2fz2~#h<806cVB{ zB0VF;oD`h}vQ7Hey|n0T{8X%kvkQK4*(@6NpT#+fMzHG*jck<*xY>-=qqAd?;xKx} z+1+immh!LMFr6ziF*XY(%x}N{g&|6+cUCUGRgV*=lv@{PnsUBLK7ibwH%MHCAs6UA z)X><&mp&GF4-uLDFc&wc;lw@mciJ)7Q*8JU%W#Q|HSZa|Ohslb?=c*y0Y~ z2G1d1z4Ck1N~eu#uX)^AhBMwjic-T1t1wNvDv~#s>hMmmQa9IY!E}!*E5_*?&tWCB zwW|Dz{V2II2~uaom?r;3^^oZ9Q!H#*s^t`K6Q;0drm4J<3lu4r^D8o~Pt+^E{Lp@N zS#(wjB_7C-iqQ5xkfX;;FET7$jcFe(eeAZeeMtNz3CD)fC`&0JeHG_!?U!=30~?Yo zPOOSgiL{)qaJ`8a>=5o~A>M59N+uSP^lY#zPv-O_!8E?i11hMv;?7@|mSW>*_tE-(Nw@B9=Q!%E4Qx4+RC&twA#6YB>pxP)4$8_u zD+@d|G0D%<5+4|gLeau_w<==d)fYcuUfeG>Jy^>9ZP>ez{N3sskz+r(GyCHnOwT+i zua!KCdex=4fp{h}moZQEj7=(}3hKk6f<9?sQF32}XO+*ChSr=CGFsi)w6wT6Fv^ME zSva<-(-6sIVP&m}RyPnqs(~Q-G&h^?-@hyPC5Yf|D#1jZbuVZaXY&Rl>WEEg81l`XPOR$rhWr@(bN;F1;%%TSZ;=h>lnn zUAF>dXA_tCp(=HY?g|Q-%fax}IQ;!ZyTv1s2a)LSO`7sOyY*#iw3q}4L|+;X)?<8N ze8l}cuB#pU*|7ksm~Vixx!&N14-2EA2eu}7hwUFn#VAlJahzMM>Nsp$J#8aYU-rFj zT|3D>o^Q1tS^{3pGhIzdr+%JkfM4CSzSeLG9m#3P5bV%Y$w(z8l~-!P9@~hoqtxEB zSDw~C;G{prd?Cs%IFl3fitz27Xc^%aW$*ryg^r#o#D~GBjo?pMWcfsNqvJ!eNqGvA zi~F=cOHZz*X={ZPzuL)smyy)`^z{7?H>O^$Z{TeU6S(u%4bStzi%8!5?9X1^2rZ8o z>65E~kBMnzfh%Ek9+8(2Q$hI2rf~<}4mYn@{>P_@@)9|6MZ)9Z+_C*V!Ap;vIoVGY z6$G;H#b=^2JU(`TYSvVVm0`19%c{(OzvOna=kW5pKUcGI5`gnMw$6=(`}M?H=I+jp z#OPG{$7VJ!GKdc6VuY{@*J#4Q<#ffGRIG{B3ig^@od~?Xr84;baEE@v#aY1X5ebXP zelG@(*y0t6D~`e`AG(! zSAv~@1F_4)6P^ayOP!ToDVB534!nHX^YPW?R@<1JR0Iws<ehm9}K1+cs^!ddZl2imD4+YIenN~OHDJ7=n?FM#>v@3wbabDu^n{(m1g<*l+QD2!8hL`MXDIrSSqy!NqkII+~w&=b8v4}`Ln zk*ihmXStpMm8{p{+YDW^KfSuIE3OKsA{1rMndF$Me@kuAyiPa?v5-nIbgVvdNy2G( zQDbm-qu*SuY4l*9E{CB=uET{`_ouQ|a=)6$NRov#e#zrvgj7N}&XN`Fq@$;O{V;b? ziP<507EjAgoK*ACr#*+Ot7=W{^zn@Fuh!y+6<(GSsjO);$vul=A@=8bAA?t)NT2Pe zP-N+h(u!GeofSlE_dYgHwUCsO>STBVE7%iSpfW)nT5nFeYhPiH%DWqR*^^{iw1p{1 zo=I&hVd>59s#!c?llVURv*5{2aH~y`ObjZcn@80)Kaq>eI~zZYbhDH7K^4uFRn~o7 zu8|`qOu{K5yqE}6S$}d??-#;4_FMcPm0Nn0eWwV+*3fJh%Cg%$ZA5-UvuBHkVreKA zY$GZV@01WSO78=Omy|6ACX38Z{exg3>Ca;9H0^LRA5&&O@~=efPz);!_=g04Dk>1q ziQ&YN%Tm~yXGn}#hGn|ul)RD5fuFjH<6z~BQqw<<38`aIW*aXm;AZQpwNtxyyb)hU5XWhR}c0u8;$~0 ze>cRmIgsazn->=LLuKai(BY1*$3F#KA1EWh=UqKrsQYEJDa>VWU!W$MaQ&&ob?m?l zPcS>hFf+zbd%)+V8X_0j4JOmGclQ?^uvJ#|1!4u{((1G1*Y-Y7pF)Y|d%tSt3qLq_ zkC<5Vw0n%sqsQ{=xc-W*$iSkm!3|-(Fm*$J{#%PV(-ji~43A6HCbdxOM zd4y*XN+&&(AReub7buA~N3>N~4e?{=S*m~SWYht#b(=#kV?SzYCnhf0(R(mGL%1v) zZz%1d*YiRCxJ|L8{OQ63MAXJRZE9%39qd;e1yEM$_9X^n)}Rq?a9 zfGh*B_aTCC0YEhx-umWzLr8tc8Z&~~(*H$HSQ}YlL3#ts!zIULFR?R)YVGG<{lf&h zHdxE6m5P&1QCzWXW5FaG{uH;^&$&U==k8MY?w1BhGlRd3W@l11ij?aRheZ$G_>LM#Qxyg14#+#DFh>@p1VO)^3G-LR3*X*cK>Vf?Ak+mf_9 zZE4{PbMXahyeyDpLAY=%>t5`qZ5CabpJe^E!Oh)Iij$L!B#+ z)XWW*Z}~T6k<&lg^83Gh3^bJy`tFpqJ4_dDdb2s|B@w*{HuSV^H;*+njm_BOijMki z3Wn^F8bF<|xW6FvAZU##P{>iB@Ym$au8T!|AuvkFn;K_|jzZ6_Bgy5D%@0l%eBV{2 z`7V^bCGcY)wCw=u>BF>FbKD`hgo^Vf$_3`XnHpG>S09mE=j%l5ThUU<9?#&9Lc0U?N9fvXH*2pfh`;GV3Iv~fS3^Sooi0h&firMc<<+_zw8ExaAZW7-fC&$F09MM?c zj1f0ccBEx%R-lkHszw|h9x=ZeN71oY)An<(nSamsA$jwdZ3Em8@Im`!x!Rd*MVtPQ zIEv@c{N~e8+n&CMlS1I=eKf#I9|O+FX?zME?RV+d`lK$ z!QiYdv!fcl}U4 z_a2$H(-KuVudy1Su6y><#)9m~-TJp>X=Lpo)E~tus|eivTCOz33$_}M6`l%v&BEE^ z;~CKz4R_wuUwk}dFfS27awtfhcd>Fa_F+?}^unDR6VsT$$dn<8p^6YXysk`4vPF1i zjQ|J6VXWKh)iG4lr@d+`jmyBN}LRR^7E&mkzlEnx7pc_Bo zi^OEO;AzDm=Q72Sdn{|+Hr5;X$rKX;-Sf?lz{snHfHBwaJMeC$P-fc{93}<^_!9LE z8~N{)y^OW>D#_RMg(hIi1^)QRhX3Uf>Uu}WmtoY@8Lf&%&g>$kieZ3v(=_Lmd8{(J zO@>s$yD~2OEF$vvNXC4h8A^-0xQC58fOyDecF1b9t67GD_!T-Xe(+(<<_`}#FOoC7 zkfzr@Gsv^{{FO|j0_u-VuEqP!bM>m^6|Ts83JO8f+Fl97sah0lJANGd;1W?YWHLb? zqg3SWvV@|a!a4-s zIaW*s83hin=S#*qI0Q+zhCg%gw)l-IX2GL&SpK~KKqX;Jlsn^n+P1*D zm zJfa^n9Zn6_uPs|;Us0dC`k`ZHCJH?}9v$`w z_9|LDVZ-Qr+TI7dK%H69z*YWK-5X4r0E)54tL-1o?KI5pdcFxL#!hf~zk*&H{Y=RW z?Seh}fm-ic4{eQOWPK-!VIf*Ey8j3{i_iFzA~ovnq3@z`Z!%A5i7;qOu*PGhO7Hcg zKX+{>rEA_<6Z2+_K4Djqwsavg{c3{YjW&MMor07=02H~(7O|fmK&o!0D zu|;Nc?ahYqN+KdL#yKs=BjHp~`_R|rchUh+h9LCopMMc+O=ijWO0ZM|+Lns5%J$3y zYbTVlFx#3W0_s^3WS)>xU>-CeI;niT;uk`u<^T;kvO;cyVaxF7q!>!WHxVkjYs61e z)4xD%dZ?ng@-+Zc26WR3wEV>GAkkl0t3PP+rco0za!mm4HLGvuuBn}hS%L~7WjQpo zf-vWIi`GG?>He*&LkB?{gese~$YEkDq8%I#`KN7aPb>xKI75ta22L(lXF* zz?L1wSLFu9H>%d`zLMqDk0U^v%oA1;?L;w5`a+DT>vbmJ+O2ip+u@#z`17@EQ z0p=Oa+gdhn?LVIh=-7!AN&}g z>}?JFk=M_rJt}^1!8gZ&mEI-grNBwQdbby2I;h?oRWdqdX-YTgbMl3y9*(@i3DdYn zyZ7@?7J|-bX(%!m4=a(jtn^*fi-&{jOR^%YDq~Xw|jXXua zzR*yVW~l9}@%=XyzaiXP`HB}QTSu5j62CYy+b)nlL5lG4p=GSsc09Z@3~&I zoDuoOarCS|+8qpg#IwXS!mtW|nJgz0Mz(@l9aU`q%Y2P8sf9xE^=d?~RO>P~u6Ut* z>to#Ze`hLVfOjUxM7p z^CI6Jo$|D)KS6vL4`0ozV_%~%8KPj-(Gfi?@{hQf|FqT;hGeve=~ATBoRzd zcTUrtYdPyb-|%CdA~|y@ct?2FJ-v8OFOHeayNBu%83wtm8P9{ZjZ&Ck+>V)ioym0@ znmBaFqMJFKx^t~9;M(m`Nl!_{RWX&AP*g1ShS~hv^@gd6<0nLK1$0w7FuXb@_i-tx ziZdfD1kQiX_{~~n=az_=jLs0V`3#rgPNBD=9FTa4y!-o|ql-7!XS9o8>a+wOgV6@3 zQq@p(0p1Di@=uN&X#|`lQ_3jt7nI+6$85x8R~{$-z-jWp#gx25 zY>#4d9+iY1hPiVlGrZYisn)PA&MSpqk|ibffa3^!gBK;ZJ?8l{eXX;iOc{M=c%GwP zBXl+9^OGN079#{B3Z}ni;taK@VEo=TR0|X3ejFG-nnuaL60TiQy4$^c9w{+f!t_i) zD>Xy(Z0%m;sVKhV2DbH@!lWaTpxExyCyoSG$Q_@iX^fK?1>}9k?(sIv$Y|r<= zFARZRv^maJAzBeXp3&ut1$@ufk@YY2SUJKIRTUnglRF|I)3A7uqEoY0L@Vcm@G9_; z^(0`kTuJ=dg!BW7a{l&B?ma(9&FD^xLD?cjAI zWlhKAAyD_&`y*z3GBLv2&-^5*7o&B$wY1+vs9~KoNmPhHnkk4z&X4^Mv-$S3+TZa0 zig6Ac6<1XTHfkbc_O#!1K|gqXtjy%jHyR%T*N=FghSUPgIG9 zAdu|kbsG6E=a*IycYe9$T-hu>s9R!5iLc6ZQoD!?#QKI211dSA67E;!?SC@ zI@_Cn_{NH@>QAwP8*=@KwvW{=%;m1&oyAe?Fbyn|dL1lQJwa2aL1Xs!ljhVFS|2i0 zG4)5c-hbryB2zHSSsJ)}VsM{(jYPgpX+#q*Ct^={Og{X9VwsFv5#6eJOb;!D@bd7H zy3r>LWuaj+>az@bm86PZ<~9j_i;gkFt7f5K3AvK|pOV&H#3RNeG|wO`r=6V|UfTA4 z_V#m6I#cT1o*qS^{T!+P++_6DY#1LgSte2NNStkO(u(-VILwh-F8*g2Msd6GsPnQ> z^MoN6v+14>4_ESAE496+ixmT$QDe;X4ueKzd=?pm+%HL_XxGL{W~Va}wgjmrJf*@ zLfXTR*w2%C)NmQXsKjVKw+3dM;(F%%cq1*U`dIY)6*f)AI__te^HcYto~fyUb8PyM z)P75K8+yH7!O%((=ydIL=M9oLk(gJn$cKOU%UY9La={!^c0ujjn6=WOJ#i1NDbr?> z_7}l)T35k*xBee%ezVE^lbV-H#Mma&F-?h7^F4#DdZ{xBTG|gZJ~2B`%vCiTs7}9} z>z4{krXW(mmHRaEv(%cYzUR|P<(*X1F>z>uPxDbqiW9iSDn?ZNvt!HxrFN{C5j50C#gA*AaOM-y+uzYPJ#IR+K1bwGa}>nlU7dVq6Gtv#?`@h} zRJ_Cc!%BVW-8!6Iq~ifZ;Zf-$^}TNgQHtg9F-^~?%^k8XQBM{*mg3qmm-t?-V>Asg z>v}w((TAv}-j$CjT1+ajHnT7*U~RmUwLSTfCG3tHwA5_IZDq%lawU^l+M0_#T;ib- z8B&eP{z&2?tkOj#j5Wo__Wn~=5{nT+mIYTslLjdtE! zPaEg_TI#0Tj)SLLS`8R<_~AV~T{KU;F+lldelNWA(Mi5RSLsmOj2` z$8DQA-7Hv1aB~+SR^++(w0(#syH9bC%NSl2G9@j0KOrkc)P?@}$##KJEi_RXqX16D zPI~Os8MtryyiwSi^$H^_FaeeQ#_hZ8o88zc0!9fPXEbGQRR5AjEDWBXluuI1)1VLE zp?nn=_t@BVkX)liU)mkSdn+ZAS{FC_(U6)*Hdsr``7CT*6M?>=k4;D0J-_dO%>tyk z#ZCqBn4=PmQqE&gzkf*^bFW{V2 z!#VJPKK19Irmp)BWdq@o+xvQ3{*O9%=KA2H87b)QPqyPEn)I$gi^oCs%2V`I*0ofQa0E9G_9F>=s zgCUAMh73uHLPAUu1whDS$*@Von5d{oNNI?PV~9`*3E9bz02Bgd!Y0+{;E-n|0U?qQ zPC!6NNI<~ON(6vKMUml=k_ZYY39wO7k`WN#;}b;VV-m9w;ewC^Ns2{6Ld-8{MKJ;aAPpt} zL&7otSPW7m9Q`kf#K9tls{=qL>n+E)<#?0?QE=)%_zo@%j~FKz0Akox26(pUWBxWk4FLie9Sj!x7r^@$(5Hamz(`0H3H}2xV6a>Ou;xJ$ zp^(6E!&HY&9`CLkv6$KoK;?Pllu8!f|oQsbb(U zKs0UwJRTeZ85r>ZIPSqwluZx=Kt&{DWKdL86r-e3r6eUKkm5)&6d^u7aPUh;Ng*Y1 zCE~=zL`6h|g#-l!`1z51D7;d9w=+OGN(x6(Qru2j+DJk`TpY=Z;Nj-x;^O3#Qe*=y z6$4)n~_nxi3BLqX%X~7bgX}rK=U}*Sy`AEGXcPu21yMmLIUIx44gtt zbbmMp8#^0F>FLq|zz9i=MMFId0KW9>>_|F-+w$2snVA?E=n%9ZH~hn+03eT60r5BI z-~=fh;@_N^)))W^#BaITtv(Yg6aBxqF&#AnGj%oqq=*~bWn!kg<=mWH|Kar12x^fn z0Fa04SzKBFN|@RQ~AG{f93Mk9`&u0o3DkT2Pgm4%E42N`LFpWdOj7w6urz^0ydCNBtKDd+4vK!LBo;W}&8`5n{eA z7)eiYdpd>xg>QR~2c)#Tw={~L>X!an8Kl-6AY@|JK+w@e)06!lv={)~Bp4VNnLy1L zde}eMCOA%g>5vF09bGIv=Dz@v4xBm4lMCQVaqEY$QE1D_=A{gfIFShcOe9KhB2j_{8d=5IqT1M4TO+ODmKGNG z?wOgIni%V9sz(7)R^*nqNoi)L#zqGEdOA8UT8nAOSsym8I1!Huo_yaM95= zFu1FJ=Z>1HsLtxm%f-FSkWy9 z%eUj_5)kGt1b}Q6OGBif!L5BVQquqC_WWFY+$!7P`Uf^p`!D+>rEafj0{pl7_FRHW zcAvq80c@XufZ`v0S;7DC#qo(9BtW((1*-E42pZj%uke>XA75cC;CzzDd)sy3b?Hyv z8UCfq#}Ag>kemC+Q;QcY`9ECzZ_ZZ$05)90+}u3!!hfp^-Ja4r|KhiOBMoBks(V|p zAX13>mW%z1gXO!4gIG|=;I{H8A&P%se!eFF;HLx{CJ0uI1S#wv^lJ=&9{#62NWo|! zoPUs50JDH!SVTZTNH9hSehX9urEfb!SRjfIOXAiNNf}v@7$MAC#-}H(i4;T?`LjG= zivHC|k!T?pKS=R;g;c?DCWsV>;>Q#K&#a)3uvD}Vgf|L6Q+E;&5<&{b3SiuxNg-iL zq!5Y#FAum>F(lB(Gk`OUG9K^{zwZu#pkdwKzTF;B6cki6G&FSZKtn@CMS(*9O8@I$ zC={gV7?@aC*w|QDm>B42|Hwm1|L^nv zb^H>56!Z^C#th%y9GP;R^yGR8Uk>R#j8K3m$(KvfE`$UY`C|`_J*$>;)(9 z?cDvx)CD0Jn_B<^!L0zisa`WTM zvgf_KA77KWz_Fw-N2@|m~ zNYOP9qv$b`2$XM7^zN3+UHQ9ee7+xe@P+QJ(D~&4Ps~FPr>{#A&XX%e5<>3i3djzH zrWaorEg#DZynIW_u=}cEU2mRRUa)r!xkh~KKxn>3hWo{o3U*OH%$Vp99I^O@1)-$jzP{U_nblB zbVyRP@V{f8X@TYta^$mgQ!rp$9HQb&z4ppUGf-r~CROc!Oyy)l_W2<4=IPg;*C7;g zbkeCc#mlxNBgDta><>AH&{GT8RFf>%1RQV{7x3%+?KROG#f9aw^j=4ODV3;3yI%3^ z&*N+GISF9lvam0IF|UZna`^m%t*lMM`M07%83#s)Qy7WiR=cviFFh3h`Bz8NS2ny> zk-sE5+uYi-+TEvQExzv%J6tXdjuH(_%9Uc5K zX0wWlvL&{_UWjKDpDp=Acs}WUg>=HqJ4Ldg2$O2v{>f#z)z-@4T*gQDI&PH0u5P4) zHgfYx#@~op_rE;&S+V!~K~649ZuwCVigx;!gil6ZyT~al=1mH9<|}FLj0N!PzKmVu z3vA81xGxS}VpOCDyRN^eiTm!yIw|bU4vx{~<1J5aQaBWE#t#Z&ET+mYIjucxzN-}b zv68_~xkoR(GOOyt-F-IXH75R}kH1d7_G}Rr>xt1)B0ePLQJ@l}^y$RaG8$^zD}Ph2 zNySO?F4f3R9ON#N4OGxM-ZXVt<>2TEvK>NpGL>xS5Xec&#>G+1J?~F6XnQA<`zS~~ zy6b8Br|dcn5g`oB1XCN-dE;k?BNf5yj)UAV3(APT(F|5|kK%O(y3kc`JAF zhWR`E%U*Wl@zt8!l0{rzNBH|ME32JrO`4f@HW0G$1@wJ=)8N3sPk8u5Jd;0@QUC>K z#HGg33MYH~#DgWPKwpM5L+&+N=-ZF+W@ok|t>G;&6Vpt?#KqBrfjGR0=Njd|ZX_5L zzb7Oi9ft*aGAUbQw|E})oK*w2csDD?Ojgg!QV`BJ9H*M7-*22rps{NTQJA@a|$ z%!;T?jjvy0t!zxZL-#y?>g?%Pk7jkjvkvOO~okdci*$%;WDW zLsRtBY5Hq}GG0$?u&{RO8H^j6aEG3fkr)hZG>OZ*jX5Yio`|i}(u&SbOTWMQqhVw1 z;-lzcxVnv)c0FM^L3V8AGquQKxsV=gyXe?CNde_zh_I1O}miWXViXPd*i2G`2}_(c6~ zeWEBu82|B_KcoQA8-T)S#$lNX38$5B!bEaR~_E008L~%eI27A-PjC(61|HybGpQ~ULpiBbF zl0bIA=i5A#0025XVUoZ|>oYFUPX_WRI7}Q+#Kob2|1F}bf?^CD9RT3Oa6cq~A`Zig zx)rI3;hp9ipnwJ^AcDg)fD8c1jm5>!$;kn_nplvaM8?I<2|9ZiL5~eR z0Dz7mgZS8(CV)-@?3uxLOdAzeujEwwNA4x$5>T8mdFp`mx zgZdyQ(*xAW$;go87`HM5MHuMCRVJgNAg2IjHUBR%V93I1lI|0|0qh zN!xi~W(GJ^Vd7#105K5(USmLqK@oV(!3-MA%gw>63xMB?_m4<3fifrPpaW%g?$t&{ zE>PwHWdooraTU;EWCqK>^t8SJ5H}rs`i-{AbW!<%uKgeBx}}i$m4B6Yo4ZG? z0ezPknX#H-6}kC$J%36GN70SM{6A{%C9Bqf$VSVBTtD3VhgE0T^4GNgG$#!0UYRWP z0_$eyOzq`A%#4jRDl7vY0dGjB0?b3Z{meTNb^pM+49!%02U|_)RYB?+))sAtX%Bd= zxrlMY7A>LnWpWAD_7vp!Kf`>&uuNqBbjRO~<$Nt~>*rcw!8tGJq=}pnf0;5QlAhG7 zkr?UHpWumN1HagwUJsLrszLm-H3!w`KSjxt?hXbjyAyP!UTTDeFS4T1U0@>_#sCzm z{CdB(tTs2CEq&~uCV;o-Ex5?p(fxCGxxI0>Yhki3csdO$A3jS?%# zL?m-Ou`_T%g!1az>-bVPG>U=V_bdg1|4Iy}>A9ou7a6osJvMKp)1}bl%cd;KD;k;& zQ5cIk`ri7aWE>>y{QJ(mHum8iH-{_Q>$*OG_DDEU^Sz)Q>k6)p^{3EHE1{5giQOV| zLMY|zxhcV%TY=a_5Fw3-?A`H!ZHk6<)~rYeR5QM{-(=Qwr*)`j%at$bYHeyyOV#Rv zR?q291*%V0t%l&~m|=wV_&@1t>6+s|y<#Cc-RvL!wj(dq^7^$tt4W!oCM4jsRRwkP zXI{L^>DE@r!Q_CXO6KR!ny-L)f!{ykT&di0X$LEZ-#mXPcp5XFV&}ar@S3Mxt$tNCiwla9)?ygcJ?HE(~m$|gBjk|l}1b25QxVr>*cbCRp5m0>$<&qKQ(5gnZ>klFCuh^?OIa#i~+jZ zhuB+YPRRhbHw=dBC~KpYsF=ffP-3HoOl#J*I-m%vxyf2_373A0L>%o6ivny!4ZbW1 zuZm_bR~?D-hY3_RkM<|ffqWe4ZV8Hy>5(>^Zf6S`1*1>E^bkA@&yog*AE$1zbX2ky zG$3QdT!E*22e??4a(lg;MK8 zZ8D&kt?yDxcm!?y1Vkd|{KR3&o-ZExSvb?N{Osf^$MbuRaT#`)D?6fU^~BWrQB3Eb z@2b)jXI7DVO6<9I5F|n#CgqDI1yU4p_+s5>a=3Tbkp8+sfj9@DP>~h)bwGPdE?EWPWaZJXghq$gNXBP}*?(?F>Qs?` ztcc3SAtR^SDXDW2Vcq|m{6b`)*W@$vL9wT;xZUV8{B%QT?nN(iT4Ngus z4~tJzvy`prY^RnfV}2xzDD!y>E0wy~aLSajMtL9@*uwD{KK14Yj7w=-Q@J>FG!>np zXGT~Mk>wr*E^0*o0{DTZe6?-0oFF7q`aFSTy(1;Ixd=;OCH-Ia_T;9|CeJ#rD(~AD zL>)o_GN#JYFj;fGNjy}vC30KFm7Vj-P-K&Bzaf->#v1Tnja2E{3{&wh?AWN77tL>4 zjD6Hi3`JpvusYLzEJWoqWM-CTmHCO7x~BIyS9 z@a{ywv&7)wX#n_%xacNKVK+5Qwj2ECfyDz}z~Aq%oz=+mG`kTdpJGue>lbb;50@Ip zgy7JfiQ?U<81tZfD5!-6B;t8T$8EC1HnS#u>Zoq3yw}m*ErhuuUDu~GzsX=viRp^MW7v2o309lg(h|>oTyT(8f2XvxyH`!a=8d4 zV)+1`Y|EZ5xW0-bo*1ADc@?K#c5(g23spEu%HW`A&iEP7^XF}PFm3i`JUv;+kc$P} z+f$xmvfVceiw7V1l(bj$4}J09^oTu!zXA{oZO%DmZ1GLy>9X%%Q^O0V4C9ReF!t4fZrb{w!eA`-4SFOMb)#Yh58qzL*s;NkR8H3SRzcEhvJ7h0&}{j~;*^a0H+i|a!8 z=x>aZ{UL*8rq)+X{)2Jro4uNR8VW$P;5Vf4HXZ4DRjr8tqtY52hU=w2E*+6$emJEW z+a}u~r%Xi_x+^WJsJ}ZhA&d@Oe{;)eyM|q)Zlo!Wso1i=H%~7$9&}$>%GAtu?&I6cSyh989Gv1c3EVCRGZrzDW*6zY&s0w;VXzH1L zh2|0!RO;`SG-K`N%qgvCwR{?lXy2Q^CivJ%uYUy%eRH+wyGk!zURRb4H;))SK7Lc7 z(V43FTa}bdAA@Wwp5>Xh<${-ZK+$Y#hP;N@|1N1Gc!i0oG_Z+g2GceK!2~mVEdFU| zlKx32_>qbNRoB3v%1-3KMC%j1f1#EKgF?#=G2=q2UV)3aGRNnXB$c6}Is_)BrPLoSI`_-dGWj(-XZ@MW+eE)dp+Nx;&;c{{NKiDcx zq~F!T$hWYE!(NPE`8g4e8Pn7>LLde6;@{9$U7c)5-UG}ECD=E$ky0D*9oc6sCm4{3 z@ceUUh-^rT{En0YASDhi5Vw!GZ#IbHYm&)W1x((T=xtgLGm4Tb`;Uh+CLVf3bGTS-7q7=nV%>O6wJ}T{Bxxap|Jv1b*V}k1kQi9wbz%H8J6w?3sRLXA>f4|1yCKy@e71X(4{F>P()@k1bGi z^x3pTd2=`>0~3HxTgDCC7m!CI9^`KA4p8-S_~nsHOP z!?i6vlC6COfWuWV*Sr9h;Xp~xE&;~TQh|g{KKL#w+hHww61iTXvv@dR%xizPU}w~2 z-EH@b889DuY65CUOtcE?oJ7JUU4-6#IP`;DCxCFD)DpTLPjTY$J}uZ(D@-Kznf$KH z0IW=`0tdtXMzrnCj%Z>Zq7CcQecqjn2!MN^_epj&EL(uStjrsHy%i2xq$HbsK5c;g zZlqsydC4Aq-oP=eEoM-e)+RXLWEC$;Cc1*MQA<}0ZR+PqDVf(947S44kqU!t(97r_ zSxI`mw_lO>xm^A3EcsIvEIRfD1q2n1_&wW)YzAphVinkGmNQCsy3_tD(|ya-i6}jA zc4sB9x~%B$+bj|iw*s4-6LtcF;Z2=$fZWP)nZ`1upn1aV#Eqs#!!C7M8l4H#z$Mmz zd2^P#GP?Bj^F9n3qTy-HK`oKG#46NiDFX4aJ=e%FE@%1N!p1~72D^*&2H5K2j;bC` z?!`&$EOK%ywqSj@+dTQ+-z&X*`3GBNTX{Q~HOZM;S?sNP$Ksd$l0mKCmx8*}>bDKO z1Jvm#x75R53O-uBL@+O(5&J>MMzoW*KoIxl#5A-qd~4iI>17}1BY7WgLX7DOvPKV# zKv67~2?^CITnfZ67q}7|)`lsatq#oC2XwSq8}eHxYrf>x?ix7u7ysDOL8~50ffbpa zf5Z|1c5E<%me?Z^gg#%T1Cp}N{e8A*0Yi{?tdA{IJjHTk7V%ofZTGK_$FMKo3?Sy{ zph(WdF9LxlYz_{{3kw8AmlgbeyESU_>&~btpt^FE|CHhSP)}yiG1*qfg(Dq@Fa)7uB^VHO`urfLKqHHTFot`6 z%K%!Zq68Gl( zwpnK5=bC_adR%7dVC>-NgoxjSrE|z@=&nj^y%43{glg6)~nT5^8h_Rlqm6QK9ENs=?CSK|_ zet3@Uhnjt|CP_WCr1_}h3he!)Yv!FJK?+6zXLurK@>a2z&vSOF1c@^Z_mZ4&v!{2x zhFqi5f6Yimoq_ATU5=@dM2?e_e^%x zRZCt*oh_+7CK5qs=4D36<(DDe7Uyr;E>_}9{IE)>)xh!V#`@�#f88*-)&@OoAI& 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�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

Z;OJ0D(E1=R~)ZE*U!gGDS7hZ5KWdflY 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 ia5Gp2JN^F|`W)z7IKvu0 Date: Thu, 19 Sep 2013 10:05:13 -0400 Subject: [PATCH 052/556] made canDraw() abstract in PGL --- core/src/processing/opengl/PGL.java | 4 +--- core/src/processing/opengl/PJOGL.java | 6 ++++++ java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java | 5 +++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index e1310dbdd..f43d19433 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -714,9 +714,7 @@ public abstract class PGL { } - protected boolean canDraw() { - return pg.initialized && pg.parent.isDisplayable(); - } + protected abstract boolean canDraw(); protected abstract void requestFocus(); diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index f977f4319..01a0dabe7 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -557,6 +557,12 @@ public class PJOGL extends PGL { } + @Override + protected boolean canDraw() { + return pg.initialized && pg.parent.isDisplayable(); + } + + @Override protected void requestFocus() { } diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java index 795d5828f..477a345f5 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java @@ -229,6 +229,11 @@ public class PLWJGL extends PGL { // Frame rendering + protected boolean canDraw() { + return pg.initialized && pg.parent.isDisplayable(); + } + + protected void requestFocus() { } From 2f8af18ba639989bdbc6f27b8eb547066d91f4dd Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 19 Sep 2013 11:35:03 -0400 Subject: [PATCH 053/556] some changes for android compatibility --- core/src/processing/opengl/PGL.java | 22 ++++++++- .../processing/opengl/PGraphicsOpenGL.java | 47 +++++++------------ core/src/processing/opengl/PJOGL.java | 31 +++++++++++- .../lwjgl/src/processing/lwjgl/PLWJGL.java | 26 +++++++++- 4 files changed, 92 insertions(+), 34 deletions(-) diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index f43d19433..6bbab3c9b 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -24,6 +24,7 @@ package processing.opengl; import processing.core.PApplet; + import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -1882,6 +1883,23 @@ public abstract class PGL { } + // TODO: the next three functions shouldn't be here... + + protected int getFontAscent(Object font) { + return 0; + } + + + protected int getFontDescent(Object font) { + return 0; + } + + + protected int getTextWidth(Object font, char buffer[], int start, int stop) { + return 0; + } + + /////////////////////////////////////////////////////////// // Tessellator interface @@ -1912,7 +1930,7 @@ public abstract class PGL { protected String tessError(int err) { return ""; - } + } /////////////////////////////////////////////////////////// @@ -2424,7 +2442,7 @@ public abstract class PGL { public abstract void linkProgram(int program); public abstract void useProgram(int program); public abstract void deleteProgram(int program); - public abstract String glGetActiveAttrib (int program, int index, IntBuffer size, IntBuffer type); + public abstract String getActiveAttrib(int program, int index, IntBuffer size, IntBuffer type); public abstract int getAttribLocation(int program, String name); public abstract void bindAttribLocation(int program, int index, String name); public abstract int getUniformLocation(int program, String name); diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 592f12b71..ba671f35d 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -23,9 +23,6 @@ package processing.opengl; import processing.core.*; - -import java.awt.Font; -import java.awt.FontMetrics; import java.net.URL; import java.nio.*; import java.util.*; @@ -3254,43 +3251,33 @@ public class PGraphicsOpenGL extends PGraphics { @Override public float textAscent() { - if (textFont == null) { - defaultFontOrDeath("textAscent"); - } - Font font = (Font) textFont.getNative(); - if (font != null) { - FontMetrics metrics = parent.getFontMetrics(font); - return metrics.getAscent(); - } - return super.textAscent(); + if (textFont == null) defaultFontOrDeath("textAscent"); + Object font = textFont.getNative(); + float ascent = 0; + if (font != null) ascent = pgl.getFontAscent(font); + if (ascent == 0) ascent = super.textAscent(); + return ascent; } @Override public float textDescent() { - if (textFont == null) { - defaultFontOrDeath("textAscent"); - } - Font font = (Font) textFont.getNative(); - if (font != null) { - FontMetrics metrics = parent.getFontMetrics(font); - return metrics.getDescent(); - } - return super.textDescent(); + if (textFont == null) defaultFontOrDeath("textAscent"); + Object font = textFont.getNative(); + float descent = 0; + if (font != null) descent = pgl.getFontDescent(font); + if (descent == 0) descent = super.textDescent(); + return descent; } @Override protected float textWidthImpl(char buffer[], int start, int stop) { - Font font = (Font) textFont.getNative(); - if (font != null) { - // maybe should use one of the newer/fancier functions for this? - int length = stop - start; - FontMetrics metrics = parent.getFontMetrics(font); - return metrics.charsWidth(buffer, start, length); - } - - return super.textWidthImpl(buffer, start, stop); + Object font = textFont.getNative(); + float twidth = 0; + if (font != null) twidth = pgl.getTextWidth(font, buffer, start, stop); + if (twidth == 0) twidth = super.textWidthImpl(buffer, start, stop); + return twidth; } diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index 01a0dabe7..59092b6a7 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -3,6 +3,7 @@ package processing.opengl; import java.awt.BorderLayout; import java.awt.Canvas; import java.awt.Color; +import java.awt.FontMetrics; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.FloatBuffer; @@ -941,6 +942,34 @@ public class PJOGL extends PGL { } + /////////////////////////////////////////////////////////// + + // Utility functions + + + @Override + protected int getFontAscent(Object font) { + FontMetrics metrics = pg.parent.getFontMetrics((Font)font); + return metrics.getAscent(); + } + + + @Override + protected int getFontDescent(Object font) { + FontMetrics metrics = pg.parent.getFontMetrics((Font)font); + return metrics.getDescent(); + } + + + @Override + protected int getTextWidth(Object font, char buffer[], int start, int stop) { + // maybe should use one of the newer/fancier functions for this? + int length = stop - start; + FontMetrics metrics = pg.parent.getFontMetrics((Font)font); + return metrics.charsWidth(buffer, start, length); + } + + /////////////////////////////////////////////////////////// // Tessellator @@ -1816,7 +1845,7 @@ public class PJOGL extends PGL { } @Override - public String glGetActiveAttrib (int program, int index, IntBuffer size, IntBuffer type) { + public String getActiveAttrib(int program, int index, IntBuffer size, IntBuffer type) { int[] tmp = {0, 0, 0}; byte[] namebuf = new byte[1024]; gl2.glGetActiveAttrib(program, index, 1024, tmp, 0, tmp, 1, tmp, 2, namebuf, 0); diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java index 477a345f5..7b8c223be 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java @@ -27,6 +27,7 @@ import java.awt.BorderLayout; import java.awt.Canvas; import java.awt.Color; import java.awt.Font; +import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.font.FontRenderContext; @@ -332,6 +333,29 @@ public class PLWJGL extends PGL { } + @Override + protected int getFontAscent(Object font) { + FontMetrics metrics = pg.parent.getFontMetrics((Font)font); + return metrics.getAscent(); + } + + + @Override + protected int getFontDescent(Object font) { + FontMetrics metrics = pg.parent.getFontMetrics((Font)font); + return metrics.getDescent(); + } + + + @Override + protected int getTextWidth(Object font, char buffer[], int start, int stop) { + // maybe should use one of the newer/fancier functions for this? + int length = stop - start; + FontMetrics metrics = pg.parent.getFontMetrics((Font)font); + return metrics.charsWidth(buffer, start, length); + } + + /////////////////////////////////////////////////////////// // LWJGL event handling @@ -1598,7 +1622,7 @@ public class PLWJGL extends PGL { GL20.glDeleteProgram(program); } - public String glGetActiveAttrib (int program, int index, IntBuffer size, IntBuffer type) { + public String getActiveAttrib (int program, int index, IntBuffer size, IntBuffer type) { IntBuffer typeTmp = BufferUtils.createIntBuffer(2); String name = GL20.glGetActiveAttrib(program, index, 256, typeTmp); size.put(typeTmp.get(0)); From 11acf3468184396bcab7fa53dafd6b7b4350a1c8 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 21 Sep 2013 09:41:16 -0400 Subject: [PATCH 054/556] give up on inane Java XML writer that cannot do indents --- build/macosx/.gitignore | 1 + .../com/oracle/appbundler/AppBundlerTask.java | 1316 +++++++++-------- todo.txt | 7 +- 3 files changed, 734 insertions(+), 590 deletions(-) create mode 100644 build/macosx/.gitignore diff --git a/build/macosx/.gitignore b/build/macosx/.gitignore new file mode 100644 index 000000000..773ff5149 --- /dev/null +++ b/build/macosx/.gitignore @@ -0,0 +1 @@ +appbundler.jar \ No newline at end of file diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index 14f9e3022..1269942b4 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -34,6 +34,11 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.URL; import java.nio.file.Files; @@ -42,6 +47,7 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Iterator; +import java.util.Stack; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -49,6 +55,12 @@ import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; @@ -61,674 +73,804 @@ import org.apache.tools.ant.types.resources.FileResource; * App bundler Ant task. */ public class AppBundlerTask extends Task { - // Output folder for generated bundle - private File outputDirectory = null; + // Output folder for generated bundle + private File outputDirectory = null; - // General bundle properties - private String name = null; - private String displayName = null; - private String identifier = null; - private File icon = null; - private String executableName = EXECUTABLE_NAME; + // General bundle properties + private String name = null; + private String displayName = null; + private String identifier = null; + private File icon = null; + private String executableName = EXECUTABLE_NAME; - private String shortVersion = "1.0"; - private String version = "1.0"; - private String signature = "????"; - private String copyright = ""; - private String privileged = null; - private String workingDirectory = null; + private String shortVersion = "1.0"; + private String version = "1.0"; + private String signature = "????"; + private String copyright = ""; + private String privileged = null; + private String workingDirectory = null; - private String applicationCategory = null; + private String applicationCategory = null; - private boolean highResolutionCapable = true; + private boolean highResolutionCapable = true; - // JVM info properties - private String mainClassName = null; - private FileSet runtime = null; - private ArrayList classPath = new ArrayList<>(); - private ArrayList libraryPath = new ArrayList<>(); - private ArrayList options = new ArrayList<>(); - private ArrayList arguments = new ArrayList<>(); - private ArrayList architectures = new ArrayList<>(); - private ArrayList bundleDocuments = new ArrayList<>(); - - private Reference classPathRef; + // JVM info properties + private String mainClassName = null; + private FileSet runtime = null; + private ArrayList classPath = new ArrayList<>(); + private ArrayList libraryPath = new ArrayList<>(); + private ArrayList options = new ArrayList<>(); + private ArrayList arguments = new ArrayList<>(); + private ArrayList architectures = new ArrayList<>(); + private ArrayList bundleDocuments = new ArrayList<>(); - private static final String EXECUTABLE_NAME = "JavaAppLauncher"; - private static final String DEFAULT_ICON_NAME = "GenericApp.icns"; - private static final String OS_TYPE_CODE = "APPL"; + private Reference classPathRef; - private static final String PLIST_DTD = ""; - private static final String PLIST_TAG = "plist"; - private static final String PLIST_VERSION_ATTRIBUTE = "version"; - private static final String DICT_TAG = "dict"; - private static final String KEY_TAG = "key"; - private static final String ARRAY_TAG = "array"; - private static final String STRING_TAG = "string"; - - private static final int BUFFER_SIZE = 2048; + private static final String EXECUTABLE_NAME = "JavaAppLauncher"; + private static final String DEFAULT_ICON_NAME = "GenericApp.icns"; + private static final String OS_TYPE_CODE = "APPL"; - public void setOutputDirectory(File outputDirectory) { - this.outputDirectory = outputDirectory; + private static final String PLIST_DTD = ""; + private static final String PLIST_TAG = "plist"; + private static final String PLIST_VERSION_ATTRIBUTE = "version"; + private static final String DICT_TAG = "dict"; + private static final String KEY_TAG = "key"; + private static final String ARRAY_TAG = "array"; + private static final String STRING_TAG = "string"; + + private static final int BUFFER_SIZE = 2048; + + + public void setOutputDirectory(File outputDirectory) { + this.outputDirectory = outputDirectory; + } + + + public void setName(String name) { + this.name = name; + } + + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + + public void setIcon(File icon) { + this.icon = icon; + } + + + public void setExecutableName(String executable) { + this.executableName = executable; + } + + + public void setShortVersion(String shortVersion) { + this.shortVersion = shortVersion; + } + + + public void setVersion(String version) { + this.version = version; + } + + + public void setSignature(String signature) { + this.signature = signature; + } + + + public void setCopyright(String copyright) { + this.copyright = copyright; + } + + + public void setPrivileged(String privileged) { + this.privileged = privileged; + } + + + public void setWorkingDirectory(String workingDirectory) { + this.workingDirectory = workingDirectory; + } + + + public void setApplicationCategory(String applicationCategory) { + this.applicationCategory = applicationCategory; + } + + + public void setHighResolutionCapable(boolean highResolutionCapable) { + this.highResolutionCapable = highResolutionCapable; + } + + + public void setMainClassName(String mainClassName) { + this.mainClassName = mainClassName; + } + + + public void addConfiguredRuntime(FileSet runtime) throws BuildException { + if (this.runtime != null) { + throw new BuildException("Runtime already specified."); } - public void setName(String name) { - this.name = name; + this.runtime = runtime; + + runtime.appendIncludes(new String[] { + "jre/", + }); + + runtime.appendExcludes(new String[] { + "bin/", + "jre/bin/", + "jre/lib/deploy/", + "jre/lib/deploy.jar", + "jre/lib/javaws.jar", + "jre/lib/libdeploy.dylib", + "jre/lib/libnpjp2.dylib", + "jre/lib/plugin.jar", + "jre/lib/security/javaws.policy" + }); + } + + + public void setClasspathRef(Reference ref) { + this.classPathRef = ref; + } + + + public void addConfiguredClassPath(FileSet classPath) { + this.classPath.add(classPath); + } + + + public void addConfiguredLibraryPath(FileSet libraryPath) { + this.libraryPath.add(libraryPath); + } + + + public void addConfiguredBundleDocument(BundleDocument document) { + this.bundleDocuments.add(document); + } + + + public void addConfiguredOption(Option option) throws BuildException { + String value = option.getValue(); + + if (value == null) { + throw new BuildException("Value is required."); } - public void setDisplayName(String displayName) { - this.displayName = displayName; + options.add(value); + } + + + public void addConfiguredArgument(Argument argument) throws BuildException { + String value = argument.getValue(); + + if (value == null) { + throw new BuildException("Value is required."); } - public void setIdentifier(String identifier) { - this.identifier = identifier; + arguments.add(value); + } + + + public void addConfiguredArch(Architecture architecture) throws BuildException { + String name = architecture.getName(); + + if (name == null) { + throw new BuildException("Name is required."); } - public void setIcon(File icon) { - this.icon = icon; - } - - public void setExecutableName(String executable) { - this.executableName = executable; + architectures.add(name); + } + + + @Override + public void execute() throws BuildException { + // Validate required properties + if (outputDirectory == null) { + throw new IllegalStateException("Output directory is required."); } - public void setShortVersion(String shortVersion) { - this.shortVersion = shortVersion; + if (!outputDirectory.exists()) { + throw new IllegalStateException("Output directory does not exist."); } - public void setVersion(String version) { - this.version = version; + if (!outputDirectory.isDirectory()) { + throw new IllegalStateException("Invalid output directory."); } - public void setSignature(String signature) { - this.signature = signature; + if (name == null) { + throw new IllegalStateException("Name is required."); } - public void setCopyright(String copyright) { - this.copyright = copyright; - } - - public void setPrivileged(String privileged) { - this.privileged = privileged; - } - - public void setWorkingDirectory(String workingDirectory) { - this.workingDirectory = workingDirectory; - } - - public void setApplicationCategory(String applicationCategory) { - this.applicationCategory = applicationCategory; + if (displayName == null) { + throw new IllegalStateException("Display name is required."); } - public void setHighResolutionCapable(boolean highResolutionCapable) { - this.highResolutionCapable = highResolutionCapable; + if (identifier == null) { + throw new IllegalStateException("Identifier is required."); } - public void setMainClassName(String mainClassName) { - this.mainClassName = mainClassName; + if (icon != null) { + if (!icon.exists()) { + throw new IllegalStateException("Icon does not exist."); + } + + if (icon.isDirectory()) { + throw new IllegalStateException("Invalid icon."); + } } - public void addConfiguredRuntime(FileSet runtime) throws BuildException { - if (this.runtime != null) { - throw new BuildException("Runtime already specified."); - } - - this.runtime = runtime; - - runtime.appendIncludes(new String[] { - "jre/", - }); - - runtime.appendExcludes(new String[] { - "bin/", - "jre/bin/", - "jre/lib/deploy/", - "jre/lib/deploy.jar", - "jre/lib/javaws.jar", - "jre/lib/libdeploy.dylib", - "jre/lib/libnpjp2.dylib", - "jre/lib/plugin.jar", - "jre/lib/security/javaws.policy" - }); - } - - public void setClasspathRef(Reference ref) { - this.classPathRef = ref; + if (shortVersion == null) { + throw new IllegalStateException("Short version is required."); } - public void addConfiguredClassPath(FileSet classPath) { - this.classPath.add(classPath); + if (signature == null) { + throw new IllegalStateException("Signature is required."); } - public void addConfiguredLibraryPath(FileSet libraryPath) { - this.libraryPath.add(libraryPath); - } - - public void addConfiguredBundleDocument(BundleDocument document) { - this.bundleDocuments.add(document); + if (signature.length() != 4) { + throw new IllegalStateException("Invalid signature."); } - public void addConfiguredOption(Option option) throws BuildException { - String value = option.getValue(); - - if (value == null) { - throw new BuildException("Value is required."); - } - - options.add(value); + if (copyright == null) { + throw new IllegalStateException("Copyright is required."); } - public void addConfiguredArgument(Argument argument) throws BuildException { - String value = argument.getValue(); - - if (value == null) { - throw new BuildException("Value is required."); - } - - arguments.add(value); + if (mainClassName == null) { + throw new IllegalStateException("Main class name is required."); } - public void addConfiguredArch(Architecture architecture) throws BuildException { - String name = architecture.getName(); + // Create the app bundle + try { + System.out.println("Creating app bundle: " + name); - if (name == null) { - throw new BuildException("Name is required."); - } + // Create directory structure + File rootDirectory = new File(outputDirectory, name + ".app"); + delete(rootDirectory); + rootDirectory.mkdir(); - architectures.add(name); + File contentsDirectory = new File(rootDirectory, "Contents"); + contentsDirectory.mkdir(); + + File macOSDirectory = new File(contentsDirectory, "MacOS"); + macOSDirectory.mkdir(); + + File javaDirectory = new File(contentsDirectory, "Java"); + javaDirectory.mkdir(); + + File plugInsDirectory = new File(contentsDirectory, "PlugIns"); + plugInsDirectory.mkdir(); + + File resourcesDirectory = new File(contentsDirectory, "Resources"); + resourcesDirectory.mkdir(); + + // Generate Info.plist + File infoPlistFile = new File(contentsDirectory, "Info.plist"); + infoPlistFile.createNewFile(); + writeInfoPlist(infoPlistFile); + + // Generate PkgInfo + File pkgInfoFile = new File(contentsDirectory, "PkgInfo"); + pkgInfoFile.createNewFile(); + writePkgInfo(pkgInfoFile); + + // Copy executable to MacOS folder + File executableFile = new File(macOSDirectory, executableName); + copy(getClass().getResource(EXECUTABLE_NAME), executableFile); + + executableFile.setExecutable(true, false); + + // Copy localized resources to Resources folder + copyResources(resourcesDirectory); + + // Copy runtime to PlugIns folder + copyRuntime(plugInsDirectory); + + // Copy class path entries to Java folder + copyClassPathEntries(javaDirectory); + + // Copy class path ref entries to Java folder + copyClassPathRefEntries(javaDirectory); + + // Copy library path entries to MacOS folder + copyLibraryPathEntries(macOSDirectory); + + // Copy icon to Resources folder + copyIcon(resourcesDirectory); + + } catch (IOException exception) { + throw new BuildException(exception); } + } - @Override - public void execute() throws BuildException { - // Validate required properties - if (outputDirectory == null) { - throw new IllegalStateException("Output directory is required."); - } - if (!outputDirectory.exists()) { - throw new IllegalStateException("Output directory does not exist."); - } + private void copyResources(File resourcesDirectory) throws IOException { + // Unzip res.zip into resources directory + InputStream inputStream = getClass().getResourceAsStream("res.zip"); + ZipInputStream zipInputStream = new ZipInputStream(inputStream); - if (!outputDirectory.isDirectory()) { - throw new IllegalStateException("Invalid output directory."); - } + try { + ZipEntry zipEntry = zipInputStream.getNextEntry(); + while (zipEntry != null) { + File file = new File(resourcesDirectory, zipEntry.getName()); - if (name == null) { - throw new IllegalStateException("Name is required."); - } - - if (displayName == null) { - throw new IllegalStateException("Display name is required."); - } - - if (identifier == null) { - throw new IllegalStateException("Identifier is required."); - } - - if (icon != null) { - if (!icon.exists()) { - throw new IllegalStateException("Icon does not exist."); - } - - if (icon.isDirectory()) { - throw new IllegalStateException("Invalid icon."); - } - } - - if (shortVersion == null) { - throw new IllegalStateException("Short version is required."); - } - - if (signature == null) { - throw new IllegalStateException("Signature is required."); - } - - if (signature.length() != 4) { - throw new IllegalStateException("Invalid signature."); - } - - if (copyright == null) { - throw new IllegalStateException("Copyright is required."); - } - - if (mainClassName == null) { - throw new IllegalStateException("Main class name is required."); - } - - // Create the app bundle - try { - System.out.println("Creating app bundle: " + name); - - // Create directory structure - File rootDirectory = new File(outputDirectory, name + ".app"); - delete(rootDirectory); - rootDirectory.mkdir(); - - File contentsDirectory = new File(rootDirectory, "Contents"); - contentsDirectory.mkdir(); - - File macOSDirectory = new File(contentsDirectory, "MacOS"); - macOSDirectory.mkdir(); - - File javaDirectory = new File(contentsDirectory, "Java"); - javaDirectory.mkdir(); - - File plugInsDirectory = new File(contentsDirectory, "PlugIns"); - plugInsDirectory.mkdir(); - - File resourcesDirectory = new File(contentsDirectory, "Resources"); - resourcesDirectory.mkdir(); - - // Generate Info.plist - File infoPlistFile = new File(contentsDirectory, "Info.plist"); - infoPlistFile.createNewFile(); - writeInfoPlist(infoPlistFile); - - // Generate PkgInfo - File pkgInfoFile = new File(contentsDirectory, "PkgInfo"); - pkgInfoFile.createNewFile(); - writePkgInfo(pkgInfoFile); - - // Copy executable to MacOS folder - File executableFile = new File(macOSDirectory, executableName); - copy(getClass().getResource(EXECUTABLE_NAME), executableFile); - - executableFile.setExecutable(true, false); - - // Copy localized resources to Resources folder - copyResources(resourcesDirectory); - - // Copy runtime to PlugIns folder - copyRuntime(plugInsDirectory); - - // Copy class path entries to Java folder - copyClassPathEntries(javaDirectory); - - // Copy class path ref entries to Java folder - copyClassPathRefEntries(javaDirectory); - - // Copy library path entries to MacOS folder - copyLibraryPathEntries(macOSDirectory); - - // Copy icon to Resources folder - copyIcon(resourcesDirectory); - } catch (IOException exception) { - throw new BuildException(exception); - } - } - - private void copyResources(File resourcesDirectory) throws IOException { - // Unzip res.zip into resources directory - InputStream inputStream = getClass().getResourceAsStream("res.zip"); - ZipInputStream zipInputStream = new ZipInputStream(inputStream); - - try { - ZipEntry zipEntry = zipInputStream.getNextEntry(); - while (zipEntry != null) { - File file = new File(resourcesDirectory, zipEntry.getName()); - - if (zipEntry.isDirectory()) { - file.mkdir(); - } else { - OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE); - - try { - int b = zipInputStream.read(); - while (b != -1) { - outputStream.write(b); - b = zipInputStream.read(); - } - - outputStream.flush(); - } finally { - outputStream.close(); - } - - } - - zipEntry = zipInputStream.getNextEntry(); - } - } finally { - zipInputStream.close(); - } - } - - private void copyRuntime(File plugInsDirectory) throws IOException { - if (runtime != null) { - File runtimeHomeDirectory = runtime.getDir(); - File runtimeContentsDirectory = runtimeHomeDirectory.getParentFile(); - File runtimeDirectory = runtimeContentsDirectory.getParentFile(); - - // Create root plug-in directory - File pluginDirectory = new File(plugInsDirectory, runtimeDirectory.getName()); - pluginDirectory.mkdir(); - - // Create Contents directory - File pluginContentsDirectory = new File(pluginDirectory, runtimeContentsDirectory.getName()); - pluginContentsDirectory.mkdir(); - - // Copy MacOS directory - File runtimeMacOSDirectory = new File(runtimeContentsDirectory, "MacOS"); - copy(runtimeMacOSDirectory, new File(pluginContentsDirectory, runtimeMacOSDirectory.getName())); - - // Copy Info.plist file - File runtimeInfoPlistFile = new File(runtimeContentsDirectory, "Info.plist"); - copy(runtimeInfoPlistFile, new File(pluginContentsDirectory, runtimeInfoPlistFile.getName())); - - // Copy included contents of Home directory - File pluginHomeDirectory = new File(pluginContentsDirectory, runtimeHomeDirectory.getName()); - - DirectoryScanner directoryScanner = runtime.getDirectoryScanner(getProject()); - String[] includedFiles = directoryScanner.getIncludedFiles(); - - for (int i = 0; i < includedFiles.length; i++) { - String includedFile = includedFiles[i]; - File source = new File(runtimeHomeDirectory, includedFile); - File destination = new File(pluginHomeDirectory, includedFile); - copy(source, destination); - } - } - } - - private void copyClassPathRefEntries(File javaDirectory) throws IOException { - if(classPathRef != null) { - org.apache.tools.ant.types.Path classpath = - (org.apache.tools.ant.types.Path) classPathRef.getReferencedObject(getProject()); - - Iterator iter = (Iterator)(Object)classpath.iterator(); - while(iter.hasNext()) { - FileResource resource = iter.next(); - File source = resource.getFile(); - File destination = new File(javaDirectory, source.getName()); - copy(source, destination); - } - } - } - - private void copyClassPathEntries(File javaDirectory) throws IOException { - for (FileSet fileSet : classPath) { - File classPathDirectory = fileSet.getDir(); - DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject()); - String[] includedFiles = directoryScanner.getIncludedFiles(); - - for (int i = 0; i < includedFiles.length; i++) { - String includedFile = includedFiles[i]; - File source = new File(classPathDirectory, includedFile); - File destination = new File(javaDirectory, new File(includedFile).getName()); - copy(source, destination); - } - } - } - - private void copyLibraryPathEntries(File macOSDirectory) throws IOException { - for (FileSet fileSet : libraryPath) { - File libraryPathDirectory = fileSet.getDir(); - DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject()); - String[] includedFiles = directoryScanner.getIncludedFiles(); - - for (int i = 0; i < includedFiles.length; i++) { - String includedFile = includedFiles[i]; - File source = new File(libraryPathDirectory, includedFile); - File destination = new File(macOSDirectory, new File(includedFile).getName()); - copy(source, destination); - } - } - } - - private void copyIcon(File resourcesDirectory) throws IOException { - if (icon == null) { - copy(getClass().getResource(DEFAULT_ICON_NAME), new File(resourcesDirectory, DEFAULT_ICON_NAME)); + if (zipEntry.isDirectory()) { + file.mkdir(); } else { - copy(icon, new File(resourcesDirectory, icon.getName())); + OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE); + + try { + int b = zipInputStream.read(); + while (b != -1) { + outputStream.write(b); + b = zipInputStream.read(); + } + + outputStream.flush(); + } finally { + outputStream.close(); + } + } + + zipEntry = zipInputStream.getNextEntry(); + } + } finally { + zipInputStream.close(); } - - private void writeInfoPlist(File file) throws IOException { - Writer out = new BufferedWriter(new FileWriter(file)); - XMLOutputFactory output = XMLOutputFactory.newInstance(); -// output.setProperty("indent-number", 2); - output.setProperty(OutputKeys.INDENT, "yes"); - - try { - XMLStreamWriter xout = output.createXMLStreamWriter(out); - - // Write XML declaration - xout.writeStartDocument(); - xout.writeCharacters("\n"); - - // Write plist DTD declaration - xout.writeDTD(PLIST_DTD); - xout.writeCharacters("\n"); - - // Begin root element - xout.writeStartElement(PLIST_TAG); - xout.writeAttribute(PLIST_VERSION_ATTRIBUTE, "1.0"); - xout.writeCharacters("\n"); - - // Begin root dictionary - xout.writeStartElement(DICT_TAG); - xout.writeCharacters("\n"); - - // Write bundle properties - writeProperty(xout, "CFBundleDevelopmentRegion", "English"); - writeProperty(xout, "CFBundleExecutable", executableName); - writeProperty(xout, "CFBundleIconFile", (icon == null) ? DEFAULT_ICON_NAME : icon.getName()); - writeProperty(xout, "CFBundleIdentifier", identifier); - writeProperty(xout, "CFBundleDisplayName", displayName); - writeProperty(xout, "CFBundleInfoDictionaryVersion", "6.0"); - writeProperty(xout, "CFBundleName", name); - writeProperty(xout, "CFBundlePackageType", OS_TYPE_CODE); - writeProperty(xout, "CFBundleShortVersionString", shortVersion); - writeProperty(xout, "CFBundleVersion", version); - writeProperty(xout, "CFBundleSignature", signature); - writeProperty(xout, "NSHumanReadableCopyright", copyright); - - if (applicationCategory != null) { - writeProperty(xout, "LSApplicationCategoryType", applicationCategory); - } - - if (highResolutionCapable) { - writeKey(xout, "NSHighResolutionCapable"); - writeBoolean(xout, true); - xout.writeCharacters("\n"); - } - - // Write runtime - if (runtime != null) { - writeProperty(xout, "JVMRuntime", runtime.getDir().getParentFile().getParentFile().getName()); - } - - if (privileged != null) { - writeProperty(xout, "JVMRunPrivileged", privileged); - } - - if (workingDirectory != null) { - writeProperty(xout, "WorkingDirectory", workingDirectory); - } - - // Write main class name - writeProperty(xout, "JVMMainClassName", mainClassName); + } - // Write CFBundleDocument entries - writeKey(xout, "CFBundleDocumentTypes"); - - xout.writeStartElement(ARRAY_TAG); - xout.writeCharacters("\n"); - - for (BundleDocument bundleDocument: bundleDocuments) { - xout.writeStartElement(DICT_TAG); - xout.writeCharacters("\n"); - - writeKey(xout, "CFBundleTypeExtensions"); - xout.writeStartElement(ARRAY_TAG); - xout.writeCharacters("\n"); - for (String extension : bundleDocument.getExtensions()) { - writeString(xout, extension); - } - xout.writeEndElement(); - xout.writeCharacters("\n"); - - if (bundleDocument.hasIcon()) { - writeKey(xout, "CFBundleTypeIconFile"); - writeString(xout, bundleDocument.getIcon()); - } - - writeKey(xout, "CFBundleTypeName"); - writeString(xout, bundleDocument.getName()); - - writeKey(xout, "CFBundleTypeRole"); - writeString(xout, bundleDocument.getRole()); - - writeKey(xout, "LSTypeIsPackage"); - writeBoolean(xout, bundleDocument.isPackage()); - - xout.writeEndElement(); - xout.writeCharacters("\n"); - } - - xout.writeEndElement(); - xout.writeCharacters("\n"); - - // Write architectures - writeKey(xout, "LSArchitecturePriority"); + private void copyRuntime(File plugInsDirectory) throws IOException { + if (runtime != null) { + File runtimeHomeDirectory = runtime.getDir(); + File runtimeContentsDirectory = runtimeHomeDirectory.getParentFile(); + File runtimeDirectory = runtimeContentsDirectory.getParentFile(); - xout.writeStartElement(ARRAY_TAG); - xout.writeCharacters("\n"); + // Create root plug-in directory + File pluginDirectory = new File(plugInsDirectory, runtimeDirectory.getName()); + pluginDirectory.mkdir(); - for (String architecture : architectures) { - writeString(xout, architecture); - } + // Create Contents directory + File pluginContentsDirectory = new File(pluginDirectory, runtimeContentsDirectory.getName()); + pluginContentsDirectory.mkdir(); - xout.writeEndElement(); - xout.writeCharacters("\n"); + // Copy MacOS directory + File runtimeMacOSDirectory = new File(runtimeContentsDirectory, "MacOS"); + copy(runtimeMacOSDirectory, new File(pluginContentsDirectory, runtimeMacOSDirectory.getName())); - // Write Environment - writeKey(xout, "LSEnvironment"); - xout.writeStartElement(DICT_TAG); - xout.writeCharacters("\n"); - writeKey(xout, "LC_CTYPE"); - writeString(xout, "UTF-8"); - xout.writeEndElement(); - xout.writeCharacters("\n"); + // Copy Info.plist file + File runtimeInfoPlistFile = new File(runtimeContentsDirectory, "Info.plist"); + copy(runtimeInfoPlistFile, new File(pluginContentsDirectory, runtimeInfoPlistFile.getName())); - // Write options - writeKey(xout, "JVMOptions"); + // Copy included contents of Home directory + File pluginHomeDirectory = new File(pluginContentsDirectory, runtimeHomeDirectory.getName()); - xout.writeStartElement(ARRAY_TAG); - xout.writeCharacters("\n"); + DirectoryScanner directoryScanner = runtime.getDirectoryScanner(getProject()); + String[] includedFiles = directoryScanner.getIncludedFiles(); - for (String option : options) { - writeString(xout, option); - } - - xout.writeEndElement(); - xout.writeCharacters("\n"); - - // Write arguments - writeKey(xout, "JVMArguments"); - - xout.writeStartElement(ARRAY_TAG); - xout.writeCharacters("\n"); - - for (String argument : arguments) { - writeString(xout, argument); - } - - xout.writeEndElement(); - xout.writeCharacters("\n"); - - // End root dictionary - xout.writeEndElement(); - xout.writeCharacters("\n"); - - // End root element - xout.writeEndElement(); - xout.writeCharacters("\n"); - - // Close document - xout.writeEndDocument(); - xout.writeCharacters("\n"); - - out.flush(); - } catch (XMLStreamException exception) { - throw new IOException(exception); - } finally { - out.close(); - } + for (int i = 0; i < includedFiles.length; i++) { + String includedFile = includedFiles[i]; + File source = new File(runtimeHomeDirectory, includedFile); + File destination = new File(pluginHomeDirectory, includedFile); + copy(source, destination); + } } + } - private void writeKey(XMLStreamWriter xout, String key) throws XMLStreamException { - xout.writeStartElement(KEY_TAG); - xout.writeCharacters(key); - xout.writeEndElement(); - xout.writeCharacters("\n"); + + private void copyClassPathRefEntries(File javaDirectory) throws IOException { + if(classPathRef != null) { + org.apache.tools.ant.types.Path classpath = + (org.apache.tools.ant.types.Path) classPathRef.getReferencedObject(getProject()); + + Iterator iter = (Iterator)(Object)classpath.iterator(); + while(iter.hasNext()) { + FileResource resource = iter.next(); + File source = resource.getFile(); + File destination = new File(javaDirectory, source.getName()); + copy(source, destination); + } } + } - private void writeString(XMLStreamWriter xout, String value) throws XMLStreamException { - xout.writeStartElement(STRING_TAG); - xout.writeCharacters(value); - xout.writeEndElement(); - xout.writeCharacters("\n"); + + private void copyClassPathEntries(File javaDirectory) throws IOException { + for (FileSet fileSet : classPath) { + File classPathDirectory = fileSet.getDir(); + DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject()); + String[] includedFiles = directoryScanner.getIncludedFiles(); + + for (int i = 0; i < includedFiles.length; i++) { + String includedFile = includedFiles[i]; + File source = new File(classPathDirectory, includedFile); + File destination = new File(javaDirectory, new File(includedFile).getName()); + copy(source, destination); + } + } + } + + + private void copyLibraryPathEntries(File macOSDirectory) throws IOException { + for (FileSet fileSet : libraryPath) { + File libraryPathDirectory = fileSet.getDir(); + DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject()); + String[] includedFiles = directoryScanner.getIncludedFiles(); + + for (int i = 0; i < includedFiles.length; i++) { + String includedFile = includedFiles[i]; + File source = new File(libraryPathDirectory, includedFile); + File destination = new File(macOSDirectory, new File(includedFile).getName()); + copy(source, destination); + } + } + } + + + private void copyIcon(File resourcesDirectory) throws IOException { + if (icon == null) { + copy(getClass().getResource(DEFAULT_ICON_NAME), new File(resourcesDirectory, DEFAULT_ICON_NAME)); + } else { + copy(icon, new File(resourcesDirectory, icon.getName())); + } + } + + + class SimpleXML { + PrintWriter writer; + int indentSpaces; +// int indentLevel; + Stack elements = new Stack<>(); + + public SimpleXML(OutputStream output) throws UnsupportedEncodingException { + OutputStreamWriter osw = new OutputStreamWriter(output, "UTF-8"); + writer = new PrintWriter(osw); } - private void writeBoolean(XMLStreamWriter xout, boolean value) throws XMLStreamException { - xout.writeEmptyElement(value ? "true" : "false"); + void writeStartDocument() { + writer.println(""); } - - private void writeProperty(XMLStreamWriter xout, String key, String value) throws XMLStreamException { - writeKey(xout, key); - writeString(xout, value); + + void writeEndDocument() { + writer.flush(); + writer.close(); } - - private void writePkgInfo(File file) throws IOException { - Writer out = new BufferedWriter(new FileWriter(file)); - - try { - out.write(OS_TYPE_CODE + signature); - out.flush(); - } finally { - out.close(); + + void println(String line) { + writer.println(line); + } + + void writeStartElement(String element, String... args) { + emitIndent(); + writer.print("<" + element); + + for (int i = 0; i < args.length; i += 2) { + String attr = args[i]; + String value = args[i+1]; + writer.print(" " + attr + "=\"" + value + "\""); + } + writer.println(">"); +// indentLevel++; + elements.push(element); + } + + void writeStartElement(String element) { + writer.println("<" + element + ">"); +// indentLevel++; + elements.push(element); + } + + void writeEndElement() { + emitIndent(); + writer.println(""); + } + + void writeKey(String key) { + emitIndent(); + writer.println("" + key + ""); + } + + void writeString(String value) { + emitIndent(); + writer.println("" + value + ""); + } + + void writeBoolean(boolean value) { + emitIndent(); + writer.println("<" + (value ? "true" : "false") + "/>"); + } + + void writeProperty(String property, String value) { + writeKey(property); + writeString(value); + } + + void emitIndent() { + for (int i = 0; i < elements.size(); i++) { + for (int j = 0; j < indentSpaces; j++) { + writer.print(' '); } + } } + } + + + private void writeInfoPlist(File file) throws IOException { +// Writer out = new BufferedWriter(new FileWriter(file)); +//// StringWriter out = new StringWriter(); +// XMLOutputFactory output = XMLOutputFactory.newInstance(); +// +// try { +// XMLStreamWriter xout = output.createXMLStreamWriter(out); + FileOutputStream output = new FileOutputStream(file); + SimpleXML xout = new SimpleXML(output); - private static void delete(File file) throws IOException { - Path filePath = file.toPath(); + // Write XML declaration +// xout.writeStartDocument(); +// xout.writeCharacters("\n"); - if (Files.exists(filePath, LinkOption.NOFOLLOW_LINKS)) { - if (Files.isDirectory(filePath, LinkOption.NOFOLLOW_LINKS)) { - File[] files = file.listFiles(); + // Write plist DTD declaration +// xout.writeDTD(PLIST_DTD); +// xout.writeCharacters("\n"); + xout.println(PLIST_DTD); - for (int i = 0; i < files.length; i++) { - delete(files[i]); - } - } + // Begin root element +// xout.writeStartElement(PLIST_TAG); +// xout.writeAttribute(PLIST_VERSION_ATTRIBUTE, "1.0"); +// xout.writeCharacters("\n"); + xout.writeStartElement(PLIST_TAG, PLIST_VERSION_ATTRIBUTE, "1.0"); - Files.delete(filePath); + // Begin root dictionary + xout.writeStartElement(DICT_TAG); +// xout.writeCharacters("\n"); + + // Write bundle properties + xout.writeProperty("CFBundleDevelopmentRegion", "English"); + xout.writeProperty("CFBundleExecutable", executableName); + xout.writeProperty("CFBundleIconFile", (icon == null) ? DEFAULT_ICON_NAME : icon.getName()); + xout.writeProperty("CFBundleIdentifier", identifier); + xout.writeProperty("CFBundleDisplayName", displayName); + xout.writeProperty("CFBundleInfoDictionaryVersion", "6.0"); + xout.writeProperty("CFBundleName", name); + xout.writeProperty("CFBundlePackageType", OS_TYPE_CODE); + xout.writeProperty("CFBundleShortVersionString", shortVersion); + xout.writeProperty("CFBundleVersion", version); + xout.writeProperty("CFBundleSignature", signature); + xout.writeProperty("NSHumanReadableCopyright", copyright); + + if (applicationCategory != null) { + xout.writeProperty("LSApplicationCategoryType", applicationCategory); + } + + if (highResolutionCapable) { + xout.writeKey("NSHighResolutionCapable"); + xout.writeBoolean(true); + } + + // Write runtime + if (runtime != null) { + xout.writeProperty("JVMRuntime", runtime.getDir().getParentFile().getParentFile().getName()); + } + + if (privileged != null) { + xout.writeProperty("JVMRunPrivileged", privileged); + } + + if (workingDirectory != null) { + xout.writeProperty("WorkingDirectory", workingDirectory); + } + + // Write main class name + xout.writeProperty("JVMMainClassName", mainClassName); + + + // Write CFBundleDocument entries + xout.writeKey("CFBundleDocumentTypes"); + + xout.writeStartElement(ARRAY_TAG); + + for (BundleDocument bundleDocument: bundleDocuments) { + xout.writeStartElement(DICT_TAG); + + xout.writeKey("CFBundleTypeExtensions"); + xout.writeStartElement(ARRAY_TAG); + for (String extension : bundleDocument.getExtensions()) { + xout.writeString(extension); } - } + xout.writeEndElement(); - private static void copy(URL location, File file) throws IOException { - try (InputStream in = location.openStream()) { - Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING); + if (bundleDocument.hasIcon()) { + xout.writeKey("CFBundleTypeIconFile"); + xout.writeString(bundleDocument.getIcon()); } + + xout.writeKey("CFBundleTypeName"); + xout.writeString(bundleDocument.getName()); + + xout.writeKey("CFBundleTypeRole"); + xout.writeString(bundleDocument.getRole()); + + xout.writeKey("LSTypeIsPackage"); + xout.writeBoolean(bundleDocument.isPackage()); + + xout.writeEndElement(); + } + + xout.writeEndElement(); + + // Write architectures + xout.writeKey("LSArchitecturePriority"); + + xout.writeStartElement(ARRAY_TAG); + + for (String architecture : architectures) { + xout.writeString(architecture); + } + + xout.writeEndElement(); + + // Write Environment + xout.writeKey("LSEnvironment"); + xout.writeStartElement(DICT_TAG); + xout.writeKey("LC_CTYPE"); + xout.writeString("UTF-8"); + xout.writeEndElement(); + + // Write options + xout.writeKey("JVMOptions"); + + xout.writeStartElement(ARRAY_TAG); + + for (String option : options) { + xout.writeString(option); + } + + xout.writeEndElement(); + + // Write arguments + xout.writeKey("JVMArguments"); + + xout.writeStartElement(ARRAY_TAG); + + for (String argument : arguments) { + xout.writeString(argument); + } + + xout.writeEndElement(); + + // End root dictionary + xout.writeEndElement(); + + // End root element + xout.writeEndElement(); + + // Close document + xout.writeEndDocument(); + +// out.flush(); +// } catch (XMLStreamException exception) { +// throw new IOException(exception); +// } finally { +// out.close(); +// } +// try { +//// TransformerFactory factory = TransformerFactory.newInstance(); +//// Transformer transformer = factory.newTransformer(); +////// transformer.setOutputProperty(OutputKeys.METHOD, "xml"); +////// transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8"); +//// transformer.setOutputProperty(OutputKeys.INDENT, "yes"); +////// transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); +//// +//// StringWriter formatted = new StringWriter(); +//// transformer.transform(new StreamSource(new StringReader(out.toString())), +//// new StreamResult(formatted)); +//// System.out.println(formatted); +// +// FileWriter fw = new FileWriter(file); +//// fw.write(formatted.toString()); +// fw.write(out.toString()); +// fw.flush(); +// fw.close(); +// +// } catch (Exception e) { +// +//// } catch (TransformerConfigurationException tce) { +//// throw new IOException(tce); +//// } catch (TransformerException te) { +//// throw new IOException(te); +// } + } + + + private void writeKey(XMLStreamWriter xout, String key) throws XMLStreamException { + xout.writeStartElement(KEY_TAG); + xout.writeCharacters(key); + xout.writeEndElement(); + xout.writeCharacters("\n"); + } + + + private void writeString(XMLStreamWriter xout, String value) throws XMLStreamException { + xout.writeStartElement(STRING_TAG); + xout.writeCharacters(value); + xout.writeEndElement(); + xout.writeCharacters("\n"); + } + + + private void writeBoolean(XMLStreamWriter xout, boolean value) throws XMLStreamException { + xout.writeEmptyElement(value ? "true" : "false"); + } + + + private void writeProperty(XMLStreamWriter xout, String key, String value) throws XMLStreamException { + writeKey(xout, key); + writeString(xout, value); + } + + + private void writePkgInfo(File file) throws IOException { + Writer out = new BufferedWriter(new FileWriter(file)); + + try { + out.write(OS_TYPE_CODE + signature); + out.flush(); + } finally { + out.close(); } + } - private static void copy(File source, File destination) throws IOException { - Path sourcePath = source.toPath(); - Path destinationPath = destination.toPath(); - destination.getParentFile().mkdirs(); + private static void delete(File file) throws IOException { + Path filePath = file.toPath(); - Files.copy(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS); + if (Files.exists(filePath, LinkOption.NOFOLLOW_LINKS)) { + if (Files.isDirectory(filePath, LinkOption.NOFOLLOW_LINKS)) { + File[] files = file.listFiles(); - if (Files.isDirectory(sourcePath, LinkOption.NOFOLLOW_LINKS)) { - String[] files = source.list(); - - for (int i = 0; i < files.length; i++) { - String file = files[i]; - copy(new File(source, file), new File(destination, file)); - } + for (int i = 0; i < files.length; i++) { + delete(files[i]); } + } + + Files.delete(filePath); } + } + + + private static void copy(URL location, File file) throws IOException { + try (InputStream in = location.openStream()) { + Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + } + + + private static void copy(File source, File destination) throws IOException { + Path sourcePath = source.toPath(); + Path destinationPath = destination.toPath(); + + destination.getParentFile().mkdirs(); + + Files.copy(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS); + + if (Files.isDirectory(sourcePath, LinkOption.NOFOLLOW_LINKS)) { + String[] files = source.list(); + + for (int i = 0; i < files.length; i++) { + String file = files[i]; + copy(new File(source, file), new File(destination, file)); + } + } + } } diff --git a/todo.txt b/todo.txt index 3901ae507..746421b2c 100644 --- a/todo.txt +++ b/todo.txt @@ -3,10 +3,8 @@ X MovieMaker needs to be compiling as 1.6 X deal with null/missing folders for Tools and Modes X https://github.com/processing/processing/issues/2068 -_ add pref to select PDE font (so that CJKV languages work better) -_ https://github.com/processing/processing/issues/2078 - high +_ remove video library for other platforms in download _ move old Google Code SVN back to processing.org _ then cull out the old branches/tags from the Github repo _ figure out Android build w/o javac so we can remove tools.jar and javac @@ -17,8 +15,11 @@ _ "String index out of range" error _ https://github.com/processing/processing/issues/1940 _ freeze after splash screen on OS X (looks like core.jar in the path) _ https://github.com/processing/processing/issues/1872 +_ add pref to select PDE font (so that CJKV languages work better) +_ https://github.com/processing/processing/issues/2078 medium +_ use platformDelete() to remove untitled sketches? _ change to using platformDelete() instead of Base.removeDir() where possible _ verify that the OS X version uses the real call _ and doesn't just look for .Trash From 11f5b0f9902a96607de284f45423cf2ebd3e4f37 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 21 Sep 2013 09:52:48 -0400 Subject: [PATCH 055/556] fixes for Xcode 5 --- build/macosx/appbundler/build.xml | 2 +- build/macosx/appbundler/native/main.m | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/macosx/appbundler/build.xml b/build/macosx/appbundler/build.xml index e0a5e5b3b..f2af99aea 100644 --- a/build/macosx/appbundler/build.xml +++ b/build/macosx/appbundler/build.xml @@ -85,7 +85,7 @@ questions. - + diff --git a/build/macosx/appbundler/native/main.m b/build/macosx/appbundler/native/main.m index 516efb08f..5386ac60c 100644 --- a/build/macosx/appbundler/native/main.m +++ b/build/macosx/appbundler/native/main.m @@ -98,13 +98,13 @@ int launch(char *commandName) { // execute privileged NSString *privileged = [infoDictionary objectForKey:@JVM_RUN_PRIVILEGED]; - if ( privileged != nil && getuid() != 0 ) { + if (privileged != nil && getuid() != 0) { NSDictionary *error = [NSDictionary new]; NSString *script = [NSString stringWithFormat:@"do shell script \"\\\"%@\\\" > /dev/null 2>&1 &\" with administrator privileges", [NSString stringWithCString:commandName encoding:NSASCIIStringEncoding]]; NSAppleScript *appleScript = [[NSAppleScript new] initWithSource:script]; if ([appleScript executeAndReturnError:&error]) { // This means we successfully elevated the application and can stop in here. - return; + return 0; // Should this return 'error' instead? [fry] } } From 148a201a7c5cecf6da80304f694f00169a82684c Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 21 Sep 2013 09:53:04 -0400 Subject: [PATCH 056/556] further cleanup to XML plisting --- .../com/oracle/appbundler/AppBundlerTask.java | 329 +++++++----------- 1 file changed, 123 insertions(+), 206 deletions(-) diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index 1269942b4..a5f01ba64 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -36,8 +36,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; -import java.io.StringReader; -import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.URL; @@ -51,17 +49,6 @@ import java.util.Stack; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Task; @@ -527,13 +514,13 @@ public class AppBundlerTask extends Task { } - class SimpleXML { + class PropertyLister { PrintWriter writer; - int indentSpaces; + int indentSpaces = 2; // int indentLevel; Stack elements = new Stack<>(); - public SimpleXML(OutputStream output) throws UnsupportedEncodingException { + public PropertyLister(OutputStream output) throws UnsupportedEncodingException { OutputStreamWriter osw = new OutputStreamWriter(output, "UTF-8"); writer = new PrintWriter(osw); } @@ -576,14 +563,21 @@ public class AppBundlerTask extends Task { writer.println(""); } - void writeKey(String key) { + void writeSingle(String tag, String content) { emitIndent(); - writer.println("" + key + ""); + writer.println("<" + tag + ">" + content + ""); + } + + void writeKey(String key) { + writeSingle(KEY_TAG, key); +// emitIndent(); +// writer.println("" + key + ""); } void writeString(String value) { - emitIndent(); - writer.println("" + value + ""); +// emitIndent(); +// writer.println("" + value + ""); + writeSingle(STRING_TAG, value); } void writeBoolean(boolean value) { @@ -607,216 +601,139 @@ public class AppBundlerTask extends Task { private void writeInfoPlist(File file) throws IOException { -// Writer out = new BufferedWriter(new FileWriter(file)); -//// StringWriter out = new StringWriter(); -// XMLOutputFactory output = XMLOutputFactory.newInstance(); -// -// try { -// XMLStreamWriter xout = output.createXMLStreamWriter(out); FileOutputStream output = new FileOutputStream(file); - SimpleXML xout = new SimpleXML(output); + PropertyLister xout = new PropertyLister(output); - // Write XML declaration -// xout.writeStartDocument(); -// xout.writeCharacters("\n"); + xout.println(PLIST_DTD); - // Write plist DTD declaration -// xout.writeDTD(PLIST_DTD); -// xout.writeCharacters("\n"); - xout.println(PLIST_DTD); + // Begin root element + xout.writeStartElement(PLIST_TAG, PLIST_VERSION_ATTRIBUTE, "1.0"); - // Begin root element -// xout.writeStartElement(PLIST_TAG); -// xout.writeAttribute(PLIST_VERSION_ATTRIBUTE, "1.0"); -// xout.writeCharacters("\n"); - xout.writeStartElement(PLIST_TAG, PLIST_VERSION_ATTRIBUTE, "1.0"); + // Begin root dictionary + xout.writeStartElement(DICT_TAG); - // Begin root dictionary + // Write bundle properties + xout.writeProperty("CFBundleDevelopmentRegion", "English"); + xout.writeProperty("CFBundleExecutable", executableName); + xout.writeProperty("CFBundleIconFile", (icon == null) ? DEFAULT_ICON_NAME : icon.getName()); + xout.writeProperty("CFBundleIdentifier", identifier); + xout.writeProperty("CFBundleDisplayName", displayName); + xout.writeProperty("CFBundleInfoDictionaryVersion", "6.0"); + xout.writeProperty("CFBundleName", name); + xout.writeProperty("CFBundlePackageType", OS_TYPE_CODE); + xout.writeProperty("CFBundleShortVersionString", shortVersion); + xout.writeProperty("CFBundleVersion", version); + xout.writeProperty("CFBundleSignature", signature); + xout.writeProperty("NSHumanReadableCopyright", copyright); + + if (applicationCategory != null) { + xout.writeProperty("LSApplicationCategoryType", applicationCategory); + } + + if (highResolutionCapable) { + xout.writeKey("NSHighResolutionCapable"); + xout.writeBoolean(true); + } + + // Write runtime + if (runtime != null) { + xout.writeProperty("JVMRuntime", runtime.getDir().getParentFile().getParentFile().getName()); + } + + if (privileged != null) { + xout.writeProperty("JVMRunPrivileged", privileged); + } + + if (workingDirectory != null) { + xout.writeProperty("WorkingDirectory", workingDirectory); + } + + // Write main class name + xout.writeProperty("JVMMainClassName", mainClassName); + + + // Write CFBundleDocument entries + xout.writeKey("CFBundleDocumentTypes"); + + xout.writeStartElement(ARRAY_TAG); + + for (BundleDocument bundleDocument: bundleDocuments) { xout.writeStartElement(DICT_TAG); -// xout.writeCharacters("\n"); - - // Write bundle properties - xout.writeProperty("CFBundleDevelopmentRegion", "English"); - xout.writeProperty("CFBundleExecutable", executableName); - xout.writeProperty("CFBundleIconFile", (icon == null) ? DEFAULT_ICON_NAME : icon.getName()); - xout.writeProperty("CFBundleIdentifier", identifier); - xout.writeProperty("CFBundleDisplayName", displayName); - xout.writeProperty("CFBundleInfoDictionaryVersion", "6.0"); - xout.writeProperty("CFBundleName", name); - xout.writeProperty("CFBundlePackageType", OS_TYPE_CODE); - xout.writeProperty("CFBundleShortVersionString", shortVersion); - xout.writeProperty("CFBundleVersion", version); - xout.writeProperty("CFBundleSignature", signature); - xout.writeProperty("NSHumanReadableCopyright", copyright); - - if (applicationCategory != null) { - xout.writeProperty("LSApplicationCategoryType", applicationCategory); - } - - if (highResolutionCapable) { - xout.writeKey("NSHighResolutionCapable"); - xout.writeBoolean(true); - } - - // Write runtime - if (runtime != null) { - xout.writeProperty("JVMRuntime", runtime.getDir().getParentFile().getParentFile().getName()); - } - - if (privileged != null) { - xout.writeProperty("JVMRunPrivileged", privileged); - } - - if (workingDirectory != null) { - xout.writeProperty("WorkingDirectory", workingDirectory); - } - - // Write main class name - xout.writeProperty("JVMMainClassName", mainClassName); - - - // Write CFBundleDocument entries - xout.writeKey("CFBundleDocumentTypes"); + xout.writeKey("CFBundleTypeExtensions"); xout.writeStartElement(ARRAY_TAG); + for (String extension : bundleDocument.getExtensions()) { + xout.writeString(extension); + } + xout.writeEndElement(); - for (BundleDocument bundleDocument: bundleDocuments) { - xout.writeStartElement(DICT_TAG); - - xout.writeKey("CFBundleTypeExtensions"); - xout.writeStartElement(ARRAY_TAG); - for (String extension : bundleDocument.getExtensions()) { - xout.writeString(extension); - } - xout.writeEndElement(); - - if (bundleDocument.hasIcon()) { - xout.writeKey("CFBundleTypeIconFile"); - xout.writeString(bundleDocument.getIcon()); - } - - xout.writeKey("CFBundleTypeName"); - xout.writeString(bundleDocument.getName()); - - xout.writeKey("CFBundleTypeRole"); - xout.writeString(bundleDocument.getRole()); - - xout.writeKey("LSTypeIsPackage"); - xout.writeBoolean(bundleDocument.isPackage()); - - xout.writeEndElement(); + if (bundleDocument.hasIcon()) { + xout.writeKey("CFBundleTypeIconFile"); + xout.writeString(bundleDocument.getIcon()); } - xout.writeEndElement(); + xout.writeKey("CFBundleTypeName"); + xout.writeString(bundleDocument.getName()); - // Write architectures - xout.writeKey("LSArchitecturePriority"); + xout.writeKey("CFBundleTypeRole"); + xout.writeString(bundleDocument.getRole()); - xout.writeStartElement(ARRAY_TAG); - - for (String architecture : architectures) { - xout.writeString(architecture); - } + xout.writeKey("LSTypeIsPackage"); + xout.writeBoolean(bundleDocument.isPackage()); xout.writeEndElement(); + } - // Write Environment - xout.writeKey("LSEnvironment"); - xout.writeStartElement(DICT_TAG); - xout.writeKey("LC_CTYPE"); - xout.writeString("UTF-8"); - xout.writeEndElement(); - - // Write options - xout.writeKey("JVMOptions"); - - xout.writeStartElement(ARRAY_TAG); - - for (String option : options) { - xout.writeString(option); - } - - xout.writeEndElement(); - - // Write arguments - xout.writeKey("JVMArguments"); - - xout.writeStartElement(ARRAY_TAG); - - for (String argument : arguments) { - xout.writeString(argument); - } - - xout.writeEndElement(); - - // End root dictionary - xout.writeEndElement(); - - // End root element - xout.writeEndElement(); - - // Close document - xout.writeEndDocument(); - -// out.flush(); -// } catch (XMLStreamException exception) { -// throw new IOException(exception); -// } finally { -// out.close(); -// } -// try { -//// TransformerFactory factory = TransformerFactory.newInstance(); -//// Transformer transformer = factory.newTransformer(); -////// transformer.setOutputProperty(OutputKeys.METHOD, "xml"); -////// transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8"); -//// transformer.setOutputProperty(OutputKeys.INDENT, "yes"); -////// transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); -//// -//// StringWriter formatted = new StringWriter(); -//// transformer.transform(new StreamSource(new StringReader(out.toString())), -//// new StreamResult(formatted)); -//// System.out.println(formatted); -// -// FileWriter fw = new FileWriter(file); -//// fw.write(formatted.toString()); -// fw.write(out.toString()); -// fw.flush(); -// fw.close(); -// -// } catch (Exception e) { -// -//// } catch (TransformerConfigurationException tce) { -//// throw new IOException(tce); -//// } catch (TransformerException te) { -//// throw new IOException(te); -// } - } - - - private void writeKey(XMLStreamWriter xout, String key) throws XMLStreamException { - xout.writeStartElement(KEY_TAG); - xout.writeCharacters(key); xout.writeEndElement(); - xout.writeCharacters("\n"); - } + // Write architectures + xout.writeKey("LSArchitecturePriority"); + + xout.writeStartElement(ARRAY_TAG); + + for (String architecture : architectures) { + xout.writeString(architecture); + } - private void writeString(XMLStreamWriter xout, String value) throws XMLStreamException { - xout.writeStartElement(STRING_TAG); - xout.writeCharacters(value); xout.writeEndElement(); - xout.writeCharacters("\n"); - } + // Write Environment + xout.writeKey("LSEnvironment"); + xout.writeStartElement(DICT_TAG); + xout.writeKey("LC_CTYPE"); + xout.writeString("UTF-8"); + xout.writeEndElement(); - private void writeBoolean(XMLStreamWriter xout, boolean value) throws XMLStreamException { - xout.writeEmptyElement(value ? "true" : "false"); - } + // Write options + xout.writeKey("JVMOptions"); + xout.writeStartElement(ARRAY_TAG); - private void writeProperty(XMLStreamWriter xout, String key, String value) throws XMLStreamException { - writeKey(xout, key); - writeString(xout, value); + for (String option : options) { + xout.writeString(option); + } + + xout.writeEndElement(); + + // Write arguments + xout.writeKey("JVMArguments"); + + xout.writeStartElement(ARRAY_TAG); + + for (String argument : arguments) { + xout.writeString(argument); + } + + xout.writeEndElement(); + + // End root dictionary + xout.writeEndElement(); + + // End root element + xout.writeEndElement(); + + // Close document + xout.writeEndDocument(); } From 1f616001dc90cf014bf42ddf23e4154c10cd9dec Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 21 Sep 2013 10:18:46 -0400 Subject: [PATCH 057/556] more cleanup --- .../com/oracle/appbundler/AppBundlerTask.java | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index a5f01ba64..c9d256e8d 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -516,7 +516,8 @@ public class AppBundlerTask extends Task { class PropertyLister { PrintWriter writer; - int indentSpaces = 2; +// int indentSpaces = 2; + String indentSpaces = " "; // int indentLevel; Stack elements = new Stack<>(); @@ -553,23 +554,19 @@ public class AppBundlerTask extends Task { } void writeStartElement(String element) { + emitIndent(); writer.println("<" + element + ">"); // indentLevel++; elements.push(element); } void writeEndElement() { - emitIndent(); + emitOutdent(); writer.println(""); } - void writeSingle(String tag, String content) { - emitIndent(); - writer.println("<" + tag + ">" + content + ""); - } - void writeKey(String key) { - writeSingle(KEY_TAG, key); + emitSingle(KEY_TAG, key); // emitIndent(); // writer.println("" + key + ""); } @@ -577,7 +574,7 @@ public class AppBundlerTask extends Task { void writeString(String value) { // emitIndent(); // writer.println("" + value + ""); - writeSingle(STRING_TAG, value); + emitSingle(STRING_TAG, value); } void writeBoolean(boolean value) { @@ -590,11 +587,23 @@ public class AppBundlerTask extends Task { writeString(value); } - void emitIndent() { + private void emitSingle(String tag, String content) { + emitIndent(); + writer.println("<" + tag + ">" + content + ""); + } + + private void emitIndent() { for (int i = 0; i < elements.size(); i++) { - for (int j = 0; j < indentSpaces; j++) { - writer.print(' '); - } +// for (int j = 0; j < indentSpaces; j++) { +// writer.print(' '); +// } + writer.print(indentSpaces); + } + } + + private void emitOutdent() { + for (int i = 0; i < elements.size() - 1; i++) { + writer.print(indentSpaces); } } } @@ -603,6 +612,7 @@ public class AppBundlerTask extends Task { private void writeInfoPlist(File file) throws IOException { FileOutputStream output = new FileOutputStream(file); PropertyLister xout = new PropertyLister(output); + xout.writeStartDocument(); xout.println(PLIST_DTD); From ab24f64efeeafb666dcae1b54534d7874e0d4fc3 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 21 Sep 2013 10:34:30 -0400 Subject: [PATCH 058/556] further work on the plist simplification --- .../com/oracle/appbundler/AppBundlerTask.java | 135 ++---------------- .../com/oracle/appbundler/PropertyLister.java | 133 +++++++++++++++++ 2 files changed, 144 insertions(+), 124 deletions(-) create mode 100644 build/macosx/appbundler/src/com/oracle/appbundler/PropertyLister.java diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index c9d256e8d..f87a355b1 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -34,9 +34,6 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.URL; import java.nio.file.Files; @@ -45,7 +42,6 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Iterator; -import java.util.Stack; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -97,14 +93,6 @@ public class AppBundlerTask extends Task { private static final String DEFAULT_ICON_NAME = "GenericApp.icns"; private static final String OS_TYPE_CODE = "APPL"; - private static final String PLIST_DTD = ""; - private static final String PLIST_TAG = "plist"; - private static final String PLIST_VERSION_ATTRIBUTE = "version"; - private static final String DICT_TAG = "dict"; - private static final String KEY_TAG = "key"; - private static final String ARRAY_TAG = "array"; - private static final String STRING_TAG = "string"; - private static final int BUFFER_SIZE = 2048; @@ -514,113 +502,15 @@ public class AppBundlerTask extends Task { } - class PropertyLister { - PrintWriter writer; -// int indentSpaces = 2; - String indentSpaces = " "; -// int indentLevel; - Stack elements = new Stack<>(); - - public PropertyLister(OutputStream output) throws UnsupportedEncodingException { - OutputStreamWriter osw = new OutputStreamWriter(output, "UTF-8"); - writer = new PrintWriter(osw); - } - - void writeStartDocument() { - writer.println(""); - } - - void writeEndDocument() { - writer.flush(); - writer.close(); - } - - void println(String line) { - writer.println(line); - } - - void writeStartElement(String element, String... args) { - emitIndent(); - writer.print("<" + element); - - for (int i = 0; i < args.length; i += 2) { - String attr = args[i]; - String value = args[i+1]; - writer.print(" " + attr + "=\"" + value + "\""); - } - writer.println(">"); -// indentLevel++; - elements.push(element); - } - - void writeStartElement(String element) { - emitIndent(); - writer.println("<" + element + ">"); -// indentLevel++; - elements.push(element); - } - - void writeEndElement() { - emitOutdent(); - writer.println(""); - } - - void writeKey(String key) { - emitSingle(KEY_TAG, key); -// emitIndent(); -// writer.println("" + key + ""); - } - - void writeString(String value) { -// emitIndent(); -// writer.println("" + value + ""); - emitSingle(STRING_TAG, value); - } - - void writeBoolean(boolean value) { - emitIndent(); - writer.println("<" + (value ? "true" : "false") + "/>"); - } - - void writeProperty(String property, String value) { - writeKey(property); - writeString(value); - } - - private void emitSingle(String tag, String content) { - emitIndent(); - writer.println("<" + tag + ">" + content + ""); - } - - private void emitIndent() { - for (int i = 0; i < elements.size(); i++) { -// for (int j = 0; j < indentSpaces; j++) { -// writer.print(' '); -// } - writer.print(indentSpaces); - } - } - - private void emitOutdent() { - for (int i = 0; i < elements.size() - 1; i++) { - writer.print(indentSpaces); - } - } - } - - private void writeInfoPlist(File file) throws IOException { FileOutputStream output = new FileOutputStream(file); PropertyLister xout = new PropertyLister(output); + + // Get started, write all necessary header info and open plist element xout.writeStartDocument(); - xout.println(PLIST_DTD); - - // Begin root element - xout.writeStartElement(PLIST_TAG, PLIST_VERSION_ATTRIBUTE, "1.0"); - // Begin root dictionary - xout.writeStartElement(DICT_TAG); + xout.writeStartDictElement(); // Write bundle properties xout.writeProperty("CFBundleDevelopmentRegion", "English"); @@ -665,13 +555,13 @@ public class AppBundlerTask extends Task { // Write CFBundleDocument entries xout.writeKey("CFBundleDocumentTypes"); - xout.writeStartElement(ARRAY_TAG); + xout.writeStartArrayElement(); for (BundleDocument bundleDocument: bundleDocuments) { - xout.writeStartElement(DICT_TAG); + xout.writeStartDictElement(); xout.writeKey("CFBundleTypeExtensions"); - xout.writeStartElement(ARRAY_TAG); + xout.writeStartArrayElement(); for (String extension : bundleDocument.getExtensions()) { xout.writeString(extension); } @@ -699,7 +589,7 @@ public class AppBundlerTask extends Task { // Write architectures xout.writeKey("LSArchitecturePriority"); - xout.writeStartElement(ARRAY_TAG); + xout.writeStartArrayElement(); for (String architecture : architectures) { xout.writeString(architecture); @@ -709,7 +599,7 @@ public class AppBundlerTask extends Task { // Write Environment xout.writeKey("LSEnvironment"); - xout.writeStartElement(DICT_TAG); + xout.writeStartDictElement(); xout.writeKey("LC_CTYPE"); xout.writeString("UTF-8"); xout.writeEndElement(); @@ -717,7 +607,7 @@ public class AppBundlerTask extends Task { // Write options xout.writeKey("JVMOptions"); - xout.writeStartElement(ARRAY_TAG); + xout.writeStartArrayElement(); for (String option : options) { xout.writeString(option); @@ -728,7 +618,7 @@ public class AppBundlerTask extends Task { // Write arguments xout.writeKey("JVMArguments"); - xout.writeStartElement(ARRAY_TAG); + xout.writeStartArrayElement(); for (String argument : arguments) { xout.writeString(argument); @@ -739,10 +629,7 @@ public class AppBundlerTask extends Task { // End root dictionary xout.writeEndElement(); - // End root element - xout.writeEndElement(); - - // Close document + // Close out the plist xout.writeEndDocument(); } diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/PropertyLister.java b/build/macosx/appbundler/src/com/oracle/appbundler/PropertyLister.java new file mode 100644 index 000000000..2b4e7aa9e --- /dev/null +++ b/build/macosx/appbundler/src/com/oracle/appbundler/PropertyLister.java @@ -0,0 +1,133 @@ +package com.oracle.appbundler; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.Stack; + + +/** + * Class that handles Info.plist files. Started because of Java's brain dead + * XML implementation doesn't have simple indentation support, but evolved + * from there to hide some of the Info.plist innards for cleaner code in the + * AppBundlerTask object. + * @author fry at processing dot org + */ +class PropertyLister { + static private final String XML_HEADER = ""; + static private final String PLIST_DTD = ""; + static private final String PLIST_TAG = "plist"; + static private final String PLIST_VERSION_ATTRIBUTE = "version"; + static private final String DICT_TAG = "dict"; + static private final String KEY_TAG = "key"; + static private final String ARRAY_TAG = "array"; + static private final String STRING_TAG = "string"; + + PrintWriter writer; + String indentSpaces = " "; + Stack elements = new Stack<>(); + + + public PropertyLister(OutputStream output) throws UnsupportedEncodingException { + OutputStreamWriter osw = new OutputStreamWriter(output, "UTF-8"); + writer = new PrintWriter(osw); + } + + + void writeStartDocument() { + writer.println(XML_HEADER); + writer.println(PLIST_DTD); + + // Begin root 'plist' element + writeStartElement(PLIST_TAG, PLIST_VERSION_ATTRIBUTE, "1.0"); + } + + + void writeEndDocument() { + // End root 'plist' element + writeEndElement(); + + writer.flush(); + writer.close(); + } + + + void writeStartElement(String element, String... args) { + emitIndent(); + writer.print("<" + element); + + for (int i = 0; i < args.length; i += 2) { + String attr = args[i]; + String value = args[i+1]; + writer.print(" " + attr + "=\"" + value + "\""); + } + writer.println(">"); + elements.push(element); + } + + + void writeStartElement(String element) { + emitIndent(); + writer.println("<" + element + ">"); + elements.push(element); + } + + + void writeStartDictElement() { + writeStartElement(DICT_TAG); + } + + + void writeStartArrayElement() { + writeStartElement(ARRAY_TAG); + } + + + void writeEndElement() { + emitOutdent(); + writer.println(""); + } + + + void writeKey(String key) { + emitSingle(KEY_TAG, key); + } + + + void writeString(String value) { + emitSingle(STRING_TAG, value); + } + + + void writeBoolean(boolean value) { + emitIndent(); + writer.println("<" + (value ? "true" : "false") + "/>"); + } + + + void writeProperty(String property, String value) { + writeKey(property); + writeString(value); + } + + + private void emitSingle(String tag, String content) { + emitIndent(); + writer.println("<" + tag + ">" + content + ""); + } + + + private void emitIndent() { + for (int i = 0; i < elements.size(); i++) { + writer.print(indentSpaces); + } + } + + + private void emitOutdent() { + for (int i = 0; i < elements.size() - 1; i++) { + writer.print(indentSpaces); + } + } +} \ No newline at end of file From cdae8066a0b5e939833b6ec213919a1241cd27c9 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 21 Sep 2013 10:45:35 -0400 Subject: [PATCH 059/556] other minor cleanups --- .../com/oracle/appbundler/AppBundlerTask.java | 138 ++++++++---------- 1 file changed, 61 insertions(+), 77 deletions(-) diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index f87a355b1..349a794dc 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -446,7 +446,7 @@ public class AppBundlerTask extends Task { private void copyClassPathRefEntries(File javaDirectory) throws IOException { - if(classPathRef != null) { + if (classPathRef != null) { org.apache.tools.ant.types.Path classpath = (org.apache.tools.ant.types.Path) classPathRef.getReferencedObject(getProject()); @@ -467,8 +467,7 @@ public class AppBundlerTask extends Task { DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject()); String[] includedFiles = directoryScanner.getIncludedFiles(); - for (int i = 0; i < includedFiles.length; i++) { - String includedFile = includedFiles[i]; + for (String includedFile : includedFiles) { File source = new File(classPathDirectory, includedFile); File destination = new File(javaDirectory, new File(includedFile).getName()); copy(source, destination); @@ -483,8 +482,7 @@ public class AppBundlerTask extends Task { DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject()); String[] includedFiles = directoryScanner.getIncludedFiles(); - for (int i = 0; i < includedFiles.length; i++) { - String includedFile = includedFiles[i]; + for (String includedFile : includedFiles) { File source = new File(libraryPathDirectory, includedFile); File destination = new File(macOSDirectory, new File(includedFile).getName()); copy(source, destination); @@ -504,133 +502,119 @@ public class AppBundlerTask extends Task { private void writeInfoPlist(File file) throws IOException { FileOutputStream output = new FileOutputStream(file); - PropertyLister xout = new PropertyLister(output); + PropertyLister plist = new PropertyLister(output); // Get started, write all necessary header info and open plist element - xout.writeStartDocument(); + plist.writeStartDocument(); // Begin root dictionary - xout.writeStartDictElement(); + plist.writeStartDictElement(); // Write bundle properties - xout.writeProperty("CFBundleDevelopmentRegion", "English"); - xout.writeProperty("CFBundleExecutable", executableName); - xout.writeProperty("CFBundleIconFile", (icon == null) ? DEFAULT_ICON_NAME : icon.getName()); - xout.writeProperty("CFBundleIdentifier", identifier); - xout.writeProperty("CFBundleDisplayName", displayName); - xout.writeProperty("CFBundleInfoDictionaryVersion", "6.0"); - xout.writeProperty("CFBundleName", name); - xout.writeProperty("CFBundlePackageType", OS_TYPE_CODE); - xout.writeProperty("CFBundleShortVersionString", shortVersion); - xout.writeProperty("CFBundleVersion", version); - xout.writeProperty("CFBundleSignature", signature); - xout.writeProperty("NSHumanReadableCopyright", copyright); + plist.writeProperty("CFBundleDevelopmentRegion", "English"); + plist.writeProperty("CFBundleExecutable", executableName); + plist.writeProperty("CFBundleIconFile", (icon == null) ? DEFAULT_ICON_NAME : icon.getName()); + plist.writeProperty("CFBundleIdentifier", identifier); + plist.writeProperty("CFBundleDisplayName", displayName); + plist.writeProperty("CFBundleInfoDictionaryVersion", "6.0"); + plist.writeProperty("CFBundleName", name); + plist.writeProperty("CFBundlePackageType", OS_TYPE_CODE); + plist.writeProperty("CFBundleShortVersionString", shortVersion); + plist.writeProperty("CFBundleVersion", version); + plist.writeProperty("CFBundleSignature", signature); + plist.writeProperty("NSHumanReadableCopyright", copyright); if (applicationCategory != null) { - xout.writeProperty("LSApplicationCategoryType", applicationCategory); + plist.writeProperty("LSApplicationCategoryType", applicationCategory); } if (highResolutionCapable) { - xout.writeKey("NSHighResolutionCapable"); - xout.writeBoolean(true); + plist.writeKey("NSHighResolutionCapable"); + plist.writeBoolean(true); } - // Write runtime if (runtime != null) { - xout.writeProperty("JVMRuntime", runtime.getDir().getParentFile().getParentFile().getName()); + plist.writeProperty("JVMRuntime", runtime.getDir().getParentFile().getParentFile().getName()); } if (privileged != null) { - xout.writeProperty("JVMRunPrivileged", privileged); + plist.writeProperty("JVMRunPrivileged", privileged); } if (workingDirectory != null) { - xout.writeProperty("WorkingDirectory", workingDirectory); + plist.writeProperty("WorkingDirectory", workingDirectory); } // Write main class name - xout.writeProperty("JVMMainClassName", mainClassName); - + plist.writeProperty("JVMMainClassName", mainClassName); // Write CFBundleDocument entries - xout.writeKey("CFBundleDocumentTypes"); - - xout.writeStartArrayElement(); - + plist.writeKey("CFBundleDocumentTypes"); + plist.writeStartArrayElement(); for (BundleDocument bundleDocument: bundleDocuments) { - xout.writeStartDictElement(); + plist.writeStartDictElement(); - xout.writeKey("CFBundleTypeExtensions"); - xout.writeStartArrayElement(); + plist.writeKey("CFBundleTypeExtensions"); + plist.writeStartArrayElement(); for (String extension : bundleDocument.getExtensions()) { - xout.writeString(extension); + plist.writeString(extension); } - xout.writeEndElement(); + plist.writeEndElement(); if (bundleDocument.hasIcon()) { - xout.writeKey("CFBundleTypeIconFile"); - xout.writeString(bundleDocument.getIcon()); + plist.writeKey("CFBundleTypeIconFile"); + plist.writeString(bundleDocument.getIcon()); } - xout.writeKey("CFBundleTypeName"); - xout.writeString(bundleDocument.getName()); + plist.writeKey("CFBundleTypeName"); + plist.writeString(bundleDocument.getName()); - xout.writeKey("CFBundleTypeRole"); - xout.writeString(bundleDocument.getRole()); + plist.writeKey("CFBundleTypeRole"); + plist.writeString(bundleDocument.getRole()); - xout.writeKey("LSTypeIsPackage"); - xout.writeBoolean(bundleDocument.isPackage()); + plist.writeKey("LSTypeIsPackage"); + plist.writeBoolean(bundleDocument.isPackage()); - xout.writeEndElement(); + plist.writeEndElement(); } - - xout.writeEndElement(); + plist.writeEndElement(); // Write architectures - xout.writeKey("LSArchitecturePriority"); - - xout.writeStartArrayElement(); - + plist.writeKey("LSArchitecturePriority"); + plist.writeStartArrayElement(); for (String architecture : architectures) { - xout.writeString(architecture); + plist.writeString(architecture); } - - xout.writeEndElement(); + plist.writeEndElement(); // Write Environment - xout.writeKey("LSEnvironment"); - xout.writeStartDictElement(); - xout.writeKey("LC_CTYPE"); - xout.writeString("UTF-8"); - xout.writeEndElement(); + plist.writeKey("LSEnvironment"); + plist.writeStartDictElement(); + plist.writeKey("LC_CTYPE"); + plist.writeString("UTF-8"); + plist.writeEndElement(); // Write options - xout.writeKey("JVMOptions"); - - xout.writeStartArrayElement(); - + plist.writeKey("JVMOptions"); + plist.writeStartArrayElement(); for (String option : options) { - xout.writeString(option); + plist.writeString(option); } - - xout.writeEndElement(); + plist.writeEndElement(); // Write arguments - xout.writeKey("JVMArguments"); - - xout.writeStartArrayElement(); - + plist.writeKey("JVMArguments"); + plist.writeStartArrayElement(); for (String argument : arguments) { - xout.writeString(argument); + plist.writeString(argument); } - - xout.writeEndElement(); + plist.writeEndElement(); // End root dictionary - xout.writeEndElement(); + plist.writeEndElement(); // Close out the plist - xout.writeEndDocument(); + plist.writeEndDocument(); } From 5d97a9c0bcb9bdcb9a1b5a0fe00e13f64dc3d50b Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 21 Sep 2013 12:22:00 -0400 Subject: [PATCH 060/556] the Contents/Java switch ain't all that useful --- app/src/processing/app/Base.java | 10 +++--- build/build-7u40.xml | 8 +---- build/macosx/appbundler/native/main.m | 33 +++++++++++++++---- .../com/oracle/appbundler/AppBundlerTask.java | 4 +++ todo.txt | 12 ++++--- 5 files changed, 45 insertions(+), 22 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 8a0052502..44cb895df 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2355,14 +2355,16 @@ public class Base { // This works for Windows, Linux, and Apple's Java 6 on OS X. processingRoot = jarFolder.getParentFile(); } else if (Base.isMacOS()) { - // This works for Java 7 on OS X. + // This works for Java 7 on OS X. The 'lib' folder is not part of the + // classpath on OS X, and adding it creates more problems than it's + // worth. processingRoot = jarFolder; } if (processingRoot == null || !processingRoot.exists()) { // Try working directory instead (user.dir, different from user.home) - Base.log("Could not find lib folder via " + - jarFolder.getAbsolutePath() + - ", switching to user.dir"); + System.err.println("Could not find lib folder via " + + jarFolder.getAbsolutePath() + + ", switching to user.dir"); processingRoot = new File(System.getProperty("user.dir")); } } diff --git a/build/build-7u40.xml b/build/build-7u40.xml index 73b45d858..f8f2d19d3 100755 --- a/build/build-7u40.xml +++ b/build/build-7u40.xml @@ -408,7 +408,7 @@ - @@ -515,12 +515,6 @@ - - - diff --git a/build/macosx/appbundler/native/main.m b/build/macosx/appbundler/native/main.m index 5386ac60c..4a365e304 100644 --- a/build/macosx/appbundler/native/main.m +++ b/build/macosx/appbundler/native/main.m @@ -142,17 +142,21 @@ int launch(char *commandName) { // Set the class path NSString *mainBundlePath = [mainBundle bundlePath]; - NSString *javaPath = [mainBundlePath stringByAppendingString:@"/Contents/Java"]; - //NSMutableString *classPath = [NSMutableString stringWithFormat:@"-Djava.class.path=%@/Classes", javaPath]; + NSString *javaPath = + [mainBundlePath stringByAppendingString:@"/Contents/Java"]; + // Changed Contents/Java to the old Contents/Resources/Java [fry] + //[mainBundlePath stringByAppendingString:@"/Contents/Resources/Java"]; // Removed the /Classes, because the P5 compiler (ECJ?) will throw an - // error if it doesn't exist. But it's harmless to leave this as including - // the root dir, since it will always exist, and I guess if you wanted to - // put .class files in there, they'd work. If I knew more Cocoa, I'd just - // make this an empty string to start, to be appended a few lines later. + // error if it doesn't exist. But it's harmless to leave the root dir, + // since it will always exist, and I guess if you wanted to put .class + // files in there, they'd work. If I knew more Cocoa, I'd just make this + // an empty string to start, to be appended a few lines later. [fry] + //NSMutableString *classPath = [NSMutableString stringWithFormat:@"-Djava.class.path=%@/Classes", javaPath]; NSMutableString *classPath = [NSMutableString stringWithFormat:@"-Djava.class.path=%@", javaPath]; NSFileManager *defaultFileManager = [NSFileManager defaultManager]; - NSArray *javaDirectoryContents = [defaultFileManager contentsOfDirectoryAtPath:javaPath error:nil]; + NSArray *javaDirectoryContents = + [defaultFileManager contentsOfDirectoryAtPath:javaPath error:nil]; if (javaDirectoryContents == nil) { [[NSException exceptionWithName:@JAVA_LAUNCH_ERROR reason:NSLocalizedString(@"JavaDirectoryNotFound", @UNSPECIFIED_ERROR) @@ -165,6 +169,21 @@ int launch(char *commandName) { } } + /* + // search the 'lib' subfolder as well [fry] + NSString *libPath = + [mainBundlePath stringByAppendingString:@"/Contents/Resources/Java/lib"]; + NSArray *libDirectoryContents = + [defaultFileManager contentsOfDirectoryAtPath:libPath error:nil]; + if (libDirectoryContents != nil) { + for (NSString *file in libDirectoryContents) { + if ([file hasSuffix:@".jar"]) { + [classPath appendFormat:@":%@/%@", libPath, file]; + } + } + } + */ + // Set the library path NSString *libraryPath = [NSString stringWithFormat:@"-Djava.library.path=%@/Contents/MacOS", mainBundlePath]; diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index 349a794dc..9f5931412 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -330,6 +330,10 @@ public class AppBundlerTask extends Task { File resourcesDirectory = new File(contentsDirectory, "Resources"); resourcesDirectory.mkdir(); +// // Move back to Contents/Resources/Java instead of Contents/Java [fry] +// File javaDirectory = new File(resourcesDirectory, "Java"); +// javaDirectory.mkdir(); + // Generate Info.plist File infoPlistFile = new File(contentsDirectory, "Info.plist"); infoPlistFile.createNewFile(); diff --git a/todo.txt b/todo.txt index 746421b2c..3640a227f 100644 --- a/todo.txt +++ b/todo.txt @@ -2,6 +2,9 @@ X MovieMaker needs to be compiling as 1.6 X deal with null/missing folders for Tools and Modes X https://github.com/processing/processing/issues/2068 +o bad JS mode causing crash on startup +X https://github.com/processing/processing/issues/2088 +X looks like issue that was covered in 2.0.3 changes high _ remove video library for other platforms in download @@ -35,10 +38,11 @@ X the "Classes" folder is included X appears to be line 138 of main.m o maybe this is a holdover from OS X Java? don't know. _ icon location uses path, even when embedded -_ add indents to the Info.plist output file -_ inside writeInfoPlist from AppBundlerTask.java -_ use Contents/Resources/Java instead of Contents/Java? -_ this is in main.m. why the change? +X add indents to the Info.plist output file +X inside writeInfoPlist from AppBundlerTask.java +o use Contents/Resources/Java instead of Contents/Java? +o this is in main.m. why the change? +X doesn't make any difference, just use Contents/Java _ any missing args from our app (copyrights/versions?) _ make sure it's only running on 64-bit machines? _ add MinimumSystemVersion? From bd27e998c4d3775a39658a50078c727042544b5a Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 21 Sep 2013 14:29:15 -0400 Subject: [PATCH 061/556] remove unused video lib files, add icon bundle stuff --- build/build-7u40.xml | 127 +++++++----------- build/build.xml | 53 -------- .../com/oracle/appbundler/AppBundlerTask.java | 43 ++++-- .../com/oracle/appbundler/BundleDocument.java | 23 +++- todo.txt | 6 + 5 files changed, 107 insertions(+), 145 deletions(-) diff --git a/build/build-7u40.xml b/build/build-7u40.xml index f8f2d19d3..ff8e22b78 100755 --- a/build/build-7u40.xml +++ b/build/build-7u40.xml @@ -134,7 +134,6 @@ - @@ -146,7 +145,6 @@ - @@ -154,19 +152,8 @@ - - - - - - - - - - - - - + + @@ -378,8 +365,6 @@ - - @@ -415,10 +400,12 @@ --> + @@ -512,14 +501,15 @@ + - @@ -538,7 +528,8 @@ $JAVAROOT/lib/about.jpg --> - + - - + + + + + + + @@ -614,57 +612,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ======================================================= - Processing for Mac OS X was built. Grab the image from - - macosx/processing-${version}.dmg - ======================================================= - - - @@ -723,6 +670,11 @@ + + + + + @@ -856,6 +808,29 @@ + + + + + + + + + + + + + - - @@ -494,57 +492,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ======================================================= - Processing for Mac OS X was built. Grab the image from - - macosx/processing-${version}.dmg - ======================================================= - - - diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index 9f5931412..f5e238107 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -66,10 +66,11 @@ public class AppBundlerTask extends Task { private File icon = null; private String executableName = EXECUTABLE_NAME; - private String shortVersion = "1.0"; - private String version = "1.0"; + private String shortVersion = null; //"1.0"; + private String version = null; //"1.0"; private String signature = "????"; - private String copyright = ""; + private String copyright = null; //""; + private String getInfo = null; private String privileged = null; private String workingDirectory = null; @@ -146,6 +147,11 @@ public class AppBundlerTask extends Task { } + public void setGetInfo(String getInfo) { + this.getInfo = getInfo; + } + + public void setPrivileged(String privileged) { this.privileged = privileged; } @@ -367,6 +373,9 @@ public class AppBundlerTask extends Task { // Copy icon to Resources folder copyIcon(resourcesDirectory); + + // Copy the bundle/document icons as well + copyBundleIcons(resourcesDirectory); } catch (IOException exception) { throw new BuildException(exception); @@ -387,22 +396,19 @@ public class AppBundlerTask extends Task { if (zipEntry.isDirectory()) { file.mkdir(); } else { - OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE); - + OutputStream outputStream = + new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE); try { int b = zipInputStream.read(); while (b != -1) { outputStream.write(b); b = zipInputStream.read(); } - outputStream.flush(); } finally { outputStream.close(); } - } - zipEntry = zipInputStream.getNextEntry(); } } finally { @@ -497,12 +503,23 @@ public class AppBundlerTask extends Task { private void copyIcon(File resourcesDirectory) throws IOException { if (icon == null) { - copy(getClass().getResource(DEFAULT_ICON_NAME), new File(resourcesDirectory, DEFAULT_ICON_NAME)); + copy(getClass().getResource(DEFAULT_ICON_NAME), + new File(resourcesDirectory, DEFAULT_ICON_NAME)); } else { copy(icon, new File(resourcesDirectory, icon.getName())); } } - + + + private void copyBundleIcons(File resourcesDirectory) throws IOException { + for (BundleDocument bundleDocument : bundleDocuments) { + if (bundleDocument.hasIcon()) { + File iconFile = bundleDocument.getIconFile(); + copy(iconFile, new File(resourcesDirectory, iconFile.getName())); + } + } + } + private void writeInfoPlist(File file) throws IOException { FileOutputStream output = new FileOutputStream(file); @@ -527,6 +544,10 @@ public class AppBundlerTask extends Task { plist.writeProperty("CFBundleVersion", version); plist.writeProperty("CFBundleSignature", signature); plist.writeProperty("NSHumanReadableCopyright", copyright); + + if (getInfo != null) { + plist.writeProperty("CFBundleGetInfoString", getInfo); + } if (applicationCategory != null) { plist.writeProperty("LSApplicationCategoryType", applicationCategory); @@ -567,7 +588,7 @@ public class AppBundlerTask extends Task { if (bundleDocument.hasIcon()) { plist.writeKey("CFBundleTypeIconFile"); - plist.writeString(bundleDocument.getIcon()); + plist.writeString(bundleDocument.getIconName()); } plist.writeKey("CFBundleTypeName"); diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java b/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java index 3e64dbb2c..a959f08c4 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java @@ -23,6 +23,8 @@ package com.oracle.appbundler; +import java.io.File; + import org.apache.tools.ant.BuildException; @@ -33,6 +35,7 @@ public class BundleDocument { private String name = "editor"; private String role = ""; private String icon = null; + private File iconFile; private String[] extensions; private boolean isPackage = false; @@ -55,8 +58,9 @@ public class BundleDocument { public void setIcon(String icon) { this.icon = icon; + this.iconFile = new File(icon); } - + public void setName(String name) { this.name = name; } @@ -73,10 +77,19 @@ public class BundleDocument { } } - public String getIcon() { - return icon; +// public String getIcon() { +// return icon; +// } + + public String getIconName() { + return iconFile.getName(); } - + + + public File getIconFile() { + return iconFile; + } + public String getName() { return name; } @@ -100,7 +113,7 @@ public class BundleDocument { @Override public String toString() { StringBuilder s = new StringBuilder(getName()); - s.append(" ").append(getRole()).append(" ").append(getIcon()). append(" "); + s.append(" ").append(getRole()).append(" ").append(getIconName()). append(" "); for(String extension : extensions) { s.append(extension).append(" "); } diff --git a/todo.txt b/todo.txt index 3640a227f..977f567f8 100644 --- a/todo.txt +++ b/todo.txt @@ -33,6 +33,8 @@ _ changing modes brings the PDE back on the second screen _ the Find window (also the save windows) also have the same problem 7u40 switch +_ remove Mangler from tools/Mangler +_ update tools/howto.txt to just point at the correct online location _ appbundler fixes/changes X the "Classes" folder is included X appears to be line 138 of main.m @@ -51,6 +53,10 @@ _ don't re-copy jre into work folder if already exists _ change how export is handled _ remove ability to export cross-platform apps _ add ability to embed the current JRE +_ change app stub in OS X exported application +_ we become full 64-bit on OS X +_ meaning that the macosx32 video library goes away +_ and the preference for launching in 32- or 64-bit mode no good installer, will need JDK anyway for the export require that this folder exists: From da39a2a1a4e6b0059ae7b4da19ea6dad7bb8fa39 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 21 Sep 2013 15:28:19 -0400 Subject: [PATCH 062/556] replace crusty icon with generic document icon --- build/macosx/pde.icns | Bin 42258 -> 148757 bytes todo.txt | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/build/macosx/pde.icns b/build/macosx/pde.icns index 214b19877ae38e580adf5e2466aceaa6f6b798a6..9f697634cd434b57b6428d53e75f921802816b1f 100644 GIT binary patch literal 148757 zcmeFYXH=BU(kS}OFu)8TS%Rct7y$(dih#sHvg9NP5(E*Eq!J`EgJh5(C@N9Opacbx zJSaIx&LW7!A?M7T2lsx@{`UFyy=UEZ?ppW9eS0nKs;-{y>guX`x~mI&8)sJls(jW^ zM-d4Cz2QFd>khMSX zcJL}>`wz4qyan0+104kKKo0&uN5Kb>qdyQa_yj`yHwXYiL6&gDZ~)}*Zx;XGkm6s8 z1ONh(|0tlE{V9^fe-u!U{*-I~#EGCnotFQJ|Fc2rFFKJZbxN217cPB@%l-?OJ;mkz zh0C4d^8do+PjSq@aLg&L@Go596j%Hgu6T+o{R>w*#g+esEB_~4T*u_DgR`^4T@xK~ z0Qk$0aKvZ8Gf>Gw=E!EJC%T*TfGAM0=Yj{x2l~6ezMs$nB2V#7z!pO2C}L#rTk6TdcCR|9#}HsK^asV* zXlE+%WPhVm6$k;Fmcqsff#EqN_mcRe;oLyWjSIJ{$r%O zxiafT{68Ch!6$!=^t9KP7XE2ii<~C^H9p$c+3@Wjc+?Ep)WleSSN9)u{n;$(^yJv! zk3ZPPvw70FnO_srf3U5XMUwd$!XJ1$W{G5Re)S)4>@sv|;}5tKw+3q7DQ~-R>yX_) z(0<&hC7-tK$8G-;I*2>9>C?8uxP8dsALuCV)VfdGj^Ymg7YG32PXLhiSN#HnUx3#B z_m=#rW1AlH*|yl4c+K}L%;bq{T~wezmWg`Z{#C+*Xci$yMLX;019UA|4^7IPNnzP z4Io@sTlEaZxzn~Y>S{{*V2wTf2PXsn|0Z{*9lSQ6?G+Vu)fE+yx{qD%**n?-fFxb8 z(S*yGA){Qli+(1PJkmrpG@`M{$iS?E?c9eZGWGbZ{3&R)D(^3-Qd2Hlk3!n3K zd~gzEM-a>i35}Wz_Zc#4pOGDWsk%Yv#e8)&pZNwFZr){5qhD1X)_evHx3>@4uT5N= zlb*8}Q> z+n3{3PPBJ;>bxU=^n{~y@XlvB{8;y>^g8+-K5H=6kst2amy`Y2WMAtOhd~RViGIoS zo;}TcvfAA8i0JN%i)TN;tI1@lhwllO-?1cNX^H=3wOUn<8KgoWQ`t&@^q0~Bj;4bRJ&Qj8|eSYy(3yc!Utu6F85kGHJtOgEZ(7I*_b-1D}h8yzOCN@X66 zO&jlBawB8$8kVn?5}qYvA2aXQxBi@gSDjZ<;?ZWhWId2~LpoD8^>RW(jf%L;`O7Uq z!Qa~Nh@y0Q=^e+tuEqRr4vPB7TyyE2UY2xo(Zjmd5)*lY5y%mj^`|8fHamvQVu|6T zCAdbtR6R8*#bYO_vlsjP__sH!b=(b^q_lN6jxc`wVS3+3R?i)D#+-z_Db^6!;?e0A z6*F6AK$0`ucbDju%W-g!U!s<2Bdgl`zFh0z;CA$A^VxW$Q?q!nbJORqd&5N~myVqD zq0&~~5ij4it$BP!c=B+_-iGv@KeOmEd8>O=f3zeci?EOD=HacEZ;|Wht@zcQfAa1m z&pFpJm$`pJ`auw@bT-=WqMyJqzaO8U@Udou+pS8}G1~k^ZJZG4wW`&cwDZG0MV5CM z#v{z{4>+V<7+X5s9|xV`1C-l%;(ZN zj75y*JXs3aP?KR}P=OoMt+BNDY<=;Trr|A~9FN<{GcO}NrBWmK)WTOIbsCzdu0YFE ztM@GSc#E@1wol?2M5Lr9odh+{w_KS@k$QAfd5gj=sk_tMpKOBqoqB=Cpm^I^2UJ7Pc8ZPF0@A1U$8g=n0Npne@ zBNj@WleR<=nR;wDZ&K)p_E1Ie#g77?^4MA?_NUi#u5WMk5119DxLkNoWSb#x$- zdsabB6Xiuet%g>se*4bz8eu-ywe`U1P=0X9ZFeEn++&qsK{?o8<1uhRbTC@3@#(5w zSXg);)o~@SJk5psQP$a)3$+wZw#cu#S3ae*<%@j3_Uw+u>ude>pOq}h%VTeU9gFKo zlMf(_S3UX7z`zjG)ZAQmd4I7dLsi(k&j0x3S@|n|Hd40BIr`gVwz8N`Dqt^CYlsC> z`%&atJ!J&25f(H*J$={W9=he5=?C$hrIAna%Rg%lhlUEx4`Z~LVnpoUpb;iDwlE1A zNQmYL^f?o*3k{Rwo<=HJ*7?`Ctxq*3btPZhoa2!8IKt-(Ni>p`9lX5X8(Pi)zSvb;AsqlQn=_4QqsQ?19b6bQrVB01b|>Sv zNFYH$=`#C+0S`>a%Fmjr`Ib1IG^er8PEU>cJYuO3*4U8X=jX8ibvcmKC5WiOzlUnb z`0mACdh0RY{kG5Sv*UiD?WHS?JiH2lEU@B=oy0K4XV*6py527rBCA~Iw8h25U(@!U8D`MKi;sBhv#2Oti?O-@BJ*IQuuhuXu>@sWlD0|84LQDt zG*#<1g2BqB z6JFBL(~{p#q0GI(nZ9@nD+95W;htv4$m9B#?C;oi!B!y9%rFX>;5ME!tlieP?QqP( z7Sq#{>{w>ZqS$AXL&3cnC31; zpsS_7+}*cK+BsT5@qeQ7oF#4l#`j4V+8P@&sjVr9KH&_rBIfpO7B^S4-_H;97u=6jR454S$?npJr?efHiaIF5X@ zy(YROkeLh{T-AvIeZWXmINz(%t<1QKgiR(s44Wb8qT0!jMs+c;2HF!l%6_m zJkZDTHjNYuiK8tS>YkZ`a82rchKZr6A9>-XZYgXpRef6`3>1uP%(Qa8x@A?KL9qB3o*Kviq+n&!l zBC|K=y6g&WelWd1!I50!ces;dTzGrGe1P@JvmK_ArRKN3^gEaO==#cbS0{*(!G7nV zp|p+e3{yY7jw2uMDKY{SF-D8ZILsY5ugmZ^MuYeN4e_Y!c4ZHTHek zT%+47w~mLheLp&PQgQ^Pl+mSWb%~!V&Asfyd+B1fVbHp*%@qBVz6@?B0HS6(2h8-) ztczsI_g03qAptaxlCXK@R!UD#56@1@Z6YeN+}t&MijsX(nDrZhvX2F>>g=5T9nP+(mcJup2;BZxL!TGE@RW zxkryrRHcngpkr1rG`0`kpnagqPe1(ma<%K+_f8e;go)3I4WjFXoxIu2W~UI)x)RMW zJ<+s~hY-zzWJwAHzbZEc9+HkRl085dR^F*4M3|tU_Mc%s{%d{?CuRmK@Skr!5@sC_ zU%^_=SU+9RfB*=*hFcrCCXhq5_U#2F{*KRR1VB*rLXm7Mb53nQcivll7%;bP(;y|& zZ(CM5k3ExJL>fz)e6y$;un&rr!Tf$nOG}zR%JeMrbH1wC6bd($xoq5YB+a?QR;)N7 z@AR?dHu@q&EUtnoli*}B01YgGUfv{S#1)oec?{XUYAY=(AxC@D%oAV41aiE0rLj_( ze{6!Twf!7xAFB_zF>zylQR2;;s&O)5~wxw z;s_N*h}dAGRpYEkAe675xg1tk2WYKkf|m#QZ14DEfU5#$RnBAb;?SckC^$0ix`AG8 z@10?)7L^A0q0^wyQdPXCAvB0&`7UkV(3v@oK+f56>1Nu=;v$c+C#J%@5VBdS?zR?J zNX>8>Hm1k8WYt=V7ZTy;;~mY!4;8-7SSjE~jtS61&{h_GwUPyo`W-(E4BdR?-p4pX z`0%RY4+pBAKn*$G#>mv>+F_@D&G5vGSH)O?aag*jSC5&su?anqA|4Y^6pQGL&<~Q# zD2t$y<}JXF=wt=+F)pOs1ztSOtRi^~bsPHmqUsGp`s3KrtLgV$EK&fck*WZJMj6;_ z-OFW5gYCJFA0%6Rg-%@;^U2qqK%B;E9F^rs63Wuc16&{zP_kr1Eh&{GW(*)Ii}C)nOP5Gged_!z)dV@}vB;Uuw`Vl>P8&WPn& zgm_!;5N`J)bU6gQFVokZSqdL1aMjxd2I}AO@jQZVH7sQb6UuQ}TJs#!OkoRw8OGy#v3=l3C{D)KYic?;lnr_Zu#Xgq_1*2%PO2=hGk--IB5cRcL0NlQLPwP zq7QcVGiw+K(Tei5d|(0`xYnGf>@7A8)}m4~krY3a`-7P?P!raNR8&ITs~0}WXY8DRg; z{(aFY{~ zx3r2UguI7QU6yRPE93}l}*kpg$WDaPX6|^k}ggSsyu2v(+QFW#1q<$~-{bNQm z8=H|T#=SuuaTo8(1oGCUN%C$rI=7iR;q5xxOUU%=m+yw8ZOrut*h4!O@_*)DW?GZ2 zysW!*4@o4EH(VOZ@-_Ms9#L1;Rw}%175LW!=zkA`K){O(1o#sMx&1iz-rr%6zr!GZ zhe7@hgZv+cLAc`n83su)%QYYHZ!(@bU(TULWx-GX-ihulMa~VSVlu9NlZKmbw`KMT zik1#E7thgg5#o1BCN;8xGn${?TqNaw5tyS-!TI7Qy}FpGrsLHfG;h!S=g|{xeyss9 z-^+$ZeO9gxy>jp)Y2vgwY7V$PD>1v5Q0dwcZb02 z(~*&{w6C6=S7(0dHS=|ru&_mEqSq!x+FPXQD$S?d5T1af(>;hE2;d6`V9c#L+nWik zX;d?9&4IDB7epAj0ly7JXH-L-NaM2$g*Ws(vRbEg0ccK_^r}quBdHG)t*6(i*bP4Y zquR9Rd?+$KT5qPOL2BG@GtB___W|M&qr~!P*`j6FwYg;X;7PG7eO9WkRw;B+rrycP zquGpi;^mLlzOAp;5l_Y#sX65RkMOmAhjL?8PgcJ(Tl%g~oRW`Q=hPya4H8(AZv-ls zxuuVCWLAF*qUES3v0D|N-j>LR@yR91m%)jN5cmc<+=9pn6zRMGju72RToIxTKeDr{4MW1OON9ThI zDARbAl%z;idp!A+=43zBXJsTczfLpG>?zkHt@Q+D;bI57-@lVmVgrwfQ2Cx@7J(&D^iH6K4@y zj?wGsFbMW2h=5kJFJn{VBiVf(ed$gycrCQ>p7$nmVL~@s-fgBHnK7_E2$&B&km(lp z)9=>kf_Z~CtD_q53R+#^zBnka>F;{M6!sWzdNC0Ru;+UK9jfIdM55pWM8YjLm4?|b z+-t?O$E^ar+Fn_em(rtU%3(e`OA9GJD;3PLn;ln(rC{_ZE$d<=0B9kpESGn9Nq@bL zQA)3glkJs(5y1N*gWB(#^5x-s9}6_|=SWH?YJ8r!oT^cp|G|Rg#G_`8fP|w$ngjD(vONy<#)b?xG&gzwY&u*=(5*+ zV1%^9^h0BL^mSizK!Ys!b1fR0jlJ}PCf9y_8@Phg5URL4&Y&Z6ht34vEjsXmAK)dv zVyaRvM~V4ie#$86h1G6Ejs=WrP1x__C@>9`4r5j0q%wt9_C z&URMnsI+NYGz@8I>l2z?Y^zvq7p{BHNwLu;;uN3WA-mDSQ_BJ5ijq;{S?W`=3%PBz zA4KbT=r2>L*;p)33*0WX(S1!GC_}01<4i6Hy>2IyM`|VW#UtOCPE6Yr7A-zABj2GK zRHU(>;V~nBxb%sjRc};q)2QgYtJ$vdfFRJhmQ*>2a*`3DGyI&~?d}nFgSKA1B=1Ap z@VgZ8Y6c8;PbnPO#3v>Uh14+QT0PimhIYeiNA3&KH)k|vr^_@Lrb=yiH3-qShk88F zXrsnHfhir`hE1pGufl*5gpD*4RDTbD7Y-3!3MAF5FOghas;#{I9SYrj(Vl*#1_ zYe}$?6aHNw_hKpr&|PuaoLh#KQexQG?)V<*OHWV(^Qh}3(pY8or{>LJ0Ia=eFJpL3 z4=K+-WnkRw3V2ZVt6P=!>DIxOsgAw8`DhhbpQpu4(%Kn!@j_!oXezYsGQM69{j!mf zTHPzdH5R7|Abp8#7Td}JrOnwb&e)Vw!CW}t`RZFwmT(Cm!IpT*L1Qn6sF{q+WEk$q zWO1Sd^kcMOe8LdglJ)aNc2IgCYxu?Lt_@uauIR!cQ#u)Al8Pemu4#-!E#FDXonnLM zg}GPO-bI}@61fqi*q!bo#>Q)g(RM^bRBVL5h$mCLSA{hxHXh5+_Er$~nEs9G9i*BPlj^_rw(E{UZG9Jt7T@xzkpd&9m)MTM1ob;2 zvswhliVc;bFL)`B_RT$+@H2KlFWAA}Qm`F0m8C-HgDg9e+>-Wvt*M5@S zXI!cf>9+9W24LHvDVOAC?kG52k)NQxi!}i*V{SW!0O)}M6E8YbS%c`$CNEROB0`jq z*#sBe2Xrh!9k;4TCk2_lU!sGwT`i6h0>h4k4f0$;*$%QNURjfy7v*2k6Gbi*pBSz z+~Kn53JgZq5mngIZgg!&gUcP~5jleBPtovhk!+X7S(Bza_c#eKL(~N5Xs<2a6W|VW z-=m4>5$y8g=&%%_} zD(ekZDXt}&!O-IS!xervmGIEmG=z{aB@|VhN_k(p@bY$pNi>O~FM*k1E#`MO`LP3^ z$bG?Q^#$Ly;#w?UKPUFfGw|O8UOtB2=T6Zk!+Dm4IL4}@8DHBn=yCJa?$KQk$nUg{ z4iP7qxu(}BA-|UtPIyXV{0I)thdaw%IWg44qnSiYf8p2BnI?W37oNFa97t;_DtK!G znZKBxy4y>KO{RzI%N6mNJEm(fLdu%IR{{HMA^AlbuNlfo7A9hkFAnIWz)b+c&GFAo za147P-it+L-Xs8gBD+#YmAo6DxGCVn2=OgzN7_o@#pNmL(PN# zFu_p!+gEnyq3F8;)Bjy-K{aNJz84@HRF$~rq7KtUr6fC)o&~+P0 zu9_(E8AZwIQ6Z%>gVN(NW6kNfV5(4_67JyYi&x0JoJnXyI+G-Jh3bwrE?Rhu*w%p0 z4>zyl(nVe>kt?tup>2Skm^o)8E_7DalDYQT#HEQiSSHPl)J z8cy!U>-uhXO4Jn9omB3g9ImF((Rk3nzYZ8%j#m-#3%nC8yzN)NQVPFU!lhkMr9F6C z$)N^y>vAZn*-`koZdH81`djQ?4kwia34Grz_V8n0ybLtYQS^Sm)$mjBEtq%s=}I`(Vu6HZ|g174xd57?1$=AgX**w z(pH8`et+w?gZ__%DXz@my_tOQ7?D%0SPyU5sm(*P zhn-i4whF6ODt|UITi$-=w>7Uf>o*Tdf*8O1)5qn>gRW&j8j|V{CaYM1mN!%E22(y&~35WS>|>r!mxH`*Rh*SRCD2E zc9L_xGuz}QfZi7^)zz+g3YfX5WngY)HmIa-pVwFI zZ+30l46=Av|5W+~9ik03+Uzf2v!|Fct5EyhSX@8F^<&RjF9hKFE+ZS>Wb9YJYiY?4i!ONkob#uWl)Trsc?nLFhC>6>shS97f9C<;xPv-c#^I zd7W_cL+XZ$;8D-2)dV;4-JZ%FwT=h5h+TqkcqtRI4^;_6VmpYr7Aelwd( z_4-^MLPtK!Kj(1s+M(NXZAt_a_BxaGXm-82u>RsO>X$7~qp{xIL>7!UT=kYTc35S* zM1Ds3UR>fw#|oMqIXxqztOpq$gvfn<;?9`M?#}AOMAh-mSisI~lFLb_Q~CIgah@m? zUnd^8mvi99%m=!)QYq^8rx*_0M(R4K>NMOhTUC=V7uSoU#tv4c4=q`SFc@P1vmTPlUR~9*P2Kkt z&!5>9^HMyb-@ZziEw2UCoe~n=^k;I)wCZ^Va@p6s2150HSq+@-8cVnJU$Bm$gCN-29Pf`42^`~Vv^OYk}D=F6- zH0#OVHxrc68?nmZ_t@9-3wd5iT+9WXF{2{G+H>)8jK!_m@=F0p0hrVhsYy!&ok@l0wnZl3WLYP#{IiBq` z9-Zw;9jB>J(4%m@`>5sw;~QM=ULy%piM#44j+shI7;yraCeV@tOUx>wA)?0V9d*Vr zzT;5-tiy0}N_<12l{X*qc{2~=2)86UL)=f5=u-qcnH&0K1pfcXId#3nYEBV$4c2M~XeaC1_y(*7Q` zO8NyTYT)`Y#-fEsG*;L)9P8-S<_e4|VuG*x4;17N`@VRcwn0wK{srlW_H>}f>KN25LAPWu-!#R_08Pe|1@_wwQL21_3RHn@ z^nfGkj91)i8SbCwa-Gnojs>Fr5BB?EBPjtru17;H%&EF)!xsMDj*;UB@w%9xC=@{Fz1yFrh~$y7lXH zkE#Ly?I(@Xyx>2LKrwkaMhtUbqv=~4B9R}tCegxhRmdxF=~2|HqU2t#5&rnDv34Ds zT+5|40bA+~1KCZ!%nHi{dIT^=J=H2U+h9p`@g_izq2^FQ(nowt*TkYJVp*ot<~L>h zW5YgI67mH<#^uZI57#xd&IQUwXH~SO86HpO&^n#dKpV3Xe+YM`OjKYUZXa{kIYab4 zKGs7;ZXM-3aHI2n`!vw8M`xNL++KjI@E}O-A_2+LV89lqQ=5t6_WFDh*D`FaEB{e> zVwh(8O{A~e*z=)0^8n{qIXH#u_JP?Bg=5fZhdZeYIc-q_6d zoYQhYPj(xX30LE=X%U*JG~A4=ElHEKV1(|gG0saL>@@cdT3)zEeX{g2cXjxlHRL|S zGAj$EwF+uF^!>pd6!PP5RnF_->2VL+u2468;I@zpzG8b&KuIw8-AY~+#?=_H- z#CYxHoZquu?HVrOdKN!seap{=XJ;L|Cfero&b|aHqGu@M$pb^>E%5WviSP5j;L2;s z{P3kErl4tV?thY5fyahdBA{_Wjkxd^}E1FA_RpR`%T8TVuIA=+UGiy(srKMfRt7#~Cdj;x# zj1<-NvIZjo*40kPyxlc+g8X_~}X(%~6G-FNxu z4DYO{7rR-N!$Q$qOW(@*O72jCQ&J+k4rtrCp>&FL+TwKYqmwsS6K3yzKi=?ucD~M6 z$cwd3DrrQ>>CKUk}nJS(zh_EKbV5)!lgs!lMRpr`bz@)4S!8S#IRl z{x~IfvD|{RA-$(xk&jH&Sf+l2oO!mIE*etilu>&Zl6#V8&4%=hYDFQhpFvd;Hg8dH zbR9EYq#>B?*q-~g3K1-Y7hZuPi%oi41K8*DT(Z6eS(zM5&VFI{ds$6l68+nii$e*M z+1IauG?wG*)XF0)&gM()zf3R%ZkV3w%3{JvK?mqQe16p4R9P`NVwyUL|0M{JynUqH z3NO{l*C)+cICl$pgPPyDg2VF%_9@2|104+ui%%U%a0)2VmY+?@A<8+e|ub@Y1JP(sYhw z*$6s*dI%*Zu6;_K73V=)43s|oq$&zkMp;4lAK#L>z|&0)o>M#??(nOmtHC1t=)w}Q zM=0I6xhTFeHP{Wgm>Lq3Y3tE(xF!SG&)!svE0WFx4T66r7tw<6vEs!(WXEKw!H%fX zTWr@eqp);qm#|%6K>r)a%{|X`zj>APc{|`dF*Z<#gGb~d)Spb`qW;bms7ksK%$KtJ z;t$RactSA9@B8gF$0$qz_%qYsv8SxKk08GZWt^$c=+hp5 z0`NWM^wXZ7qOg{*H!}mfC2Y7rP(qmc$lrOaxJNuz5EhBAD-&?WKm6>`1wRi^dpmh` zyPrbwAByl*n@Oh`UV1vFR;lbuI({mUw>y+m3oJNsI*_;U&&`*i!Q3EkjtVjyJl)`R z87tniW1^BS0`eAoDJ;hZHVR&XyLm@B+u@8M;5fyk>uyn)Bv8r`$HOLIYm$PKZu7OfRZH@@^Y7vI90hlCaVzUiBM;7>2l;zc&bxoe>LvDWrI-uH>He$Xq;TL zO_NfwGK3w8PUfnObirA0H&1ux|4!HNP~AaqPw`Xr6$CzfU9OM9+yd9tW=hl51TO_| z;ORzRWM9$oQ-b?+Yw_2}>5$+)QIwNkf!dz#lY^`b8&CH|aDg{}?O3U#3!duGhfq5k zn5lC5unWnC7XEpi@&MtYSFtva?nb$34axjg-b^bS?jAVLn_qK-D(QV7Bvs>^T1|KV zbVphJotO;cOsaxzQ{FRy@Vq9=J!q@m?290q}QV=nb;R-T8cTw~CQlHqV(v$vfpR@4@A_ zFvw&JBoK}PnyY~*+6xcTJ9FD@%8j{JV72ThD8m+hh zpT8Y_T_omc0a$zO2|l_3*VDs~GO=X)W!vQdT7*496`A^NU_h?Z#5%naMQuIBMM424 zWFjA{epF>EyjbwsfJYYvjZLOCpsV}%qWIV@un`W#>%pzDt(nXs+Erm#rF3J81)eZv z3QThPrV1V&MFWvF;+lZ3jDViR8Z>*xDzVg8bS(0qv9H@K(Sc4LG~5XDb2=UHC@#=N z?uqWeRnkpB56~#|j1T-Q#o&n$(J|SfHh9}U0G9uf76ktJx)tkxPYZ&Ay`cX{3)=GR zKlnQ>=8M zfIj|pqeL(von`%*FSdoIup|r~r>;AB5pM3tBS(vh3Tmz4zHM1wrt~EUb_dGT6an1o zhM%ijb{^Y0bb2ydr+xgL)h^Y@s9Y9YH4QU6x{;}7ELcoZM$j}Y@lEBU_>(xW#JYLnK` zt6@W_`8jeon`l1slDx=wM>rxMj*}hN=SjebFjwfo)ertoRVV}0LNi&#<+V^4x;PFK zxV?`ZCsi{lGbOxSez`Beypg37@X2!T=OLIbmFh9>4u+lmSAKI5_w1bO zj(2p3gD%H|9G!ED%ifvhH01)V_zZ{FN^f=G@Es%ZPey^Yy>V+ksz?*TP))ovu)H;- z1Bac!j`|TNaTPPfQV%~P4d5hGJrYJ8h@tGy*tsUY*X-OPE=B*We{6MHFX^!7C6({& zW*YH`PwsG}%YW&+^y*Q=;RNx7=D5-Fs4-{sof^e+mgyVTy74&J;a#DtbZWAs;}uQa zfj4DA5q?Cl`$F*rIFAn4$+@Hb?ulm~hzrXH`O+(2eiQ9`QMg71H4G;k+iqFGj(ckU z>f(@v&vK97?)dI&@Tq1oT9wml`u8Qey?}rnyMP_VWhAGgF@4|c57CTCF<7M>K^&9sa(dJLl|&Qq1F=$3?h&(v4A7R z$$qlZPvRUkp6Jyb!y*wN0&Dtl!Y8>JsK5N6=DXhZdZKtGjL3MGuuye!uo&~4R_0{y z_Y-l;w1YnR#LB)`DWX*^1Ya z7~j%8ME>HF->auN8H_nNPn^>Ok+W2!7);JjbnjkZLs|fa$Pl`SWP0EB&v(kZHji&F;C^-0%Y3_88NBCmeTzG7b z%cxqdJ)G}LJ8?T2->Mv{SxK97##37EePtF)I^r%$8hz1_TIG#CIZE9m$V)(PW{rRw zA_-cwq+Fpw>h7`EcG_65*Si*mrYoZ_>PXh=P8Wni&|*Jb3ta0~DHzuca8s=M1?CiwSig3NLxv`pJV7%gi3E&;Mr`^8@!qLP=53V&KMa?kkb zli=1@EyJaW69od|c{FDo3mOXjjMj3G>E32A9mS*`FWJfO8~e`~`~MF0pAWSdIN1Ea zxdMybv-@_u>U;YG@AnT_F+qA03f!-WwXCI;jU5G4xBP|Msm7`rlT>uW39#h5l(5|c z3J&>&j5Lfk*JA_uR;3jtt9a48xd#CPRxe;^y1lldqc(?tl{x>F0IznlpBri7@xGtt zUV6+3P3Y3c&H<@B#`P2Ebh;A35P)W-(Q%$p{QBgot;vT}nD!lNbG6A1TFGbVbeazL z%`#zcs5b%j$Pu+rv@N%HMf_lR&K05#Y*b)h!q|y>F~q&Plh27@W2i2HX1BayM>RWnfBTc9f*gVupDtC+;&ufu8YhJKDmBXMp?XMTSk zp{@2YYeFu>EVg{18;X}_?@x5q{(igyGUmnUiBiXGF4#f6O+R-rLKv`=%>(4bb9)ZQU*Qh)l1M1* zXZy&8Zif={Ery`dh4$o9b)^SMCoOV&#)s7$YvDS+Q@O|W>AsR{dxy2FhbLn@szHT* zi)IrCE@RzCsYx){yBQ>WFT!K*mBe|HZ-WocBXMVO=ZX~qg>aHZy*m19^}__daKv$3 zMR!l(F^$~bq~4);7r_ZqD{c;(5QHdYoZRnzRK>6+JT?ZAAMVhCV)Jhcf;-d5`2pl;fnII0`bQv5p!boU&ZN%5(}Nq= z)}B6E__~T6xiJvHgWRbAGX~#g>=0#dPOzxace^zgd38GcyhmRgo_TPdP6T4oYhTHX zxUCF@-MMRiBhZ^dp=z|>n?q6dxMHnm(O$KwkQjkPG{&ZFjeE_d6i7q71ST)&c(q+b z-2Wq?;z4G0Jj^PtnUIYZ(Sahq`f*>F-yR0gV;RdmOkh#~2cc`8=S4phhofH&2^176cr6J{J(Y$YMst1a zDuFp5BBE2eW>TtIT){a8%W< zy~gG9T?i}ORrKNbVSHSoO3c&od$8?+?@Qe&%~&kzvLvmWa&4xozAN&`bDbfMs$c#^ImfTV*&7tf(|Bx54hO6*nN}EW8jhuM+1xonU)WLq9`>_xcbFSDX zQM}gLxcMeAZ|(+b{_ovip?oVEO!R^VDsgzau1Ei2z3W4I@lr`@qta3r*(Uc!iBZ; zEqm4)^poWz6pRIS@mK_YL`K5+5>7zd3dxe%b}oCvjM;b&$%<(ba$k{}Uc~PI#w-hy z6h6nI8Chc-XPb+BX9WDD)1jaJc@g0LwA#4#(3>#f&ZUox#5&Ip_?6jFJ+D=BQ#*Ko z!V0C4g39g!%M{7(aG?jq`1(9}7`_+tJy^ra9|liod0#x({9bbBe0O1pQYhE7(8Ta| z?ZH(m<87~1dGL7$OkOcPZpIHc=-l0ZIJquhu}-miYP^4Z*cJENLN}p(bSxA>$BtEj z_AZuVH385Ejt8|;g@d6>Yw@*jPx844b|;nP{hPP2;OW(I`x%x%a#$uDkM+j<*FlUE z@!5c>@ztj6QG?ay0W3S)0b(zT?fJ0Cy(F!P=2u5C*wd_yqdCAjbmC&tC^|j#{-GwV z2t<;hc^Y+IgbRxBx1qp^eJ-o*8uq{Kl=Hoj-LLAqvSr=L{Dra;Fsq)^Z^?$s?AQoj zeKyvNc%de3`;`&>T4dc`q`x%qs%?aUWj9IY(CG^XyoHFt`++a56D&!7O;a=#_JZC^ zsJuSrTkic{joJZ4InUBcU1t`tF)|x1J@IKr(?-(Z*{s)cZ24PI0S(z37)I~f6DTj> zD$hN{hhwFmw^ZKMSR#2ap~EIW%(F0oUi=dEmgBH=y>F;|dq}Qn&I#)Sp5y1i+!wjk zPor6>6|bAoNF_nLU{E)1UAr)J0e3|Wi+Ph}pi1qOvy-L$uu;77!Ba~&qaAg~=e_*p z2WE$xiI7d5z>O~4MjF(n`3=ETUo{PloS`;GoF1&DbvhDz{Q?`6ql1Fbj5O8wY>ckk}B72{95~Fi;Pcw~OEPxk+ zG5Q_>uIzpEw?;K9IoJc>M`^yOc+`i_W!eG4K1r|<)7~^n+2!GWDVuI?M1QHoNMpbX zbeaSw@ze7+fdt3uI_^G{LL39ofV=Zi;n0(#-o)DeauV$OWKvvYK*qfiG&45@(GiRZ z94`Fov}*3*ClC2ZIK)IV2hf#_P)_gr zFM!NWso&D!n5OLSKem3mevm-GW!fD)8JT?hi5$mT%PW+My6#m$#BQt)k_ zqa71tebLj_n&vcq|AW1EkB0L7|3>c_Q%vR1sGJQMbaX6o8Y2}#ltfM=l$=5idG=oW^GB_9*FE=r zUGM9Cy$`SV>wVpQG;+@Z3Dz`sQ?WQwJ0eq~`%_8`7Uj3X;eC!-0*5eHXU7 zffzH++WgkE=xb|Uf3GGPSv(;&33@>WwpAnFh(ryyW!DvYWym0LC$ZZMvl2|+3Ac2` zgfraAW=!Gdde(fafibe15%dW|ro-S!hlZ2zL8FtQ-V6BEGxAv~R=QX(xSuE8U}?0| zs!6~8>!!A0t~Ripjk6NsbiBrH7+}a1AD%n>PD*7yg81}nz+qakSM zBSZJHarHct*q3V`z?@j@>o#kM&pp-oHad{yA+g$)y?-=k+z(nQBD%G5>ov*2=;iOO zkG;0?v{6R#Z2Dj+1MD8PQ>y~;X;%cI%072YWEw;u=1Yj6@6o?=#T+P2v{PV;Y z_CK$Bs@=UyUXs1u8`yh4F!DeEOQt|D&ZA+;RhvK;Nq#C5zDqc*KDsBTgGvLda5Owr zs1ay#yl&|s;2`&#eqF)%v>*kfYQ1D4u9!>^w)=~uN!{jEAr#QC{&6{`Bf0iJ^XA(H zzu@b(c5=RSO!`5^(jmE$B)cxbxvq;Ghg9-86Zp~QtH(E1;`G;3auKhk%lSOT)YG#x z&IS|Kvh=TrrgFU00>o?D7^lmUl)HXX=>^&n) zNudAzeh@y4oHP&QLmr63Mbb)-62+Wp1KU;-N+;)sr{<^wISIwiCn0Rv?5f*>DHN%z zf^`x!qR6+&Jd#(*rIn2z37e0_PuFstyRoKxIASU<)6tC+wA;F${51iwB%3&V^DE!5 zCC~M=>EA=av$1L%!2=cvUTfJ29aT9A3ZuaTeNShN@vP79)x0K|w-fBTTtnBs$*Z;B zTi;^6e%NO^39*q@?-yIU$agYyER8EcXQ^*x#W{8Vl<9@R3RAxfgm~kOmv;z$huHh~ zFBWBU+VXdgPTwAzda*J@Q2N++wGZ)<%cpOA_Lr>E-UvjE-N4C6kCWcCT4%ula6pL= zHhS$?ZNXW5MKhX3CaklU%TPoFyZv483qgSphLO~nggEj#OR6S-&oeC^Gr~RaJaect zZ6H9u;rEk+=yIN_Hp<7hek)r7Thud-!)=jsSzp{;@)01vkcK;dH}MSoB5TfVs?x3CC~NHqM2Y>yR8#nfdBLa}RW%;!U!}J)W`?jcLvmjJE4!fCmDZY1 zVrdu{y*u>-#_{GGw5p8KnwWa!@p^HPM{^K7iD~ERi`K8UERwrR>uox;3A&oSoy)3N z6(oe-W#VHd-IgzzhFIHyf>`$|zAzpU`<|k8@0pIf!p|LJ`#uK#=~Qwa8AzoBfoiYW z8Hx9{Xf5ITz9Mz|AS*kNMNcr%>(wYyP@Bjx4`+Uhu`+@kVMuY62t>7)EW5!|B`oe^UQkQiT~oNPi+4il`}#Z#RL6zW zZPrmkER!W|r%$m0DZwwp5A5+dn12+g{8^>RV{jA^7dcpSbmZ%$?qx60O0UweZ8dG0 z+%?GO_uUP2RFF7wH$DKd9B0}{W|`^K)XgR65S)J@T-y6P=3^ZgyVtD+xO26YBeo_i z2{!m-ZLE4MQb1g>H{N4Argr67^A4>aod*c`e!E6?B6;%nVG0J?8&HA>_>qSpX5nYP zhl6N*Wp0MZ8S$Jo1@6w_HmhP2o-n_Ed|6>DJo!Wf~HjwNH=f&Jcd}q zLm^Hd6ibi8LGmRPzCYad-E4QBuC3Wz5f-KGjBlOO60v7FqwQV%8TqC@3GHv!sxub9 z%dm^NRvABwh)idPu{)WszPgP^MOCc^ClS}YU~odU8G316BF!+gTGNQQt_97#KaGgH zl%wQ^fg#gxKzi=o*6`Upju$IVVxQ&k>g=itxmGX6yQQZQV=d1^tDy1`Tv~qaeqoWX z$m$WK%XGIyAMUA$({HKSnFOt0139A>u#eNno<;z?Rs+!sb1#ZTRGMDA99mr#5Xz{p zDnd_oji-d1oD8t@vLbjch!9`yGZT3p8_u}rHeMK!PD#K95>SbOEQ?9&(A_jOIoSR) z9ASXhIUd+M1D4nbiFvqqF*QCc(nUh|X%V|;R7PltX`)ML^m1U2KRK(_(u!uaRryhI zST*D=2_bTDokJ5i4Eo8}jeJjjH!pa`UL+>*w7bNh^*ieyoi7+Oldj@{U!`&AM`f_z zWbNQknVeyDB!%20i2Lk_g1mmZZG^(ScUV9>YEafqnuG58@)4;^a&;fC*y0z}TNKm~ zm!<{RrX--y&uF8@_`3=-c8GwEHcY}rlLe;@!U&6O7q3D z>drEbl+7T74D`iK%*?+oS|;my`7`rAT4S)64dj?PuG(zo#CVp(Bjvg!plcmW8-p0T zvUeDw{%Jn&B;hwt&cIO*w{C32n;fiww`de$CLw-5OFGS+R15t!g-+_KlM^dqd1rt` z9)Zv~D0jnqxqbg64@26iMIbuw8#>(P*Lce}fHj{LeSKv5yP{QOxGD5m_lH}PEA$4xkas&xHffnq^3Y4fV z_+$&Q`?9OwMDOP~>1(OX*jdQJJV4lx#VJbcf>)4^fbGeVC{*;!QL;YWzGzk6GOiU{i)iGhV}N71=hSg|jM)UH9l&r!@L zS|1{|oj#+^y^*yX*+i3qA&WssUFl>rY_4?IlvT56rJFX%q_5_f6|jw<=%LMy2b?eS zmxzS}>ofWJ)8VlhV!L2N+;E_L)~DtHm}1D64{LX%xC0zNBSt8EUuRB^6r=if`KZs_ z9(l~MLAzU_5#I}QGRdJ(`LcoT^I5aGnXLo6z>U zzo{XGh$w|eAhMNjQiMUSAlgt6-fma%WvMXJ(QbT@u?tr{K|56SpwH)`r{`sZyo{-; zBxp_9pua>sL|#gmuPAQyp!NZ|U+3VcBd-ytKD88bf|T&8&1|dRa&~{55j1DZF5$Xj znL$chd>dW28`+sW`*M`{PpSpMhc1-(Aj!OZ8lNs(f+J z_7`u0EP8@etuhhtK?w}Rjc%w;*!Scck*r`-IhgoocrKCx=cgVt8c9TA zh}1I!`q#MV@&ZfF69%NEL^P}Q{m`uDh{GXmH9JQ4rBFtypS+aw)KGW4_n604l|KvL z4Ho{>`FcTQ`d&Dqe19E1>{B)_-ZbSf?g`MsS%{(1TxB<1R-&l!e}^9UaE)hqXLw1n8EY@DQy5Zi4u2Kut9 zWuz76aUs6Y`CtGq{rQ9YaRX;v?MR3peo)-)xP-pErys>VGC;!6el-jLV&ew}ZzFb@ z5glK8vyG1vZ7+rn9FuoP>B2t$eSd zAgsWk#t9{`W$Ru!Xsd={El5z)<0zWt_J@w#KEXiPXf`Iu=QXUwJ{Tue$AMHBGzcdVE@n=LdJi>BTnMkaq>3k24dA3g;g3VuUgN)s0}nJ`mI zf5MoOcpOuG>~q2uD-=#3;cE(FBsr+i6PaX0*}+fTKkfI}V1DP&jcy|xJVswC;V^h8`f^$SoNrL$@UJ7-q29pkFI*D-3b) zZj{us#mYH*Ha*4@RBxSHXFaDq$_>!(4zBn3y;Tc)rmDa~^i{=-b%f@hwiYB?^Lx2W zpP}bx99|0FcO=k~#J*^kL}a-}8A(l&grfH@NQrU(LWr-pM(Hy>cg{lTB@0)p!FJgU zN1j2roABJKDk>)Q2=<-1Y|!HBG9zPnEw)nN^E? zlIDzI5;1NV%z0NxOI9pClvZzq(@CkcXkvEx2lmdKlm(VLT{I$iTq?rrnZR73_;W2U z`=(69sExIme?hldMj!^JQ*#(;sKx$@Gz3{PXu0a_rrFH}60gDGjBWR0(MGP0%?hW1 zUG#(_vXpnAp1O;O8cP)gR$~vzAzuUh-uk0li7Ril=YW;xME)tQBn)V7fpwjZP9pZ5 z!|N~7ZO+TWX2X^nOyQ8GbI`nZYn;#|*y%8&K-*C#37@6NGx&+w!#+CrvGx@Hw!!dq z_GTQPcMCdya`h~%Dbt7IZ0_gHGAu4iGHP3sk%u*KF$6ZknESN3a! zV{hx|cVIp$5Ihcz1UNNMrAJ62*hQCf&p=Xx#mLtkEGje9GTL_A#2(N4sw+POBUMKC z8}xb2Thy?tN~Rla3lB9Fbw?3RL%(Y!?H4N}l(?aMj!W{Us=rg_fBM1CPtBl~+dEU_ zs_gdnI^}jogfcw7uJxLJ!xcB0YX9QbCFAuWxr0Ch_6qbd)+&uidsnK$J%bwBVYxRld#)9aQ_5CWC(`lU|ke*?fPMek2jV#&~TbQ zwaD;JsxT{f&MF)&FQ_lpU`d~6FNI7IsPiJ%z&R#mrA;eoP3KK%2_4)*-VHM~)WtYg z?NR#qj^N%&g;yoDL-i*S54CF7{S2fd(z5{U`HrH`uT%9q13h5|k7y6Ady-Ry#R^}q zA`9ZI6gw`uj{j!m)dSB}ceqRBoiJ z*48hScAv4G;;uvJqFFr;vP>{#e1+XA>u=rf+>&4B5O-Ih=3ZZmRcVzf_#?B|jdo^$ z8n5|0UQg(q<*J9oKpDHgOotWi&5X`@`E!nnXH&rg+elGTKos7y&w8os@>J0;V9exT@xJt;gSP!oWpGY0 zafBJ?Qo1{OagyXq-+f+&@F>5xqH#1{EBMs16cI3GYi_D?*sB$%dQnDt z23pT&ho3rcTQZz>lM&1+@D@vx;*<=tN(}JJ0r+c-NTHV_dr0cH6ugCwT{8RPkwmon z623O()HD^8$sFOoTKsnWV7a^5MVPCHsf@+PJq$x>@nbTk#!Gf$0j(##a4&h&Uvfe7FLFRAazDN_k3W#)bAPwe8St}0gmutPJCWi3)1em2df)vWzV z$4x%1wJZQY4uaO(AVy3$GiHClkizu|V|*~d*a+^fky?@wlKtRV7B7DO_bFVi|Eqc=1=$RuY}AW-L~q2% z+HRiq@ts^LaoIhZ^=!)|!B4x9-^l!WNE`#muM0%&p%8 z_!v}gYHqyZ(s5mmdUZ~j-&;-ux8xDl2D62l(y=vkpq4N&xxi(#4WM+31!nex(j)Pd z$5ZpmVYAB|e$Zz9a%U1gfIz{YrA>Sl==Lr=P^Y8QI}sEw>8(`j1a~F8j@@yf?orAeheOl!TczfckH1zva4<)HNt^|K*Rm zMn_d^r}Y7}(193HC9SlFEW?UR0DhQ3$s3>bVu@Z3Za{pYcebht)%TykbNNv%b;6K8 z8clQ~u*1n_T55HM2;tYFN23FBPf4B1c!f=*%XCSH0PibdoS{*~8^9_*jvt?xqV8I4 zv%{}1;=>tttX?{$@XR%BW|ljOE&mKuAK_h}<6obvIM-3j^*f0875NOk&19|&Ni@Q7 zUH$9?2l@Kv*7#A3&preXst$Hf;F zF?Vuzr>7)=J%wLa`~`ZoJ8CNG1m}DjuF7Z0!4?N#UtSvFqI{CRyF#aqepCj&{*iQN z)18tT(Y8K;dP9YwDKmi_Nh5P(sRS?o#XFg50b{paN|_T|3H0t$%{8;G2dS41XT@dP zUu?0&w_A8UQ@z&TXDQ)EtQ`EigJVt;a)zGYAi6h=%!k_blf02 zUP6V92y!9wlSWea2f&>iCeEl}*^F$16T=<1XAFWVvB2k zRFn|tPBA2gpNDQh|Abj$M~WtC(=*o4wf=!EdWY1`8{<2_$$R;ywJ@+X)kS4}6`2lZ zT32a1b*b2y(15w>GQ!NHE&LmmQ_*GMuv|}LtCvj0&eS*A2Wb&&;k&uw_dA~Rc|2?^ zU4809?gom#SMV@cv^XRN`bpgfE5lE+QbvwX_Q^kc%3w2PE?W-Ay^bEaOJWFmU#Fra zSTCDQ!(G-~B}avT@1?OAi(yYjUj?Sc&6wXNm%`E<47At*L+|4> z+06L04^3+ya+csz^oFL@2CMbla(2Ntq4gziaFRjO`fAg9_!R{tbH#jQ#j&ZBR*P5* zc8pS~xxNu!IHULX8#$ujLBEI3sx2NTIVL3qdmF4L9y3rXR9Un`cHY|?bhzVTPsO+; zww`WL796QF45wUU%!@oq3O?v2Xg-l+KQp0k(2&{?y3DS&pJE=j8YozvaW~LiyQ~@= z$nh~><LJ2*u`yQpX%m zITkuQk;sUG9yeEU=NB_(=Ei3z+I3n=hvfVOwpqy6Ioh$#xaw3G6*yamP%|p~*Ijk_ z{iussueF> zXU-&GlQf$ZU|L3c{d?UkR18doFRQ9yAMrn`Xg@9yUVWEH z_22{IJ_v)DTh*$+ud;^jcoa{T6$qR`^A2{RBG(sX6@%WT+2E5Ptf09d6sZ$4I}U?i zHCBf8!Cjy2Z(;)C;>e_+VR@FovCHxg1@3qKyr!<{*)1n^L0{nQHQvcSscxaw`^@({ zhruE54bXgqLK22p{Z?(!u6S?2$r6Lqz_l!N5`C`uMStnykn4aLKnndR*|LIkCF ztfsXUx<_VxvWzpiCtN0rJ@suMY|$!wF(!-&f)A^Km*9{)>eYdSubZBkeHJ3Nyt=v_ zh$+^m4~Xd#0O(%rfWOT z5ryum9P9DBc=uiao{{YwifLbXL|n7|hF`75uP!dBb8&*EzLPfD|K=rb^PnBSjq|Y8 z1mLNJKpGf9ihQCx2N6N`{Jb3KW;I|_R?{U|US#TzXs6eqigP;p-KAvqDD#o-i5NGV z^;3m{;b@K%H@6El_tXVXFIT=TQ@MAG!@8s=il(ypZ<`LEz+WtB#d;}>5xs{K)~C62 zH`vdC44vTx9kVNV-cZ}sRcO8N%a8pL$fdd@314-o7$1(*tA>>q3|Ma*U)@7U{P#q| zHDtOkd`f<4L9cQ66l+!GX{;$#&>y9GM&9~@)i^+TbBv)=Y1YXjC!|iqcxB|ozZ0*v zA8+ASv&?fau0F2&bZT{kcu*y9T5FN+f%o5gIE&P6SAJ1Zq?NOuM0f69JwXabuhGKU zG=rJf#NpwgEzFNg=WrZnDfAW$Q$}OWa>UzXxdh^KIcN%LN~wXe{>ANvL}~i-N(Ten z$+?q8S))!SF1+U^%)VKwHy_j-k~GvI-(wzY4Q1q%q1L;yTd~hSr3G%Oc~lm!LDO3E ziv#S#fr9ZZGLwjf_gf^??%glcPq;yqxc1eT@p4>emYEv9k{X`PHfTnJC<5_ghIm9Y zSZn0Tv8*rFy}+%8?g7Y=YZ3+9Tr%v~(u=cPMV>>fB8q#ERdm(O5_*pVSxE@Y<>Nvm zgi>z?j|bQ2;jjC5x*bcRO&HM(Se+q*9{QwW?7|Y z==AoeY%fhK$vr^}2dt8wOwnj}O@}&5ZTlDF0(F)vN$ly6v??&}d=tk3zpgwoePW8s z@PPpy!@d`1-00mMV*)C6_}N&%&tL>-!$=kP7zS70f+bN@VegI8Sw0(Z#l+k1)9>$% zCsLKuJiAF)&&00$rwJ7Szx*1(WEi5N&j4RhK5C;ngRN zZl(PRri1`V36|)zszPw@2`#k?h7IVnCG&Lj~VEv@cP`V_pnuLAMx1IU^Rkw<}316fX`G9FT^cTOAGiHQmcd;Qk;f78$)s;8$SYOjsG;DnuP?5XU zHz=U*!?(8ELUnACehHpeyY?A~y?evw-Xcau&~SJnWewRw=`MQ!9Uq~ux&i(pClPr- z#4Js@@AIi}Po#Bq1~Kz!`N_sf9tXDOJauZc;X(F1TR7>4X1wO8+j32#;&e2ormb&8 z5gk^{V$Am%P44jA?WaucbvAzf_Qk%1y0|4OWom#1Ur)|kH*B~nB*op#4VU3c`mnq% zw(SlQ!rTYzV+o30#O3oln(J5v0j$wv$XIH(wY-331EW=q{j%OPF;=2^?^4C9$&F(U}(K&UcctN-xki91c{n^6R#E6Y^<|jAYEfC zgIS2}Bz)V7e=%0qLHPCI58M5xA8GX~;Ui&abK8CnW#kkDJju{wTC+Tt95l1t=^ha= zW=52%^~fcZ7c3pVex@wUBHx~k={trGD99JM|Cyv2abRW#+|m^BP=+lMPnE-VXIh5ma7VJ~WAAw2sr z?d90Yj3Oe8Tp)QxsCoSfWticH4ju8{cJ3_#LTz+KwWFl6sNmZpmrEA*Wqj~pfqO|Hf*J$_Hd%NOI=qhImTGC=yDQewtN%`D&k7UB)2T}DeC-5@`GT&hG zzp~DTS6s|2zFSeDhnBF?Rb!1U*8{Sx_Z1`sU(0!On7r9=H^mmVc^%$~$fA_*17#`# zoFH)I-5rzoravwBUehf%ZoLb(AWpo~7JueD(Qt8sbAqaVGgzNC5~W&nO5<0Y#MiLap{ zn@fB+c&ensb0(Nu3W?+82vKPqKGrEB5=xND1#qAoj{r~ft~BxvxWOb+6Tz(7OEvS> zCrUeRf2tz)4%QsMlE}Qo(d5R`V`qEZRMi60)-I@?TOzBLF5gvT=sR~FcWOO?Vf8UW zZte59sY z3Kg0$&2qWD8zr+Uq^A*_=gfTSQOC*E?=e!lv|4fta(N>%7>E zR}!H`ZsD6CJMXZ|N5X_xg|zP-f`8qlXvK$gM&$#|2P@_H)w+TS4>(1F_>cy`Pu=UF zN;1a}gBdzzB6x7CrKS9ZBEzeNYSlvnC0rlewWkbm?}a^)N4vglJ$xe?>=d`S2yJ9uPXbwc3)zN?b2=ZVG6eXpIiKEZ7tB;8B8aaYV(0aWl7H4QNF3 zpp-3c%O$vtB@J=y1GRtuzAKh+W9dXk93~xq2QfmUZ?h2rCME7VpJ+=#j>kR-AkFD5;|E zvcYp~FF#jrl$V!5t0pUK?G3p!`>;nRx={7zbI_eIcVVM+WCTCl=GjkCNb4Ww7K0lz z5aN+2*g-Frle)iwl*emqO<(yKomJ;S$x&RY{=^K`x?myleAdhPb!dTV9*r6pTApvn znj5U$pTnRk2Z<3iM9dmk*`JtwPD0@;ayW~b`mG}pkd%7e$~}v?Vu0eIUf3Xh|2PFr z&=Mh>V_#1U@AKst?5KrVvwY1x`fg_{t{{H~4clvq4x7}T?@sM=^>nGe2$(tS9*^~h z8x?n2?Yu2bSYpQTTO=(-tzt>>vu@Axe7G4C+ z&1#tV0c)+oBXC2#ZjTu!_2G|eYR!>Ey)?=h?h$UWmN$9*t$d`4i-fN3ROPq?)04cD zZuumQio2Pwj`ZuRO%w(8mCLo9I`~L^LFpRx=ecmkbZ!5e(*72M{^_D6Wl0GYXB+8} z<;Cnke{Opdh>yh_e2Mr3S~DVl-R3;GNuyjnZQusn&Ao?~x)UFcQ*QGvQ9tSQk90mbNUdrkC{{ zhlCuLllzxcA?#*g_bTguyCruz677*hqFfG`s*lpF7y(8%vuxJ{801})vZz{~8p=W8)V zozd%Uu{go$Mt_?@R5gFNoRO0awsgd1NFD4b)eLWQf+=sP^)?ML<7gZwohee^77 zSYD7ZkD_!=x_3%WCd6myQ7Eou30|{`YJIf%3e$%E*7zGz>>Xp$dnx>EOBFzuZe_a1 zl=f3OMV4h#7n;s*4Uy}#vY-5BZQRt9U55Q$dDoaY8x=ZS`isBj3f!mMV75ipM-ADN zrBW3odLxF_WeJ!w6|%xq$K$w@x)I#=gr6U5oT4P0A13>DE$43j$go5=&Xfk)uPY1? zR%?|fY3XVqm+bue7N_1w*135xzxI@I&VbZ1Rpqn{*s;E#Q_OVWS#v5yACm6OYUOUe z1KreNQ^`xp3V|=L0Ypn8M$u)s^#x;@5LfWLzcRj1Y&3^ewCF=rHTjHZdwaP4>f7yX zOt@?xfE~MN@}r(n##mJge1BrY25r=v#&`sd)Es=d`L=We)_l9a+Qht`lq~%Mo_3=w zE?al;-l)WR0wr7LkQMJS#4pipF}=60wBg6fu-#ZU5t|MJxgj& z;3ZTQwb$1yE|a7CyQu73oxC30UBcS78NcFn`;ZHOaO~}z|8;{OsxEU7>{L~pRD`2d z`4@R)+k?>r$bz6ML>MVhqwik5k+qbYN%^um>BUm>z%|V>O-I#cV5_Do3;ZS7%j)+r zZ^mob46Is-9y<&q$V;QS)j+P!AOsY#ne4+zIU_G4an%m14|DpD)tYsRo)l2qbaE`# z#nkdz-C_kcW=ZSNE(z_)K`#G>UhU|&3g{*LNkFDOBj>&`EE6f1tCb_D0r4I{#rElcl!pwiPbWB^?72-UaK z+Ik6ljZ5W{MWT#(SAt6>V_B26TLd4_GoHy){z)0Nxh<|>anf0^(zIA@r2t!kHv#W= zlB@ymzbRmd>)UZ)a+jH?W9_E&up#LIchw#|?O`xsr(Nq(pjDC1(v|mpiDv!LS|X(9;o13x7AE!tD^00svLJ@V zwPUSimJYW)X+S+!8LWxUUc5w@&SmL^%l3x1`TYm>5f_f|g1Pe?=d~daMV}8F)b3TL z6ELTr)wnI}6CD`ZtOJ07#tkx*^yZY)Ym6Csbjxv4q|Wd3UXoQL*tRKI)8Zga^W+h@ zT(c=R`)#KG*Tgb{|KZE7cEdwYi~KxA^_|SUYN;2>KjzJD9Z!y%VtcyJhQz0>i9Z=a zj0l(w>Hxc2l;xi^aysgZQA-DsfQlj{6A3hY5bxc=H$Jo@p?9laI|N05mu=eB3zmvY z1~=EY<3`{&$I$6hlg>18i)H>ni9WS)H~DQT-)e$pvpR*41A~KNd5~{20*h&7JOI z8n2-NaL?pQzo(#(<^w-WM6KlwUCpTMZT%FIq%6NU*d$RN+f~Y`nCkrH4;pOJ`3xF? z?b|AE&Q%oQ$t>TWBOS|#k$7Hv&%?~6A7nXIp^FM&krQ!f`Zl{!ev!a7&F8dt)t@!k zpin!ZO3eX=!V%#tbAbRexM-TXLTmBa@5XUZlO0gBp0g zD8hh(Zb7~HN+i^cu9ke~|FTS5`iW7bb{I`M_g+Ia8B03D%YSqS0Q(A1aj6JGdT4e8(#8;WwT|rmI|i!<8@u4=jOX7moEMn$Acjartv_`#b9@YR8;JM- z5_Et*X#M`=?{B&R`T604vY`!z7MMmQ#u2Xc!P)op-$%HC5t)3jn*GlcH}3vf@d7aR z|2(Y<%rft1(Y3#q2f*F!zpd@={~4~KqYW5u_it*$-^&N!?n^-j6hHxGV@65`!Svi# zChh-T8iTtlwRZ{0{+<2CZ2nQVjh8)?-4KRkY;4j$!Z6t&vfGe@|0ByJaQA_Px5xj= zCJ%6xl@8(?|I8YQ%4nqie5rd&tR@zlIX`Ll`0tR!0Sp*7`V_SNZ_MBEG#KHofb=UT z{thV~JoLyZo4?Q8bsW6%bnC>Wzp@(z8|J^~$4y-2yyuLq=vjFFtJbYZv`K!398;bi{-`D7`rWR}{ zuBr9<-%Btra3*B-3(Q|l?b%RVx#IA@m)nqb>aP!f3^rwJ_< z%HPE}kDBBAztw3Vk$<=H|GKU0@bA`1q-@);`TqrrLHp=qTIuk4ety1~HV&w>e>S)C z#yJJsWWD}gZryOML+KaESgN`|$`K{&fMz zHYSF^yY2qixl2ZXBk@1ZQT_jAQ~L~7{Yo8YGnv;S4SI}^!LR7QR^7lr z4#IBvs|DP^1B^iYg9rb51W*{=_SX`FZbJaTOV-;y_{UN|gqXsAgC=n)V1~K0{c8{W z2Lm(_P^5p9~;s9mo&_$6G;&)nLg4%Zt|WLzEb#LE^`8N>sEJCqb>7TPBU}*t*vR!ffECXItQdqeBN)VWtmH`uHJ1!wnB)C{+#@4V zVWWOz0OlF^l8>Uy(U*fP%{s?-g>UZRzR38xX@shKZI_eBpQJW|jhstwUpNTEMv%sT zVj#DiSV=91wu>)wHyZW1bFh>r@3`b(jdHLc$L)Q#i=lI7ogG|vNAQ9OL1NO$C9A4Mv;jeyT!W3!w01S)&84rBDWztRPuo3Sj5?_{20mW ziz&Lzq#N1sl>mbT@0ORLEL_3p>8Nycv^|ENp2D+4XyBuOKbnOEiGKVM+DA}TG8Vsy zMz>29wG&yCVea+piblnOKM`Je8ZPtNRLVF#c>a!V5||K_1Z9riYjAZaf7>h%t$3Ty zG_VhY6HU2p9LvHYI`b845MeI`uh8R26Q{8^mx(5ZCC4 zAQ4C3!hc`ehm}O83r;WKWau);wMNgpzpD*{WhNK>s1r6SAI3PhG6fG@c%%<@MEX=` zR1}8D%@266R;!jRG5}4u|zn0he) zL1;r;L|~CxIqKD2%b(3S`d9u?EDtptlbRI$;n6tz`X=Zf0P%O8436j;-Cr8OrF%ou z4c-Y8ap%KuQH#wsyORR`+2-+-;}PUjqa~b^&M&UOmD+!vt449|rjM!vO#N9|qVZ3qiYNVMb>#a}Wf7u|Wo~Mt*!y7cZ(O5beQt1qOFh zkAUt8tZcu&{c4PMgsg!u63G)3Wjg&PK8VlYlr;)rm=3Q>FAX=bRjt&~=Z`y(dT4Uu zmnONeRHN#{&!d4|hi14sd^e>a#nzm{%k;LH-oEN~NVL(gSHc+5C3W~85x-n#_c^d3 zqh?@6PJS+9c{ATd((P@y7)~g5Sy=`Sm5$CE7E$lWCBL)C?{=HlekCw`R@w#HKHNq# z<#U1wN9%Q6?kRkAsq*$xaHCw&T+Nc@rlXs)UTcUCqv+p+zt11ZJ+oJoFXn8)+4d{7 ztDC0w38)ZleI-_jN~X!5Ck}nQq>9Krn(g@8_mEkBw<*tFV(HWa83W8agym5*PUX?I zyRFWV2YX}RKIw9=_7NuwoPk_m2K(R;T|U{!*#0bHD)-F0%ZEfwn?~mlM46otl993~ z&1xH3g2-tA@Wik3s3RoYTz`V%{#7y!cY) zdS>CdA`*+uG3!P1h{b`|nykhX8cj~ZdzJ<+!UDs_gt(VW!V^41( ze$0Z(o4cWAUy9^{^??&#JRdBr>eLJ!ey{_wFa9k_G^o8b34^!Z`mj{>(&NBhD1FER z)+g=Jx4WFUec5NLM1vvhMz+0jn~s#HUP;Ky((~yg2L~{ZD1&2|i0!z`XC4{C1lEQm zeYhjgFO$lk$(>M;@NN_mL8M%O-O3S=`t|gw0VJcyRm(-KOVu?amhY2-%1ldoxh|-E zvxk(nG{E6+bU2kVb0^ybDMfByMV@^sgWPqXi;7NE;*~}mq{Jsi;l+$4G|t^jpfK<2>Iau!h7PtZMZ+)v(U|V=wI*oulM}dd;aS^|BK#plfd84 z>ZECzO`j7WHuCSX9!h*Fqln2mp>F#AX-@o^Gt&EZi#|1UyS%5sFcwE7O71niZ~XMo zu{9!3p`pOB-2yittCxZALdjZIm#S;zr~ALq?p;ctjWg39d5^^<2qj++4!*i}a`!#M zleRWL2>1B6w4OO`Bk960zSnf@*YV#^oE;_&x3t_$>0vM!wUw2X!#4s#jkNgM#uwsy z`T6<1KYjWXHt^-kitmLB-&WJo(o}tK9OAw{DJv*c+WcBiR`%|fNW|j)BHn>SI|c4I zPb({05h&Ts*3{I5NlHkt&u%u`dgIvnWTu_?W}=a*%C(kp)*X_Zs3aPlF)(18pPPHp z-`96OKRY`+!R5)>9RjZ)N5?ZS1(AeYtM_$VzJn@|kDuQH?c29+{5eENSXS@}8!qWb zCYl9j-y7w3Ums?F3eu3YwznUQg-41&caBNBA98lqj<#@B5y`Kvrj~#?Wc>Q|E8^$R zpLg_?xNh~Z-_!{6B8X7L9&?`Y@$pl5JgIwNK&!l}>g;KrOVH`-_|`XLux12>DizJYoA~4>#&5dHuSSXx_X!5vy{8!y=_uk8 z|3pAjOKULQTmhj9U0V{y_CW;|CauaRNST?M^78Vfc6N3z9z%Mwd>$SiAu=*DQJ?2X zfpHIFq_3%zo%wb97Isck;N{Txb!X?-8k(9{OUudzOH>9fqGXJ-b8=pbh>3|=61s^vQf^T>$i+0&c54D(Y354B_$uBC}Z&g!Uo8hUpI<&U7rf6Yd zLHaQC%`75uYn0>Wkx$~I+}rb^{(%9b>!ssA=dDSi!#XFp5W>sL%b$RhN4|dj`n$co zo%ZBcilKs`mmpE;j-KGlr@W)v2X_fhe&w`n(v~e;R<_#&{kDzVs)q~J(9l@9IV~EV z=*!f5du{JS$PuyS?fJGf`oRk`r()-|#T+qHq@!BFr-j0deFkQK{Yv8I=EfVP(suhV z-G!?{uarw8W0X&Nhl}zaixjmf-pa0vzlbA!`0!!ZMEAbmC!U5vz9*n^<;`WPWpMLR z<#Vyi4+A$z2Sp8UAHE_}?RUFh941?OcY4R>5NV&d3;QU0EvqtYB%jP_UJ!c`SOR5! zkAvbYc-(i4--!j({Fld3&%FCWR?ov;Yzb0~o3d^e5^Gy~8}x3#ploY*_ckfdtY-rU zH+LCGx6Lmk&YkYumi4fvBZy#H+2HR|Xyf6R-TS`t_5LhlnJ?UF6L0jJ3%N6YD@#q^bsc&~ zW#3ic8IcTH{kB|UCka{ZE%40!0JpF+Br0(#L)tkr=8Y{Z`aa%PC*N^~Z7q;|{OhEyfrJ_(aWl zzjfV_)Ag5{>uLlh^7|`qgVaGy)2%0v$Q#V$;^#=vi){H*GF$QN->8(- zhpm9O^}l;%k{}R2>i_i0z`$ML{{=gIA$u8J-irpAIs7+&Xn$5j#%Jwh zh$)t04f&Z3)LuvHCEt&r=zYBqoqqXkLk9Sr<(_~w%Kg^nZz_w_1wTVhh# zXaD_)$&)=|$=-vNRrmS!F(RY`tiZ)wW`c<1nNGR%3&{e3# z9em5(*W?8CF&0-}wc+@n-x&~S=Oe$(Uw3Bie4G3lCxpebAH>1Y>{+v+Au6n|V}2o- zzVi1yrw35M6dd#BTQ;2ECQhtoLyn1a6 zplOE{#-)OQrOyc`O8GZdL0mq!KpzuQuD5-l^ZYo{67`O|p~$NFWPP#cQ^E0>c5Bob zPwy-4lrmVLVG0f8hI|L83|DkYi`K|zD!`GF5V@Dw2k=xVtkZ+5GWZwFbkniu*@fM9dv(BEhfS(r9;LE#; z9Rt`%0o?u0nzQ9opF%pGkx)!pJ6x4p157&vMqUim-beZ#m9k+c_+{8pCNoq}heKS? z3(zOf3}!@_e_#5Ne6sq6&D?7_i1S&c=rWUU+QH2V!pwO32iY}n;AJRii{(Qc@{g?y zlMvN@Y^2g-mxgm};nNu_ay1X4nFC_D6|57maU7=^h~+lSC^^&OA|th?!i#@L?O6O) zT)@e)alMZfIZwS5_KvW7KVJnTdw&g-81;-s*_(A2+M08L&(eL2$?IXu$?T=4SvC6O zta_ShrZ1^z7^YtQ`V^&1=>y1EWyzmfQ6LOGtk?K^y|#+iJRf|~**fYu55x%t%An2k z&c%(W`3)Ni_HTnn>W{YCK6y2jC@Axiv(C6N?>8!7pod)_uY*y0IAKdm1SEjE6hF+1S=@cO ztnTL*FQg8OiV?`5c7u+TwlP2vh}yIrNgTD0LVV zRaPMS7(YM!G)bxl;ss4s|j7P~l&i5LG*NsWgV?^oVfpI|0zl@>Lrvv13%A z3d2x)b{^#5Dw90_bZ{icukpmbf8A*j(nx+1;T4R@Y}UAsmcyd2#xXx>)_irw>(gK} zdk#lj%2(RyRz3W<9EAut+Qg}~=Kl06i7wCj8E{O)BrD(k8b}tGY$$!Gi?SWPm*8>r zr}o^_gl(s}KYIXPP>S)Kw@qR>uc!ksF4LW9K=zRhkQji_iA%k&K=miZ zSmA&!Ve3{Wl}g&VY=5#T6grTiPftoAaO+o~fU|X2ic@P_z=tT<GSpjxAVtoJ;T2w;*`63g7 zRvJP;cR^7mQ0Ovi7Arx7`gu|{%VUo_sGBxh&=^yXncO|OA8m}dE%HLPXJ%;x?&9>N zzwXNREEV*uV9eOG1$f936FkDLmMmcXqZNn3$PHdA@QIJN>~dJRRs*&X#pKcHC&c@3_@zJb}Or=wu~0;Ily5vL=Q@$u~a6K0yvn};v?@Cs9Zbi|xI zA*ETm;?)%}*p3KbR;Hlo;^$!Dwr<-vY(7iiSC%S6K<^M$9CDYt{1F?POXANf4Bk6& z0YttQv_3+`s5q61dG)XYc-}Lzh?zr-G$Ijp)l_>?TESW%WGZv0&&Vd`q36hkE(ko$ zA^>Tp3iz|JubZy&breC5kvTH@C^hTI0_IlSeJw6-qa3xGG=&n6TsC#m9tLkj5<+lq zLCR|8tXsNMTw}?tCLrl^qi!;S6%MXLXL;rKW}2g-yjV$D z;E{9D^Ai3RGY#qLpi&vO>!9SHPD`dLjS`qY5-r%TEqCQKLj(0GPjeHlY#^C_=&+Y^ zwxE!%g|K(I624UrZsJaZD(IE7;onAxe_V!7a<> zIX-ac>CL_!s?Cxo**JZ3uFLC?4`NJ3EU=P#3{+NxG;sgg^YZm4USkNtYn+n8^!02`PM3NNYn6sQ@So~z|=6oVgit$|QX(vu9<7W#D$!BhNGuidig17lx*yC*nB zULK9+z~#3xpNoXz{Q81wQ1~6q*;DEbQII#KA=usWVRXUKb;zxcN_j@0kt~Omk8mbl zDMl?}i8g7GOEK=Z&13d<4o(i&Wz2p@6$zc|P!Yy&X+n?Sj}_cl37(G}$3YOLn=IJ7 zB}#G0J~8r#whG36p5V_@A$|5)rCbQ~Grq-O3pf)Xl+8-m-gJ3N4ZW@ZN9}b`NEMHQ zP5HhJ$()XAt)C5o(F+(Fo;FBh?UOz{@I-!cm39V``31|LV?eRX_TOq?dC!FHOhwyt zKd7ssq78Osgv(%eZp~YLKR0D{J!O<15^b0%_WjC=ThdXc7MdAU_IsA-A(W0~xhY0@ zTYmD~;(W+Cj9pOg1zw~?=ZKaXaUNU$TKryD)eAUySKDs3c~Y|w2IXNTxMw9wnlUk{ zWbO6{a($LvY~WVwP_fF6O0lh%z$%>cgqHFZvXBQV>dOAC)0%*u+sckhK#?ge+F412 zS;Ni)>H2co9zpbzK3SB9X|gou$q4PYV%VL4l#!q`CyjIrrVFI@?_)LmwYJA+F&lWQ z@3BNSA|~x3r|@?gb7fRV0nLik<3C68;!c+TI&>{AonCV-Qvk8vr#DLji4F!5V1On; z$Xl}&6FMmLm*Di=TBV;Jwm4fZ7Xh7Nk`ffR7VleyGq?BE#Z_d#S`y3d%Fid@(o%1z#`SK?dWA>p;R zQ5N79yI0$_NaV|k3t!~*TdMj|$Rgop(X|j#Mg8&G=Kw(q@RcrTLIo5IH({hH<2Fw6 zu@qeh*t)BS$x?K%m&KePp2sWh+JDHTqTeH7SsBci+Nq$P%L0nbsnnsq(F*pt$u z3&O2QXboQ|?C82ha5g15uhzfof?fwXaO%%{=-Si`zsU)B=gZnoKa)M-GgDM^U%9GI7RJXL~Gv zx#)mnhTUBcFboTI?)e~sR#ND1i=k0V&P~Y!ck{R}M6Rtw@-+vs@2q(P)&Orjd#L?;7IIQTWvliR@;Xf?JUF8h*QiY4eK_DmQs5q=`N0EfW&yug7SV<&za8n{DYssZom_LwDA+m1vnQ`ctC;&5mG+JaNb_1Fi+71 z+--cBK3EOMoyQv_C1<~ z)3!oK7VuJO`pZbMK)>Vy$4vPJYXb#Z(6+qG6zR$7$#IAK%QJ45^f;Pht5t0CI^A|S$gAr~yfME-JXw6@x-9TeK*UHml7-_Y5E;B@G6C>`pC^wzTJ ztl@*F!;x+egpw&p0STJ4OGxU937=~f)PrZ>l7c3T+z>3t8>gm)$40DGhhOx zec)RBpLGvX-p?8$Zg1M$DT^^%yJCga|*~UFmdX zVWxx4p2VFD!d*{4*zo(~)|!#85&Em)87Ep&b(Ak@Y$0_3P4z@@+Nozx23~b(N~SYO zt5QQV9y$rRU(A$y<3fJ1k0>S$^MP-7rek*_>XS_cda5}L_J-xz;5gr#)Gy$>JLE99-F^Y(c7KR31 z@z?O-;eTNkIX}M;VBKlC0nZ9@Z{V3?FzDBhjCd4wchs*={?ScB67RTe32c_&V5G%s zxPw;Wm}@h4!0Apeww`Ickjg^eaGcIB{8@W@1MImvCi7tdqJ`d@pL*-_b$E2%9d8DV zFD!&9T3;}PV6STSw9DE!^{7q0-^!VVgCfS~RLE<@3sC@+Rh<>tAsY*i=jm1NgtY7} z%!u5+$a?8IDC`zKv?*1?2QJNWXLc~&-1=9V)9j_}IG1kYe+k7D63%<|vhkA7c6?OR zeRSsXwJfLaAivO~G!@tgV$5^Yss0dvpuY^;G(puE!FDkNyw4X`z}kn=t2 z&uBqw)_hTjdzqg^tS|oMXH9Bsz4jT=p&~t^b0^zaPw6SgQ@-RT&&#H8#P;CcRo zfo0i`i|M)yAP+A*P$Ervl+UO&x^7**qneXS>9{H}71+dqhGQ}9b9zK`;)^Lp41Y{|| zRn6C}LD8;Vrn}=Wn4!fOQ`i=DKeJa=rFBGj_F7?6yPA>tiT9Y>1j>0hijuAz2KS7> z-hLpx3!gD(@t(lViBoxM7Pqr3^(lzLIw)Q{L&VMP{)U0@~rny$b9DXe>i`=WIl9!1o; zV|w7yFJ!HMkEQ{cHWK2uC2)!Mcgb#-TGRVilo*l2d3^TZqgmBSx+>kZCiho60ta1J zKVBBQQUZxo*Z!PEMz+_6F3eiL_ntP&aqHeyw0?}XscQ@Z7YfD~#~CxJ2+t%RCUj}& zkJx2oh*)Vg-b|a%@zIZbwKt>3eUOxJ4%0UCTnBz7)c7rExA6{hjCNg>IrL|+bf%i0 zyB^}U`?!yHD1&kpcGyGl_Ga9T=mg?cc!Au?__^gK70dLkA3!|dM>?)HP<_>Jb_l5> zc>Unctt0o^kOXZZ1WaBeyI?iB*+A(yq_L{&QGuNGW4-#@?xQ1Htb`FG>(Kc)?TnxH zEP>i;flrbWqwo4#3fW4`*EAXAh!1SX6lmS8>Oha)q;ag`cKXU0^}So@xZOq{@O5uB z?TM&hUU#IbgvVY-J=rrbfBnhKw8j5-#ZGcxKym<&=I(8d+*KWqDl;DRaF#RH?I#cL zNFI#&E^qlQs6-Gd#Svw~DK{r6Eb{viC4Tp^4u0-Ys|4Ojx(xT+9&EBh_pOCo@)qP0 z^4$K@^UL>rq;GUMKlGot_pa_k@@m!j9`~va&GLtT?9YKdJ5iOePANu3@R5Ap8>=c= zUt4pkO=wK{+;Lrb&g9_gU(KasG5_9lgnL{ zaruJZaI?>}9!2+>!@ptYfteO33ZRQgQ5&^N4JN>PHJJN*((_JgBIPd%hW_;V5xpSo z^u$jnLOjn2u`5N7*~VTv1T|P)X9dIUnR^Uzoo=xKOBLqc`jf@ZJ?wZ!i&}M;R5&Ow zB3Acg8-w+~mMRGCU0x7x&RZ;*=O!6(5f9ms5LD_HbE>LVxu?%=8%|0a_y4Z=(g)G& zwf7RugO$RwBc9|%_)3>|lywYjmkKi2ffHd7*X%XYo%Q>#%9;(fK)NrfRN!c#w(u0* zx3AAx2zcYdr0F*hN`FbJR!>y}4p9eT{Sk@Vn!w)qCNXc)%~sdBlosh3&i|oJ&WfD7}Se zGXwrfeA~1(MAp6` z(+=x<1JpNvcf&CpQvke#&zsR#9D&t9J^IRc(jwrCmw=ZjaPhstr^g2AuY)z}V5I6X z_XZ_=q^0=uw&|TFz zx@yja?SQp&0)|in_dL}|2f7caPt=vZBUQRf1z)p_IR2L*-1jW@lGjMb0%iJtTq_F4 z*Z_6AYRZIdhV6s`b;Fh_y@zL?2kK@+KfS~rs0{SZPH1_v1SFmpsGFmTA~#>R5KuSe zo;?$dbP1rGc#)7SD<}o9mTrJL*9N;Egy}DU3?50fwhr|4eq{&O(>>ap_OjQoh=*^8 zkj`rDKL-^1?MT=HWW)hf`G5YEy~m4W1RXQE%yo5r2Bpt$4=E5n%l`6X(y(v`YAGF@ zY|0V%83WkC#kR#)Hz3KXz@^;SSS#%MIiN0sc}y|OAE4ul?#u5O$Sp^vt}l}ktNOclqO$yI=^ z)sU5+1O2=qX8|>02P#V^R>wFFROkO`lmX{Ww!4H6`@|t7sHrHhoq8)?g9O`o3-r$a ztF5sTst10Shy&(p0bacHjL{aldpJmu0 z%6V_i7A20;z~$;g7nb?zy9?LalYVvDjFvk+S`rKQ(r#RXztE_;KE19s#=ZF`Waw*i zm%=MhL&ifWQr7q|4$gbL8M3b7Co~-sB80NcI=K&^U*5dA>Nx1qoxHPGBd}X?LLRS(G6N##{o6u%t*B+6lMp5g+51r#<>2I8|8^70^y;e&mVXgcbZ;szFjYwoms~K8?{EJK&xV7wbX&fL zOb*!(ok%v=LkYjH@QahI|Io8%sj6X6H*((Wa5P>$hs1V!1B?26Fd;3c%Ne@w2o1-S z0fRrs>@v0;){X$Cpd;};m`3_TV0`wAMhMwL=c9m$?1bGH%BLp+%zpL>O)Qd-ZOy4u zaP22a_qux#V<6y9TU}Qz|CYter&i)OK_J}n|Cu2K0q%nQuMD9buRh9uGlc$|A@tu2 zq5ozG{eR35!hrrKL#Wmv+-cNs!PsNH%6W9Cst%uADPqn#MT6&yesf+nT~Qfn8U0c( z`lHrRVzz?ptw7c#GF2k<>$!Phk3-em3nDk{N%|}v>48ifgkvdj1I@P+}(2c{WO|%1;R;BP5<`Zd5>69Cot0vAUU-t zQayus)Xt35Jwre|hYA`*M=&3ZV!VEyS}P}(!~onSZ(=qrR8$bx-c+^sjfTMP=_v7JWU0T*)CcO9K?0!jtvMg1y}s!{)9S?V|XcgkzL>dNF$WJ{^mDj8|aZ~}auJHV_}T$fU4db-`5wwN0p zx~YdSo6RYkw5w*NO3)sP0m@_r33+cA^A+=G?>+X|-gGsH6Q<6=a+-^>Qt(aEw5tkW zW_%*qsc44$xKHU5@8S z>(Wo-NajpWLVfzYBk!JUa&ARL-r_snQ}FH{z|R5)7Y8ju=!4&kcnT0F{SGidBm+(( zU)0Qu|AzxsRQ{D_bkjvnAK7P#{H+|XBLe+{Ref=jeWbf}nvwQ;GHHShq{#UsA*m4; zhjylX|2$0m6KRK^qC$|dcSraOy&&2xR_-(T`2PBQgI)jACQfI?Cof>iTcKFLX{xgT zb@0S?+Wt{JfLlaUeAjM`4MtvsR;fmRr>c@9jR$(X!H7`%JxB+atN}g(L9xGbi=w0s z3Pnq3ihxemk9`xpnhv$n1?TTB;8=D|(DOSE=~ym`mY)G^c5v@+Frw~z?aRVyg$;M~ zzWe&o8M<`8{3+2%(_EruJdiR0rVpfU6b!sgf=t~87m6M%_%nMS6BR)9=HQV8l0I#C z)iKs>qA8uyk2m|Y%pzv>T>Io{%Z}AqRu+Rklj7cx6(V3NkVbh6@$fJMLCHAnZbvw2 z{yVP+bM*C2uj29dN&hwX5A$4__WFCmInr+kQXSNF5=ZXsS~(R4os@Xa3J_jM0e$q5 zcEizkR6DXGp3KWqk$-RZn|85gQx>Iv^RrHZ(Jzuy#rU3uujF5Jx%`yze>!Ku^jlZy z%!y~;Ey6xEGHzof#^XBV^2O0&U?6f`0%;%ZA`djbfGYF2FM{g-P=FeI!1&wN{Znh6 z*E)(0)zn`<t0jEJL4QJe;4FJNj*~5t6cy&4{b}}t?LXJ9Wi8?|% zwbrh+=up*YB7YMhpr`Qe^r1aqvq|bdhe_KN+H{|73vi>E>hzptAc@HUZ)8c!KP;H^ z%;7ubegL!2b3>w3&)-+y4!>n8x+i0cgRq4F4;aa3%65j$_JUdpZ{M>3L>N8!qi65%WyBTsXigjZ=WrvA zf-FndFUdX;qvG--|3v75T}Io?_li%K|ML=SVYs8|fIssKVKr`=VsHH4`kQa5&hIPM zZ$DjIYPhFxnPLEGLjmLXrz-xh_Qoy)=Go~2qxy-3Vj1@V4(|^bFuwdxcvn2>c!2ob1%k!)hqe^yNrHj3NPzqNGk`}c zKN%SvJ$TSJYvv!q%|YBd^7UvGI?f1kjwhEz(eaczUs5CwH7k4mhhZFwJ}f~WZcpx- zP42$6?aK10WQkVrJqC76iXbEU1#?XAFn=LCM3Kbie#_1aRR)7)h0l2e5iUptKvv!o zdRJ3s&50Q-Lei`JZjLP;o^M0PL`XvJf4VkX_@chOC0vAHeg4Ef^J_Dm*ea-7Kdf7q z>JV^Vt^LGZ)h2Tv+BbP%xK#mrlIa-6YjNv4ML(A8s||PAJuk&|HRTMzT`4cHvfQ+P-O8k!oWO8dwU!atlLsSS@-tNtDAo$RMI zQ7h&iJ;dj0ws-4C)CJ#v-MwA%n~(83-f~l_2uiogJo=0P?e`y?=Ck_aJ=2MuFEYn} zS~nN1UN(=nOSUwG-11gy3}1uNB-7DJ|IcvF-fi?mj^0PVs9%G1l@iKa7|HyU`7 zsJLhBopBs~-O3#$J`bk8V*Qu@I+$;NIGxK1pk$qnvMPwtj7>zID1lkQ1Y^;+By%=U zRYb*{{oWqF#-`eq_IfaenLMQNgL`XXFn|B+rmtxP3#aBzyJ`Y?ak*x3<0*nxk(>-5 zt6!NutC|CbYA)`0S*8LtHTogoAJhbT-(`z6-!Lrj=|3HN3o>UYgn?4rihy@z^?j-&P8%+y z7dJzGkhTA9r62!nd|^sd#V8$jY?Abn;JT|#v2}8Ha8rIPCJYQhs zB;rAmv-7_RT2RjaR#=KiAb+QWQzP=L5YI9HNvZPJf_GHtL^c*znlYoC6Bh7h*XGnK zMxN5s^&(0mY4emp)^83t*TjlI24e2l^8?O>PW6YhFlas>IQB;IGXZU-h)gqo`})od zgfD~Tj!#p}<_a36r6PV&s5}Zd+s;)0dkd!@vo(BkCj-#fAE@+~W%XJ>F<~{|(%wPm zwUOGD&KJ+s@=V%m4j$UpbQf9T$ui{&X)rChU=JvJhd(B-R9(t)>zM=_>)*R6zR-R?CEL#O)eMfqY*3XfFrK{+J zdkw=nt*qBi&WVl4_{ZenQ_PdZu#qGU^U2QUm%zeTBoIlcsX4KLDlwY-q&+eIvmbj8kCj5-tEUS->2%bR z*;%clNYaFgFmp4Tia@*PYR~LClyGytuudJ6`Hn3KXh-!rpMPc$Nj}U+HCx{@wC(pz zp`K|3w`=sM<;-9+N{|`d6yv>y#xXn}b*jiav9j=E7K)Xj`2zDAZZn@xCD3)Aya9r* zE*YW;$?<@CdJyyD`jK+$k;6e(1o8D{;)Kyc|4B5$)snN=_&7RscctnxaUY^cS^SiX zh4!(NHSOSf1(C;LfI&`uG!x&y7Pz8iVFt-Fy*y)ZytKbw+Ek-rw-laqXq;Vh4CH9LQf9sHE1@l^dzXHr)qOI|6MCM8YR4a2>-hZ}x>Aoq2 z-`MX{u5zQgu?_Cxl+HK#{JQ=$XXDjqra<@RKJgfa5cd<(LaW zi8F?-Smw$|sMg2i^1`q#XPt>QiM#UysoL6PaQIgi zWdI+ciQeNS=6u2ycO>E?3_RLHXG5HKf3tH^YG{y?=MxL4BSkeuAQHB^J5Sp?+JI)h z#(x6ndeaj)%r92(2Zr4us8u|z*N#-p8;sMMF?CwnUr{sm55ZY6Wl{D#{c`w?B8bk^ zj=zt#lEEwAPg&wBlX}@`Siww&oe^ifl^=2#1DH`CwDOsbm0zN%zXQTo%$LYNJYv}u znC9wdPn27X=C^NJIbucwOKK1aSiEd@gGlXF&zJtpty8CivK?4t$}fTeI<1bM9H^!B z0h8%6_P#@~{&&LS+m7Z_f*$Dx_PUK*~wvzR01Kd@#c zu>d3mDSK@+&={Y?JSPiz(t!saJFWICw8*a07QzVGZVb@;qc81`W&WuEsHkYDmfwmr z)>7T5{%*Cs4zaP-uj$+5p=9K&g|6lK;m`g)y!) z*}_3)b6h}>wEgeZN*dbsM9kgSE9F&T*xfvT%QzD&&f=NiRsW!-&`{-At0#HOrh{7G z==U;Iv5S1Y62aa>#Txx~j_|@Cb5UmplZn6IxNtHjN(S;5IEnoJcQeAe=Gikd1%GCd zljEas?e@)v$km060@vW@RrJy8R4s>~X`PQz;b^OY*P8rAn{BCtGwN`i5Fsq1Mii>M z&*^JczWfmwiz&4HRWUmQYm&-OwT>k6<)?Rij*2An-IwB?Z$9So1@^OY&#m!0HH^qf zxfSD!~ht~a*31FNK zw9K7)^0uRJtE!rg?YVor<3PIFaK8|k0_~EO5J&Y0Fcfv$bd)ZNKq5`Z+Z3kCElyAW zfft5=HW~!3^>TC||CinP*kZ28?~=%ptnfJNC99}RtVI5deV3o(Vp7~kJ{)~Gc3hRx zv#@x`v7q%cZ3rmK=*f{QH_-TxXck3<1HG7?W|n3U^bh! zX@3j{J)QH04;^v(n16TS243(MTx)A&K+DDI$cLCg?lDx_^yMz{3D}A8V4$sB_EoS_ zrp0V&3TpVFw8{M5{3~i-b}8*x_{K-J+7>L$H`sxdJtX0axy94X1J%OP?JYn4!fSyu zugg3x(>kYGnVYU#iFdB;mGZak%p`j)TD8ei79|SyBe0GDd2+$1j-yvd*K#&Qd7C9l zcJpz>kuix<5IB>7nks7MF+E@sbLeK4ByxG}^k|9|AnLh>oi86oI`e+=zkFQs@@>`(3HNWH?#Un}F3Rn1Vr~xY4s`vYV2#nn=WT;5IY@1X}#vtuhol426ocYQ5%(@Yj@Kut+M zUwAZ2h3BvpROsM0AVm#BNS$Ga*x0Dj`kD+xfw0+@8cwycgG8M`spP z`<=gW4)bvQnl^V;J`A~JT;DkP8TQ28UoO4gCGrK3|6V95Aq43E4c<-{?8`9Gj`Sau z7CPDd>b{bAP^(1A2ns0so9s+=r%iU#tviZmTo2A9YYw>RVSUEE95IbnjQfNL$1&*vxDS^cw+2S(BMYT6jJW^_z_&oOl0~`;oAU91C%06Zlc{X{^AZO}`DCDFF z=3~K0(O=@wW+=bWiUE{dPX#LAQYSe|)5Ylm^ZQd+bml;Zz-E4l^B=o^dbt#3ymQ;p z1Pymll0lciZ+Y#?&OH1gpQISg?^NaT#a`^ksCIV5p5B54BgdqXpB~iDH+lP=C$J$+ z9*q(5KG1)8loxfrlr{Y)?^jKPR)QxrnY4VT5#};^;hd?y6EYGPGpcUl?td-~% zv{g1`ApFy+vOeP$`d#~*W!AwhC0nJu^^KZ{B-h9fE!szmGlOhkj^;F@1!fiwL>S?c zV8ANI;?Q}Xq2W0&&iGv(LbPrDN5A~kjs3PA{JdWmE$%jjZ67Myt@GX^zA`#aBzggF z(0PyLURsPsi6E2HNv-z114UjT2Ea9UUnXL|H}O^)-%9e9~6)sL%#kiQfpN?IM;e+$&e>`Prc|SO|LC z0l_U%Bm${KwR%7YPBrqAGt2=EO_Ch5mi}m8;eM#sIM-3Gl6>T1uwPDqIiy7h{N#9~ z@m7q*%40(w){e1jM{UPZbDZ*)?~7ErbLe0B9ifL4#uX9b)-8_T9$EJSg(@ zP5H;Rl-U1R*k3vUi`wq|f_kw?qZ5#-s3Lx&oV26#m&;qG_tL9H)@5l-I9G6d!#zPg?1 z+1`+Z@OKuCj?AO25r2xz%LEP<_Ru)!MWTHdSuu>@ajJg9H|I@|Iwn6n5AescZ>|Ez zA#p71w<8CupAZQwQP4`A)w{krik1wu>*tkXdOZZe=DG^FV0kgaK356Qx*yLi!fNvS-(#fX&g3pjc&~UETl6n!+R<;{rXQ*faj+gNWr zNnM~&_;0>~P^`mh8Tw|vxK^W~Cc3-^To@J1Jvlxro3nOsE7q3c8%An^)#A^fz!zOD(_*L9D1?1?-4vgl8ssL9I7_22%AtB9|IZUB_x#j3%*ZMbyKYvOBBUDs2kiXm`uObFIgF8I-`=@-L zD1Hv)>QKW!RtJ}n5K%VN{8Kl8B9w*x=hr*NHU~f*Lfg=GKr1s3Q9<~7eRBA>a#jvi zw|%%nONrl~Dca)wWSNB=Zbb4wb-oI*Z1V;E`O{THNdsB-d3}Q?tCQ%)CypvhW$b)3 zgg)R{lYw_xgT}f9Jv?ofuXmSnl@!AtuUnM~Nbgs^`J_+2HOR)2$xT_y5}hi%s%T}h#Dno z$}fS}Is?@~Y}OfWWErOnp_QkA2X?3m-JVjEQjCXi}$p*zpI|P%h$ChnH&T zn=c04d0Dr$s>Ataeg>wx63H_NM69etb;drFNesVK0{AZSVT5Qi^AeEBgw$?0f1wG4 zKido&tv1-Dp!=+r;`SqNZzojsWsUu`@Wo@fB8>}|5Dcr~B?+aAgS#`FzBuTtKd3!4 z9P8IBVH=?ZtR(N%j|)L2eRDh3{DqDXE22jnKUU`zf8xPTOpkzEtgK|+fRUBZK=;X6 zjl_LJ)9{W<#vDLFjlps;n_pd*G#^4At;DAd`q2}-%@|(*URw$j3){?>%`agjr1Y9wfK7e}$*o|nCMMVHR(LmBZ zNhr@ftsdeBju?XsO7ZooD}@PKtBXJ<@^7{{se{BHWVQNX3F@SaQH1RXxsFd{zpjRU zz->@MMXTNX62rBbx1Ez0@PHTJpKuVf7}M`*bgb+-e$AmVm`Y*ht~$nVI;s>#Sj6A1 zr}JuFNyBjgLj>Tm#XhX3Blbt(TZHzOStb=?~ZFmyS}QC>*!7KSVjQX63U3fO{#SCGkg51}b1XW!8VAY4aX zFD)A_rnk*NI#+E1@T-|k02leKS_B(yjB9+q20BzE!j=D*N?8oQLruxQ5}N5^WvkT~ zxx)RK#S+|(AC<*Ud+rP1GZHSzCbj_U9bpI%EzX0H_sT1>N@w;w$HpQR8`?E5LZl@6 zZ!>Il=J-4yi#8tQFWaAKJlkrdcd2qLAmIaRf{*u3`te4`_z3>7ksKxe z)g2B^eW>-x7ZkFNEJG$sWf=eF-aZegWX-0oFaNPk~0;Q8nVV@m%!e zgB8j#KgVDb{-X{;!M`bne}_DPLe30Tu|zAM#7MEOWHb-3`v@VCVtNV(TGbfN7rB7> z@boZAs|w>d3O>vDt#HQe=(F*?IG*RHM{EiL`{a zf}-rlEJSGSatYXRso5xuF!bl64j+%Ql+oG@+f#Vqtrxs_!16-cW(9%boS<6fwK(Sf zYH8~*2Bl)+>Bdh+#Mybk=$Iep5+bH7<0+(d_u zrb60Cq+JD$QUM$)0x>B9sk$D$vhyJJ#bI;Se%J+HKdY`1kLOFD0#=KfMOS)-%>CRf z0JdigS132p?;QiqF=layQ^IGUX03dbA#FQl;oDx*3A^HcRhOB-G7t_RZid@^YdVYW zH5jDD%8XZ3Ovog?RxWSglMsnjT2TDcEOdNxk25qcVKcY7e6sm;it%KsITDQ`C)wiD zxuZ(?RNTdj16zQv?LS@Mj`%6$GpYtX;vs~RE*k-&=DrYZ(bB$kyBI`M<5bc!<{Q44 z!Szp3&9ZKbS~Z93^`}z>C(8w*L`J;a;C|hH?JLSq4zB4;nu9Uz1i++63Mu}j&HXqH z2stQKuH=7b(7&O$8H%l`IVES!rEImMyT~O8T-sX~Z^lF^#-{k+2WDmw{07Dry%Y5r z*ynwe>O!!BwrfQH0c=Hfm2_;Ks)1IYwr(xD+#G!|Yk8VzWD_AZYwF=4_ATO@>x?ny zN=B~h$M3+$Z^oK$Lrd}aiAr+Kf|9d`;_g?hlGjLYT6wjv%R=gleC8MP))5z}sy<=F zqh*C5`sWqNQ?Fc2%j#euxJdqhhucLkP*Z!R7?{jVYUhc4W=DkW(7tuYWko4z2dl-o z?*3v8jW8YD{Dd&2$R);^j+528oHmAXBkY>mqw;v#BShICCwDt{A(M)nv=5j9?!5mKY^B zo^P6C?V)+UypELCy}M2i#wU-*(USxFa|9oFzQLpdXppw14ZyH&^F~8|NpA3e2O=Q1 z({>-cpvX{#`k<; zyn0Nt$Fw-|8(d}ewdmswjUP2N(I_G3x9#`V847i$5k%EGp(*0=EcRq}2AG)6b-uvx z)ZUv}tbOn`$nE>wCaVzE1UtdZk@(GC5x`FZq_d+>>R8$o@xZ$QU4z51-G%CZqLf8u z>bkhn8YF;p1VsaNTivu;&FNr<|BJo%j%up=7DbbQ0xF?3kq-fuQ z*HOc@h*4?U0`8n87Xd+CeT}zF(R0xt%IB^GMyyWe5j8_QKK0;&*E`p%``0@p8ReNc z?RZIyx@+s`=u;2x&B6ML>3V(mtp;t@;xn)BiOd}t%v5Vq6_>h<&)TGAZBpQ?e(=Wz zw?=jGKxgnm+X|E*Uld3lqJ!QLkKvDCL<*Srt;}n!^xNM?8F3*%e;ojjsBifxsq9(# z)v+364McXS+VYyAiNE>jII@c;joRq@oo#3=lQz$PoOA>mT1bau4+^ zC!4ZKU>1V7%@)I>1eMpjo6X9d=R=id4G*!7wy^{Z&@u*SDe%oz;wF*VivWB5$4%Dx zbk#Z#u6S5+DjTop*aaK>HWI(%lP1QhWy*+f(50QF%xmHkH**>dSfANiT5)RJr-X?*=M$M@)rM z;pnjsxJyKNDUGGF#DRJer3Aa=)u%MPOw+||K@AGWg@o_BTS)UM7v^S@NJgQ=-2&&Sk8Hy@A}f{iayTOtj!gt%@ugh zMj2AXX-`9fFO7gd2rWDKsQCK*9Q$`ICJxLP2Z(Zb#ZQR()v>3q_m*oVvBvsy^9a=` zT82CNxU@UdZbvzXOIJ*4L_MxX1d8TZUxTWt%DSyy&JCz-lU+F))2Ti5-nLAKM-H>x z?UP`zT%8q;a(x-tK;2t5bvx@0+S+-K-~82MEkme98FPxv!0*|8KIx5g2PI)UV#>_t z%W8BtUy#`0+B2pNNj)*H%#3XBpGd0dbk?zo-&dl^WyYfkOMz?srF|UdXJbDJpKa$~SMO6H#Tz5A9 zl@_(jj6P)mAKCi?w5Pmt;1LCY$Eh-}@5HLpog0sqoI^Z*63G$MWN+v>r;tz=Wf0k1 zNMCvbd{l^EtOIQ({P`0!p&_kc;{MWtIzcyFqqB?NhCDVFb55KRA(Hb>266quytUqoh}A<#~jhrJ8Px z*JQypp+%h}a3HI!ezwt&CR*L@ap<>@aSFje|;x9QR(;MPPv=zb+yb?`Oq z%7S36&!nRUSci$DR2Spveludeo{5`#JVrGWL;6FERtTmn;GJlnKn-d6qgSy^dti0k z$*bNNlTkBt=GmH+nwehRGhfmD3b|1c*W+3}!hLsvaABRsb5W*usDn-I>VB_xTuZx> zS`{iD{vqh${cA3-96!TN!xbboS6eS2SC$k`?zcOj=71Q_QGB-|N^=*tZ?jWXB-FZN zI^@u=f+Q)lXnOn;-E>~~##bSvI(`uu&@zU zt>aZXDKA4sDe?gg56t&`J6%vQl~ys8jn*Eld;k~N7+c|ds!Uc5o5oSqI=)@qa1%{w9%)&v>Ja=Zwa^aU;wu z46(aJ^A%*}@W7I5cIwiDe7Gqg@EJz)z36VrRMEuZa)=SoWS9Dw(_32&)5F^|2!X)>|N zOy5nZe7HdAQT2p;{Qxoi{$Ro9lttrmKE#maNGW0GhVT6IGc(oAUi-&^u}u9g zhZ&Yby+f9K9}g2Xe`2JF5O9X|vXaRmEzwYMLA%6G5JS#gM>2p913t-->h_+_Xo}Q5QF`F_wiP8xPRnai@1dBz9eAA35Rox7#U*evO(E_Z&?6=r??F zrKc3PzsE0yMYXyhTZNkkGw7!WaiBYllamKCcuW9(koXFl4QhHtn1*?PO{%$>Y^!d4u=V$GLmv7vQ8qn0T9-h6-y zdG31M?Sw`87He7LNaAEJd@`r1!Ihj_s1BO1TZy){*n|pP&Evj19ie(?4`Cr%?DPeR zCo2Sb)ZN;mq_~CGbo89}z;{=W5TJyeXT#2udlG!H17j47FKd0y)m5FuqP;DI0!xq( zi8=@r%3f_>))?N;fziA_%p!C6@5u>vEHZC$~>^SY{>|B zw7N!>2aYHRwufE8>gUdWAy~m{Nxy6bji@g|9Z`&!7qURONg;xg3b4nG%N@nwxswjAzH#Ca@CW?`xH#KkcACrXwZQewhVfhQ>72;Q8K zLyUTUo2WJM0Fkzo7CO=~7hzbA%CQ%S9cX^1`I$0tA<22Jm-xd;b0{d7dtq^m_!Sot zrTZ)O4{yw~wS2hwEAg@0F;wf{AX7pP49t=6(P`TRodJ)C9C<3odSy2vAZt_ZsPtZl z=1IW%WL=As(7D`G;jSUK)=9h(tlGzq8zB$et|Sc$C^bKf7#Y%Vd4=7WzuUO_dcW4w zoV&JM-Y-?rO{H+#hmJYC66;5M=VykUVpT`tRDi!qU;QJ%CxFSJj`JmDt2gJX>810t z^rfPfzX=g+a_s<>^wzHpa2CgRF( zMQUv>11TB(44Kmz(#owR-+pxI?yY9Yf`-6qTv0qy)@ph(@9=P~KIAvES=zeMj1rVV zF<*OYzIN%BN;_BhW?=Qe65kwp$Z4N`BMidBw7!4vh`j4~ev|k94CQP>M24&VQ!S~V z(FlFs{fZk}CVY8pW3~-p`J}y)M~SJkC)O=ZPAr7Q6AiV}-5E0HyiLXh(95Z~=WOvs z&u$LaM7ih6jS<+;Zi4jR6UM)_XDt0B?(f1UNqaBy4{&K7!)rsuHeoHWWPCQ5MreWs zj4a<68vaOAIBtwucOIA;H7Kbuee85=*Xm@dwaWAOP{ZqD`_e;9Zs%=yQ(os&z7e)CW`e}k1aG8Ik`7I<3>FmrX+1{ zNIXQT%grt^q>mObr zPtN&}hVK`8NDD})O?>f!=tGBUi*nMux&fUB8B#RK`>cqWxO12?q>Vj!#bMh1xy2)56z@Vi{QzmyE{}-Uqy>T$lQ_g-c=!!8r>d*nzRoWt{81k|vI4O_ zZ9{U16icT`Tj3CeU}CKzHUb-xfa$}k;_k7dH)3!jbGG^4qrAdMF-Pipi~=NGds3lX zb7hpK(w?Gzs3!D!#AYDFxvac`*8++c)jS38!45+_eb-2cyfUPzsujSRB$+{&L~EW$ zoDKhb?1Q{WcaCs4Dc!tFWOqTeZjz+yaN#*&l%+LXi9#b)|D`I;W{SWxsK3YQVYyll zuwV&~UJ9F99}+?tJwrK%j{eb+>vPi}kH@Hj*o?(zPiUy=A&|=F`y5QdG~DNhc!l7y zQpx$MEv1#Kl|~PafdgyU_!T7l@1c)j(NBzrURMth%a+JyQlW59xYVZ{4MO=eH8i1I zvLB()ylSO#@4b0pz;v-wxdiHan>7+?- z34naYF%bwyLj;85eplbJmJDUxup@QFyK=ZXH?|oS{#uI7Jp8&_^xVN0EYWI9adsD z?0;m@uUY%JkMfX(W%l~2l#mj?vPS+TQs>Kh-c1(~v^uCA{vD294#}X3UU5Lkc8+yF z3Ey8*otBe=)H-lRihMqmmYtLyphAClSc!ahK$flYG&%ORUQ%@Y5n8QcVd5=^hT)AA z?I0Af#bm5H%O!(Gx_`O(0*1%uZIOnp5(sV%s)O9kXmLLjUy?@(BGY|A^AaMWpBudq zz7!FysXHey@fejGa$)*?kXT=`B3)-AwTs0mQf=*lwX6)srqLQyD_&)q@4V`>OD`D1gunE^5I zyTavrq8_T5!S~W!7o{NfQc2Ds>Pc%0H4+PpTE3rpJdS|0I<g9KK5l(dJETQjMCt|sWC9<{_=))X`jr$PifG~X&}L2 zcy#Q0<*;-gP-gZbYCL8~-ft{a{yb5cr*#;ykAR3&^pjsbk3@B-Vyc5B)`7t`c3u_r zK<10BppyNNfJ%s0aDdOfG|Xx?a!gm;NRFKC(J`uzU5a;F4m4lZ2@Y1sva>`fT8(|X z@?&mYeRyJ}#0WCIJW3ro@ko*#alj2bq32L07Rl=`^;vR4)H%)hUj4-%f!vG^U^g9B zLABbR18V2n68R{6I*blZdz?aUtgq^d=S979Pq9q$%KEG6L@-TXp+mkQqhuZ3iEvW0o zPqZO1gles%NF{Fd3<6)SUdFJGVd{XMHE$A$Z2CqK=Q?dUc+2|n0v)<~#9!u5n}*o6 znXYW_ZYmev%*;dY4y<1EHA3wdpJHijwx%G$#45pHxF%FDp%?ir9j;VSE&AQMVdKuh zzc-f_s^o^h+WscLSIr{yq!Xi6xN`!XfQ@i%AEGOVkWOh4y^uvfH1R(;@Ms?aX3;2m z3AlvkRbet5`(`r5W{!EgAvk$rXU;j$ZIp=yDXS{i>5Zk1mpV4{6yZfLq)Q7iPHY zRsR&6o*d^>p-AbbQ9`8+FrCHKg1<~-aw-hQ|GYRSwP3`uE>_paF;Y;hKAx~T{Vp?K zi#W4+EQ!C0;Q=i1UcSj=Abs>TM9aRd6J!j;XbW1wahKYVMHTx+^i?aHw9^p{U&-_f zvk}&A)1v5}*XMG)>7SOrI?d$mcDWV2y5#DO-Sa|cVfD@+Ly+ct51;h-XCJ6Loo;I2 z1ELHRdrU3`ej4b>ysS1x=_EAO*-%x|TY&5k?k>LaY*u=~zw_(3oR}Dyn)4MUNj81z=o}L? zVzMqHn1uw%orxh}==R{#{hBcV73)K6fM6 z4B`E?#C`@BqTp5m&Zxep^sA^9IyPGxIt0C=+X2KIT(|);P)safTJpU-dpSHE?tRfp zUpXVznUUL5IP-<}sgf+bzIF@u2d_v!s*>yCw@cCINuaqn{}VVd6#(tg6OSek3%9vy zVSMjyZ|QH&+IV-Z&`U4CSwRj}(IKoMOOfU(!AcrG%E4ka){Y6u3GG(YCl9qpujqlK zI{CV)Fc1pb57S~NhhJ8yX%i#qaHN`h))vzCb(4kLvYMZgfA`Nl2_g3D@Re5n{E+C> zfeZOKa2|wl?w+&HN3C|gZw1r357f@t>j=lmYCaVrSDw@7xl32dIcK&!X=%;nF$Qu! z;M2i5dMAvsaNLzR)_+xVF;8DF|14}1nI&ch5AGjh=R?Rz>5lxwlxc$q! zpcV84*pj7H(=(MJ^N6!0l-F-3KdJ1Sky{@&u@hVx&)GzqRlzKhvMR>U`KgFzpSsBT z?z2{!-gR|G=|tzD-RR(hdphJS6E6?Eyjaik}59pujUoT|b-H z$ZLOp-Sz=*IUdpq({)y>6-cRiDAYnGrM z|IS@EMbu+xOr9LYqML^tk52^A&dF{CrdKcT7pta)xs~K%nzusC^o~_X4e6^C%noUl zT_>R@JY|`A=Kd)+fYL?AjY$@=7+NjZiiRdIE%*XARoW=JrLI~7-=Kx)2bvYwk* z=E4y^k6OjNuDbkR3hO|pbYGBp59rsH)ow`YK|)_mmPyy;w^T)`-sOK}s-}gspN>|& zl??yzed2s1`MwEKP#mH=_=q_n-a-);_liZoJkm<`%|2p!U5~odI^Qd$5$|$0*MWiM zp4Gdjg&pOw$kVqeQ6#ykQ z*tn)e6v9U(=!NSgDe}j&5F51D?|4@5lGZ$=zt0*9#y86pLge91na8(=)QfUBoaVaX z-{Qy$-Q;Uw*DL{BFw>s?qx2Lc%Yvs329DNwSok^S8rbY3=*4E(b7t0F4L_YnPI1XXmpMBBi@}&C?|jjsVFlACq~R&!TMoH zUeUgXe{Fw$RKdhhRACxOJ7iv9a}luX;i&IAJCE2D1#rE#=pn;=06<8f$Eze>NaES% zhkF_pB}}M+?>IoxL}XNr&dwg6z%9>@N(a!Gt*@DAPtfn0HpUjoH`OuU}`R|W4Dj(Lu10B8v!%Xe@d z1d3>~Ki5yz?cjp|XyPbQOJWBd@7Y&XAWCMsm24LOr=UXu*0YfN`_VI*w$NHPz}J9~ z`FPI9HO{{;I~T>Al%{Pl z<556umM15H$-(?=2)bsnSrGS5Q6bap*F3kri#`FgL&IWj(W#xEd}E?x)ZT69<5?y; z{(re_5<8k{Q}zX5i*K$e;~#7>i`eCLpX_`*3>v{&+=yz6_y=2{r|0?52(uk=dzp!? zt=#2pnLW&u*~1^Ac6k2=6I<>IDttSzmIv4xmY)RGU|ZNaxP`5HuPV;YYf8u4wq?4F zCMXQ53L1*sA%I(;JR~|cdx2Tp1b%e^RFs|n_cH81f#uNyfA84kNG@(}+j3PokhsJI z@lkaUkojNuW3TTE)9ZQ~+rs+1KTvo7`&g6X5nxR@(BA&vtodInbI$1qV7ywv6zV9? zn~A{x0jx4D#59WgPEeokFb*3VI3L@y!&KhPOdoEEl2l->GwCE7GB3H!Upyprz@*-f zTUD&LR$lw=^2Kdm^cpV=E+kb2&7Rt^bwC(lAM@wHl3D>5;)TuJ^o+Ji3xqhCfh498 zmK^}Zz{>o4@1NUJgBgxw*%2TrfSt1gj`ZD%+|~xG0}xN2egD>{0CJ#j#Q%2*_}{Bq{tfVd1DvT*{+peP|4uSnDSMzzxfUfyFGvSm>;JXd4rQb8uQ5-P&6$x`4jgq+2~&7ZiY`paa_d@l3y zmbTBl;1|$K19fqpN^Dr7aaSjAQTv${HxoEwNz@DS@%=UEqq#qS{>aIB87n<}pt0K5 z9x6~D_I@f`FvA{%1A+T|3%s+~_?)E1?9Z{spM|);4S)BjCJa18NXFK^7uo*{q}T}W z(;_`k*8JMQ@)9P(olUxF-Tyljv3b5B>^Nv0`RsV|7l*AEdvq1Hq0%&PFLXnv=>lEQ z%jL>}*Nhe+$h}Ly?BIQ7T6=vXqDoPkzfzy1Uski39~527Is?(Y;)&QYcv6qy2ZrCl zL^xD;sfA-hbvz*}s7X0gRNOAS^}#5mgV1HaNZVzQN4;SC7y9~@W>ZKa-PQJ31;{1= zmJcZbf{j@7)_$rtG(P9D$2Yk3G7hdcA~m27d?dl|pSiQ|FZyczm33K7*buSOSsuR; zu|!c5UF(8&kk>swNNCoOPZW=hc02vk+BM?g%>6N}$n?M!rX| zCbAt3OnTnLavHT9gQXpYaDv2RU_S62s2%A2M)Qn1E)ot)zPjf*$+f+5#_>Lwe&Bls z_e@zWe2`-CMT+}F&ts7Vd|LB{7USSP_eAv8)5{A%8M9Zy+eIlZyEX~XJI(vHn=sYr{J*06ZstVL61IXEGh+w@HG$%B} z(c-N4suH~(G^moOo2*BVdYeO7|LS_2JmS|@NP4fA+sqR30f$(i<`#oy72vmn2U%C+ zOio~f!Vv53QkVwSn!}L_HL$^-?m|xhuIH}T%s9mvQH*HLR<6Oyu;T|LVyCVZP$TO&3uuvJzh8m>?&#L`qY)p*2{p)hVaeG*Tbtt?T4Y&84T1~#A=v(<_=^*n@RN8oRrj= z4|(WncjrJUrEse#3GsHkXcPxfsJkS0(kC0q@uN?)?+I`bocYsI>Ho+_mY= zpD(f@ML+I!oB?fL5ES?DZczOSZf6$FpbGE@u?#h7nz#4b4_!*D ze7!tmKgcWsTSkXMI1&$m9AKS|{Zk)ysj*qzm%qO6@4||spJms##et9?Z(zl_;S9!A z%OWS}`G(PJ-;DPJTrjEu^$Lo>p5oQu2@uW|X^JI)0U=>pS*@c6D` zx^>6bYJlQb<(aMk(=lN->{2P4NX*^(2pkbSaeGD6f}453_vbS8&Ca&KW7+-R=&|58 zxithaGb-=LgZ>|#{?9|8Tn+!Z(?2V?jCH%yKUV0>vwwH`|97YVe|P%-cc=gVqE7$Q zdi7-Q6CVvGFTH$!iT{`yJIArQIt2x!)5dszC7NMt)lfWUx6*H) zK~K8viXK=kksNbMw3>06F7B)t1k*_4N7()L|K~rF11vypebL1|O>OY0OZpGRT>qV` zqTi~mT?VJ2QfIzZ2dJ?>S7T2<>$i8Yq9B)QGjq7$`4v@xUG|<`d4tUB4eept_Op36 zvO71qa#xw($e(A;g+8))xV$Lg=I@V9Bw!NbN6oEH`)_UK!0&fCjuEq%Cz<_V)5k^S z*nZft?0)cz?0%|Kvw`aSNx0qb0H5Xj1|H*a8$lRzeLt*?y`jA}>Yn8gvHDu>sq-_P z)$pyAY-8pxjjiO;XWtMivy7a&jb&418s~Ca)kRqU0)G}ptOV&fbx_oldn`L$DOz!R zzgrwuEEcEVKNC7{IczRBw`_RcxPX5#I$9Aq{0|TU@Yjd?zjhrN$SrjE+HE^GR?iC) zpU!!)^%iHJsmVejFFLE+?~~qie}Xm5=xtur8NJ=p$uD`f-u*n%&jHfF@i3z8iu5L$lP>L@1dpGE=l%)Ww}bD? z?CqSzUHs&zCUo8>=UcmCm;Qlm6hucRTrqh4!_a*3YynD1QnO}q z-Z{yP=pLAmqs)_iVdoY1!&Cs2T3E(JVr?B5<&qjvW!drhZ#YYddoEZ`D*8-6nIS)= zY=dJzOqAmrzmDN0uwj6)W>3jGsi(Q&5q-^a< z)OB`G1CE5M@ag5atCQY(LgjCwi$6;h>b{n`z%6rFC2}qc7 zYNxiL=Xp8HD0LJrNO+549%Xa<{&?)1yj>iDgm^Gz8pT-}yK$%Ms8SB8ER=lWW1N9( zc~<_1dv1fh{Ep=%;HLd>K0VT4^A-Hz>mra&B`ZCi6?33Cxkj~uv7EJeUF$~5 zTqDXdN_vxY)c)=-_xIXU?dxAYz)7#Gy@Gpdkr?DT0jSc+_gnnqC-xc#5uE6)bYIxG zo*e>`rYDYuFXroRHg49O7<=3ec^vU-bmxhcVg0MzGJO=2H7PP@$5%8)C*4@m`kBQ| zS=NW=1lYQ;%vsJB-Dg+v?p>zT!~w?40Amw$PVXv9tM0#{E3+Z~#UEaJkHq>q^HTyR zbTa;OU-$mcj{L64qSkY5rSUE*v#GjP+k6cb0W`?+C?eH#2)|p+o;SH;)v|Z35gS7Z zcQLyo3t>>dtqpT;A=ywBCjGO1_5}5-nZ0mkVCfCwH-ZLExPzBX?(MKCvqy?I12hYu zxii~XGYr1G^WR)5c+*rT1{HuU+xW)1%Cf$C62%FP_0)13GU1wB99@Sh?(y29pl6o> zrLvJRa#@|S5E?&bv~@((y3LlsM_I$7J1f^`uwgxr$EINlOgSpTDjN)Gbm==N;Sy7y z{?Yy0RKA0Wc0${$3`^-1bpe=0sGx!u=rL1PsC;a`fZ1nN;*1`9SzdMg=~SmZ_g&TE zpqh#M)P43? zj4vXsnLLfYHO zkF-(-!rdv&ypSG9iw0zg)fW)X`&z+m{U&h9_llm+8< zEI__ng-a>df%RHu(a@{BIqc^8CY@Q}ZoV39t2`_bq!$M%jJl<_YyLT8fcLzOsPC9* zc;4r}KPbMVT{QjqmZ8#@Wla78X2BT%pmcJA@vjnZS;+lWnY|_aK0?wA@h__MR2;<3 z9AfwZJXO+h*X`>a*rELW*2^#Jzq0f*F*c`oCnuw)`UcT*{;um}Mg6%_2NzJ*?s}8) z6)&FU-A6W~yPH$pD^2d@bKrTQnzFFhc7tp0)et)6R!L?i<7?8L7dJXJcbiXy%3R&% ztrFhkFUC}IEzL6k(pdQ+v?7NgwC3+iHoa%IO~!v&$Z>o&cU(>v?|qnI*<+GlxiRWn z#~dYc?Pt~m2qD<_insAz%r`+`(t~Ax`M~<8#@f+ua*cQMH?#&ydViEJ2A@stQ)FoPRzs4 zul|9>eMp21DnVA+@%C?{cj$-CG2c5|5|%*y8F^cSLhZ2YE)G@9I#i$EQE|a`>2F3c zi|S(hc)Y*fuP(J}m04$89nq(OcI@TN3y0*dZAlA1)e` zdkaZJGo0nigeLC2*M1a5Ze;&awXm@7_-M8xIr(|+%Ve*k`7&hk9q!nY<>qp!HT80C zuLB%vI#K58Go_%rxfru=h3u(;cNdDmybSkNAh#!w<)h+GUNsSkOCOrW^Yz}`5`gxw z&f|7Xa44hC`cm)p2k>>x^_8h|cWW2B2GAQGH60b-=II&s5mAV}XMJQL7@-5FUBqJ_ zf5s-aL^q3EoeJQl>;I@^oxg1zzk|U>j+SqooaC~o{B*_G%FNq1bcjj7IA@KwprVX& zvwKojfxWVLk|2GE4&{FA%ed!@I(*)XSv~q`F~=8P42Hj;{vK-~!Z!A@EIUI`{DW|| zN2b~o-0u0u*d&BmuF}t*mo*3Zwk6;d)^_|TJM@4BFaAMM$NYd{rI2#7f6S~R z?Wzj)@Dg|i(JYS8>)7U&HC{5l+)a))8akM^Trn&(H<8HRB8IPmGv@Wy!7QD6gN=sf zjfRw~jw+n^Bdm*IkVIAs*F>s~?7WwR=ND_c^pwbly?a_RFNJPfa``7-BO#qDo#GYq zQyjju0I1U}osG>6p=veH>MN|ZgoK#otX{o!Y#WxU94+#=2NuM1S2^-h#~8mM+*xxP zP}0H;?Uf#leLSkaTm!?Z&y|P1ov95IjR;U4IY#qf%s%j4>|$X|+A~{AP^(5y&eDQl zUOZ|8f7kLtYH1u0Ov>CZcbzPj-cH}k9x4BbroB)ZXNA9##Rf~)^JfKis1L;l=o6$9rB#?f-+vg3lYNB4SEfj-H2;z} zWsI{Ta^w1-s&q1i<%PD&lh1JFCC%g5-Sbord-@lFZG^6~-hV6;A@`NiR2Iyik-x8F z*?#`_yZ8!uyRe|?;bW?jBTpQc^aZ`zI}P<9zt{VziNC=}kEGvV-cJP1XGAnYu3{ks zyYN{JdZLUCB9IbdLc&2lbmM(_SyV-EM?`Ky?->jE>;`3?bFB) zvfjT(<*kaAIqBclHKkM5n>sm?Z&%<#tTx5cmm`=Bc;ZbkYomQ)c%}^ZE}sUyE!TJx z=UM5+YMYwAve3}T2vy$CI*@W(GQ9-T9GQ^!IRS+jZM(&>v9Bd$$C=13VR~mJRGSWc z0yk?}U8$S7qj^5L_Q|$rzrvI3ygcvats;|OFF&QYOd9{(rFZt1W$U_+yZF$Nu-KqA zgbeYUSM818pb$^mixM}Wtbo~gT*z^qaTDJ<$C#aCI5neZT`SAe)ABizQ=#9WcroAp zygZKUBHQlzv%i?u*{E)_M}qVM+GzEJaq8yzRs+$MZO)T9aeht=|2|4PPx+H>pJqgm z;4RCr=m(Tqy;2qruUcD9@fv5 zg4gGUpA4)}XFI)>WW|BOKhkMY$++v5H@+j7nO0fwyKmi+Rd|rx>IYsCU9=p&Z`Pym3}&VaGgF8n=b^~M+R=%yc_eg030k(+Z^7tiaDn=6jKRu{f{lFUC^ILU>=^i8?a&&m)XA>$oo&ERPnuXK5i z-w*9C3#*oj9C^cC9^o~|X0WxMe#CFDMEr~=Yg_E7wW&&@6PbP)WloKjIhA@_oBT0y zYN;k$I5R8sR){`|l52x|XOk8=cH`_Ce@X<^kK4z>rS>&C4QHz9B(ykLZpNmFdr;dyIm&6}Gu74i~Mcq zj%+h!`DB3vBLNIt909Z2;!M0o-}Xg7h@nDpZ^ky~xi|3K8#oOn(Vdm?;_;nhZHZ!` zfli}lnMsFQ?Z14ys~**U%-i!mFGOX>BEvFcQ`ohvsp-6m8|!hE=56Wj%5vMm2t4Y* zg#GDMaa%b#=%+>%+(1^Fd&gIz8TLSu3)v@@*3%T9UoK3|pvKx~#!N`CP7Fh6H`N?r zZzwIEK19!r-^1|D)y=;bzi}i}3>B7d_|k?U(wmz7bEc8s9ANB!ZRvGGHV_pu3@H5; zYwsXKWw2bVuZ%Sazr7Rr3h{M)2Tn^HL1d^1Ic+x-s8LEZIa5`Q>4 zM>wUVIzhqp)A~)dK3?>x6DAxNS50(- z(&)?4cR*MnwhROb<`N+%&3BW)J9GLz!kbLW~Pkx*1&buI^<2z|_>riyf#Qc;P6 z_=apL6`2#j9hWJ0UjH^-;hz`+*{DU|vH8Tg<$p&kTZgCI;Q}+%%RbZR1mxccn^F?tbgNZ0&YJRV` z-bywEyp`-s=xqOTOS|a0%@5pkP|yx*KI3Q)nN*HabPAyr&Z@go8(Y6#yruGYGrB*x z6dl{-IhIp!CmffMQ{O|)^enf3U&)n>gT>1`zh6Izf2STG7QhYfBtkKE-n?o9Y>%83 zhz_tN70zVq30nw;OYL4%yZP-$-nR8S?&K^l2-nSCXxg`}b-{mak?V5#r@M1?;_MRR zFWcKSb(S#_IMiLg$s%4-OEQNwDkgQDrv6sh^=M<&S%v8Z53sfnp{ry_1xK=~Kt>Xu z!h`udj+O(BTenE(X3Fg5@}F0CBC#T@pY|WMdz1P>R$%FY0%f&aYy1>6YZy~l+W+cH zmZ@a?&kibdgFdi{rlKJ|fK6a_ylQ%|HxXN6kHp%tTTK?avHQ|iVB{a1+2>9x_ZN!E zovzV2#nvOtow0{3yjeuz zAmT5#Lb`Z=X8h8>uf;@nJB-IJco5b<7+P)v6v%D+>6En$uP?^+`VL7UCTrwI*0tYy z`(&w>6eK5TGRAn|0!C@M3jkYdkd$NDw@izG3@qskNG~Dq@1#;O{_Qb9y6@gr>@vrg zDnc zFi!iT_9V}Zwtc~|_|zBr)a!9N!0t2O11)!Y%QP^&%Vgd^aST!Cr_&U>2X^nu;PWo2tzYgEklC--W^g7dl zY~I5MT@`0svXF%eI&8TXhAhlmJd1mCV%q`$n(nMFUSJ4?UN9oup0MvBPv+aO5>E@V?{s_@Z}_J6is5T&8qC=MlWCmVvLUlk zOxq1bJ$+`IhuQs1MbEdNY*J)Kih!ANONZZN(lXSjvxSy{whuM3D_As^?MNrvspN+& zFx#)x<#(BtQf@#1sjtreNx;GGb2-9%C~{a=S?C?S}h7S~{iFD?vK1RDl@XBd*&f3r64wUI@5% zFsr!CBaHyUrAVM|He1kq$&9nffJ#y!K+3Z`>|s3#XIrfUlUW0Okbs30|JpWQmYH<8 zTx?+UVCNps@xiS3%>sTAs`rh~MP}vSNG>jWm*oD?C2Rz=(sWAt?NTou0YYkSSmD1c83{yTYdU z+*H@(6Ct^|$J2^q8LA$Q?$5H;?#On&b0_bGF0=XqM`i6!9E5fc?*LPi*iwm|0eD9F ztt{@8bm=WChIy-?4Jc?JwM;J0yYhZ0w70~pc`Y`vg8mF0OC;PMI*C+fGq%xt#&u2MlY|( zG+VlOiux1EvI;PHbM_tysfV()n4#!7)MoP$*i zoSo^c#e=s$xBd1JKxcGPDy%zpMD?R&j%n)%Wr>NBVqs$;sh0b$uNM5Uwk#4$ohCOA}PL->v~m_JQI@o!Ayg3+TTjyUs@pT zG6)>18pzmiS^{F1%q^xbO}0hIRjxJmMM3RY@RfUg-Ip9-%0PXtuVo=zndgIeH}JC2 zO(zfhYnL;+zW(2wV!){w<5;O2QQg^cJi0)?@%uO>V5~~c16_>^qviP)_IVgn58^K$ zF>P1bm0YE)JrzD7kfx zVYeTMdvMU0etd_dWS>Gf|CE>n%VcVsyQCHL-cc;*8#I(#Q$LbU@+=z`iimTnC|=L= zRo*oy09n4n7gYjWOlH$u45k$qMHzAtJ~Q6xB7AE6-OMf3fT=QzbvL274_t(a1n1uV zNo&l#g`KGK-#|KDht{3{7b&Z7T(gf2pj90kFyuF@TGq#ucfK1l$)E3XCo5(YTZx)0 z%2>61k(6Ci81V*^DbKf3Arlh7Z2{@~CkYh8fR5sMragtT<%PtCF;S4s&&riWkjj1a zFM#bgM8oVJmB&2HFl;=Z^asv6@Kv(0V7dg|wbbNU;pzg$YI+RpdbBuFSNG*sst4mK zB#!M)np+kteoYVRAy{_MNxm=y|&&zYU@B48-?#F#U!9vd^z*tYepmD98A8+GThvzV;b~wKK8mOS5rwbotsKz{4f@wh0})cTK{+>>`tH&EmkXZ zKR@(#`b-~wrf<{r^lNQcAm27FTY3fIP_DVZpEi4VX68750s9B%2^|iHxU2~-R?Acq?^uKL{ z)U3>vil8c#gG;BjJksyj4G4ayVGHaTqZA~302Q2~?cXYnqzc0x2|+;>h_HYivEQ@F z+`Sg_Oj9Bs_|X^{xQlI=VA6vs^mGB1Teg=!c;LPK=<`$jlUOUag()1Wv?+u25BZ8o zZ8D0p>hs6IGTM#KQ;O7c5>#7`VbLT&jNRu*X7`%jzJ0+^_zixfr}+Jbvz=!^tje){ zJdeo%jOZ^I>phuH!Ut*&4L$!m^=c&zyJsAtB40r-(~?2(ns98!cy-x3Fe(ES-6#T+ z7v6S*OX1K#9CT0pbsL!PdxAWnHd_42=;7+I3@NQ#jAw6u^~u+1{8mX~b z&AKf&;(b<(5nOstxng>`00seR8AS)2%|wTC)8yd<Wli*H!{1M^rqP5&cxF|{t+;K3@mk-0Dsn--};!hQ6)J&a?W{reg ztH`duxhkX``;;o0bkBa159~-NkP5Ak?k`mgHUe#>`Hf< zGL}6;NwZY0ly&Te2<+bRNnOS%48s>mh8qU+zA9bdf$kVNhQzObimrp<)21|qnp{?Y zkYV1~&M-;8fQUi*CH?d_DjS&cqcE8EutK9{Z$70+zcbcqI+c-@{@Ifx+#ZCn=F_WN zd!_K{B0&~49g6E~r*Jo=NiwcOMXLlf!&wB!urYqz*f-Ul@r$Paz#!A`VI=#4vp*j< zREc3@1V+aDXIVVr8-)n4n`quNyqQvpKl5rzwtbjA2h(yh+di>xIm&;;hz=Jh%}fIu zIPZr#;Li$^JCgqK74pOYTKkqRqrDTOkNff236UyKZNIy%o>n=hG$7Dme+GQRek!3E zxfAaHV2W<%Z1<5!A-rmw_k87jJ+baFYl&p09_L*mqQ{z2K%{e*SR%a5576xVRP_6q z;a{KBvM`)maRncSe~qWSz-Qz^^Wf^ki-Z;#Z!!K)z1wl2RqeRRhK=E*bJp7U@m zCh*#y8CEAys=~52xEtlioW=|7)n!+GfU;nez?K8wjl%63T2^n9!O%%_5io!@ zX#jOZO<)i71T9WMhP~(&S{BQHe}?S!+#Dd(o{_B=Ss45(@_C%gS9Yz+{!7bIN{#*+ z8||jnoLfS>|Hgy__tL zz^EkN$^0_iVyQr4`Y6I25k`ow{;W=*p|ZKYg}5YF%f`9|2mYqU0{Vc#458x$=G;n{F`|FkIGszcP#@6pS2%lJ($5Dx_!IT zt&EV?aka_0IZ_I9kL#2a6Ig-ar}LmNH`fXSdePeXy!MPf`t39#gM?jl;G86o<B3)sMtOGM-e2RfoBixe0KL9#*B|ob(fn5{dbxm4u^P5V9c) z0V-kmG^~aYiXVBMvUD21WEFX~?hQ1$eaoqbiS)+{BINpB1p==>@g_QcH#WW$RZCHL z@CL;yD;us}6n!*BVTyLc`0xPnj{#J!nEt5#K<}VeufI={9?lX|vDBM8Nw$K?EH$;h z;?7^DD_>QloWj4#XE|~1+lq9c6>*q!e7~~8Cl2N9wSUt%n4^e74$OK{PTIyqWTN+)4 zU8q?n`N4SvPXsFQ{O0j$UvkRWst$Qu>p@>oY!-G&8!f0?ug!+#jrbZ zzGR})X>i_~4ZFfcl%lOn_Y`I$Wg->a;H;w-61)J4K@Z>kf(nOBovgo#x z4S`Z_=lH|__&#AqnMX2i!BOuCh1^!7A2QDgLyNj%s zBjXjroJ|8CPhXpE@CJ3EzUIGUU<;fKW7JYveSX_O{4Zvtpei$~Ce15{%ZD35u7%}2yBt;5G`Z_E-=d2kb zWpZ^1=O6Ho7jw@k#$a2~n~BTiX=_~m_&sX6utK|rt3E12;kr};_$)$kQDum#(%K+W zB^UY(I>0Xw9l(E1>YLybIG$+<1}7%Ygdn5LQ7=qw_KXR^q7CM$8xo>fg(qZsm!ZO}*kAK}((V=9n<}2C4X$ueLPvcu^MDB)x z=zN6Rh86CF7wxT_!j?sGndW9@i>n zDy8l$E}$STKnuFpWD;UbsnxHGc)Ag7?D+ai*It<4uQy7Yf^?MKLv7|g;icQ|ysUDq zEGa?TU!2Pm3Zx8xU4W$>`bP3Xw%E$jmgkkC(0Vdm-BG1>*5!K0hzc8@g02ciGvN)T zPU9>+WPZ))+22>sx{q6^AJ#hHj;3*qIl&of9d(XhFgTP^Nlk z6J5$&QpdYXtA#2C4NV31r2DP0GZSRAQgp*6Fw~t$wT7QtOB^U*d1SabqbGki4L@)T z3Lq0&wWqR!k*7@&CyRN$l~weEs!BbI?ik%6?1(c3^W*>|n!EAzf%9N+8XKL)RW=sh zI%=d?`bqylF`la=g-Ar37TF2VP94>FI<2tandlS0FquBOW^bBTBi4#&1od5_2hB(q z_Nlc$yW1h#>R1w4%SNT^OzKBhN5-}<#QeDY^0qPJEnid7CCB&}=vEsZ1%B7?rP2!| z6iT6J${?DTotTlUhcBUb`bS28!6)w~} zXRyNfaE_|R$T1uEdWg;ZL-@jLp1Au8AcNeV?_cg;cIMfHri0!`T8S7hQgRl+nM zd5jvyH}Kvq2Y6+^Ajpqo9|rcE-7)aVXa}`uvz#p;-lUco1Y-JVZ|Ff;B`0Egub<@d!o@;qK1viwP~on0hRg(>R{_Bu*^wX8&*t!M;2T>yj$ho&_?H# zwaTrvBN0W!a2X9_FV=j6St{m-Hv z>_a{xSWQQ$!$+oQA@zc(E$>scEV12I0I6nmKTp$7dS@nPP~1BxFORU|2S~#@y1+mJ7dsm!PSi-ga+4LYJA@>?YRyq3YMDNbJSy|f7N#GW7Ix3Fc z0?%(s8wr4Zs!H^lrCnL8-dZ}@-7TgA)!z{55Y08BqM=B6nM-{tux?>P6@`6z^Ty^n zn|spJS9g69B?pM9&I)W>ZR{Iut_3W4zX)N#m1jm*nGV&n@jo@$CJnaFJYrv4p?C^! zbKiM8?X1rfchqm_3-`s24ZS5^;%k<=t>ru`+B(yLUG7c^sH4-mW&7(m88QQsx+0pX z?bxhi#fml|tyb@{B#L$FfxirZ{N>YYPYqgZeP?T`5RUu10uCvvXvEl{M~ z>jedz)hVx|=U63ZCTE5a$wEi_(unXWFJ-xyqDp=};!N(SN5&ki?TskR?XYAJ+y2^> zJU#Y*cJxyu%$Rq98)QdSfCC%$ANXprLpNvdXNdiHg=kF7s527~=sy)pi zk7E`R{bJVjpw{(9v@Ui9tLbtp_(JV0hWhMLj`!u4i_02 z4yD^AOH#R~s1|cTItC^lE0w)*QP%Ye#`aA;uDyot76t+o9LXE@ zT2Z)U0`gYYE+uKWLSIXWXwg7}@Em1( z35qC8IjI)knyR?+3>oL62%Pb@^M4`AP<#P`@fIH;^!(B3k%Z)T)UXr@YwmrENY)uR z(rOf=*x-svZy|kn!wnxQM5L3m>fo(~M%9^n(=hJ|K_1>Jm90VSnwz2WgQSe64Bmw5 zH=_o5eKNIy0}jZ9o%L9Ia}0~&N5uGzYU>(3ofXh8skRF2PD#Iybm{!*R!_Lwqy(7~ zGQn7hd*HWkrI9kG;?35QGS_!I+IHX&Me?#Y0~BQ(y`MxWyr9Kr*KBR!^VVCBOv zG=R|^b>ZFoEU@{RY|UY@|Ed`<5jjYkAUBsd@qEV(jPGm97RTjTcg=I>F6THHT~7&` z7DL9=;^gyO3JGobcOEKH>&@z)Dm19PD^Zj`dvDXKImUZP&@YlSm`Eb#=JPFDEK>HV?xPHMvrusHA3BaLx;EO(WE8 zXfgT~z4-+V#{j-z6b8I(IHbP-UKX4=$E;=UH@O?QX9pRaRwgR!?LwMG`R|gkg6-tx z$CjU*&9$6rZl;8Jcx%Pv6ieq?n;KhL_KWhQfyXsIv(L$lFQ6Z`Rj|$HPga5Ru7*B3 z*#N*(qWgsi;8iuZz3MY)JHI@bxV5vL-7IbCIsa2ci9?%tJ;Vis6J=zE6vDI>(QGVV zhMISbX?b-u&KVIF=ZJfl_E0oTIX4aSfUot{iWD+nqAKv6Z}VSZC&BAT&2?EVvoD8u!SM;@6xr?vZz0lIGMdeGj5IZ>4wbv7$vTGg~HCpgo#|4nP z@wk9m@JSC;dccHUb_=9VGfnTiZ`0IYjR?WCPAF94v^{t1rikThVVcSeC&-q#p=^ne z02W8sV0*Cf9l|_PV|iR4FUh#QkqY9F^B#=rjy9L8DGYmqYkX$FI+18C;h^({1;*E) z$C?`{MH5yyI_F&dAvAX3o`-RQbS+t`;|^!seNg`5h00$f7~^VODiFO9_k9&9M{vA* z^bH*t9d29OQ~9@9?JsS4&Bhdv4w+89rF6s$(2+MwiX@V>D5CoG%}q^S;x%6PZvF<* zxu)0B1HI3#WU{5%O>)Zw>hxewgBQFbb**w=7uEZMWKGM>w{>(i{o{xI5|Z4blmbsS ztfO8c@%Si}tF^mVR>EdkSnc#i0tPjM7;5M};~5xAL;tSCV!ZXC37a!`ckI}3e!s(j zHK+bWWpb0a_cw*cD>ZK=&(Ha%cOV|vsEi~_LSPHjO%9oC7|G-GZK!Px4Vyg z+|QN3yHIxW4xeQ|xoDm!H?nr$ynK39&%akDx%eI7TG)M+XjWA`oCjG)m|yW?^SQQc z6?vcIgaGrwP)JZtfr1_7F)@E)H`U`~ltFyrt2@w8IN=#^ONlkxWeSJnBZOpcgbbJy zvr+J9Gjzsj&73z}Xbl79Qc^gHriB2&0gFi?%!>&my<_tsA>wL*|1>uJ9$n??6Se(= zpHplVXl^+=r<|uO-)R-MSPo)S%A#^9{eN_XenYp^L!?#JUZ2wX9VQt3QGe~rzNM?4 zB0uqmp}dO`oAW39W5TerI&N*%PQp$=DR5-UaO(LJB@cB&i?0kOFH2+7VqiLeBXUis2W$ba}(K`8@fc0v&Zs^!2 zGlR8(C2#Acqt16hx&|f@$liX3?CtlV#Iq7Rxu(TghS)1(q;k*ESIi1I(7IM|?YB+L z!=`5=XIb;ew@PF&L|b|Vo1#L*mzDJScC>GyUeLvcPm1*~t3_0?EA#i}vZRVz+IUyO z@q6tfdYM+R0&7_Fl@ZC!k-(^X;L8w$`G3F6wwHlB`_2a=rzp<5F=Vf1g6!d7`x*-# z4)wDUyqa!4>MqfS-GYgfaY=@A82S0ha9E;OSQED>pKQ|oj?3D9J$5(H#pbS-7{LK#MzIr-e!tZc zdpVgSJEjSp9;4AvqSq62YOC#ydO|Z%I0^mUO79$8lW!%DC>J_^h*FGe;YzBzW?%~K z?BiPL#Ca_c4)V6c!4(JsTyeS{y~9^9zl1gSyd_o|AYU=}l+5DpO$W#6Yk2aHD#}(& z)(|2ZtWAq5@05hKKmKhNJlQ*Q%a9!_(QYh7dZmHQS&43Tt?im$!STc2tzk7EaHt)D zqFnZQD63c)sNX@?!~Tbp|BhW=sMl!G)6gD0ABLA*?0FqY4;*#zs#Y3oIuV*y3B2a*p}FBTE=BE39N!OoR`hNYN^)wAG1` z6xcNsyFVthTwgu6mlPBUE@{!%(T{@$R`v;R6ut_gSV_Vl9yHm&sq`MEZ|*1SGH^dx zZu0rjyYA;bN3v#IT3)PH*p;bpEtT3&USYjvYsdA_&PlgbbS#amd?bP*yPhn*60D%9 zz`Bw>(;OXa&h|X7LF_Cz7|rD_}o+gt#e%kdas!zoTcqQS`(!Wdr}W5<~%2e zZg%=2{Z9tN#VGUG%FQj9qKo{B(r&vd6AJUMS+XGTd?-j z{585`*-Wv-yF>%2>LPBJQ};x54#%x`RiW9v%|o%SGPwKl zr8VDoUk9Q}-eph-Du}+VR~qt^p4KhImQiYIK4COvl;fEvSf5cxLV(7Se6c{01Sw={ zPY@;RNs=OWi9K8r>zL(QyP|v*H)RRFpcV+8Ha^HGre>iqXDjwd@b0DWR{v+!#Np)A zam&Agi)yUlsV@6fFs)fy&M}>>`GNWMA>RDfQL5)Bfy{9pSObl>mSn_QYMI9&8q|y! zu1j-ngaAZN%Z@WW50dOKD9N6d2IeqLW&O0cyOPm;ZBe1Yc*GI<*0u*3hzLV$zBPf@IQW6iygH>S z(7t=wNZe11=m3)2OtNoMip(3hGN#2d?9_q6y>c)^_6S+&=*uze71kc+V#ieR4`s(h z^<%VscEh8l1LHdM8XM+z9IWoS7@&Kj0Nrb00Qnh%`P9d|JA39(@*DNs|MdnC&X4gJ zt=$+5$6y|aG4rrGn$H56kcUY%p)}-FyD@9&um6v$0haj!V78}?;i3!xm2F2v_m?0d zx*v6VzRM7v1#*h+awKQHfpoppZDxV|m!m~v7_0i%B9wA3lhzb3aUSYpU%o(g&6e;* zR#?r8;QMT~5nmSGluXYeYDT_=#C(GOzkMhH2#m#ceJFZgyfBlG+}L?)}tI~SaMpo?kv1j6rf9p6axJ-tv)x}0V(tisk;j< zzWo4$sllL0|H04}2HQ{llT)8zh{c*F+~<5=LKw&|O6BJj0vu)w9Lb?3K2^12?3^DZ2{1W?6vT zU%N#V{nxNiUYF>ijw*0RA@tx~kxy17h*Ugf$sm9Lhr(nx34774T&VXam zdTRy3thVdnU;zR5nh(vcd1X1d-=VZIsQ6p(s9y%y!4WXIRgN9nGrNA#^pu)V@fYFX zuDikpl+;5}cw6!Abasqn5CO=-DA^kYC!SQ!+v?2Bvg9s zOvw;_bjgRyGRwMAHw0r|+}mQ9e>7MisaBllY%M_7-vfBG5U3_^Q{hz+kO9}L>HP!x z=2+UUi7Qg`rxtTQQp#rMQSRsrnqnG1aUPy{%Kf@o)*w*nC?nI_qp{s%jXDX@L#Qti zUk1DM_VbM5SKe?hgl0&~FvH)qLVE`w-%B5<;bS3C1NT{|&K3Pp>dtP^CPcwlxf(Hb zq-CuZT;knPr0G~!bFq(2YvN0i!c^UwbNXK7ef1b+&xL*t7(d#ql~VfrAw39qr?KAx zF4XIT9RzTpyZT3J;=DpM*u=xoCTc;2h4&WMU+i8F?UQQK@=LJ~LNSz%mF^{}(JSO7 zg{cQaDD~C0)uMZkrn>4M;4lf?B)gsk4j}=Yu%de{fbA!MNB)@0RpQA8mzT=3bamUh4$fBTtMVu;09i{I~|84_;{2nx_8D34<`(66s7`}lSO?kkf# zou!Lk2N&ZL)vM{RoM>@Xsoh(TIB`rBKK|!|%~j+yZ*X-29OZSc!Yu0# zZ1>>_M-3;_G&{%}^SJ)Zx_bthKtC1#ytB1Wc|2zf(C(w{lYorl1QdJ@a9mKH4wGj( zCR7ziw7e6+_nrD5WocUD@*X;1H?dyQgN&~vil1KwN^zWLfZe$mOG6F{H8qku|FeOF zXOTAXPxA$k$|_mW3*~y;Y|Sh)h7^j;^G;t49HB@u^s}kx=7}7yz%R@T8vBmZdp~8( zgxm>MoE0vn))7|R;V*)7va$|u-*IMGAad`b`YsL>PaP}Ta4(MeqNwo~m`>FDa(b=3UW z!PZxgr`7+tF8M59gDY2pCB49?fldGOEs?Ok8xSd2d+601pNq-N<=xWIpH;O7lRsxk zrnj2a%}hLgA=_r5V{E>$-=Y>?;wGS{hwX&#Rm&z9$k`X!(}P~Hn;zy z1|faQ%z%AVgcvbXBo_HQz|il_SKpfheaeS-Bp^?5I0u=>N2rL}Bs#cj9kRk|A7v;V z4+#&Ng?tk|$qBB%IZZ33Kj}h-i^cVo)*9s>y3t3OC$YlD>E(F-_khG1sA%hm2>3|3x1Jb0o98yQNYq(L<&bpzEQA zilC(To39L;)%!_khCI0i8U4}hJ;vh3zLrMXCI8R6DhFT+=>L^`d=qdjXCbbI3-Y2u zCr%0fbF7#BMI7ZHwvBbWHYv$_e!@8-l#et%xR^jJna%m2Bw8}$>z!~OIZa817yl3) z#KR2NSMtPa9TK1ZCq3!X-RN42xtGXvFbZNUD!{I`1&eHxCBQcTwU~%niVQ`z?Ok)M z#`;;Rgd(SF@%;h+V#_?%9IH=h>kl^_!xlE?J^G!QJDY_o;P%+={BhCLiJN`LwTgk` z0f}a3&1WHk1M=T!WfQ!1_|~4$%@ATH&Z&WQ?s+uwFIqy1$#$x?IxKWPHdicZ?<0Hh z5oJtnJ(p$+S5M67l4l~!!V&XP)?zzW_y8A9I<95e$^EPb&0c2NKcPSx(BI~XAi^Nu zp3&s3w!bbtO1ISf_=G0xB9tmT;so`r5BnpycK!LK-jtGRsTO1OCC8nBdyUH|Wo-im`sdbJ1Vwg4c13Ig)1;B&TW zL8o_)(n5M)+lico?zVklrlZ;OR+JXdQWhPJB1kgW=hRVLoVK^|D%?%eZ93!>_Mr-R zSMdK*FB#hY<{RDSsCIS!h48hg-BVP8JnGYLJ%Ha_dXujI1INu@DK8Wz6ls_JRgWge z-`zYge2^un($N?4P0IkabfyF2PemU3DQvkeQr8#>lWf^3eDi@7?ass5))TqMz?uik z3%cmE$AdT|KkF&?3Fo_Y2m3@hH}?4xt@-k?Y(H9jY$S9m3nT7q=9j**P!&Zvc;+vlQ7=S204L}ZHud-A> zbHG1aHC_;4{_+KI4Qz5xnjdQ@la|jJ?1*&)AHi7Krp4Df9$u~^%mia*fFS(1v5Q-L zD+BwFf4q_K&)k(mqn7zCwmzl{`qPRa(gZ%geVF`9AMQTo>;#_@PHWOKr5`dgF$iOd zxvS^@qnl|KIoHL>O0T`~`jnsj^bM1w)){~$W}@-gbFg%U6_e13lKrBo;~r304^;&I z@{G>UKv-XgJVO|#@%MIxryAfp%yWt4=etNO^FxIz{71pkmeqxn49P`n+#f`KJjSLWPF=S7kf1vF_6^)FR=&Qj zvkoaBv_L1Vw$Mo?HZFjWc=LD?8+VFq2f2XY*uiAcG{v@jc51SuNt&#zkaM){SpzY% z$3q2(k%Ap01!kPf{9Y|q`;}~1S;WlUmOhRg*ImI)&jiF^ZVs} zyiCBjF6{GAAaZ?&B+T(J*0%g}Z6Cz52FsBTDsrVjZ>qFIg-juTN!$>_F!kCp!vD~Z zPJd!9STyi)ZMBuac0vGneB-nzZT}dkwL3?SLE;R49qI3&c1SR9TOAqXAxk{6BYwzp zXR>8NeHQ20yo;*t+;__+M3_@SB#>*|wq;;N+P|qi0*iien=BD@Gyc766t;)b%bj9FOfgB=1ii!@J_oQD^ z9lPP1O8J>9D^yF1@ULydC#XM_u5 z@drru<^Egs0je36wv|PVrinNA;=~a}Z^;#V7Nq(<=o%={IXZ`VF}i(0~PMOjP_t=5BD2`xC~RBvD7JC|91yITbqA*88a^ z3%Gjcd#nrC2S47(yvhF_Ti?>kLJSzUBH8>coaA94|Bfw@fNjGR72bS`&E+ zB$D*JhV=GW*@+9)67~KYuvUL+VBS78khBj0`uq4mKb4ys2+VQNoTE6Ts;eyUSl@oU zulbAEzt)o|n|MnD`F&6i8aSu9U`)Y(gGkZAp9GP<;_|o3EXn9SK=dvY8FP?y7K$O+ zYp=5a+Sx`M;P>l&ZI{EeV`UR@YcxJs6MB&*A3G!w^6FczCNl-1VaA1@x?VKYL=j8&Gu=_y+x*UI)QE4JO;nC0pEk9cfDM z!%f3K(HVb*N?||snxPHGtzbDc0-Kk+ar23t58gHp*%bM2OcF*RX|y2re)H|qLk2^vVaj|gLL z8q2M(tlB54gLtrm*c}?n0C%Jw5p&Scn{jnrC+r|ema&{=rkCmT&Jv_SPuFWfYq!qK zZAz~rb|YadMoNeLS~ zhuS01)WymOFYBd@-5`7n8n+P8w(H|bpNGZpbj%7bzM7o;( znBQ0X{}kJ^^C`M5o06Emq_$}(kZ6}2kC(o3jDo~no)B+h=2E}YnFIb8$epAoS*=jV zQ5E_QNph(Yu575NC!~#NUu`5cn7wB^Q{tNiwl~@PGykFO0yGs zjNr7WpgH6w0NYx^c{FqC;r*$%ccL^PBLRQ+=8ox*Z#IHEGP=?lk%O`~5%W-Wz|Z37 zHG%&on{wlRy1qt{DwT#vn1Q)_kF`P6y$xsB#%r}9STbD$)OZfM{#gY-NLrQj6cA~N z+P&0*c^OQ$9|)7HMhN#f3NH6<9i{p$9*?7s@7T*WsJGh0KX!R$b6t7q&CaFP1Tm}| z<4XgOpzR*;G198SCEM}%gX#{%*!`U zjJ)Dj8$Hgac+c3#G5q=`_ydw4kC(J4?eWj|uM4Vulsj@&UG9i9rWH|e%pQK#CebSd z#rNJ^3pKNoCvCf+>iy`~azhrD}BR%pZdhXT;0GjDTeff3plh5RbUta_m%C0W8Vh z2ZS3HCOTOdyBcCZ*@99@GCh-+zq>r}k48~7*OK*yndc}fttVr|mpG3}S)`=LnfrYDSM&?w z{8{wV1iax|40_M{?>Esg1wc^=Mn`B`@ocTiZ_z$PO_40-Y9UVH12lQA|E1>Hf4-ZS z&tywlvU-AYUGBL%Dx>O5Il19AH35{%|4KG2FaInuMvSxgqt~daTU5?t$Y~KZgtWie zUulfE(~Gy*Vo_t!FM=npLSId1`6_V7p>?}=_B$rBxX8HH9lY4wXCvVHI+5aKF2Q;) z$!}n$#UD}g0~saa{xjSK70CHlZ2XpNS|!hbvd(=8QS$?asw~5Cuv6KHg$naGJ#&!_ zhj`Y%%|{~dTk*R=&TiiYWZ)miPUi8b>|-Td+TS;R-?YTMi~@4Kp7EaL;&OAI<-I>T z_S~qSIw48WB8}eaRNd$_Ka=SM1`1g8ioj6MV?8HjXr1?20A6DjloV_`QRQdIYHCXWOJ#*swtRVY#(VO{`8 z$2PzC9k~++^=l5XwE(WcGv(#Adn>zJ!_5{`1FdI(;K$TOu$%>O15xq7y}qDSOzJG%J#{>-%Y76 zSq$uZEG_RaBjXR+!z}|Ai0x#e$v+6QR0Blm|A&tloN@G6TLesQ!Ifqae}6!;s6hLs z!kF;zAIq>v*w?m*eIQUaxX?&=F1U2!TIJ?{VlvPA|H)z@gM^PR`)w`z;nIQF0nP?W zpiH0vWg60NPah^l?dHyaR1{USy5Po_^Q!l%mBMWs4phsV|0ED1i9fY^PiVO13u}(y z$t%F2^1u{nC>UMGpHWa_-&rW@iq@1a`qxU>S=z#B+6v7>G2|uOUaNPObzhM2t=M{8 zLB@Za>fhy(iM%7nInY2}x}!`1pV?YZ7@~vO1>nvp+6*uaYcbH@s>XbIZ@)bLBx2xZ zZYS!Mkh(<*1gKJ+oFx9KM1hfg<|me2#LJ|}g|Ra3I33G@iB+?F(p;&<8)OyiN9Qsj z3|U%sW8IhULZ^w3BA!WW{bW@r>Dzkq7Tj?GW-h9*KewmqornqkGJC~5CszM$VON~4 z+SWxdjn`Btd@F61yZ6Yqj0C(|XZObgg_cB>z5}XmU)sjNKy&-mb4%kRM57}q%Ou<} z`1B?`1g#k1sK++%Xb?Y5Qr025PBb0=YkK895gA2Ua(q-}R{iH1qZVW`e`(QI*5Mx# zE_B<23UnGa49~rAh~i3sl&hmu=M9L!z<=2u%=&oRN+3&>gQU2w%DSrjSqJgzr zda>{VZ7R3nT>+Zj&7pZZp!u_BuvzZqrChNcTJ!`{^ffisPG#oitwOW=Mkv|a-pDRQ zMjbw^!X&1(>^zj*8N8dpFVs9xR!TpH+H> zlO8d<_e1FCaQaz=Ez+m$DgWY8NzZyMd_j7SHcaL3roCzd>(USQ_=^mk!lm}MHzKFM zxBx5EJ_QhRU#gkuzjs1Er0Pb}MWI4Vty$BSwxYra!py1>G4DW}>r<8=J#|jfPo1Xf zB$ywVWxn!1PWb!uUZxKp;(=WzG8%&H`&|-Z-BgnJ0;GTS*melnwU@|q?#>6uGiS23 zop|lny%zqELZL4Akna`FDzyCJC-$SauKsCRVNvQ;Abjx++UxKAW?!oSy%08Ww% zwPCUgw7b`pBWSrmvXWoEfg4Qs&Ohe94O z6qiu?YBy{F_q3DV}4Qaoc{^ee3oARppq1 zbZt8w4{{r2^hMpR#X1#;8#2L~=A#IHCvULC+YOqgebzX(+%f^fy$egItu(0%!;d#0 z_Sx@!lCy=A8#Qt{`cELq>tI?cNNekt(U%pb8^%$df0U?@G>7x?msu-pA&oZa?aVe~ z{T6@z2=b$Tnxe(QlID*m&Ho9_m`0y2#sb7JeCN;FA!`G#zCei#tF(DZA~waT6!cB} zgbzSmwdg_B+)$whtd~6ro6s&oIhM@TmQzd$CN5ivD=FU6y_Nj&)%rvCk@8$(l`bD( ziCYE#RrLWfzcC>JdNt6ez216H0+VXI%Kr>7??5_jwwHB`|0N=DdadPVZpyZF1}5m|ya`Zufh)1fRWHNp&41g;RbFq79yOZ_qdwvolK? z2p6AMWvgyAakthas(2UcsR;0CW^0Yt>mG>U3JrP@YB%2sNGeNh^2so__0pDs7b^q#L-eKE$%6WV=)AMW#k znt`|HZuG4`wL1TP{h;2vi8fDYV5D4)l#LB3g)`@7U~b%=IIZ>kZui>iYiu>2spW!k zgujw{ca*b)Tq9hG-#n+^{C;Q#xo_nM$J1noapk)$eT|;Dc$;F~iyT!(4HGuUXG7Xe ze<#X14un8iilI59T|ZQd-2It8#1K0u)!BSlDRt1X+BVepx^cm3Iw6A_S%9fU>nX^* zx;AB-{n6?xtES75Q7;s$bX$X-pt`%D=b)1gfBZumAe&>d?=xOfJPD2fc ze<@0*@|Psn|0n4)l~Xe4!2no56ZP}enz?_F~+5O}YrozBMX7kkGiy}HM9){9KFf78yGh#Yd@ z*M-lo$2uxAvgob>t$DGm43Frc2MSx(6RZWVI7b;O)SXMLu zZB{!ex|X1t)wA2}Mo!veQsRE5X_9-(V!`VHjtMf^&vQ0N}@r8lB4P$cSr{$ZSeL@97#lZ^i@GVi;%q@~?k^fZ2n|8MlzJ zAH76mO;B(kAuS*oVY_A{vsv!efmzTWuwbq)#fnO~U@oAT4?1hPU1*tLocG1$7k{o= zu^92BC31nY0E4tKv+E@E1}R9VXWeRVEK#1(cJ&lC1<|A#zwqAm>)h||Ie)2-g0{T5 z(#*RPWnVM1a=os49v-g5gEGz9P}9x(h&^hv_KaNb(wU)>DBGY)>(N~)Vbe9W&;V{U zQgKSwdrvLWA`8Q+zeDhE@{C+$}jyS8T=J4z34E>~`ifl=aWC7LHHr`m@LPM^r|6N_IM zjSN+Gqu&YiL({m8;b`YdJ1`@K+3zcJk}H_;l!jj_!l2?L1VmIofgd%*oP31akBFV= zl5n-*Q2Wy*n-wAjn{yg2{VQAJWr)pmZvS{w#__Tz2RbJj8Mf}|TG3+qUW#&=fN(8y zvyU9=^!#)iwqW z?UBcn_g=SjY}%xav|5BVOqho$7QrdUz_wMbyIxIgsAIryK&`feX3@ym2X0yAjaqUH zvwsK&Xp1KEWocK|nwYacSx_~r&@0lJ322b0Y0=>5hz1KQC3n8^sgiGRY}tX>n~I z$bGESt*&v)*lJQHd}U48^@K_o@~Q2G7>Xw59_ z^t8Jiir>tC;>Z)Hl4COa#ac#@Mb^ejL;UtIDU&;i7LPr!Se8fmU(!l+ zXJqmi)Tn5nCVvuXB@L}pdXAEwb!IE21w1))i{+c(h6LtNvlo~Vvpww$-5#4I%_8QN zYrMmVDS|Gl^JY(Zm){5-P2p{gY$aQSG+VtdGsSMHde3nqjExB1Ev5#UOb@v&wGKYx zKNSA#;#2Ny9Zd~}_ZJ(_us(nH;nNkC!!z&bE+L}rZi>D0mpX+L+?3;&jJ+A9P}i@Q zTy;G>5>!(7tH9;eccr8&=_g{&JpW_K0=;FjR=Mn_y2fV}CPn6T4U;9$X-{|!E|*rc zu7ut!o1o^F5;C>pXNr1Cz}(0PaX+HSWXy6W?)+Cp>jXr?N6&YSo~!ntnFv*yiO)4I z%|EtgoSGvmKp{SV*%AmlJ%?YL?RHJ1#=m4^!h?!2azls-x8;>VpWFO%$Y}LORnp-+ z^z56fzY||~xUM}M=$!d{$giX)bw{?XISUkglF8M*^}^Q)L$62PF68g zMaGm9D@y4HTAGD9`uJXMPIb&TPEv`<{zJbX%iOTH_Me{z1-+dIW=xPW2S^A zglWc+A2#|Fm$=!r+;3GWEFLV*EHLwJK|D+#_$ruD3e(^y*_dXG2^rZii)>IdSCYkF z@D1@>eUKTAf1l-D=wqZfcgF$gP#Im zSn4QDabLJAe({m5c+c|Gb%e3j?`cL7{Q0!!k_Qdh7}#LZu99qKEX*)wjg|mty(jVx zGWOx+lei7IU(mY2ig`k<3Zn<$(F85rp-ef9gGb1smnS<$dG4Ymo{n7JQ4Al-pS)`S>roG4DOvwGEr`8tx zdIJ{5@o^JiEse~KMylhdb?*x71>>51>ZUxwdnl{$DGjE@jwk-yeyB?)*cp7dl2vF2 zY(MB|w$jd$2+gWPe2nGzwSn909=JMOjIXHL<^?r=*av#a*g>@u$3@ls_xMMazU-9z zbC3UI(=%vwuqT}-hDGj8bzcu{6cJu_;cqN_Xf`?)gHLS4w2D;BG`#kGSb(28f7LU- zano_6h>%yYnwsQr=Ru2IXK%A_?-4y(N4+S;*-@)!s$a35cY#Mb)7+HEtG*O1jzm%W zg;2NVN@wi;r-G5g=;;p?vNji?1IZCy^hgFUk2#W%^y>=rxJq|H(#ABRxsr|1ZC|oF zgWq|zWkY6$OwlCC8Nmd~VnH%eeyh%)a<$uOrJoF6e%&GtE^IJ^0@GLRONlbz*mPEx z*vw6q(GseR=R)?0frT;bi~o&5exIJClbwm&iBceyP1UAyi&ieuOnkdjA5-jObUu1% z_N}^2CgBscyc~zRdZJm4rj%P>^|tjzcfd3IT>DU_nHsoqxmMFGLLx?VfRj>QJl)yn zcz0u}*Ed>kdNPiBx>RCt)%0=~Z)vo7?$Mh>g0&7sST-|9Hzw)Vwsju-XCD2bje(&G zuX-)B{EoSUH%2k){$5~ko9JD?P6NE6DX#X9Fv1JB0! z!G9{E*T-!V-Y+^XWV?pY1{=L{a;PTfDcPJ8+W9PJH2MOijCxI^oP2ved(SK8Sw<;hG?%fqdCRZ`}to@I@F!xYPkf+ zw)A2*JwOJpEw(r))Jmcji=~JyLZ>%s`Wh&$nKK0M0nvoM%?RJgbHfz;EQP?#uzKi; z(p^UMz5=jx8N0v*KG}dC)S`wz{3+gaf(I0r-xsu!{paF>vIKQ zD;G5JD{4$3p@M8_r|Z=cbGT2N^Y(ut@eKB3j?xp z^h0WYb2eeApiqKp5Jz|jd{41LEw0PJSnke}Zo)#@gL*{|@#6PQsF%_Xu?7jt+7+&! zhG;a+0$a_=fB+Xld&eCCj6A(~I-`-E8o$(S4E&Vzo&S%mFAqyPUEf#pR5K^DW~P%)9E>vcwh?Iy6h}h{&&Qxk;X^KcrF5?2^0tyN=$5C@ZO9fOE zEE57mQZ@m>-^b?LoPU0Qc6oL2zMuDfpXYw=XSoZ0CHZcHx#}~TnbJ|(m%DM`u+0B{ zeioPuBxupyuv@;N0)GKq+?%;8XL9|v&Imq#lJI@kX}$N-i`}b>YiLrysk4*C`kKEi zG+XX9l{lED`8ZrH_*FbBx=Z|JrReF(+<) ztjo!c!noV=$FsgAge79FK@*LNDXB6jYQPBxUP3e?9z=-BM?ak3a^V+~*P9=f~*LlM)H4(L=T0bp0Nsz!Mo#Vp_8`vj{PW>WG* zwdT9$(6(vH8k_eFsT}|_kVEhaxa@Nv&9n>@<)z6=)=RcLA1+Lll)ikq0u=VH1b#>* z)1x?HX77gA8N)SiwmiA{{FtMejY&DjP@d*$V{+=hKOgza=_?m&75b$hQk>{a7#P$6CZ}AN%C^u<#8~l ze`J39Os_Sn9L$z>`2+SxQJIara`Y%>`E{OOngFdaWCM=iLdeg~wV}Xu3ukt%m&%3N1=hjB;10p|x63>GPrucF=D9bMtMQ0}HqvZ;Y}U?Ms;0SdB^$~qeAMrL6r?U5@&HlB=AvD&oS_cO zI{MgENTwhfl7faXTcJzSUx49#0I zw-jGzh>cBe15LilO8Dl}4>xV|4;Lh;_fP}->f0CI9$|K@czDqpgziNOzSS#XlF$Mk zxPq(FkVCJh3=vwUsxqAPS%ge?MOm-_*_ZHwBt&fHMphHM1KbMBgGD_f>WA!%y9DPN zi93NDse9`!eH_Q194H65N#|$F8a0#6Vb1z{tVP|=H^MNw(MXK|v#N96_%6`Q7Oi}x zD*VT?1{loaPs$GU1%wa`d0ZeITWubA3f!`8``pT}!)}{wFmXV5)yACCSh{R58NK(~ z!gM3>XdI4TI2CZeq?5q3%C~V1i{V8gdy`@fjlp)^lg={EL<*L38~AmJO#;1o#iuPT z6fovfklyN?s}&neD!fX#L#53_=$#Kd-nJDs?GM9GBLO8piDZ(2M)EZF^gL@MsrIey z?K%og4fLi=L||hDD=a~$gwev()xdN$DhJc-E%*Gao+Jc1&*@(T`Yt)FHFsdB!LRK$ zytL0X{_9DOU9PXilhu2Mk#$9If`aWxBKU;WQPtDKH`|7Kwrxz__uTaPmE#W5SB9<^ zrqBEMF;1I498u4f$2vYL3gcSukyJsWkW?vY^w5s9A$&T^keZ#}!j!2?8a=xy%B2Rz z&}>h?npO;!ls8l>GLmC%qV=g!FmYM-&i$@}-j}x6;{y%|k4PeIVbnq#Z+%3`xptL# zr>%f{gq%%^(kBF5XBSJ$6V$$R3EROeR{7gDLXI*JlcoatRS@VcPwXsS4)}dFBd~mu zF!y1`)3g_Vu|V){Nnd2*X#)Ih^Gpr+wEL7a+2|u5v@zRg7Uu!jx^qMHW0`xW{cZ!d zu-w!7`wu?(!A7O)X0&UHl+^QeAS;}!Ci6oYm7FXhS<#m4*pa3tPkRQ-OLHbiSyaQf z?qb|<4)Oe91V|L@M)KiSa3aLWsy000fspe6(41$qZ-%+H5-E+m#bUsUdk;ffPDKqt zVSR&$MRn60Vzy;M-A-hcbII<)-+ie=)Y&LcE=n(JBP~!x73?)>lt;#g7c>bb+&oj= z(cGM){+Q4ohf6k>`7ZxqY2;7c?e1}dWBw{ToHAkO_(#`z~%Sm)1l~*9M_VS>Y`~6LJLX75Eeg7Ayyjn$H{Y^ zq8)AyP=Fhdy#Kk(?o zajjts(~Yeg-^C3jWkx-9L#ykM?k5Si`duO@mrjeQRZBt;wX;Oh7UL@xk*f^#FkLMR z82_wk4LQB&h}Lal^#bfiXRTCY8>>7jKgai~1+mJvDEZO+4=Kv)9nZ4$*jPW;U1@cv+9P><%Gc7bu z0)x(h=b#klR}TQMj!~H&tQo=N7Edd0RUXqOW>%y^-$^*`2~t~#HF(!EXTU1X-`SJ3 zwzChO*WZ3d_%Dkez&B&RFB`a<5$eSus~(^!^}{PW{L+cp{gv|P+>3OLGB#!At(=;@ z(v0Uu92oM{pG^9NjDP@I3(bmCC z6CIauM+~VI#tPV^;&c4+pOQ$7Dl$^TN695X*c#;{OAL!*2jl`ng6xbF3!|n0lms#$ za$0B7;BYo^ub%LZDQu%{%)Qgu*D$Mkc>AnK?(9a zdl)NCZoNGE%qgz&dw;yU0$l0Y`&+EQ5 zxRf(CbZyws42hld42$%_n;-h=Eq`ri8C84!^VhZWpE>hMd)>H7r+(xhy|%lYR^B#W z9}xF@(B#|E=Gq~6u&f%SOf(fwy+40aR02`cPJ;0&HB-fj0){P{OjJc0v*R0;R!i*n zNcz?6CUDo-nLeg4ZL=6oG#BF)r}!n#Xg8KVRU^(@+P^Q5s247gxc5E0GqP2W7~R9y zAGlJ4_lDOJTkN&!UG^RD${Y5YRF?|;&zH^?V|a`C3f#f9`O?OCO;D~g1E3^VEpZ*# z%%3Se00bQO!(yb_+h<%qGi%v0V{+lE#yvm(-_A_TwwX^=wR=n#2lsf@&efDVGK-xQ zFDg&~oe{P=dD){7OZMIG$9ov&Y#}1*bzXW3M7DjW+0_`xbzd z_Qr625(Qi*Qw9ORheK2ofJxi>$0$2)xwIVRENvwY&d2QsYsZIm#Se$qW^t2zfsB2l zZT9;=*l?g4;n8MOCCZeRATG{eC~&LOYk5Sxeio?UvqUT=%}BrVC+atw&d**E)b5KQ zCEN%zZB6-thFd$UBj11af7lfWpu4tS3or7jaS|;}v<`WzOU?we%3fAjrF51LkjGO> zb4KO{@;3BGs)itT6X;)_2nERQq!+};Q^OvYM?aoW>rZo2rMnSjytAT{DOlkS5qW-x zgMreeZOhMyW)*So`8v{NDq8sw6(fcB?W3-oir^X_5dcj^k-)`6ofT-%f;QT!QI9rx zk|5@QSGvI~tUSA%VqAs5ohQ7u_L4?(hy+oOEy1H(w?HG+4O~l*f2?KSkAl3JU%yQ z{RbQAf8oA41#NfKb;xKeAYVKOOGH1Sc*R1br)y$7MryJKoalzjn#mDQQ46UGswNNm z^(NphOTLsw>c*X+6}1oXoc{fF_K9d#B35aIPKA0u-zLYCH?d+)gUe;%)k|W>i$dAJ zMSPPHomJ1zsvgeLk(DFWd_~iURwgG`5f@8`vxO1@3@w#F7(&Qd&+RYqn^u+qJ(6W9 zcvZ(Wbos4x1>ksb)6(E+>Ec4QpXKi*w#N-_r-FQv_jk;Z$=E}E$xZ5O{zB9p(2&XskhnzseO&{N{xsgQ_RrTe#sYHy{lgW9j&(PN)AuvS=|H4Cx1f5opbDEF z*kCfTBE6vi!I?C12wb{{`?O)PX9H*b9`k*l0k8GzXW^+LlbMGL`?zKw90hO7xY|cG zc1+)}gLRP}Kbe}+F-s2>Q>|lrgXJY@0qMN*f$Mc)!0D-5(pmscuXR74>i8%OuAk^V zO_fB`yv?75EnwktdtBfU0UOMr*EBZ3IL9srGeZ>6rBnH01x!q6Ib-k`mNvx>|B{C& z9)VOqq&7vT{Z1|cjUw49ppZA!0EpsQ%>cc+?-O$7dvoRyVB=DWA6F{@q>8@C1?rPB zHogRivw(A!=4bv5tyfJ(uU~IY*$bc)%G=Og1?zG@Z~ryg?8BX%KXn1CVTZ@f<3oP^ zw2d(owQVoBmwSvPn7>)c&T$>fswlZ3qI#z22s7WxO zs$1@z7gfu%g(P2~h=O1QM%6790YS}kYfmux(_MamNRP?tv0U44naUqkJI$7FNQ-Fe zd9 zG`r21FDC#3z|;I?t;rh2YW@OqyOX0uS%?3A2;x=7%nJK$Mds9`tk^C=!dV z3d3GHT|yZ<$Y&(IlO;@KY@7kjJJh|-CLZKM^4yw2NE=W5&WY zx3Mbs>ey@ou#M=APd;y82tJt+3O1Nc{?~I23qxK50rkI~d0S?NO;Q5#xBrE#Ow2=X z<@!!`{6{m2m7G8cIuYTz>~Q%pu>?QVLXh+x4iB~L&a`x0Oe_i`${-lmeo6+W1Z~)F z#@(|YqrK|nH`m732Rr-GkA9mcg!DFm=jEOwltkkAUAR-som zMo~L!lRX5jdD(eO9{ijkDE)E|FAS+ac^1tnb?crRe;CEk4Xwfq92kMGrnC_%fR213 zpgf-QHXg49Ml7j-X{`rWX-67L<&bw@I$?AAC}^eKFRQy>-8?Vi#CW&j)~z$^So7uE zkbnLSkZ)`?pUQ5(xO3}>^zg$j{Wr%%^uGVTTq+srVm;zU)WFDdlln8O3~6($vEm@u z*6epT_tlDl1!`5SEuZJvH!-W;V zrovQ+p|Rjva&@Y33KG;?9Rp|97aI1scBWU54=dG8{H3N|+bB9PXyE*sxbu0RH7bEl zv~=%9jCh>7I2TBGz5c zu9}4lg2PnYZm)gT?g34#5#0f31d`Upw9Qi=xc&G{rt3Ln3P=y19(Lu$?&WXYkI>LaMH?L zj}5LHOhng8sK-A%z3l-PB>H!CM&cjW$)7ayM~o4Z3z?+3S}OMeJE6!2eylL{*wA4_ zLDMO$VQ&<&`-Gr*|30i?kUip+R|V;NT+T}oZzt`Af0KSSxf#f14!)#KmXpF@DEyRL zsFsqy^L7KJ(~jWNfKdf?2oX3Vnle_4!9iq|VP>5w0xaf3JYz5dVOn0!k^^Q5hYQIw zF;?e-#X`V5g4e&iDJiji=56vKD}k22YbNVtjNtvc1F-ex|2ElRVmdojlXuKyd2L<> z13ufY`inc5+jB^TR-VE9bp391Q2b~(R2@VY5spnHm$ZgSQe$PraNh#W)M?+_ipkUy z&UW2*e{BH<6VbyYgob9_GVR+rc~(DpNwQ5}6$+oTJpx*caBn5L$tP;t=zH6KO`I$J z&3dvWo>$f4qm4=^RRxvkqHA-$Iqs$hoyCwo#M5iTj2ib~0O>nL8%A4#(PCuDx}Qu| zv;23Oy~VF@%v-}0rUAJ}7#1fcTEJ3^%eK$9AMgrC~4#cUV6Z`8>v zYjq8u^`4{A&IZI`|P@<43Jpy z&L}7dl^I(tdq6oK$>l^&h-!84Gt6j_cid6C<_H0FX2`g1kR7VshH!thWgri$Vc-RuP67P zEuW7d>AdS%$UgfhU5IMhEuD+(=^1cF`?SqB2%?Yp#(9&PyN7)d&ZKxbA56m7KLJvF z8odeQ+OUsi`R zxJ+(*zUztm0+v4`iVsx{k5^`a`Na&C_2j6th?;>Pi z`utkn-@#_^u9=>_kVNqaF-w2P90CG%Lf#I`SGVS^*q7>W*G=ErPwJBnCKhVt7{u4OMcf%KrWo~o?%3Ig^QZtsrBkPj7~DB>kcatI#p_J z2`#t@rX40}9ffJX-z+nl;Fu)iR|e) z?b}Jl16O_yWex-<;YK}!r7^frA2cDAvNsmP3x^>eMTZw}YY zVbfW8*|(Bi3%T%~Q+?A*P!}>jUVzv%0c~mYI8DkTHjp5v>{!l>61Qw7pxv3HPQawA zP)rSK70`ji7?_e&={7T6iJ1`mkN34^Q_E43*F#inc3*kM0K$<&;AY?O-}}7KB#-acV1um4WBTp*m7|2I9SO_>5Z~T&FpOAQL5Vf`i|32dhx3y8U5w%Y7j;uwL5NG7;V?{? z29)!*oY}19E=TivN8IGQOFc%2RD+FkqTPVS8TGRw zlo(AP@anOQ5)*JQ)iUw-FXZAM{b~3H(1<`81$r!o{PU>x!E0 zkB8jm;8dqTY$?VfUsahrD@Wr8y)u{4P2whr;$|N5ZIJVA@6!DQ|(U z;cxK57$N|@4ggvBGj}~RKJa%{dTx9nH=_7;B=m|PpINP@x|Qr+XBOn2Z}Wc$?*rNB zZ@x19Cpx88{);AmilnP1IL9Kj5rX;#YLwO{F42y(*Hr?dhKr~SR5G?2iXe23i06*! z&&kQD=ORVa6fJBd5ypHg%{mDV5X45vL2&tClPr2rvK@O6vNY8cn?R4?CLD3lqX<)+ z^C0ddS3AnhDW+KTNg5EUk_ABfU`Dd0Z&qOhbf2YpUNvFwVs+E!+cKQdU-Ou82bnHh zU<*$};TAmSv)jPV#;4S0)fFD*W#-G~{+|zIeba%tyHa@K5ptV7t_p0-+rJlY^1m}W zYhIJ1NUmpIxN>Sp(SfZSwthJhT+&3%OD<>v6XC>Tq9#7Il@jVpReQ$~Al>H@@Ri5( z?UZOPRoY+X0}B#+N8jZ3%kIO)6523nxa~{9h{YT^q?uDesZ&&XmP76qqW9J=*TRM% zw!ClYU}Di7RRrbDd=aW<$i>m)twvevhgLl(>3kc!CNn9QUQz)%kl#OdMmPh}G2rZM zeGQ=|LB9WZ`Q3&2LK7yS1^R8@U(q8_^RVNymsz@(SR?ela!xjCDJyc(EnIf%PYmD8 zgZOF_mqAg|yX0w?#Fo(0Ih6Rj$sVmRUHs090pjbPFzw}rW+8jBDRID?iP$mPU;n_9ObzG2Utf`o> z8GxGiAuPJucU$Z>Ftmk8B#@f*(sK<98D>+e1)y@-(N6>S)A%9O$vVSgj=KT*xLV;Z zDPMTw_b2i4L89)eW0a)p=l$kR0NQw7^pUDJG2eX3Kjepo#A`P@LOfhKsB;GrhNQ^G zkQ{0W$BJRg>kRFHN^={)Z%aI6@^S>h#wz74=MM1ihHP;ht~y#TY^J8LaDfUNzL%mZ z23a^5X&5C9gLQ)!nP(fJju;-O**Q|U1NGvb3xWP8aiMm*)UEqqf{r5ObF+@r5_fae zDj)V_da!=H#%EM$l}s{HjYWRiA~t3^AECWB_r*9FjjSk z8?8(k1lzohxb@;C0I@$d|Lp(3hv~*Na|u>Yt(=czx_FHA=C|u_wu+HZ61O5p4O9}@ zfd+)_gO2o6UXAwUyMfv5+`4Srl=sOk59veI3It#TrGu!8P`eW^imCMUyYa$e=JDW! z)#7rAp#LHcPA#t2(Dp*^qRWq1e%9DB{IJWkTNvvR$!LYdYU&}qQF!tRhmLARN6J8J zR3y5i2BTV2Pc2w0(uS>xG_UxjrQ4aki?cDdW88oU_R(tB`|teSmYe55#!VZi{ss6Z z?7b%+il{zN7z4XzYM!1Qt<6{mT`dN)fvi>keQ6~%d-_tgIFdooBRXHM6c$ zB7rDBsr@|MLd`0RVk8bz-?$Uziu4{#CAuqb3!6wkdKiyjyK}=0JF(X})yXo#<6_@g zz+yziL3{~{YyMQ52CBSCRqAZGObTGI9k^v)cvbAd5`-&^KRkFpXNRL7v&qA;?;gbJpfwo?Qbz~3h{i4Iz$1`ghaG?AV{QchuuITd zxIep|3HKZt(M_H^hi~r5#5FCo#U2(l_qA2G;blwgXTEVGy-59pkSy!pi@k*?<^*~2 zX@lVibsK-gg@EAf>Nu_gUriZ{K*f0Vq!vx*M9?Vp@+eqG7}!_ZE1d2o^$2M&q7HO- z9wwIFOBSDobyUYmJ>za=Umi#pXCVK{H+=n^y{2<102Gk6L;xwAyXawFiRP zKu7FX2Vv8!>Y2j}kl+px-x*yV)+}rT&NCPvpq($$F{p<4;hvWWPbY4_{Pp8jUNNnF zfQZ<6hz<~wNEs5K=w4cmfXJY%0|Ly03S;|R@W7C(g7`Jf_Kst|B=-0yCAa~DZk61-g z5tz*DHG&2L<4%oA=Lh{NfQqA#2*I`zqdKv#DTgqQBsk*H zlELQgYDp(Yl|=+CAsYyjM~IWHL+i{$sX5)kXrmQSK~Nq5&$j~0w#7EEyDa@ys=&)X zgEJ?9iBzOjIc`C{P%Sq$Xt^0Wm0iAVj=O%_>eiTdK5dRz^aPR6LDR5Z>=^xr+b-l;e&~M@WHS~MO&h*``LmwitnbwWVAuHnzWfFO3K}#z?q=>`5 zf-eqX?7;dqdz4h8ffVJ)0(vLbMVtVnCKOYY#$dR<3amSUM~xR7JxZp#u7e`&NTX*( zAk<|iY5ib1g`5^ZvB&g64{C5IZnk61P@)(@fQSKKUp@P6xIAkChBNFX04aDJ@E;wW z`8nW!O#^y|4Qr{}Rk@F5N>LLEOteC_qQrrwD{&^et+^{MCObF%PK6o1@vn{LUDlXB z2c@G>j&?nzp97dG!Dw<#`!UZspO?!YmoNFExXYcNqVwFbWrH$mHJZ$M={jCRmX)EZ zrWH!KllCAU3Q&J>WJ;mXR^9fn@D`EfNq`f{c}lB-QE%#1oae&=O^|_N^Q-c{Ia`2M`*MhKi6Z$Y$|KpogmsDT|zNN(j-$XX7A* z`yNh5xtg)bEU0v}+DAlKZbdD4b{5-MV_kSdB7TFA1mWUz<-Cf+rPZ(@8J@$<2_x4c@2-XNB zGbKugimiTgm@h5s@@d|&~gg2ph3`{7<3PeK%29v2nkRahl|lzp^~ zu;AEnOSY}SnwiAxwZmkq<^lGDiu-}N&L03*&jpzZcd_zW!wn!&7h>qfJi~Rd?<0qy z0TmvmIp#Bib|y}CA1MRF)|b}0O7|7Cm&Z`^ocrYlV_dc@PHY2kG*(XT9*pC>@X0W3 z755%fNU3H*0rHxWvd{{cmax-qqEmE5Ezvcy^Oj~b8nrpUiTWt+cQwbhU)G*9+|x2i zIj@;JQUp!i+`T*zWGA1K7PCBu8(2UAFpM84P94*O6q&NegTU!8MU*QYE7Tc7zS>95 zn7RF=%*y5TGij{gY2V{rhO1Z89SW(@(~` z@>#dzS&xk3*{sQ(5Nx$l9lmZ4{g#L_!3;al!zdG7bCSNT{R!*M3r8}?5*MzpsL8Oo zK}a+B5xFPH4pi9Z_XP~A$eexv~uz{0ERzDT%@Q(N%i$MJDz3< zSy|JOQe_*xe^tp|trDzz@9c>-Y&G$DNxQGA{-SPla)YUA)MQC7B8D1mo_yo7ywk*c z-AD8052)&nooGM*;#M4Ya>}3UjqoGM0AIEjH|(k9QqySb^*UOW=9*$|{jhKG(rEN< zH23ya@U2VDv9%{-hM-|$T9v{#QE)T^PVEazXa9B|Mf`Fd*yhO0$We=Kwm}x9V*TlJ za_;v9C(IB(%GIHmOY&c$5Nd@u&?g+GNbzxjJM2y=l z6N{)T-Y{*Ak7mq!Hr0C==Dg)gdSGH}Euyu|e?(fDT$ zTZkA4^r+n|n|-}+hvMPu)CaQo`mOcx| z0z_neS%O~xn|7;er2dbRu#@5)TiTBUfF1J9! zVKSB82McEnMM$ret6~TILjBbyIsnPNY)9x_?(22+JnJbx zukcI|!T==FiLjIIBq4fyUVoC2jjmmCNN&+`qXn;q*X5>Ujb2lLEgm6n$aI_0dWw?#icvAAJ9S-M#K}56nSy&tCyp4^kRa{Vb{B~D zMD3OOxdxx!&D;cxXcT#Ml@{ohKD76|Az7+u^Qnf9ZI?zd>Uh0VsCWxUoVqz@lu9kDR<89w-8TUdH=+0FD_5sk zXmDaj{A4E>45e_-5qu828KTlfiP{O~NiDMd{Gb8aqO^^Ts$r0JkYSJbZIUPm_pBT~ z!1e6C8Z$d`1=Ht?)?JNNM09Y6N{pO|+P$NK^xg=pGD5VEE{PhPo1FsK^Sx2}6Y@-X zgeGO@#xa9UL$(z ziyPt82c&}obSXzPjPSUqkog)LH21-E9;e7dGDQ{|$rA(@kfpXQnZurn0Am%jHYou~ zPd>N`{PGmDA8z*JY9c`;KZz|jX*jNkK&j=@&uV53m(h6Em3C1kg4|C9q9IwK-`ebd8NZ5CpRu=48 zSQZJ%w~C`DySAmFSrI*bVF6V57;60XeWr4y9(C(Z!_=?EfUpzIm)1 z$Yf0)ql(juM*E*;2e?4uvahGq9cC*2BPA#HoTwwmk<-y-kWF*6_m5YlV^$9c4cM}- z>*4VWqxD_dsa#9#xV!weW8dwteqph?l};j-#4}6>6#OM=24;wX#Ns!BpyKo zV>^2GbEj$RMTrxQqqgYXv-*{{qX}?6=i&`H0S!t$wb1yJM>Nm}HyS*AT$pB2@Kbir zoHrb@a9>;1;4-pSe;79ZAEtt|!P|PZd;q8$7S)3` zZ4N)Ma0e>RD}%ZF7VzHkL?vWi;Nd)LxO+^ZB3gB9$O4;O5Y(XzklrmJ<-rqW^khgM zEpQ;gY5K8Fr?$1`EseTzFEZ_;@?Uux9(6(NK0RY6dXG+$VYBAt-s&*A&=H-}8|%vt zhjZ(wfd})F(a2r|=98I)lnQ}LW1kzdXL??+Y&Z0CAXG;m$`mG?T3aVW8}0d5b(x7- zp8XSd17Y9A(S;o)@b0-u)^bfY#fvk73=%c74x<~T3i9+}!$XJjFM2(PxwjYYyg53R zyq~D63RPIOgg%?wChE7kb(%eSD?6;)Esd2pfZ}J!mcp2{g*ytnNTIQ!IcMBrDU(D2d-^EaoKL$#|3c(@D`b!J_=aA>CSXb9ntf zKQ41i`>(m!3GAjL`Z_ntP#LF2y79 z$-1k2tJ{dX^Ytt(d1%U`gaEtDC=QFo4DbQkbZQ?MQW!$3v~ufKPehR&RvE{{vReJ& z)>!KfXLSpV7`0)Y>imz!?}|X43?K9(%9T`!t~a zKx%A_tqN+t_MvI&!`tfJ{iJ3$_E(y1eIwA!6 z^+MpGzf_%ZQ`|W+7cI4kv~D2xb04WW+24Q%{4`f5qG(8hc=mYnQV2&s1sg5l&XXfH9?Si9Oj^-eTJ)B+6CXBEyBcMN2|v%+zc>HJ!omQ`O3WUgQTsyV8} z0?EO_ryVS$*@DIlVsSYrPkk*%UMi&pHmv8CGH}Ekkzm#Sgiw0xS<34|<3KHG(XKh( zSLm>IK|g0uqpd!kykg6bE%z+?ygQ~IyIL2VJ#tZAIa%Jtc)&Sd14IiggU9p(HLteC zbr=v9OYCdA`849$a)c|Ns;^q|I_q0NGKR~ctSE&Ap{2stPv5$%?7sWTOTJxD=iBd7 z!v|;<`4m?_mf?f2)W@S8W9V13Z52DX_w~ox6d({7&dZ6w=jY(Oj;c84`-K6y<-7v# zIKYaQFS0}<9}`W-fO-9y$+X{!Nr>Xo0E;lUcT2B+++76kJt5lHmwz8x(3Dm&)#cfH z4(UuflBX$h)SSYX50Hq}qxTrX1{64RK_q=RC2sJ{*ii~8@y@#&0YHA^a<*j2D01bT zV?$9rZ7bRNj+lw1tR@)eV$7qVNY%9NjbHOWZwdn-S=ENGC2ty(#>=@!JA96A^Uxyu z)=s$(wrlP~%i>y+$i^%MR6FlG7JavGHgn)^&~(k@2-gGT$tw@@wMu$C;wNfG;jZt9 z>p<_FYpCoAO3zOoXJ5tqu7P#Vf{Y) zde7mT5Sx7(s3l3;6qT=NC91%Usm!k|rK!$R5Goy;C*0)M!At?y4CXkzja z^x2g8GZyi*j2_`sRz1<}q`Ih)Q3si@!FtFNNY9an$v_d%Hpu#yafLpeUWe%w6(d!R9Y>H@=RE1jGYQ^*w6vvWL zrwFX;`eHcez9v7My%EAXNpARVN74yUba@x+q+6(1J|z~N)6Pvn z+)t&vY~I=cmp{@%I?;O|xPlf(F4|KJZ)F6`PmYpYfnr)Z=YpZ`MID!WsnznUoY2GE zmzWLp9lm}$qC`k1@1#ae=vQc}wJTMdfedn2W7857Hs8Pkd8ccifA+=4Rrp`9GNn(z zI)4>Bu5z=mUiV-7ICx4)y>)$)?#gD?^b?iqp;8`o&k+thNPmnt?5?^!dII+bK33Do zk&fTpaYUo4g-v@wJ>)2-o}L6^csUp4mX=S@A9^d-KstJ#jc%{ zdTRR1>haugg;(fd%?Pq2`Zh44UlzCgdkxaBC3LQii;EsPijvE{AqU_T6Ghj|Z#UqYuV*F@ORr3R~s*PO^>nuuD6#FvS7p9WJ{=sCG0yKu(Rnbq44d zA_<$}yMC-Ie^my2G}=V;fsY?;VDFRlm89<`&XCJ2+&}loh-S0NhSRi*iR`zTK^Ah{ zB3meJ&{dL?`(>bq0@bllPwg04X;sI3*=m4W>Vqh1AUETqgc1=x1QIhN8a&E2JsV?l$-jA;6kfkZJ3Gbl4#tA`1qGB}h z8MCpn+uR?+k32jGO?f_c#>*F;=_GEKh-{V;T}8yebPM;GZ4Gxwt_j4^uqG;aGBuXu z03BRgKt?I_9YZy7I99>&QNtt9wZy!nd(atO&rw5Mc1`i!)g3@t?aZc>!zCYMp69PO zCTGU^ojU<;@!9^xaXEBHjjB~b=4`+EFOIsBRu2Crl1!~jfBHzxpnlpEqL^%FN2~j` zi&MV|#G_xFg)bvd`yI_7ER|Y$J=8o*zBHBrOTz^WH_pz7bNl)zgC44iw}!#&{@qcm z5+kvilY|bC_<`J4i!It}P8zdUn7<0M9|Birm@Yi|5kIt>n@=50j;goX;!a9AaJWPU z7z=Lp?@sPM{754jRqJT|GG+M_=^R^icOh&>O-Tr5ON5 zEvAn0-G?XVcjK%ZTT%QZT5`*oY+*}m>e}O~IHgbJJ`M-T6=k(kg11f;=kr9xVn~d@ z=N<|Dtvg3&&R7ztklgT{Q#tCpIRpl_U|KZT(nxU}ApjliyulxEs6p?jW{# zyM6ns!#Q&XN66bV=pIXUZKoAOO&jud#9BW|<~%xxhF55hwmGVZ-Bc*Vg}7J%oeRYR z0#vMtr5z2{9is7UxE6|H1zZO@Z#$A1Oa@7}&>>QJ9_&5KFAmKD=|EA!5~i$}T%ilP z@l5oc|L>*WU+@CZUUF~#H-CSZLkDkE?nBM@kQaZyo^rYQ{Qbh&dJGZL@(7p&u|NyO z@T%aBrGB!4hWv-K$zc=Q`WgLCUkk5<$LfJn>2}7gXzG!nrU&S!x`AO=&wU!oQ0lufS=@OA2;Ur0 zC?iN)WHy)M!?SA8n+|HnP|}0}9YZgrODn<`0(!1Q12gI#2V95*wm*OJUgrO{@9z(j zOds9U?i!MGTxWIvihtpVYx^Hp*`sUgaCCDGx!o7-0h?eL0TU^Hqf_oy9SBe+(n|cUEA}9x_{}}b-dF~WKRt7@-cJp~TV8R|3IZ;2p*IfTVf0!{NtBbV0%56I@m*qKiuT_#X z0irRirVgpt^U=38M#q?g7}WrMgj3S-DBN{y94K0#s_VJPa7N|$S%! zf|e#|KDx7ZDr)Xf$9}{&HHBo-5!r}}?G+Eswtuz;TmUV@O&{$yP=|SeC;Tt(_Z!!a zT%2}m=KRDh9Su3@_CtViM*|gGQAwlct%|{v4}p;O={LHc@$pKXP3LrQLgvj zZvts#QHHl2iOHXjmb8$FzN<|-B-6%S**KnX+otPll8d2wn5+%~bALiNmXL_y>bug8 z^j>@WLk_@FgjK;QA3yxAXMtu(HtJWq*th<)IOVqgy!y=QUG|j4aLpuSXY9d1FtnMx z(pfvtcQ;g#0#M0IbuJ*7wdh=5B|0zpHZJb5#$Lmz$P!TKP6Bz;A_1cGaor%QXC#&o zh&v-m2MzN#|MT2_%`9!~pZ_a?x%LV?&B))4ufJ{eYn??X1b^1i5f=v}osago9ZC7O z8(ZF4+EE<^i)B>dXXzwP04iaA9CCW-?kIBpr7f?gVEXAW?5f~wOn9bJMhz0wCt}gP ze0e4EOz@qXmzryUas`bH7?E8oAGm3277j!uhaPP={_pW^FhkzNTm0!(r_S2=#L!~v zzN-$Nk0x7oA9I^~xSmD*QeJktL^st1*L%8YC}EF0_gsr6%OC`#kRQhbL1KFA5nS|_ ze!`r{P~Sa=H_Y{2L<2SE1}J>$7b(ribJ=lW^Qh*7&v8T!n z*e)84i;J5VJeYVwT}%R)#q}o@QypQ>ewO;n<-qKq5O$5K#xu$#LWHc(v6C_&<+NJG zseFa&F}}1eb)JFNCtKq+ewH_N>N@Tm8tC#fbW&RJ^PGuopWHxy4z!^N{?)hPZ;H@u z%S-G^_9*iYI=53EU;=%Jpza8Y`D(PeEp5k0-m>g}1Uimk@^2)WOp|dfLF+#-6B5oXRUmv>xMM8prW9ysGxv|Gzf?jgEG_Y zgbWQLGf`f1NaUcW;lOjn&h#-(KlUL~$ zlE7VWy?58WZ~gA?!C$O8=hUhC_P4*`pRrKT@bOQ);v*UX!ff80Wj;;?RaLmeExF5Z1VU?{jk>M0JvK25kgIXU9|=qrWRp%wUWmR;}wQxz-ioJ*ISqjSAPr z0$CX$O}`j_@&Tj}t^it*{rYL-9;sQi%xl*me|Ox-2|9^pW$!q%YV(ZMW7NlU+}`YZ z0|7erT`WEjQ5Y8V%UG=S9`tW*q=^eCH^%GObIct(de~U|ykL(Ar=rtNruk}vIf$e@ zyxIL59Vh+p;escdSfb&&(+P~LFF!qy^a4@v7?!=Gkhy|c4L zK|#eY1`I#?czhz-aPcu26^&IG0*#Nn(~K+5s)OTnVpIa;P?P1Q)BUD}W=_q#Sw?vP z;13VQv7MOw@Y?#6qHsL4N^+fhhw3ALXuyhWgS9A)fxRxD-tQZY&%~m}eZ82C zB|CaUys8`PJqX4@^^xkYBUSRNKYf@YzM_Tl$I9*DheDEPJx za!M)SPtnF*hHNhR?Edvkc*S6hTcVPp;XxAFa&z<+pK0!W@R?t@X~oOt>grEk!`|5~ z_c-{mSqDby*u!9Zb4{O^)Mv99!A|F?MJ8wbJaz_ux<^J8VE0S&g>fC~x9w}@N3oW@ zQv1L1xt;KsSx#>8Z)`uP^yhh*Dnd-{fN8V&jAw27G{55{vdema7<4`H#z+-yD)z6< zll+mH{t_G9SlG21gl|@On(%a%UA-G|qhM;CCmf`YtwPTmCd2|7Ad_(WTF|i!b$|Rb zxqG9n-}qhL%PN1{6}{^DL%~fPg1c=EnV}cHbq{HV(O!5NBA!6RWI4KHH*%Qpj?w~x>o<@yZY49HQyUtX&v${ zAvT0>J!nRVWVr8P7&lB|uRER6XJs70IhFYpoz4J#b!DOMX^T3$PHMjlb6>5YhV}}> zt%#3$9vzPc0>?e=57_77*AII746k~AkhU?eik})-ADh$NGj&UtO4qCQ_GVY|d6RWE zp9nUH!DlxTwQBWv+?}-7#Fn&ZH-9p9 zzfrAL-H!$dZ?f5}Z#IS6%C}qr$W^>n-!Q*yrW_xa`Czx)TZ7()J7_1{%-aVTIVKhQ zFHJH7+H$=1s{{_Bylc}v6U)py)p41H`0%?a5iEHlP2dSx?>boSbCH*k7Bpa6$8>$@ zX#`uv31JY9KcuJBXY6(@FTBvcc_5wYSi#w{bHtrp{-XU^c(3=ws#d*LB=&9WwI~?A zHus9Dy-*}_qG05C=o){D%fy|($dBqnuyKxo1;%w?5B*=qJYV?AO zOd~8YiBhO2_eAL^FH~sl>t8=R1~L_sjB)pE2P(&Q)FAOU3Xsk6Wvc)o%2q{Q-8=_W z97P%$aFzvkEIxNTnjnj*ezSj#tb3xA(mLhW?~C_fFM+Yysl6IkVjDfib?KR$Ht@11 zGAikfo1s&x6e)_?x5=XHe4T4?nO9N!HLWp`FRK#z(*r=i@*XFSGAyrbQVHww;@|Ee zE1e0+opGO9MJKMbKBK0;To^0fJ!UsYCE-Dj0e0@TROMc>!hxn(gy*xhh)Ls zZ(xz8!;*OC;*57`;|N+)1H(EuI^IQJ9$?3la$lMq+8aA@#t2kz-KDZsU5%&)mM|(%)622T99MP zIv?}mZpfBl(+FLkep6?h$*LCK=3PCft;`ac-e|L$IyO<5o5J;-B2BGb9{(7$f1}Nc z8obO)QG0+10MIdcmK;XBLzX!3xVnA4vDCbr@lN{i!VVd`$)6eKD+-FP)|!EAVY! zo^J#bz944M)J61y9SSd5+&ySbLxRuRxDc~u-r#+H*|p2|&l?yaItj~b&Kmqgxg-p| z?`B$RiL6~LAF?h7NqhVolg;xlqJ{}d@$VS7mrJoHR|QdT8p#X@E$sD|!pixcsD^M4 zmRp5>N|Z8L-6J!uN}(Mus`YId2){x5;HP~t>mcxr#u?e}Ns+T|mHkou@K>b6k2JHi zaT(3N@F`{A&LG5-e#_=J>XowhGr@ zZ@*wfJEDrC+A_~0;fB3!KXyGakC3^h28g`z*!X;m0all3Y9r)|EL7fT zr%)^CT-F(pO(qmx0-1BEX?k|qtLU8eW!qUB-zRzS0ePdt!kc@%*th3zhDaY$czGzg z=#b&qM(3udS(E*^Ul~vJaAB$;dBO>79$fLc7+T7|TEOl{7b4TD2lXnAOk5{B9#&I9 zK6xA!$<9@pH#5LX^O)+IHAbt9-elJMZV?WvhyQ5Ip0}-V#zff&joPUH0{t@a*-vT* zS{mcQO`iM=#OQK1J>&E+CYLF#s<)rmwL2Y`kuK#{~o^#zuYjG2Q>P7o3Y$0c zeBKR07`?8}|2TKHlV}R5a}D6IvO+E8E0JG*`Q9h}GPs0r(9jf-VQ$m$w9p?~mw-gr zUeiu>Q3yoh2VGpEF2aT-j|3u_FORLAe51B&hZ!b zT3Hy`AO49Z+NYf3O}sVWTDQZ4*2Pu{`4042S;5R>ZXaXLDB$Zc;q=D(H$RodtWglg zh~JH$|L17QIoO4UG5Q7&VD6*}q{`Gb3KW8d}@c77Z#uH#8wPWN`R} zG70khgoo1HJ5nNAftia8fP?~_+!jNcO9-3OLg0PEBXSeBHJB}+J2;k4UHG-c&qJ-7 z7Y!UC-wJi|mwi)W(cYJTZwQZ&P=D$lxL7Ce38SQM-wrGut&O$;om}b^2q69&ELFNC zK%H-F4=rtfy6Ih1XH=1-JzY0Tm6r%7Y>UUxdg0`7)7@mz_r`PfezZ>*IdE?{Eauv& zuZ58VBsFC*p&kl@ymOI1Ar}vadxb&X*SQb=gCI|sh;37$-n5uD>B2a8uZ4!j;_zkh zq-Sm@rwG?k(xtSu7CVrQFvxrRNrpGq&ADeF(tg4qZ z6}aRVckI|=UwA7F@}3;DGF^<)CU8mrs}qi5bBQnQNfQQn|AwZ5d$?ORA>5^lJjr41 ziht4qUQj2w^4{W15Q=lpaKXou#K4E*hDONu=oOZ_(vuJMAJ zs%XnF<fDltE^fRBmARy%{O!h%wq)Blh!j*> zMqbq-4iev`I>a?pey1k8D!#O|^amF;P$;^}mK|S485y{fAu1DIG&ybo8PX5X+$Mgr z6qL439%4f4%#i)N>bY7d&!nXxYwkyEn|tR!7lurvq?W1{L+bx)K&nj#j@w;07H=*{ z*?lMMgWPQq;o>pth9dZ3P9HA)L)m#=F;>bzsymw$7SN3s*g+?)O9G6kV)&bKq3pePTCsmfDdD_M*I z?pE2JQl`4Vv3O8u9KkUBy9LEzpcs?6R`ENrs=+&|y@47YJ3IMh z4lYN<%n;9l#!9`8xg?h)X@rzG2xUy{KA}CcEG!@)myQ}N5CT=m(3ZJ|eHnfN%jI76j|`9yp`YVmkngO-=?qA-8I0na?ThX$81sOrY`eFBW!HfkU)N;3 zmgJ-bpyY233xxXx(Bc=j0?$e+rYa~s@~tEzEqtV;EP7t;-zU*jRe4alJw@{IyN}}_ zcRzpJyjha#;CDe)*B+C6{I#nEw8fb^xng{oMHhMh9!ak2gF)=F z)fGvqj{;7Q-tkahAotc55dCjYEEoh~V7ywYb_s+yizOylEP)`L*ex+(350*buO%id zF=2@b^TE}UJ1n`wk~=K91Mq?+5SBpr_nk`j8p=$M{GHt~pJ#Ak!_caZs0f^iffVJI zCZ%t|VxBr!he&dWSS`6aG4vx?`n#oh>i#=+&JnF(FC;0al5T%cY+Zw~Y*^>cFp^+C z`;wnhI(bfWNDu5YeebGJ7VeYBkLkZyI*HG+fr+a1-|%v8IJTrDb|0A@JK%qZq5_4$ zF2NLD+U_vC?@@cC#)C-|Ta_Ftp;Y<*H8C;eU4u(Hd!4dIN-B=+td?cjlD|5|5Ma-*kZXu2%Kbr;CHFF`ry`CIu=?JnlHy z%C<9jkJ|``Z!azPi-vF0DnR!;H#hX73*K0Xw2hLptbY?S_A|kso z*b(oa!J!)vXuMGu>Z;Xo0Po9sdDk_Y%^ z0-asms@Yo=)OY{9&Jg}{%PKBoS^tZn2>-Emqx>v$9z!qF1dUqCNaiYkCV(gs} za~xj&uGxCX2@ifoQq;Mvy9BlTHb1oxCjizh)~HgypX07ha^4A38zOxVrq9LjF*2S2 za3?lhFMywlnjk0&rh5ghoyZCE1PI1@T*E?5WRInm?Cr2%M4^%Agb8*Xt$RIr2E%L+iqso;fvvL-tXRq`NsOW{Pvb%7eNZ| zsX02J#zT$b`)(?f?cN@&Bs7Uf zg>QhW03S0mIDkkhf80ckfa{O^8rjAwhTG9|;3u84(eMb~TQujnxtawRu@mz0v!i#p zyO^i4!>SuB%64m0`;<7@zhMS^ zObszUZiYE+np~o{VX+QkiYR}Vf5$q`-QHu1Iw#M?%?3FByw92(yNeAhd4Tor2q3V# z3tfzB{>;G^V=)D0m^_uF-2@d5#=3GB9qU_^V;dC)bnaCRB=J3a#}B*c&NON`9UL-? zFlKPRPQw7IWshmp7NoZM&o+_VabpAvRSu@V3_D>&hl`wjXjS}#aakjd%|s^Hn$pU& z0+~d6@989FK#hA?WmA&xWJe$&C~X};&CX;Z@g762XZ(z5X>YS(lw~*aF`W`e)ceh9BaS|?Yu9(*5zoSik zbZs>h$i?+zd>$5(+ygp9^3m-EEyV`C^X{E4#v)S@GtIDBcI-&WNX&E-RTY&FR|^4~ zIw7gO%GU*zI>DIUJ#FP~%CKC--lJ17))|~|pSon9hM-mh3=uv10mf@1@L&CkrWfeq zY&^{IW|r`2yVO4OAI{fkxCaNA(!XA z4YLEiF=o%)Cttcd0D-L7aP&LN6F)F)?|D}T9<8eLF=dwE;m6#D9dW$Tqi!h96?5N7 z_CtYdb7;OU)zdyxw699JFWpZzu<4I#u5xZJ2@cAn=Bt?Z-Qs)H7L53N05NssZh)GD zl(N_lMl;9YYilu_00L=(PfdE-0}H$h4^FwiHdU z)0=g1*nIbB`RO0?6o)3h-a}y6=A~6Oxm3*(X8T{HDo(Z;PSyKzJvekiU0Y7w1i}pk z!%-z<$wQS^kH}!N$lUR5I35s)W)9hiM@E_XH9CEr=O0aUlbPNQ^4zXIt6LM_zOP@y z1V|B*^sq4V&GZL!A!C*v*=b&z0UPERjUefPWarqfez7r}w*DpJGjR{?4@TWYZ#9X= zaW*fap;$fizXDO-#VELw=1?Mpf>DKr-+D=nXv;V0JYI~4ADQ690$lebLWthA_?{Ed zjkk(PTg)-pp}MUngNRM#V)|1cQ%|Eh(*7k7)hTa<`Am zrroRBV$1J&HgjI2C<<)CD_e4~JrA;A(}jlQD=q{%FBuWxX2Zv#%Kk;Wp(rOgPf#~JK1NDv;*__?vAmrk-M7ZgsCuSBq!k(Z}PIcF40V|LN%z*g)`#FB`VtprofM3YT%EjDwr_9GI(bZ{Bymkf?ou}~jTcSJD z0MpB_P;7xj*xq&u&Q-FhI*-m?bz;)r)c3}3m@#cOl2<`A3obyWjnc&H+AH1fHda<2 zl-ISB4XB2P1r{J0xns?NnO7(k6lO2G>sy%^!Jf*hhF#5!{&O~NQ-CUr{#w!if{<0} zjPedEBHM}rH%f^#yvm`0n}^OWG@EEj2k|7=-MDmO0)5W4bJ;W$M2%?{9cPD&?@T@} zL=|w$nqukLS!27@*0f@N13#MAmgf5jXCO)!i9fv3GkQZ&U^>%0pTQr^;21Zyr^U8L z;Io)OhV`YVp{E>jQz*TMAwZ>~OnE7T71K9un4a0QKh&rsj%&%3G17v>5>*I0^lKil z+gPNg;8dc0PzBMH+h>TWEw7oy{Ol_OGQaOSkkuRv(<@)*U^DHADoob1ADKkb#Ku9esmN9pM zM-bhcO7w~8`XDA`1oe=Z-8jNP8!4&n2GiUfZH~hTGQ3bggzGo=qZP{5K~Hq`{5o-% z!{AR)jS0$Q?kYi|LD<`?d;DoE7fIk5lTc60Zg6_h4!NEnE63CF&8SQKb5+&lMqfke zv3T7X^Agmj0=xOpyqmu4#;(CyP8Dg!-Gduh(1GR(asy`mj(2{2;Q>{VmLf8%6sMz^ zH*!4tqT3k<=I31T{wv#K+-ky3k4<(mSIy7}cSx`l^S=Q!x{;R!z2( zC^hOLiPE7srldHQhnlVzBw$%a1RjY1vHOtu|8rKGPbbpU7-NYP3E`v-pWb9m!c|wJv^#)Hb7s z+%v+7bxFhlp}bMbLEcD5{ZeQwG1-VbcF8}}l literal 42258 zcmeHwcXS)qnePCknk8AbWI1tc$ zaZy%sx1>P_NP-~126l=C?7fp933h@MdnZ`H27)9i(F=+9-2o{UiB+IwXF1>qxO2a9 z%XbUrH$Uj|8}D7ku%y$M-?;jB7>4~+^0efX;HARUXs70d&&Be zbF&xN`2mKJjxM>(mJ1e(kHvDq^?q(yy*gQ#bU7%X_Lvv$L!-{wVE$jk-o_U8gOE!3&9W`<+>lSw%f`Ej^n!Urqn25e!}Al^k3m3hY>5)k zBE_LJ?K~2&m{$zwwJ2@1XK_*q14cbc+nsI$v%?l6cIr6hq&SY*?KT^JQ%i3mWm*vo`ktSh9Yd7#jcQ&UmOjk1qVvowQ5x z^!l_b`>}QTF4wm=q+i^S{>l3E(!~wwUqBiL>7CGO;lc%2E36iad7~gK2tiXC|wXWu)6$veRAcbB?23l%0AF_}~ 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 Ze8jT{SUj{dc036kWX~Uj-MhYd{C^CIlIj2e diff --git a/todo.txt b/todo.txt index 977f567f8..00802cdb0 100644 --- a/todo.txt +++ b/todo.txt @@ -39,17 +39,16 @@ _ appbundler fixes/changes X the "Classes" folder is included X appears to be line 138 of main.m o maybe this is a holdover from OS X Java? don't know. -_ icon location uses path, even when embedded +X icon location uses path, even when embedded X add indents to the Info.plist output file X inside writeInfoPlist from AppBundlerTask.java o use Contents/Resources/Java instead of Contents/Java? o this is in main.m. why the change? X doesn't make any difference, just use Contents/Java -_ any missing args from our app (copyrights/versions?) -_ make sure it's only running on 64-bit machines? -_ add MinimumSystemVersion? -_ bring back the splash screen? -_ don't re-copy jre into work folder if already exists +X any missing args from our app (copyrights/versions?) +X copy GenericDocumentIcon.icns for placeholder icon +X from /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ +_ don't re-copy jre into work folder if already exists _ change how export is handled _ remove ability to export cross-platform apps _ add ability to embed the current JRE @@ -57,6 +56,13 @@ _ change app stub in OS X exported application _ we become full 64-bit on OS X _ meaning that the macosx32 video library goes away _ and the preference for launching in 32- or 64-bit mode +_ try the bundle on Mac Mini running 10.6 +_ make sure it's only running on 64-bit machines? +_ add MinimumSystemVersion? +_ remove javafx from the embed +_ more about optional files: +_ http://www.oracle.com/technetwork/java/javase/jdk-7-readme-429198.html +_ bring back the splash screen no good installer, will need JDK anyway for the export require that this folder exists: From c2a571e6cfd32d9fe1872a060425e5946d798f56 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 21 Sep 2013 15:38:50 -0400 Subject: [PATCH 063/556] remove the mangler and the old howto --- build/shared/tools/Mangler/make.sh | 11 -- build/shared/tools/Mangler/src/Mangler.java | 94 ------------- build/shared/tools/howto.txt | 143 -------------------- todo.txt | 11 +- 4 files changed, 8 insertions(+), 251 deletions(-) delete mode 100755 build/shared/tools/Mangler/make.sh delete mode 100644 build/shared/tools/Mangler/src/Mangler.java delete mode 100644 build/shared/tools/howto.txt diff --git a/build/shared/tools/Mangler/make.sh b/build/shared/tools/Mangler/make.sh deleted file mode 100755 index 8b2b2b5dc..000000000 --- a/build/shared/tools/Mangler/make.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -# The pde.jar file may be buried inside the .app file on Mac OS X. -PDE=`find ../.. -name pde.jar` - -javac -target 1.6 \ - -cp "../../lib/core.jar:$PDE" \ - -d bin \ - src/Mangler.java - -cd bin && zip -r ../tool/mangler.jar * && cd .. diff --git a/build/shared/tools/Mangler/src/Mangler.java b/build/shared/tools/Mangler/src/Mangler.java deleted file mode 100644 index cfd527954..000000000 --- a/build/shared/tools/Mangler/src/Mangler.java +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2008 Ben Fry and Casey Reas - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package com.transformers.supermangletron; - - -import java.text.SimpleDateFormat; -import java.util.Date; - -import javax.swing.JOptionPane; - -import processing.app.Editor; -import processing.app.tools.Tool; - - -/** - * Example Tools menu entry. - */ -public class Mangler implements Tool { - Editor editor; - - - public void init(Editor editor) { - this.editor = editor; - } - - - public String getMenuTitle() { - return "Mangle Selection"; - } - - - public void run() { - String sketchName = editor.getSketch().getName(); - - Object[] options = { "Yes, please", "No, thanks" }; - int result = JOptionPane.showOptionDialog(editor, - "Is " + sketchName + - " ready for destruction?", - "Super Mangle Tron", - JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE, - null, - options, - options[1]); - if (result == JOptionPane.YES_OPTION) { - mangleSelection(); - } - } - - - protected void mangleSelection() { - if (editor.isSelectionActive()) { - String selection = editor.getSelectedText(); - char[] stuff = selection.toCharArray(); - // Randomly swap a bunch of characters in the text - for (int i = 0; i < stuff.length / 10; i++) { - int a = (int) (Math.random() * stuff.length); - int b = (int) (Math.random() * stuff.length); - if (stuff[a] == '\n' || stuff[b] == '\n') { - continue; // skip newline characters - } - stuff[a] = selection.charAt(b); - stuff[b] = selection.charAt(a); - } - editor.startCompoundEdit(); - editor.setSelectedText(new String(stuff)); - editor.stopCompoundEdit(); - editor.statusNotice("Now that feels better, doesn't it?"); - - } else { - editor.statusError("No selection, no dice."); - } - } -} diff --git a/build/shared/tools/howto.txt b/build/shared/tools/howto.txt deleted file mode 100644 index 77df31c91..000000000 --- a/build/shared/tools/howto.txt +++ /dev/null @@ -1,143 +0,0 @@ -TOOLS IN PROCESSING - -With initial help from code contributed by fjen, Processing release 0147 and -later have a dynamically loading tools menu, which can be used to expand the -environment in fun and fantastic ways. - -A Tool is a chunk of code that runs from the Tools menu. Tools are a means -of building onto the Processing Development Environment without needing to -rebuild the beast from source. - -The interface (at least for now) is extremely simple: - - -package processing.app.tools.Tool; - -public interface Tool extends Runnable { - - public void init(Editor editor); - - public void run(); - - public String getMenuTitle(); -} - - -The init() method is called when an Editor window first opens. This means -you won't have access to a sketch object, or a GUI, and should only do minimal -setup. (However it'd be a good idea to stash the "Editor" object for later.) - -The run() method will be called by the main application when the tool is -selected from the menu. This is called using invokeLater(), so that the tool -can safely use Swing and any other GUI yackety yack. If you're using a Frame, -you'll need to detect whether the Frame is already open (and bring it to the -front) or whether to create a new window. - -Faceless tools also use the run() method. You should avail yourselves of the -statusNotice() and statusError() methods in Editor, to let the user know what's -happened. (As per p. 107 of the Processing Development Environment Tools -Reference User Interface Guide.) - -The getMenuTitle() method just returns the title for what should appear in the -Tools menu. Not doing shortcuts for now, because resolving them between tools -(and the rest of the interface) is fugly. We would also need additional -modifiers for shift and alt. It just gets messy quick. Ordering in the Tools -menu is alphabetical. - - -////////////////////////////////////////////////////////////// - - -Where to put Tools - -Core tools live inside the "tools" subfolder of the Processing distribution, -however users should install "contributed" tools in their sketchbook folder, -inside a subfolder named "tools". - -If a tool works only with a particular release of Processing, then it may make -sense for the user to put things into the Processing tools folder, however we'd -like to keep users out of there as much as possible. In fact, it may not be -visible in future releases of Processing (for instance, on Mac OS X, the tools -folder is hidden inside the .app bundle). - -Tools should be laid out similar to libraries, though the structure is a little -more flexible. The tool folder should be the name of the main class (without -its package name but using the same capitalization), and have a subfolder named -"tool" that contains the .jar and .zip files it uses. I'll use the included -"Mangler" tool as an example. - -(This Tool is not built by default, due to a lack of non-dubious arguments -regarding the usefulness of including (by default) a Tool that mangles code.) - -The folder should be called Mangler (note the capitalization), and contain: - -sketchbook/Mangler -> tool folder -sketchbook/Mangler/tool -> location for code -sketchbook/Mangler/tool/mangle.jar -> jar with one or more classes - -The naming of jar and zip files in the tool/* directory doesn't matter. - -When Processing loads, the jar and zip files will be searched for -Mangler.class. Even though this tool is found in package poos.shoe, -it will be sussed out. Package names are required. - -Loose .class files are not supported, use only jar and zip files. - - -////////////////////////////////////////////////////////////// - - -What You Can and Cannot Do - -The only API methods that are officially scrubbed and sanctioned by the -Commissioner on Fair API and Proper Manners for use by the Tools classes -are found in: - -processing.app.Base -processing.app.Editor -processing.app.Preferences -processing.app.Sketch -processing.app.SketchCode - -In fact, most of the API you should be talking to is inside Editor. -Full API documentation can be found on dev.processing.org: -http://dev.processing.org/reference/everything/ -(Keep in mind that this is not always perfectly up to date, but we'll try.) - -Of course, you're welcome to go spelunking through the rest of the API -(that's where all the fun stuff is anyway), but don't be upset when something -changes and breaks your tool and makes your users sad. - -Currently, native code is not supported with tools. This might be possible, -but it's another potentially messy thing to dynamically add native library -paths to running code. (See "Future Releases" below.) - - -////////////////////////////////////////////////////////////// - - -Future Releases - -In future releases, we are considering the following features: - -1. How shortcut keys are handled. - http://dev.processing.org/bugs/show_bug.cgi?id=140 - -2. Whether to allow tools to dock into the Preferences panel. - http://dev.processing.org/bugs/show_bug.cgi?id=883 - -3. A means to run native code from the Tools menu. - http://dev.processing.org/bugs/show_bug.cgi?id=884 - -4. Methods for reorganizing the Tools menu, or placing contributed - Tools inside other menus (such as Edit or Sketch). - http://dev.processing.org/bugs/show_bug.cgi?id=885 - -This is the first round of documentation for the Tools menu, we reserve the -right to update, clarify, and change our mind in future releases. - - -////////////////////////////////////////////////////////////// - - -Ben Fry, last updated 19 August 2008 diff --git a/todo.txt b/todo.txt index 00802cdb0..2003bcb99 100644 --- a/todo.txt +++ b/todo.txt @@ -33,9 +33,10 @@ _ changing modes brings the PDE back on the second screen _ the Find window (also the save windows) also have the same problem 7u40 switch -_ remove Mangler from tools/Mangler -_ update tools/howto.txt to just point at the correct online location -_ appbundler fixes/changes +X remove Mangler from tools/Mangler +o update tools/howto.txt to just point at the correct online location +X just remove the howto file +X appbundler fixes/changes X the "Classes" folder is included X appears to be line 138 of main.m o maybe this is a holdover from OS X Java? don't know. @@ -63,6 +64,10 @@ _ remove javafx from the embed _ more about optional files: _ http://www.oracle.com/technetwork/java/javase/jdk-7-readme-429198.html _ bring back the splash screen +_ update github instructions +_ only JRE needed at this point +_ switched over to Java 7 +_ https://github.com/processing/processing/wiki/Build-Instructions no good installer, will need JDK anyway for the export require that this folder exists: From d02e038f027849f3ff0ca9e491ef3149d3713b79 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 21 Sep 2013 16:01:21 -0400 Subject: [PATCH 064/556] working on new build with windows --- build/build-7u40.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/build-7u40.xml b/build/build-7u40.xml index ff8e22b78..5a84b9898 100755 --- a/build/build-7u40.xml +++ b/build/build-7u40.xml @@ -1,10 +1,5 @@ - - - @@ -407,6 +402,11 @@ --> + + + Date: Sat, 21 Sep 2013 16:31:37 -0400 Subject: [PATCH 065/556] more build work, use Apple version of extensions --- build/build-7u40.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build/build-7u40.xml b/build/build-7u40.xml index 5a84b9898..cc350e0ae 100755 --- a/build/build-7u40.xml +++ b/build/build-7u40.xml @@ -811,8 +811,12 @@ - + + + + + + + @@ -682,8 +690,10 @@ + - + + + + + + Date: Sat, 21 Sep 2013 16:55:58 -0400 Subject: [PATCH 067/556] change ignore for new JRE --- build/windows/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 build/windows/.gitignore diff --git a/build/windows/.gitignore b/build/windows/.gitignore old mode 100644 new mode 100755 index 5d5afb57b..63b84630b --- a/build/windows/.gitignore +++ b/build/windows/.gitignore @@ -1 +1 @@ -jre.zip +jre.tgz From 837caa5725ecfdfd52df831e7af0a9060b42e372 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 22 Sep 2013 13:50:58 -0400 Subject: [PATCH 068/556] add notes to MovieMaker project --- build/shared/tools/MovieMaker/build.xml | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/build/shared/tools/MovieMaker/build.xml b/build/shared/tools/MovieMaker/build.xml index 5ee61436a..5fb5db323 100755 --- a/build/shared/tools/MovieMaker/build.xml +++ b/build/shared/tools/MovieMaker/build.xml @@ -1,22 +1,23 @@ - + + + - - - - + Date: Sun, 22 Sep 2013 13:51:09 -0400 Subject: [PATCH 069/556] trying to tweak the Linux build --- build/build-7u40.xml | 12 ++++++++---- todo.txt | 11 +++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/build/build-7u40.xml b/build/build-7u40.xml index 55981fae8..52cae7f6b 100755 --- a/build/build-7u40.xml +++ b/build/build-7u40.xml @@ -710,13 +710,17 @@ - - + + + + + - + 1.7 +SOFTWARE\JavaSoft\Java Runtime Environment\CurrentVersion\1.7 + no good installer, will need JDK anyway for the export require that this folder exists: /Library/Java/JavaVirtualMachines/jdk1.7.0_40.jdk @@ -890,6 +900,7 @@ _ once fixed, remove notes from JavaBuild.java _ "Are you sure you want to quit?" when switching modes on Oracle JVM _ default menu bar is still broken _ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8007267 +_ fixed for 7u60 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8022667 _ blank sketch opened even if another opened by double-click _ add a 150 ms or more lag before opening the untitled window (on os x) _ https://github.com/processing/processing/issues/218 From 58daa8ba9373f88881fef6aa870cf10c006a378d Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 22 Sep 2013 14:09:58 -0400 Subject: [PATCH 070/556] making the 7u40 build the default --- build/build-7u40.xml | 1059 ------------------------------------------ build/build.xml | 266 +++++++++-- 2 files changed, 217 insertions(+), 1108 deletions(-) delete mode 100755 build/build-7u40.xml diff --git a/build/build-7u40.xml b/build/build-7u40.xml deleted file mode 100755 index 52cae7f6b..000000000 --- a/build/build-7u40.xml +++ /dev/null @@ -1,1059 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ======================================================= - Processing for Mac OS X can only be built on Mac OS X. - - Bye. - ======================================================= - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code signing will only work if you have a $99/yr Apple developer ID. - - With a proper ID, if code signing fails, you may need to use: - export CODESIGN_ALLOCATE="/Applications/Xcode.app/Contents/Developer/usr/bin/codesign_allocate" - - - - - - - - - - - - - - - - - - - - - - - - - ======================================================= - Processing for Mac OS X was built. Grab it from - - macosx/processing-${version}-macosx.zip - ======================================================= - - - - - - - - - - - - - - - ======================================================= - Processing for Linux can only be built on on unix systems. - - Bye. - ======================================================= - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ======================================================= - Processing for Linux was built. Grab the archive from - - ${linux.dist} - ======================================================= - - - - - - - - - - - - - - - ======================================================= - Processing for Windows can only be built on windows. - - Bye. - ======================================================= - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ======================================================= - Processing for Windows was built. Grab the archive from - - ${windows.dist} - ======================================================= - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/build.xml b/build/build.xml index 1a463e4d2..52cae7f6b 100755 --- a/build/build.xml +++ b/build/build.xml @@ -1,6 +1,6 @@ - + @@ -19,6 +19,14 @@ + + + + + + + + @@ -36,18 +44,15 @@ - - + value="macosx/work/Processing.app/Contents/Java"> @@ -72,6 +76,7 @@ + @@ -132,7 +137,6 @@ - @@ -144,7 +148,6 @@ - @@ -152,21 +155,8 @@ - - - - - - - - + + @@ -396,6 +386,7 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - + + @@ -472,10 +597,13 @@ + + @@ -550,6 +678,11 @@ + + + + + @@ -557,13 +690,13 @@ + - - - + + + + + - + + + + + + + + + + + + + + + --> - + + + + Date: Sun, 22 Sep 2013 15:33:37 -0400 Subject: [PATCH 071/556] add minimum system version and javafx removal --- .../com/oracle/appbundler/AppBundlerTask.java | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index f5e238107..2507d9cfe 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -75,8 +75,11 @@ public class AppBundlerTask extends Task { private String workingDirectory = null; private String applicationCategory = null; - private boolean highResolutionCapable = true; + // Oracle Java 7 requires 10.7.3 or later, so require it here. + private String minimumSystem = "10.7.3"; + // By default, don't embed Java FX. + private boolean javafx = false; // JVM info properties private String mainClassName = null; @@ -167,9 +170,19 @@ public class AppBundlerTask extends Task { } + public void setMinimumSystem(String minimumSystem) { + this.minimumSystem = minimumSystem; + } + + public void setHighResolutionCapable(boolean highResolutionCapable) { this.highResolutionCapable = highResolutionCapable; } + + + public void setJavaFX(boolean javafx) { + this.javafx = javafx; + } public void setMainClassName(String mainClassName) { @@ -199,6 +212,29 @@ public class AppBundlerTask extends Task { "jre/lib/plugin.jar", "jre/lib/security/javaws.policy" }); + + if (!javafx) { + // http://www.oracle.com/technetwork/java/javase/jdk-7-readme-429198.html + runtime.appendExcludes(new String[] { + "jre/THIRDPARTYLICENSEREADME-JAVAFX.txt", + + "jre/lib/javafx.properties", + "jre/lib/jfxrt.jar", + "jre/lib/security/javafx.policy", + + "jre/lib/fxplugins.dylib", + "jre/lib/libdecora-sse.dylib", + "jre/lib/libglass.dylib", + "jre/lib/libglib-2.0.0.dylib", + "jre/lib/libgstplugins-lite.dylib", + "jre/lib/libgstreamer-lite.dylib", + "jre/lib/libjavafx-font.dylib", + "jre/lib/libjavafx-iio.dylib", + "jre/lib/libjfxmedia.dylib", + "jre/lib/libjfxwebkit.dylib", + "jre/lib/libprism-es2.dylib" + }); + } } @@ -552,6 +588,10 @@ public class AppBundlerTask extends Task { if (applicationCategory != null) { plist.writeProperty("LSApplicationCategoryType", applicationCategory); } + + if (minimumSystem != null) { + plist.writeProperty("LSMinimumSystemVersion", minimumSystem); + } if (highResolutionCapable) { plist.writeKey("NSHighResolutionCapable"); From 56f129d902705f6b3dd05477add1515fb88705b0 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 22 Sep 2013 15:33:49 -0400 Subject: [PATCH 072/556] working to remove javafx from the download --- build/build.xml | 65 +++++++++++++++++++++++++++++++ todo.txt | 100 +++++++++++++++--------------------------------- 2 files changed, 95 insertions(+), 70 deletions(-) diff --git a/build/build.xml b/build/build.xml index 52cae7f6b..06a3e0bb8 100755 --- a/build/build.xml +++ b/build/build.xml @@ -27,6 +27,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -721,6 +773,13 @@ + + + + + + + + + + + + + 1.7 -SOFTWARE\JavaSoft\Java Runtime Environment\CurrentVersion\1.7 - -no good installer, will need JDK anyway for the export -require that this folder exists: -/Library/Java/JavaVirtualMachines/jdk1.7.0_40.jdk -could also require that it's b40, but probably more trouble than it's worth -that would be 'java -version' for string 'build 1.7.0_40-b40' - -direct link for download (replace .md5 with .dmg on that page) -http://www.java.net/download/jdk7u40/archive/b38/binaries/jre-7u40-ea-bin-b38-macosx-x86_64-07_aug_2013.dmg -http://www.java.net/download/jdk7u40/archive/b40/binaries/jre-7u40-fcs-bin-b40-macosx-x86_64-16_aug_2013.dmg - -needs cookie for proper download -http://download.oracle.com/otn-pub/java/jdk/7u25-b15/jre-7u25-linux-i586.tar.gz - -http://ivan-site.com/2012/05/download-oracle-java-jre-jdk-using-a-script/ -wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F" http://download.oracle.com/otn-pub/java/jdk/7u25-b15/jre-7u25-linux-i586.tar.gz - -wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F" http://download.oracle.com/otn-pub/java/jdk/7u40-b43/jre-7u40-linux-i586.tar.gz - -http://download.oracle.com/otn-pub/java/jdk/7u40-b43/jre-7u40-linux-i586.tar.gz - -http://download.oracle.com/otn-pub/java/jdk/7u25-b15/jre-7u25-linux-i586.tar.gz -http://download.oracle.com/otn-pub/java/jdk/7u25-b15/jre-7u25-linux-x64.tar.gz -http://download.oracle.com/otn-pub/java/jdk/7u25-b17/jre-7u25-windows-i586.tar.gz -http://download.oracle.com/otn-pub/java/jdk/7u25-b17/jre-7u25-windows-x64.tar.gz - -or a direct download from http://www.java.com/en/download/manual.jsp - -for 7u25 -http://javadl.sun.com/webapps/download/AutoDL?BundleId=78695 Linux i386 -http://javadl.sun.com/webapps/download/AutoDL?BundleId=78697 Linux x64 -http://javadl.sun.com/webapps/download/AutoDL?BundleId=78698 OS X (64-bit) -http://javadl.sun.com/webapps/download/AutoDL?BundleId=79063 Windows (32?) -http://javadl.sun.com/webapps/download/AutoDL?BundleId=79065 Windows (64-bit) - -for 7u40 -http://javadl.sun.com/webapps/download/AutoDL?BundleId=80806 OS X (64-bit) -http://javadl.sun.com/webapps/download/AutoDL?BundleId=80803 Linux i386 -http://javadl.sun.com/webapps/download/AutoDL?BundleId=80805 Linux x64 -http://javadl.sun.com/webapps/download/AutoDL?BundleId=80812 Windows i586 -http://javadl.sun.com/webapps/download/AutoDL?BundleId=80814 Windows (64-bit) - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . From 0e5bfcd20f8ae8743236e44bf2d2f9b07eb44e84 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 22 Sep 2013 15:43:55 -0400 Subject: [PATCH 073/556] remove build failure when no JDK is installed --- build/build.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/build.xml b/build/build.xml index 06a3e0bb8..991e838b5 100755 --- a/build/build.xml +++ b/build/build.xml @@ -100,8 +100,10 @@ + @@ -110,8 +112,10 @@ + Date: Sun, 22 Sep 2013 16:16:32 -0400 Subject: [PATCH 074/556] continued efforts with build scripts, removing unused JRE files --- build/build.xml | 60 +++++++-- build/macosx/template.app/Contents/Info.plist | 120 ------------------ .../Contents/MacOS/JavaApplicationStub | Bin 35072 -> 0 bytes build/macosx/template.app/Contents/PkgInfo | 1 - .../template.app/Contents/Resources/pde.icns | Bin 42258 -> 0 bytes .../Contents/Resources/processing.icns | Bin 415779 -> 0 bytes todo.txt | 23 +++- 7 files changed, 63 insertions(+), 141 deletions(-) delete mode 100755 build/macosx/template.app/Contents/Info.plist delete mode 100755 build/macosx/template.app/Contents/MacOS/JavaApplicationStub delete mode 100755 build/macosx/template.app/Contents/PkgInfo delete mode 100644 build/macosx/template.app/Contents/Resources/pde.icns delete mode 100644 build/macosx/template.app/Contents/Resources/processing.icns diff --git a/build/build.xml b/build/build.xml index 06a3e0bb8..66f22a22b 100755 --- a/build/build.xml +++ b/build/build.xml @@ -27,9 +27,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -158,18 +202,6 @@ - - - - @@ -774,10 +806,11 @@ - + + @@ -975,6 +1008,7 @@ + diff --git a/build/macosx/template.app/Contents/Info.plist b/build/macosx/template.app/Contents/Info.plist deleted file mode 100755 index 85f50779a..000000000 --- a/build/macosx/template.app/Contents/Info.plist +++ /dev/null @@ -1,120 +0,0 @@ - - - - - CFBundleName - Processing - - - CFBundleGetInfoString - VERSION, Copyright © Ben Fry and Casey Reas - CFBundleVersion - REVISION - CFBundleShortVersionString - VERSION - - - CFBundleAllowMixedLocalizations - true - CFBundleExecutable - JavaApplicationStub - CFBundleDevelopmentRegion - English - CFBundlePackageType - APPL - CFBundleSignature - Pde1 - CFBundleInfoDictionaryVersion - 6.0 - CFBundleIconFile - processing.icns - CFBundleIdentifier - org.processing.app - - CFBundleDocumentTypes - - - CFBundleTypeExtensions - - pde - java - - CFBundleTypeIconFile - pde.icns - CFBundleTypeName - Processing Source File - CFBundleTypeMIMETypes - - text/plain - - CFBundleTypeOSTypes - - TEXT - - CFBundleTypeRole - Editor - - - - - LSMinimumSystemVersion - 10.6.8 - - NSHighResolutionCapable - - - Java - - SplashFile - $JAVAROOT/lib/about.jpg - - VMOptions - - -Xms128M - -Xmx256M - - - MainClass - processing.app.Base - - - JVMVersion - 1.6* - - ClassPath - - $JAVAROOT/lib/pde.jar:$JAVAROOT/core/library/core.jar:$JAVAROOT/lib/ant.jar:$JAVAROOT/lib/ant-launcher.jar:$JAVAROOT/lib/antlr.jar:$JAVAROOT/lib/jna.jar:$JAVAROOT/lib/org-netbeans-swing-outline.jar:$JAVAROOT/lib/com.ibm.icu_4.4.2.v20110823.jar:$JAVAROOT/lib/jdi.jar:$JAVAROOT/lib/jdimodel.jar:$JAVAROOT/lib/org.eclipse.osgi_3.8.1.v20120830-144521.jar - - - Properties - - - javaroot - $JAVAROOT - - - apple.laf.useScreenMenuBar - true - - apple.awt.showGrowBox - true - com.apple.smallTabs - true - apple.awt.Antialiasing - false - apple.awt.TextAntialiasing - true - com.apple.hwaccel - true - apple.awt.use-file-dialog-packages - false - apple.awt.graphics.UseQuartz - true - - - - diff --git a/build/macosx/template.app/Contents/MacOS/JavaApplicationStub b/build/macosx/template.app/Contents/MacOS/JavaApplicationStub deleted file mode 100755 index 73994852797b8e123c6ab378c21a6fffb7ebd720..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35072 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 diff --git a/build/macosx/template.app/Contents/PkgInfo b/build/macosx/template.app/Contents/PkgInfo deleted file mode 100755 index 3f338b4a0..000000000 --- a/build/macosx/template.app/Contents/PkgInfo +++ /dev/null @@ -1 +0,0 @@ -APPLPde1 \ No newline at end of file diff --git a/build/macosx/template.app/Contents/Resources/pde.icns b/build/macosx/template.app/Contents/Resources/pde.icns deleted file mode 100644 index 214b19877ae38e580adf5e2466aceaa6f6b798a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42258 zcmeHwcXS)qnePCknk8AbWI1tc$ zaZy%sx1>P_NP-~126l=C?7fp933h@MdnZ`H27)9i(F=+9-2o{UiB+IwXF1>qxO2a9 z%XbUrH$Uj|8}D7ku%y$M-?;jB7>4~+^0efX;HARUXs70d&&Be zbF&xN`2mKJjxM>(mJ1e(kHvDq^?q(yy*gQ#bU7%X_Lvv$L!-{wVE$jk-o_U8gOE!3&9W`<+>lSw%f`Ej^n!Urqn25e!}Al^k3m3hY>5)k zBE_LJ?K~2&m{$zwwJ2@1XK_*q14cbc+nsI$v%?l6cIr6hq&SY*?KT^JQ%i3mWm*vo`ktSh9Yd7#jcQ&UmOjk1qVvowQ5x z^!l_b`>}QTF4wm=q+i^S{>l3E(!~wwUqBiL>7CGO;lc%2E36iad7~gK2tiXC|wXWu)6$veRAcbB?23l%0AF_}~ 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 Ze8jT{SUj{dc036kWX~Uj-MhYd{C^CIlIj2e diff --git a/build/macosx/template.app/Contents/Resources/processing.icns b/build/macosx/template.app/Contents/Resources/processing.icns deleted file mode 100644 index 901fc569e7e2f8de6a78df10fc9574c3319237ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 415779 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

Z; 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�#f88*-)&@OoAI& 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�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

Z;OJ0D(E1=R~)ZE*U!gGDS7hZ5KWdflY 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 ia5Gp2JN^F|`W)z7IKvu0 Date: Sun, 22 Sep 2013 16:57:14 -0400 Subject: [PATCH 075/556] add java executable on OS X, force local when running --- app/src/processing/app/Base.java | 18 +++++ .../processing/mode/java/runner/Runner.java | 9 ++- build/build.xml | 80 ++++--------------- .../com/oracle/appbundler/AppBundlerTask.java | 16 +++- 4 files changed, 53 insertions(+), 70 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 44cb895df..d0c98d4a4 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2384,6 +2384,24 @@ public class Base { */ return new File(processingRoot, name); } + + + /** Get the path to the embedded Java executable. */ + static public String getJavaPath() { + if (isMacOS()) { + //return "Contents/PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java"; + return getContentFile("../PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java").getAbsolutePath(); + + } else if (isLinux()) { + return getContentFile("../java/bin/java").getAbsolutePath(); + + } else if (isWindows()) { + return getContentFile("../java/bin/java.exe").getAbsolutePath(); + } + System.err.println("No appropriate platform found. " + + "Hoping that Java is in the path."); + return Base.isWindows() ? "java.exe" : "java"; + } // /** diff --git a/app/src/processing/mode/java/runner/Runner.java b/app/src/processing/mode/java/runner/Runner.java index c7a0599ff..4bc3cb72d 100644 --- a/app/src/processing/mode/java/runner/Runner.java +++ b/app/src/processing/mode/java/runner/Runner.java @@ -142,7 +142,9 @@ public class Runner implements MessageConsumer { String[] commandArgs = null; if (!Base.isMacOS()) { commandArgs = new String[] { - "java", jdwpArg + //"java", + Base.getJavaPath(), + jdwpArg }; } else { // Decided to just set this to 1.6 only, because otherwise it's gonna @@ -160,7 +162,7 @@ public class Runner implements MessageConsumer { // OS X at this point, because we require 10.6.8 and higher. That also // means we don't need to check for any other OS versions, the user is // a douchebag and modifies Info.plist to get around the restriction. - if (true) { + if (false) { if (System.getProperty("os.version").startsWith("10.6")) { commandArgs = new String[] { "/usr/libexec/java_home", @@ -183,7 +185,8 @@ public class Runner implements MessageConsumer { } else { // testing jdk-7u40 commandArgs = new String[] { - "/Library/Java/JavaVirtualMachines/jdk1.7.0_40.jdk/Contents/Home/bin/java", + //"/Library/Java/JavaVirtualMachines/jdk1.7.0_40.jdk/Contents/Home/bin/java", + Base.getJavaPath(), jdwpArg }; } diff --git a/build/build.xml b/build/build.xml index 2e58cc6cf..40478d795 100755 --- a/build/build.xml +++ b/build/build.xml @@ -473,31 +473,6 @@ - - - - - - - - + + - - - - - -

diff --git a/core/todo.txt b/core/todo.txt index 96faef665..87f151ad3 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -2,6 +2,7 @@ X background color for present mode has no effect X https://github.com/processing/processing/issues/2071 X https://github.com/processing/processing/pull/2072 +X add desktopPath() and desktopFile() methods for testing _ Sort out blending differences with P2D/P3D _ https://github.com/processing/processing/issues/1844 diff --git a/todo.txt b/todo.txt index ec57b2d72..375b3a3ec 100644 --- a/todo.txt +++ b/todo.txt @@ -6,7 +6,8 @@ o bad JS mode causing crash on startup X https://github.com/processing/processing/issues/2088 X looks like issue that was covered in 2.0.3 changes -_ Windows and 7u40 has some sort of font problem w/ the console +_ fix console font on Windows and Linux with 7u40 +_ the message area text also looks ugly.. can we fix? build X remove video library for other platforms in download From d46e55714d519d54ce6cf4e0dcdda1058e1eb32f Mon Sep 17 00:00:00 2001 From: gohai Date: Tue, 24 Sep 2013 08:26:08 -0700 Subject: [PATCH 078/556] Replace RXTX-based serial library by one based on JSSC Development on this was done in https://github.com/gohai/processing-serial-jssc. See also https://github.com/gohai/java-simple-serial-connector for changes to JSSC (not yet upstreamed). --- java/libraries/serial/.classpath | 2 +- java/libraries/serial/build.xml | 4 +- java/libraries/serial/library/jssc.txt | 1 + .../serial/src/processing/serial/Serial.java | 974 ++++++------------ 4 files changed, 328 insertions(+), 653 deletions(-) create mode 100644 java/libraries/serial/library/jssc.txt diff --git a/java/libraries/serial/.classpath b/java/libraries/serial/.classpath index fb88820a0..d8894f2e3 100644 --- a/java/libraries/serial/.classpath +++ b/java/libraries/serial/.classpath @@ -2,7 +2,7 @@ - + diff --git a/java/libraries/serial/build.xml b/java/libraries/serial/build.xml index d04e8a66a..d6b18410e 100755 --- a/java/libraries/serial/build.xml +++ b/java/libraries/serial/build.xml @@ -3,7 +3,7 @@ - + @@ -18,7 +18,7 @@ srcdir="src" destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../../../core/library/core.jar; library/RXTXcomm.jar" + classpath="../../../core/library/core.jar; library/jssc.jar" nowarn="true" compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> diff --git a/java/libraries/serial/library/jssc.txt b/java/libraries/serial/library/jssc.txt new file mode 100644 index 000000000..cf2f974ac --- /dev/null +++ b/java/libraries/serial/library/jssc.txt @@ -0,0 +1 @@ +This is using a modified version of Java Simple Serial Connector by Alexey Sokolov. See https://github.com/gohai/java-simple-serial-connector for details on the modifications. diff --git a/java/libraries/serial/src/processing/serial/Serial.java b/java/libraries/serial/src/processing/serial/Serial.java index fd3595fc1..8e82e2184 100644 --- a/java/libraries/serial/src/processing/serial/Serial.java +++ b/java/libraries/serial/src/processing/serial/Serial.java @@ -5,6 +5,7 @@ Part of the Processing project - http://processing.org Copyright (c) 2004-05 Ben Fry & Casey Reas + Reworked by Gottfried Haider as part of GSOC 2013 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -24,728 +25,401 @@ package processing.serial; import processing.core.*; - -import gnu.io.*; - -import java.io.*; -import java.util.*; import java.lang.reflect.*; +import java.util.Map; +import jssc.*; -/** - * @generate Serial.xml - * @webref net - * @usage application - */ public class Serial implements SerialPortEventListener { PApplet parent; + public SerialPort port; + Method serialAvailableMethod; Method serialEventMethod; - // properties can be passed in for default values - // otherwise defaults to 9600 N81 + byte[] buffer = new byte[32768]; + int inBuffer = 0; + int readOffset = 0; - // these could be made static, which might be a solution - // for the classloading problem.. because if code ran again, - // the static class would have an object that could be closed + int bufferUntilSize = 1; + byte bufferUntilByte = 0; - public SerialPort port; + volatile boolean invokeSerialAvailable = false; - public int rate; - public int parity; - public int databits; - public int stopbits; + // Things we are currently not exposing: + // * hardware flow control + // * state of the RING, RLSD line + // * sending breaks - - // read buffer and streams - - public InputStream input; - public OutputStream output; - - byte buffer[] = new byte[32768]; - int bufferIndex; - int bufferLast; - - //boolean bufferUntil = false; - int bufferSize = 1; // how big before reset or event firing - boolean bufferUntil; - byte bufferUntilByte; - - - // defaults - - static String dname = "COM1"; - static int drate = 9600; - static char dparity = 'N'; - static int ddatabits = 8; - static float dstopbits = 1; - - - public void setProperties(Properties props) { - dname = - props.getProperty("serial.port", dname); - drate = - Integer.parseInt(props.getProperty("serial.rate", "9600")); - dparity = - props.getProperty("serial.parity", "N").charAt(0); - ddatabits = - Integer.parseInt(props.getProperty("serial.databits", "8")); - dstopbits = - new Float(props.getProperty("serial.stopbits", "1")).floatValue(); - } - -/** - * @param parent typically use "this" - */ public Serial(PApplet parent) { - this(parent, dname, drate, dparity, ddatabits, dstopbits); + this(parent, "COM1", 9600, 'N', 8, 1); } - -/** - * @param irate 9600 is the default - */ - public Serial(PApplet parent, int irate) { - this(parent, dname, irate, dparity, ddatabits, dstopbits); + public Serial(PApplet parent, int baudRate) { + this(parent, "COM1", baudRate, 'N', 8, 1); } - -/** - * @param iname name of the port (COM1 is the default) - */ - public Serial(PApplet parent, String iname, int irate) { - this(parent, iname, irate, dparity, ddatabits, dstopbits); + public Serial(PApplet parent, String portName) { + this(parent, portName, 9600, 'N', 8, 1); } - public Serial(PApplet parent, String iname) { - this(parent, iname, drate, dparity, ddatabits, dstopbits); + public Serial(PApplet parent, String portName, int baudRate) { + this(parent, portName, baudRate, 'N', 8, 1); } - -/** - * @param iparity 'N' for none, 'E' for even, 'O' for odd ('N' is the default) - * @param idatabits 8 is the default - * @param istopbits 1.0, 1.5, or 2.0 (1.0 is the default) - */ - public Serial(PApplet parent, String iname, int irate, - char iparity, int idatabits, float istopbits) { - //if (port != null) port.close(); + public Serial(PApplet parent, String portName, int baudRate, char parity, int dataBits, float stopBits) { this.parent = parent; - //parent.attach(this); + parent.registerMethod("dispose", this); + parent.registerMethod("pre", this); - // On OS X, make sure the lock folder needed by RXTX is present - if (PApplet.platform == PConstants.MACOSX) { - File lockFolder = new File("/var/lock"); - if (!lockFolder.exists() || - !lockFolder.canRead() || - !lockFolder.canWrite() || - !lockFolder.canExecute()) { - final String MESSAGE = - "To use the serial library, first open\n" + - "Applications -> Utilities -> Terminal.app\n" + - "and enter the following:\n" + - "sudo mkdir -p /var/lock\n" + - "sudo chmod 777 /var/lock"; - System.err.println(MESSAGE); - //throw new RuntimeException("Additional installation required to " + - // "use serial, read the console below."); - final String msg = - "Please use Tools \u2192 Fix the Serial Library."; - throw new RuntimeException(msg); - } + // setup parity + if (parity == 'O') { + parity = SerialPort.PARITY_ODD; + } else if (parity == 'E') { + parity = SerialPort.PARITY_EVEN; + } else if (parity == 'M') { + parity = SerialPort.PARITY_MARK; + } else if (parity == 'S') { + parity = SerialPort.PARITY_SPACE; + } else { + parity = SerialPort.PARITY_NONE; } - this.rate = irate; + // setup stop bits + int stopBitsIdx = SerialPort.STOPBITS_1; + if (stopBits == 1.5f) { + stopBitsIdx = SerialPort.STOPBITS_1_5; + } else if (stopBits == 2) { + stopBitsIdx = SerialPort.STOPBITS_2; + } - parity = SerialPort.PARITY_NONE; - if (iparity == 'E') parity = SerialPort.PARITY_EVEN; - if (iparity == 'O') parity = SerialPort.PARITY_ODD; - - this.databits = idatabits; - - stopbits = SerialPort.STOPBITS_1; - if (istopbits == 1.5f) stopbits = SerialPort.STOPBITS_1_5; - if (istopbits == 2) stopbits = SerialPort.STOPBITS_2; + port = new SerialPort(portName); + try { + // the native open() call is not using O_NONBLOCK, so this might block for certain operations (see write()) + port.openPort(); + port.setParams(baudRate, dataBits, stopBitsIdx, parity); + // we could register more events here + port.addEventListener(this, SerialPort.MASK_RXCHAR); + } catch (SerialPortException e) { + // this used to be a RuntimeException before, so stick with it + throw new RuntimeException("Error opening serial port "+e.getPortName()+": "+e.getExceptionType()); + } try { - Enumeration portList = CommPortIdentifier.getPortIdentifiers(); - while (portList.hasMoreElements()) { - CommPortIdentifier portId = - (CommPortIdentifier) portList.nextElement(); + serialEventMethod = parent.getClass().getMethod("serialEvent", new Class[] { this.getClass() }); + } catch (Exception e) { + } - if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { - //System.out.println("found " + portId.getName()); - if (portId.getName().equals(iname)) { - port = (SerialPort)portId.open("serial madness", 2000); - input = port.getInputStream(); - output = port.getOutputStream(); - port.setSerialPortParams(rate, databits, stopbits, parity); - port.addEventListener(this); - port.notifyOnDataAvailable(true); - //System.out.println("opening, ready to roll"); - } + try { + serialAvailableMethod = parent.getClass().getMethod("serialAvailable", new Class[] { this.getClass() }); + } catch (Exception e) { + } + } + + public void dispose() { + stop(); + } + + public void pre() { + if (serialAvailableMethod != null && invokeSerialAvailable) { + invokeSerialAvailable = false; + try { + serialAvailableMethod.invoke(parent, new Object[] { this }); + } catch (Exception e) { + System.err.println("Error, disabling serialAvailable() for "+port.getPortName()); + System.err.println(e.getLocalizedMessage()); + serialAvailableMethod = null; + } + } + } + + + public int available() { + return (inBuffer-readOffset); + } + + public void buffer(int size) { + bufferUntilSize = size; + } + + public void bufferUntil(int inByte) { + bufferUntilSize = 0; + bufferUntilByte = (byte)inByte; + } + + public void clear() { + synchronized (buffer) { + inBuffer = 0; + readOffset = 0; + } + } + + public boolean getCTS() { + try { + return port.isCTS(); + } catch (SerialPortException e) { + throw new RuntimeException("Error reading the CTS line: "+e.getExceptionType()); + } + } + + public boolean getDSR() { + try { + return port.isDSR(); + } catch (SerialPortException e) { + throw new RuntimeException("Error reading the DSR line: "+e.getExceptionType()); + } + } + + public static Map getProperties(String portName) { + SerialPortList list = new SerialPortList(); + return list.getPortProperties(portName); + } + + public int last() { + if (inBuffer == readOffset) { + return -1; + } + + synchronized (buffer) { + int ret = buffer[inBuffer-1] & 0xFF; + inBuffer = 0; + readOffset = 0; + return ret; + } + } + + public char lastChar() { + return (char)last(); + } + + public static String[] list() { + SerialPortList list = new SerialPortList(); + // returns list sorted alphabetically, thus cu.* comes before tty.* + // this was different with RXTX + return list.getPortNames(); + } + + public int read() { + if (inBuffer == readOffset) { + return -1; + } + + synchronized (buffer) { + int ret = buffer[readOffset++] & 0xFF; + if (inBuffer == readOffset) { + inBuffer = 0; + readOffset = 0; + } + return ret; + } + } + + public byte[] readBytes() { + if (inBuffer == readOffset) { + return null; + } + + synchronized (buffer) { + byte[] ret = new byte[inBuffer-readOffset]; + System.arraycopy(buffer, readOffset, ret, 0, ret.length); + inBuffer = 0; + readOffset = 0; + return ret; + } + } + + public int readBytes(byte[] dest) { + if (inBuffer == readOffset) { + return 0; + } + + synchronized (buffer) { + int toCopy = inBuffer-readOffset; + if (dest.length < toCopy) { + toCopy = dest.length; + } + System.arraycopy(buffer, readOffset, dest, 0, toCopy); + readOffset += toCopy; + if (inBuffer == readOffset) { + inBuffer = 0; + readOffset = 0; + } + return toCopy; + } + } + + public byte[] readBytesUntil(int inByte) { + if (inBuffer == readOffset) { + return null; + } + + synchronized (buffer) { + // look for needle in buffer + int found = -1; + for (int i=readOffset; i < inBuffer; i++) { + if (buffer[i] == (byte)inByte) { + found = i; + break; } } - - } catch (Exception e) { - errorMessage("", e); - //exception = e; - //e.printStackTrace(); - port = null; - input = null; - output = null; - } - - parent.registerMethod("dispose", this); - - // reflection to check whether host applet has a call for - // public void serialEvent(processing.serial.Serial) - // which would be called each time an event comes in - try { - serialEventMethod = - parent.getClass().getMethod("serialEvent", - new Class[] { Serial.class }); - } catch (Exception e) { - // no such method, or an error.. which is fine, just ignore - } - } - - - /** - * @generate Serial_stop.xml - * @webref serial:serial - * @usage web_application - */ - public void stop() { - dispose(); - } - - - /** - * Used by PApplet to shut things down. - */ - public void dispose() { - try { - if (input != null) { - input.close(); - input = null; + if (found == -1) { + return null; } - } catch (Exception e) { - e.printStackTrace(); - } - try { - if (output != null) { - output.close(); - output = null; + int toCopy = found-readOffset+1; + byte[] dest = new byte[toCopy]; + System.arraycopy(buffer, readOffset, dest, 0, toCopy); + readOffset += toCopy; + if (inBuffer == readOffset) { + inBuffer = 0; + readOffset = 0; } - } catch (Exception e) { - e.printStackTrace(); - } - - try { - if (port != null) { - port.close(); - port = null; - } - } catch (Exception e) { - e.printStackTrace(); + return dest; } } + public int readBytesUntil(int inByte, byte[] dest) { + if (inBuffer == readOffset) { + return 0; + } - /** - * Set the DTR line. Addition from Tom Hulbert. - */ - public void setDTR(boolean state) { - port.setDTR(state); + synchronized (buffer) { + // look for needle in buffer + int found = -1; + for (int i=readOffset; i < inBuffer; i++) { + if (buffer[i] == (byte)inByte) { + found = i; + break; + } + } + if (found == -1) { + return 0; + } + + // check if bytes to copy fit in dest + int toCopy = found-readOffset+1; + if (dest.length < toCopy) { + System.err.println( "The buffer passed to readBytesUntil() is to small " + + "to contain " + toCopy + " bytes up to and including " + + "char " + (byte)inByte); + return -1; + } + System.arraycopy(buffer, readOffset, dest, 0, toCopy); + readOffset += toCopy; + if (inBuffer == readOffset) { + inBuffer = 0; + readOffset = 0; + } + return toCopy; + } } + public char readChar() { + return (char)read(); + } - /** - * @generate serialEvent.xml - * @webref serial:events - * @usage web_application - * @param serialEvent the port where new data is available - */ - synchronized public void serialEvent(SerialPortEvent serialEvent) { - if (serialEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { + public String readString() { + if (inBuffer == readOffset) { + return null; + } + + return new String(readBytes()); + } + + public void serialEvent(SerialPortEvent event) { + if (event.getEventType() == SerialPortEvent.RXCHAR) { + int toRead; try { - while (input.available() > 0) { + while (0 < (toRead = port.getInputBufferBytesCount())) { + // this method can be called from the context of another thread synchronized (buffer) { - if (bufferLast == buffer.length) { - byte temp[] = new byte[bufferLast << 1]; - System.arraycopy(buffer, 0, temp, 0, bufferLast); + // enlarge buffer if necessary + if (buffer.length < inBuffer+toRead) { + byte temp[] = new byte[buffer.length<<1]; + System.arraycopy(buffer, 0, temp, 0, inBuffer); buffer = temp; } - buffer[bufferLast++] = (byte) input.read(); + // read an array of bytes and copy it into our buffer + byte[] read = port.readBytes(toRead); + System.arraycopy(read, 0, buffer, inBuffer, read.length); + inBuffer += read.length; if (serialEventMethod != null) { - if ((bufferUntil && - (buffer[bufferLast-1] == bufferUntilByte)) || - (!bufferUntil && - ((bufferLast - bufferIndex) >= bufferSize))) { + if ((0 < bufferUntilSize && bufferUntilSize <= inBuffer-readOffset) || + (0 == bufferUntilSize && bufferUntilByte == buffer[inBuffer-1])) { try { + // serialEvent() is invoked in the context of the current (serial) thread + // which means that serialization and atomic variables need to be used to + // guarantee reliable operation (and better not draw() etc..) + // serialAvailable() does not provide any real benefits over using + // available() and read() inside draw - but this function has no + // thread-safety issues since it's being invoked during pre in the context + // of the Processing applet serialEventMethod.invoke(parent, new Object[] { this }); } catch (Exception e) { - String msg = "error, disabling serialEvent() for " + port; - System.err.println(msg); - e.printStackTrace(); + System.err.println("Error, disabling serialEvent() for "+port.getPortName()); + System.err.println(e.getLocalizedMessage()); serialEventMethod = null; } } } + invokeSerialAvailable = true; } } - - } catch (IOException e) { - errorMessage("serialEvent", e); + } catch (SerialPortException e) { + throw new RuntimeException("Error reading from serial port "+e.getPortName()+": "+e.getExceptionType()); } } } - - /** - * @generate Serial_buffer.xml - * @webref serial:serial - * @usage web_application - * @param count number of bytes to buffer - */ - public void buffer(int count) { - bufferUntil = false; - bufferSize = count; - } - - - /** - * @generate Serial_bufferUntil.xml - * @webref serial:serial - * @usage web_application - * @param what the value to buffer until - */ - public void bufferUntil(int what) { - bufferUntil = true; - bufferUntilByte = (byte) what; - } - - - /** - * @generate Serial_available.xml - * @webref serial:serial - * @usage web_application - */ - public int available() { - return (bufferLast - bufferIndex); - } - - - /** - * @generate Serial_clear.xml - * @webref serial:serial - * @usage web_application - */ - public void clear() { - bufferLast = 0; - bufferIndex = 0; - } - - - /** - * @generate Serial_read.xml - * @webref serial:serial - * @usage web_application - */ - public int read() { - if (bufferIndex == bufferLast) return -1; - - synchronized (buffer) { - int outgoing = buffer[bufferIndex++] & 0xff; - if (bufferIndex == bufferLast) { // rewind - bufferIndex = 0; - bufferLast = 0; - } - return outgoing; - } - } - - - /** - * @generate Serial_last.xml - *

Advanced

- * Same as read() but returns the very last value received - * and clears the buffer. Useful when you just want the most - * recent value sent over the port. - * @webref serial:serial - * @usage web_application - */ - public int last() { - if (bufferIndex == bufferLast) return -1; - synchronized (buffer) { - int outgoing = buffer[bufferLast-1]; - bufferIndex = 0; - bufferLast = 0; - return outgoing; - } - } - - - /** - * @generate Serial_readChar.xml - * @webref serial:serial - * @usage web_application - */ - public char readChar() { - if (bufferIndex == bufferLast) return (char)(-1); - return (char) read(); - } - - - /** - * @generate Serial_lastChar.xml - * @webref serial:serial - * @usage web_application - */ - public char lastChar() { - if (bufferIndex == bufferLast) return (char)(-1); - return (char) last(); - } - - - /** - * @generate Serial_readBytes.xml - * @webref serial:serial - * @usage web_application - */ - public byte[] readBytes() { - if (bufferIndex == bufferLast) return null; - - synchronized (buffer) { - int length = bufferLast - bufferIndex; - byte outgoing[] = new byte[length]; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex = 0; // rewind - bufferLast = 0; - return outgoing; - } - } - - - /** - *

Advanced

- * Grab whatever is in the serial buffer, and stuff it into a - * byte buffer passed in by the user. This is more memory/time - * efficient than readBytes() returning a byte[] array. - * - * Returns an int for how many bytes were read. If more bytes - * are available than can fit into the byte array, only those - * that will fit are read. - */ - public int readBytes(byte outgoing[]) { - if (bufferIndex == bufferLast) return 0; - - synchronized (buffer) { - int length = bufferLast - bufferIndex; - if (length > outgoing.length) length = outgoing.length; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex += length; - if (bufferIndex == bufferLast) { - bufferIndex = 0; // rewind - bufferLast = 0; - } - return length; - } - } - - - /** - * @generate Serial_readBytesUntil.xml - * @webref serial:serial - * @usage web_application - * @param interesting character designated to mark the end of the data - */ - public byte[] readBytesUntil(int interesting) { - if (bufferIndex == bufferLast) return null; - byte what = (byte)interesting; - - synchronized (buffer) { - int found = -1; - for (int k = bufferIndex; k < bufferLast; k++) { - if (buffer[k] == what) { - found = k; - break; - } - } - if (found == -1) return null; - - int length = found - bufferIndex + 1; - byte outgoing[] = new byte[length]; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex += length; - if (bufferIndex == bufferLast) { - bufferIndex = 0; // rewind - bufferLast = 0; - } - return outgoing; - } - } - - - /** - *

Advanced

- * If outgoing[] is not big enough, then -1 is returned, - * and an error message is printed on the console. - * If nothing is in the buffer, zero is returned. - * If 'interesting' byte is not in the buffer, then 0 is returned. - * @param outgoing passed in byte array to be altered - */ - public int readBytesUntil(int interesting, byte outgoing[]) { - if (bufferIndex == bufferLast) return 0; - byte what = (byte)interesting; - - synchronized (buffer) { - int found = -1; - for (int k = bufferIndex; k < bufferLast; k++) { - if (buffer[k] == what) { - found = k; - break; - } - } - if (found == -1) return 0; - - int length = found - bufferIndex + 1; - if (length > outgoing.length) { - System.err.println("readBytesUntil() byte buffer is" + - " too small for the " + length + - " bytes up to and including char " + interesting); - return -1; - } - //byte outgoing[] = new byte[length]; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex += length; - if (bufferIndex == bufferLast) { - bufferIndex = 0; // rewind - bufferLast = 0; - } - return length; - } - } - - - /** - * @generate Serial_readString.xml - * @webref serial:serial - * @usage web_application - */ - public String readString() { - if (bufferIndex == bufferLast) return null; - return new String(readBytes()); - } - - - /** - * @generate Serial_readStringUntil.xml - *

Advanced

- * If you want to move Unicode data, you can first convert the - * String to a byte stream in the representation of your choice - * (i.e. UTF8 or two-byte Unicode data), and send it as a byte array. - * - * @webref serial:serial - * @usage web_application - * @param interesting character designated to mark the end of the data - */ - public String readStringUntil(int interesting) { - byte b[] = readBytesUntil(interesting); - if (b == null) return null; - return new String(b); - } - - - /** - *

Advanced

- * This will handle both ints, bytes and chars transparently. - * @param what data to write - */ - public void write(int what) { // will also cover char + public void setDTR(boolean state) { + // there is no way to influence the behavior of the DTR line when opening the serial port + // this means that at least on Linux and OS X, Arduino devices are always reset try { - output.write(what & 0xff); // for good measure do the & - output.flush(); // hmm, not sure if a good idea - - } catch (Exception e) { // null pointer or serial port dead - errorMessage("write", e); + port.setDTR(state); + } catch (SerialPortException e) { + throw new RuntimeException("Error setting the DTR line: "+e.getExceptionType()); } } - /** - * @param bytes[] data to write - */ - public void write(byte bytes[]) { + public void setRTS(boolean state) { try { - output.write(bytes); - output.flush(); // hmm, not sure if a good idea - - } catch (Exception e) { // null pointer or serial port dead - //errorMessage("write", e); - e.printStackTrace(); + port.setRTS(state); + } catch (SerialPortException e) { + throw new RuntimeException("Error setting the RTS line: "+e.getExceptionType()); } } - - /** - * @generate Serial_write.xml - *

Advanced

- * Write a String to the output. Note that this doesn't account - * for Unicode (two bytes per char), nor will it send UTF8 - * characters.. It assumes that you mean to send a byte buffer - * (most often the case for networking and serial i/o) and - * will only use the bottom 8 bits of each char in the string. - * (Meaning that internally it uses String.getBytes) - * - * If you want to move Unicode data, you can first convert the - * String to a byte stream in the representation of your choice - * (i.e. UTF8 or two-byte Unicode data), and send it as a byte array. - * - * @webref serial:serial - * @usage web_application - * @param what data to write - */ - public void write(String what) { - write(what.getBytes()); - } - - - /** - * @generate Serial_list.xml - *

Advanced

- * If this just hangs and never completes on Windows, - * it may be because the DLL doesn't have its exec bit set. - * Why the hell that'd be the case, who knows. - * - * @webref serial - * @usage web_application - */ - static public String[] list() { - Vector list = new Vector(); + public void stop() { try { - //System.err.println("trying"); - Enumeration portList = CommPortIdentifier.getPortIdentifiers(); - //System.err.println("got port list"); - while (portList.hasMoreElements()) { - CommPortIdentifier portId = - (CommPortIdentifier) portList.nextElement(); - //System.out.println(portId); - - if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { - String name = portId.getName(); - list.addElement(name); - } - } - - } catch (UnsatisfiedLinkError e) { - //System.err.println("1"); - errorMessage("ports", e); - - } catch (Exception e) { - //System.err.println("2"); - errorMessage("ports", e); + port.closePort(); + } catch (SerialPortException e) { } - //System.err.println("move out"); - String outgoing[] = new String[list.size()]; - list.copyInto(outgoing); - return outgoing; + inBuffer = 0; + readOffset = 0; } - - /** - * General error reporting, all corraled here just in case - * I think of something slightly more intelligent to do. - */ - static public void errorMessage(String where, Throwable e) { - e.printStackTrace(); - throw new RuntimeException("Error inside Serial." + where + "()"); - } -} - - - /* - class SerialMenuListener implements ItemListener { - //public SerialMenuListener() { } - - public void itemStateChanged(ItemEvent e) { - int count = serialMenu.getItemCount(); - for (int i = 0; i < count; i++) { - ((CheckboxMenuItem)serialMenu.getItem(i)).setState(false); - } - CheckboxMenuItem item = (CheckboxMenuItem)e.getSource(); - item.setState(true); - String name = item.getLabel(); - //System.out.println(item.getLabel()); - PdeBase.properties.put("serial.port", name); - //System.out.println("set to " + get("serial.port")); - } - } - */ - - - /* - protected Vector buildPortList() { - // get list of names for serial ports - // have the default port checked (if present) - Vector list = new Vector(); - - //SerialMenuListener listener = new SerialMenuListener(); - boolean problem = false; - - // if this is failing, it may be because - // lib/javax.comm.properties is missing. - // java is weird about how it searches for java.comm.properties - // so it tends to be very fragile. i.e. quotes in the CLASSPATH - // environment variable will hose things. + public void write(byte[] src) { try { - //System.out.println("building port list"); - Enumeration portList = CommPortIdentifier.getPortIdentifiers(); - while (portList.hasMoreElements()) { - CommPortIdentifier portId = - (CommPortIdentifier) portList.nextElement(); - //System.out.println(portId); - - if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { - //if (portId.getName().equals(port)) { - String name = portId.getName(); - //CheckboxMenuItem mi = - //new CheckboxMenuItem(name, name.equals(defaultName)); - - //mi.addItemListener(listener); - //serialMenu.add(mi); - list.addElement(name); - } - } - } catch (UnsatisfiedLinkError e) { - e.printStackTrace(); - problem = true; - - } catch (Exception e) { - System.out.println("exception building serial menu"); - e.printStackTrace(); + // this might block if the serial device is not yet ready (esp. tty devices under OS X) + port.writeBytes(src); + // we used to call flush() here + } catch (SerialPortException e) { + throw new RuntimeException("Error writing to serial port "+e.getPortName()+": "+e.getExceptionType()); } - - //if (serialMenu.getItemCount() == 0) { - //System.out.println("dimming serial menu"); - //serialMenu.setEnabled(false); - //} - - // only warn them if this is the first time - if (problem && PdeBase.firstTime) { - JOptionPane.showMessageDialog(this, //frame, - "Serial port support not installed.\n" + - "Check the readme for instructions\n" + - "if you need to use the serial port. ", - "Serial Port Warning", - JOptionPane.WARNING_MESSAGE); - } - return list; } - */ + public void write(int src) { + try { + port.writeInt(src); + } catch (SerialPortException e) { + throw new RuntimeException("Error writing to serial port "+e.getPortName()+": "+e.getExceptionType()); + } + } + public void write(String src) { + try { + port.writeString(src); + } catch (SerialPortException e) { + throw new RuntimeException("Error writing to serial port "+e.getPortName()+": "+e.getExceptionType()); + } + } +} \ No newline at end of file From 91ae0c5aeb8b778c30112d83aa37c08e8677a771 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Wed, 25 Sep 2013 10:50:29 -0400 Subject: [PATCH 079/556] set dock icon attempt --- build/build.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index 40478d795..936380e63 100755 --- a/build/build.xml +++ b/build/build.xml @@ -527,9 +527,10 @@ role="Editor"> + +
  • Converts doubles into floats, i.e. 12.3 becomes 12.3f so that people - * don't have to add f after their numbers all the time since it's confusing - * for beginners. Also, most functions of p5 core deal with floats only. - * - * @author Manindra Moharana - * - */ - private class XQASTVisitor extends ASTVisitor { - @SuppressWarnings({ "unchecked", "rawtypes" }) - public boolean visit(MethodDeclaration node) { - if (node.getReturnType2() != null) { - // if return type is color, make it int - // if (node.getReturnType2().toString().equals("color")) { - // System.err.println("color type detected!"); - // node.setReturnType2(rewrite.getAST().newPrimitiveType( - // PrimitiveType.INT)); - // } - - // The return type is not void, no need to make it public - // if (!node.getReturnType2().toString().equals("void")) - // return true; - } - - // Simple method, make it public - if (node.modifiers().size() == 0 && !node.isConstructor()) { - // rewrite.set(node, node.getModifiersProperty(), - // Modifier.PUBLIC, - // null); - // rewrite.getListRewrite(node, - // node.getModifiersProperty()).insertLast(Modifier., null) - List newMod = rewrite.getAST().newModifiers(Modifier.PUBLIC); - node.modifiers().add(newMod.get(0)); - } - - return true; - } - - public boolean visit(NumberLiteral node) { - if (!node.getToken().endsWith("f") - && !node.getToken().endsWith("d")) { - for (int i = 0; i < node.getToken().length(); i++) { - if (node.getToken().charAt(i) == '.') { - - String s = node.getToken() + "f"; - node.setToken(s); - break; - } - } - } - return true; - } - - // public boolean visit(FieldDeclaration node) { - // if (node.getType().toString().equals("color")){ - // System.err.println("color type detected!"); - // node.setType(rewrite.getAST().newPrimitiveType( - // PrimitiveType.INT)); - // } - // return true; - // } - // - // public boolean visit(VariableDeclarationStatement node) { - // if (node.getType().toString().equals("color")){ - // System.err.println("color type detected!"); - // node.setType(rewrite.getAST().newPrimitiveType( - // PrimitiveType.INT)); - // } - // return true; - // } - - /** - * This is added just for debugging purposes - to make sure that all - * instances of color type have been substituded as in by the regex - * search in ErrorCheckerService.preprocessCode(). - */ - public boolean visit(SimpleType node) { - if (node.toString().equals("color")) { - System.err - .println("color type detected! \nThis shouldn't be happening! Please report this as an issue."); - } - return true; - - } - - } - -} diff --git a/experimental/theme/theme.txt b/experimental/theme/theme.txt deleted file mode 100755 index 1a6179f5c..000000000 --- a/experimental/theme/theme.txt +++ /dev/null @@ -1,34 +0,0 @@ -# DEBUGGER - -# breakpointed line background color -breakpoint.bgcolor = #f0f0f0 -# marker for breakpointed lines in left hand gutter (2 ascii characters) -breakpoint.marker = <> -breakpoint.marker.color = #4a545e - -# current line background color -currentline.bgcolor = #ffff96 -# marker for the current line in left hand gutter (2 ascii characters) -currentline.marker = -> -currentline.marker.color = #e27500 - -# left hand gutter background color -gutter.bgcolor = #fcfcfc -# color of vertical separation line -gutter.linecolor = #e9e9e9 -# space (in px) added to left and right of gutter markers -gutter.padding = 3 - - -# XQMODE - -# underline colors -editor.errorcolor = #ed2630 -editor.warningcolor = #ffc30e -editor.errormarkercolor = #ed2630 -editor.warningmarkercolor = #ffc30e - -# ERROR BAR - error bar on the right that shows the markers -errorbar.errorcolor = #ed2630 -errorbar.warningcolor = #ffc30e -errorbar.backgroundcolor = #2c343d diff --git a/experimental/theme/var-icons.gif b/experimental/theme/var-icons.gif deleted file mode 100755 index 1d0086a38ebb728a2a44d3b4d510cf12992fc1dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5152 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 Date: Wed, 25 Sep 2013 14:12:56 -0400 Subject: [PATCH 084/556] update serial with p5 code conventions, fix two warnings --- .../serial/src/processing/serial/Serial.java | 67 ++++++++++++++----- todo.txt | 9 ++- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/java/libraries/serial/src/processing/serial/Serial.java b/java/libraries/serial/src/processing/serial/Serial.java index 8e82e2184..8265dffdd 100644 --- a/java/libraries/serial/src/processing/serial/Serial.java +++ b/java/libraries/serial/src/processing/serial/Serial.java @@ -24,13 +24,16 @@ */ package processing.serial; + import processing.core.*; + import java.lang.reflect.*; import java.util.Map; + import jssc.*; -public class Serial implements SerialPortEventListener { +public class Serial implements SerialPortEventListener { PApplet parent; public SerialPort port; Method serialAvailableMethod; @@ -50,22 +53,27 @@ public class Serial implements SerialPortEventListener { // * state of the RING, RLSD line // * sending breaks + public Serial(PApplet parent) { this(parent, "COM1", 9600, 'N', 8, 1); } + public Serial(PApplet parent, int baudRate) { this(parent, "COM1", baudRate, 'N', 8, 1); } + public Serial(PApplet parent, String portName) { this(parent, portName, 9600, 'N', 8, 1); } + public Serial(PApplet parent, String portName, int baudRate) { this(parent, portName, baudRate, 'N', 8, 1); } + public Serial(PApplet parent, String portName, int baudRate, char parity, int dataBits, float stopBits) { this.parent = parent; parent.registerMethod("dispose", this); @@ -101,7 +109,7 @@ public class Serial implements SerialPortEventListener { port.addEventListener(this, SerialPort.MASK_RXCHAR); } catch (SerialPortException e) { // this used to be a RuntimeException before, so stick with it - throw new RuntimeException("Error opening serial port "+e.getPortName()+": "+e.getExceptionType()); + throw new RuntimeException("Error opening serial port " + e.getPortName() + ": " + e.getExceptionType()); } try { @@ -115,10 +123,12 @@ public class Serial implements SerialPortEventListener { } } + public void dispose() { stop(); } + public void pre() { if (serialAvailableMethod != null && invokeSerialAvailable) { invokeSerialAvailable = false; @@ -137,15 +147,18 @@ public class Serial implements SerialPortEventListener { return (inBuffer-readOffset); } + public void buffer(int size) { bufferUntilSize = size; } + public void bufferUntil(int inByte) { bufferUntilSize = 0; bufferUntilByte = (byte)inByte; } + public void clear() { synchronized (buffer) { inBuffer = 0; @@ -153,27 +166,32 @@ public class Serial implements SerialPortEventListener { } } + public boolean getCTS() { try { return port.isCTS(); } catch (SerialPortException e) { - throw new RuntimeException("Error reading the CTS line: "+e.getExceptionType()); + throw new RuntimeException("Error reading the CTS line: " + e.getExceptionType()); } } + public boolean getDSR() { try { return port.isDSR(); } catch (SerialPortException e) { - throw new RuntimeException("Error reading the DSR line: "+e.getExceptionType()); + throw new RuntimeException("Error reading the DSR line: " + e.getExceptionType()); } } + public static Map getProperties(String portName) { - SerialPortList list = new SerialPortList(); - return list.getPortProperties(portName); + //SerialPortList list = new SerialPortList(); + //return list.getPortProperties(portName); + return SerialPortList.getPortProperties(portName); } + public int last() { if (inBuffer == readOffset) { return -1; @@ -187,17 +205,21 @@ public class Serial implements SerialPortEventListener { } } + public char lastChar() { return (char)last(); } + public static String[] list() { - SerialPortList list = new SerialPortList(); // returns list sorted alphabetically, thus cu.* comes before tty.* // this was different with RXTX - return list.getPortNames(); + //SerialPortList list = new SerialPortList(); + //return list.getPortNames(); + return SerialPortList.getPortNames(); } + public int read() { if (inBuffer == readOffset) { return -1; @@ -213,6 +235,7 @@ public class Serial implements SerialPortEventListener { } } + public byte[] readBytes() { if (inBuffer == readOffset) { return null; @@ -226,6 +249,7 @@ public class Serial implements SerialPortEventListener { return ret; } } + public int readBytes(byte[] dest) { if (inBuffer == readOffset) { @@ -246,6 +270,7 @@ public class Serial implements SerialPortEventListener { return toCopy; } } + public byte[] readBytesUntil(int inByte) { if (inBuffer == readOffset) { @@ -277,6 +302,7 @@ public class Serial implements SerialPortEventListener { } } + public int readBytesUntil(int inByte, byte[] dest) { if (inBuffer == readOffset) { return 0; @@ -313,18 +339,20 @@ public class Serial implements SerialPortEventListener { } } + public char readChar() { - return (char)read(); + return (char) read(); } + public String readString() { if (inBuffer == readOffset) { return null; } - return new String(readBytes()); } + public void serialEvent(SerialPortEvent event) { if (event.getEventType() == SerialPortEvent.RXCHAR) { int toRead; @@ -365,61 +393,68 @@ public class Serial implements SerialPortEventListener { } } } catch (SerialPortException e) { - throw new RuntimeException("Error reading from serial port "+e.getPortName()+": "+e.getExceptionType()); + throw new RuntimeException("Error reading from serial port " + e.getPortName() + ": " + e.getExceptionType()); } } } + public void setDTR(boolean state) { // there is no way to influence the behavior of the DTR line when opening the serial port // this means that at least on Linux and OS X, Arduino devices are always reset try { port.setDTR(state); } catch (SerialPortException e) { - throw new RuntimeException("Error setting the DTR line: "+e.getExceptionType()); + throw new RuntimeException("Error setting the DTR line: " + e.getExceptionType()); } } + public void setRTS(boolean state) { try { port.setRTS(state); } catch (SerialPortException e) { - throw new RuntimeException("Error setting the RTS line: "+e.getExceptionType()); + throw new RuntimeException("Error setting the RTS line: " + e.getExceptionType()); } } + public void stop() { try { port.closePort(); } catch (SerialPortException e) { + // ignored } inBuffer = 0; readOffset = 0; } + public void write(byte[] src) { try { // this might block if the serial device is not yet ready (esp. tty devices under OS X) port.writeBytes(src); // we used to call flush() here } catch (SerialPortException e) { - throw new RuntimeException("Error writing to serial port "+e.getPortName()+": "+e.getExceptionType()); + throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType()); } } + public void write(int src) { try { port.writeInt(src); } catch (SerialPortException e) { - throw new RuntimeException("Error writing to serial port "+e.getPortName()+": "+e.getExceptionType()); + throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType()); } } + public void write(String src) { try { port.writeString(src); } catch (SerialPortException e) { - throw new RuntimeException("Error writing to serial port "+e.getPortName()+": "+e.getExceptionType()); + throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType()); } } } \ No newline at end of file diff --git a/todo.txt b/todo.txt index 43c9649f2..c4a319016 100644 --- a/todo.txt +++ b/todo.txt @@ -7,11 +7,10 @@ X https://github.com/processing/processing/issues/2088 X looks like issue that was covered in 2.0.3 changes X non-compliant libraries cause crash on "Add Library" X https://github.com/processing/processing/issues/2026 - -_ incorporate the new serial library -_ https://github.com/processing/processing/pull/2093 -_ moviemaker problem with tga files -_ maybe same as the OS X problem? +X Open new PDE maximized when current PDE is maximized +X https://github.com/processing/processing/pull/2037 +X incorporate the new serial library +X https://github.com/processing/processing/pull/2093 _ fix console font on Windows and Linux with 7u40 _ the message area text also looks ugly.. can we fix? From 607ecc6f9a75a023030d1adb5df088b788c730b7 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Wed, 25 Sep 2013 21:20:04 -0400 Subject: [PATCH 085/556] misc notes --- core/todo.txt | 4 ++-- todo.txt | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/todo.txt b/core/todo.txt index 6080b199b..774f81dec 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -3,6 +3,8 @@ X background color for present mode has no effect X https://github.com/processing/processing/issues/2071 X https://github.com/processing/processing/pull/2072 X add desktopPath() and desktopFile() methods for testing +X screen stops updating sometimes with retina +X https://github.com/processing/processing/issues/1699 _ Sort out blending differences with P2D/P3D _ https://github.com/processing/processing/issues/1844 @@ -22,8 +24,6 @@ _ test PGraphicsRetina2D w/ 7u40 _ make sure that 7u40 doesn't reintroduce starvation issue on retina Macs _ draw() called again before finishing on OS X (retina issue) _ https://github.com/processing/processing/issues/1709 -_ screen stops updating sometimes with retina -_ https://github.com/processing/processing/issues/1699 _ Linux sometimes not responding correctly w/ the size() command _ https://github.com/processing/processing/issues/1672 _ clean up requestFocus() stuff diff --git a/todo.txt b/todo.txt index c4a319016..7ea331d95 100644 --- a/todo.txt +++ b/todo.txt @@ -12,6 +12,12 @@ X https://github.com/processing/processing/pull/2037 X incorporate the new serial library X https://github.com/processing/processing/pull/2093 +add appbundler.jar, otherwise folks have to include Xcode +if they want to build appbundler, they'll need Xcode + and the command line tools, from Preferences > Downloads > Command Line Tools +appbundler will have an NPE if the osx binary isn't built +also need to have 10.8 version of the SDK (old Xcode won't work) + _ fix console font on Windows and Linux with 7u40 _ the message area text also looks ugly.. can we fix? From 08e93b02d34c9aab106a34185f46319e7e1f344d Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 28 Sep 2013 12:51:41 -0400 Subject: [PATCH 086/556] deal with cmd-left popup issue (#2103), formatting and notes --- app/src/processing/app/EditorState.java | 11 +++++--- .../processing/app/syntax/JEditTextArea.java | 25 +++++++++++-------- core/todo.txt | 5 ++++ todo.txt | 2 ++ 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/app/src/processing/app/EditorState.java b/app/src/processing/app/EditorState.java index ffd43584f..f8cc950c2 100644 --- a/app/src/processing/app/EditorState.java +++ b/app/src/processing/app/EditorState.java @@ -21,6 +21,7 @@ package processing.app; +import java.awt.Frame; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; @@ -174,7 +175,7 @@ public class EditorState { synchronized (editors) { final int OVER = 50; Editor lastOpened = editors.get(editors.size() - 1); - isMaximized = (lastOpened.getExtendedState() == Editor.MAXIMIZED_BOTH); + isMaximized = (lastOpened.getExtendedState() == Frame.MAXIMIZED_BOTH); editorBounds = lastOpened.getBounds(); editorBounds.x += OVER; editorBounds.y += OVER; @@ -182,8 +183,10 @@ public class EditorState { if (!deviceBounds.contains(editorBounds)) { // Warp the next window to a randomish location on screen. - editorBounds.x = deviceBounds.x + (int) (Math.random() * (deviceBounds.width - defaultWidth)); - editorBounds.y = deviceBounds.y + (int) (Math.random() * (deviceBounds.height - defaultHeight)); + editorBounds.x = deviceBounds.x + + (int) (Math.random() * (deviceBounds.width - defaultWidth)); + editorBounds.y = deviceBounds.y + + (int) (Math.random() * (deviceBounds.height - defaultHeight)); } if (isMaximized) { editorBounds.width = defaultWidth; @@ -211,7 +214,7 @@ public class EditorState { editor.setDividerLocation(dividerLocation); } if (isMaximized) { - editor.setExtendedState(Editor.MAXIMIZED_BOTH); + editor.setExtendedState(Frame.MAXIMIZED_BOTH); } } diff --git a/app/src/processing/app/syntax/JEditTextArea.java b/app/src/processing/app/syntax/JEditTextArea.java index 89b77502f..9a36a882e 100644 --- a/app/src/processing/app/syntax/JEditTextArea.java +++ b/app/src/processing/app/syntax/JEditTextArea.java @@ -2403,19 +2403,22 @@ public class JEditTextArea extends JComponent // the problem, though it's not clear why the wrong Document data was // being using regardless of the focusedComponent. // if (focusedComponent != JEditTextArea.this) return; - if (!hasFocus()) { + if (!hasFocus()) { // System.out.println("requesting focus in window"); - requestFocusInWindow(); - return; - } + requestFocusInWindow(); + return; + } - // isPopupTrigger wasn't working for danh on windows - boolean trigger = (evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0; - // but it's required for macosx, since control-click does - // the same thing as a right-mouse click - if (!trigger && evt.isPopupTrigger()) trigger = true; - - if (trigger && (popup != null)) { + // Disabling this block since it was a workaround for old buggy Java, + // and is now causing problems b/c cmd-click was opening popups on OS X. + // https://github.com/processing/processing/issues/2103 +// // isPopupTrigger wasn't working for danh on windows +// boolean trigger = (evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0; +// // but it's required for macosx, since control-click does +// // the same thing as a right-mouse click +// if (!trigger && evt.isPopupTrigger()) trigger = true; +// if (trigger && (popup != null)) { + if (evt.isPopupTrigger() && (popup != null)) { popup.show(painter,evt.getX(),evt.getY()); return; } diff --git a/core/todo.txt b/core/todo.txt index 774f81dec..a13ccb15e 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -6,6 +6,11 @@ X add desktopPath() and desktopFile() methods for testing X screen stops updating sometimes with retina X https://github.com/processing/processing/issues/1699 +_ Unicode NLF causing problems in XML files +_ not handled by BufferedReader (or XML parser) +_ http://stackoverflow.com/questions/10556875/list-of-unicode-characters-that-should-be-filtered-in-output +_ http://stackoverflow.com/questions/3072152/what-is-unicode-character-2028-ls-line-separator-used-for + _ Sort out blending differences with P2D/P3D _ https://github.com/processing/processing/issues/1844 _ 'collector' class.. Dict that points to a list diff --git a/todo.txt b/todo.txt index 7ea331d95..d41afc57f 100644 --- a/todo.txt +++ b/todo.txt @@ -11,6 +11,8 @@ X Open new PDE maximized when current PDE is maximized X https://github.com/processing/processing/pull/2037 X incorporate the new serial library X https://github.com/processing/processing/pull/2093 +X cmd-left is bringing up the text area popup +X https://github.com/processing/processing/issues/2103 add appbundler.jar, otherwise folks have to include Xcode if they want to build appbundler, they'll need Xcode From 9b2d4bcb111f67df7a4ae7ca3d223fa1c3daf5fc Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 28 Sep 2013 15:53:46 -0400 Subject: [PATCH 087/556] workaround for unicode issues with NLF in XML files (#2100) --- core/src/processing/core/PApplet.java | 1 + core/src/processing/data/XML.java | 63 +++++++++++++++++++-------- core/todo.txt | 1 + todo.txt | 13 ++++-- 4 files changed, 56 insertions(+), 22 deletions(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 023917444..71c85020b 100755 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -6104,6 +6104,7 @@ public class PApplet extends Applet public XML loadXML(String filename, String options) { try { return new XML(createReader(filename), options); +// return new XML(createInput(filename), options); } catch (Exception e) { e.printStackTrace(); return null; diff --git a/core/src/processing/data/XML.java b/core/src/processing/data/XML.java index 28023b768..5860eafc2 100644 --- a/core/src/processing/data/XML.java +++ b/core/src/processing/data/XML.java @@ -82,7 +82,9 @@ public class XML implements Serializable { /** - * Advanced users only; see loadXML() in PApplet. + * Advanced users only; use loadXML() in PApplet. This is not a supported + * function and is subject to change. It is available simply for users that + * would like to handle the exceptions in a particular way. * * @nowebref */ @@ -92,7 +94,7 @@ public class XML implements Serializable { /** - * Advanced users only; see loadXML() in PApplet. + * Advanced users only; use loadXML() in PApplet. * * @nowebref */ @@ -109,19 +111,31 @@ public class XML implements Serializable { /** - * Shouldn't be part of main p5 reference, this is for advanced users. - * Note that while it doesn't accept anything but UTF-8, this is preserved - * so that we have some chance of implementing that in the future. + * Unlike the loadXML() method in PApplet, this version works with files + * that are not in UTF-8 format. * * @nowebref */ public XML(InputStream input, String options) throws IOException, ParserConfigurationException, SAXException { - this(PApplet.createReader(input), options); + //this(PApplet.createReader(input), options); // won't handle non-UTF8 + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + try { + // Prevent 503 errors from www.w3.org + factory.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + } catch (IllegalArgumentException e) { + // ignore this; Android doesn't like it + } + + factory.setExpandEntityReferences(false); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(new InputSource(input)); + node = document.getDocumentElement(); } /** - * Advanced users only; see loadXML() in PApplet. + * Advanced users only; use loadXML() in PApplet. * * @nowebref */ @@ -131,11 +145,17 @@ public class XML implements Serializable { /** - * Advanced users only; see loadXML() in PApplet. + * Advanced users only; use loadXML() in PApplet. + * + * Added extra code to handle \u2028 (Unicode NLF), which is sometimes + * inserted by web browsers (Safari?) and not distinguishable from a "real" + * LF (or CRLF) in some text editors (i.e. TextEdit on OS X). Only doing + * this for XML (and not all Reader objects) because LFs are essential. + * https://github.com/processing/processing/issues/2100 * * @nowebref */ - public XML(Reader reader, String options) throws IOException, ParserConfigurationException, SAXException { + public XML(final Reader reader, String options) throws IOException, ParserConfigurationException, SAXException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // Prevent 503 errors from www.w3.org @@ -164,17 +184,24 @@ public class XML implements Serializable { // builder = new SAXBuilder(); // builder.setValidation(validating); -// print(dataPath("1broke.html"), System.out); + Document document = builder.parse(new InputSource(new Reader() { + @Override + public int read(char[] cbuf, int off, int len) throws IOException { + int count = reader.read(cbuf, off, len); + for (int i = 0; i < count; i++) { + if (cbuf[off+i] == '\u2028') { + cbuf[off+i] = '\n'; + } + } + return count; + } -// Document document = builder.parse(dataPath("1_alt.html")); - Document document = builder.parse(new InputSource(reader)); + @Override + public void close() throws IOException { + reader.close(); + } + })); node = document.getDocumentElement(); -// name = node.getNodeName(); - -// NodeList nodeList = document.getDocumentElement().getChildNodes(); -// for (int i = 0; i < nodeList.getLength(); i++) { -// } -// print(createWriter("data/1_alt_reparse.html"), document.getDocumentElement(), 0); } diff --git a/core/todo.txt b/core/todo.txt index a13ccb15e..f5891d7f2 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -7,6 +7,7 @@ X screen stops updating sometimes with retina X https://github.com/processing/processing/issues/1699 _ Unicode NLF causing problems in XML files +_ https://github.com/processing/processing/issues/2100 _ not handled by BufferedReader (or XML parser) _ http://stackoverflow.com/questions/10556875/list-of-unicode-characters-that-should-be-filtered-in-output _ http://stackoverflow.com/questions/3072152/what-is-unicode-character-2028-ls-line-separator-used-for diff --git a/todo.txt b/todo.txt index d41afc57f..b5b17f66d 100644 --- a/todo.txt +++ b/todo.txt @@ -22,6 +22,13 @@ also need to have 10.8 version of the SDK (old Xcode won't work) _ fix console font on Windows and Linux with 7u40 _ the message area text also looks ugly.. can we fix? +_ add pref to select PDE font (so that CJKV languages work better) +_ https://github.com/processing/processing/issues/2078 +_ should we embed the PDE font into the JRE? +_ this would allow it to show up in the menus, etc +_ but might be a problem on Linux +_ where the JRE is often replaced +_ and where the font is needed most build X remove video library for other platforms in download @@ -93,8 +100,6 @@ _ "String index out of range" error _ https://github.com/processing/processing/issues/1940 _ freeze after splash screen on OS X (looks like core.jar in the path) _ https://github.com/processing/processing/issues/1872 -_ add pref to select PDE font (so that CJKV languages work better) -_ https://github.com/processing/processing/issues/2078 medium _ use platformDelete() to remove untitled sketches? @@ -511,6 +516,8 @@ _ mark examples as untitled (rather than read-only) _ maybe even pull these directly from the zip file? _ load examples from zip files _ http://code.google.com/p/processing/issues/detail?id=143 +_ don't make examples read-only +_ just do them from psk files _ disallow add file to sketch, export, export application _ pretty much anything inside the sketch? _ but don't do this with untitled, cuz it kinda stinks @@ -519,8 +526,6 @@ _ mark example files as untitled _ though will that require the sketch to be saved before export? _ examples window sketches should load in proper environment _ write build.xml file to automatically update the examples -_ don't make examples read-only -_ just do them from psk files _ sketch.isReadOnly returns false for examples coming from multiple modes _ http://code.google.com/p/processing/issues/detail?id=734 _ see how library installation goes, then possibly do same w/ examples From fa3a5d9fb6cb494c27c3097fba8617ea80eb5bdc Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 29 Sep 2013 10:10:13 -0400 Subject: [PATCH 088/556] update javadoc and fix generation to link out --- build/build.xml | 9 +- build/javadoc/everything/package-list | 4 +- build/javadoc/stylesheet.css | 187 -------------------------- core/todo.txt | 11 +- todo.txt | 3 + 5 files changed, 17 insertions(+), 197 deletions(-) delete mode 100644 build/javadoc/stylesheet.css diff --git a/build/build.xml b/build/build.xml index 936380e63..35a950f38 100755 --- a/build/build.xml +++ b/build/build.xml @@ -1022,6 +1022,11 @@ + + + + @@ -1042,9 +1047,11 @@ - + + + diff --git a/build/javadoc/everything/package-list b/build/javadoc/everything/package-list index 324f2b779..cd4505a9e 100644 --- a/build/javadoc/everything/package-list +++ b/build/javadoc/everything/package-list @@ -3,12 +3,10 @@ japplemenubar processing.app processing.app.contrib processing.app.exec -processing.app.linux -processing.app.macosx +processing.app.platform processing.app.syntax processing.app.syntax.im processing.app.tools -processing.app.windows processing.core processing.data processing.event diff --git a/build/javadoc/stylesheet.css b/build/javadoc/stylesheet.css deleted file mode 100644 index 88654c77d..000000000 --- a/build/javadoc/stylesheet.css +++ /dev/null @@ -1,187 +0,0 @@ -/* Javadoc style sheet */ - -/* Define colors, fonts and other style attributes here to override the defaults */ - -/* Page background color */ -body { background-color: #FFFFFF } - -/* Headings */ -h1 { font-size: 120% } - - -/* Table colors */ -.TableHeadingColor { background: #CCCCCC } /* Dark mauve */ -.TableSubHeadingColor { background: #EEEEEE } /* Light mauve */ -.TableRowColor { background: #FFFFFF } /* White */ - -/* - * /* Font used in left-hand frame lists */ - * .FrameTitleFont { font-size: 90%; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif } - * .FrameHeadingFont { font-size: 90%; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif } - * .FrameItemFont { font-size: 90%; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif } - */ - -/* Navigation bar fonts and colors */ -.NavBarCell1 { background-color:#EEEEEE;} /* Light mauve */ -.NavBarCell1Rev { background-color:#00008B;} /* Dark Blue */ - -.NavBarFont1 { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; color:#000000;} -.NavBarFont1Rev { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; color:#FFFFFF;} - -.NavBarCell2 { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color:#FFFFFF;} -.NavBarCell3 { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color:#FFFFFF;} - - - -/* - * Processing - Styling - * - * fjenett - mail@florianjenett.de - 2005.08.14 - * Updated by REAS 2011.09.02 - * - */ - - -/* first let's restyle what's there .. */ - -/* Table colors */ -.TableHeadingColor { - background: #CCCCCC; - color: #5A5A5A; - } -.TableSubHeadingColor { background: #EEEEEE } /* Gray */ -.TableRowColor { background: #FFFFFF } /* White */ - - -/* Font used in left-hand frame lists */ -.FrameTitleFont { - font-size: 1.0em; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif -} -.FrameHeadingFont { - font-size: 1.0em; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - color: #5A5A5A; -} -.FrameItemFont { - font-size: 1.0em; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif -} - - -/* Navigation bar fonts and colors */ -.NavBarCell1 { background-color:#CCCCCC;} /* Light */ -.NavBarCell1Rev { background-color:#5A5A5A;} /* Dark */ - -.NavBarFont1 { - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - color:#5A5A5A; -} -.NavBarFont1Rev { - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - color:#FFFFFF; -} - -.NavBarCell2 { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color:#FFFFFF;} -.NavBarCell3 { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; background-color:#FFFFFF;} - - -/* try to style some more ... */ - -body, -html -{ - font-size: small; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - color: #333333; -} - -h1, h2, h3, h4, h5, h6 { - - color: #5A5A5A; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-weight: normal; - line-height: normal; -} - -h1, h2, h3, h4 { - word-spacing: 0.2em; - font-weight: bold; -} - -h4, h5, h6 { - font-weight: bold; -} -/* Font Sizes */ -h1 { font-size: 1.5em; } -h2 { font-size: 1.4em; } -h3 { font-size: 1.3em; } -h4 { font-size: 1.2em; } -h5 { font-size: 1.1em; } -h6 { font-size: 1em; } -p { font-size: 1em; } - -dl, dd, dt, -dt > b -{ - color: #666666; - font-size: 1.0em; -} - -code, -pre -{ - font-size: 1.2em; - color:#333333; -} - -pre -{ - font-size: 1.2em; -} - - -/* force the table-headers small .. */ -b -{ - font-size: small; -} - - -tr, -td -{ - border-top: 0px solid; - border-left: 0px solid; - border-color: #999999; -} - -table -{ - border: 0px; -} - -img -{ - border: 0px solid #000000; -} - -a { - text-decoration: underline; - font-weight: normal; - color: #3399CC; -} - -a:hover -a:active { - text-decoration: underline; - font-weight: normal; - color: #3399CC; -} - -a:visited, -a:link:visited { - text-decoration: underline; - font-weight: normal; - color: #3399CC; -} \ No newline at end of file diff --git a/core/todo.txt b/core/todo.txt index f5891d7f2..187a6ccc1 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -5,12 +5,11 @@ X https://github.com/processing/processing/pull/2072 X add desktopPath() and desktopFile() methods for testing X screen stops updating sometimes with retina X https://github.com/processing/processing/issues/1699 - -_ Unicode NLF causing problems in XML files -_ https://github.com/processing/processing/issues/2100 -_ not handled by BufferedReader (or XML parser) -_ http://stackoverflow.com/questions/10556875/list-of-unicode-characters-that-should-be-filtered-in-output -_ http://stackoverflow.com/questions/3072152/what-is-unicode-character-2028-ls-line-separator-used-for +X Unicode NLF causing problems in XML files +X https://github.com/processing/processing/issues/2100 +X not handled by BufferedReader (or XML parser) +X http://stackoverflow.com/questions/10556875/list-of-unicode-characters-that-should-be-filtered-in-output +X http://stackoverflow.com/questions/3072152/what-is-unicode-character-2028-ls-line-separator-used-for _ Sort out blending differences with P2D/P3D _ https://github.com/processing/processing/issues/1844 diff --git a/todo.txt b/todo.txt index b5b17f66d..dc2fd832a 100644 --- a/todo.txt +++ b/todo.txt @@ -52,6 +52,9 @@ X add MinimumSystemVersion for 10.7.3 X https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/20001431-113253 X copy GenericDocumentIcon.icns for placeholder icon X from /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ +X the javadoc includes java.io.* and java.lang.* prefixes.. why? +X re-run and and check in +X upload javadoc updates _ remove JAVA_HOME requirement from build.xml _ what's needed on OS X? just the JDK 7u40? From b41033e88eafcfc1a5c0bfb4c20ca83253ea23e0 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 1 Oct 2013 18:24:57 -0400 Subject: [PATCH 089/556] check in appbundler to fix build issues --- build/macosx/.gitignore | 1 - todo.txt | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 build/macosx/.gitignore diff --git a/build/macosx/.gitignore b/build/macosx/.gitignore deleted file mode 100644 index 773ff5149..000000000 --- a/build/macosx/.gitignore +++ /dev/null @@ -1 +0,0 @@ -appbundler.jar \ No newline at end of file diff --git a/todo.txt b/todo.txt index dc2fd832a..6ee6d3ce0 100644 --- a/todo.txt +++ b/todo.txt @@ -72,6 +72,8 @@ X make OS X launch from its local JRE _ change how export is handled _ remove ability to export cross-platform apps _ add ability to embed the current JRE +_ the case for the embedded JRE +_ https://github.com/processing/processing/issues/2104 _ change Windows export to use launch4j instead of the launcher.cpp file _ actually call ant from inside p5? _ change app stub in OS X exported application From 506aeebc6cc4abdcfc5734bd7dd23983674fa0ee Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 1 Oct 2013 18:36:47 -0400 Subject: [PATCH 091/556] trying again with JDK 7u40 requirement on OS X --- build/build.xml | 12 +++++++++--- todo.txt | 15 ++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/build/build.xml b/build/build.xml index 35a950f38..90243d41d 100755 --- a/build/build.xml +++ b/build/build.xml @@ -140,9 +140,12 @@ + + + + - - + + + + + + + + + + + + From ba4f204c254adb2098f9e54d5f59e264a49b8643 Mon Sep 17 00:00:00 2001 From: gohai Date: Tue, 1 Oct 2013 21:27:27 -0700 Subject: [PATCH 094/556] Remove commented out lines --- java/libraries/serial/src/processing/serial/Serial.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/java/libraries/serial/src/processing/serial/Serial.java b/java/libraries/serial/src/processing/serial/Serial.java index 8265dffdd..130fc3129 100644 --- a/java/libraries/serial/src/processing/serial/Serial.java +++ b/java/libraries/serial/src/processing/serial/Serial.java @@ -186,8 +186,6 @@ public class Serial implements SerialPortEventListener { public static Map getProperties(String portName) { - //SerialPortList list = new SerialPortList(); - //return list.getPortProperties(portName); return SerialPortList.getPortProperties(portName); } @@ -214,8 +212,6 @@ public class Serial implements SerialPortEventListener { public static String[] list() { // returns list sorted alphabetically, thus cu.* comes before tty.* // this was different with RXTX - //SerialPortList list = new SerialPortList(); - //return list.getPortNames(); return SerialPortList.getPortNames(); } @@ -457,4 +453,4 @@ public class Serial implements SerialPortEventListener { throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType()); } } -} \ No newline at end of file +} From 7c2f50ef8af519ab79db8cfb685d3204b2b5eb73 Mon Sep 17 00:00:00 2001 From: gohai Date: Tue, 1 Oct 2013 21:27:48 -0700 Subject: [PATCH 095/556] Remove obsolete .cvsignore file --- java/libraries/serial/library/.cvsignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 java/libraries/serial/library/.cvsignore diff --git a/java/libraries/serial/library/.cvsignore b/java/libraries/serial/library/.cvsignore deleted file mode 100644 index 718e029bc..000000000 --- a/java/libraries/serial/library/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -serial.jar From 3b8ed3db5550ea2ac0474bcb9d1fd41b4eb4fc9a Mon Sep 17 00:00:00 2001 From: gohai Date: Tue, 1 Oct 2013 21:29:15 -0700 Subject: [PATCH 096/556] Document how to compile the native JSSC library --- java/libraries/serial/library/jssc.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/libraries/serial/library/jssc.txt b/java/libraries/serial/library/jssc.txt index cf2f974ac..7174ece29 100644 --- a/java/libraries/serial/library/jssc.txt +++ b/java/libraries/serial/library/jssc.txt @@ -1 +1,4 @@ This is using a modified version of Java Simple Serial Connector by Alexey Sokolov. See https://github.com/gohai/java-simple-serial-connector for details on the modifications. + +To compile the C++ portion of the library on OS X: +g++ -shared [or: -dynamiclib?] -arch i386 -arch x86_64 -I/System/Library/Frameworks/IOKit.framework/Versions/A/Headers -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin -framework IOKit -framework CoreFoundation -o libjSSC-2.6.jnilib jssc.cpp From 22e55751b0444e44afe3fe21f3363f1447ea00ae Mon Sep 17 00:00:00 2001 From: gohai Date: Tue, 1 Oct 2013 21:30:09 -0700 Subject: [PATCH 097/556] Add JSSC to Javadoc build --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index 572fdc06a..54a738a77 100755 --- a/build/build.xml +++ b/build/build.xml @@ -1066,7 +1066,7 @@ - + From 06fe38f218cfd4c4fb62438c8036fb9e10c2b1c6 Mon Sep 17 00:00:00 2001 From: gohai Date: Tue, 1 Oct 2013 22:13:39 -0700 Subject: [PATCH 098/556] Add support for custom source regions in imageImpl As suggested by Ben --- java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java b/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java index 45b020710..762a78db7 100644 --- a/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java +++ b/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java @@ -413,7 +413,13 @@ public class PGraphicsPDF extends PGraphicsJava2D { int imageHeight = image.height; scale((x2 - x1) / (float)imageWidth, (y2 - y1) / (float)imageHeight); - g2.drawImage(image.getImage(), u1, v1, null); + if (u2-u1 != imageWidth || v2-v1 != imageHeight) { + PImage tmp = new PImage(u2-u1, v2-v1, ARGB); + tmp.copy(image, u1, v1, u2, v2, 0, 0, u2-u1, v2-v1); + g2.drawImage(image.getImage(), 0, 0, null); + } else { + g2.drawImage(image.getImage(), u1, v1, null); + } popMatrix(); } From ee891808e7b49c3d35db128ad783f55dc6d60992 Mon Sep 17 00:00:00 2001 From: gohai Date: Tue, 1 Oct 2013 22:22:05 -0700 Subject: [PATCH 099/556] Remove obsolete SerialFixer The SerialFixer removed stale lock files on OS X, which are no longer used by the new serial library (JSSC). --- app/src/processing/app/Editor.java | 3 - app/src/processing/app/tools/SerialFixer.java | 89 ------------------- 2 files changed, 92 deletions(-) delete mode 100644 app/src/processing/app/tools/SerialFixer.java diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index f0dfe17b2..a117489c9 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -1009,9 +1009,6 @@ public abstract class Editor extends JFrame implements RunnerListener { addToolMenuItem(menu, "processing.app.tools.Archiver"); if (Base.isMacOS()) { - if (SerialFixer.isNeeded()) { - addToolMenuItem(menu, "processing.app.tools.SerialFixer"); - } addToolMenuItem(menu, "processing.app.tools.InstallCommander"); } diff --git a/app/src/processing/app/tools/SerialFixer.java b/app/src/processing/app/tools/SerialFixer.java deleted file mode 100644 index 7065b53bc..000000000 --- a/app/src/processing/app/tools/SerialFixer.java +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2012 The Processing Foundation - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, version 2. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package processing.app.tools; - -import java.io.File; - -import javax.swing.JOptionPane; - -import processing.app.Base; -import processing.app.Editor; -import processing.core.PApplet; - - -public class SerialFixer implements Tool { - Editor editor; - - - public String getMenuTitle() { - return "Fix the Serial Library"; - } - - - public void init(Editor editor) { - this.editor = editor; - } - - - public void run() { - final String primary = - "Attempt to fix common serial port problems?"; - final String secondary = - "Click “OK” to perform additional installation steps to enable " + - "the Serial library. An administrator password will be required."; - - int result = - JOptionPane.showConfirmDialog(editor, - " " + - " " + - "" + primary + "" + - "

    " + secondary + "

    ", - "Commander", - JOptionPane.OK_CANCEL_OPTION, - JOptionPane.QUESTION_MESSAGE); - - if (result == JOptionPane.OK_OPTION) { - String shellScript = "mkdir -p /var/lock && chmod 777 /var/lock"; - String appleScript = - "do shell script \"" + shellScript + "\" with administrator privileges"; - PApplet.exec(new String[] { "osascript", "-e", appleScript }); - } - editor.statusNotice("Finished."); - } - - - static public boolean isNeeded() { - if (Base.isMacOS()) { - File lockFolder = new File("/var/lock"); - if (!lockFolder.exists() || - !lockFolder.canRead() || - !lockFolder.canWrite() || - !lockFolder.canExecute()) { - return true; - } - } - return false; - } -} \ No newline at end of file From 0388ebbe4a403f51e95c906cd15f5c498b8ddf2e Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 3 Oct 2013 13:51:56 -0400 Subject: [PATCH 100/556] takes care of #2102 by reverting setAmbient to false if it was false before calling popStyle() --- core/src/processing/opengl/PGraphicsOpenGL.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index ba671f35d..fe238db2e 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -4519,8 +4519,20 @@ public class PGraphicsOpenGL extends PGraphics { return nonZero(ow) ? oz / ow : oz; } + ////////////////////////////////////////////////////////////// + // STYLES + @Override + public void popStyle() { + // popStyle() sets ambient to true (because it calls ambient() in style()) + // and so setting the setAmbient flag to true, even if the user didn't call + // ambient, so need to revert to false. + boolean savedSetAmbient = setAmbient; + super.popStyle(); + if (!savedSetAmbient) setAmbient = false; + } + // public void pushStyle() // public void popStyle() // public void style(PStyle) From dbc9b78804e403a22437aeb686e214c370d6cf46 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 3 Oct 2013 15:02:05 -0400 Subject: [PATCH 101/556] slightly different ortho() setup in P2D allows for identity modelview --- core/src/processing/opengl/PGraphics2D.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/src/processing/opengl/PGraphics2D.java b/core/src/processing/opengl/PGraphics2D.java index 0f35b711c..9c1761cba 100644 --- a/core/src/processing/opengl/PGraphics2D.java +++ b/core/src/processing/opengl/PGraphics2D.java @@ -119,7 +119,7 @@ public class PGraphics2D extends PGraphicsOpenGL { @Override protected void defaultPerspective() { - super.ortho(0, width, 0, height, -1, +1); + super.ortho(width/2f, (3f/2f) * width, -height/2f, height/2f, -1, +1); } @@ -156,7 +156,7 @@ public class PGraphics2D extends PGraphicsOpenGL { @Override protected void defaultCamera() { - super.camera(width/2f, height/2f); + resetMatrix(); } @@ -180,6 +180,12 @@ public class PGraphics2D extends PGraphicsOpenGL { popProjection(); } +// @Override +// public void resetMatrix() { +// super.resetMatrix(); +// defaultCamera(); +// } + ////////////////////////////////////////////////////////////// From 994be867e9a2af5a795ad43c0b4e1ce6f1073950 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 3 Oct 2013 16:02:36 -0400 Subject: [PATCH 102/556] get gl objects also in init() and reshape() events --- core/src/processing/opengl/PJOGL.java | 42 +++++++++++++-------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index 59092b6a7..8e35baf5f 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -682,19 +682,7 @@ public class PJOGL extends PGL { @Override public void display(GLAutoDrawable glDrawable) { - drawable = glDrawable; - context = glDrawable.getContext(); - glContext = context.hashCode(); - - glThread = Thread.currentThread(); - - gl = context.getGL(); - gl2 = gl.getGL2ES2(); - try { - gl2x = gl.getGL2(); - } catch (javax.media.opengl.GLException e) { - gl2x = null; - } + getGL(glDrawable); if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { // The onscreen drawing surface is backed by an FBO layer. @@ -767,13 +755,10 @@ public class PJOGL extends PGL { } @Override - public void init(GLAutoDrawable adrawable) { - drawable = adrawable; - context = adrawable.getContext(); - glContext = context.hashCode(); - capabilities = adrawable.getChosenGLCapabilities(); - gl = context.getGL(); + public void init(GLAutoDrawable glDrawable) { + getGL(glDrawable); + capabilities = glDrawable.getChosenGLCapabilities(); if (!hasFBOs()) { throw new RuntimeException(MISSING_FBO_ERROR); } @@ -787,10 +772,23 @@ public class PJOGL extends PGL { } @Override - public void reshape(GLAutoDrawable adrawable, int x, int y, int w, int h) { - drawable = adrawable; - context = adrawable.getContext(); + public void reshape(GLAutoDrawable glDrawable, int x, int y, int w, int h) { + getGL(glDrawable); + } + + private void getGL(GLAutoDrawable glDrawable) { + drawable = glDrawable; + context = glDrawable.getContext(); glContext = context.hashCode(); + glThread = Thread.currentThread(); + + gl = context.getGL(); + gl2 = gl.getGL2ES2(); + try { + gl2x = gl.getGL2(); + } catch (javax.media.opengl.GLException e) { + gl2x = null; + } } } From 312fb9950880e92befb19649cb7a312fd6af258e Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 3 Oct 2013 17:03:14 -0400 Subject: [PATCH 103/556] sets the resized native font in PGraphicsOpenGL, fix #2109 --- core/src/processing/opengl/PGL.java | 5 +++++ core/src/processing/opengl/PGraphicsOpenGL.java | 13 +++++++++++++ core/src/processing/opengl/PJOGL.java | 6 ++++++ .../lwjgl/src/processing/lwjgl/PLWJGL.java | 6 ++++++ 4 files changed, 30 insertions(+) diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index 6bbab3c9b..aad1a8aaf 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -1900,6 +1900,11 @@ public abstract class PGL { } + protected Object getDerivedFont(Object font, float size) { + return null; + } + + /////////////////////////////////////////////////////////// // Tessellator interface diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index fe238db2e..c71b4cf7c 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -23,6 +23,7 @@ package processing.opengl; import processing.core.*; + import java.net.URL; import java.nio.*; import java.util.*; @@ -3281,6 +3282,18 @@ public class PGraphicsOpenGL extends PGraphics { } + @Override + public void textSize(float size) { + if (textFont == null) defaultFontOrDeath("textSize", size); + Object font = textFont.getNative(); + if (font != null) { + Object dfont = pgl.getDerivedFont(font, size); + textFont.setNative(dfont); + } + super.textSize(size); + } + + /** * Implementation of actual drawing for a line of text. */ diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index 8e35baf5f..f70587ad6 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -968,6 +968,12 @@ public class PJOGL extends PGL { } + @Override + protected Object getDerivedFont(Object font, float size) { + return ((Font)font).deriveFont(size); + } + + /////////////////////////////////////////////////////////// // Tessellator diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java index 7b8c223be..f06b24a90 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java @@ -354,6 +354,12 @@ public class PLWJGL extends PGL { FontMetrics metrics = pg.parent.getFontMetrics((Font)font); return metrics.charsWidth(buffer, start, length); } + + + @Override + protected Object getDerivedFont(Object font, float size) { + return ((Font)font).deriveFont(size); + } /////////////////////////////////////////////////////////// From eb72df73408cd0fed31b0251ccaf9cbf65147bd7 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 3 Oct 2013 18:23:04 -0400 Subject: [PATCH 104/556] correctly implements SUBTRACT blend mode --- core/src/processing/opengl/PGraphicsOpenGL.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index c71b4cf7c..6ad53ce7b 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -5690,9 +5690,11 @@ public class PGraphicsOpenGL extends PGraphics { } else if (blendMode == SUBTRACT) { if (blendEqSupported) { - pgl.blendEquation(PGL.FUNC_ADD); + pgl.blendEquation(PGL.FUNC_REVERSE_SUBTRACT); + pgl.blendFunc(PGL.ONE, PGL.SRC_ALPHA); + } else { + PGraphics.showWarning(BLEND_DRIVER_ERROR, "SUBTRACT"); } - pgl.blendFunc(PGL.ONE_MINUS_DST_COLOR, PGL.ZERO); } else if (blendMode == LIGHTEST) { if (blendEqSupported) { @@ -5712,11 +5714,9 @@ public class PGraphicsOpenGL extends PGraphics { } else if (blendMode == DIFFERENCE) { if (blendEqSupported) { - pgl.blendEquation(PGL.FUNC_REVERSE_SUBTRACT); - pgl.blendFunc(PGL.ONE, PGL.ONE); - } else { - PGraphics.showWarning(BLEND_DRIVER_ERROR, "DIFFERENCE"); + pgl.blendEquation(PGL.FUNC_ADD); } + pgl.blendFunc(PGL.ONE_MINUS_DST_COLOR, PGL.ZERO); } else if (blendMode == EXCLUSION) { if (blendEqSupported) { From 8a60de14d3d65deecc7e6bbc3b2ebfe11d4192fe Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 4 Oct 2013 00:21:01 -0400 Subject: [PATCH 105/556] some simplifications to the shader code --- .../processing/opengl/PGraphicsOpenGL.java | 545 +++++++++++++----- core/src/processing/opengl/PShader.java | 13 +- 2 files changed, 421 insertions(+), 137 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 6ad53ce7b..ccaa95534 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -230,31 +230,38 @@ public class PGraphicsOpenGL extends PGraphics { static protected URL defPointShaderFragURL = PGraphicsOpenGL.class.getResource("PointFrag.glsl"); - static protected ColorShader defColorShader; - static protected TextureShader defTextureShader; - static protected LightShader defLightShader; - static protected TexlightShader defTexlightShader; +// static protected ColorShader defColorShader; +// static protected TextureShader defTextureShader; +// static protected LightShader defLightShader; +// static protected TexlightShader defTexlightShader; + static protected PolyShader defColorShader; + static protected PolyShader defTextureShader; + static protected PolyShader defLightShader; + static protected PolyShader defTexlightShader; static protected LineShader defLineShader; static protected PointShader defPointShader; static protected URL maskShaderFragURL = PGraphicsOpenGL.class.getResource("MaskFrag.glsl"); - static protected TextureShader maskShader; +// static protected TextureShader maskShader; + static protected PolyShader maskShader; - protected ColorShader colorShader; - protected TextureShader textureShader; - protected LightShader lightShader; - protected TexlightShader texlightShader; +// protected ColorShader colorShader; +// protected TextureShader textureShader; +// protected LightShader lightShader; +// protected TexlightShader texlightShader; + protected PolyShader polyShader; protected LineShader lineShader; protected PointShader pointShader; + // When shader warnings are enabled, the renderer is strict in regards to the // use of the polygon shaders. For instance, if a light shader is set to // render lit geometry, but the geometry is mixed with some pieces of unlit or // textured geometry, then it will warn that the set shader cannot be used for // that other type of geometry, even though Processing will use the correct, // built-in shaders to handle it. - protected boolean shaderWarningsEnabled = true; +// protected boolean shaderWarningsEnabled = true; // ........................................................ @@ -5485,8 +5492,10 @@ public class PGraphicsOpenGL extends PGraphics { } if (maskShader == null) { - maskShader = new TextureShader(parent, defTextureShaderVertURL, - maskShaderFragURL); +// maskShader = new TextureShader(parent, defTextureShaderVertURL, +// maskShaderFragURL); + maskShader = new PolyShader(parent, defTextureShaderVertURL, + maskShaderFragURL); } maskShader.set("mask", alpha); filter(maskShader); @@ -5527,7 +5536,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void filter(PShader shader) { - if (!(shader instanceof TextureShader)) { + if (!(shader instanceof PolyShader) || !((PolyShader)shader).hasTexture()) { PGraphics.showWarning(INVALID_FILTER_SHADER_ERROR); return; } @@ -5569,8 +5578,11 @@ public class PGraphicsOpenGL extends PGraphics { stroke = false; int prevBlendMode = blendMode; blendMode(REPLACE); - TextureShader prevTexShader = textureShader; - textureShader = (TextureShader) shader; +// TextureShader prevTexShader = textureShader; +// textureShader = (TextureShader) shader; + PolyShader prevShader = polyShader; + polyShader = (PolyShader)shader; + beginShape(QUADS); texture(filterImage); @@ -5582,7 +5594,7 @@ public class PGraphicsOpenGL extends PGraphics { end2D(); // Restoring previous configuration. - textureShader = prevTexShader; + polyShader = prevShader; stroke = prevStroke; lights = prevLights; textureMode = prevTextureMode; @@ -6273,7 +6285,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public PShader loadShader(String fragFilename) { int shaderType = getShaderType(fragFilename); - if (shaderType == -1) shaderType = PShader.COLOR; + //if (shaderType == -1) shaderType = PShader.COLOR; PShader shader = null; if (shaderType == PShader.POINT) { shader = new PointShader(parent); @@ -6282,17 +6294,20 @@ public class PGraphicsOpenGL extends PGraphics { shader = new LineShader(parent); shader.setVertexShader(defLineShaderVertURL); } else if (shaderType == PShader.TEXLIGHT) { - shader = new TexlightShader(parent); + shader = new PolyShader(parent); shader.setVertexShader(defTexlightShaderVertURL); } else if (shaderType == PShader.LIGHT) { - shader = new LightShader(parent); + shader = new PolyShader(parent); shader.setVertexShader(defLightShaderVertURL); } else if (shaderType == PShader.TEXTURE) { - shader = new TextureShader(parent); + shader = new PolyShader(parent); shader.setVertexShader(defTextureShaderVertURL); } else if (shaderType == PShader.COLOR) { - shader = new ColorShader(parent); + shader = new PolyShader(parent); shader.setVertexShader(defColorShaderVertURL); + } else { + shader = new PolyShader(parent); + shader.setVertexShader(defTexlightShaderVertURL); } shader.setFragmentShader(fragFilename); return shader; @@ -6306,7 +6321,7 @@ public class PGraphicsOpenGL extends PGraphics { int shaderType = -1; if (vertType == -1 && fragType == -1) { - shaderType = PShader.COLOR; + shaderType = PShader.POLY; } else if (vertType == -1) { shaderType = fragType; } else if (fragType == -1) { @@ -6327,17 +6342,20 @@ public class PGraphicsOpenGL extends PGraphics { shader = new LineShader(parent); shader.setFragmentShader(defLineShaderFragURL); } else if (shaderType == PShader.TEXLIGHT) { - shader = new TexlightShader(parent); + shader = new PolyShader(parent); shader.setFragmentShader(defTextureShaderFragURL); } else if (shaderType == PShader.LIGHT) { - shader = new LightShader(parent); + shader = new PolyShader(parent); shader.setFragmentShader(defColorShaderFragURL); } else if (shaderType == PShader.TEXTURE) { - shader = new TextureShader(parent); + shader = new PolyShader(parent); shader.setFragmentShader(defTextureShaderFragURL); } else if (shaderType == PShader.COLOR) { - shader = new ColorShader(parent); + shader = new PolyShader(parent); shader.setFragmentShader(defColorShaderFragURL); + } else { + shader = new PolyShader(parent); + shader.setVertexShader(defTexlightShaderVertURL); } if (shader != null) { shader.setVertexShader(vertFilename); @@ -6347,15 +6365,18 @@ public class PGraphicsOpenGL extends PGraphics { shader = new PointShader(parent, vertFilename, fragFilename); } else if (shaderType == PShader.LINE) { shader = new LineShader(parent, vertFilename, fragFilename); - } else if (shaderType == PShader.TEXLIGHT) { - shader = new TexlightShader(parent, vertFilename, fragFilename); - } else if (shaderType == PShader.LIGHT) { - shader = new LightShader(parent, vertFilename, fragFilename); - } else if (shaderType == PShader.TEXTURE) { - shader = new TextureShader(parent, vertFilename, fragFilename); - } else if (shaderType == PShader.COLOR) { - shader = new ColorShader(parent, vertFilename, fragFilename); + } else { + shader = new PolyShader(parent, vertFilename, fragFilename); } +// if (shaderType == PShader.TEXLIGHT) { +// shader = new TexlightShader(parent, vertFilename, fragFilename); +// } else if (shaderType == PShader.LIGHT) { +// shader = new LightShader(parent, vertFilename, fragFilename); +// } else if (shaderType == PShader.TEXTURE) { +// shader = new TextureShader(parent, vertFilename, fragFilename); +// } else if (shaderType == PShader.COLOR) { +// shader = new ColorShader(parent, vertFilename, fragFilename); +// } } return shader; } @@ -6372,14 +6393,16 @@ public class PGraphicsOpenGL extends PGraphics { flush(); // Flushing geometry drawn with a different shader. if (kind == TRIANGLES || kind == QUADS || kind == POLYGON) { - if (shader instanceof TexlightShader) { - texlightShader = (TexlightShader) shader; - } else if (shader instanceof TextureShader) { - textureShader = (TextureShader) shader; - } else if (shader instanceof LightShader) { - lightShader = (LightShader) shader; - } else if (shader instanceof ColorShader) { - colorShader = (ColorShader) shader; + if (shader instanceof PolyShader) { + polyShader = (PolyShader) shader; +// if (shader instanceof TexlightShader) { +// texlightShader = (TexlightShader) shader; +// } else if (shader instanceof TextureShader) { +// textureShader = (TextureShader) shader; +// } else if (shader instanceof LightShader) { +// lightShader = (LightShader) shader; +// } else if (shader instanceof ColorShader) { +// colorShader = (ColorShader) shader; } else { PGraphics.showWarning(WRONG_SHADER_TYPE_ERROR); } @@ -6412,10 +6435,11 @@ public class PGraphicsOpenGL extends PGraphics { flush(); // Flushing geometry drawn with a different shader. if (kind == TRIANGLES || kind == QUADS || kind == POLYGON) { - textureShader = null; - colorShader = null; - texlightShader = null; - lightShader = null; +// textureShader = null; +// colorShader = null; +// texlightShader = null; +// lightShader = null; + polyShader = null; } else if (kind == LINES) { lineShader = null; } else if (kind == POINTS) { @@ -6426,14 +6450,14 @@ public class PGraphicsOpenGL extends PGraphics { } - public void shaderWarnings(boolean enable) { - shaderWarningsEnabled = enable; - } +// public void shaderWarnings(boolean enable) { +// shaderWarningsEnabled = enable; +// } protected int getShaderType(String filename) { String[] source = parent.loadStrings(filename); - int type = -1; + int type = PShader.POLY; for (int i = 0; i < source.length; i++) { String line = source[i].trim(); @@ -6449,6 +6473,12 @@ public class PGraphicsOpenGL extends PGraphics { type = PShader.TEXTURE; } else if (line.indexOf("#define PROCESSING_TEXLIGHT_SHADER") == 0) { type = PShader.TEXLIGHT; + } else if (line.indexOf("#define PROCESSING_POLYGON_SHADER") == 0) { + type = PShader.POLY; + } else if (line.indexOf("#define PROCESSING_TRIANGLES_SHADER") == 0) { + type = PShader.POLY; + } else if (line.indexOf("#define PROCESSING_QUADS_SHADER") == 0) { + type = PShader.POLY; } } return type; @@ -6469,58 +6499,58 @@ public class PGraphicsOpenGL extends PGraphics { } - protected BaseShader getPolyShader(boolean lit, boolean tex) { - BaseShader shader; + protected PolyShader getPolyShader(boolean lit, boolean tex) { + PolyShader shader; if (lit) { if (tex) { - if (texlightShader == null) { + if (polyShader == null) { if (defTexlightShader == null) { - defTexlightShader = new TexlightShader(parent, - defTexlightShaderVertURL, - defTextureShaderFragURL); + defTexlightShader = new PolyShader(parent, + defTexlightShaderVertURL, + defTextureShaderFragURL); } shader = defTexlightShader; - texlightShaderCheck(); +// texlightShaderCheck(); } else { - shader = texlightShader; + shader = polyShader; } } else { - if (lightShader == null) { + if (polyShader == null) { if (defLightShader == null) { - defLightShader = new LightShader(parent, - defLightShaderVertURL, - defColorShaderFragURL); + defLightShader = new PolyShader(parent, + defLightShaderVertURL, + defColorShaderFragURL); } shader = defLightShader; - lightShaderCheck(); +// lightShaderCheck(); } else { - shader = lightShader; + shader = polyShader; } } } else { if (tex) { - if (textureShader == null) { + if (polyShader == null) { if (defTextureShader == null) { - defTextureShader = new TextureShader(parent, - defTextureShaderVertURL, - defTextureShaderFragURL); + defTextureShader = new PolyShader(parent, + defTextureShaderVertURL, + defTextureShaderFragURL); } shader = defTextureShader; - textureShaderCheck(); +// textureShaderCheck(); } else { - shader = textureShader; + shader = polyShader; } } else { - if (colorShader == null) { + if (polyShader == null) { if (defColorShader == null) { - defColorShader = new ColorShader(parent, - defColorShaderVertURL, - defColorShaderFragURL); + defColorShader = new PolyShader(parent, + defColorShaderVertURL, + defColorShaderFragURL); } shader = defColorShader; - colorShaderCheck(); +// colorShaderCheck(); } else { - shader = colorShader; + shader = polyShader; } } } @@ -6531,44 +6561,44 @@ public class PGraphicsOpenGL extends PGraphics { } - protected void texlightShaderCheck() { - if (shaderWarningsEnabled && - (lightShader != null || - textureShader != null || - colorShader != null)) { - PGraphics.showWarning(NO_TEXLIGHT_SHADER_ERROR); - } - } - - - protected void lightShaderCheck() { - if (shaderWarningsEnabled && - (texlightShader != null || - textureShader != null || - colorShader != null)) { - PGraphics.showWarning(NO_LIGHT_SHADER_ERROR); - } - } - - - protected void textureShaderCheck() { - if (shaderWarningsEnabled && - (texlightShader != null || - lightShader != null || - colorShader != null)) { - PGraphics.showWarning(NO_TEXTURE_SHADER_ERROR); - } - } - - - protected void colorShaderCheck() { - if (shaderWarningsEnabled && - (texlightShader != null || - lightShader != null || - textureShader != null)) { - PGraphics.showWarning(NO_COLOR_SHADER_ERROR); - } - } +// protected void texlightShaderCheck() { +// if (shaderWarningsEnabled && +// (lightShader != null || +// textureShader != null || +// colorShader != null)) { +// PGraphics.showWarning(NO_TEXLIGHT_SHADER_ERROR); +// } +// } +// +// +// protected void lightShaderCheck() { +// if (shaderWarningsEnabled && +// (texlightShader != null || +// textureShader != null || +// colorShader != null)) { +// PGraphics.showWarning(NO_LIGHT_SHADER_ERROR); +// } +// } +// +// +// protected void textureShaderCheck() { +// if (shaderWarningsEnabled && +// (texlightShader != null || +// lightShader != null || +// colorShader != null)) { +// PGraphics.showWarning(NO_TEXTURE_SHADER_ERROR); +// } +// } +// +// +// protected void colorShaderCheck() { +// if (shaderWarningsEnabled && +// (texlightShader != null || +// lightShader != null || +// textureShader != null)) { +// PGraphics.showWarning(NO_COLOR_SHADER_ERROR); +// } +// } protected LineShader getLineShader() { @@ -6608,9 +6638,9 @@ public class PGraphicsOpenGL extends PGraphics { protected class BaseShader extends PShader { - protected int transformLoc; - protected int modelviewLoc; - protected int projectionLoc; + protected int transformMatLoc; + protected int modelviewMatLoc; + protected int projectionMatLoc; protected int bufferLoc; protected int bufferUnit; protected int viewportLoc; @@ -6629,9 +6659,15 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void loadUniforms() { - transformLoc = getUniformLoc("transform"); - modelviewLoc = getUniformLoc("modelview"); - projectionLoc = getUniformLoc("projection"); + transformMatLoc = getUniformLoc("transform"); + if (transformMatLoc == -1) transformMatLoc = getUniformLoc("transformMatrix"); + + modelviewMatLoc = getUniformLoc("modelview"); + if (modelviewMatLoc == -1) modelviewMatLoc = getUniformLoc("modelviewMatrix"); + + projectionMatLoc = getUniformLoc("projection"); + if (projectionMatLoc == -1) projectionMatLoc = getUniformLoc("projectionMatrix"); + viewportLoc = getUniformLoc("viewport"); bufferLoc = getUniformLoc("buffer"); } @@ -6651,19 +6687,19 @@ public class PGraphicsOpenGL extends PGraphics { } protected void setCommonUniforms() { - if (-1 < transformLoc) { + if (-1 < transformMatLoc) { pgCurrent.updateGLProjmodelview(); - setUniformMatrix(transformLoc, pgCurrent.glProjmodelview); + setUniformMatrix(transformMatLoc, pgCurrent.glProjmodelview); } - if (-1 < modelviewLoc) { + if (-1 < modelviewMatLoc) { pgCurrent.updateGLModelview(); - setUniformMatrix(modelviewLoc, pgCurrent.glModelview); + setUniformMatrix(modelviewMatLoc, pgCurrent.glModelview); } - if (-1 < projectionLoc) { + if (-1 < projectionMatLoc) { pgCurrent.updateGLProjection(); - setUniformMatrix(projectionLoc, pgCurrent.glProjection); + setUniformMatrix(projectionMatLoc, pgCurrent.glProjection); } if (-1 < viewportLoc) { @@ -6684,6 +6720,10 @@ public class PGraphicsOpenGL extends PGraphics { } } + public boolean hasTexture() { + return false; + } + public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { } public void setColorAttribute(int vboId, int size, int type, @@ -6703,13 +6743,13 @@ public class PGraphicsOpenGL extends PGraphics { public void setTexture(Texture tex) { } } - +/* protected class ColorShader extends BaseShader { protected int vertexLoc; protected int colorLoc; protected int normalLoc; protected int texCoordLoc; - protected int normalMatrixLoc; + protected int normalMatLoc; public ColorShader(PApplet parent) { super(parent); @@ -6736,7 +6776,7 @@ public class PGraphicsOpenGL extends PGraphics { public void loadUniforms() { super.loadUniforms(); - normalMatrixLoc = getUniformLoc("normalMatrix"); + normalMatLoc = getUniformLoc("normalMatrix"); } @Override @@ -6778,9 +6818,9 @@ public class PGraphicsOpenGL extends PGraphics { if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc); if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc); - if (-1 < normalMatrixLoc) { + if (-1 < normalMatLoc) { pgCurrent.updateGLNormal(); - setUniformMatrix(normalMatrixLoc, pgCurrent.glNormal); + setUniformMatrix(normalMatLoc, pgCurrent.glNormal); } } @@ -7092,6 +7132,249 @@ public class PGraphicsOpenGL extends PGraphics { super.unbind(); } } +*/ + + protected class PolyShader extends BaseShader { + protected int vertexLoc; + protected int colorLoc; + protected int normalLoc; + protected int texCoordLoc; + protected int normalMatLoc; + + protected int lightCountLoc; + protected int lightPositionLoc; + protected int lightNormalLoc; + protected int lightAmbientLoc; + protected int lightDiffuseLoc; + protected int lightSpecularLoc; + protected int lightFalloffLoc; + protected int lightSpotLoc; + + protected int ambientLoc; + protected int specularLoc; + protected int emissiveLoc; + protected int shininessLoc; + + protected Texture texture; + protected int texUnit; + + protected int textureLoc; + protected int texMatrixLoc; + protected int texOffsetLoc; + + protected float[] tcmat; + + public PolyShader(PApplet parent) { + super(parent); + } + + public PolyShader(PApplet parent, String vertFilename, + String fragFilename) { + super(parent, vertFilename, fragFilename); + } + + public PolyShader(PApplet parent, URL vertURL, URL fragURL) { + super(parent, vertURL, fragURL); + } + + @Override + public void loadAttributes() { + vertexLoc = getAttributeLoc("vertex"); + colorLoc = getAttributeLoc("color"); + texCoordLoc = getAttributeLoc("texCoord"); + normalLoc = getAttributeLoc("normal"); + + ambientLoc = getAttributeLoc("ambient"); + specularLoc = getAttributeLoc("specular"); + emissiveLoc = getAttributeLoc("emissive"); + shininessLoc = getAttributeLoc("shininess"); + + textureLoc = getUniformLoc("texture"); + texMatrixLoc = getUniformLoc("texMatrix"); + texOffsetLoc = getUniformLoc("texOffset"); + } + + @Override + public void loadUniforms() { + super.loadUniforms(); + + normalMatLoc = getUniformLoc("normalMatrix"); + + lightCountLoc = getUniformLoc("lightCount"); + lightPositionLoc = getUniformLoc("lightPosition"); + lightNormalLoc = getUniformLoc("lightNormal"); + lightAmbientLoc = getUniformLoc("lightAmbient"); + lightDiffuseLoc = getUniformLoc("lightDiffuse"); + lightSpecularLoc = getUniformLoc("lightSpecular"); + lightFalloffLoc = getUniformLoc("lightFalloff"); + lightSpotLoc = getUniformLoc("lightSpot"); + + textureLoc = getUniformLoc("texture"); + texMatrixLoc = getUniformLoc("texMatrix"); + texOffsetLoc = getUniformLoc("texOffset"); + } + + @Override + public int getLastTexUnit() { + return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit(); + } + + @Override + public void setTexture(Texture tex) { + float scaleu = 1; + float scalev = 1; + float dispu = 0; + float dispv = 0; + + if (tex.invertedX()) { + scaleu = -1; + dispu = 1; + } + + if (tex.invertedY()) { + scalev = -1; + dispv = 1; + } + + scaleu *= tex.maxTexcoordU(); + dispu *= tex.maxTexcoordU(); + scalev *= tex.maxTexcoordV(); + dispv *= tex.maxTexcoordV(); + + if (-1 < texMatrixLoc) { + if (tcmat == null) { + tcmat = new float[16]; + } + tcmat[0] = scaleu; tcmat[4] = 0; tcmat[ 8] = 0; tcmat[12] = dispu; + tcmat[1] = 0; tcmat[5] = scalev; tcmat[ 9] = 0; tcmat[13] = dispv; + tcmat[2] = 0; tcmat[6] = 0; tcmat[10] = 0; tcmat[14] = 0; + tcmat[3] = 0; tcmat[7] = 0; tcmat[11] = 0; tcmat[15] = 0; + setUniformMatrix(texMatrixLoc, tcmat); + } + + setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height); + + if (-1 < textureLoc) { + texUnit = getLastTexUnit() + 1; + setUniformValue(textureLoc, texUnit); + pgl.activeTexture(PGL.TEXTURE0 + texUnit); + tex.bind(); + texture = tex; + } + } + + @Override + public boolean hasTexture() { + return -1 < textureLoc; + } + + @Override + public void setVertexAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset); + } + + @Override + public void setColorAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset); + } + + @Override + public void setNormalAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(normalLoc, vboId, size, type, false, stride, offset); + } + + @Override + public void setTexcoordAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset); + } + + @Override + public void setAmbientAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(ambientLoc, vboId, size, type, true, stride, offset); + } + + @Override + public void setSpecularAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(specularLoc, vboId, size, type, true, stride, offset); + } + + @Override + public void setEmissiveAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(emissiveLoc, vboId, size, type, true, stride, offset); + } + + @Override + public void setShininessAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(shininessLoc, vboId, size, type, false, stride, offset); + } + + @Override + public void bind() { + super.bind(); + if (pgCurrent == null) { + setRenderer(PGraphicsOpenGL.pgCurrent); + loadAttributes(); + loadUniforms(); + } + setCommonUniforms(); + + if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc); + if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc); + if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc); + if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc); + + if (-1 < normalMatLoc) { + pgCurrent.updateGLNormal(); + setUniformMatrix(normalMatLoc, pgCurrent.glNormal); + } + + if (-1 < ambientLoc) pgl.enableVertexAttribArray(ambientLoc); + if (-1 < specularLoc) pgl.enableVertexAttribArray(specularLoc); + if (-1 < emissiveLoc) pgl.enableVertexAttribArray(emissiveLoc); + if (-1 < shininessLoc) pgl.enableVertexAttribArray(shininessLoc); + + int count = pgCurrent.lightCount; + setUniformValue(lightCountLoc, count); + setUniformVector(lightPositionLoc, pgCurrent.lightPosition, 4, count); + setUniformVector(lightNormalLoc, pgCurrent.lightNormal, 3, count); + setUniformVector(lightAmbientLoc, pgCurrent.lightAmbient, 3, count); + setUniformVector(lightDiffuseLoc, pgCurrent.lightDiffuse, 3, count); + setUniformVector(lightSpecularLoc, pgCurrent.lightSpecular, 3, count); + setUniformVector(lightFalloffLoc, pgCurrent.lightFalloffCoefficients, + 3, count); + setUniformVector(lightSpotLoc, pgCurrent.lightSpotParameters, 2, count); + } + + @Override + public void unbind() { + if (-1 < textureLoc && texture != null) { + pgl.activeTexture(PGL.TEXTURE0 + texUnit); + texture.unbind(); + pgl.activeTexture(PGL.TEXTURE0); + texture = null; + } + + if (-1 < ambientLoc) pgl.disableVertexAttribArray(ambientLoc); + if (-1 < specularLoc) pgl.disableVertexAttribArray(specularLoc); + if (-1 < emissiveLoc) pgl.disableVertexAttribArray(emissiveLoc); + if (-1 < shininessLoc) pgl.disableVertexAttribArray(shininessLoc); + + if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc); + if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc); + if (-1 < texCoordLoc) pgl.disableVertexAttribArray(texCoordLoc); + if (-1 < normalLoc) pgl.disableVertexAttribArray(normalLoc); + + super.unbind(); + } + } protected class LineShader extends BaseShader { diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShader.java index 8f751dc2e..711e616e6 100644 --- a/core/src/processing/opengl/PShader.java +++ b/core/src/processing/opengl/PShader.java @@ -41,12 +41,13 @@ import java.util.HashMap; */ public class PShader { // shaders constants - static protected final int COLOR = 0; - static protected final int LIGHT = 1; - static protected final int TEXTURE = 2; - static protected final int TEXLIGHT = 3; - static protected final int LINE = 4; - static protected final int POINT = 5; + static protected final int LINE = 0; + static protected final int POINT = 1; + static protected final int POLY = 3; + static protected final int COLOR = 4; + static protected final int LIGHT = 5; + static protected final int TEXTURE = 6; + static protected final int TEXLIGHT = 7; protected PApplet parent; // The main renderer associated to the parent PApplet. From 5d8bd9e96eb202fc4037d4dc00179d5d855b9069 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 4 Oct 2013 00:43:58 -0400 Subject: [PATCH 106/556] some shader aliases --- core/src/processing/opengl/ColorFrag.glsl | 4 ++-- core/src/processing/opengl/ColorVert.glsl | 10 ++++---- core/src/processing/opengl/LightVert.glsl | 20 ++++++++-------- core/src/processing/opengl/LineFrag.glsl | 4 ++-- core/src/processing/opengl/LineVert.glsl | 18 +++++++------- core/src/processing/opengl/MaskFrag.glsl | 6 ++--- .../processing/opengl/PGraphicsOpenGL.java | 6 +++++ core/src/processing/opengl/PointFrag.glsl | 4 ++-- core/src/processing/opengl/PointVert.glsl | 16 ++++++------- core/src/processing/opengl/TexlightVert.glsl | 24 +++++++++---------- core/src/processing/opengl/TextureFrag.glsl | 6 ++--- core/src/processing/opengl/TextureVert.glsl | 14 +++++------ 12 files changed, 69 insertions(+), 63 deletions(-) diff --git a/core/src/processing/opengl/ColorFrag.glsl b/core/src/processing/opengl/ColorFrag.glsl index d5d23ae22..5ab649aec 100644 --- a/core/src/processing/opengl/ColorFrag.glsl +++ b/core/src/processing/opengl/ColorFrag.glsl @@ -23,8 +23,8 @@ precision mediump float; precision mediump int; #endif -varying vec4 vertColor; +varying vec4 varColor; void main() { - gl_FragColor = vertColor; + gl_FragColor = varColor; } \ No newline at end of file diff --git a/core/src/processing/opengl/ColorVert.glsl b/core/src/processing/opengl/ColorVert.glsl index 5a03b41a0..d43d40549 100644 --- a/core/src/processing/opengl/ColorVert.glsl +++ b/core/src/processing/opengl/ColorVert.glsl @@ -20,15 +20,15 @@ #define PROCESSING_COLOR_SHADER -uniform mat4 transform; +uniform mat4 transformMatrix; -attribute vec4 vertex; +attribute vec4 position; attribute vec4 color; -varying vec4 vertColor; +varying vec4 varColor; void main() { - gl_Position = transform * vertex; + gl_Position = transformMatrix * position; - vertColor = color; + varColor = color; } \ No newline at end of file diff --git a/core/src/processing/opengl/LightVert.glsl b/core/src/processing/opengl/LightVert.glsl index 6e5829fe2..cfdcc44e0 100644 --- a/core/src/processing/opengl/LightVert.glsl +++ b/core/src/processing/opengl/LightVert.glsl @@ -20,8 +20,8 @@ #define PROCESSING_LIGHT_SHADER -uniform mat4 modelview; -uniform mat4 transform; +uniform mat4 modelviewMatrix; +uniform mat4 transformMatrix; uniform mat3 normalMatrix; uniform int lightCount; @@ -33,7 +33,7 @@ uniform vec3 lightSpecular[8]; uniform vec3 lightFalloff[8]; uniform vec2 lightSpot[8]; -attribute vec4 vertex; +attribute vec4 position; attribute vec4 color; attribute vec3 normal; @@ -42,7 +42,7 @@ attribute vec4 specular; attribute vec4 emissive; attribute float shininess; -varying vec4 vertColor; +varying vec4 varColor; const float zero_float = 0.0; const float one_float = 1.0; @@ -75,10 +75,10 @@ float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine) void main() { // Vertex in clip coordinates - gl_Position = transform * vertex; + gl_Position = transformMatrix * position; // Vertex in eye coordinates - vec3 ecVertex = vec3(modelview * vertex); + vec3 ecVertex = vec3(modelviewMatrix * position); // Normal vector in eye coordinates vec3 ecNormal = normalize(normalMatrix * normal); @@ -134,8 +134,8 @@ void main() { // Calculating final color as result of all lights (plus emissive term). // Transparency is determined exclusively by the diffuse component. - vertColor = vec4(totalAmbient, 0) * ambient + - vec4(totalDiffuse, 1) * color + - vec4(totalSpecular, 0) * specular + - vec4(emissive.rgb, 0); + varColor = vec4(totalAmbient, 0) * ambient + + vec4(totalDiffuse, 1) * color + + vec4(totalSpecular, 0) * specular + + vec4(emissive.rgb, 0); } \ No newline at end of file diff --git a/core/src/processing/opengl/LineFrag.glsl b/core/src/processing/opengl/LineFrag.glsl index dc08a3fa2..8ce920e33 100644 --- a/core/src/processing/opengl/LineFrag.glsl +++ b/core/src/processing/opengl/LineFrag.glsl @@ -23,8 +23,8 @@ precision mediump float; precision mediump int; #endif -varying vec4 vertColor; +varying vec4 varColor; void main() { - gl_FragColor = vertColor; + gl_FragColor = varColor; } \ No newline at end of file diff --git a/core/src/processing/opengl/LineVert.glsl b/core/src/processing/opengl/LineVert.glsl index 52f334b28..37687845a 100644 --- a/core/src/processing/opengl/LineVert.glsl +++ b/core/src/processing/opengl/LineVert.glsl @@ -20,18 +20,18 @@ #define PROCESSING_LINE_SHADER -uniform mat4 modelview; -uniform mat4 projection; +uniform mat4 modelviewMatrix; +uniform mat4 projectionMatrix; uniform vec4 viewport; uniform int perspective; uniform vec3 scale; -attribute vec4 vertex; +attribute vec4 position; attribute vec4 color; attribute vec4 direction; -varying vec4 vertColor; +varying vec4 varColor; vec3 clipToWindow(vec4 clip, vec4 viewport) { vec3 post_div = clip.xyz / clip.w; @@ -45,20 +45,20 @@ vec4 windowToClipVector(vec2 window, vec4 viewport, float clip_w) { } void main() { - vec4 posp = modelview * vertex; + vec4 posp = modelviewMatrix * position; // Moving vertices slightly toward the camera // to avoid depth-fighting with the fill triangles. // Discussed here: // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=252848 posp.xyz = posp.xyz * scale; - vec4 clipp = projection * posp; + vec4 clipp = projectionMatrix * posp; float thickness = direction.w; if (thickness != 0.0) { - vec4 posq = posp + modelview * vec4(direction.xyz, 0); + vec4 posq = posp + modelviewMatrix * vec4(direction.xyz, 0); posq.xyz = posq.xyz * scale; - vec4 clipq = projection * posq; + vec4 clipq = projectionMatrix * posq; vec3 window_p = clipToWindow(clipp, viewport); vec3 window_q = clipToWindow(clipq, viewport); @@ -81,5 +81,5 @@ void main() { gl_Position = clipp; } - vertColor = color; + varColor = color; } diff --git a/core/src/processing/opengl/MaskFrag.glsl b/core/src/processing/opengl/MaskFrag.glsl index 508a39649..4b517e3a0 100644 --- a/core/src/processing/opengl/MaskFrag.glsl +++ b/core/src/processing/opengl/MaskFrag.glsl @@ -28,11 +28,11 @@ precision mediump int; uniform sampler2D texture; uniform sampler2D mask; -varying vec4 vertTexCoord; +varying vec4 varTexCoord; void main() { - vec3 texColor = texture2D(texture, vertTexCoord.st).rgb; - vec3 maskColor = texture2D(mask, vertTexCoord.st).rgb; + vec3 texColor = texture2D(texture, varTexCoord.st).rgb; + vec3 maskColor = texture2D(mask, varTexCoord.st).rgb; float luminance = dot(maskColor, vec3(0.2126, 0.7152, 0.0722)); gl_FragColor = vec4(texColor, luminance); } \ No newline at end of file diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index ccaa95534..0623ba3c8 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -7180,6 +7180,8 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void loadAttributes() { vertexLoc = getAttributeLoc("vertex"); + if (vertexLoc == -1) vertexLoc = getAttributeLoc("position"); + colorLoc = getAttributeLoc("color"); texCoordLoc = getAttributeLoc("texCoord"); normalLoc = getAttributeLoc("normal"); @@ -7401,6 +7403,8 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void loadAttributes() { vertexLoc = getAttributeLoc("vertex"); + if (vertexLoc == -1) vertexLoc = getAttributeLoc("position"); + colorLoc = getAttributeLoc("color"); directionLoc = getAttributeLoc("direction"); } @@ -7499,6 +7503,8 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void loadAttributes() { vertexLoc = getAttributeLoc("vertex"); + if (vertexLoc == -1) vertexLoc = getAttributeLoc("position"); + colorLoc = getAttributeLoc("color"); offsetLoc = getAttributeLoc("offset"); } diff --git a/core/src/processing/opengl/PointFrag.glsl b/core/src/processing/opengl/PointFrag.glsl index d5d23ae22..5ab649aec 100644 --- a/core/src/processing/opengl/PointFrag.glsl +++ b/core/src/processing/opengl/PointFrag.glsl @@ -23,8 +23,8 @@ precision mediump float; precision mediump int; #endif -varying vec4 vertColor; +varying vec4 varColor; void main() { - gl_FragColor = vertColor; + gl_FragColor = varColor; } \ No newline at end of file diff --git a/core/src/processing/opengl/PointVert.glsl b/core/src/processing/opengl/PointVert.glsl index 7523e3326..542efaa67 100644 --- a/core/src/processing/opengl/PointVert.glsl +++ b/core/src/processing/opengl/PointVert.glsl @@ -20,17 +20,17 @@ #define PROCESSING_POINT_SHADER -uniform mat4 projection; -uniform mat4 modelview; +uniform mat4 projectionMatrix; +uniform mat4 modelviewMatrix; uniform vec4 viewport; uniform int perspective; -attribute vec4 vertex; +attribute vec4 position; attribute vec4 color; attribute vec2 offset; -varying vec4 vertColor; +varying vec4 varColor; vec4 windowToClipVector(vec2 window, vec4 viewport, float clipw) { vec2 xypos = (window / viewport.zw) * 2.0; @@ -38,18 +38,18 @@ vec4 windowToClipVector(vec2 window, vec4 viewport, float clipw) { } void main() { - vec4 pos = modelview * vertex; - vec4 clip = projection * pos; + vec4 pos = modelviewMatrix * position; + vec4 clip = projectionMatrix * pos; if (0 < perspective) { // Perspective correction (points will look thiner as they move away // from the view position). - gl_Position = clip + projection * vec4(offset.xy, 0, 0); + gl_Position = clip + projectionMatrix * vec4(offset.xy, 0, 0); } else { // No perspective correction. vec4 offset = windowToClipVector(offset.xy, viewport, clip.w); gl_Position = clip + offset; } - vertColor = color; + varColor = color; } \ No newline at end of file diff --git a/core/src/processing/opengl/TexlightVert.glsl b/core/src/processing/opengl/TexlightVert.glsl index ff981c59c..620d50c70 100644 --- a/core/src/processing/opengl/TexlightVert.glsl +++ b/core/src/processing/opengl/TexlightVert.glsl @@ -20,8 +20,8 @@ #define PROCESSING_TEXLIGHT_SHADER -uniform mat4 modelview; -uniform mat4 transform; +uniform mat4 modelviewMatrix; +uniform mat4 transformMatrix; uniform mat3 normalMatrix; uniform mat4 texMatrix; @@ -34,7 +34,7 @@ uniform vec3 lightSpecular[8]; uniform vec3 lightFalloff[8]; uniform vec2 lightSpot[8]; -attribute vec4 vertex; +attribute vec4 position; attribute vec4 color; attribute vec3 normal; attribute vec2 texCoord; @@ -44,8 +44,8 @@ attribute vec4 specular; attribute vec4 emissive; attribute float shininess; -varying vec4 vertColor; -varying vec4 vertTexCoord; +varying vec4 varColor; +varying vec4 varTexCoord; const float zero_float = 0.0; const float one_float = 1.0; @@ -78,10 +78,10 @@ float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine) void main() { // Vertex in clip coordinates - gl_Position = transform * vertex; + gl_Position = transformMatrix * position; // Vertex in eye coordinates - vec3 ecVertex = vec3(modelview * vertex); + vec3 ecVertex = vec3(modelviewMatrix * position); // Normal vector in eye coordinates vec3 ecNormal = normalize(normalMatrix * normal); @@ -137,11 +137,11 @@ void main() { // Calculating final color as result of all lights (plus emissive term). // Transparency is determined exclusively by the diffuse component. - vertColor = vec4(totalAmbient, 0) * ambient + - vec4(totalDiffuse, 1) * color + - vec4(totalSpecular, 0) * specular + - vec4(emissive.rgb, 0); + varColor = vec4(totalAmbient, 0) * ambient + + vec4(totalDiffuse, 1) * color + + vec4(totalSpecular, 0) * specular + + vec4(emissive.rgb, 0); // Calculating texture coordinates, with r and q set both to one - vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); + varTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); } diff --git a/core/src/processing/opengl/TextureFrag.glsl b/core/src/processing/opengl/TextureFrag.glsl index f041e61d1..dc3bcbe7e 100644 --- a/core/src/processing/opengl/TextureFrag.glsl +++ b/core/src/processing/opengl/TextureFrag.glsl @@ -27,9 +27,9 @@ uniform sampler2D texture; uniform vec2 texOffset; -varying vec4 vertColor; -varying vec4 vertTexCoord; +varying vec4 varColor; +varying vec4 varTexCoord; void main() { - gl_FragColor = texture2D(texture, vertTexCoord.st) * vertColor; + gl_FragColor = texture2D(texture, varTexCoord.st) * varColor; } \ No newline at end of file diff --git a/core/src/processing/opengl/TextureVert.glsl b/core/src/processing/opengl/TextureVert.glsl index 5260321fb..e52789316 100644 --- a/core/src/processing/opengl/TextureVert.glsl +++ b/core/src/processing/opengl/TextureVert.glsl @@ -20,19 +20,19 @@ #define PROCESSING_TEXTURE_SHADER -uniform mat4 transform; +uniform mat4 transformMatrix; uniform mat4 texMatrix; -attribute vec4 vertex; +attribute vec4 position; attribute vec4 color; attribute vec2 texCoord; -varying vec4 vertColor; -varying vec4 vertTexCoord; +varying vec4 varColor; +varying vec4 varTexCoord; void main() { - gl_Position = transform * vertex; + gl_Position = transformMatrix * position; - vertColor = color; - vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); + varColor = color; + varTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); } \ No newline at end of file From c41c53f93135ff83fa2ae0362f6e0ea9f763ef90 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 4 Oct 2013 18:54:31 -0400 Subject: [PATCH 107/556] some debugging --- core/src/processing/opengl/ColorFrag.glsl | 4 +- core/src/processing/opengl/ColorVert.glsl | 4 +- core/src/processing/opengl/LightVert.glsl | 10 +- core/src/processing/opengl/LineFrag.glsl | 4 +- core/src/processing/opengl/LineVert.glsl | 4 +- core/src/processing/opengl/MaskFrag.glsl | 6 +- .../processing/opengl/PGraphicsOpenGL.java | 536 +----------------- core/src/processing/opengl/PShader.java | 10 +- core/src/processing/opengl/PShapeOpenGL.java | 4 + core/src/processing/opengl/PointFrag.glsl | 4 +- core/src/processing/opengl/PointVert.glsl | 4 +- core/src/processing/opengl/TexlightVert.glsl | 14 +- core/src/processing/opengl/TextureFrag.glsl | 6 +- core/src/processing/opengl/TextureVert.glsl | 10 +- 14 files changed, 75 insertions(+), 545 deletions(-) diff --git a/core/src/processing/opengl/ColorFrag.glsl b/core/src/processing/opengl/ColorFrag.glsl index 5ab649aec..d5d23ae22 100644 --- a/core/src/processing/opengl/ColorFrag.glsl +++ b/core/src/processing/opengl/ColorFrag.glsl @@ -23,8 +23,8 @@ precision mediump float; precision mediump int; #endif -varying vec4 varColor; +varying vec4 vertColor; void main() { - gl_FragColor = varColor; + gl_FragColor = vertColor; } \ No newline at end of file diff --git a/core/src/processing/opengl/ColorVert.glsl b/core/src/processing/opengl/ColorVert.glsl index d43d40549..3736ffd2e 100644 --- a/core/src/processing/opengl/ColorVert.glsl +++ b/core/src/processing/opengl/ColorVert.glsl @@ -25,10 +25,10 @@ uniform mat4 transformMatrix; attribute vec4 position; attribute vec4 color; -varying vec4 varColor; +varying vec4 vertColor; void main() { gl_Position = transformMatrix * position; - varColor = color; + vertColor = color; } \ No newline at end of file diff --git a/core/src/processing/opengl/LightVert.glsl b/core/src/processing/opengl/LightVert.glsl index cfdcc44e0..bfbb6a8d3 100644 --- a/core/src/processing/opengl/LightVert.glsl +++ b/core/src/processing/opengl/LightVert.glsl @@ -42,7 +42,7 @@ attribute vec4 specular; attribute vec4 emissive; attribute float shininess; -varying vec4 varColor; +varying vec4 vertColor; const float zero_float = 0.0; const float one_float = 1.0; @@ -134,8 +134,8 @@ void main() { // Calculating final color as result of all lights (plus emissive term). // Transparency is determined exclusively by the diffuse component. - varColor = vec4(totalAmbient, 0) * ambient + - vec4(totalDiffuse, 1) * color + - vec4(totalSpecular, 0) * specular + - vec4(emissive.rgb, 0); + vertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalDiffuse, 1) * color + + vec4(totalSpecular, 0) * specular + + vec4(emissive.rgb, 0); } \ No newline at end of file diff --git a/core/src/processing/opengl/LineFrag.glsl b/core/src/processing/opengl/LineFrag.glsl index 8ce920e33..dc08a3fa2 100644 --- a/core/src/processing/opengl/LineFrag.glsl +++ b/core/src/processing/opengl/LineFrag.glsl @@ -23,8 +23,8 @@ precision mediump float; precision mediump int; #endif -varying vec4 varColor; +varying vec4 vertColor; void main() { - gl_FragColor = varColor; + gl_FragColor = vertColor; } \ No newline at end of file diff --git a/core/src/processing/opengl/LineVert.glsl b/core/src/processing/opengl/LineVert.glsl index 37687845a..d16f4d519 100644 --- a/core/src/processing/opengl/LineVert.glsl +++ b/core/src/processing/opengl/LineVert.glsl @@ -31,7 +31,7 @@ attribute vec4 position; attribute vec4 color; attribute vec4 direction; -varying vec4 varColor; +varying vec4 vertColor; vec3 clipToWindow(vec4 clip, vec4 viewport) { vec3 post_div = clip.xyz / clip.w; @@ -81,5 +81,5 @@ void main() { gl_Position = clipp; } - varColor = color; + vertColor = color; } diff --git a/core/src/processing/opengl/MaskFrag.glsl b/core/src/processing/opengl/MaskFrag.glsl index 4b517e3a0..508a39649 100644 --- a/core/src/processing/opengl/MaskFrag.glsl +++ b/core/src/processing/opengl/MaskFrag.glsl @@ -28,11 +28,11 @@ precision mediump int; uniform sampler2D texture; uniform sampler2D mask; -varying vec4 varTexCoord; +varying vec4 vertTexCoord; void main() { - vec3 texColor = texture2D(texture, varTexCoord.st).rgb; - vec3 maskColor = texture2D(mask, varTexCoord.st).rgb; + vec3 texColor = texture2D(texture, vertTexCoord.st).rgb; + vec3 maskColor = texture2D(mask, vertTexCoord.st).rgb; float luminance = dot(maskColor, vec3(0.2126, 0.7152, 0.0722)); gl_FragColor = vec4(texColor, luminance); } \ No newline at end of file diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 0623ba3c8..8850be7e1 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -84,18 +84,12 @@ public class PGraphicsOpenGL extends PGraphics { "shader() called with a wrong shader"; static final String UNKNOWN_SHADER_KIND_ERROR = "Unknown shader kind"; - static final String NO_TEXLIGHT_SHADER_ERROR = - "Your shader needs to be of TEXLIGHT type " + - "to render this geometry properly, using default shader instead."; - static final String NO_LIGHT_SHADER_ERROR = - "Your shader needs to be of LIGHT type " + - "to render this geometry properly, using default shader instead."; - static final String NO_TEXTURE_SHADER_ERROR = - "Your shader needs to be of TEXTURE type " + - "to render this geometry properly, using default shader instead."; - static final String NO_COLOR_SHADER_ERROR = - "Your shader needs to be of COLOR type " + - "to render this geometry properly, using default shader instead."; + static final String LIGHT_SHADER_ERROR = + "The shader expects lights but it is beging used to draw an unlit scene, " + + "this might lead to unexpected rendering errors."; + static final String TEXTURE_SHADER_ERROR = + "The shader expects textures but it is being used to draw an untextured scene, " + + "this might lead to unexpected rendering errors."; static final String TOO_LONG_STROKE_PATH_ERROR = "Stroke path is too long, some bevel triangles won't be added"; static final String TESSELLATION_ERROR = @@ -230,10 +224,6 @@ public class PGraphicsOpenGL extends PGraphics { static protected URL defPointShaderFragURL = PGraphicsOpenGL.class.getResource("PointFrag.glsl"); -// static protected ColorShader defColorShader; -// static protected TextureShader defTextureShader; -// static protected LightShader defLightShader; -// static protected TexlightShader defTexlightShader; static protected PolyShader defColorShader; static protected PolyShader defTextureShader; static protected PolyShader defLightShader; @@ -243,26 +233,12 @@ public class PGraphicsOpenGL extends PGraphics { static protected URL maskShaderFragURL = PGraphicsOpenGL.class.getResource("MaskFrag.glsl"); -// static protected TextureShader maskShader; static protected PolyShader maskShader; -// protected ColorShader colorShader; -// protected TextureShader textureShader; -// protected LightShader lightShader; -// protected TexlightShader texlightShader; protected PolyShader polyShader; protected LineShader lineShader; protected PointShader pointShader; - - // When shader warnings are enabled, the renderer is strict in regards to the - // use of the polygon shaders. For instance, if a light shader is set to - // render lit geometry, but the geometry is mixed with some pieces of unlit or - // textured geometry, then it will warn that the set shader cannot be used for - // that other type of geometry, even though Processing will use the correct, - // built-in shaders to handle it. -// protected boolean shaderWarningsEnabled = true; - // ........................................................ // Tessellator, geometry @@ -2389,7 +2365,7 @@ public class PGraphicsOpenGL extends PGraphics { // If the renderer is 2D, then lights should always be false, // so no need to worry about that. - BaseShader shader = getPolyShader(lights, tex != null); + PolyShader shader = getPolyShader(lights, tex != null); shader.bind(); int first = texCache.firstCache[i]; @@ -2422,10 +2398,14 @@ public class PGraphicsOpenGL extends PGraphics { 4 * voffset * PGL.SIZEOF_BYTE); shader.setShininessAttribute(glPolyShininess, 1, PGL.FLOAT, 0, voffset * PGL.SIZEOF_FLOAT); + } else if (shader.supportLighting()) { + PGraphics.showWarning(LIGHT_SHADER_ERROR); } if (tex != null) { shader.setTexture(tex); + } else if (shader.supportsTexturing()) { + PGraphics.showWarning(TEXTURE_SHADER_ERROR); } pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPolyIndex); @@ -5536,7 +5516,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void filter(PShader shader) { - if (!(shader instanceof PolyShader) || !((PolyShader)shader).hasTexture()) { + if (!(shader instanceof PolyShader) || !((PolyShader)shader).supportsTexturing()) { PGraphics.showWarning(INVALID_FILTER_SHADER_ERROR); return; } @@ -5583,7 +5563,6 @@ public class PGraphicsOpenGL extends PGraphics { PolyShader prevShader = polyShader; polyShader = (PolyShader)shader; - beginShape(QUADS); texture(filterImage); vertex(0, 0, 0, 0); @@ -6307,7 +6286,7 @@ public class PGraphicsOpenGL extends PGraphics { shader.setVertexShader(defColorShaderVertURL); } else { shader = new PolyShader(parent); - shader.setVertexShader(defTexlightShaderVertURL); + shader.setVertexShader(defTextureShaderVertURL); } shader.setFragmentShader(fragFilename); return shader; @@ -6328,6 +6307,8 @@ public class PGraphicsOpenGL extends PGraphics { shaderType = vertType; } else if (fragType == vertType) { shaderType = vertType; + } else if (2 <= fragType && 2 <= vertType) { + shaderType = PShader.POLY; } else { PGraphics.showWarning(INCONSISTENT_SHADER_TYPES); return null; @@ -6355,7 +6336,7 @@ public class PGraphicsOpenGL extends PGraphics { shader.setFragmentShader(defColorShaderFragURL); } else { shader = new PolyShader(parent); - shader.setVertexShader(defTexlightShaderVertURL); + shader.setVertexShader(defTextureShaderVertURL); } if (shader != null) { shader.setVertexShader(vertFilename); @@ -6368,15 +6349,6 @@ public class PGraphicsOpenGL extends PGraphics { } else { shader = new PolyShader(parent, vertFilename, fragFilename); } -// if (shaderType == PShader.TEXLIGHT) { -// shader = new TexlightShader(parent, vertFilename, fragFilename); -// } else if (shaderType == PShader.LIGHT) { -// shader = new LightShader(parent, vertFilename, fragFilename); -// } else if (shaderType == PShader.TEXTURE) { -// shader = new TextureShader(parent, vertFilename, fragFilename); -// } else if (shaderType == PShader.COLOR) { -// shader = new ColorShader(parent, vertFilename, fragFilename); -// } } return shader; } @@ -6395,14 +6367,6 @@ public class PGraphicsOpenGL extends PGraphics { if (kind == TRIANGLES || kind == QUADS || kind == POLYGON) { if (shader instanceof PolyShader) { polyShader = (PolyShader) shader; -// if (shader instanceof TexlightShader) { -// texlightShader = (TexlightShader) shader; -// } else if (shader instanceof TextureShader) { -// textureShader = (TextureShader) shader; -// } else if (shader instanceof LightShader) { -// lightShader = (LightShader) shader; -// } else if (shader instanceof ColorShader) { -// colorShader = (ColorShader) shader; } else { PGraphics.showWarning(WRONG_SHADER_TYPE_ERROR); } @@ -6435,10 +6399,6 @@ public class PGraphicsOpenGL extends PGraphics { flush(); // Flushing geometry drawn with a different shader. if (kind == TRIANGLES || kind == QUADS || kind == POLYGON) { -// textureShader = null; -// colorShader = null; -// texlightShader = null; -// lightShader = null; polyShader = null; } else if (kind == LINES) { lineShader = null; @@ -6450,11 +6410,6 @@ public class PGraphicsOpenGL extends PGraphics { } -// public void shaderWarnings(boolean enable) { -// shaderWarningsEnabled = enable; -// } - - protected int getShaderType(String filename) { String[] source = parent.loadStrings(filename); int type = PShader.POLY; @@ -6510,7 +6465,6 @@ public class PGraphicsOpenGL extends PGraphics { defTextureShaderFragURL); } shader = defTexlightShader; -// texlightShaderCheck(); } else { shader = polyShader; } @@ -6522,7 +6476,6 @@ public class PGraphicsOpenGL extends PGraphics { defColorShaderFragURL); } shader = defLightShader; -// lightShaderCheck(); } else { shader = polyShader; } @@ -6536,7 +6489,6 @@ public class PGraphicsOpenGL extends PGraphics { defTextureShaderFragURL); } shader = defTextureShader; -// textureShaderCheck(); } else { shader = polyShader; } @@ -6548,7 +6500,6 @@ public class PGraphicsOpenGL extends PGraphics { defColorShaderFragURL); } shader = defColorShader; -// colorShaderCheck(); } else { shader = polyShader; } @@ -6561,46 +6512,6 @@ public class PGraphicsOpenGL extends PGraphics { } -// protected void texlightShaderCheck() { -// if (shaderWarningsEnabled && -// (lightShader != null || -// textureShader != null || -// colorShader != null)) { -// PGraphics.showWarning(NO_TEXLIGHT_SHADER_ERROR); -// } -// } -// -// -// protected void lightShaderCheck() { -// if (shaderWarningsEnabled && -// (texlightShader != null || -// textureShader != null || -// colorShader != null)) { -// PGraphics.showWarning(NO_LIGHT_SHADER_ERROR); -// } -// } -// -// -// protected void textureShaderCheck() { -// if (shaderWarningsEnabled && -// (texlightShader != null || -// lightShader != null || -// colorShader != null)) { -// PGraphics.showWarning(NO_TEXTURE_SHADER_ERROR); -// } -// } -// -// -// protected void colorShaderCheck() { -// if (shaderWarningsEnabled && -// (texlightShader != null || -// lightShader != null || -// textureShader != null)) { -// PGraphics.showWarning(NO_COLOR_SHADER_ERROR); -// } -// } - - protected LineShader getLineShader() { LineShader shader; if (lineShader == null) { @@ -6720,7 +6631,11 @@ public class PGraphicsOpenGL extends PGraphics { } } - public boolean hasTexture() { + public boolean supportsTexturing() { + return false; + } + + public boolean supportLighting() { return false; } @@ -6743,396 +6658,6 @@ public class PGraphicsOpenGL extends PGraphics { public void setTexture(Texture tex) { } } -/* - protected class ColorShader extends BaseShader { - protected int vertexLoc; - protected int colorLoc; - protected int normalLoc; - protected int texCoordLoc; - protected int normalMatLoc; - - public ColorShader(PApplet parent) { - super(parent); - } - - public ColorShader(PApplet parent, String vertFilename, - String fragFilename) { - super(parent, vertFilename, fragFilename); - } - - public ColorShader(PApplet parent, URL vertURL, URL fragURL) { - super(parent, vertURL, fragURL); - } - - @Override - public void loadAttributes() { - vertexLoc = getAttributeLoc("vertex"); - colorLoc = getAttributeLoc("color"); - texCoordLoc = getAttributeLoc("texCoord"); - normalLoc = getAttributeLoc("normal"); - } - - @Override - public void loadUniforms() { - super.loadUniforms(); - - normalMatLoc = getUniformLoc("normalMatrix"); - } - - @Override - public void setVertexAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void setColorAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset); - } - - @Override - public void setNormalAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(normalLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void setTexcoordAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void bind() { - super.bind(); - if (pgCurrent == null) { - setRenderer(PGraphicsOpenGL.pgCurrent); - loadAttributes(); - loadUniforms(); - } - setCommonUniforms(); - - if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc); - if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc); - if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc); - if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc); - - if (-1 < normalMatLoc) { - pgCurrent.updateGLNormal(); - setUniformMatrix(normalMatLoc, pgCurrent.glNormal); - } - } - - @Override - public void unbind() { - if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc); - if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc); - if (-1 < texCoordLoc) pgl.disableVertexAttribArray(texCoordLoc); - if (-1 < normalLoc) pgl.disableVertexAttribArray(normalLoc); - - super.unbind(); - } - } - - - protected class LightShader extends ColorShader { - protected int lightCountLoc; - protected int lightPositionLoc; - protected int lightNormalLoc; - protected int lightAmbientLoc; - protected int lightDiffuseLoc; - protected int lightSpecularLoc; - protected int lightFalloffLoc; - protected int lightSpotLoc; - - protected int ambientLoc; - protected int specularLoc; - protected int emissiveLoc; - protected int shininessLoc; - - public LightShader(PApplet parent) { - super(parent); - } - - public LightShader(PApplet parent, String vertFilename, - String fragFilename) { - super(parent, vertFilename, fragFilename); - } - - public LightShader(PApplet parent, URL vertURL, URL fragURL) { - super(parent, vertURL, fragURL); - } - - @Override - public void loadAttributes() { - super.loadAttributes(); - ambientLoc = getAttributeLoc("ambient"); - specularLoc = getAttributeLoc("specular"); - emissiveLoc = getAttributeLoc("emissive"); - shininessLoc = getAttributeLoc("shininess"); - } - - @Override - public void loadUniforms() { - super.loadUniforms(); - - lightCountLoc = getUniformLoc("lightCount"); - lightPositionLoc = getUniformLoc("lightPosition"); - lightNormalLoc = getUniformLoc("lightNormal"); - lightAmbientLoc = getUniformLoc("lightAmbient"); - lightDiffuseLoc = getUniformLoc("lightDiffuse"); - lightSpecularLoc = getUniformLoc("lightSpecular"); - lightFalloffLoc = getUniformLoc("lightFalloff"); - lightSpotLoc = getUniformLoc("lightSpot"); - } - - @Override - public void setAmbientAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(ambientLoc, vboId, size, type, true, stride, offset); - } - - @Override - public void setSpecularAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(specularLoc, vboId, size, type, true, stride, offset); - } - - @Override - public void setEmissiveAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(emissiveLoc, vboId, size, type, true, stride, offset); - } - - @Override - public void setShininessAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(shininessLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void bind() { - super.bind(); - - if (-1 < ambientLoc) pgl.enableVertexAttribArray(ambientLoc); - if (-1 < specularLoc) pgl.enableVertexAttribArray(specularLoc); - if (-1 < emissiveLoc) pgl.enableVertexAttribArray(emissiveLoc); - if (-1 < shininessLoc) pgl.enableVertexAttribArray(shininessLoc); - - int count = pgCurrent.lightCount; - setUniformValue(lightCountLoc, count); - setUniformVector(lightPositionLoc, pgCurrent.lightPosition, 4, count); - setUniformVector(lightNormalLoc, pgCurrent.lightNormal, 3, count); - setUniformVector(lightAmbientLoc, pgCurrent.lightAmbient, 3, count); - setUniformVector(lightDiffuseLoc, pgCurrent.lightDiffuse, 3, count); - setUniformVector(lightSpecularLoc, pgCurrent.lightSpecular, 3, count); - setUniformVector(lightFalloffLoc, pgCurrent.lightFalloffCoefficients, - 3, count); - setUniformVector(lightSpotLoc, pgCurrent.lightSpotParameters, 2, count); - } - - @Override - public void unbind() { - if (-1 < ambientLoc) pgl.disableVertexAttribArray(ambientLoc); - if (-1 < specularLoc) pgl.disableVertexAttribArray(specularLoc); - if (-1 < emissiveLoc) pgl.disableVertexAttribArray(emissiveLoc); - if (-1 < shininessLoc) pgl.disableVertexAttribArray(shininessLoc); - - super.unbind(); - } - } - - - protected class TextureShader extends ColorShader { - protected Texture texture; - protected int texUnit; - - protected int textureLoc; - protected int texMatrixLoc; - protected int texOffsetLoc; - - protected float[] tcmat; - - public TextureShader(PApplet parent) { - super(parent); - } - - public TextureShader(PApplet parent, String vertFilename, - String fragFilename) { - super(parent, vertFilename, fragFilename); - } - - public TextureShader(PApplet parent, URL vertURL, URL fragURL) { - super(parent, vertURL, fragURL); - } - - @Override - public void loadUniforms() { - super.loadUniforms(); - - textureLoc = getUniformLoc("texture"); - texMatrixLoc = getUniformLoc("texMatrix"); - texOffsetLoc = getUniformLoc("texOffset"); - } - - @Override - public int getLastTexUnit() { - return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit(); - } - - @Override - public void setTexture(Texture tex) { - float scaleu = 1; - float scalev = 1; - float dispu = 0; - float dispv = 0; - - if (tex.invertedX()) { - scaleu = -1; - dispu = 1; - } - - if (tex.invertedY()) { - scalev = -1; - dispv = 1; - } - - scaleu *= tex.maxTexcoordU(); - dispu *= tex.maxTexcoordU(); - scalev *= tex.maxTexcoordV(); - dispv *= tex.maxTexcoordV(); - - if (-1 < texMatrixLoc) { - if (tcmat == null) { - tcmat = new float[16]; - } - tcmat[0] = scaleu; tcmat[4] = 0; tcmat[ 8] = 0; tcmat[12] = dispu; - tcmat[1] = 0; tcmat[5] = scalev; tcmat[ 9] = 0; tcmat[13] = dispv; - tcmat[2] = 0; tcmat[6] = 0; tcmat[10] = 0; tcmat[14] = 0; - tcmat[3] = 0; tcmat[7] = 0; tcmat[11] = 0; tcmat[15] = 0; - setUniformMatrix(texMatrixLoc, tcmat); - } - - setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height); - - if (-1 < textureLoc) { - texUnit = getLastTexUnit() + 1; - setUniformValue(textureLoc, texUnit); - pgl.activeTexture(PGL.TEXTURE0 + texUnit); - tex.bind(); - texture = tex; - } - } - - @Override - public void unbind() { - if (-1 < textureLoc && texture != null) { - pgl.activeTexture(PGL.TEXTURE0 + texUnit); - texture.unbind(); - pgl.activeTexture(PGL.TEXTURE0); - texture = null; - } - - super.unbind(); - } - } - - - protected class TexlightShader extends LightShader { - protected Texture texture; - protected int texUnit; - - protected int textureLoc; - protected int texMatrixLoc; - protected int texOffsetLoc; - - protected float[] tcmat; - - public TexlightShader(PApplet parent) { - super(parent); - } - - public TexlightShader(PApplet parent, String vertFilename, - String fragFilename) { - super(parent, vertFilename, fragFilename); - } - - public TexlightShader(PApplet parent, URL vertURL, URL fragURL) { - super(parent, vertURL, fragURL); - } - - @Override - public void loadUniforms() { - super.loadUniforms(); - - textureLoc = getUniformLoc("texture"); - texMatrixLoc = getUniformLoc("texMatrix"); - texOffsetLoc = getUniformLoc("texOffset"); - } - - @Override - public int getLastTexUnit() { - return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit(); - } - - @Override - public void setTexture(Texture tex) { - float scaleu = 1; - float scalev = 1; - float dispu = 0; - float dispv = 0; - - if (tex.invertedX()) { - scaleu = -1; - dispu = 1; - } - - if (tex.invertedY()) { - scalev = -1; - dispv = 1; - } - - scaleu *= tex.maxTexcoordU; - dispu *= tex.maxTexcoordU; - scalev *= tex.maxTexcoordV; - dispv *= tex.maxTexcoordV; - - if (-1 < texMatrixLoc) { - if (tcmat == null) { - tcmat = new float[16]; - } - tcmat[0] = scaleu; tcmat[4] = 0; tcmat[ 8] = 0; tcmat[12] = dispu; - tcmat[1] = 0; tcmat[5] = scalev; tcmat[ 9] = 0; tcmat[13] = dispv; - tcmat[2] = 0; tcmat[6] = 0; tcmat[10] = 0; tcmat[14] = 0; - tcmat[3] = 0; tcmat[7] = 0; tcmat[11] = 0; tcmat[15] = 0; - setUniformMatrix(texMatrixLoc, tcmat); - } - - setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height); - - if (-1 < textureLoc) { - texUnit = getLastTexUnit() + 1; - setUniformValue(textureLoc, texUnit); - pgl.activeTexture(PGL.TEXTURE0 + texUnit); - tex.bind(); - texture = tex; - } - } - - @Override - public void unbind() { - if (-1 < textureLoc && texture != null) { - pgl.activeTexture(PGL.TEXTURE0 + texUnit); - texture.unbind(); - pgl.activeTexture(PGL.TEXTURE0); - texture = null; - } - - super.unbind(); - } - } -*/ protected class PolyShader extends BaseShader { protected int vertexLoc; @@ -7190,10 +6715,6 @@ public class PGraphicsOpenGL extends PGraphics { specularLoc = getAttributeLoc("specular"); emissiveLoc = getAttributeLoc("emissive"); shininessLoc = getAttributeLoc("shininess"); - - textureLoc = getUniformLoc("texture"); - texMatrixLoc = getUniformLoc("texMatrix"); - texOffsetLoc = getUniformLoc("texOffset"); } @Override @@ -7216,10 +6737,10 @@ public class PGraphicsOpenGL extends PGraphics { texOffsetLoc = getUniformLoc("texOffset"); } - @Override - public int getLastTexUnit() { - return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit(); - } +// @Override +// public int getLastTexUnit() { +// return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit(); +// } @Override public void setTexture(Texture tex) { @@ -7266,10 +6787,15 @@ public class PGraphicsOpenGL extends PGraphics { } @Override - public boolean hasTexture() { + public boolean supportsTexturing() { return -1 < textureLoc; } + @Override + public boolean supportLighting() { + return -1 < lightCountLoc || -1 < lightPositionLoc || -1 < lightNormalLoc; + } + @Override public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShader.java index 711e616e6..5c390a55d 100644 --- a/core/src/processing/opengl/PShader.java +++ b/core/src/processing/opengl/PShader.java @@ -43,11 +43,11 @@ public class PShader { // shaders constants static protected final int LINE = 0; static protected final int POINT = 1; - static protected final int POLY = 3; - static protected final int COLOR = 4; - static protected final int LIGHT = 5; - static protected final int TEXTURE = 6; - static protected final int TEXLIGHT = 7; + static protected final int POLY = 2; + static protected final int COLOR = 3; + static protected final int LIGHT = 4; + static protected final int TEXTURE = 5; + static protected final int TEXLIGHT = 6; protected PApplet parent; // The main renderer associated to the parent PApplet. diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index 38e39d719..bfeefc37d 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -4479,10 +4479,14 @@ public class PShapeOpenGL extends PShape { 0, 4 * voffset * PGL.SIZEOF_BYTE); shader.setShininessAttribute(root.glPolyShininess, 1, PGL.FLOAT, 0, voffset * PGL.SIZEOF_FLOAT); + } else if (shader.supportLighting()) { + PGraphics.showWarning(PGraphicsOpenGL.LIGHT_SHADER_ERROR); } if (tex != null) { shader.setTexture(tex); + } else if (shader.supportsTexturing()) { + PGraphics.showWarning(PGraphicsOpenGL.TEXTURE_SHADER_ERROR); } pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, root.glPolyIndex); diff --git a/core/src/processing/opengl/PointFrag.glsl b/core/src/processing/opengl/PointFrag.glsl index 5ab649aec..d5d23ae22 100644 --- a/core/src/processing/opengl/PointFrag.glsl +++ b/core/src/processing/opengl/PointFrag.glsl @@ -23,8 +23,8 @@ precision mediump float; precision mediump int; #endif -varying vec4 varColor; +varying vec4 vertColor; void main() { - gl_FragColor = varColor; + gl_FragColor = vertColor; } \ No newline at end of file diff --git a/core/src/processing/opengl/PointVert.glsl b/core/src/processing/opengl/PointVert.glsl index 542efaa67..c677ce75b 100644 --- a/core/src/processing/opengl/PointVert.glsl +++ b/core/src/processing/opengl/PointVert.glsl @@ -30,7 +30,7 @@ attribute vec4 position; attribute vec4 color; attribute vec2 offset; -varying vec4 varColor; +varying vec4 vertColor; vec4 windowToClipVector(vec2 window, vec4 viewport, float clipw) { vec2 xypos = (window / viewport.zw) * 2.0; @@ -51,5 +51,5 @@ void main() { gl_Position = clip + offset; } - varColor = color; + vertColor = color; } \ No newline at end of file diff --git a/core/src/processing/opengl/TexlightVert.glsl b/core/src/processing/opengl/TexlightVert.glsl index 620d50c70..6542bf8fb 100644 --- a/core/src/processing/opengl/TexlightVert.glsl +++ b/core/src/processing/opengl/TexlightVert.glsl @@ -44,8 +44,8 @@ attribute vec4 specular; attribute vec4 emissive; attribute float shininess; -varying vec4 varColor; -varying vec4 varTexCoord; +varying vec4 vertColor; +varying vec4 vertTexCoord; const float zero_float = 0.0; const float one_float = 1.0; @@ -137,11 +137,11 @@ void main() { // Calculating final color as result of all lights (plus emissive term). // Transparency is determined exclusively by the diffuse component. - varColor = vec4(totalAmbient, 0) * ambient + - vec4(totalDiffuse, 1) * color + - vec4(totalSpecular, 0) * specular + - vec4(emissive.rgb, 0); + vertColor = vec4(totalAmbient, 0) * ambient + + vec4(totalDiffuse, 1) * color + + vec4(totalSpecular, 0) * specular + + vec4(emissive.rgb, 0); // Calculating texture coordinates, with r and q set both to one - varTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); + vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); } diff --git a/core/src/processing/opengl/TextureFrag.glsl b/core/src/processing/opengl/TextureFrag.glsl index dc3bcbe7e..f041e61d1 100644 --- a/core/src/processing/opengl/TextureFrag.glsl +++ b/core/src/processing/opengl/TextureFrag.glsl @@ -27,9 +27,9 @@ uniform sampler2D texture; uniform vec2 texOffset; -varying vec4 varColor; -varying vec4 varTexCoord; +varying vec4 vertColor; +varying vec4 vertTexCoord; void main() { - gl_FragColor = texture2D(texture, varTexCoord.st) * varColor; + gl_FragColor = texture2D(texture, vertTexCoord.st) * vertColor; } \ No newline at end of file diff --git a/core/src/processing/opengl/TextureVert.glsl b/core/src/processing/opengl/TextureVert.glsl index e52789316..cbbb361b1 100644 --- a/core/src/processing/opengl/TextureVert.glsl +++ b/core/src/processing/opengl/TextureVert.glsl @@ -18,7 +18,7 @@ Boston, MA 02111-1307 USA */ -#define PROCESSING_TEXTURE_SHADER +//#define PROCESSING_TEXTURE_SHADER uniform mat4 transformMatrix; uniform mat4 texMatrix; @@ -27,12 +27,12 @@ attribute vec4 position; attribute vec4 color; attribute vec2 texCoord; -varying vec4 varColor; -varying vec4 varTexCoord; +varying vec4 vertColor; +varying vec4 vertTexCoord; void main() { gl_Position = transformMatrix * position; - varColor = color; - varTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); + vertColor = color; + vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0); } \ No newline at end of file From 39ed7ef0ce2be52a855b67c779a66b5c926ee639 Mon Sep 17 00:00:00 2001 From: Benjamin Maus Date: Sat, 5 Oct 2013 12:58:38 +0200 Subject: [PATCH 108/556] Ignored bin in experimental --- experimental/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 experimental/.gitignore diff --git a/experimental/.gitignore b/experimental/.gitignore new file mode 100644 index 000000000..c5e82d745 --- /dev/null +++ b/experimental/.gitignore @@ -0,0 +1 @@ +bin \ No newline at end of file From b68a7834e3477b600de0e663f34681448c7002fb Mon Sep 17 00:00:00 2001 From: Benjamin Maus Date: Sat, 5 Oct 2013 18:33:18 +0200 Subject: [PATCH 109/556] Revalidating the PApplet on resize, so child components (like GLCanvas) scale accordingly. --- core/src/processing/core/PApplet.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 71c85020b..936ae1daa 100755 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -10170,6 +10170,7 @@ public class PApplet extends Applet if (!newBounds.equals(oldBounds)) { // the ComponentListener in PApplet will handle calling size() setBounds(newBounds); + revalidate(); // let the layout manager do its work } } } From 047d771fb7e489d9be242730e6189e6c412907d5 Mon Sep 17 00:00:00 2001 From: Benjamin Maus Date: Sat, 5 Oct 2013 18:35:55 +0200 Subject: [PATCH 110/556] Added reinitSurface() method to PGL/PJOGL backend. Does not destroy the active canvas and keeps the current capabilities, but triggers a reset of the allocated FBOs. --- core/src/processing/opengl/PGL.java | 3 +++ core/src/processing/opengl/PJOGL.java | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index aad1a8aaf..3053e86cf 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -328,6 +328,9 @@ public abstract class PGL { protected abstract void initSurface(int antialias); + protected abstract void reinitSurface(); + + protected abstract void registerListeners(); diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index f70587ad6..6aac7975a 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -311,6 +311,15 @@ public class PJOGL extends PGL { } + @Override + protected void reinitSurface() { + sinkFBO = backFBO = frontFBO = null; + fboLayerCreated = false; + fboLayerInUse = false; + firstFrame = true; + } + + @Override protected void registerListeners() { if (WINDOW_TOOLKIT == AWT) { From eed51037511ee86d826e0d0ef8aaffd3ee73a008 Mon Sep 17 00:00:00 2001 From: Benjamin Maus Date: Sat, 5 Oct 2013 18:38:46 +0200 Subject: [PATCH 111/556] Changed setSize logic: SetSize only sets the sized flag. All the rest is done directly before draw. Force reallocation of lights and transformation matrices (might get garbled during resize...). Do not perform a full init of the primary surface but rather a light version... --- .../processing/opengl/PGraphicsOpenGL.java | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 8850be7e1..fa7806d10 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -559,22 +559,6 @@ public class PGraphicsOpenGL extends PGraphics { width = iwidth; height = iheight; - allocate(); - reapplySettings(); - - // init perspective projection based on new dimensions - cameraFOV = 60 * DEG_TO_RAD; // at least for now - cameraX = width / 2.0f; - cameraY = height / 2.0f; - cameraZ = cameraY / ((float) Math.tan(cameraFOV / 2.0f)); - cameraNear = cameraZ / 10.0f; - cameraFar = cameraZ * 10.0f; - cameraAspect = (float) width / (float) height; - - // Forces a restart of OpenGL so the canvas has the right size. - restartPGL(); - - // set this flag so that beginDraw() will do an update to the camera. sized = true; } @@ -1582,6 +1566,8 @@ public class PGraphicsOpenGL extends PGraphics { public void requestDraw() { if (primarySurface) { if (initialized) { + if (sized) reinitPrimary(); + pgl.requestDraw(); } else { initPrimary(); @@ -5961,6 +5947,32 @@ public class PGraphicsOpenGL extends PGraphics { } + protected void reinitPrimary() { + lightsAllocated = false; + matricesAllocated = false; + + allocate(); + + reapplySettings(); + + // init perspective projection based on new dimensions + cameraFOV = 60 * DEG_TO_RAD; // at least for now + cameraX = width / 2.0f; + cameraY = height / 2.0f; + cameraZ = cameraY / ((float) Math.tan(cameraFOV / 2.0f)); + cameraNear = cameraZ / 10.0f; + cameraFar = cameraZ * 10.0f; + cameraAspect = (float) width / (float) height; + + // Forces a restart of OpenGL so the canvas has the right size. + // restartPGL(); + + // System.out.println("hasbeenSized"); + + pgl.reinitSurface(); + } + + protected void beginOnscreenDraw() { pgl.beginDraw(clearColorBuffer); From 2a7d4ffba22811561bafcf43d33f0de3dd954265 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sat, 5 Oct 2013 13:39:29 -0400 Subject: [PATCH 112/556] create PMatrix2D or 3D in PShapeOpenGL depending on value of is3D --- core/src/processing/opengl/PShapeOpenGL.java | 24 +++++--------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index bfeefc37d..3c88cdd15 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -1261,19 +1261,7 @@ public class PShapeOpenGL extends PShape { protected void transform(int type, float... args) { - int dimensions; - if (type == ROTATE) { - dimensions = args.length == 1 ? 2 : 3; - } else if (type == MATRIX) { - dimensions = args.length == 6 ? 2 : 3; - } else { - dimensions = args.length; - } - transformImpl(type, dimensions, args); - } - - - protected void transformImpl(int type, int ncoords, float... args) { + int ncoords = is3D ? 3 : 2; checkMatrix(ncoords); calcTransform(type, ncoords, args); if (tessellated) { @@ -1397,9 +1385,9 @@ public class PShapeOpenGL extends PShape { ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); inGeo.addBezierVertex(x2, y2, z2, - x3, y3, z3, - x4, y4, z4, - fill, stroke, bezierDetail, vertexCode(), kind); + x3, y3, z3, + x4, y4, z4, + fill, stroke, bezierDetail, vertexCode(), kind); } @@ -1425,8 +1413,8 @@ public class PShapeOpenGL extends PShape { ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); inGeo.addQuadraticVertex(cx, cy, cz, - x3, y3, z3, - fill, stroke, bezierDetail, vertexCode(), kind); + x3, y3, z3, + fill, stroke, bezierDetail, vertexCode(), kind); } From 3bf0166518ca61dfce8c260c2a1d28d8243ca9b7 Mon Sep 17 00:00:00 2001 From: Benjamin Maus Date: Sun, 6 Oct 2013 10:51:14 +0200 Subject: [PATCH 113/556] Not getting gl context on reshape. --- core/src/processing/opengl/PJOGL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index 6aac7975a..b7a6abe4f 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -782,7 +782,7 @@ public class PJOGL extends PGL { @Override public void reshape(GLAutoDrawable glDrawable, int x, int y, int w, int h) { - getGL(glDrawable); + //getGL(glDrawable); } private void getGL(GLAutoDrawable glDrawable) { From ec89911766faf3fd41ea1d2dc9c94f0d11ea1724 Mon Sep 17 00:00:00 2001 From: Benjamin Maus Date: Sun, 6 Oct 2013 10:52:00 +0200 Subject: [PATCH 114/556] Added STENCIL_TEST -> GL.STENCIL_TEST field to PGL/PJOGL --- core/src/processing/opengl/PGL.java | 1 + core/src/processing/opengl/PJOGL.java | 1 + 2 files changed, 2 insertions(+) diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index 3053e86cf..4f91aa09b 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -2218,6 +2218,7 @@ public abstract class PGL { public static int SRC_ALPHA_SATURATE; public static int SCISSOR_TEST; + public static int STENCIL_TEST; public static int DEPTH_TEST; public static int DEPTH_WRITEMASK; public static int ALPHA_TEST; diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index b7a6abe4f..ae40f68b0 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -1348,6 +1348,7 @@ public class PJOGL extends PGL { SRC_ALPHA_SATURATE = GL.GL_SRC_ALPHA_SATURATE; SCISSOR_TEST = GL.GL_SCISSOR_TEST; + STENCIL_TEST = GL.GL_STENCIL_TEST; DEPTH_TEST = GL.GL_DEPTH_TEST; DEPTH_WRITEMASK = GL.GL_DEPTH_WRITEMASK; ALPHA_TEST = GL2ES1.GL_ALPHA_TEST; From 98108a4c0a06f003bb2743553ec52a4adca4dcab Mon Sep 17 00:00:00 2001 From: Benjamin Maus Date: Sun, 6 Oct 2013 10:56:21 +0200 Subject: [PATCH 115/556] Reapplying settings when the renderer has been sized, but not outside actual GLCanvas/NEWTWindow display context. Calling gl things when not told to by GLCanvas leads to very bad effects, because GLCanvas might do an internal rebuild on resiszing the component, leading to all sorts of NullPointer and native issues. --- core/src/processing/opengl/PGraphicsOpenGL.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index fa7806d10..bf2aacfef 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -5953,8 +5953,6 @@ public class PGraphicsOpenGL extends PGraphics { allocate(); - reapplySettings(); - // init perspective projection based on new dimensions cameraFOV = 60 * DEG_TO_RAD; // at least for now cameraX = width / 2.0f; @@ -6148,6 +6146,8 @@ public class PGraphicsOpenGL extends PGraphics { pgl.disable(PGL.POLYGON_SMOOTH); if (sized) { + reapplySettings(); + // To avoid having garbage in the screen after a resize, // in the case background is not called in draw(). background(backgroundColor); From 28b53e495987467f090a8449987a66a5031a354a Mon Sep 17 00:00:00 2001 From: Benjamin Maus Date: Sun, 6 Oct 2013 10:58:28 +0200 Subject: [PATCH 116/556] Not reinitializing the backing arrays for matrices and lights. Not needed and seems to blow up some bound buffers. --- core/src/processing/opengl/PGraphicsOpenGL.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index bf2aacfef..44f764994 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -5948,9 +5948,6 @@ public class PGraphicsOpenGL extends PGraphics { protected void reinitPrimary() { - lightsAllocated = false; - matricesAllocated = false; - allocate(); // init perspective projection based on new dimensions From 1604cfd0014d15ab2848c55c0f811098a2fe1ef7 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sun, 6 Oct 2013 15:27:46 -0400 Subject: [PATCH 117/556] fix #2097 --- core/src/processing/opengl/PShapeOpenGL.java | 71 +++++++++++++------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index 3c88cdd15..aabb6019c 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -41,6 +41,7 @@ import processing.opengl.PGraphicsOpenGL.Tessellator; import java.util.Arrays; import java.util.HashSet; +import java.util.Stack; /** * This class holds a 3D model composed of vertices, normals, colors @@ -155,6 +156,7 @@ public class PShapeOpenGL extends PShape { // Geometric transformations. protected PMatrix transform; + protected Stack transformStack; // ........................................................ @@ -1243,34 +1245,31 @@ public class PShapeOpenGL extends PShape { @Override public void resetMatrix() { - if (shapeCreated && matrix != null) { + if (shapeCreated && matrix != null && transformStack != null) { if (family == GROUP) { updateTessellation(); } - boolean res = matrix.invert(); - if (res) { - if (tessellated) { - applyMatrixImpl(matrix); + if (tessellated) { + PMatrix mat = popTransform(); + while (mat != null) { + boolean res = mat.invert(); + if (res) { + applyMatrixImpl(mat); + } else { + PGraphics.showWarning("Transformation applied on the shape cannot be inverted"); + } + mat = popTransform(); } - matrix = null; - } else { - PGraphics.showWarning("The transformation matrix cannot be inverted"); } + matrix.reset(); + transformStack.clear(); } } protected void transform(int type, float... args) { - int ncoords = is3D ? 3 : 2; - checkMatrix(ncoords); - calcTransform(type, ncoords, args); - if (tessellated) { - applyMatrixImpl(transform); - } - } - - - protected void calcTransform(int type, int dimensions, float... args) { + int dimensions = is3D ? 3 : 2; + checkMatrix(dimensions); if (transform == null) { if (dimensions == 2) { transform = new PMatrix2D(); @@ -1281,30 +1280,37 @@ public class PShapeOpenGL extends PShape { transform.reset(); } + int ncoords = args.length; + if (type == ROTATE) { + ncoords = args.length == 1 ? 2 : 3; + } else if (type == MATRIX) { + ncoords = args.length == 6 ? 2 : 3; + } + switch (type) { case TRANSLATE: - if (dimensions == 3) { + if (ncoords == 3) { transform.translate(args[0], args[1], args[2]); } else { transform.translate(args[0], args[1]); } break; case ROTATE: - if (dimensions == 3) { + if (ncoords == 3) { transform.rotate(args[0], args[1], args[2], args[3]); } else { transform.rotate(args[0]); } break; case SCALE: - if (dimensions == 3) { + if (ncoords == 3) { transform.scale(args[0], args[1], args[2]); } else { transform.scale(args[0], args[1]); } break; case MATRIX: - if (dimensions == 3) { + if (ncoords == 3) { transform.set(args[ 0], args[ 1], args[ 2], args[ 3], args[ 4], args[ 5], args[ 6], args[ 7], args[ 8], args[ 9], args[10], args[11], @@ -1316,9 +1322,29 @@ public class PShapeOpenGL extends PShape { break; } matrix.apply(transform); + pushTransform(); + if (tessellated) applyMatrixImpl(transform); } + protected void pushTransform() { + if (transformStack == null) transformStack = new Stack(); + PMatrix mat; + if (transform instanceof PMatrix2D) { + mat = new PMatrix2D(); + } else { + mat = new PMatrix3D(); + } + mat.set(transform); + transformStack.push(mat); + } + + + protected PMatrix popTransform() { + if (transformStack == null || transformStack.size() == 0) return null; + return transformStack.pop(); + } + protected void applyMatrixImpl(PMatrix matrix) { if (hasPolys) { tessGeo.applyMatrixOnPolyGeometry(matrix, @@ -3138,7 +3164,6 @@ public class PShapeOpenGL extends PShape { if (matrix != null) { // Some geometric transformations were applied on // this shape before tessellation, so they are applied now. - //applyMatrixImpl(matrix); if (hasPolys) { tessGeo.applyMatrixOnPolyGeometry(matrix, firstPolyVertex, lastPolyVertex); From e6d7ff653d160a4cde917b02d25770686ecc718d Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 6 Oct 2013 15:46:21 -0400 Subject: [PATCH 118/556] fixes for image transparency with PDF output --- core/todo.txt | 2 ++ .../pdf/src/processing/pdf/PGraphicsPDF.java | 18 +++++++----------- todo.txt | 8 ++++++++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/core/todo.txt b/core/todo.txt index 187a6ccc1..63785fa5e 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -10,6 +10,8 @@ X https://github.com/processing/processing/issues/2100 X not handled by BufferedReader (or XML parser) X http://stackoverflow.com/questions/10556875/list-of-unicode-characters-that-should-be-filtered-in-output X http://stackoverflow.com/questions/3072152/what-is-unicode-character-2028-ls-line-separator-used-for +X fix image transparency in PDF output +X https://github.com/processing/processing/pull/2070 _ Sort out blending differences with P2D/P3D _ https://github.com/processing/processing/issues/1844 diff --git a/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java b/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java index 762a78db7..b49895706 100644 --- a/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java +++ b/java/libraries/pdf/src/processing/pdf/PGraphicsPDF.java @@ -22,16 +22,13 @@ package processing.pdf; import java.awt.Font; import java.awt.Graphics2D; +import java.awt.Image; import java.io.*; import java.util.*; import com.lowagie.text.*; import com.lowagie.text.pdf.*; -// Tried iText 5, but it was too slow -//import com.itextpdf.text.*; -//import com.itextpdf.text.pdf.*; - import processing.core.*; @@ -405,20 +402,19 @@ public class PGraphicsPDF extends PGraphicsJava2D { protected void imageImpl(PImage image, - float x1, float y1, float x2, float y2, - int u1, int v1, int u2, int v2) { + float x1, float y1, float x2, float y2, + int u1, int v1, int u2, int v2) { pushMatrix(); translate(x1, y1); int imageWidth = image.width; int imageHeight = image.height; scale((x2 - x1) / (float)imageWidth, (y2 - y1) / (float)imageHeight); - if (u2-u1 != imageWidth || v2-v1 != imageHeight) { - PImage tmp = new PImage(u2-u1, v2-v1, ARGB); - tmp.copy(image, u1, v1, u2, v2, 0, 0, u2-u1, v2-v1); - g2.drawImage(image.getImage(), 0, 0, null); + if (u2-u1 == imageWidth && v2-v1 == imageHeight) { + g2.drawImage((Image) image.getNative(), 0, 0, null); } else { - g2.drawImage(image.getImage(), u1, v1, null); + PImage tmp = image.get(u1, v1, u2-u1, v2-v1); + g2.drawImage((Image) tmp.getNative(), 0, 0, null); } popMatrix(); } diff --git a/todo.txt b/todo.txt index 9b9c0f6b9..291fb94dc 100644 --- a/todo.txt +++ b/todo.txt @@ -14,12 +14,20 @@ X https://github.com/processing/processing/pull/2093 X cmd-left is bringing up the text area popup X https://github.com/processing/processing/issues/2103 +_ still having right-click issues +_ https://github.com/processing/processing/issues/2103 + X add appbundler.jar, otherwise folks have to include Xcode _ if they want to build appbundler, they'll need Xcode _ and the command line tools Preferences > Downloads > Command Line Tools _ appbundler will have an NPE if the osx binary isn't built _ also need to have 10.8 version of the SDK (old Xcode won't work) +_ type looks a little feeble on OS X +_ retina problem? may need to turn off (on?) smoothing +_ also need to have a central menubar +_ add the offscreen window hack +_ otherwise mode change causes "do you want to quit?" on OS X _ fix console font on Windows and Linux with 7u40 _ the message area text also looks ugly.. can we fix? _ add pref to select PDE font (so that CJKV languages work better) From a581cc7550e3bfd88d3e8b49379537cee2e16344 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 6 Oct 2013 16:16:41 -0400 Subject: [PATCH 119/556] Java2D images crash after being resized (#2113) --- core/src/processing/core/PGraphicsJava2D.java | 22 ++++++++++++++----- core/todo.txt | 16 ++++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/core/src/processing/core/PGraphicsJava2D.java b/core/src/processing/core/PGraphicsJava2D.java index f35c83998..288642bc4 100644 --- a/core/src/processing/core/PGraphicsJava2D.java +++ b/core/src/processing/core/PGraphicsJava2D.java @@ -1247,15 +1247,25 @@ public class PGraphicsJava2D extends PGraphics { // Image not ready yet, or an error if (who.width <= 0 || who.height <= 0) return; - if (getCache(who) == null) { + ImageCache cash = (ImageCache) getCache(who); + + // Nuke the cache if the image was resized + if (cash != null) { + if (who.width != cash.image.getWidth() || + who.height != cash.image.getHeight()) { + cash = null; + } + } + + if (cash == null) { //System.out.println("making new image cache"); - this.setCache(who, new ImageCache(who)); + cash = new ImageCache(who); + setCache(who, cash); who.updatePixels(); // mark the whole thing for update who.modified = true; } - ImageCache cash = (ImageCache) getCache(who); - // if image previously was tinted, or the color changed + // If image previously was tinted, or the color changed // or the image was tinted, and tint is now disabled if ((tint && !cash.tinted) || (tint && (cash.tintedColor != tintColor)) || @@ -1273,8 +1283,8 @@ public class PGraphicsJava2D extends PGraphics { (int) x1, (int) y1, (int) x2, (int) y2, u1, v1, u2, v2, null); - // every few years I think "nah, Java2D couldn't possibly be that - // f*king slow, why are we doing this by hand? then comes the affirmation. + // Every few years I think "nah, Java2D couldn't possibly be that f*king + // slow, why are we doing this by hand?" then comes the affirmation: // Composite oldComp = null; // if (false && tint) { // oldComp = g2.getComposite(); diff --git a/core/todo.txt b/core/todo.txt index 63785fa5e..e4b30739b 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -12,6 +12,20 @@ X http://stackoverflow.com/questions/10556875/list-of-unicode-characters-that- X http://stackoverflow.com/questions/3072152/what-is-unicode-character-2028-ls-line-separator-used-for X fix image transparency in PDF output X https://github.com/processing/processing/pull/2070 +X Java2D images crash after being resized +X https://github.com/processing/processing/issues/2113 + +opengl +X fix inconsistency with P2D and resetMatrix() +X https://github.com/processing/processing/issues/2087 +X text rendering problems +X https://github.com/processing/processing/issues/2109 +X textSize() not working properly in P2D +X https://github.com/processing/processing/issues/2073 +X incorrectly applied transformations in retained mode +X https://github.com/processing/processing/issues/2097 +X push/popStyle() causes color problems with P2D/P3D +X https://github.com/processing/processing/issues/2102 _ Sort out blending differences with P2D/P3D _ https://github.com/processing/processing/issues/1844 @@ -19,6 +33,8 @@ _ 'collector' class.. Dict that points to a list _ String as a key, int/float/string list as values high +_ custom DPI settings with PDF +_ https://github.com/processing/processing/pull/2069 _ loadPixels doesn't set alpha value for pixels on Java2D _ https://github.com/processing/processing/issues/2030 _ blendMode(ADD) is broken with default renderer From ce2cb00f635da02f51bedaaefcd0c68a0176e158 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sun, 6 Oct 2013 16:20:50 -0400 Subject: [PATCH 120/556] better logic of shader type detection --- .../processing/opengl/PGraphicsOpenGL.java | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 8850be7e1..ae7e3d62e 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -27,6 +27,7 @@ import processing.core.*; import java.net.URL; import java.nio.*; import java.util.*; +import java.util.regex.Pattern; /** * OpenGL renderer. @@ -6264,7 +6265,6 @@ public class PGraphicsOpenGL extends PGraphics { @Override public PShader loadShader(String fragFilename) { int shaderType = getShaderType(fragFilename); - //if (shaderType == -1) shaderType = PShader.COLOR; PShader shader = null; if (shaderType == PShader.POINT) { shader = new PointShader(parent); @@ -6412,31 +6412,32 @@ public class PGraphicsOpenGL extends PGraphics { protected int getShaderType(String filename) { String[] source = parent.loadStrings(filename); - int type = PShader.POLY; + Pattern pointAttr = Pattern.compile("attribute *vec2 *offset"); + Pattern lineAttr = Pattern.compile("attribute *vec4 *direction"); + Pattern pointDef = Pattern.compile("#define *PROCESSING_POINT_SHADER"); + Pattern lineDef = Pattern.compile("#define *PROCESSING_LINE_SHADER"); + Pattern colorDef = Pattern.compile("#define *PROCESSING_COLOR_SHADER"); + Pattern lightDef = Pattern.compile("#define *PROCESSING_LIGHT_SHADER"); + Pattern texDef = Pattern.compile("#define *PROCESSING_TEXTURE_SHADER"); + Pattern texlightDef = Pattern.compile("#define *PROCESSING_TEXLIGHT_SHADER"); + Pattern polyDef = Pattern.compile("#define *PROCESSING_POLYGON_SHADER"); + Pattern triDef = Pattern.compile("#define *PROCESSING_TRIANGLES_SHADER"); + Pattern quadDef = Pattern.compile("#define *PROCESSING_QUADS_SHADER"); for (int i = 0; i < source.length; i++) { String line = source[i].trim(); - - if (line.indexOf("#define PROCESSING_POINT_SHADER") == 0) { - type = PShader.POINT; - } else if (line.indexOf("#define PROCESSING_LINE_SHADER") == 0) { - type = PShader.LINE; - } else if (line.indexOf("#define PROCESSING_COLOR_SHADER") == 0) { - type = PShader.COLOR; - } else if (line.indexOf("#define PROCESSING_LIGHT_SHADER") == 0) { - type = PShader.LIGHT; - } else if (line.indexOf("#define PROCESSING_TEXTURE_SHADER") == 0) { - type = PShader.TEXTURE; - } else if (line.indexOf("#define PROCESSING_TEXLIGHT_SHADER") == 0) { - type = PShader.TEXLIGHT; - } else if (line.indexOf("#define PROCESSING_POLYGON_SHADER") == 0) { - type = PShader.POLY; - } else if (line.indexOf("#define PROCESSING_TRIANGLES_SHADER") == 0) { - type = PShader.POLY; - } else if (line.indexOf("#define PROCESSING_QUADS_SHADER") == 0) { - type = PShader.POLY; - } + if (pointAttr.matcher(line).find()) return PShader.POINT; + else if (lineAttr.matcher(line).find()) return PShader.LINE; + else if (pointDef.matcher(line).find()) return PShader.POINT; + else if (lineDef.matcher(line).find()) return PShader.LINE; + else if (colorDef.matcher(line).find()) return PShader.COLOR; + else if (lightDef.matcher(line).find()) return PShader.LIGHT; + else if (texDef.matcher(line).find()) return PShader.TEXTURE; + else if (texlightDef.matcher(line).find()) return PShader.TEXLIGHT; + else if (polyDef.matcher(line).find()) return PShader.POLY; + else if (triDef.matcher(line).find()) return PShader.POLY; + else if (quadDef.matcher(line).find()) return PShader.POLY; } - return type; + return PShader.POLY; } From b4a54cf269fd54e97fa08ba4b2ff663d7c384c9e Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sun, 6 Oct 2013 17:33:55 -0400 Subject: [PATCH 121/556] use PApplet.match() to detect shader types. --- .../processing/opengl/PGraphicsOpenGL.java | 67 +++++++++++++------ 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index ae7e3d62e..f6dc52b72 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -204,6 +204,29 @@ public class PGraphicsOpenGL extends PGraphics { // Shaders + static protected String pointShaderAttrRegexp = + "attribute *vec2 *offset"; + static protected String lineShaderAttrRegexp = + "attribute *vec4 *direction"; + static protected String pointShaderDefRegexp = + "#define *PROCESSING_POINT_SHADER"; + static protected String lineShaderDefRegexp = + "#define *PROCESSING_LINE_SHADER"; + static protected String colorShaderDefRegexp = + "#define *PROCESSING_COLOR_SHADER"; + static protected String lightShaderDefRegexp = + "#define *PROCESSING_LIGHT_SHADER"; + static protected String texShaderDefRegexp = + "#define *PROCESSING_TEXTURE_SHADER"; + static protected String texlightShaderDefRegexp = + "#define *PROCESSING_TEXLIGHT_SHADER"; + static protected String polyShaderDefRegexp = + "#define *PROCESSING_POLYGON_SHADER"; + static protected String triShaderAttrRegexp = + "#define *PROCESSING_TRIANGLES_SHADER"; + static protected String quadShaderAttrRegexp = + "#define *PROCESSING_QUADS_SHADER"; + static protected URL defColorShaderVertURL = PGraphicsOpenGL.class.getResource("ColorVert.glsl"); static protected URL defTextureShaderVertURL = @@ -6412,30 +6435,30 @@ public class PGraphicsOpenGL extends PGraphics { protected int getShaderType(String filename) { String[] source = parent.loadStrings(filename); - Pattern pointAttr = Pattern.compile("attribute *vec2 *offset"); - Pattern lineAttr = Pattern.compile("attribute *vec4 *direction"); - Pattern pointDef = Pattern.compile("#define *PROCESSING_POINT_SHADER"); - Pattern lineDef = Pattern.compile("#define *PROCESSING_LINE_SHADER"); - Pattern colorDef = Pattern.compile("#define *PROCESSING_COLOR_SHADER"); - Pattern lightDef = Pattern.compile("#define *PROCESSING_LIGHT_SHADER"); - Pattern texDef = Pattern.compile("#define *PROCESSING_TEXTURE_SHADER"); - Pattern texlightDef = Pattern.compile("#define *PROCESSING_TEXLIGHT_SHADER"); - Pattern polyDef = Pattern.compile("#define *PROCESSING_POLYGON_SHADER"); - Pattern triDef = Pattern.compile("#define *PROCESSING_TRIANGLES_SHADER"); - Pattern quadDef = Pattern.compile("#define *PROCESSING_QUADS_SHADER"); for (int i = 0; i < source.length; i++) { String line = source[i].trim(); - if (pointAttr.matcher(line).find()) return PShader.POINT; - else if (lineAttr.matcher(line).find()) return PShader.LINE; - else if (pointDef.matcher(line).find()) return PShader.POINT; - else if (lineDef.matcher(line).find()) return PShader.LINE; - else if (colorDef.matcher(line).find()) return PShader.COLOR; - else if (lightDef.matcher(line).find()) return PShader.LIGHT; - else if (texDef.matcher(line).find()) return PShader.TEXTURE; - else if (texlightDef.matcher(line).find()) return PShader.TEXLIGHT; - else if (polyDef.matcher(line).find()) return PShader.POLY; - else if (triDef.matcher(line).find()) return PShader.POLY; - else if (quadDef.matcher(line).find()) return PShader.POLY; + if (PApplet.match(line, pointShaderAttrRegexp) != null) + return PShader.POINT; + else if (PApplet.match(line, lineShaderAttrRegexp) != null) + return PShader.LINE; + else if (PApplet.match(line, pointShaderDefRegexp) != null) + return PShader.POINT; + else if (PApplet.match(line, lineShaderDefRegexp) != null) + return PShader.LINE; + else if (PApplet.match(line, colorShaderDefRegexp) != null) + return PShader.COLOR; + else if (PApplet.match(line, lightShaderDefRegexp) != null) + return PShader.LIGHT; + else if (PApplet.match(line, texShaderDefRegexp) != null) + return PShader.TEXTURE; + else if (PApplet.match(line, texlightShaderDefRegexp) != null) + return PShader.TEXLIGHT; + else if (PApplet.match(line, polyShaderDefRegexp) != null) + return PShader.POLY; + else if (PApplet.match(line, triShaderAttrRegexp) != null) + return PShader.POLY; + else if (PApplet.match(line, quadShaderAttrRegexp) != null) + return PShader.POLY; } return PShader.POLY; } From d258654f85d0ede7e495ea697465c87b279ac844 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sun, 6 Oct 2013 17:44:23 -0400 Subject: [PATCH 122/556] removed unused import --- core/src/processing/opengl/PGraphicsOpenGL.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index f6dc52b72..876345526 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -27,7 +27,6 @@ import processing.core.*; import java.net.URL; import java.nio.*; import java.util.*; -import java.util.regex.Pattern; /** * OpenGL renderer. From 023a3b21efdfd548aaf26e3af1d861d1acaa3cf0 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sun, 6 Oct 2013 17:51:14 -0400 Subject: [PATCH 123/556] using CORNER for rectMode and ellipseMode by default in PShapeOpenGL, fix #2086 --- core/src/processing/opengl/PShapeOpenGL.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index aabb6019c..b2bdceacd 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -356,8 +356,10 @@ public class PShapeOpenGL extends PShape { sphereDetailU = pg.sphereDetailU; sphereDetailV = pg.sphereDetailV; - rectMode = pg.rectMode; - ellipseMode = pg.ellipseMode; + // The rect and ellipse modes are set to CORNER since it is the expected + // mode for svg shapes. + rectMode = CORNER; + ellipseMode = CORNER; normalX = normalY = 0; normalZ = 1; From e61c2149675cac35bd33284e57c981edc00c4923 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 6 Oct 2013 19:41:28 -0400 Subject: [PATCH 124/556] couple additional notes --- core/todo.txt | 2 ++ todo.txt | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/core/todo.txt b/core/todo.txt index e4b30739b..fd4b3fc53 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -26,6 +26,8 @@ X incorrectly applied transformations in retained mode X https://github.com/processing/processing/issues/2097 X push/popStyle() causes color problems with P2D/P3D X https://github.com/processing/processing/issues/2102 +X child SVG elements misplaced when rendering with P2D/P3D +X https://github.com/processing/processing/issues/2086 _ Sort out blending differences with P2D/P3D _ https://github.com/processing/processing/issues/1844 diff --git a/todo.txt b/todo.txt index 291fb94dc..2098b45ff 100644 --- a/todo.txt +++ b/todo.txt @@ -25,6 +25,11 @@ _ also need to have 10.8 version of the SDK (old Xcode won't work) _ type looks a little feeble on OS X _ retina problem? may need to turn off (on?) smoothing +_ type cut off in dialog boxes on OS X retina machines +_ https://github.com/processing/processing/issues/2116 +_ dialog box icon is fuzzy on OS X retina machines +_ https://github.com/processing/processing/issues/2117 + _ also need to have a central menubar _ add the offscreen window hack _ otherwise mode change causes "do you want to quit?" on OS X From 8563ff0fe5c5eb1c833704674d5f077fecb40e21 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 6 Oct 2013 23:25:17 -0400 Subject: [PATCH 125/556] attempting press/release versions of isPopupTrigger --- .../processing/app/syntax/JEditTextArea.java | 159 ++++++++---------- 1 file changed, 66 insertions(+), 93 deletions(-) diff --git a/app/src/processing/app/syntax/JEditTextArea.java b/app/src/processing/app/syntax/JEditTextArea.java index 9a36a882e..cb081a87d 100644 --- a/app/src/processing/app/syntax/JEditTextArea.java +++ b/app/src/processing/app/syntax/JEditTextArea.java @@ -2369,28 +2369,21 @@ public class JEditTextArea extends JComponent } - class FocusHandler implements FocusListener - { - public void focusGained(FocusEvent evt) - { -// System.out.println("JEditTextArea: focusGained"); + class FocusHandler implements FocusListener { + + public void focusGained(FocusEvent evt) { setCaretVisible(true); -// focusedComponent = JEditTextArea.this; } - public void focusLost(FocusEvent evt) - { -// System.out.println("JEditTextArea: focusLost"); + public void focusLost(FocusEvent evt) { setCaretVisible(false); -// focusedComponent = null; } } - class MouseHandler extends MouseAdapter - { - public void mousePressed(MouseEvent evt) - { + class MouseHandler extends MouseAdapter { + + public void mousePressed(MouseEvent event) { // try { // requestFocus(); // // Focus events not fired sometimes? @@ -2409,45 +2402,36 @@ public class JEditTextArea extends JComponent return; } - // Disabling this block since it was a workaround for old buggy Java, - // and is now causing problems b/c cmd-click was opening popups on OS X. - // https://github.com/processing/processing/issues/2103 -// // isPopupTrigger wasn't working for danh on windows -// boolean trigger = (evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0; -// // but it's required for macosx, since control-click does -// // the same thing as a right-mouse click -// if (!trigger && evt.isPopupTrigger()) trigger = true; -// if (trigger && (popup != null)) { - if (evt.isPopupTrigger() && (popup != null)) { - popup.show(painter,evt.getX(),evt.getY()); + if (event.isPopupTrigger() && (popup != null)) { + System.out.println("firing popup press"); + popup.show(painter, event.getX(), event.getY()); return; } - int line = yToLine(evt.getY()); - int offset = xToOffset(line,evt.getX()); + int line = yToLine(event.getY()); + int offset = xToOffset(line, event.getX()); int dot = getLineStartOffset(line) + offset; selectLine = false; selectWord = false; - switch(evt.getClickCount()) { + switch (event.getClickCount()) { case 1: - doSingleClick(evt,line,offset,dot); + doSingleClick(event,line,offset,dot); break; case 2: - // It uses the bracket matching stuff, so - // it can throw a BLE + // It uses the bracket matching stuff, so it can throw a BLE try { - doDoubleClick(evt,line,offset,dot); - } catch(BadLocationException bl) { + doDoubleClick(event, line, offset, dot); + } catch (BadLocationException bl) { bl.printStackTrace(); } break; case 3: - doTripleClick(evt,line,offset,dot); + doTripleClick(event,line,offset,dot); break; } // } catch (ArrayIndexOutOfBoundsException aioobe) { @@ -2458,8 +2442,18 @@ public class JEditTextArea extends JComponent } - private void doSingleClick(MouseEvent evt, int line, - int offset, int dot) { + // Because isPopupTrigger() is handled differently across platforms, + // it may fire during release, or during the press. + // http://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseEvent.html#isPopupTrigger() + public void mouseReleased(MouseEvent event) { + if (event.isPopupTrigger() && (popup != null)) { + System.out.println("firing popup release"); + popup.show(painter, event.getX(), event.getY()); + } + } + + + private void doSingleClick(MouseEvent evt, int line, int offset, int dot) { if ((evt.getModifiers() & InputEvent.SHIFT_MASK) != 0) { rectSelect = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0; select(getMarkPosition(),dot); @@ -2469,35 +2463,32 @@ public class JEditTextArea extends JComponent } - private void doDoubleClick(MouseEvent evt, int line, - int offset, int dot) throws BadLocationException - { + private void doDoubleClick(MouseEvent evt, int line, int offset, + int dot) throws BadLocationException { // Ignore empty lines - if (getLineLength(line) == 0) - return; - - try { - int bracket = bracketHelper.findMatchingBracket(document.getText(0, document.getLength()), - Math.max(0,dot - 1)); - if (bracket != -1) { - int mark = getMarkPosition(); - // Hack - if (bracket > mark) { - bracket++; - mark--; + if (getLineLength(line) != 0) { + try { + String text = document.getText(0, document.getLength()); + int bracket = bracketHelper.findMatchingBracket(text, Math.max(0, dot - 1)); + if (bracket != -1) { + int mark = getMarkPosition(); + // Hack + if (bracket > mark) { + bracket++; + mark--; + } + select(mark,bracket); + return; } - select(mark,bracket); - return; + } catch(BadLocationException bl) { + bl.printStackTrace(); } - } catch(BadLocationException bl) { - bl.printStackTrace(); - } - setNewSelectionWord( line, offset ); - select(newSelectionStart,newSelectionEnd); - selectWord = true; - selectionAncorStart = selectionStart; - selectionAncorEnd = selectionEnd; + setNewSelectionWord( line, offset ); + select(newSelectionStart,newSelectionEnd); + selectWord = true; + selectionAncorStart = selectionStart; + selectionAncorEnd = selectionEnd; /* String lineText = getLineText(line); @@ -2508,11 +2499,11 @@ public class JEditTextArea extends JComponent int lineStart = getLineStartOffset(line); select(lineStart + wordStart,lineStart + wordEnd); */ - } + } + } - private void doTripleClick(MouseEvent evt, int line, - int offset, int dot) - { + + private void doTripleClick(MouseEvent evt, int line, int offset, int dot) { selectLine = true; select(getLineStartOffset(line),getLineSelectionStopOffset(line)); selectionAncorStart = selectionStart; @@ -2520,61 +2511,43 @@ public class JEditTextArea extends JComponent } } - class CaretUndo extends AbstractUndoableEdit - { + + class CaretUndo extends AbstractUndoableEdit { private int start; private int end; - CaretUndo(int start, int end) - { + CaretUndo(int start, int end) { this.start = start; this.end = end; } - public boolean isSignificant() - { + public boolean isSignificant() { return false; } - public String getPresentationName() - { + public String getPresentationName() { return "caret move"; } - public void undo() throws CannotUndoException - { + public void undo() throws CannotUndoException { super.undo(); - select(start,end); } - public void redo() throws CannotRedoException - { + public void redo() throws CannotRedoException { super.redo(); - select(start,end); } - public boolean addEdit(UndoableEdit edit) - { - if(edit instanceof CaretUndo) - { + public boolean addEdit(UndoableEdit edit) { + if (edit instanceof CaretUndo) { CaretUndo cedit = (CaretUndo)edit; start = cedit.start; end = cedit.end; cedit.die(); - return true; } - else - return false; + return false; } } - -// static -// { -// caretTimer = new Timer(500, new CaretBlinker()); -// caretTimer.setInitialDelay(500); -// caretTimer.start(); -// } } From 5196601ffc9a4a26214c841f3f50200353dc8075 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 6 Oct 2013 23:37:41 -0400 Subject: [PATCH 126/556] fixes for isPopupTrigger() issues --- app/src/processing/app/syntax/JEditTextArea.java | 2 -- todo.txt | 7 ++++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/processing/app/syntax/JEditTextArea.java b/app/src/processing/app/syntax/JEditTextArea.java index cb081a87d..b35e7b329 100644 --- a/app/src/processing/app/syntax/JEditTextArea.java +++ b/app/src/processing/app/syntax/JEditTextArea.java @@ -2403,7 +2403,6 @@ public class JEditTextArea extends JComponent } if (event.isPopupTrigger() && (popup != null)) { - System.out.println("firing popup press"); popup.show(painter, event.getX(), event.getY()); return; } @@ -2447,7 +2446,6 @@ public class JEditTextArea extends JComponent // http://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseEvent.html#isPopupTrigger() public void mouseReleased(MouseEvent event) { if (event.isPopupTrigger() && (popup != null)) { - System.out.println("firing popup release"); popup.show(painter, event.getX(), event.getY()); } } diff --git a/todo.txt b/todo.txt index 2098b45ff..937c2b689 100644 --- a/todo.txt +++ b/todo.txt @@ -13,9 +13,8 @@ X incorporate the new serial library X https://github.com/processing/processing/pull/2093 X cmd-left is bringing up the text area popup X https://github.com/processing/processing/issues/2103 - -_ still having right-click issues -_ https://github.com/processing/processing/issues/2103 +X still having right-click issues (re-opened) +X https://github.com/processing/processing/issues/2103 X add appbundler.jar, otherwise folks have to include Xcode _ if they want to build appbundler, they'll need Xcode @@ -119,6 +118,8 @@ _ "String index out of range" error _ https://github.com/processing/processing/issues/1940 _ freeze after splash screen on OS X (looks like core.jar in the path) _ https://github.com/processing/processing/issues/1872 +_ look through all isPopupTrigger() code +_ make sure both press/release are implemented medium _ use platformDelete() to remove untitled sketches? From 5414b13f487f5308022518a751005f4013fabc6c Mon Sep 17 00:00:00 2001 From: codeanticode Date: Mon, 7 Oct 2013 00:25:37 -0400 Subject: [PATCH 127/556] Added CustomBlend example --- .../Shaders/CustomBlend/CustomBlend.pde | 110 ++++++++++++++++++ .../Topics/Shaders/CustomBlend/data/burn.glsl | 22 ++++ .../Shaders/CustomBlend/data/difference.glsl | 22 ++++ .../Shaders/CustomBlend/data/dodge.glsl | 22 ++++ .../Shaders/CustomBlend/data/overlay.glsl | 28 +++++ 5 files changed, 204 insertions(+) create mode 100644 java/examples/Topics/Shaders/CustomBlend/CustomBlend.pde create mode 100644 java/examples/Topics/Shaders/CustomBlend/data/burn.glsl create mode 100644 java/examples/Topics/Shaders/CustomBlend/data/difference.glsl create mode 100644 java/examples/Topics/Shaders/CustomBlend/data/dodge.glsl create mode 100644 java/examples/Topics/Shaders/CustomBlend/data/overlay.glsl diff --git a/java/examples/Topics/Shaders/CustomBlend/CustomBlend.pde b/java/examples/Topics/Shaders/CustomBlend/CustomBlend.pde new file mode 100644 index 000000000..c6fb40b1d --- /dev/null +++ b/java/examples/Topics/Shaders/CustomBlend/CustomBlend.pde @@ -0,0 +1,110 @@ +/** + * Custom Blend + * + * The OpenGL-based renderers (P2D and P3D) only support some of the + * blending modes available in the default renderer. The reason for this + * is that the blend equations in OpenGL allow for combinations of the + * form dest_factor * dest_color + src_factor * src_color of the source and + * destination colors (see this page http://www.opengl.org/wiki/Blending + * for an extensive discussion of blending in OpenGL). + * Complex blending modes typically available in photo editing tools, + * like hard light or dodge, cannot be modeled with those equations. + * However, we can implement virtually any blending math directly in the + * fragment shader. + * + * This example shows how custom blend shaders can be loaded and used in + * Processing. + * For detailed information on how to implement Photoshop-like blending modes, + * check the following pages (a bit old but still useful): + * http://www.pegtop.net/delphi/articles/blendmodes/index.htm + * http://mouaif.wordpress.com/2009/01/05/photoshop-math-with-glsl-shaders/ + * + */ + +PImage destImage; +PImage srcImage; +PShader dodge; +PShader burn; +PShader overlay; +PShader difference; + +void setup() { + size(640, 360, P2D); + destImage = loadImage("leaves.jpg"); + srcImage = loadImage("moonwalk.jpg"); + + initShaders(); +} + +void draw() { + background(0); + + shader(dodge); + drawOutput(0, 0, width/2, height/2); + shader(burn); + drawOutput(width/2, 0, width/2, height/2); + shader(overlay); + drawOutput(0, height/2, width/2, height/2); + shader(difference); + drawOutput(width/2, height/2, width/2, height/2); + + noLoop(); +} + +void initShaders() { + dodge = loadShader("dodge.glsl"); + burn = loadShader("burn.glsl"); + overlay = loadShader("overlay.glsl"); + difference = loadShader("difference.glsl"); + + // The names destination and source come from the OpenGL terminology: + // destination from the image already in the framebuffer, or "base layer", + // and source for the image that will be blended into the framebuffer, or + // "blend layer": + dodge.set("destSampler", destImage); + dodge.set("srcSampler", srcImage); + burn.set("destSampler", destImage); + burn.set("srcSampler", srcImage); + overlay.set("destSampler", destImage); + overlay.set("srcSampler", srcImage); + difference.set("destSampler", destImage); + difference.set("srcSampler", srcImage); + + // We set the sizes of de st and src images, and the rectangular areas + // from the images that we will use for blending: + dodge.set("destSize", 640, 360); + dodge.set("destRect", 100, 50, 200, 200); + burn.set("destSize", 640, 360); + burn.set("destRect", 100, 50, 200, 200); + overlay.set("destSize", 640, 360); + overlay.set("destRect", 100, 50, 200, 200); + difference.set("destSize", 640, 360); + difference.set("destRect", 100, 50, 200, 200); + + dodge.set("srcSize", 640, 360); + dodge.set("srcRect", 0, 0, 640, 360); + burn.set("srcSize", 640, 360); + burn.set("srcRect", 0, 0, 640, 360); + overlay.set("srcSize", 640, 360); + overlay.set("srcRect", 0, 0, 640, 360); + difference.set("srcSize", 640, 360); + difference.set("srcRect", 0, 0, 640, 360); +} + +void drawOutput(float x, float y, float w, float h) { + pushMatrix(); + translate(x, y); + noStroke(); + beginShape(QUAD); + // Although we are not associating a texture to + // this shape, the uv coordinates will be stored + // anyways so they can be used in the fragment + // shader to access the destination and source + // images. + vertex(0, 0, 0, 0); + vertex(w, 0, 1, 0); + vertex(w, h, 1, 1); + vertex(0, h, 0, 1); + endShape(); + popMatrix(); +} diff --git a/java/examples/Topics/Shaders/CustomBlend/data/burn.glsl b/java/examples/Topics/Shaders/CustomBlend/data/burn.glsl new file mode 100644 index 000000000..0d090a6ac --- /dev/null +++ b/java/examples/Topics/Shaders/CustomBlend/data/burn.glsl @@ -0,0 +1,22 @@ +uniform sampler2D destSampler; +uniform sampler2D srcSampler; + +uniform ivec2 destSize; +uniform ivec4 destRect; + +uniform ivec2 srcSize; +uniform ivec4 srcRect; + +varying vec4 vertTexCoord; + +void main() { + vec2 st = vertTexCoord.st; + + vec2 dest = vec2(destRect.xy) / vec2(destSize) + st * vec2(destRect.zw) / vec2(destSize); + vec2 src = vec2(srcRect.xy) / vec2(srcSize) + st * vec2(srcRect.zw) / vec2(srcSize); + + vec3 destColor = texture2D(destSampler, dest).rgb; + vec3 srcColor = texture2D(srcSampler, src).rgb; + + gl_FragColor = vec4(1.0 - (1.0 - destColor) / srcColor, 1.0); +} \ No newline at end of file diff --git a/java/examples/Topics/Shaders/CustomBlend/data/difference.glsl b/java/examples/Topics/Shaders/CustomBlend/data/difference.glsl new file mode 100644 index 000000000..7f0040a22 --- /dev/null +++ b/java/examples/Topics/Shaders/CustomBlend/data/difference.glsl @@ -0,0 +1,22 @@ +uniform sampler2D destSampler; +uniform sampler2D srcSampler; + +uniform ivec2 destSize; +uniform ivec4 destRect; + +uniform ivec2 srcSize; +uniform ivec4 srcRect; + +varying vec4 vertTexCoord; + +void main() { + vec2 st = vertTexCoord.st; + + vec2 dest = vec2(destRect.xy) / vec2(destSize) + st * vec2(destRect.zw) / vec2(destSize); + vec2 src = vec2(srcRect.xy) / vec2(srcSize) + st * vec2(srcRect.zw) / vec2(srcSize); + + vec3 destColor = texture2D(destSampler, dest).rgb; + vec3 srcColor = texture2D(srcSampler, src).rgb; + + gl_FragColor = vec4(abs(srcColor - destColor), 1.0); +} \ No newline at end of file diff --git a/java/examples/Topics/Shaders/CustomBlend/data/dodge.glsl b/java/examples/Topics/Shaders/CustomBlend/data/dodge.glsl new file mode 100644 index 000000000..115dbaa09 --- /dev/null +++ b/java/examples/Topics/Shaders/CustomBlend/data/dodge.glsl @@ -0,0 +1,22 @@ +uniform sampler2D destSampler; +uniform sampler2D srcSampler; + +uniform ivec2 destSize; +uniform ivec4 destRect; + +uniform ivec2 srcSize; +uniform ivec4 srcRect; + +varying vec4 vertTexCoord; + +void main() { + vec2 st = vertTexCoord.st; + + vec2 dest = vec2(destRect.xy) / vec2(destSize) + st * vec2(destRect.zw) / vec2(destSize); + vec2 src = vec2(srcRect.xy) / vec2(srcSize) + st * vec2(srcRect.zw) / vec2(srcSize); + + vec3 destColor = texture2D(destSampler, dest).rgb; + vec3 srcColor = texture2D(srcSampler, src).rgb; + + gl_FragColor = vec4(destColor / (1.0 - srcColor), 1.0); +} \ No newline at end of file diff --git a/java/examples/Topics/Shaders/CustomBlend/data/overlay.glsl b/java/examples/Topics/Shaders/CustomBlend/data/overlay.glsl new file mode 100644 index 000000000..f7d28efac --- /dev/null +++ b/java/examples/Topics/Shaders/CustomBlend/data/overlay.glsl @@ -0,0 +1,28 @@ +uniform sampler2D destSampler; +uniform sampler2D srcSampler; + +uniform ivec2 destSize; +uniform ivec4 destRect; + +uniform ivec2 srcSize; +uniform ivec4 srcRect; + +varying vec4 vertTexCoord; + +void main() { + vec2 st = vertTexCoord.st; + + vec2 dest = vec2(destRect.xy) / vec2(destSize) + st * vec2(destRect.zw) / vec2(destSize); + vec2 src = vec2(srcRect.xy) / vec2(srcSize) + st * vec2(srcRect.zw) / vec2(srcSize); + + vec3 destColor = texture2D(destSampler, dest).rgb; + vec3 srcColor = texture2D(srcSampler, src).rgb; + + float luminance = dot(vec3(0.2126, 0.7152, 0.0722), destColor); + + if (luminance < 0.5) { + gl_FragColor = vec4(2.0 * destColor * srcColor, 1.0); + } else { + gl_FragColor = vec4(1.0 - 2.0 * (1.0 - destColor) * (1.0 - srcColor), 1); + } +} \ No newline at end of file From 40198890bbafdbfb4a5e28158b435ae10a17a80c Mon Sep 17 00:00:00 2001 From: codeanticode Date: Mon, 7 Oct 2013 00:30:15 -0400 Subject: [PATCH 128/556] solved some issues in PShader, better handling of gl buffers when using built-in shaders --- .../processing/opengl/PGraphicsOpenGL.java | 172 +++++++++--------- core/src/processing/opengl/PShader.java | 2 +- core/src/processing/opengl/PShapeOpenGL.java | 24 +-- core/src/processing/opengl/TextureVert.glsl | 2 +- 4 files changed, 102 insertions(+), 98 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 876345526..ef7f30235 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -84,12 +84,6 @@ public class PGraphicsOpenGL extends PGraphics { "shader() called with a wrong shader"; static final String UNKNOWN_SHADER_KIND_ERROR = "Unknown shader kind"; - static final String LIGHT_SHADER_ERROR = - "The shader expects lights but it is beging used to draw an unlit scene, " + - "this might lead to unexpected rendering errors."; - static final String TEXTURE_SHADER_ERROR = - "The shader expects textures but it is being used to draw an untextured scene, " + - "this might lead to unexpected rendering errors."; static final String TOO_LONG_STROKE_PATH_ERROR = "Stroke path is too long, some bevel triangles won't be added"; static final String TESSELLATION_ERROR = @@ -1294,7 +1288,8 @@ public class PGraphicsOpenGL extends PGraphics { } - protected void updatePolyBuffers(boolean lit, boolean tex) { + protected void updatePolyBuffers(boolean lit, boolean tex, + boolean needNormals, boolean needTexCoords) { createPolyBuffers(); int size = tessGeo.polyVertexCount; @@ -1312,11 +1307,6 @@ public class PGraphicsOpenGL extends PGraphics { tessGeo.polyColorsBuffer, PGL.STATIC_DRAW); if (lit) { - tessGeo.updatePolyNormalsBuffer(); - pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyNormal); - pgl.bufferData(PGL.ARRAY_BUFFER, 3 * sizef, - tessGeo.polyNormalsBuffer, PGL.STATIC_DRAW); - tessGeo.updatePolyAmbientBuffer(); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyAmbient); pgl.bufferData(PGL.ARRAY_BUFFER, sizei, @@ -1337,8 +1327,14 @@ public class PGraphicsOpenGL extends PGraphics { pgl.bufferData(PGL.ARRAY_BUFFER, sizef, tessGeo.polyShininessBuffer, PGL.STATIC_DRAW); } + if (lit || needNormals) { + tessGeo.updatePolyNormalsBuffer(); + pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyNormal); + pgl.bufferData(PGL.ARRAY_BUFFER, 3 * sizef, + tessGeo.polyNormalsBuffer, PGL.STATIC_DRAW); + } - if (tex) { + if (tex || needTexCoords) { tessGeo.updatePolyTexCoordsBuffer(); pgl.bindBuffer(PGL.ARRAY_BUFFER, glPolyTexcoord); pgl.bufferData(PGL.ARRAY_BUFFER, 2 * sizef, @@ -2381,7 +2377,11 @@ public class PGraphicsOpenGL extends PGraphics { protected void flushPolys() { - updatePolyBuffers(lights, texCache.hasTextures); + boolean customShader = polyShader != null; + boolean needNormals = customShader ? polyShader.accessNormals() : false; + boolean needTexCoords = customShader ? polyShader.accessTexCoords() : false; + + updatePolyBuffers(lights, texCache.hasTextures, needNormals, needTexCoords); for (int i = 0; i < texCache.size; i++) { Texture tex = texCache.getTexture(i); @@ -2405,10 +2405,6 @@ public class PGraphicsOpenGL extends PGraphics { 4 * voffset * PGL.SIZEOF_FLOAT); shader.setColorAttribute(glPolyColor, 4, PGL.UNSIGNED_BYTE, 0, 4 * voffset * PGL.SIZEOF_BYTE); - shader.setNormalAttribute(glPolyNormal, 3, PGL.FLOAT, 0, - 3 * voffset * PGL.SIZEOF_FLOAT); - shader.setTexcoordAttribute(glPolyTexcoord, 2, PGL.FLOAT, 0, - 2 * voffset * PGL.SIZEOF_FLOAT); if (lights) { shader.setNormalAttribute(glPolyNormal, 3, PGL.FLOAT, 0, @@ -2421,14 +2417,17 @@ public class PGraphicsOpenGL extends PGraphics { 4 * voffset * PGL.SIZEOF_BYTE); shader.setShininessAttribute(glPolyShininess, 1, PGL.FLOAT, 0, voffset * PGL.SIZEOF_FLOAT); - } else if (shader.supportLighting()) { - PGraphics.showWarning(LIGHT_SHADER_ERROR); } - if (tex != null) { + if (lights || needNormals) { + shader.setNormalAttribute(glPolyNormal, 3, PGL.FLOAT, 0, + 3 * voffset * PGL.SIZEOF_FLOAT); + } + + if (tex != null || needTexCoords) { + shader.setTexcoordAttribute(glPolyTexcoord, 2, PGL.FLOAT, 0, + 2 * voffset * PGL.SIZEOF_FLOAT); shader.setTexture(tex); - } else if (shader.supportsTexturing()) { - PGraphics.showWarning(TEXTURE_SHADER_ERROR); } pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, glPolyIndex); @@ -5539,7 +5538,8 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void filter(PShader shader) { - if (!(shader instanceof PolyShader) || !((PolyShader)shader).supportsTexturing()) { + if (!(shader instanceof PolyShader) || + !((PolyShader)shader).supportsTexturing()) { PGraphics.showWarning(INVALID_FILTER_SHADER_ERROR); return; } @@ -5671,7 +5671,7 @@ public class PGraphicsOpenGL extends PGraphics { * Allows to set custom blend modes for the entire scene, using openGL. * Reference article about blending modes: * http://www.pegtop.net/delphi/articles/blendmodes/ - * HARD_LIGHT, SOFT_LIGHT, OVERLAY, DODGE, BURN modes cannot be + * DIFFERENCE, HARD_LIGHT, SOFT_LIGHT, OVERLAY, DODGE, BURN modes cannot be * implemented in fixed-function pipeline because they require * conditional blending and non-linear blending equations. */ @@ -5726,12 +5726,6 @@ public class PGraphicsOpenGL extends PGraphics { PGraphics.showWarning(BLEND_DRIVER_ERROR, "DARKEST"); } - } else if (blendMode == DIFFERENCE) { - if (blendEqSupported) { - pgl.blendEquation(PGL.FUNC_ADD); - } - pgl.blendFunc(PGL.ONE_MINUS_DST_COLOR, PGL.ZERO); - } else if (blendMode == EXCLUSION) { if (blendEqSupported) { pgl.blendEquation(PGL.FUNC_ADD); @@ -5750,6 +5744,9 @@ public class PGraphicsOpenGL extends PGraphics { } pgl.blendFunc(PGL.ONE_MINUS_DST_COLOR, PGL.ONE); + } else if (blendMode == DIFFERENCE) { + PGraphics.showWarning(BLEND_RENDERER_ERROR, "DIFFERENCE"); + } else if (blendMode == OVERLAY) { PGraphics.showWarning(BLEND_RENDERER_ERROR, "OVERLAY"); @@ -6645,7 +6642,7 @@ public class PGraphicsOpenGL extends PGraphics { } if (-1 < bufferLoc) { - bufferUnit = getLastTexUnit() + 1; + bufferUnit = super.getLastTexUnit() + 1; setUniformValue(bufferLoc, bufferUnit); pgl.activeTexture(PGL.TEXTURE0 + bufferUnit); pgCurrent.bindFrontTexture(); @@ -6654,6 +6651,11 @@ public class PGraphicsOpenGL extends PGraphics { } } + @Override + public int getLastTexUnit() { + return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit(); + } + public boolean supportsTexturing() { return false; } @@ -6662,6 +6664,14 @@ public class PGraphicsOpenGL extends PGraphics { return false; } + public boolean accessTexCoords() { + return false; + } + + public boolean accessNormals() { + return false; + } + public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { } public void setColorAttribute(int vboId, int size, int type, @@ -6760,32 +6770,40 @@ public class PGraphicsOpenGL extends PGraphics { texOffsetLoc = getUniformLoc("texOffset"); } -// @Override -// public int getLastTexUnit() { -// return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit(); -// } - @Override public void setTexture(Texture tex) { + texture = tex; + float scaleu = 1; float scalev = 1; float dispu = 0; float dispv = 0; - if (tex.invertedX()) { - scaleu = -1; - dispu = 1; - } + if (tex != null) { + if (tex.invertedX()) { + scaleu = -1; + dispu = 1; + } - if (tex.invertedY()) { - scalev = -1; - dispv = 1; - } + if (tex.invertedY()) { + scalev = -1; + dispv = 1; + } - scaleu *= tex.maxTexcoordU(); - dispu *= tex.maxTexcoordU(); - scalev *= tex.maxTexcoordV(); - dispv *= tex.maxTexcoordV(); + scaleu *= tex.maxTexcoordU(); + dispu *= tex.maxTexcoordU(); + scalev *= tex.maxTexcoordV(); + dispv *= tex.maxTexcoordV(); + + setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height); + + if (-1 < textureLoc) { + texUnit = getLastTexUnit() + 1; + setUniformValue(textureLoc, texUnit); + pgl.activeTexture(PGL.TEXTURE0 + texUnit); + tex.bind(); + } + } if (-1 < texMatrixLoc) { if (tcmat == null) { @@ -6797,16 +6815,6 @@ public class PGraphicsOpenGL extends PGraphics { tcmat[3] = 0; tcmat[7] = 0; tcmat[11] = 0; tcmat[15] = 0; setUniformMatrix(texMatrixLoc, tcmat); } - - setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height); - - if (-1 < textureLoc) { - texUnit = getLastTexUnit() + 1; - setUniformValue(textureLoc, texUnit); - pgl.activeTexture(PGL.TEXTURE0 + texUnit); - tex.bind(); - texture = tex; - } } @Override @@ -6819,6 +6827,16 @@ public class PGraphicsOpenGL extends PGraphics { return -1 < lightCountLoc || -1 < lightPositionLoc || -1 < lightNormalLoc; } + @Override + public boolean accessTexCoords() { + return -1 < texCoordLoc; + } + + @Override + public boolean accessNormals() { + return -1 < normalLoc; + } + @Override public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { @@ -6894,14 +6912,16 @@ public class PGraphicsOpenGL extends PGraphics { int count = pgCurrent.lightCount; setUniformValue(lightCountLoc, count); - setUniformVector(lightPositionLoc, pgCurrent.lightPosition, 4, count); - setUniformVector(lightNormalLoc, pgCurrent.lightNormal, 3, count); - setUniformVector(lightAmbientLoc, pgCurrent.lightAmbient, 3, count); - setUniformVector(lightDiffuseLoc, pgCurrent.lightDiffuse, 3, count); - setUniformVector(lightSpecularLoc, pgCurrent.lightSpecular, 3, count); - setUniformVector(lightFalloffLoc, pgCurrent.lightFalloffCoefficients, - 3, count); - setUniformVector(lightSpotLoc, pgCurrent.lightSpotParameters, 2, count); + if (0 < count) { + setUniformVector(lightPositionLoc, pgCurrent.lightPosition, 4, count); + setUniformVector(lightNormalLoc, pgCurrent.lightNormal, 3, count); + setUniformVector(lightAmbientLoc, pgCurrent.lightAmbient, 3, count); + setUniformVector(lightDiffuseLoc, pgCurrent.lightDiffuse, 3, count); + setUniformVector(lightSpecularLoc, pgCurrent.lightSpecular, 3, count); + setUniformVector(lightFalloffLoc, pgCurrent.lightFalloffCoefficients, + 3, count); + setUniformVector(lightSpotLoc, pgCurrent.lightSpotParameters, 2, count); + } } @Override @@ -8008,24 +8028,6 @@ public class PGraphicsOpenGL extends PGraphics { vert[SA] = ((strokeColors[i] >> 24) & 0xFF) / 255.0f; vert[SW] = strokeWeights[i]; - - /* - // Android doesn't have these: - vert[AR] = ((ambient[i] >> 16) & 0xFF) / 255.0f; - vert[AG] = ((ambient[i] >> 8) & 0xFF) / 255.0f; - vert[AB] = ((ambient[i] >> 0) & 0xFF) / 255.0f; - - vert[SPR] = ((specular[i] >> 16) & 0xFF) / 255.0f; - vert[SPG] = ((specular[i] >> 8) & 0xFF) / 255.0f; - vert[SPB] = ((specular[i] >> 0) & 0xFF) / 255.0f; - - vert[ER] = ((emissive[i] >> 16) & 0xFF) / 255.0f; - vert[EG] = ((emissive[i] >> 8) & 0xFF) / 255.0f; - vert[EB] = ((emissive[i] >> 0) & 0xFF) / 255.0f; - - vert[SHINE] = shininess[i]; - */ - } return data; diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShader.java index 5c390a55d..0bc608368 100644 --- a/core/src/processing/opengl/PShader.java +++ b/core/src/processing/opengl/PShader.java @@ -265,7 +265,7 @@ public class PShader { * @param w fourth component of the variable to modify. The variable has to be declared with an array/vector type in the shader (i.e.: int[4], vec4) */ public void set(String name, int x, int y, int z, int w) { - setUniformImpl(name, UniformValue.INT4, new int[] { x, y, z }); + setUniformImpl(name, UniformValue.INT4, new int[] { x, y, z, w }); } diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index b2bdceacd..bd33f666f 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -33,9 +33,9 @@ import processing.core.PShape; import processing.core.PVector; import processing.opengl.PGraphicsOpenGL.LineShader; import processing.opengl.PGraphicsOpenGL.PointShader; -import processing.opengl.PGraphicsOpenGL.BaseShader; import processing.opengl.PGraphicsOpenGL.IndexCache; import processing.opengl.PGraphicsOpenGL.InGeometry; +import processing.opengl.PGraphicsOpenGL.PolyShader; import processing.opengl.PGraphicsOpenGL.TessGeometry; import processing.opengl.PGraphicsOpenGL.Tessellator; @@ -4432,10 +4432,14 @@ public class PShapeOpenGL extends PShape { protected void renderPolys(PGraphicsOpenGL g, PImage textureImage) { + boolean customShader = g.polyShader != null; + boolean needNormals = customShader ? g.polyShader.accessNormals() : false; + boolean needTexCoords = customShader ? g.polyShader.accessTexCoords() : false; + Texture tex = textureImage != null ? g.getTexture(textureImage) : null; boolean renderingFill = false, renderingStroke = false; - BaseShader shader = null; + PolyShader shader = null; IndexCache cache = tessGeo.polyIndexCache; for (int n = firstPolyIndexCache; n <= lastPolyIndexCache; n++) { if (is3D() || (tex != null && (firstLineIndexCache == -1 || @@ -4478,10 +4482,6 @@ public class PShapeOpenGL extends PShape { 0, 4 * voffset * PGL.SIZEOF_FLOAT); shader.setColorAttribute(root.glPolyColor, 4, PGL.UNSIGNED_BYTE, 0, 4 * voffset * PGL.SIZEOF_BYTE); - shader.setNormalAttribute(root.glPolyNormal, 3, PGL.FLOAT, - 0, 3 * voffset * PGL.SIZEOF_FLOAT); - shader.setTexcoordAttribute(root.glPolyTexcoord, 2, PGL.FLOAT, - 0, 2 * voffset * PGL.SIZEOF_FLOAT); if (g.lights) { shader.setNormalAttribute(root.glPolyNormal, 3, PGL.FLOAT, @@ -4494,14 +4494,16 @@ public class PShapeOpenGL extends PShape { 0, 4 * voffset * PGL.SIZEOF_BYTE); shader.setShininessAttribute(root.glPolyShininess, 1, PGL.FLOAT, 0, voffset * PGL.SIZEOF_FLOAT); - } else if (shader.supportLighting()) { - PGraphics.showWarning(PGraphicsOpenGL.LIGHT_SHADER_ERROR); + } + if (g.lights || needNormals) { + shader.setNormalAttribute(root.glPolyNormal, 3, PGL.FLOAT, + 0, 3 * voffset * PGL.SIZEOF_FLOAT); } - if (tex != null) { + if (tex != null || needTexCoords) { + shader.setTexcoordAttribute(root.glPolyTexcoord, 2, PGL.FLOAT, + 0, 2 * voffset * PGL.SIZEOF_FLOAT); shader.setTexture(tex); - } else if (shader.supportsTexturing()) { - PGraphics.showWarning(PGraphicsOpenGL.TEXTURE_SHADER_ERROR); } pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, root.glPolyIndex); diff --git a/core/src/processing/opengl/TextureVert.glsl b/core/src/processing/opengl/TextureVert.glsl index cbbb361b1..87f101536 100644 --- a/core/src/processing/opengl/TextureVert.glsl +++ b/core/src/processing/opengl/TextureVert.glsl @@ -18,7 +18,7 @@ Boston, MA 02111-1307 USA */ -//#define PROCESSING_TEXTURE_SHADER +#define PROCESSING_TEXTURE_SHADER uniform mat4 transformMatrix; uniform mat4 texMatrix; From d338bdebabef4534f8d340028c9850502ba4c0b4 Mon Sep 17 00:00:00 2001 From: Benjamin Maus Date: Mon, 7 Oct 2013 15:32:38 +0200 Subject: [PATCH 129/556] Not reapplying settings after sizing, because it calls smooth() without parameters. With smooth(4) called in setup, this would lead do a complete reinitialization of the canvas and thus crashing natively... --- core/src/processing/opengl/PGraphicsOpenGL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 44f764994..995712ca0 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -6143,7 +6143,7 @@ public class PGraphicsOpenGL extends PGraphics { pgl.disable(PGL.POLYGON_SMOOTH); if (sized) { - reapplySettings(); + //reapplySettings(); // To avoid having garbage in the screen after a resize, // in the case background is not called in draw(). From 54c9409d5d80bda8210c8daf37d48f5fa44c4da8 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Mon, 7 Oct 2013 16:21:49 -0400 Subject: [PATCH 130/556] constrain lerpColor() between 0 and 1 --- core/src/processing/core/PGraphics.java | 3 +++ core/todo.txt | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index 037ae6fa8..dc47a2c6c 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -7635,6 +7635,9 @@ public class PGraphics extends PImage implements PConstants { * individual color components of a color supplied as an int value. */ static public int lerpColor(int c1, int c2, float amt, int mode) { + if (amt < 0) amt = 0; + if (amt > 1) amt = 1; + if (mode == RGB) { float a1 = ((c1 >> 24) & 0xff); float r1 = (c1 >> 16) & 0xff; diff --git a/core/todo.txt b/core/todo.txt index fd4b3fc53..41f5106fe 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -14,6 +14,10 @@ X fix image transparency in PDF output X https://github.com/processing/processing/pull/2070 X Java2D images crash after being resized X https://github.com/processing/processing/issues/2113 +X constrain lerpColor() between 0 and 1 + +_ JSONObject/Array.format(-1) not working on embedded JSONObjects +_ https://github.com/processing/processing/issues/2119 opengl X fix inconsistency with P2D and resetMatrix() @@ -28,6 +32,8 @@ X push/popStyle() causes color problems with P2D/P3D X https://github.com/processing/processing/issues/2102 X child SVG elements misplaced when rendering with P2D/P3D X https://github.com/processing/processing/issues/2086 +X SUBTRACT and DIFFERENCE blend modes are swapped +X https://github.com/processing/processing/issues/2075 _ Sort out blending differences with P2D/P3D _ https://github.com/processing/processing/issues/1844 From bb1c16c7fc569e060e8915de7ffe2a35ba8f17f0 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Mon, 7 Oct 2013 18:48:19 -0400 Subject: [PATCH 131/556] some more tweaks to shader loading and selection --- .../processing/opengl/PGraphicsOpenGL.java | 80 ++++++++++++++++++- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index ef7f30235..626035891 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -82,8 +82,23 @@ public class PGraphicsOpenGL extends PGraphics { "The vertex and fragment shaders have different types"; static final String WRONG_SHADER_TYPE_ERROR = "shader() called with a wrong shader"; + static final String SHADER_NEED_LIGHT_ATTRIBS = + "The provided shader needs light attributes (ambient, diffuse, etc.), but " + + "the current scene is unlit, so the default shader will be used instead"; static final String UNKNOWN_SHADER_KIND_ERROR = "Unknown shader kind"; + static final String NO_TEXLIGHT_SHADER_ERROR = + "Your shader needs to be of TEXLIGHT type " + + "to render this geometry properly, using default shader instead."; + static final String NO_LIGHT_SHADER_ERROR = + "Your shader needs to be of LIGHT type " + + "to render this geometry properly, using default shader instead."; + static final String NO_TEXTURE_SHADER_ERROR = + "Your shader needs to be of TEXTURE type " + + "to render this geometry properly, using default shader instead."; + static final String NO_COLOR_SHADER_ERROR = + "Your shader needs to be of COLOR type " + + "to render this geometry properly, using default shader instead."; static final String TOO_LONG_STROKE_PATH_ERROR = "Stroke path is too long, some bevel triangles won't be added"; static final String TESSELLATION_ERROR = @@ -6294,15 +6309,19 @@ public class PGraphicsOpenGL extends PGraphics { } else if (shaderType == PShader.TEXLIGHT) { shader = new PolyShader(parent); shader.setVertexShader(defTexlightShaderVertURL); + ((PolyShader)shader).setType(PShader.TEXLIGHT); } else if (shaderType == PShader.LIGHT) { shader = new PolyShader(parent); shader.setVertexShader(defLightShaderVertURL); + ((PolyShader)shader).setType(PShader.LIGHT); } else if (shaderType == PShader.TEXTURE) { shader = new PolyShader(parent); + ((PolyShader)shader).setType(PShader.TEXTURE); shader.setVertexShader(defTextureShaderVertURL); } else if (shaderType == PShader.COLOR) { shader = new PolyShader(parent); shader.setVertexShader(defColorShaderVertURL); + ((PolyShader)shader).setType(PShader.COLOR); } else { shader = new PolyShader(parent); shader.setVertexShader(defTextureShaderVertURL); @@ -6344,15 +6363,19 @@ public class PGraphicsOpenGL extends PGraphics { } else if (shaderType == PShader.TEXLIGHT) { shader = new PolyShader(parent); shader.setFragmentShader(defTextureShaderFragURL); + ((PolyShader)shader).setType(PShader.TEXLIGHT); } else if (shaderType == PShader.LIGHT) { shader = new PolyShader(parent); shader.setFragmentShader(defColorShaderFragURL); + ((PolyShader)shader).setType(PShader.LIGHT); } else if (shaderType == PShader.TEXTURE) { shader = new PolyShader(parent); shader.setFragmentShader(defTextureShaderFragURL); + ((PolyShader)shader).setType(PShader.TEXTURE); } else if (shaderType == PShader.COLOR) { shader = new PolyShader(parent); shader.setFragmentShader(defColorShaderFragURL); + ((PolyShader)shader).setType(PShader.COLOR); } else { shader = new PolyShader(parent); shader.setVertexShader(defTextureShaderVertURL); @@ -6476,9 +6499,10 @@ public class PGraphicsOpenGL extends PGraphics { protected PolyShader getPolyShader(boolean lit, boolean tex) { PolyShader shader; + boolean useDefault = polyShader == null; if (lit) { if (tex) { - if (polyShader == null) { + if (useDefault || !polyShader.checkType(PShader.TEXLIGHT)) { if (defTexlightShader == null) { defTexlightShader = new PolyShader(parent, defTexlightShaderVertURL, @@ -6489,7 +6513,7 @@ public class PGraphicsOpenGL extends PGraphics { shader = polyShader; } } else { - if (polyShader == null) { + if (useDefault || !polyShader.checkType(PShader.LIGHT)) { if (defLightShader == null) { defLightShader = new PolyShader(parent, defLightShaderVertURL, @@ -6501,8 +6525,13 @@ public class PGraphicsOpenGL extends PGraphics { } } } else { + if (polyShader != null && polyShader.accessLightAttribs()) { + PGraphics.showWarning(SHADER_NEED_LIGHT_ATTRIBS); + useDefault = true; + } + if (tex) { - if (polyShader == null) { + if (useDefault || !polyShader.checkType(PShader.TEXTURE)) { if (defTextureShader == null) { defTextureShader = new PolyShader(parent, defTextureShaderVertURL, @@ -6513,7 +6542,7 @@ public class PGraphicsOpenGL extends PGraphics { shader = polyShader; } } else { - if (polyShader == null) { + if (useDefault || !polyShader.checkType(PShader.COLOR)) { if (defColorShader == null) { defColorShader = new PolyShader(parent, defColorShaderVertURL, @@ -6672,6 +6701,10 @@ public class PGraphicsOpenGL extends PGraphics { return false; } + public boolean accessLightAttribs() { + return false; + } + public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { } public void setColorAttribute(int vboId, int size, int type, @@ -6693,6 +6726,8 @@ public class PGraphicsOpenGL extends PGraphics { protected class PolyShader extends BaseShader { + protected int type = 0; + protected int vertexLoc; protected int colorLoc; protected int normalLoc; @@ -6817,6 +6852,37 @@ public class PGraphicsOpenGL extends PGraphics { } } + public boolean hasType() { + return COLOR <= type && type <= TEXLIGHT; + } + + public void setType(int type) { + this.type = type; + } + + public int getType() { + return type; + } + + public boolean checkType(int type) { + if (!hasType()) return true; + + if (getType() != type) { + if (type == TEXLIGHT) { + PGraphics.showWarning(NO_TEXLIGHT_SHADER_ERROR); + } else if (type == LIGHT) { + PGraphics.showWarning(NO_LIGHT_SHADER_ERROR); + } else if (type == TEXTURE) { + PGraphics.showWarning(NO_TEXTURE_SHADER_ERROR); + } else if (type == COLOR) { + PGraphics.showWarning(NO_COLOR_SHADER_ERROR); + } + return false; + } + + return true; + } + @Override public boolean supportsTexturing() { return -1 < textureLoc; @@ -6837,6 +6903,12 @@ public class PGraphicsOpenGL extends PGraphics { return -1 < normalLoc; } + @Override + public boolean accessLightAttribs() { + return -1 < ambientLoc || -1 < specularLoc || -1 < emissiveLoc || + -1 < shininessLoc; + } + @Override public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { From 2acfefddf0fd69fbaacb7f9e5d93e8c187a09e4e Mon Sep 17 00:00:00 2001 From: codeanticode Date: Mon, 7 Oct 2013 19:14:33 -0400 Subject: [PATCH 132/556] first load attributes for custom shaders --- core/src/processing/opengl/PGraphicsOpenGL.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 626035891..3cd19c3cd 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -6500,6 +6500,11 @@ public class PGraphicsOpenGL extends PGraphics { protected PolyShader getPolyShader(boolean lit, boolean tex) { PolyShader shader; boolean useDefault = polyShader == null; + if (polyShader != null) { + polyShader.setRenderer(this); + polyShader.loadAttributes(); + polyShader.loadUniforms(); + } if (lit) { if (tex) { if (useDefault || !polyShader.checkType(PShader.TEXLIGHT)) { @@ -6554,9 +6559,11 @@ public class PGraphicsOpenGL extends PGraphics { } } } - shader.setRenderer(this); - shader.loadAttributes(); - shader.loadUniforms(); + if (shader != polyShader) { + shader.setRenderer(this); + shader.loadAttributes(); + shader.loadUniforms(); + } return shader; } From 0898ce1a45f5b00805b9b4864c198386b04392b5 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 8 Oct 2013 19:57:40 -0400 Subject: [PATCH 133/556] improvements to MovieMaker, add Gamma support, better Image IO --- build/shared/tools/MovieMaker/.classpath | 1 + build/shared/tools/MovieMaker/.gitignore | 4 +- build/shared/tools/MovieMaker/build.xml | 4 +- .../media/quicktime/QuickTimeWriter.java | 34 ++- .../src/processing/app/tools/MovieMaker.java | 286 ++++++++++++++++-- build/shared/tools/MovieMaker/tool/.gitignore | 2 + 6 files changed, 304 insertions(+), 27 deletions(-) create mode 100644 build/shared/tools/MovieMaker/tool/.gitignore diff --git a/build/shared/tools/MovieMaker/.classpath b/build/shared/tools/MovieMaker/.classpath index 74aba6a10..33f763597 100644 --- a/build/shared/tools/MovieMaker/.classpath +++ b/build/shared/tools/MovieMaker/.classpath @@ -3,5 +3,6 @@ + diff --git a/build/shared/tools/MovieMaker/.gitignore b/build/shared/tools/MovieMaker/.gitignore index 06fd927b5..7b057f39e 100644 --- a/build/shared/tools/MovieMaker/.gitignore +++ b/build/shared/tools/MovieMaker/.gitignore @@ -1,2 +1,4 @@ bin -tool + + + diff --git a/build/shared/tools/MovieMaker/build.xml b/build/shared/tools/MovieMaker/build.xml index a4b9bd7c0..eda108b57 100755 --- a/build/shared/tools/MovieMaker/build.xml +++ b/build/shared/tools/MovieMaker/build.xml @@ -11,11 +11,13 @@ Broken out as a separate project because the license probably isn't compatible with the rest of Processing and we don't want any confusion. + + Added JAI ImageIO to support lots of other image file formats [131008]. --> - + diff --git a/build/shared/tools/MovieMaker/src/ch/randelshofer/media/quicktime/QuickTimeWriter.java b/build/shared/tools/MovieMaker/src/ch/randelshofer/media/quicktime/QuickTimeWriter.java index 15893e41d..001ea9ada 100644 --- a/build/shared/tools/MovieMaker/src/ch/randelshofer/media/quicktime/QuickTimeWriter.java +++ b/build/shared/tools/MovieMaker/src/ch/randelshofer/media/quicktime/QuickTimeWriter.java @@ -1268,7 +1268,12 @@ public class QuickTimeWriter { // A 32-bit integer containing the number of sample descriptions that follow. // A 32-bit integer indicating the number of bytes in the sample description. - d.writeInt(86); // sampleDescriptionTable[0].size +// d.writeInt(86); // sampleDescriptionTable[0].size + d.writeInt(86 + 12); + // This looks like a bug, it'll be incorrect if the color table + // is written down below. [fry 131008] + // 12 bytes for gamma (appears from the file) + // 18 bytes for colr d.writeType(mediaCompressionType); // sampleDescriptionTable[0].type @@ -1353,13 +1358,36 @@ public class QuickTimeWriter { // for the specified depth. Depths of 16, 24, and 32 have no // color table. - - if (videoColorTable != null) { writeColorTableAtom(leaf); } + // Add gamma atom so things aren't all washed out [fry 131008] + writeGammaAtom(leaf); } + /** + * Color table atoms define a list of preferred colors for displaying + * the movie on devices that support only 256 colors. The list may + * contain up to 256 colors. These optional atoms have a type value of + * 'ctab'. The color table atom contains a Macintosh color table data + * structure. + * + * @param stblAtom + * @throws IOException + */ + protected void writeGammaAtom(CompositeAtom stblAtom) throws IOException { + DataAtom leaf; + DataAtomOutputStream d; + leaf = new DataAtom("gama"); + stblAtom.add(leaf); + + d = leaf.getOutputStream(); + + // Write the gamma value as a 16:16 fixed number + //d.writeFixed16D16(1.8); + d.writeFixed16D16(2.2); + } + /** * Color table atoms define a list of preferred colors for displaying * the movie on devices that support only 256 colors. The list may diff --git a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java index c3e29e860..9232cc3b9 100644 --- a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java +++ b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java @@ -26,11 +26,15 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; +import java.awt.image.WritableRaster; import java.io.File; import java.io.FileFilter; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.util.Arrays; import java.util.prefs.Preferences; + import javax.imageio.ImageIO; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; @@ -231,17 +235,18 @@ public class MovieMaker extends JFrame implements Tool { "This tool creates a QuickTime movie from a sequence of images.
    " + "
    " + "To avoid artifacts caused by re-compressing images as video,
    " + - "use uncompressed TIFF or (lossless) PNG images as the source.
    " + + "use TIFF, TGA (from Processing), or PNG images as the source.
    " + "
    " + - "TIFF images will write more quickly, but require more disk space:
    " + + "TIFF and TGA images will write more quickly, but require more disk:
    " + "saveFrame(\"frames/####.tif\");
    " + + "saveFrame(\"frames/####.tga\");
    " + "
    " + "PNG images are smaller, but your sketch will run more slowly:
    " + "saveFrame(\"frames/####.png\");
    " + "
    " + "This code is based on QuickTime Movie Maker 1.5.1 2011-01-17.
    " + - "Copyright © 2010-2011 Werner Randelshofer. All rights reserved.
    " + - "This software is licensed under Creative Commons Atribution 3.0."); + "Copyright \u00A9 2010-2011 Werner Randelshofer. All rights reserved.
    " + + "This software is licensed under Creative Commons Atribution 3.0."); imageFolderHelpLabel.setText("Drag a folder with image files into the field below:"); chooseImageFolderButton.setText("Choose..."); @@ -544,21 +549,32 @@ public class MovieMaker extends JFrame implements Tool { File[] imgFiles = null; if (imageFolder != null) { imgFiles = imageFolder.listFiles(new FileFilter() { - FileSystemView fsv = FileSystemView.getFileSystemView(); public boolean accept(File f) { return f.isFile() && !fsv.isHiddenFile(f) && !f.getName().equals("Thumbs.db"); } }); + if (imgFiles == null || imgFiles.length == 0) { + return new RuntimeException("No image files found."); + } Arrays.sort(imgFiles); } // Check on first image, if we can actually do pass through if (originalSize) { - ImageIcon temp = new ImageIcon(imgFiles[0].getAbsolutePath()); - width = temp.getIconWidth(); - height = temp.getIconHeight(); + // This was using ImageIcon, which can't handle some file types. + // For 2.1, switching to ImageIO (which is used for movie + // generation anyway) [fry 131008] + BufferedImage temp = readImage(imgFiles[0]); + if (temp == null) { + return new RuntimeException("Coult not read " + imgFiles[0].getAbsolutePath()); + } + width = temp.getWidth(); + height = temp.getHeight(); + if (width <= 0 || height <= 0) { + return new RuntimeException("Could not read " + imgFiles[0].getName() + ", it may be bad."); + } } // Delete movie file if it already exists. @@ -572,9 +588,9 @@ public class MovieMaker extends JFrame implements Tool { writeVideoOnlyVFR(movieFile, imgFiles, width, height, fps, videoFormat, /*passThrough,*/ streaming); } else { writeAudioOnly(movieFile, soundFile, streaming); - } return null; + } catch (Throwable t) { return t; } @@ -600,6 +616,232 @@ public class MovieMaker extends JFrame implements Tool { }//GEN-LAST:event_createMovie + + + private BufferedImage readImage(File file) throws IOException { + BufferedImage image = ImageIO.read(file); + + /* + String[] loadImageFormats = ImageIO.getReaderFormatNames(); + if (loadImageFormats != null) { + for (String format : loadImageFormats) { + System.out.println(format); + } + } + */ + + if (image == null) { + String path = file.getAbsolutePath(); + // Might be an incompatible TGA or TIFF created by Processing + if (path.toLowerCase().endsWith(".tga")) { + return loadImageTGA(file); + + } else if (path.toLowerCase().endsWith(".tif")) { + throw new IOException("Try TGA or PNG images instead of TIFF."); + } + } + return image; + } + + + /** + * Targa image loader for RLE-compressed TGA files. + *

    + * Rewritten for 0115 to read/write RLE-encoded targa images. + * For 0125, non-RLE encoded images are now supported, along with + * images whose y-order is reversed (which is standard for TGA files). + */ + static protected BufferedImage loadImageTGA(File file) throws IOException { + InputStream is = new FileInputStream(file); + if (is == null) return null; + + byte header[] = new byte[18]; + int offset = 0; + do { + int count = is.read(header, offset, header.length - offset); + if (count == -1) return null; + offset += count; + } while (offset < 18); + + /* + header[2] image type code + 2 (0x02) - Uncompressed, RGB images. + 3 (0x03) - Uncompressed, black and white images. + 10 (0x0A) - Runlength encoded RGB images. + 11 (0x0B) - Compressed, black and white images. (grayscale?) + + header[16] is the bit depth (8, 24, 32) + + header[17] image descriptor (packed bits) + 0x20 is 32 = origin upper-left + 0x28 is 32 + 8 = origin upper-left + 32 bits + + 7 6 5 4 3 2 1 0 + 128 64 32 16 8 4 2 1 + */ + + int format = 0; + final int RGB = 1; + final int ARGB = 2; + final int ALPHA = 4; + + if (((header[2] == 3) || (header[2] == 11)) && // B&W, plus RLE or not + (header[16] == 8) && // 8 bits + ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 bit + format = ALPHA; + + } else if (((header[2] == 2) || (header[2] == 10)) && // RGB, RLE or not + (header[16] == 24) && // 24 bits + ((header[17] == 0x20) || (header[17] == 0))) { // origin + format = RGB; + + } else if (((header[2] == 2) || (header[2] == 10)) && + (header[16] == 32) && + ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 + format = ARGB; + } + + if (format == 0) { + throw new IOException("Unknown .tga file format for " + file.getName()); + } + + int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff); + int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff); + //PImage outgoing = createImage(w, h, format); + int[] pixels = new int[w * h]; + + // where "reversed" means upper-left corner (normal for most of + // the modernized world, but "reversed" for the tga spec) + //boolean reversed = (header[17] & 0x20) != 0; + // https://github.com/processing/processing/issues/1682 + boolean reversed = (header[17] & 0x20) == 0; + + if ((header[2] == 2) || (header[2] == 3)) { // not RLE encoded + if (reversed) { + int index = (h-1) * w; + switch (format) { + case ALPHA: + for (int y = h-1; y >= 0; y--) { + for (int x = 0; x < w; x++) { + pixels[index + x] = is.read(); + } + index -= w; + } + break; + case RGB: + for (int y = h-1; y >= 0; y--) { + for (int x = 0; x < w; x++) { + pixels[index + x] = + is.read() | (is.read() << 8) | (is.read() << 16) | + 0xff000000; + } + index -= w; + } + break; + case ARGB: + for (int y = h-1; y >= 0; y--) { + for (int x = 0; x < w; x++) { + pixels[index + x] = + is.read() | (is.read() << 8) | (is.read() << 16) | + (is.read() << 24); + } + index -= w; + } + } + } else { // not reversed + int count = w * h; + switch (format) { + case ALPHA: + for (int i = 0; i < count; i++) { + pixels[i] = is.read(); + } + break; + case RGB: + for (int i = 0; i < count; i++) { + pixels[i] = + is.read() | (is.read() << 8) | (is.read() << 16) | + 0xff000000; + } + break; + case ARGB: + for (int i = 0; i < count; i++) { + pixels[i] = + is.read() | (is.read() << 8) | (is.read() << 16) | + (is.read() << 24); + } + break; + } + } + + } else { // header[2] is 10 or 11 + int index = 0; + + while (index < pixels.length) { + int num = is.read(); + boolean isRLE = (num & 0x80) != 0; + if (isRLE) { + num -= 127; // (num & 0x7F) + 1 + int pixel = 0; + switch (format) { + case ALPHA: + pixel = is.read(); + break; + case RGB: + pixel = 0xFF000000 | + is.read() | (is.read() << 8) | (is.read() << 16); + //(is.read() << 16) | (is.read() << 8) | is.read(); + break; + case ARGB: + pixel = is.read() | + (is.read() << 8) | (is.read() << 16) | (is.read() << 24); + break; + } + for (int i = 0; i < num; i++) { + pixels[index++] = pixel; + if (index == pixels.length) break; + } + } else { // write up to 127 bytes as uncompressed + num += 1; + switch (format) { + case ALPHA: + for (int i = 0; i < num; i++) { + pixels[index++] = is.read(); + } + break; + case RGB: + for (int i = 0; i < num; i++) { + pixels[index++] = 0xFF000000 | + is.read() | (is.read() << 8) | (is.read() << 16); + } + break; + case ARGB: + for (int i = 0; i < num; i++) { + pixels[index++] = is.read() | + (is.read() << 8) | (is.read() << 16) | (is.read() << 24); + } + break; + } + } + } + + if (!reversed) { + int[] temp = new int[w]; + for (int y = 0; y < h/2; y++) { + int z = (h-1) - y; + System.arraycopy(pixels, y*w, temp, 0, w); + System.arraycopy(pixels, z*w, pixels, y*w, w); + System.arraycopy(temp, 0, pixels, z*w, w); + } + } + } + int type = (format == RGB) ? + BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; + BufferedImage image = new BufferedImage(w, h, type); + WritableRaster wr = image.getRaster(); + wr.setDataElements(0, 0, w, h, pixels); + return image; + } + // private void streamingRadioPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_streamingRadioPerformed // prefs.put("movie.streaming", evt.getActionCommand()); @@ -937,20 +1179,20 @@ public class MovieMaker extends JFrame implements Tool { } } -// /** -// * @param args the command line arguments -// */ -// public static void main(String args[]) { -// EventQueue.invokeLater(new Runnable() { -// public void run() { -// MovieMakerFrame m = new MovieMakerFrame(); -//// m.init(null); + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + MovieMaker m = new MovieMaker(); + m.init(null); // m.init(); -// m.setVisible(true); -//// m.pack(); -// } -// }); -// } + m.setVisible(true); +// m.pack(); + } + }); + } private JLabel aboutLabel; private JButton chooseImageFolderButton; diff --git a/build/shared/tools/MovieMaker/tool/.gitignore b/build/shared/tools/MovieMaker/tool/.gitignore new file mode 100644 index 000000000..fb9e88d2d --- /dev/null +++ b/build/shared/tools/MovieMaker/tool/.gitignore @@ -0,0 +1,2 @@ +MovieMaker.jar + From 44505258b92f93766b04c07b6a015f3369a5092d Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 8 Oct 2013 20:33:13 -0400 Subject: [PATCH 134/556] fix class loader issues with JAI ImageIO --- app/src/processing/app/Base.java | 4 +-- .../src/processing/app/tools/MovieMaker.java | 26 +++++++++++++++++-- todo.txt | 3 +++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 93ce3df03..f5fa6f9d7 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -53,8 +53,8 @@ public class Base { // static private boolean RELEASE = false; /** True if heavy debugging error/log messages are enabled */ - static public boolean DEBUG = false; -// static public boolean DEBUG = true; +// static public boolean DEBUG = false; + static public boolean DEBUG = true; static HashMap platformNames = new HashMap(); diff --git a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java index 9232cc3b9..13edb3eae 100644 --- a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java +++ b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java @@ -32,6 +32,7 @@ import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.prefs.Preferences; @@ -619,16 +620,37 @@ public class MovieMaker extends JFrame implements Tool { private BufferedImage readImage(File file) throws IOException { + /* + BufferedImage image = null; + try { + Class iio = getClass().getClassLoader().loadClass("javax.imageio.ImageIO"); + Method readMethod = iio.getMethod("read", new Class[] { File.class }); + image = (BufferedImage) readMethod.invoke(null, file); + + Method scanMethod = iio.getMethod("scanForPlugins", new Class[] { }); + scanMethod.invoke(null); + + Method formatMethod = iio.getMethod("getReaderFormatNames", new Class[] { }); + String[] formats = (String[]) formatMethod.invoke(null); + for (String f : formats) { + System.out.println("dynamically found " + f); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } + */ + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); +// System.out.println("reading image with CL " + getClass().getClassLoader()); + BufferedImage image = ImageIO.read(file); - /* String[] loadImageFormats = ImageIO.getReaderFormatNames(); if (loadImageFormats != null) { for (String format : loadImageFormats) { System.out.println(format); } } - */ if (image == null) { String path = file.getAbsolutePath(); diff --git a/todo.txt b/todo.txt index 937c2b689..e52b2a49c 100644 --- a/todo.txt +++ b/todo.txt @@ -16,6 +16,9 @@ X https://github.com/processing/processing/issues/2103 X still having right-click issues (re-opened) X https://github.com/processing/processing/issues/2103 +X add gamma, better image options, etc to MovieMaker +_ fix file selection dialog (just import PApplet) with MovieMaker + X add appbundler.jar, otherwise folks have to include Xcode _ if they want to build appbundler, they'll need Xcode _ and the command line tools Preferences > Downloads > Command Line Tools From 395d131ba5a53583e3d33e8729016aa5a09a2bba Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 8 Oct 2013 20:34:13 -0400 Subject: [PATCH 135/556] don't need that debug --- .../MovieMaker/src/processing/app/tools/MovieMaker.java | 2 ++ todo.txt | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java index 13edb3eae..455ce8066 100644 --- a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java +++ b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java @@ -645,12 +645,14 @@ public class MovieMaker extends JFrame implements Tool { BufferedImage image = ImageIO.read(file); + /* String[] loadImageFormats = ImageIO.getReaderFormatNames(); if (loadImageFormats != null) { for (String format : loadImageFormats) { System.out.println(format); } } + */ if (image == null) { String path = file.getAbsolutePath(); diff --git a/todo.txt b/todo.txt index e52b2a49c..a4183109a 100644 --- a/todo.txt +++ b/todo.txt @@ -16,6 +16,10 @@ X https://github.com/processing/processing/issues/2103 X still having right-click issues (re-opened) X https://github.com/processing/processing/issues/2103 +cleaning +o moviemaker video sizes / usability +o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Exhibition;action=display;num=1211318862 + X add gamma, better image options, etc to MovieMaker _ fix file selection dialog (just import PApplet) with MovieMaker @@ -179,8 +183,6 @@ _ and that java2d should complain if people try it _ method to go from function name to the included examples where used? _ encourage use of set() instead of point() in the drawing api _ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1114204116 -_ moviemaker video sizes / usability -_ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Exhibition;action=display;num=1211318862 _ other projects on which p5 is built _ no longer oro matcher and jikes _ add: quaqua, jna, registry stuff, .. ? From ac1d7f5ab0e5343087d0e39ca4e5617cef340d37 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 8 Oct 2013 20:34:28 -0400 Subject: [PATCH 136/556] unused import --- .../tools/MovieMaker/src/processing/app/tools/MovieMaker.java | 1 - 1 file changed, 1 deletion(-) diff --git a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java index 455ce8066..5378dea18 100644 --- a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java +++ b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java @@ -32,7 +32,6 @@ import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.Method; import java.util.Arrays; import java.util.prefs.Preferences; From 6b72094013370e3184e23f1044fdb058016d4bd4 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 8 Oct 2013 20:47:23 -0400 Subject: [PATCH 137/556] notes about movie build --- core/todo.txt | 2 -- todo.txt | 16 ++++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/core/todo.txt b/core/todo.txt index 41f5106fe..e4a57303b 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -64,8 +64,6 @@ _ needs to have a way to set width/height properly _ draw(s) doesn't work on the returned PShape _ TGA files writing strangely _ https://github.com/processing/processing/issues/2096 -_ also causes Movie Maker to not work properly -_ https://github.com/processing/processing/issues/1933 table _ addRow() is not efficient, probably need to do the doubling diff --git a/todo.txt b/todo.txt index a4183109a..6c3e834ea 100644 --- a/todo.txt +++ b/todo.txt @@ -16,11 +16,17 @@ X https://github.com/processing/processing/issues/2103 X still having right-click issues (re-opened) X https://github.com/processing/processing/issues/2103 -cleaning +movie maker o moviemaker video sizes / usability o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Exhibition;action=display;num=1211318862 - X add gamma, better image options, etc to MovieMaker +X TGA files cause Movie Maker to not work properly +X https://github.com/processing/processing/issues/1933 +o move Movie Maker out to its own separate tool package (with separate build) +X http://code.google.com/p/processing/issues/detail?id=837 +X https://github.com/processing/processing/issues/875 +X basically done in more recent releases + _ fix file selection dialog (just import PApplet) with MovieMaker X add appbundler.jar, otherwise folks have to include Xcode @@ -768,12 +774,6 @@ _ handle native code for tools menu (?) _ http://code.google.com/p/processing/issues/detail?id=109 -TOOLS / Movie Maker - -_ move Movie Maker out to its own separate tool package (with separate build) -_ http://code.google.com/p/processing/issues/detail?id=837 - - TOOLS / Ideas _ eclipse import/export From c88b412fd4b0aba01a70b3d229866040676787e7 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Wed, 9 Oct 2013 00:21:53 -0400 Subject: [PATCH 138/556] fix up file selection dialogs --- .../src/processing/app/tools/Chooser.java | 242 ++++++++ .../src/processing/app/tools/MovieMaker.java | 570 +++++++++++------- core/src/processing/core/PApplet.java | 9 +- todo.txt | 4 +- 4 files changed, 608 insertions(+), 217 deletions(-) create mode 100644 build/shared/tools/MovieMaker/src/processing/app/tools/Chooser.java diff --git a/build/shared/tools/MovieMaker/src/processing/app/tools/Chooser.java b/build/shared/tools/MovieMaker/src/processing/app/tools/Chooser.java new file mode 100644 index 000000000..b75ffe138 --- /dev/null +++ b/build/shared/tools/MovieMaker/src/processing/app/tools/Chooser.java @@ -0,0 +1,242 @@ +package processing.app.tools; + +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Frame; +import java.io.File; + +import javax.swing.JFileChooser; + + +public class Chooser { + static final boolean useNativeSelect = true; + + + static abstract class Callback { + //abstract void select(File file); + void handle(final File file) { + EventQueue.invokeLater(new Runnable() { +// new Thread(new Runnable() { + public void run() { + select(file); + } + }); +// }).start(); + } + + abstract void select(File file); + } + + +// Frame parent; +// +// public Chooser(Frame parent) { +// this.parent = parent; +// } + + /** + * Open a platform-specific file chooser dialog to select a file for input. + * After the selection is made, the selected File will be passed to the + * 'callback' function. If the dialog is closed or canceled, null will be + * sent to the function, so that the program is not waiting for additional + * input. The callback is necessary because of how threading works. + * + *

    +   * void setup() {
    +   *   selectInput("Select a file to process:", "fileSelected");
    +   * }
    +   *
    +   * void fileSelected(File selection) {
    +   *   if (selection == null) {
    +   *     println("Window was closed or the user hit cancel.");
    +   *   } else {
    +   *     println("User selected " + fileSeleted.getAbsolutePath());
    +   *   }
    +   * }
    +   * 
    + * + * For advanced users, the method must be 'public', which is true for all + * methods inside a sketch when run from the PDE, but must explicitly be + * set when using Eclipse or other development environments. + * + * @webref input:files + * @param prompt message to the user + * @param callback name of the method to be called when the selection is made + */ +// public void selectInput(String prompt, String callback) { +// selectInput(prompt, callback, null); +// } + + +// public void selectInput(String prompt, String callback, File file) { +// selectInput(prompt, callback, file, this); +// } + + +// public void selectInput(String prompt, String callback, +// File file, Object callbackObject) { +// selectInput(prompt, callback, file, callbackObject, selectFrame()); +// } + + + static public void selectInput(Frame parent, String prompt, File file, + Callback callback) { + selectImpl(parent, prompt, file, callback, FileDialog.LOAD); + } + + + /** + * See selectInput() for details. + * + * @webref output:files + * @param prompt message to the user + * @param callback name of the method to be called when the selection is made + */ +// public void selectOutput(String prompt, String callback) { +// selectOutput(prompt, callback, null); +// } +// +// public void selectOutput(String prompt, String callback, File file) { +// selectOutput(prompt, callback, file, this); +// } +// +// +// public void selectOutput(String prompt, String callback, +// File file, Object callbackObject) { +// selectOutput(prompt, callback, file, callbackObject, selectFrame()); +// } + + + static public void selectOutput(Frame parent, String prompt, File file, + Callback callback) { + selectImpl(parent, prompt, file, callback, FileDialog.SAVE); + } + + + static protected void selectImpl(final Frame parentFrame, + final String prompt, + final File defaultSelection, + final Callback callback, + final int mode) { +// EventQueue.invokeLater(new Runnable() { +// public void run() { + File selectedFile = null; + + if (useNativeSelect) { + FileDialog dialog = new FileDialog(parentFrame, prompt, mode); + if (defaultSelection != null) { + dialog.setDirectory(defaultSelection.getParent()); + dialog.setFile(defaultSelection.getName()); + } + dialog.setVisible(true); + String directory = dialog.getDirectory(); + String filename = dialog.getFile(); + if (filename != null) { + selectedFile = new File(directory, filename); + } + + } else { + JFileChooser chooser = new JFileChooser(); + chooser.setDialogTitle(prompt); + if (defaultSelection != null) { + chooser.setSelectedFile(defaultSelection); + } + + int result = -1; + if (mode == FileDialog.SAVE) { + result = chooser.showSaveDialog(parentFrame); + } else if (mode == FileDialog.LOAD) { + result = chooser.showOpenDialog(parentFrame); + } + if (result == JFileChooser.APPROVE_OPTION) { + selectedFile = chooser.getSelectedFile(); + } + } + //selectCallback(selectedFile, callbackMethod, callbackObject); + callback.handle(selectedFile); +// } +// }); + } + + + /** + * See selectInput() for details. + * + * @webref input:files + * @param prompt message to the user + * @param callback name of the method to be called when the selection is made + */ +// public void selectFolder(String prompt, String callback) { +// selectFolder(prompt, callback, null); +// } +// +// +// public void selectFolder(String prompt, String callback, File file) { +// selectFolder(prompt, callback, file, this); +// } +// +// +// public void selectFolder(String prompt, String callback, +// File file, Object callbackObject) { +// selectFolder(prompt, callback, file, callbackObject, selectFrame()); +// } + + + static public void selectFolder(final Frame parentFrame, + final String prompt, + final File defaultSelection, + final Callback callback) { +// EventQueue.invokeLater(new Runnable() { +// public void run() { + File selectedFile = null; + + if (System.getProperty("os.name").contains("Mac") && useNativeSelect) { + FileDialog fileDialog = + new FileDialog(parentFrame, prompt, FileDialog.LOAD); + System.setProperty("apple.awt.fileDialogForDirectories", "true"); + fileDialog.setVisible(true); + System.setProperty("apple.awt.fileDialogForDirectories", "false"); + String filename = fileDialog.getFile(); + if (filename != null) { + selectedFile = new File(fileDialog.getDirectory(), fileDialog.getFile()); + } + } else { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle(prompt); + fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + if (defaultSelection != null) { + fileChooser.setSelectedFile(defaultSelection); + } + + int result = fileChooser.showOpenDialog(parentFrame); + if (result == JFileChooser.APPROVE_OPTION) { + selectedFile = fileChooser.getSelectedFile(); + } + } + //selectCallback(selectedFile, callbackMethod, callbackObject); + callback.handle(selectedFile); +// } +// }); + } + + +// static private void selectCallback(File selectedFile, +// String callbackMethod, +// Object callbackObject) { +// try { +// Class callbackClass = callbackObject.getClass(); +// Method selectMethod = +// callbackClass.getMethod(callbackMethod, new Class[] { File.class }); +// selectMethod.invoke(callbackObject, new Object[] { selectedFile }); +// +// } catch (IllegalAccessException iae) { +// System.err.println(callbackMethod + "() must be public"); +// +// } catch (InvocationTargetException ite) { +// ite.printStackTrace(); +// +// } catch (NoSuchMethodException nsme) { +// System.err.println(callbackMethod + "() could not be found"); +// } +// } +} \ No newline at end of file diff --git a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java index 5378dea18..7a37ea60f 100644 --- a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java +++ b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java @@ -11,10 +11,6 @@ package processing.app.tools; * For details see accompanying license terms. */ -import ch.randelshofer.gui.datatransfer.FileTextFieldTransferHandler; -import ch.randelshofer.media.mp3.MP3AudioInputStream; -import ch.randelshofer.media.quicktime.QuickTimeWriter; - import java.awt.Font; import java.awt.Graphics2D; import java.awt.RenderingHints; @@ -40,11 +36,30 @@ import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; -import javax.swing.*; +import javax.swing.DefaultComboBoxModel; +import javax.swing.GroupLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JRootPane; +import javax.swing.JTextField; +import javax.swing.KeyStroke; +import javax.swing.LayoutStyle; +import javax.swing.ProgressMonitor; +import javax.swing.SwingWorker; +import javax.swing.WindowConstants; import javax.swing.border.EmptyBorder; import javax.swing.filechooser.FileSystemView; import processing.app.Editor; +import ch.randelshofer.gui.datatransfer.FileTextFieldTransferHandler; +import ch.randelshofer.media.mp3.MP3AudioInputStream; +import ch.randelshofer.media.quicktime.QuickTimeWriter; // TODO [fry 2011-09-06] @@ -63,9 +78,9 @@ import processing.app.Editor; * can be found
    here. */ public class MovieMaker extends JFrame implements Tool { - private JFileChooser imageFolderChooser; - private JFileChooser soundFileChooser; - private JFileChooser movieFileChooser; +// private JFileChooser imageFolderChooser; +// private JFileChooser soundFileChooser; +// private JFileChooser movieFileChooser; private Preferences prefs; // private Editor editor; @@ -213,7 +228,7 @@ public class MovieMaker extends JFrame implements Tool { // fastStartRadio = new JRadioButton(); // fastStartCompressedRadio = new JRadioButton(); - FormListener formListener = new FormListener(); +// FormListener formListener = new FormListener(); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { @@ -250,14 +265,72 @@ public class MovieMaker extends JFrame implements Tool { imageFolderHelpLabel.setText("Drag a folder with image files into the field below:"); chooseImageFolderButton.setText("Choose..."); - chooseImageFolderButton.addActionListener(formListener); + //chooseImageFolderButton.addActionListener(formListener); + chooseImageFolderButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Chooser.selectFolder(MovieMaker.this, + "Select image folder...", + new File(imageFolderField.getText()), + new Chooser.Callback() { + void select(File file) { + if (file != null) { + imageFolderField.setText(file.getAbsolutePath()); + } + } + }); + } + }); + soundFileHelpLabel.setText("Drag a sound file into the field below (.au, .aiff, .wav, .mp3):"); chooseSoundFileButton.setText("Choose..."); - chooseSoundFileButton.addActionListener(formListener); + //chooseSoundFileButton.addActionListener(formListener); + chooseSoundFileButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + Chooser.selectInput(MovieMaker.this, + "Select sound file...", + new File(soundFileField.getText()), + new Chooser.Callback() { + + void select(File file) { + if (file != null) { + soundFileField.setText(file.getAbsolutePath()); + } + } + }); + } + }); createMovieButton.setText("Create Movie..."); - createMovieButton.addActionListener(formListener); +// createMovieButton.addActionListener(formListener); + createMovieButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + String lastPath = prefs.get("movie.outputFile", null); + File lastFile = lastPath == null ? null : new File(lastPath); + Chooser.selectOutput(MovieMaker.this, + "Save movie as...", + lastFile, + new Chooser.Callback() { + @Override + void select(File file) { + if (file != null) { + String path = file.getAbsolutePath(); + if (!path.toLowerCase().endsWith(".mov")) { + path += ".mov"; + } + prefs.put("movie.outputFile", path); + createMovie(new File(path)); + } + } + }); + } + }); Font font = new Font("Dialog", Font.PLAIN, 11); @@ -394,58 +467,58 @@ public class MovieMaker extends JFrame implements Tool { // Code for dispatching events from components to event handlers. - private class FormListener implements java.awt.event.ActionListener { - FormListener() {} - public void actionPerformed(java.awt.event.ActionEvent evt) { - if (evt.getSource() == chooseImageFolderButton) { - MovieMaker.this.chooseImageFolder(evt); - } - else if (evt.getSource() == chooseSoundFileButton) { - MovieMaker.this.chooseSoundFile(evt); - } - else if (evt.getSource() == createMovieButton) { - MovieMaker.this.createMovie(evt); - } -// else if (evt.getSource() == fastStartCompressedRadio) { -// MovieMaker.this.streamingRadioPerformed(evt); +// private class FormListener implements java.awt.event.ActionListener { +// FormListener() {} +// public void actionPerformed(java.awt.event.ActionEvent evt) { +// if (evt.getSource() == chooseImageFolderButton) { +// MovieMaker.this.chooseImageFolder(evt); // } -// else if (evt.getSource() == fastStartRadio) { -// MovieMaker.this.streamingRadioPerformed(evt); +// else if (evt.getSource() == chooseSoundFileButton) { +// MovieMaker.this.chooseSoundFile(evt); // } -// else if (evt.getSource() == noPreparationRadio) { -// MovieMaker.this.streamingRadioPerformed(evt); +// else if (evt.getSource() == createMovieButton) { +// MovieMaker.this.createMovie(evt); // } - } - } +//// else if (evt.getSource() == fastStartCompressedRadio) { +//// MovieMaker.this.streamingRadioPerformed(evt); +//// } +//// else if (evt.getSource() == fastStartRadio) { +//// MovieMaker.this.streamingRadioPerformed(evt); +//// } +//// else if (evt.getSource() == noPreparationRadio) { +//// MovieMaker.this.streamingRadioPerformed(evt); +//// } +// } +// } - private void chooseImageFolder(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chooseImageFolder - if (imageFolderChooser == null) { - imageFolderChooser = new JFileChooser(); - imageFolderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - if (imageFolderField.getText().length() > 0) { - imageFolderChooser.setSelectedFile(new File(imageFolderField.getText())); - } else if (soundFileField.getText().length() > 0) { - imageFolderChooser.setCurrentDirectory(new File(soundFileField.getText()).getParentFile()); - } - } - if (JFileChooser.APPROVE_OPTION == imageFolderChooser.showOpenDialog(this)) { - imageFolderField.setText(imageFolderChooser.getSelectedFile().getPath()); - } - } - - private void chooseSoundFile(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chooseSoundFile - if (soundFileChooser == null) { - soundFileChooser = new JFileChooser(); - if (soundFileField.getText().length() > 0) { - soundFileChooser.setSelectedFile(new File(soundFileField.getText())); - } else if (imageFolderField.getText().length() > 0) { - soundFileChooser.setCurrentDirectory(new File(imageFolderField.getText())); - } - } - if (JFileChooser.APPROVE_OPTION == soundFileChooser.showOpenDialog(this)) { - soundFileField.setText(soundFileChooser.getSelectedFile().getPath()); - } - } +// private void chooseImageFolder(ActionEvent evt) { +// if (imageFolderChooser == null) { +// imageFolderChooser = new JFileChooser(); +// imageFolderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); +// if (imageFolderField.getText().length() > 0) { +// imageFolderChooser.setSelectedFile(new File(imageFolderField.getText())); +// } else if (soundFileField.getText().length() > 0) { +// imageFolderChooser.setCurrentDirectory(new File(soundFileField.getText()).getParentFile()); +// } +// } +// if (JFileChooser.APPROVE_OPTION == imageFolderChooser.showOpenDialog(this)) { +// imageFolderField.setText(imageFolderChooser.getSelectedFile().getPath()); +// } +// } +// +// private void chooseSoundFile(ActionEvent evt) { +// if (soundFileChooser == null) { +// soundFileChooser = new JFileChooser(); +// if (soundFileField.getText().length() > 0) { +// soundFileChooser.setSelectedFile(new File(soundFileField.getText())); +// } else if (imageFolderField.getText().length() > 0) { +// soundFileChooser.setCurrentDirectory(new File(imageFolderField.getText())); +// } +// } +// if (JFileChooser.APPROVE_OPTION == soundFileChooser.showOpenDialog(this)) { +// soundFileField.setText(soundFileChooser.getSelectedFile().getPath()); +// } +// } // this is super naughty, and shouldn't be out here. it's a hack to get the @@ -453,7 +526,9 @@ public class MovieMaker extends JFrame implements Tool { // given a bit of time. you know, time? the infinite but non-renewable resource? int width, height; - private void createMovie(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createMovie + private void createMovie(final File movieFile) { + createMovieButton.setEnabled(false); + // --------------------------------- // Check input // --------------------------------- @@ -512,6 +587,7 @@ public class MovieMaker extends JFrame implements Tool { // --------------------------------- // Choose an output file // --------------------------------- + /* if (movieFileChooser == null) { movieFileChooser = new JFileChooser(); if (prefs.get("movie.outputFile", null) != null) { @@ -533,6 +609,7 @@ public class MovieMaker extends JFrame implements Tool { : new File(movieFileChooser.getSelectedFile().getPath() + ".mov"); prefs.put("movie.outputFile", movieFile.getPath()); createMovieButton.setEnabled(false); + */ final boolean originalSize = originalSizeCheckBox.isSelected(); @@ -668,29 +745,26 @@ public class MovieMaker extends JFrame implements Tool { /** - * Targa image loader for RLE-compressed TGA files. - *

    - * Rewritten for 0115 to read/write RLE-encoded targa images. - * For 0125, non-RLE encoded images are now supported, along with - * images whose y-order is reversed (which is standard for TGA files). + * Targa image loader for RLE-compressed TGA files. + * Code taken from PApplet, any changes here should lead to updates there. */ static protected BufferedImage loadImageTGA(File file) throws IOException { InputStream is = new FileInputStream(file); - if (is == null) return null; - - byte header[] = new byte[18]; - int offset = 0; - do { - int count = is.read(header, offset, header.length - offset); - if (count == -1) return null; - offset += count; - } while (offset < 18); + + try { + byte header[] = new byte[18]; + int offset = 0; + do { + int count = is.read(header, offset, header.length - offset); + if (count == -1) return null; + offset += count; + } while (offset < 18); /* header[2] image type code 2 (0x02) - Uncompressed, RGB images. 3 (0x03) - Uncompressed, black and white images. - 10 (0x0A) - Runlength encoded RGB images. + 10 (0x0A) - Run-length encoded RGB images. 11 (0x0B) - Compressed, black and white images. (grayscale?) header[16] is the bit depth (8, 24, 32) @@ -703,167 +777,235 @@ public class MovieMaker extends JFrame implements Tool { 128 64 32 16 8 4 2 1 */ - int format = 0; - final int RGB = 1; - final int ARGB = 2; - final int ALPHA = 4; + int format = 0; + final int RGB = 1; + final int ARGB = 2; + final int ALPHA = 4; - if (((header[2] == 3) || (header[2] == 11)) && // B&W, plus RLE or not - (header[16] == 8) && // 8 bits - ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 bit - format = ALPHA; + if (((header[2] == 3) || (header[2] == 11)) && // B&W, plus RLE or not + (header[16] == 8) && // 8 bits + ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 bit + format = ALPHA; - } else if (((header[2] == 2) || (header[2] == 10)) && // RGB, RLE or not - (header[16] == 24) && // 24 bits - ((header[17] == 0x20) || (header[17] == 0))) { // origin - format = RGB; + } else if (((header[2] == 2) || (header[2] == 10)) && // RGB, RLE or not + (header[16] == 24) && // 24 bits + ((header[17] == 0x20) || (header[17] == 0))) { // origin + format = RGB; - } else if (((header[2] == 2) || (header[2] == 10)) && - (header[16] == 32) && - ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 - format = ARGB; - } - - if (format == 0) { - throw new IOException("Unknown .tga file format for " + file.getName()); - } - - int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff); - int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff); - //PImage outgoing = createImage(w, h, format); - int[] pixels = new int[w * h]; - - // where "reversed" means upper-left corner (normal for most of - // the modernized world, but "reversed" for the tga spec) - //boolean reversed = (header[17] & 0x20) != 0; - // https://github.com/processing/processing/issues/1682 - boolean reversed = (header[17] & 0x20) == 0; - - if ((header[2] == 2) || (header[2] == 3)) { // not RLE encoded - if (reversed) { - int index = (h-1) * w; - switch (format) { - case ALPHA: - for (int y = h-1; y >= 0; y--) { - for (int x = 0; x < w; x++) { - pixels[index + x] = is.read(); - } - index -= w; - } - break; - case RGB: - for (int y = h-1; y >= 0; y--) { - for (int x = 0; x < w; x++) { - pixels[index + x] = - is.read() | (is.read() << 8) | (is.read() << 16) | - 0xff000000; - } - index -= w; - } - break; - case ARGB: - for (int y = h-1; y >= 0; y--) { - for (int x = 0; x < w; x++) { - pixels[index + x] = - is.read() | (is.read() << 8) | (is.read() << 16) | - (is.read() << 24); - } - index -= w; - } - } - } else { // not reversed - int count = w * h; - switch (format) { - case ALPHA: - for (int i = 0; i < count; i++) { - pixels[i] = is.read(); - } - break; - case RGB: - for (int i = 0; i < count; i++) { - pixels[i] = - is.read() | (is.read() << 8) | (is.read() << 16) | - 0xff000000; - } - break; - case ARGB: - for (int i = 0; i < count; i++) { - pixels[i] = - is.read() | (is.read() << 8) | (is.read() << 16) | - (is.read() << 24); - } - break; - } + } else if (((header[2] == 2) || (header[2] == 10)) && + (header[16] == 32) && + ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 + format = ARGB; } - } else { // header[2] is 10 or 11 - int index = 0; + if (format == 0) { + throw new IOException("Unknown .tga file format for " + file.getName()); + } - while (index < pixels.length) { - int num = is.read(); - boolean isRLE = (num & 0x80) != 0; - if (isRLE) { - num -= 127; // (num & 0x7F) + 1 - int pixel = 0; + int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff); + int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff); + //PImage outgoing = createImage(w, h, format); + int[] pixels = new int[w * h]; + + // where "reversed" means upper-left corner (normal for most of + // the modernized world, but "reversed" for the tga spec) + //boolean reversed = (header[17] & 0x20) != 0; + // https://github.com/processing/processing/issues/1682 + boolean reversed = (header[17] & 0x20) == 0; + + if ((header[2] == 2) || (header[2] == 3)) { // not RLE encoded + if (reversed) { + int index = (h-1) * w; switch (format) { case ALPHA: - pixel = is.read(); + for (int y = h-1; y >= 0; y--) { + for (int x = 0; x < w; x++) { + pixels[index + x] = is.read(); + } + index -= w; + } break; case RGB: - pixel = 0xFF000000 | + for (int y = h-1; y >= 0; y--) { + for (int x = 0; x < w; x++) { + pixels[index + x] = + is.read() | (is.read() << 8) | (is.read() << 16) | + 0xff000000; + } + index -= w; + } + break; + case ARGB: + for (int y = h-1; y >= 0; y--) { + for (int x = 0; x < w; x++) { + pixels[index + x] = + is.read() | (is.read() << 8) | (is.read() << 16) | + (is.read() << 24); + } + index -= w; + } + } + } else { // not reversed + int count = w * h; + switch (format) { + case ALPHA: + for (int i = 0; i < count; i++) { + pixels[i] = is.read(); + } + break; + case RGB: + for (int i = 0; i < count; i++) { + pixels[i] = + is.read() | (is.read() << 8) | (is.read() << 16) | + 0xff000000; + } + break; + case ARGB: + for (int i = 0; i < count; i++) { + pixels[i] = + is.read() | (is.read() << 8) | (is.read() << 16) | + (is.read() << 24); + } + break; + } + } + + } else { // header[2] is 10 or 11 + int index = 0; + + while (index < pixels.length) { + int num = is.read(); + boolean isRLE = (num & 0x80) != 0; + if (isRLE) { + num -= 127; // (num & 0x7F) + 1 + int pixel = 0; + switch (format) { + case ALPHA: + pixel = is.read(); + break; + case RGB: + pixel = 0xFF000000 | is.read() | (is.read() << 8) | (is.read() << 16); - //(is.read() << 16) | (is.read() << 8) | is.read(); - break; - case ARGB: - pixel = is.read() | + //(is.read() << 16) | (is.read() << 8) | is.read(); + break; + case ARGB: + pixel = is.read() | (is.read() << 8) | (is.read() << 16) | (is.read() << 24); - break; - } - for (int i = 0; i < num; i++) { - pixels[index++] = pixel; - if (index == pixels.length) break; - } - } else { // write up to 127 bytes as uncompressed - num += 1; - switch (format) { - case ALPHA: - for (int i = 0; i < num; i++) { - pixels[index++] = is.read(); + break; } - break; - case RGB: for (int i = 0; i < num; i++) { - pixels[index++] = 0xFF000000 | - is.read() | (is.read() << 8) | (is.read() << 16); + pixels[index++] = pixel; + if (index == pixels.length) break; } - break; - case ARGB: - for (int i = 0; i < num; i++) { - pixels[index++] = is.read() | - (is.read() << 8) | (is.read() << 16) | (is.read() << 24); + } else { // write up to 127 bytes as uncompressed + num += 1; + switch (format) { + case ALPHA: + for (int i = 0; i < num; i++) { + pixels[index++] = is.read(); + } + break; + case RGB: + for (int i = 0; i < num; i++) { + pixels[index++] = 0xFF000000 | + is.read() | (is.read() << 8) | (is.read() << 16); + } + break; + case ARGB: + for (int i = 0; i < num; i++) { + pixels[index++] = is.read() | + (is.read() << 8) | (is.read() << 16) | (is.read() << 24); + } + break; } - break; } } + + if (!reversed) { + int[] temp = new int[w]; + for (int y = 0; y < h/2; y++) { + int z = (h-1) - y; + System.arraycopy(pixels, y*w, temp, 0, w); + System.arraycopy(pixels, z*w, pixels, y*w, w); + System.arraycopy(temp, 0, pixels, z*w, w); + } + } + } + is.close(); + int type = (format == RGB) ? + BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; + BufferedImage image = new BufferedImage(w, h, type); + WritableRaster wr = image.getRaster(); + wr.setDataElements(0, 0, w, h, pixels); + return image; + + } finally { + is.close(); + } + } + + + /* + static public void selectFolder(final Frame parentFrame, + final String prompt, +// final String callbackMethod, + final File defaultSelection, +// final Object callbackObject, + final SelectCallback callback) { +// EventQueue.invokeLater(new Runnable() { +// public void run() { + File selectedFile = null; + + if (System.getProperty("os.name").contains("Mac")) { + FileDialog fileDialog = + new FileDialog(parentFrame, prompt, FileDialog.LOAD); + System.setProperty("apple.awt.fileDialogForDirectories", "true"); + fileDialog.setVisible(true); + System.setProperty("apple.awt.fileDialogForDirectories", "false"); + String filename = fileDialog.getFile(); + if (filename != null) { + selectedFile = new File(fileDialog.getDirectory(), fileDialog.getFile()); + } + } else { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle(prompt); + fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + if (defaultSelection != null) { + fileChooser.setSelectedFile(defaultSelection); } - if (!reversed) { - int[] temp = new int[w]; - for (int y = 0; y < h/2; y++) { - int z = (h-1) - y; - System.arraycopy(pixels, y*w, temp, 0, w); - System.arraycopy(pixels, z*w, pixels, y*w, w); - System.arraycopy(temp, 0, pixels, z*w, w); - } + int result = fileChooser.showOpenDialog(parentFrame); + if (result == JFileChooser.APPROVE_OPTION) { + selectedFile = fileChooser.getSelectedFile(); } } - int type = (format == RGB) ? - BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; - BufferedImage image = new BufferedImage(w, h, type); - WritableRaster wr = image.getRaster(); - wr.setDataElements(0, 0, w, h, pixels); - return image; + //selectCallback(selectedFile, callbackMethod, callbackObject); + callback.select(selectedFile); +// } +// }); } + */ + + +// static private void selectCallback(File selectedFile, +// String callbackMethod, +// Object callbackObject) { +// try { +// Class callbackClass = callbackObject.getClass(); +// Method selectMethod = +// callbackClass.getMethod(callbackMethod, new Class[] { File.class }); +// selectMethod.invoke(callbackObject, new Object[] { selectedFile }); +// +// } catch (IllegalAccessException iae) { +// System.err.println(callbackMethod + "() must be public"); +// +// } catch (InvocationTargetException ite) { +// ite.printStackTrace(); +// +// } catch (NoSuchMethodException nsme) { +// System.err.println(callbackMethod + "() could not be found"); +// } +// } // private void streamingRadioPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_streamingRadioPerformed diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 71c85020b..652c7e862 100755 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -5864,6 +5864,13 @@ public class PApplet extends Applet * Rewritten for 0115 to read/write RLE-encoded targa images. * For 0125, non-RLE encoded images are now supported, along with * images whose y-order is reversed (which is standard for TGA files). + *

    + * A version of this function is in MovieMaker.java. Any fixes here + * should be applied over in MovieMaker as well. + *

    + * Known issue with RLE encoding and odd behavior in some apps: + * https://github.com/processing/processing/issues/2096 + * Please help! */ protected PImage loadImageTGA(String filename) throws IOException { InputStream is = createInput(filename); @@ -5881,7 +5888,7 @@ public class PApplet extends Applet header[2] image type code 2 (0x02) - Uncompressed, RGB images. 3 (0x03) - Uncompressed, black and white images. - 10 (0x0A) - Runlength encoded RGB images. + 10 (0x0A) - Run-length encoded RGB images. 11 (0x0B) - Compressed, black and white images. (grayscale?) header[16] is the bit depth (8, 24, 32) diff --git a/todo.txt b/todo.txt index 6c3e834ea..88d0d6dc0 100644 --- a/todo.txt +++ b/todo.txt @@ -26,8 +26,8 @@ o move Movie Maker out to its own separate tool package (with separate build) X http://code.google.com/p/processing/issues/detail?id=837 X https://github.com/processing/processing/issues/875 X basically done in more recent releases - -_ fix file selection dialog (just import PApplet) with MovieMaker +X fix file selection dialog with MovieMaker +X copied from PApplet, but not importing PApplet X add appbundler.jar, otherwise folks have to include Xcode _ if they want to build appbundler, they'll need Xcode From 5fcf6acecb093885f70bc4120e827d7737b9404a Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Wed, 9 Oct 2013 01:03:21 -0400 Subject: [PATCH 139/556] more cleanups and fixes for the Movie Maker --- build/shared/tools/MovieMaker/build.xml | 14 - .../src/processing/app/tools/Chooser.java | 3 +- .../src/processing/app/tools/MovieMaker.java | 545 +++++++++--------- 3 files changed, 267 insertions(+), 295 deletions(-) diff --git a/build/shared/tools/MovieMaker/build.xml b/build/shared/tools/MovieMaker/build.xml index eda108b57..419914718 100755 --- a/build/shared/tools/MovieMaker/build.xml +++ b/build/shared/tools/MovieMaker/build.xml @@ -1,19 +1,5 @@ - - diff --git a/build/shared/tools/MovieMaker/src/processing/app/tools/Chooser.java b/build/shared/tools/MovieMaker/src/processing/app/tools/Chooser.java index b75ffe138..2585f0563 100644 --- a/build/shared/tools/MovieMaker/src/processing/app/tools/Chooser.java +++ b/build/shared/tools/MovieMaker/src/processing/app/tools/Chooser.java @@ -8,7 +8,8 @@ import java.io.File; import javax.swing.JFileChooser; -public class Chooser { +/** File chooser additions, cannibalized from PApplet. */ +class Chooser { static final boolean useNativeSelect = true; diff --git a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java index 7a37ea60f..eba834ee3 100644 --- a/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java +++ b/build/shared/tools/MovieMaker/src/processing/app/tools/MovieMaker.java @@ -1,7 +1,7 @@ package processing.app.tools; /* * Nearly all of this code is - * Copyright © 2010-2011 Werner Randelshofer, Immensee, Switzerland. + * Copyright (c) 2010-2011 Werner Randelshofer, Immensee, Switzerland. * All rights reserved. * (However, he should not be held responsible for the current mess of a hack * that it has become.) @@ -11,48 +11,16 @@ package processing.app.tools; * For details see accompanying license terms. */ -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferInt; -import java.awt.image.WritableRaster; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.*; +import java.io.*; +import java.util.*; import java.util.prefs.Preferences; import javax.imageio.ImageIO; -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.UnsupportedAudioFileException; -import javax.swing.DefaultComboBoxModel; -import javax.swing.GroupLayout; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JComponent; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JRootPane; -import javax.swing.JTextField; -import javax.swing.KeyStroke; -import javax.swing.LayoutStyle; -import javax.swing.ProgressMonitor; -import javax.swing.SwingWorker; -import javax.swing.WindowConstants; +import javax.sound.sampled.*; +import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.filechooser.FileSystemView; @@ -62,20 +30,34 @@ import ch.randelshofer.media.mp3.MP3AudioInputStream; import ch.randelshofer.media.quicktime.QuickTimeWriter; -// TODO [fry 2011-09-06] -// + The dialog box is super ugly. It's a hacked up version of the previous -// interface, but it'll take a bit of time to clean it up. -// http://code.google.com/p/processing/issues/detail?id=836 -// + the None compressor seems to have bugs, so just disabled it instead. -// + the 'pass through' option seems to be broken, it's been removed, and in -// its place is an option to use the same width and height as the originals. -// + when this new 'pass through' is set, there's some nastiness with how -// the 'final' width/height variables are passed to the movie maker. -// this is an easy fix but needs a couple minutes. - /** * Hacked from Werner Randelshofer's QuickTimeWriter demo. The original version * can be found here. + *

    + * A more up-to-date version of the project seems to be + * here. + * If someone would like to help us update the encoder, that'd be great. + *

    + * Broken out as a separate project because the license (CC) probably isn't + * compatible with the rest of Processing and we don't want any confusion. + *

    + * Added JAI ImageIO to support lots of other image file formats [131008]. + * Also copied the Processing TGA implementation. + *

    + * Added support for the gamma ('gama') atom [131008]. + *

    + * A few more notes on the implementation: + *

      + *
    • The dialog box is super ugly. It's a hacked up version of the previous + * interface, but I'm too scared to pull that GUI layout code apart. + *
    • The 'None' compressor seems to have bugs, so just disabled it instead. + *
    • The 'pass through' option seems to be broken, so it's been removed. + * In its place is an option to use the same width/height as the originals. + *
    • When this new 'pass through' is set, there's some nastiness with how + * the 'final' width/height variables are passed to the movie maker. + * This is an easy fix but needs a couple minutes. + *
    + * Ben Fry 2011-09-06, updated 2013-10-09 */ public class MovieMaker extends JFrame implements Tool { // private JFileChooser imageFolderChooser; @@ -118,7 +100,7 @@ public class MovieMaker extends JFrame implements Tool { public void init(Editor editor) { // System.out.println("calling init for MovieMaker " + EventQueue.isDispatchThread()); // this.editor = editor; - initComponents(); + initComponents(editor == null); // String version = getClass().getPackage().getImplementationVersion(); // if (version != null) { @@ -205,7 +187,7 @@ public class MovieMaker extends JFrame implements Tool { } - private void initComponents() { + private void initComponents(final boolean standalone) { imageFolderHelpLabel = new JLabel(); imageFolderField = new JTextField(); chooseImageFolderButton = new JButton(); @@ -239,8 +221,11 @@ public class MovieMaker extends JFrame implements Tool { }); registerWindowCloseKeys(getRootPane(), new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { - setVisible(false); -// System.exit(0); + if (standalone) { + System.exit(0); + } else { + setVisible(false); + } } }); setTitle("QuickTime Movie Maker"); @@ -326,6 +311,16 @@ public class MovieMaker extends JFrame implements Tool { } prefs.put("movie.outputFile", path); createMovie(new File(path)); +// final File target = new File(path); +// //new Thread(new Runnable() { +// EventQueue.invokeLater(new Runnable() { +// +// @Override +// public void run() { +// createMovie(target); +// } +// +// }); } } }); @@ -696,30 +691,15 @@ public class MovieMaker extends JFrame implements Tool { private BufferedImage readImage(File file) throws IOException { - /* - BufferedImage image = null; - try { - Class iio = getClass().getClassLoader().loadClass("javax.imageio.ImageIO"); - Method readMethod = iio.getMethod("read", new Class[] { File.class }); - image = (BufferedImage) readMethod.invoke(null, file); - - Method scanMethod = iio.getMethod("scanForPlugins", new Class[] { }); - scanMethod.invoke(null); - - Method formatMethod = iio.getMethod("getReaderFormatNames", new Class[] { }); - String[] formats = (String[]) formatMethod.invoke(null); - for (String f : formats) { - System.out.println("dynamically found " + f); - } - - } catch (Exception e) { - throw new RuntimeException(e); - } - */ - Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); -// System.out.println("reading image with CL " + getClass().getClassLoader()); - + // Make sure that we're using a ClassLoader that's aware of the ImageIO jar + //Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); + //BufferedImage image = ImageIO.read(file); + // rewritten to switch back to the default loader + Thread current = Thread.currentThread(); + ClassLoader origLoader = Thread.currentThread().getContextClassLoader(); + current.setContextClassLoader(getClass().getClassLoader()); BufferedImage image = ImageIO.read(file); + current.setContextClassLoader(origLoader); /* String[] loadImageFormats = ImageIO.getReaderFormatNames(); @@ -744,207 +724,6 @@ public class MovieMaker extends JFrame implements Tool { } - /** - * Targa image loader for RLE-compressed TGA files. - * Code taken from PApplet, any changes here should lead to updates there. - */ - static protected BufferedImage loadImageTGA(File file) throws IOException { - InputStream is = new FileInputStream(file); - - try { - byte header[] = new byte[18]; - int offset = 0; - do { - int count = is.read(header, offset, header.length - offset); - if (count == -1) return null; - offset += count; - } while (offset < 18); - - /* - header[2] image type code - 2 (0x02) - Uncompressed, RGB images. - 3 (0x03) - Uncompressed, black and white images. - 10 (0x0A) - Run-length encoded RGB images. - 11 (0x0B) - Compressed, black and white images. (grayscale?) - - header[16] is the bit depth (8, 24, 32) - - header[17] image descriptor (packed bits) - 0x20 is 32 = origin upper-left - 0x28 is 32 + 8 = origin upper-left + 32 bits - - 7 6 5 4 3 2 1 0 - 128 64 32 16 8 4 2 1 - */ - - int format = 0; - final int RGB = 1; - final int ARGB = 2; - final int ALPHA = 4; - - if (((header[2] == 3) || (header[2] == 11)) && // B&W, plus RLE or not - (header[16] == 8) && // 8 bits - ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 bit - format = ALPHA; - - } else if (((header[2] == 2) || (header[2] == 10)) && // RGB, RLE or not - (header[16] == 24) && // 24 bits - ((header[17] == 0x20) || (header[17] == 0))) { // origin - format = RGB; - - } else if (((header[2] == 2) || (header[2] == 10)) && - (header[16] == 32) && - ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 - format = ARGB; - } - - if (format == 0) { - throw new IOException("Unknown .tga file format for " + file.getName()); - } - - int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff); - int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff); - //PImage outgoing = createImage(w, h, format); - int[] pixels = new int[w * h]; - - // where "reversed" means upper-left corner (normal for most of - // the modernized world, but "reversed" for the tga spec) - //boolean reversed = (header[17] & 0x20) != 0; - // https://github.com/processing/processing/issues/1682 - boolean reversed = (header[17] & 0x20) == 0; - - if ((header[2] == 2) || (header[2] == 3)) { // not RLE encoded - if (reversed) { - int index = (h-1) * w; - switch (format) { - case ALPHA: - for (int y = h-1; y >= 0; y--) { - for (int x = 0; x < w; x++) { - pixels[index + x] = is.read(); - } - index -= w; - } - break; - case RGB: - for (int y = h-1; y >= 0; y--) { - for (int x = 0; x < w; x++) { - pixels[index + x] = - is.read() | (is.read() << 8) | (is.read() << 16) | - 0xff000000; - } - index -= w; - } - break; - case ARGB: - for (int y = h-1; y >= 0; y--) { - for (int x = 0; x < w; x++) { - pixels[index + x] = - is.read() | (is.read() << 8) | (is.read() << 16) | - (is.read() << 24); - } - index -= w; - } - } - } else { // not reversed - int count = w * h; - switch (format) { - case ALPHA: - for (int i = 0; i < count; i++) { - pixels[i] = is.read(); - } - break; - case RGB: - for (int i = 0; i < count; i++) { - pixels[i] = - is.read() | (is.read() << 8) | (is.read() << 16) | - 0xff000000; - } - break; - case ARGB: - for (int i = 0; i < count; i++) { - pixels[i] = - is.read() | (is.read() << 8) | (is.read() << 16) | - (is.read() << 24); - } - break; - } - } - - } else { // header[2] is 10 or 11 - int index = 0; - - while (index < pixels.length) { - int num = is.read(); - boolean isRLE = (num & 0x80) != 0; - if (isRLE) { - num -= 127; // (num & 0x7F) + 1 - int pixel = 0; - switch (format) { - case ALPHA: - pixel = is.read(); - break; - case RGB: - pixel = 0xFF000000 | - is.read() | (is.read() << 8) | (is.read() << 16); - //(is.read() << 16) | (is.read() << 8) | is.read(); - break; - case ARGB: - pixel = is.read() | - (is.read() << 8) | (is.read() << 16) | (is.read() << 24); - break; - } - for (int i = 0; i < num; i++) { - pixels[index++] = pixel; - if (index == pixels.length) break; - } - } else { // write up to 127 bytes as uncompressed - num += 1; - switch (format) { - case ALPHA: - for (int i = 0; i < num; i++) { - pixels[index++] = is.read(); - } - break; - case RGB: - for (int i = 0; i < num; i++) { - pixels[index++] = 0xFF000000 | - is.read() | (is.read() << 8) | (is.read() << 16); - } - break; - case ARGB: - for (int i = 0; i < num; i++) { - pixels[index++] = is.read() | - (is.read() << 8) | (is.read() << 16) | (is.read() << 24); - } - break; - } - } - } - - if (!reversed) { - int[] temp = new int[w]; - for (int y = 0; y < h/2; y++) { - int z = (h-1) - y; - System.arraycopy(pixels, y*w, temp, 0, w); - System.arraycopy(pixels, z*w, pixels, y*w, w); - System.arraycopy(temp, 0, pixels, z*w, w); - } - } - } - is.close(); - int type = (format == RGB) ? - BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; - BufferedImage image = new BufferedImage(w, h, type); - WritableRaster wr = image.getRaster(); - wr.setDataElements(0, 0, w, h, pixels); - return image; - - } finally { - is.close(); - } - } - - /* static public void selectFolder(final Frame parentFrame, final String prompt, @@ -1015,7 +794,10 @@ public class MovieMaker extends JFrame implements Tool { /** variable frame rate. */ private void writeVideoOnlyVFR(File movieFile, File[] imgFiles, int width, int height, double fps, QuickTimeWriter.VideoFormat videoFormat, /*boolean passThrough,*/ String streaming) throws IOException { File tmpFile = streaming.equals("none") ? movieFile : new File(movieFile.getPath() + ".tmp"); - ProgressMonitor p = new ProgressMonitor(MovieMaker.this, "Creating " + movieFile.getName(), "Creating Output File...", 0, imgFiles.length); + ProgressMonitor p = new ProgressMonitor(MovieMaker.this, + "Creating " + movieFile.getName(), + "Creating output file...", + 0, imgFiles.length); Graphics2D g = null; BufferedImage img = null; BufferedImage prevImg = null; @@ -1344,6 +1126,208 @@ public class MovieMaker extends JFrame implements Tool { } } + + /** + * Targa image loader for RLE-compressed TGA files. + * Code taken from PApplet, any changes here should lead to updates there. + */ + static private BufferedImage loadImageTGA(File file) throws IOException { + InputStream is = new FileInputStream(file); + + try { + byte header[] = new byte[18]; + int offset = 0; + do { + int count = is.read(header, offset, header.length - offset); + if (count == -1) return null; + offset += count; + } while (offset < 18); + + /* + header[2] image type code + 2 (0x02) - Uncompressed, RGB images. + 3 (0x03) - Uncompressed, black and white images. + 10 (0x0A) - Run-length encoded RGB images. + 11 (0x0B) - Compressed, black and white images. (grayscale?) + + header[16] is the bit depth (8, 24, 32) + + header[17] image descriptor (packed bits) + 0x20 is 32 = origin upper-left + 0x28 is 32 + 8 = origin upper-left + 32 bits + + 7 6 5 4 3 2 1 0 + 128 64 32 16 8 4 2 1 + */ + + int format = 0; + final int RGB = 1; + final int ARGB = 2; + final int ALPHA = 4; + + if (((header[2] == 3) || (header[2] == 11)) && // B&W, plus RLE or not + (header[16] == 8) && // 8 bits + ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 bit + format = ALPHA; + + } else if (((header[2] == 2) || (header[2] == 10)) && // RGB, RLE or not + (header[16] == 24) && // 24 bits + ((header[17] == 0x20) || (header[17] == 0))) { // origin + format = RGB; + + } else if (((header[2] == 2) || (header[2] == 10)) && + (header[16] == 32) && + ((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 + format = ARGB; + } + + if (format == 0) { + throw new IOException("Unknown .tga file format for " + file.getName()); + } + + int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff); + int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff); + //PImage outgoing = createImage(w, h, format); + int[] pixels = new int[w * h]; + + // where "reversed" means upper-left corner (normal for most of + // the modernized world, but "reversed" for the tga spec) + //boolean reversed = (header[17] & 0x20) != 0; + // https://github.com/processing/processing/issues/1682 + boolean reversed = (header[17] & 0x20) == 0; + + if ((header[2] == 2) || (header[2] == 3)) { // not RLE encoded + if (reversed) { + int index = (h-1) * w; + switch (format) { + case ALPHA: + for (int y = h-1; y >= 0; y--) { + for (int x = 0; x < w; x++) { + pixels[index + x] = is.read(); + } + index -= w; + } + break; + case RGB: + for (int y = h-1; y >= 0; y--) { + for (int x = 0; x < w; x++) { + pixels[index + x] = + is.read() | (is.read() << 8) | (is.read() << 16) | + 0xff000000; + } + index -= w; + } + break; + case ARGB: + for (int y = h-1; y >= 0; y--) { + for (int x = 0; x < w; x++) { + pixels[index + x] = + is.read() | (is.read() << 8) | (is.read() << 16) | + (is.read() << 24); + } + index -= w; + } + } + } else { // not reversed + int count = w * h; + switch (format) { + case ALPHA: + for (int i = 0; i < count; i++) { + pixels[i] = is.read(); + } + break; + case RGB: + for (int i = 0; i < count; i++) { + pixels[i] = + is.read() | (is.read() << 8) | (is.read() << 16) | + 0xff000000; + } + break; + case ARGB: + for (int i = 0; i < count; i++) { + pixels[i] = + is.read() | (is.read() << 8) | (is.read() << 16) | + (is.read() << 24); + } + break; + } + } + + } else { // header[2] is 10 or 11 + int index = 0; + + while (index < pixels.length) { + int num = is.read(); + boolean isRLE = (num & 0x80) != 0; + if (isRLE) { + num -= 127; // (num & 0x7F) + 1 + int pixel = 0; + switch (format) { + case ALPHA: + pixel = is.read(); + break; + case RGB: + pixel = 0xFF000000 | + is.read() | (is.read() << 8) | (is.read() << 16); + //(is.read() << 16) | (is.read() << 8) | is.read(); + break; + case ARGB: + pixel = is.read() | + (is.read() << 8) | (is.read() << 16) | (is.read() << 24); + break; + } + for (int i = 0; i < num; i++) { + pixels[index++] = pixel; + if (index == pixels.length) break; + } + } else { // write up to 127 bytes as uncompressed + num += 1; + switch (format) { + case ALPHA: + for (int i = 0; i < num; i++) { + pixels[index++] = is.read(); + } + break; + case RGB: + for (int i = 0; i < num; i++) { + pixels[index++] = 0xFF000000 | + is.read() | (is.read() << 8) | (is.read() << 16); + } + break; + case ARGB: + for (int i = 0; i < num; i++) { + pixels[index++] = is.read() | + (is.read() << 8) | (is.read() << 16) | (is.read() << 24); + } + break; + } + } + } + + if (!reversed) { + int[] temp = new int[w]; + for (int y = 0; y < h/2; y++) { + int z = (h-1) - y; + System.arraycopy(pixels, y*w, temp, 0, w); + System.arraycopy(pixels, z*w, pixels, y*w, w); + System.arraycopy(temp, 0, pixels, z*w, w); + } + } + } + //is.close(); + int type = (format == RGB) ? + BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; + BufferedImage image = new BufferedImage(w, h, type); + WritableRaster wr = image.getRaster(); + wr.setDataElements(0, 0, w, h, pixels); + return image; + + } finally { + is.close(); + } + } + + /** * @param args the command line arguments */ @@ -1358,6 +1342,7 @@ public class MovieMaker extends JFrame implements Tool { } }); } + private JLabel aboutLabel; private JButton chooseImageFolderButton; From 6b1eb45e9a0a3711e66be44c441c1b9128791308 Mon Sep 17 00:00:00 2001 From: Martin Leopold Date: Thu, 10 Oct 2013 10:41:24 +0200 Subject: [PATCH 140/556] Fixed build errors on OS X, when ant is run from a location other than build/macosx --- .../src/com/oracle/appbundler/BundleDocument.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java b/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java index a959f08c4..2f0a01fdf 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/BundleDocument.java @@ -34,8 +34,7 @@ import org.apache.tools.ant.BuildException; public class BundleDocument { private String name = "editor"; private String role = ""; - private String icon = null; - private File iconFile; + private File icon = null; private String[] extensions; private boolean isPackage = false; @@ -56,9 +55,8 @@ public class BundleDocument { } } - public void setIcon(String icon) { + public void setIcon(File icon) { this.icon = icon; - this.iconFile = new File(icon); } public void setName(String name) { @@ -82,12 +80,12 @@ public class BundleDocument { // } public String getIconName() { - return iconFile.getName(); + return icon.getName(); } public File getIconFile() { - return iconFile; + return icon; } public String getName() { From c1dfec1263c6f355501587336b8444babfe2d339 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Fri, 11 Oct 2013 12:30:40 -0400 Subject: [PATCH 141/556] stick with old naming --- .../com/oracle/appbundler/AppBundlerTask.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index eb06b9a3f..87231566b 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -63,7 +63,7 @@ public class AppBundlerTask extends Task { private String name = null; private String displayName = null; private String identifier = null; - private File icon = null; + private File iconFile = null; private String executableName = EXECUTABLE_NAME; private String shortVersion = null; //"1.0"; @@ -121,7 +121,7 @@ public class AppBundlerTask extends Task { public void setIcon(File icon) { - this.icon = icon; + this.iconFile = icon; } @@ -332,12 +332,12 @@ public class AppBundlerTask extends Task { throw new IllegalStateException("Identifier is required."); } - if (icon != null) { - if (!icon.exists()) { + if (iconFile != null) { + if (!iconFile.exists()) { throw new IllegalStateException("Icon does not exist."); } - if (icon.isDirectory()) { + if (iconFile.isDirectory()) { throw new IllegalStateException("Invalid icon."); } } @@ -552,11 +552,11 @@ public class AppBundlerTask extends Task { private void copyIcon(File resourcesDirectory) throws IOException { - if (icon == null) { + if (iconFile == null) { copy(getClass().getResource(DEFAULT_ICON_NAME), new File(resourcesDirectory, DEFAULT_ICON_NAME)); } else { - copy(icon, new File(resourcesDirectory, icon.getName())); + copy(iconFile, new File(resourcesDirectory, iconFile.getName())); } } @@ -584,7 +584,7 @@ public class AppBundlerTask extends Task { // Write bundle properties plist.writeProperty("CFBundleDevelopmentRegion", "English"); plist.writeProperty("CFBundleExecutable", executableName); - plist.writeProperty("CFBundleIconFile", (icon == null) ? DEFAULT_ICON_NAME : icon.getName()); + plist.writeProperty("CFBundleIconFile", (iconFile == null) ? DEFAULT_ICON_NAME : iconFile.getName()); plist.writeProperty("CFBundleIdentifier", identifier); plist.writeProperty("CFBundleDisplayName", displayName); plist.writeProperty("CFBundleInfoDictionaryVersion", "6.0"); From a9097a8962b2b2e844608cdf21d57be24c8eb0c7 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Fri, 11 Oct 2013 16:51:30 -0400 Subject: [PATCH 142/556] handle warning, remove debug flag, update appbundler --- app/src/processing/app/Base.java | 4 ++-- .../src/com/oracle/appbundler/AppBundlerTask.java | 8 ++++---- core/todo.txt | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index f5fa6f9d7..93ce3df03 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -53,8 +53,8 @@ public class Base { // static private boolean RELEASE = false; /** True if heavy debugging error/log messages are enabled */ -// static public boolean DEBUG = false; - static public boolean DEBUG = true; + static public boolean DEBUG = false; +// static public boolean DEBUG = true; static HashMap platformNames = new HashMap(); diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index 87231566b..30ba1d126 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -508,11 +508,11 @@ public class AppBundlerTask extends Task { private void copyClassPathRefEntries(File javaDirectory) throws IOException { if (classPathRef != null) { org.apache.tools.ant.types.Path classpath = - (org.apache.tools.ant.types.Path) classPathRef.getReferencedObject(getProject()); + (org.apache.tools.ant.types.Path) classPathRef.getReferencedObject(getProject()); - Iterator iter = (Iterator)(Object)classpath.iterator(); - while(iter.hasNext()) { - FileResource resource = iter.next(); + Iterator iter = classpath.iterator(); + while (iter.hasNext()) { + FileResource resource = (FileResource) iter.next(); File source = resource.getFile(); File destination = new File(javaDirectory, source.getName()); copy(source, destination); diff --git a/core/todo.txt b/core/todo.txt index e4a57303b..1aa0972b8 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -17,6 +17,7 @@ X https://github.com/processing/processing/issues/2113 X constrain lerpColor() between 0 and 1 _ JSONObject/Array.format(-1) not working on embedded JSONObjects +_ should be a quick fix, notes are in the report _ https://github.com/processing/processing/issues/2119 opengl From ef93f09b9c1bc7f95e3395cdcc0547af65d1b5cd Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Fri, 11 Oct 2013 18:25:41 -0400 Subject: [PATCH 143/556] add varargs to print() and println() (#2056) --- core/src/processing/core/PApplet.java | 28 +++++++++++++++++++++++++-- core/todo.txt | 2 ++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 652c7e862..3bd550fa4 100755 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -4380,6 +4380,23 @@ public class PApplet extends Applet System.out.flush(); } + + static public void print(Object... variables) { + StringBuilder sb = new StringBuilder(); + for (Object o : variables) { + if (sb.length() != 0) { + sb.append(" "); + } + if (o == null) { + sb.append("null"); + } else { + sb.append(o.toString()); + } + } + System.out.print(sb.toString()); + } + + static public void print(Object what) { if (what == null) { // special case since this does fuggly things on > 1.1 @@ -4389,8 +4406,8 @@ public class PApplet extends Applet } } - // -/** + + /** * ( begin auto-generated from println.xml ) * * Writes to the text area of the Processing environment's console. This is @@ -4458,6 +4475,13 @@ public class PApplet extends Applet System.out.flush(); } + + static public void println(Object... variables) { + print(variables); + println(); + } + + static public void println(Object what) { if (what == null) { // special case since this does fuggly things on > 1.1 diff --git a/core/todo.txt b/core/todo.txt index 1aa0972b8..8fde85231 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -15,6 +15,8 @@ X https://github.com/processing/processing/pull/2070 X Java2D images crash after being resized X https://github.com/processing/processing/issues/2113 X constrain lerpColor() between 0 and 1 +X allow println() and print() to take varargs +X https://github.com/processing/processing/issues/2056 _ JSONObject/Array.format(-1) not working on embedded JSONObjects _ should be a quick fix, notes are in the report From 316a600a9d0991c0d18246b2d32e4fc07a045cd6 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Fri, 11 Oct 2013 19:15:01 -0400 Subject: [PATCH 144/556] looking for a better solution here --- core/src/processing/core/PApplet.java | 16 +++++++++++++++- core/todo.txt | 3 ++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 3bd550fa4..9e6e20b4a 100755 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -4431,7 +4431,7 @@ public class PApplet extends Applet System.out.println(); } - // + /** * @param what boolean, byte, char, color, int, float, String, Object */ @@ -4477,11 +4477,25 @@ public class PApplet extends Applet static public void println(Object... variables) { +// System.out.println("got " + variables.length + " variables"); print(variables); println(); } + /* + // Breaking this out since the compiler doesn't know the difference between + // Object... and just Object (with an array passed in). This should take care + // of the confusion for at least the most common case (a String array). + static public void println(String[] array) { + for (int i = 0; i < array.length; i++) { + System.out.println("[" + i + "] \"" + array[i] + "\""); + } + System.out.flush(); + } + */ + + static public void println(Object what) { if (what == null) { // special case since this does fuggly things on > 1.1 diff --git a/core/todo.txt b/core/todo.txt index 8fde85231..5b4901c66 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -16,7 +16,8 @@ X Java2D images crash after being resized X https://github.com/processing/processing/issues/2113 X constrain lerpColor() between 0 and 1 X allow println() and print() to take varargs -X https://github.com/processing/processing/issues/2056 +o https://github.com/processing/processing/issues/2056 +_ causes conflict with printing arrays _ JSONObject/Array.format(-1) not working on embedded JSONObjects _ should be a quick fix, notes are in the report From c1b076ba07f4481bea1e92ab6cd00f3094200230 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Fri, 11 Oct 2013 19:27:10 -0400 Subject: [PATCH 145/556] fix indents for child elements when using -1 (#2119) --- core/src/processing/data/JSONArray.java | 11 +++++++---- core/src/processing/data/JSONObject.java | 11 ++++++----- core/todo.txt | 6 ++---- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/core/src/processing/data/JSONArray.java b/core/src/processing/data/JSONArray.java index c25ac93f3..0e665c805 100644 --- a/core/src/processing/data/JSONArray.java +++ b/core/src/processing/data/JSONArray.java @@ -1182,9 +1182,10 @@ public class JSONArray { if (length == 1) { JSONObject.writeValue(writer, this.myArrayList.get(0), - thisFactor, indent); + indentFactor, indent); +// thisFactor, indent); } else if (length != 0) { - final int newindent = indent + thisFactor; + final int newIndent = indent + thisFactor; for (int i = 0; i < length; i += 1) { if (commanate) { @@ -1193,9 +1194,11 @@ public class JSONArray { if (indentFactor != -1) { writer.write('\n'); } - JSONObject.indent(writer, newindent); + JSONObject.indent(writer, newIndent); +// JSONObject.writeValue(writer, this.myArrayList.get(i), +// thisFactor, newIndent); JSONObject.writeValue(writer, this.myArrayList.get(i), - thisFactor, newindent); + indentFactor, newIndent); commanate = true; } if (indentFactor != -1) { diff --git a/core/src/processing/data/JSONObject.java b/core/src/processing/data/JSONObject.java index 0b1c1127c..165b099cd 100644 --- a/core/src/processing/data/JSONObject.java +++ b/core/src/processing/data/JSONObject.java @@ -1790,9 +1790,10 @@ public class JSONObject { if (actualFactor > 0) { writer.write(' '); } - writeValue(writer, this.map.get(key), actualFactor, indent); + //writeValue(writer, this.map.get(key), actualFactor, indent); + writeValue(writer, this.map.get(key), indentFactor, indent); } else if (length != 0) { - final int newindent = indent + actualFactor; + final int newIndent = indent + actualFactor; while (keys.hasNext()) { Object key = keys.next(); if (commanate) { @@ -1801,14 +1802,14 @@ public class JSONObject { if (indentFactor != -1) { writer.write('\n'); } - indent(writer, newindent); + indent(writer, newIndent); writer.write(quote(key.toString())); writer.write(':'); if (actualFactor > 0) { writer.write(' '); } - writeValue(writer, this.map.get(key), actualFactor, - newindent); + //writeValue(writer, this.map.get(key), actualFactor, newIndent); + writeValue(writer, this.map.get(key), indentFactor, newIndent); commanate = true; } if (indentFactor != -1) { diff --git a/core/todo.txt b/core/todo.txt index 5b4901c66..329e82178 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -15,14 +15,12 @@ X https://github.com/processing/processing/pull/2070 X Java2D images crash after being resized X https://github.com/processing/processing/issues/2113 X constrain lerpColor() between 0 and 1 +X JSONObject/Array.format(-1) not working on embedded JSONObjects +X https://github.com/processing/processing/issues/2119 X allow println() and print() to take varargs o https://github.com/processing/processing/issues/2056 _ causes conflict with printing arrays -_ JSONObject/Array.format(-1) not working on embedded JSONObjects -_ should be a quick fix, notes are in the report -_ https://github.com/processing/processing/issues/2119 - opengl X fix inconsistency with P2D and resetMatrix() X https://github.com/processing/processing/issues/2087 From f7dc181bbe9ecd9b5988f76740b11c806801ccfe Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Fri, 11 Oct 2013 20:37:19 -0400 Subject: [PATCH 146/556] textureMode(REPEAT) throws an error (#2052) --- core/src/processing/core/PGraphics.java | 3 +++ core/todo.txt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index dc47a2c6c..8ec72c89d 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -1224,6 +1224,9 @@ public class PGraphics extends PImage implements PConstants { * @see PGraphics#textureWrap(int) */ public void textureMode(int mode) { + if (mode != IMAGE && mode != NORMAL) { + throw new RuntimeException("textureMode() only supports IMAGE and NORMAL"); + } this.textureMode = mode; } diff --git a/core/todo.txt b/core/todo.txt index 329e82178..43fcad9c1 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -36,6 +36,8 @@ X child SVG elements misplaced when rendering with P2D/P3D X https://github.com/processing/processing/issues/2086 X SUBTRACT and DIFFERENCE blend modes are swapped X https://github.com/processing/processing/issues/2075 +X throw an error for textureMode(REPEAT) [fry] +X https://github.com/processing/processing/issues/2052 _ Sort out blending differences with P2D/P3D _ https://github.com/processing/processing/issues/1844 From b2e5752975ffc4a782be2d29ce87332bed76cb70 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Fri, 11 Oct 2013 20:45:37 -0400 Subject: [PATCH 147/556] clearing out serial issues --- todo.txt | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/todo.txt b/todo.txt index 88d0d6dc0..8e71e3b2d 100644 --- a/todo.txt +++ b/todo.txt @@ -16,6 +16,29 @@ X https://github.com/processing/processing/issues/2103 X still having right-click issues (re-opened) X https://github.com/processing/processing/issues/2103 +serial +X closing several bugs because no longer relevant +X need 64-bit version of RXTX library +X http://code.google.com/p/processing/issues/detail?id=1237 +X https://github.com/processing/processing/issues/1275 +X serial still causing problems on OS X +X http://code.google.com/p/processing/issues/detail?id=52 +X had already been closed +X serial ports missing from list (OS X) +X http://code.google.com/p/processing/issues/detail?id=52 +X also was marked fixed... +X Serial.write problem with Bluetooth SPP virtual serial port +X http://code.google.com/p/processing/issues/detail?id=318 +X was marked duplicate of #52 +X Serial silently fails when invalid port entered as string +o https://github.com/processing/processing/issues/2114 +X Serial Issue for RPi (and others) +o https://github.com/processing/processing/issues/2066 +X RXTX-2.1-7 doesn't list ports created in /dev with VirtualSerialPortApp +o https://github.com/processing/processing/issues/1460 +X Bluetooth serial problems on Windows when connecting to Arduino device +o https://github.com/processing/processing/issues/1374 + movie maker o moviemaker video sizes / usability o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Exhibition;action=display;num=1211318862 @@ -815,18 +838,6 @@ _ need to unpack InvocationTargetException in xxxxxxEvent calls _ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=VideoCamera;action=display;num=1116850328#3 -LIBRARIES / Serial - -_ need 64-bit version of RXTX library -_ http://code.google.com/p/processing/issues/detail?id=1237 -_ serial still causing problems on OS X -_ http://code.google.com/p/processing/issues/detail?id=52 -_ serial ports missing from list (OS X) -_ http://code.google.com/p/processing/issues/detail?id=52 -_ Serial.write problem with Bluetooth SPP virtual serial port -_ http://code.google.com/p/processing/issues/detail?id=318 - - //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// From 543d51fc3b201da4e596323cf13fda6980fd0560 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 12 Oct 2013 18:01:06 -0400 Subject: [PATCH 148/556] add notes about iText library and version --- java/libraries/pdf/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 java/libraries/pdf/README.md diff --git a/java/libraries/pdf/README.md b/java/libraries/pdf/README.md new file mode 100644 index 000000000..a5fe4967c --- /dev/null +++ b/java/libraries/pdf/README.md @@ -0,0 +1,11 @@ +This library uses iText 2.1.7, which is the last LGPL/MPL version of the iText project. + +We've used iText for several years. The license for iText has changed for subsequent versions and is no longer compatible with Processing, so we're stuck at 2.x. + +At the iText site, there's also some [vague wording](http://lowagie.com/itext2) about legal liability for commercial projects using the 2.x series. It's not clear where this leaves us. + +Bruno Lowagie did an enormous amount of (free) work with the iText project, and we certainly don't fault him for the new commercial license. + +We're using iText in a very limited way--drawing to it like it's a Java Graphics2D object. There might be other options for us in this space, but it's not much of a priority. + +Ben Fry, 12 October 2013 From cf559b4a90f1bfa830cb8b92e283066eae99657f Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 12 Oct 2013 18:01:16 -0400 Subject: [PATCH 149/556] resolution for println() issues --- app/src/processing/mode/java/runner/Runner.java | 2 +- build/shared/revisions.txt | 7 +++++++ core/src/processing/core/PApplet.java | 15 +++++++++++++++ core/todo.txt | 3 ++- todo.txt | 5 ++++- 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/src/processing/mode/java/runner/Runner.java b/app/src/processing/mode/java/runner/Runner.java index 4bc3cb72d..31e9bf2a1 100644 --- a/app/src/processing/mode/java/runner/Runner.java +++ b/app/src/processing/mode/java/runner/Runner.java @@ -470,7 +470,7 @@ public class Runner implements MessageConsumer { // PApplet.println("launchJava stderr:"); // PApplet.println(errorStrings); // PApplet.println("launchJava stdout:"); - PApplet.println(inputStrings); + PApplet.printArray(inputStrings); if (errorStrings != null && errorStrings.length > 1) { if (errorStrings[0].indexOf("Invalid maximum heap size") != -1) { diff --git a/build/shared/revisions.txt b/build/shared/revisions.txt index 53d874efb..134ac7d0a 100644 --- a/build/shared/revisions.txt +++ b/build/shared/revisions.txt @@ -1,3 +1,10 @@ +PROCESSING 2.1 beta 1 (REV 0222) - XX October 2013 + ++ Added printArray() function for people who want to avoid the compiler warnings with Eclipse or whatever else, and deprecating the old println(Object) in favor of people using printArray(). In the PDE, this should be transparent (the warnings are not shown). + +. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + PROCESSING 2.0.3 (REV 0221) - 5 September 2013 Lots of bug fixes, primarily a ton of work by Andres to improve diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 9e6e20b4a..1077b794a 100755 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -4397,6 +4397,7 @@ public class PApplet extends Applet } + /* static public void print(Object what) { if (what == null) { // special case since this does fuggly things on > 1.1 @@ -4405,6 +4406,7 @@ public class PApplet extends Applet System.out.println(what.toString()); } } + */ /** @@ -4487,6 +4489,8 @@ public class PApplet extends Applet // Breaking this out since the compiler doesn't know the difference between // Object... and just Object (with an array passed in). This should take care // of the confusion for at least the most common case (a String array). + // On second thought, we're going the printArray() route, since the other + // object types are also used frequently. static public void println(String[] array) { for (int i = 0; i < array.length; i++) { System.out.println("[" + i + "] \"" + array[i] + "\""); @@ -4496,7 +4500,18 @@ public class PApplet extends Applet */ + /** + * Use printArray() instead. This function causes a warning because the new + * print(Object...) and println(Object...) functions can't be reliably + * bound by the compiler. + */ + @Deprecated static public void println(Object what) { + printArray(what); + } + + + static public void printArray(Object what) { if (what == null) { // special case since this does fuggly things on > 1.1 System.out.println("null"); diff --git a/core/todo.txt b/core/todo.txt index 43fcad9c1..9f0071548 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -19,7 +19,8 @@ X JSONObject/Array.format(-1) not working on embedded JSONObjects X https://github.com/processing/processing/issues/2119 X allow println() and print() to take varargs o https://github.com/processing/processing/issues/2056 -_ causes conflict with printing arrays +X causes conflict with printing arrays +X added printArray() function instead opengl X fix inconsistency with P2D and resetMatrix() diff --git a/todo.txt b/todo.txt index 8e71e3b2d..007b5eecb 100644 --- a/todo.txt +++ b/todo.txt @@ -588,6 +588,8 @@ _ see how library installation goes, then possibly do same w/ examples PDE / Libraries +_ Add a means to specify packages to import in library.properties +_ https://github.com/processing/processing/issues/2134 _ need to deal with classpath conflicts _ avoid garbage that people have installed on their machines _ antlr.jar in the classpath will cause trouble.. @@ -632,7 +634,8 @@ _ String osName = System.getProperty("os.name"); _ String osArch = System.getProperty("os.arch"); _ http://stackoverflow.com/questions/1611357/how-to-make-a-jar-file-that-include-dll-files _ add control for dependencies (i.e. svg needs xml), needed for export -_ http://code.google.com/p/processing/issues/detail?id=70 +X http://code.google.com/p/processing/issues/detail?id=70 +_ https://github.com/processing/processing/issues/109 _ need better platform designation setup for libs _ library installation should use the sketchbook folder, not the p5 folder _ actually enforce this, give users a warning about other libs From d821d04c5b6b54b2b66e72108229d504b5405a81 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 12 Oct 2013 21:54:49 -0400 Subject: [PATCH 150/556] remove 32/64 pref, add dummy window, other OS X fixes for 7u40 --- app/src/processing/app/Base.java | 2 + app/src/processing/app/Preferences.java | 10 ++++- .../app/platform/ThinkDifferent.java | 38 ++++++++++++------- .../processing/mode/java/runner/Runner.java | 34 +++-------------- core/todo.txt | 10 +++-- todo.txt | 30 ++++++++------- 6 files changed, 63 insertions(+), 61 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 93ce3df03..6f86dbba5 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1038,6 +1038,7 @@ public class Base { // Close the running window, avoid window boogers with multiple sketches editor.internalCloseRunner(); +// System.out.println("editors size is " + editors.size()); if (editors.size() == 1) { // For 0158, when closing the last window /and/ it was already an // untitled sketch, just give up and let the user quit. @@ -1077,6 +1078,7 @@ public class Base { // This will store the sketch count as zero editors.remove(editor); +// System.out.println("editors size now " + editors.size()); // storeSketches(); // Save out the current prefs state diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 51a4d7127..ba391e47e 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -116,8 +116,8 @@ public class Preferences { JTextField fontSizeField; JCheckBox inputMethodBox; JCheckBox autoAssociateBox; - JRadioButton bitsThirtyTwoButton; - JRadioButton bitsSixtyFourButton; + //JRadioButton bitsThirtyTwoButton; + //JRadioButton bitsSixtyFourButton; JComboBox displaySelectionBox; int displayCount; @@ -455,6 +455,7 @@ public class Preferences { // Launch programs as [ ] 32-bit [ ] 64-bit (Mac OS X only) + /* if (Base.isMacOS()) { box = Box.createHorizontalBox(); label = new JLabel("Launch programs in "); @@ -473,6 +474,7 @@ public class Preferences { box.setBounds(left, top, d.width, d.height); top += d.height + GUI_BETWEEN; } + */ // More preferences are in the ... @@ -679,6 +681,7 @@ public class Preferences { } */ + /* // If a change has been made between 32- and 64-bit, the libraries need // to be reloaded so that their native paths are set correctly. if (Base.isMacOS()) { @@ -691,6 +694,7 @@ public class Preferences { } } } + */ String newSizeText = fontSizeField.getText(); try { @@ -756,6 +760,7 @@ public class Preferences { memoryField. setText(get("run.options.memory.maximum")); //$NON-NLS-1$ + /* if (Base.isMacOS()) { String bits = Preferences.get("run.options.bits"); //$NON-NLS-1$ if (bits.equals("32")) { //$NON-NLS-1$ @@ -769,6 +774,7 @@ public class Preferences { bitsThirtyTwoButton.setEnabled(false); } } + */ if (autoAssociateBox != null) { autoAssociateBox. diff --git a/app/src/processing/app/platform/ThinkDifferent.java b/app/src/processing/app/platform/ThinkDifferent.java index 69c94218d..aba1ed4ba 100644 --- a/app/src/processing/app/platform/ThinkDifferent.java +++ b/app/src/processing/app/platform/ThinkDifferent.java @@ -22,7 +22,9 @@ package processing.app.platform; +import java.awt.Dimension; import java.awt.event.*; + import javax.swing.*; import processing.app.About; @@ -74,27 +76,37 @@ public class ThinkDifferent implements ApplicationListener { // Set the menubar to be used when nothing else is open. http://j.mp/dkZmka // Only available since Java for Mac OS X 10.6 Update 1, but removed // dynamic loading code because that should be installed in 10.6.8, and - // we may be dropped 10.6 really soon anyway. + // we may be dropped 10.6 really soon anyway + + JMenuBar defaultMenuBar = new JMenuBar(); + JMenu fileMenu = buildFileMenu(base); + defaultMenuBar.add(fileMenu); + // This is kind of a gross way to do this, but the alternatives? Hrm. + Base.defaultFileMenu = fileMenu; + if (PApplet.javaVersion <= 1.6f) { // doesn't work on Oracle's Java -// if (System.getProperty("java.vendor").contains("Apple") || -// Base.isUsableOracleJava()) { try { - JMenuBar defaultMenuBar = new JMenuBar(); - JMenu fileMenu = buildFileMenu(base); - defaultMenuBar.add(fileMenu); - application.setDefaultMenuBar(new JMenuBar()); - // This is kind of a gross way to do this, but the alternatives? Hrm. - Base.defaultFileMenu = fileMenu; + application.setDefaultMenuBar(defaultMenuBar); + } catch (Exception e) { e.printStackTrace(); // oh well nevermind } } else { - // http://java.net/jira/browse/MACOSX_PORT-775?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel - System.err.println("Skipping default menu bar due to Oracle Java 7 bug:"); - System.err.println("http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8007267"); + // The douchebags at Oracle didn't feel that a working f*king menubar + // on OS X was important enough to make it into the 7u40 release. + //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8007267 + // It languished in the JDK 8 source and has been backported for 7u60: + //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8022667 + + JFrame offscreen = new JFrame(); + offscreen.setUndecorated(true); + offscreen.setJMenuBar(defaultMenuBar); + Dimension screen = Toolkit.getScreenSize(); + offscreen.setLocation(screen.width, screen.height); + offscreen.setVisible(true); } } - + public ThinkDifferent(Base base) { this.base = base; diff --git a/app/src/processing/mode/java/runner/Runner.java b/app/src/processing/mode/java/runner/Runner.java index 31e9bf2a1..118376dd3 100644 --- a/app/src/processing/mode/java/runner/Runner.java +++ b/app/src/processing/mode/java/runner/Runner.java @@ -123,11 +123,7 @@ public class Runner implements MessageConsumer { } -// public void launch(String appletClassName, boolean presenting) { -// this.appletClassName = appletClassName; public boolean launchVirtualMachine(boolean presenting) { -// this.presenting = presenting; - String[] vmParams = getMachineParams(); String[] sketchParams = getSketchParams(presenting); int port = 8000 + (int) (Math.random() * 1000); @@ -139,10 +135,13 @@ public class Runner implements MessageConsumer { // Newer (Java 1.5+) version that uses JVMTI String jdwpArg = "-agentlib:jdwp=transport=dt_socket,address=" + portStr + ",server=y,suspend=y"; + // Everyone works the same under Java 7 (also on OS X) + String[] commandArgs = new String[] { Base.getJavaPath(), jdwpArg }; + + /* String[] commandArgs = null; if (!Base.isMacOS()) { commandArgs = new String[] { - //"java", Base.getJavaPath(), jdwpArg }; @@ -191,36 +190,13 @@ public class Runner implements MessageConsumer { }; } } + */ commandArgs = PApplet.concat(commandArgs, vmParams); commandArgs = PApplet.concat(commandArgs, sketchParams); // PApplet.println(commandArgs); // commandArg.setValue(commandArgs); launchJava(commandArgs); -// try { -// Thread.sleep(2000); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } - -// boolean available = false; -// while (!available) { -// try { -// Socket socket = new Socket((String) null, port); -//// socket.close(); -// // this should mean we're all set? -// available = true; -// -// } catch (IOException e) { -// System.out.println("waiting"); -// //e.printStackTrace(); -// try { -// Thread.sleep(100); -// } catch (InterruptedException e1) { -// e1.printStackTrace(); -// } -// } -// } AttachingConnector connector = (AttachingConnector) findConnector("com.sun.jdi.SocketAttach"); diff --git a/core/todo.txt b/core/todo.txt index 9f0071548..6f3cda91c 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -21,6 +21,12 @@ X allow println() and print() to take varargs o https://github.com/processing/processing/issues/2056 X causes conflict with printing arrays X added printArray() function instead +o custom DPI settings with PDF +X https://github.com/processing/processing/pull/2069 +X pdf not rendering unicode with beginRecord() +X seems to have fixed itself / can't reproduce +X http://code.google.com/p/processing/issues/detail?id=90 +X https://github.com/processing/processing/issues/129 opengl X fix inconsistency with P2D and resetMatrix() @@ -46,8 +52,6 @@ _ 'collector' class.. Dict that points to a list _ String as a key, int/float/string list as values high -_ custom DPI settings with PDF -_ https://github.com/processing/processing/pull/2069 _ loadPixels doesn't set alpha value for pixels on Java2D _ https://github.com/processing/processing/issues/2030 _ blendMode(ADD) is broken with default renderer @@ -540,8 +544,6 @@ _ touchEvent(), gestureEvent()? LIBRARIES / PDF -_ pdf not rendering unicode with beginRecord() -_ http://code.google.com/p/processing/issues/detail?id=90 _ beginRecord() doesn't use current settings of the sketch _ sometimes reported as a bug, but probably not a good way to _ consistently carry these over diff --git a/todo.txt b/todo.txt index 007b5eecb..df019aa12 100644 --- a/todo.txt +++ b/todo.txt @@ -16,6 +16,11 @@ X https://github.com/processing/processing/issues/2103 X still having right-click issues (re-opened) X https://github.com/processing/processing/issues/2103 +cleaning +o the first time someone hides a tab, put up a msg explaining what it does +o "don't warn me about this anymore" +X removed this feature a while back + serial X closing several bugs because no longer relevant X need 64-bit version of RXTX library @@ -58,16 +63,14 @@ _ and the command line tools Preferences > Downloads > Command Line Tools _ appbundler will have an NPE if the osx binary isn't built _ also need to have 10.8 version of the SDK (old Xcode won't work) -_ type looks a little feeble on OS X -_ retina problem? may need to turn off (on?) smoothing +_ type looks a little feeble on OS X with non-retina machines +_ https://github.com/processing/processing/issues/2135 _ type cut off in dialog boxes on OS X retina machines _ https://github.com/processing/processing/issues/2116 _ dialog box icon is fuzzy on OS X retina machines _ https://github.com/processing/processing/issues/2117 +_ solution might be our own dialog boxes (see 'dialogs' section) -_ also need to have a central menubar -_ add the offscreen window hack -_ otherwise mode change causes "do you want to quit?" on OS X _ fix console font on Windows and Linux with 7u40 _ the message area text also looks ugly.. can we fix? _ add pref to select PDE font (so that CJKV languages work better) @@ -117,6 +120,11 @@ X http://www.oracle.com/technetwork/java/javase/jdk-7-readme-429198.html 7u40 switch X make OS X launch from its local JRE +X also need to have a central menubar +X add the offscreen window hack +X otherwise mode change causes "do you want to quit?" on OS X +X remove 32- and 64-bit preference from Preferences on OS X +o try the bundle on Mac Mini running 10.6 _ change how export is handled _ remove ability to export cross-platform apps @@ -129,9 +137,8 @@ _ change app stub in OS X exported application _ we become full 64-bit on OS X _ meaning that the macosx32 video library goes away _ and the preference for launching in 32- or 64-bit mode -_ try the bundle on Mac Mini running 10.6 -_ make sure it's only running on 64-bit machines? -_ try installing 10.7.3 on Mac Mini and check whether things run +_ make sure it's only running on 64-bit machines? +_ try installing 10.7.3 on Mac Mini and check whether things run _ bring back the splash screen _ update github instructions _ only JRE needed at this point @@ -358,15 +365,11 @@ PDE - Processing Development Environment PDE / Dialogs -_ proper dialog support -_ http://javagraphics.blogspot.com/2008/06/joptionpane-making-alternative.html _ two-tiered dialogs for everything - use big font/little font style throughout _ http://javagraphics.blogspot.com/2008/06/joptionpane-making-alternative.html _ option to suppress warning dialogs _ starting with the one about modifying the sketch name for spaces _ http://code.google.com/p/processing/issues/detail?id=7 -_ the first time someone hides a tab, put up a msg explaining what it does -_ "don't warn me about this anymore" _ add "don't warn me about this" for sketch renaming _ make sure renamed version doesn't exist already _ prompt user before nuking applet or application folders @@ -406,7 +409,8 @@ _ missing brackets, unmatched brackets _ examples added to the bug report _ http://code.google.com/p/processing/issues/detail?id=6 _ enums not supported properly -_ http://code.google.com/p/processing/issues/detail?id=1352 +_ https://github.com/processing/processing/issues/1390 +X http://code.google.com/p/processing/issues/detail?id=1352 low (features) _ combining char/int/etc casts in one statement causes preproc trouble From 0ce9322a6d293da9d25bda79be2e27a9b4ecd0d0 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 12 Oct 2013 23:18:53 -0400 Subject: [PATCH 151/556] notes about build --- todo.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/todo.txt b/todo.txt index df019aa12..768e72049 100644 --- a/todo.txt +++ b/todo.txt @@ -136,7 +136,7 @@ _ actually call ant from inside p5? _ change app stub in OS X exported application _ we become full 64-bit on OS X _ meaning that the macosx32 video library goes away -_ and the preference for launching in 32- or 64-bit mode +X and the preference for launching in 32- or 64-bit mode _ make sure it's only running on 64-bit machines? _ try installing 10.7.3 on Mac Mini and check whether things run _ bring back the splash screen @@ -175,6 +175,10 @@ _ add .bat file to lib on windows so that we can get better debugging info _ changing modes brings the PDE back on the second screen _ the Find window (also the save windows) also have the same problem +post 2.1 cleaning +_ remove video for macosx32 from the repo permanently +_ remove the prefs for 32/64-bit from Preferences +_ remove the extra OS X cruft inside Runner.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . From af3067ab2e82d4cb0cb8c0ccca2bff0ac8009986 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 12 Oct 2013 23:41:52 -0400 Subject: [PATCH 152/556] moving notes --- todo.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/todo.txt b/todo.txt index 768e72049..91a9f51be 100644 --- a/todo.txt +++ b/todo.txt @@ -125,21 +125,18 @@ X add the offscreen window hack X otherwise mode change causes "do you want to quit?" on OS X X remove 32- and 64-bit preference from Preferences on OS X o try the bundle on Mac Mini running 10.6 +X we become full 64-bit on OS X +X meaning that the macosx32 video library goes away +X and the preference for launching in 32- or 64-bit mode _ change how export is handled _ remove ability to export cross-platform apps _ add ability to embed the current JRE _ the case for the embedded JRE _ https://github.com/processing/processing/issues/2104 -_ change Windows export to use launch4j instead of the launcher.cpp file -_ actually call ant from inside p5? _ change app stub in OS X exported application -_ we become full 64-bit on OS X -_ meaning that the macosx32 video library goes away -X and the preference for launching in 32- or 64-bit mode -_ make sure it's only running on 64-bit machines? _ try installing 10.7.3 on Mac Mini and check whether things run -_ bring back the splash screen +_ make sure it's only running on 64-bit machines? _ update github instructions _ only JRE needed at this point _ switched over to Java 7 @@ -149,6 +146,10 @@ _ JAVA_HOME warnings from Ant can also be ignored _ appbundler improvements _ don't re-copy JRE into work folder if already exists +_ implement a splash screen + +_ change Windows export to use launch4j instead of the launcher.cpp file +_ actually call ant from inside p5? high _ move old Google Code SVN back to processing.org From 3f326e994b5958cec60ff8e5bfdf2afd364d0699 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 00:04:52 -0400 Subject: [PATCH 153/556] cleaning up Linux JRE issues --- build/build.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/build/build.xml b/build/build.xml index 54a738a77..025e2772a 100755 --- a/build/build.xml +++ b/build/build.xml @@ -776,7 +776,18 @@ + + + + + + + + + From bc3b191de9eaa830c61a608b6765a61928cbaa60 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 13:18:45 -0400 Subject: [PATCH 154/556] working on font options and prefs --- app/src/processing/app/EditorConsole.java | 1 + app/src/processing/app/Preferences.java | 103 +++++++++++++++---- app/src/processing/app/Toolkit.java | 46 +++++++++ app/src/processing/app/tools/CreateFont.java | 4 +- build/build.xml | 7 ++ todo.txt | 2 + 6 files changed, 142 insertions(+), 21 deletions(-) diff --git a/app/src/processing/app/EditorConsole.java b/app/src/processing/app/EditorConsole.java index dd822c7d0..18b582cc4 100644 --- a/app/src/processing/app/EditorConsole.java +++ b/app/src/processing/app/EditorConsole.java @@ -176,6 +176,7 @@ public class EditorConsole extends JScrollPane { consoleDoc.setParagraphAttributes(0, 0, standard, true); Font font = Preferences.getFont("console.font"); + //Font font = Toolkit.getMonoFont(size, style); // build styles for different types of console output Color bgColor = mode.getColor("console.color"); diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index ba391e47e..0699ffd3b 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -26,6 +26,7 @@ import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; +import java.util.List; import javax.swing.*; @@ -116,15 +117,18 @@ public class Preferences { JTextField fontSizeField; JCheckBox inputMethodBox; JCheckBox autoAssociateBox; + //JRadioButton bitsThirtyTwoButton; //JRadioButton bitsSixtyFourButton; + JComboBox displaySelectionBox; - int displayCount; + + //List monoFontList; + Font[] monoFontList; + JComboBox fontSelectionBox; - // the calling editor, so updates can be applied - -// Editor editor; + /** Base object so that updates can be applied to the list of editors. */ Base base; @@ -294,6 +298,39 @@ public class Preferences { top += vmax + GUI_BETWEEN; + // Editor and console font [ Source Code Pro ] + + // Nevermind on this for now.. Java doesn't seem to have a method for + // enumerating only the fixed-width (monospaced) fonts. To do this + // properly, we'd need to list the fonts, and compare the metrics of + // i and M for each. When they're identical (and not degenerate), + // we'd call that font fixed width. That's all a very expensive set of + // operations, so it should also probably be cached between runs and + // updated in the background. + + Container fontBox = Box.createHorizontalBox(); + JLabel fontLabel = new JLabel("Editor and Console font "); + final String fontTip = "" + + "Select the font used in the Editor and the Console.
    " + + "Only monospaced (fixed-width) fonts may be used,
    " + + "though the list may be imperfect."; + fontLabel.setToolTipText(fontTip); + fontBox.add(fontLabel); + // needs to happen here for getPreferredSize() + fontSelectionBox = new JComboBox(new Object[] { Toolkit.getMonoFontName() }); + fontSelectionBox.setToolTipText(fontTip); +// fontSelectionBox.addItem(Toolkit.getMonoFont(size, style)); + //updateDisplayList(); + fontSelectionBox.setEnabled(false); // don't enable until fonts are loaded + fontBox.add(fontSelectionBox); +// fontBox.add(Box.createHorizontalGlue()); + pain.add(fontBox); + d = fontBox.getPreferredSize(); + fontBox.setBounds(left, top, d.width + 150, d.height); +// fontBox.setBounds(left, top, dialog.getWidth() - left*2, d.height); + top += d.height + GUI_BETWEEN; + + // Editor font size [ ] Container box = Box.createHorizontalBox(); @@ -310,23 +347,7 @@ public class Preferences { fontSizeField.setText(String.valueOf(editorFont.getSize())); top += d.height + GUI_BETWEEN; - - // Nevermind on this for now.. Java doesn't seem to have a method for - // enumerating only the fixed-width (monospaced) fonts. To do this - // properly, we'd need to list the fonts, and compare the metrics of - // i and M for each. When they're identical (and not degenerate), - // we'd call that font fixed width. That's all a very expensive set of - // operations, so it should also probably be cached between runs and - // updated in the background. -// // Editor font -// -// GraphicsEnvironment ge = -// GraphicsEnvironment.getLocalGraphicsEnvironment(); -// Font fonts[] = ge.getAllFonts(); -// ArrayList monoFonts = new ArrayList(); - - // [ ] Use smooth text in editor window editorAntialiasBox = @@ -754,6 +775,15 @@ public class Preferences { // System.out.println("setting num to " + displayNum); displaySelectionBox.setSelectedIndex(displayNum); } + + new Thread(new Runnable() { + public void run() { + initFontList(); +// while (monoFontList == null) { +// System.out.println("Waiting for font list to finish loading..."); +// } + } + }).start(); memoryOverrideBox. setSelected(getBoolean("run.options.memory")); //$NON-NLS-1$ @@ -785,6 +815,39 @@ public class Preferences { } + /** + * I have some ideas on how we could make Swing even more obtuse for the + * most basic usage scenarios. Is there someone on the team I can contact? + * Oracle, are you listening? + */ + class FontNamer extends JLabel implements ListCellRenderer { + public Component getListCellRendererComponent(JList list, + Font value, int index, + boolean isSelected, + boolean cellHasFocus) { + setText(value.getName()); + return this; + } + } + + + void initFontList() { + if (monoFontList == null) { + Font[] list = Toolkit.getMonoFontList().toArray(new Font[0]); + fontSelectionBox.setModel(new DefaultComboBoxModel(list)); + fontSelectionBox.setRenderer(new FontNamer()); + // Preferred size just makes it extend to the container + //fontSelectionBox.setSize(fontSelectionBox.getPreferredSize()); + // Minimum size is better, but cuts things off (on OS X), so we add 20 + //Dimension minSize = fontSelectionBox.getMinimumSize(); + //Dimension minSize = fontSelectionBox.getPreferredSize(); + //fontSelectionBox.setSize(minSize.width + 20, minSize.height); + fontSelectionBox.setEnabled(true); + monoFontList = list; // signal that we're finished + } + } + + void updateDisplayList() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); displayCount = ge.getScreenDevices().length; diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index a22ca11b9..3d9fd488e 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -36,12 +36,14 @@ import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.font.FontRenderContext; import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.List; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; @@ -320,12 +322,56 @@ public class Toolkit { // } + static public List getMonoFontList() { + GraphicsEnvironment ge = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + Font[] fonts = ge.getAllFonts(); + ArrayList outgoing = new ArrayList(); + // Using AffineTransform.getScaleInstance(100, 100) doesn't change sizes + FontRenderContext frc = + new FontRenderContext(new AffineTransform(), + Preferences.getBoolean("editor.antialias"), + true); // use fractional metrics + for (Font font : fonts) { + if (font.canDisplay('i') && font.canDisplay('M') && + font.canDisplay(' ') && font.canDisplay('.')) { + + // The old method just returns 1 or 0, and using deriveFont(size) + // is overkill. It also causes deprecation warnings +// @SuppressWarnings("deprecation") +// FontMetrics fm = awtToolkit.getFontMetrics(font); + //FontMetrics fm = awtToolkit.getFontMetrics(font.deriveFont(24)); +// System.out.println(fm.charWidth('i') + " " + fm.charWidth('M')); +// if (fm.charWidth('i') == fm.charWidth('M') && +// fm.charWidth('M') == fm.charWidth(' ') && +// fm.charWidth(' ') == fm.charWidth('.')) { + double w = font.getStringBounds(" ", frc).getWidth(); + if (w == font.getStringBounds("i", frc).getWidth() && + w == font.getStringBounds("M", frc).getWidth() && + w == font.getStringBounds(".", frc).getWidth()) { + outgoing.add(font); +// System.out.println(" good " + w); + } + } + } + return outgoing; + } + + static Font monoFont; static Font monoBoldFont; static Font sansFont; static Font sansBoldFont; + static public String getMonoFontName() { + if (monoFont == null) { + getMonoFont(12, Font.PLAIN); // load a dummy version + } + return monoFont.getName(); + } + + static public Font getMonoFont(int size, int style) { if (monoFont == null) { try { diff --git a/app/src/processing/app/tools/CreateFont.java b/app/src/processing/app/tools/CreateFont.java index 217af0bfa..17d6cbc73 100644 --- a/app/src/processing/app/tools/CreateFont.java +++ b/app/src/processing/app/tools/CreateFont.java @@ -112,9 +112,11 @@ public class CreateFont extends JFrame implements Tool { // also ignore dialog, dialoginput, monospaced, serif, sansserif // getFontList is deprecated in 1.4, so this has to be used + //long t = System.currentTimeMillis(); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - Font fonts[] = ge.getAllFonts(); + Font[] fonts = ge.getAllFonts(); + //System.out.println("font startup took " + (System.currentTimeMillis() - t) + " ms"); if (false) { ArrayList fontList = new ArrayList(); diff --git a/build/build.xml b/build/build.xml index 025e2772a..c54ad2d68 100755 --- a/build/build.xml +++ b/build/build.xml @@ -592,6 +592,13 @@ + + diff --git a/todo.txt b/todo.txt index 91a9f51be..6c810e637 100644 --- a/todo.txt +++ b/todo.txt @@ -71,6 +71,8 @@ _ dialog box icon is fuzzy on OS X retina machines _ https://github.com/processing/processing/issues/2117 _ solution might be our own dialog boxes (see 'dialogs' section) +_ console font in EditorConsole +_ Font font = Preferences.getFont("console.font"); _ fix console font on Windows and Linux with 7u40 _ the message area text also looks ugly.. can we fix? _ add pref to select PDE font (so that CJKV languages work better) From e697d18058f819cad1642ec7a827309b2db08cfc Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 13:23:14 -0400 Subject: [PATCH 155/556] embedding fonts with build --- build/build.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index c54ad2d68..283a8d836 100755 --- a/build/build.xml +++ b/build/build.xml @@ -594,10 +594,10 @@ - --> @@ -803,6 +803,10 @@
    + + + +
    + + + + Date: Sun, 13 Oct 2013 13:29:23 -0400 Subject: [PATCH 156/556] maybe we should add the fonts for windows to the windows version --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index 283a8d836..9def0cfe6 100755 --- a/build/build.xml +++ b/build/build.xml @@ -1005,7 +1005,7 @@ - + From 33762fd258d96b48ab37e459cd0f3c4d54e1be87 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 13:49:18 -0400 Subject: [PATCH 157/556] let's be more specific --- app/src/processing/app/Preferences.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 0699ffd3b..76583e1ad 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -26,7 +26,6 @@ import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; -import java.util.List; import javax.swing.*; @@ -400,10 +399,10 @@ public class Preferences { // top += d.height + GUI_BETWEEN; - // [ ] Delete previous folder on export + // [ ] Delete previous application folder on export deletePreviousBox = - new JCheckBox("Delete previous folder on export"); + new JCheckBox("Delete previous application folder on export"); pain.add(deletePreviousBox); d = deletePreviousBox.getPreferredSize(); deletePreviousBox.setBounds(left, top, d.width + 10, d.height); From 1e21b1b2cec268d0c7a40b891175daf784185aa2 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 15:17:48 -0400 Subject: [PATCH 158/556] oh fonts.. so fickle --- app/src/processing/app/Preferences.java | 8 +++++++- app/src/processing/app/Toolkit.java | 15 ++------------- build/shared/lib/preferences.txt | 1 + core/todo.txt | 2 ++ todo.txt | 15 +++++++++------ 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 76583e1ad..7f93d1e70 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -241,6 +241,11 @@ public class Preferences { dialog = new JFrame("Preferences"); dialog.setResizable(false); +// GroupLayout layout = new GroupLayout(getContentPane()); +// dialog.getContentPane().setLayout(layout); +// layout.setAutoCreateGaps(true); +// layout.setAutoCreateContainerGaps(true); + Container pain = dialog.getContentPane(); pain.setLayout(null); @@ -824,7 +829,8 @@ public class Preferences { Font value, int index, boolean isSelected, boolean cellHasFocus) { - setText(value.getName()); + //if (Base.isMacOS()) { + setText(value.getFamily() + " / " + value.getName() + " (" + value.getPSName() + ")"); return this; } } diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index 3d9fd488e..8a263c980 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -387,20 +387,15 @@ public class Toolkit { if (size == monoBoldFont.getSize()) { return monoBoldFont; } else { -// System.out.println("deriving new font"); return monoBoldFont.deriveFont((float) size); } } else { if (size == monoFont.getSize()) { return monoFont; } else { -// System.out.println("deriving new font"); return monoFont.deriveFont((float) size); } } -// return style == Font.BOLD ? -// monoBoldFont.deriveFont((float) size) : -// monoFont.deriveFont((float) size); } @@ -411,26 +406,20 @@ public class Toolkit { sansBoldFont = createFont("SourceSansPro-Semibold.ttf", size); } catch (Exception e) { Base.log("Could not load sans font", e); - sansFont = new Font("Monospaced", Font.PLAIN, size); - sansBoldFont = new Font("Monospaced", Font.BOLD, size); + sansFont = new Font("SansSerif", Font.PLAIN, size); + sansBoldFont = new Font("SansSerif", Font.BOLD, size); } } -// System.out.println("deriving new font"); -// return style == Font.BOLD ? -// sansBoldFont.deriveFont((float) size) : -// sansFont.deriveFont((float) size); if (style == Font.BOLD) { if (size == sansBoldFont.getSize()) { return sansBoldFont; } else { -// System.out.println("deriving new font"); return sansBoldFont.deriveFont((float) size); } } else { if (size == sansFont.getSize()) { return sansFont; } else { -// System.out.println("deriving new font"); return sansFont.deriveFont((float) size); } } diff --git a/build/shared/lib/preferences.txt b/build/shared/lib/preferences.txt index e6be447f2..caf43a63a 100644 --- a/build/shared/lib/preferences.txt +++ b/build/shared/lib/preferences.txt @@ -107,6 +107,7 @@ editor.window.height.min.windows = 530 #editor.font.macosx = Monaco,plain,10 # trying for a built-in, consistent monospace for 2.0 editor.font = processing.mono,plain,12 +#editor.font.size=12 # anti-aliased text, turned off by default #editor.antialias=false diff --git a/core/todo.txt b/core/todo.txt index 6f3cda91c..6ba9c3fa0 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -46,6 +46,8 @@ X https://github.com/processing/processing/issues/2075 X throw an error for textureMode(REPEAT) [fry] X https://github.com/processing/processing/issues/2052 +_ insertRow() bug +_ https://github.com/processing/processing/issues/2137 _ Sort out blending differences with P2D/P3D _ https://github.com/processing/processing/issues/1844 _ 'collector' class.. Dict that points to a list diff --git a/todo.txt b/todo.txt index 6c810e637..7e71c28ee 100644 --- a/todo.txt +++ b/todo.txt @@ -718,6 +718,14 @@ _ move styling to separate constants that are more accessible PDE / Preferences +_ control text size in console +o why aren't prefs from theme.txt showing up in preferences.txt? hrm +o or rather, why can't they be overridden? +X because theme.txt data is a different animal / that's part of the point +_ should fonts at least be in prefs.txt? +_ http://code.google.com/p/processing/issues/detail?id=226 +_ https://github.com/processing/processing/issues/265 + _ the .macosx, .linux, etc prefs should be stripped _ only use them on first load, and merge into preferences.txt _ Editor.applyFrame() may not have a valid 'editor' object to work with @@ -728,12 +736,6 @@ _ clear up prefs so that multiple editors don't trash each other's prefs _ when are prefs saved? could instead save whenever changes are made _ and then if the file gets modified, it'll put up an error message _ also, this may be part of why other sketches aren't reloading properly -_ control text size in console -o why aren't prefs from theme.txt showing up in preferences.txt? hrm -o or rather, why can't they be overridden? -X because theme.txt data is a different animal / that's part of the point -_ should fonts at least be in prefs.txt? -_ http://code.google.com/p/processing/issues/detail?id=226 _ simple prefs implementation to set key/value pairs using a JTable _ separate prefs and sketch state info? _ this would mean prefs being rewritten far less @@ -748,6 +750,7 @@ _ preferences window has been hit with the ugly stick _ redo panel to use proper Box layout etc _ also needs to look good across all platforms _ http://code.google.com/p/processing/issues/detail?id=28 +_ https://github.com/processing/processing/issues/67 _ make available the background colors for present mode, stop button color _ isolate color chooser into a simpler/smaller class outside tools _ then can also use from inside processing applications as well From 7dde37c139704c6012118838770b0afcbe3e6509 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 16:02:53 -0400 Subject: [PATCH 159/556] trying out the bold instead of the semi --- app/src/processing/app/Toolkit.java | 3 ++- build/shared/lib/fonts/SourceCodePro-Bold.ttf | Bin 0 -> 120504 bytes 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100755 build/shared/lib/fonts/SourceCodePro-Bold.ttf diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index 8a263c980..40a5af63c 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -376,7 +376,8 @@ public class Toolkit { if (monoFont == null) { try { monoFont = createFont("SourceCodePro-Regular.ttf", size); - monoBoldFont = createFont("SourceCodePro-Semibold.ttf", size); + //monoBoldFont = createFont("SourceCodePro-Semibold.ttf", size); + monoBoldFont = createFont("SourceCodePro-Bold.ttf", size); } catch (Exception e) { Base.log("Could not load mono font", e); monoFont = new Font("Monospaced", Font.PLAIN, size); diff --git a/build/shared/lib/fonts/SourceCodePro-Bold.ttf b/build/shared/lib/fonts/SourceCodePro-Bold.ttf new file mode 100755 index 0000000000000000000000000000000000000000..a56f1fa5ddf408b863fec053dbdf0a96e52a5fc9 GIT binary patch literal 120504 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

    Z`gjry=dL{u?Rk99b9+wg`Siwu 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 literal 0 HcmV?d00001 From 009d51d5408f8e5292d808613964af8d751ae762 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 17:46:14 -0400 Subject: [PATCH 160/556] better option for setting code font --- app/src/processing/app/Preferences.java | 41 +++++++++++++++--- app/src/processing/app/Toolkit.java | 24 +++++++++- build/shared/lib/fonts/SourceCodePro-Bold.ttf | Bin .../lib/fonts/SourceCodePro-Semibold.ttf | Bin 120252 -> 0 bytes build/shared/lib/preferences.txt | 6 ++- todo.txt | 3 ++ 6 files changed, 63 insertions(+), 11 deletions(-) mode change 100755 => 100644 build/shared/lib/fonts/SourceCodePro-Bold.ttf delete mode 100644 build/shared/lib/fonts/SourceCodePro-Semibold.ttf diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 7f93d1e70..a2318afb4 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -123,8 +123,8 @@ public class Preferences { JComboBox displaySelectionBox; int displayCount; - //List monoFontList; - Font[] monoFontList; + //Font[] monoFontList; + String[] monoFontFamilies; JComboBox fontSelectionBox; /** Base object so that updates can be applied to the list of editors. */ @@ -320,7 +320,7 @@ public class Preferences { "though the list may be imperfect."; fontLabel.setToolTipText(fontTip); fontBox.add(fontLabel); - // needs to happen here for getPreferredSize() + // get a wide name in there before getPreferredSize() is called fontSelectionBox = new JComboBox(new Object[] { Toolkit.getMonoFontName() }); fontSelectionBox.setToolTipText(fontTip); // fontSelectionBox.addItem(Toolkit.getMonoFont(size, style)); @@ -646,7 +646,8 @@ public class Preferences { * then send a message to the editor saying that it's time to do the same. */ protected void applyFrame() { - setBoolean("editor.antialias", editorAntialiasBox.isSelected()); //$NON-NLS-1$ + setBoolean("editor.antialias", //$NON-NLS-1$ + editorAntialiasBox.isSelected()); setBoolean("export.delete_target_folder", //$NON-NLS-1$ deletePreviousBox.isSelected()); @@ -721,6 +722,9 @@ public class Preferences { } */ + //set("editor.font", fontSelectionBox.getSelectedItem()); + String fontFamily = (String) fontSelectionBox.getSelectedItem(); + String newSizeText = fontSizeField.getText(); try { int newSize = Integer.parseInt(newSizeText.trim()); @@ -837,10 +841,12 @@ public class Preferences { void initFontList() { + /* if (monoFontList == null) { - Font[] list = Toolkit.getMonoFontList().toArray(new Font[0]); - fontSelectionBox.setModel(new DefaultComboBoxModel(list)); + monoFontList = Toolkit.getMonoFontList().toArray(new Font[0]); + fontSelectionBox.setModel(new DefaultComboBoxModel(monoFontList)); fontSelectionBox.setRenderer(new FontNamer()); + // Preferred size just makes it extend to the container //fontSelectionBox.setSize(fontSelectionBox.getPreferredSize()); // Minimum size is better, but cuts things off (on OS X), so we add 20 @@ -848,7 +854,28 @@ public class Preferences { //Dimension minSize = fontSelectionBox.getPreferredSize(); //fontSelectionBox.setSize(minSize.width + 20, minSize.height); fontSelectionBox.setEnabled(true); - monoFontList = list; // signal that we're finished + } + */ + if (monoFontFamilies == null) { + monoFontFamilies = Toolkit.getMonoFontFamilies(); + fontSelectionBox.setModel(new DefaultComboBoxModel(monoFontFamilies)); + String family = get("editor.font.family"); +// System.out.println("family is " + family); +// System.out.println("font sel items = " + fontSelectionBox.getItemCount()); +// for (int i = 0; i < fontSelectionBox.getItemCount(); i++) { +// String item = (String) fontSelectionBox.getItemAt(i); +// if (fontSelectionBox.getItemAt(i) == family) { +// System.out.println("found at index " + i); +// } else if (item.equals(family)) { +// System.out.println("equals at index " + i); +// } else { +// System.out.println("nothing doing: " + item); +// } +// } + // Set a reasonable default, in case selecting the family fails + fontSelectionBox.setSelectedItem("Monospaced"); + fontSelectionBox.setSelectedItem(family); + fontSelectionBox.setEnabled(true); } } diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java index 40a5af63c..e549371af 100644 --- a/app/src/processing/app/Toolkit.java +++ b/app/src/processing/app/Toolkit.java @@ -43,6 +43,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import javax.swing.ImageIcon; @@ -322,7 +323,8 @@ public class Toolkit { // } - static public List getMonoFontList() { + // Gets the plain (not bold, not italic) version of each + static private List getMonoFontList() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); Font[] fonts = ge.getAllFonts(); @@ -333,7 +335,8 @@ public class Toolkit { Preferences.getBoolean("editor.antialias"), true); // use fractional metrics for (Font font : fonts) { - if (font.canDisplay('i') && font.canDisplay('M') && + if (font.getStyle() == Font.PLAIN && + font.canDisplay('i') && font.canDisplay('M') && font.canDisplay(' ') && font.canDisplay('.')) { // The old method just returns 1 or 0, and using deriveFont(size) @@ -349,6 +352,14 @@ public class Toolkit { if (w == font.getStringBounds("i", frc).getWidth() && w == font.getStringBounds("M", frc).getWidth() && w == font.getStringBounds(".", frc).getWidth()) { + +// //PApplet.printArray(font.getAvailableAttributes()); +// Map attr = font.getAttributes(); +// System.out.println(font.getFamily() + " > " + font.getName()); +// System.out.println(font.getAttributes()); +// System.out.println(" " + attr.get(TextAttribute.WEIGHT)); +// System.out.println(" " + attr.get(TextAttribute.POSTURE)); + outgoing.add(font); // System.out.println(" good " + w); } @@ -356,6 +367,15 @@ public class Toolkit { } return outgoing; } + + + static public String[] getMonoFontFamilies() { + HashSet families = new HashSet(); + for (Font font : getMonoFontList()) { + families.add(font.getFamily()); + } + return families.toArray(new String[0]); + } static Font monoFont; diff --git a/build/shared/lib/fonts/SourceCodePro-Bold.ttf b/build/shared/lib/fonts/SourceCodePro-Bold.ttf old mode 100755 new mode 100644 diff --git a/build/shared/lib/fonts/SourceCodePro-Semibold.ttf b/build/shared/lib/fonts/SourceCodePro-Semibold.ttf deleted file mode 100644 index b425f9ceea70c1e76d38d66f712caeccc1a00626..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120252 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 z 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 Date: Sun, 13 Oct 2013 18:30:32 -0400 Subject: [PATCH 161/556] changing font size now working --- app/src/processing/app/Preferences.java | 52 ++++++++++++++++++------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index a2318afb4..518013d9f 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -61,6 +61,7 @@ import processing.core.*; */ public class Preferences { + static final Integer[] FONT_SIZES = { 10, 12, 14, 18, 24, 36, 48 }; // what to call the feller static final String PREFS_FILE = "preferences.txt"; //$NON-NLS-1$ @@ -113,7 +114,8 @@ public class Preferences { JCheckBox memoryOverrideBox; JTextField memoryField; JCheckBox checkUpdatesBox; - JTextField fontSizeField; + //JTextField fontSizeField; + JComboBox fontSizeField; JCheckBox inputMethodBox; JCheckBox autoAssociateBox; @@ -340,7 +342,9 @@ public class Preferences { Container box = Box.createHorizontalBox(); label = new JLabel("Editor font size: "); box.add(label); - fontSizeField = new JTextField(4); + //fontSizeField = new JTextField(4); + fontSizeField = new JComboBox(FONT_SIZES); + fontSizeField.setEditable(true); box.add(fontSizeField); label = new JLabel(" (requires restart of Processing)"); box.add(label); @@ -348,7 +352,8 @@ public class Preferences { d = box.getPreferredSize(); box.setBounds(left, top, d.width, d.height); Font editorFont = Preferences.getFont("editor.font"); - fontSizeField.setText(String.valueOf(editorFont.getSize())); + //fontSizeField.setText(String.valueOf(editorFont.getSize())); + fontSizeField.setSelectedItem(editorFont.getSize()); top += d.height + GUI_BETWEEN; @@ -722,18 +727,39 @@ public class Preferences { } */ - //set("editor.font", fontSelectionBox.getSelectedItem()); - String fontFamily = (String) fontSelectionBox.getSelectedItem(); - + // Don't change anything if the user closes the window before fonts load + if (fontSelectionBox.isEnabled()) { + String fontFamily = (String) fontSelectionBox.getSelectedItem(); + set("editor.font.family", fontFamily); + } + + /* String newSizeText = fontSizeField.getText(); try { int newSize = Integer.parseInt(newSizeText.trim()); - String pieces[] = PApplet.split(get("editor.font"), ','); //$NON-NLS-1$ - pieces[2] = String.valueOf(newSize); - set("editor.font", PApplet.join(pieces, ',')); //$NON-NLS-1$ + //String pieces[] = PApplet.split(get("editor.font"), ','); //$NON-NLS-1$ + //pieces[2] = String.valueOf(newSize); + //set("editor.font", PApplet.join(pieces, ',')); //$NON-NLS-1$ + set("editor.font.size", String.valueOf(newSize)); } catch (Exception e) { - Base.log("ignoring invalid font size " + newSizeText); //$NON-NLS-1$ + Base.log("Ignoring invalid font size " + newSizeText); //$NON-NLS-1$ + } + */ + try { + Object selection = fontSizeField.getSelectedItem(); + if (selection instanceof String) { + // Replace with Integer version + selection = Integer.parseInt((String) selection); + } + //Integer newSize = (Integer) selection; + //Integer newSize = Integer.valueOf(selection); + //System.out.println("setting size to " + selection + " " + selection.getClass()); + set("editor.font.size", String.valueOf(selection)); + + } catch (NumberFormatException e) { + Base.log("Ignoring invalid font size " + fontSizeField); //$NON-NLS-1$ + fontSizeField.setSelectedItem(getInteger("editor.font.size")); } setBoolean("editor.input_method_support", inputMethodBox.isSelected()); //$NON-NLS-1$ @@ -784,14 +810,14 @@ public class Preferences { displaySelectionBox.setSelectedIndex(displayNum); } + // This takes a while to load, so run it from a separate thread new Thread(new Runnable() { public void run() { initFontList(); -// while (monoFontList == null) { -// System.out.println("Waiting for font list to finish loading..."); -// } } }).start(); + + fontSizeField.setSelectedItem(getInteger("editor.font.size")); memoryOverrideBox. setSelected(getBoolean("run.options.memory")); //$NON-NLS-1$ From 409bd30cebd46b6a09ee97ccf4dec4ca08e45ff6 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 21:50:39 -0400 Subject: [PATCH 162/556] trying to get to the bottom of the font trouble --- app/src/processing/app/Mode.java | 5 +- app/src/processing/app/Preferences.java | 5 +- .../app/syntax/PdeTextAreaDefaults.java | 7 +- .../processing/app/syntax/SyntaxStyle.java | 118 ++++++++---------- .../app/syntax/TextAreaPainter.java | 3 + 5 files changed, 68 insertions(+), 70 deletions(-) diff --git a/app/src/processing/app/Mode.java b/app/src/processing/app/Mode.java index f45a6523b..0efa9c72e 100644 --- a/app/src/processing/app/Mode.java +++ b/app/src/processing/app/Mode.java @@ -959,9 +959,10 @@ public abstract class Mode { s = st.nextToken(); boolean bold = (s.indexOf("bold") != -1); - boolean italic = (s.indexOf("italic") != -1); +// boolean italic = (s.indexOf("italic") != -1); - return new SyntaxStyle(color, italic, bold); +// return new SyntaxStyle(color, italic, bold); + return new SyntaxStyle(color, bold); } diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 518013d9f..9f460fa94 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -1162,9 +1162,10 @@ public class Preferences { s = st.nextToken(); boolean bold = (s.indexOf("bold") != -1); //$NON-NLS-1$ - boolean italic = (s.indexOf("italic") != -1); //$NON-NLS-1$ +// boolean italic = (s.indexOf("italic") != -1); //$NON-NLS-1$ //System.out.println(what + " = " + str + " " + bold + " " + italic); - return new SyntaxStyle(color, italic, bold); +// return new SyntaxStyle(color, italic, bold); + return new SyntaxStyle(color, bold); } } diff --git a/app/src/processing/app/syntax/PdeTextAreaDefaults.java b/app/src/processing/app/syntax/PdeTextAreaDefaults.java index 16ba8a876..0ffe9072e 100644 --- a/app/src/processing/app/syntax/PdeTextAreaDefaults.java +++ b/app/src/processing/app/syntax/PdeTextAreaDefaults.java @@ -24,6 +24,8 @@ package processing.app.syntax; +import java.awt.Font; + import processing.app.*; @@ -194,7 +196,10 @@ public class PdeTextAreaDefaults extends TextAreaDefaults { // http://code.google.com/p/processing/issues/detail?id=1275 rows = 5; - font = Preferences.getFont("editor.font"); + //font = Preferences.getFont("editor.font"); + font = new Font(Preferences.get("editor.font.family"), + Font.PLAIN, Preferences.getInteger("editor.font.size")); + System.out.println("font is " + font.getFamily() + " / " + font.getName() + " / " + font.getFontName() + " / " + font.getPSName()); antialias = Preferences.getBoolean("editor.antialias"); styles = new SyntaxStyle[Token.ID_COUNT]; diff --git a/app/src/processing/app/syntax/SyntaxStyle.java b/app/src/processing/app/syntax/SyntaxStyle.java index 674bbdc78..3d5d19425 100644 --- a/app/src/processing/app/syntax/SyntaxStyle.java +++ b/app/src/processing/app/syntax/SyntaxStyle.java @@ -12,8 +12,6 @@ package processing.app.syntax; import java.awt.*; import javax.swing.JComponent; -import processing.app.Preferences; - /** * A simple text style class. It can specify the color, italic flag, @@ -21,81 +19,76 @@ import processing.app.Preferences; * @author Slava Pestov * @version $Id$ */ -public class SyntaxStyle -{ +public class SyntaxStyle { + private Color color; +// private boolean italic; + private boolean bold; + private Font lastFont; + private Font lastStyledFont; + private FontMetrics fontMetrics; + /** * Creates a new SyntaxStyle. * @param color The text color * @param italic True if the text should be italics * @param bold True if the text should be bold */ - public SyntaxStyle(Color color, boolean italic, boolean bold) - { +// public SyntaxStyle(Color color, boolean italic, boolean bold) { + public SyntaxStyle(Color color, boolean bold) { this.color = color; - this.italic = italic; +// this.italic = italic; this.bold = bold; } - /** - * Returns the color specified in this style. - */ - public Color getColor() - { + + /** Returns the color specified in this style. */ + public Color getColor() { return color; } - /** - * Returns true if no font styles are enabled. - */ - public boolean isPlain() - { - return !(bold || italic); - } + +// /** +// * Returns true if no font styles are enabled. +// */ +// public boolean isPlain() { +// return !(bold || italic); +// } - /** - * Returns true if italics is enabled for this style. - */ - public boolean isItalic() - { - return italic; - } +// /** +// * Returns true if italics is enabled for this style. +// */ +// public boolean isItalic() { +// return italic; +// } - /** - * Returns true if boldface is enabled for this style. - */ - public boolean isBold() - { + + /** Returns true if boldface is enabled for this style. */ + public boolean isBold() { return bold; } + /** - * Returns the specified font, but with the style's bold and - * italic flags applied. + * Returns the specified font, but with the style's bold flags applied. */ - public Font getStyledFont(Font font) - { - if(font == null) - throw new NullPointerException("font param must not" - + " be null"); - if(font.equals(lastFont)) + public Font getStyledFont(Font font) { + if (font.equals(lastFont)) { return lastStyledFont; + } lastFont = font; -// lastStyledFont = new Font(font.getFamily(), -// (bold ? Font.BOLD : 0) -// | (italic ? Font.ITALIC : 0), -// font.getSize()); lastStyledFont = findFont(font.getFamily(), bold ? Font.BOLD : Font.PLAIN, font.getSize()); return lastStyledFont; } + /** * Returns the font metrics for the styled font. */ public FontMetrics getFontMetrics(Font font, JComponent comp) { - if (font == null) { - throw new NullPointerException("font param must not be null"); - } +// if (font == null) { +// throw new NullPointerException("font param must not be null"); +// } if (font.equals(lastFont) && fontMetrics != null) { return fontMetrics; } @@ -112,6 +105,7 @@ public class SyntaxStyle return fontMetrics; } + /* on Windows (and I presume Linux) we get something like this: @@ -130,12 +124,14 @@ public class SyntaxStyle //private String monoFontFamily; private Font findFont(String familyName, int style, int size) { - // getFamily() is too unreliable across platforms - if (Preferences.get("editor.font").startsWith("processing.mono")) { - return processing.app.Toolkit.getMonoFont(size, style); - } else { - return new Font(familyName, style, size); - } +// // getFamily() is too unreliable across platforms +// if (Preferences.get("editor.font").startsWith("processing.mono")) { +// return processing.app.Toolkit.getMonoFont(size, style); +// } else { + System.out.println("creating new font for " + familyName); + return new Font(familyName, style, size); +// } + /* if (monoFontFamily == null) { // This should be more reliable across platforms than the @@ -166,34 +162,26 @@ public class SyntaxStyle */ } + /** * Sets the foreground color and font of the specified graphics * context to that specified in this style. * @param gfx The graphics context * @param font The font to add the styles to */ - public void setGraphicsFlags(Graphics gfx, Font font) - { + public void setGraphicsFlags(Graphics gfx, Font font) { Font _font = getStyledFont(font); gfx.setFont(_font); gfx.setColor(color); } + /** * Returns a string representation of this object. */ - public String toString() - { + public String toString() { return getClass().getName() + "[color=" + color + - (italic ? ",italic" : "") + +// (italic ? ",italic" : "") + (bold ? ",bold" : "") + "]"; } - - // private members - private Color color; - private boolean italic; - private boolean bold; - private Font lastFont; - private Font lastStyledFont; - private FontMetrics fontMetrics; } diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index 4f23686ce..2cef5962a 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -55,6 +55,7 @@ implements TabExpander, Printable { // unfortunately probably can't just do setDefaults() since things aren't quite set up setFont(defaults.font); +// System.out.println("defaults font is " + defaults.font); setForeground(defaults.fgcolor); setBackground(defaults.bgcolor); @@ -75,6 +76,7 @@ implements TabExpander, Printable { } + /* public void setDefaults(TextAreaDefaults defaults) { setFont(defaults.font); setForeground(defaults.fgcolor); @@ -96,6 +98,7 @@ implements TabExpander, Printable { cols = defaults.cols; rows = defaults.rows; } + */ /** From 42555d453077802b070951cbc8fa6c594f270031 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 22:53:16 -0400 Subject: [PATCH 163/556] clearing up this font mess to debug the plain/bold/family issue --- .../processing/app/syntax/HtmlSelection.java | 8 +- app/src/processing/app/syntax/KeywordMap.java | 32 ++++- .../app/syntax/PdeTextAreaDefaults.java | 8 +- .../processing/app/syntax/SyntaxStyle.java | 5 +- .../app/syntax/SyntaxUtilities.java | 131 ++++-------------- .../app/syntax/TextAreaDefaults.java | 3 +- .../app/syntax/TextAreaPainter.java | 51 ++++++- 7 files changed, 126 insertions(+), 112 deletions(-) diff --git a/app/src/processing/app/syntax/HtmlSelection.java b/app/src/processing/app/syntax/HtmlSelection.java index d8e906604..d7a016aa5 100644 --- a/app/src/processing/app/syntax/HtmlSelection.java +++ b/app/src/processing/app/syntax/HtmlSelection.java @@ -9,12 +9,14 @@ import java.io.StringReader; import java.util.ArrayList; import java.util.List; + public class HtmlSelection implements Transferable { - private static List flavors = new ArrayList(); + private static List flavors; static { try { + flavors = new ArrayList(); flavors.add(DataFlavor.stringFlavor); flavors.add(new DataFlavor("text/html;class=java.lang.String")); flavors.add(new DataFlavor("text/html;class=java.io.Reader")); @@ -26,18 +28,22 @@ public class HtmlSelection implements Transferable { private String html; + public HtmlSelection(String html) { this.html = html; } + public DataFlavor[] getTransferDataFlavors() { return flavors.toArray(new DataFlavor[flavors.size()]); } + public boolean isDataFlavorSupported(DataFlavor flavor) { return flavors.contains(flavor); } + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { if (flavor.equals(DataFlavor.stringFlavor)) { diff --git a/app/src/processing/app/syntax/KeywordMap.java b/app/src/processing/app/syntax/KeywordMap.java index b8b66871d..cfa4caa68 100644 --- a/app/src/processing/app/syntax/KeywordMap.java +++ b/app/src/processing/app/syntax/KeywordMap.java @@ -76,7 +76,7 @@ public class KeywordMap { // continue; // } if (length == k.keyword.length) { - if (SyntaxUtilities.regionMatches(ignoreCase, text, offset, k.keyword)) { + if (regionMatches(ignoreCase, text, offset, k.keyword)) { return k.id; } } @@ -84,6 +84,36 @@ public class KeywordMap { } return Token.NULL; } + + + /** + * Checks if a subregion of a Segment is equal to a + * character array. + * @param ignoreCase True if case should be ignored, false otherwise + * @param text The segment + * @param offset The offset into the segment + * @param match The character array to match + */ + static public boolean regionMatches(boolean ignoreCase, Segment text, + int offset, char[] match) { + int length = offset + match.length; + char[] textArray = text.array; + if(length > text.offset + text.count) + return false; + for(int i = offset, j = 0; i < length; i++, j++) + { + char c1 = textArray[i]; + char c2 = match[j]; + if(ignoreCase) + { + c1 = Character.toUpperCase(c1); + c2 = Character.toUpperCase(c2); + } + if(c1 != c2) + return false; + } + return true; + } /** diff --git a/app/src/processing/app/syntax/PdeTextAreaDefaults.java b/app/src/processing/app/syntax/PdeTextAreaDefaults.java index 0ffe9072e..5e010f153 100644 --- a/app/src/processing/app/syntax/PdeTextAreaDefaults.java +++ b/app/src/processing/app/syntax/PdeTextAreaDefaults.java @@ -197,9 +197,11 @@ public class PdeTextAreaDefaults extends TextAreaDefaults { rows = 5; //font = Preferences.getFont("editor.font"); - font = new Font(Preferences.get("editor.font.family"), - Font.PLAIN, Preferences.getInteger("editor.font.size")); - System.out.println("font is " + font.getFamily() + " / " + font.getName() + " / " + font.getFontName() + " / " + font.getPSName()); + String fontFamily = Preferences.get("editor.font.family"); + int fontSize = Preferences.getInteger("editor.font.size"); + plainFont = new Font(fontFamily, Font.PLAIN, fontSize); + boldFont = new Font(fontFamily, Font.BOLD, fontSize); + //System.out.println("font is " + plainFont.getFamily() + " / " + plainFont.getName() + " / " + plainFont.getFontName() + " / " + plainFont.getPSName()); antialias = Preferences.getBoolean("editor.antialias"); styles = new SyntaxStyle[Token.ID_COUNT]; diff --git a/app/src/processing/app/syntax/SyntaxStyle.java b/app/src/processing/app/syntax/SyntaxStyle.java index 3d5d19425..277640fba 100644 --- a/app/src/processing/app/syntax/SyntaxStyle.java +++ b/app/src/processing/app/syntax/SyntaxStyle.java @@ -14,8 +14,8 @@ import javax.swing.JComponent; /** - * A simple text style class. It can specify the color, italic flag, - * and bold flag of a run of text. + * A simple text style class. + * It can specify the color and bold flag of a run of text. * @author Slava Pestov * @version $Id$ */ @@ -27,6 +27,7 @@ public class SyntaxStyle { private Font lastStyledFont; private FontMetrics fontMetrics; + /** * Creates a new SyntaxStyle. * @param color The text color diff --git a/app/src/processing/app/syntax/SyntaxUtilities.java b/app/src/processing/app/syntax/SyntaxUtilities.java index 1e40ac831..5d6e983ec 100644 --- a/app/src/processing/app/syntax/SyntaxUtilities.java +++ b/app/src/processing/app/syntax/SyntaxUtilities.java @@ -22,64 +22,34 @@ import java.awt.*; */ public class SyntaxUtilities { - /** - * Checks if a subregion of a Segment is equal to a - * string. - * @param ignoreCase True if case should be ignored, false otherwise - * @param text The segment - * @param offset The offset into the segment - * @param match The string to match - */ - public static boolean regionMatches(boolean ignoreCase, Segment text, - int offset, String match) { - int length = offset + match.length(); - char[] textArray = text.array; - if(length > text.offset + text.count) - return false; - for(int i = offset, j = 0; i < length; i++, j++) - { - char c1 = textArray[i]; - char c2 = match.charAt(j); - if(ignoreCase) - { - c1 = Character.toUpperCase(c1); - c2 = Character.toUpperCase(c2); - } - if(c1 != c2) - return false; - } - return true; - } - - - /** - * Checks if a subregion of a Segment is equal to a - * character array. - * @param ignoreCase True if case should be ignored, false otherwise - * @param text The segment - * @param offset The offset into the segment - * @param match The character array to match - */ - public static boolean regionMatches(boolean ignoreCase, Segment text, - int offset, char[] match) { - int length = offset + match.length; - char[] textArray = text.array; - if(length > text.offset + text.count) - return false; - for(int i = offset, j = 0; i < length; i++, j++) - { - char c1 = textArray[i]; - char c2 = match[j]; - if(ignoreCase) - { - c1 = Character.toUpperCase(c1); - c2 = Character.toUpperCase(c2); - } - if(c1 != c2) - return false; - } - return true; - } +// /** +// * Checks if a subregion of a Segment is equal to a +// * string. +// * @param ignoreCase True if case should be ignored, false otherwise +// * @param text The segment +// * @param offset The offset into the segment +// * @param match The string to match +// */ +// public static boolean regionMatches(boolean ignoreCase, Segment text, +// int offset, String match) { +// int length = offset + match.length(); +// char[] textArray = text.array; +// if(length > text.offset + text.count) +// return false; +// for(int i = offset, j = 0; i < length; i++, j++) +// { +// char c1 = textArray[i]; +// char c2 = match.charAt(j); +// if(ignoreCase) +// { +// c1 = Character.toUpperCase(c1); +// c2 = Character.toUpperCase(c2); +// } +// if(c1 != c2) +// return false; +// } +// return true; +// } // /** @@ -107,50 +77,7 @@ public class SyntaxUtilities { // } - /** - * Paints the specified line onto the graphics context. Note that this - * method munges the offset and count values of the segment. - * @param line The line segment - * @param tokens The token list for the line - * @param styles The syntax style list - * @param expander The tab expander used to determine tab stops. May - * be null - * @param gfx The graphics context - * @param x The x co-ordinate - * @param y The y co-ordinate - * @return The x co-ordinate, plus the width of the painted string - */ - public static int paintSyntaxLine(Segment line, Token tokens, - SyntaxStyle[] styles, - TabExpander expander, Graphics gfx, - int x, int y) { - Font defaultFont = gfx.getFont(); - Color defaultColor = gfx.getColor(); - - for (;;) { - byte id = tokens.id; - if(id == Token.END) - break; - - int length = tokens.length; - if (id == Token.NULL) { - if(!defaultColor.equals(gfx.getColor())) - gfx.setColor(defaultColor); - if(!defaultFont.equals(gfx.getFont())) - gfx.setFont(defaultFont); - } else { - styles[id].setGraphicsFlags(gfx,defaultFont); - } - line.count = length; - x = Utilities.drawTabbedText(line,x,y,gfx,expander,0); - line.offset += length; - - tokens = tokens.next; - } - - return x; - } // private members - private SyntaxUtilities() {} +// private SyntaxUtilities() {} } diff --git a/app/src/processing/app/syntax/TextAreaDefaults.java b/app/src/processing/app/syntax/TextAreaDefaults.java index 9401c4e32..ac856102b 100644 --- a/app/src/processing/app/syntax/TextAreaDefaults.java +++ b/app/src/processing/app/syntax/TextAreaDefaults.java @@ -41,7 +41,8 @@ public class TextAreaDefaults { public boolean paintInvalid; // moved from TextAreaPainter [fry] - public Font font; + public Font plainFont; + public Font boldFont; public Color fgcolor; public Color bgcolor; public boolean antialias; diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index 2cef5962a..30b0f6200 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -15,6 +15,7 @@ import processing.app.syntax.im.CompositionTextPainter; import javax.swing.ToolTipManager; import javax.swing.text.*; import javax.swing.JComponent; + import java.awt.event.MouseEvent; import java.awt.*; import java.awt.print.*; @@ -54,7 +55,7 @@ implements TabExpander, Printable { setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); // unfortunately probably can't just do setDefaults() since things aren't quite set up - setFont(defaults.font); + setFont(defaults.plainFont); // System.out.println("defaults font is " + defaults.font); setForeground(defaults.fgcolor); setBackground(defaults.bgcolor); @@ -611,6 +612,7 @@ implements TabExpander, Printable { gfx.drawString(".",x,y); } } + protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker, int line, Font defaultFont, @@ -624,7 +626,7 @@ implements TabExpander, Printable { gfx.setFont(defaultFont); gfx.setColor(defaultColor); y += fm.getHeight(); - x = SyntaxUtilities.paintSyntaxLine(currentLine, + x = paintSyntaxLine(currentLine, currentLineTokens, styles, this, gfx, x, y); /* @@ -638,6 +640,51 @@ implements TabExpander, Printable { gfx.drawString(".",x,y); } } + + + /** + * Paints the specified line onto the graphics context. Note that this + * method munges the offset and count values of the segment. + * @param line The line segment + * @param tokens The token list for the line + * @param styles The syntax style list + * @param expander The tab expander used to determine tab stops. May + * be null + * @param gfx The graphics context + * @param x The x co-ordinate + * @param y The y co-ordinate + * @return The x co-ordinate, plus the width of the painted string + */ + static public int paintSyntaxLine(Segment line, Token tokens, + SyntaxStyle[] styles, + TabExpander expander, Graphics gfx, + int x, int y) { + Font defaultFont = gfx.getFont(); + Color defaultColor = gfx.getColor(); + + for (;;) { + byte id = tokens.id; + if(id == Token.END) + break; + + int length = tokens.length; + if (id == Token.NULL) { + if(!defaultColor.equals(gfx.getColor())) + gfx.setColor(defaultColor); + if(!defaultFont.equals(gfx.getFont())) + gfx.setFont(defaultFont); + } else { + styles[id].setGraphicsFlags(gfx,defaultFont); + } + line.count = length; + x = Utilities.drawTabbedText(line,x,y,gfx,expander,0); + line.offset += length; + + tokens = tokens.next; + } + + return x; + } protected void paintHighlight(Graphics gfx, int line, int y) { From f86a05dfb051cdaf76908add3336d465e7004a5f Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 23:35:40 -0400 Subject: [PATCH 164/556] wow, there's more. and maybe that was too aggressive. --- app/src/processing/app/Editor.java | 4 +- app/src/processing/app/Preferences.java | 3 +- .../processing/app/syntax/JEditTextArea.java | 7 + .../app/syntax/PdeTextAreaDefaults.java | 2 +- .../app/syntax/SyntaxUtilities.java | 83 --- .../app/syntax/TextAreaDefaults.java | 1 - .../app/syntax/TextAreaPainter.java | 496 +++++++++--------- 7 files changed, 268 insertions(+), 328 deletions(-) delete mode 100644 app/src/processing/app/syntax/SyntaxUtilities.java diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index a117489c9..ffa6cfdc8 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -2326,9 +2326,9 @@ public abstract class Editor extends JFrame implements RunnerListener { } if (pageFormat != null) { //System.out.println("setting page format " + pageFormat); - printerJob.setPrintable(textarea.getPainter(), pageFormat); + printerJob.setPrintable(textarea.getPrintable(), pageFormat); } else { - printerJob.setPrintable(textarea.getPainter()); + printerJob.setPrintable(textarea.getPrintable()); } // set the name of the job to the code name printerJob.setJobName(sketch.getCurrentCode().getPrettyName()); diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 9f460fa94..594072e1c 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -29,7 +29,6 @@ import java.util.*; import javax.swing.*; -import processing.app.syntax.*; import processing.core.*; @@ -1148,6 +1147,7 @@ public class Preferences { } + /* static public SyntaxStyle getStyle(String what) { String str = get("editor." + what + ".style"); //, dflt); //$NON-NLS-1$ //$NON-NLS-2$ @@ -1168,4 +1168,5 @@ public class Preferences { // return new SyntaxStyle(color, italic, bold); return new SyntaxStyle(color, bold); } + */ } diff --git a/app/src/processing/app/syntax/JEditTextArea.java b/app/src/processing/app/syntax/JEditTextArea.java index b35e7b329..49eeb1299 100644 --- a/app/src/processing/app/syntax/JEditTextArea.java +++ b/app/src/processing/app/syntax/JEditTextArea.java @@ -24,7 +24,9 @@ import javax.swing.event.*; import javax.swing.text.*; import javax.swing.undo.*; import javax.swing.*; + import java.awt.im.InputMethodRequests; +import java.awt.print.Printable; import processing.app.syntax.im.InputMethodSupport; import processing.core.PApplet; @@ -210,6 +212,11 @@ public class JEditTextArea extends JComponent public final TextAreaPainter getPainter() { return painter; } + + + public final Printable getPrintable() { + return painter.getPrintable(); + } /** diff --git a/app/src/processing/app/syntax/PdeTextAreaDefaults.java b/app/src/processing/app/syntax/PdeTextAreaDefaults.java index 5e010f153..b427f9ef4 100644 --- a/app/src/processing/app/syntax/PdeTextAreaDefaults.java +++ b/app/src/processing/app/syntax/PdeTextAreaDefaults.java @@ -202,7 +202,7 @@ public class PdeTextAreaDefaults extends TextAreaDefaults { plainFont = new Font(fontFamily, Font.PLAIN, fontSize); boldFont = new Font(fontFamily, Font.BOLD, fontSize); //System.out.println("font is " + plainFont.getFamily() + " / " + plainFont.getName() + " / " + plainFont.getFontName() + " / " + plainFont.getPSName()); - antialias = Preferences.getBoolean("editor.antialias"); +// antialias = Preferences.getBoolean("editor.antialias"); styles = new SyntaxStyle[Token.ID_COUNT]; diff --git a/app/src/processing/app/syntax/SyntaxUtilities.java b/app/src/processing/app/syntax/SyntaxUtilities.java deleted file mode 100644 index 5d6e983ec..000000000 --- a/app/src/processing/app/syntax/SyntaxUtilities.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SyntaxUtilities.java - Utility functions used by syntax colorizing - * Copyright (C) 1999 Slava Pestov - * - * You may use and modify this package for any purpose. Redistribution is - * permitted, in both source and binary form, provided that this notice - * remains intact in all source distributions of this package. - */ - -package processing.app.syntax; - -import javax.swing.text.*; -import java.awt.*; - - -/** - * Class with several utility functions used by jEdit's syntax colorizing - * subsystem. - * - * @author Slava Pestov - * @version $Id$ - */ -public class SyntaxUtilities { - -// /** -// * Checks if a subregion of a Segment is equal to a -// * string. -// * @param ignoreCase True if case should be ignored, false otherwise -// * @param text The segment -// * @param offset The offset into the segment -// * @param match The string to match -// */ -// public static boolean regionMatches(boolean ignoreCase, Segment text, -// int offset, String match) { -// int length = offset + match.length(); -// char[] textArray = text.array; -// if(length > text.offset + text.count) -// return false; -// for(int i = offset, j = 0; i < length; i++, j++) -// { -// char c1 = textArray[i]; -// char c2 = match.charAt(j); -// if(ignoreCase) -// { -// c1 = Character.toUpperCase(c1); -// c2 = Character.toUpperCase(c2); -// } -// if(c1 != c2) -// return false; -// } -// return true; -// } - - -// /** -// * Returns the default style table. This can be passed to the -// * setStyles() method of SyntaxDocument -// * to use the default syntax styles. -// */ -// public static SyntaxStyle[] getDefaultSyntaxStyles() { -// SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT]; -// -// styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,false); -// styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false); -// styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true); -// styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false); -// styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false); -// styles[Token.FUNCTION1] = new SyntaxStyle(Color.magenta,false,false); -// styles[Token.FUNCTION2] = new SyntaxStyle(new Color(0x009600),false,false); -// styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false); -// styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true); -// styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true); -// styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true); -// styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true); -// -// return styles; -// } - - - - // private members -// private SyntaxUtilities() {} -} diff --git a/app/src/processing/app/syntax/TextAreaDefaults.java b/app/src/processing/app/syntax/TextAreaDefaults.java index ac856102b..746685c03 100644 --- a/app/src/processing/app/syntax/TextAreaDefaults.java +++ b/app/src/processing/app/syntax/TextAreaDefaults.java @@ -40,7 +40,6 @@ public class TextAreaDefaults { public boolean eolMarkers; public boolean paintInvalid; - // moved from TextAreaPainter [fry] public Font plainFont; public Font boldFont; public Color fgcolor; diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index 30b0f6200..f1ad29e58 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -10,15 +10,15 @@ */ package processing.app.syntax; -import processing.app.syntax.im.CompositionTextPainter; +import java.awt.event.MouseEvent; +import java.awt.*; +import java.awt.print.*; import javax.swing.ToolTipManager; import javax.swing.text.*; import javax.swing.JComponent; -import java.awt.event.MouseEvent; -import java.awt.*; -import java.awt.print.*; +import processing.app.syntax.im.CompositionTextPainter; /** @@ -26,22 +26,45 @@ import java.awt.print.*; * lines of text. * @author Slava Pestov */ -public class TextAreaPainter extends JComponent -implements TabExpander, Printable { +public class TextAreaPainter extends JComponent implements TabExpander { /** True if inside printing, will handle disabling the highlight */ boolean printing; /** Current setting for editor.antialias preference */ - boolean antialias; +// boolean antialias; /** A specific painter composed by the InputMethod.*/ protected CompositionTextPainter compositionTextPainter; + // protected members + protected JEditTextArea textArea; + protected TextAreaDefaults defaults; + +// protected boolean blockCaret; +// protected SyntaxStyle[] styles; +// protected Color caretColor; +// protected Color selectionColor; +// protected Color lineHighlightColor; +// protected boolean lineHighlight; +// protected Color bracketHighlightColor; +// protected boolean bracketHighlight; +// protected Color eolMarkerColor; +// protected boolean eolMarkers; + + protected int cols; + protected int rows; + + protected int tabSize; + protected FontMetrics fm; + + protected Highlight highlights; + /** * Creates a new repaint manager. This should be not be called directly. */ public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults) { this.textArea = textArea; + this.defaults = defaults; setAutoscrolls(true); setDoubleBuffered(true); @@ -60,17 +83,17 @@ implements TabExpander, Printable { setForeground(defaults.fgcolor); setBackground(defaults.bgcolor); - blockCaret = defaults.blockCaret; - styles = defaults.styles; - caretColor = defaults.caretColor; - selectionColor = defaults.selectionColor; - lineHighlightColor = defaults.lineHighlightColor; - lineHighlight = defaults.lineHighlight; - bracketHighlightColor = defaults.bracketHighlightColor; - bracketHighlight = defaults.bracketHighlight; - eolMarkerColor = defaults.eolMarkerColor; - eolMarkers = defaults.eolMarkers; - antialias = defaults.antialias; +// blockCaret = defaults.blockCaret; +// styles = defaults.styles; +// caretColor = defaults.caretColor; +// selectionColor = defaults.selectionColor; +// lineHighlightColor = defaults.lineHighlightColor; +// lineHighlight = defaults.lineHighlight; +// bracketHighlightColor = defaults.bracketHighlightColor; +// bracketHighlight = defaults.bracketHighlight; +// eolMarkerColor = defaults.eolMarkerColor; +// eolMarkers = defaults.eolMarkers; +// antialias = defaults.antialias; cols = defaults.cols; rows = defaults.rows; @@ -119,81 +142,82 @@ implements TabExpander, Printable { * @see processing.app.syntax.Token */ public final SyntaxStyle[] getStyles() { - return styles; + return defaults.styles; } - /** - * Sets the syntax styles used to paint colorized text. Entry n - * will be used to paint tokens with id = n. - * @param styles The syntax styles - * @see processing.app.syntax.Token - */ - public final void setStyles(SyntaxStyle[] styles) { - this.styles = styles; - repaint(); - } +// /** +// * Sets the syntax styles used to paint colorized text. Entry n +// * will be used to paint tokens with id = n. +// * @param styles The syntax styles +// * @see processing.app.syntax.Token +// */ +// public final void setStyles(SyntaxStyle[] styles) { +// this.styles = styles; +// repaint(); +// } - /** - * Returns the caret color. - */ - public final Color getCaretColor() { - return caretColor; - } +// /** +// * Returns the caret color. +// */ +// public final Color getCaretColor() { +// return caretColor; +// } - /** - * Sets the caret color. - * @param caretColor The caret color - */ - public final void setCaretColor(Color caretColor) { - this.caretColor = caretColor; - invalidateSelectedLines(); - } - - /** - * Returns the selection color. - */ - public final Color getSelectionColor() { - return selectionColor; - } +// /** +// * Sets the caret color. +// * @param caretColor The caret color +// */ +// public final void setCaretColor(Color caretColor) { +// this.caretColor = caretColor; +// invalidateSelectedLines(); +// } - /** - * Sets the selection color. - * @param selectionColor The selection color - */ - public final void setSelectionColor(Color selectionColor) { - this.selectionColor = selectionColor; - invalidateSelectedLines(); - } - - - /** - * Returns the line highlight color. - */ - public final Color getLineHighlightColor() { - return lineHighlightColor; - } +// /** +// * Returns the selection color. +// */ +// public final Color getSelectionColor() { +// return selectionColor; +// } - /** - * Sets the line highlight color. - * @param lineHighlightColor The line highlight color - */ - public final void setLineHighlightColor(Color lineHighlightColor) { - this.lineHighlightColor = lineHighlightColor; - invalidateSelectedLines(); - } +// /** +// * Sets the selection color. +// * @param selectionColor The selection color +// */ +// public final void setSelectionColor(Color selectionColor) { +// this.selectionColor = selectionColor; +// invalidateSelectedLines(); +// } - /** - * Returns true if line highlight is enabled, false otherwise. - */ - public final boolean isLineHighlightEnabled() { - return lineHighlight; - } +// /** +// * Returns the line highlight color. +// */ +// public final Color getLineHighlightColor() { +// return lineHighlightColor; +// } + + +// /** +// * Sets the line highlight color. +// * @param lineHighlightColor The line highlight color +// */ +// public final void setLineHighlightColor(Color lineHighlightColor) { +// this.lineHighlightColor = lineHighlightColor; +// invalidateSelectedLines(); +// } + + +// /** +// * Returns true if line highlight is enabled, false otherwise. +// */ +// public final boolean isLineHighlightEnabled() { +// return lineHighlight; +// } /** @@ -202,28 +226,29 @@ implements TabExpander, Printable { * should be enabled, false otherwise */ public final void setLineHighlightEnabled(boolean lineHighlight) { - this.lineHighlight = lineHighlight; +// this.lineHighlight = lineHighlight; + defaults.lineHighlight = lineHighlight; invalidateSelectedLines(); } - /** - * Returns the bracket highlight color. - */ - public final Color getBracketHighlightColor() { - return bracketHighlightColor; - } +// /** +// * Returns the bracket highlight color. +// */ +// public final Color getBracketHighlightColor() { +// return bracketHighlightColor; +// } - /** - * Sets the bracket highlight color. - * @param bracketHighlightColor The bracket highlight color - */ - public final void setBracketHighlightColor(Color bracketHighlightColor) - { - this.bracketHighlightColor = bracketHighlightColor; - invalidateLine(textArea.getBracketLine()); - } +// /** +// * Sets the bracket highlight color. +// * @param bracketHighlightColor The bracket highlight color +// */ +// public final void setBracketHighlightColor(Color bracketHighlightColor) { +// this.bracketHighlightColor = bracketHighlightColor; +// invalidateLine(textArea.getBracketLine()); +// } + /** * Returns true if bracket highlighting is enabled, false otherwise. @@ -231,91 +256,92 @@ implements TabExpander, Printable { * one before the caret (if any) is highlighted. */ public final boolean isBracketHighlightEnabled() { - return bracketHighlight; +// return bracketHighlight; + return defaults.bracketHighlight; } - /** - * Enables or disables bracket highlighting. - * When bracket highlighting is enabled, the bracket matching the - * one before the caret (if any) is highlighted. - * @param bracketHighlight True if bracket highlighting should be - * enabled, false otherwise - */ - public final void setBracketHighlightEnabled(boolean bracketHighlight) { - this.bracketHighlight = bracketHighlight; - invalidateLine(textArea.getBracketLine()); - } +// /** +// * Enables or disables bracket highlighting. +// * When bracket highlighting is enabled, the bracket matching the +// * one before the caret (if any) is highlighted. +// * @param bracketHighlight True if bracket highlighting should be +// * enabled, false otherwise +// */ +// public final void setBracketHighlightEnabled(boolean bracketHighlight) { +// this.bracketHighlight = bracketHighlight; +// invalidateLine(textArea.getBracketLine()); +// } /** * Returns true if the caret should be drawn as a block, false otherwise. */ public final boolean isBlockCaretEnabled() { - return blockCaret; + return defaults.blockCaret; } - /** - * Sets if the caret should be drawn as a block, false otherwise. - * @param blockCaret True if the caret should be drawn as a block, - * false otherwise. - */ - public final void setBlockCaretEnabled(boolean blockCaret) { - this.blockCaret = blockCaret; - invalidateSelectedLines(); - } +// /** +// * Sets if the caret should be drawn as a block, false otherwise. +// * @param blockCaret True if the caret should be drawn as a block, +// * false otherwise. +// */ +// public final void setBlockCaretEnabled(boolean blockCaret) { +// this.blockCaret = blockCaret; +// invalidateSelectedLines(); +// } - /** - * Returns the EOL marker color. - */ - public final Color getEOLMarkerColor() { - return eolMarkerColor; - } +// /** +// * Returns the EOL marker color. +// */ +// public final Color getEOLMarkerColor() { +// return eolMarkerColor; +// } - /** - * Sets the EOL marker color. - * @param eolMarkerColor The EOL marker color - */ - public final void setEOLMarkerColor(Color eolMarkerColor) { - this.eolMarkerColor = eolMarkerColor; - repaint(); - } +// /** +// * Sets the EOL marker color. +// * @param eolMarkerColor The EOL marker color +// */ +// public final void setEOLMarkerColor(Color eolMarkerColor) { +// this.eolMarkerColor = eolMarkerColor; +// repaint(); +// } - /** - * Returns true if EOL markers are drawn, false otherwise. - */ - public final boolean getEOLMarkersPainted() { - return eolMarkers; - } +// /** +// * Returns true if EOL markers are drawn, false otherwise. +// */ +// public final boolean getEOLMarkersPainted() { +// return eolMarkers; +// } - /** - * Sets if EOL markers are to be drawn. - * @param eolMarkers True if EOL markers should be drawn, false otherwise - */ - public final void setEOLMarkersPainted(boolean eolMarkers) { - this.eolMarkers = eolMarkers; - repaint(); - } +// /** +// * Sets if EOL markers are to be drawn. +// * @param eolMarkers True if EOL markers should be drawn, false otherwise +// */ +// public final void setEOLMarkersPainted(boolean eolMarkers) { +// this.eolMarkers = eolMarkers; +// repaint(); +// } - public final void setAntialias(boolean antialias) { - this.antialias = antialias; - } +// public final void setAntialias(boolean antialias) { +// this.antialias = antialias; +// } - /** - * Adds a custom highlight painter. - * @param highlight The highlight - */ - public void addCustomHighlight(Highlight highlight) { - highlight.init(textArea,highlights); - highlights = highlight; - } +// /** +// * Adds a custom highlight painter. +// * @param highlight The highlight +// */ +// public void addCustomHighlight(Highlight highlight) { +// highlight.init(textArea,highlights); +// highlights = highlight; +// } /** @@ -349,13 +375,13 @@ implements TabExpander, Printable { } - /** - * Returns the tool tip to display at the specified location. - * @param evt The mouse event - */ - public String getToolTipText(MouseEvent evt) { - return (highlights == null) ? null : highlights.getToolTipText(evt); - } +// /** +// * Returns the tool tip to display at the specified location. +// * @param evt The mouse event +// */ +// public String getToolTipText(MouseEvent evt) { +// return (highlights == null) ? null : highlights.getToolTipText(evt); +// } /** @@ -385,7 +411,7 @@ implements TabExpander, Printable { public void paint(Graphics gfx) { Graphics2D g2 = (Graphics2D) gfx; g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - antialias ? + defaults.antialias ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); @@ -411,7 +437,7 @@ implements TabExpander, Printable { int x = textArea.getHorizontalOffset(); for (int line = firstInvalid; line <= lastInvalid; line++) { - paintLine(gfx,tokenMarker,line,x); + paintLine(gfx, tokenMarker, line, x); } if (tokenMarker != null && tokenMarker.isNextLineRequested()) { @@ -427,28 +453,35 @@ implements TabExpander, Printable { } - public int print(Graphics g, PageFormat pageFormat, int pageIndex) { - int lineHeight = fm.getHeight(); - int linesPerPage = (int) (pageFormat.getImageableHeight() / lineHeight); - int lineCount = textArea.getLineCount(); - int lastPage = lineCount / linesPerPage; + public Printable getPrintable() { + return new Printable() { + + @Override + public int print(Graphics graphics, PageFormat pageFormat, + int pageIndex) throws PrinterException { + int lineHeight = fm.getHeight(); + int linesPerPage = (int) (pageFormat.getImageableHeight() / lineHeight); + int lineCount = textArea.getLineCount(); + int lastPage = lineCount / linesPerPage; - if (pageIndex > lastPage) { - return NO_SUCH_PAGE; + if (pageIndex > lastPage) { + return NO_SUCH_PAGE; - } else { - Graphics2D g2d = (Graphics2D)g; - TokenMarker tokenMarker = textArea.getDocument().getTokenMarker(); - int firstLine = pageIndex*linesPerPage; - g2d.translate(Math.max(54, pageFormat.getImageableX()), - pageFormat.getImageableY() - firstLine*lineHeight); - printing = true; - for (int line = firstLine; line < firstLine + linesPerPage; line++) { - paintLine(g2d, tokenMarker, line, 0); + } else { + Graphics2D g2d = (Graphics2D) graphics; + TokenMarker tokenMarker = textArea.getDocument().getTokenMarker(); + int firstLine = pageIndex*linesPerPage; + g2d.translate(Math.max(54, pageFormat.getImageableX()), + pageFormat.getImageableY() - firstLine*lineHeight); + printing = true; + for (int line = firstLine; line < firstLine + linesPerPage; line++) { + paintLine(g2d, tokenMarker, line, 0); + } + printing = false; + return PAGE_EXISTS; + } } - printing = false; - return PAGE_EXISTS; - } + }; } @@ -495,6 +528,7 @@ implements TabExpander, Printable { int ntabs = ((int)x - offset) / tabSize; return (ntabs + 1) * tabSize + offset; } + /** * Returns the painter's preferred size. @@ -555,28 +589,6 @@ implements TabExpander, Printable { } - // protected members - protected JEditTextArea textArea; - - protected SyntaxStyle[] styles; - protected Color caretColor; - protected Color selectionColor; - protected Color lineHighlightColor; - protected Color bracketHighlightColor; - protected Color eolMarkerColor; - - protected boolean blockCaret; - protected boolean lineHighlight; - protected boolean bracketHighlight; - protected boolean eolMarkers; - protected int cols; - protected int rows; - - protected int tabSize; - protected FontMetrics fm; - - protected Highlight highlights; - protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line, int x) { Font defaultFont = getFont(); @@ -586,16 +598,18 @@ implements TabExpander, Printable { int y = textArea.lineToY(line); if (tokenMarker == null) { - paintPlainLine(gfx,line,defaultFont,defaultColor,x,y); + paintPlainLine(gfx, line, defaultFont, defaultColor, x, y); } else if (line >= 0 && line < textArea.getLineCount()) { - paintSyntaxLine(gfx,tokenMarker,line,defaultFont, - defaultColor,x,y); + paintSyntaxLine(gfx, tokenMarker, line, defaultFont, defaultColor, x, y); } } + protected void paintPlainLine(Graphics gfx, int line, Font defaultFont, Color defaultColor, int x, int y) { - paintHighlight(gfx,line,y); + if (!printing) { + paintHighlight(gfx,line,y); + } textArea.getLineText(line,currentLine); gfx.setFont(defaultFont); @@ -605,10 +619,10 @@ implements TabExpander, Printable { x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0); // Draw characters via input method. if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) { - compositionTextPainter.draw(gfx, lineHighlightColor); + compositionTextPainter.draw(gfx, defaults.lineHighlightColor); } - if (eolMarkers) { - gfx.setColor(eolMarkerColor); + if (defaults.eolMarkers) { + gfx.setColor(defaults.eolMarkerColor); gfx.drawString(".",x,y); } } @@ -621,22 +635,22 @@ implements TabExpander, Printable { currentLineTokens = tokenMarker.markTokens(currentLine, currentLineIndex); - paintHighlight(gfx,line,y); + paintHighlight(gfx, line, y); gfx.setFont(defaultFont); gfx.setColor(defaultColor); y += fm.getHeight(); x = paintSyntaxLine(currentLine, - currentLineTokens, - styles, this, gfx, x, y); + currentLineTokens, + defaults.styles, this, gfx, x, y); /* * Draw characters via input method. */ if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) { - compositionTextPainter.draw(gfx, lineHighlightColor); + compositionTextPainter.draw(gfx, defaults.lineHighlightColor); } - if (eolMarkers) { - gfx.setColor(eolMarkerColor); + if (defaults.eolMarkers) { + gfx.setColor(defaults.eolMarkerColor); gfx.drawString(".",x,y); } } @@ -687,20 +701,23 @@ implements TabExpander, Printable { } - protected void paintHighlight(Graphics gfx, int line, int y) { - if (!printing) { - if (line >= textArea.getSelectionStartLine() - && line <= textArea.getSelectionStopLine()) - paintLineHighlight(gfx,line,y); + protected void paintHighlight(Graphics gfx, int line, int y) {//, boolean printing) { +// if (!printing) { + if (line >= textArea.getSelectionStartLine() && + line <= textArea.getSelectionStopLine()) { + paintLineHighlight(gfx, line, y); + } - if (highlights != null) - highlights.paintHighlight(gfx,line,y); + if (highlights != null) { + highlights.paintHighlight(gfx, line, y); + } - if (bracketHighlight && line == textArea.getBracketLine()) - paintBracketHighlight(gfx,line,y); + if (defaults.bracketHighlight && line == textArea.getBracketLine()) { + paintBracketHighlight(gfx, line, y); + } - if (line == textArea.getCaretLine()) - paintCaret(gfx,line,y); + if (line == textArea.getCaretLine()) { + paintCaret(gfx, line, y); } } @@ -713,12 +730,12 @@ implements TabExpander, Printable { int selectionEnd = textArea.getSelectionStop(); if (selectionStart == selectionEnd) { - if (lineHighlight) { - gfx.setColor(lineHighlightColor); - gfx.fillRect(0,y,getWidth(),height); + if (defaults.lineHighlight) { + gfx.setColor(defaults.lineHighlightColor); + gfx.fillRect(0, y, getWidth(), height); } } else { - gfx.setColor(selectionColor); + gfx.setColor(defaults.selectionColor); int selectionStartLine = textArea.getSelectionStartLine(); int selectionEndLine = textArea.getSelectionStopLine(); @@ -767,12 +784,11 @@ implements TabExpander, Printable { } y += fm.getLeading() + fm.getMaxDescent(); int x = textArea._offsetToX(line,position); - gfx.setColor(bracketHighlightColor); + gfx.setColor(defaults.bracketHighlightColor); // Hack!!! Since there is no fast way to get the character // from the bracket matching routine, we use ( since all // brackets probably have the same width anyway - gfx.drawRect(x,y,fm.charWidth('(') - 1, - fm.getHeight() - 1); + gfx.drawRect(x,y,fm.charWidth('(') - 1, fm.getHeight() - 1); } @@ -783,7 +799,7 @@ implements TabExpander, Printable { int offset = textArea.getCaretPosition() - textArea.getLineStartOffset(line); int caretX = textArea._offsetToX(line, offset); - int caretWidth = ((blockCaret || + int caretWidth = ((defaults.blockCaret || textArea.isOverwriteEnabled()) ? fm.charWidth('w') : 1); y += fm.getLeading() + fm.getMaxDescent(); @@ -791,7 +807,7 @@ implements TabExpander, Printable { //System.out.println("caretX, width = " + caretX + " " + caretWidth); - gfx.setColor(caretColor); + gfx.setColor(defaults.caretColor); if (textArea.isOverwriteEnabled()) { gfx.fillRect(caretX,y + height - 1, caretWidth,1); From c47e931d21550eb9af8a582bf3e08a7b66751134 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sun, 13 Oct 2013 23:47:53 -0400 Subject: [PATCH 165/556] but wait, there's more --- .../processing/app/syntax/JEditTextArea.java | 17 +- .../processing/app/syntax/SyntaxStyle.java | 213 +++++++++--------- .../app/syntax/TextAreaPainter.java | 17 +- 3 files changed, 128 insertions(+), 119 deletions(-) diff --git a/app/src/processing/app/syntax/JEditTextArea.java b/app/src/processing/app/syntax/JEditTextArea.java index 49eeb1299..9f46161a8 100644 --- a/app/src/processing/app/syntax/JEditTextArea.java +++ b/app/src/processing/app/syntax/JEditTextArea.java @@ -594,7 +594,7 @@ public class JEditTextArea extends JComponent tokens = painter.currentLineTokens = tokenMarker.markTokens(lineSegment, line); } - Font defaultFont = painter.getFont(); +// Font defaultFont = painter.getFont(); SyntaxStyle[] styles = painter.getStyles(); for (;;) { @@ -606,7 +606,8 @@ public class JEditTextArea extends JComponent if (id == Token.NULL) { fm = painter.getFontMetrics(); } else { - fm = styles[id].getFontMetrics(defaultFont, this); + //fm = styles[id].getFontMetrics(defaultFont, this); + fm = painter.getFontMetrics(styles[id]); } int length = tokens.length; @@ -681,19 +682,21 @@ public class JEditTextArea extends JComponent } int offset = 0; - Font defaultFont = painter.getFont(); +// Font defaultFont = painter.getFont(); SyntaxStyle[] styles = painter.getStyles(); // System.out.println("painter is " + painter + ", doc is " + document); - for(;;) { + for (;;) { byte id = tokens.id; if(id == Token.END) return offset; - if(id == Token.NULL) + if (id == Token.NULL) { fm = painter.getFontMetrics(); - else - fm = styles[id].getFontMetrics(defaultFont, this); + } else { + //fm = styles[id].getFontMetrics(defaultFont, this); + fm = painter.getFontMetrics(styles[id]); + } int length = tokens.length; diff --git a/app/src/processing/app/syntax/SyntaxStyle.java b/app/src/processing/app/syntax/SyntaxStyle.java index 277640fba..9415a4bf0 100644 --- a/app/src/processing/app/syntax/SyntaxStyle.java +++ b/app/src/processing/app/syntax/SyntaxStyle.java @@ -9,8 +9,7 @@ package processing.app.syntax; -import java.awt.*; -import javax.swing.JComponent; +import java.awt.Color; /** @@ -23,9 +22,9 @@ public class SyntaxStyle { private Color color; // private boolean italic; private boolean bold; - private Font lastFont; - private Font lastStyledFont; - private FontMetrics fontMetrics; +// private Font lastFont; +// private Font lastStyledFont; +// private FontMetrics fontMetrics; /** @@ -69,112 +68,112 @@ public class SyntaxStyle { } - /** - * Returns the specified font, but with the style's bold flags applied. - */ - public Font getStyledFont(Font font) { - if (font.equals(lastFont)) { - return lastStyledFont; - } - lastFont = font; - lastStyledFont = - findFont(font.getFamily(), bold ? Font.BOLD : Font.PLAIN, font.getSize()); - return lastStyledFont; - } - - - /** - * Returns the font metrics for the styled font. - */ - public FontMetrics getFontMetrics(Font font, JComponent comp) { -// if (font == null) { -// throw new NullPointerException("font param must not be null"); +// /** +// * Returns the specified font, but with the style's bold flags applied. +// */ +// public Font getStyledFont(Font font) { +// if (font.equals(lastFont)) { +// return lastStyledFont; // } - if (font.equals(lastFont) && fontMetrics != null) { - return fontMetrics; - } - lastFont = font; -// lastStyledFont = new Font(font.getFamily(), -// (bold ? Font.BOLD : 0) -// | (italic ? Font.ITALIC : 0), -// font.getSize()); - lastStyledFont = - findFont(font.getFamily(), bold ? Font.BOLD : Font.PLAIN, font.getSize()); - - //fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(lastStyledFont); - fontMetrics = comp.getFontMetrics(lastStyledFont); - return fontMetrics; - } - - - /* - on Windows (and I presume Linux) we get something like this: - - mono family Source Code Pro - mono fontname Source Code Pro - mono name Source Code Pro - mono psname SourceCodePro-Regular - - mono family Source Code Pro Semibold - mono fontname Source Code Pro Semibold - mono name Source Code Pro Semibold - mono psname SourceCodePro-Semibold - - ...which means that 'family' is not a usable method. - */ - //private String monoFontFamily; - - private Font findFont(String familyName, int style, int size) { -// // getFamily() is too unreliable across platforms -// if (Preferences.get("editor.font").startsWith("processing.mono")) { +// lastFont = font; +// lastStyledFont = +// findFont(font.getFamily(), bold ? Font.BOLD : Font.PLAIN, font.getSize()); +// return lastStyledFont; +// } +// +// +// /** +// * Returns the font metrics for the styled font. +// */ +// public FontMetrics getFontMetrics(Font font, JComponent comp) { +//// if (font == null) { +//// throw new NullPointerException("font param must not be null"); +//// } +// if (font.equals(lastFont) && fontMetrics != null) { +// return fontMetrics; +// } +// lastFont = font; +//// lastStyledFont = new Font(font.getFamily(), +//// (bold ? Font.BOLD : 0) +//// | (italic ? Font.ITALIC : 0), +//// font.getSize()); +// lastStyledFont = +// findFont(font.getFamily(), bold ? Font.BOLD : Font.PLAIN, font.getSize()); +// +// //fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(lastStyledFont); +// fontMetrics = comp.getFontMetrics(lastStyledFont); +// return fontMetrics; +// } +// +// +// /* +// on Windows (and I presume Linux) we get something like this: +// +// mono family Source Code Pro +// mono fontname Source Code Pro +// mono name Source Code Pro +// mono psname SourceCodePro-Regular +// +// mono family Source Code Pro Semibold +// mono fontname Source Code Pro Semibold +// mono name Source Code Pro Semibold +// mono psname SourceCodePro-Semibold +// +// ...which means that 'family' is not a usable method. +// */ +// //private String monoFontFamily; +// +// private Font findFont(String familyName, int style, int size) { +//// // getFamily() is too unreliable across platforms +//// if (Preferences.get("editor.font").startsWith("processing.mono")) { +//// return processing.app.Toolkit.getMonoFont(size, style); +//// } else { +// System.out.println("creating new font for " + familyName); +// return new Font(familyName, style, size); +//// } +// +// /* +// if (monoFontFamily == null) { +// // This should be more reliable across platforms than the +// // family name, which only seems to work correctly on OS X. +// // (Or perhaps only when it's installed locally.) +// String psName = +// processing.app.Toolkit.getMonoFont(size, style).getPSName(); +// int dash = psName.indexOf('-'); +// monoFontFamily = psName.substring(0, dash); +// +// // Just get the font family name for comparison +// //monoFontFamily = +// //processing.app.Toolkit.getMonoFont(size, style).getFamily(); +// //processing.app.Toolkit.getMonoFont(size, style).getFamily(); +// Font mono = processing.app.Toolkit.getMonoFont(size, style); +// System.out.println("mono family " + mono.getFamily()); +// System.out.println("mono fontname " + mono.getFontName()); +// System.out.println("mono name " + mono.getName()); +// System.out.println("mono psname " + mono.getPSName()); +// } +// if (familyName.equals(monoFontFamily)) { +// System.out.println("getting style bold? " + (style == Font.BOLD)); // return processing.app.Toolkit.getMonoFont(size, style); // } else { - System.out.println("creating new font for " + familyName); - return new Font(familyName, style, size); +// //System.out.println("name is " + name + " mono name is " + monoFontName + " " + style); +// return new Font(familyName, style, size); // } - - /* - if (monoFontFamily == null) { - // This should be more reliable across platforms than the - // family name, which only seems to work correctly on OS X. - // (Or perhaps only when it's installed locally.) - String psName = - processing.app.Toolkit.getMonoFont(size, style).getPSName(); - int dash = psName.indexOf('-'); - monoFontFamily = psName.substring(0, dash); - - // Just get the font family name for comparison - //monoFontFamily = - //processing.app.Toolkit.getMonoFont(size, style).getFamily(); - //processing.app.Toolkit.getMonoFont(size, style).getFamily(); - Font mono = processing.app.Toolkit.getMonoFont(size, style); - System.out.println("mono family " + mono.getFamily()); - System.out.println("mono fontname " + mono.getFontName()); - System.out.println("mono name " + mono.getName()); - System.out.println("mono psname " + mono.getPSName()); - } - if (familyName.equals(monoFontFamily)) { - System.out.println("getting style bold? " + (style == Font.BOLD)); - return processing.app.Toolkit.getMonoFont(size, style); - } else { - //System.out.println("name is " + name + " mono name is " + monoFontName + " " + style); - return new Font(familyName, style, size); - } - */ - } - - - /** - * Sets the foreground color and font of the specified graphics - * context to that specified in this style. - * @param gfx The graphics context - * @param font The font to add the styles to - */ - public void setGraphicsFlags(Graphics gfx, Font font) { - Font _font = getStyledFont(font); - gfx.setFont(_font); - gfx.setColor(color); - } +// */ +// } +// +// +// /** +// * Sets the foreground color and font of the specified graphics +// * context to that specified in this style. +// * @param gfx The graphics context +// * @param font The font to add the styles to +// */ +// public void setGraphicsFlags(Graphics gfx, Font font) { +// Font _font = getStyledFont(font); +// gfx.setFont(_font); +// gfx.setColor(color); +// } /** diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index f1ad29e58..9849b38af 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -384,13 +384,17 @@ public class TextAreaPainter extends JComponent implements TabExpander { // } - /** - * Returns the font metrics used by this component. - */ + /** Returns the font metrics used by this component. */ public FontMetrics getFontMetrics() { return fm; } + + public FontMetrics getFontMetrics(SyntaxStyle style) { + return getFontMetrics(style.isBold() ? + defaults.boldFont : defaults.plainFont); + } + /** * Sets the font for this component. This is overridden to update the @@ -669,7 +673,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { * @param y The y co-ordinate * @return The x co-ordinate, plus the width of the painted string */ - static public int paintSyntaxLine(Segment line, Token tokens, + public int paintSyntaxLine(Segment line, Token tokens, SyntaxStyle[] styles, TabExpander expander, Graphics gfx, int x, int y) { @@ -688,7 +692,10 @@ public class TextAreaPainter extends JComponent implements TabExpander { if(!defaultFont.equals(gfx.getFont())) gfx.setFont(defaultFont); } else { - styles[id].setGraphicsFlags(gfx,defaultFont); + //styles[id].setGraphicsFlags(gfx,defaultFont); + SyntaxStyle ss = styles[id]; + gfx.setColor(ss.getColor()); + gfx.setFont(ss.isBold() ? defaults.boldFont : defaults.plainFont); } line.count = length; x = Utilities.drawTabbedText(line,x,y,gfx,expander,0); From e069242cd7489aa68356ea06a2d4be8615a072ba Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Mon, 14 Oct 2013 12:10:56 -0400 Subject: [PATCH 166/556] font issues sorted, lots of cleanup, fix retina crustiness --- app/src/processing/app/Editor.java | 9 +- .../app/syntax/PdeTextAreaDefaults.java | 2 +- .../app/syntax/TextAreaPainter.java | 232 +++++++++--------- .../app/syntax/im/CompositionTextPainter.java | 23 +- todo.txt | 2 + 5 files changed, 147 insertions(+), 121 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index ffa6cfdc8..4f5a6878b 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -472,6 +472,9 @@ public abstract class Editor extends JFrame implements RunnerListener { * with things in the Preferences window. */ protected void applyPreferences() { + // All of this code was specific to using an external editor. + // Keeping this around so we can update fonts. + /* // // apply the setting for 'use external editor' // boolean external = Preferences.getBoolean("editor.external"); // textarea.setEditable(!external); @@ -494,7 +497,7 @@ public abstract class Editor extends JFrame implements RunnerListener { // } // apply changes to the font size for the editor - painter.setFont(Preferences.getFont("editor.font")); +// painter.setFont(Preferences.getFont("editor.font")); // in case tab expansion stuff has changed // removing this, just checking prefs directly instead @@ -505,6 +508,7 @@ public abstract class Editor extends JFrame implements RunnerListener { //sketchbook.rebuildMenus(); // For 0126, moved into Base, which will notify all editors. //base.rebuildMenusAsync(); + */ } @@ -2007,6 +2011,9 @@ public abstract class Editor extends JFrame implements RunnerListener { // As of Processing 1.0.10, this always happens immediately. // http://dev.processing.org/bugs/show_bug.cgi?id=1456 + // With Java 7u40 on OS X, need to bring the window forward. + toFront(); + String prompt = "Save changes to " + sketch.getName() + "? "; if (!Base.isMacOS()) { diff --git a/app/src/processing/app/syntax/PdeTextAreaDefaults.java b/app/src/processing/app/syntax/PdeTextAreaDefaults.java index b427f9ef4..31b117354 100644 --- a/app/src/processing/app/syntax/PdeTextAreaDefaults.java +++ b/app/src/processing/app/syntax/PdeTextAreaDefaults.java @@ -201,7 +201,7 @@ public class PdeTextAreaDefaults extends TextAreaDefaults { int fontSize = Preferences.getInteger("editor.font.size"); plainFont = new Font(fontFamily, Font.PLAIN, fontSize); boldFont = new Font(fontFamily, Font.BOLD, fontSize); - //System.out.println("font is " + plainFont.getFamily() + " / " + plainFont.getName() + " / " + plainFont.getFontName() + " / " + plainFont.getPSName()); + System.out.println("font is " + plainFont.getFamily() + " / " + plainFont.getName() + " / " + plainFont.getFontName() + " / " + plainFont.getPSName()); // antialias = Preferences.getBoolean("editor.antialias"); styles = new SyntaxStyle[Token.ID_COUNT]; diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index 9849b38af..f93b7584e 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -35,7 +35,6 @@ public class TextAreaPainter extends JComponent implements TabExpander { /** A specific painter composed by the InputMethod.*/ protected CompositionTextPainter compositionTextPainter; - // protected members protected JEditTextArea textArea; protected TextAreaDefaults defaults; @@ -50,13 +49,17 @@ public class TextAreaPainter extends JComponent implements TabExpander { // protected Color eolMarkerColor; // protected boolean eolMarkers; - protected int cols; - protected int rows; +// protected int cols; +// protected int rows; protected int tabSize; protected FontMetrics fm; protected Highlight highlights; + + int currentLineIndex; + Token currentLineTokens; + Segment currentLine; /** @@ -67,7 +70,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { this.defaults = defaults; setAutoscrolls(true); - setDoubleBuffered(true); +// setDoubleBuffered(true); // breaks retina with 7u40 setOpaque(true); ToolTipManager.sharedInstance().registerComponent(this); @@ -77,11 +80,12 @@ public class TextAreaPainter extends JComponent implements TabExpander { setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); - // unfortunately probably can't just do setDefaults() since things aren't quite set up - setFont(defaults.plainFont); -// System.out.println("defaults font is " + defaults.font); - setForeground(defaults.fgcolor); - setBackground(defaults.bgcolor); +// // unfortunately probably can't just do setDefaults() since things aren't quite set up +// setFont(defaults.plainFont); +//// System.out.println("defaults font is " + defaults.font); +// setForeground(defaults.fgcolor); +// setBackground(defaults.bgcolor); + applyDefaults(); // blockCaret = defaults.blockCaret; // styles = defaults.styles; @@ -95,8 +99,17 @@ public class TextAreaPainter extends JComponent implements TabExpander { // eolMarkers = defaults.eolMarkers; // antialias = defaults.antialias; - cols = defaults.cols; - rows = defaults.rows; +// cols = defaults.cols; +// rows = defaults.rows; + } + + + public void applyDefaults() { + // unfortunately probably can't just do setDefaults() since things aren't quite set up + setFont(defaults.plainFont); +// System.out.println("defaults font is " + defaults.font); + setForeground(defaults.fgcolor); + setBackground(defaults.bgcolor); } @@ -126,9 +139,9 @@ public class TextAreaPainter extends JComponent implements TabExpander { /** - * Get CompositionTextPainter. if CompositionTextPainter is not created, create it. + * Get CompositionTextPainter, creating one if it doesn't exist. */ - public CompositionTextPainter getCompositionTextpainter(){ + public CompositionTextPainter getCompositionTextpainter() { if (compositionTextPainter == null){ compositionTextPainter = new CompositionTextPainter(textArea); } @@ -402,6 +415,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { * @param font The font */ public void setFont(Font font) { +// new Exception().printStackTrace(System.out); super.setFont(font); fm = super.getFontMetrics(font); textArea.recalculateVisibleLines(); @@ -414,6 +428,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { */ public void paint(Graphics gfx) { Graphics2D g2 = (Graphics2D) gfx; + defaults.antialias = true; g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, defaults.antialias ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : @@ -424,7 +439,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { Rectangle clipRect = gfx.getClipBounds(); gfx.setColor(getBackground()); - gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height); + gfx.fillRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height); // We don't use yToLine() here because that method doesn't // return lines past the end of the document @@ -446,12 +461,11 @@ public class TextAreaPainter extends JComponent implements TabExpander { if (tokenMarker != null && tokenMarker.isNextLineRequested()) { int h = clipRect.y + clipRect.height; - repaint(0,h,getWidth(),getHeight() - h); + repaint(0, h, getWidth(), getHeight() - h); } } catch (Exception e) { - System.err.println("Error repainting line" - + " range {" + firstInvalid + "," - + lastInvalid + "}:"); + System.err.println("Error repainting line" + + " range {" + firstInvalid + "," + lastInvalid + "}:"); e.printStackTrace(); } } @@ -472,14 +486,14 @@ public class TextAreaPainter extends JComponent implements TabExpander { return NO_SUCH_PAGE; } else { - Graphics2D g2d = (Graphics2D) graphics; + Graphics2D g2 = (Graphics2D) graphics; TokenMarker tokenMarker = textArea.getDocument().getTokenMarker(); int firstLine = pageIndex*linesPerPage; - g2d.translate(Math.max(54, pageFormat.getImageableX()), + g2.translate(Math.max(54, pageFormat.getImageableX()), pageFormat.getImageableY() - firstLine*lineHeight); printing = true; for (int line = firstLine; line < firstLine + linesPerPage; line++) { - paintLine(g2d, tokenMarker, line, 0); + paintLine(g2, tokenMarker, line, 0); } printing = false; return PAGE_EXISTS; @@ -493,9 +507,9 @@ public class TextAreaPainter extends JComponent implements TabExpander { * Marks a line as needing a repaint. * @param line The line to invalidate */ - public final void invalidateLine(int line) { - repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(), - getWidth(),fm.getHeight()); + final void invalidateLine(int line) { + repaint(0, textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(), + getWidth(), fm.getHeight()); } @@ -504,58 +518,41 @@ public class TextAreaPainter extends JComponent implements TabExpander { * @param firstLine The first line to invalidate * @param lastLine The last line to invalidate */ - public final void invalidateLineRange(int firstLine, int lastLine) { + final void invalidateLineRange(int firstLine, int lastLine) { repaint(0,textArea.lineToY(firstLine) + fm.getMaxDescent() + fm.getLeading(), getWidth(),(lastLine - firstLine + 1) * fm.getHeight()); } - /** - * Repaints the lines containing the selection. - */ - public final void invalidateSelectedLines() { + /** Repaints the lines containing the selection. */ + final void invalidateSelectedLines() { invalidateLineRange(textArea.getSelectionStartLine(), textArea.getSelectionStopLine()); } - /** - * Implementation of TabExpander interface. Returns next tab stop after - * a specified point. - * @param x The x co-ordinate - * @param tabOffset Ignored - * @return The next tab stop after x - */ + /** Returns next tab stop after a specified point. */ +// TabExpander tabExpander = new TabExpander() { + @Override public float nextTabStop(float x, int tabOffset) { int offset = textArea.getHorizontalOffset(); int ntabs = ((int)x - offset) / tabSize; return (ntabs + 1) * tabSize + offset; } - +// }; + - /** - * Returns the painter's preferred size. - */ public Dimension getPreferredSize() { - Dimension dim = new Dimension(); - dim.width = fm.charWidth('w') * cols; - dim.height = fm.getHeight() * rows; - return dim; + return new Dimension(fm.charWidth('w') * defaults.cols, + fm.getHeight() * defaults.rows); } - /** - * Returns the painter's minimum size. - */ public Dimension getMinimumSize() { return getPreferredSize(); } - // package-private members - int currentLineIndex; - Token currentLineTokens; - Segment currentLine; /** * Accessor used by tools that want to hook in and grab the formatting. @@ -563,6 +560,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { public int getCurrentLineIndex() { return currentLineIndex; } + /** * Accessor used by tools that want to hook in and grab the formatting. @@ -570,6 +568,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { public void setCurrentLineIndex(int what) { currentLineIndex = what; } + /** * Accessor used by tools that want to hook in and grab the formatting. @@ -578,12 +577,14 @@ public class TextAreaPainter extends JComponent implements TabExpander { return currentLineTokens; } + /** * Accessor used by tools that want to hook in and grab the formatting. */ public void setCurrentLineTokens(Token tokens) { currentLineTokens = tokens; } + /** * Accessor used by tools that want to hook in and grab the formatting. @@ -595,67 +596,73 @@ public class TextAreaPainter extends JComponent implements TabExpander { protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line, int x) { - Font defaultFont = getFont(); - Color defaultColor = getForeground(); +// Font defaultFont = getFont(); +// Color defaultColor = getForeground(); currentLineIndex = line; int y = textArea.lineToY(line); if (tokenMarker == null) { - paintPlainLine(gfx, line, defaultFont, defaultColor, x, y); + //paintPlainLine(gfx, line, defaultFont, defaultColor, x, y); + paintPlainLine(gfx, line, x, y); } else if (line >= 0 && line < textArea.getLineCount()) { - paintSyntaxLine(gfx, tokenMarker, line, defaultFont, defaultColor, x, y); + //paintSyntaxLine(gfx, tokenMarker, line, defaultFont, defaultColor, x, y); + paintSyntaxLine(gfx, line, x, y, tokenMarker); } } - protected void paintPlainLine(Graphics gfx, int line, Font defaultFont, - Color defaultColor, int x, int y) { +// protected void paintPlainLine(Graphics gfx, int line, Font defaultFont, +// Color defaultColor, int x, int y) { + protected void paintPlainLine(Graphics gfx, int line, int x, int y) { if (!printing) { paintHighlight(gfx,line,y); } textArea.getLineText(line,currentLine); - gfx.setFont(defaultFont); - gfx.setColor(defaultColor); +// gfx.setFont(defaultFont); +// gfx.setColor(defaultColor); y += fm.getHeight(); - x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0); + x = Utilities.drawTabbedText(currentLine, x, y, gfx, this, 0); + // Draw characters via input method. + if (compositionTextPainter != null && + compositionTextPainter.hasComposedTextLayout()) { + compositionTextPainter.draw(gfx, defaults.lineHighlightColor); + } + if (defaults.eolMarkers) { + gfx.setColor(defaults.eolMarkerColor); + gfx.drawString(".", x, y); + } + } + + +// protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker, +// int line, Font defaultFont, +// Color defaultColor, int x, int y) { + protected void paintSyntaxLine(Graphics gfx, int line, int x, int y, + TokenMarker tokenMarker) { + textArea.getLineText(currentLineIndex, currentLine); + currentLineTokens = tokenMarker.markTokens(currentLine, currentLineIndex); + + paintHighlight(gfx, line, y); + +// gfx.setFont(defaultFont); +// gfx.setColor(defaultColor); + y += fm.getHeight(); +// x = paintSyntaxLine(currentLine, +// currentLineTokens, +// defaults.styles, this, gfx, x, y); + x = paintSyntaxLine(gfx, currentLine, x, y, + currentLineTokens, + defaults.styles); // Draw characters via input method. if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) { compositionTextPainter.draw(gfx, defaults.lineHighlightColor); } if (defaults.eolMarkers) { gfx.setColor(defaults.eolMarkerColor); - gfx.drawString(".",x,y); - } - } - - - protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker, - int line, Font defaultFont, - Color defaultColor, int x, int y) { - textArea.getLineText(currentLineIndex,currentLine); - currentLineTokens = tokenMarker.markTokens(currentLine, - currentLineIndex); - - paintHighlight(gfx, line, y); - - gfx.setFont(defaultFont); - gfx.setColor(defaultColor); - y += fm.getHeight(); - x = paintSyntaxLine(currentLine, - currentLineTokens, - defaults.styles, this, gfx, x, y); - /* - * Draw characters via input method. - */ - if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) { - compositionTextPainter.draw(gfx, defaults.lineHighlightColor); - } - if (defaults.eolMarkers) { - gfx.setColor(defaults.eolMarkerColor); - gfx.drawString(".",x,y); + gfx.drawString(".", x, y); } } @@ -673,24 +680,28 @@ public class TextAreaPainter extends JComponent implements TabExpander { * @param y The y co-ordinate * @return The x co-ordinate, plus the width of the painted string */ - public int paintSyntaxLine(Segment line, Token tokens, - SyntaxStyle[] styles, - TabExpander expander, Graphics gfx, - int x, int y) { - Font defaultFont = gfx.getFont(); - Color defaultColor = gfx.getColor(); +// public int paintSyntaxLine(Segment line, Token tokens, SyntaxStyle[] styles, +// TabExpander expander, Graphics gfx, +// int x, int y) { + protected int paintSyntaxLine(Graphics gfx, Segment line, int x, int y, + Token tokens, SyntaxStyle[] styles) { +// Font defaultFont = gfx.getFont(); +// Color defaultColor = gfx.getColor(); +// for (byte id = tokens.id; id != Token.END; tokens = tokens.next) { for (;;) { byte id = tokens.id; - if(id == Token.END) + if (id == Token.END) break; int length = tokens.length; if (id == Token.NULL) { - if(!defaultColor.equals(gfx.getColor())) - gfx.setColor(defaultColor); - if(!defaultFont.equals(gfx.getFont())) - gfx.setFont(defaultFont); +// if(!defaultColor.equals(gfx.getColor())) +// gfx.setColor(defaultColor); +// if(!defaultFont.equals(gfx.getFont())) +// gfx.setFont(defaultFont); + gfx.setColor(defaults.fgcolor); + gfx.setFont(defaults.plainFont); } else { //styles[id].setGraphicsFlags(gfx,defaultFont); SyntaxStyle ss = styles[id]; @@ -698,7 +709,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { gfx.setFont(ss.isBold() ? defaults.boldFont : defaults.plainFont); } line.count = length; - x = Utilities.drawTabbedText(line,x,y,gfx,expander,0); + x = Utilities.drawTabbedText(line, x, y, gfx, this, 0); line.offset += length; tokens = tokens.next; @@ -786,16 +797,15 @@ public class TextAreaPainter extends JComponent implements TabExpander { protected void paintBracketHighlight(Graphics gfx, int line, int y) { int position = textArea.getBracketPosition(); - if (position == -1) { - return; + if (position != -1) { + y += fm.getLeading() + fm.getMaxDescent(); + int x = textArea._offsetToX(line, position); + gfx.setColor(defaults.bracketHighlightColor); + // Hack!!! Since there is no fast way to get the character + // from the bracket matching routine, we use ( since all + // brackets probably have the same width anyway + gfx.drawRect(x,y,fm.charWidth('(') - 1, fm.getHeight() - 1); } - y += fm.getLeading() + fm.getMaxDescent(); - int x = textArea._offsetToX(line,position); - gfx.setColor(defaults.bracketHighlightColor); - // Hack!!! Since there is no fast way to get the character - // from the bracket matching routine, we use ( since all - // brackets probably have the same width anyway - gfx.drawRect(x,y,fm.charWidth('(') - 1, fm.getHeight() - 1); } @@ -817,7 +827,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { gfx.setColor(defaults.caretColor); if (textArea.isOverwriteEnabled()) { - gfx.fillRect(caretX,y + height - 1, caretWidth,1); + gfx.fillRect(caretX, y + height - 1, caretWidth,1); } else { // some machines don't like the drawRect for the single diff --git a/app/src/processing/app/syntax/im/CompositionTextPainter.java b/app/src/processing/app/syntax/im/CompositionTextPainter.java index 0084f491f..ae0930a3b 100644 --- a/app/src/processing/app/syntax/im/CompositionTextPainter.java +++ b/app/src/processing/app/syntax/im/CompositionTextPainter.java @@ -8,7 +8,6 @@ import java.awt.Point; import java.awt.font.TextLayout; import processing.app.syntax.JEditTextArea; -import processing.app.syntax.TextAreaPainter; /** * Paint texts from input method. Text via input method are transmitted by @@ -26,15 +25,17 @@ public class CompositionTextPainter { private int composedBeginCaretPosition = 0; private JEditTextArea textArea; + /** * Constructor for painter. - * @param textarea textarea used by PDE. + * @param textArea textarea used by PDE. */ public CompositionTextPainter(JEditTextArea textArea) { this.textArea = textArea; composedTextLayout = null; } + /** * Check the painter has TextLayout. * If a user input via InputMethod, this result will return true. @@ -44,6 +45,7 @@ public class CompositionTextPainter { return (composedTextLayout != null); } + /** * Set TextLayout to the painter. * TextLayout will be created and set by CompositionTextManager. @@ -55,6 +57,7 @@ public class CompositionTextPainter { this.composedTextLayout = composedTextLayout; this.composedBeginCaretPosition = composedStartCaretPosition; } + /** * Invalidate this TextLayout to set null. @@ -66,6 +69,7 @@ public class CompositionTextPainter { //this.composedBeginCaretPosition = textArea.getCaretPosition(); } + /** * Draw text via input method with composed text information. * This method can draw texts with some underlines to illustrate converting characters. @@ -92,6 +96,7 @@ public class CompositionTextPainter { refillComposedArea(fillBackGroundColor, composedLoc.x, composedLoc.y); composedTextLayout.draw((Graphics2D) gfx, composedLoc.x, composedLoc.y); } + /** * Fill color to erase characters drawn by original TextAreaPainter. @@ -109,16 +114,18 @@ public class CompositionTextPainter { int paintWidth = (int) composedTextLayout.getBounds().getWidth(); gfx.fillRect(x, newY, paintWidth, paintHeight); } + private Point getCaretLocation() { - Point loc = new Point(); - TextAreaPainter painter = textArea.getPainter(); - FontMetrics fm = painter.getFontMetrics(); + FontMetrics fm = textArea.getPainter().getFontMetrics(); int offsetY = fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT; int lineIndex = textArea.getCaretLine(); - loc.y = lineIndex * fm.getHeight() + offsetY; +// loc.y = lineIndex * fm.getHeight() + offsetY; int offsetX = composedBeginCaretPosition - textArea.getLineStartOffset(lineIndex); - loc.x = textArea.offsetToX(lineIndex, offsetX); - return loc; +// loc.x = textArea.offsetToX(lineIndex, offsetX); + return new Point(textArea.offsetToX(lineIndex, offsetX), + lineIndex * fm.getHeight() + offsetY); +// Point loc = new Point(); +// return loc; } } diff --git a/todo.txt b/todo.txt index eeb48f8b4..97f748dea 100644 --- a/todo.txt +++ b/todo.txt @@ -18,6 +18,8 @@ X https://github.com/processing/processing/issues/2103 X update with bold version of Source Code Pro X http://www.google.com/fonts#UsePlace:use/Collection:Source+Code+Pro +_ Editor.applyPreferences() -> painter.setFont() removed +_ need to instead update defaults, then run from there cleaning o the first time someone hides a tab, put up a msg explaining what it does From e954e309b233069b154b73afe9e41cc2414bf181 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Mon, 14 Oct 2013 12:11:15 -0400 Subject: [PATCH 167/556] oops, no need to do that --- app/src/processing/app/syntax/TextAreaPainter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index f93b7584e..1c950ce2d 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -428,7 +428,6 @@ public class TextAreaPainter extends JComponent implements TabExpander { */ public void paint(Graphics gfx) { Graphics2D g2 = (Graphics2D) gfx; - defaults.antialias = true; g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, defaults.antialias ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : From 70ce3f6010ab9d3ba1b80c77d10265e5d1cdc81d Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Mon, 14 Oct 2013 13:26:34 -0400 Subject: [PATCH 168/556] add some bulletproofing for tools --- app/src/processing/app/Editor.java | 25 ++++++++++++++----- .../app/contrib/ToolContribution.java | 13 ++++++++++ todo.txt | 10 +++++--- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 4f5a6878b..862efd442 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -942,16 +942,29 @@ public abstract class Editor extends JFrame implements RunnerListener { for (final ToolContribution tool : tools) { String title = tool.getMenuTitle(); - JMenuItem item = new JMenuItem(title); + final JMenuItem item = new JMenuItem(title); item.addActionListener(new ActionListener() { boolean inited; public void actionPerformed(ActionEvent e) { - if (!inited) { - tool.init(Editor.this); - inited = true; + try { + if (!inited) { + tool.init(Editor.this); + // even if an error, don't keep trying to re-init the tool + inited = true; + } + EventQueue.invokeLater(tool); + + } catch (NoSuchMethodError nsme) { + statusError("\"" + tool.getMenuTitle() + "\" " + + "is not compatible with this version of Processing"); + nsme.printStackTrace(); + item.setEnabled(false); // don't you try that again + + } catch (Exception ex) { + statusError("An error occurred inside \"" + tool.getMenuTitle() + "\""); + ex.printStackTrace(); } - EventQueue.invokeLater(tool); } }); //menu.add(item); @@ -988,7 +1001,7 @@ public abstract class Editor extends JFrame implements RunnerListener { item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - SwingUtilities.invokeLater(tool); + EventQueue.invokeLater(tool); } }); menu.add(item); diff --git a/app/src/processing/app/contrib/ToolContribution.java b/app/src/processing/app/contrib/ToolContribution.java index aec572f7c..bccbda1bb 100644 --- a/app/src/processing/app/contrib/ToolContribution.java +++ b/app/src/processing/app/contrib/ToolContribution.java @@ -92,13 +92,26 @@ public class ToolContribution extends LocalContribution implements Tool { } +// Editor editor; // used to send error messages + public void init(Editor editor) { +// try { +// this.editor = editor; tool.init(editor); +// } catch (NoSuchMethodError nsme) { +// editor.statusError(tool.getMenuTitle() + " is not compatible with this version of Processing"); +// nsme.printStackTrace(); +// } } public void run() { +// try { tool.run(); +// } catch (NoSuchMethodError nsme) { +// editor.statusError(tool.getMenuTitle() + " is not compatible with this version of Processing"); +// nsme.printStackTrace(); +// } } diff --git a/todo.txt b/todo.txt index 97f748dea..105065ee0 100644 --- a/todo.txt +++ b/todo.txt @@ -201,8 +201,8 @@ _ import p5 reference into the javadoc _ local web server to run reference from .zip? _ no more gazillion file nastiness _ yahoo search example is out of date (included in the examples? the book?) -_ document the move of the auto format menu -_ in the book(s)? in the reference? +o document the move of the auto format menu +o in the book(s)? in the reference? _ improve documentation of the pdf stuff _ be clearer about the font setup stuff _ fonts by default not working that well? @@ -838,10 +838,12 @@ _ update will update classes from shared in the current folder TOOLS / Auto Format +_ for() loop with nothing inside parens crashes Auto Format +_ https://github.com/processing/processing/issues/2141 _ extra indent found -_ http://code.google.com/p/processing/issues/detail?id=1003 +_ https://github.com/processing/processing/issues/1041 _ Switch block cases not indented -_ http://code.google.com/p/processing/issues/detail?id=1004 +_ https://github.com/processing/processing/issues/1042 _ do a better job of maintaining cursor _ only auto-format a particular section of code _ set the 'tabs' var based on how many spaces on previous line From 38c968ff683578858c504dad8e9aefb45a615327 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Mon, 14 Oct 2013 13:46:44 -0400 Subject: [PATCH 169/556] and... turns out we can't use the status area at that point --- app/src/processing/app/Editor.java | 74 +++++++++++++++++++----------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 862efd442..edea0c699 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -937,38 +937,60 @@ public abstract class Editor extends JFrame implements RunnerListener { } + /** + * Attempt to init or run a Tool from the safety of a try/catch block that + * will report errors to the user. + * @param tool The Tool object to be inited or run + * @param item null to call init(), or the existing JMenuItem for run() + * @return + */ + protected boolean safeTool(Tool tool, JMenuItem item) { + try { + if (item == null) { + tool.init(Editor.this); + } else { + tool.run(); + } + return true; + + } catch (NoSuchMethodError nsme) { + System.out.println("tool is " + tool + " "); + statusError("\"" + tool.getMenuTitle() + "\" " + + "is not compatible with this version of Processing"); + nsme.printStackTrace(); + + } catch (Exception ex) { + statusError("An error occurred inside \"" + tool.getMenuTitle() + "\""); + ex.printStackTrace(); + } + if (item != null) { + item.setEnabled(false); // don't you try that again + } + return false; + } + + protected void addTools(JMenu menu, ArrayList tools) { HashMap toolItems = new HashMap(); for (final ToolContribution tool : tools) { - String title = tool.getMenuTitle(); - final JMenuItem item = new JMenuItem(title); - item.addActionListener(new ActionListener() { - boolean inited; + if (safeTool(tool, null)) { +// tool.init(Editor.this); + + String title = tool.getMenuTitle(); + final JMenuItem item = new JMenuItem(title); + item.addActionListener(new ActionListener() { +// boolean inited; - public void actionPerformed(ActionEvent e) { - try { - if (!inited) { - tool.init(Editor.this); - // even if an error, don't keep trying to re-init the tool - inited = true; - } - EventQueue.invokeLater(tool); - - } catch (NoSuchMethodError nsme) { - statusError("\"" + tool.getMenuTitle() + "\" " + - "is not compatible with this version of Processing"); - nsme.printStackTrace(); - item.setEnabled(false); // don't you try that again - - } catch (Exception ex) { - statusError("An error occurred inside \"" + tool.getMenuTitle() + "\""); - ex.printStackTrace(); + public void actionPerformed(ActionEvent e) { + //EventQueue.invokeLater(tool); + //tool.run(); + safeTool(tool, item); } - } - }); - //menu.add(item); - toolItems.put(title, item); + }); + //menu.add(item); + toolItems.put(title, item); + } } ArrayList toolList = new ArrayList(toolItems.keySet()); From 6387479ec88c05ce77c843fd162793c8fbb3a2c1 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Mon, 14 Oct 2013 14:10:11 -0400 Subject: [PATCH 170/556] more error checking/handling for Modes and Tools --- app/src/processing/app/Base.java | 6 +- app/src/processing/app/Editor.java | 60 ++++++++++++++----- .../app/contrib/ModeContribution.java | 14 ++--- todo.txt | 5 +- 4 files changed, 58 insertions(+), 27 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 6f86dbba5..86ac38538 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2082,7 +2082,7 @@ public class Base { /** * Non-fatal error message with optional stack trace side dish. */ - static public void showWarning(String title, String message, Exception e) { + static public void showWarning(String title, String message, Throwable e) { if (title == null) title = "Warning"; if (commandLine) { @@ -2101,7 +2101,7 @@ public class Base { */ static public void showWarningTiered(String title, String primary, String secondary, - Exception e) { + Throwable e) { if (title == null) title = "Warning"; final String message = primary + "\n" + secondary; @@ -3007,7 +3007,7 @@ public class Base { } - static public void log(String message, Exception e) { + static public void log(String message, Throwable e) { if (DEBUG) { System.out.println(message); e.printStackTrace(); diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index edea0c699..3af0eac95 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -970,26 +970,56 @@ public abstract class Editor extends JFrame implements RunnerListener { } + void addToolItem(final Tool tool, HashMap toolItems) { + String title = tool.getMenuTitle(); + final JMenuItem item = new JMenuItem(title); + item.addActionListener(new ActionListener() { + + public void actionPerformed(ActionEvent e) { + try { + tool.run(); + + } catch (NoSuchMethodError nsme) { + statusError("\"" + tool.getMenuTitle() + "\" is not" + + "compatible with this version of Processing"); + nsme.printStackTrace(); + item.setEnabled(false); + + } catch (Exception ex) { + statusError("An error occurred inside \"" + tool.getMenuTitle() + "\""); + ex.printStackTrace(); + item.setEnabled(false); + } + } + }); + //menu.add(item); + toolItems.put(title, item); + } + + protected void addTools(JMenu menu, ArrayList tools) { HashMap toolItems = new HashMap(); for (final ToolContribution tool : tools) { - if (safeTool(tool, null)) { -// tool.init(Editor.this); - - String title = tool.getMenuTitle(); - final JMenuItem item = new JMenuItem(title); - item.addActionListener(new ActionListener() { -// boolean inited; + try { + tool.init(Editor.this); + // If init() fails, the item won't be added to the menu + addToolItem(tool, toolItems); + + // With the exceptions, we can't call statusError because the window + // isn't completely set up yet. Also not gonna pop up a warning because + // people may still be running different versions of Processing. + // TODO Once the dust settles on 2.x, change this to Base.showError() + // and open the Tools folder instead of showing System.err.println(). + + } catch (NoSuchMethodError nsme) { + System.err.println("\"" + tool.getMenuTitle() + "\" is not " + + "compatible with this version of Processing"); + nsme.printStackTrace(); - public void actionPerformed(ActionEvent e) { - //EventQueue.invokeLater(tool); - //tool.run(); - safeTool(tool, item); - } - }); - //menu.add(item); - toolItems.put(title, item); + } catch (Exception ex) { + System.err.println("An error occurred inside \"" + tool.getMenuTitle() + "\""); + ex.printStackTrace(); } } diff --git a/app/src/processing/app/contrib/ModeContribution.java b/app/src/processing/app/contrib/ModeContribution.java index 18a1b2a4a..9fdac9f0d 100644 --- a/app/src/processing/app/contrib/ModeContribution.java +++ b/app/src/processing/app/contrib/ModeContribution.java @@ -43,19 +43,19 @@ public class ModeContribution extends LocalContribution { String searchName) { try { return new ModeContribution(base, folder, searchName); + } catch (IgnorableException ig) { Base.log(ig.getMessage()); - } catch (Error err) { - // Handles UnsupportedClassVersionError and others - err.printStackTrace(); - } catch (Exception e) { + + } catch (Throwable err) { + // Throwable to catch Exceptions or UnsupportedClassVersionError et al if (searchName == null) { - e.printStackTrace(); + err.printStackTrace(); } else { // For the built-in modes, don't print the exception, just log it // for debugging. This should be impossible for most users to reach, // but it helps us load experimental mode when it's available. - Base.log("ModeContribution.load() failed for " + searchName, e); + Base.log("ModeContribution.load() failed for " + searchName, err); } } return null; @@ -104,7 +104,7 @@ public class ModeContribution extends LocalContribution { contribModes.add(new ModeContribution(base, folder, null)); } catch (IgnorableException ig) { Base.log(ig.getMessage()); - } catch (Exception e) { + } catch (Throwable e) { e.printStackTrace(); } } diff --git a/todo.txt b/todo.txt index 105065ee0..b3f349909 100644 --- a/todo.txt +++ b/todo.txt @@ -15,6 +15,9 @@ X cmd-left is bringing up the text area popup X https://github.com/processing/processing/issues/2103 X still having right-click issues (re-opened) X https://github.com/processing/processing/issues/2103 +X bad tool brings down the environment +X http://code.google.com/p/processing/issues/detail?id=798 +X https://github.com/processing/processing/issues/836 X update with bold version of Source Code Pro X http://www.google.com/fonts#UsePlace:use/Collection:Source+Code+Pro @@ -811,8 +814,6 @@ TOOLS / General _ create default tools folder (just like libraries) _ for tools, maybe don't run on event thread? (makes the gui hang) _ but instead, things that affect gui need to be called w/ invokeLater? -_ bad tool brings down the environment -_ http://code.google.com/p/processing/issues/detail?id=798 _ need a proper means to handle command keys for tools (?) _ http://code.google.com/p/processing/issues/detail?id=44 _ handle native code for tools menu (?) From a3c0fb84b14c01743e6dcd3d646b21c988793f07 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Mon, 14 Oct 2013 14:12:36 -0400 Subject: [PATCH 171/556] not using these anymore --- .../processing/app/tools/ExportExamples.java | 158 ------------------ app/src/processing/app/tools/FixEncoding.java | 109 ------------ 2 files changed, 267 deletions(-) delete mode 100644 app/src/processing/app/tools/ExportExamples.java delete mode 100644 app/src/processing/app/tools/FixEncoding.java diff --git a/app/src/processing/app/tools/ExportExamples.java b/app/src/processing/app/tools/ExportExamples.java deleted file mode 100644 index 65889cbad..000000000 --- a/app/src/processing/app/tools/ExportExamples.java +++ /dev/null @@ -1,158 +0,0 @@ -/* -package processing.app.tools; - -import java.io.*; -//import java.util.HashMap; - -import processing.app.*; -import processing.mode.java.JavaBuild; - -public class ExportExamples implements Tool { - static final String DELETE_TARGET = "export.delete_target_folder"; - static final String SEPARATE_JAR = "export.applet.separate_jar_files"; - -// HashMap errors; - Editor orig; - - // copy the files to processing.org/content/examples with their hierarchy intact - // that won't be checked into svn, even though they were before - -// File webroot; -// File templates; -// File xml; - - Base base; - File[] folders; - File outputFolder; - String examplesPath; - - - public void init(Editor editor) { - orig = editor; - base = editor.getBase(); - Mode mode = editor.getMode(); - folders = mode.getExampleCategoryFolders(); - examplesPath = mode.getExamplesFolder().getAbsolutePath(); - - // Not perfect, but will work for Casey and I - File desktop = new File(System.getProperty("user.home"), "Desktop"); - outputFolder = new File(desktop, "examples"); -// webroot = new File("/Users/fry/coconut/processing.web"); -// templates = new File(webroot, "templates"); - } - - - public void run() { - new Thread(new Runnable() { public void run() { - if (outputFolder.exists()) { - Base.showWarning("Try Again", "Please remove the examples folder from the desktop,\n" + - "because that's where I wanna put things.", null); - return; - } -// errors = new HashMap(); - boolean delete = Preferences.getBoolean(DELETE_TARGET); - Preferences.setBoolean(DELETE_TARGET, false); - boolean separate = Preferences.getBoolean(SEPARATE_JAR); - Preferences.setBoolean(SEPARATE_JAR, true); - - for (File folder : folders) { - if (!folder.getName().equals("Books")) { - handleFolder(folder); - } - } - - Preferences.setBoolean(DELETE_TARGET, delete); - Preferences.setBoolean(SEPARATE_JAR, separate); - orig.statusNotice("Finished exporting examples."); - } }).start(); - -// if (errors.size() > 0) { -// orig.statusError((errors.size() == 1 ? "One sketch" : (errors.size() + " sketches")) + " had errors."); -// } else { -// } -// for (String path : errors.keySet()) { -// System.err.println("Error: " -// } - } - - - public void handleFolder(File folder) { - File pdeFile = new File(folder, folder.getName() + ".pde"); - if (pdeFile.exists()) { - String pdePath = pdeFile.getAbsolutePath(); - Editor editor = base.handleOpen(pdePath); - if (editor != null) { - try { -// System.out.println(pdePath); - if (handle(editor)) { - base.handleClose(editor, false); - try { - Thread.sleep(20); - } catch (InterruptedException e) { } - } - } catch (Exception e) { - e.printStackTrace(); - // errors.put(pdePath, e); - // System.err.println("Error handling " + pdePath); - // e.printStackTrace(); - } - } - } else { // recurse into the folder - //System.out.println(" into " + folder.getAbsolutePath()); - File[] sub = folder.listFiles(); - for (File f : sub) { - if (f.isDirectory()) { - handleFolder(f); - } - } - } - } - - - public boolean handle(Editor editor) throws SketchException, IOException { - Sketch sketch = editor.getSketch(); - File sketchFolder = sketch.getFolder(); - String sketchPath = sketchFolder.getAbsolutePath(); - String uniquePath = sketchPath.substring(examplesPath.length()); - File sketchTarget = new File(outputFolder, uniquePath); - - // copy the PDE files so that they can be pulled in by the generator script -// File[] files = sketchFolder.listFiles(); -// for (File file : files) { -// if (file.getName().endsWith(".pde")) { -// Base.copyFile(file, new File(sketchTarget, file.getName())); -// } -// } - // no need to do this because the source files will be in 'applet' anyway - - // build the applet into this folder - File appletFolder = new File(sketchTarget, "applet"); - JavaBuild build = new JavaBuild(sketch); - boolean result = build.exportApplet(appletFolder); - - // Just one copy of core.jar into the root - File coreTarget = new File(outputFolder, "core.jar"); - File sketchCore = new File(appletFolder, "core.jar"); - if (!coreTarget.exists()) { - Base.copyFile(sketchCore, coreTarget); - } - sketchCore.delete(); - - File loadingTarget = new File(outputFolder, "loading.gif"); - if (!loadingTarget.exists()) { - Base.copyFile(new File(appletFolder, "loading.gif"), loadingTarget); - } - - new File(appletFolder, "index.html").delete(); - new File(appletFolder, "loading.gif").delete(); - new File(appletFolder, sketch.getName() + ".java").delete(); - - return result; - } - - - public String getMenuTitle() { - return "Export Examples"; - } -} -*/ \ No newline at end of file diff --git a/app/src/processing/app/tools/FixEncoding.java b/app/src/processing/app/tools/FixEncoding.java deleted file mode 100644 index e58768ab3..000000000 --- a/app/src/processing/app/tools/FixEncoding.java +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2008-11 Ben Fry and Casey Reas - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, version 2. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package processing.app.tools; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; - -import javax.swing.JOptionPane; - -import processing.app.*; - - -public class FixEncoding implements Tool { - Editor editor; - - - public String getMenuTitle() { - return "Fix Encoding & Reload"; - } - - - public void init(Editor editor) { - this.editor = editor; - } - - - public void run() { - Sketch sketch = editor.getSketch(); - //SketchCode code = sketch.current; - - if (sketch.isModified()) { - int result = - JOptionPane.showConfirmDialog(editor, - "Discard all changes and reload sketch?", - "Fix Encoding & Reload", - JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE); - - if (result == JOptionPane.NO_OPTION) { - return; - } - } - try { - for (int i = 0; i < sketch.getCodeCount(); i++) { - SketchCode code = sketch.getCode(i); - code.setProgram(loadWithLocalEncoding(code.getFile())); - code.setModified(true); // yes, because we want them to save this - } - // Update the currently visible program with its code - editor.setText(sketch.getCurrentCode().getProgram()); - - } catch (IOException e) { - String msg = - "An error occurred while trying to fix the file encoding.\n" + - "Do not attempt to save this sketch as it may overwrite\n" + - "the old version. Use Open to re-open the sketch and try again.\n" + - e.getMessage(); - Base.showWarning("Fix Encoding & Reload", msg, e); - } - } - - - protected String loadWithLocalEncoding(File file) throws IOException { - // FileReader uses the default encoding, which is what we want. - String encoding = System.getProperty("file.encoding"); - if (Base.isMacOS()) { - // Remember that time that Apple decided to change the file encoding - // in later releases of Java? That was really awesome. - if (encoding.equals("UTF-8")) { - // Changing from UTF-8 to UTF-8 isn't going to help much. Argh. - encoding = "MacRoman"; - } - } - FileInputStream fis = new FileInputStream(file); - InputStreamReader isr = new InputStreamReader(fis, encoding); - BufferedReader reader = new BufferedReader(isr); - - StringBuffer buffer = new StringBuffer(); - String line = null; - while ((line = reader.readLine()) != null) { - buffer.append(line); - buffer.append('\n'); - } - reader.close(); - return buffer.toString(); - } -} \ No newline at end of file From a45fbc4fd1cf20fda1fe5f503be6809ca9284a60 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Mon, 14 Oct 2013 16:34:53 -0400 Subject: [PATCH 172/556] more 7u40 retina fixes, removed unused Tool code --- app/src/processing/app/Editor.java | 68 ++++++++++--------- .../app/syntax/PdeTextAreaDefaults.java | 4 +- todo.txt | 34 +++++----- 3 files changed, 55 insertions(+), 51 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 3af0eac95..0d925f6e6 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -937,37 +937,37 @@ public abstract class Editor extends JFrame implements RunnerListener { } - /** - * Attempt to init or run a Tool from the safety of a try/catch block that - * will report errors to the user. - * @param tool The Tool object to be inited or run - * @param item null to call init(), or the existing JMenuItem for run() - * @return - */ - protected boolean safeTool(Tool tool, JMenuItem item) { - try { - if (item == null) { - tool.init(Editor.this); - } else { - tool.run(); - } - return true; - - } catch (NoSuchMethodError nsme) { - System.out.println("tool is " + tool + " "); - statusError("\"" + tool.getMenuTitle() + "\" " + - "is not compatible with this version of Processing"); - nsme.printStackTrace(); - - } catch (Exception ex) { - statusError("An error occurred inside \"" + tool.getMenuTitle() + "\""); - ex.printStackTrace(); - } - if (item != null) { - item.setEnabled(false); // don't you try that again - } - return false; - } +// /** +// * Attempt to init or run a Tool from the safety of a try/catch block that +// * will report errors to the user. +// * @param tool The Tool object to be inited or run +// * @param item null to call init(), or the existing JMenuItem for run() +// * @return +// */ +// protected boolean safeTool(Tool tool, JMenuItem item) { +// try { +// if (item == null) { +// tool.init(Editor.this); +// } else { +// tool.run(); +// } +// return true; +// +// } catch (NoSuchMethodError nsme) { +// System.out.println("tool is " + tool + " "); +// statusError("\"" + tool.getMenuTitle() + "\" " + +// "is not compatible with this version of Processing"); +// nsme.printStackTrace(); +// +// } catch (Exception ex) { +// statusError("An error occurred inside \"" + tool.getMenuTitle() + "\""); +// ex.printStackTrace(); +// } +// if (item != null) { +// item.setEnabled(false); // don't you try that again +// } +// return false; +// } void addToolItem(final Tool tool, HashMap toolItems) { @@ -982,7 +982,8 @@ public abstract class Editor extends JFrame implements RunnerListener { } catch (NoSuchMethodError nsme) { statusError("\"" + tool.getMenuTitle() + "\" is not" + "compatible with this version of Processing"); - nsme.printStackTrace(); + //nsme.printStackTrace(); + Base.log("Incompatible tool found during tool.run()", nsme); item.setEnabled(false); } catch (Exception ex) { @@ -1015,7 +1016,8 @@ public abstract class Editor extends JFrame implements RunnerListener { } catch (NoSuchMethodError nsme) { System.err.println("\"" + tool.getMenuTitle() + "\" is not " + "compatible with this version of Processing"); - nsme.printStackTrace(); + System.err.println("This method no longer exists: " + nsme.getMessage()); + Base.log("Incompatible Tool found during tool.init()", nsme); } catch (Exception ex) { System.err.println("An error occurred inside \"" + tool.getMenuTitle() + "\""); diff --git a/app/src/processing/app/syntax/PdeTextAreaDefaults.java b/app/src/processing/app/syntax/PdeTextAreaDefaults.java index 31b117354..8ab7aae91 100644 --- a/app/src/processing/app/syntax/PdeTextAreaDefaults.java +++ b/app/src/processing/app/syntax/PdeTextAreaDefaults.java @@ -201,8 +201,8 @@ public class PdeTextAreaDefaults extends TextAreaDefaults { int fontSize = Preferences.getInteger("editor.font.size"); plainFont = new Font(fontFamily, Font.PLAIN, fontSize); boldFont = new Font(fontFamily, Font.BOLD, fontSize); - System.out.println("font is " + plainFont.getFamily() + " / " + plainFont.getName() + " / " + plainFont.getFontName() + " / " + plainFont.getPSName()); -// antialias = Preferences.getBoolean("editor.antialias"); +// System.out.println("font is " + plainFont.getFamily() + " / " + plainFont.getName() + " / " + plainFont.getFontName() + " / " + plainFont.getPSName()); + antialias = Preferences.getBoolean("editor.antialias"); styles = new SyntaxStyle[Token.ID_COUNT]; diff --git a/todo.txt b/todo.txt index b3f349909..633d2b58b 100644 --- a/todo.txt +++ b/todo.txt @@ -71,6 +71,7 @@ _ and the command line tools Preferences > Downloads > Command Line Tools _ appbundler will have an NPE if the osx binary isn't built _ also need to have 10.8 version of the SDK (old Xcode won't work) +_ type in the status area is gross on retina displays and 7u40 _ type looks a little feeble on OS X with non-retina machines _ https://github.com/processing/processing/issues/2135 _ type cut off in dialog boxes on OS X retina machines @@ -128,7 +129,7 @@ X remove javafx from the embed X more about optional files: X http://www.oracle.com/technetwork/java/javase/jdk-7-readme-429198.html -7u40 switch +7u40 macosx X make OS X launch from its local JRE X also need to have a central menubar X add the offscreen window hack @@ -138,6 +139,20 @@ o try the bundle on Mac Mini running 10.6 X we become full 64-bit on OS X X meaning that the macosx32 video library goes away X and the preference for launching in 32- or 64-bit mode +X package Java 7u40 version of the app +X docs.oracle.com/javase/7/docs/technotes/guides/jweb/packagingAppsForMac.html +X http://www.intransitione.com/blog/take-java-to-app-store/ +X retina support http://bugs.sun.com/view_bug.do?bug_id=8009754 +_ useful retina digging/findings for Oracle Java +_ http://bulenkov.com/2013/06/23/retina-support-in-oracle-jdk-1-7/ +X 7u40 target release is "late August" +X http://openjdk.java.net/projects/jdk7u/releases/7u40.html +X Contents/Java/Classes folder is added to java.class.path +X so the folder must exist otherwise the ECJ compiler will crash +X once fixed, remove notes from JavaBuild.java +X "Are you sure you want to quit?" when switching modes on Oracle JVM +X default menu bar is still broken +X http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8007267 _ change how export is handled _ remove ability to export cross-platform apps @@ -935,21 +950,8 @@ _ http://code.google.com/p/processing/issues/detail?id=632 DIST / Mac OS X -_ package Java 7u40 version of the app -_ docs.oracle.com/javase/7/docs/technotes/guides/jweb/packagingAppsForMac.html -_ http://www.intransitione.com/blog/take-java-to-app-store/ -X retina support http://bugs.sun.com/view_bug.do?bug_id=8009754 -_ useful retina digging/findings for Oracle Java -_ http://bulenkov.com/2013/06/23/retina-support-in-oracle-jdk-1-7/ -_ 7u40 target release is "late August" -_ http://openjdk.java.net/projects/jdk7u/releases/7u40.html -_ Contents/Java/Classes folder is added to java.class.path -_ so the folder must exist otherwise the ECJ compiler will crash -_ once fixed, remove notes from JavaBuild.java -_ "Are you sure you want to quit?" when switching modes on Oracle JVM -_ default menu bar is still broken -_ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8007267 -_ fixed for 7u60 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8022667 +_ remove default menu bar hack when 7u60 arrives +_ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8022667 _ blank sketch opened even if another opened by double-click _ add a 150 ms or more lag before opening the untitled window (on os x) _ https://github.com/processing/processing/issues/218 From fdc0c3b5185a9475906cb594abda9f3a499feb0f Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Mon, 14 Oct 2013 17:14:29 -0400 Subject: [PATCH 173/556] more font and prefs work, cleanups and more --- app/src/processing/app/Editor.java | 5 +- app/src/processing/app/EditorStatus.java | 6 + .../processing/app/syntax/JEditTextArea.java | 130 +++++++----------- .../app/syntax/PdeTextAreaDefaults.java | 14 +- .../app/syntax/TextAreaDefaults.java | 8 +- .../app/syntax/TextAreaPainter.java | 73 ++++++---- todo.txt | 51 +++---- 7 files changed, 150 insertions(+), 137 deletions(-) diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 0d925f6e6..d3de86914 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -472,8 +472,11 @@ public abstract class Editor extends JFrame implements RunnerListener { * with things in the Preferences window. */ protected void applyPreferences() { + // Update fonts and other items controllable from the prefs + textarea.getPainter().updateAppearance(); + textarea.repaint(); + // All of this code was specific to using an external editor. - // Keeping this around so we can update fonts. /* // // apply the setting for 'use external editor' // boolean external = Preferences.getBoolean("editor.external"); diff --git a/app/src/processing/app/EditorStatus.java b/app/src/processing/app/EditorStatus.java index 361db92d9..4f006d580 100644 --- a/app/src/processing/app/EditorStatus.java +++ b/app/src/processing/app/EditorStatus.java @@ -25,6 +25,7 @@ package processing.app; import java.awt.*; import java.awt.event.*; + import javax.swing.*; @@ -196,6 +197,11 @@ public class EditorStatus extends JPanel { Graphics2D g2 = (Graphics2D) g; if (Toolkit.highResDisplay()) { g2.scale(2, 2); + if (Base.isUsableOracleJava()) { + // Oracle Java looks better with anti-aliasing turned on + g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + } } else { g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); diff --git a/app/src/processing/app/syntax/JEditTextArea.java b/app/src/processing/app/syntax/JEditTextArea.java index 9f46161a8..bc5bb0ed3 100644 --- a/app/src/processing/app/syntax/JEditTextArea.java +++ b/app/src/processing/app/syntax/JEditTextArea.java @@ -131,7 +131,7 @@ public class JEditTextArea extends JComponent // Load the defaults setInputHandler(defaults.inputHandler); setDocument(defaults.document); - editable = defaults.editable; +// editable = defaults.editable; caretVisible = defaults.caretVisible; caretBlinks = defaults.caretBlinks; electricScroll = defaults.electricScroll; @@ -1405,30 +1405,23 @@ public class JEditTextArea extends JComponent * Replaces the selection with the specified text. * @param selectedText The replacement text for the selection */ - public void setSelectedText(String selectedText) - { - if(!editable) - { - throw new InternalError("Text component" - + " read only"); + public void setSelectedText(String selectedText) { + if (!editable) { + throw new InternalError("Text component read only"); } - document.beginCompoundEdit(); - try - { - if(rectSelect) - { + try { + if (rectSelect) { Element map = document.getDefaultRootElement(); - int start = selectionStart - map.getElement(selectionStartLine) - .getStartOffset(); - int end = selectionEnd - map.getElement(selectionEndLine) - .getStartOffset(); + int start = selectionStart - + map.getElement(selectionStartLine).getStartOffset(); + int end = selectionEnd - + map.getElement(selectionEndLine).getStartOffset(); // Certain rectangles satisfy this condition... - if(end < start) - { + if (end < start) { int tmp = end; end = start; start = tmp; @@ -1437,123 +1430,102 @@ public class JEditTextArea extends JComponent int lastNewline = 0; int currNewline = 0; - for(int i = selectionStartLine; i <= selectionEndLine; i++) - { + for (int i = selectionStartLine; i <= selectionEndLine; i++) { Element lineElement = map.getElement(i); int lineStart = lineElement.getStartOffset(); int lineEnd = lineElement.getEndOffset() - 1; int rectStart = Math.min(lineEnd,lineStart + start); - document.remove(rectStart,Math.min(lineEnd - rectStart, - end - start)); + document.remove(rectStart,Math.min(lineEnd - rectStart, end - start)); - if(selectedText == null) - continue; - - currNewline = selectedText.indexOf('\n',lastNewline); - if(currNewline == -1) - currNewline = selectedText.length(); - - document.insertString(rectStart,selectedText - .substring(lastNewline,currNewline),null); - - lastNewline = Math.min(selectedText.length(), - currNewline + 1); + if (selectedText != null) { + currNewline = selectedText.indexOf('\n', lastNewline); + if (currNewline == -1) { + currNewline = selectedText.length(); + } + document.insertString(rectStart, selectedText.substring(lastNewline, currNewline), null); + lastNewline = Math.min(selectedText.length(), currNewline + 1); + } } - if(selectedText != null && - currNewline != selectedText.length()) - { - int offset = map.getElement(selectionEndLine) - .getEndOffset() - 1; - document.insertString(offset,"\n",null); - document.insertString(offset + 1,selectedText - .substring(currNewline + 1),null); + if (selectedText != null && + currNewline != selectedText.length()) { + int offset = map.getElement(selectionEndLine).getEndOffset() - 1; + document.insertString(offset, "\n", null); + document.insertString(offset + 1,selectedText.substring(currNewline + 1), null); + } + } else { + document.remove(selectionStart, selectionEnd - selectionStart); + if (selectedText != null) { + document.insertString(selectionStart, selectedText,null); } } - else - { - document.remove(selectionStart, - selectionEnd - selectionStart); - if(selectedText != null) - { - document.insertString(selectionStart, - selectedText,null); - } - } - } - catch(BadLocationException bl) - { + } catch(BadLocationException bl) { bl.printStackTrace(); - throw new InternalError("Cannot replace" - + " selection"); - } - // No matter what happends... stops us from leaving document - // in a bad state - finally - { + throw new InternalError("Cannot replace selection"); + + } finally { + // No matter what happens... stops us from leaving document in a bad state document.endCompoundEdit(); } - setCaretPosition(selectionEnd); } + /** * Returns true if this text area is editable, false otherwise. */ - public final boolean isEditable() - { + public final boolean isEditable() { return editable; } + /** * Sets if this component is editable. * @param editable True if this text area should be editable, * false otherwise */ - public final void setEditable(boolean editable) - { + public final void setEditable(boolean editable) { this.editable = editable; } + /** * Returns the right click popup menu. */ - public final JPopupMenu getRightClickPopup() - { + public final JPopupMenu getRightClickPopup() { return popup; } + /** * Sets the right click popup menu. * @param popup The popup */ - //public final void setRightClickPopup(EditPopupMenu popup) - public final void setRightClickPopup(JPopupMenu popup) - { + public final void setRightClickPopup(JPopupMenu popup) { this.popup = popup; } /** - * Returns the `magic' caret position. This can be used to preserve + * Returns the 'magic' caret position. This can be used to preserve * the column position when moving up and down lines. */ - public final int getMagicCaretPosition() - { + public final int getMagicCaretPosition() { return magicCaret; } + /** - * Sets the `magic' caret position. This can be used to preserve + * Sets the 'magic' caret position. This can be used to preserve * the column position when moving up and down lines. * @param magicCaret The magic caret position */ - public final void setMagicCaretPosition(int magicCaret) - { + public final void setMagicCaretPosition(int magicCaret) { this.magicCaret = magicCaret; } + /** * Similar to setSelectedText(), but overstrikes the * appropriate number of characters if overwrite mode is enabled. @@ -1993,7 +1965,7 @@ public class JEditTextArea extends JComponent protected boolean caretVisible; protected boolean blink; - protected boolean editable; + protected boolean editable = true; protected int firstLine; protected int visibleLines; diff --git a/app/src/processing/app/syntax/PdeTextAreaDefaults.java b/app/src/processing/app/syntax/PdeTextAreaDefaults.java index 8ab7aae91..33427f864 100644 --- a/app/src/processing/app/syntax/PdeTextAreaDefaults.java +++ b/app/src/processing/app/syntax/PdeTextAreaDefaults.java @@ -24,8 +24,6 @@ package processing.app.syntax; -import java.awt.Font; - import processing.app.*; @@ -182,7 +180,7 @@ public class PdeTextAreaDefaults extends TextAreaDefaults { inputHandler.addKeyBinding(mod + "+ENTER", InputHandler.REPEAT); document = new SyntaxDocument(); - editable = true; +// editable = true; // Set to 0 for revision 0215 because it causes strange jumps // http://code.google.com/p/processing/issues/detail?id=1055 @@ -196,13 +194,16 @@ public class PdeTextAreaDefaults extends TextAreaDefaults { // http://code.google.com/p/processing/issues/detail?id=1275 rows = 5; - //font = Preferences.getFont("editor.font"); + /* String fontFamily = Preferences.get("editor.font.family"); int fontSize = Preferences.getInteger("editor.font.size"); plainFont = new Font(fontFamily, Font.PLAIN, fontSize); boldFont = new Font(fontFamily, Font.BOLD, fontSize); -// System.out.println("font is " + plainFont.getFamily() + " / " + plainFont.getName() + " / " + plainFont.getFontName() + " / " + plainFont.getPSName()); antialias = Preferences.getBoolean("editor.antialias"); + */ + + fgcolor = mode.getColor("editor.fgcolor"); + bgcolor = mode.getColor("editor.bgcolor"); styles = new SyntaxStyle[Token.ID_COUNT]; @@ -229,9 +230,6 @@ public class PdeTextAreaDefaults extends TextAreaDefaults { // area that's not in use by the text (replaced with tildes) styles[Token.INVALID] = mode.getStyle("invalid"); - fgcolor = mode.getColor("editor.fgcolor"); - bgcolor = mode.getColor("editor.bgcolor"); - caretColor = mode.getColor("editor.caret.color"); selectionColor = mode.getColor("editor.selection.color"); lineHighlight = mode.getBoolean("editor.linehighlight"); diff --git a/app/src/processing/app/syntax/TextAreaDefaults.java b/app/src/processing/app/syntax/TextAreaDefaults.java index 746685c03..1c9edb7cd 100644 --- a/app/src/processing/app/syntax/TextAreaDefaults.java +++ b/app/src/processing/app/syntax/TextAreaDefaults.java @@ -20,15 +20,17 @@ import java.awt.*; public class TextAreaDefaults { public InputHandler inputHandler; public SyntaxDocument document; - public boolean editable; +// public boolean editable; public boolean caretVisible; public boolean caretBlinks; public boolean blockCaret; public int electricScroll; + // default/preferred number of rows/cols public int cols; public int rows; + public SyntaxStyle[] styles; public Color caretColor; public Color selectionColor; @@ -40,9 +42,11 @@ public class TextAreaDefaults { public boolean eolMarkers; public boolean paintInvalid; + /* public Font plainFont; public Font boldFont; + public boolean antialias; + */ public Color fgcolor; public Color bgcolor; - public boolean antialias; } diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index 1c950ce2d..758e48933 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -18,6 +18,7 @@ import javax.swing.ToolTipManager; import javax.swing.text.*; import javax.swing.JComponent; +import processing.app.Preferences; import processing.app.syntax.im.CompositionTextPainter; @@ -52,6 +53,13 @@ public class TextAreaPainter extends JComponent implements TabExpander { // protected int cols; // protected int rows; + // moved from TextAreaDefaults + private Font plainFont; + private Font boldFont; + private boolean antialias; +// private Color fgcolor; +// private Color bgcolor; + protected int tabSize; protected FontMetrics fm; @@ -70,7 +78,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { this.defaults = defaults; setAutoscrolls(true); -// setDoubleBuffered(true); // breaks retina with 7u40 +// setDoubleBuffered(true); setOpaque(true); ToolTipManager.sharedInstance().registerComponent(this); @@ -85,7 +93,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { //// System.out.println("defaults font is " + defaults.font); // setForeground(defaults.fgcolor); // setBackground(defaults.bgcolor); - applyDefaults(); + updateAppearance(); // blockCaret = defaults.blockCaret; // styles = defaults.styles; @@ -104,12 +112,25 @@ public class TextAreaPainter extends JComponent implements TabExpander { } - public void applyDefaults() { - // unfortunately probably can't just do setDefaults() since things aren't quite set up - setFont(defaults.plainFont); -// System.out.println("defaults font is " + defaults.font); - setForeground(defaults.fgcolor); - setBackground(defaults.bgcolor); + public void updateAppearance() { +// // unfortunately probably can't just do setDefaults() since things aren't quite set up +// setFont(defaults.plainFont); +//// System.out.println("defaults font is " + defaults.font); +// setForeground(defaults.fgcolor); +// setBackground(defaults.bgcolor); + + String fontFamily = Preferences.get("editor.font.family"); + int fontSize = Preferences.getInteger("editor.font.size"); + plainFont = new Font(fontFamily, Font.PLAIN, fontSize); + boldFont = new Font(fontFamily, Font.BOLD, fontSize); + antialias = Preferences.getBoolean("editor.antialias"); + + // moved from setFont() override (never quite comfortable w/ that override) + fm = super.getFontMetrics(plainFont); + textArea.recalculateVisibleLines(); + +// fgcolor = mode.getColor("editor.fgcolor"); +// bgcolor = mode.getColor("editor.bgcolor"); } @@ -404,22 +425,23 @@ public class TextAreaPainter extends JComponent implements TabExpander { public FontMetrics getFontMetrics(SyntaxStyle style) { - return getFontMetrics(style.isBold() ? - defaults.boldFont : defaults.plainFont); +// return getFontMetrics(style.isBold() ? +// defaults.boldFont : defaults.plainFont); + return getFontMetrics(style.isBold() ? boldFont : plainFont); } - /** - * Sets the font for this component. This is overridden to update the - * cached font metrics and to recalculate which lines are visible. - * @param font The font - */ - public void setFont(Font font) { -// new Exception().printStackTrace(System.out); - super.setFont(font); - fm = super.getFontMetrics(font); - textArea.recalculateVisibleLines(); - } +// /** +// * Sets the font for this component. This is overridden to update the +// * cached font metrics and to recalculate which lines are visible. +// * @param font The font +// */ +// public void setFont(Font font) { +//// new Exception().printStackTrace(System.out); +// super.setFont(font); +// fm = super.getFontMetrics(font); +// textArea.recalculateVisibleLines(); +// } /** @@ -429,9 +451,12 @@ public class TextAreaPainter extends JComponent implements TabExpander { public void paint(Graphics gfx) { Graphics2D g2 = (Graphics2D) gfx; g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - defaults.antialias ? + antialias ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + + g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); tabSize = fm.charWidth(' ') * ((Integer)textArea.getDocument().getProperty(PlainDocument.tabSizeAttribute)).intValue(); @@ -700,12 +725,12 @@ public class TextAreaPainter extends JComponent implements TabExpander { // if(!defaultFont.equals(gfx.getFont())) // gfx.setFont(defaultFont); gfx.setColor(defaults.fgcolor); - gfx.setFont(defaults.plainFont); + gfx.setFont(plainFont); } else { //styles[id].setGraphicsFlags(gfx,defaultFont); SyntaxStyle ss = styles[id]; gfx.setColor(ss.getColor()); - gfx.setFont(ss.isBold() ? defaults.boldFont : defaults.plainFont); + gfx.setFont(ss.isBold() ? boldFont : plainFont); } line.count = length; x = Utilities.drawTabbedText(line, x, y, gfx, this, 0); diff --git a/todo.txt b/todo.txt index 633d2b58b..f05de8980 100644 --- a/todo.txt +++ b/todo.txt @@ -21,8 +21,12 @@ X https://github.com/processing/processing/issues/836 X update with bold version of Source Code Pro X http://www.google.com/fonts#UsePlace:use/Collection:Source+Code+Pro +_ does editor line status work? _ Editor.applyPreferences() -> painter.setFont() removed _ need to instead update defaults, then run from there +_ then call repaint() on the text area? or invalidate()? or the painter? +_ make sure font family change is working +_ make sure fonts can actually update size/etc in prefs cleaning o the first time someone hides a tab, put up a msg explaining what it does @@ -65,21 +69,16 @@ X basically done in more recent releases X fix file selection dialog with MovieMaker X copied from PApplet, but not importing PApplet -X add appbundler.jar, otherwise folks have to include Xcode -_ if they want to build appbundler, they'll need Xcode -_ and the command line tools Preferences > Downloads > Command Line Tools -_ appbundler will have an NPE if the osx binary isn't built -_ also need to have 10.8 version of the SDK (old Xcode won't work) - -_ type in the status area is gross on retina displays and 7u40 -_ type looks a little feeble on OS X with non-retina machines -_ https://github.com/processing/processing/issues/2135 -_ type cut off in dialog boxes on OS X retina machines -_ https://github.com/processing/processing/issues/2116 -_ dialog box icon is fuzzy on OS X retina machines -_ https://github.com/processing/processing/issues/2117 -_ solution might be our own dialog boxes (see 'dialogs' section) - +fonts and prefs +_ slightly gray background +_ spacing problem with large sizes (on retina?) +_ control text size in console +o why aren't prefs from theme.txt showing up in preferences.txt? hrm +o or rather, why can't they be overridden? +X because theme.txt data is a different animal / that's part of the point +_ should fonts at least be in prefs.txt? +_ http://code.google.com/p/processing/issues/detail?id=226 +_ https://github.com/processing/processing/issues/265 _ console font in EditorConsole _ Font font = Preferences.getFont("console.font"); _ fix console font on Windows and Linux with 7u40 @@ -92,6 +91,15 @@ _ but might be a problem on Linux _ where the JRE is often replaced _ and where the font is needed most +_ type in the status area is gross on retina displays and 7u40 +_ type looks a little feeble on OS X with non-retina machines +_ https://github.com/processing/processing/issues/2135 +_ type cut off in dialog boxes on OS X retina machines +_ https://github.com/processing/processing/issues/2116 +_ dialog box icon is fuzzy on OS X retina machines +_ https://github.com/processing/processing/issues/2117 +_ solution might be our own dialog boxes (see 'dialogs' section) + build X remove video library for other platforms in download X update apple.jar file with new version @@ -153,6 +161,11 @@ X once fixed, remove notes from JavaBuild.java X "Are you sure you want to quit?" when switching modes on Oracle JVM X default menu bar is still broken X http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8007267 +X add appbundler.jar, otherwise folks have to include Xcode +_ if they want to build appbundler, they'll need Xcode +_ and the command line tools Preferences > Downloads > Command Line Tools +_ appbundler will have an NPE if the osx binary isn't built +_ also need to have 10.8 version of the SDK (old Xcode won't work) _ change how export is handled _ remove ability to export cross-platform apps @@ -741,14 +754,6 @@ _ move styling to separate constants that are more accessible PDE / Preferences -_ control text size in console -o why aren't prefs from theme.txt showing up in preferences.txt? hrm -o or rather, why can't they be overridden? -X because theme.txt data is a different animal / that's part of the point -_ should fonts at least be in prefs.txt? -_ http://code.google.com/p/processing/issues/detail?id=226 -_ https://github.com/processing/processing/issues/265 - _ the .macosx, .linux, etc prefs should be stripped _ only use them on first load, and merge into preferences.txt _ Editor.applyFrame() may not have a valid 'editor' object to work with From acda315d6514231bf66d27485544858a8436b649 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 15 Oct 2013 13:00:36 -0400 Subject: [PATCH 174/556] move args around in line with the others --- app/src/processing/app/syntax/TextAreaPainter.java | 8 ++++---- todo.txt | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index 758e48933..5bac9d2fa 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -480,7 +480,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { int x = textArea.getHorizontalOffset(); for (int line = firstInvalid; line <= lastInvalid; line++) { - paintLine(gfx, tokenMarker, line, x); + paintLine(gfx, line, x, tokenMarker); } if (tokenMarker != null && tokenMarker.isNextLineRequested()) { @@ -517,7 +517,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { pageFormat.getImageableY() - firstLine*lineHeight); printing = true; for (int line = firstLine; line < firstLine + linesPerPage; line++) { - paintLine(g2, tokenMarker, line, 0); + paintLine(g2, line, 0, tokenMarker); } printing = false; return PAGE_EXISTS; @@ -618,8 +618,8 @@ public class TextAreaPainter extends JComponent implements TabExpander { } - protected void paintLine(Graphics gfx, TokenMarker tokenMarker, - int line, int x) { + protected void paintLine(Graphics gfx, int line, int x, + TokenMarker tokenMarker) { // Font defaultFont = getFont(); // Color defaultColor = getForeground(); diff --git a/todo.txt b/todo.txt index f05de8980..dc4dc1bac 100644 --- a/todo.txt +++ b/todo.txt @@ -21,6 +21,7 @@ X https://github.com/processing/processing/issues/836 X update with bold version of Source Code Pro X http://www.google.com/fonts#UsePlace:use/Collection:Source+Code+Pro +X instead of semibold, which wouldn't correctly connect to the other fonts _ does editor line status work? _ Editor.applyPreferences() -> painter.setFont() removed _ need to instead update defaults, then run from there From 0cfd53520e1324882e15b7bc0376daf72fe5e57f Mon Sep 17 00:00:00 2001 From: KiwiStrongis Date: Tue, 15 Oct 2013 17:57:54 -0400 Subject: [PATCH 175/556] added PMatrix.preApply( PMatrix) to resolve Issue #2145 --- core/src/processing/core/PMatrix.java | 2 ++ core/src/processing/core/PMatrix2D.java | 9 +++++++++ core/src/processing/core/PMatrix3D.java | 9 +++++++++ 3 files changed, 20 insertions(+) diff --git a/core/src/processing/core/PMatrix.java b/core/src/processing/core/PMatrix.java index 53f7fa54b..2670eb5ce 100644 --- a/core/src/processing/core/PMatrix.java +++ b/core/src/processing/core/PMatrix.java @@ -97,6 +97,8 @@ public interface PMatrix { /** * Apply another matrix to the left of this one. */ + public void preApply(PMatrix left); + public void preApply(PMatrix2D left); public void preApply(PMatrix3D left); diff --git a/core/src/processing/core/PMatrix2D.java b/core/src/processing/core/PMatrix2D.java index d5616b58d..1ee6b0a88 100644 --- a/core/src/processing/core/PMatrix2D.java +++ b/core/src/processing/core/PMatrix2D.java @@ -247,6 +247,15 @@ public class PMatrix2D implements PMatrix { /** * Apply another matrix to the left of this one. */ + public void preApply(PMatrix source) { + if (source instanceof PMatrix2D) { + preApply((PMatrix2D) source); + } else if (source instanceof PMatrix3D) { + preApply((PMatrix3D) source); + } + } + + public void preApply(PMatrix2D left) { preApply(left.m00, left.m01, left.m02, left.m10, left.m11, left.m12); diff --git a/core/src/processing/core/PMatrix3D.java b/core/src/processing/core/PMatrix3D.java index deeb23b45..f75cb1227 100644 --- a/core/src/processing/core/PMatrix3D.java +++ b/core/src/processing/core/PMatrix3D.java @@ -369,6 +369,15 @@ public final class PMatrix3D implements PMatrix /*, PConstants*/ { /** * Apply another matrix to the left of this one. */ + public void preApply(PMatrix source) { + if (source instanceof PMatrix2D) { + preApply((PMatrix2D) source); + } else if (source instanceof PMatrix3D) { + preApply((PMatrix3D) source); + } + } + + public void preApply(PMatrix3D left) { preApply(left.m00, left.m01, left.m02, left.m03, left.m10, left.m11, left.m12, left.m13, From 42c6a8d0711154cec15008d016fb3b53e0db20fe Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 15 Oct 2013 19:36:32 -0400 Subject: [PATCH 176/556] fix character width issues, also allow run from Eclipse --- app/src/processing/app/Base.java | 51 ++++++++++++------- .../app/syntax/TextAreaPainter.java | 31 ++++++++--- 2 files changed, 58 insertions(+), 24 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 86ac38538..4145c18ad 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2350,24 +2350,39 @@ public class Base { String path = Base.class.getProtectionDomain().getCodeSource().getLocation().getPath(); // Path may have URL encoding, so remove it String decodedPath = PApplet.urlDecode(path); - // The .jar file will be in the lib folder - File jarFolder = new File(decodedPath).getParentFile(); - if (jarFolder.getName().equals("lib")) { - // The main Processing installation directory. - // This works for Windows, Linux, and Apple's Java 6 on OS X. - processingRoot = jarFolder.getParentFile(); - } else if (Base.isMacOS()) { - // This works for Java 7 on OS X. The 'lib' folder is not part of the - // classpath on OS X, and adding it creates more problems than it's - // worth. - processingRoot = jarFolder; - } - if (processingRoot == null || !processingRoot.exists()) { - // Try working directory instead (user.dir, different from user.home) - System.err.println("Could not find lib folder via " + - jarFolder.getAbsolutePath() + - ", switching to user.dir"); - processingRoot = new File(System.getProperty("user.dir")); + + //if (decodedPath.contains(PApplet.platformNames[PApplet.platform] + System.out.println("path is " + decodedPath); + if (decodedPath.contains("/app/bin")) { + if (Base.isMacOS()) { + processingRoot = + new File(path, "../../build/macosx/work/Processing.app/Contents/Java"); + } else if (Base.isWindows()) { + processingRoot = new File(path, "../../build/windows/work"); + } else if (Base.isLinux()) { + processingRoot = new File(path, "../../build/linux/work"); + } + } else { + // The .jar file will be in the lib folder + File jarFolder = new File(decodedPath).getParentFile(); + if (jarFolder.getName().equals("lib")) { + // The main Processing installation directory. + // This works for Windows, Linux, and Apple's Java 6 on OS X. + processingRoot = jarFolder.getParentFile(); + } else if (Base.isMacOS()) { + // This works for Java 7 on OS X. The 'lib' folder is not part of the + // classpath on OS X, and adding it creates more problems than it's + // worth. + processingRoot = jarFolder; + + } + if (processingRoot == null || !processingRoot.exists()) { + // Try working directory instead (user.dir, different from user.home) + System.err.println("Could not find lib folder via " + + jarFolder.getAbsolutePath() + + ", switching to user.dir"); + processingRoot = new File(System.getProperty("user.dir")); + } } } /* diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index 5bac9d2fa..749d98828 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -642,13 +642,21 @@ public class TextAreaPainter extends JComponent implements TabExpander { if (!printing) { paintHighlight(gfx,line,y); } - textArea.getLineText(line,currentLine); + textArea.getLineText(line, currentLine); +// gfx.setFont(plainFont); // gfx.setFont(defaultFont); // gfx.setColor(defaultColor); y += fm.getHeight(); - x = Utilities.drawTabbedText(currentLine, x, y, gfx, this, 0); + // doesn't respect fixed width like it should +// x = Utilities.drawTabbedText(currentLine, x, y, gfx, this, 0); + int w = fm.charWidth(' '); + for (int i = 0; i < currentLine.count; i++) { + gfx.drawChars(currentLine.array, currentLine.offset+i, 1, x, y); + x += w; + } + // Draw characters via input method. if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) { @@ -669,6 +677,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { textArea.getLineText(currentLineIndex, currentLine); currentLineTokens = tokenMarker.markTokens(currentLine, currentLineIndex); +// gfx.setFont(plainFont); paintHighlight(gfx, line, y); // gfx.setFont(defaultFont); @@ -681,7 +690,8 @@ public class TextAreaPainter extends JComponent implements TabExpander { currentLineTokens, defaults.styles); // Draw characters via input method. - if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) { + if (compositionTextPainter != null && + compositionTextPainter.hasComposedTextLayout()) { compositionTextPainter.draw(gfx, defaults.lineHighlightColor); } if (defaults.eolMarkers) { @@ -708,7 +718,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { // TabExpander expander, Graphics gfx, // int x, int y) { protected int paintSyntaxLine(Graphics gfx, Segment line, int x, int y, - Token tokens, SyntaxStyle[] styles) { + Token tokens, SyntaxStyle[] styles) { // Font defaultFont = gfx.getFont(); // Color defaultColor = gfx.getColor(); @@ -732,8 +742,17 @@ public class TextAreaPainter extends JComponent implements TabExpander { gfx.setColor(ss.getColor()); gfx.setFont(ss.isBold() ? boldFont : plainFont); } - line.count = length; - x = Utilities.drawTabbedText(line, x, y, gfx, this, 0); + line.count = length; // huh? suspicious + // doesn't respect mono metrics, insists on spacing w/ fractional or something +// x = Utilities.drawTabbedText(line, x, y, gfx, this, 0); +// gfx.drawChars(line.array, line.offset, line.count, x, y); + int w = fm.charWidth(' '); + for (int i = 0; i < line.count; i++) { + gfx.drawChars(line.array, line.offset+i, 1, x, y); + x += w; + } + //x += fm.charsWidth(line.array, line.offset, line.count); + //x += fm.charWidth(' ') * line.count; line.offset += length; tokens = tokens.next; From 0c8cc53eb84147d990469753b5562917fe442c0d Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 15 Oct 2013 22:22:43 -0400 Subject: [PATCH 177/556] fix console font, also reset on default font --- app/src/processing/app/Base.java | 2 - app/src/processing/app/Editor.java | 2 + app/src/processing/app/EditorConsole.java | 15 +- app/src/processing/app/Preferences.java | 42 ++++-- .../app/syntax/TextAreaPainter.java | 12 +- build/shared/lib/preferences.txt | 4 +- todo.txt | 139 +++++++++--------- 7 files changed, 128 insertions(+), 88 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 4145c18ad..051bc9c1d 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2351,8 +2351,6 @@ public class Base { // Path may have URL encoding, so remove it String decodedPath = PApplet.urlDecode(path); - //if (decodedPath.contains(PApplet.platformNames[PApplet.platform] - System.out.println("path is " + decodedPath); if (decodedPath.contains("/app/bin")) { if (Base.isMacOS()) { processingRoot = diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index d3de86914..3463555e0 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -476,6 +476,8 @@ public abstract class Editor extends JFrame implements RunnerListener { textarea.getPainter().updateAppearance(); textarea.repaint(); + console.updateAppearance(); + // All of this code was specific to using an external editor. /* // // apply the setting for 'use external editor' diff --git a/app/src/processing/app/EditorConsole.java b/app/src/processing/app/EditorConsole.java index 18b582cc4..6ad9eb709 100644 --- a/app/src/processing/app/EditorConsole.java +++ b/app/src/processing/app/EditorConsole.java @@ -164,6 +164,20 @@ public class EditorConsole extends JScrollPane { } + /** + * Update the font family and sizes based on the Preferences window. + */ + protected void updateAppearance() { + String fontFamily = Preferences.get("editor.font.family"); + int fontSize = Preferences.getInteger("console.font.size"); + StyleConstants.setFontFamily(stdStyle, fontFamily); + StyleConstants.setFontSize(stdStyle, fontSize); + StyleConstants.setFontFamily(errStyle, fontFamily); + StyleConstants.setFontSize(errStyle, fontSize); + clear(); // otherwise we'll have mixed fonts + } + + /** * Change coloring, fonts, etc in response to a mode change. */ @@ -176,7 +190,6 @@ public class EditorConsole extends JScrollPane { consoleDoc.setParagraphAttributes(0, 0, standard, true); Font font = Preferences.getFont("console.font"); - //Font font = Toolkit.getMonoFont(size, style); // build styles for different types of console output Color bgColor = mode.getColor("console.color"); diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 594072e1c..332fe1fc1 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -115,6 +115,7 @@ public class Preferences { JCheckBox checkUpdatesBox; //JTextField fontSizeField; JComboBox fontSizeField; + JComboBox consoleSizeField; JCheckBox inputMethodBox; JCheckBox autoAssociateBox; @@ -336,31 +337,41 @@ public class Preferences { top += d.height + GUI_BETWEEN; - // Editor font size [ ] + // Editor font size [ 12 ] Console font size [ 10 ] Container box = Box.createHorizontalBox(); + label = new JLabel("Editor font size: "); box.add(label); //fontSizeField = new JTextField(4); fontSizeField = new JComboBox(FONT_SIZES); fontSizeField.setEditable(true); box.add(fontSizeField); - label = new JLabel(" (requires restart of Processing)"); +// label = new JLabel(" (requires restart of Processing)"); +// box.add(label); + box.add(Box.createHorizontalStrut(GUI_BETWEEN)); + + label = new JLabel("Console font size: "); box.add(label); + consoleSizeField = new JComboBox(FONT_SIZES); + consoleSizeField.setEditable(true); + box.add(consoleSizeField); + pain.add(box); d = box.getPreferredSize(); box.setBounds(left, top, d.width, d.height); - Font editorFont = Preferences.getFont("editor.font"); +// Font editorFont = Preferences.getFont("editor.font"); //fontSizeField.setText(String.valueOf(editorFont.getSize())); - fontSizeField.setSelectedItem(editorFont.getSize()); +// fontSizeField.setSelectedItem(editorFont.getSize()); + fontSizeField.setSelectedItem(Preferences.getFont("editor.font.size")); top += d.height + GUI_BETWEEN; // [ ] Use smooth text in editor window - editorAntialiasBox = - new JCheckBox("Use smooth text in editor window " + - "(requires restart of Processing)"); + editorAntialiasBox = new JCheckBox("Use smooth text in editor window"); +// new JCheckBox("Use smooth text in editor window " + +// "(requires restart of Processing)"); pain.add(editorAntialiasBox); d = editorAntialiasBox.getPreferredSize(); // adding +10 because ubuntu + jre 1.5 truncating items @@ -751,9 +762,6 @@ public class Preferences { // Replace with Integer version selection = Integer.parseInt((String) selection); } - //Integer newSize = (Integer) selection; - //Integer newSize = Integer.valueOf(selection); - //System.out.println("setting size to " + selection + " " + selection.getClass()); set("editor.font.size", String.valueOf(selection)); } catch (NumberFormatException e) { @@ -761,6 +769,19 @@ public class Preferences { fontSizeField.setSelectedItem(getInteger("editor.font.size")); } + try { + Object selection = consoleSizeField.getSelectedItem(); + if (selection instanceof String) { + // Replace with Integer version + selection = Integer.parseInt((String) selection); + } + set("console.font.size", String.valueOf(selection)); + + } catch (NumberFormatException e) { + Base.log("Ignoring invalid font size " + consoleSizeField); //$NON-NLS-1$ + consoleSizeField.setSelectedItem(getInteger("console.font.size")); + } + setBoolean("editor.input_method_support", inputMethodBox.isSelected()); //$NON-NLS-1$ if (autoAssociateBox != null) { @@ -817,6 +838,7 @@ public class Preferences { }).start(); fontSizeField.setSelectedItem(getInteger("editor.font.size")); + consoleSizeField.setSelectedItem(getInteger("console.font.size")); memoryOverrideBox. setSelected(getBoolean("run.options.memory")); //$NON-NLS-1$ diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index 749d98828..34ee50056 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -116,14 +116,22 @@ public class TextAreaPainter extends JComponent implements TabExpander { // // unfortunately probably can't just do setDefaults() since things aren't quite set up // setFont(defaults.plainFont); //// System.out.println("defaults font is " + defaults.font); -// setForeground(defaults.fgcolor); -// setBackground(defaults.bgcolor); + setForeground(defaults.fgcolor); + setBackground(defaults.bgcolor); String fontFamily = Preferences.get("editor.font.family"); int fontSize = Preferences.getInteger("editor.font.size"); plainFont = new Font(fontFamily, Font.PLAIN, fontSize); + if (!fontFamily.equals(plainFont.getFamily())) { + System.err.println("Primary font not available, resetting to monospaced"); + fontFamily = "Monospaced"; + Preferences.set("editor.font.family", fontFamily); + plainFont = new Font(fontFamily, Font.PLAIN, fontSize); + } boldFont = new Font(fontFamily, Font.BOLD, fontSize); antialias = Preferences.getBoolean("editor.antialias"); +// System.out.println(plainFont.getFamily()); +// System.out.println(plainFont); // moved from setFont() override (never quite comfortable w/ that override) fm = super.getFontMetrics(plainFont); diff --git a/build/shared/lib/preferences.txt b/build/shared/lib/preferences.txt index cb8918f2a..a2310249d 100644 --- a/build/shared/lib/preferences.txt +++ b/build/shared/lib/preferences.txt @@ -107,7 +107,6 @@ editor.window.height.min.windows = 530 #editor.font.macosx = Monaco,plain,10 # trying for a built-in, consistent monospace for 2.0 #editor.font = processing.mono,plain,12 - editor.font.family = Source Code Pro editor.font.size = 12 @@ -168,7 +167,8 @@ toolbar.hide.image = false # font choice and size for the console #console.font = Monospaced,plain,11 #console.font.macosx = Monaco,plain,10 -console.font = processing.mono,plain,12 +#console.font = processing.mono,plain,12 +console.font.size = 12 # number of lines to show by default console.lines = 4 diff --git a/todo.txt b/todo.txt index dc4dc1bac..8de12e48e 100644 --- a/todo.txt +++ b/todo.txt @@ -19,20 +19,55 @@ X bad tool brings down the environment X http://code.google.com/p/processing/issues/detail?id=798 X https://github.com/processing/processing/issues/836 -X update with bold version of Source Code Pro -X http://www.google.com/fonts#UsePlace:use/Collection:Source+Code+Pro -X instead of semibold, which wouldn't correctly connect to the other fonts -_ does editor line status work? -_ Editor.applyPreferences() -> painter.setFont() removed -_ need to instead update defaults, then run from there -_ then call repaint() on the text area? or invalidate()? or the painter? -_ make sure font family change is working -_ make sure fonts can actually update size/etc in prefs - cleaning o the first time someone hides a tab, put up a msg explaining what it does o "don't warn me about this anymore" X removed this feature a while back +o document the move of the auto format menu +o in the book(s)? in the reference? +o jer: opengl2 tutorial +o jer: android tutorial +o probably later: examples into categories based on difficulty +o add ratings/difficult level to examples online and in the pde +o go through examples, figure out how to do many on the site w/ js instead +X import p5 reference into the javadoc + +fonts/prefs +X update with bold version of Source Code Pro +X http://www.google.com/fonts#UsePlace:use/Collection:Source+Code+Pro +X instead of semibold, which wouldn't correctly connect to the other fonts +_ does editor line status work? +X Editor.applyPreferences() -> painter.setFont() removed +X need to instead update defaults, then run from there +X then call repaint() on the text area? or invalidate()? or the painter? +X make sure font family change is working +X make sure fonts can actually update size/etc in prefs +X slightly gray background +X bgcolor wasn't getting set (since fgcolor was set elsewhere) +X spacing problem with large sizes (on retina?) +X not just retina, was problem with non-mono text from Java +X control text size in console +o why aren't prefs from theme.txt showing up in preferences.txt? hrm +o or rather, why can't they be overridden? +X because theme.txt data is a different animal / that's part of the point +X should fonts at least be in prefs.txt? +_ http://code.google.com/p/processing/issues/detail?id=226 +_ https://github.com/processing/processing/issues/265 +X console font in EditorConsole +X Font font = Preferences.getFont("console.font"); +o fix console font on Windows and Linux with 7u40 +X couldn't reproduce, but shouldn't be a problem with the rewrite +X the message area text also looks ugly.. can we fix? +X add pref to select PDE font (so that CJKV languages work better) +_ https://github.com/processing/processing/issues/2078 +X should we embed the PDE font into the JRE? +X this would allow it to show up in the menus, etc +_ but might be a problem on Linux +_ where the JRE is often replaced +_ and where the font is needed most +_ make note of this on the platforms page +X type in the status area is gross on retina displays and 7u40 +X no longer require restart of Processing when changing the font serial X closing several bugs because no longer relevant @@ -70,33 +105,12 @@ X basically done in more recent releases X fix file selection dialog with MovieMaker X copied from PApplet, but not importing PApplet -fonts and prefs -_ slightly gray background -_ spacing problem with large sizes (on retina?) -_ control text size in console -o why aren't prefs from theme.txt showing up in preferences.txt? hrm -o or rather, why can't they be overridden? -X because theme.txt data is a different animal / that's part of the point -_ should fonts at least be in prefs.txt? -_ http://code.google.com/p/processing/issues/detail?id=226 -_ https://github.com/processing/processing/issues/265 -_ console font in EditorConsole -_ Font font = Preferences.getFont("console.font"); -_ fix console font on Windows and Linux with 7u40 -_ the message area text also looks ugly.. can we fix? -_ add pref to select PDE font (so that CJKV languages work better) -_ https://github.com/processing/processing/issues/2078 -_ should we embed the PDE font into the JRE? -_ this would allow it to show up in the menus, etc -_ but might be a problem on Linux -_ where the JRE is often replaced -_ and where the font is needed most - -_ type in the status area is gross on retina displays and 7u40 _ type looks a little feeble on OS X with non-retina machines _ https://github.com/processing/processing/issues/2135 +_ should we increase the size of the mode dropdown? _ type cut off in dialog boxes on OS X retina machines _ https://github.com/processing/processing/issues/2116 +_ add spaces to the end of the text? _ dialog box icon is fuzzy on OS X retina machines _ https://github.com/processing/processing/issues/2117 _ solution might be our own dialog boxes (see 'dialogs' section) @@ -129,14 +143,23 @@ X upload javadoc updates X need to require JDK 7u40 to be installed on OS X X remove JAVA_HOME requirement from build.xml X what's needed on OS X? just the JDK 7u40? - -jre work X remove Java FX from OS X build X remove Java FX during Linux builds X remove Java FX during Windows builds X remove javafx from the embed X more about optional files: X http://www.oracle.com/technetwork/java/javase/jdk-7-readme-429198.html +_ update github instructions +_ only JRE needed at this point +_ switched over to Java 7 +_ https://github.com/processing/processing/wiki/Build-Instructions +_ "unable to locate tools.jar" (Windows) can be ignored +_ JAVA_HOME warnings from Ant can also be ignored +_ updates for macosx instructions +_ to build appbundler, you'll need Xcode +_ and the command line tools Preferences > Downloads > Command Line Tools +_ appbundler will have an NPE if the osx binary isn't built +_ also need to have 10.8 version of the SDK (old Xcode won't work) 7u40 macosx X make OS X launch from its local JRE @@ -152,8 +175,8 @@ X package Java 7u40 version of the app X docs.oracle.com/javase/7/docs/technotes/guides/jweb/packagingAppsForMac.html X http://www.intransitione.com/blog/take-java-to-app-store/ X retina support http://bugs.sun.com/view_bug.do?bug_id=8009754 -_ useful retina digging/findings for Oracle Java -_ http://bulenkov.com/2013/06/23/retina-support-in-oracle-jdk-1-7/ +X useful retina digging/findings for Oracle Java +X http://bulenkov.com/2013/06/23/retina-support-in-oracle-jdk-1-7/ X 7u40 target release is "late August" X http://openjdk.java.net/projects/jdk7u/releases/7u40.html X Contents/Java/Classes folder is added to java.class.path @@ -163,40 +186,22 @@ X "Are you sure you want to quit?" when switching modes on Oracle JVM X default menu bar is still broken X http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8007267 X add appbundler.jar, otherwise folks have to include Xcode -_ if they want to build appbundler, they'll need Xcode -_ and the command line tools Preferences > Downloads > Command Line Tools -_ appbundler will have an NPE if the osx binary isn't built -_ also need to have 10.8 version of the SDK (old Xcode won't work) +_ try installing 10.7.3 on Mac Mini and check whether things run +_ make sure it's only running on 64-bit machines? +export _ change how export is handled _ remove ability to export cross-platform apps _ add ability to embed the current JRE _ the case for the embedded JRE _ https://github.com/processing/processing/issues/2104 _ change app stub in OS X exported application -_ try installing 10.7.3 on Mac Mini and check whether things run -_ make sure it's only running on 64-bit machines? -_ update github instructions -_ only JRE needed at this point -_ switched over to Java 7 -_ https://github.com/processing/processing/wiki/Build-Instructions -_ "unable to locate tools.jar" (Windows) can be ignored -_ JAVA_HOME warnings from Ant can also be ignored - -_ appbundler improvements -_ don't re-copy JRE into work folder if already exists -_ implement a splash screen - _ change Windows export to use launch4j instead of the launcher.cpp file _ actually call ant from inside p5? high _ move old Google Code SVN back to processing.org _ then cull out the old branches/tags from the Github repo -_ figure out Android build w/o javac so we can remove tools.jar and javac -_ also to the p5 repo with just a JRE -_ remove initRequirements from Base (no longer need JDI) -_ move this into Android mode? _ "String index out of range" error _ https://github.com/processing/processing/issues/1940 _ freeze after splash screen on OS X (looks like core.jar in the path) @@ -220,33 +225,22 @@ _ remove video for macosx32 from the repo permanently _ remove the prefs for 32/64-bit from Preferences _ remove the extra OS X cruft inside Runner.java + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . -DOC / Mess +DOC / Misc _ find in reference for copy() (on image) tries to open PVector.copy() _ might need disambiguation pages? _ if a reference page is missing, throws a bunch of exceptions _ i.e. PVector.copy() not in the reference -_ import p5 reference into the javadoc _ local web server to run reference from .zip? _ no more gazillion file nastiness _ yahoo search example is out of date (included in the examples? the book?) -o document the move of the auto format menu -o in the book(s)? in the reference? _ improve documentation of the pdf stuff _ be clearer about the font setup stuff _ fonts by default not working that well? -_ jer: opengl2 tutorial -_ jer: android tutorial -_ probably later: examples into categories based on difficulty -_ add ratings/difficult level to examples online and in the pde -_ go through examples, figure out how to do many on the site w/ js instead - - -DOC / Write Me - _ stop() to shut down a sketch (but not quit/close window) _ actually pause/resume _ MIN_FLOAT, MAX_FLOAT, also the difference from the Java functions @@ -956,6 +950,9 @@ _ http://code.google.com/p/processing/issues/detail?id=632 DIST / Mac OS X +_ appbundler improvements +_ don't re-copy JRE into work folder if already exists +_ implement a splash screen _ remove default menu bar hack when 7u60 arrives _ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8022667 _ blank sketch opened even if another opened by double-click From e9030acc9fb2f15dd2d3df05632e78bfd3115446 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 15 Oct 2013 22:53:40 -0400 Subject: [PATCH 178/556] better message --- app/src/processing/app/syntax/TextAreaPainter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index 34ee50056..e143438f6 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -123,7 +123,7 @@ public class TextAreaPainter extends JComponent implements TabExpander { int fontSize = Preferences.getInteger("editor.font.size"); plainFont = new Font(fontFamily, Font.PLAIN, fontSize); if (!fontFamily.equals(plainFont.getFamily())) { - System.err.println("Primary font not available, resetting to monospaced"); + System.err.println(fontFamily + " not available, resetting to monospaced"); fontFamily = "Monospaced"; Preferences.set("editor.font.family", fontFamily); plainFont = new Font(fontFamily, Font.PLAIN, fontSize); From 4e9e24bad38b85a3ccf8c5a429fabc1f36cbf36d Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 15 Oct 2013 23:03:36 -0400 Subject: [PATCH 179/556] increase a few fonts a bit, antialias on the status --- app/src/processing/app/EditorLineStatus.java | 8 +++++++- app/src/processing/app/syntax/TextAreaPainter.java | 7 ++++--- build/shared/lib/theme.txt | 4 ++-- todo.txt | 1 + 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/src/processing/app/EditorLineStatus.java b/app/src/processing/app/EditorLineStatus.java index dc1a842fb..ff7a1bacd 100644 --- a/app/src/processing/app/EditorLineStatus.java +++ b/app/src/processing/app/EditorLineStatus.java @@ -23,6 +23,7 @@ package processing.app; import java.awt.*; + import javax.swing.*; @@ -87,6 +88,10 @@ public class EditorLineStatus extends JComponent { public void paintComponent(Graphics g) { + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setColor(background); Dimension size = getSize(); g.fillRect(0, 0, size.width, size.height); @@ -94,7 +99,8 @@ public class EditorLineStatus extends JComponent { g.setFont(font); g.setColor(foreground); int baseline = (high + g.getFontMetrics().getAscent()) / 2; - g.drawString(text, 6, baseline); + // With 7u40 (or Source Code Sans?) things seem to be edged up a bit + g.drawString(text, 6, baseline - 1); } diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java index e143438f6..88d338ba8 100644 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ b/app/src/processing/app/syntax/TextAreaPainter.java @@ -462,9 +462,10 @@ public class TextAreaPainter extends JComponent implements TabExpander { antialias ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); - - g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, - RenderingHints.VALUE_FRACTIONALMETRICS_ON); + + // no effect, one way or the other +// g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, +// RenderingHints.VALUE_FRACTIONALMETRICS_ON); tabSize = fm.charWidth(' ') * ((Integer)textArea.getDocument().getProperty(PlainDocument.tabSizeAttribute)).intValue(); diff --git a/build/shared/lib/theme.txt b/build/shared/lib/theme.txt index ab31f72e8..95bcad988 100755 --- a/build/shared/lib/theme.txt +++ b/build/shared/lib/theme.txt @@ -38,7 +38,7 @@ buttons.status.font = processing.sans,plain,13 buttons.status.color = #ffffff # MODE SELECTOR -mode.button.font = processing.sans,plain,12 +mode.button.font = processing.sans,plain,13 # outline color of the mode button mode.button.color = #ffffff @@ -46,7 +46,7 @@ mode.button.color = #ffffff # The editor line number status bar at the bottom of the screen linestatus.color = #ffffff linestatus.bgcolor = #29333d -linestatus.font = processing.sans,plain,12 +linestatus.font = processing.sans,plain,13 linestatus.height = 20 diff --git a/todo.txt b/todo.txt index 8de12e48e..efe63fc95 100644 --- a/todo.txt +++ b/todo.txt @@ -149,6 +149,7 @@ X remove Java FX during Windows builds X remove javafx from the embed X more about optional files: X http://www.oracle.com/technetwork/java/javase/jdk-7-readme-429198.html +_ exclude 'fonts' folder from build (since it's going into the JRE) _ update github instructions _ only JRE needed at this point _ switched over to Java 7 From 6bea584648cb4841d718bb62f11dd9bfdc2587af Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Tue, 15 Oct 2013 23:17:31 -0400 Subject: [PATCH 180/556] cleaning up a bit --- todo.txt | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/todo.txt b/todo.txt index efe63fc95..74f0babcf 100644 --- a/todo.txt +++ b/todo.txt @@ -31,12 +31,16 @@ o probably later: examples into categories based on difficulty o add ratings/difficult level to examples online and in the pde o go through examples, figure out how to do many on the site w/ js instead X import p5 reference into the javadoc +o freeze after splash screen on OS X (looks like core.jar in the path) +X https://github.com/processing/processing/issues/1872 +X can't really fix this fonts/prefs X update with bold version of Source Code Pro X http://www.google.com/fonts#UsePlace:use/Collection:Source+Code+Pro X instead of semibold, which wouldn't correctly connect to the other fonts -_ does editor line status work? +X does editor line status work? +X not sure what this one was, but added anti-aliasing to the status X Editor.applyPreferences() -> painter.setFont() removed X need to instead update defaults, then run from there X then call repaint() on the text area? or invalidate()? or the painter? @@ -51,15 +55,15 @@ o why aren't prefs from theme.txt showing up in preferences.txt? hrm o or rather, why can't they be overridden? X because theme.txt data is a different animal / that's part of the point X should fonts at least be in prefs.txt? -_ http://code.google.com/p/processing/issues/detail?id=226 -_ https://github.com/processing/processing/issues/265 +X http://code.google.com/p/processing/issues/detail?id=226 +X https://github.com/processing/processing/issues/265 X console font in EditorConsole X Font font = Preferences.getFont("console.font"); o fix console font on Windows and Linux with 7u40 X couldn't reproduce, but shouldn't be a problem with the rewrite X the message area text also looks ugly.. can we fix? X add pref to select PDE font (so that CJKV languages work better) -_ https://github.com/processing/processing/issues/2078 +X https://github.com/processing/processing/issues/2078 X should we embed the PDE font into the JRE? X this would allow it to show up in the menus, etc _ but might be a problem on Linux @@ -200,16 +204,6 @@ _ change app stub in OS X exported application _ change Windows export to use launch4j instead of the launcher.cpp file _ actually call ant from inside p5? -high -_ move old Google Code SVN back to processing.org -_ then cull out the old branches/tags from the Github repo -_ "String index out of range" error -_ https://github.com/processing/processing/issues/1940 -_ freeze after splash screen on OS X (looks like core.jar in the path) -_ https://github.com/processing/processing/issues/1872 -_ look through all isPopupTrigger() code -_ make sure both press/release are implemented - medium _ use platformDelete() to remove untitled sketches? _ change to using platformDelete() instead of Base.removeDir() where possible @@ -220,6 +214,12 @@ _ "new Library()" constructor needs to go back to private _ add .bat file to lib on windows so that we can get better debugging info _ changing modes brings the PDE back on the second screen _ the Find window (also the save windows) also have the same problem +_ move old Google Code SVN back to processing.org +_ then cull out the old branches/tags from the Github repo +_ "String index out of range" error +_ https://github.com/processing/processing/issues/1940 +_ look through all isPopupTrigger() code +_ make sure both press/release are implemented post 2.1 cleaning _ remove video for macosx32 from the repo permanently From 626bc8f70cc080623c0e1ea97ee44a1b956a863e Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 15 Oct 2013 23:41:42 -0400 Subject: [PATCH 181/556] removed first,last vertex and count from InGeometry, implementing vertex codes --- .../processing/opengl/PGraphicsOpenGL.java | 1114 +++++++++++------ core/src/processing/opengl/PShader.java | 17 +- core/src/processing/opengl/PShapeOpenGL.java | 274 +++- 3 files changed, 978 insertions(+), 427 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 3cd19c3cd..3b0cdace3 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -531,7 +531,7 @@ public class PGraphicsOpenGL extends PGraphics { final static protected float POINT_ACCURACY_FACTOR = 10.0f; /** Used in quad point tessellation. */ - final protected float[][] QUAD_POINT_SIGNS = + final static protected float[][] QUAD_POINT_SIGNS = { {-1, +1}, {-1, -1}, {+1, -1}, {+1, +1} }; /** To get data from OpenGL. */ @@ -559,8 +559,8 @@ public class PGraphicsOpenGL extends PGraphics { viewport = PGL.allocateIntBuffer(4); - inGeo = newInGeometry(IMMEDIATE); - tessGeo = newTessGeometry(IMMEDIATE); + inGeo = newInGeometry(this, IMMEDIATE); + tessGeo = newTessGeometry(this, IMMEDIATE); texCache = newTexCache(); initialized = false; @@ -2067,7 +2067,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void beginShape(int kind) { shape = kind; - curveVertexCount = 0; +// curveVertexCount = 0; inGeo.clear(); breakShape = true; @@ -2196,17 +2196,16 @@ public class PGraphicsOpenGL extends PGraphics { u, v, scolor, sweight, ambientColor, specularColor, emissiveColor, shininess, - vertexCode()); + VERTEX, vertexBreak()); } - protected int vertexCode() { - int code = VERTEX; + protected boolean vertexBreak() { if (breakShape) { - code = BREAK; breakShape = false; + return true; } - return code; + return false; } @@ -2249,12 +2248,13 @@ public class PGraphicsOpenGL extends PGraphics { tessellator.setInGeometry(inGeo); tessellator.setTessGeometry(tessGeo); tessellator.setFill(fill || textureImage != null); + tessellator.setTexCache(texCache, textureImage0, textureImage); tessellator.setStroke(stroke); tessellator.setStrokeColor(strokeColor); tessellator.setStrokeWeight(strokeWeight); tessellator.setStrokeCap(strokeCap); tessellator.setStrokeJoin(strokeJoin); - tessellator.setTexCache(texCache, textureImage0, textureImage); + tessellator.setRenderer(pgCurrent); tessellator.setTransform(modelview); tessellator.set3D(is3D()); @@ -2279,8 +2279,6 @@ public class PGraphicsOpenGL extends PGraphics { if (normalMode == NORMAL_MODE_AUTO) inGeo.calcTriangleStripNormals(); tessellator.tessellateTriangleStrip(); } else if (shape == QUAD || shape == QUADS) { - - if (stroke && defaultEdges) inGeo.addQuadsEdges(); if (normalMode == NORMAL_MODE_AUTO) inGeo.calcQuadsNormals(); tessellator.tessellateQuads(); @@ -2793,9 +2791,7 @@ public class PGraphicsOpenGL extends PGraphics { inGeo.setNormal(normalX, normalY, normalZ); inGeo.addBezierVertex(x2, y2, z2, x3, y3, z3, - x4, y4, z4, - fill, stroke, bezierDetail, vertexCode(), shape); - + x4, y4, z4, vertexBreak()); } @@ -2821,8 +2817,7 @@ public class PGraphicsOpenGL extends PGraphics { ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); inGeo.addQuadraticVertex(cx, cy, cz, - x3, y3, z3, - fill, stroke, bezierDetail, vertexCode(), shape); + x3, y3, z3, vertexBreak()); } @@ -2847,8 +2842,7 @@ public class PGraphicsOpenGL extends PGraphics { inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); - inGeo.addCurveVertex(x, y, z, - fill, stroke, curveDetail, vertexCode(), shape); + inGeo.addCurveVertex(x, y, z, vertexBreak()); } @@ -2939,7 +2933,21 @@ public class PGraphicsOpenGL extends PGraphics { x2, y2, 0, x3, y3, 0, x4, y4, 0, - fill, stroke); + stroke); + endShape(); + } + + + @Override + protected void rectImpl(float x1, float y1, float x2, float y2, + float tl, float tr, float br, float bl) { + beginShape(POLYGON); + defaultEdges = false; + normalMode = NORMAL_MODE_SHAPE; + inGeo.setMaterial(fillColor, strokeColor, strokeWeight, + ambientColor, specularColor, emissiveColor, shininess); + inGeo.setNormal(normalX, normalY, normalZ); + inGeo.addRect(x1, y1, x2, y2, tl, tr, br, bl, stroke); endShape(); } @@ -2948,8 +2956,6 @@ public class PGraphicsOpenGL extends PGraphics { // ELLIPSE - // public void ellipseMode(int mode) - @Override public void ellipseImpl(float a, float b, float c, float d) { @@ -2964,9 +2970,6 @@ public class PGraphicsOpenGL extends PGraphics { } - // public void ellipse(float a, float b, float c, float d) - - @Override protected void arcImpl(float x, float y, float w, float h, float start, float stop, int mode) { @@ -3008,6 +3011,10 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void sphere(float r) { + if ((sphereDetailU < 3) || (sphereDetailV < 2)) { + sphereDetail(30); + } + beginShape(TRIANGLES); defaultEdges = false; normalMode = NORMAL_MODE_VERTEX; @@ -6627,13 +6634,16 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void loadUniforms() { transformMatLoc = getUniformLoc("transform"); - if (transformMatLoc == -1) transformMatLoc = getUniformLoc("transformMatrix"); + if (transformMatLoc == -1) + transformMatLoc = getUniformLoc("transformMatrix"); modelviewMatLoc = getUniformLoc("modelview"); - if (modelviewMatLoc == -1) modelviewMatLoc = getUniformLoc("modelviewMatrix"); + if (modelviewMatLoc == -1) + modelviewMatLoc = getUniformLoc("modelviewMatrix"); projectionMatLoc = getUniformLoc("projection"); - if (projectionMatLoc == -1) projectionMatLoc = getUniformLoc("projectionMatrix"); + if (projectionMatLoc == -1) + projectionMatLoc = getUniformLoc("projectionMatrix"); viewportLoc = getUniformLoc("viewport"); bufferLoc = getUniformLoc("buffer"); @@ -6644,7 +6654,7 @@ public class PGraphicsOpenGL extends PGraphics { if (-1 < bufferLoc) { pgl.requestFBOLayer(); pgl.activeTexture(PGL.TEXTURE0 + bufferUnit); - pgCurrent.unbindFrontTexture(); + pg.unbindFrontTexture(); pgl.activeTexture(PGL.TEXTURE0); } @@ -6655,25 +6665,25 @@ public class PGraphicsOpenGL extends PGraphics { protected void setCommonUniforms() { if (-1 < transformMatLoc) { - pgCurrent.updateGLProjmodelview(); - setUniformMatrix(transformMatLoc, pgCurrent.glProjmodelview); + pg.updateGLProjmodelview(); + setUniformMatrix(transformMatLoc, pg.glProjmodelview); } if (-1 < modelviewMatLoc) { - pgCurrent.updateGLModelview(); - setUniformMatrix(modelviewMatLoc, pgCurrent.glModelview); + pg.updateGLModelview(); + setUniformMatrix(modelviewMatLoc, pg.glModelview); } if (-1 < projectionMatLoc) { - pgCurrent.updateGLProjection(); - setUniformMatrix(projectionMatLoc, pgCurrent.glProjection); + pg.updateGLProjection(); + setUniformMatrix(projectionMatLoc, pg.glProjection); } if (-1 < viewportLoc) { - float x = pgCurrent.viewport.get(0); - float y = pgCurrent.viewport.get(1); - float w = pgCurrent.viewport.get(2); - float h = pgCurrent.viewport.get(3); + float x = pg.viewport.get(0); + float y = pg.viewport.get(1); + float w = pg.viewport.get(2); + float h = pg.viewport.get(3); setUniformValue(viewportLoc, x, y, w, h); } @@ -6681,7 +6691,7 @@ public class PGraphicsOpenGL extends PGraphics { bufferUnit = super.getLastTexUnit() + 1; setUniformValue(bufferLoc, bufferUnit); pgl.activeTexture(PGL.TEXTURE0 + bufferUnit); - pgCurrent.bindFrontTexture(); + pg.bindFrontTexture(); } else { bufferUnit = -1; } @@ -6967,7 +6977,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void bind() { super.bind(); - if (pgCurrent == null) { + if (pg == null) { setRenderer(PGraphicsOpenGL.pgCurrent); loadAttributes(); loadUniforms(); @@ -6980,8 +6990,8 @@ public class PGraphicsOpenGL extends PGraphics { if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc); if (-1 < normalMatLoc) { - pgCurrent.updateGLNormal(); - setUniformMatrix(normalMatLoc, pgCurrent.glNormal); + pg.updateGLNormal(); + setUniformMatrix(normalMatLoc, pg.glNormal); } if (-1 < ambientLoc) pgl.enableVertexAttribArray(ambientLoc); @@ -6989,17 +6999,17 @@ public class PGraphicsOpenGL extends PGraphics { if (-1 < emissiveLoc) pgl.enableVertexAttribArray(emissiveLoc); if (-1 < shininessLoc) pgl.enableVertexAttribArray(shininessLoc); - int count = pgCurrent.lightCount; + int count = pg.lightCount; setUniformValue(lightCountLoc, count); if (0 < count) { - setUniformVector(lightPositionLoc, pgCurrent.lightPosition, 4, count); - setUniformVector(lightNormalLoc, pgCurrent.lightNormal, 3, count); - setUniformVector(lightAmbientLoc, pgCurrent.lightAmbient, 3, count); - setUniformVector(lightDiffuseLoc, pgCurrent.lightDiffuse, 3, count); - setUniformVector(lightSpecularLoc, pgCurrent.lightSpecular, 3, count); - setUniformVector(lightFalloffLoc, pgCurrent.lightFalloffCoefficients, + setUniformVector(lightPositionLoc, pg.lightPosition, 4, count); + setUniformVector(lightNormalLoc, pg.lightNormal, 3, count); + setUniformVector(lightAmbientLoc, pg.lightAmbient, 3, count); + setUniformVector(lightDiffuseLoc, pg.lightDiffuse, 3, count); + setUniformVector(lightSpecularLoc, pg.lightSpecular, 3, count); + setUniformVector(lightFalloffLoc, pg.lightFalloffCoefficients, 3, count); - setUniformVector(lightSpotLoc, pgCurrent.lightSpotParameters, 2, count); + setUniformVector(lightSpotLoc, pg.lightSpotParameters, 2, count); } } @@ -7086,7 +7096,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void bind() { super.bind(); - if (pgCurrent == null) { + if (pg == null) { setRenderer(PGraphicsOpenGL.pgCurrent); loadAttributes(); loadUniforms(); @@ -7096,14 +7106,14 @@ public class PGraphicsOpenGL extends PGraphics { if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc); if (-1 < directionLoc) pgl.enableVertexAttribArray(directionLoc); - if (pgCurrent.getHint(ENABLE_STROKE_PERSPECTIVE) && - pgCurrent.nonOrthoProjection()) { + if (pg.getHint(ENABLE_STROKE_PERSPECTIVE) && + pg.nonOrthoProjection()) { setUniformValue(perspectiveLoc, 1); } else { setUniformValue(perspectiveLoc, 0); } - if (pgCurrent.getHint(DISABLE_OPTIMIZED_STROKE)) { + if (pg.getHint(DISABLE_OPTIMIZED_STROKE)) { setUniformValue(scaleLoc, 1.0f, 1.0f, 1.0f); } else { float f = PGL.STROKE_DISPLACEMENT; @@ -7184,7 +7194,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void bind() { super.bind(); - if (pgCurrent == null) { + if (pg == null) { setRenderer(PGraphicsOpenGL.pgCurrent); loadAttributes(); loadUniforms(); @@ -7194,8 +7204,8 @@ public class PGraphicsOpenGL extends PGraphics { if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc); if (-1 < offsetLoc) pgl.enableVertexAttribArray(offsetLoc); - if (pgCurrent.getHint(ENABLE_STROKE_PERSPECTIVE) && - pgCurrent.nonOrthoProjection()) { + if (pg.getHint(ENABLE_STROKE_PERSPECTIVE) && + pg.nonOrthoProjection()) { setUniformValue(perspectiveLoc, 1); } else { setUniformValue(perspectiveLoc, 0); @@ -7232,24 +7242,24 @@ public class PGraphicsOpenGL extends PGraphics { // Input (raw) and Tessellated geometry, tessellator. - protected InGeometry newInGeometry(int mode) { - return new InGeometry(mode); + static protected InGeometry newInGeometry(PGraphicsOpenGL pg, int mode) { + return new InGeometry(pg, mode); } - protected TessGeometry newTessGeometry(int mode) { - return new TessGeometry(mode); + static protected TessGeometry newTessGeometry(PGraphicsOpenGL pg, int mode) { + return new TessGeometry(pg, mode); } - protected TexCache newTexCache() { + static protected TexCache newTexCache() { return new TexCache(); } // Holds an array of textures and the range of vertex // indices each texture applies to. - protected class TexCache { + static protected class TexCache { int size; PImage[] textures; int[] firstIndex; @@ -7367,7 +7377,7 @@ public class PGraphicsOpenGL extends PGraphics { // Stores the offsets and counts of indices and vertices // to render a piece of geometry that doesn't fit in a single // glDrawElements() call. - protected class IndexCache { + static protected class IndexCache { int size; int[] indexCount; int[] indexOffset; @@ -7472,23 +7482,14 @@ public class PGraphicsOpenGL extends PGraphics { // Holds the input vertices: xyz coordinates, fill/tint color, // normal, texture coordinates and stroke color and weight. - protected class InGeometry { + static protected class InGeometry { + PGraphicsOpenGL pg; int renderMode; + int vertexCount; + int codeCount; int edgeCount; - // Range of vertices that will be processed by the - // tessellator. They can be used in combination with the - // edges array to have the tessellator using only a specific - // range of vertices to generate fill geometry, while the - // line geometry will be read from the edge vertices, which - // could be completely different. - int firstVertex; - int lastVertex; - - int firstEdge; - int lastEdge; - float[] vertices; int[] colors; float[] normals; @@ -7496,8 +7497,11 @@ public class PGraphicsOpenGL extends PGraphics { int[] strokeColors; float[] strokeWeights; - // lines + // codes + int[] codes; boolean[] breaks; + + // Stroke edges int[][] edges; // Material properties @@ -7516,7 +7520,8 @@ public class PGraphicsOpenGL extends PGraphics { float shininessFactor; float normalX, normalY, normalZ; - InGeometry(int mode) { + InGeometry(PGraphicsOpenGL pg, int mode) { + this.pg = pg; renderMode = mode; allocate(); } @@ -7526,12 +7531,13 @@ public class PGraphicsOpenGL extends PGraphics { // Allocate/dispose void clear() { - vertexCount = firstVertex = lastVertex = 0; - edgeCount = firstEdge = lastEdge = 0; + vertexCount = 0; + codeCount = 0; + edgeCount = 0; } void clearEdges() { - edgeCount = firstEdge = lastEdge = 0; + edgeCount = 0; } void allocate() { @@ -7569,6 +7575,14 @@ public class PGraphicsOpenGL extends PGraphics { } } + void codeCheck() { + if (codeCount == codes.length) { + int newLen = codeCount << 1; + + expandCodes(newLen); + } + } + void edgeCheck() { if (edgeCount == edges.length) { int newLen = edgeCount << 1; @@ -7607,17 +7621,17 @@ public class PGraphicsOpenGL extends PGraphics { int getNumEdgeClosures() { int count = 0; - for (int i = firstEdge; i <= lastEdge; i++) { + for (int i = 0; i < edgeCount; i++) { if (edges[i][2] == EDGE_CLOSE) count++; } return count; } int getNumEdgeVertices(boolean bevel) { - int segVert = lastEdge - firstEdge + 1; + int segVert = edgeCount; int bevVert = 0; if (bevel) { - for (int i = firstEdge; i <= lastEdge; i++) { + for (int i = 0; i < edgeCount; i++) { int[] edge = edges[i]; if (edge[2] == EDGE_MIDDLE || edge[2] == EDGE_START) bevVert++; if (edge[2] == EDGE_CLOSE) segVert--; @@ -7629,10 +7643,10 @@ public class PGraphicsOpenGL extends PGraphics { } int getNumEdgeIndices(boolean bevel) { - int segInd = lastEdge - firstEdge + 1; + int segInd = edgeCount; int bevInd = 0; if (bevel) { - for (int i = firstEdge; i <= lastEdge; i++) { + for (int i = 0; i < edgeCount; i++) { int[] edge = edges[i]; if (edge[2] == EDGE_MIDDLE || edge[2] == EDGE_START) bevInd++; if (edge[2] == EDGE_CLOSE) segInd--; @@ -7738,6 +7752,12 @@ public class PGraphicsOpenGL extends PGraphics { shininess = temp; } + void expandCodes(int n) { + int temp[] = new int[n]; + PApplet.arrayCopy(codes, 0, temp, 0, codeCount); + codes = temp; + } + void expandBreaks(int n) { boolean temp[] = new boolean[n]; PApplet.arrayCopy(breaks, 0, temp, 0, vertexCount); @@ -7834,6 +7854,12 @@ public class PGraphicsOpenGL extends PGraphics { shininess = temp; } +// void trimCodes() { +// int temp[] = new int[vertexCount]; +// PApplet.arrayCopy(codes, 0, temp, 0, vertexCount); +// codes = temp; +// } + void trimBreaks() { boolean temp[] = new boolean[vertexCount]; PApplet.arrayCopy(breaks, 0, temp, 0, vertexCount); @@ -7850,8 +7876,12 @@ public class PGraphicsOpenGL extends PGraphics { // // Vertices + int addVertex(float x, float y, boolean brk) { + return addVertex(x, y, VERTEX, brk); + } + int addVertex(float x, float y, - int code) { + int code, boolean brk) { return addVertex(x, y, 0, fillColor, normalX, normalY, normalZ, @@ -7859,12 +7889,18 @@ public class PGraphicsOpenGL extends PGraphics { strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininessFactor, - code); + code, brk); } int addVertex(float x, float y, float u, float v, - int code) { + boolean brk) { + return addVertex(x, y, u, v, VERTEX, brk); + } + + int addVertex(float x, float y, + float u, float v, + int code, boolean brk) { return addVertex(x, y, 0, fillColor, normalX, normalY, normalZ, @@ -7872,11 +7908,15 @@ public class PGraphicsOpenGL extends PGraphics { strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininessFactor, - code); + code, brk); + } + + int addVertex(float x, float y, float z, boolean brk) { + return addVertex(x, y, z, VERTEX, brk); } int addVertex(float x, float y, float z, - int code) { + int code, boolean brk) { return addVertex(x, y, z, fillColor, normalX, normalY, normalZ, @@ -7884,12 +7924,18 @@ public class PGraphicsOpenGL extends PGraphics { strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininessFactor, - code); + code, brk); } int addVertex(float x, float y, float z, float u, float v, - int code) { + boolean brk) { + return addVertex(x, y, z, u, v, VERTEX, brk); + } + + int addVertex(float x, float y, float z, + float u, float v, + int code, boolean brk) { return addVertex(x, y, z, fillColor, normalX, normalY, normalZ, @@ -7897,7 +7943,7 @@ public class PGraphicsOpenGL extends PGraphics { strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininessFactor, - code); + code, brk); } int addVertex(float x, float y, float z, @@ -7906,12 +7952,10 @@ public class PGraphicsOpenGL extends PGraphics { float u, float v, int scolor, float sweight, int am, int sp, int em, float shine, - int code) { + int code, boolean brk) { vertexCheck(); int index; - curveVertexCount = 0; - index = 3 * vertexCount; vertices[index++] = x; vertices[index++] = y; @@ -7936,14 +7980,52 @@ public class PGraphicsOpenGL extends PGraphics { emissive[vertexCount] = PGL.javaToNativeARGB(em); shininess[vertexCount] = shine; - breaks[vertexCount] = code == BREAK; + breaks[vertexCount] = brk; + + if (code == BEZIER_VERTEX || code == QUADRATIC_VERTEX || + code == CURVE_VERTEX || (code == VERTEX && codes != null) || brk) { + if (codes == null) { + codes = new int[vertexCount]; + Arrays.fill(codes, 0, vertexCount, VERTEX); + } + + if (brk) { + codeCheck(); + codes[vertexCount] = BREAK; + codeCount++; + } + + if (code != -1) { + codeCheck(); + codes[vertexCount] = code; + codeCount++; + } + } - lastVertex = vertexCount; vertexCount++; - return lastVertex; + return vertexCount - 1; } + public void addBezierVertex(float x2, float y2, float z2, + float x3, float y3, float z3, + float x4, float y4, float z4, boolean brk) { + addVertex(x2, y2, z2, BEZIER_VERTEX, brk); + addVertex(x3, y3, z3, -1, false); + addVertex(x4, y4, z4, -1, false); + } + + public void addQuadraticVertex(float cx, float cy, float cz, + float x3, float y3, float z3, boolean brk) { + addVertex(cx, cy, cz, QUADRATIC_VERTEX, brk); + addVertex(x3, y3, z3, -1, false); + } + + public void addCurveVertex(float x, float y, float z, boolean brk) { + addVertex(x, y, z, CURVE_VERTEX, brk); + } + + /* void addBezierVertex(float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, @@ -7957,7 +8039,7 @@ public class PGraphicsOpenGL extends PGraphics { void addBezierVertex(float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, - boolean fill, boolean stroke, int detail, int code, + boolean fill, boolean stroke, int detail, int code, // this should be break flag int shape) { bezierInitCheck(); bezierVertexCheck(shape, vertexCount); @@ -7987,11 +8069,17 @@ public class PGraphicsOpenGL extends PGraphics { addVertex(x1, y1, z1, j == 0 && code == BREAK ? BREAK : VERTEX); } } + */ + /* public void addQuadraticVertex(float cx, float cy, float cz, float x3, float y3, float z3, boolean fill, boolean stroke, int detail, int code) { + addVertex(cx, cy, cz, QUADRATIC_VERTEX, brk); + addVertex(x3, y3, z3, QUADRATIC_VERTEX, false); + + addQuadraticVertex(cx, cy, cz, x3, y3, z3, fill, stroke, detail, code, POLYGON); @@ -8010,7 +8098,9 @@ public class PGraphicsOpenGL extends PGraphics { x3, y3, z3, fill, stroke, detail, code, shape); } + */ + /* void addCurveVertex(float x, float y, float z, boolean fill, boolean stroke, int detail, int code) { addCurveVertex(x, y, z, @@ -8078,6 +8168,7 @@ public class PGraphicsOpenGL extends PGraphics { curveVertexCount = savedCount; } +*/ // Returns the vertex data in the PGraphics double array format. float[][] getVertexData() { @@ -8112,6 +8203,27 @@ public class PGraphicsOpenGL extends PGraphics { return data; } + boolean hasBezierVertex() { + for (int i = 0; i < codeCount; i++) { + if (codes[i] == BEZIER_VERTEX) return true; + } + return false; + } + + boolean hasQuadraticVertex() { + for (int i = 0; i < codeCount; i++) { + if (codes[i] == QUADRATIC_VERTEX) return true; + } + return false; + } + + boolean hasCurveVertex() { + for (int i = 0; i < codeCount; i++) { + if (codes[i] == CURVE_VERTEX) return true; + } + return false; + } + // ----------------------------------------------------------------- // // Edges @@ -8130,10 +8242,9 @@ public class PGraphicsOpenGL extends PGraphics { // 3 = isolated edge (start, end) edge[2] = (start ? 1 : 0) + 2 * (end ? 1 : 0); - lastEdge = edgeCount; edgeCount++; - return lastEdge; + return edgeCount - 1; } int closeEdge(int i, int j) { @@ -8144,14 +8255,13 @@ public class PGraphicsOpenGL extends PGraphics { edge[1] = j; edge[2] = -1; - lastEdge = edgeCount; edgeCount++; - return lastEdge; + return edgeCount - 1; } void addTrianglesEdges() { - for (int i = 0; i < (lastVertex - firstVertex + 1) / 3; i++) { + for (int i = 0; i < vertexCount / 3; i++) { int i0 = 3 * i + 0; int i1 = 3 * i + 1; int i2 = 3 * i + 2; @@ -8164,8 +8274,8 @@ public class PGraphicsOpenGL extends PGraphics { } void addTriangleFanEdges() { - for (int i = firstVertex + 1; i < lastVertex; i++) { - int i0 = firstVertex; + for (int i = 1; i < vertexCount - 1; i++) { + int i0 = 0; int i1 = i; int i2 = i + 1; @@ -8177,7 +8287,7 @@ public class PGraphicsOpenGL extends PGraphics { } void addTriangleStripEdges() { - for (int i = firstVertex + 1; i < lastVertex; i++) { + for (int i = 1; i < vertexCount - 1; i++) { int i0 = i; int i1, i2; if (i % 2 == 0) { @@ -8196,7 +8306,7 @@ public class PGraphicsOpenGL extends PGraphics { } void addQuadsEdges() { - for (int i = 0; i < (lastVertex - firstVertex + 1) / 4; i++) { + for (int i = 0; i < vertexCount / 4; i++) { int i0 = 4 * i + 0; int i1 = 4 * i + 1; int i2 = 4 * i + 2; @@ -8211,11 +8321,11 @@ public class PGraphicsOpenGL extends PGraphics { } void addQuadStripEdges() { - for (int qd = 1; qd < (lastVertex - firstVertex + 1) / 2; qd++) { - int i0 = firstVertex + 2 * (qd - 1); - int i1 = firstVertex + 2 * (qd - 1) + 1; - int i2 = firstVertex + 2 * qd + 1; - int i3 = firstVertex + 2 * qd; + for (int qd = 1; qd < vertexCount / 2; qd++) { + int i0 = 2 * (qd - 1); + int i1 = 2 * (qd - 1) + 1; + int i2 = 2 * qd + 1; + int i3 = 2 * qd; addEdge(i0, i1, true, false); addEdge(i1, i2, false, false); @@ -8226,9 +8336,11 @@ public class PGraphicsOpenGL extends PGraphics { } void addPolygonEdges(boolean closed) { - int start = firstVertex; + // TODO: need to expand bezier, quadratic and curve vertices...crap. + + int start = 0; boolean begin = true; - for (int i = firstVertex + 1; i <= lastVertex; i++) { + for (int i = 1; i <= vertexCount - 1; i++) { if (breaks[i]) { if (closed) { // Closing previous contour. @@ -8240,7 +8352,7 @@ public class PGraphicsOpenGL extends PGraphics { start = i; begin = true; } else { - if (i == lastVertex) { + if (i == vertexCount - 1) { if (closed && start + 1 < i) { // Closing the end of the last contour, if it // has more than 1 segment. @@ -8253,7 +8365,7 @@ public class PGraphicsOpenGL extends PGraphics { } } else { - if (i < lastVertex && breaks[i + 1] && !closed) { + if ((i < vertexCount - 1) && breaks[i + 1] && !closed) { // A new contour starts at the next vertex and // the polygon is not closed, so this is the last // segment of the current contour. @@ -8267,6 +8379,8 @@ public class PGraphicsOpenGL extends PGraphics { begin = false; } } + + } // ----------------------------------------------------------------- @@ -8328,7 +8442,7 @@ public class PGraphicsOpenGL extends PGraphics { } void calcTrianglesNormals() { - for (int i = 0; i < (lastVertex - firstVertex + 1) / 3; i++) { + for (int i = 0; i < vertexCount / 3; i++) { int i0 = 3 * i + 0; int i1 = 3 * i + 1; int i2 = 3 * i + 2; @@ -8338,8 +8452,8 @@ public class PGraphicsOpenGL extends PGraphics { } void calcTriangleFanNormals() { - for (int i = firstVertex + 1; i < lastVertex; i++) { - int i0 = firstVertex; + for (int i = 1; i < vertexCount - 1; i++) { + int i0 = 0; int i1 = i; int i2 = i + 1; @@ -8348,7 +8462,7 @@ public class PGraphicsOpenGL extends PGraphics { } void calcTriangleStripNormals() { - for (int i = firstVertex + 1; i < lastVertex; i++) { + for (int i = 1; i < vertexCount - 1; i++) { int i1 = i; int i0, i2; if (i % 2 == 0) { @@ -8365,7 +8479,7 @@ public class PGraphicsOpenGL extends PGraphics { } void calcQuadsNormals() { - for (int i = 0; i < (lastVertex - firstVertex + 1) / 4; i++) { + for (int i = 0; i < vertexCount / 4; i++) { int i0 = 4 * i + 0; int i1 = 4 * i + 1; int i2 = 4 * i + 2; @@ -8377,11 +8491,11 @@ public class PGraphicsOpenGL extends PGraphics { } void calcQuadStripNormals() { - for (int qd = 1; qd < (lastVertex - firstVertex + 1) / 2; qd++) { - int i0 = firstVertex + 2 * (qd - 1); - int i1 = firstVertex + 2 * (qd - 1) + 1; - int i2 = firstVertex + 2 * qd; - int i3 = firstVertex + 2 * qd + 1; + for (int qd = 1; qd < vertexCount / 2; qd++) { + int i0 = 2 * (qd - 1); + int i1 = 2 * (qd - 1) + 1; + int i2 = 2 * qd; + int i3 = 2 * qd + 1; calcTriangleNormal(i0, i3, i1); calcTriangleNormal(i0, i2, i3); @@ -8411,14 +8525,14 @@ public class PGraphicsOpenGL extends PGraphics { } void addPoint(float x, float y, float z, boolean fill, boolean stroke) { - addVertex(x, y, z, VERTEX); + addVertex(x, y, z, VERTEX, true); } void addLine(float x1, float y1, float z1, float x2, float y2, float z2, boolean fill, boolean stroke) { - int idx1 = addVertex(x1, y1, z1, VERTEX); - int idx2 = addVertex(x2, y2, z2, VERTEX); + int idx1 = addVertex(x1, y1, z1, VERTEX, true); + int idx2 = addVertex(x2, y2, z2, VERTEX, false); if (stroke) addEdge(idx1, idx2, true, true); } @@ -8426,9 +8540,9 @@ public class PGraphicsOpenGL extends PGraphics { float x2, float y2, float z2, float x3, float y3, float z3, boolean fill, boolean stroke) { - int idx1 = addVertex(x1, y1, z1, VERTEX); - int idx2 = addVertex(x2, y2, z2, VERTEX); - int idx3 = addVertex(x3, y3, z3, VERTEX); + int idx1 = addVertex(x1, y1, z1, VERTEX, true); + int idx2 = addVertex(x2, y2, z2, VERTEX, false); + int idx3 = addVertex(x3, y3, z3, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8441,11 +8555,11 @@ public class PGraphicsOpenGL extends PGraphics { float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, - boolean fill, boolean stroke) { - int idx1 = addVertex(x1, y1, z1, 0, 0, VERTEX); - int idx2 = addVertex(x2, y2, z2, 1, 0, VERTEX); - int idx3 = addVertex(x3, y3, z3, 1, 1, VERTEX); - int idx4 = addVertex(x4, y4, z4, 0, 1, VERTEX); + boolean stroke) { + int idx1 = addVertex(x1, y1, z1, 0, 0, VERTEX, true); + int idx2 = addVertex(x2, y2, z2, 1, 0, VERTEX, false); + int idx3 = addVertex(x3, y3, z3, 1, 1, VERTEX, false); + int idx4 = addVertex(x4, y4, z4, 0, 1, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8456,44 +8570,40 @@ public class PGraphicsOpenGL extends PGraphics { } void addRect(float a, float b, float c, float d, - boolean fill, boolean stroke) { + boolean stroke) { addQuad(a, b, 0, c, b, 0, c, d, 0, a, d, 0, - fill, stroke); + stroke); } void addRect(float a, float b, float c, float d, float tl, float tr, float br, float bl, - boolean fill, boolean stroke, int detail) { + boolean stroke) { if (nonZero(tr)) { - addVertex(c-tr, b, VERTEX); - addQuadraticVertex(c, b, 0, c, b+tr, 0, - fill, stroke, detail, VERTEX); + addVertex(c-tr, b, VERTEX, true); + addQuadraticVertex(c, b, 0, c, b+tr, 0, false); } else { - addVertex(c, b, VERTEX); + addVertex(c, b, VERTEX, true); } if (nonZero(br)) { - addVertex(c, d-br, VERTEX); - addQuadraticVertex(c, d, 0, c-br, d, 0, - fill, stroke, detail, VERTEX); + addVertex(c, d-br, VERTEX, false); + addQuadraticVertex(c, d, 0, c-br, d, 0, false); } else { - addVertex(c, d, VERTEX); + addVertex(c, d, VERTEX, false); } if (nonZero(bl)) { - addVertex(a+bl, d, VERTEX); - addQuadraticVertex(a, d, 0, a, d-bl, 0, - fill, stroke, detail, VERTEX); + addVertex(a+bl, d, VERTEX, false); + addQuadraticVertex(a, d, 0, a, d-bl, 0, false); } else { - addVertex(a, d, VERTEX); + addVertex(a, d, VERTEX, false); } if (nonZero(tl)) { - addVertex(a, b+tl, VERTEX); - addQuadraticVertex(a, b, 0, a+tl, b, 0, - fill, stroke, detail, VERTEX); + addVertex(a, b+tl, VERTEX, false); + addQuadraticVertex(a, b, 0, a+tl, b, 0, false); } else { - addVertex(a, b, VERTEX); + addVertex(a, b, VERTEX, false); } if (stroke) addPolygonEdges(true); @@ -8508,10 +8618,10 @@ public class PGraphicsOpenGL extends PGraphics { float centerY = y + radiusV; // should call screenX/Y using current renderer. - float sx1 = pgCurrent.screenX(x, y); - float sy1 = pgCurrent.screenY(x, y); - float sx2 = pgCurrent.screenX(x + w, y + h); - float sy2 = pgCurrent.screenY(x + w, y + h); + float sx1 = pg.screenX(x, y); + float sy1 = pg.screenY(x, y); + float sx2 = pg.screenX(x + w, y + h); + float sy2 = pg.screenY(x + w, y + h); int accuracy = PApplet.min(MAX_POINT_ACCURACY, PApplet.max(MIN_POINT_ACCURACY, @@ -8520,7 +8630,7 @@ public class PGraphicsOpenGL extends PGraphics { float inc = (float) SINCOS_LENGTH / accuracy; if (fill) { - addVertex(centerX, centerY, VERTEX); + addVertex(centerX, centerY, VERTEX, true); } int idx0, pidx, idx; idx0 = pidx = idx = 0; @@ -8528,7 +8638,7 @@ public class PGraphicsOpenGL extends PGraphics { for (int i = 0; i < accuracy; i++) { idx = addVertex(centerX + cosLUT[(int) val] * radiusH, centerY + sinLUT[(int) val] * radiusV, - VERTEX); + VERTEX, i == 0 && !fill); val = (val + inc) % SINCOS_LENGTH; if (0 < i) { @@ -8542,7 +8652,7 @@ public class PGraphicsOpenGL extends PGraphics { // Back to the beginning addVertex(centerX + cosLUT[0] * radiusH, centerY + sinLUT[0] * radiusV, - VERTEX); + VERTEX, false); if (stroke) { addEdge(idx, idx0, false, false); closeEdge(idx, idx0); @@ -8563,7 +8673,7 @@ public class PGraphicsOpenGL extends PGraphics { int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH); if (fill) { - addVertex(centerX, centerY, VERTEX); + addVertex(centerX, centerY, VERTEX, true); } int increment = 1; // what's a good algorithm? stopLUT - startLUT; @@ -8575,7 +8685,7 @@ public class PGraphicsOpenGL extends PGraphics { if (ii < 0) ii += SINCOS_LENGTH; idx = addVertex(centerX + cosLUT[ii] * hr, centerY + sinLUT[ii] * vr, - VERTEX); + VERTEX, i == startLUT && !fill); if (stroke) { if (arcMode == PIE) { @@ -8592,7 +8702,7 @@ public class PGraphicsOpenGL extends PGraphics { // draw last point explicitly for accuracy idx = addVertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr, centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr, - VERTEX); + VERTEX, false); if (stroke) { if (arcMode == PIE) { addEdge(idx, idx0, false, false); @@ -8607,7 +8717,7 @@ public class PGraphicsOpenGL extends PGraphics { if (ii < 0) ii += SINCOS_LENGTH; idx = addVertex(centerX + cosLUT[ii] * hr, centerY + sinLUT[ii] * vr, - VERTEX); + VERTEX, false); if (stroke && arcMode == CHORD) { addEdge(pidx, idx, false, true); } @@ -8624,10 +8734,10 @@ public class PGraphicsOpenGL extends PGraphics { if (fill || stroke) { // front face setNormal(0, 0, 1); - idx1 = addVertex(x1, y1, z1, 0, 0, VERTEX); - idx2 = addVertex(x2, y1, z1, 1, 0, VERTEX); - idx3 = addVertex(x2, y2, z1, 1, 1, VERTEX); - idx4 = addVertex(x1, y2, z1, 0, 1, VERTEX); + idx1 = addVertex(x1, y1, z1, 0, 0, VERTEX, true); + idx2 = addVertex(x2, y1, z1, 1, 0, VERTEX, false); + idx3 = addVertex(x2, y2, z1, 1, 1, VERTEX, false); + idx4 = addVertex(x1, y2, z1, 0, 1, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8638,10 +8748,10 @@ public class PGraphicsOpenGL extends PGraphics { // back face setNormal(0, 0, -1); - idx1 = addVertex(x2, y1, z2, 0, 0, VERTEX); - idx2 = addVertex(x1, y1, z2, 1, 0, VERTEX); - idx3 = addVertex(x1, y2, z2, 1, 1, VERTEX); - idx4 = addVertex(x2, y2, z2, 0, 1, VERTEX); + idx1 = addVertex(x2, y1, z2, 0, 0, VERTEX, false); + idx2 = addVertex(x1, y1, z2, 1, 0, VERTEX, false); + idx3 = addVertex(x1, y2, z2, 1, 1, VERTEX, false); + idx4 = addVertex(x2, y2, z2, 0, 1, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8652,10 +8762,10 @@ public class PGraphicsOpenGL extends PGraphics { // right face setNormal(1, 0, 0); - idx1 = addVertex(x2, y1, z1, 0, 0, VERTEX); - idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX); - idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX); - idx4 = addVertex(x2, y2, z1, 0, 1, VERTEX); + idx1 = addVertex(x2, y1, z1, 0, 0, VERTEX, false); + idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX, false); + idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX, false); + idx4 = addVertex(x2, y2, z1, 0, 1, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8666,10 +8776,10 @@ public class PGraphicsOpenGL extends PGraphics { // left face setNormal(-1, 0, 0); - idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX); - idx2 = addVertex(x1, y1, z1, 1, 0, VERTEX); - idx3 = addVertex(x1, y2, z1, 1, 1, VERTEX); - idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX); + idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX, false); + idx2 = addVertex(x1, y1, z1, 1, 0, VERTEX, false); + idx3 = addVertex(x1, y2, z1, 1, 1, VERTEX, false); + idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8680,10 +8790,10 @@ public class PGraphicsOpenGL extends PGraphics { // top face setNormal(0, 1, 0); - idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX); - idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX); - idx3 = addVertex(x2, y1, z1, 1, 1, VERTEX); - idx4 = addVertex(x1, y1, z1, 0, 1, VERTEX); + idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX, false); + idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX, false); + idx3 = addVertex(x2, y1, z1, 1, 1, VERTEX, false); + idx4 = addVertex(x1, y1, z1, 0, 1, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8694,10 +8804,10 @@ public class PGraphicsOpenGL extends PGraphics { // bottom face setNormal(0, -1, 0); - idx1 = addVertex(x1, y2, z1, 0, 0, VERTEX); - idx2 = addVertex(x2, y2, z1, 1, 0, VERTEX); - idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX); - idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX); + idx1 = addVertex(x1, y2, z1, 0, 0, VERTEX, false); + idx2 = addVertex(x2, y2, z1, 1, 0, VERTEX, false); + idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX, false); + idx4 = addVertex(x1, y2, z2, 0, 1, VERTEX, false); if (stroke) { addEdge(idx1, idx2, true, false); addEdge(idx2, idx3, false, false); @@ -8712,13 +8822,6 @@ public class PGraphicsOpenGL extends PGraphics { // any vertex or edge. int[] addSphere(float r, int detailU, int detailV, boolean fill, boolean stroke) { - if ((detailU < 3) || (detailV < 2)) { - sphereDetail(30); - detailU = detailV = 30; - } else { - sphereDetail(detailU, detailV); - } - int nind = 3 * detailU + (6 * detailU + 3) * (detailV - 2) + 3 * detailU; int[] indices = new int[nind]; @@ -8738,21 +8841,23 @@ public class PGraphicsOpenGL extends PGraphics { u = 1; v = 1; for (int i = 0; i < detailU; i++) { setNormal(0, 1, 0); - addVertex(0, r, 0, u , v, VERTEX); + addVertex(0, r, 0, u , v, VERTEX, true); u -= du; } vertCount = detailU; vert0 = vertCount; u = 1; v -= dv; for (int i = 0; i < detailU; i++) { - setNormal(sphereX[i], sphereY[i], sphereZ[i]); - addVertex(r * sphereX[i], r *sphereY[i], r * sphereZ[i], u , v, VERTEX); + setNormal(pg.sphereX[i], pg.sphereY[i], pg.sphereZ[i]); + addVertex(r*pg.sphereX[i], r*pg.sphereY[i], r*pg.sphereZ[i], u , v, + VERTEX, false); u -= du; } vertCount += detailU; vert1 = vertCount; - setNormal(sphereX[0], sphereY[0], sphereZ[0]); - addVertex(r * sphereX[0], r * sphereY[0], r * sphereZ[0], u, v, VERTEX); + setNormal(pg.sphereX[0], pg.sphereY[0], pg.sphereZ[0]); + addVertex(r*pg.sphereX[0], r*pg.sphereY[0], r*pg.sphereZ[0], u, v, + VERTEX, false); vertCount++; for (int i = 0; i < detailU; i++) { @@ -8777,16 +8882,16 @@ public class PGraphicsOpenGL extends PGraphics { u = 1; v -= dv; for (int i = 0; i < detailU; i++) { int ioff = offset + i; - setNormal(sphereX[ioff], sphereY[ioff], sphereZ[ioff]); - addVertex(r * sphereX[ioff], r *sphereY[ioff], r * sphereZ[ioff], - u , v, VERTEX); + setNormal(pg.sphereX[ioff], pg.sphereY[ioff], pg.sphereZ[ioff]); + addVertex(r*pg.sphereX[ioff], r*pg.sphereY[ioff], r*pg.sphereZ[ioff], + u , v, VERTEX, false); u -= du; } vertCount += detailU; vert1 = vertCount; - setNormal(sphereX[offset], sphereY[offset], sphereZ[offset]); - addVertex(r * sphereX[offset], r * sphereY[offset], r * sphereZ[offset], - u, v, VERTEX); + setNormal(pg.sphereX[offset], pg.sphereY[offset], pg.sphereZ[offset]); + addVertex(r*pg.sphereX[offset], r*pg.sphereY[offset], r*pg.sphereZ[offset], + u, v, VERTEX, false); vertCount++; for (int i = 0; i < detailU; i++) { @@ -8823,7 +8928,7 @@ public class PGraphicsOpenGL extends PGraphics { u = 1; v = 0; for (int i = 0; i < detailU; i++) { setNormal(0, -1, 0); - addVertex(0, -r, 0, u , v, VERTEX); + addVertex(0, -r, 0, u , v, VERTEX, false); u -= du; } vertCount += detailU; @@ -8847,8 +8952,9 @@ public class PGraphicsOpenGL extends PGraphics { // Holds tessellated data for polygon, line and point geometry. - protected class TessGeometry { + static protected class TessGeometry { int renderMode; + PGraphicsOpenGL pg; // Tessellated polygon data int polyVertexCount; @@ -8919,7 +9025,8 @@ public class PGraphicsOpenGL extends PGraphics { float[] pointOffsets; short[] pointIndices; - TessGeometry(int mode) { + TessGeometry(PGraphicsOpenGL pg, int mode) { + this.pg = pg; renderMode = mode; allocate(); } @@ -9721,8 +9828,8 @@ public class PGraphicsOpenGL extends PGraphics { float y = in.vertices[index++]; float z = in.vertices[index ]; - if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL) { - PMatrix3D mm = modelview; + if (renderMode == IMMEDIATE && pg.flushMode == FLUSH_WHEN_FULL) { + PMatrix3D mm = pg.modelview; index = 4 * tessIdx; pointVertices[index++] = x*mm.m00 + y*mm.m01 + z*mm.m02 + mm.m03; @@ -9752,8 +9859,8 @@ public class PGraphicsOpenGL extends PGraphics { float y0 = in.vertices[index++]; float z0 = in.vertices[index ]; - if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL) { - PMatrix3D mm = modelview; + if (renderMode == IMMEDIATE && pg.flushMode == FLUSH_WHEN_FULL) { + PMatrix3D mm = pg.modelview; index = 4 * tessIdx; lineVertices[index++] = x0*mm.m00 + y0*mm.m01 + z0*mm.m02 + mm.m03; @@ -9796,8 +9903,8 @@ public class PGraphicsOpenGL extends PGraphics { float dy = y1 - y0; float dz = z1 - z0; - if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL) { - PMatrix3D mm = modelview; + if (renderMode == IMMEDIATE && pg.flushMode == FLUSH_WHEN_FULL) { + PMatrix3D mm = pg.modelview; index = 4 * tessIdx; lineVertices[index++] = x0*mm.m00 + y0*mm.m01 + z0*mm.m02 + mm.m03; @@ -9862,9 +9969,9 @@ public class PGraphicsOpenGL extends PGraphics { boolean clampXY) { int index; - if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL) { - PMatrix3D mm = modelview; - PMatrix3D nm = modelviewInv; + if (renderMode == IMMEDIATE && pg.flushMode == FLUSH_WHEN_FULL) { + PMatrix3D mm = pg.modelview; + PMatrix3D nm = pg.modelviewInv; index = 4 * tessIdx; if (clampXY) { @@ -9910,7 +10017,7 @@ public class PGraphicsOpenGL extends PGraphics { } void addPolyVertices(InGeometry in, boolean clampXY) { - addPolyVertices(in, in.firstVertex, in.lastVertex, clampXY); + addPolyVertices(in, 0, in.vertexCount - 1, clampXY); } void addPolyVertex(InGeometry in, int i, boolean clampXY) { @@ -9923,9 +10030,9 @@ public class PGraphicsOpenGL extends PGraphics { polyVertexCheck(nvert); - if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL) { - PMatrix3D mm = modelview; - PMatrix3D nm = modelviewInv; + if (renderMode == IMMEDIATE && pg.flushMode == FLUSH_WHEN_FULL) { + PMatrix3D mm = pg.modelview; + PMatrix3D nm = pg.modelviewInv; for (int i = 0; i < nvert; i++) { int inIdx = i0 + i; @@ -10220,7 +10327,7 @@ public class PGraphicsOpenGL extends PGraphics { // Generates tessellated geometry given a batch of input vertices. // Generates tessellated geometry given a batch of input vertices. - protected class Tessellator { + static protected class Tessellator { InGeometry in; TessGeometry tess; TexCache texCache; @@ -10243,6 +10350,7 @@ public class PGraphicsOpenGL extends PGraphics { PMatrix transform; float transformScale; boolean is2D, is3D; + protected PGraphicsOpenGL pg; int[] rawIndices; int rawSize; @@ -10285,6 +10393,13 @@ public class PGraphicsOpenGL extends PGraphics { this.fill = fill; } + void setTexCache(TexCache texCache, PImage prevTexImage, + PImage newTexImage) { + this.texCache = texCache; + this.prevTexImage = prevTexImage; + this.newTexImage = newTexImage; + } + void setStroke(boolean stroke) { this.stroke = stroke; } @@ -10297,23 +10412,20 @@ public class PGraphicsOpenGL extends PGraphics { this.strokeWeight = weight; } - void setStrokeJoin(int strokeJoin) { - this.strokeJoin = strokeJoin; - } - void setStrokeCap(int strokeCap) { this.strokeCap = strokeCap; } + void setStrokeJoin(int strokeJoin) { + this.strokeJoin = strokeJoin; + } + void setAccurate2DStrokes(boolean accurate) { this.accurate2DStrokes = accurate; } - void setTexCache(TexCache texCache, PImage prevTexImage, - PImage newTexImage) { - this.texCache = texCache; - this.prevTexImage = prevTexImage; - this.newTexImage = newTexImage; + protected void setRenderer(PGraphicsOpenGL pg) { + this.pg = pg; } void set3D(boolean value) { @@ -10344,7 +10456,7 @@ public class PGraphicsOpenGL extends PGraphics { } void tessellateRoundPoints() { - int nInVert = in.lastVertex - in.firstVertex + 1; + int nInVert = in.vertexCount; if (stroke && 1 <= nInVert) { // Each point generates a separate triangle fan. // The number of triangles of each fan depends on the @@ -10379,7 +10491,7 @@ public class PGraphicsOpenGL extends PGraphics { IndexCache cache = tess.pointIndexCache; int index = in.renderMode == RETAINED ? cache.addNew() : cache.getLast(); firstPointIndexCache = index; - for (int i = in.firstVertex; i <= in.lastVertex; i++) { + for (int i = 0; i < in.vertexCount; i++) { // Creating the triangle fan for each input vertex. int count = cache.vertexCount[index]; @@ -10439,7 +10551,7 @@ public class PGraphicsOpenGL extends PGraphics { IndexCache cache = tess.polyIndexCache; int index = in.renderMode == RETAINED ? cache.addNew() : cache.getLast(); firstPointIndexCache = index; - for (int i = in.firstVertex; i <= in.lastVertex; i++) { + for (int i = 0; i < in.vertexCount; i++) { int count = cache.vertexCount[index]; if (PGL.MAX_VERTEX_INDEX1 <= count + nPtVert) { // We need to start a new index block for this point. @@ -10482,7 +10594,7 @@ public class PGraphicsOpenGL extends PGraphics { } void tessellateSquarePoints() { - int nInVert = in.lastVertex - in.firstVertex + 1; + int nInVert = in.vertexCount; if (stroke && 1 <= nInVert) { updateTex(); int quadCount = nInVert; // Each point generates a separate quad. @@ -10512,7 +10624,7 @@ public class PGraphicsOpenGL extends PGraphics { IndexCache cache = tess.pointIndexCache; int index = in.renderMode == RETAINED ? cache.addNew() : cache.getLast(); firstPointIndexCache = index; - for (int i = in.firstVertex; i <= in.lastVertex; i++) { + for (int i = 0; i < in.vertexCount; i++) { int nvert = 5; int count = cache.vertexCount[index]; if (PGL.MAX_VERTEX_INDEX1 <= count + nvert) { @@ -10567,7 +10679,7 @@ public class PGraphicsOpenGL extends PGraphics { IndexCache cache = tess.polyIndexCache; int index = in.renderMode == RETAINED ? cache.addNew() : cache.getLast(); firstPointIndexCache = index; - for (int i = in.firstVertex; i <= in.lastVertex; i++) { + for (int i = 0; i < in.vertexCount; i++) { int nvert = 5; int count = cache.vertexCount[index]; if (PGL.MAX_VERTEX_INDEX1 <= count + nvert) { @@ -10607,7 +10719,7 @@ public class PGraphicsOpenGL extends PGraphics { boolean clamp2D() { return is2D && tess.renderMode == IMMEDIATE && - zero(modelview.m01) && zero(modelview.m10); + zero(pg.modelview.m01) && zero(pg.modelview.m10); } boolean clampSquarePoints2D() { @@ -10619,7 +10731,7 @@ public class PGraphicsOpenGL extends PGraphics { // Line tessellation void tessellateLines() { - int nInVert = in.lastVertex - in.firstVertex + 1; + int nInVert = in.vertexCount; if (stroke && 2 <= nInVert) { updateTex(); int lineCount = nInVert / 2; // Each individual line is formed by two consecutive input vertices. @@ -10640,15 +10752,14 @@ public class PGraphicsOpenGL extends PGraphics { // require 3 indices to specify their connectivities. int nind = lineCount * 2 * 3; - int first = in.firstVertex; tess.lineVertexCheck(nvert); tess.lineIndexCheck(nind); int index = in.renderMode == RETAINED ? tess.lineIndexCache.addNew() : tess.lineIndexCache.getLast(); firstLineIndexCache = index; for (int ln = 0; ln < lineCount; ln++) { - int i0 = first + 2 * ln + 0; - int i1 = first + 2 * ln + 1; + int i0 = 2 * ln + 0; + int i1 = 2 * ln + 1; index = addLineSegment3D(i0, i1, index, null, false); } lastLineIndexCache = index; @@ -10658,7 +10769,6 @@ public class PGraphicsOpenGL extends PGraphics { int nvert = lineCount * 4; int nind = lineCount * 2 * 3; - int first = in.firstVertex; if (noCapsJoins(nvert)) { tess.polyVertexCheck(nvert); tess.polyIndexCheck(nind); @@ -10668,16 +10778,16 @@ public class PGraphicsOpenGL extends PGraphics { if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index. boolean clamp = clampLines2D(lineCount); for (int ln = 0; ln < lineCount; ln++) { - int i0 = first + 2 * ln + 0; - int i1 = first + 2 * ln + 1; + int i0 = 2 * ln + 0; + int i1 = 2 * ln + 1; index = addLineSegment2D(i0, i1, index, false, clamp); } lastLineIndexCache = lastPolyIndexCache = index; } else { // full stroking algorithm LinePath path = new LinePath(LinePath.WIND_NON_ZERO); for (int ln = 0; ln < lineCount; ln++) { - int i0 = first + 2 * ln + 0; - int i1 = first + 2 * ln + 1; + int i0 = 2 * ln + 0; + int i1 = 2 * ln + 1; path.moveTo(in.vertices[3 * i0 + 0], in.vertices[3 * i0 + 1], in.strokeColors[i0]); path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1], @@ -10690,10 +10800,9 @@ public class PGraphicsOpenGL extends PGraphics { boolean clampLines2D(int lineCount) { boolean res = clamp2D(); if (res) { - int first = in.firstVertex; for (int ln = 0; ln < lineCount; ln++) { - int i0 = first + 2 * ln + 0; - int i1 = first + 2 * ln + 1; + int i0 = 2 * ln + 0; + int i1 = 2 * ln + 1; res = segmentIsAxisAligned(i0, i1); if (!res) break; } @@ -10702,7 +10811,7 @@ public class PGraphicsOpenGL extends PGraphics { } void tessellateLineStrip() { - int nInVert = in.lastVertex - in.firstVertex + 1; + int nInVert = in.vertexCount; if (stroke && 2 <= nInVert) { updateTex(); int lineCount = nInVert - 1; @@ -10726,10 +10835,10 @@ public class PGraphicsOpenGL extends PGraphics { int index = in.renderMode == RETAINED ? tess.lineIndexCache.addNew() : tess.lineIndexCache.getLast(); firstLineIndexCache = index; - int i0 = in.firstVertex; + int i0 = 0; short[] lastInd = {-1, -1}; for (int ln = 0; ln < lineCount; ln++) { - int i1 = in.firstVertex + ln + 1; + int i1 = ln + 1; if (0 < nBevelTr) { index = addLineSegment3D(i0, i1, index, lastInd, false); } else { @@ -10751,21 +10860,19 @@ public class PGraphicsOpenGL extends PGraphics { tess.polyIndexCache.getLast(); firstLineIndexCache = index; if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index. - int i0 = in.firstVertex; + int i0 = 0; boolean clamp = clampLineStrip2D(lineCount); for (int ln = 0; ln < lineCount; ln++) { - int i1 = in.firstVertex + ln + 1; + int i1 = ln + 1; index = addLineSegment2D(i0, i1, index, false, clamp); i0 = i1; } lastLineIndexCache = lastPolyIndexCache = index; } else { // full stroking algorithm - int first = in.firstVertex; LinePath path = new LinePath(LinePath.WIND_NON_ZERO); - path.moveTo(in.vertices[3 * first + 0], in.vertices[3 * first + 1], - in.strokeColors[first]); + path.moveTo(in.vertices[0], in.vertices[1], in.strokeColors[0]); for (int ln = 0; ln < lineCount; ln++) { - int i1 = first + ln + 1; + int i1 = ln + 1; path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1], in.strokeColors[i1]); } @@ -10776,10 +10883,8 @@ public class PGraphicsOpenGL extends PGraphics { boolean clampLineStrip2D(int lineCount) { boolean res = clamp2D(); if (res) { - int i0 = in.firstVertex; for (int ln = 0; ln < lineCount; ln++) { - int i1 = in.firstVertex + ln + 1; - res = segmentIsAxisAligned(i0, i1); + res = segmentIsAxisAligned(0, ln + 1); if (!res) break; } } @@ -10787,7 +10892,7 @@ public class PGraphicsOpenGL extends PGraphics { } void tessellateLineLoop() { - int nInVert = in.lastVertex - in.firstVertex + 1; + int nInVert = in.vertexCount; if (stroke && 2 <= nInVert) { updateTex(); int lineCount = nInVert; @@ -10811,11 +10916,11 @@ public class PGraphicsOpenGL extends PGraphics { int index = in.renderMode == RETAINED ? tess.lineIndexCache.addNew() : tess.lineIndexCache.getLast(); firstLineIndexCache = index; - int i0 = in.firstVertex; + int i0 = 0; short[] lastInd = {-1, -1}; short firstInd = -1; for (int ln = 0; ln < lineCount - 1; ln++) { - int i1 = in.firstVertex + ln + 1; + int i1 = ln + 1; if (0 < nBevelTr) { index = addLineSegment3D(i0, i1, index, lastInd, false); if (ln == 0) firstInd = (short)(lastInd[0] - 2); @@ -10824,10 +10929,9 @@ public class PGraphicsOpenGL extends PGraphics { } i0 = i1; } - index = addLineSegment3D(in.lastVertex, in.firstVertex, index, lastInd, - false); + index = addLineSegment3D(0, in.vertexCount - 1, index, lastInd, false); if (0 < nBevelTr) { - index = addBevel3D(in.firstVertex, index, lastInd, firstInd, false); + index = addBevel3D(0, index, lastInd, firstInd, false); } lastLineIndexCache = index; } @@ -10843,23 +10947,20 @@ public class PGraphicsOpenGL extends PGraphics { tess.polyIndexCache.getLast(); firstLineIndexCache = index; if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index. - int i0 = in.firstVertex; + int i0 = 0; boolean clamp = clampLineLoop2D(lineCount); for (int ln = 0; ln < lineCount - 1; ln++) { - int i1 = in.firstVertex + ln + 1; + int i1 = ln + 1; index = addLineSegment2D(i0, i1, index, false, clamp); i0 = i1; } - index = addLineSegment2D(in.lastVertex, in.firstVertex, index, false, - clamp); + index = addLineSegment2D(0, in.vertexCount - 1, index, false, clamp); lastLineIndexCache = lastPolyIndexCache = index; } else { // full stroking algorithm - int first = in.firstVertex; LinePath path = new LinePath(LinePath.WIND_NON_ZERO); - path.moveTo(in.vertices[3 * first + 0], in.vertices[3 * first + 1], - in.strokeColors[first]); + path.moveTo(in.vertices[0], in.vertices[1], in.strokeColors[0]); for (int ln = 0; ln < lineCount - 1; ln++) { - int i1 = first + ln + 1; + int i1 = ln + 1; path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1], in.strokeColors[i1]); } @@ -10871,10 +10972,8 @@ public class PGraphicsOpenGL extends PGraphics { boolean clampLineLoop2D(int lineCount) { boolean res = clamp2D(); if (res) { - int i0 = in.firstVertex; for (int ln = 0; ln < lineCount; ln++) { - int i1 = in.firstVertex + ln + 1; - res = segmentIsAxisAligned(i0, i1); + res = segmentIsAxisAligned(0, ln + 1); if (!res) break; } } @@ -10906,7 +11005,7 @@ public class PGraphicsOpenGL extends PGraphics { firstLineIndexCache = index; short[] lastInd = {-1, -1}; short firstInd = -1; - for (int i = in.firstEdge; i <= in.lastEdge; i++) { + for (int i = 0; i <= in.edgeCount - 1; i++) { int[] edge = in.edges[i]; int i0 = edge[0]; int i1 = edge[1]; @@ -10940,7 +11039,7 @@ public class PGraphicsOpenGL extends PGraphics { firstLineIndexCache = index; if (firstPolyIndexCache == -1) firstPolyIndexCache = index; // If the geometry has no fill, needs the first poly index. boolean clamp = clampEdges2D(); - for (int i = in.firstEdge; i <= in.lastEdge; i++) { + for (int i = 0; i <= in.edgeCount - 1; i++) { int[] edge = in.edges[i]; if (edge[2] == EDGE_CLOSE) continue; // ignoring edge closures when not doing caps or joins. int i0 = edge[0]; @@ -10950,7 +11049,7 @@ public class PGraphicsOpenGL extends PGraphics { lastLineIndexCache = lastPolyIndexCache = index; } else { // full stroking algorithm LinePath path = new LinePath(LinePath.WIND_NON_ZERO); - for (int i = in.firstEdge; i <= in.lastEdge; i++) { + for (int i = 0; i <= in.edgeCount - 1; i++) { int[] edge = in.edges[i]; int i0 = edge[0]; int i1 = edge[1]; @@ -10991,7 +11090,7 @@ public class PGraphicsOpenGL extends PGraphics { boolean clampEdges2D() { boolean res = clamp2D(); if (res) { - for (int i = in.firstEdge; i <= in.lastEdge; i++) { + for (int i = 0; i <= in.edgeCount - 1; i++) { int[] edge = in.edges[i]; if (edge[2] == EDGE_CLOSE) continue; int i0 = edge[0]; @@ -11236,7 +11335,7 @@ public class PGraphicsOpenGL extends PGraphics { } void unclampLine2D(int tessIdx, float x, float y) { - PMatrix3D mm = modelview; + PMatrix3D mm = pg.modelview; int index = 4 * tessIdx; tess.polyVertices[index++] = x*mm.m00 + y*mm.m01 + mm.m03; tess.polyVertices[index++] = x*mm.m10 + y*mm.m11 + mm.m13; @@ -11303,13 +11402,13 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateTriangles() { beginTex(); - int nTri = (in.lastVertex - in.firstVertex + 1) / 3; + int nTri = in.vertexCount / 3; if (fill && 1 <= nTri) { int nInInd = 3 * nTri; setRawSize(nInInd); int idx = 0; boolean clamp = clampTriangles(); - for (int i = in.firstVertex; i < in.firstVertex + 3 * nTri; i++) { + for (int i = 0; i < 3 * nTri; i++) { rawIndices[idx++] = i; } splitRawIndices(clamp); @@ -11321,7 +11420,7 @@ public class PGraphicsOpenGL extends PGraphics { boolean clampTriangles() { boolean res = clamp2D(); if (res) { - int nTri = (in.lastVertex - in.firstVertex + 1) / 3; + int nTri = in.vertexCount / 3; for (int i = 0; i < nTri; i++) { int i0 = 3 * i + 0; int i1 = 3 * i + 1; @@ -11339,7 +11438,7 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateTriangles(int[] indices) { beginTex(); - int nInVert = in.lastVertex - in.firstVertex + 1; + int nInVert = in.vertexCount; if (fill && 3 <= nInVert) { int nInInd = indices.length; setRawSize(nInInd); @@ -11372,14 +11471,14 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateTriangleFan() { beginTex(); - int nInVert = in.lastVertex - in.firstVertex + 1; + int nInVert = in.vertexCount; if (fill && 3 <= nInVert) { int nInInd = 3 * (nInVert - 2); setRawSize(nInInd); int idx = 0; boolean clamp = clampTriangleFan(); - for (int i = in.firstVertex + 1; i < in.lastVertex; i++) { - rawIndices[idx++] = in.firstVertex; + for (int i = 1; i < in.vertexCount - 1; i++) { + rawIndices[idx++] = 0; rawIndices[idx++] = i; rawIndices[idx++] = i + 1; } @@ -11392,8 +11491,8 @@ public class PGraphicsOpenGL extends PGraphics { boolean clampTriangleFan() { boolean res = clamp2D(); if (res) { - for (int i = in.firstVertex + 1; i < in.lastVertex; i++) { - int i0 = in.firstVertex; + for (int i = 1; i < in.vertexCount - 1; i++) { + int i0 = 0; int i1 = i; int i2 = i + 1; int count = 0; @@ -11409,13 +11508,13 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateTriangleStrip() { beginTex(); - int nInVert = in.lastVertex - in.firstVertex + 1; + int nInVert = in.vertexCount; if (fill && 3 <= nInVert) { int nInInd = 3 * (nInVert - 2); setRawSize(nInInd); int idx = 0; boolean clamp = clampTriangleStrip(); - for (int i = in.firstVertex + 1; i < in.lastVertex; i++) { + for (int i = 1; i < in.vertexCount - 1; i++) { rawIndices[idx++] = i; if (i % 2 == 0) { rawIndices[idx++] = i - 1; @@ -11434,7 +11533,7 @@ public class PGraphicsOpenGL extends PGraphics { boolean clampTriangleStrip() { boolean res = clamp2D(); if (res) { - for (int i = in.firstVertex + 1; i < in.lastVertex; i++) { + for (int i = 1; i < in.vertexCount - 1; i++) { int i0 = i; int i1, i2; if (i % 2 == 0) { @@ -11457,17 +11556,17 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateQuads() { beginTex(); - int quadCount = (in.lastVertex - in.firstVertex + 1) / 4; + int quadCount = in.vertexCount / 4; if (fill && 1 <= quadCount) { int nInInd = 6 * quadCount; setRawSize(nInInd); int idx = 0; boolean clamp = clampQuads(quadCount); for (int qd = 0; qd < quadCount; qd++) { - int i0 = in.firstVertex + 4 * qd + 0; - int i1 = in.firstVertex + 4 * qd + 1; - int i2 = in.firstVertex + 4 * qd + 2; - int i3 = in.firstVertex + 4 * qd + 3; + int i0 = 4 * qd + 0; + int i1 = 4 * qd + 1; + int i2 = 4 * qd + 2; + int i3 = 4 * qd + 3; rawIndices[idx++] = i0; rawIndices[idx++] = i1; @@ -11487,10 +11586,10 @@ public class PGraphicsOpenGL extends PGraphics { boolean res = clamp2D(); if (res) { for (int qd = 0; qd < quadCount; qd++) { - int i0 = in.firstVertex + 4 * qd + 0; - int i1 = in.firstVertex + 4 * qd + 1; - int i2 = in.firstVertex + 4 * qd + 2; - int i3 = in.firstVertex + 4 * qd + 3; + int i0 = 4 * qd + 0; + int i1 = 4 * qd + 1; + int i2 = 4 * qd + 2; + int i3 = 4 * qd + 3; res = segmentIsAxisAligned(i0, i1) && segmentIsAxisAligned(i1, i2) && segmentIsAxisAligned(i2, i3); @@ -11502,17 +11601,17 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateQuadStrip() { beginTex(); - int quadCount = (in.lastVertex - in.firstVertex + 1) / 2 - 1; + int quadCount = in.vertexCount / 2 - 1; if (fill && 1 <= quadCount) { int nInInd = 6 * quadCount; setRawSize(nInInd); int idx = 0; boolean clamp = clampQuadStrip(quadCount); for (int qd = 1; qd < quadCount + 1; qd++) { - int i0 = in.firstVertex + 2 * (qd - 1); - int i1 = in.firstVertex + 2 * (qd - 1) + 1; - int i2 = in.firstVertex + 2 * qd + 1; - int i3 = in.firstVertex + 2 * qd; + int i0 = 2 * (qd - 1); + int i1 = 2 * (qd - 1) + 1; + int i2 = 2 * qd + 1; + int i3 = 2 * qd; rawIndices[idx++] = i0; rawIndices[idx++] = i1; @@ -11532,10 +11631,10 @@ public class PGraphicsOpenGL extends PGraphics { boolean res = clamp2D(); if (res) { for (int qd = 1; qd < quadCount + 1; qd++) { - int i0 = in.firstVertex + 2 * (qd - 1); - int i1 = in.firstVertex + 2 * (qd - 1) + 1; - int i2 = in.firstVertex + 2 * qd + 1; - int i3 = in.firstVertex + 2 * qd; + int i0 = 2 * (qd - 1); + int i1 = 2 * (qd - 1) + 1; + int i2 = 2 * qd + 1; + int i3 = 2 * qd; res = segmentIsAxisAligned(i0, i1) && segmentIsAxisAligned(i1, i2) && segmentIsAxisAligned(i2, i3); @@ -11567,7 +11666,7 @@ public class PGraphicsOpenGL extends PGraphics { // Current index and vertex ranges int inInd0 = 0, inInd1 = 0; - int inMaxVert0 = in.firstVertex, inMaxVert1 = in.firstVertex; + int inMaxVert0 = 0, inMaxVert1 = 0; int inMaxVertRef = inMaxVert0; // Reference vertex where last break split occurred int inMaxVertRel = -1; // Position of vertices from last range relative to @@ -11778,7 +11877,7 @@ public class PGraphicsOpenGL extends PGraphics { void tessellatePolygon(boolean solid, boolean closed, boolean calcNormals) { beginTex(); - int nInVert = in.lastVertex - in.firstVertex + 1; + int nInVert = in.vertexCount; if (fill && 3 <= nInVert) { firstPolyIndexCache = -1; @@ -11799,44 +11898,36 @@ public class PGraphicsOpenGL extends PGraphics { gluTess.beginContour(); // Now, iterate over all input data and send to GLU tessellator.. - for (int i = in.firstVertex; i <= in.lastVertex; i++) { - boolean breakPt = in.breaks[i]; - if (breakPt) { + int vidx = 0; + int cidx = 0; + while (vidx < in.vertexCount) { + boolean brk = in.breaks[vidx]; + + int code = VERTEX; + if (in.codes != null) { + + } + + // in.codes[cidx]; + + if (brk) { gluTess.endContour(); gluTess.beginContour(); } - // Separting colors into individual rgba components for interpolation. - int fa = (in.colors[i] >> 24) & 0xFF; - int fr = (in.colors[i] >> 16) & 0xFF; - int fg = (in.colors[i] >> 8) & 0xFF; - int fb = (in.colors[i] >> 0) & 0xFF; - - int aa = (in.ambient[i] >> 24) & 0xFF; - int ar = (in.ambient[i] >> 16) & 0xFF; - int ag = (in.ambient[i] >> 8) & 0xFF; - int ab = (in.ambient[i] >> 0) & 0xFF; - - int sa = (in.specular[i] >> 24) & 0xFF; - int sr = (in.specular[i] >> 16) & 0xFF; - int sg = (in.specular[i] >> 8) & 0xFF; - int sb = (in.specular[i] >> 0) & 0xFF; - - int ea = (in.emissive[i] >> 24) & 0xFF; - int er = (in.emissive[i] >> 16) & 0xFF; - int eg = (in.emissive[i] >> 8) & 0xFF; - int eb = (in.emissive[i] >> 0) & 0xFF; - - // Vertex data includes coordinates, colors, normals, texture - // coordinates, and material properties. - double[] vertex = new double[] { - in.vertices [3*i + 0], in.vertices [3*i + 1], in.vertices[3*i + 2], - fa, fr, fg, fb, - in.normals [3*i + 0], in.normals [3*i + 1], in.normals [3*i + 2], - in.texcoords[2*i + 0], in.texcoords[2*i + 1], - aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, in.shininess[i]}; - - gluTess.addVertex(vertex); + if (code == BEZIER_VERTEX) { + addBezierVertex(vidx); + vidx += 3; + } else if (code == QUADRATIC_VERTEX) { + addQuadraticVertex(vidx); + vidx += 2; + } else if (code == CURVE_VERTEX) { + addCurveVertex(vidx); + vidx++; + } else { + addVertex(vidx); + vidx++; + } } gluTess.endContour(); @@ -11847,6 +11938,311 @@ public class PGraphicsOpenGL extends PGraphics { tessellateEdges(); } + void addBezierVertex(int i) { + pg.curveVertexCount = 0; + pg.bezierInitCheck(); + pg.bezierVertexCheck(pg.shape, i); + + PMatrix3D draw = pg.bezierDrawMatrix; + + int i1 = i - 1; + float x1 = in.vertices[3*i1 + 0]; + float y1 = in.vertices[3*i1 + 1]; + float z1 = in.vertices[3*i1 + 2]; + + int fa = (in.colors[i] >> 24) & 0xFF; + int fr = (in.colors[i] >> 16) & 0xFF; + int fg = (in.colors[i] >> 8) & 0xFF; + int fb = (in.colors[i] >> 0) & 0xFF; + + int aa = (in.ambient[i] >> 24) & 0xFF; + int ar = (in.ambient[i] >> 16) & 0xFF; + int ag = (in.ambient[i] >> 8) & 0xFF; + int ab = (in.ambient[i] >> 0) & 0xFF; + + int sa = (in.specular[i] >> 24) & 0xFF; + int sr = (in.specular[i] >> 16) & 0xFF; + int sg = (in.specular[i] >> 8) & 0xFF; + int sb = (in.specular[i] >> 0) & 0xFF; + + int ea = (in.emissive[i] >> 24) & 0xFF; + int er = (in.emissive[i] >> 16) & 0xFF; + int eg = (in.emissive[i] >> 8) & 0xFF; + int eb = (in.emissive[i] >> 0) & 0xFF; + + float nx = in.normals[3*i + 0]; + float ny = in.normals[3*i + 1]; + float nz = in.normals[3*i + 2]; + float u = in.texcoords[2*i + 0]; + float v = in.texcoords[2*i + 1]; + float sh = in.shininess[i]; + + float x2 = in.vertices[3*i + 0]; + float y2 = in.vertices[3*i + 1]; + float z2 = in.vertices[3*i + 2]; + float x3 = in.vertices[3*(i+1) + 0]; + float y3 = in.vertices[3*(i+1) + 1]; + float z3 = in.vertices[3*(i+1) + 2]; + float x4 = in.vertices[3*(i+2) + 0]; + float y4 = in.vertices[3*(i+2) + 1]; + float z4 = in.vertices[3*(i+2) + 2]; + + float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4; + float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4; + float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4; + + float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4; + float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4; + float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4; + + float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4; + float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4; + float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4; + + for (int j = 0; j < pg.bezierDetail; j++) { + x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3; + y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3; + z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3; + double[] vertex = new double[] { + x1, y1, z1, + fa, fr, fg, fb, + nx, ny, nz, + u, v, + aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; + gluTess.addVertex(vertex); + } + } + + void addQuadraticVertex(int i) { + pg.curveVertexCount = 0; + pg.bezierInitCheck(); + pg.bezierVertexCheck(pg.shape, i); + + PMatrix3D draw = pg.bezierDrawMatrix; + + int i1 = i - 1; + float x1 = in.vertices[3*i1 + 0]; + float y1 = in.vertices[3*i1 + 1]; + float z1 = in.vertices[3*i1 + 2]; + + int fa = (in.colors[i] >> 24) & 0xFF; + int fr = (in.colors[i] >> 16) & 0xFF; + int fg = (in.colors[i] >> 8) & 0xFF; + int fb = (in.colors[i] >> 0) & 0xFF; + + int aa = (in.ambient[i] >> 24) & 0xFF; + int ar = (in.ambient[i] >> 16) & 0xFF; + int ag = (in.ambient[i] >> 8) & 0xFF; + int ab = (in.ambient[i] >> 0) & 0xFF; + + int sa = (in.specular[i] >> 24) & 0xFF; + int sr = (in.specular[i] >> 16) & 0xFF; + int sg = (in.specular[i] >> 8) & 0xFF; + int sb = (in.specular[i] >> 0) & 0xFF; + + int ea = (in.emissive[i] >> 24) & 0xFF; + int er = (in.emissive[i] >> 16) & 0xFF; + int eg = (in.emissive[i] >> 8) & 0xFF; + int eb = (in.emissive[i] >> 0) & 0xFF; + + float nx = in.normals[3*i + 0]; + float ny = in.normals[3*i + 1]; + float nz = in.normals[3*i + 2]; + float u = in.texcoords[2*i + 0]; + float v = in.texcoords[2*i + 1]; + float sh = in.shininess[i]; + + float cx = in.vertices[3*i + 0]; + float cy = in.vertices[3*i + 1]; + float cz = in.vertices[3*i + 2]; + float x = in.vertices[3*(i+1) + 0]; + float y = in.vertices[3*(i+1) + 1]; + float z = in.vertices[3*(i+1) + 2]; + + float x2 = x1 + ((cx-x1)*2/3.0f); + float y2 = y1 + ((cy-y1)*2/3.0f); + float z2 = z1 + ((cz-z1)*2/3.0f); + float x3 = x + ((cx-x)*2/3.0f); + float y3 = y + ((cy-y)*2/3.0f); + float z3 = z + ((cz-z)*2/3.0f); + float x4 = x; + float y4 = y; + float z4 = z; + + float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4; + float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4; + float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4; + + float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4; + float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4; + float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4; + + float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4; + float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4; + float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4; + + for (int j = 0; j < pg.bezierDetail; j++) { + x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3; + y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3; + z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3; + double[] vertex = new double[] { + x1, y1, z1, + fa, fr, fg, fb, + nx, ny, nz, + u, v, + aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; + + gluTess.addVertex(vertex); + } + +/* + float x1 = getLastVertexX(); + float y1 = getLastVertexY(); + float z1 = getLastVertexZ(); + addBezierVertex( + x1 + ((cx-x1)*2/3.0f), y1 + ((cy-y1)*2/3.0f), z1 + ((cz-z1)*2/3.0f), + x3 + ((cx-x3)*2/3.0f), y3 + ((cy-y3)*2/3.0f), z3 + ((cz-z3)*2/3.0f), + x3, y3, z3, + fill, stroke, detail, code, shape); + */ + } + + void addCurveVertex(int i) { + pg.curveVertexCheck(pg.shape); + + float[] vertex = pg.curveVertices[pg.curveVertexCount]; + vertex[X] = in.vertices[3*i + 0]; + vertex[Y] = in.vertices[3*i + 1]; + vertex[Z] = in.vertices[3*i + 2]; + + pg.curveVertexCount++; + + // draw a segment if there are enough points + if (pg.curveVertexCount > 3) { + float[] v1 = pg.curveVertices[pg.curveVertexCount - 4]; + float[] v2 = pg.curveVertices[pg.curveVertexCount - 3]; + float[] v3 = pg.curveVertices[pg.curveVertexCount - 2]; + float[] v4 = pg.curveVertices[pg.curveVertexCount - 1]; + addCurveVertexSegment(i, v1[X], v1[Y], v1[Z], + v2[X], v2[Y], v2[Z], + v3[X], v3[Y], v3[Z], + v4[X], v4[Y], v4[Z]); + } + } + + void addCurveVertexSegment(int i, float x1, float y1, float z1, + float x2, float y2, float z2, + float x3, float y3, float z3, + float x4, float y4, float z4) { + int fa = (in.colors[i] >> 24) & 0xFF; + int fr = (in.colors[i] >> 16) & 0xFF; + int fg = (in.colors[i] >> 8) & 0xFF; + int fb = (in.colors[i] >> 0) & 0xFF; + + int aa = (in.ambient[i] >> 24) & 0xFF; + int ar = (in.ambient[i] >> 16) & 0xFF; + int ag = (in.ambient[i] >> 8) & 0xFF; + int ab = (in.ambient[i] >> 0) & 0xFF; + + int sa = (in.specular[i] >> 24) & 0xFF; + int sr = (in.specular[i] >> 16) & 0xFF; + int sg = (in.specular[i] >> 8) & 0xFF; + int sb = (in.specular[i] >> 0) & 0xFF; + + int ea = (in.emissive[i] >> 24) & 0xFF; + int er = (in.emissive[i] >> 16) & 0xFF; + int eg = (in.emissive[i] >> 8) & 0xFF; + int eb = (in.emissive[i] >> 0) & 0xFF; + + float nx = in.normals[3*i + 0]; + float ny = in.normals[3*i + 1]; + float nz = in.normals[3*i + 2]; + float u = in.texcoords[2*i + 0]; + float v = in.texcoords[2*i + 1]; + float sh = in.shininess[i]; + + float x0 = x2; + float y0 = y2; + float z0 = z2; + + PMatrix3D draw = pg.curveDrawMatrix; + + float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4; + float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4; + float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4; + + float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4; + float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4; + float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4; + + float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4; + float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4; + float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4; + + // addVertex() will reset curveVertexCount, so save it +// int savedCount = pg.curveVertexCount; + + //addVertex(x0, y0, z0, code == BREAK ? BREAK : VERTEX); + double[] vertex0 = new double[] { + x0, y0, z0, + fa, fr, fg, fb, + nx, ny, nz, + u, v, + aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; + gluTess.addVertex(vertex0); + + for (int j = 0; j < pg.curveDetail; j++) { + x0 += xplot1; xplot1 += xplot2; xplot2 += xplot3; + y0 += yplot1; yplot1 += yplot2; yplot2 += yplot3; + z0 += zplot1; zplot1 += zplot2; zplot2 += zplot3; + double[] vertex1 = new double[] { + x0, y0, z0, + fa, fr, fg, fb, + nx, ny, nz, + u, v, + aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; + gluTess.addVertex(vertex1); + } + +// pg.curveVertexCount = savedCount; + } + + void addVertex(int i) { + pg.curveVertexCount = 0; + + // Separting colors into individual rgba components for interpolation. + int fa = (in.colors[i] >> 24) & 0xFF; + int fr = (in.colors[i] >> 16) & 0xFF; + int fg = (in.colors[i] >> 8) & 0xFF; + int fb = (in.colors[i] >> 0) & 0xFF; + + int aa = (in.ambient[i] >> 24) & 0xFF; + int ar = (in.ambient[i] >> 16) & 0xFF; + int ag = (in.ambient[i] >> 8) & 0xFF; + int ab = (in.ambient[i] >> 0) & 0xFF; + + int sa = (in.specular[i] >> 24) & 0xFF; + int sr = (in.specular[i] >> 16) & 0xFF; + int sg = (in.specular[i] >> 8) & 0xFF; + int sb = (in.specular[i] >> 0) & 0xFF; + + int ea = (in.emissive[i] >> 24) & 0xFF; + int er = (in.emissive[i] >> 16) & 0xFF; + int eg = (in.emissive[i] >> 8) & 0xFF; + int eb = (in.emissive[i] >> 0) & 0xFF; + + // Vertex data includes coordinates, colors, normals, texture + // coordinates, and material properties. + double[] vertex = new double[] { + in.vertices [3*i + 0], in.vertices [3*i + 1], in.vertices[3*i + 2], + fa, fr, fg, fb, + in.normals [3*i + 0], in.normals [3*i + 1], in.normals [3*i + 2], + in.texcoords[2*i + 0], in.texcoords[2*i + 1], + aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, in.shininess[i]}; + + gluTess.addVertex(vertex); + } + boolean clampPolygon() { return false; } diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShader.java index 0bc608368..220f93352 100644 --- a/core/src/processing/opengl/PShader.java +++ b/core/src/processing/opengl/PShader.java @@ -51,13 +51,12 @@ public class PShader { protected PApplet parent; // The main renderer associated to the parent PApplet. - protected PGraphicsOpenGL pgMain; + //protected PGraphicsOpenGL pgMain; // We need a reference to the renderer since a shader might // be called by different renderers within a single application // (the one corresponding to the main surface, or other offscreen // renderers). - protected PGraphicsOpenGL pgCurrent; - + protected PGraphicsOpenGL pg; protected PGL pgl; protected int context; // The context that created this shader. @@ -87,7 +86,7 @@ public class PShader { public PShader() { parent = null; - pgMain = null; +// pgMain = null; pgl = null; context = -1; @@ -110,7 +109,7 @@ public class PShader { public PShader(PApplet parent) { this(); this.parent = parent; - pgMain = (PGraphicsOpenGL) parent.g; +// pgMain = (PGraphicsOpenGL) parent.g; pgl = PGraphicsOpenGL.pgl; context = pgl.createEmptyContext(); } @@ -126,7 +125,7 @@ public class PShader { */ public PShader(PApplet parent, String vertFilename, String fragFilename) { this.parent = parent; - pgMain = (PGraphicsOpenGL) parent.g; +// pgMain = (PGraphicsOpenGL) parent.g; pgl = PGraphicsOpenGL.pgl; this.vertexURL = null; @@ -149,7 +148,7 @@ public class PShader { */ public PShader(PApplet parent, URL vertURL, URL fragURL) { this.parent = parent; - pgMain = (PGraphicsOpenGL) parent.g; +// pgMain = (PGraphicsOpenGL) parent.g; pgl = PGraphicsOpenGL.pgl; this.vertexURL = vertURL; @@ -623,7 +622,7 @@ public class PShader { pgl.uniformMatrix4fv(loc, 1, false, floatBuffer); } else if (val.type == UniformValue.SAMPLER2D) { PImage img = (PImage)val.value; - Texture tex = pgMain.getTexture(img); + Texture tex = PGraphicsOpenGL.pgPrimary.getTexture(img); if (textures == null) textures = new HashMap(); textures.put(loc, tex); @@ -869,7 +868,7 @@ public class PShader { protected void setRenderer(PGraphicsOpenGL pg) { - pgCurrent = pg; + this.pg = pg; } protected void loadAttributes() { } diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index bd33f666f..5d4ce029e 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -186,9 +186,13 @@ public class PShapeOpenGL extends PShape { // Bezier and Catmull-Rom curves - protected int bezierDetail = 20; - protected int curveDetail = 20; - protected float curveTightness = 0; + protected int bezierDetail; + protected int curveDetail; + protected float curveTightness; + + protected int savedBezierDetail; + protected int savedCurveDetail; + protected float savedCurveTightness; // ........................................................ @@ -290,7 +294,7 @@ public class PShapeOpenGL extends PShape { public PShapeOpenGL(PApplet parent, int family) { - pg = (PGraphicsOpenGL)parent.g; + pg = PGraphicsOpenGL.pgCurrent; pgl = PGraphicsOpenGL.pgl; context = pgl.createEmptyContext(); @@ -321,7 +325,7 @@ public class PShapeOpenGL extends PShape { this.tessellated = false; if (family == GEOMETRY || family == PRIMITIVE || family == PATH) { - inGeo = pg.newInGeometry(PGraphicsOpenGL.RETAINED); + inGeo = PGraphicsOpenGL.newInGeometry(pg, PGraphicsOpenGL.RETAINED); } // Style parameters are retrieved from the current values in the renderer. @@ -356,6 +360,10 @@ public class PShapeOpenGL extends PShape { sphereDetailU = pg.sphereDetailU; sphereDetailV = pg.sphereDetailV; + bezierDetail = pg.bezierDetail; + curveDetail = pg.curveDetail; + curveTightness = pg.curveTightness; + // The rect and ellipse modes are set to CORNER since it is the expected // mode for svg shapes. rectMode = CORNER; @@ -1061,24 +1069,23 @@ public class PShapeOpenGL extends PShape { } inGeo.addVertex(x, y, z, - fcolor, - normalX, normalY, normalZ, - u, v, - scolor, sweight, - ambientColor, specularColor, emissiveColor, shininess, - vertexCode()); + fcolor, + normalX, normalY, normalZ, + u, v, + scolor, sweight, + ambientColor, specularColor, emissiveColor, shininess, + VERTEX, vertexBreak()); markForTessellation(); } - protected int vertexCode() { - int code = VERTEX; + protected boolean vertexBreak() { if (breakShape) { - code = BREAK; breakShape = false; + return true; } - return code; + return false; } @@ -1382,7 +1389,10 @@ public class PShapeOpenGL extends PShape { @Override public void bezierDetail(int detail) { bezierDetail = detail; - pg.bezierDetail(detail); + if (0 < inGeo.codeCount) { + markForTessellation(); + } + //pg.bezierDetail(detail); // setting the detail in the renderer, WTF?? } @@ -1414,8 +1424,15 @@ public class PShapeOpenGL extends PShape { inGeo.setNormal(normalX, normalY, normalZ); inGeo.addBezierVertex(x2, y2, z2, x3, y3, z3, - x4, y4, z4, - fill, stroke, bezierDetail, vertexCode(), kind); + x4, y4, z4, vertexBreak()); + +// inGeo.addVertex(x2, y2, z2, BEZIER_VERTEX, vertexBreak()); +// inGeo.addVertex(x3, y3, z3, BEZIER_VERTEX, false); +// inGeo.addVertex(x4, y4, z4, BEZIER_VERTEX, false); +//// inGeo.addBezierVertex(x2, y2, z2, +// x3, y3, z3, +// x4, y4, z4, +// fill, stroke, bezierDetail, vertexCode(), kind); } @@ -1441,8 +1458,12 @@ public class PShapeOpenGL extends PShape { ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); inGeo.addQuadraticVertex(cx, cy, cz, - x3, y3, z3, - fill, stroke, bezierDetail, vertexCode(), kind); + x3, y3, z3, vertexBreak()); +// inGeo.addVertex(cx, cy, cz, QUADRATIC_VERTEX, vertexBreak()); +// inGeo.addVertex(x3, y3, z3, QUADRATIC_VERTEX, false); +// inGeo.addQuadraticVertex(cx, cy, cz, +// x3, y3, z3, +// fill, stroke, bezierDetail, vertexCode(), kind); } @@ -1456,14 +1477,20 @@ public class PShapeOpenGL extends PShape { @Override public void curveDetail(int detail) { curveDetail = detail; - pg.curveDetail(detail); +// pg.curveDetail(detail); + if (0 < inGeo.codeCount) { + markForTessellation(); + } } @Override public void curveTightness(float tightness) { curveTightness = tightness; - pg.curveTightness(tightness); +// pg.curveTightness(tightness); + if (0 < inGeo.codeCount) { + markForTessellation(); + } } @@ -1483,8 +1510,10 @@ public class PShapeOpenGL extends PShape { inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); - inGeo.addCurveVertex(x, y, z, - fill, stroke, curveDetail, vertexCode(), kind); + inGeo.addCurveVertex(x, y, z, vertexBreak()); +// inGeo.addVertex(x, y, z, CURVE_VERTEX, vertexBreak()); +// inGeo.addCurveVertex(x, y, z, +// fill, stroke, curveDetail, vertexCode(), kind); } @@ -1856,7 +1885,7 @@ public class PShapeOpenGL extends PShape { } else if (this.stroke != stroke) { if (this.stroke) { // Disabling stroke on a shape previously with - // stroke needs a re-tesellation in order to remove + // stroke needs a re-tessellation in order to remove // the additional geometry of lines and/or points. markForTessellation(); stroke = false; @@ -1977,7 +2006,7 @@ public class PShapeOpenGL extends PShape { root.setModifiedLineAttributes(firstLineVertex, lastLineVertex); } else if (is2D()) { // Changing the stroke weight on a 2D shape needs a - // re-tesellation in order to replace the old line + // re-tessellation in order to replace the old line // geometry. markForTessellation(); } @@ -1991,7 +2020,7 @@ public class PShapeOpenGL extends PShape { root.setModifiedPointAttributes(firstPointVertex, lastPointVertex); } else if (is2D()) { // Changing the stroke weight on a 2D shape needs a - // re-tesellation in order to replace the old point + // re-tessellation in order to replace the old point // geometry. markForTessellation(); } @@ -2027,7 +2056,7 @@ public class PShapeOpenGL extends PShape { } else { if (is2D() && strokeJoin != join) { // Changing the stroke join on a 2D shape needs a - // re-tesellation in order to replace the old join + // re-tessellation in order to replace the old join // geometry. markForTessellation(); } @@ -2051,7 +2080,7 @@ public class PShapeOpenGL extends PShape { } else { if (is2D() && strokeCap != cap) { // Changing the stroke cap on a 2D shape needs a - // re-tesellation in order to replace the old cap + // re-tessellation in order to replace the old cap // geometry. markForTessellation(); } @@ -2311,6 +2340,44 @@ public class PShapeOpenGL extends PShape { markForTessellation(); } + /////////////////////////////////////////////////////////// + + // + + // Vertex codes + + @Override + public int[] getVertexCodes() { + if (family == GROUP) return null; + else { + if (inGeo.codes == null) { + return null; + } + if (inGeo.codes.length != inGeo.codeCount) { + inGeo.codes = PApplet.subset(inGeo.codes, 0, inGeo.codeCount); + } + return inGeo.codes; + } + } + + + @Override + public int getVertexCodeCount() { + if (family == GROUP) return 0; + else { + return inGeo.codeCount; + } + } + + + /** + * One of VERTEX, BEZIER_VERTEX, CURVE_VERTEX, or BREAK. + */ + @Override + public int getVertexCode(int index) { + return inGeo.codes[index]; + } + /////////////////////////////////////////////////////////// @@ -2318,6 +2385,7 @@ public class PShapeOpenGL extends PShape { // Tessellated geometry getter. + @Override public PShape getTessellation() { updateTessellation(); @@ -2413,6 +2481,34 @@ public class PShapeOpenGL extends PShape { } + /////////////////////////////////////////////////////////// + + // + + // Geometry utils + + // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html + @Override + public boolean contains(float x, float y) { + if (family == PATH) { + boolean c = false; + for (int i = 0, j = inGeo.vertexCount-1; i < inGeo.vertexCount; j = i++) { + if (((inGeo.vertices[3 * i + 1] > y) != (inGeo.vertices[3 * j + 1] > y)) && + (x < + (inGeo.vertices[3 * j]-inGeo.vertices[3 * i]) * + (y-inGeo.vertices[3 * i + 1]) / + (inGeo.vertices[3 * j + 1]-inGeo.vertices[3 * i + 1]) + + inGeo.vertices[3 * i])) { + c = !c; + } + } + return c; + } else { + throw new IllegalArgumentException("The contains() method is only implemented for paths."); + } + } + + /////////////////////////////////////////////////////////// // @@ -2492,7 +2588,7 @@ public class PShapeOpenGL extends PShape { protected void tessellate() { if (root == this && parent == null) { if (tessGeo == null) { - tessGeo = pg.newTessGeometry(PGraphicsOpenGL.RETAINED); + tessGeo = PGraphicsOpenGL.newTessGeometry(pg, PGraphicsOpenGL.RETAINED); } tessGeo.clear(); @@ -2532,12 +2628,13 @@ public class PShapeOpenGL extends PShape { tessellator.setInGeometry(inGeo); tessellator.setTessGeometry(tessGeo); tessellator.setFill(fill || image != null); + tessellator.setTexCache(null, null, null); tessellator.setStroke(stroke); tessellator.setStrokeColor(strokeColor); tessellator.setStrokeWeight(strokeWeight); tessellator.setStrokeCap(strokeCap); tessellator.setStrokeJoin(strokeJoin); - tessellator.setTexCache(null, null, null); + tessellator.setRenderer(pg); tessellator.setTransform(matrix); tessellator.set3D(is3D()); @@ -2571,9 +2668,16 @@ public class PShapeOpenGL extends PShape { if (normalMode == NORMAL_MODE_AUTO) inGeo.calcQuadStripNormals(); tessellator.tessellateQuadStrip(); } else if (kind == POLYGON) { + boolean bez = inGeo.hasBezierVertex(); + boolean quad = inGeo.hasQuadraticVertex(); + boolean curv = inGeo.hasCurveVertex(); + if (bez || quad) saveBezierVertexSettings(); + if (curv) saveCurveVertexSettings(); if (stroke) inGeo.addPolygonEdges(close); tessellator.tessellatePolygon(solid, close, normalMode == NORMAL_MODE_AUTO); + if (bez ||quad) restoreBezierVertexSettings(); + if (curv) restoreCurveVertexSettings(); } } else if (family == PRIMITIVE) { // The input geometry needs to be cleared because the geometry @@ -2720,7 +2824,7 @@ public class PShapeOpenGL extends PShape { x2, y2, 0, x3, y3, 0, x4, y4, 0, - fill, stroke); + stroke); tessellator.tessellateQuads(); } @@ -2797,11 +2901,12 @@ public class PShapeOpenGL extends PShape { ambientColor, specularColor, emissiveColor, shininess); inGeo.setNormal(normalX, normalY, normalZ); if (rounded) { - inGeo.addRect(a, b, c, d, tl, tr, br, bl, - fill, stroke, bezierDetail); + saveBezierVertexSettings(); + inGeo.addRect(a, b, c, d, tl, tr, br, bl, stroke); tessellator.tessellatePolygon(false, true, true); + restoreBezierVertexSettings(); } else { - inGeo.addRect(a, b, c, d, fill, stroke); + inGeo.addRect(a, b, c, d, stroke); tessellator.tessellateQuads(); } } @@ -2951,10 +3056,23 @@ public class PShapeOpenGL extends PShape { } } + if (nu < 3 || nv < 2) { + nu = nv = 30; + } + int savedDetailU = pg.sphereDetailU; + int savedDetailV = pg.sphereDetailV; + if (pg.sphereDetailU != nu || pg.sphereDetailV != nv) { + pg.sphereDetail(nu, nv); + } + inGeo.setMaterial(fillColor, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); int[] indices = inGeo.addSphere(r, nu, nv, fill, stroke); tessellator.tessellateTriangles(indices); + + if (savedDetailU != nu || savedDetailV != nv) { + pg.sphereDetail(savedDetailU, savedDetailV); + } } @@ -2965,18 +3083,19 @@ public class PShapeOpenGL extends PShape { ambientColor, specularColor, emissiveColor, shininess); if (vertexCodeCount == 0) { // each point is a simple vertex - if (vertices[0].length == 2) { // tesellating 2D vertices + if (vertices[0].length == 2) { // tessellating 2D vertices for (int i = 0; i < vertexCount; i++) { - inGeo.addVertex(vertices[i][X], vertices[i][Y], VERTEX); + inGeo.addVertex(vertices[i][X], vertices[i][Y], VERTEX, false); } } else { // drawing 3D vertices for (int i = 0; i < vertexCount; i++) { - inGeo.addVertex(vertices[i][X], vertices[i][Y], vertices[i][Z], VERTEX); + inGeo.addVertex(vertices[i][X], vertices[i][Y], vertices[i][Z], + VERTEX, false); } } } else { // coded set of vertices int idx = 0; - int code = BREAK; + boolean brk = true; if (vertices[0].length == 2) { // tessellating a 2D path @@ -2984,16 +3103,16 @@ public class PShapeOpenGL extends PShape { switch (vertexCodes[j]) { case VERTEX: - inGeo.addVertex(vertices[idx][X], vertices[idx][Y], code); - code = VERTEX; + inGeo.addVertex(vertices[idx][X], vertices[idx][Y], VERTEX, brk); + brk = false; idx++; break; case QUADRATIC_VERTEX: inGeo.addQuadraticVertex(vertices[idx+0][X], vertices[idx+0][Y], 0, vertices[idx+1][X], vertices[idx+1][Y], 0, - fill, stroke, bezierDetail, code); - code = VERTEX; + brk); + brk = false; idx += 2; break; @@ -3001,20 +3120,19 @@ public class PShapeOpenGL extends PShape { inGeo.addBezierVertex(vertices[idx+0][X], vertices[idx+0][Y], 0, vertices[idx+1][X], vertices[idx+1][Y], 0, vertices[idx+2][X], vertices[idx+2][Y], 0, - fill, stroke, bezierDetail, code); - code = VERTEX; + brk); + brk = false; idx += 3; break; case CURVE_VERTEX: - inGeo.addCurveVertex(vertices[idx][X], vertices[idx][Y], 0, - fill, stroke, curveDetail, code); - code = VERTEX; + inGeo.addCurveVertex(vertices[idx][X], vertices[idx][Y], 0, brk); + brk = false; idx++; break; case BREAK: - code = BREAK; + brk = true; } } } else { // tessellating a 3D path @@ -3023,8 +3141,8 @@ public class PShapeOpenGL extends PShape { case VERTEX: inGeo.addVertex(vertices[idx][X], vertices[idx][Y], - vertices[idx][Z], code); - code = VERTEX; + vertices[idx][Z], brk); + brk = false; idx++; break; @@ -3035,12 +3153,11 @@ public class PShapeOpenGL extends PShape { vertices[idx+1][X], vertices[idx+1][Y], vertices[idx+0][Z], - fill, stroke, bezierDetail, code); - code = VERTEX; + brk); + brk = false; idx += 2; break; - case BEZIER_VERTEX: inGeo.addBezierVertex(vertices[idx+0][X], vertices[idx+0][Y], @@ -3051,8 +3168,8 @@ public class PShapeOpenGL extends PShape { vertices[idx+2][X], vertices[idx+2][Y], vertices[idx+2][Z], - fill, stroke, bezierDetail, code); - code = VERTEX; + brk); + brk = false; idx += 3; break; @@ -3060,22 +3177,61 @@ public class PShapeOpenGL extends PShape { inGeo.addCurveVertex(vertices[idx][X], vertices[idx][Y], vertices[idx][Z], - fill, stroke, curveDetail, code); - code = VERTEX; + brk); + brk = false; idx++; break; case BREAK: - code = BREAK; + brk = true; } } } } + boolean bez = inGeo.hasBezierVertex(); + boolean quad = inGeo.hasQuadraticVertex(); + boolean curv = inGeo.hasCurveVertex(); + if (bez || quad) saveBezierVertexSettings(); + if (curv) saveCurveVertexSettings(); if (stroke) inGeo.addPolygonEdges(close); tessellator.tessellatePolygon(false, close, true); + if (bez || quad) restoreBezierVertexSettings(); + if (curv) restoreCurveVertexSettings(); } + protected void saveBezierVertexSettings() { + savedBezierDetail = pg.bezierDetail; + if (pg.bezierDetail != bezierDetail) { + pg.bezierDetail(bezierDetail); + } + } + + protected void restoreBezierVertexSettings() { + if (savedBezierDetail != bezierDetail) { + pg.bezierDetail(savedBezierDetail); + } + } + + protected void saveCurveVertexSettings() { + savedCurveDetail = pg.curveDetail; + savedCurveTightness = pg.curveTightness; + if (pg.curveDetail != curveDetail) { + pg.curveDetail(curveDetail); + } + if (pg.curveTightness != curveTightness) { + pg.curveTightness(curveTightness); + } + } + + protected void restoreCurveVertexSettings() { + if (savedCurveDetail != curveDetail) { + pg.curveDetail(savedCurveDetail); + } + if (savedCurveTightness != curveTightness) { + pg.curveTightness(savedCurveTightness); + } + } /////////////////////////////////////////////////////////// From d7e2a65cc0c2e5c3519d444dbadca1ade7f9ab02 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Tue, 15 Oct 2013 23:56:48 -0400 Subject: [PATCH 182/556] tessellatePolygon() should be done now --- core/src/processing/opengl/PGraphicsOpenGL.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 3b0cdace3..2ff7157c6 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -11901,15 +11901,16 @@ public class PGraphicsOpenGL extends PGraphics { int vidx = 0; int cidx = 0; while (vidx < in.vertexCount) { - boolean brk = in.breaks[vidx]; - int code = VERTEX; + boolean brk = false; if (in.codes != null) { - + code = in.codes[cidx]; + if (code == BREAK) { + brk = true; + code = in.codes[cidx++]; + } } - // in.codes[cidx]; - if (brk) { gluTess.endContour(); gluTess.beginContour(); From 85e5e7242395cf04794d4ffc9f78748bb17f5f3e Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Wed, 16 Oct 2013 00:05:22 -0400 Subject: [PATCH 183/556] more notes --- todo.txt | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/todo.txt b/todo.txt index 74f0babcf..89c2446d5 100644 --- a/todo.txt +++ b/todo.txt @@ -66,12 +66,11 @@ X add pref to select PDE font (so that CJKV languages work better) X https://github.com/processing/processing/issues/2078 X should we embed the PDE font into the JRE? X this would allow it to show up in the menus, etc -_ but might be a problem on Linux -_ where the JRE is often replaced -_ and where the font is needed most -_ make note of this on the platforms page X type in the status area is gross on retina displays and 7u40 X no longer require restart of Processing when changing the font +_ type looks a little feeble on OS X with non-retina machines +_ https://github.com/processing/processing/issues/2135 +_ should we increase the size of the mode dropdown? serial X closing several bugs because no longer relevant @@ -109,16 +108,6 @@ X basically done in more recent releases X fix file selection dialog with MovieMaker X copied from PApplet, but not importing PApplet -_ type looks a little feeble on OS X with non-retina machines -_ https://github.com/processing/processing/issues/2135 -_ should we increase the size of the mode dropdown? -_ type cut off in dialog boxes on OS X retina machines -_ https://github.com/processing/processing/issues/2116 -_ add spaces to the end of the text? -_ dialog box icon is fuzzy on OS X retina machines -_ https://github.com/processing/processing/issues/2117 -_ solution might be our own dialog boxes (see 'dialogs' section) - build X remove video library for other platforms in download X update apple.jar file with new version @@ -165,6 +154,12 @@ _ to build appbundler, you'll need Xcode _ and the command line tools Preferences > Downloads > Command Line Tools _ appbundler will have an NPE if the osx binary isn't built _ also need to have 10.8 version of the SDK (old Xcode won't work) +_ changing JRE might be a problem for fonts on Linux +_ where the JRE is often replaced +_ and where the font is needed most +_ make note of this on the platforms page +_ also make note re: only JRE needed (instead of JDK) +_ http://wiki.processing.org/index.php?title=Supported_Platforms&action=edit§ion=4 7u40 macosx X make OS X launch from its local JRE @@ -239,9 +234,6 @@ _ i.e. PVector.copy() not in the reference _ local web server to run reference from .zip? _ no more gazillion file nastiness _ yahoo search example is out of date (included in the examples? the book?) -_ improve documentation of the pdf stuff -_ be clearer about the font setup stuff -_ fonts by default not working that well? _ stop() to shut down a sketch (but not quit/close window) _ actually pause/resume _ MIN_FLOAT, MAX_FLOAT, also the difference from the Java functions @@ -301,6 +293,9 @@ _ 3) use createFont() (which you already are) _ this will convert all the shape data from the fonts for writing. _ it will be *extremely* slow, which is part of why it's not documented yet. _ but it will work with beginRaw(). +_ improve documentation of the pdf stuff +_ be clearer about the font setup stuff +_ fonts by default not working that well? DOC / Other @@ -404,6 +399,12 @@ PDE - Processing Development Environment PDE / Dialogs +_ type cut off in dialog boxes on OS X retina machines +_ https://github.com/processing/processing/issues/2116 +_ add spaces to the end of the text? +_ dialog box icon is fuzzy on OS X retina machines +_ https://github.com/processing/processing/issues/2117 +_ solution might be our own dialog boxes _ two-tiered dialogs for everything - use big font/little font style throughout _ http://javagraphics.blogspot.com/2008/06/joptionpane-making-alternative.html _ option to suppress warning dialogs From 62f07ec9ceccba46d3465df3e28cd2709222def2 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Wed, 16 Oct 2013 00:13:51 -0400 Subject: [PATCH 184/556] a couple of tweaks --- .../processing/opengl/PGraphicsOpenGL.java | 30 +++++++++++-------- core/src/processing/opengl/PShapeOpenGL.java | 11 ++----- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 2ff7157c6..55a818774 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -7497,7 +7497,7 @@ public class PGraphicsOpenGL extends PGraphics { int[] strokeColors; float[] strokeWeights; - // codes + // vertex codes int[] codes; boolean[] breaks; @@ -7789,6 +7789,10 @@ public class PGraphicsOpenGL extends PGraphics { trimBreaks(); } + if (0 < codeCount && codeCount < codes.length) { + trimCodes(); + } + if (0 < edgeCount && edgeCount < edges.length) { trimEdges(); } @@ -7854,11 +7858,11 @@ public class PGraphicsOpenGL extends PGraphics { shininess = temp; } -// void trimCodes() { -// int temp[] = new int[vertexCount]; -// PApplet.arrayCopy(codes, 0, temp, 0, vertexCount); -// codes = temp; -// } + void trimCodes() { + int temp[] = new int[codeCount]; + PApplet.arrayCopy(codes, 0, temp, 0, codeCount); + codes = temp; + } void trimBreaks() { boolean temp[] = new boolean[vertexCount]; @@ -7982,22 +7986,24 @@ public class PGraphicsOpenGL extends PGraphics { breaks[vertexCount] = brk; - if (code == BEZIER_VERTEX || code == QUADRATIC_VERTEX || - code == CURVE_VERTEX || (code == VERTEX && codes != null) || brk) { + if (brk || (code == VERTEX && codes != null) || + code == BEZIER_VERTEX || + code == QUADRATIC_VERTEX || + code == CURVE_VERTEX) { if (codes == null) { - codes = new int[vertexCount]; - Arrays.fill(codes, 0, vertexCount, VERTEX); + codes = new int[PApplet.max(PGL.DEFAULT_IN_VERTICES, vertexCount)]; + Arrays.fill(codes, 0, codes.length, VERTEX); } if (brk) { codeCheck(); - codes[vertexCount] = BREAK; + codes[codeCount] = BREAK; codeCount++; } if (code != -1) { codeCheck(); - codes[vertexCount] = code; + codes[codeCount] = code; codeCount++; } } diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index 5d4ce029e..de5a703d8 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -2350,12 +2350,7 @@ public class PShapeOpenGL extends PShape { public int[] getVertexCodes() { if (family == GROUP) return null; else { - if (inGeo.codes == null) { - return null; - } - if (inGeo.codes.length != inGeo.codeCount) { - inGeo.codes = PApplet.subset(inGeo.codes, 0, inGeo.codeCount); - } + if (inGeo.codes == null) return null; return inGeo.codes; } } @@ -2364,9 +2359,7 @@ public class PShapeOpenGL extends PShape { @Override public int getVertexCodeCount() { if (family == GROUP) return 0; - else { - return inGeo.codeCount; - } + else return inGeo.codeCount; } From 92755a2b1affb955bc1245719fd6a2e28b6ba02c Mon Sep 17 00:00:00 2001 From: codeanticode Date: Wed, 16 Oct 2013 00:14:12 -0400 Subject: [PATCH 185/556] a few more --- core/src/processing/opengl/PShapeOpenGL.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index de5a703d8..c1c59a919 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -2346,6 +2346,7 @@ public class PShapeOpenGL extends PShape { // Vertex codes + @Override public int[] getVertexCodes() { if (family == GROUP) return null; From 2636366a1848e9d4bf006d8b31f1888c391c13d8 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Wed, 16 Oct 2013 00:16:50 -0400 Subject: [PATCH 186/556] removed unnecessary references to curveVertexCount --- core/src/processing/opengl/PGraphicsOpenGL.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 55a818774..3c70ea0e1 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -2067,7 +2067,6 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void beginShape(int kind) { shape = kind; -// curveVertexCount = 0; inGeo.clear(); breakShape = true; @@ -12186,10 +12185,6 @@ public class PGraphicsOpenGL extends PGraphics { float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4; float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4; - // addVertex() will reset curveVertexCount, so save it -// int savedCount = pg.curveVertexCount; - - //addVertex(x0, y0, z0, code == BREAK ? BREAK : VERTEX); double[] vertex0 = new double[] { x0, y0, z0, fa, fr, fg, fb, @@ -12210,8 +12205,6 @@ public class PGraphicsOpenGL extends PGraphics { aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; gluTess.addVertex(vertex1); } - -// pg.curveVertexCount = savedCount; } void addVertex(int i) { From 901a4bf1c15dde97781f059ce3afbae23477f422 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Wed, 16 Oct 2013 11:39:09 -0400 Subject: [PATCH 187/556] argh, this println() thing is a mess... --- core/src/processing/core/PApplet.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index 1077b794a..129a3516b 100755 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -4501,13 +4501,17 @@ public class PApplet extends Applet /** - * Use printArray() instead. This function causes a warning because the new - * print(Object...) and println(Object...) functions can't be reliably - * bound by the compiler. + * For arrays, use printArray() instead. This function causes a warning + * because the new print(Object...) and println(Object...) functions can't + * be reliably bound by the compiler. */ - @Deprecated static public void println(Object what) { - printArray(what); + if (what != null && what.getClass().isArray()) { + printArray(what); + } else { + System.out.println(what.toString()); + System.out.flush(); + } } From 8e47e8b3c5d914571d205da3228a8bf2eba27d59 Mon Sep 17 00:00:00 2001 From: melgior Date: Thu, 17 Oct 2013 13:17:33 +0200 Subject: [PATCH 188/556] Updated Arduino example code to be Arduino 1.0+ compatible --- java/libraries/serial/examples/SimpleRead/SimpleRead.pde | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/libraries/serial/examples/SimpleRead/SimpleRead.pde b/java/libraries/serial/examples/SimpleRead/SimpleRead.pde index b5b455e13..856da8f17 100644 --- a/java/libraries/serial/examples/SimpleRead/SimpleRead.pde +++ b/java/libraries/serial/examples/SimpleRead/SimpleRead.pde @@ -54,9 +54,9 @@ void setup() { void loop() { if (digitalRead(switchPin) == HIGH) { // If switch is ON, - Serial.print(1, BYTE); // send 1 to Processing + Serial.write(1); // send 1 to Processing } else { // If the switch is not ON, - Serial.print(0, BYTE); // send 0 to Processing + Serial.write(0); // send 0 to Processing } delay(100); // Wait 100 milliseconds } From f5eb74c0834392dbea206f1d3d905618a3a4ce80 Mon Sep 17 00:00:00 2001 From: melgior Date: Thu, 17 Oct 2013 13:20:53 +0200 Subject: [PATCH 189/556] Updated Arduino example code to be Arduino 1.0+ compatible --- .../examples/SerialCallResponse/SerialCallResponse.pde | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/java/libraries/serial/examples/SerialCallResponse/SerialCallResponse.pde b/java/libraries/serial/examples/SerialCallResponse/SerialCallResponse.pde index cae1e6a1d..b68641ac0 100644 --- a/java/libraries/serial/examples/SerialCallResponse/SerialCallResponse.pde +++ b/java/libraries/serial/examples/SerialCallResponse/SerialCallResponse.pde @@ -133,15 +133,15 @@ void loop() // so that you're sending 100 or 255: thirdSensor = 100 + (155 * digitalRead(2)); // send sensor values: - Serial.print(firstSensor, BYTE); - Serial.print(secondSensor, BYTE); - Serial.print(thirdSensor, BYTE); + Serial.write(firstSensor); + Serial.write(secondSensor); + Serial.write(thirdSensor); } } void establishContact() { while (Serial.available() <= 0) { - Serial.print('A', BYTE); // send a capital A + Serial.write('A'); // send a capital A delay(300); } } From e208f2fec8a2d4a9a56b95e7e0660054e53f64ee Mon Sep 17 00:00:00 2001 From: melgior Date: Thu, 17 Oct 2013 13:22:10 +0200 Subject: [PATCH 190/556] Updated Arduino example code to be Arduino 1.0+ compatible --- .../libraries/serial/examples/SerialMultiple/SerialMultiple.pde | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/libraries/serial/examples/SerialMultiple/SerialMultiple.pde b/java/libraries/serial/examples/SerialMultiple/SerialMultiple.pde index 4334e1a2b..cd46cbcd8 100644 --- a/java/libraries/serial/examples/SerialMultiple/SerialMultiple.pde +++ b/java/libraries/serial/examples/SerialMultiple/SerialMultiple.pde @@ -77,7 +77,7 @@ void setup() void loop() { // read analog input, divide by 4 to make the range 0-255: int analogValue = analogRead(0)/4; - Serial.print(analogValue, BYTE); + Serial.write(analogValue); // pause for 10 milliseconds: delay(10); } From d0411d434dfd1baf94bc9a48abd2c891917d6fdc Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 17 Oct 2013 16:37:19 -0400 Subject: [PATCH 191/556] don't use breaks array in addPolygonEdges --- .../processing/opengl/PGraphicsOpenGL.java | 129 +++++++++++++----- 1 file changed, 94 insertions(+), 35 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 3c70ea0e1..142e93492 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -7498,7 +7498,6 @@ public class PGraphicsOpenGL extends PGraphics { // vertex codes int[] codes; - boolean[] breaks; // Stroke edges int[][] edges; @@ -7550,7 +7549,6 @@ public class PGraphicsOpenGL extends PGraphics { specular = new int[PGL.DEFAULT_IN_VERTICES]; emissive = new int[PGL.DEFAULT_IN_VERTICES]; shininess = new float[PGL.DEFAULT_IN_VERTICES]; - breaks = new boolean[PGL.DEFAULT_IN_VERTICES]; edges = new int[PGL.DEFAULT_IN_EDGES][3]; clear(); @@ -7570,7 +7568,6 @@ public class PGraphicsOpenGL extends PGraphics { expandSpecular(newSize); expandEmissive(newSize); expandShininess(newSize); - expandBreaks(newSize); } } @@ -7757,12 +7754,6 @@ public class PGraphicsOpenGL extends PGraphics { codes = temp; } - void expandBreaks(int n) { - boolean temp[] = new boolean[n]; - PApplet.arrayCopy(breaks, 0, temp, 0, vertexCount); - breaks = temp; - } - void expandEdges(int n) { int temp[][] = new int[n][3]; PApplet.arrayCopy(edges, 0, temp, 0, edgeCount); @@ -7785,7 +7776,6 @@ public class PGraphicsOpenGL extends PGraphics { trimSpecular(); trimEmissive(); trimShininess(); - trimBreaks(); } if (0 < codeCount && codeCount < codes.length) { @@ -7863,12 +7853,6 @@ public class PGraphicsOpenGL extends PGraphics { codes = temp; } - void trimBreaks() { - boolean temp[] = new boolean[vertexCount]; - PApplet.arrayCopy(breaks, 0, temp, 0, vertexCount); - breaks = temp; - } - void trimEdges() { int temp[][] = new int[edgeCount][3]; PApplet.arrayCopy(edges, 0, temp, 0, edgeCount); @@ -7983,8 +7967,6 @@ public class PGraphicsOpenGL extends PGraphics { emissive[vertexCount] = PGL.javaToNativeARGB(em); shininess[vertexCount] = shine; - breaks[vertexCount] = brk; - if (brk || (code == VERTEX && codes != null) || code == BEZIER_VERTEX || code == QUADRATIC_VERTEX || @@ -8341,7 +8323,84 @@ public class PGraphicsOpenGL extends PGraphics { } void addPolygonEdges(boolean closed) { - // TODO: need to expand bezier, quadratic and curve vertices...crap. + int start = 0; + boolean begin = true; + int i = 0; + int c = 0; + while (i < vertexCount) { + int code = VERTEX; + boolean brk = false; + boolean brk1 = false; + if (codes != null && c < codes.length) { + code = codes[c++]; + if (code == BREAK && c < codes.length) { + brk = true; + code = codes[c++]; + } + if (c < codes.length) brk1 = codes[c] == BREAK; + } + + if (brk) { + if (closed) { + // Closing previous contour. + addEdge(i - 1, start, begin, false); + closeEdge(i - 1, start); + } + + // Starting new contour. + start = i; + begin = true; + } else { + if (i == vertexCount - 1) { + if (closed && start + 1 < i) { + // Closing the end of the last contour, if it + // has more than 1 segment. + addEdge(i - 1, i, begin, false); + addEdge(i, start, false, false); + closeEdge(i, start); + } else { + // Leaving the last contour open. + addEdge(i - 1, i, begin, true); + } + } else { + + if ((i < vertexCount - 1) && brk1 && !closed) { + // A new contour starts at the next vertex and + // the polygon is not closed, so this is the last + // segment of the current contour. + addEdge(i - 1, i, begin, true); + } else { + // The current contour does not end at vertex i. + addEdge(i - 1, i, begin, false); + } + } + + begin = false; + } + + + + + + + + if (code == BEZIER_VERTEX) { + i += 3; + } else if (code == QUADRATIC_VERTEX) { + i += 2; + } else if (code == CURVE_VERTEX) { + i++; + } else { + i++; + } + } + + //for (int j = 0; j < pg.bezierDetail; j++) { + //for (int j = 0; j < pg.curveDetail; j++) { + + + +/* int start = 0; boolean begin = true; @@ -8384,7 +8443,7 @@ public class PGraphicsOpenGL extends PGraphics { begin = false; } } - +*/ } @@ -11903,16 +11962,16 @@ public class PGraphicsOpenGL extends PGraphics { gluTess.beginContour(); // Now, iterate over all input data and send to GLU tessellator.. - int vidx = 0; - int cidx = 0; - while (vidx < in.vertexCount) { + int i = 0; + int c = 0; + while (i < in.vertexCount) { int code = VERTEX; boolean brk = false; - if (in.codes != null) { - code = in.codes[cidx]; - if (code == BREAK) { + if (in.codes != null && c < in.codes.length) { + code = in.codes[c++]; + if (code == BREAK && c < in.codes.length) { brk = true; - code = in.codes[cidx++]; + code = in.codes[c++]; } } @@ -11922,17 +11981,17 @@ public class PGraphicsOpenGL extends PGraphics { } if (code == BEZIER_VERTEX) { - addBezierVertex(vidx); - vidx += 3; + addBezierVertex(i); + i += 3; } else if (code == QUADRATIC_VERTEX) { - addQuadraticVertex(vidx); - vidx += 2; + addQuadraticVertex(i); + i += 2; } else if (code == CURVE_VERTEX) { - addCurveVertex(vidx); - vidx++; + addCurveVertex(i); + i++; } else { - addVertex(vidx); - vidx++; + addVertex(i); + i++; } } gluTess.endContour(); From 3231d63fbd34b6a74b1d2f0ae88303d1b6529c4f Mon Sep 17 00:00:00 2001 From: codeanticode Date: Thu, 17 Oct 2013 18:55:24 -0400 Subject: [PATCH 192/556] fixed handling of breaks --- .../processing/opengl/PGraphicsOpenGL.java | 27 ++++++++++++------- core/src/processing/opengl/PShapeOpenGL.java | 6 +---- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 142e93492..9ff81f365 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -2069,7 +2069,7 @@ public class PGraphicsOpenGL extends PGraphics { shape = kind; inGeo.clear(); - breakShape = true; + breakShape = false; defaultEdges = true; textureImage0 = textureImage; @@ -7973,7 +7973,8 @@ public class PGraphicsOpenGL extends PGraphics { code == CURVE_VERTEX) { if (codes == null) { codes = new int[PApplet.max(PGL.DEFAULT_IN_VERTICES, vertexCount)]; - Arrays.fill(codes, 0, codes.length, VERTEX); + Arrays.fill(codes, 0, vertexCount, VERTEX); + codeCount = vertexCount; } if (brk) { @@ -8325,19 +8326,27 @@ public class PGraphicsOpenGL extends PGraphics { void addPolygonEdges(boolean closed) { int start = 0; boolean begin = true; - int i = 0; - int c = 0; + int i = 1; + + int c = 1; + + // The following line handles the situation when the vertex codes start + // with a BREAK. This can only be the result of starting a shape with a + // contour, which doesn't work on JAVA2D. + // In order to mantain consistency between renderers, it is disabled. + // if (0 < codeCount && codes[0] == BREAK) c++; + while (i < vertexCount) { int code = VERTEX; boolean brk = false; boolean brk1 = false; - if (codes != null && c < codes.length) { + if (codes != null && c < codeCount) { code = codes[c++]; - if (code == BREAK && c < codes.length) { + if (code == BREAK && c < codeCount) { brk = true; code = codes[c++]; } - if (c < codes.length) brk1 = codes[c] == BREAK; + if (c < codeCount) brk1 = codes[c] == BREAK; } if (brk) { @@ -11967,9 +11976,9 @@ public class PGraphicsOpenGL extends PGraphics { while (i < in.vertexCount) { int code = VERTEX; boolean brk = false; - if (in.codes != null && c < in.codes.length) { + if (in.codes != null && c < in.codeCount) { code = in.codes[c++]; - if (code == BREAK && c < in.codes.length) { + if (code == BREAK && c < in.codeCount) { brk = true; code = in.codes[c++]; } diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index c1c59a919..282df1054 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -376,7 +376,7 @@ public class PShapeOpenGL extends PShape { // To make sure that the first vertex is marked as a break. // Same behavior as in the immediate mode. - breakShape = true; + breakShape = false; if (family == GROUP) { // GROUP shapes are always marked as ended. @@ -992,9 +992,6 @@ public class PShapeOpenGL extends PShape { } -//public void beginContour() { -//super.beginContour(); - @Override protected void beginContourImpl() { breakShape = true; @@ -1006,7 +1003,6 @@ public class PShapeOpenGL extends PShape { } - @Override public void vertex(float x, float y) { vertexImpl(x, y, 0, 0, 0); From 31b9f385f54bbe67c009520354294743f2c8bffd Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 18 Oct 2013 11:44:20 -0400 Subject: [PATCH 193/556] finished implementing new path tessellation using vertex codes --- .../processing/opengl/PGraphicsOpenGL.java | 488 +++++++++++------- core/src/processing/opengl/PShapeOpenGL.java | 4 +- 2 files changed, 298 insertions(+), 194 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 9ff81f365..9066e9f5c 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -2286,7 +2286,7 @@ public class PGraphicsOpenGL extends PGraphics { if (normalMode == NORMAL_MODE_AUTO) inGeo.calcQuadStripNormals(); tessellator.tessellateQuadStrip(); } else if (shape == POLYGON) { - if (stroke && defaultEdges) inGeo.addPolygonEdges(mode == CLOSE); +// if (stroke && defaultEdges) inGeo.addPolygonEdges(mode == CLOSE); tessellator.tessellatePolygon(false, mode == CLOSE, normalMode == NORMAL_MODE_AUTO); } @@ -8241,7 +8241,7 @@ public class PGraphicsOpenGL extends PGraphics { int[] edge = edges[edgeCount]; edge[0] = i; edge[1] = j; - edge[2] = -1; + edge[2] = EDGE_CLOSE; edgeCount++; @@ -8323,6 +8323,7 @@ public class PGraphicsOpenGL extends PGraphics { } } + /* void addPolygonEdges(boolean closed) { int start = 0; boolean begin = true; @@ -8387,12 +8388,6 @@ public class PGraphicsOpenGL extends PGraphics { begin = false; } - - - - - - if (code == BEZIER_VERTEX) { i += 3; } else if (code == QUADRATIC_VERTEX) { @@ -8403,58 +8398,8 @@ public class PGraphicsOpenGL extends PGraphics { i++; } } - - //for (int j = 0; j < pg.bezierDetail; j++) { - //for (int j = 0; j < pg.curveDetail; j++) { - - - -/* - - int start = 0; - boolean begin = true; - for (int i = 1; i <= vertexCount - 1; i++) { - if (breaks[i]) { - if (closed) { - // Closing previous contour. - addEdge(i - 1, start, begin, false); - closeEdge(i - 1, start); - } - - // Starting new contour. - start = i; - begin = true; - } else { - if (i == vertexCount - 1) { - if (closed && start + 1 < i) { - // Closing the end of the last contour, if it - // has more than 1 segment. - addEdge(i - 1, i, begin, false); - addEdge(i, start, false, false); - closeEdge(i, start); - } else { - // Leaving the last contour open. - addEdge(i - 1, i, begin, true); - } - } else { - - if ((i < vertexCount - 1) && breaks[i + 1] && !closed) { - // A new contour starts at the next vertex and - // the polygon is not closed, so this is the last - // segment of the current contour. - addEdge(i - 1, i, begin, true); - } else { - // The current contour does not end at vertex i. - addEdge(i - 1, i, begin, false); - } - } - - begin = false; - } - } -*/ - } +*/ // ----------------------------------------------------------------- // @@ -8679,7 +8624,7 @@ public class PGraphicsOpenGL extends PGraphics { addVertex(a, b, VERTEX, false); } - if (stroke) addPolygonEdges(true); +// if (stroke) addPolygonEdges(true); } void addEllipse(float x, float y, float w, float h, @@ -9924,13 +9869,13 @@ public class PGraphicsOpenGL extends PGraphics { // // Add line geometry - void setLineVertex(int tessIdx, InGeometry in, int inIdx0, int rgba) { + void setLineVertex(int tessIdx, float[] vertices, int inIdx0, int rgba) { int index; index = 3 * inIdx0; - float x0 = in.vertices[index++]; - float y0 = in.vertices[index++]; - float z0 = in.vertices[index ]; + float x0 = vertices[index++]; + float y0 = vertices[index++]; + float z0 = vertices[index ]; if (renderMode == IMMEDIATE && pg.flushMode == FLUSH_WHEN_FULL) { PMatrix3D mm = pg.modelview; @@ -9957,20 +9902,20 @@ public class PGraphicsOpenGL extends PGraphics { } // Sets line vertex with index tessIdx using the data from input vertices - //inIdx0 and inIdx1. - void setLineVertex(int tessIdx, InGeometry in, int inIdx0, int inIdx1, + // inIdx0 and inIdx1. + void setLineVertex(int tessIdx, float[] vertices, int inIdx0, int inIdx1, int rgba, float weight) { int index; index = 3 * inIdx0; - float x0 = in.vertices[index++]; - float y0 = in.vertices[index++]; - float z0 = in.vertices[index ]; + float x0 = vertices[index++]; + float y0 = vertices[index++]; + float z0 = vertices[index ]; index = 3 * inIdx1; - float x1 = in.vertices[index++]; - float y1 = in.vertices[index++]; - float z1 = in.vertices[index ]; + float x1 = vertices[index++]; + float y1 = vertices[index++]; + float z1 = vertices[index ]; float dx = x1 - x0; float dy = y1 - y0; @@ -11056,6 +11001,9 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateEdges() { if (stroke) { if (in.edgeCount == 0) return; + strokeVertices = in.vertices; + strokeColors = in.strokeColors; + strokeWeights = in.strokeWeights; if (is3D) { tessellateEdges3D(); } else if (is2D) { @@ -11128,28 +11076,28 @@ public class PGraphicsOpenGL extends PGraphics { int i1 = edge[1]; switch (edge[2]) { case EDGE_MIDDLE: - path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1], - in.strokeColors[i1]); + path.lineTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1], + strokeColors[i1]); break; case EDGE_START: - path.moveTo(in.vertices[3 * i0 + 0], in.vertices[3 * i0 + 1], - in.strokeColors[i0]); - path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1], - in.strokeColors[i1]); + path.moveTo(strokeVertices[3 * i0 + 0], strokeVertices[3 * i0 + 1], + strokeColors[i0]); + path.lineTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1], + strokeColors[i1]); break; case EDGE_STOP: - path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1], - in.strokeColors[i1]); - path.moveTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1], - in.strokeColors[i1]); + path.lineTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1], + strokeColors[i1]); + path.moveTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1], + strokeColors[i1]); break; case EDGE_SINGLE: - path.moveTo(in.vertices[3 * i0 + 0], in.vertices[3 * i0 + 1], - in.strokeColors[i0]); - path.lineTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1], - in.strokeColors[i1]); - path.moveTo(in.vertices[3 * i1 + 0], in.vertices[3 * i1 + 1], - in.strokeColors[i1]); + path.moveTo(strokeVertices[3 * i0 + 0], strokeVertices[3 * i0 + 1], + strokeColors[i0]); + path.lineTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1], + strokeColors[i1]); + path.moveTo(strokeVertices[3 * i1 + 0], strokeVertices[3 * i1 + 1], + strokeColors[i1]); break; case EDGE_CLOSE: path.closePath(); @@ -11168,7 +11116,7 @@ public class PGraphicsOpenGL extends PGraphics { if (edge[2] == EDGE_CLOSE) continue; int i0 = edge[0]; int i1 = edge[1]; - res = segmentIsAxisAligned(i0, i1); + res = segmentIsAxisAligned(strokeVertices, i0, i1); if (!res) break; } } @@ -11178,7 +11126,7 @@ public class PGraphicsOpenGL extends PGraphics { // Adding the data that defines a quad starting at vertex i0 and // ending at i1. int addLineSegment3D(int i0, int i1, int index, short[] lastInd, - boolean constStroke) { + boolean constStroke) { IndexCache cache = tess.lineIndexCache; int count = cache.vertexCount[index]; boolean addBevel = lastInd != null && -1 < lastInd[0] && -1 < lastInd[1]; @@ -11194,26 +11142,26 @@ public class PGraphicsOpenGL extends PGraphics { int color, color0; float weight; - color0 = color = constStroke ? strokeColor : in.strokeColors[i0]; - weight = constStroke ? strokeWeight : in.strokeWeights[i0]; + color0 = color = constStroke ? strokeColor : strokeColors[i0]; + weight = constStroke ? strokeWeight : strokeWeights[i0]; - tess.setLineVertex(vidx++, in, i0, i1, color, +weight/2); + tess.setLineVertex(vidx++, strokeVertices, i0, i1, color, +weight/2); tess.lineIndices[iidx++] = (short) (count + 0); - tess.setLineVertex(vidx++, in, i0, i1, color, -weight/2); + tess.setLineVertex(vidx++, strokeVertices, i0, i1, color, -weight/2); tess.lineIndices[iidx++] = (short) (count + 1); - color = constStroke ? strokeColor : in.strokeColors[i1]; - weight = constStroke ? strokeWeight : in.strokeWeights[i1]; + color = constStroke ? strokeColor : strokeColors[i1]; + weight = constStroke ? strokeWeight : strokeWeights[i1]; - tess.setLineVertex(vidx++, in, i1, i0, color, -weight/2); + tess.setLineVertex(vidx++, strokeVertices, i1, i0, color, -weight/2); tess.lineIndices[iidx++] = (short) (count + 2); // Starting a new triangle re-using prev vertices. tess.lineIndices[iidx++] = (short) (count + 2); tess.lineIndices[iidx++] = (short) (count + 1); - tess.setLineVertex(vidx++, in, i1, i0, color, +weight/2); + tess.setLineVertex(vidx++, strokeVertices, i1, i0, color, +weight/2); tess.lineIndices[iidx++] = (short) (count + 3); cache.incCounts(index, 6, 4); @@ -11221,7 +11169,7 @@ public class PGraphicsOpenGL extends PGraphics { if (lastInd != null) { if (-1 < lastInd[0] && -1 < lastInd[1]) { // Adding bevel triangles - tess.setLineVertex(vidx, in, i0, color0); + tess.setLineVertex(vidx, strokeVertices, i0, color0); if (newCache) { PGraphics.showWarning(TOO_LONG_STROKE_PATH_ERROR); @@ -11269,11 +11217,11 @@ public class PGraphicsOpenGL extends PGraphics { } int iidx = cache.indexOffset[index] + cache.indexCount[index]; int vidx = cache.vertexOffset[index] + cache.vertexCount[index]; - int color0 = constStroke ? strokeColor : in.strokeColors[i0]; + int color0 = constStroke ? strokeColor : strokeColors[i0]; if (lastInd != null) { if (-1 < lastInd[0] && -1 < lastInd[1]) { - tess.setLineVertex(vidx, in, i0, color0); + tess.setLineVertex(vidx, strokeVertices, i0, color0); if (newCache) { PGraphics.showWarning(TOO_LONG_STROKE_PATH_ERROR); @@ -11308,7 +11256,7 @@ public class PGraphicsOpenGL extends PGraphics { // ending at i1, in the case of pure 2D renderers (line geometry // is added to the poly arrays). int addLineSegment2D(int i0, int i1, int index, - boolean constStroke, boolean clamp) { + boolean constStroke, boolean clamp) { IndexCache cache = tess.polyIndexCache; int count = cache.vertexCount[index]; if (PGL.MAX_VERTEX_INDEX1 <= count + 4) { @@ -11319,15 +11267,15 @@ public class PGraphicsOpenGL extends PGraphics { int iidx = cache.indexOffset[index] + cache.indexCount[index]; int vidx = cache.vertexOffset[index] + cache.vertexCount[index]; - int color = constStroke ? strokeColor : in.strokeColors[i0]; - float weight = constStroke ? strokeWeight : in.strokeWeights[i0]; + int color = constStroke ? strokeColor : strokeColors[i0]; + float weight = constStroke ? strokeWeight : strokeWeights[i0]; if (subPixelStroke(weight)) clamp = false; - float x0 = in.vertices[3 * i0 + 0]; - float y0 = in.vertices[3 * i0 + 1]; + float x0 = strokeVertices[3 * i0 + 0]; + float y0 = strokeVertices[3 * i0 + 1]; - float x1 = in.vertices[3 * i1 + 0]; - float y1 = in.vertices[3 * i1 + 1]; + float x1 = strokeVertices[3 * i1 + 0]; + float y1 = strokeVertices[3 * i1 + 1]; // Calculating direction and normal of the line. float dirx = x1 - x0; @@ -11372,8 +11320,8 @@ public class PGraphicsOpenGL extends PGraphics { } if (!constStroke) { - color = in.strokeColors[i1]; - weight = in.strokeWeights[i1]; + color = strokeColors[i1]; + weight = strokeWeights[i1]; normdx = normx * weight/2; normdy = normy * weight/2; if (subPixelStroke(weight)) clamp = false; @@ -11469,6 +11417,11 @@ public class PGraphicsOpenGL extends PGraphics { zero(in.vertices[3 * i0 + 1] - in.vertices[3 * i1 + 1]); } + boolean segmentIsAxisAligned(float[] vertices, int i0, int i1) { + return zero(vertices[3 * i0 + 0] - vertices[3 * i1 + 0]) || + zero(vertices[3 * i0 + 1] - vertices[3 * i1 + 1]); + } + // ----------------------------------------------------------------- // // Polygon primitives tessellation @@ -11945,7 +11898,7 @@ public class PGraphicsOpenGL extends PGraphics { // ----------------------------------------------------------------- // - // Polygon tessellation + // Polygon tessellation, includes edge calculation and tessellation. void tessellatePolygon(boolean solid, boolean closed, boolean calcNormals) { beginTex(); @@ -11968,11 +11921,14 @@ public class PGraphicsOpenGL extends PGraphics { gluTess.setWindingRule(PGL.TESS_WINDING_ODD); } - gluTess.beginContour(); - - // Now, iterate over all input data and send to GLU tessellator.. + // Now, iterate over all input data and send to GLU tessellator... int i = 0; int c = 0; + gluTess.beginContour(); + if (stroke) { + beginPolygonStroke(); + beginStrokePath(); + } while (i < in.vertexCount) { int code = VERTEX; boolean brk = false; @@ -11985,6 +11941,10 @@ public class PGraphicsOpenGL extends PGraphics { } if (brk) { + if (stroke) { + endStrokePath(closed); + beginStrokePath(); + } gluTess.endContour(); gluTess.beginContour(); } @@ -12003,13 +11963,16 @@ public class PGraphicsOpenGL extends PGraphics { i++; } } + if (stroke) { + endStrokePath(closed); + endPolygonStroke(); + } gluTess.endContour(); - gluTess.endPolygon(); } endTex(); - tessellateEdges(); + if (stroke) tessellateStrokePath(); } void addBezierVertex(int i) { @@ -12024,25 +11987,36 @@ public class PGraphicsOpenGL extends PGraphics { float y1 = in.vertices[3*i1 + 1]; float z1 = in.vertices[3*i1 + 2]; - int fa = (in.colors[i] >> 24) & 0xFF; - int fr = (in.colors[i] >> 16) & 0xFF; - int fg = (in.colors[i] >> 8) & 0xFF; - int fb = (in.colors[i] >> 0) & 0xFF; + int strokeColor = 0; + float strokeWeight = 0; + if (stroke) { + strokeColor = in.strokeColors[i]; + strokeWeight = in.strokeWeights[i]; + } - int aa = (in.ambient[i] >> 24) & 0xFF; - int ar = (in.ambient[i] >> 16) & 0xFF; - int ag = (in.ambient[i] >> 8) & 0xFF; - int ab = (in.ambient[i] >> 0) & 0xFF; + int fcol = in.colors[i]; + int fa = (fcol >> 24) & 0xFF; + int fr = (fcol >> 16) & 0xFF; + int fg = (fcol >> 8) & 0xFF; + int fb = (fcol >> 0) & 0xFF; - int sa = (in.specular[i] >> 24) & 0xFF; - int sr = (in.specular[i] >> 16) & 0xFF; - int sg = (in.specular[i] >> 8) & 0xFF; - int sb = (in.specular[i] >> 0) & 0xFF; + int acol = in.ambient[i]; + int aa = (acol >> 24) & 0xFF; + int ar = (acol >> 16) & 0xFF; + int ag = (acol >> 8) & 0xFF; + int ab = (acol >> 0) & 0xFF; - int ea = (in.emissive[i] >> 24) & 0xFF; - int er = (in.emissive[i] >> 16) & 0xFF; - int eg = (in.emissive[i] >> 8) & 0xFF; - int eb = (in.emissive[i] >> 0) & 0xFF; + int scol = in.specular[i]; + int sa = (scol >> 24) & 0xFF; + int sr = (scol >> 16) & 0xFF; + int sg = (scol >> 8) & 0xFF; + int sb = (scol >> 0) & 0xFF; + + int ecol = in.emissive[i]; + int ea = (ecol >> 24) & 0xFF; + int er = (ecol >> 16) & 0xFF; + int eg = (ecol >> 8) & 0xFF; + int eb = (ecol >> 0) & 0xFF; float nx = in.normals[3*i + 0]; float ny = in.normals[3*i + 1]; @@ -12084,6 +12058,7 @@ public class PGraphicsOpenGL extends PGraphics { u, v, aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; gluTess.addVertex(vertex); + if (stroke) addStrokeVertex(x1, y1, z1, strokeColor, strokeWeight); } } @@ -12099,25 +12074,36 @@ public class PGraphicsOpenGL extends PGraphics { float y1 = in.vertices[3*i1 + 1]; float z1 = in.vertices[3*i1 + 2]; - int fa = (in.colors[i] >> 24) & 0xFF; - int fr = (in.colors[i] >> 16) & 0xFF; - int fg = (in.colors[i] >> 8) & 0xFF; - int fb = (in.colors[i] >> 0) & 0xFF; + int strokeColor = 0; + float strokeWeight = 0; + if (stroke) { + strokeColor = in.strokeColors[i]; + strokeWeight = in.strokeWeights[i]; + } - int aa = (in.ambient[i] >> 24) & 0xFF; - int ar = (in.ambient[i] >> 16) & 0xFF; - int ag = (in.ambient[i] >> 8) & 0xFF; - int ab = (in.ambient[i] >> 0) & 0xFF; + int fcol = in.colors[i]; + int fa = (fcol >> 24) & 0xFF; + int fr = (fcol >> 16) & 0xFF; + int fg = (fcol >> 8) & 0xFF; + int fb = (fcol >> 0) & 0xFF; - int sa = (in.specular[i] >> 24) & 0xFF; - int sr = (in.specular[i] >> 16) & 0xFF; - int sg = (in.specular[i] >> 8) & 0xFF; - int sb = (in.specular[i] >> 0) & 0xFF; + int acol = in.ambient[i]; + int aa = (acol >> 24) & 0xFF; + int ar = (acol >> 16) & 0xFF; + int ag = (acol >> 8) & 0xFF; + int ab = (acol >> 0) & 0xFF; - int ea = (in.emissive[i] >> 24) & 0xFF; - int er = (in.emissive[i] >> 16) & 0xFF; - int eg = (in.emissive[i] >> 8) & 0xFF; - int eb = (in.emissive[i] >> 0) & 0xFF; + int scol = in.specular[i]; + int sa = (scol >> 24) & 0xFF; + int sr = (scol >> 16) & 0xFF; + int sg = (scol >> 8) & 0xFF; + int sb = (scol >> 0) & 0xFF; + + int ecol = in.emissive[i]; + int ea = (ecol >> 24) & 0xFF; + int er = (ecol >> 16) & 0xFF; + int eg = (ecol >> 8) & 0xFF; + int eb = (ecol >> 0) & 0xFF; float nx = in.normals[3*i + 0]; float ny = in.normals[3*i + 1]; @@ -12165,8 +12151,8 @@ public class PGraphicsOpenGL extends PGraphics { nx, ny, nz, u, v, aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; - gluTess.addVertex(vertex); + if (stroke) addStrokeVertex(x1, y1, z1, strokeColor, strokeWeight); } /* @@ -12208,25 +12194,36 @@ public class PGraphicsOpenGL extends PGraphics { float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4) { - int fa = (in.colors[i] >> 24) & 0xFF; - int fr = (in.colors[i] >> 16) & 0xFF; - int fg = (in.colors[i] >> 8) & 0xFF; - int fb = (in.colors[i] >> 0) & 0xFF; + int strokeColor = 0; + float strokeWeight = 0; + if (stroke) { + strokeColor = in.strokeColors[i]; + strokeWeight = in.strokeWeights[i]; + } - int aa = (in.ambient[i] >> 24) & 0xFF; - int ar = (in.ambient[i] >> 16) & 0xFF; - int ag = (in.ambient[i] >> 8) & 0xFF; - int ab = (in.ambient[i] >> 0) & 0xFF; + int fcol = in.colors[i]; + int fa = (fcol >> 24) & 0xFF; + int fr = (fcol >> 16) & 0xFF; + int fg = (fcol >> 8) & 0xFF; + int fb = (fcol >> 0) & 0xFF; - int sa = (in.specular[i] >> 24) & 0xFF; - int sr = (in.specular[i] >> 16) & 0xFF; - int sg = (in.specular[i] >> 8) & 0xFF; - int sb = (in.specular[i] >> 0) & 0xFF; + int acol = in.ambient[i]; + int aa = (acol >> 24) & 0xFF; + int ar = (acol >> 16) & 0xFF; + int ag = (acol >> 8) & 0xFF; + int ab = (acol >> 0) & 0xFF; - int ea = (in.emissive[i] >> 24) & 0xFF; - int er = (in.emissive[i] >> 16) & 0xFF; - int eg = (in.emissive[i] >> 8) & 0xFF; - int eb = (in.emissive[i] >> 0) & 0xFF; + int scol = in.specular[i]; + int sa = (scol >> 24) & 0xFF; + int sr = (scol >> 16) & 0xFF; + int sg = (scol >> 8) & 0xFF; + int sb = (scol >> 0) & 0xFF; + + int ecol = in.emissive[i]; + int ea = (ecol >> 24) & 0xFF; + int er = (ecol >> 16) & 0xFF; + int eg = (ecol >> 8) & 0xFF; + int eb = (ecol >> 0) & 0xFF; float nx = in.normals[3*i + 0]; float ny = in.normals[3*i + 1]; @@ -12235,9 +12232,9 @@ public class PGraphicsOpenGL extends PGraphics { float v = in.texcoords[2*i + 1]; float sh = in.shininess[i]; - float x0 = x2; - float y0 = y2; - float z0 = z2; + float x = x2; + float y = y2; + float z = z2; PMatrix3D draw = pg.curveDrawMatrix; @@ -12254,61 +12251,168 @@ public class PGraphicsOpenGL extends PGraphics { float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4; double[] vertex0 = new double[] { - x0, y0, z0, + x, y, z, fa, fr, fg, fb, nx, ny, nz, u, v, aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; gluTess.addVertex(vertex0); + if (stroke) addStrokeVertex(x, y, z, strokeColor, strokeWeight); for (int j = 0; j < pg.curveDetail; j++) { - x0 += xplot1; xplot1 += xplot2; xplot2 += xplot3; - y0 += yplot1; yplot1 += yplot2; yplot2 += yplot3; - z0 += zplot1; zplot1 += zplot2; zplot2 += zplot3; + x += xplot1; xplot1 += xplot2; xplot2 += xplot3; + y += yplot1; yplot1 += yplot2; yplot2 += yplot3; + z += zplot1; zplot1 += zplot2; zplot2 += zplot3; double[] vertex1 = new double[] { - x0, y0, z0, + x, y, z, fa, fr, fg, fb, nx, ny, nz, u, v, aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; gluTess.addVertex(vertex1); + if (stroke) addStrokeVertex(x, y, z, strokeColor, strokeWeight); } } void addVertex(int i) { pg.curveVertexCount = 0; + float x = in.vertices[3*i + 0]; + float y = in.vertices[3*i + 1]; + float z = in.vertices[3*i + 2]; + + int strokeColor = 0; + float strokeWeight = 0; + if (stroke) { + strokeColor = in.strokeColors[i]; + strokeWeight = in.strokeWeights[i]; + } + // Separting colors into individual rgba components for interpolation. - int fa = (in.colors[i] >> 24) & 0xFF; - int fr = (in.colors[i] >> 16) & 0xFF; - int fg = (in.colors[i] >> 8) & 0xFF; - int fb = (in.colors[i] >> 0) & 0xFF; + int fcol = in.colors[i]; + int fa = (fcol >> 24) & 0xFF; + int fr = (fcol >> 16) & 0xFF; + int fg = (fcol >> 8) & 0xFF; + int fb = (fcol >> 0) & 0xFF; - int aa = (in.ambient[i] >> 24) & 0xFF; - int ar = (in.ambient[i] >> 16) & 0xFF; - int ag = (in.ambient[i] >> 8) & 0xFF; - int ab = (in.ambient[i] >> 0) & 0xFF; + int acol = in.ambient[i]; + int aa = (acol >> 24) & 0xFF; + int ar = (acol >> 16) & 0xFF; + int ag = (acol >> 8) & 0xFF; + int ab = (acol >> 0) & 0xFF; - int sa = (in.specular[i] >> 24) & 0xFF; - int sr = (in.specular[i] >> 16) & 0xFF; - int sg = (in.specular[i] >> 8) & 0xFF; - int sb = (in.specular[i] >> 0) & 0xFF; + int scol = in.specular[i]; + int sa = (scol >> 24) & 0xFF; + int sr = (scol >> 16) & 0xFF; + int sg = (scol >> 8) & 0xFF; + int sb = (scol >> 0) & 0xFF; - int ea = (in.emissive[i] >> 24) & 0xFF; - int er = (in.emissive[i] >> 16) & 0xFF; - int eg = (in.emissive[i] >> 8) & 0xFF; - int eb = (in.emissive[i] >> 0) & 0xFF; + int ecol = in.emissive[i]; + int ea = (ecol >> 24) & 0xFF; + int er = (ecol >> 16) & 0xFF; + int eg = (ecol >> 8) & 0xFF; + int eb = (ecol >> 0) & 0xFF; // Vertex data includes coordinates, colors, normals, texture // coordinates, and material properties. double[] vertex = new double[] { - in.vertices [3*i + 0], in.vertices [3*i + 1], in.vertices[3*i + 2], + x, y, z, fa, fr, fg, fb, in.normals [3*i + 0], in.normals [3*i + 1], in.normals [3*i + 2], in.texcoords[2*i + 0], in.texcoords[2*i + 1], aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, in.shininess[i]}; - gluTess.addVertex(vertex); + if (stroke) addStrokeVertex(x, y, z, strokeColor, strokeWeight); + } + + // Accessor arrays to get the geometry data needed to tessellate the + // strokes, it can point to either the input geometry, or the internal + // path vertices generated in the polygon discretization. + float[] strokeVertices; + int[] strokeColors; + float[] strokeWeights; + + // Path vertex data that results from discretizing a polygon (i.e.: turning + // bezier, quadratic, and curve vertices into "regular" vertices). + int pathVertexCount; + float[] pathVertices; + int[] pathColors; + float[] pathWeights; + int beginPath; + + void beginPolygonStroke() { + pathVertexCount = 0; + if (pathVertices == null) { + pathVertices = new float[3 * PGL.DEFAULT_IN_VERTICES]; + pathColors = new int[PGL.DEFAULT_IN_VERTICES]; + pathWeights = new float[PGL.DEFAULT_IN_VERTICES]; + } + } + + void endPolygonStroke() { + // Nothing to do here. + } + + void beginStrokePath() { + beginPath = pathVertexCount; + } + + void endStrokePath(boolean closed) { + int idx = pathVertexCount; + if (beginPath + 1 < idx) { + boolean begin = beginPath == idx - 2; + boolean end = begin || !closed; + in.addEdge(idx - 2, idx - 1, begin, end); + if (!end) { + in.addEdge(idx - 1, beginPath, false, false); + in.closeEdge(idx - 1, beginPath); + } + } + } + + void addStrokeVertex(float x, float y, float z, int c, float w) { + int idx = pathVertexCount; + if (beginPath + 1 < idx) { + in.addEdge(idx - 2, idx - 1, beginPath == idx - 2, false); + } + + if (pathVertexCount == pathVertices.length / 3) { + int newSize = pathVertexCount << 1; + + float vtemp[] = new float[3 * newSize]; + PApplet.arrayCopy(pathVertices, 0, vtemp, 0, 3 * pathVertexCount); + pathVertices = vtemp; + + int ctemp[] = new int[newSize]; + PApplet.arrayCopy(pathColors, 0, ctemp, 0, newSize); + pathColors = ctemp; + + float wtemp[] = new float[newSize]; + PApplet.arrayCopy(pathWeights, 0, wtemp, 0, newSize); + pathWeights = wtemp; + } + + pathVertices[3 * idx + 0] = x; + pathVertices[3 * idx + 1] = y; + pathVertices[3 * idx + 2] = z; + pathColors[idx] = c; + pathWeights[idx] = w; + + pathVertexCount++; + } + + void tessellateStrokePath() { + if (in.edgeCount == 0) return; + strokeVertices = pathVertices; + strokeColors = pathColors; + strokeWeights = pathWeights; + if (is3D) { + tessellateEdges3D(); + } else if (is2D) { + beginNoTex(); + tessellateEdges2D(); + endNoTex(); + } } boolean clampPolygon() { @@ -12386,7 +12490,7 @@ public class PGraphicsOpenGL extends PGraphics { ///////////////////////////////////////// - // Interenting notes about using the GLU tessellator to render thick + // Interesting notes about using the GLU tessellator to render thick // polylines: // http://stackoverflow.com/questions/687173/how-do-i-render-thick-2d-lines-as-polygons // diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index 282df1054..60104ced8 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -2663,7 +2663,7 @@ public class PShapeOpenGL extends PShape { boolean curv = inGeo.hasCurveVertex(); if (bez || quad) saveBezierVertexSettings(); if (curv) saveCurveVertexSettings(); - if (stroke) inGeo.addPolygonEdges(close); +// if (stroke) inGeo.addPolygonEdges(close); tessellator.tessellatePolygon(solid, close, normalMode == NORMAL_MODE_AUTO); if (bez ||quad) restoreBezierVertexSettings(); @@ -3184,7 +3184,7 @@ public class PShapeOpenGL extends PShape { boolean curv = inGeo.hasCurveVertex(); if (bez || quad) saveBezierVertexSettings(); if (curv) saveCurveVertexSettings(); - if (stroke) inGeo.addPolygonEdges(close); +// if (stroke) inGeo.addPolygonEdges(close); tessellator.tessellatePolygon(false, close, true); if (bez || quad) restoreBezierVertexSettings(); if (curv) restoreCurveVertexSettings(); From 386a21ab568e864c7e50cb01896b959a903b4066 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 18 Oct 2013 12:08:33 -0400 Subject: [PATCH 194/556] some fixes to the path tessellation --- .../processing/opengl/PGraphicsOpenGL.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 9066e9f5c..176b08afc 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -10343,7 +10343,6 @@ public class PGraphicsOpenGL extends PGraphics { } } - // Generates tessellated geometry given a batch of input vertices. // Generates tessellated geometry given a batch of input vertices. static protected class Tessellator { InGeometry in; @@ -10382,6 +10381,21 @@ public class PGraphicsOpenGL extends PGraphics { int firstPointIndexCache; int lastPointIndexCache; + // Accessor arrays to get the geometry data needed to tessellate the + // strokes, it can point to either the input geometry, or the internal + // path vertices generated in the polygon discretization. + float[] strokeVertices; + int[] strokeColors; + float[] strokeWeights; + + // Path vertex data that results from discretizing a polygon (i.e.: turning + // bezier, quadratic, and curve vertices into "regular" vertices). + int pathVertexCount; + float[] pathVertices; + int[] pathColors; + float[] pathWeights; + int beginPath; + public Tessellator() { callback = new TessellatorCallback(); gluTess = pgl.createTessellator(callback); @@ -11978,7 +11992,7 @@ public class PGraphicsOpenGL extends PGraphics { void addBezierVertex(int i) { pg.curveVertexCount = 0; pg.bezierInitCheck(); - pg.bezierVertexCheck(pg.shape, i); + pg.bezierVertexCheck(POLYGON, i); PMatrix3D draw = pg.bezierDrawMatrix; @@ -12168,7 +12182,7 @@ public class PGraphicsOpenGL extends PGraphics { } void addCurveVertex(int i) { - pg.curveVertexCheck(pg.shape); + pg.curveVertexCheck(POLYGON); float[] vertex = pg.curveVertices[pg.curveVertexCount]; vertex[X] = in.vertices[3*i + 0]; @@ -12325,21 +12339,6 @@ public class PGraphicsOpenGL extends PGraphics { if (stroke) addStrokeVertex(x, y, z, strokeColor, strokeWeight); } - // Accessor arrays to get the geometry data needed to tessellate the - // strokes, it can point to either the input geometry, or the internal - // path vertices generated in the polygon discretization. - float[] strokeVertices; - int[] strokeColors; - float[] strokeWeights; - - // Path vertex data that results from discretizing a polygon (i.e.: turning - // bezier, quadratic, and curve vertices into "regular" vertices). - int pathVertexCount; - float[] pathVertices; - int[] pathColors; - float[] pathWeights; - int beginPath; - void beginPolygonStroke() { pathVertexCount = 0; if (pathVertices == null) { @@ -12384,11 +12383,11 @@ public class PGraphicsOpenGL extends PGraphics { pathVertices = vtemp; int ctemp[] = new int[newSize]; - PApplet.arrayCopy(pathColors, 0, ctemp, 0, newSize); + PApplet.arrayCopy(pathColors, 0, ctemp, 0, pathVertexCount); pathColors = ctemp; float wtemp[] = new float[newSize]; - PApplet.arrayCopy(pathWeights, 0, wtemp, 0, newSize); + PApplet.arrayCopy(pathWeights, 0, wtemp, 0, pathVertexCount); pathWeights = wtemp; } From 661f0746dbb1d747f2b9099fed440054f3b30c57 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 18 Oct 2013 14:17:34 -0400 Subject: [PATCH 195/556] properly separating fill and stroke poly/path tessellation --- .../processing/opengl/PGraphicsOpenGL.java | 347 ++++++++++-------- 1 file changed, 194 insertions(+), 153 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 176b08afc..210e33c2d 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -11919,30 +11919,31 @@ public class PGraphicsOpenGL extends PGraphics { int nInVert = in.vertexCount; - if (fill && 3 <= nInVert) { + if (3 <= nInVert) { firstPolyIndexCache = -1; boolean clamp = clampPolygon(); callback.init(in.renderMode == RETAINED, false, calcNormals, clamp); - gluTess.beginPolygon(); - - if (solid) { - // Using NONZERO winding rule for solid polygons. - gluTess.setWindingRule(PGL.TESS_WINDING_NONZERO); - } else { - // Using ODD winding rule to generate polygon with holes. - gluTess.setWindingRule(PGL.TESS_WINDING_ODD); + if (fill) { + gluTess.beginPolygon(); + if (solid) { + // Using NONZERO winding rule for solid polygons. + gluTess.setWindingRule(PGL.TESS_WINDING_NONZERO); + } else { + // Using ODD winding rule to generate polygon with holes. + gluTess.setWindingRule(PGL.TESS_WINDING_ODD); + } + gluTess.beginContour(); } - // Now, iterate over all input data and send to GLU tessellator... - int i = 0; - int c = 0; - gluTess.beginContour(); if (stroke) { beginPolygonStroke(); beginStrokePath(); } + + int i = 0; + int c = 0; while (i < in.vertexCount) { int code = VERTEX; boolean brk = false; @@ -11959,8 +11960,10 @@ public class PGraphicsOpenGL extends PGraphics { endStrokePath(closed); beginStrokePath(); } - gluTess.endContour(); - gluTess.beginContour(); + if (fill) { + gluTess.endContour(); + gluTess.beginContour(); + } } if (code == BEZIER_VERTEX) { @@ -11981,8 +11984,10 @@ public class PGraphicsOpenGL extends PGraphics { endStrokePath(closed); endPolygonStroke(); } - gluTess.endContour(); - gluTess.endPolygon(); + if (fill) { + gluTess.endContour(); + gluTess.endPolygon(); + } } endTex(); @@ -12008,36 +12013,43 @@ public class PGraphicsOpenGL extends PGraphics { strokeWeight = in.strokeWeights[i]; } - int fcol = in.colors[i]; - int fa = (fcol >> 24) & 0xFF; - int fr = (fcol >> 16) & 0xFF; - int fg = (fcol >> 8) & 0xFF; - int fb = (fcol >> 0) & 0xFF; + int fcol = 0, fa = 0, fr = 0, fg = 0, fb = 0; + int acol = 0, aa = 0, ar = 0, ag = 0, ab = 0; + int scol = 0, sa = 0, sr = 0, sg = 0, sb = 0; + int ecol = 0, ea = 0, er = 0, eg = 0, eb = 0; + float nx = 0, ny = 0, nz = 0, u = 0, v = 0, sh = 0; + if (fill) { + fcol = in.colors[i]; + fa = (fcol >> 24) & 0xFF; + fr = (fcol >> 16) & 0xFF; + fg = (fcol >> 8) & 0xFF; + fb = (fcol >> 0) & 0xFF; - int acol = in.ambient[i]; - int aa = (acol >> 24) & 0xFF; - int ar = (acol >> 16) & 0xFF; - int ag = (acol >> 8) & 0xFF; - int ab = (acol >> 0) & 0xFF; + acol = in.ambient[i]; + aa = (acol >> 24) & 0xFF; + ar = (acol >> 16) & 0xFF; + ag = (acol >> 8) & 0xFF; + ab = (acol >> 0) & 0xFF; - int scol = in.specular[i]; - int sa = (scol >> 24) & 0xFF; - int sr = (scol >> 16) & 0xFF; - int sg = (scol >> 8) & 0xFF; - int sb = (scol >> 0) & 0xFF; + scol = in.specular[i]; + sa = (scol >> 24) & 0xFF; + sr = (scol >> 16) & 0xFF; + sg = (scol >> 8) & 0xFF; + sb = (scol >> 0) & 0xFF; - int ecol = in.emissive[i]; - int ea = (ecol >> 24) & 0xFF; - int er = (ecol >> 16) & 0xFF; - int eg = (ecol >> 8) & 0xFF; - int eb = (ecol >> 0) & 0xFF; + ecol = in.emissive[i]; + ea = (ecol >> 24) & 0xFF; + er = (ecol >> 16) & 0xFF; + eg = (ecol >> 8) & 0xFF; + eb = (ecol >> 0) & 0xFF; - float nx = in.normals[3*i + 0]; - float ny = in.normals[3*i + 1]; - float nz = in.normals[3*i + 2]; - float u = in.texcoords[2*i + 0]; - float v = in.texcoords[2*i + 1]; - float sh = in.shininess[i]; + nx = in.normals[3*i + 0]; + ny = in.normals[3*i + 1]; + nz = in.normals[3*i + 2]; + u = in.texcoords[2*i + 0]; + v = in.texcoords[2*i + 1]; + sh = in.shininess[i]; + } float x2 = in.vertices[3*i + 0]; float y2 = in.vertices[3*i + 1]; @@ -12065,13 +12077,15 @@ public class PGraphicsOpenGL extends PGraphics { x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3; y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3; z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3; - double[] vertex = new double[] { - x1, y1, z1, - fa, fr, fg, fb, - nx, ny, nz, - u, v, - aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; - gluTess.addVertex(vertex); + if (fill) { + double[] vertex = new double[] { + x1, y1, z1, + fa, fr, fg, fb, + nx, ny, nz, + u, v, + aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; + gluTess.addVertex(vertex); + } if (stroke) addStrokeVertex(x1, y1, z1, strokeColor, strokeWeight); } } @@ -12095,36 +12109,43 @@ public class PGraphicsOpenGL extends PGraphics { strokeWeight = in.strokeWeights[i]; } - int fcol = in.colors[i]; - int fa = (fcol >> 24) & 0xFF; - int fr = (fcol >> 16) & 0xFF; - int fg = (fcol >> 8) & 0xFF; - int fb = (fcol >> 0) & 0xFF; + int fcol = 0, fa = 0, fr = 0, fg = 0, fb = 0; + int acol = 0, aa = 0, ar = 0, ag = 0, ab = 0; + int scol = 0, sa = 0, sr = 0, sg = 0, sb = 0; + int ecol = 0, ea = 0, er = 0, eg = 0, eb = 0; + float nx = 0, ny = 0, nz = 0, u = 0, v = 0, sh = 0; + if (fill) { + fcol = in.colors[i]; + fa = (fcol >> 24) & 0xFF; + fr = (fcol >> 16) & 0xFF; + fg = (fcol >> 8) & 0xFF; + fb = (fcol >> 0) & 0xFF; - int acol = in.ambient[i]; - int aa = (acol >> 24) & 0xFF; - int ar = (acol >> 16) & 0xFF; - int ag = (acol >> 8) & 0xFF; - int ab = (acol >> 0) & 0xFF; + acol = in.ambient[i]; + aa = (acol >> 24) & 0xFF; + ar = (acol >> 16) & 0xFF; + ag = (acol >> 8) & 0xFF; + ab = (acol >> 0) & 0xFF; - int scol = in.specular[i]; - int sa = (scol >> 24) & 0xFF; - int sr = (scol >> 16) & 0xFF; - int sg = (scol >> 8) & 0xFF; - int sb = (scol >> 0) & 0xFF; + scol = in.specular[i]; + sa = (scol >> 24) & 0xFF; + sr = (scol >> 16) & 0xFF; + sg = (scol >> 8) & 0xFF; + sb = (scol >> 0) & 0xFF; - int ecol = in.emissive[i]; - int ea = (ecol >> 24) & 0xFF; - int er = (ecol >> 16) & 0xFF; - int eg = (ecol >> 8) & 0xFF; - int eb = (ecol >> 0) & 0xFF; + ecol = in.emissive[i]; + ea = (ecol >> 24) & 0xFF; + er = (ecol >> 16) & 0xFF; + eg = (ecol >> 8) & 0xFF; + eb = (ecol >> 0) & 0xFF; - float nx = in.normals[3*i + 0]; - float ny = in.normals[3*i + 1]; - float nz = in.normals[3*i + 2]; - float u = in.texcoords[2*i + 0]; - float v = in.texcoords[2*i + 1]; - float sh = in.shininess[i]; + nx = in.normals[3*i + 0]; + ny = in.normals[3*i + 1]; + nz = in.normals[3*i + 2]; + u = in.texcoords[2*i + 0]; + v = in.texcoords[2*i + 1]; + sh = in.shininess[i]; + } float cx = in.vertices[3*i + 0]; float cy = in.vertices[3*i + 1]; @@ -12159,13 +12180,15 @@ public class PGraphicsOpenGL extends PGraphics { x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3; y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3; z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3; - double[] vertex = new double[] { - x1, y1, z1, - fa, fr, fg, fb, - nx, ny, nz, - u, v, - aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; - gluTess.addVertex(vertex); + if (fill) { + double[] vertex = new double[] { + x1, y1, z1, + fa, fr, fg, fb, + nx, ny, nz, + u, v, + aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; + gluTess.addVertex(vertex); + } if (stroke) addStrokeVertex(x1, y1, z1, strokeColor, strokeWeight); } @@ -12215,36 +12238,43 @@ public class PGraphicsOpenGL extends PGraphics { strokeWeight = in.strokeWeights[i]; } - int fcol = in.colors[i]; - int fa = (fcol >> 24) & 0xFF; - int fr = (fcol >> 16) & 0xFF; - int fg = (fcol >> 8) & 0xFF; - int fb = (fcol >> 0) & 0xFF; + int fcol = 0, fa = 0, fr = 0, fg = 0, fb = 0; + int acol = 0, aa = 0, ar = 0, ag = 0, ab = 0; + int scol = 0, sa = 0, sr = 0, sg = 0, sb = 0; + int ecol = 0, ea = 0, er = 0, eg = 0, eb = 0; + float nx = 0, ny = 0, nz = 0, u = 0, v = 0, sh = 0; + if (fill) { + fcol = in.colors[i]; + fa = (fcol >> 24) & 0xFF; + fr = (fcol >> 16) & 0xFF; + fg = (fcol >> 8) & 0xFF; + fb = (fcol >> 0) & 0xFF; - int acol = in.ambient[i]; - int aa = (acol >> 24) & 0xFF; - int ar = (acol >> 16) & 0xFF; - int ag = (acol >> 8) & 0xFF; - int ab = (acol >> 0) & 0xFF; + acol = in.ambient[i]; + aa = (acol >> 24) & 0xFF; + ar = (acol >> 16) & 0xFF; + ag = (acol >> 8) & 0xFF; + ab = (acol >> 0) & 0xFF; - int scol = in.specular[i]; - int sa = (scol >> 24) & 0xFF; - int sr = (scol >> 16) & 0xFF; - int sg = (scol >> 8) & 0xFF; - int sb = (scol >> 0) & 0xFF; + scol = in.specular[i]; + sa = (scol >> 24) & 0xFF; + sr = (scol >> 16) & 0xFF; + sg = (scol >> 8) & 0xFF; + sb = (scol >> 0) & 0xFF; - int ecol = in.emissive[i]; - int ea = (ecol >> 24) & 0xFF; - int er = (ecol >> 16) & 0xFF; - int eg = (ecol >> 8) & 0xFF; - int eb = (ecol >> 0) & 0xFF; + ecol = in.emissive[i]; + ea = (ecol >> 24) & 0xFF; + er = (ecol >> 16) & 0xFF; + eg = (ecol >> 8) & 0xFF; + eb = (ecol >> 0) & 0xFF; - float nx = in.normals[3*i + 0]; - float ny = in.normals[3*i + 1]; - float nz = in.normals[3*i + 2]; - float u = in.texcoords[2*i + 0]; - float v = in.texcoords[2*i + 1]; - float sh = in.shininess[i]; + nx = in.normals[3*i + 0]; + ny = in.normals[3*i + 1]; + nz = in.normals[3*i + 2]; + u = in.texcoords[2*i + 0]; + v = in.texcoords[2*i + 1]; + sh = in.shininess[i]; + } float x = x2; float y = y2; @@ -12264,26 +12294,30 @@ public class PGraphicsOpenGL extends PGraphics { float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4; float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4; - double[] vertex0 = new double[] { - x, y, z, - fa, fr, fg, fb, - nx, ny, nz, - u, v, - aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; - gluTess.addVertex(vertex0); + if (fill) { + double[] vertex0 = new double[] { + x, y, z, + fa, fr, fg, fb, + nx, ny, nz, + u, v, + aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; + gluTess.addVertex(vertex0); + } if (stroke) addStrokeVertex(x, y, z, strokeColor, strokeWeight); for (int j = 0; j < pg.curveDetail; j++) { x += xplot1; xplot1 += xplot2; xplot2 += xplot3; y += yplot1; yplot1 += yplot2; yplot2 += yplot3; z += zplot1; zplot1 += zplot2; zplot2 += zplot3; - double[] vertex1 = new double[] { - x, y, z, - fa, fr, fg, fb, - nx, ny, nz, - u, v, - aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; - gluTess.addVertex(vertex1); + if (fill) { + double[] vertex1 = new double[] { + x, y, z, + fa, fr, fg, fb, + nx, ny, nz, + u, v, + aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; + gluTess.addVertex(vertex1); + } if (stroke) addStrokeVertex(x, y, z, strokeColor, strokeWeight); } } @@ -12302,40 +12336,47 @@ public class PGraphicsOpenGL extends PGraphics { strokeWeight = in.strokeWeights[i]; } - // Separting colors into individual rgba components for interpolation. - int fcol = in.colors[i]; - int fa = (fcol >> 24) & 0xFF; - int fr = (fcol >> 16) & 0xFF; - int fg = (fcol >> 8) & 0xFF; - int fb = (fcol >> 0) & 0xFF; + if (fill) { + // Separating colors into individual rgba components for interpolation. + int fcol = in.colors[i]; + int fa = (fcol >> 24) & 0xFF; + int fr = (fcol >> 16) & 0xFF; + int fg = (fcol >> 8) & 0xFF; + int fb = (fcol >> 0) & 0xFF; - int acol = in.ambient[i]; - int aa = (acol >> 24) & 0xFF; - int ar = (acol >> 16) & 0xFF; - int ag = (acol >> 8) & 0xFF; - int ab = (acol >> 0) & 0xFF; + int acol = in.ambient[i]; + int aa = (acol >> 24) & 0xFF; + int ar = (acol >> 16) & 0xFF; + int ag = (acol >> 8) & 0xFF; + int ab = (acol >> 0) & 0xFF; - int scol = in.specular[i]; - int sa = (scol >> 24) & 0xFF; - int sr = (scol >> 16) & 0xFF; - int sg = (scol >> 8) & 0xFF; - int sb = (scol >> 0) & 0xFF; + int scol = in.specular[i]; + int sa = (scol >> 24) & 0xFF; + int sr = (scol >> 16) & 0xFF; + int sg = (scol >> 8) & 0xFF; + int sb = (scol >> 0) & 0xFF; - int ecol = in.emissive[i]; - int ea = (ecol >> 24) & 0xFF; - int er = (ecol >> 16) & 0xFF; - int eg = (ecol >> 8) & 0xFF; - int eb = (ecol >> 0) & 0xFF; + int ecol = in.emissive[i]; + int ea = (ecol >> 24) & 0xFF; + int er = (ecol >> 16) & 0xFF; + int eg = (ecol >> 8) & 0xFF; + int eb = (ecol >> 0) & 0xFF; - // Vertex data includes coordinates, colors, normals, texture - // coordinates, and material properties. - double[] vertex = new double[] { - x, y, z, - fa, fr, fg, fb, - in.normals [3*i + 0], in.normals [3*i + 1], in.normals [3*i + 2], - in.texcoords[2*i + 0], in.texcoords[2*i + 1], - aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, in.shininess[i]}; - gluTess.addVertex(vertex); + float nx = in.normals[3*i + 0]; + float ny = in.normals[3*i + 1]; + float nz = in.normals[3*i + 2]; + float u = in.texcoords[2*i + 0]; + float v = in.texcoords[2*i + 1]; + float sh = in.shininess[i]; + + double[] vertex = new double[] { + x, y, z, + fa, fr, fg, fb, + nx, ny, nz, + u, v, + aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, sh}; + gluTess.addVertex(vertex); + } if (stroke) addStrokeVertex(x, y, z, strokeColor, strokeWeight); } From ceb1396b726be32536ed3db454d9172e0d2ced5a Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 18 Oct 2013 14:59:47 -0400 Subject: [PATCH 196/556] using internal stroke arrays in line tessellation too --- core/src/processing/opengl/PGraphicsOpenGL.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 210e33c2d..aa9feaa22 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -10765,6 +10765,9 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateLines() { int nInVert = in.vertexCount; if (stroke && 2 <= nInVert) { + strokeVertices = in.vertices; + strokeColors = in.strokeColors; + strokeWeights = in.strokeWeights; updateTex(); int lineCount = nInVert / 2; // Each individual line is formed by two consecutive input vertices. if (is3D) { @@ -10845,6 +10848,9 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateLineStrip() { int nInVert = in.vertexCount; if (stroke && 2 <= nInVert) { + strokeVertices = in.vertices; + strokeColors = in.strokeColors; + strokeWeights = in.strokeWeights; updateTex(); int lineCount = nInVert - 1; if (is3D) { @@ -10926,6 +10932,9 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateLineLoop() { int nInVert = in.vertexCount; if (stroke && 2 <= nInVert) { + strokeVertices = in.vertices; + strokeColors = in.strokeColors; + strokeWeights = in.strokeWeights; updateTex(); int lineCount = nInVert; if (is3D) { From bb4da2575ec87433a79fddfc855a3d32f3a0d71f Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 18 Oct 2013 15:06:47 -0400 Subject: [PATCH 197/556] removed some old code --- .../processing/opengl/PGraphicsOpenGL.java | 237 ------------------ core/src/processing/opengl/PShapeOpenGL.java | 2 - 2 files changed, 239 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index aa9feaa22..420d5808e 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -2286,7 +2286,6 @@ public class PGraphicsOpenGL extends PGraphics { if (normalMode == NORMAL_MODE_AUTO) inGeo.calcQuadStripNormals(); tessellator.tessellateQuadStrip(); } else if (shape == POLYGON) { -// if (stroke && defaultEdges) inGeo.addPolygonEdges(mode == CLOSE); tessellator.tessellatePolygon(false, mode == CLOSE, normalMode == NORMAL_MODE_AUTO); } @@ -8013,151 +8012,6 @@ public class PGraphicsOpenGL extends PGraphics { addVertex(x, y, z, CURVE_VERTEX, brk); } - /* - void addBezierVertex(float x2, float y2, float z2, - float x3, float y3, float z3, - float x4, float y4, float z4, - boolean fill, boolean stroke, int detail, int code) { - addBezierVertex(x2, y2, z2, - x3, y3, z3, - x4, y4, z4, - fill, stroke, detail, code, POLYGON); - } - - void addBezierVertex(float x2, float y2, float z2, - float x3, float y3, float z3, - float x4, float y4, float z4, - boolean fill, boolean stroke, int detail, int code, // this should be break flag - int shape) { - bezierInitCheck(); - bezierVertexCheck(shape, vertexCount); - - PMatrix3D draw = bezierDrawMatrix; - - float x1 = getLastVertexX(); - float y1 = getLastVertexY(); - float z1 = getLastVertexZ(); - - float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4; - float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4; - float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4; - - float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4; - float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4; - float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4; - - float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4; - float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4; - float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4; - - for (int j = 0; j < detail; j++) { - x1 += xplot1; xplot1 += xplot2; xplot2 += xplot3; - y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3; - z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3; - addVertex(x1, y1, z1, j == 0 && code == BREAK ? BREAK : VERTEX); - } - } - */ - - /* - public void addQuadraticVertex(float cx, float cy, float cz, - float x3, float y3, float z3, - boolean fill, boolean stroke, int detail, - int code) { - addVertex(cx, cy, cz, QUADRATIC_VERTEX, brk); - addVertex(x3, y3, z3, QUADRATIC_VERTEX, false); - - - addQuadraticVertex(cx, cy, cz, - x3, y3, z3, - fill, stroke, detail, code, POLYGON); - } - - public void addQuadraticVertex(float cx, float cy, float cz, - float x3, float y3, float z3, - boolean fill, boolean stroke, int detail, - int code, int shape) { - float x1 = getLastVertexX(); - float y1 = getLastVertexY(); - float z1 = getLastVertexZ(); - addBezierVertex( - x1 + ((cx-x1)*2/3.0f), y1 + ((cy-y1)*2/3.0f), z1 + ((cz-z1)*2/3.0f), - x3 + ((cx-x3)*2/3.0f), y3 + ((cy-y3)*2/3.0f), z3 + ((cz-z3)*2/3.0f), - x3, y3, z3, - fill, stroke, detail, code, shape); - } - */ - - /* - void addCurveVertex(float x, float y, float z, - boolean fill, boolean stroke, int detail, int code) { - addCurveVertex(x, y, z, - fill, stroke, detail, code, POLYGON); - } - - void addCurveVertex(float x, float y, float z, - boolean fill, boolean stroke, int detail, int code, - int shape) { - curveVertexCheck(shape); - - float[] vertex = curveVertices[curveVertexCount]; - vertex[X] = x; - vertex[Y] = y; - vertex[Z] = z; - curveVertexCount++; - - // draw a segment if there are enough points - if (curveVertexCount > 3) { - float[] v1 = curveVertices[curveVertexCount-4]; - float[] v2 = curveVertices[curveVertexCount-3]; - float[] v3 = curveVertices[curveVertexCount-2]; - float[] v4 = curveVertices[curveVertexCount-1]; - addCurveVertexSegment(v1[X], v1[Y], v1[Z], - v2[X], v2[Y], v2[Z], - v3[X], v3[Y], v3[Z], - v4[X], v4[Y], v4[Z], - detail, code); - } - } - - void addCurveVertexSegment(float x1, float y1, float z1, - float x2, float y2, float z2, - float x3, float y3, float z3, - float x4, float y4, float z4, - int detail, int code) { - float x0 = x2; - float y0 = y2; - float z0 = z2; - - PMatrix3D draw = curveDrawMatrix; - - float xplot1 = draw.m10*x1 + draw.m11*x2 + draw.m12*x3 + draw.m13*x4; - float xplot2 = draw.m20*x1 + draw.m21*x2 + draw.m22*x3 + draw.m23*x4; - float xplot3 = draw.m30*x1 + draw.m31*x2 + draw.m32*x3 + draw.m33*x4; - - float yplot1 = draw.m10*y1 + draw.m11*y2 + draw.m12*y3 + draw.m13*y4; - float yplot2 = draw.m20*y1 + draw.m21*y2 + draw.m22*y3 + draw.m23*y4; - float yplot3 = draw.m30*y1 + draw.m31*y2 + draw.m32*y3 + draw.m33*y4; - - float zplot1 = draw.m10*z1 + draw.m11*z2 + draw.m12*z3 + draw.m13*z4; - float zplot2 = draw.m20*z1 + draw.m21*z2 + draw.m22*z3 + draw.m23*z4; - float zplot3 = draw.m30*z1 + draw.m31*z2 + draw.m32*z3 + draw.m33*z4; - - // addVertex() will reset curveVertexCount, so save it - int savedCount = curveVertexCount; - - addVertex(x0, y0, z0, code == BREAK ? BREAK : VERTEX); - for (int j = 0; j < detail; j++) { - x0 += xplot1; xplot1 += xplot2; xplot2 += xplot3; - y0 += yplot1; yplot1 += yplot2; yplot2 += yplot3; - z0 += zplot1; zplot1 += zplot2; zplot2 += zplot3; - addVertex(x0, y0, z0, VERTEX); - } - - curveVertexCount = savedCount; - } -*/ - // Returns the vertex data in the PGraphics double array format. float[][] getVertexData() { float[][] data = new float[vertexCount][VERTEX_FIELD_COUNT]; @@ -8323,84 +8177,6 @@ public class PGraphicsOpenGL extends PGraphics { } } - /* - void addPolygonEdges(boolean closed) { - int start = 0; - boolean begin = true; - int i = 1; - - int c = 1; - - // The following line handles the situation when the vertex codes start - // with a BREAK. This can only be the result of starting a shape with a - // contour, which doesn't work on JAVA2D. - // In order to mantain consistency between renderers, it is disabled. - // if (0 < codeCount && codes[0] == BREAK) c++; - - while (i < vertexCount) { - int code = VERTEX; - boolean brk = false; - boolean brk1 = false; - if (codes != null && c < codeCount) { - code = codes[c++]; - if (code == BREAK && c < codeCount) { - brk = true; - code = codes[c++]; - } - if (c < codeCount) brk1 = codes[c] == BREAK; - } - - if (brk) { - if (closed) { - // Closing previous contour. - addEdge(i - 1, start, begin, false); - closeEdge(i - 1, start); - } - - // Starting new contour. - start = i; - begin = true; - } else { - if (i == vertexCount - 1) { - if (closed && start + 1 < i) { - // Closing the end of the last contour, if it - // has more than 1 segment. - addEdge(i - 1, i, begin, false); - addEdge(i, start, false, false); - closeEdge(i, start); - } else { - // Leaving the last contour open. - addEdge(i - 1, i, begin, true); - } - } else { - - if ((i < vertexCount - 1) && brk1 && !closed) { - // A new contour starts at the next vertex and - // the polygon is not closed, so this is the last - // segment of the current contour. - addEdge(i - 1, i, begin, true); - } else { - // The current contour does not end at vertex i. - addEdge(i - 1, i, begin, false); - } - } - - begin = false; - } - - if (code == BEZIER_VERTEX) { - i += 3; - } else if (code == QUADRATIC_VERTEX) { - i += 2; - } else if (code == CURVE_VERTEX) { - i++; - } else { - i++; - } - } - } -*/ - // ----------------------------------------------------------------- // // Normal calculation @@ -8623,8 +8399,6 @@ public class PGraphicsOpenGL extends PGraphics { } else { addVertex(a, b, VERTEX, false); } - -// if (stroke) addPolygonEdges(true); } void addEllipse(float x, float y, float w, float h, @@ -12200,17 +11974,6 @@ public class PGraphicsOpenGL extends PGraphics { } if (stroke) addStrokeVertex(x1, y1, z1, strokeColor, strokeWeight); } - -/* - float x1 = getLastVertexX(); - float y1 = getLastVertexY(); - float z1 = getLastVertexZ(); - addBezierVertex( - x1 + ((cx-x1)*2/3.0f), y1 + ((cy-y1)*2/3.0f), z1 + ((cz-z1)*2/3.0f), - x3 + ((cx-x3)*2/3.0f), y3 + ((cy-y3)*2/3.0f), z3 + ((cz-z3)*2/3.0f), - x3, y3, z3, - fill, stroke, detail, code, shape); - */ } void addCurveVertex(int i) { diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index 60104ced8..462e2f56f 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -2663,7 +2663,6 @@ public class PShapeOpenGL extends PShape { boolean curv = inGeo.hasCurveVertex(); if (bez || quad) saveBezierVertexSettings(); if (curv) saveCurveVertexSettings(); -// if (stroke) inGeo.addPolygonEdges(close); tessellator.tessellatePolygon(solid, close, normalMode == NORMAL_MODE_AUTO); if (bez ||quad) restoreBezierVertexSettings(); @@ -3184,7 +3183,6 @@ public class PShapeOpenGL extends PShape { boolean curv = inGeo.hasCurveVertex(); if (bez || quad) saveBezierVertexSettings(); if (curv) saveCurveVertexSettings(); -// if (stroke) inGeo.addPolygonEdges(close); tessellator.tessellatePolygon(false, close, true); if (bez || quad) restoreBezierVertexSettings(); if (curv) restoreCurveVertexSettings(); From 321660f11532eed7e320e13c4363939fb096efa3 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 18 Oct 2013 15:45:31 -0400 Subject: [PATCH 198/556] fix #2151 --- core/src/processing/opengl/PGraphicsOpenGL.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 420d5808e..0cd5dc208 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -8524,8 +8524,8 @@ public class PGraphicsOpenGL extends PGraphics { int idx1 = 0, idx2 = 0, idx3 = 0, idx4 = 0; if (fill || stroke) { - // front face - setNormal(0, 0, 1); + // back face + setNormal(0, 0, -1); idx1 = addVertex(x1, y1, z1, 0, 0, VERTEX, true); idx2 = addVertex(x2, y1, z1, 1, 0, VERTEX, false); idx3 = addVertex(x2, y2, z1, 1, 1, VERTEX, false); @@ -8538,8 +8538,8 @@ public class PGraphicsOpenGL extends PGraphics { closeEdge(idx4, idx1); } - // back face - setNormal(0, 0, -1); + // front face + setNormal(0, 0, 1); idx1 = addVertex(x2, y1, z2, 0, 0, VERTEX, false); idx2 = addVertex(x1, y1, z2, 1, 0, VERTEX, false); idx3 = addVertex(x1, y2, z2, 1, 1, VERTEX, false); @@ -8580,8 +8580,8 @@ public class PGraphicsOpenGL extends PGraphics { closeEdge(idx4, idx1); } - // top face - setNormal(0, 1, 0); + // bottom face + setNormal(0, -1, 0); idx1 = addVertex(x1, y1, z2, 0, 0, VERTEX, false); idx2 = addVertex(x2, y1, z2, 1, 0, VERTEX, false); idx3 = addVertex(x2, y1, z1, 1, 1, VERTEX, false); @@ -8594,8 +8594,8 @@ public class PGraphicsOpenGL extends PGraphics { closeEdge(idx4, idx1); } - // bottom face - setNormal(0, -1, 0); + // top face + setNormal(0, 1, 0); idx1 = addVertex(x1, y2, z1, 0, 0, VERTEX, false); idx2 = addVertex(x2, y2, z1, 1, 0, VERTEX, false); idx3 = addVertex(x2, y2, z2, 1, 1, VERTEX, false); From 30ce02d0ec421e5f74e3ee4f04d9bc05472bc7cd Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 18 Oct 2013 16:15:32 -0400 Subject: [PATCH 199/556] reset curveVertexCount when tessellating a polygon PShape --- core/src/processing/opengl/PGraphicsOpenGL.java | 6 +++++- core/src/processing/opengl/PShapeOpenGL.java | 10 ++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 0cd5dc208..c9966f2ab 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -2069,6 +2069,7 @@ public class PGraphicsOpenGL extends PGraphics { shape = kind; inGeo.clear(); + curveVertexCount = 0; breakShape = false; defaultEdges = true; @@ -10249,6 +10250,10 @@ public class PGraphicsOpenGL extends PGraphics { transformScale = -1; } + void resetCurveVertexCount() { + pg.curveVertexCount = 0; + } + // ----------------------------------------------------------------- // // Point tessellation @@ -11983,7 +11988,6 @@ public class PGraphicsOpenGL extends PGraphics { vertex[X] = in.vertices[3*i + 0]; vertex[Y] = in.vertices[3*i + 1]; vertex[Z] = in.vertices[3*i + 2]; - pg.curveVertexCount++; // draw a segment if there are enough points diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index 462e2f56f..b04575c5e 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -2662,7 +2662,10 @@ public class PShapeOpenGL extends PShape { boolean quad = inGeo.hasQuadraticVertex(); boolean curv = inGeo.hasCurveVertex(); if (bez || quad) saveBezierVertexSettings(); - if (curv) saveCurveVertexSettings(); + if (curv) { + saveCurveVertexSettings(); + tessellator.resetCurveVertexCount(); + } tessellator.tessellatePolygon(solid, close, normalMode == NORMAL_MODE_AUTO); if (bez ||quad) restoreBezierVertexSettings(); @@ -3182,7 +3185,10 @@ public class PShapeOpenGL extends PShape { boolean quad = inGeo.hasQuadraticVertex(); boolean curv = inGeo.hasCurveVertex(); if (bez || quad) saveBezierVertexSettings(); - if (curv) saveCurveVertexSettings(); + if (curv) { + saveCurveVertexSettings(); + tessellator.resetCurveVertexCount(); + } tessellator.tessellatePolygon(false, close, true); if (bez || quad) restoreBezierVertexSettings(); if (curv) restoreCurveVertexSettings(); From 0e6dc98dc1302818889bdcddda20c93293f6144e Mon Sep 17 00:00:00 2001 From: codeanticode Date: Fri, 18 Oct 2013 21:09:38 -0400 Subject: [PATCH 200/556] update PShape tessellation when requesting vertex codes --- core/src/processing/opengl/PShapeOpenGL.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index b04575c5e..b23435535 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -2347,6 +2347,11 @@ public class PShapeOpenGL extends PShape { public int[] getVertexCodes() { if (family == GROUP) return null; else { + if (family == PRIMITIVE || family == PATH) { + // the input geometry of primitive and path shapes is built during + // tessellation + updateTessellation(); + } if (inGeo.codes == null) return null; return inGeo.codes; } @@ -2356,7 +2361,14 @@ public class PShapeOpenGL extends PShape { @Override public int getVertexCodeCount() { if (family == GROUP) return 0; - else return inGeo.codeCount; + else { + if (family == PRIMITIVE || family == PATH) { + // the input geometry of primitive and path shapes is built during + // tessellation + updateTessellation(); + } + return inGeo.codeCount; + } } From f33ca59c5f123034d83aea7b5a054c952846cb9a Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sat, 19 Oct 2013 09:29:44 -0400 Subject: [PATCH 201/556] removed shader inner-classes in PGraphicsOpenGL, now everything is in PShader --- .../processing/opengl/PGraphicsOpenGL.java | 192 +++++-- core/src/processing/opengl/PShader.java | 494 +++++++++++++++++- core/src/processing/opengl/PShapeOpenGL.java | 9 +- 3 files changed, 608 insertions(+), 87 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index c9966f2ab..10b857ff1 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -24,6 +24,7 @@ package processing.opengl; import processing.core.*; +import java.io.IOException; import java.net.URL; import java.nio.*; import java.util.*; @@ -85,6 +86,10 @@ public class PGraphicsOpenGL extends PGraphics { static final String SHADER_NEED_LIGHT_ATTRIBS = "The provided shader needs light attributes (ambient, diffuse, etc.), but " + "the current scene is unlit, so the default shader will be used instead"; + static final String MISSING_FRAGMENT_SHADER = + "The fragment shader is missing, cannot create shader object"; + static final String MISSING_VERTEX_SHADER = + "The vertex shader is missing, cannot create shader object"; static final String UNKNOWN_SHADER_KIND_ERROR = "Unknown shader kind"; static final String NO_TEXLIGHT_SHADER_ERROR = @@ -256,20 +261,20 @@ public class PGraphicsOpenGL extends PGraphics { static protected URL defPointShaderFragURL = PGraphicsOpenGL.class.getResource("PointFrag.glsl"); - static protected PolyShader defColorShader; - static protected PolyShader defTextureShader; - static protected PolyShader defLightShader; - static protected PolyShader defTexlightShader; - static protected LineShader defLineShader; - static protected PointShader defPointShader; + static protected PShader defColorShader; + static protected PShader defTextureShader; + static protected PShader defLightShader; + static protected PShader defTexlightShader; + static protected PShader defLineShader; + static protected PShader defPointShader; static protected URL maskShaderFragURL = PGraphicsOpenGL.class.getResource("MaskFrag.glsl"); - static protected PolyShader maskShader; + static protected PShader maskShader; - protected PolyShader polyShader; - protected LineShader lineShader; - protected PointShader pointShader; + protected PShader polyShader; + protected PShader lineShader; + protected PShader pointShader; // ........................................................ @@ -2400,7 +2405,7 @@ public class PGraphicsOpenGL extends PGraphics { // If the renderer is 2D, then lights should always be false, // so no need to worry about that. - PolyShader shader = getPolyShader(lights, tex != null); + PShader shader = getPolyShader(lights, tex != null); shader.bind(); int first = texCache.firstCache[i]; @@ -2563,7 +2568,7 @@ public class PGraphicsOpenGL extends PGraphics { protected void flushLines() { updateLineBuffers(); - LineShader shader = getLineShader(); + PShader shader = getLineShader(); shader.bind(); IndexCache cache = tessGeo.lineIndexCache; @@ -2667,7 +2672,7 @@ public class PGraphicsOpenGL extends PGraphics { protected void flushPoints() { updatePointBuffers(); - PointShader shader = getPointShader(); + PShader shader = getPointShader(); shader.bind(); IndexCache cache = tessGeo.pointIndexCache; @@ -5515,10 +5520,8 @@ public class PGraphicsOpenGL extends PGraphics { } if (maskShader == null) { -// maskShader = new TextureShader(parent, defTextureShaderVertURL, -// maskShaderFragURL); - maskShader = new PolyShader(parent, defTextureShaderVertURL, - maskShaderFragURL); + maskShader = new PShader(parent, defTextureShaderVertURL, + maskShaderFragURL); } maskShader.set("mask", alpha); filter(maskShader); @@ -5559,8 +5562,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void filter(PShader shader) { - if (!(shader instanceof PolyShader) || - !((PolyShader)shader).supportsTexturing()) { + if (!shader.isPolyShader() || !shader.supportsTexturing()) { PGraphics.showWarning(INVALID_FILTER_SHADER_ERROR); return; } @@ -5602,10 +5604,8 @@ public class PGraphicsOpenGL extends PGraphics { stroke = false; int prevBlendMode = blendMode; blendMode(REPLACE); -// TextureShader prevTexShader = textureShader; -// textureShader = (TextureShader) shader; - PolyShader prevShader = polyShader; - polyShader = (PolyShader)shader; + PShader prevShader = polyShader; + polyShader = shader; beginShape(QUADS); texture(filterImage); @@ -6304,6 +6304,33 @@ public class PGraphicsOpenGL extends PGraphics { @Override public PShader loadShader(String fragFilename) { + if (fragFilename == null || fragFilename.equals("")) { + PGraphics.showWarning(MISSING_FRAGMENT_SHADER); + return null; + } + + int type = getShaderType(fragFilename, PShader.POLY); + PShader shader = new PShader(parent); + shader.setType(type); + shader.setFragmentShader(fragFilename); + if (type == PShader.POINT) { + shader.setVertexShader(defPointShaderVertURL); + } else if (type == PShader.LINE) { + shader.setVertexShader(defLineShaderVertURL); + } else if (type == PShader.TEXLIGHT) { + shader.setVertexShader(defTexlightShaderVertURL); + } else if (type == PShader.LIGHT) { + shader.setVertexShader(defLightShaderVertURL); + } else if (type == PShader.TEXTURE) { + shader.setVertexShader(defTextureShaderVertURL); + } else if (type == PShader.COLOR) { + shader.setVertexShader(defColorShaderVertURL); + } else { + shader.setVertexShader(defTextureShaderVertURL); + } + return shader; + + /* int shaderType = getShaderType(fragFilename); PShader shader = null; if (shaderType == PShader.POINT) { @@ -6334,11 +6361,23 @@ public class PGraphicsOpenGL extends PGraphics { } shader.setFragmentShader(fragFilename); return shader; + */ } @Override public PShader loadShader(String fragFilename, String vertFilename) { + if (fragFilename == null || fragFilename.equals("")) { + PGraphics.showWarning(MISSING_FRAGMENT_SHADER); + return null; + } else if (fragFilename == null || fragFilename.equals("")) { + PGraphics.showWarning(MISSING_VERTEX_SHADER); + return null; + } else { + return new PShader(parent, vertFilename, fragFilename); + } + + /* int vertType = getShaderType(vertFilename); int fragType = getShaderType(fragFilename); @@ -6399,19 +6438,27 @@ public class PGraphicsOpenGL extends PGraphics { } } return shader; + */ } @Override public void shader(PShader shader) { - shader(shader, POLYGON); + flush(); // Flushing geometry drawn with a different shader. + + if (shader.isPolyShader()) polyShader = shader; + else if (shader.isLineShader()) lineShader = shader; + else if (shader.isPointShader()) pointShader = shader; + else PGraphics.showWarning(UNKNOWN_SHADER_KIND_ERROR); } @Override + // TODO: deprecate this method, the kind arguments is not used anymore public void shader(PShader shader, int kind) { - flush(); // Flushing geometry drawn with a different shader. + shader(shader); + /* if (kind == TRIANGLES || kind == QUADS || kind == POLYGON) { if (shader instanceof PolyShader) { polyShader = (PolyShader) shader; @@ -6433,12 +6480,13 @@ public class PGraphicsOpenGL extends PGraphics { } else { PGraphics.showWarning(UNKNOWN_SHADER_KIND_ERROR); } + */ } @Override public void resetShader() { - resetShader(POLYGON); + resetShader(TRIANGLES); } @@ -6458,8 +6506,19 @@ public class PGraphicsOpenGL extends PGraphics { } - protected int getShaderType(String filename) { + protected int getShaderType(String filename, int defaulType) { String[] source = parent.loadStrings(filename); + return getShaderTypeImpl(source, defaulType); + } + + + protected int getShaderType(URL url, int defaultType) throws IOException { + String[] source = PApplet.loadStrings(url.openStream()); + return getShaderTypeImpl(source, defaultType); + } + + + protected int getShaderTypeImpl(String[] source, int defaultType) { for (int i = 0; i < source.length; i++) { String line = source[i].trim(); if (PApplet.match(line, pointShaderAttrRegexp) != null) @@ -6485,7 +6544,7 @@ public class PGraphicsOpenGL extends PGraphics { else if (PApplet.match(line, quadShaderAttrRegexp) != null) return PShader.POLY; } - return PShader.POLY; + return defaultType; } @@ -6503,8 +6562,8 @@ public class PGraphicsOpenGL extends PGraphics { } - protected PolyShader getPolyShader(boolean lit, boolean tex) { - PolyShader shader; + protected PShader getPolyShader(boolean lit, boolean tex) { + PShader shader; boolean useDefault = polyShader == null; if (polyShader != null) { polyShader.setRenderer(this); @@ -6513,22 +6572,22 @@ public class PGraphicsOpenGL extends PGraphics { } if (lit) { if (tex) { - if (useDefault || !polyShader.checkType(PShader.TEXLIGHT)) { + if (useDefault || !polyShader.checkPolyType(PShader.TEXLIGHT)) { if (defTexlightShader == null) { - defTexlightShader = new PolyShader(parent, - defTexlightShaderVertURL, - defTextureShaderFragURL); + defTexlightShader = new PShader(parent, + defTexlightShaderVertURL, + defTextureShaderFragURL); } shader = defTexlightShader; } else { shader = polyShader; } } else { - if (useDefault || !polyShader.checkType(PShader.LIGHT)) { + if (useDefault || !polyShader.checkPolyType(PShader.LIGHT)) { if (defLightShader == null) { - defLightShader = new PolyShader(parent, - defLightShaderVertURL, - defColorShaderFragURL); + defLightShader = new PShader(parent, + defLightShaderVertURL, + defColorShaderFragURL); } shader = defLightShader; } else { @@ -6542,22 +6601,22 @@ public class PGraphicsOpenGL extends PGraphics { } if (tex) { - if (useDefault || !polyShader.checkType(PShader.TEXTURE)) { + if (useDefault || !polyShader.checkPolyType(PShader.TEXTURE)) { if (defTextureShader == null) { - defTextureShader = new PolyShader(parent, - defTextureShaderVertURL, - defTextureShaderFragURL); + defTextureShader = new PShader(parent, + defTextureShaderVertURL, + defTextureShaderFragURL); } shader = defTextureShader; } else { shader = polyShader; } } else { - if (useDefault || !polyShader.checkType(PShader.COLOR)) { + if (useDefault || !polyShader.checkPolyType(PShader.COLOR)) { if (defColorShader == null) { - defColorShader = new PolyShader(parent, - defColorShaderVertURL, - defColorShaderFragURL); + defColorShader = new PShader(parent, + defColorShaderVertURL, + defColorShaderFragURL); } shader = defColorShader; } else { @@ -6574,12 +6633,12 @@ public class PGraphicsOpenGL extends PGraphics { } - protected LineShader getLineShader() { - LineShader shader; + protected PShader getLineShader() { + PShader shader; if (lineShader == null) { if (defLineShader == null) { - defLineShader = new LineShader(parent, defLineShaderVertURL, - defLineShaderFragURL); + defLineShader = new PShader(parent, defLineShaderVertURL, + defLineShaderFragURL); } shader = defLineShader; } else { @@ -6592,12 +6651,12 @@ public class PGraphicsOpenGL extends PGraphics { } - protected PointShader getPointShader() { - PointShader shader; + protected PShader getPointShader() { + PShader shader; if (pointShader == null) { if (defPointShader == null) { - defPointShader = new PointShader(parent, defPointShaderVertURL, - defPointShaderFragURL); + defPointShader = new PShader(parent, defPointShaderVertURL, + defPointShaderFragURL); } shader = defPointShader; } else { @@ -6609,7 +6668,7 @@ public class PGraphicsOpenGL extends PGraphics { return shader; } - +/* protected class BaseShader extends PShader { protected int transformMatLoc; protected int modelviewMatLoc; @@ -6662,6 +6721,7 @@ public class PGraphicsOpenGL extends PGraphics { super.unbind(); } + @Override protected void setCommonUniforms() { if (-1 < transformMatLoc) { pg.updateGLProjmodelview(); @@ -6701,42 +6761,56 @@ public class PGraphicsOpenGL extends PGraphics { return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit(); } + @Override public boolean supportsTexturing() { return false; } + @Override public boolean supportLighting() { return false; } + @Override public boolean accessTexCoords() { return false; } + @Override public boolean accessNormals() { return false; } + @Override public boolean accessLightAttribs() { return false; } + @Override public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { } + @Override public void setColorAttribute(int vboId, int size, int type, int stride, int offset) { } + @Override public void setNormalAttribute(int vboId, int size, int type, int stride, int offset) { } + @Override public void setAmbientAttribute(int vboId, int size, int type, int stride, int offset) { } + @Override public void setSpecularAttribute(int vboId, int size, int type, int stride, int offset) { } + @Override public void setEmissiveAttribute(int vboId, int size, int type, int stride, int offset) { } + @Override public void setShininessAttribute(int vboId, int size, int type, int stride, int offset) { } + @Override public void setTexcoordAttribute(int vboId, int size, int type, int stride, int offset) { } + @Override public void setTexture(Texture tex) { } } @@ -6868,18 +6942,22 @@ public class PGraphicsOpenGL extends PGraphics { } } + @Override public boolean hasType() { return COLOR <= type && type <= TEXLIGHT; } + @Override public void setType(int type) { this.type = type; } + @Override public int getType() { return type; } + @Override public boolean checkType(int type) { if (!hasType()) return true; @@ -7087,6 +7165,7 @@ public class PGraphicsOpenGL extends PGraphics { setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset); } + @Override public void setLineAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(directionLoc, vboId, size, type, false, stride, offset); @@ -7185,6 +7264,7 @@ public class PGraphicsOpenGL extends PGraphics { setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset); } + @Override public void setPointAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(offsetLoc, vboId, size, type, false, stride, offset); @@ -7222,7 +7302,7 @@ public class PGraphicsOpenGL extends PGraphics { super.unbind(); } } - +*/ ////////////////////////////////////////////////////////////// diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShader.java index 220f93352..652d93c97 100644 --- a/core/src/processing/opengl/PShader.java +++ b/core/src/processing/opengl/PShader.java @@ -3,7 +3,7 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2011-12 Ben Fry and Casey Reas + Copyright (c) 2011-13 Ben Fry and Casey Reas This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -39,10 +39,9 @@ import java.util.HashMap; * * @webref rendering:shaders */ -public class PShader { - // shaders constants - static protected final int LINE = 0; - static protected final int POINT = 1; +public class PShader implements PConstants { + static protected final int POINT = 0; + static protected final int LINE = 1; static protected final int POLY = 2; static protected final int COLOR = 3; static protected final int LIGHT = 4; @@ -84,9 +83,56 @@ public class PShader { protected IntBuffer intBuffer; protected FloatBuffer floatBuffer; + + + protected int type; + protected int transformMatLoc; + protected int modelviewMatLoc; + protected int projectionMatLoc; + protected int bufferLoc; + protected int bufferUnit; + protected int viewportLoc; + + protected int vertexLoc; + protected int colorLoc; + protected int normalLoc; + protected int texCoordLoc; + protected int normalMatLoc; + + // For lines + protected int perspectiveLoc; + protected int scaleLoc; + protected int directionLoc; + + // For points + protected int offsetLoc; + + protected int lightCountLoc; + protected int lightPositionLoc; + protected int lightNormalLoc; + protected int lightAmbientLoc; + protected int lightDiffuseLoc; + protected int lightSpecularLoc; + protected int lightFalloffLoc; + protected int lightSpotLoc; + + protected int ambientLoc; + protected int specularLoc; + protected int emissiveLoc; + protected int shininessLoc; + + protected Texture texture; + protected int texUnit; + + protected int textureLoc; + protected int texMatrixLoc; + protected int texOffsetLoc; + + protected float[] tcmat; + + public PShader() { parent = null; -// pgMain = null; pgl = null; context = -1; @@ -103,13 +149,14 @@ public class PShader { floatBuffer = PGL.allocateFloatBuffer(1); bound = false; + + type = -1; } public PShader(PApplet parent) { this(); this.parent = parent; -// pgMain = (PGraphicsOpenGL) parent.g; pgl = PGraphicsOpenGL.pgl; context = pgl.createEmptyContext(); } @@ -125,7 +172,6 @@ public class PShader { */ public PShader(PApplet parent, String vertFilename, String fragFilename) { this.parent = parent; -// pgMain = (PGraphicsOpenGL) parent.g; pgl = PGraphicsOpenGL.pgl; this.vertexURL = null; @@ -139,6 +185,20 @@ public class PShader { intBuffer = PGL.allocateIntBuffer(1); floatBuffer = PGL.allocateFloatBuffer(1); + + int vertType = PGraphicsOpenGL.pgPrimary.getShaderType(vertFilename, -1); + int fragType = PGraphicsOpenGL.pgPrimary.getShaderType(fragFilename, -1); + if (vertType == -1 && fragType == -1) { + type = PShader.POLY; + } else if (vertType == -1) { + type = fragType; + } else if (fragType == -1) { + type = vertType; + } else if (fragType == vertType) { + type = vertType; + } else { + PGraphics.showWarning(PGraphicsOpenGL.INCONSISTENT_SHADER_TYPES); + } } @@ -148,7 +208,6 @@ public class PShader { */ public PShader(PApplet parent, URL vertURL, URL fragURL) { this.parent = parent; -// pgMain = (PGraphicsOpenGL) parent.g; pgl = PGraphicsOpenGL.pgl; this.vertexURL = vertURL; @@ -162,6 +221,30 @@ public class PShader { intBuffer = PGL.allocateIntBuffer(1); floatBuffer = PGL.allocateFloatBuffer(1); + + int vertType = -1, fragType = -1; + try { + vertType = PGraphicsOpenGL.pgPrimary.getShaderType(vertURL, -1); + } catch (IOException e) { + PGraphics.showException("Vertex URL cannot be accessed both null!"); + } + try { + fragType = PGraphicsOpenGL.pgPrimary.getShaderType(fragURL, -1); + } catch (IOException e) { + PGraphics.showException("Fragment URL cannot be accessed both null!"); + } + + if (vertType == -1 && fragType == -1) { + type = PShader.POLY; + } else if (vertType == -1) { + type = fragType; + } else if (fragType == -1) { + type = vertType; + } else if (fragType == vertType) { + type = vertType; + } else { + PGraphics.showWarning(PGraphicsOpenGL.INCONSISTENT_SHADER_TYPES); + } } @@ -214,6 +297,8 @@ public class PShader { consumeUniforms(); bindTextures(); } + + if (hasType()) bindTyped(); } @@ -221,6 +306,8 @@ public class PShader { * Unbinds the shader program. */ public void unbind() { + if (hasType()) unbindTyped(); + if (bound) { unbindTextures(); pgl.useProgram(0); @@ -384,6 +471,13 @@ public class PShader { + protected boolean setup() { + + return true; + } + + + /** * Returns the ID location of the attribute parameter given its name. * @@ -685,12 +779,6 @@ public class PShader { } } - - protected int getLastTexUnit() { - if (texUnits == null) return -1; - else return texUnits.size() - 1; - } - protected void init() { if (glProgram == 0 || contextIsOutdated()) { context = pgl.getCurrentContext(); @@ -733,6 +821,8 @@ public class PShader { if (hasFrag) { pgl.attachShader(glProgram, glFragment); } + setup(); + pgl.linkProgram(glProgram); pgl.getProgramiv(glProgram, PGL.LINK_STATUS, intBuffer); @@ -867,16 +957,6 @@ public class PShader { } - protected void setRenderer(PGraphicsOpenGL pg) { - this.pg = pg; - } - - protected void loadAttributes() { } - - - protected void loadUniforms() { } - - protected void dispose() { if (glVertex != 0) { PGraphicsOpenGL.deleteGLSLVertShaderObject(glVertex, context); @@ -892,6 +972,370 @@ public class PShader { } } + // *************************************************************************** + // + // Processing specific + + protected int getType() { + return type; + } + + protected void setType(int type) { + this.type = type; + } + + protected boolean hasType() { + return POINT <= type && type <= TEXLIGHT; + } + + protected boolean isPointShader() { + return type == POINT; + } + + protected boolean isLineShader() { + return type == LINE; + } + + protected boolean isPolyShader() { + return POLY <= type && type <= TEXLIGHT; + } + + protected boolean checkPolyType(int type) { + if (getType() == PShader.POLY) return true; + + if (getType() != type) { + if (type == TEXLIGHT) { + PGraphics.showWarning(PGraphicsOpenGL.NO_TEXLIGHT_SHADER_ERROR); + } else if (type == LIGHT) { + PGraphics.showWarning(PGraphicsOpenGL.NO_LIGHT_SHADER_ERROR); + } else if (type == TEXTURE) { + PGraphics.showWarning(PGraphicsOpenGL.NO_TEXTURE_SHADER_ERROR); + } else if (type == COLOR) { + PGraphics.showWarning(PGraphicsOpenGL.NO_COLOR_SHADER_ERROR); + } + return false; + } + + return true; + } + + protected int getLastTexUnit() { + return texUnits == null ? -1 : texUnits.size() - 1; + } + + protected void setRenderer(PGraphicsOpenGL pg) { + this.pg = pg; + } + + protected void loadAttributes() { + vertexLoc = getAttributeLoc("vertex"); + if (vertexLoc == -1) vertexLoc = getAttributeLoc("position"); + + colorLoc = getAttributeLoc("color"); + texCoordLoc = getAttributeLoc("texCoord"); + normalLoc = getAttributeLoc("normal"); + + ambientLoc = getAttributeLoc("ambient"); + specularLoc = getAttributeLoc("specular"); + emissiveLoc = getAttributeLoc("emissive"); + shininessLoc = getAttributeLoc("shininess"); + + directionLoc = getAttributeLoc("direction"); + + offsetLoc = getAttributeLoc("offset"); + + directionLoc = getAttributeLoc("direction"); + offsetLoc = getAttributeLoc("offset"); + } + + + protected void loadUniforms() { + transformMatLoc = getUniformLoc("transform"); + if (transformMatLoc == -1) + transformMatLoc = getUniformLoc("transformMatrix"); + + modelviewMatLoc = getUniformLoc("modelview"); + if (modelviewMatLoc == -1) + modelviewMatLoc = getUniformLoc("modelviewMatrix"); + + projectionMatLoc = getUniformLoc("projection"); + if (projectionMatLoc == -1) + projectionMatLoc = getUniformLoc("projectionMatrix"); + + viewportLoc = getUniformLoc("viewport"); + bufferLoc = getUniformLoc("buffer"); + + normalMatLoc = getUniformLoc("normalMatrix"); + + lightCountLoc = getUniformLoc("lightCount"); + lightPositionLoc = getUniformLoc("lightPosition"); + lightNormalLoc = getUniformLoc("lightNormal"); + lightAmbientLoc = getUniformLoc("lightAmbient"); + lightDiffuseLoc = getUniformLoc("lightDiffuse"); + lightSpecularLoc = getUniformLoc("lightSpecular"); + lightFalloffLoc = getUniformLoc("lightFalloff"); + lightSpotLoc = getUniformLoc("lightSpot"); + + textureLoc = getUniformLoc("texture"); + texMatrixLoc = getUniformLoc("texMatrix"); + texOffsetLoc = getUniformLoc("texOffset"); + + + perspectiveLoc = getUniformLoc("perspective"); + scaleLoc = getUniformLoc("scale"); + } + + + protected void setCommonUniforms() { + if (-1 < transformMatLoc) { + pg.updateGLProjmodelview(); + setUniformMatrix(transformMatLoc, pg.glProjmodelview); + } + + if (-1 < modelviewMatLoc) { + pg.updateGLModelview(); + setUniformMatrix(modelviewMatLoc, pg.glModelview); + } + + if (-1 < projectionMatLoc) { + pg.updateGLProjection(); + setUniformMatrix(projectionMatLoc, pg.glProjection); + } + + if (-1 < viewportLoc) { + float x = pg.viewport.get(0); + float y = pg.viewport.get(1); + float w = pg.viewport.get(2); + float h = pg.viewport.get(3); + setUniformValue(viewportLoc, x, y, w, h); + } + + if (-1 < bufferLoc) { + bufferUnit = getLastTexUnit() + 1; + setUniformValue(bufferLoc, bufferUnit); + pgl.activeTexture(PGL.TEXTURE0 + bufferUnit); + pg.bindFrontTexture(); + } else { + bufferUnit = -1; + } + } + + protected void bindTyped() { + if (pg == null) { + setRenderer(PGraphicsOpenGL.pgCurrent); + loadAttributes(); + loadUniforms(); + } + setCommonUniforms(); + + if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc); + if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc); + if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc); + if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc); + + if (-1 < normalMatLoc) { + pg.updateGLNormal(); + setUniformMatrix(normalMatLoc, pg.glNormal); + } + + if (-1 < ambientLoc) pgl.enableVertexAttribArray(ambientLoc); + if (-1 < specularLoc) pgl.enableVertexAttribArray(specularLoc); + if (-1 < emissiveLoc) pgl.enableVertexAttribArray(emissiveLoc); + if (-1 < shininessLoc) pgl.enableVertexAttribArray(shininessLoc); + + int count = pg.lightCount; + setUniformValue(lightCountLoc, count); + if (0 < count) { + setUniformVector(lightPositionLoc, pg.lightPosition, 4, count); + setUniformVector(lightNormalLoc, pg.lightNormal, 3, count); + setUniformVector(lightAmbientLoc, pg.lightAmbient, 3, count); + setUniformVector(lightDiffuseLoc, pg.lightDiffuse, 3, count); + setUniformVector(lightSpecularLoc, pg.lightSpecular, 3, count); + setUniformVector(lightFalloffLoc, pg.lightFalloffCoefficients, + 3, count); + setUniformVector(lightSpotLoc, pg.lightSpotParameters, 2, count); + } + + if (-1 < directionLoc) pgl.enableVertexAttribArray(directionLoc); + + if (-1 < offsetLoc) pgl.enableVertexAttribArray(offsetLoc); + + if (-1 < perspectiveLoc) { + if (pg.getHint(ENABLE_STROKE_PERSPECTIVE) && + pg.nonOrthoProjection()) { + setUniformValue(perspectiveLoc, 1); + } else { + setUniformValue(perspectiveLoc, 0); + } + } + + if (-1 < scaleLoc) { + if (pg.getHint(DISABLE_OPTIMIZED_STROKE)) { + setUniformValue(scaleLoc, 1.0f, 1.0f, 1.0f); + } else { + float f = PGL.STROKE_DISPLACEMENT; + if (pg.orthoProjection()) { + setUniformValue(scaleLoc, 1, 1, f); + } else { + setUniformValue(scaleLoc, f, f, f); + } + } + } + } + + protected void unbindTyped() { + if (-1 < offsetLoc) pgl.disableVertexAttribArray(offsetLoc); + + if (-1 < directionLoc) pgl.disableVertexAttribArray(directionLoc); + + if (-1 < textureLoc && texture != null) { + pgl.activeTexture(PGL.TEXTURE0 + texUnit); + texture.unbind(); + pgl.activeTexture(PGL.TEXTURE0); + texture = null; + } + + if (-1 < ambientLoc) pgl.disableVertexAttribArray(ambientLoc); + if (-1 < specularLoc) pgl.disableVertexAttribArray(specularLoc); + if (-1 < emissiveLoc) pgl.disableVertexAttribArray(emissiveLoc); + if (-1 < shininessLoc) pgl.disableVertexAttribArray(shininessLoc); + + if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc); + if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc); + if (-1 < texCoordLoc) pgl.disableVertexAttribArray(texCoordLoc); + if (-1 < normalLoc) pgl.disableVertexAttribArray(normalLoc); + + if (-1 < bufferLoc) { + pgl.requestFBOLayer(); + pgl.activeTexture(PGL.TEXTURE0 + bufferUnit); + pg.unbindFrontTexture(); + pgl.activeTexture(PGL.TEXTURE0); + } + + pgl.bindBuffer(PGL.ARRAY_BUFFER, 0); + } + + protected void setTexture(Texture tex) { + texture = tex; + + float scaleu = 1; + float scalev = 1; + float dispu = 0; + float dispv = 0; + + if (tex != null) { + if (tex.invertedX()) { + scaleu = -1; + dispu = 1; + } + + if (tex.invertedY()) { + scalev = -1; + dispv = 1; + } + + scaleu *= tex.maxTexcoordU(); + dispu *= tex.maxTexcoordU(); + scalev *= tex.maxTexcoordV(); + dispv *= tex.maxTexcoordV(); + + setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height); + + if (-1 < textureLoc) { + texUnit = -1 < bufferUnit ? bufferUnit + 1 : getLastTexUnit() + 1; + setUniformValue(textureLoc, texUnit); + pgl.activeTexture(PGL.TEXTURE0 + texUnit); + tex.bind(); + } + } + + if (-1 < texMatrixLoc) { + if (tcmat == null) { + tcmat = new float[16]; + } + tcmat[0] = scaleu; tcmat[4] = 0; tcmat[ 8] = 0; tcmat[12] = dispu; + tcmat[1] = 0; tcmat[5] = scalev; tcmat[ 9] = 0; tcmat[13] = dispv; + tcmat[2] = 0; tcmat[6] = 0; tcmat[10] = 0; tcmat[14] = 0; + tcmat[3] = 0; tcmat[7] = 0; tcmat[11] = 0; tcmat[15] = 0; + setUniformMatrix(texMatrixLoc, tcmat); + } + } + + + protected boolean supportsTexturing() { + return -1 < textureLoc; + } + + protected boolean supportLighting() { + return -1 < lightCountLoc || -1 < lightPositionLoc || -1 < lightNormalLoc; + } + + protected boolean accessTexCoords() { + return -1 < texCoordLoc; + } + + protected boolean accessNormals() { + return -1 < normalLoc; + } + + protected boolean accessLightAttribs() { + return -1 < ambientLoc || -1 < specularLoc || -1 < emissiveLoc || + -1 < shininessLoc; + } + + protected void setVertexAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset); + } + + protected void setColorAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset); + } + + protected void setNormalAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(normalLoc, vboId, size, type, false, stride, offset); + } + + protected void setTexcoordAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset); + } + + protected void setAmbientAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(ambientLoc, vboId, size, type, true, stride, offset); + } + + protected void setSpecularAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(specularLoc, vboId, size, type, true, stride, offset); + } + + protected void setEmissiveAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(emissiveLoc, vboId, size, type, true, stride, offset); + } + + protected void setShininessAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(shininessLoc, vboId, size, type, false, stride, offset); + } + + protected void setLineAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(directionLoc, vboId, size, type, false, stride, offset); + } + + protected void setPointAttribute(int vboId, int size, int type, + int stride, int offset) { + setAttributeVBO(offsetLoc, vboId, size, type, false, stride, offset); + } + + + // *************************************************************************** + // // Class to store a user-specified value for a uniform parameter // in the shader protected class UniformValue { diff --git a/core/src/processing/opengl/PShapeOpenGL.java b/core/src/processing/opengl/PShapeOpenGL.java index b23435535..466f2ba51 100644 --- a/core/src/processing/opengl/PShapeOpenGL.java +++ b/core/src/processing/opengl/PShapeOpenGL.java @@ -31,11 +31,8 @@ import processing.core.PMatrix2D; import processing.core.PMatrix3D; import processing.core.PShape; import processing.core.PVector; -import processing.opengl.PGraphicsOpenGL.LineShader; -import processing.opengl.PGraphicsOpenGL.PointShader; import processing.opengl.PGraphicsOpenGL.IndexCache; import processing.opengl.PGraphicsOpenGL.InGeometry; -import processing.opengl.PGraphicsOpenGL.PolyShader; import processing.opengl.PGraphicsOpenGL.TessGeometry; import processing.opengl.PGraphicsOpenGL.Tessellator; @@ -4601,7 +4598,7 @@ public class PShapeOpenGL extends PShape { Texture tex = textureImage != null ? g.getTexture(textureImage) : null; boolean renderingFill = false, renderingStroke = false; - PolyShader shader = null; + PShader shader = null; IndexCache cache = tessGeo.polyIndexCache; for (int n = firstPolyIndexCache; n <= lastPolyIndexCache; n++) { if (is3D() || (tex != null && (firstLineIndexCache == -1 || @@ -4776,7 +4773,7 @@ public class PShapeOpenGL extends PShape { protected void renderLines(PGraphicsOpenGL g) { - LineShader shader = g.getLineShader(); + PShader shader = g.getLineShader(); shader.bind(); IndexCache cache = tessGeo.lineIndexCache; @@ -4876,7 +4873,7 @@ public class PShapeOpenGL extends PShape { protected void renderPoints(PGraphicsOpenGL g) { - PointShader shader = g.getPointShader(); + PShader shader = g.getPointShader(); shader.bind(); IndexCache cache = tessGeo.pointIndexCache; From 9b4060b6e9c5c93cd5bedb19c1a55c548de978f1 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sat, 19 Oct 2013 14:00:31 -0400 Subject: [PATCH 202/556] removed some commented out code --- .../processing/opengl/PGraphicsOpenGL.java | 755 ------------------ 1 file changed, 755 deletions(-) diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 10b857ff1..f77dadb29 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -6329,39 +6329,6 @@ public class PGraphicsOpenGL extends PGraphics { shader.setVertexShader(defTextureShaderVertURL); } return shader; - - /* - int shaderType = getShaderType(fragFilename); - PShader shader = null; - if (shaderType == PShader.POINT) { - shader = new PointShader(parent); - shader.setVertexShader(defPointShaderVertURL); - } else if (shaderType == PShader.LINE) { - shader = new LineShader(parent); - shader.setVertexShader(defLineShaderVertURL); - } else if (shaderType == PShader.TEXLIGHT) { - shader = new PolyShader(parent); - shader.setVertexShader(defTexlightShaderVertURL); - ((PolyShader)shader).setType(PShader.TEXLIGHT); - } else if (shaderType == PShader.LIGHT) { - shader = new PolyShader(parent); - shader.setVertexShader(defLightShaderVertURL); - ((PolyShader)shader).setType(PShader.LIGHT); - } else if (shaderType == PShader.TEXTURE) { - shader = new PolyShader(parent); - ((PolyShader)shader).setType(PShader.TEXTURE); - shader.setVertexShader(defTextureShaderVertURL); - } else if (shaderType == PShader.COLOR) { - shader = new PolyShader(parent); - shader.setVertexShader(defColorShaderVertURL); - ((PolyShader)shader).setType(PShader.COLOR); - } else { - shader = new PolyShader(parent); - shader.setVertexShader(defTextureShaderVertURL); - } - shader.setFragmentShader(fragFilename); - return shader; - */ } @@ -6376,69 +6343,6 @@ public class PGraphicsOpenGL extends PGraphics { } else { return new PShader(parent, vertFilename, fragFilename); } - - /* - int vertType = getShaderType(vertFilename); - int fragType = getShaderType(fragFilename); - - int shaderType = -1; - if (vertType == -1 && fragType == -1) { - shaderType = PShader.POLY; - } else if (vertType == -1) { - shaderType = fragType; - } else if (fragType == -1) { - shaderType = vertType; - } else if (fragType == vertType) { - shaderType = vertType; - } else if (2 <= fragType && 2 <= vertType) { - shaderType = PShader.POLY; - } else { - PGraphics.showWarning(INCONSISTENT_SHADER_TYPES); - return null; - } - - PShader shader = null; - if (fragFilename == null || fragFilename.equals("")) { - if (shaderType == PShader.POINT) { - shader = new PointShader(parent); - shader.setFragmentShader(defPointShaderFragURL); - } else if (shaderType == PShader.LINE) { - shader = new LineShader(parent); - shader.setFragmentShader(defLineShaderFragURL); - } else if (shaderType == PShader.TEXLIGHT) { - shader = new PolyShader(parent); - shader.setFragmentShader(defTextureShaderFragURL); - ((PolyShader)shader).setType(PShader.TEXLIGHT); - } else if (shaderType == PShader.LIGHT) { - shader = new PolyShader(parent); - shader.setFragmentShader(defColorShaderFragURL); - ((PolyShader)shader).setType(PShader.LIGHT); - } else if (shaderType == PShader.TEXTURE) { - shader = new PolyShader(parent); - shader.setFragmentShader(defTextureShaderFragURL); - ((PolyShader)shader).setType(PShader.TEXTURE); - } else if (shaderType == PShader.COLOR) { - shader = new PolyShader(parent); - shader.setFragmentShader(defColorShaderFragURL); - ((PolyShader)shader).setType(PShader.COLOR); - } else { - shader = new PolyShader(parent); - shader.setVertexShader(defTextureShaderVertURL); - } - if (shader != null) { - shader.setVertexShader(vertFilename); - } - } else { - if (shaderType == PShader.POINT) { - shader = new PointShader(parent, vertFilename, fragFilename); - } else if (shaderType == PShader.LINE) { - shader = new LineShader(parent, vertFilename, fragFilename); - } else { - shader = new PolyShader(parent, vertFilename, fragFilename); - } - } - return shader; - */ } @@ -6457,30 +6361,6 @@ public class PGraphicsOpenGL extends PGraphics { // TODO: deprecate this method, the kind arguments is not used anymore public void shader(PShader shader, int kind) { shader(shader); - - /* - if (kind == TRIANGLES || kind == QUADS || kind == POLYGON) { - if (shader instanceof PolyShader) { - polyShader = (PolyShader) shader; - } else { - PGraphics.showWarning(WRONG_SHADER_TYPE_ERROR); - } - } else if (kind == LINES) { - if (shader instanceof LineShader) { - lineShader = (LineShader)shader; - } else { - PGraphics.showWarning(WRONG_SHADER_TYPE_ERROR); - } - } else if (kind == POINTS) { - if (shader instanceof PointShader) { - pointShader = (PointShader)shader; - } else { - PGraphics.showWarning(WRONG_SHADER_TYPE_ERROR); - } - } else { - PGraphics.showWarning(UNKNOWN_SHADER_KIND_ERROR); - } - */ } @@ -6668,641 +6548,6 @@ public class PGraphicsOpenGL extends PGraphics { return shader; } -/* - protected class BaseShader extends PShader { - protected int transformMatLoc; - protected int modelviewMatLoc; - protected int projectionMatLoc; - protected int bufferLoc; - protected int bufferUnit; - protected int viewportLoc; - - public BaseShader(PApplet parent) { - super(parent); - } - - public BaseShader(PApplet parent, String vertFilename, String fragFilename) { - super(parent, vertFilename, fragFilename); - } - - public BaseShader(PApplet parent, URL vertURL, URL fragURL) { - super(parent, vertURL, fragURL); - } - - @Override - public void loadUniforms() { - transformMatLoc = getUniformLoc("transform"); - if (transformMatLoc == -1) - transformMatLoc = getUniformLoc("transformMatrix"); - - modelviewMatLoc = getUniformLoc("modelview"); - if (modelviewMatLoc == -1) - modelviewMatLoc = getUniformLoc("modelviewMatrix"); - - projectionMatLoc = getUniformLoc("projection"); - if (projectionMatLoc == -1) - projectionMatLoc = getUniformLoc("projectionMatrix"); - - viewportLoc = getUniformLoc("viewport"); - bufferLoc = getUniformLoc("buffer"); - } - - @Override - public void unbind() { - if (-1 < bufferLoc) { - pgl.requestFBOLayer(); - pgl.activeTexture(PGL.TEXTURE0 + bufferUnit); - pg.unbindFrontTexture(); - pgl.activeTexture(PGL.TEXTURE0); - } - - pgl.bindBuffer(PGL.ARRAY_BUFFER, 0); - - super.unbind(); - } - - @Override - protected void setCommonUniforms() { - if (-1 < transformMatLoc) { - pg.updateGLProjmodelview(); - setUniformMatrix(transformMatLoc, pg.glProjmodelview); - } - - if (-1 < modelviewMatLoc) { - pg.updateGLModelview(); - setUniformMatrix(modelviewMatLoc, pg.glModelview); - } - - if (-1 < projectionMatLoc) { - pg.updateGLProjection(); - setUniformMatrix(projectionMatLoc, pg.glProjection); - } - - if (-1 < viewportLoc) { - float x = pg.viewport.get(0); - float y = pg.viewport.get(1); - float w = pg.viewport.get(2); - float h = pg.viewport.get(3); - setUniformValue(viewportLoc, x, y, w, h); - } - - if (-1 < bufferLoc) { - bufferUnit = super.getLastTexUnit() + 1; - setUniformValue(bufferLoc, bufferUnit); - pgl.activeTexture(PGL.TEXTURE0 + bufferUnit); - pg.bindFrontTexture(); - } else { - bufferUnit = -1; - } - } - - @Override - public int getLastTexUnit() { - return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit(); - } - - @Override - public boolean supportsTexturing() { - return false; - } - - @Override - public boolean supportLighting() { - return false; - } - - @Override - public boolean accessTexCoords() { - return false; - } - - @Override - public boolean accessNormals() { - return false; - } - - @Override - public boolean accessLightAttribs() { - return false; - } - - @Override - public void setVertexAttribute(int vboId, int size, int type, - int stride, int offset) { } - @Override - public void setColorAttribute(int vboId, int size, int type, - int stride, int offset) { } - @Override - public void setNormalAttribute(int vboId, int size, int type, - int stride, int offset) { } - @Override - public void setAmbientAttribute(int vboId, int size, int type, - int stride, int offset) { } - @Override - public void setSpecularAttribute(int vboId, int size, int type, - int stride, int offset) { } - @Override - public void setEmissiveAttribute(int vboId, int size, int type, - int stride, int offset) { } - @Override - public void setShininessAttribute(int vboId, int size, int type, - int stride, int offset) { } - @Override - public void setTexcoordAttribute(int vboId, int size, int type, - int stride, int offset) { } - @Override - public void setTexture(Texture tex) { } - } - - - protected class PolyShader extends BaseShader { - protected int type = 0; - - protected int vertexLoc; - protected int colorLoc; - protected int normalLoc; - protected int texCoordLoc; - protected int normalMatLoc; - - protected int lightCountLoc; - protected int lightPositionLoc; - protected int lightNormalLoc; - protected int lightAmbientLoc; - protected int lightDiffuseLoc; - protected int lightSpecularLoc; - protected int lightFalloffLoc; - protected int lightSpotLoc; - - protected int ambientLoc; - protected int specularLoc; - protected int emissiveLoc; - protected int shininessLoc; - - protected Texture texture; - protected int texUnit; - - protected int textureLoc; - protected int texMatrixLoc; - protected int texOffsetLoc; - - protected float[] tcmat; - - public PolyShader(PApplet parent) { - super(parent); - } - - public PolyShader(PApplet parent, String vertFilename, - String fragFilename) { - super(parent, vertFilename, fragFilename); - } - - public PolyShader(PApplet parent, URL vertURL, URL fragURL) { - super(parent, vertURL, fragURL); - } - - @Override - public void loadAttributes() { - vertexLoc = getAttributeLoc("vertex"); - if (vertexLoc == -1) vertexLoc = getAttributeLoc("position"); - - colorLoc = getAttributeLoc("color"); - texCoordLoc = getAttributeLoc("texCoord"); - normalLoc = getAttributeLoc("normal"); - - ambientLoc = getAttributeLoc("ambient"); - specularLoc = getAttributeLoc("specular"); - emissiveLoc = getAttributeLoc("emissive"); - shininessLoc = getAttributeLoc("shininess"); - } - - @Override - public void loadUniforms() { - super.loadUniforms(); - - normalMatLoc = getUniformLoc("normalMatrix"); - - lightCountLoc = getUniformLoc("lightCount"); - lightPositionLoc = getUniformLoc("lightPosition"); - lightNormalLoc = getUniformLoc("lightNormal"); - lightAmbientLoc = getUniformLoc("lightAmbient"); - lightDiffuseLoc = getUniformLoc("lightDiffuse"); - lightSpecularLoc = getUniformLoc("lightSpecular"); - lightFalloffLoc = getUniformLoc("lightFalloff"); - lightSpotLoc = getUniformLoc("lightSpot"); - - textureLoc = getUniformLoc("texture"); - texMatrixLoc = getUniformLoc("texMatrix"); - texOffsetLoc = getUniformLoc("texOffset"); - } - - @Override - public void setTexture(Texture tex) { - texture = tex; - - float scaleu = 1; - float scalev = 1; - float dispu = 0; - float dispv = 0; - - if (tex != null) { - if (tex.invertedX()) { - scaleu = -1; - dispu = 1; - } - - if (tex.invertedY()) { - scalev = -1; - dispv = 1; - } - - scaleu *= tex.maxTexcoordU(); - dispu *= tex.maxTexcoordU(); - scalev *= tex.maxTexcoordV(); - dispv *= tex.maxTexcoordV(); - - setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height); - - if (-1 < textureLoc) { - texUnit = getLastTexUnit() + 1; - setUniformValue(textureLoc, texUnit); - pgl.activeTexture(PGL.TEXTURE0 + texUnit); - tex.bind(); - } - } - - if (-1 < texMatrixLoc) { - if (tcmat == null) { - tcmat = new float[16]; - } - tcmat[0] = scaleu; tcmat[4] = 0; tcmat[ 8] = 0; tcmat[12] = dispu; - tcmat[1] = 0; tcmat[5] = scalev; tcmat[ 9] = 0; tcmat[13] = dispv; - tcmat[2] = 0; tcmat[6] = 0; tcmat[10] = 0; tcmat[14] = 0; - tcmat[3] = 0; tcmat[7] = 0; tcmat[11] = 0; tcmat[15] = 0; - setUniformMatrix(texMatrixLoc, tcmat); - } - } - - @Override - public boolean hasType() { - return COLOR <= type && type <= TEXLIGHT; - } - - @Override - public void setType(int type) { - this.type = type; - } - - @Override - public int getType() { - return type; - } - - @Override - public boolean checkType(int type) { - if (!hasType()) return true; - - if (getType() != type) { - if (type == TEXLIGHT) { - PGraphics.showWarning(NO_TEXLIGHT_SHADER_ERROR); - } else if (type == LIGHT) { - PGraphics.showWarning(NO_LIGHT_SHADER_ERROR); - } else if (type == TEXTURE) { - PGraphics.showWarning(NO_TEXTURE_SHADER_ERROR); - } else if (type == COLOR) { - PGraphics.showWarning(NO_COLOR_SHADER_ERROR); - } - return false; - } - - return true; - } - - @Override - public boolean supportsTexturing() { - return -1 < textureLoc; - } - - @Override - public boolean supportLighting() { - return -1 < lightCountLoc || -1 < lightPositionLoc || -1 < lightNormalLoc; - } - - @Override - public boolean accessTexCoords() { - return -1 < texCoordLoc; - } - - @Override - public boolean accessNormals() { - return -1 < normalLoc; - } - - @Override - public boolean accessLightAttribs() { - return -1 < ambientLoc || -1 < specularLoc || -1 < emissiveLoc || - -1 < shininessLoc; - } - - @Override - public void setVertexAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void setColorAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset); - } - - @Override - public void setNormalAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(normalLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void setTexcoordAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void setAmbientAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(ambientLoc, vboId, size, type, true, stride, offset); - } - - @Override - public void setSpecularAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(specularLoc, vboId, size, type, true, stride, offset); - } - - @Override - public void setEmissiveAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(emissiveLoc, vboId, size, type, true, stride, offset); - } - - @Override - public void setShininessAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(shininessLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void bind() { - super.bind(); - if (pg == null) { - setRenderer(PGraphicsOpenGL.pgCurrent); - loadAttributes(); - loadUniforms(); - } - setCommonUniforms(); - - if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc); - if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc); - if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc); - if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc); - - if (-1 < normalMatLoc) { - pg.updateGLNormal(); - setUniformMatrix(normalMatLoc, pg.glNormal); - } - - if (-1 < ambientLoc) pgl.enableVertexAttribArray(ambientLoc); - if (-1 < specularLoc) pgl.enableVertexAttribArray(specularLoc); - if (-1 < emissiveLoc) pgl.enableVertexAttribArray(emissiveLoc); - if (-1 < shininessLoc) pgl.enableVertexAttribArray(shininessLoc); - - int count = pg.lightCount; - setUniformValue(lightCountLoc, count); - if (0 < count) { - setUniformVector(lightPositionLoc, pg.lightPosition, 4, count); - setUniformVector(lightNormalLoc, pg.lightNormal, 3, count); - setUniformVector(lightAmbientLoc, pg.lightAmbient, 3, count); - setUniformVector(lightDiffuseLoc, pg.lightDiffuse, 3, count); - setUniformVector(lightSpecularLoc, pg.lightSpecular, 3, count); - setUniformVector(lightFalloffLoc, pg.lightFalloffCoefficients, - 3, count); - setUniformVector(lightSpotLoc, pg.lightSpotParameters, 2, count); - } - } - - @Override - public void unbind() { - if (-1 < textureLoc && texture != null) { - pgl.activeTexture(PGL.TEXTURE0 + texUnit); - texture.unbind(); - pgl.activeTexture(PGL.TEXTURE0); - texture = null; - } - - if (-1 < ambientLoc) pgl.disableVertexAttribArray(ambientLoc); - if (-1 < specularLoc) pgl.disableVertexAttribArray(specularLoc); - if (-1 < emissiveLoc) pgl.disableVertexAttribArray(emissiveLoc); - if (-1 < shininessLoc) pgl.disableVertexAttribArray(shininessLoc); - - if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc); - if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc); - if (-1 < texCoordLoc) pgl.disableVertexAttribArray(texCoordLoc); - if (-1 < normalLoc) pgl.disableVertexAttribArray(normalLoc); - - super.unbind(); - } - } - - - protected class LineShader extends BaseShader { - protected int perspectiveLoc; - protected int scaleLoc; - - protected int vertexLoc; - protected int colorLoc; - protected int directionLoc; - - public LineShader(PApplet parent) { - super(parent); - } - - public LineShader(PApplet parent, String vertFilename, - String fragFilename) { - super(parent, vertFilename, fragFilename); - } - - public LineShader(PApplet parent, URL vertURL, URL fragURL) { - super(parent, vertURL, fragURL); - } - - @Override - public void loadAttributes() { - vertexLoc = getAttributeLoc("vertex"); - if (vertexLoc == -1) vertexLoc = getAttributeLoc("position"); - - colorLoc = getAttributeLoc("color"); - directionLoc = getAttributeLoc("direction"); - } - - @Override - public void loadUniforms() { - super.loadUniforms(); - - viewportLoc = getUniformLoc("viewport"); - perspectiveLoc = getUniformLoc("perspective"); - scaleLoc = getUniformLoc("scale"); - } - - @Override - public void setVertexAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void setColorAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset); - } - - @Override - public void setLineAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(directionLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void bind() { - super.bind(); - if (pg == null) { - setRenderer(PGraphicsOpenGL.pgCurrent); - loadAttributes(); - loadUniforms(); - } - - if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc); - if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc); - if (-1 < directionLoc) pgl.enableVertexAttribArray(directionLoc); - - if (pg.getHint(ENABLE_STROKE_PERSPECTIVE) && - pg.nonOrthoProjection()) { - setUniformValue(perspectiveLoc, 1); - } else { - setUniformValue(perspectiveLoc, 0); - } - - if (pg.getHint(DISABLE_OPTIMIZED_STROKE)) { - setUniformValue(scaleLoc, 1.0f, 1.0f, 1.0f); - } else { - float f = PGL.STROKE_DISPLACEMENT; - if (orthoProjection()) { - setUniformValue(scaleLoc, 1, 1, f); - } else { - setUniformValue(scaleLoc, f, f, f); - } - } - - setCommonUniforms(); - } - - @Override - public void unbind() { - if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc); - if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc); - if (-1 < directionLoc) pgl.disableVertexAttribArray(directionLoc); - - super.unbind(); - } - } - - - protected class PointShader extends BaseShader { - protected int perspectiveLoc; - - protected int vertexLoc; - protected int colorLoc; - protected int offsetLoc; - - public PointShader(PApplet parent) { - super(parent); - } - - public PointShader(PApplet parent, String vertFilename, - String fragFilename) { - super(parent, vertFilename, fragFilename); - } - - public PointShader(PApplet parent, URL vertURL, URL fragURL) { - super(parent, vertURL, fragURL); - } - - @Override - public void loadAttributes() { - vertexLoc = getAttributeLoc("vertex"); - if (vertexLoc == -1) vertexLoc = getAttributeLoc("position"); - - colorLoc = getAttributeLoc("color"); - offsetLoc = getAttributeLoc("offset"); - } - - @Override - public void loadUniforms() { - super.loadUniforms(); - - perspectiveLoc = getUniformLoc("perspective"); - } - - @Override - public void setVertexAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void setColorAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset); - } - - @Override - public void setPointAttribute(int vboId, int size, int type, - int stride, int offset) { - setAttributeVBO(offsetLoc, vboId, size, type, false, stride, offset); - } - - @Override - public void bind() { - super.bind(); - if (pg == null) { - setRenderer(PGraphicsOpenGL.pgCurrent); - loadAttributes(); - loadUniforms(); - } - - if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc); - if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc); - if (-1 < offsetLoc) pgl.enableVertexAttribArray(offsetLoc); - - if (pg.getHint(ENABLE_STROKE_PERSPECTIVE) && - pg.nonOrthoProjection()) { - setUniformValue(perspectiveLoc, 1); - } else { - setUniformValue(perspectiveLoc, 0); - } - - super.setCommonUniforms(); - } - - @Override - public void unbind() { - if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc); - if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc); - if (-1 < offsetLoc) pgl.disableVertexAttribArray(offsetLoc); - - super.unbind(); - } - } -*/ ////////////////////////////////////////////////////////////// From 6c1b4ee095925ce7f341ae6319f01c5d7ce80054 Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sat, 19 Oct 2013 14:15:06 -0400 Subject: [PATCH 203/556] updated to JOGL 2.1.1, fix #2136 --- core/src/processing/opengl/PJOGL.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index f70587ad6..d7e0df101 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -15,6 +15,7 @@ import javax.media.opengl.GL; import javax.media.opengl.GL2; import javax.media.opengl.GL2ES1; import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL2ES3; import javax.media.opengl.GL2GL3; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; @@ -45,6 +46,7 @@ import java.awt.Shape; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.PathIterator; + import javax.media.opengl.glu.GLUtessellator; import javax.media.opengl.glu.GLUtessellatorCallbackAdapter; @@ -1164,7 +1166,7 @@ public class PJOGL extends PGL { EXTENSIONS = GL.GL_EXTENSIONS; SHADING_LANGUAGE_VERSION = GL2ES2.GL_SHADING_LANGUAGE_VERSION; - MAX_SAMPLES = GL2.GL_MAX_SAMPLES; + MAX_SAMPLES = GL2ES3.GL_MAX_SAMPLES; SAMPLES = GL.GL_SAMPLES; ALIASED_LINE_WIDTH_RANGE = GL.GL_ALIASED_LINE_WIDTH_RANGE; @@ -1325,8 +1327,8 @@ public class PJOGL extends PGL { NOTEQUAL = GL.GL_NOTEQUAL; FUNC_ADD = GL.GL_FUNC_ADD; - FUNC_MIN = GL2.GL_MIN; - FUNC_MAX = GL2.GL_MAX; + FUNC_MIN = GL2ES3.GL_MIN; + FUNC_MAX = GL2ES3.GL_MAX; FUNC_REVERSE_SUBTRACT = GL.GL_FUNC_REVERSE_SUBTRACT; FUNC_SUBTRACT = GL.GL_FUNC_SUBTRACT; @@ -1355,8 +1357,8 @@ public class PJOGL extends PGL { RENDERBUFFER = GL.GL_RENDERBUFFER; DEPTH_ATTACHMENT = GL.GL_DEPTH_ATTACHMENT; STENCIL_ATTACHMENT = GL.GL_STENCIL_ATTACHMENT; - READ_FRAMEBUFFER = GL2.GL_READ_FRAMEBUFFER; - DRAW_FRAMEBUFFER = GL2.GL_DRAW_FRAMEBUFFER; + READ_FRAMEBUFFER = GL2ES3.GL_READ_FRAMEBUFFER; + DRAW_FRAMEBUFFER = GL2ES3.GL_DRAW_FRAMEBUFFER; RGBA8 = GL.GL_RGBA8; DEPTH24_STENCIL8 = GL.GL_DEPTH24_STENCIL8; @@ -1629,7 +1631,7 @@ public class PJOGL extends PGL { @Override public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer data) { - gl2.glVertexAttribPointer(index, size, type, normalized, stride, data); + gl2x.glVertexAttribPointer(index, size, type, normalized, stride, data); } @Override @@ -1654,7 +1656,7 @@ public class PJOGL extends PGL { @Override public void drawElements(int mode, int count, int type, Buffer indices) { - gl.glDrawElements(mode, count, type, indices); + gl2x.glDrawElements(mode, count, type, indices); } ////////////////////////////////////////////////////////////////////////////// From 1efba6b431bec6c784935c3fa7b2cbaf0a3d7502 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 19 Oct 2013 16:24:03 -0400 Subject: [PATCH 204/556] update for JDK 7u45 on OS X, and prevent hard-coding of JDK version in Base --- app/src/processing/app/Base.java | 11 ++++++++++- build/build.xml | 30 +++++++----------------------- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 051bc9c1d..170fe5276 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2405,7 +2405,16 @@ public class Base { static public String getJavaPath() { if (isMacOS()) { //return "Contents/PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java"; - return getContentFile("../PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java").getAbsolutePath(); + File[] plugins = getContentFile("../PlugIns").listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.endsWith(".jdk") && dir.isDirectory(); + } + }); + //PApplet.printArray(plugins); + File javaBinary = new File(plugins[0], "Contents/Home/jre/bin/java"); + //return getContentFile(plugins[0].getAbsolutePath() + "/Contents/Home/jre/bin/java").getAbsolutePath(); + //return getContentFile("../PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java").getAbsolutePath(); + return javaBinary.getAbsolutePath(); } else if (isLinux()) { return getContentFile("java/bin/java").getAbsolutePath(); diff --git a/build/build.xml b/build/build.xml index 9def0cfe6..324fed312 100755 --- a/build/build.xml +++ b/build/build.xml @@ -151,30 +151,14 @@ - - - + + + - - - - - + + message="JDK 7u${jdk.update.macosx} required.${line.separator}To build on OS X, you must install Oracle's JDK 7u${jdk.update.macosx} from${line.separator}http://www.oracle.com/technetwork/java/javase/downloads${line.separator}Note that only 7u${jdk.update.macosx} (not a later or earlier version) will work. ${line.separator}And it must be the JDK, not the JRE. And do not try to defy me again." /> - + @@ -595,7 +579,7 @@ - + From 26da73d4221245181842c6042508b9f4431b686e Mon Sep 17 00:00:00 2001 From: codeanticode Date: Sat, 19 Oct 2013 20:20:27 -0400 Subject: [PATCH 205/556] some edits, additional null checks in PJOGL --- core/src/processing/opengl/PJOGL.java | 92 +++++++++++++------------ core/src/processing/opengl/PShader.java | 58 ++++++++-------- 2 files changed, 78 insertions(+), 72 deletions(-) diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index d7e0df101..4418d67f0 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -614,49 +614,51 @@ public class PJOGL extends PGL { @Override protected void beginGL() { - if (projMatrix == null) { - projMatrix = new float[16]; - } - gl2x.glMatrixMode(GLMatrixFunc.GL_PROJECTION); - projMatrix[ 0] = pg.projection.m00; - projMatrix[ 1] = pg.projection.m10; - projMatrix[ 2] = pg.projection.m20; - projMatrix[ 3] = pg.projection.m30; - projMatrix[ 4] = pg.projection.m01; - projMatrix[ 5] = pg.projection.m11; - projMatrix[ 6] = pg.projection.m21; - projMatrix[ 7] = pg.projection.m31; - projMatrix[ 8] = pg.projection.m02; - projMatrix[ 9] = pg.projection.m12; - projMatrix[10] = pg.projection.m22; - projMatrix[11] = pg.projection.m32; - projMatrix[12] = pg.projection.m03; - projMatrix[13] = pg.projection.m13; - projMatrix[14] = pg.projection.m23; - projMatrix[15] = pg.projection.m33; - gl2x.glLoadMatrixf(projMatrix, 0); + if (gl2x != null) { + if (projMatrix == null) { + projMatrix = new float[16]; + } + gl2x.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + projMatrix[ 0] = pg.projection.m00; + projMatrix[ 1] = pg.projection.m10; + projMatrix[ 2] = pg.projection.m20; + projMatrix[ 3] = pg.projection.m30; + projMatrix[ 4] = pg.projection.m01; + projMatrix[ 5] = pg.projection.m11; + projMatrix[ 6] = pg.projection.m21; + projMatrix[ 7] = pg.projection.m31; + projMatrix[ 8] = pg.projection.m02; + projMatrix[ 9] = pg.projection.m12; + projMatrix[10] = pg.projection.m22; + projMatrix[11] = pg.projection.m32; + projMatrix[12] = pg.projection.m03; + projMatrix[13] = pg.projection.m13; + projMatrix[14] = pg.projection.m23; + projMatrix[15] = pg.projection.m33; + gl2x.glLoadMatrixf(projMatrix, 0); - if (mvMatrix == null) { - mvMatrix = new float[16]; + if (mvMatrix == null) { + mvMatrix = new float[16]; + } + gl2x.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + mvMatrix[ 0] = pg.modelview.m00; + mvMatrix[ 1] = pg.modelview.m10; + mvMatrix[ 2] = pg.modelview.m20; + mvMatrix[ 3] = pg.modelview.m30; + mvMatrix[ 4] = pg.modelview.m01; + mvMatrix[ 5] = pg.modelview.m11; + mvMatrix[ 6] = pg.modelview.m21; + mvMatrix[ 7] = pg.modelview.m31; + mvMatrix[ 8] = pg.modelview.m02; + mvMatrix[ 9] = pg.modelview.m12; + mvMatrix[10] = pg.modelview.m22; + mvMatrix[11] = pg.modelview.m32; + mvMatrix[12] = pg.modelview.m03; + mvMatrix[13] = pg.modelview.m13; + mvMatrix[14] = pg.modelview.m23; + mvMatrix[15] = pg.modelview.m33; + gl2x.glLoadMatrixf(mvMatrix, 0); } - gl2x.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); - mvMatrix[ 0] = pg.modelview.m00; - mvMatrix[ 1] = pg.modelview.m10; - mvMatrix[ 2] = pg.modelview.m20; - mvMatrix[ 3] = pg.modelview.m30; - mvMatrix[ 4] = pg.modelview.m01; - mvMatrix[ 5] = pg.modelview.m11; - mvMatrix[ 6] = pg.modelview.m21; - mvMatrix[ 7] = pg.modelview.m31; - mvMatrix[ 8] = pg.modelview.m02; - mvMatrix[ 9] = pg.modelview.m12; - mvMatrix[10] = pg.modelview.m22; - mvMatrix[11] = pg.modelview.m32; - mvMatrix[12] = pg.modelview.m03; - mvMatrix[13] = pg.modelview.m13; - mvMatrix[14] = pg.modelview.m23; - mvMatrix[15] = pg.modelview.m33; - gl2x.glLoadMatrixf(mvMatrix, 0); } @@ -1631,7 +1633,9 @@ public class PJOGL extends PGL { @Override public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer data) { - gl2x.glVertexAttribPointer(index, size, type, normalized, stride, data); + if (gl2x != null) { + gl2x.glVertexAttribPointer(index, size, type, normalized, stride, data); + } } @Override @@ -1656,7 +1660,9 @@ public class PJOGL extends PGL { @Override public void drawElements(int mode, int count, int type, Buffer indices) { - gl2x.glDrawElements(mode, count, type, indices); + if (gl2x != null) { + gl2x.glDrawElements(mode, count, type, indices); + } } ////////////////////////////////////////////////////////////////////////////// diff --git a/core/src/processing/opengl/PShader.java b/core/src/processing/opengl/PShader.java index 652d93c97..4dcdc12cd 100644 --- a/core/src/processing/opengl/PShader.java +++ b/core/src/processing/opengl/PShader.java @@ -59,6 +59,9 @@ public class PShader implements PConstants { protected PGL pgl; protected int context; // The context that created this shader. + // The shader type: POINT, LINE, POLY, etc. + protected int type; + public int glProgram; public int glVertex; public int glFragment; @@ -83,9 +86,7 @@ public class PShader implements PConstants { protected IntBuffer intBuffer; protected FloatBuffer floatBuffer; - - - protected int type; + // Uniforms common to all shader types protected int transformMatLoc; protected int modelviewMatLoc; protected int projectionMatLoc; @@ -93,20 +94,11 @@ public class PShader implements PConstants { protected int bufferUnit; protected int viewportLoc; - protected int vertexLoc; - protected int colorLoc; - protected int normalLoc; - protected int texCoordLoc; - protected int normalMatLoc; - - // For lines + // Uniforms only for lines and points protected int perspectiveLoc; protected int scaleLoc; - protected int directionLoc; - - // For points - protected int offsetLoc; + // Lighting uniforms protected int lightCountLoc; protected int lightPositionLoc; protected int lightNormalLoc; @@ -116,21 +108,27 @@ public class PShader implements PConstants { protected int lightFalloffLoc; protected int lightSpotLoc; + // Texturing uniforms + protected Texture texture; + protected int texUnit; + protected int textureLoc; + protected int texMatrixLoc; + protected int texOffsetLoc; + protected float[] tcmat; + + // Vertex attributes + protected int vertexLoc; + protected int colorLoc; + protected int normalLoc; + protected int texCoordLoc; + protected int normalMatLoc; + protected int directionLoc; + protected int offsetLoc; protected int ambientLoc; protected int specularLoc; protected int emissiveLoc; protected int shininessLoc; - protected Texture texture; - protected int texUnit; - - protected int textureLoc; - protected int texMatrixLoc; - protected int texOffsetLoc; - - protected float[] tcmat; - - public PShader() { parent = null; pgl = null; @@ -470,14 +468,16 @@ public class PShader implements PConstants { } - - protected boolean setup() { - - return true; + /** + * Extra initialization method that can be used by subclasses, called after + * compiling and attaching the vertex and fragment shaders, and before + * linking the shader program. + * + */ + protected void setup() { } - /** * Returns the ID location of the attribute parameter given its name. * From ff618bc0b583dc0127467bafd99bc29dfb6f6bab Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 19 Oct 2013 21:04:42 -0400 Subject: [PATCH 206/556] try to switch to JRE only; fail --- app/src/processing/app/Base.java | 4 ++++ .../src/com/oracle/appbundler/AppBundlerTask.java | 5 +++-- core/todo.txt | 6 ++++++ todo.txt | 1 + 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 170fe5276..74bda230e 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2401,6 +2401,10 @@ public class Base { } +// static public File getJavaHome() { +// } + + /** Get the path to the embedded Java executable. */ static public String getJavaPath() { if (isMacOS()) { diff --git a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java index 30ba1d126..5d944f4d7 100644 --- a/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java +++ b/build/macosx/appbundler/src/com/oracle/appbundler/AppBundlerTask.java @@ -495,8 +495,9 @@ public class AppBundlerTask extends Task { DirectoryScanner directoryScanner = runtime.getDirectoryScanner(getProject()); String[] includedFiles = directoryScanner.getIncludedFiles(); - for (int i = 0; i < includedFiles.length; i++) { - String includedFile = includedFiles[i]; + for (String includedFile : includedFiles) { + //for (int i = 0; i < includedFiles.length; i++) { + //String includedFile = includedFiles[i]; File source = new File(runtimeHomeDirectory, includedFile); File destination = new File(pluginHomeDirectory, includedFile); copy(source, destination); diff --git a/core/todo.txt b/core/todo.txt index 6ba9c3fa0..cb7346925 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -45,6 +45,12 @@ X SUBTRACT and DIFFERENCE blend modes are swapped X https://github.com/processing/processing/issues/2075 X throw an error for textureMode(REPEAT) [fry] X https://github.com/processing/processing/issues/2052 +X Updated to JOGL 2.1.0 +X https://github.com/processing/processing/issues/2136 +X vertex codes not being properly set in P2D/P3D +X https://github.com/processing/processing/issues/2131 +X some box normals are inverted +X https://github.com/processing/processing/issues/2151 _ insertRow() bug _ https://github.com/processing/processing/issues/2137 diff --git a/todo.txt b/todo.txt index 89c2446d5..5557df2eb 100644 --- a/todo.txt +++ b/todo.txt @@ -150,6 +150,7 @@ _ https://github.com/processing/processing/wiki/Build-Instructions _ "unable to locate tools.jar" (Windows) can be ignored _ JAVA_HOME warnings from Ant can also be ignored _ updates for macosx instructions +_ JDK 7u45 is needed (or whatever version currently in the build) _ to build appbundler, you'll need Xcode _ and the command line tools Preferences > Downloads > Command Line Tools _ appbundler will have an NPE if the osx binary isn't built From 9d0bfd3f9d96251269bad649f059d4735bc24de7 Mon Sep 17 00:00:00 2001 From: Ben Fry Date: Sat, 19 Oct 2013 22:24:05 -0400 Subject: [PATCH 207/556] working on OS X export with embedded JRE --- app/src/processing/app/Base.java | 42 +++++++++++++++++- app/src/processing/mode/java/JavaBuild.java | 45 ++++++++++++++++---- build/build.xml | 10 ++--- java/application/sketch.icns | Bin 0 -> 174666 bytes 4 files changed, 82 insertions(+), 15 deletions(-) create mode 100644 java/application/sketch.icns diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 74bda230e..a3584a407 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -2401,12 +2401,26 @@ public class Base { } -// static public File getJavaHome() { -// } + static public File getJavaHome() { + if (isMacOS()) { + //return "Contents/PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java"; + File[] plugins = getContentFile("../PlugIns").listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.endsWith(".jdk") && dir.isDirectory(); + } + }); + return new File(plugins[0], "Contents/Home/jre"); + } + // On all other platforms, it's the 'java' folder adjacent to Processing + return getContentFile("java"); + } /** Get the path to the embedded Java executable. */ static public String getJavaPath() { + String javaPath = "bin/java" + (isWindows() ? ".exe" : ""); + return new File(getJavaHome(), javaPath).getAbsolutePath(); + /* if (isMacOS()) { //return "Contents/PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java"; File[] plugins = getContentFile("../PlugIns").listFiles(new FilenameFilter() { @@ -2429,6 +2443,7 @@ public class Base { System.err.println("No appropriate platform found. " + "Hoping that Java is in the path."); return Base.isWindows() ? "java.exe" : "java"; + */ } @@ -2569,6 +2584,7 @@ public class Base { to = null; targetFile.setLastModified(sourceFile.lastModified()); + targetFile.setExecutable(sourceFile.canExecute()); } @@ -2639,6 +2655,28 @@ public class Base { } } } + + + static public void copyDirNative(File sourceDir, + File targetDir) throws IOException { + Process process = null; + if (Base.isMacOS() || Base.isLinux()) { + process = Runtime.getRuntime().exec(new String[] { + "cp", "-a", sourceDir.getAbsolutePath(), targetDir.getAbsolutePath() + }); + } else { + // TODO implement version that uses XCOPY here on Windows + throw new RuntimeException("Not yet implemented on Windows"); + } + try { + int result = process.waitFor(); + if (result != 0) { + throw new IOException("Error while copying (result " + result + ")"); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } /** diff --git a/app/src/processing/mode/java/JavaBuild.java b/app/src/processing/mode/java/JavaBuild.java index 43112e227..cb80b60e2 100644 --- a/app/src/processing/mode/java/JavaBuild.java +++ b/app/src/processing/mode/java/JavaBuild.java @@ -1162,11 +1162,42 @@ public class JavaBuild { File dotAppFolder = null; if (exportPlatform == PConstants.MACOSX) { dotAppFolder = new File(destFolder, sketch.getName() + ".app"); -// String APP_SKELETON = "skeleton.app"; - //File dotAppSkeleton = new File(folder, APP_SKELETON); - File dotAppSkeleton = mode.getContentFile("application/template.app"); - Base.copyDir(dotAppSkeleton, dotAppFolder); + File contentsOrig = new File(Base.getJavaHome(), "../../../../.."); + +// File dotAppSkeleton = mode.getContentFile("application/template.app"); +// Base.copyDir(dotAppSkeleton, dotAppFolder); + File contentsFolder = new File(dotAppFolder, "Contents"); + contentsFolder.mkdirs(); + + // Info.plist will be written later + + // set the jar folder to a different location than windows/linux + //jarFolder = new File(dotAppFolder, "Contents/Resources/Java"); + jarFolder = new File(contentsFolder, "Java"); + + File macosFolder = new File(contentsFolder, "MacOS"); + macosFolder.mkdirs(); + Base.copyFile(new File(contentsOrig, "MacOS/Processing"), + new File(contentsFolder, "MacOS/" + sketch.getName())); + + File pkgInfo = new File(contentsFolder, "PkgInfo"); + PrintWriter writer = PApplet.createWriter(pkgInfo); + writer.println("APPL????"); + writer.flush(); + writer.close(); + + // Use faster(?) native copy here (also to do sym links) + Base.copyDirNative(new File(contentsOrig, "PlugIns"), + new File(contentsFolder, "PlugIns")); + + File resourcesFolder = new File(contentsFolder, "Resources"); + Base.copyDir(new File(contentsOrig, "Resources/en.lproj"), + new File(resourcesFolder, "en.lproj")); + Base.copyFile(mode.getContentFile("application/sketch.icns"), + new File(resourcesFolder, "sketch.icns")); + + /* String stubName = "Contents/MacOS/JavaApplicationStub"; // need to set the stub to executable // will work on osx or *nix, but just dies on windows, oh well.. @@ -1189,13 +1220,11 @@ public class JavaBuild { String stubPath = stubFile.getAbsolutePath(); Runtime.getRuntime().exec(new String[] { "chmod", "+x", stubPath }); } - - // set the jar folder to a different location than windows/linux - jarFolder = new File(dotAppFolder, "Contents/Resources/Java"); + */ } - /// make the jar folder (windows and linux) + /// make the jar folder (all platforms) if (!jarFolder.exists()) jarFolder.mkdirs(); diff --git a/build/build.xml b/build/build.xml index 324fed312..f538c898e 100755 --- a/build/build.xml +++ b/build/build.xml @@ -542,11 +542,11 @@
  • va7#V7S081beNuZCtzB^M-SjD@aQwki*8qYS^;zc z-VB|QTu7z)9pYPa2vSx707h?PqxQmg#?oP#oa-4v%f4Us?LUagn`LzI zD&+FzUKv3vzlg0L=XwTl8n8&l=Cab&T!jNVvw)gIH!8BqrA5PpAdr(GWbLkb$|4t| z3t7a0J9=})=nZ6w&}qa{lj-OIwty7?wD@yVIHFwJq}x*4%I0txX|eRpW-xr2lQG<3 z=)z+>4S%fwF*!o_z-(m?Ao<3SPcW2;A;!`#bRn_LD$(_9t8EelwpZLY1-3F3j{ z&zjyHO1$;W8I*BFEp~2ZGGE0#0oPm&SaS#fZZ3-I*m@}Q&TySj4cn~ zomu;*D$9p%F_g%{Hu}B??!{z`nTT0gS&@;UL3#Q0*X5qu4`D{{4!Lysvh3f}jk^F^ z^eQm2d+yZ}^46&ynF5&^p`m34oR@@*qYFRM)FF2r=)exItjsjEVEL~H_XTo>9bNo6 z*6SiyM@(0qv%V@(B$hN|PHuV0$j`BQc?UM z50DCqFavyR%*$B;N>kuHpsCcOXwRna*EB;7D=Gv-K91Z6@ z4^#}tfRf?qIB*QTu2mfTna1i%4GMmV^vt5ymRphfx*A!%?IBd|ID_%lv$_Q9xHvvs zsxK-=_ii03Rskeh{~!(Q051xYtr`dj(AMGMjiETdtRSI0$~X@2HW%q0K;*#U+*5cc z$ifv3WCw8kcVKi%zWSYKq;FtC4t7+?pMU2~8Ny`_Z=Sd;_uai$`QLr)7*6w*$;Tgm zSoZG5oB^OuKmU?k7@U)xE#)#cjf+$;33%$tsO-djVdVeXtFKCZO@-7KPhu7rLvmc! z$vUg4y$%<3Ov!=HTJ#EVTo=QHn)W@|IcP?FT>iN_k3&6Rg3&(qj@C$N<*Kw}doLMB znG@TK`%Xiya(V5QS!_Zo*Q>*N(A$8w@|~B>u0!NGnL)?p%!NTa?&Kw(3;~qYqQdV0 z){V)epa4!fs60pv5LqGI^>;`Q)^ixT#cz`eqs4nyz!0kd0vs2`sxOUSMc)7v}ZyGgn4KX4Ey1M6h}ZO5djnK%64fJeoE?)>X$sE|Wl4f2gwF328K z6eoMp_3zq=qrnR@i&EH)4Mzi0xGA=yMwTl|8_ zJt`hWK7Z4Zc!Ak+F2 z>;M+7paO7{6hL%2Dvu_j_NGMo84`2SF!aXbL!NZDfTlVmfXqfdFGpM>lgVdcx8ArV z_zi&06xE^ot){lJf4i+HYV z7j6zJkyTwjMx3A$IQ#nZ&SU5pBF>CrsAunEQApt*UjZaqe^R(4%Vd`q%DDWK!9-F7 zhLN)Sh;!(G-LSH;<0HxO_5k=0BzhvlMBW46kvLr)oyF;n0`?@x`t;DznHV0GvwaxH2WkdAlu$)c#hyaG^0DfJ_Xi`9QRj_NenREm=TngZl zlgQ2z38v8K#}lF#V+c(j#bU&G0oS2N3}7PAIe@?!BSQpJeg+|5BwtfR-1Cv(MkafsRs6LSr29^6K9=%&;F@A5s#*c5kf~CLdRaq%(lydI#EUCj~ zp{sJJy;v?!F3G<3YFSxY#2JB7Iey}-b0C1v_T2MgcTv{+IZH@>XvM z9BDN0e0E8E*pnd7Del0NdJ_|H#4xVsU9f28p|R(9&;<>z^m6qK?x zykB_fRk`=BJ7lTvgw%H*m6}qtF4C+MzS$$kr01PCm1Mm?X%zrz8N)#=8yUjjnXY1p zLf6nvHft%%Eo7?b4q$X=ON&Iq-DCL3^zgtbk_147M~=w?A0@EGf%d@N$E3NsO#bMv zzl-w_XbF(0u4az$R!hX&Sd9;CagU$xQ&4+tsoeX4qw@OsLAmQ-r@VG<5NEqFd=O!|($B#V59ZXHT1fRygPBlXFo02f2yuY7Ilmm5PZeTVERRg2m?f|Ro^UeQ381%n1L$z$O+%$T z`NSjocmpQR6*h_qxTx?4_|7BkDTalSK0+xfe{%B310R%L9{)zh?H!oZTZOBZM&v+C zsq|j%!{Z#gakk)s3}KAUiX-w5D*}_Y^KRoPimFf+5UH}TJf}QBARh>W^fW!M06#EV zBI{S6MM7C1iNG{0s0lvCYVkZP*kgFkngzE&NZ&h8AcuTlHexv((mS(9H2VYs){%?D zwRFy!!h=qCqPKS%SHv&lUB|fcgbH3nLC(~5NOpQmIy*Y`eu%hS7C%mgHz>|vGB^?|j1dcr;>e0I6^kwF zmwJ z$kzN#Rsd@vdq>7@V5MvvFwRqu~c)B>?ob?q=7vZlmL3GOFT#K^pFpZ z_9Af?7SZlP&L$N8zx>wIxSq=#_%Z$knU?_a4>F#YN&VFy`Kga$M<3KID(PGXYx3De z>AQe#Je)5KxTB^*QqUVhPz`;&fHyAdzq;lP)#4$I$t^KY=* z6RQWfn8t0{bMA%ovXmkCBMX0IrzM4&508$uz@kcO%zQbLvnJ;z$3gk+}JE_I1YDcUJv*O##opMC9$iwyfqD)pUdx zS_QBMt&JTYNe(p*@V1nI8w!t+h)f4}x=+2-NX&~Yk}0X9ck)rUj%iNb&G^SidHAsh zWoT?lm)Yn%fN^0}S$`l>#^|JTq-PqqfinaMU3L~8r%W|dnGRACb4f2RG zFu>r~ht)fKLkvqT>g3#=ZbdT!I!i#CVq8c1#d^sYHhJGPD#P?k;jh@h@k9>C0vx%5 z0i!%b&l{2Y*a0SIEEGx2(P~73cg&h6fVwJl9dTd+;KBj_v2o`>d#%h)t>9Ik6`98U z{RSt}ShwxlzfXEjzKu5|?}anZ^I18J$0|eqPatbxbo{wh8|#DlWCb7_s{m3wBwr6+ zPh@%I7-d2{AjMiPLlpihf#>B7DSXoWN#etf9eE51x9C#m)k}}weMtW78&AtfU%%N^ z;mMrA=}Htugo62#lZWrzD^q2yU|%e?cqecU*K9A3UY7H?Lm;|C&(g;XlZGYseubp)zpO-eupp&K>8=tDrWEbl-hy)ds7O3z&|iL{xMcI zqCzw$eGIRFWdjv}^`vksvB9CAPEH>#$IswLVkH6+u?MdNZ)K6dC(NU9NMiZ|m}!FyX5C5=JdTqi zMi>DVFF+3EaUOXbIO5>d{RdlQuzyK`L#0m3l>#qRFJC*=}XMwSx(2T4Yo)IRVx#))z(igjv}!U$hk1mn`k z1t!ZU@TR`8MwW1a2J`CIfB2eAU9~6T6gNP0d}8sz{q|;a(7ksa!i6E-$Zthbhu4DG ztC*Xc#}!|8Tdrjlaiob~kh_$3fN1l%f#BDnS`;HvVDUy6yx9rvbT~LZC?7`UrHI9G zd_ra+b_Q1SIGlD zF06je!@5yJ6qvNPFh&WD)~W_IdjK4%U{8V^T=n3`;`wq*Cr@kn&>kd*BB;E`Fg^c*QwE79ail8TtjRLl?z$ZQ2SOwt2?G4};rVQYr z6I}C(qj&d)giPd-=H^*IJ!Y27R=M;Pe1wO=3ti|Fu zE(sw6u)%M{G1^BSd{CBo)fHT)E?q?7H_Gic^E|8<0TX%RzQb|}7kIpLzDK)tJj^k9 z`Kt8t(oCyN`bKsSS061r=^Pepb#n;NozXE;JpcwqBFC(r2GCRo2agJXVQ-NWU@iPg zLI>h-+--5aU)B(YN%=Tt3H*dLWTPxt5#-@G|3hq`fx!8qE-{N`lHg@xjKBa{aqyD> z8{hEY>&%qAb9G84dQahj)izneu1+Up3%dR+{8hN!N0p5SWoaPxHv#chZ-`;vsAb(1 zfKH?$;_`eibQbKKdvF}ZMg9Ov|bVDT-55zR~H zT1*eH?g?zmLzyL<3_$=4jKq&wE%$ZtA+8b!99Rx~SupT0It_cm`31$_B6(7SXz-K` zemFy~W;%L9fJtf#cg{|CaK$Fj@$v|Pi{%q{vhJxsxTU~J!Elisl||uu35~f4+@0DX zXU4Fb6nSD{ei3g*)W`_-lu)f;h_e`58cgu_R&P+ct@>Ga1)!mXOf3BEXfX%kgIX(J zA)x_JbxHwRPbPv?hSD{@^dKMBV3wR@SN?v4}VZD^bO18r3;pxn!~d?%WIGi z>0W~||KksSPLDJl7{Xak0k|w{~KKkKxI)oX?AR2dtCveq0AP$Tq zidh{mLQ@?QKyUR1&mr_yqcn_%lrDLE@{asmg*;sp?y=otC23HdFZRWv|5I z@!(|~{D~>g%Nt_OTW#4u1rTL17XDTYZ+JRx*z9Jpa@qt^8v>LXrUX!}Yh+$BNsy!f zjQ^TDU6eT@rzcQ=%fKJFeV@$DFX&ZE#9VNmg}mtCGM!-~pMUZpna6(be(d(rn1TBg zj(?uKG-f#j{=yj86kh?1E*E9aKj#l^&|AI1AzIzQomk#6 zQ5Iq{lEj6_3lZ?QMwi-(>R^s8K=*#Cfe!qD=x`{UGkfF!5Ez{^k6?Ko^iy$C5S1W+ z2S)EHVNULqCA<>7N5%#(co#{5bz>O01qi_WYM(_SF=Be^?&U6lCzgz zk}|yV)P&yh=mfg{M1bd%C(E()Eu=P90mLFACnG$;ie5ks!W5l8N(rEXlF8v>!Q$tU z5s(K2D1dpRHz-Yn62hH-)F}&&<~H+1Vh_?nTArxU^+j zMki;b_v}e&-nm1jrzaqVp`jN!R9M*!?9q?7Z>?!#6#ycj1_hpt9b?W#>oR7;D%k)6 zs#hPV!}S#Sl)$<|6LX3uL4-nh+|7_#Sm0cT$yh#c=~`{SV_TW!!%=WGh6AgZ58%pYVwwXGOB}?T ziG)0WEs)05(>Zzzwq-Qp>(D*k+Ws-niF~+& z@LIr!uz)3tqZVkwh~`wR&^w^ho!_u~Bf?QyCi~i|G0A6|5uPiX#JJxm!<-j=+=^=b z6@Z4=gqp2UqX+7J)0S9nCE@7U_W~ii}+xE3$pboMi%;% zji3^Qjh7oB8f0>INhWbwWql3$0UBZa2|w!>6D|A{9O9uUdK8*NH_OuT^@xOrc+PC` zJsxDm8vQ(O`!N_S_U6xcs=`?Lt$AD9lo()z@N=L0l>EULep9Zz@m=|gKm1qn)W<(; z($^-JOADu~$LfY3mxfN7wDe|KbNDueV~Oc_KsQGEM5RQL?yWGy{88lS2lw&S;%e?a ztyS3lIVSGq3@!XP7__P_zwsd=+B_3009GOi&1pS*(LzGiyYSLj%4>k1+ z2Ae;(BEU?f%^;kpYbwKFGnb=MCzAsV4|`HD0y#|M9Q_h*s2z-#e?0Jk+wgL8uY%YY z;8#|HA_>&>bo|+RQ>_Lo1kM+}KSS~P0up_*M>24B;5^PUMl1(wa2SD}{B+ihVj5p6;Hq!0DC%Rs15jyOw8-+InB8KI#Q0%5Hn!ri^F619tlt- z3vm@-<$>o8*9vDaS=jOC+yLZNe~PPk5kK6@F5Ru1;lP8rxYTi5-JBR;&)~oR^s*Km97sF3B*AW-wsfxwV|C3eUr-O!zIePq{TW)Z+U0V$7WtOI>vZE{iFX+L~%< z#_Li1YB8Ly#%aPV3VIeBZWge|WC|H~8gEG8^2I9lW5&KnY9T6msw0B}at zoh4#pAOYMNRgYN$B5ZNSu0FiEA=8UldE%jaaY@7R$bH*%(_-M~KKB%c2~WwN{ngjy zfBU^Z#AB=M5jf@2k9m#-7P?DU=$gMwc60>L9ZhItC6L#a2Q=3*M$|>+FG~tTv<{Czg;i2ei4*57|;v{Nh zg2;?CPPgc$PPa9?%H$j@K4^-HgPfr_mXGqnII65%_8;CS_ug?p{?oUg1_f!i)w>k~ ztOQOx{WtPEzxf;bB5o|-u(j6YV-dk0%@mXqx0;@`S#y}yilvzO!72dGM+_h+oLOA| zHML;+zzt~VyBf-MRjj1ERuPv_NW1X1V|QaI8qH!UUmTIPnqoW`my@x9OVWi$J-+w! z^K$CUIeGQX<8lG_L>42j)}oNr<1UF76neb$i-%%Mv11i};YOK}(Q%pL{tO#d&NJv- zgW3c6)?wUO1z;o7?PxU7ZX??zgvL7)1r-6hEoDfQGL*g18BC3$3T)L0LPd(meZn|i zkX(%pFM=DBCOdsJk>H$dganLD6u5|iu0sJIF?jd`l^Hh#{mSP*gKiBwaF837*EE(1 zx7E8J1ONCR{pWJ>*>A{GpLkr;I^Ly+d|}t!C7HGzE>jc^gXW*m+0lovf@Zd~t5Q>m z3*_g9rKTE%wl*X4)jn z1gWg5mLi-bs0J>YDp|nub1dxRQ!~PwewP;JaiPqdeoOXg`hsF@(1A_zhSfA@|7?Tm z%9bf~`K*?JKu>r$Zgk2-PGc3j23fs1B}SnM;8MZqj^G@Cn0^uIQjSpG8w;mDV zq!v(i?rf5Fyuw>vZYC^8$0y{iGnWj(_U|nd1DqrH^Z(~}CnpZ)m(#PaV;Oifk|Wj93OQiPh)T%8oT$8 z?xBi!8&Zt-A%Agwz09weTI}q_%kl^R-_S z&W=VY!^917im-%p1v>$Uu3V9^Ic6r{5N%uCvN6Ekz~6r9kK}*&r@sanZE0tk>G9O$01{ui8$+2k?%+9BAu>$)p|RqpVy1&mu8F_8(ySaP5BT&?)=1Je_j6ffBh%&&F?;g zO5q$?ZL3=#27d0RKP}IH>q}TAs58=N*WC)nw6t|YBr1Vxt7}yPMObGq1{<#MSJu>F zvQDI-sY#ih!x{OVjUSota|hRds%#Y44)w>EY~iW=J0Ry{EQ zA@DpGZ6PUS4Xui-5I_?S3`A{tMi$FaJ1^rsKJ1QSLe&;6%FtwR2naki#LCR@At=r; zU~U}Y9KqtIoILix2bG&Sr_a%$fjw&B>bU*0sWI^O$eCiVvlE9@jxefxAu^b z0x3&DwWec1szMH#c}!-nuKZwX_`>6ba2$NyJpjh!7$!8hmOqb~&x-0Y$%RiIX(@04 zQH%2<(t|=10coEH#@xc34heXuB3}V1)e8ee4__Z>%wS!WBNe2Xbhb3g zSbvWU@hGELz~{U`9xn%QItW6fz#OlVfRF#DUwBRNc?{ObnUiNw_`mV*|8MW}W*gqd z`TI#e44I1JE(FrVXw;4Z(MH??4ZyGr+iYjqC~h;qU&h^7&u>rx4PX zeAg48*i1?bHf7%d=$Nl!y#P3KGY$)XcV`1wnS8zzCx0fVCS-JW1>YEE^%rG-3(7?i z2DD+}&u5>2tSw6dc~h+$r~t6m+14tf!^371CO6GcZl^c_lcs{g5_b;ptqvV5^G0WII=D%Yu{nCp?&$n|oMRy$19)JJ(*`yKqQ0(H?!5ho?B3ZW$Dkj( z{V3u@RRX-wgNdp84ncCUe_S_^ z?ccXc>57+!WXJCPx~#YN*u%09y#MZdmK%A?(E!@4T~%AduvM{J>~a_A1# zmMq}$17r8UQR(s^W3Ys@1V&myE7QfK6`=T^guMYD&sTH3wFomX(>nA3fXWjaLop6p zEJ>Nn&(2959$+ZJcFkq%#3JGxWcBFY6hV9|uVFA!s2?7eY%D&sxa0;N{wkTWu{4I+ z7X7Zn4@IFsR0Z&D_(InS&VxMvvOG<)|L|4*Dmg2I58>RzQ%^o|%Tx$I_tT$&tgpxy z|HIdeocwh`PU;cH+9t$F2J7|RolVj+z||`RA4hMm_7C8U%Mu;|ZIHV9Ci(Cq4@l43 z&q?dS`_|@n3%Ra)6~M@hollx^O!m;i&kPfOK5)dbpSn9Mi%t0F2n-+2N$8RzNmX$! z0LyaZ#T`XZ^;M|1oSznlT5ChK%wu_yg`eo$+FMn$B%=^?UMph)-A5zL;RjHph(|>n zqbaU}9Do)ogF{w^p8@HzloDGUYMZW-vLrlk&eWrT#F13=9)M<147{b&CI!yogqQrv@^Yx}}){d4qE4p~oa7^qPtbq_Gk$zRTn z6`|GZ>S(a1UaHv;mM^E=Oh zfHfUcDK-PRp$cFWhY-qm_&A)4xmoBB|IgpHt`OSI1yFQ`A=DKsJxrV%XCBun za-6%r+>ePrpjP1sFZTjG{mipC=Yk`;m=xpaa=7=5oIQO`?z;1^9?P`?+|t^HDu5Pr zbu>RANE2vM%|lv@JbYGD9Y4`u7=GfpF9G)q$jROFu!2t@OX4Lhs_o_slKyf|FR6&+}t9b<|@NG?90+pTP};!<9OrG7I^yY zmE&o3Z}o-*rYrDpCyH0JI~oHt)_k~ig%)GrIc<)Cyj{V!9Ibei%Nnf&p)GWzIpG!x zN2gG+;9RrtaE5$Z{`qhHj<84YZVU}r0qoYxMIdb03t(7Wn4InbQ9yYCPjgFyTpfrG z>aaIZnOl*E?!dkkL;@$QC+zAAp8;#FFP6b~UX;3qX1JzAlJ_t2=iM}Ir~+Ud)noaO znWe9POj>Y9xGDH92td$W=kx%s5zNrj&1fFi0~|heQvglN%Sr%Ue(dP0(cXY#fW)Z4 zKmlX@8jKYdu*ruBgjE@(k30&k^xx4_cUbTbEjB-es1p+~#5MS&F*vY$UKZxMNDj`j zNi^j{oXu8NCTdn3YqTCY8+9me^#%ja`?dHE?$Di`dP@Edon4T7an0A0|KK0WfA_z9 z!CYbyL)u!)?_fT_D;Ff{E@=ydp}aIBrpL=GwxaYaLf^j>hkP#fUXc@L&SO(tG$VcL z)G5i8RZ9)_1ZZ?^;9?Fh<4rbfpaNhP#!?7oKXXKY3H`Kd~PTfVY3BE>~0yQ>h zC62cQK{YVf&Gu*sJ~&E^Hwkcv2M8RS@tdDtlG(W>jLCRw3a%^HbNuwjc~7&qsGr7$ z&;V|_^~8Y_Q(C+1v;?iH5)j9J91c-F!;1GSp ztVakEUqclrK%OdK!3o1pq9Wj?otve&H24@+D!kGL#M_L)%V-Q0ywi@E0dY2jt>VFA z9xmR%Jka+%Z|O$wD%6V7xMra+|HY-ynkt~YdWS8+z@O76@c+4 zhw*gJAa)utLqYjNfj(o|08rD<8x%kKF>u$yTXv4f>K5B&Ug#aze9?sTVG?l;f&r+* ziL5DXOW+2jLVnUWs#t+HAVP!B0@Y6oR(A^zae+fLzcQ!)%x!Wy^~HU>0roj9eHz}LV1y~6mL?D9YA$w4xOAmLDel^118RAL$I8f~nr zmVx0(9fFdQiWPbV?z=-rQ`PQ{W}W#rHuHNH7ku=ec|$U|;3L{#8)DpA=Ji(qj3{K} zk%>9!ZqkGNvcicsjX_2%-3?AuDhP1OAh=dn%Y-@`c*Fqs&e7?XMMpJ~06l;i)WVDK z>_}&ot^`cElZjpk$BhLP+cz8^FHV}DfxpVf<&FSX`4G#VW^@?%X$(?# z%D`@*>Z>+#WUKa*0zTsxzbT=OheE8== z8qr%sb#UfT_Y|9FNR9i=V{bSy3^%A!Sa7A_W-S-~{6F}N4FCiw&&yUIiHV3U;;1%793tCs$Eg$1bo`D;O|F9dV zZUD75gJyUb95vIZ%2W@=NPaN!iwx@YBk`l*3PR#?e*nreCTW21-(r>EX3Pn2hak5y zNB#X2VK9SSg~MXJc$1UPX=-KOoK@Y`)h1)(+^il2oFt2w9~d4U!UH+B2f>T|H>?VH zzF|JsCfJ~K6wGXkG^{ZuZ$yzqq4MQQ9Sok${T3ClIFf<;!eImLNxcDuA1y!b?Vzx% z0Pft|BCnktbnla-^C47OM0_k_9A9O!Af%-!!X`W(-|-=?GW9Oj4!Gmva6JkE+p16u za5%t;LA~O-5Yi^WpZerSEGMQH5}Re0$pgI#XZx!&bJ$5*xa&{iTycdQK6;xRKXZ{* zLvKv_yTWcNcvi2BV<=#I$btK4;O|RfZ?|Me0T2toG2py9m%G9ix{y(yBCvKMF0W+su zg<|XrxGwzi_?+38HpgK?J}<>A05)9KbTlZN@VkKufWA>E)^H2BShG_1=Bo^00WbiM zYe_%`T3={P0Bt~$zu*iv6c51D#_{``OQmOgMGiEfHU*;v?6bT)f*Vw0ywt`J9tlW0nBjz||LJ?3|P+pOlm%saOwtOh? z)F+;Z$y$W%y0yH_6P3Z#>?-cPDIBn!tqs!E*)HcVUDe&?o{`HM7BG$-v+cEIGKb*= zmlQL&OW;;j8>;|p!Mi*fU1L1I$d}4eGP{C8xQPM-Nh|PlkMMV(#a~!7cMdErFXULWgfVD*JZtG`O)}mp3dB4aWTRq?F@% zFb)Guo{13{OM)x~V@pBnuK>c#j##QJkH$6i*cj*veOOSV5ISN&)QBHnXb5mBhX)pN zGRmWVa9_rZ>Y0IA-SQh1cZ*NW@t_`4>PQ5O;~X8F_JGFnQ4R12%bA=`GMLrsVAOw9 zRZ2-n26dysUk6L}0=80pj2C&}X4{c5bILDOq##^X*l^a-+#n0s`O5U?OHx!Or=&}| zghs2SrA6k8`3hEY=$cNG4-JIKcia@n`YV8-Sd`=KGrn_n-?0OT4;;wRt+-Ae3LSpV z3K$EIx;b3x76!K(hXUx1<|?^>zJDx|71i;e9;yHy7(IXb!?jW2J9f$C%YADE2l-n!zTqJm9Q}Rf<+o*K zHn>&VQ^q5QwjuN?mhrGBrWS5lwK36bf#GE!RP%VT)RmByN?$@O2zFb@3_wXdzIU@^ zEa=>GH;u0oxA|Nd#lT$>W^b>85&~eslfqED-_~ebnA(=k(V>lY(E8(;{BxJ z89LbTW+K7G(?+5s!E!CqFMjzeYdPPL+YZd+PfbqXVc1>L+tXusQ8tDtMaG62ta!~# z%R>)8Du?!U8~khhlFc0E{>%~cYaqXi&IQgZt|bv;2{ZI~^k7-v{l%-lSRSn{XJJXB zv%rL#7DS8Al^0H`vghB5#}${cj;e((#x7t$qqllP2=w%!t6>*HVD?sTi1RT-!EZ_q z30!|9jmaQ~QMKLxCwW|h?uXbHuvKbDN1Jr*+$GC)=07j5F??3ux|%BKY_6B?J$nGm z$&0U_&`oK1vIR7B%kT7WFaq*C*c!mbdH_*rk--7;{1MOQ@2JDgD5g_jrDSa23tMJ| zm=-uJ{PkFh;qIwY;BuSq62@7>c*Vz*%oIN4sd6|SRx0aP`ox{Xh3<_sdyC|x~PR&U@qr$xGVEMX>xD-E#TmWqNtm&BV)dnFOs{pi+K_KXim=!z>!kTV)YE_!+ z%uPYAATm%j3Vl3@NlXD1MI6oA~-PzJ4ojZ3* zb7Q?UHa4j^+CxnhEFMW4D_p4zw;Xt#GUBRk+`>~^T_GPhdH^@{u%_f=oAE!Do^cXX z9HumyaB&ybB;HJ~#RHxh6n<_hGG$$fNN7KU@A#MkPrn>DXQFO_3c?Tl4lvdIdVYdT zu_n0{VNIM{(lHUh(7Mqukv62i&hY*a_xo>^+NCE06Wl3t5Y~$FGHJ!^|BBv&iHBq{ zSvWR{xv34PsIRaAqML}ifeHXI;|nq*gtZpWNS!=!M(<0J)T;E;23)` zPWSBIwNnPK_M_*(GuXJoUzbV}_?FM6cIyLawv8?Z5~Ve?GD+5}NEgzsmo61AqXjP2 zX%m3$XxSr`A~eFiXwUOEwsy$=J-g-ao_Ps30!7Q;5xq0T`Q*<7IJ{d&-#`Umgm!KG zp8}CFUPxo&2<$Re_c}C(y}s4D6V4cZzmDL zLhrc+JjldZ)$AyCj$sZChd#g;VJL$@yG zd}wuRh5;owuDh11#IC;?TsglqIfO?((3WFA{~Pa|UyCHqjXi)BlrR>uTeUZ^{t7_L z9e!A-wUCRHR5f67q(RS7uL4$8mNBn)IozN!Xt7Kt62c@~ITX^eH74A_V z7@yTjU~Va>@3g`IBMcEnhs`}|-FSA|RU~$P#nmZ5yjIRj73vlNGPAx{6hEZBL32T`HzNNH%CIJRBA12MYl#@*uIWd*BfHw=Wu>wcTX9!bR-|uWSUOPP zyRb8FDO)5?{E#H-rULcY-PyqzF z0~Nv4%z{3W!0y_s&pwNZKs=e8Ex~I&W+k8k=c`wj%^7OfBRF#8keoh!=H0013Ix9p z*p}iT$Z<^T9tW;ryTOvP2Im`c3dJfIR_jBEy8%y0#sXi4f?tXjpBr#iQTTDrTlS++ z4UCSVgdo-f>jkIet>l?T=4Q>GR2~%WKLrGBPxn7Xs}3-B#~P4BS8| z4&-I`n2Onf4FC-#rQ8FOl@j|LRu03wJ=p8P;a)$7i5-pTV$aD{bm_5iT;^x7r55+_ zmsM2gK^xk2BN+JdX|8!(ugz}}FFtRD8XBL(u%i;9XJs1OjvE{5{V&wl!2dVA1ce)VsIU4++`uB?>p|E)P0xb6xdDzlO4!liyW zuy-f!Q^U=@$OMx^!_wK=B$>)O8R@@*YrNPSFzR+x5+_fb)J)@G+xoj017TedC235c zB6Qi=@)cp@7Rm{ZwPrBKv#Jkf6ycH!PJXp_c1wA27I#FNOrFC*E?%+4?*7FK7jf;D z*>LmL+b49j2#Y{)<0YITQz&@oO2+&|ErNX^QNBqyZkjcRarx;pXK}i3mwfu856e3j zE=x5kgi*BEFT8$S7G@^!;`EZdiOS%<`|m@~1;f{_R{8!bC*+9_KO*1#-qY)rrGJvU zWHD?;6ip!foIt--)VeDGBQS#DGfNIH^HfNE`wlo|aQ9geHcVu7mh;ku9>M&eD(16; zhxW@!^bl?}#hF{bx1o@5VL?$GMnE305cMqt4`dFEPC#zUX6?-V@q7W7y**CgW-yN< zrB&$FmCD@IIHq{8mjmv5+Ul`=zDQ;kiC=^VF&6Na-Y6byS&bc*nZl(Te6*E2J>8Pt z5>Mf293}=9U7>V0iCV07%G4WiUZA zEAwMG6=5j7W$Vvg^%ROJ8#CUh?u41}=-_aH1uBy(iPUSH)Hl<~YTOb|t)8{V!Xq2~W z+ys05k$7_`Gia&#m1B%ug>JjPv4H&I7CnpZepxvlzsO2?k?Dq?INKw&*x+^U z%8>L7*ekSFm*ncz0V!U<>$!{OcAQ1D>bwSHg4FW3g8py#-F)xNq+ka z|CdJo_{^ew^*b-h1uPA|b@B}69+q`!^3Z`@a{J+ZGLGR2hdnPJKQCiL{c`!@Y5C-b z9*`%WctrTH$Xcordt@+pVh2kVF4VeZ)D4T$*VnIs+0_<*E1keSdv?hwY_Ql?w?+(b zd8?%v>4ZX`!L80UwbinU0?cn^c2ZX7XJi>iyeFpSa5+ny(N?48JqRpYdiMq3n6Yr-CoOOB-3s;V|MM5*#aCXJEP6dJpX`x| ziD^s*Vu%AZg^BEEUw%`*|H7-%gzLa5;l4fHxZ-ONUH=g|*)t%$c%^o{zXvWNpZeH` zAZp>F#9kH^I!$;Z0PAJ>og)VIT~URlUZ*(R3Y=Y-k`r%4V|<>M+IL{Loa?!?PA)ea zZLLgqEm_{Bl)9E!1>KFjO}Kl3S6@#om&$5sjm+YJOUbHPrY%Ngz^}BX0sA}3^^8X` zcE082Czb2i6eQJDP=xSTw72IKG&dHwVy znZ!=ODI7^pDn9Z__4RK*gZV7XZ=nb9$b;kVBW5qa=v+>EPP{5Z7mv#mA9=K3 zAs&SvW#}byB9W@T=7x)%VYCUqHzY}0YZIPGn#EeJ$w(YIQhn;jJ|gYyZN{?Izw60o zTP?#a%)h*{QtCT);T5MUS;|yM5ytz=lY{zLMKNahn{lJ_>O3xA#h1m*_Y^KZAdE&8$G0%a^K6A@b(b%C9%@3ZJ#^zQjM(-+3&CX0> zm|TyQ09-O^pR`ZIyVa(S>@?E0-U9?stIo zhl~`SeEnoMjM>uGfsI+%z=GFod1-TYWljrz$e4FIqWr5Wu|eb63_fbR%5}f%QftN0 zwPT_Z71q832W1w^W%nFAdR-D+i|F;Yqu#2)rCe*tEpiro)=Qh(B!kNIw#>M^h>b;Qt4njmbuxMRGKODxkFc@~Lo4vY5bNDm*WCkXYOIwH zedGx_i^9*iesJ@>{~$(H|+bcK!&0S_rWaJRrReV=-s&p?I%C1vb?* z;*pE$7B0;qO^V87bzxc-1~1C;M0}>26H(O_oVQ1%jZbfOzjpZ~+cnf$VZ1i;_Kpte z+H+7}=jHI?o;$Z@{QvX|FRu{>>%^d>i0q!H`~5%ulH7OqopS89!%|a+6R|*VZmO4~ zyXxfd&iZ`*=-J$T&k?D`!5|JJZiT{6A+M_f;D(8Z9(hbRN-*T;2RfMcJ?vERfR?uEgF6{UH-Krj!$p#mfq_67R;1q(Y4OX(Vb1$WVYJ~w#mOw z`>V!WK&?(OX+1Z7ge&u*bH~%jyvVyM?WmPaIS&sXm@zykjVM-J=iN# zEfwhDl;I9N_PAWHO9|ekpA8QIxE8vMb>3C<6W{p$w=fZeI747KA2cy|NvfN7$cfYE zw;(v{NSTJNFgb=duy~mf3mwdnr5B#2kA?)#r@fI%_+v8b0GoD=TY$b z-+$`f>aM%??Upp7t!C6!x9Xfzb?ert_0&0&u+*Hx^s^cwxU;;AkK?NVMi?KC=<KBXJGh+r<7PNl^8Jw74!2JpjGSGIFPlDXRxtbvv34V$-!#60Bx15my( zH8DmzUVFJc!aQT2a#AqDN4%Y zJBE7?IXX2sO$RRDC%zFY&S`>7MN9o04NU6mWe<5R7D(AM09N6B$L+V#p{E`o*gh1F zw^FXZb{DmFbkR#kUd4;bab~fKeG%z8wqK_Pe-X=uta1=(&48J6xHJ=KXci2_C14ec zGbtX^i)yLtR`m&Jy@+}%39;8#J&(O^`-y*2)-?s#pHQx8KvTw`+X16sqlJOL#jIT#CxL~ypu zYl3C(N`LgF@QN9X-ds|?KFh8SbNC!~oK;KeHKBl*rSayT*|Eqk3$lbmyc3|gvKoa% zD%0l~OAU@5*Kh2Cbex|~9(jr4y7G_Cw$?>E|F^FHWhZ6xy=|i0Uh~UeyH6y)jLpFV zS6xZhTz!CEd-dgX^EFq{`UXFwDT88$mcWr>E`W=XnXhb#e18H_`YcpAADT z_{1DFt&396P@D!6dD?;79mA6;nw;c2)62)%?bupMZ)phJXe^Nyw2Ki@8;MXFx9oTZ zFb(4sd<9!=(%etS*+vyRhaykmLQVu7Kn<36S;)Kd?7<0E(DC#mOJM|NG2~e5dZA~Z zEkF03JxS}J6M#33Gh^Du@n8JO$Bjq}^wbTZwL?cw=+tCo=)PK9j`H}4x&5f_tKa^S zczoYow+WpG9k3~Ip}U)|*$<^Ty?s=VqrxHRL72fEil$hYrXfS)?u_)^Varb~tFz~# zoO$_KN+sqf))GQP!7VUE?(b@$5QIohoIYQE36>ki5)%im!!_J6#AU&{VBTb*Hldt} zHbZ(X>$I*lwW}(uzr)bV1A%uzqpXHe$kja%!u@`>$Jf%-h#84?$9{S`NoUSz?S{4I zY=y#@cfaFKcS04We)~H=w8xa+l|fQ5-iVre2{f z+jm}!vaaP}Qv*{tca9Wi?~v!uk-s)9cJ~>4*VfIDdDj?BSi&(ez9cyX4LMCsd>0jioqN@IrldmxN6QP?l?Lp4|i0!V-M@&8sy7M^hK zxleWgvJ&JlFP{}Mg{VS6Nwf*tfZh9(Cj{WHz3C?C6=ikWWD_vsK-x1=n9*F zSgSRnLrjbeQFSOv87zZB;7Wh67T=>*?8oGAzV3ro;w)d-f=lAMbv=}n@;!`#b&bAHRi|Ja}vrNUO0AMq^*u0o3HKi;^jfR z5OPT3oqzm?h$$=B2+{cT3?%-7)ZLFGKs1JZySLHN4KdQ(j-`brZp1eSSWa(hy}$me zE)*+I;@y9%odJ9qx%)3a68qfP<+Dqc#_7K^(sv(xir#kXHDJyxqyal{&G;Oh8Ol%t zL^v8)E&w*MNAX#zlX0OqG>9cwdQ8)Wm_|Y5Y%GX7_NkP1a*zQmyQbE4G&S0fdTyj? zTv3i;ppHZK!>g0DOTuSnlGM{ZN-w$))=R8j~|kW5opr& z^Iig`uKpmDiG-tKl%JkvWuH079i%b4$WyGbk-}K(1~L8r_=ny@H(qy@k>mnB@#f#R zEz^H@hSjq60^_xiKKkwh|3&vd@gi-;@gUdM)@DtLGYVBf8#gu4y6wAYHiAwQE`h9* z;I?X5Bo5ZF#!X0jiWKY*K+6)#bVPBRQ#!ul&2xiTy>@$1#+ULvcK}SNrZIwD|8b~u z^3nLj1UCLK&FmYbr(Qgcsfo5XP%6VElU~WU^^D^gaNgD7hZvvi1XN`rHp~V@%Tf@z17MfW;&>4{0>ZH-CDl2|cjcK@Z4~MD;i9%4JKb4q98c5q_>fqlG-KKtjYP5jhbCa$y4w!5+kg3)PdO8xXUboH z`Je46i0MC)!Bj(PiQj0Lk!o$aR1_1ev~VcdPMhMKPc zMw=Y&_p@W20Mcb3QCNj3Ip6!Qt_fkSK85MJ)-gyJv+u_=K7>uIEOz&Kb4u6m$tBaT6~C`mAj8f$x07Om4xRjibLLE4f_ZbQvW(1Ng;4hz{M<0Ed-f;UJ=zx5f#*fo+C?uW5hRH1U*;JR-bqh>E z0#rISVa9G6$HDB%C{AI2K_I&RC<+g{Hg?c7)|$yg98-}z9X@`_74_03mQxiTOUVso znK>btg>_*smTbJ?R>Pvgb2H?}pAUBe_(;wV=9O+1SA)}WtSK>FXO-Bo7$4ioRHM&~ z5Jq|p?jp=!CmMUuK%3Qc3qq$r$e*W9Y<$Jg0pu}qjE{~&)OQ>mzzo*JA$st>Z$K)} zU89aM$MT+xqrZF!-FN+#61Kejyh6|F>-6vc^k;O~-1G+e%>zEVA>w1jw*1cQ~H@Phv_Lgr<~TyZ6%3GXslU#7jxOR6|+ZMzZj4o`*5kQApge z<{xapfg!7*-V0)#$O@ZrVZFhD+j;6A#B?*6NYG@a3N|3LDW_T{-na|nDr^>)ig9=#NDC>DcG8 zt3DpfbFMuJNXg8MRMR-J%RrXqz8^j)682sF8anaHVd^>aD&2a+H3Ew@5-q0lyabSi z;1Au1GssvVL%tvv&Zebzgc$^s!I>xeUUWOelRNsm!2Z`Y&)Rq^YB2&=LRp5AMe-%SXTQ&bLzE zxs%j??p3<;&9@Q@O8w-a$3-s5Mc8NaJOhw*6oy{o>UCtiMogiI{_l5xOkF$n((cQy!tL4%0{hk*u7(UjPHdWb zB<)nMLZ`4H#M)X<_dw8OwYUZP&`YDbik%;K0^&v?W&}JdsD?ZN8};z>`90pb z7WV^u{u(emvXQ{@Iefo1Qw3Ux3t3vuNSoTS!5S6^_2^3<}*w9U*Be>_jABeb)OEtHT0I(zm`(?HrqDwNy@^xvN`}(JJlFv*(5e9QC*NRU%29|QM$M_VD1F4 zi;sPQ1dfVQng0=cp}0L~L_0!NkAG&EWK$O}}KH8K~y28zt! z!~OgqcKTT=&yS;B7SQ3{d$#$acI zlfMPqtV82s?M|IP3EuzXZ}egiHa`wBzKDCsL0o`Qmu zLeCSD4&;hvO^ib|dlZ_4|MJWKLSOjICn*B?iQoO;-SiLt{H=0wwT1QE0dTPfG1c1` zTTj7!3cLT>4y7&Cwa6t`13s+jh3PLy1y(^@FiQbfVJ26PJsozenybE^FM4H#-ax)l z$U;DTnP(ynRaR(pe!#$zAhh^wrem+XA})h9LZ1JvZ+g8@;kDSudQO$9G5?25>wboo z%miO_+U)C8%zh!kJ{QBqw_tzO2&NC zt_JtWp(qqnd!G-NbHLPmL1zX6J3Dr4qY>N}Xo6A-7Wzr^6=1aMNNt_4l3RtDf~Mcm zC&W^t`1bqu?x)?j%<_p3ypvcPE=#OkYIpZXKB;K>aVU+d7)A1~^c_$fqebT-dk`n6 zQt3{3?(q{44gUP!YIhs{=5wEGqaa`a0L06gk3_1X_;}P-ju~)^^{6haAB;p{giD^0?<()m>L!%Q@;)suL zj^bE;aYtfA|*;=lzla(I`aQ zz>jPrGD-R(p`16XwC6w`g*@%@b4@HD42(@u=ej2P{NMdEeetuO5b;y6(3PIe&=b!d zEWmjQcG20ujJFpB&I=><^^B1rA+R;)N z)%>}YBs)ws&M^HKbj-w5XbzW3H^Z0z+&iSnTKvVAzKVUE8v2Vr{22Yizup5Sr2FaF zr?fi-UZ`S`=grk36Ccb+Pi3IT40n##TzNGhuWy!zwFYfh13bfd&qqJy!u*l}b)T7? zon(6Hi%1D89z6U=Vje&*0?5hkerjrr(La9UUi#DD`Ayg-_z)Dq@Fu-C=XnOe8$y8~ z3yrf%Cr#kPTNbMuikC`txH_HE4Q{UP+L-^_%MHJxc3(41$%(+A%5Hrm$JNr$l~9_{wmyWh~U& zV3!24@vzBF8DAYWZrDzv1Lp;C)|yktCn#&KWDW3bzAr$Fukkvs8=9Gc^k??uCzie& z89mLy{DPc04?98*Fb>gn6fQ-a=MI2P4h_Q|0Gn{i@|D1)=J+FDRA>IO&~qPaz|FWc zg@d?En-~$g??YgGmZ7NSOE+uIu?BdP@2|i7RZREGIbt?{1CW=@ZuUjaHtC}ehPyuYcbtW6bHQ5+Vj*bZJI%z1)6uTx+xUt$D@9Hz-mp;;St0@y_@uT`} zWU?CPMh_74*~-kCbFYChjQVUOBLbUuypc7IqtjSp z0~Bqp&LsdFBYEb9gY@@b`Byq(XFx{qf>(x+a5{JMqsr(qEPe5*B#!-evoOB^cgHDG za)5J)F5)enkmn8{i>rnqoNp&!;BoahZb@+bLG_?`cKg9nfUVtTas4(@Hw%ldm;vBi zHVfmOtHJT~{>KkIN>4oV3+U$iIW*dK(#~DGsAK&)I&$JP>d|XOnrlmPmCoIA-EWFE zbOO);KY>GMPW`nY&Th{QXL_;pvHCXmSm} zv{Sw40H(ndk+An0TJ!s)7Z>|UOzXR$gye~5o~J{Q)z>cRXcbfqgCR#woTCP46WX$E z3+>ynnZ{u+pl@(gE2Q9sav1{flKJJU>U}~v%r8-mz9eLfE$gY=*C~tm!UKEm05Z@A zx3b(KeksfX{IIz<8cz$$t*m7?lUW==Al^Y|clo~EIEK{JdtHHWJ#6tUlw&4mcL+Dk zCMV-y^yAPx)F*sv9qNzt==yGsml&-z{06p~R6VwDX;$u)s;@wG_I);?; z<7mmV()UQzI{KGGz*HWYr$e+%)<%!w(^3d|?f~RnfTd9AOIC(5+DJN~HSkbV6Xl@B zX|eWCz92dPE||0H+PJ~h7)N8Qo_v_$jp?_@c<+LlU2|yFvSFLEk@1DBIl>6UF})b^ zTN)zN4?U7y?ak;6(=>*eK#_2PfK9-ZiOfRv8Os1>c(Bl16y~?&vOFR@cK{VH-Ihl^ zlu=3#y@1XGtZI7_4V_gu2Nvx%ppoIMFX9t=0*$%?i%^XXQEF&v7FU+L&!5NfWiib) z0Iv+-Tn4A(hD!WOqcK3PKS7V1{!XAo09 z7Ay}DB}tS7@Q}&EgLu9Uyzp5sGl~^_zkCjcHu$ePxFkiWYhlbYo52PpBs&NCdTp3r zdFfL9j9?-okb(_UV!VX((PK|OOPB52OS?9;3%!KStw3VyH2G0wbTwIqOE9uM^E;Qo zno`Kfn&cW&DV{6Q1xZ|H9e}Zcm97C7c$XvtU0XQYNFB|ZmV{(rD6;g_sHMUDt!?Wt z^&f-AA_wtqyS8f=SEw{C(GFx9s;#>RkQa=NvOBPAQvu69z;y{qV$)9x3OHHCda{OV zm!p=#zn6~ri)C1fp=H(qEP*PN8&G8yC8t||EfZ}4z$Ld>N$uOcjiw>kRRfc6^LNhq zNZL8*loYc7sIa>Jx~u7RH(m#;!ggxKB{NIrXJ4lxnO^!LS|-Yzy!fTdTclEgzH72; zVlj(L6k6*5DysN$KWZL&_%GEFs(o2E;aon=dJ3_-J26>8Ot~bl$UHP(KG{`m3d@c0 z=@dQq@FOC*HCzSp=|)A7rGmXc$9>k(-_U#56;p{*%A>>#n|s>ZfyofUq`fVfv-U z{MOe|D#0~TfxGmWzoW4WF+Qnq7c;zP#}?QIjFTU7`YfC@YpdeTrV-mjX`DL0(hrYMQ$t-9{rs`V zY4>*RSdjN7PWQl`q0CeIA}hm#ZRQ5%w}o(vEJ43SvK!^4n6@?p@cLDj2LF03E#Ryz zwX>t0;)xkp{H>zaW+*PPWqv&iMt6N@Nni8jlc9hj(l(_4#>3oMYN2O; zahOJNg_y;Y`OjDecUnx;!u(?0U&yXRpalIA$#!*KBEw6byo_c5uC39gBFlxhAt9sq z!wYhfrb|nZAQJbI`1a*XCX%#cTNf@0Md;Bdo`KaOvN-{;!L>wj1iz@3U`gh8wvFTj z)oFBiDbU#(qi25kGX37~d_YjX@B2Tc6TR4rt?fIAG#U$sP^5jUq=Bdqzt#1Bpo66pe)V z)#(UfAHvn)JhUcNQU6#Hn}K6cAks$p)C3(n-J{^x2N#w3?Xxt+mU>qc_!4?t{vCj9 zs28JBrC`d%$g8Y8xBm=te3t+>RC%cDf@Z0y$ z{yn?t&f9OIVJH*H%vIB=^Q=0&=+>COSQnLsmj4W((l_^tXUhz>kzOfYRJaWt>*@N- zcG4BQw?a$t9KC$>m~;LLZwesuv*1(>-IB!7BGNWRLn{30^(RMvi2|Rc1bYTYC`&== z8ycl;Tek_aTiffYy|smEU}S~erDy)a%Pi}_S_iPKKVRv>PbU(@#!Am#=))8{MMI-@ zl7Er|LC>*olQ7aZ)gC)GmMlp*%VfPN%j;bEHJ3Rkck?sj!~o~A}q1RbQ>D7A1LHgpy7l1v=pu>r!W(k zfG)vtx^STfN0wFeu@AnVF5A{YT^rhqv={oEztn4p0+$3TmT!rNmPrSow#l}TG7^x9rVO=FMzos*ie&80KGA@r&gDxjdP+FX-V=_ zTA6_fTYs#DGLjV5{q-=cTI0`CC_hb|%|UtvDhh6U-A&Zh)kW>?ZCJjrYV`;;HxP}% z&f-iO^1=(@OvQ30=^4A$2k=D01P<3jIe)An~5@5Hz{#N?Z=l=|y)d>B^ z4}K`t{D1p*U#5?K;`4L{9YeLG<*71UfL)S|q&))~(U!r}S_iNUK2jw`e8WxGfzN#O z;*k^7wthW55A$3_r!;7_b5o)(8Z~yCju-o!Z(U)!>dlySh*vC5A?z`~%}oVvIO;-`+j+=pzr)t9=Q2>X*l; zIv60{4Pfno_dk7<*qll;W-kP(KyIuY&vsUQCH2(1l-eZ;NCGcge|dKR%c9!3 zA*r0U_=Udprt2w&O|os9H_;eWe{JaOpo2$Po?dU%p4zqxkVtY#M?Q5puWxFE!4ZH3 z{eJS#&Cpf2i!ePkDaz5hu9fb;{}Fon`QtQ;eSj*!P(Dj>tnGccu^>)pX0>(x=#)>0!|UaL)BX=vj2MRqIkVm!#sC@dQ)^U&f)e4qzF7JiDTAhYh|f_iPhMQ&T6X zp|zDxynGbTdZU(YTkVr%T!A1*Fn~qeMkixI5ST4ZF{D?CI|m$5HJ7Fxo4as!KSQaR zYC3oJtT@t}Wc{dqA5CL;udBg$kF5BlLNh)GnPpj4Cc+NuhZGO}x{KouQyry<_Ym04 z8D<0aWfOodNg~}lP!W8YhgM++pf&9Bzgwkv<>yo>Mmu!;PfsVnOmp-TSmwR!Ew|G> z-}^B%?$**w3fv|cfL}#A87H3wkoK;YqykJa;D>I3?OQep{ep>9hJsZXwR368rIOS$ zIZG3xhXn967`PVYn9V}vmycmM8l$+_&DTbHjr!}<#jzD-_=y-Vfri~fCl@ADFxBqTHyPG zK4=>vYJ@>#wu&C-z6WI4P^jkY>%xio8He+Q$yI8^=|*4w0Q3h|Q#_{{thJ{p@^eYj z%EP~&fQsNNB(&B6IDJTM5Ohjia`7xkbK`5T6H;`I^-(%{{1gmuCY+hy_6?W`tS`P1 znuL15bQ{`R(W&Gqh)q4dnA6@ErW9uE$4{N3P3xOsUto$dNlfMQFeN{e6BqqNHXvEN zNa>N$^pRgJ=E&#-H3T)LpT+(F<~5WQCH6>DC1wcE7vDf^Sv{tYl0OB>_zEE9-F?bO56HUi@0Gs9i8pvAo8oV*Fyf z%(ktYg_*5;zkff-`^3$^S{$j(K*~-jl9sjQ-N4`-Fwq6(=Oq5)eS^N9bCiVfpb?xT zG>84-NN#g`1I1zEZ)|FYW&s!lEbI6`-_Pp1@Q(6^AHOaWlD>GrvyHPdzYUNcl|-h~ zafk@R@yS7b#7`q*+OrN)^f-T4R}#P#dnF_;gAQN`RC77)L^gUuvCAP~KrH#d3O*Yk zMtk%1SLqgreRTWH*TD+!FKn5gH_rXyAYJ3n4H)I;vOKNkB;$ZxIz(JO+WR;f$Sdj8A zbs}pWfY&d?ZF~v32CVld<5Rdjm!?OdTKnqDcT*xgOAR=KAHZDz=~xhm&*r(=`}n9X zfRQv2r=i|H#O1M}rZEIJ2<+Vn*MMETTvZK?$CETX#^?7%$D49m7s7GCWpr6bGOUqQ z;275EjHACw(+DS@5-4*UPCEt%hY6Dts>Q}+EshdXc;|vE#sdPXHTD|I2d&dw*L0->!2489;W(mi1=(iK9i<~a8Qi#<3s&4 ziKVpm;e9xJ#|0dW=B=1YuY+(7J08^sCcyMKyUS+f&b>>q?WX<(9xDV~2q4L3)6Wip zXC7I_(sF%m6%9`+rvW9iD+yqi?TU?C>i`z{({gju2FAr{c#TcXn4;&PIj4(WJo+l# zaQ!t90e*>E>T4-j7lm+LlCsm2bh0=Z5N`~%8nmf3NR%ZBMK*4E6$`-=kFn8F>cELa-vEvt6JUOzGPaz66rs%_Z+V!pR`T;& z2jKQ~ZCeyaE}e$-%NLJOQ^ZFD@jUI{v624cyFaC_&27{_GL0$nH0d+@!dvo+xpQ5N za$wr&S-i_^MwsYIz-EBKxxS)IgwH`)Pckf%UFxa8{Dw?RJ!phkpoldCv75pHKsfB8 z;=DkzP^d!8T0qVO*J{GK2Gn*Vrn=6cS_%+6!Ih%pEjUYyJgV@NN#BpReqwE1xLVgwF ztildpK404heRLgy(V3w&hL6%sueoMEMCXmGb}lzNl;!DPyg+9m5_|!6_kR9gzo71( zUh0OTP>U11W@R`HPR7IMpzI@MSSDMD79+|Z{q2d)U-YZgPSw;*bwe#wdS7)4M9Asv~ zjz=%01n-b4K%Ne{7N_%rU<^@~lT7wf#Rls3X&>76=%rpO$ZfJ zlD~Zkb~tBeW?|KD0v{NW@UWq;^5sGO5PT}A&S)FVO#I?p{T38-Cv1`rD{iv6gr!xx zgMRRSVon#!#ozBk)+~uxr3YaA9G-V$5^nh-2?{tZnAxN({`A{vn;fo%bo}FUBVSqElSquJ9$j0KYh3zMgWL$(;P?8M zuoEpQ6zkE{`_MO!Z9H=`nGMUELE3sX{e*QFr&X~#>BoB13XviRxqT~$pNNNgA3+%- z6asPDx~4*>r_CY7-E52cCwMInv`05Nv?v>%r7z-no6H`)xsj4e$*s9bpwU&hQ~qJn z+$6(0q%CW@Er-8koV+rGX;#BYYeuvX#DLju(!JbYSwoSoa#XXkQmyoP0j<;H6t2jg zU(d`4j;i(FK$P$FWfoe@P$}w~f5_m6XHE@M(4Icl>B!EH-^|uQQ6gDg{w;bFx^>0g zEaN~)J1-I@s7Z;%DpxEi6fI?dL#U~8=l$9^*Rp_^>L72)Rtqi`PT%%8X2=~{aPm&N zhT5IEZOQ&US}=nq79Ji-ibsgvSbG;=04mrq%)qVRf%NVT*gL1pcsYKMlM$yDm(d?m zPTJI7>tT%*yq+|`J5o~W_9>GqkfQ%TIK2^}r_)Ep_Ak#BB;vsXd=H0A^c^9y4iwz* z#Mb(H&^;B*^5Sf8Ho;f`$d%8T_5J$}Y9Gj`E+SajEP--oJ{9h8KuiP3A68nutgZCT+g;&pG@QgNr!?U!wh?lbU^Oxb*4U7fUyRYw|JETfIz20cKK|9I=xI)E<_gf;o5QuR3hzd`0)k;Qji;K zF;c-2OJD+&!U-)oXRgBHb%`KO<49sZRa#JjRJCuJP5?`M`=XX<-?I@@vr?D-z#@(i zbu@vy7d);&^PL<{PlWm)$-L4aWZ%d8$b}HpAeIHUjgJseG>KUGQYzWcbPbDs69Xc& zqQ69`Ekr?uCP!K^uPJP)SmNSIQu1KMGX=9X5iJ-^W&Q`m(8H8Q2rxEy-J?~@>&9ES^jMJhsXn# zZwIe|0J^8);t8g)zR(n?;fbpC*7*FIV`dIE!SIt7EN}5bds*kTX*3RgQ1kx4pNPVc zJq=MK7;d!r5{U&T{~Y`oz9)uH|!P(+MfJN%#VgJJPzFmgY`@q zexsrk5B~+SvV_X{XBA?YTNTn~U3@bK{{5Y%qBt=`EWXL_DUP^yX*3{I9}acu96Px4 z@bIe`gOK&Ajc7Jz17a%h#`>iO7;M)q4~#`rEIzX4jjCid<3W^ZpZf)zn+O|ZG0CR) zaK9ALxhiCF*Mj*z+;GGMu$IDKUeJT~CbF{froc+MJH$qz`o%-6w2UA;q50i+iHh=y z-?QIxkaNF|Ao&YG|7n!9w})XAW@}uWcm9`AhLZ)tP1q$}VVuSBcS3M- zl}n_#v3i+{8Km~nP!$y21u%qYChoR6;O>=7RUt0?AS=Yi$H+=tJkN6xs(`ceJmM}_ zk)wS0B++4H%$PN1Ueu#iu&1~HKhEdH)>Ty$yu=<_N(%v^;XFBgux$lXy`5d+|AOtx zCpR5&0I_l~1KnYluW82Qv0rre<8m`pCl^%pBKL~_8O{5&;0oQIu>DL7rWa$UiHuDg z!dko&lPC+TxT{PZ#(-Y1V2sn#PLnJZIdX2MH1L3^ z1Xz*(3}XryFAFgmccEgQLyx2S;P~5w&_2>p4#yvkZ{@`i@R{5_&x28XJ>J8nivJK@HA6K}B1=AjjEybhYt ze(ictgac?nH$g`gh;AE1SLl(XAqYFUGV@yKWwu03k)WPW7Df|=pe-DDBqwVU8V=7b zd#XUU5A{C#TP;%g-t(U38kcosb3Q*}djNwVuM4(c7?Suj30~SWcqED#t2wH;_u;dA zaE+@pJ1KaCd8^;E7ga^5$alP$f;o)IdZ`e+Z-&eJr7fk55pHT1Bimm4lDuU_+l)3EHv;_NyCv4gPi^M7i+a!+;Rdlj*57^;JO8dDMX&i5 z6$2X@%d-*i`GCIADY@Bz}(VA^Z!dJe6?#Zl}>j3IU%~Yby%Bx?P6h7jP=` zp1M9t4v;ipXRTCRJ?h_+4iL=PA50v8rB zP^pTqIxfVBOK%3hKJC@ap(By!L(T7Ud~R}%r@!tIkHx=UpgLcgG>=C{?|@%ru`4}e${C$q5WHK0&$Ft7{a-+;e=T>yvEKctPjLK9YEHD!$<@zFf&y4;qoaS zjvn|chl&qy(a!ruVO8?kuvrpFKdxIHTdY|HZ#Yv;0$9`?uYuMA{V#LPgvc3^pk@ND zTMf}w9aef?Q7f zSk@t6%Y{CQR$g^|+M11d)H%u#Nh*e>-E?UFL~s=+2I;zXYH!O+y8%*2s6RTKafT(C zmv*`UHt-bKAye7KFi%34ZTwQjkQJIo`-N>(1jJGYw8}hgArtf%@SWo{#fE z^kS>=js|;0v;5K|Cl(ekFSB7LrA2hVMq2^SYzy*6HVIRRQNQs>E?%QG&Aq@(XYDrn z?c4T3sE=<-bc>riPB4(09gh$^Zm#XuNn#a;hbDhqem9nZG)-1`cxpIJtSPXt8}ZwC z6kI5XQZ~H)31gT(?)3dsiJ^D`!ZXnTE|kKtVmDP8rZ~BRhM?SpG@1lg_ zx!?m-6W?L_VwxG zE`$-d88}3o;%1mx)x`ctO{o31wkhzjVM@8u0D>vNl6JWRYiefTl#remU|}bph;FLs z(m~B19h^mIy5hxFG3v>TzRJUCwWpOBA2v(px5qd7>=jAdEB2^l>dqosT9Z5Hg zsC>4NVsHNL`}a&tvxBq7MT{%3;QI)s-9;=?Qu}Dz7vjr$i3le2;8f>|w>zzzlr~=l z{Vz^E{`Y|sAXrvF2ZExJxPML@g?R^0?1)mL zirva~(A_=z(ONsUK_?=gIdvc&2iCG?NnLXDz=Colj*5;5{Odc2U_D5>rP_-zfMf5b zA^8P+bU}i4A{V78$k|9T&@%o@WXD<0F;gb-hKHo){lqCXD9BWIxAX>&Jm*0VxeSRI z*nxM9AHs^g4R*>RNIo7RKgAYRittOTR4UVz2cvIn`;woT-vxvSJT(t%>C^iiC(mSz zQl)~;rJ}r$p&U4DjT)B`x7l(1@Ovkn+Nbd51{#@_kx$NtVfl_8zxc7q+3E0^bi@7( z-l?lOr)qOn5Okh%?O$W8k9~eDu$FC11|fjqa}vzl1qD;k?IcT9cm%ZWp;zp-x0ttj zNp0EF5O%2~k8I2jyU&?eNT8P=S2iaA53Kwn5Gz9y&?WO}Khdajw8T{}|Jh>$u*hHexZfEb zVBt=bn{9-w>LKWX0%J~KNh{9_k@w55B?I{bZpf@zlmHE5&>wP(Z8fqu``iO=F>stC zX4)Gw{3%&+ruJL_!wkarW&HBKdw>ga_|BY>ud>h0GCJ&$pqSYUO9?}0r}dHrFq9PA zt+`zI!O`eVjsa)Ufq4L_NPjqX5b`l zGqEfQh7e*+XE}6+*9=sU@gCT>nGOy1I6@{o%o*l&pG629-k{Y}3x{2iNP@fDu@D45 z1n?PSUak>Ua=d4-!?OhK1!PJKzOh>5?+{ADGh* z7&rGUK%&x_40)j#W0+75VX&gURFO2Euukwu0*FrujfupbKPBfP!iZ9sDP{!i~I0&F<8?HhEHdRE-p9w8uIYi z+3q#SSoWY{5twP_Xiu>PK|x+0S_tRGjfC4ijxBlD;ijWDE{BcquYfr{fT*Zf2#@nSRf2Kz37V0M+qa5JdVi=#Tb!jvB z8Y+tRNgx|(PgaKuK)1c&s!`ayWP;J6Xk`HRtf~jLlNEK&wm4{gOvOaF~ z-sN=f1;_xcbDfp4)yv&G83I4Ox&La&6a(|%$B3z>kR(3a#N#lZc=IM8v5ieuh7 zPs!1lNXbJT-Gz08W^h^x!-_h<7j%I)4YtT{Dq$EAVMvvPT(h6p`tD9sTTCR( z&6w4T|3>8WAb1iENmWHu1l^K9K2U|k{5n8 z(T3y3Mrn*gx7Dehp!VVuFFx(=t{yCW-rI_rio^GYQu0cLR@ibIF@C(5O*}@HD~J(z zgT;neg1UCw!?!$U(AsPOJ%E$>RzIHihFQ?F(prnzy;l4% z9}waDG==gJ)PNM~i{icWPpfw#`)2>KTt2DDkKU}Q; zfe|<2v5Hs_TZb46;9nM<5^64Cdn7OF?g9m7csk@`@@pM&%WBwo>Xc-%8sZ`DCF zk@Tw-*B#{Rb2;ylTANko>1VQlKg4{EFkXbUHI{{+T8!z|;V|jgAWjraloM!=Vhi}o z@qNh>JO9o!KucH$k{Ir#rccg-g?x5qr02#7on>v!bf|&0j`mA7oA`MEc zX7wmh8g`oJd$mr2pn z`IxGjbb1_MT)#i-A=68#OI`iBCn+V|OpIxZQ-^o1rlsAMOGoWc<(ojJmuIHTaVV>E z%2e&)w8;&~CuES#sS27U@s@zOEa`6n8-NdEo$GQl`V?oXdy!l+i5+2d$d@iQyJ3|0%J2cum62O_>dwIP>0J^DrTiC~dDU+h)*Y>Fw6 zGv%fygi2bkPQ&K2-Z^{314tD&eT#&+yx1DE@|jx<2eyS{%((^I2|E5qLMt z0+BJ(M*G8scOOS3*l-gp7Dngcx$j%8TaZ5IDEfWEQct;oY35fm`pdO`oe|VgPwm$zv;@bTe>_LaRIzGT7#a9@S`7}_6 zjs7xaSx2;+!!2rMx1t8!^)*v}@-jFCrhk%roLLd-aU`3xzdoX`VapJd8d?QKfHp-q zb^N%4rAD~U(8e(nKl^7)r0s}j_7x}@YDwwJz~o!t{_w&-MDxjjJCRLPd4D6UbzZjo z4S?~e%I3y&z)J>+j~R1SzcDks6G!hxz+!EhT?**zAb1cU9^K+#04n?bWe7YrxQkt_COG$J_TEhixElWusax(EJC5B$Y z-c(*Ebi1{q>HbL5WlB3m_fOlv4GdxZEelWiKhPwi?D12O8iXh0Lc?+aVZ%h4OtO5n z%^ZBhTl6ChnyW1Iix-yD}9mWF;=JpJn@R z5-ULXaAMT`J1_6z5^fW|bI2MK{Y${JiZQ_D9VlORI7!*SLsT)U`6VkrUa6uaB@LM(^@vT7LuUT*Pj;Z0V7F(U)4D$40E?_xW&1bL zvaght-!2UpkGg+(DX73NW)Qj#e|nRJeTL4u6R_0lNO3tKobtro`4zYdB61rpvri#l z1&$Cw@NeBFsAbH@m1~{=bM<8KbB(sS@XSB&)bPB%P>Ak%n=fo+U*Vn@tgK4Zt+P#l zgGE(1cI3S_h%G#>v>-`(-09DMv#=BTU;0jc9e1|0fXiqF5-#{C{uY6TKCl4NJK+^{ z+fR+d>UY()@F3zm3dXJZk{vRu;2MJiJP-m!*EPm z4t^|~`MMG_Oo5sCWj6tCt~diNJz~_ZPU+7SjiEP&QicZqtMKS$IIxboXG6tJ6;+iY z1xN3AF@R~Om#3mL&1PpOK1Ot1jl+IvTSM5lp)4sqI$7FEeH=dsBSKreYP8`A{(c^I z$ir!0nWMpo&8l4lKS$xAFNiCu_sQpk#A9n#y02}|%Y5sMHRQ?Lm8^yNk`pK-gN4p_+=?o#KsCbjvb$L@I&}(7efpV7O{X z7j%nc+PE<2$;nX7iKn>7#d*n^J%vH($QGe3dq8jI3P!)R)MCEo(0cSx%&pOwD994V zZ{ykDQA#H4ll<0@mzVhn0VdNEYs z+)gv|I;T=(IPzE)11r6^s7d}J#3Dh?863VSvv=>cY*gX_#(o&)NoRke2_|h;lgNq?-uTKPZDhXPU=iaR>q!K>S|F z8IX70rPIlEWTX@jMyRhSnHJlg1!2=|G?uv#hWuR3Kpn32?R531f()kA1~~bbPf=f; z5m6>s42Rua6zrC~S`^G2LVSP|R2>>w42Sn|g}Q~^)Q;IyChj!e`wU=^4ty|+#$n*- z!vwRuJfD`V@&v7b;5k(WZO;AFUZA5%W$AfcM(eUZX~Pz~0awO`V_*n?@G_^kFOs8JF9-l7)*y z#w(3FZE^VvmhE<2L9$!skOo!jF#qLFh%JHYZ8X}G7wIlQCs-ZeyM|M-HR}#}?QObG zBcMybaWLS5^=#FRb9RpgKG?L7Rb6TK!5=H5E#(oVxH0*%AInFH*!&p3Wy=xj@2 z(|Z%*$iTZKD0ak`+Rk0$f3h}bS^#*#w@|m?(LSd=LChx7C;5(^w#)bkkLqL~`u5P%7ceIV`G^lhX`8t$oy8z*25TED|7$lZlc27%K)PND$XaE7*&-LQhjgH{OSW3 z;x8eiHFEpS4R92kCAK54!S=0VZb9F1z++Dww7bjWCR`tM!=z`SzA&a9Wd38Gcbs}c zw|q2wA3zx7ivTzMDQb_|_^r$>CR@u^ix5{SqAWw11a%f<#KnKA-y22M!C84t6GG#o zU=QC>F+ZnwuZu1KA8C}-i)ZSSGLX4z+@`8q3FO9eYo8S`(+0n)aYjoZ9Igp*5(x?!HyzAOsyxGNJ%Zt|Z(Eq%ZdTe48^S zs})P5B0fzCE8Gy0eDCmVyspgYe3xSb&(=ppe|^qK$Ay6^TER|d9(*0=Zu~U8yPK37 zknCur_UdLV0~~0?xp|c0aV*l3#ogK`6Wb*`S@Nn2uV3Qyp?~yi&xRsokNSS$GmuP#k%UbEo;&NC#QE4s@Gc zfiomFwB-S9&nrZ(M+p>wZY^s{GfBORfm4!Q6;D?@?lPwO6huvip7T%$r1e>9?lwxu zn~!UN3HRuc`Io74x*A?Jz+94%Gw#p4m!6YlX5WEYfg2-3{cJg*TN(ilOEZcf;1GPj z*sQ#3RFFW@22h+wrn9S+>L=66J%}4JDsl`+zJV)26V5GrPC$60ioww}Ux~^77S>jd znV&h6bLySOe6^QrFuCvdyr^6B3$1b;(SNencrr7KGe&7=LjS?F^nX!u3vzGmsfvrK zv0Asl1C>xi-^54(*`6@JRhM4$fp;&3HV(QtW@=OHAhnib=l=tHlvIMME$KViJ-}LH z#0@w^u;HCM@<7oSN#9iyZkVSLFxC;H=2~TO_s-)?79*|-lZQ&1-)9CbWqDSY-7|Hm z!*emm5pnOCfI?67yBphP|R6MesYiFo=(RI{0=7 z=_ZZ$<9UC2!s~DirI4n<2x2gV20Q77GdT<2I*n`&TnSmnmxiI;%S3ljaSxO0JSkSO zLwj{y?_xV^_k6Pw&Dy_y=-oxR+0OpE1{iL`hGMDqaOPVBk@{P#fdM008p7)Xu0A86}d_nneevETlTpbY`s70bKa+F!VQtS7MrdGdOpc ze+_1VUxclHJ6NzLQt|=choq>SNR^OYfVm+9Cjcmh7cMU+4iAF^^Bn~*DIuZ&006&l zfdD9o@5{a0!t3`1+D<~<5deTi{qF<;q-SFNUni4pAm^R#afQRqAe< zcAO^Qsz5;EumE5^!f4gGEo;f5BWI2MmZ1kw)%fkm2$gtzY#p_hKD5mtK+->fAaa?sdxkBeIfrp zx%Xm}{sQm?@Oym3pZyQ19-sw2@c*YcUSOKJd?3$IpT`g4RsTcGAYbK-+^@8+HuPy1 z4bLt|jShm!{}C-uT#rM4bx;>m>?SF#tJQKH?M(YYjSBCzq77o0%O9$1h=qyx=wX+IE;Z;XVu{ol^(O7*y+Q^?_zdkwJoW{|`BUxKlF(uSbD#k2c3V^6fPM4Y zE6&>Zj~`hJ&|0Bc#3#6JO8E# z-y%HuMBbNMc7jGePmR=%BIezWN9gU1n?ghsMhy2P+R`u}=Bq|X25y;-oC>Un19cEW zqY16h+Z&&SlllxB9_a#&3W>YUk4`A`_g6B&0vjq^l{IcWtiyGY75n|e_V!KQ)1R2g z;UN-$*uV}`S7ywz$qP36o7_(Le%&+Ttu6uk9S?7h4fdx7_}T6hS1`cq>Ec+kg<|;F z!ss3Uqq6S{|Ar+@W{JswYzzLE?waSm4ztH(SQqO&Gcb=LIntf#z!e$=z%1>Pcsf3C zgjKUkmf&jys!qT2ilIw*UkUoKQBXx#p;vLABVOsY{X}@rSbDduGXxg{>4jX4_()hm zSRb<1@Dt_!+cWFQu>f~tQFBPCWv&6GB)q)!>$-?Irh3&3UTH#n_apRG>YH-OI$ZBDstc*=2!Tq z#}e^MiU&JjMww#zj*grbgI-3uhG{mcW>}ETt{k&2_VKX?peg+wAEUT&16nh9$Ni%= zWAxF#nQ8}5Xs4InubtE@14BzL|+APcfeyv+(x^x5>mPCryQxF_FRd@vcmVx{NTQDL*f=ajN24z(7CSd6L%stDa zzZ2Px8Ga;_y2O&!u%abxc7=f_qH9Y+o7~xV8ACGY!&iY_fKi$Lf)R9 ze47WkwEEuHy?cwB_GP7u59i#xB$E9yKr{_wneCX|R;K_vwznG|%ao8qQ2gmh5xd}v z0plgZ9#PcGMvP`WKV^g#aQa7Ye<^vGZ)eC$&pWRTbWKuFGUI2{ED zX2rKr;Swg4W!WTsNL?QOmA@#c{3Mvm{ER`RL^aS&kGYs>@Qr)gSvuyE+3hxosnr>(C z8TCV)0PDee9-bxe4LVEOr0e)gpH~Zu6n^VB9mxL+7^J2vUNOv{L>o6Gz}4PCck1&x z!nZd1$IRL}8lr7}VbPq>qh^MjRleJ8hl`gBsW_I`Cn;aQW9%6H8(ZgfZcq$6wHBdO5O`2ovmH@VUgl>cI7v z*9HZK>*kniB!>c0rFh=o{q0jfRi*8~9HWex87?;1zUvLrzkKX#A6bVj&3%NMB zRh=5ORxKLWV3NYrvqU7v=N>Jqn~lz`p;^RSf3{OupE@@LjGy+Zg`Pw~U^sC~PO;S6 z57@#a2AOo931(N^)=(-48b(5)<@_hm2gmr37#%*if5GpWtaPnytrW{YRrD$vf4w6y zqPYNtYbE6%V`p;HZIf-CU7r0@8(I~ci;(8;MWBSC`XmNC!V-}=^~&zm-vC&>9giV6 zulh>AeZ?fvsz3UI+Kj01$k)xE%G7pn~u*>V`np0(8UJy;bO=tEs)o3~B4w<{Je$U-zg&2wyceKb@Ns(XRK@wSbeCxIC~L^K3H zbGybC{cCFGqTNu4rZPMG={oiv{N(YR%ehGN_;mpI6Sv?#Py!^_k8IlFQTM zq@7;J`68npESGpuB&`uWf{o=j(**a>qn^y;g#hiKQ~+KJ-M7ckM+#QGU51%|q8HW* z=5mJ}?cF@cE27nXs`HyvmOqf4;pPYk^25r(vk-Jmu8Kv$SCqYs!KMzBzu>sq@v2hf zK~N9`Zg^vURmuC9W`z7>WVE|k1mQD&_M2?Wn9jSqjl`W8pz!|?Bwe<%PhbbhA0?o& zk};$f1N5wZP7fx}-jAom@o2Ho`StdcChG0<&4PINqmMDnB7xYReLN zw@@pI)+mOVf=9RgbHu02Y9@h|{O*Bnm_QREolQ99Ic{%7`~(4~z=j~khDwfB4-#byqOgVcg2gnl>CU{C zP6Oy|e*pW?6vp(gdo64n6Fu7J zSZ0=KRdV0&E$j(w&2p8bQ8%!%@=C7w1$@2r(dP0{8kWZI2O&Mp-AZ#l-?@({_Zby# z#yk)cBk3rvA6y#ey~$(Na8l6ywR6hgK?6zV%0wirgn7O!W97lX5286w7y3HQ$GO$o z6VCjuA#v75A+kG&F_2gDXl;SZmKDf(cezh zEB=z3I4;a?kf+*pQv~i-UMBadgr4=Np7UHmRN>&W%(*x<5X*#MDZvC&&H+!Rhbp#F zfS>nlM;rn9s;=>sCCMwi^~c?}#!}`VhLKz#+%^GX!@IAqVRHa_*I%GK2f8~_ ze@l!9d0Tfw<5aqksmgu6pc;B+KR{Xdxn=wNg$?MtnX`(^T8&>vgWC`1@31^OU^Q+* zLGN!D-Pb5ZORGyVAm*XN#>el=6g!h-n&b%xHIN9mqUhe(Tdvu02V@MkW{4_rJs)E? zd{<~lioF}iW{}POq4bb5#-d(_CMjQ4eP2k3;ng%X%Pshh^^|{7dgd!TQAxM#;!-ap zspr`V$}u$+XruKv2`gHrDpRDwI*N z06Vv;o|k}qT%ko!f#&*dwyCxu@Z(Zg&xaKHH8n^RSOpb!(|DGJc8cw_W)$;wifJb5 zLHPmYFkF6nivj++!dWzO9@rQQ=*-{0jPF^F6(?pFGy^n=bOcy|GKTh7|K0mq+BCQ2-L->mAZ)_BJJmE#FkZZtdfykZX^M(H<-qUshN*`_-!0u9Ur%(**41Hx;B0H2GrhT``$jn zfOTyhEAMNEI(BBz()DC=6wdo_f=CcC6b0VC&A~IE*vslLbpuc2RMmF9&|Ly}TeIW) zaoMIml49v#W0Hn^jGzEVJ&mXGX^QYTJ8rv)tl-Z9y5%g7550xlu#d7^O2=x7L8&!x zUR)!cVV~N1fld)7DaoZkrh|MYNP<}*LSFSW#8roJG`d6@aUA{kcLNRD`JsM1BLfc+ zqxJ+k=oVb?b_?#aNoU+-ZbY7pwcDmK+^5wUp&yptMa#IR;{xnx@U!HD#WB2k7N^uw zm}n=Qd@|SS@w=VuQkY-!L-m?rMv#iJQ=F+g7jU>7?2a8kH|#C!+{HybTFe#Q$pP6# zVm_=)i7(m9a~TD}i+tzF;A;!NthVF$XU2~MF)13pBRuRE{hUzr4Mni}Q4r{}WG4Xo zh`<=M2191zemq&ONV(mtrP~VE$@}q-X~W@xgh8igxDn34 z915)gTMe>CDK2)~Kg7EqXgZ-q2QD8?xYm|sJl&i5{3BPuC{$ev>hZ+!TkUg4MDJ)FR(sX0MDc#fu$*eLK&)s64L1Q4m@K87+pwJ+ovP zIYVbIom<$LC`Dql6W#DLxqc+6fslN+5x5MQ+=|FsAMQ4cd-8NiDP7KF_}f<6PH2jM z`MV_IL7`(&`>1G8x#@;mZCc@>ws(Lu1@3`#SUc}~s2B2O=g?t1?$`*kQQ`7o-JF;P z)rD-0yf41#V}2p(Lyr#EUx8KZ0plu&K+(e|S%XO2*2)I1L4gfr^jC9@A-9G_{4y~ zz|Q-_XBghQYviznzL^!onPxh<*}YItGs1t!Kki+eS0+9)V~6gZXi}Q>RUE}v0vqz$ zdsliekvQks^Q&-OaV>GJtiE^ZOp#7b(9iDPVlrWK2cgm44 z7BB6LP_)SLHbm)wkq}Q9srKSp>i_X8R3Sr6SjWF-fk-KECV zzvuB&F+)p*c4za{h__l$wG1lw$C@s0^uB!fgmTCzq!ONM@Lwo8nAOkR@>d(BL+j5Z zvhuO#%LoRM5_?k4adaoIUtp5@`NRhA5KRyR1FP6FD4JPD*zcFaH=z&DYq$q|J5xHy z3VsZOdlpQ2O+Zr9?3_BHgwCW(17ebn6bI*-qoh26ICdO)DbTuW%D$ph|KYJeKFEoF zPtL$?*5~>F!i@X>ASVw^;QeEx=Jors5dY`Nbg4Xo(4JSy(2*Y;?j z{JQk~>?fN>u#i?^TweF{2`v}%2u|xa9{U@Na5u;6DSz^OdbRJgGE&e>T)&Bf$m0|C zSGrlPTTOlnH!P_dq#hvTw)^ho*9@-e)m+ynS`%%UPA7};ZS4=0W&;-it`VUHgYS;z zLhxXUeviA4&jgYMOiE3#M-;j;#B-3Tpm&Aa{0ZHhf)3#mCv`BjVs?F&AfJH3@Nq}O zxE$aVNBwOTS3J9QyGix;cGwZCI5g;fUp>Ggb-&#dfTiH8pU%+=gAW(>DGlya-|-HV zwFRv}Uon|wA8FGBB|`F!s8hpYSwxa$5xJgN>b4L~4XR^`DO5(}Ehag!%V~MR9cg>f z1F5(>XyHDtFshQ<8*&wP@*2P&{rhYK25WH3M52<-9C9_(m(ZP}j19Ufgk)2@_=7jZ zdI*UdBtnP^TD8w(`vRzAbR0ib*TpFMKBg+Open|=6O{!XNa^9pjfbYG8 z40C7b&v7Cle~c@HOA|M?1{K@9;}hcS)A!OIo}<1&@*`Em>FHsfz56S~Px%cri!EX} zcc_WB8Oh13=)Ac9{#ino`(iut)An<-#LUA!8sXxs#MnyL%Gw4RvjIi*j1w!D{NSm& zz9M4#2fK$phBO`hkr}wECsqW!#2u*~?Yi7qi<`6`JtwrCeZ2EENVycf&?P^cZf<2V zr$%ZTDhoBzdh}LSZhT*BV91dYk_SqhAVCELZK4H1+tB?9nkjH&lW=)Yl80 zKia1LMVG3TwlC5}OvxICQt<3uO03x{ONlEm#I}crK&j5W&+ynaYGG_KH<5SI1%viQCB|fQ^+1K)Ff9x(5gNx;asoLG*hgV*Ud5rBe5}Nys3yq{5L^9e)m} z^qeq@6D`8X!zQJw3o;Zs!4@vOdnbc+(4zw2J}U;UX|)v2W5p=;^Nx?$`~gzDUP_wV z`?G>vE3wHRz4~h_D+8Ne;Q`}9X_9BI>TTS{zghiC(KxE)l zMf9(2jrm~bskWGKRz9=cOs`M7Sd;T(RGvwK&2{3= zW|R_0>WGpuC@u1vf2qM4enZV4XZ>SYPb_u`!w&3&_SYLQJbpW*?y2r}tr$l87gPc9ZI>Evp`@ zIA|5M+w!Mo`NQ|?RMk4`kNocgy3)-PL=T4filGXURBkgUjpLM);>IJAKh_ z$Bqio9{r#dsq0Ttx2dfKlsw>L+SifqvuK-}WklEONj*zT@ZJNg_XSZOlX+o^DnpjFq$H$k*O{hqn~!H&NC@P~$y?inh}hp#ziGEBsusXPs5b;#&59`g z(iky};LG12UM-c<-5EIgxI3ikF-a7_L?8R{JM|9>=R}sJJ0;4#NBP`J4I^c+r}@$+ zp^XhJh;M*RwCa*oX{mrz96P2k;~Q%rt<5`uW)}yqt+_wJ7LN8aLz2D`04u10XyRor zl=RWh5_dQUpP;3i7hrC}mv*O7dfbLA6rjYQwdjqz%s_IfpFB9fX^-#(9$U2ze2lTF za4!!ZmJ+YZl{1iE;^GMKhw-ve!x6tGBzs*MJZf}9dey#uf!1&qsX>?UJtTKq#Jp~p z`NOZQ^E!M%x7nXz@IKC%n>`C>5N5eU5FBCH)Ab}G#?DCi60!;^`nHq@^EvY4y?cGJ zwlR~4zcR3NE8=V4H&^Qx;?5|Rv({Ak5ImmatypdkbY!I>zS}{X-LZk|=f#ywXLHM9 zR>jN_O;J8)5O#`HT2ta^npAnj5w949huj4MGp*0TVFb#ls7ok6shTiHh z3cvW_JvaX_x3IR&btxs$+ypI0|1k}o>X*p`H){%WiBOP=2i*-gW{ufi>1lnS+2~-l zJq4--7EUuCD`Qa5`IReBX4Z_@#Mi4K2jgl6Z9n59Tb315DvI>>A!wP~pb!~Q_!*-45&Qqurwa3J^ken1( zMCiq*mYRUM<2@l@qq!xb5N4zhmg%L3cZ`(h$Q;lRh{9GDpEV44wv$i~MP+8q>SsFEE&4GykMVg`cYuOO7 z0p{fmRPIqc^IvpL2GzoqJEu6mfBn8(79YQ^fNJJVbBJ0BtPIe_Nd%~{?vCR}F^O!% zMUpN_F+f@sf?9LDLwPyaj zb)hf~69#AfXM1IZqQvhd6m6Vp7PjqP>02l1orn%I@$qJ}<{`OV-7yIgo+l1ji7$dA%08uRG!WwTUD(&uloyC|Kn4zIID3Ftn`sP`? z7BlBPj41pb>krfQ$>}5@{8)l{HMiw{S~!ELr{?)LO{b${WHuc%7T1nZV73D-*;Wu! zz!?D-J1ixB7g6~urFC9nfTRz3+ScdN{PpBtvnY8@4NU!@2uWov-ZZik#*gt5Vf#39 z$t=*}=xxv?YA?e^8T>)fQ~1ifU}MOHUJ&5_V(hJ=;%d8~!N$FDZ!~CdcZc8}+#P}w zTpM=?A$YLh7Tnzl?hv$*V8Pv)&inoUtTlIYdv5o0wp7)wO*$VZrI=aPY~qBNJ`1RK zVvu5rQQVz8>RSdX_f2qk5paCRnh&wZ-}V-@as~oZjJ*w1_^)~E?+@^;6BZ=NhZNgAp$Ky|Zfa7~gk0;%<+boRPZ)CbQ9J>39Ytq;56+rE~VzR7B-`*Lk4<<#C^ zz#m?Kr-m3B8O`STr+4$B){MTy0Kud+6fb2+Tm~^5e)A3IIg08F?(M9-29x9i6Wle11@-uT8h>+?v$~Fq&C@R zev{`iA@Zlu7P5AH?NYIyxzh1Q0?S5>;ZAU_#fE6aC-<19TrZi9!f;5OAzboynEV5L{NrH#?szoj&8}DWpS72Wb z(VVB9zY9^B*2;ysVL1m~$?{QAwKP+1j&e>^ImG<-!{WNPp%7wuB+&j7Yua{dXqbS0 zGd+658ea1TwRC?A1NQoDbwAWo%&IwuIH@?IuDTENv30@JOA%%pHTt&k>%#k{BFK#M zh0k0gYy;RFsBAdgT3XALW zXexcf(dqnG?be}1A>6+f_zo{`x>n0B?(D-8kSsIvQe@S*;(agM&m2;W2M8{vfA=Tc z;BHxP)8Pl~NH5%F4Ta0<4%3WMo|&S~ZHPM;4vxv)$y{`ohG3gS7Rykq6-f_7bYWc4 zBqM60S&l06#EZNSPs+XAv_-uosogC;DbF*leIFvFmVI@Ls3IFZm(8=VcdhsNU(GA} zluoXmth*=h)d`j?ct=Ze;!O4*R;BmJgT(Iybe~X2rc>ljgK*W7Wg8WBCJrO)0;AD- z)Lci2*cA@Bcz2Ys@$6v>7Wr`5)%HnTWRC0S)qV>)+H^ohjvm&}VLjM%2fN}`+^g$@ zg2b8LfTv)~AQGA3SWF&BohTKO_Tq#E+BZA8-p{T+$-LTWGC7a^7G>_Fm6X>!axjw_ zWnS3oH$H^S@MQw;%v=$sY>)o?3&G(u2~QJq)6?t$&@*U+Plf{gfEB)Zz>QC7(DJ_Ks%LvSg?wFCQ(V(m*U3foVfE z4Oo8!yh)Fzg&V55RE9MLVw!fQizDC@1jC0Vlv0b&5@xE!yfRhD|GHsS6l&40zAJOs z0rJ3oQXIB}#bvr`^-07(lk&0Gl4Ek9K{Qy%uW-@{c5L|>)~Df7A9MW)v0ii!u7zj? z=F=B-FTbDfik1eG!VCZ9Q$xb~$#Rf&xzQoe-vZCC3;P79|?Be&t19X z{b_)yxv$}-468s<2<-hJaI)w4QyX-QA549HJRT>`3j&gaeJSm~9IVARO@Lln@k{Ld zivrMon<`k=EI(*FFlm&2IbDFQ=_%-s^gSH9A-(Q?n|qT+Z;5B$HVLM4P}F?Kv)vyh zU38!8*!lX<{R9knoWaFH8B4Uz~@m9GEabQEo{~)?=3n=;7JQ0D=JR zjGTb;yc#amfspN%DQ&zd3dH&YxglF5#17qWvo|x0AZff3v6ov+N^InrlU1)$+|jt# z-Vz*9(_gYv*ZU5Ci0-XzB0-46Fmt$>{iq_y7(27Gu#FKlz+h@4>=HUBgnV2qg<0)9 z?AvGBBbDK>bR2~@?I)^HG6Lbexl3y8_akGwX0Qkn)?V)=Vy8ol2b?*g<>wQBG7}YP z|4a@pTpukZ*3$fXCYrq>W}2i2ajEst^T<~jRW##fW`9MO;=#_OUb7TF@SiQEOl%?;@XFAOg??sYY07lbX(XBa3<)wkFsj=TjbITGol& zo+SFVbNpX`{fgrEYq;DC(LaNgYy;In6z9{_s^-Nt8xm+$C`5Ycu z@TLL(6M;tX#w7fZKIBvUucs9MDpMTpZll7F=`d^R^9OZF8&PbOL@|1a`VgX#t4 z3dn{7LMN9cYHKLPIKtnIZ{X+|z83)SU==zXzpeerUYg?7$JF06xc}$qE zW7t>=ytCqE!jWJbhAW%~wH(>Cq-`@LUYzoN4;8ukMSpmD!_*MUA&f2t=S7LViaBR> zp%V27qqo!A+Ndnjx!!;zLMOVF%yk#TPXWN0!f6r+{mp{f0}>45Vv|m^{g~FRv-O%O zZ+Rbp?^AN;#RJ2x{U%j@K5J}rUA^)n@XjeX`jF@GdYGcH`{6b5V8>=kP3rU4m3)*{ z#JMyYhu8MJ-SI6BaqL-nJFIP-upn-D(Pou|hKC-f7f#n@Nj{i(f<>y5eBcuWu4fLs z>8cYK*usMYW|c8wE2>Q1@Hl4R%OJ8r&`)_AP;w-Myvq8vCIBax&i!4ybEGXvtosIC z1~|ExT&7TGv^pD%+Zz^}XubgfHWY=1sLRn%hMJlD{gch}$)XSpaK15XS4KWFNd(yph^UF0fh5n_12@# zdJ^ORO(p?cAny;e>n^H`V&k5ZgoZNv^1<+?=K+td$j+ z=(X8x9SVo8FepUN1dWy*1#*5v(INRuI!-0tUEM-b0mcnWT3aUb#AFC$`lx@bf(=@~1c^F|uTSNbvw zUn8b^p?&lTZF=CINaW&xgXCama!S3lLIYhU{9-m*+>C36{zk678$~ zscx0w555PpDS!Kl&W>kM$u{`ps>~tU4Gu;hhf?z!aO5B~z5dp*P^U*TsJaOeq9Tsh z5gHivl+KPvP`^w$vVHGnhaT_Xupr=moTEeAk^Cf-12DY_B0&(%N3E)U)l!^43uFP1 ziD9?336_NgcLSoKaGp#h^&R@t8Z|TQ&z?!oPuAoHupNEYxiIZSSR{vRT|tBMKk$jS z6Nd>Mtya3chSp?c-2(73FAjl9wSNfpdzhc+f4!5F{LPjo<3p?tjJ-y#P}Amr-Y%J( zsXDasy^W46Lt2GFQBpWfNYE#X(Jn^V#j!^j;wn{95&4Q)wxIqioj!BhOuHBM{Ahb} zoDRf-P+HayaYg77ho${y1?`qYYtgoZ+rArBz6o)l9P|$Q!pM)um}1EHM}q|El{QAP zL9^e&8Ry?C?+|S;rjxTe>`}_tg>8t31B@Nmr*qL~KnL^PE@%mN;S)jpP8|%UGw4N% zIfx?w>K8%}8vIm`>KN1f^7IE%aOzH1KBqHZ*697lAiph0o=;f|Ufx`44%aCG)!eMi zOGN@59a>RkO5cpBoviO=uZOONXWc&LA30f;(QH2KiZ;PwNm!TOCD=Tnmx0i&e>hz( z@ZXKtwRzZl&+&gG_GS*Z>2XNaZsw#3h=qXS;rdPOrisTDrzJ)tVEDSxoU;#}_>VXF z&}D7auHjfM-R^I74>1?Qi0-^ew8tIWfD^{rA(C1gD|^gF~7#0M5V)}O*!+FLT*}xfP$zH%2@geZh7TpWtuJG z+6}0;|6Ki9P6Xa zpx0DhjP~7ok8Sy$@oj<=#}hR_Til7T6yCq*;?!!RR<>L#GQ@IlO?QR2WPVO~U1Jxd zm(5*dcA@6GtV;PLrPw;`sXZ6t7!94=@5;SGvhOSMjx2@QnD{(+#`eDi)nZJq&^FO7 z&wu54Mg7Y)AI3sBuf#x=iD7xEF`j)_j_e8h|D*6yChlzX_O&g+*82b#A?X zMT}9|uNDc#)K!y+&5_l5u~Tv)K||om?X4tr19@*g%v6{g)DVyMcV;{CpR2^|7bwd! zpbY07$JHzC?)QI2zYbW(Gkr;=J_`8~DZTy5HSF4Fs}A9#HG`pbgFKSlQER_42QZnd z_wB`EL=3B^ei0Bp&a|kNFupojR|0h9DVSZD{ZoBwpq;x+uYpP|kRst%R89P((jRJ3 zluX(XWMPmPA}o9bo`-cde!LwsP0gNU@eRoK)rdV|vdy(!p}~LemVYrfT+L$xEK&q+ z>ExByb#lri*R%#eun_&Dc0}Lq%>H@^&4edmLnp_t&t{*A<3DK{ABN>?So_?GcKVp_)mZD5(~3Q}#>@y4LiFTXr+Gwx*XjS-)Z68D-~E@D95Cu)QVoVcQ2Ce_UckbS_XH=8o_o6E&u6q91t@@lH^aPnH*rT@ST)QWf^#RB2eZNDB+))P zLx8GM9I8x)95bu*siOUK;2;1C7=Bo7e9stgay8XQ2=?cBinyIKdA(6|w^`q275KDS z@-Rakxq}ajY0vSRmlwSHRcR*o<-VL<=GZ}5T!3D=qTb@1uLe~&UE{>4#iF{qJ$6q! zUnKIJfeu!A0{c@#?jr5waZsForiYYMczFgH{+Ih)CZc2M)Ql=PBRp~doJqwT9(gQ2 zT>rW45Yw5Zu2cK@uUIQ3M1@weQJM&Z>TG`~qYlplQPR|oLNAQ8L)(X|`T2o~na^CL zzadP;9=#0!LWDR@SC)f&0=QDSC(`#>Mh0>6)_&zHHF&Ylf_sAq*f&@PX)uB;9nsBQ zcR(+*SN_|3SDZ#gc~>4gM-Kc>)sdu|?NGZiBs5i6vTjLYXmo$Lp+bIr1mH*bZ+=wh z*P-;_tH%>xpFls0YTxR(a8Ua<-%j^7F=tS9lmCszv-)y(;ee(Ew^>Qb?)Z#X6qv>h z1&osS&h1SH2 z_rsDF0rqK&+62fSnM=# z5y}MQiPy7RwGB3wM*5gN@)mAB0Ri-R_ZeUM}(+zm1(Bx7W3+N0{5v zyc}71eB|7VF7Y0D50F7h7gyCl;Xb!7#Z`s%l_YJbc8$d;a#Z-np|u^L8HU4s(TpS2 zu)wY4k(VABkbt&3{q$sh_d)C$=a4Ptq1)D_udYOG8&q zTze^OPLS%mk5{NagQ~hNk}f3SyCZNVJQvg4Mk@Ed?3AtweuRFjyUuRHLAG#!9Dtu% zO8WJ{4}K)ro)%xnquEUw9b%*u_WK6|hNjtIkeL}a8oD>u;4M{TKN4cz^AeoZJ}eLX z?l<17^&(BAr|=M0W|CoI(qjeEDHz@_&tpreXJEI)C~C^2@qV0gX$NAmNcRa>wJ!p6 zaGiVSKj{H~9*?^BhF%wBc9%XH>3@^>U^|fhdmz#VV)gc_Sgj^27`|gg>M{bf9{6%` zNq(Ih^w;k?WlBV9>8DY_M|-BKpEabUKe{{P7Y^Hx)Z!E%h@ZXNc(n3(`C;E%Kpti- zWJ?hO5dyC?DWq5%*0|d7f`6GIP2O264gh{m3A?5)Hq~E`hBqS=h#V(vcK8s|p9E*< zu}QFAzP##Yr!2Aya)#cFrJm={9D4YxvxVkj3}@7!b_jPzh6Zu6w@drI8@RGJcL5I6 z%G5Ij#WwCq;ei>yp5sq5u<$M_xSc!2Au`5j0ml@0c}+h@0rrEDt-j~}91W(X(w6mS z_2Wm8QA+LIeqT!wrF>7gypF$!m=Iw~_uBi6p@s;ZcgsWD+Oa*LD(kKC_N*bGy7$m} zQo~O9w}e7daxdsq^pCFzM*A|Vb(W35an1stVP#QZv%=Yd>)WsOjDgoWnY;7h9A?Zg zgE4owU^FJuhcEpiT4aqRrg_xnS27C&JhaCi4IAAS>Z_acLnt~ySL+nB^||*% z4Z~jfa5dqCLSPvF_lCBCTU@G|$Qm%b5@W}wz0B3pVu4vQeU0$B3f^EUy8`beQ9%G< z%jW%Wj5f|%X-Ag$X_rWoCs@%|5eIowwNZ{k#qFGId0IKyXPH_&>-#< zi(AKAX@btWk?zm7R=~ggk34KLb~k)9z8^5^(9MGnhQ^x(BO4^NlII$Tk@6q~_M26M ztU(@Cd#KNAQ`&k&D-MuTVt*LUx4cs`o!6B%m0;R@ga@1(vG|?2(?@)u>O|eeCON__T3U*hL|8Vp>j%fnM)4Vvd!V>hFU% zm~uugF-5@O2{?PT$)D+Ns8diCyR%D{u=XRxsiEl%(77dpxo?V+nz>ob&idjxXbT(o zR(mZ$K{z03lR;7gsR;p{`+Rjg4*QWCh6kpAu~l~fayRgrk-}8qUKk@QY#{Q}o8O(w zvNdXR)?--}YcZLTo%OH4-llEL%-surlc`7T7P-q6rtEkWx$aSK^FASfTBalO@oK{C zfpwhg6xSPED!Bv&6^IW|D#dG+(!(BH?oMhd&1qxejeTJ)6+?clF4@9yxujNyb1Zam zz-4(yJ%uKH7)9D{=;%P@%hqWAb018VX=E6>JsC&Tkp3sIwZX%sx$S*|4`OE^Y%jt& zO+6T~t3J6N3&a5x-Z8;ja;=Iy|8f|yN$gom)OpK47UXFtL~soxmgV;%&u=ACaU9rE z{xyqu()S(=$HZ*aW8qdNw_mM_ri&T(LP&}ADoC1O;JtBAP(-fT5+Z@Y?Cu}>!KP&Ue}y#fhl zHi|f80zHdoRBIjkq#RzZYUrnjgmQ_lG{;E<`F&1qTM-IFgM7ZD81f?z!)4}ww2PRJ z<9i}IWBv;tHQdWEaR-~@iWK|J$WX=`W3AuQ5I`UBY3n;dHRIz?IzU1{%BS}=3D;(} zFo|i#NIs$=2|cb%=ZC&FsuaW6-L4%S?bm;%gu^E(cy}|%(0L`&ztS>9Tmd{iJr8cH zR@pm4lQWxW0(K&o8YDs=4y|;bUwSTZE!aRks&s$>XPfM&lwse986jZnkHx zRH*t4LBB0L=qf5|ff`x7a*}e~TuyM_nT*k4B8C}qXNrj1LSqAnH$a|6-P`2ntCT??! z6MVePu|$zY_fjvEU*Y3}EEz=D*Jre{nC(;sCfYtxe(*V6kJBP{M>juzGgZb?YkBCX zb9z-Z6NSh1`EgiD6QZ&szYRFLhbsDkmNfsLBKq7|S%+?k);k00A|@|lFwS%3%Mt6^ z{QN}VXmy~fnGdie=CP26V@1nH#IY*{Ev5LBD*rpT&kN3{={9d-lO5a zg4MTd+f)l>o-Swr-P-2yP#sQn`SE`w6 zy6yOq(z0vAxA6Q8K7UFGrL--hx%EmpDXqSxkeX9RtE|Hte)KA@&0A%Po+JHj~@hz$vHzc>DPw1nty5hrC*E=C;<@^i^M(|d!X_-3v?zd+M# zC%2PFG=hS!kil?Chbbrl_&To}fuT%youFfJfSq#hu*e7F91ter3v`t6ncAxP+Le#} z>5S}$sKe!F`Yg<$(yDsWgsex~>U>3rY9d>d78+Af9osE{yIRkU;W*1oY+^D`7v`JJ z+rg%P$ccm@zjZxK{7&74I|*SlQqMnG3W_^?!V~=e!G3#@bpNUNin#xiH~bGGY~OPD zy@Aq+jv{ zeGZ`02Cw>bawhB3K7=s(>B=5M>CTigQv&W_5Yy_Ypn~F2)c^GY;Mnf;Md&C&0o>>A zN%GH&y#4aLKY#v{Cf(jpdi%;xE-UM1`MXt~;D}b+3)0XGe^5f`WY&W|JAP00C=49c zH8dVJMf0jttAFcVo#RKM1jwXof%0Hv>LpREgX0?-(5V{UZ)i8bUUsIMLMjBQ7%Qj6 zNx)0(-M%-#fydc37VN}n#5LgOC^Lf)%!B37`znN{W>Dbm5SbDQ$>AOmqJ$PkQUQ*C zH7(J-e)e+^++N95wMInr`*(M17v*(IqILIr*IdERh$;D1n;L6i0|+zAHY7Rxmrx&* z9!LF$hd=TJnA0HXOaumGR*ST-DTTNnMp77apG6K5`uo!5YQT%4_d=+$UF74| za3sTLWdTYb5;#HfxD#<7Wxk~Ia*LR8y2&szKiKO{S>)*>bB^u)qx@T_eRo5({aO z9g#BoQ?Huy<4=aX?|CqnIat{Yyct&T@^-cAJYyr~nQq+e7JE9$x?{T`{IWY?-xtwQ zR1gouY*43QM!xO8d(Gdl{?wbJ7ke>eZcL?8Zjqg(f{e#sV~1)#S-iE*YPN_W{xSX! z3MF=Mr1x#B5%_aRZMX-F!TR<(4@CSa7ju({96WS7&;eGSsNVJmD=Vo{-@9b2Ea1RS zy(I>pl_rac?*AVN-@lcpU5F|pN^7T*(mRp_LFwY2s78-Db2>S+^t6-SX9hysJcest z$&)8r+7Pape2Si?XGNFw?-6+P@tf)EPn>6x?*@Kc(A2W`a>ca_;7pJj}cQw|A|^~wf-k+2@y{4Lqhv&jO4#(qwe?FOZ+Bc$9o~~YUwL7&Ya~5wZVJUp{@4X>JIykorv+CSI13${( zy4Wr|!XJQF$=@?{ei|&jguw(6jou3k&RT1V{3T!hZU-&kP!tMv^Xt3NG=kpg6Zdj0 zJ=wd|^HL52?`AV_)$mq_9K2i+kSvdfQS^nby8~Zf6Q&%7B*fME_v|9?(c2!_QL;Gj ztWmKBkzBDp2$O&pna{ALp1(U4(x?>uUSlyOl~~DhKHWW-Hbt6Xb2b&Lj7o;9mF#W@ z{OL6IK3mPxe0s8T@Ju?5tDa$RnBlvi0$zK}K9f`{N9&XR;BIe|Vl&PhAl|?ttdng+ z+}NS_z2B8+<7iYkEG7aD$Olj16yjE;J6Fe`gzK)uCVI8{AdDrWBXEI!3wE2B-Xlyc zdcMoD<^1vWlUo697{m^{&htR86bL&i9q%%UYoGTsl}OqArnmkFLjvTFmX9i@Wc^>= zCJXQx87Qxa=exm14HB)~H;s)Srv*riX>8LgYy9~4l(gw$DeqY3bDWCgo?hJlp76I;SH7!&3rq$EdX>sg^mBARnXuPTuU@enz~rFV2~dK1{pqxdZ$z ztDu&1hh~K3-~1X-R{nF|M{m{l(=F)$h!Z~>Glq6>w{z_(3YARg4u6htg}aL0|ZA^>MNS4D>cu;!r#TU2c8Z^Ejv zT#R*Gp_Liw&tC+Rrc}n{eNN_nwmQ&R7;YT39X1u=!9XI^wKJi}E^~;DO&l?&%W@p|Z9hQ|$_EJsPyFVXb3%VXN2%E?pwwC1P;UXcK zv5^kX)bl40kZ{NXPYQTJp!v*CCCvV)F3bIZ1#oQ{N+c4G)b%)3u>8QUP)F|Blpl!w zw63c5aoUivdcytB`;h(D=wvB(JX{oD_PHscof68)n~FDJ*X3}r#hn~Je*4u4MQA>& zhd?$ehkrq}OpX{e1SO`R>b@q+6GStx@7-+5zN^O@WIJ0M8FzI?K;WT%GFU{Z8n6%* z=~{}6WXz3}LDbPdU9&&Q6gGz)s`g_yR94@`pCb~hiG})?CkZ54E9?6J{Eo8i5_c`) zW!DCGU@S9Fs@?%BT(ecpw}MF5E`dl%>*U9;X8Pc!ODvVYJ70b;6J#$P%mS6GENz8W zBnC}CR+{VDIRkOSKIBCs1{QC4_?o&DFr5Uf$7q3DQ6~p;T5MO@jBoB7MK|G zv!-uPc(ELq8l;YYVeL-E+>OQL7Mxz~Vfx_vLGfG6FVy9bruI9S%7zT+(UEk$6)l%Dd^!o_@H?#u*@ zKafdwwta0BT4QqWdb9YXj6h2Bbe1Ad_f#=kf1HE2P3m}L-mO<%C%$d!9GJY8;dLVp`(U|t}~jM*Q4nJcWS1@0=>m1 zm@B7)^F=d53%6F{v)s{>BUAoZ9i9Be6+|rXI#a`874Tx$J2<0YH`%P1vv+sTgEIiy zJw9%3UGH16{q6_V%o66W5iTU!V8yT|)cF1Ibw9DSXcZp#o4&?^|=LSY-r; z-3HIwIa22?8L1~=59tOX3oGmN;nQisuU6V#FKe?Ta=&vt<*Di(o7WbwRlYujYH|KT zRwxlRr)L;e?mhlCzJKuTeGU1y-n}GjZ@is%vHdJq)fPNPAvcoTi*oG-F27cJ!TtWX zr6M&dXzga`O{JQ!vd7!Vv+NCDVuhIa8*DpGxq#jayK%d_i(S`&+48Iw1sykr++h3K!k1j_hh>rgBp;9<8J=|*0 z!B!Nau$dTdtlFWoX`3SWVExyFV+YZ5LRt&U2JR~Iy(qS^WT_`b_ugs7Hw#yLP< z5ccTcu;8kh;6OI$h2@jTWs7NjyGvSTTSO`2$HJUN2E(U4TOZ#zg6XAb<8iG9G>BgI zheagFg&0+UJNs;3xO2;pld3tu2p3QtoEz;o`4Xz_{bcSFj_lX&Hdr)!^YpX;n?Tr` ztLimC*$?2!T!hAplTuTLygN+X)+i(}o#>bp0 z-0X7&u^`8{VwUCeQ*&o$k>mmkIL0>KCh=_kMt0bhiELqznh9Rr2)*y3x(o<;?hIZVO}#c`zL?5bdfb99)JM3awcFk4@l_s!wkfd zoE8NZywne3A$qm~O{r+uaGQqMG&gG_rH%H7e{vC`9&hW#^GG*TnJ9g1=>P!rx3OSi zeN86GUbCqV@N^8XK>Uvtn4D!GNaL^ZYiZ=IX`zGq)T@cW-NAcJWgJ8ICO6 zTjJX>CM`!(&oV6C$|93eE&_WuMwwLwKltzBLdD)vVTv}#r-e*a)B$stDO`uIvx=eY z;qu^*HDx363iQf&-MzWkA^GQa;ktxx6{+50r;AfeEka*UaVn@=Os+_bt^EZ4_45z? zpN1p6@houLXI^epzxRn_=PjL8s?jyehGMB-DcqhOzc3r<+%z-J2%zuFX@qjb&t0c3Qfc*n9%#Cw)Yz2%y__65C=Hv_x6#5I z!6w2?2e@K7AC0^k+IQ8KB%XU)bz$Z`O#&jlg$ZyBw(ZTwFi=xHVXA(TjFN0E*wsq8hKV#Y{HoRnPyF*4@J4X8oF z#_X71vL&?Oqn&CW|WFT{77ume~Sd=hKy83uxJ#ibp7U~BY9gv5&wwr zJLLqn<&zoG@`cev#92747Tk#jY$NKK4|NOHiJ|?_%*ee<4u99L@Kyv@4@}_f>@^LI zQ^hyAY_K~!+M!|6SN>3%@5iBB9R68b1cGsnDoxZae)~;B6XcCKvr&40S_H~#5QiCI zB&oaxd4);c=L?k#9I!&DSn{pNi%Cwu`;kmSJ%V`e{fK}O=2e(Ak&KK_iR01P?R}_)9KeQYe3r&xjEgTp- zyzMe`1h}M`4D=X=c&3-SAJW_*^A-*Kf!VP9b*YKmIl0F9^phe=gsdG2{lYbZL;eW9 z?(>Ut$`$;_p#f_HHAf7l3ow6tDmzl@vK*wVi_r&*&O+ttV(ZW>rpt!|sepj!VkB=^ zmDUvbn8sW6)QJ;gs$pSgyo|aN_qyuC0`aF~ zu@B+d$_M1!(Z4WN!Th^sI7D_KKvDo1VyL;67QV#S zbX)6ziBXtZ_NsJ@K_tT+SqBS`v(PTpEm2b~`b`Hv$GC67MqKLn(mGAh5{D)c-wYnEK7^^8)A``?r)w*&n{rSaSl$Nk$2 zo2ZObwtSmtW5|td61fP6B%3j)!18m!@>8PeAQ@&F17g)RZPfj$EAu(<`$Y|ZAc=w% zOGK$~JlyW^#l@*P#p6&RD2)2Phg=|-C2WwT&Hc~&6H@XB4~YnJu}0`65S@eP@G)-o zX{m{6p_aD;(KfdoUS;JtbuK(afttTt$hRf?9D-u*r8+&jNscY_EOhi8k9##>k>?8M z&JSo~=c?1FwW7dLc?*XDyOw!$Jo4)YMF=D6kjX_PzB_w$FPMG;gZOw;A1Bdux96b8 zorX9O&Y9UX0lJ7aQ^pVH%@<0q4uaJshtHqZowO-M{)GUY0L-af6mUL$BCPOZ4MB1) z(}}~Qfpe%EPK9Ca!ov)I#t~%HeniW+utI@TA#doCH zf~i}b%obB6`JJ8Jo~|_HAmaqZePIB0`J#d^D|~8IkGbkKn@vO}=z4+>K~Y-WJ}6YpZ!X7Z-*Db?fN14pm5 zvtM*m4SqU0L|RGidWe2#BDYU3L5Srqp2Z8O{|(@>afKodzy$}zBtY(3U}=>A%io8| zqzMlYgLbJB2#1s0`BbgobxuXPM+|?&LOr4}mkBr3eOk362?FimUIMkAR7AUKsA)o=?PjiRAXZl}{~CWrj_R+wWq}tV*Fyj|A8F*0iv$>tMv@+r4pi0Og?i5Xo!QOCx*6O7%i=fg9IchUcgs9+w=Nv9%_E` zFd^dW!0^FY#pcjk70#W)#f^F(E7{9Q9cUxs5;gF{-HStYBFe%-D$FkfLPRs9ED}t1 zq>us4BH=&apl_sjKeoj=)j1+IeD`zW{T}9S?_^pE6hH8+<^1SF7y*t{iiF z26B2lno@MeSM}DtARDoL#Ly0}PU@_##>iIb{vynIfdj-*q%}CWedf(3ks$Bm?yyVc zpxVL(JYZ1(yI;y8&*L3tv($(zjlRbh*?nSlv=FLQDzLzX9ex>ZS5eo6+V59mztYPA z0!?V&ulH+dziqq|y!)9Wp*5K`p1iArQ@YaY%`ZFqGNOgOwl3jl5~2M~l~~l&K5Sa| zV|;43PV?ji&Y&ZfK$BkY(@c+t)pE6@b(lJ z7u?F|Ev5i2GKoMTH*c?yE!gK!ggX=E4P_dcb*85E&GiZmJOi)mo z@TW>t%KeY;;IS2ROwxWb;>cB$^kt98&0zmk-V}pK7sv$fHFjZ2ubB5Ke3iKdXT;85 zbKT_XJyI$Yi_(Fgdhrh;FeiLct8?(=zlZx-KUP7Oo^64{ht zYh%M>1f;UVn;tC_g<^RM#|l(%KN&R?|vKFjdg?eMm91`PEKcO zguWQii+hvq_!py@pz?|cfO?Kz=AzDQKdp(pQ;0qa`d^vvh zki^w6C7;Dw^V8(W441UV*2pF}j{NB?r;1$ZGYyaX3q#=XT{y(s7`if{E%RmM-wI`h z_YjK`leN?}%#xZNX_gn0MiWPc2DJW=;;Im(H{$AYvl=7z42~h37hGGYNzE;&MVRG> zyf8mbsESDj-HHfAR~u%K+zUcK>yMp`mR#1dYM?xFqqN-p>CKhG9&Ke-ejZ3t5fmGZ zC2E@N{Q-|NAm+2RFUj$^mHh7ds8Jw&1~~gn)AU-S|C?`Fu^_p=#~lwjN(Um-$_sNY zc@cK8-OF~Lxcw@C$fk8z9u;U6Gy*yDAxkv5U<7dk4RwAJoqLq(tR6kQKMgLa16eIT z*6CRyzKb^zLVQaUxd&rO)N2?aXYQ0l%(Do3@a!iOyqU_d!-HH*RLOKguam#z`vP(W37&rp9&6m;ZN|&P7NWO*VFHlE|xYp zlu}#lrvWwH=Tn0iE{uhq&yh?ohhO_bbptFK2>ZpFy)3X!Ebpb4NBdA=c)g)wfq^6& zY-E4R*`s?NK_XT)ZXxjxDr{Y@++5~rb5Q<|bhqJ?SJ~kC93QEhzG>cwIx&`2SZtc^g z;_TISzxD*m5qlkmS19tUF~i&FS$VUu>`dp`JucV6Os5{gb}glZ+pQp%*tM8=678H9 zZ4-}|r(>%&D2Nlp32ul6pN2FZ`yGJPav_GU>5=TBcr6>CxXSk#bc>N}+qUk|{3V=% zZP=P)g7C(Cq(OV|&G-9NeC`a2c41?nu8KcJ;QI1A8{As+2I9~g!0|Jj`z@9z5S}+V z%j9>6R30O0rRv`eMh|sDMBl!= z$%-3z&{L(Xplgh7rkfe49*tIpT%HhhqQOvUS|5fk-i+Wkp&ie3M9W9p_gAP$$%F(< zbt11WBnBkeD9c2{WiWaYa)&Andxu2d@iCePOU3YuHi{`7$JdHEfwvjqKemA#Tq>$@ za|64=j@GCRaVc;7hVM#9`rSX9V;4umtVCSHt=_vl>hy)7pa!O!IhgTmt}cq#XH6sY z)jMyqCmZ#E>1f3HpQM$f(a%P;r7}2j2}j14sOjFz&KLa=`a##W*$zG1E;N_bnGIDM z{ms69{?Mt;B#ro*Y9@Tp^`C|Et!KPyR5XDGX3ca22Wmpsmdgfol8B2) z?e?GhGHozs2T%9dtMWGO`^ySe)BOvwLIxaS+f1$3(1r~wmZ@yR5`b~R3>wP>FYAwV zx4aY3M_SM7KvFec0OSAA{WjJ8_%%b1Y8#|XwD5q4s=M^A`=Q$m^7dXZo65`}I$@a0 zTivhjy6_bMM;3o7*T!W0kL%gD^1RZ<+S~5^1uqbU&LzcBy5%%IFTRo-Gd*hjJ@D)- zNG1K0<0=w(BhKg?&$^bLSK(F6*uwL!T$oCG)=*5y;?+`Df86{$|CTZVJHpT8`&!yC zB^Nh17CL39K<(&WJA5NY}{Ss<7NxIT<>ubSCC1kGvw&A@&L$$9mmR8R0ilVSA$z}==(`r zVh$WV;hcVtJD&SJv7Y<_h03&zSZX)JuUROiNOERl(AFMF-|?Qu?1B2hl3$GUhO%q3 zge~}o`=+DJUld}URX!(4`hmO!J$`k=!}tHe@`E$Lnw=-!toRWXi?LbUMh;xO=Za_1 z$}g|KyI=nws@{P+v#tvk%@fW*I*_H$Nv-_Wn1Rj9(~XB!?@wE9TnQhm+@#6!HJB`~hmKOP-D zoss^K^qN#+FBb~ibfE?41i>(j=tNX9VO#l3hA#txkAtp*?HY|1tda?A!*b<{0&hN2 z2ZM${D40glBtzy(H*m#*_!~eBuK}p!qW=0X==efJ{HuNQv?H%nKn9i;vQze(g-lv) zAEbYrS-0Q}z`)6xE~6;m?!8=$2aJj*#Jbvu<posvK_q7RLX>uQ z)%+ks?YxA5*j&H;^^>81VyP9H{D4Ip8l$VFjQxXR?<)&#?rz{$AffVCz|#Q-^nvTc z<%^0zz&&gKjb=$*61nvda6Psd5ZO+&z*7h zTC6G=vtClHcrQkf4Pm0BF5HxiT+ZuYmSfo9;rveq~GmuNs_f(Tne{jIG zkx>6~<_0;du+Hya40}U(FJP}n35*hC4L7XgVc+0;nE<%U-IwLHe8B@x?S22|TW>*- z!$lkcF#xngDk_FL`X~M5PipNX`tN;TY=l014Tm`sYZI|2u>^`2)4(wW6CVXs#T@hQ zSaaRRKc=?3;>uf35a0k4NiJN3hu-Tc-?m>4HP;{4j>wJjm2jth4%=_ry8q69`>5Ax zTyQtSOyzr-FD>72u*1*etv=y0m_}Vuhf|xjMaQ+>n4mt^DZ=M{aloY9b!d}Q$oURH z?T^m9T|uD-Jdb!A8(8WsLTt!Xk-s|{Qn#&^ki%M(*RfM4)pjsbVd}BE*f%Krd{JO3 zl*6Yex>GM1eDdNW^DDv)IdYO@w&($DKj~*g&zVkl`xqkWbj|g8=h;}iD!;g5sL}f6 zBwn!JT5%&?HVH;D`Rvf2wy65CC)~DHPM~E36I}7M5@mlG zRqdQx@We~|qRC==jPdj=Wo)f%|5muvZLs8e-P`#n<8L+>Wz)F;cEHtKFRhiF{^>BV zYl=zZTjWK`mA3ovK!Ea+GmaR5q&K`cyDUFrX&!HQ59j)0eL0vmq;<}jKoSN+56C)F zb*_IB_}#MjVAF&9YwzRn`B{N5L2MHwn?n9zL^%vBpMzt z-3-?CVSMmMC;({%K4B5A+UEQguZZnRp7YPJwLxQ6kD6U3}o*tlQA++3^Ev7T zTG+kV?4XU(h0zLJJpaZR-JnYI-Vo)Uh`5asaBCew!NXM>O;*k;F; zm*+R&KTP->%rR?x)#`s>05zUR*oIG>`&{;EIZUtmxpS62_V~G$2%uV31R)zVZ|dy^ zJU2UfjXO`I+Hi-GF9ZAj9Z>vh(eGoGKdDtPnG4pwxcV)b44iC&;RTyDRha{7K+zW; z7*<;k3`O!;o%T2K?NAZb6zWv7_4l0oHSa9OyoXI}6z`^uchfM*13Z4_6BO`cXP?Nt zt}pe9>r+Kp%-ROf}QcCWU~7 z;#)^UhiP+7cL^KMSSHyX`o#2SU?QqxvaiT(+J2hBQmH$|JG7p%siy%wv(@ zn0rv^jczv|W~LA@2V^NyMQi{cLg+KOb(Bb?;;=yRT1En-zR_mn*XGl%e8B6!6D7kl zHpWTr!5wYR6w?a!8|0$~Qz(|JT?q~#XBQ+9G!{#Og_Tv{j_WE4$AniJ)j&b|-pEP5 z`t>OBZGBrP64~cG(Ble}fTup4hlR`1##_O@b~XA%zI)jV_WI|{3{V)kE3UQxpcFAN zz_vx)A0YyV3ur3V{LO2VM1@@6H46#y1Ut&eXzq;dIg2ro3E!Y)CPl1(9sG`WM=?X$ zNu5DiglyzGaK2M9n1j~>J>16P13vX0%eAIL8{`g{N4vkfos4&Xo!3n$oUJMW?>=6r}h5Y<}$??VEt!enxEa-wQQDy5!-RU^X0MI95*@- z`*o2?s6w?)^3xk%NG-^j^U8OLJI29h`rt&`^P;^f>4c!(7JSAuKo+~G;?Kv!f=fOj zf!g*<7uVI$uSoCLMY53Qmf|FLqwGaZMZ>|zF)Mt8!+OHzixa2mEA?q`6?uwloe!R! zMpcp0!sjts9xKQxm`qx5tM)K$k^2wQO73$mu`m+2DdY59N|utmxiu|?K{3hNO-)k_ zLAwSytDrBsQp&*fK$euX7&7C)5)Oc_ZM4)d4B0SMA+q6)EyJ?39BeV4X>hnDvcX6%E?N)OJnw2kInqBc%Gu1_o!aJe#EXEmLgw>x-14zh@m+<^9J8y3yiolW?xRW9h4vBsf#c$ zD~ALmNU{Oqg7|y7z8mvo26YC3uC)?rk8&6{%SHJt)@ySD%Er_#X@xS)zc40^B}-)4 zo_@Rjjypk@>uh0lqpc3uWMdws%9i<)-lt!*YawfY%DqwbzcT*S<;W*f*rAi4OcWah zwlu1{^^pWhOn_+M+imZJ5!^7tAfsJ)X77^tiVM2Ev&O~8&XZBqEhKFBBnaGbvV%L_ zC~|dfc`gzNc9UuC`9IROGF@#2W_}&6VI#45E5F=(LB1k29FkNIxwJi|I%f$#2@uK7 z>#)R41|*#yvtWTBak;OQ^UJ%g9TtG$;oZU;(z6X`?E$J`t;STu1sZM!!=`=>=8Iu{ zBBzNX8nu8UajeO*Vr5}AVWa$!QXpQ83a(Tk5vtP4piogo86zRU5OxW+9T}3#^5SmI zoS9Qpz!%W9`qzFISTBRk^@w9UA0~qzluxO#Cy2q~dx**lBbrF@u2c@(6!ERyHxb48 z1<{JuFehY+3l-z{9>ld|NhlD7!LlV=nLUSSPCYg*B|5D$a!zhnt-dRPklks0G3fvL7YhV`b7M9o%bBo!z~9gSZeEr@5p?-%rFzbgc{W?PI&<>Ah5JVopaxPi?+ zD}_C;5XKS|pyc7Q9|jk;a|b|>Lm%RCInGvGVJutGM}6%4HG#I z$A@dZz>np8;|ZWp&&z~Qqk_=JO_XvpGggR|opgZ!jr0vM4AC(z&0mYg;nACES{1${ z!Q#5MDi_W0B)bA1ou{K>K1+C-LC~|44aIqfPwO(*!4_p!SH$r>`oq1k7=P(ok83nG zyG@;m;kHlf-YHu3(z8}^YCC5*tddjZ=H`JF|4LAx*!_V_2^w##05Upzdvliq+Tu*j ziKa~HT)4?{%)-kSmk!%Y{ftIn>J|q#q{hZ2dfk4H>5XaYZHe;H*J?rwDPgMOnb~yVx3S&)~hg4x;EFBo-{&@y-DMZ3F=!|19A!Bg6_J;DgXGf zpE*gk`X2k5#AZ)=zb>q&U{p*im%l)xJ1|mMd<@N(*N7&0J`wV83?b4juS2+%Ac$oO zJ~B!QXRJeN>~yB10h%!R8S=C(x9j`tEca`~i}bxR*tD@G3H6t8H_1&uq1?sD^hb2s zCG2QibgwMd>6On_nJfP)I+Cl`Srk>iT-T@Qkb#x@(?ihxeDPcnNf5#^B;#UhcKkxp zvCf60O4QNvnl!Qxq+S2~F=?x)V1042gaxLxlT#+A#{R>iY1?9qBEL-p82@1yITuI? zdek+Y7hm4*0|*3}#&PM4Ly_KwYa|AmNYoTO?a&0LD7P7iOaw{|H+t?1J>L{gtOt0n zlH_tVe+uLJsN7H#kQYS9wPgujkISMOV46GR)JA*ok@J_}=PTS=XEs81rAzjmbk zs4>%a@AzU?y)aT-cYcx^FVF& zY=qoyz9Nf%pJ!ZoBf~is)5BxOz|-?O{XAh={2s8wPPzu%CTAp*N3zYGb}y(n#C;{g z`Atstd7yjm8>R*>KCs!4A_j>vOSsr?&>w}F^@p|c)M#neVAPGWl2V}|=J?dk|4Mov zc?CPQ@?hBb*;=zjeM;=_rPwB$b+J5_))CxZy~T2`Uh;Yd(4ZKEeJCSAMCEY^9(j(2 z`LVOQjl12pUWbl#%=7kPvE{gKDE~+Bg_I=B>8Z*Q3C&&41Mr^f*$GK>VcqCAw^Vu574OBsZsOgU2%-Stb>049(jD@P zownXogQ42sxB9{f?wv@t!eAarsQT&#c|W%}xdSwap&Whv?6XPnF4+FE%E<9^KqBhd zUyEDcj!AT=gDRIokmpV?gZPFT>WnNV@Dj>NT6%vuZs$MsQ&P>2Tl04C0Uew}@4e0# zz2qa})A|}dUFX(^@eUMr1745%oe`3i=QaUVu)Eyd@T%7(cTJ$k@N~tx8A2<@gr*2Nx z6sulLX39fk8Y$C7vu1%?A{=lHPEtUZON9kcIu~hE5;{e=rDz!o_85$q!=MEnj+)ip zBfR{gP-{F;di47s7GZ$SFIGXp7VUThJ*4b6QXa2oAgwxQGvN{4-Drh$xe7||dU)=J z-{^zFIY>Dw=Srnj0F}nhj7EfjP5y~lpScpT>y`5P{#Q|z?RfVOZ+T{d^Up^Fyb9Mj zWggc93g6QkUF75!C)TS}Ti}t~6s7k?0~Pb_>OKd?2nvKLdql@Hf6&nw)YC-?Q@}sl zhrKsuM`?nHc(UaN&9QzLxF5BMRfl2e4R0stX%uq>>4)BW8el>fW~tOkB&o+To}F#Z z)6OLO7BI4;Z0P(NI5=8rk!WZx3cx#;uzR2LBkq@PHTav zIgf2cy1Cz-&y+9Z_~E0vuT3O7Vv`~?cfuLn&%&1hYKTeE(BEpOGR+y_tl%QOV}bNs-7r?cyMUWcoaV*Rdq zc}u1qn9V508)@&<(@)8&_XSJCq8{G10S5~Hu$t(X`9heI0MnZI_umG7wIE}cUCkNh zAT^+F`y`qC)LA47&4$rcl zT}EKfW!Kwb-t1U1G1~SZ(4Lu#E}o;c!^J0J3>z97tTWO4Zkzsz*?gFYVxC8WZbku( zfvSW@O5rZ>zZ|Rzd7nItVlK3QKtj*G8}`!@p77P1mZgLlCs%vh;kNp4{dT)hkqlyM zKN*DR{9y3-CGl0upucyDTE%%CU8AkrAQX|@=wMXN^gw$)W%xqtcQHg%&_j^AtTfaW zj7rcKEI*!BtMY;B4z$~lLj$JXd+Sv~2Cm)9mfYmbK@8b~dx9pGsuOUQ72(GOvup@N zRthysTTx7y1Tbpa15)UAVAfMDv=Tnw6ZypinFX{;;<|6ao{a_Ogh=F z0z%}!uE?&rG$qhBtRt0;g`m;A9*dh@g@OA?Nx_NuDrODbl>mRXM}58}1R(3bFR6t+ zdq+4OU`m``bJqi8L0R?@`D%yzKDQu#WuBIHJsF7*!#@}hl=iFvZs5a_+Dip3Iq!`& z=X!i$=s*V}lPeMXOT`(Mjde@)Llc549Z32swJIob=tEq-Ppclkbu*fT8bGH~Aing6XT3eiILEcH$dLRR;@e)K z=;`O!MAr9Gw?}dWJ)W4n;q2d`MyE+FT)1ux2l z9=2>D9nwt3QO$UkeU@e#qhz8DzgV@*M#~A9UYw(FK@N}SDnMdAxw74alKh#~b^75r zHXR`38Byi2+ZrQqzpZ&nq4s&;9sWV~(%*8-Ug*!D*xcv~Dc(<=VZ+_8FX>L>jHfV* z2lPu7cp4_&j!Eulbr^QgUpw#s*xsEey%}-`L?b#3%!VoDN+w8rA!{(^^i{W>Zf!;B zgVoJc@IwvyB%(CMY(S$){4(R#*1Bn2(};)?36#*ypa7+F?k~j0Fl{V8cF`80Vi~;Q zH~@Q7(466R7Jdq)&cm$OJzbcP`Plqz)W zS&8gmP$BzG=asMxqs%WrN;+l)Yl^9vSc&#l;>nO#CoeBc<&&4qc4M{#B&1V6Cg&HZ zpz}%@1?o6`el5gmy)mAC&sG&}01eg$pIaow{G8xl_0K2>iIYvmJxm)Ih_kUjN1XV^ zpOOKO+^>Hm1w+ToaI2aN;cHdkmj+%!J;O|Tg}pGt-DVKdG<=V9`Xgvd z9{S>r9+!__p^8ockkKMrWF7M*qVs$VtNRhMYbOdIM~J*sD*}GQn;9)n%C|y9BVy&q z;HuaRl(~y1dpo7L=;w07;rB*BV4tE=Z)oCVD14#tckJ*YI)>gC>#GEuHto=Ehk^x4 z9Mf65;>BaALcy0p!tQPtnIxOQB$0mt!)ew(CM>_Q{ND$j_6v&rZ8n=RbdfxizNGO{ z-3b`$0La<2%F!lPD~Cpm@%*i7zBOS5!^2r{t|kNeQnl2Ydv0KpdsAw3jO^px-_;0O zB@r@uF~uASYA*u|rY`eq!N*Zjx9+DuxZ&qT``=4*{BbtFfAq8(evuIOP4pOSg{hU} zn0}g|;3yI_r$k?Wpja#tW;pXY3($4zAN@hQ>~58WG4Am)57Rmd=%3fur*O9!SH(T-hr$)gLlTle4z86Hdn2KMdY3^ZvsR!@pl=xDQ|zzpdqh`Ti~b$KSU27wv$DdR~nKqE$2D>b65SI z_Xu&d>!0sE~23_Z>(9!$45zr~;JxE6!@?b1*UWW5lk?gMQcnrvfo`q%>GT39o1SIh*WojEHH?*Z0t* z2ATWEO*0hah$EZiEd%o_NZ*1X6mZbGZ$eIs0*%O8!O@%tkJ<348V@!M~w4>5`h?l}aFfztiY z76rLl2oLNlZxK2T@}Xct$m1Ym)%bjC?d-RwinFe@)=T_wm+1B2n=m zmO{}%2fIzd&XSX|5P<*j>f$a8tw|(o(+*D2nJriqqi>Z&GLHJWu~<^a%ajK@NG2w~ zX8SepcCF+*YZCkZSNgtuL6_4Ky8{)Qq)i@atx!GsCmXW{MLMmSC}ZYZGz}++TQk z3SJWGCgZEx700f9AD5JgNw_G^Bn#_pyf){&go<{I`NSoI8%*5iCD)H%7$B)@CANfP zMwVUF@zmoysc|)HU&R{gpLaV34x7Tfn}5$})IOaRHax2tWVMv7NulzGEOe*VXrBuu z^9GdHkSk?GfV z5RnD0ze^^)*hWb(1CQP5`j)m79|>Q3#jvAq&tLmPCuf+kaoazfVtAr65-13BG71l= z=H~gg5l#iFN;<5kKgUK8W)9Y7SCcX0)fY*{H~MzuHY|UcS$=&RMZiY8YA*`z%Hrl= zm@zxs8LaUzEo06kHb~rHKV3@1{1GET8^iTKRj6Y;9WtXrdGd3;;Wu?6WBm#Q$3rrog|MKuTsRMD6M3 zS*s}TX;%VYoMhYzb)^Wi3u=}A6Rmtupj`6W{<+2&h@RPN| zjG;`-h)K{0L-iZgF>c0n)M!w=>&5GIYs zkWA7>5-s76HsBWUX{#U5bYaLiaGh52${Oo zdNWdqWzrxnNaT8_Ct_Dr>UXS-rR>|XR4K0(;=3m_Zrqa%+Sn}agQJ1w;jkSff-Ii# zYRpXh%%m?mphd;OBw-BT$7S>=&(i9Hp-C0cLnH`C*q{@)Q{Xxo6s(u(Cb9n4EADoe z`Vr2r?zlbdK{DM@qhn(Pz0ELNkLnwZ4Fu)Rj7u7JH@_qF#oiQp#N;a|{ zTKZR~A0&*`BzbiDr{3Q9f!-{s<6PS)A^kVV%`i9lSQ-vl#`GLbc2qR_YmQap`uEqK zGCm<^-)ug@{l*&xC6wJS*!*H`-7Ib+v$YFoynOb)w@ucc8qfLl6K?nKgUWNiq*%Qbg!92jjQOjqI&y-#SA|oQS_{IE!`t2$8@a^NM&KHsn3Fn+a0CFlvk)wmGVwG*kQZ#7qpq z51>Gdc?7A6zK2a%{S5e*@uld0A*`b{;J-FM^n%@t!25o?GVEJ@g>Lbfz*!Ip_L(Ms z|8Q=LWsRNx?oBili=XWIyn$|yJ&3hi$|+;SNW5InEE{?kn<&cjU+RQn}A z&_qJv54T+|W#1M?50p{l(#T`C|2PnX)=nOWkBvc*z28VTNETZIw`>{v{+=epJQYmj zz(`O!MRddVN41^Ig}E%41E@SUKo9gkhZ6 zVu^dfRZyT>19T*{FMuia=hM=%l5876N0b2v)SDAd<*1_UlkvuOP;I~x*j}YsBKK=N+35sJn(om#%KckC7qgs=;rRiPPC)})$U#?D!$#v&_HPq~)3r4R`Dy~&|c z#FR|RjshNThH@p1^15<@^TgF&h21#hOczlK`( zb@LNELcC}8hgNagjVcIF1W`JY;gssaQ$I_*FXoJaM3lfP*g9}MGvU%rgSV%QiCJ_-aATqFnUTQPeb zY+cZkFrVW*vT6zINfS$wL@-!SVpygjgtRvOlkbp=#g@>r`w{JzciK=F4v(Isr)?eH z4HL_f-O9%h#V*UpO3r$Xb3pWqrQEol*^-3;#ERRj6&(TkXfiZ#B)ORJd}CU#480 zpPK2;?ANTESl%q6$=d&s8P{9xmH&QuPQ^a(uOI9n&A-W6q>Uf*2fI_qHC$q2{1FX? zqa1H+mFVb!Q8l4SC8TE6{PN~l_}S?4YX$N`lMSS*84H`@WU>ekPei_S?%9h^PS}$coO-%WNDj5{sukXO$ zzgHJ|;~hp+db#b^V~hdhPk2cD3fI8kiRd{w71gF4^201S^}VUvgZjC;_-RVAnQQPp zW3ojN1{47B)XcgSs2yHZhr2d0JUY$Zh>a2kw}@K!Vf2y(nMq9!zuR3r6%6>(7Y`(Q zclut=I$tr%nF&g%3`T|k$c!N_Qt9o1!k0{pRFkCu6U=0$aI>!82zMNM2^Ed5@wKCN z&LRYR)r3kMu^k4N0c*7r~BeSEN03roj$d}m|lDR!T7MN+X_4OL%H1iCP%A>=^) zE-}5>SPqr(&vL)s5of^TIZGfE5aqIW=->EImpjcaWwA@VU8cjbc3h(W!Kt}G>J6s# z=EI~v&!k9GK5K?-h@J>nUr8sel`Vp87@X8-%1aw;MkN^}b4o7JpZIt7=h2cgc>tk-A? zpRBT{3Gv-G>5oL$oByx;BBn^EBDi@Ovr#M=L9#`Y!H&XqKjv>U__QsuDe?=C)zuVi z65{!_I27zBH6T0KYl}?WW)*BY^2!yj(L79cEd9zIiA2cVtSD~yY2bTyG#?)-!ZsL| zPj|zNf|HtH0yh##9X`GHg9Bt4LIP&C*&&lVYR1^M<)?`4I?6ZZY;5%1aF?;hZHm<} z$lEqLCKtirH9Mc6#6HXuPT;Pc8*&@GKK1u_%n#`6R-)<~) z^Diq!RX*8sJ!J8GY*cHaozc^kFuH^$=^b~Cg|sU+_2l_W$~#crmdri*1%%T42mQQQ z1c%aLEhWYLh~{j7KLFvqZhzxt6Ka{k4KkRd6jc|d~>CEemdcFWg%o#108c!C* zT5HoQV?+DHr|2DNb`sV*&PkXYYT5sX%>1H+SWIAhQP}kMT=Zfk*QrYidKrF!*f0zFe$$^l>2yCFOgDTJs;|6fpFv*qza)RKe|jFq=;vSF zcDvbtn~~18Odtci+}X79mdXA{D*5ol&Au_k^m6*IG4kjutxfi6s%wwieY`u*j{~5> z+i;mV0q>15Ge9WFnE3H}TfX>NtD>T|oNWy^N1rVoU^#{sGndO>cluDi=3aotpMPYH zRRB9I{LUTpEn>%|<)>RAxG?{e%r_$VBiM96NZL`hqJ|T@`XXH?aT^UWqFEVd)ekI= zHXV+ur)3uc_|P>L7K77nSS=P@i9n1KtZU!r3hw$M2|K09J+>UJ^};|gJz$ePhBEcu#5t~~MS^$@;QJzOwiS`Q(;bbZ zzc#Z#&YeBGl=;C0bDnFlv`0+9_n91*T&uVcMh;DbSKU%FG%m?=dgZp4xbw z_v3`VXX_HbMjWZ)N zJOih&xIp4fE`LRZTc)U^EI5nPzWk%h-9$A`=arK3Lml^-qdHEVSE>A*QkZ@mgErQW zl0No23jv$gYAdAkZy5nF%2usq_^p9vY&G9IrIlTMv7zf)lD*2UAwca?+{sKAEtjv- z2T*^9L>Ac41Du|iK9GLUra{fT7lqqWr)JV2g8?MI!GB*cwcMA)Ng2n;ap)Hm&jb8c za%xR{@{CIyv)*7Vnq=Q3P)x&n`*DMEv&b~5$c0I52t=24$*a=Y|J@S8Vl)t;{_VVhlM*L872N`doOvK;Az?CU+7k~M7*$~A zEd$G@Vs&HwD^=YI^;@fw5eV4YTkEJ6Hb^goBD^kGE~2o)meDQ%(?G}Jgp0jsXLcCY z=*xR^cbrd@N2%FO9Be;%yZgzEd&gAQoDc@gt&un5GVY- zHye!=^s#}_c3&BMN`=FQ=C#W2ISqK+xZhU3OCSsH_gP@i>^J5EZKqH-@OwAB*1{4V zEj*4}l82{!+FI?4Y^vecBE3L{hJX)rQv=IsGXxn_^?^^LwEqlxs~u!15D_*v7UZ_* zlvezr^5&?+a9FU&)I>mMSlvM1H$YccLH5|q%jlA|NyQ=iAX^55lh46eu(?xjq zX@`^7q=ZNXYxa8q_ve)07uqr}k8Hr_NJPbV6lA@{!)+d1f|9ZC4oEN*DzsB*>ueo0 zDtTg6l%g*vjH#*hQ!R%CcCu(rd%T%Q1NXSRqD!;BXwFzLmlSKa?c{Id7G>xqcG;H2 zEkjx{YT{ToNl8OCilx85d8xRkN#u|~4O*2FsQe;QPz5<_{yt7UIU1!AovopyRTXjU ze4B~>PdgX2Pf@MGR`t|axbVboD{LzSwq0v)>IBDrOp7RF16K4iu>ma(-*}TstX6mW zeHeb!>@T%8yOIxG9qW=W)Rs06Ax~+5M%wYvq~MSmfg>y^-fAu4M%*;5lP7Wwy^7*) zAXbv31s@wu89xLi+_UK@D^NI_?iQsG!qGF{?V(gZp8OuZubViM4<&%qrd9j`Z z7n>$ulp@SZ6;UeFsIDFgn+ywNjx#V8Xhy&gT&|jT={-7SXzpr?`n*dz#7%JiiW)%C zndV5~O&LcGHw%&%^)w{NL%M&SNa#-Zyeq`AR<)$MS&Opu%DD2}eLJJu^^e`)YBu#W zfwH(%P$g>pyvT-sBx!!c7=URi<1h{(Sq%T_)&PpNq@_G4jDlIlVi}TFe`^K$&Ziu@ z+>W|OpLAd?oCb^^EQ^Y|!)Tm&ej#lgp5t%;30CDK-=mPh07eBKiM&Zi*+o&;IxP*_ zCfY5nsh8apyT$1@l>6=jn9R!bhFR&2Zv5GMdxkOD;DN17YxE5X>OjC-Fe%S>rmMmI z8GmGv+Rk2^6trXj)^24fHuue-hfjvfv?TbI=6oQ_2oQ)Iw%|US9*q`Q> z4}#6E?}abtlHyD(8eA<)WobNWpR4#el@-3w0^l!&pkky7*x&IQUO#;VkexSvKK>dt zo*9TVuiP*Qs&A7(hGKO5Te5oD!686NF9ZduFA9am23OjU5O-@Ju47qNbOm1epV)9M z_Bis$@N%}yPj};TU{BF3)MCLsxuT;ZVytt|x1Ft{~`Mmc3Yp<2y6LUUl zd8WGi!b-sH&iikAd49fq=f}UAc6jeIYgz*8n4k99)suUW(jIYUe}W2NF!3ehC*{a_6Z!9b4KZPm2Pm049(^g5N& z)vbQM%V48w#}k#)Kv}HY);kt{2a;^*5+W0onRTn^6IEN7FpW!}ig5I&4(SjcR!k+W z9NaPSY+LpV@|W1%kAi=_YqNP%#x}g85;xH7Qf6K^Bdk%ys4j=kaQa^*6BW^|hNn#S zy&d*ZX5kg(M0P}>IXlt{vBQ;2#xi+ke|w~8}06QrO~MBi3podq5$<>-V4Gy3h-)Tphl zu2fDAJ}0%WvG06gWIBp^5;BGyNjpP8fB?RYVlkEQ{2JA$L+@SRCC-h-h3LM`)8|{d z&`Ke8wzfzIKi?5o$GDsWQqPQ*#4l_bfT~vl`l^ zU%$Wb$ZM+rN>ONOZc9=^swJxg9G{h+_Qxxn|0NPDt&eu#mwU`k zAC*KFPJ~u0dght-#-|gRW-ftJDtTi8etnNd$bRkBe8#Wo#r??6jZL&oG^a}e$PvSk z$%&w%c0c|Io8uaGMO8z7ms$(4QnAAUF?jD3E_lhbDH`<3gt;MwxuOXvH2ue~Cu9?7 zn}H26*A$1opvt=Tbm9|9e>;*$z7vW=RT7D+Z#;f)G+0D+FwW%b2)DD*5Gpl!oKoBje^@xTbRrws0dcE>~XnXb+O8|ytEa2#qvN_Jy<_*cLD!T9}iK$NLL5f z+Jtq4S6|R&tVQh`VlZDl;@WE=`|oU0b?9c<>b&wimql~*OpOPm@92!lIaR~I^NKBU z1!2~MkW1iZPNZ(=au~3HLYW&ASn+idOCot7eolx7MDOc$?}@=iuNRu%*{x>E2JD3b zBBFO{fZfcx^UugJ;i1W{uYaBkw-oPxs6Gk(j_G!X9(y>}R`JRmg1CX2^2JPo5^oFC z+WlHPu#^{iBc6R~AHv-R%Y>Dv1w-LegnfGQ^RKfRiwnL0h(Y%HW1oIX7rT>shDp!a(;)LZDLg@hmK}rF!Cx)ERiqwv)EkM9nUUx7( zt-$q$+b-2Mqhf0_AnxkaLE>XcrkrsOB_EubO+ZZEo`78ti{L9}u+?(c0UwD^W+>#4 zmcgW#uqVp;h-op$jOrjXsrcC=;Xg?4jg3C1{WY3Y<->)lkAEy`ob&C9Wxk|NxJjUW zH^VjP@Te6jO_q6%Y$e92GxS6%+eBekaxSTz3nLA z=5JLao&sI{1Iu!MNz-8y&Lw5t1u)D8UHqdZi_WKca6+}u1VSX#3o}ED-3pa`NxpX* z(dcsXn5P%xfBd|-ctDrLITIfsmPs3N(ckq+%|mi(E^aL7Wsh8dgC1q4P@BIgO0Y>E zzj;|2ZH{j`HpXAdlw!=Nc@|=diVlq(G0`YsnQlT6sDqhj`EK9=wWWW73uvOl(&Fiy zF^nNDTpd&7EVhYcFGP8vxPtK1hkqTEPDK)6U0}3s`*>6pJcvv}+457O+{u8<<_-Qu zOfF!TF*wE(^ZYiz#ADOd)K-FGC$o>{%k!_`3kUR^^}D|gN9WE|!cCLPND^Y( zF+-edaE1=xOPibQO|&*g?se%^@+_Py-MGR~DvNI-Mv=I6QW8V7qxq7i1;Nc7?`=_w z9$%O+j=;fLANfVT^YxW^XlXUHFtgU;m;+g^aZA#q3*d6J8%R9xbfVK@<`xh+90Jbj z6+TB$HEJF>v0YFJDJKMB>XuNtpyBQBXbt?e0lA@Y8OY4kEwIgqW#QD7?&6wRw4UBS zm=rfx|7i$QOkB>_Et#f4`+rS?ICc@qfn_lgVzpaC_d;?qwGDTh$^94Pn%SAn(;CN) zTtfe2bKDX4&Xyk>>_}2q?EyB-a>=Z9hc^Kb!!sjKJ71LQLN>O)&Qt^b{jl5akb8>{ zgyP~^4l#hSd*bDkN-($@(dsj)BC=&-LIAOXA3_*0xY58$5@qFa_Hx!Lur$1Nxj3qC z!C|0>X}D!E{(opLC5#Jw%lM~4O%ljLS;64k(Xe&;{lLMfNs6RY1d$l^#t*B`Nk3@; zpI=iEey|hdNF{>=?KP)^zF+}bD39O2s?k}S(n?Ou$#mFL*`%mo#HMMq_vjccD3>^~ z&Xj`t8NW3hup+`3^g=+F0sXMk))R&3U|llz^*gs^}!AuuZo_kyrpq)7`My$pP; z_vwIDL&s^A&gSoFkjG9rH=V4FWc67g0QW@qgqP*$9&`hQFNcyJ@bVRy zx~EWXVf2;yLtPD!P*S*zlQ)GKl?Gh)MuOKbHat)kTu2Bk${mnmi@@Q!T2WBUa~!P9 z9wRL*LL)hzq;g9sh<`UUq!G!*$wMm=-)$pLxt9u&r>`CT%}QghVDC4|iiU=0gN|0Y z?d@E4mzsRs1-dvyn;+XyPuGPc@Rp5-Q^&cW>$lw;S1)S!QNd>5fUpnYuZ~&BzzNJ` z!`12G=&an=u->+Rw7G{v8L+u5O76Ys2+LvmBXvI}S7X09WKW5RP`FG7PpR`6Z}M&F zkE|PVHI6%UAwp2C!b3}^K_c4EGvgj`CeyUsL7uMCOIsR$1UX8*!o&E_fe504IlrS# zx5w{bX63I!1U#kKaSqCas1c%FCRLVfUe*vWzq2 z_8bY>a6j3jh>S9DSoOx0i?UuJRT0%_ut3lnOo6oW;?fF*CL}`HZ7=y@>3HL; zh1v{oRWp@_6r9*W(cbv(u=O^bJ0rbD{7bYB4XK%w8mJ&vm3#bYtd5q?Z_mV}c!`s` za@4{W8`aT4Vm$fpr@rNY}4x=w~5}i(H=&Rbk9sZwxSp4^>{GUY4|Q{QS52(nEpGE{OxeIC-Mis-Qiko{u zp;uJf$fvs78Fo=kB5=Gv6&zB8%+h)BqFQY3gX>ySgdt)9{#iNFwo9hgtWf!T@MMQC z(~U~X>avbKhtw^6D9)<^C}xzDvp}ih0nNDH+Srh$@QC9e1`u6 z?(i`*bl>1E;tLDSjT6QV{#>}2R9+^t@0ZEfFMvdKwD0#y<`@8#D-a+}VFJTzGou*0 z(B2nI)~;RHo9_b07PTxDaZ>F2H8J-N-sAROvXR|YQ<~{1an+XJC-lbqTG7!O3|Wh? z*fKzZn`qvyK@eKXtw8{-HEkNM_bZHLX*?tSFE&&;pQx?Ev#ofV(%l7?V+C$_tp90P zA~E_XRwOX-I}AYiD;{OPxM1i-O}ilH;l-U#Cv&=iZu1H9fOrq*PC7z4<(1ZhFFk+| zDNH(|$RMb{dO-I71MWZ(zq&+b%`jmC5+`H*awaVJAR-q+ydFpu~;m0X;dFz2vGARq97u$2Hf(Qzz4|jklS+3&K_gfkQ&bFnJbXkcZ zya*X94F)?50GLgOhmFmcuo@VPhZbV2wP%SK;ld2D(PrVnllYvLM`h`F;+Tx`t61AZ zVD>+|mHBCE!8iRRPWqdf!TKOTM#pAo-}c>f6_x(6V~6Sd*|Q2;4V6);>%kFg3yaCR zB8C59{J8-Q0F$kfyIwB#Tpgu@n4D4F*hxF)t}4mpbV0YL5s}uWCTuW*rNIap1yek8 z$^tpns4zQ0OqI5qZKkwN9D`1~rxQK2yw{&hfSE?6yMh+*%dfmfSVM#7-_wf?2Z_tT z8J70+ZwvMom_a{&YfBTo>F_@K#`m72z55T){LCa>Jb9707oZV4NnXA(NW;A3z&ei( z;*~qYa(-LEx1_JbhK!8KOebt!s4h|rWtatn5$f*rgjhs}zJ{UlBn3xE~nDn${#=vkO0v_kMJ z;DCt$_*tUBln)35v9UBP*J~u@Y3HCY`@ae+&bqs|Q!B<5NAN=H!n~pL*xaY14JVn- zOw;z=yVd?C%UIjLI=euw8LAV&Z3s;KrzM;qy6$uiTxSCSH_5-bTrROO5H?v(^7V8N zPcB=feLFYN;^YW*RIk!VUjEyAuL&DWtj3HCWCknLDg;FEa`DADKkIZP#X3=9N(MtA zhqV3MZo3s@U{&0FZ-XbuSKgJ`$gz3h#*>P%EoUw9#K;0;ZUh_rMqo&z*`Ue?dHJS z?z+8X0wzpDpa+eEOP8+@HyGIGuytM$&?J8O{lle6F;u|9vkAc(si?5NvH_oY>Oob6 z0{WG*sAxQt{04rR=kanG&`Dr{lk)Y@wnk7>SRT~Uc6QU3t4QI+qf;*5OG31xy>id%QNjX3J{4H40F+3dEb4o6Vv)< z=&Zrb!tln{PJGa;s>+|^3G#@;*fdvS$8@IUUvh4NA{bsrg91&jH}q7 zp#sahxG~JfHHuUB3P0!i$Ec%g}*<8YTrY5{J-+(^OZ`w=h-rh0{d43%tu z0`Zi_rwL(Bq!R^GofN>8zuyv`nVqL6o_UtqaahLH>9W>orqQf()^p%*AqTi&@HW*j zc+kdv{Nx$k7bBzE4RxcaSDwwUKbghU9iHIdu;L@QK;vb_Iz1%$QSiyvg5q=W1 zQlx{ts;sW1dv3p(rm<5g_b_&LZBX6+yr)SGzW&*9&hk5t8wIhe#`OOM{@_`6K@Pl* z27tave2zOe95cE zF8#8}vx=G%1uZNf$^to!s4zQ0OqI5qZKkwN9D|opT2!bm0P$JPJ=nUlOq*(~ucno` zDSGk67pS#KI?c4q-5(Q%=PU{(zQe3j>pAeZodZX2K0y5U$shlKN(v7laL>RaXb^ny z8{aiU2V8dDbKweiRHjwX-~=A2>g#2u5hxuS(qj7+%^mgzpe5PAQh{^rWp#b1B*yWy zRey3Ke|-VxLvy2M0sr}6XFH*Smz!&TB)EW)8@Wa$;)D@c!{-;DR839?7gsCs^?_L5|6Z z^#7bBgA$wUr!F<)d%uYfd6C6S-XtQto+4trZTi7ev=++ zHyiJ#H>5qhvVkADR)|8g9EzQf$dD)Egb^EbVKcYl+Rz9!SIpB}@4ACVhV_oKJhWMb z_uJ@|%jz^hR^kec-*nu(sjS72X9W(eLnC0_W#_=_=m9VWaW66aLd%#4z-5MKoAWm& zFYB&EWm8eBzc^PG!j75Ifhz!Xt8SYkJKN|)FV2MLa#7M10zz$0P}#0DHZ@fmpGKR3 z&tQdmMF1mL9v68X<`ysyz_c{g(W063GCVPda1)J8OuKAWaAU(pY{D_y%GZhY9C%~o z0I$s8-T~<$`0_U&Mi0TWrgs4EpX4hzD)bzTSo+F^DSk$N$P0rXOOD4vgL8cQ|2+$e|h98$W@U=m{p?+uA!rT%qg4v3F zGb_<7(60=mYjl)RWz(3^rWD&H+633V^&EJE=78!Q_|<=go`EmY<6rr6`o};03GA!D z%R5cs51s)8`1xX)e4Q&6KSA=3rTj0$8CCa;3d6?=4>g!H1lXGNJTT1=^ z1uT;iD^Ea9LEan67hM~R#s%tPH1?fINuo9YQ#n-JP*y(|2Q$Q7QLSs_g9nB3uAdh0~#?WqOxRzE&uYauL0nSo4ViJ@@hwK z3pW77@fu7nTJ`v=!e8|awg%><9B7d#B~!o#`z{mzjZ|-bODCi?o`vq}WTb4-7`8Tr~1!7`)4wXLed|_}ylirj- z-;5Rm5i_ko>97B+=fDq24jjGtApNFk41D#|{~5gmA5`0o#k1VjZr>TP+hle*z z=c%X}BdS7(@1U=j;-lwVD`#j0=K!2Le=#t}x1$*coK#_`fU}AJs%jdj78BA|an!GB zEd&~G%s^v9Ey-UUHdW(FzaCw^JjA=OT8$}p{;aR^uQC4QE??6_HezDg{L~C>L>h(` zxd3RVI{gvknVIbB&>EYsLU$FKD}3;acG@4nE>3m3cVPuVCGBdzfFT8<%kfSQtiXk` zY*!kanktP?qmA%UFvT;cERY8)!t17=pq62uZ>qixnv1O$Xm}dkU;+}~CQumSTY)BW z*b!txhP*>WmKV|MjJ#Z2k~CWQ-yK3Nl{4w{X_G>p zspBn#yV~_Kn^d~aS<0iUzaS*aEw)dsQBUY8UZ~SQKu}`U_0?& zg!08olrW3}^KZ1n1!L2)9;&nKN|Z%xP-s>ZaDs+i3?cE68;w4JJ!sn0+PyV_G|3M|h=tAJ2w>_5Tu8U&wR` zXQ7rT0rsQi2V87xUyb`4Gu#ftv^lyKib|I{u9e$wrCC7hE>jw-3I|=9|fchB~oc`WmJl2`Cs zu=^>y%@`xclmzA4uy($)wE-(r8q|@-%&bIu>#;uz?`TN8dVw8QFks^x?0YncN`4l* z7%u8Rtgz$F+*Yu>k?;B{_x7kRBUW0Qi>lu>C`;LZ%9Wu>szg@}JAKv-w+6%WqB|SRD$BG9F&0gezr0% za@^w}?+oLMrjK^CNMT2w?Z~7}vV{sEex$(clCBU?Qaco4Tptx-1^zA%=w*My1J`KF z=1$Tf-LuTg(1-BX-cX4T%u4%3JcF|Vf=XG8b4Bg{G2gGeeVSz|ubI$pb4P2!d)M3V zrk$HN(B_Tp>W{zXw{>>V?(Ln_+FVQ9J9z>;s=CTLs>5!%6Bv!1Ue=@Ub2u$;cBL9C z73S<0KUem13s}01RSc`ESV@O{5O^*F&!4Nrq)6@^z^5~Y1HeOi8=6|NQIZU_>vWd; zdqd^`a0R|FJx$eRPDNZsrs9&+7PZ{P%xaUEwYG`|flLkHM$Ks)EsWfzBYU<|e{Vmv zp}8^+zVD*@qwv1Gn9eA)8LZGwAwa_|%o3rQDCAI%iXfaFInEbon)5jLb`KyyAh6km zNi}uNE!5t*nLcvYQM9J7Z-Pl+bUm=118?vg;D!MIJ&MhSe&ct4U(XZp8v#t)7m^Bq z!My?Oyls4$!D9WxM7EQ0e17Kv??16x!5T995|da~kvQ9lfrJ5UY}2VLsz6+*ADPPy zqWgaZ-P`trHY8suIMlX-=YkYphyU6WzCTG}Fe84RqpcFD4u6Z|ITHNvg(h%>*{Z zSw+9Zz$ky>BJCLNt}w$mt5_DlvZ^m&24D4D*;Qc3dlg^y?9^T@NFP_`s?yg?bw}Ef zE_I3ERbs;5BJaA3%D;*m2XGbWUI-W3D|X?}bv6LF6u82p%0z9QYO&fbH&NFRAm4D>#s~4})ZnUDB8|&!8xgkoovB`}!N8r+~08ubiDghgFDSOZa|k)RfF0vs1i?GJ2p^x;pBPx*oRyU z>(qJ<{4nRh+wQ)DzWSN}q8b9f^y~jdZAYx~!#zp}N7yzN|Sl~ zRjTktU_FJfA)nB2{K~{d7OJT7b)3G|cHxLB5a%Q|GEyAm9)LTK?51ZPeF9(69a;f# z^JVb6O1=f>QGYI=BCV@h!I!geHGK1?4&qIO#O>L+g?4rCqKiE}iZwAdMy+jniFyrs zJkMU}qwV;bzkGF=T2bFz?7N1_xSBd}%<1J(>~dSNL^W7*IB;n|>91DR(?gFvhfC(l zi&Mtm<|{ZK2R*Mmlbu<-l#!PsDls=0P{~(eEMJy4s;_t6w5^Kf%#MXEXn?GslBfDc zpjXxAMk}kjp)ff*tm5V$ZUm_O#@Q~{v=(@xTr7-JN0#e9K_^+ zot=%exG;}Xo@6>3ZnA1Atk5N7{t?`eJ^MQ8{P_XZ(AI6N)MCofaaev7w0uhx0xVKJ zm?~7Bjzc-h83UEWb^;B^m}?xE;dbFtd=GMMqYDj9=eAAl=%T8kk%3wInUB5;hnCgS z@BP`A=mEV6dtiS(u$}`y>^Z;g$WL#JrrniZS)gs6%+{e0q8omGBC>)fd&tpgnz8fh6jM z&wt$Oyj+PB1kuYdGN~(1J}GtIf&J7sI7XYcY*P(@X`Dp4Yv(rH+iUdi|K%^x!%x0I zUwHU=y6??LV6B2~xoIDDp*P^ye)qr7G0-oaIE}CIT1YSn8E4&|sI{v5W((?!WIY)nKTo)YTt%&7XetIPF01 zCsoW)*EUq(IDF_Ae(tB~>6cE?zx}VDrX%}zEB(Lx+QW47f!*}v^Dm=;p&J1I=fD3$ zEZM83S6@4?hD&+!KJQM**|V_`WAuKo6{#MMh^XrTqY_aJ@okABmZzMuj6K?NPW_(EkXVj}D1AOMzuHlFnz5!#JHwhBK4em4EV6^vKgMsR?tZjz3Ska11)T+O{tG&UYW7?d{dn zH>N);w_;b}yWVsd)flfx!&fKVCqMBM^s#^R&(Q#=q58^Y%-mn0$)#%0Jgpkt`$*d& z2IDLFgBSOK+Zy%wl4m!EO1&Mu5R2&guf>pfYqOphKZjEYd1Io%ao!^rAGbIQr=_jk z(u#PUKNY;yKL2U=>l1_Le@z0Ve7<#SZvdc+WmRTlsKTKSooT@kfNlWzg*Yl52)YVi zWIo;{w*w8bDpYP`Q`pYdu@zNYk5M2r1a98eLdP!-E1TI?M6t9~Q0iGyfim&HI;5kl zJtlJ4B?N)G3!n%h^SB_2t3}t+!W>$V#_9b4B*ean+)D#5GQk$wbg+9PP4lD`v}Awd z7d}a6G3oMj-zc3tdx^#ed(ag&N82~n(@r!1zO>!|@H2ItUeAG&Iq)dX9QfIP`m1#D z@)bO-{Jio5=$>1rY#vNCmg~3yCC{!hgCDNA#hmy`AlG|-7dN-a``uKd!Z$sruHqBO4fC(J z0iZt^Z%8t*5e+I59_Pq%>9uF$eBBY$Yn^CZ@%qk6ULgP>Hv}rGYH=fGvHStY2@lQF z(LEhhgF^7^X+1GR+bFhgu?4Ic!@Q2jGH0ka29-d&sdY#IO8W;$}}o zcD*$1*w#$T7~db9UZHz#J4lx)-S{~7A;YNV&1e3E8oW~du0@P;u1oGbqw__*c@ zoZa5$B~{UX=-!*?_$#OA=q)!X{+FKXg+EQ-dXasim(PBNmYaCp89OY=!(nL`(Hl^W z$#p!zeAe`$E@GxWPp)5?TcC|wH_D8k#P>J{O z5GEQfF6puF8hq_D&E5Ea*WK%A0Pr1mj`t$2<*tyG8H{P5T!mr)6NXdHq%?kTO5fyG z+z@u0r)t~`cW4$9J=pbDw_yCHiVk;o(5pRVjGNe`SVGy!`*A2oCD>e1t{^d?7-_~? z99QsxHST}%IDw3{gkk&^-0dx0&G`DSry=C)BD$t_VaDs*Z$C`G{D1!mRW9oF6*K5j z7*V}dDyKa|Y;@hN=fHXnl$!&;{EI(FANfjKiaT;t6={ z8fzHKUG|sMM8Z`JlVX)X|5bGJ z<0Fd4@8N2>SHM*G3vYmmUnLqp*VzCtHHuh)KQ*&REe$o)gqGBZ>XJ?|9z2JPbiCjM z3PBrE%i|T?9Ake0H<@@A=ja3q3Ecs|P5=Nv07*naQ~-Do4s36wGkv-uvyoUkmaw8c z!XX_MU~|~|i42gX10^4Nrz+35=Hx`4YipIZV?3q4sZI5wOyOJr-aYGA{?Ui&_doj` z6oTiFcQ`j2jjC~E^qklc-z8(6TF-&?99Uxx96fx9zWx_~K)>-j|B?Q~|NAGp5s*B> zVDLk(e{y1AC4l6sUHJy8bVbeJB$(lUUm5|0(Uu1A`=_;?yW}fq44eCNRn5coKmYL` zq5tPEzD?biF44m$FoPfbC(d9w0RI`sl|Q@A_9p6^ouu1uK0pJ*qck-=X+K8Cr{{6T z3^vx`;p^2J6PGryi27q5-TUJ>Kuy;6Pv9ig>7lD?rGV05C>kI`L;53g!Bqat_Gu2k zQQUPk0JyBlhCTj;R%2%(&ct*a+DG{`7YNTqK~JK{akDov$IpeJ4we4`PJZG|6UH$4 zhPPH69Gjs--J4WB{94ZtPz6SnWgnG;&tdzT##FJl#){R=`S%im)-68aZCs7m32SCn zmS1R`pbzcXfMoJn0Tt->U!ra-_xr>L?^n9xGw9~3Uq&Nfo=#uEfEg@w^;BWnl|CR2$=gssFfAOEw!~{=XjvPO5Wp&2`$CW=jc}O{^^u_lD3`|{i zBOt}49Em8E*feB_G%H(|D}Q#2v(q#=ttZPJ-mE9rafN$ibG54cZ{39rcrIZ!J+O`V zqTk)UgGR=uke}nUcUL#{V9rGg4yQYf?c}FWfw#9cqr1MErZDlY`@qdA4)w7JYJ6e> zAFjF=c?xuME5;b$Mn>=+RL)MS!#n_aw;It8h<9BLfcm-`%+L?JpE*CqW*4zcqm+|E zX)scVb5$a|sKM6*184+b+r-8CjhHN0iyMj-A(kPou8v_##x^>#Zws9`*Pm(KS$0$a z%wcOxNnv0{1=d*MyQkWjQZahb@-~pVGYffuwt%ku`H^-GlU$W4&YND0dA=A@>jN0{wx~B-Y+|Mw9~^6 zzev|i{d)nG|2yxxi5`0T6wNOz(uGSs=(5M!dW_efKYx}wI=A8@9Xs-k4$4-h*VO>fnZ$QFbd}f*sSf89<8By1iV13{ zP(5EK1IKkLmwP^Bs9|DARfelA9ke<>t@c`89RLr7=IDX#)QASlldoJXwx5w)t&}S; zHY0D%6+Y`{$HDJ{SW=C>pO>cfj@T^YO{l`EU#F+JsgkN%yXf@543=o>v9O(6JLy0D z)%P%*vPgrM`_%ZBM#sO(a?D&0ujjye4!q7B;NE~IzV;XNzy12ZrvLC?Kc(Jdfk}S! zR3m`7{Fcjd3IqXs84B=NN=?G*4U%U^zdP*Q1f^pYvm!2!w+0hcsHD~DcbG*lj;HFi zwpLJ2&zPMX$+B&oRdnIX5N*P~`@DHh+vaX+!_YHtoHI3{XWK8#>-uMC2tB~&T|AC8 z_v5Edn=g5(pCq;)UY~o?*X)*ax((9 zS9!YH;|?SK8m^oi!IBW1sDw40lQ_g?rn-qPUF=hK?z&|+e18F*3c94Sed}yw-~{?LU+)9h6`~`-6Ce+SRek}Z`-;5=Gi**}lU|e@&@gWvF zF{Aaj|M*L^JTYjyx%$WEy{~_cP+QJwQ224I)9X2~o&&Eh2Y%~c{1W}=-}%41XWX+V z4|ulJ02#zjJ3qIM6qfZBngRJPc-{+pX2nivn~H z-F^3AI(TH4K@*)CT&CNP9>HY2c53R_LSt8ZsqY#O^&%%~v9Afn@Q2Wa&)xs*CeZai zHG|JY)LB2M-T3N4uk+`+dH`zb8fb1w#z(?Ju!^qfoRxqki6OpZx-HZaxo{p0XH@MB ze;H%EyB^a<;ZI^;`RHP;3c_Pg9M_r*D*3{3T3!j}DwuFzf;nX&|Gni=iy_YU2nf&mHcnjDw zzoW6525B=*qq~0!A2P9<7+c@LG|rPa>}r!(QYy@~hbm0C`F#J)UnM?Sd4nWAN;Y&J zC=`St3j<-kM78k{CLs$)0(1)&rxL2fpanU{lWdR}%=(;f#N-ZuFQD?@x4n&SKeQE- z-ki4BE9uMEz4#@;EcER&?KxlMu|>ySO(4XJpn_&iHy2m_f=APqI_g&G*zV1WyM!0O zG=^cSR&d1R%oO&+<}re0YHP+yfYoWWS3_>)kF=@%rEQW|>G;Vr^nsuJMf%O(`y+bn znU{#S++26-Ik27sHzo(vDuK`b0U81~nYUMDS3QgNfsBM4^kk~?N0?b$*ZV$0eXI)K zh#xQh*jxz_r==DX^cGCz&#E|&M{Na=(cWY77*QpA%GX3e29+Re2|)( zv7{OM15}y`gmKjC;o=;)t{#9zoIKRl(uhfSdbXxSGl9K(8?lG)l9{dVN}wPj-xdx_ zM1U|DqQa0xf-Q67>t-fskxwba7KzJEmB{UFSCR$WyCRSi_80qq3rZE+x5d^q0;Ks?zAFeH4w z9j#%AekvOUAb-BhJQVlQ^J7EbHZ=dH|`SzoOQvj#?YNVsP zS8DG}NNY!zEKQH&TMr+lIaAY7>8hcm1}f?R(C9%eHor-~M~N3+SEp zw>(LZj(e6oo`@j9yn_XT=uxh(n&JQL+BMj3Zj$=;Uisd|JBId^)Aoz`jZ5RU)3EDC zKPT}Vur{o@=tK!@6emb^^~!p11SD@7b*#^JYe%Ovwsy(r#Jn`~6bg)d7^_qmF?bd| z<>|ZEWfRt^%z4t_iw~CVA~*h>v4ib4cjf=)^}Be0orq_!_x1=n2J8@g{FN6>_z>b% zSJgmO1En><#erYJNI>yUKruOd5Zyz%PdWkX>m0MiA#cceD}Qj&#O~X-7KIA|f8;YS z;1}<4*#6fKyB9z4d06SQEB1LN4bAfUmyn^Z{*Onv-}A*yhC|i;~1L?I@jBz`4+y=)`E{C#lNf!4^Gz12Td6 z{+oB_VZs-U`|2tdy)4V{@UXPk*#!b?YwIwGu_?2D&R-?O5-t(}JzIHwwu3A6xC z6})}nlKjCR|Am*;+0lj$!6|du&H+0KL$Ksk?HG6^RRdKGI1OkgfVKj@^p&sbBNymL zA3pam1{fP8ULREWW*ZTGfEA^_2c(1mlUxtrnbO1+KnfU{-GD(iN@d1qqlB-R-hnQ8 z8!P|mc;ese?7UpO_<@`_eo!u4y=CBk_`6@0PyW!$rs1!_HgKNY7urNIMAe_NG*D3o zU-9y98c13=@(Qi_(fk3{#6bDNsayF3KWu(Lug!&{5_v(602tQaI;D@L6Z&uE zw|?jMjTT&!9zCOFFAS`_6A)9sjwop7B8Chjd=L2Ch6tN?pz1MPzk%c2L%NY>93_vP zO7FPFpNwZ=2xuBd;vPJHJT3>Z0$Q%~&%G$u|LD(BxGJE04OG+t;Fi0F<__t>evRoV zHK>67_|45&ow+H)eJyh59=^D9@)0!^Q7A^51CDBcj5>GVU z7U4aYAt0Q&&cHiDD@RQhIiO>C3nK=+{@{Ho<+xi?h~)RWc<#K zb~B=2BGsR&1|Cxl{0nRmeCxf7Fc@^vJYo8NFvT^Go<4tB3eaZ~Tx`7QlsxHsgeB8o zeHTPK10W}s38hT>nm`h68-GIUxRReAjBtmr#?KsUQj0Hn=lCW*;TrzG{MJQz<>M~{ za@AmU+?hsx@O^~oXq+DaV`tkKDXqHQX`rGG0F%JsW zzgER`L*aNM0u|-_TttE{h{jtkkI>z6THq~w9iyek;mlJ~-)Rqhcokk-hrAvxv_P}Vzy*%{Cd!vFM7|7$av5Xr5Esv6ke8u-fZ z{2y*jzy;KL-xS+Ina76D0;A?9qp&2(!-eGebbQ`?%K2oWFog37YjEwMMlVOIQT1aI6iB}e#~UABC0I6H zURr2nhlduy`qUO0%pD#u1ls|Zv32w+x|mHEDX76d)sX>fPas*E;>ox&_m-t~OK;~i{;&>W9 zYXCDGIgP~WBRoP%qQFp?!aSME@c_J!6c+jkMxac-NaFQkBC+?GnPT|X_vGui=H@wT zSanqmJU$xGH383_KWhr*o`84({WB5=N3np5LG}ki-xCIO9%cik)2%Q=mQSl>$rlCf z{nujU{{~-9&JE&2rK!DB-uI2aMVvm=20Q;pWC5=;yy{E?KQc6^Z1R_X@jVk>#meTL zE%%nhNI=!?P6PTuygM#XPhsf4f1nSe08_!&KK9{bD_SciXzaQ4LC-U{zT_gZ^AvBb zvT0J#cpB_oaz#8W0w=ppl_0 z=j6we$s!D3`NZ5}dFP%@TN(Osw!!2ozRvOR=q`&j?C)R3BADm!a#)zWWzI)f!>Lx+ zu^S-y@Rd}X$&ThpeN8>-1Mle*w27#F+d$b0S3f2a^+Yr1@fxtcsYwXh7g0p7RQA9m zjm3oTiwH+MZs1bKjt!5G&2wM-=6CZ@CEz(a$^lc@CqMR)m`v_h@9cza4Y*I>-219~ zuo}=#z?qMJ&UA8ltAaPHP22!8F)nifPJ`-~nf>@k0CG@t9fAst5~-;Vnj3%*V(7o6 zyBpt<{xipXIN}X#nAh-eRtwY?-qW;bIsi+5EVsq-8*~e8O@p-KeL0()veo3Peo+ks zccds?3dx~^?b-%3I(j=S$r?_mTUc0yl_o5v!|L?3%Yvn;JVYA?4=5*)lSTr(gvQ@& zJwX{(Fs#0XVP!LvgsqHpSCRh_3}x_0$=;zZIgab1YH(4o6JP??Q= zg@}G&Xh>$(aBB7Xk};goR<|i*V`Dh*s2gh=>@Yvq0dW1rohfu29BXOSMQPYOrI7=lv`=`i+}!OUy$p!>>|_$m*=z& zeOg6Oo(6%hm+Wlp$dN-MSkO7_{1J3Y*-2jQ7XXmP($06wsuX`iTijVFN%YPs7&NSU_x_c2i(tLkjl=5Q1Wi zpa#wlL-LEkl)nf=g8xyBKDfp|M=v?x_`S%}l(rJY#|1HV{pM|RNk(UZBL+tf4P&jw z8TsT7yka^B9hl#(y4`7j#)5wJpZ}u#ji383z-Y(3!nym%gnls*EKfFCU!wp-R?BN5BZAR#N9ing4kD2ZdRVaZNPr> z#LO~=a}tPvCKfbrcUDMu#gJJM$_=l8CI_tatiVd5TnlJV=5e*ho+d}-^0a~|&p5b^ z#{a}{mz;NIcU6YUkNgPZLz*ysIDFG5aeq4N6^8aV z?HB*SfnJ#&pOC(eCb>Ja5^wyic>E?3^zf_zX!+0bmUL8<($RO}kXOM*e-!8ej3iu4 z@lKkP$(WJr;tDo!z6PrF z=YQ&N%i!5p<)febN%?#K;1{sX?f1-L&ukf0Xi@__PWTu8;eYCMYc-stu@6vC4>Aed zlf%veN%fH~#^&VMH>i&wP@IX4fB1sxN3;Q!Sw9FGf3E-Uwd<~p;QG3H`QQKLm*pN7 zVfT$3H|qgjf9qYBsP*O-F)eWLsDmL7RZD;|{ge}_cm#mAoafB<9Xu?zMsN7ETH7#$ zjfSh=4Ar>t8;^B?u%Srea^pFbEC;NWG8dglhyCeA5VtvotmR~EdbzmqgFCbG)JT`P zE}{~%7v;WT<5E+JTYx@mA@Kn;=v%8xvI6_Q?$MN)ttQy`Z^G8aIh=iMpol1em8CJHC-K`xsj)Q?1{jzdWNT|k}$pNYm{5y-(k+6ST}Ouj=6TAB>X zi082j<&-uDY>QtMnbuH(JQfWjT3M6#IVmyZ0gme%c>U&Y|E{6r6vB^v;WJoo@QVDk z&wo0}U5y7C_$UA1@0+cGU;4_Q0-7@tVCboIe}e)E3_6?{#z#0coL`KW+~Ljuq)~L# zf!{4$oLnP)olVl-)*5|iAem;oRB=p+ch8?ch%Mz!9=46C&uh2GaKhh~y!`BWL-*Pn zZyUcr>t~R=y}fBpf!*1{^Z<7vRb5#csCWc`RbT^)=Qgo=K6Fcq%hHIBLCPh*AX4}g zfE6&j96<m<}>y(l*(Oe$-s17Bs>X38^6UK^g>ou?X{Udk3O>7rcO6P{}PNV&Mbp z<;1fU1H+;tZj1X{i;16I4uj;Zj@T>p)zn3EiM}V~V*8T>xDL{Zr2DS0mTk7$< z5fVJ-o*!TOrY+!Glg|CZyM{AK==43?+|nuwSa{6_>5Ko)PsoA6L9{K1H`dAura*ae zU`KOF!{UOaou_%%EaAbgh?X!WO<2KLYafLP4ME>2CLrxqVbXvY@2 z#s-Y%Xk$aaq$5puIff9F5@V5JlT$nyC(P%|B^fYja_p}*BR_44Jh8jO%Y1u-_?;Uw za_(raoIloYX6hTcz0mU@m~e`Xz}WMTm8?5hcd&trW-Z&=+NB-#6zE28kHgT#4_ZBpbQRxN>GGohAVX30l|@h zurpA4A!3Dz?Nc@`3j7!71cc8{O63NSf(9iHa14gk#iM*6;Il!#cfAXO3Txo1f6UF- z@rXaTK77!$wlt&hSL1P(vZaOV12FoDC_jq+^iRGjzx}U&R~njXvH1G1G$LQ~Fo@RD z)+raSj#?)C{?VVjX2N&I#^K|0fKveIC{$hf8rYMzCMGAPa{x!{@?fB#v01`o`Bupr z!5R}@L8f!SO0QpzN)~V?f{w!H%_W(jilQpf`fTV~A%m$Y&4M|rn&TWC4S46;J$dWu zgq%KT7dAC#41naNad@y7jr^FAXR?Vs{d6<;#^f$W1$dGnZ4}VetuG?ATDjtS&juL& z_;Mou43~8A@}|fQnzDf5Wt>JlKoJ3rf)aO17gy%x&4^6PkEO(y6aePy-;-)U)7_80 zmO*`2292s;QPHS0IF&&^5p^Jo@V_BLg2IVR%Ji)FDWIJJt{pi0(a*}S{Q7U=IO_No z+542#z7xYOn7{B3|332V9twmKcgX=#(4ee}gU_H|k;s5H9ZYuuth_o{>DzYC`Rc-q z^t9DWYikSI=cviy0&>3X*0E*`2gwS%3B$1NbL8j|c^3z^t*>ok%5__=T)QE4pq<9K z0Dt%=Uz5-O@DKWotl+rw7hifonp)b86;zL?2FlVvbT`T(4~Sf2!^Yp5tBr6wn2*_j zz5RiX_{cz1yKE)#99rqrPaqP_h{vV_PJqjsugqz}0HTS~k2_O20p_v0ICm#_m@E&^ zvEoR8b`ajXH7}=zJLJRxe8IQs;FhJ0%8n2~y!yM_WNrZy4(Kc?)q#P2SzLr!U)K>J z-ym!N)NCxmJn<6fIX2;(3Q}L;xxS{Nen`kC9!^p8jSB%Ds7UWeR4$}>;_zZV8~7v6 z5`;D_BbRL8Gg&Sw+~@C+40s)(3`sR;d@mVK$XAi-r$sA9{WOJ#kmMmdP80m2fA&Ah zQ?LApnIfR=geTo`J;1Z)pMo0rFxZ=tx-|xnf(EK1&OQHxswfXC#v6z+L1lvNz(%ZA zTAGugzD}uwiE=J5zJ7ZORCsTKOfCO*bYU75-#FYe_HTdThhd*>O$un4dJptqt2sso zHnz+H><-wM`BAJ7>FKuyfoSc7rvkQO`kUO1p$~pjiu{bw#@16|w#<%oL z&*B^a*a+A(7Me(_mt)eX`YO!PmEYi#(FrjxI~VoxvI3f@`Ux5ZJ6|maF2eL=6Vih1 zikPFJU|uwf!XE6q=mgLm?5HuFfHn+o>3f)2Rn_&O@#hEe4jTU@tY&RQ7nj3h3s~{b z{jzkYPQ$t%blX(t7Tkb&O@*l-Ls{%6EKmkrfVLt7fYEKhqbPvvJyIVC!%W{G9h1Hc z0vSFS5;C0OOj!Xpen{_V0ng#g5cULsR8P)Vjj5ll0mbegP3ow?nOCbF0p8PJ#hC&2 z!Q=Cma~};j2S*_xAIVap@_A!VA;@a6MYp!86^oanks8kNkB-|@{!DWCS;4nVYilFk zZ`)G9mwy9z-@kZKCMPCg+h1hx@JZ?F>aruu$lvDHmfRhilxsIeRRmrQJMu?g{VVBd z#~T=<3pG`1fL=G{1S;zQBqY~y@r7}$B=%~=Lbfe6(HMba^(^Fx8Wao7|8>Ir%g!a4 z%TP3N%N3FsNF2bC0AAX^Om+fTC>Rq4#g262dV6$U-n+9RJ@xFvFc?RJ182^8F=owXQY6Je|6DzC~i-2X<`|UdNI<~Pw*&M{TMBQ z`A%7E?h!Nh0Q5O*u@^(pbP^o}y|+emLO7yk_}|$gPZES$X}PcX3Qhjm+M=D{s8@miv&z(ZKjn zdgGmU%!nvIIiKpQk=MWe6?yvEb1E9^0Qjb^x^gveUpfFyZC&=I9Him0$5%2 zFSq@0(k#9I3UtvRsf?f!(a&%p+K{9G8BBKZA1oakGsk^RJJMV4_~5ZV(^kMVt^udj z>*(-yVyWKTJdE_N{`Y z&>xW-<9Q~CnN2G<@-wm?k{EOX;2y>#XGCT1l}|$vNd_NR0`-AlP+u&b&cT_!$%Fa; z#6Ua0AwgbP^F%y_KOs(a<$RVryvo=c`}+s+>7}N|tF| z4hzYbmhDFrljBGzNBTQ3D)7a>`BQT7-VR3nc?xZ-OwG+oYg-$(rehq|e~^-^>WXP# z&mDjbnEr)E$m1R(fHwCE$XxHVL?XSdyZUPm&6AAIUWy~RCR|E(S^!H+Ze_7_%>#$&@$ymMGGV&l0D_D1+ zOY>~3V1++y{x704%d-m7PV=9}7>J_PH-**+{d{MsT;u8*8P6VL<69wg;3T~vR=Cmx zX=+eqd*Mo}yh&eWI{}GkEZHRMevYf2oF5k3X`+JCRnA#KVh@$&7yp-EF>3^##4UvX z^MCh`16|vDoVwEnkb(w$E|@eBcWn}QvFW*YVR7oL}QuH2N7W2e#Br_64N-Nr`~ zj&a4PGtUR88U#w;&OAuv9RS`NTsv;z#n4cXOT!|XFwS$}K$m~L=VidcRTu?YxyH|B z3W*p_xD+}CNHAnY<2>Pen2jymuox&8)pqPtWHZ4 zdrg?PQtNw9ojoh}#wH*XPXoHsDlx7ULK992Jt_ovV1g+r)$y2uf;6Aa$tf?5s1Ts1 zYy#+|TozDa&WGpULn(fWRr(C%egTCQ4Plljy!Kv<$3RCVl)&eVTL{1KQ~%);Wo3}N z0)FP-{RyWXJ}LHIr|!4`q@a$^!9&{s`q1UEIL-!q^l>4ck~g(>$(=DS`imS#G}Up$ za|YH;`2mSp0Qt-hKX0-;*wczL1D522>o=9u_%MYc1uPc0esf%Y_h0=h=|*yIfAg!p z!C#u5@@dBytC3s{RNet_B3E%o*Rbuc5yw2b??zYc&>_o}&YFbFzwB%@HRS>*F$4-DT*+W5ecrrQ;9F~S9Z11Cd!tlV< zW3TK0j`F>A<$^S!Qa57G?9LQz5t733l2)C9O$G_{02fxmv>#ErkmgMhX%+_ofuU7G z`Weonm7Zf70j<6rGFX%HizWx8NeV`RY`qK8$ddgi!&p$goVHBaa`Rjqn`Tpb`cIDg z+Bd%=uYUH6#@z6eQfjUR=ZY zSfvr$^2Ts_s(nf^)Q>Nr)u8bw1I6{W7tE>bd`rB8xqp5P&Ek}{*3KTBHme_%q_&PH zpswNg_MiA0KP@wmw}lsJZTDe$`PGj|YX?RFs%}>r$ZeuaOVQUZjOAeNrM0uqTXiBY ztuk$FY?z^MTa#F!^a4S49SV{qfnEVvgNjn$(|UkX=J-lyeV;W%8P0YgkELJ(&y9K9 zw&GoeusUq(>+I-|k)Z)}m_QFhKRn0c`Ilb8VMMD&S3O-F($rWd*T<}tEH96NRMIIx zj9eoTmAzl(--C$LB+jUJu}G9RgSUJUg@0>!Zp*-^rL~BN!^9I&rHN{th2+x)_(wJ9 z>WOMW{d9H}qdqADy%L;qN}GvHQ9rH#jt2ZE|J6Ui0XqNr6R|dcCo=y0-~C(ecJkh{ zo@g^%?p;aM%ly^CXOb-2s~bFu6}M~Bmv(vFmWEyYKZgy%j-Dg zj5`1T{Mn!V59AxKeP33wx4(c7%Gx8WsbKX@Y8s(m zj*HWW?Q}MGNM9rk2%_<$77XbZC^WQ!Kb(|jSTVjUE;_PQ3ZOw44x2Vbi*|0oL?eI zPp9;jIq}Q9BtZKhszpy{RWa%(DO`CK&HLi-fdZ2}Pj;M#5xx4^pOm-XyZG2Ef*k-m z3c#YWK3ErpLO=?tE6!CHdH3?bH|KH-6{;lV?vIH0ZXLf_(qYcVTP@ zivVFsH8eJq|A z5)=wn-=H-@zZ@6Rqd`P8ywVcl^l5wm$q=-_Rvr!=+L#;Z;|3R4M|4loCWrmeSr{K1 zlgl^|r5!_dZ(Y7En_=?)iBn)qWGtc-wx5rf$(u2Nxp>|VRF;_Zp;#qm_P@DYezxjQ6>1C`RpyS#pcVemqRDX+UU=JMt-e6p~@ih6^ z-Zvz7N5_0x{El6Q3CL^Lv8c^BM{n+`tsD*!c_B%;JP|iSp#U@?h=x~;)JH-d4@?I_ zK@8`(GiQ!Thgl4OZGy-TEBEbti@{<+42P|4%F5iLY%I^2IscgjJ$tacyhK#4q4asn z$&?32oK{yJkq&rLA4t<=LPC0k!zk$)58el1Q*RsnOraL2vLM9L5&-8s8`)34TA+*q zgs2!=5h!P%$49Ny%v#=czw?@xj>5zAbV`8R1s`YkpZ(m=;IN=!S47qsY9m&W$|%0_ z1?&_<7l^9C>U$3THydL-7R~8?uKLHT&bffWL8fOHFm>EvME#wA|MT+Bg^MyYGH4p` zFHTe1`+;{KfGd*bcG37Z8&7M^u8_3Wl!^@yfN#Oz&&w}7hf&Zv ztp2|pQHJR{D9;3V69$23LY?kMfBcIw+*T*u82PB70V1wOth%x^P+12cA({s@d~oHO zoOj+ zLG&}7c3rgT&msb|%JBgY$YKa!xd{g}k6=)Xr+&Fv{E**oOg_BwvmH|9h4Z=Nm^}V0 zc$_mY_FJ$b_&9e0e(VdM3DyEo3)Gc;R#H!l0i>Xwp4`a=fprCZ<+z5up}9>a(U|K8 z4`0d~SQiy{QM?&j1`7=^0gPz__7h%y`6cfs4vcz5vy~J|3CgO|DOEG zm%n5d9^&{Rm{nhf9Uv|#th#bEu*VJnZzygwZuX1MKNIVCu@`uBs1>W*(Ic~DE?_+3xM{X>mQxuf76Yx)e>IIpfox#b1FkRW&X0TQ|9}$Fn-XJI^DU(RR zS%NT7yG^Miy-mPnKzUqLXDKrBW=jzLdNFwcFC$1Ji`LT-8AgI|5X=(s=)<&;Dv{GN z$x28m3$00ozGVy{$#5yryixc2DwSr4Pv$p@|JHB+-eWrw@bmvMIsma}gb|kAymdka zCFnww3UEHWLR$x>dsktzEIRdc8?8wL%=@kD88D#;AGR`@v2C!qb_0j~6ksWERaTZ3 z<@;}6keUWq5=|bRm5%QCtv(mgPd(84MxXh_rGi zMsLea)9}aF#~;S?@v)D;Am4xEE!oC%w}w*%@1VCF6%uJ!5gCaoC`?pg8NMe&z?4@3 z8MHBwrL(UD@&f5E1_Ec`v{D%T1=w_1K)=JDzu_}K1jJaP2;qD=sdMy(Sz(S{Q4zQr zx(^x%wQt1{qF1p5^oAsTbR%pd{6_nYz+5kFHupJ$KGsI4@ARDsUkm4AHfr$P)OMopoHucIu3aG z%m^&_-ImD}JQzWCNOc;9sh)rJSy_QuOAb?w-a}89b0b6+b@4QENj(_?ro0Ns