propane 3.4.2-java → 3.5.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mvn/wrapper/MavenWrapperDownloader.java +1 -1
- data/.travis.yml +1 -1
- data/CHANGELOG.md +5 -1
- data/Gemfile +2 -0
- data/README.md +15 -3
- data/Rakefile +9 -10
- data/bin/propane +3 -1
- data/lib/propane.rb +2 -1
- data/lib/propane/app.rb +2 -1
- data/lib/propane/creators/sketch_class.rb +7 -1
- data/lib/propane/creators/sketch_factory.rb +4 -2
- data/lib/propane/creators/sketch_writer.rb +1 -0
- data/lib/propane/helper_methods.rb +22 -22
- data/lib/propane/helpers/numeric.rb +2 -0
- data/lib/propane/helpers/version_error.rb +1 -0
- data/lib/propane/library.rb +5 -1
- data/lib/propane/library_loader.rb +2 -0
- data/lib/propane/native_folder.rb +10 -9
- data/lib/propane/native_loader.rb +3 -0
- data/lib/propane/runner.rb +11 -5
- data/lib/propane/version.rb +2 -1
- data/library/boids/boids.rb +21 -11
- data/library/color_group/color_group.rb +2 -0
- data/library/control_panel/control_panel.rb +8 -5
- data/library/dxf/dxf.rb +2 -0
- data/library/file_chooser/chooser.rb +10 -9
- data/library/file_chooser/file_chooser.rb +10 -9
- data/library/library_proxy/library_proxy.rb +2 -0
- data/library/net/net.rb +2 -0
- data/library/simplex_noise/simplex_noise.rb +2 -0
- data/library/slider/slider.rb +23 -22
- data/library/vector_utils/vector_utils.rb +4 -0
- data/library/video_event/video_event.rb +2 -0
- data/pom.rb +46 -45
- data/pom.xml +4 -4
- data/propane.gemspec +8 -7
- data/src/main/java/monkstone/ColorUtil.java +1 -3
- data/src/main/java/monkstone/MathToolModule.java +1 -1
- data/src/main/java/monkstone/PropaneLibrary.java +2 -2
- data/src/main/java/monkstone/fastmath/Deglut.java +1 -1
- data/src/main/java/monkstone/filechooser/Chooser.java +1 -1
- data/src/main/java/monkstone/noise/SimplexNoise.java +2 -2
- data/src/main/java/monkstone/slider/CustomHorizontalSlider.java +1 -1
- data/src/main/java/monkstone/slider/CustomVerticalSlider.java +1 -1
- data/src/main/java/monkstone/slider/SimpleHorizontalSlider.java +1 -1
- data/src/main/java/monkstone/slider/SimpleVerticalSlider.java +1 -1
- data/src/main/java/monkstone/slider/SliderBar.java +1 -1
- data/src/main/java/monkstone/slider/SliderGroup.java +1 -1
- data/src/main/java/monkstone/slider/WheelHandler.java +1 -1
- data/src/main/java/monkstone/vecmath/package-info.java +1 -1
- data/src/main/java/monkstone/vecmath/vec2/Vec2.java +1 -1
- data/src/main/java/monkstone/vecmath/vec3/Vec3.java +1 -2
- data/src/main/java/monkstone/videoevent/CaptureEvent.java +1 -1
- data/src/main/java/monkstone/videoevent/MovieEvent.java +1 -1
- data/src/main/java/monkstone/videoevent/package-info.java +1 -1
- data/src/main/java/processing/awt/PGraphicsJava2D.java +788 -283
- data/src/main/java/processing/awt/PImageAWT.java +260 -0
- data/src/main/java/processing/awt/PShapeJava2D.java +56 -53
- data/src/main/java/processing/awt/PSurfaceAWT.java +309 -211
- data/src/main/java/processing/awt/ShimAWT.java +580 -0
- data/src/main/java/processing/core/PApplet.java +2877 -2098
- data/src/main/java/processing/core/PConstants.java +477 -447
- data/src/main/java/processing/core/PFont.java +930 -884
- data/src/main/java/processing/core/PGraphics.java +337 -309
- data/src/main/java/processing/core/PImage.java +1689 -1689
- data/src/main/java/processing/core/PMatrix.java +172 -159
- data/src/main/java/processing/core/PMatrix2D.java +456 -410
- data/src/main/java/processing/core/PMatrix3D.java +755 -735
- data/src/main/java/processing/core/PShape.java +2910 -2656
- data/src/main/java/processing/core/PShapeOBJ.java +97 -94
- data/src/main/java/processing/core/PShapeSVG.java +1656 -1462
- data/src/main/java/processing/core/PStyle.java +40 -37
- data/src/main/java/processing/core/PSurface.java +134 -97
- data/src/main/java/processing/core/PSurfaceNone.java +292 -218
- data/src/main/java/processing/core/PVector.java +991 -966
- data/src/main/java/processing/core/ThinkDifferent.java +12 -8
- data/src/main/java/processing/data/DoubleDict.java +756 -710
- data/src/main/java/processing/data/DoubleList.java +749 -696
- data/src/main/java/processing/data/FloatDict.java +748 -702
- data/src/main/java/processing/data/FloatList.java +751 -697
- data/src/main/java/processing/data/IntDict.java +720 -673
- data/src/main/java/processing/data/IntList.java +699 -633
- data/src/main/java/processing/data/JSONArray.java +931 -873
- data/src/main/java/processing/data/JSONObject.java +1262 -1165
- data/src/main/java/processing/data/JSONTokener.java +351 -341
- data/src/main/java/processing/data/LongDict.java +710 -663
- data/src/main/java/processing/data/LongList.java +701 -635
- data/src/main/java/processing/data/Sort.java +37 -41
- data/src/main/java/processing/data/StringDict.java +525 -486
- data/src/main/java/processing/data/StringList.java +626 -580
- data/src/main/java/processing/data/Table.java +3693 -3513
- data/src/main/java/processing/data/TableRow.java +182 -183
- data/src/main/java/processing/data/XML.java +954 -880
- data/src/main/java/processing/event/Event.java +87 -67
- data/src/main/java/processing/event/KeyEvent.java +48 -41
- data/src/main/java/processing/event/MouseEvent.java +87 -113
- data/src/main/java/processing/event/TouchEvent.java +10 -6
- data/src/main/java/processing/javafx/PSurfaceFX.java +26 -0
- data/src/main/java/processing/net/Client.java +20 -20
- data/src/main/java/processing/net/Server.java +9 -9
- data/src/main/java/processing/opengl/FontTexture.java +286 -266
- data/src/main/java/processing/opengl/FrameBuffer.java +390 -376
- data/src/main/java/processing/opengl/LinePath.java +130 -91
- data/src/main/java/processing/opengl/LineStroker.java +593 -582
- data/src/main/java/processing/opengl/PGL.java +645 -579
- data/src/main/java/processing/opengl/PGraphics2D.java +408 -315
- data/src/main/java/processing/opengl/PGraphics3D.java +107 -72
- data/src/main/java/processing/opengl/PGraphicsOpenGL.java +12287 -12030
- data/src/main/java/processing/opengl/PJOGL.java +1743 -1672
- data/src/main/java/processing/opengl/PShader.java +345 -416
- data/src/main/java/processing/opengl/PShapeOpenGL.java +4601 -4543
- data/src/main/java/processing/opengl/PSurfaceJOGL.java +1113 -1029
- data/src/main/java/processing/opengl/Texture.java +1489 -1401
- data/src/main/java/processing/opengl/VertexBuffer.java +57 -55
- data/test/create_test.rb +21 -20
- data/test/deglut_spec_test.rb +4 -2
- data/test/helper_methods_test.rb +49 -20
- data/test/math_tool_test.rb +39 -32
- data/test/native_folder.rb +47 -0
- data/test/respond_to_test.rb +3 -2
- data/test/sketches/key_event.rb +2 -2
- data/test/sketches/library/my_library/my_library.rb +3 -0
- data/test/test_helper.rb +2 -0
- data/test/vecmath_spec_test.rb +35 -22
- data/vendors/Rakefile +28 -22
- metadata +13 -13
- data/src/main/java/processing/opengl/shaders/LightVert-brcm.glsl +0 -154
- data/src/main/java/processing/opengl/shaders/LightVert-vc4.glsl +0 -154
- data/src/main/java/processing/opengl/shaders/TexLightVert-brcm.glsl +0 -160
- data/src/main/java/processing/opengl/shaders/TexLightVert-vc4.glsl +0 -160
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
/*
|
|
1
|
+
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
|
2
|
+
|
|
3
|
+
/*
|
|
2
4
|
Part of the Processing project - http://processing.org
|
|
3
5
|
|
|
4
6
|
Copyright (c) 2012-15 The Processing Foundation
|
|
@@ -22,6 +24,9 @@
|
|
|
22
24
|
package processing.opengl;
|
|
23
25
|
|
|
24
26
|
import java.awt.Component;
|
|
27
|
+
import java.awt.EventQueue;
|
|
28
|
+
import java.awt.FileDialog;
|
|
29
|
+
import java.awt.GraphicsConfiguration;
|
|
25
30
|
import java.awt.GraphicsDevice;
|
|
26
31
|
import java.awt.GraphicsEnvironment;
|
|
27
32
|
import java.awt.Point;
|
|
@@ -58,7 +63,6 @@ import com.jogamp.newt.Display.PointerIcon;
|
|
|
58
63
|
import com.jogamp.newt.NewtFactory;
|
|
59
64
|
import com.jogamp.newt.Screen;
|
|
60
65
|
import com.jogamp.newt.awt.NewtCanvasAWT;
|
|
61
|
-
import com.jogamp.newt.event.InputEvent;
|
|
62
66
|
import com.jogamp.newt.opengl.GLWindow;
|
|
63
67
|
import com.jogamp.opengl.util.FPSAnimator;
|
|
64
68
|
|
|
@@ -69,179 +73,272 @@ import processing.core.PImage;
|
|
|
69
73
|
import processing.core.PSurface;
|
|
70
74
|
import processing.event.KeyEvent;
|
|
71
75
|
import processing.event.MouseEvent;
|
|
76
|
+
import processing.awt.PImageAWT;
|
|
77
|
+
|
|
78
|
+
// have this removed by 4.0 final
|
|
79
|
+
import processing.awt.ShimAWT;
|
|
72
80
|
|
|
73
81
|
public class PSurfaceJOGL implements PSurface {
|
|
74
82
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Selected GL profile
|
|
85
|
+
*/
|
|
86
|
+
public static GLProfile profile;
|
|
79
87
|
|
|
80
|
-
|
|
88
|
+
public PJOGL pgl;
|
|
81
89
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
protected GLWindow window;
|
|
91
|
+
protected FPSAnimator animator;
|
|
92
|
+
protected Rectangle screenRect;
|
|
85
93
|
|
|
86
|
-
|
|
94
|
+
private Thread drawExceptionHandler;
|
|
87
95
|
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
protected PApplet sketch;
|
|
97
|
+
protected PGraphics graphics;
|
|
90
98
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
99
|
+
protected int sketchWidth0;
|
|
100
|
+
protected int sketchHeight0;
|
|
101
|
+
protected int sketchWidth;
|
|
102
|
+
protected int sketchHeight;
|
|
95
103
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
104
|
+
protected Display display;
|
|
105
|
+
protected Screen screen;
|
|
106
|
+
protected Rectangle displayRect;
|
|
107
|
+
protected Throwable drawException;
|
|
108
|
+
private final Object drawExceptionMutex = new Object();
|
|
101
109
|
|
|
102
|
-
|
|
110
|
+
protected NewtCanvasAWT canvas;
|
|
103
111
|
|
|
104
|
-
|
|
112
|
+
protected int windowScaleFactor;
|
|
105
113
|
|
|
106
|
-
|
|
114
|
+
protected float[] currentPixelScale = {0, 0};
|
|
107
115
|
|
|
108
|
-
|
|
116
|
+
protected boolean external = false;
|
|
109
117
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
118
|
+
public PSurfaceJOGL(PGraphics graphics) {
|
|
119
|
+
this.graphics = graphics;
|
|
120
|
+
this.pgl = (PJOGL) ((PGraphicsOpenGL) graphics).pgl;
|
|
121
|
+
}
|
|
114
122
|
|
|
115
|
-
public void initOffscreen(PApplet sketch) {
|
|
116
|
-
this.sketch = sketch;
|
|
117
123
|
|
|
118
|
-
|
|
119
|
-
|
|
124
|
+
/*
|
|
125
|
+
@Override
|
|
126
|
+
public int displayDensity() {
|
|
127
|
+
return shim.displayDensity();
|
|
128
|
+
}
|
|
120
129
|
|
|
121
|
-
if (window != null) {
|
|
122
|
-
canvas = new NewtCanvasAWT(window);
|
|
123
|
-
canvas.setBounds(0, 0, window.getWidth(), window.getHeight());
|
|
124
|
-
canvas.setFocusable(true);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
130
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
131
|
+
@Override
|
|
132
|
+
public int displayDensity(int display) {
|
|
133
|
+
return shim.displayDensity(display);
|
|
134
|
+
}
|
|
135
|
+
*/
|
|
136
|
+
// TODO rewrite before 4.0 release
|
|
137
|
+
@Override
|
|
138
|
+
public PImage loadImage(String path, Object... args) {
|
|
139
|
+
return ShimAWT.loadImage(sketch, path, args);
|
|
140
|
+
}
|
|
137
141
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
142
|
+
@Override
|
|
143
|
+
public void selectInput(String prompt, String callbackMethod,
|
|
144
|
+
File file, Object callbackObject) {
|
|
145
|
+
EventQueue.invokeLater(() -> {
|
|
146
|
+
// https://github.com/processing/processing/issues/3831
|
|
147
|
+
boolean hide = (sketch != null)
|
|
148
|
+
&& (PApplet.platform == PConstants.WINDOWS);
|
|
149
|
+
if (hide) {
|
|
150
|
+
setVisible(false);
|
|
151
|
+
}
|
|
141
152
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
display.addReference();
|
|
145
|
-
screen = NewtFactory.createScreen(display, 0);
|
|
146
|
-
screen.addReference();
|
|
153
|
+
ShimAWT.selectImpl(prompt, callbackMethod, file,
|
|
154
|
+
callbackObject, null, FileDialog.LOAD);
|
|
147
155
|
|
|
148
|
-
|
|
149
|
-
|
|
156
|
+
if (hide) {
|
|
157
|
+
setVisible(true);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@Override
|
|
163
|
+
public void selectOutput(String prompt, String callbackMethod,
|
|
164
|
+
File file, Object callbackObject) {
|
|
165
|
+
EventQueue.invokeLater(() -> {
|
|
166
|
+
// https://github.com/processing/processing/issues/3831
|
|
167
|
+
boolean hide = (sketch != null)
|
|
168
|
+
&& (PApplet.platform == PConstants.WINDOWS);
|
|
169
|
+
if (hide) {
|
|
170
|
+
setVisible(false);
|
|
171
|
+
}
|
|
150
172
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
173
|
+
ShimAWT.selectImpl(prompt, callbackMethod, file,
|
|
174
|
+
callbackObject, null, FileDialog.SAVE);
|
|
175
|
+
|
|
176
|
+
if (hide) {
|
|
177
|
+
setVisible(true);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@Override
|
|
183
|
+
public void selectFolder(String prompt, String callbackMethod,
|
|
184
|
+
File file, Object callbackObject) {
|
|
185
|
+
EventQueue.invokeLater(() -> {
|
|
186
|
+
// https://github.com/processing/processing/issues/3831
|
|
187
|
+
boolean hide = (sketch != null)
|
|
188
|
+
&& (PApplet.platform == PConstants.WINDOWS);
|
|
189
|
+
if (hide) {
|
|
190
|
+
setVisible(false);
|
|
191
|
+
}
|
|
166
192
|
|
|
167
|
-
|
|
168
|
-
|
|
193
|
+
ShimAWT.selectFolderImpl(prompt, callbackMethod, file,
|
|
194
|
+
callbackObject, null);
|
|
195
|
+
|
|
196
|
+
if (hide) {
|
|
197
|
+
setVisible(true);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@Override
|
|
203
|
+
public void initOffscreen(PApplet sketch) {
|
|
204
|
+
this.sketch = sketch;
|
|
205
|
+
|
|
206
|
+
sketchWidth = sketch.sketchWidth();
|
|
207
|
+
sketchHeight = sketch.sketchHeight();
|
|
208
|
+
|
|
209
|
+
if (window != null) {
|
|
210
|
+
canvas = new NewtCanvasAWT(window);
|
|
211
|
+
canvas.setBounds(0, 0, window.getWidth(), window.getHeight());
|
|
212
|
+
canvas.setFocusable(true);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
@Override
|
|
217
|
+
public void initFrame(PApplet sketch) {
|
|
218
|
+
this.sketch = sketch;
|
|
219
|
+
|
|
220
|
+
initIcons();
|
|
221
|
+
initDisplay();
|
|
222
|
+
initGL();
|
|
223
|
+
initWindow();
|
|
224
|
+
initListeners();
|
|
225
|
+
initAnimator();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
@Override
|
|
229
|
+
public Object getNative() {
|
|
230
|
+
return window;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
protected void initDisplay() {
|
|
234
|
+
display = NewtFactory.createDisplay(null);
|
|
235
|
+
display.addReference();
|
|
236
|
+
screen = NewtFactory.createScreen(display, 0);
|
|
237
|
+
screen.addReference();
|
|
238
|
+
|
|
239
|
+
GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
|
240
|
+
GraphicsDevice[] awtDevices = environment.getScreenDevices();
|
|
241
|
+
|
|
242
|
+
GraphicsDevice awtDisplayDevice = null;
|
|
243
|
+
int displayNum = sketch.sketchDisplay();
|
|
244
|
+
if (displayNum > 0) { // if -1, use the default device
|
|
245
|
+
if (displayNum <= awtDevices.length) {
|
|
246
|
+
awtDisplayDevice = awtDevices[displayNum - 1];
|
|
247
|
+
} else {
|
|
248
|
+
System.err.format("Display %d does not exist, "
|
|
249
|
+
+ "using the default display instead.%n", displayNum);
|
|
250
|
+
for (int i = 0; i < awtDevices.length; i++) {
|
|
251
|
+
System.err.format("Display %d is %s%n", i + 1, awtDevices[i]);
|
|
169
252
|
}
|
|
253
|
+
}
|
|
254
|
+
} else if (0 < awtDevices.length) {
|
|
255
|
+
awtDisplayDevice = awtDevices[0];
|
|
256
|
+
}
|
|
170
257
|
|
|
171
|
-
|
|
258
|
+
if (awtDisplayDevice == null) {
|
|
259
|
+
awtDisplayDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
|
|
172
260
|
}
|
|
173
261
|
|
|
174
|
-
|
|
262
|
+
GraphicsConfiguration config = awtDisplayDevice.getDefaultConfiguration();
|
|
263
|
+
displayRect = config.getBounds();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
protected void initGL() {
|
|
175
267
|
// System.out.println("*******************************");
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
} catch (GLException ex) {
|
|
196
|
-
profile = GLProfile.getMaxProgrammable(true);
|
|
197
|
-
}
|
|
198
|
-
} else if (PJOGL.profile == 3) {
|
|
199
|
-
try {
|
|
200
|
-
profile = GLProfile.getGL2GL3();
|
|
201
|
-
} catch (GLException ex) {
|
|
202
|
-
profile = GLProfile.getMaxProgrammable(true);
|
|
203
|
-
}
|
|
204
|
-
if (!profile.isGL3()) {
|
|
205
|
-
PGraphics.showWarning("Requested profile GL3 but is not available, got: " + profile);
|
|
206
|
-
}
|
|
207
|
-
} else if (PJOGL.profile == 4) {
|
|
208
|
-
try {
|
|
209
|
-
profile = GLProfile.getGL4ES3();
|
|
210
|
-
} catch (GLException ex) {
|
|
211
|
-
profile = GLProfile.getMaxProgrammable(true);
|
|
212
|
-
}
|
|
213
|
-
if (!profile.isGL4()) {
|
|
214
|
-
PGraphics.showWarning("Requested profile GL4 but is not available, got: " + profile);
|
|
215
|
-
}
|
|
216
|
-
} else {
|
|
217
|
-
throw new RuntimeException(PGL.UNSUPPORTED_GLPROF_ERROR);
|
|
268
|
+
if (profile == null) {
|
|
269
|
+
switch (PJOGL.profile) {
|
|
270
|
+
case 1:
|
|
271
|
+
try {
|
|
272
|
+
profile = GLProfile.getGL2ES1();
|
|
273
|
+
} catch (GLException ex) {
|
|
274
|
+
profile = GLProfile.getMaxFixedFunc(true);
|
|
275
|
+
}
|
|
276
|
+
break;
|
|
277
|
+
case 2:
|
|
278
|
+
try {
|
|
279
|
+
profile = GLProfile.getGL2ES2();
|
|
280
|
+
|
|
281
|
+
// workaround for https://jogamp.org/bugzilla/show_bug.cgi?id=1347
|
|
282
|
+
if (!profile.isHardwareRasterizer()) {
|
|
283
|
+
GLProfile hardware = GLProfile.getMaxProgrammable(true);
|
|
284
|
+
if (hardware.isGL2ES2()) {
|
|
285
|
+
profile = hardware;
|
|
218
286
|
}
|
|
219
|
-
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
} catch (GLException ex) {
|
|
290
|
+
profile = GLProfile.getMaxProgrammable(true);
|
|
291
|
+
}
|
|
292
|
+
break;
|
|
293
|
+
case 3:
|
|
294
|
+
try {
|
|
295
|
+
profile = GLProfile.getGL2GL3();
|
|
296
|
+
} catch (GLException ex) {
|
|
297
|
+
profile = GLProfile.getMaxProgrammable(true);
|
|
298
|
+
}
|
|
299
|
+
if (!profile.isGL3()) {
|
|
300
|
+
PGraphics.showWarning("Requested profile GL3 but is not available, got: " + profile);
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
303
|
+
case 4:
|
|
304
|
+
try {
|
|
305
|
+
profile = GLProfile.getGL4ES3();
|
|
306
|
+
} catch (GLException ex) {
|
|
307
|
+
profile = GLProfile.getMaxProgrammable(true);
|
|
308
|
+
}
|
|
309
|
+
if (!profile.isGL4()) {
|
|
310
|
+
PGraphics.showWarning("Requested profile GL4 but is not available, got: " + profile);
|
|
311
|
+
}
|
|
312
|
+
break;
|
|
313
|
+
default:
|
|
314
|
+
throw new RuntimeException(PGL.UNSUPPORTED_GLPROF_ERROR);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
220
317
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
318
|
+
// Setting up the desired capabilities;
|
|
319
|
+
GLCapabilities caps = new GLCapabilities(profile);
|
|
320
|
+
caps.setAlphaBits(PGL.REQUESTED_ALPHA_BITS);
|
|
321
|
+
caps.setDepthBits(PGL.REQUESTED_DEPTH_BITS);
|
|
322
|
+
caps.setStencilBits(PGL.REQUESTED_STENCIL_BITS);
|
|
226
323
|
|
|
227
324
|
// caps.setPBuffer(false);
|
|
228
325
|
// caps.setFBO(false);
|
|
229
326
|
// pgl.reqNumSamples = PGL.smoothToSamples(graphics.smooth);
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
327
|
+
caps.setSampleBuffers(true);
|
|
328
|
+
caps.setNumSamples(PGL.smoothToSamples(graphics.smooth));
|
|
329
|
+
caps.setBackgroundOpaque(true);
|
|
330
|
+
caps.setOnscreen(true);
|
|
331
|
+
pgl.setCaps(caps);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
protected void initWindow() {
|
|
335
|
+
window = GLWindow.create(screen, pgl.getCaps());
|
|
336
|
+
|
|
337
|
+
// Make sure that we pass the window close through to exit(), otherwise
|
|
338
|
+
// we're likely to have OpenGL try to shut down halfway through rendering
|
|
339
|
+
// a frame. Particularly problematic for complex/slow apps.
|
|
340
|
+
// https://github.com/processing/processing/issues/4690
|
|
341
|
+
window.setDefaultCloseOperation(WindowClosingProtocol.WindowClosingMode.DO_NOTHING_ON_CLOSE);
|
|
245
342
|
|
|
246
343
|
// if (displayDevice == null) {
|
|
247
344
|
//
|
|
@@ -249,25 +346,25 @@ public class PSurfaceJOGL implements PSurface {
|
|
|
249
346
|
// } else {
|
|
250
347
|
// window = GLWindow.create(displayDevice.getScreen(), pgl.getCaps());
|
|
251
348
|
// }
|
|
252
|
-
|
|
253
|
-
|
|
349
|
+
windowScaleFactor = PApplet.platform == PConstants.MACOS
|
|
350
|
+
? 1 : sketch.pixelDensity;
|
|
254
351
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
352
|
+
boolean spanDisplays = sketch.sketchDisplay() == PConstants.SPAN;
|
|
353
|
+
screenRect = spanDisplays
|
|
354
|
+
? new Rectangle(screen.getX(), screen.getY(), screen.getWidth(), screen.getHeight())
|
|
355
|
+
: new Rectangle((int) displayRect.getX(), (int) displayRect.getY(),
|
|
356
|
+
(int) displayRect.getWidth(),
|
|
357
|
+
(int) displayRect.getHeight());
|
|
261
358
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
359
|
+
// Set the displayWidth/Height variables inside PApplet, so that they're
|
|
360
|
+
// usable and can even be returned by the sketchWidth()/Height() methods.
|
|
361
|
+
sketch.displayWidth = screenRect.width;
|
|
362
|
+
sketch.displayHeight = screenRect.height;
|
|
266
363
|
|
|
267
|
-
|
|
268
|
-
|
|
364
|
+
sketchWidth0 = sketch.sketchWidth();
|
|
365
|
+
sketchHeight0 = sketch.sketchHeight();
|
|
269
366
|
|
|
270
|
-
|
|
367
|
+
/*
|
|
271
368
|
// Trying to fix
|
|
272
369
|
// https://github.com/processing/processing/issues/3401
|
|
273
370
|
if (sketch.displayWidth < sketch.width ||
|
|
@@ -284,17 +381,17 @@ public class PSurfaceJOGL implements PSurface {
|
|
|
284
381
|
// graphics.setSize(w, h - 22 - 22);
|
|
285
382
|
System.err.println("setting width/height to " + w + " " + h);
|
|
286
383
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
384
|
+
*/
|
|
385
|
+
sketchWidth = sketch.sketchWidth();
|
|
386
|
+
sketchHeight = sketch.sketchHeight();
|
|
290
387
|
// System.out.println("init: " + sketchWidth + " " + sketchHeight);
|
|
291
388
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
389
|
+
boolean fullScreen = sketch.sketchFullScreen();
|
|
390
|
+
// Removing the section below because sometimes people want to do the
|
|
391
|
+
// full screen size in a window, and it also breaks insideSettings().
|
|
392
|
+
// With 3.x, fullScreen() is so easy, that it's just better that way.
|
|
393
|
+
// https://github.com/processing/processing/issues/3545
|
|
394
|
+
/*
|
|
298
395
|
// Sketch has already requested to be the same as the screen's
|
|
299
396
|
// width and height, so let's roll with full screen mode.
|
|
300
397
|
if (screenRect.width == sketchWidth &&
|
|
@@ -302,335 +399,315 @@ public class PSurfaceJOGL implements PSurface {
|
|
|
302
399
|
fullScreen = true;
|
|
303
400
|
sketch.fullScreen();
|
|
304
401
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
if (fullScreen || spanDisplays) {
|
|
308
|
-
sketchWidth = screenRect.width / windowScaleFactor;
|
|
309
|
-
sketchHeight = screenRect.height / windowScaleFactor;
|
|
310
|
-
}
|
|
402
|
+
*/
|
|
311
403
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
if (graphics.is2X() && PApplet.platform == PConstants.MACOSX) {
|
|
316
|
-
// Retina
|
|
317
|
-
reqSurfacePixelScale = new float[]{ScalableSurface.AUTOMAX_PIXELSCALE,
|
|
318
|
-
ScalableSurface.AUTOMAX_PIXELSCALE};
|
|
319
|
-
} else {
|
|
320
|
-
// Non-retina
|
|
321
|
-
reqSurfacePixelScale = new float[]{ScalableSurface.IDENTITY_PIXELSCALE,
|
|
322
|
-
ScalableSurface.IDENTITY_PIXELSCALE};
|
|
323
|
-
}
|
|
324
|
-
window.setSurfaceScale(reqSurfacePixelScale);
|
|
325
|
-
window.setSize(sketchWidth * windowScaleFactor, sketchHeight * windowScaleFactor);
|
|
326
|
-
window.setResizable(false);
|
|
327
|
-
setSize(sketchWidth, sketchHeight);
|
|
328
|
-
if (fullScreen) {
|
|
329
|
-
PApplet.hideMenuBar();
|
|
330
|
-
if (spanDisplays) {
|
|
331
|
-
window.setFullscreen(screen.getMonitorDevices());
|
|
332
|
-
} else {
|
|
333
|
-
window.setUndecorated(true);
|
|
334
|
-
window.setTopLevelPosition((int) displayRect.getX(), (int) displayRect.getY());
|
|
335
|
-
window.setTopLevelSize((int) displayRect.getWidth(), (int) displayRect.getHeight());
|
|
336
|
-
}
|
|
337
|
-
}
|
|
404
|
+
if (fullScreen || spanDisplays) {
|
|
405
|
+
sketchWidth = screenRect.width / windowScaleFactor;
|
|
406
|
+
sketchHeight = screenRect.height / windowScaleFactor;
|
|
338
407
|
}
|
|
339
408
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
409
|
+
sketch.setSize(sketchWidth, sketchHeight);
|
|
410
|
+
|
|
411
|
+
float[] reqSurfacePixelScale;
|
|
412
|
+
if (graphics.is2X() && PApplet.platform == PConstants.MACOS) {
|
|
413
|
+
// Retina
|
|
414
|
+
reqSurfacePixelScale = new float[]{ScalableSurface.AUTOMAX_PIXELSCALE,
|
|
415
|
+
ScalableSurface.AUTOMAX_PIXELSCALE};
|
|
416
|
+
} else {
|
|
417
|
+
// Non-retina
|
|
418
|
+
reqSurfacePixelScale = new float[]{ScalableSurface.IDENTITY_PIXELSCALE,
|
|
419
|
+
ScalableSurface.IDENTITY_PIXELSCALE};
|
|
420
|
+
}
|
|
421
|
+
window.setSurfaceScale(reqSurfacePixelScale);
|
|
422
|
+
window.setSize(sketchWidth * windowScaleFactor, sketchHeight * windowScaleFactor);
|
|
423
|
+
window.setResizable(false);
|
|
424
|
+
setSize(sketchWidth, sketchHeight);
|
|
425
|
+
if (fullScreen) {
|
|
426
|
+
PApplet.hideMenuBar();
|
|
427
|
+
if (spanDisplays) {
|
|
428
|
+
window.setFullscreen(screen.getMonitorDevices());
|
|
429
|
+
} else {
|
|
430
|
+
window.setUndecorated(true);
|
|
431
|
+
window.setTopLevelPosition((int) displayRect.getX(), (int) displayRect.getY());
|
|
432
|
+
window.setTopLevelSize((int) displayRect.getWidth(), (int) displayRect.getHeight());
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
protected void initListeners() {
|
|
438
|
+
NEWTMouseListener mouseListener = new NEWTMouseListener();
|
|
439
|
+
window.addMouseListener(mouseListener);
|
|
440
|
+
NEWTKeyListener keyListener = new NEWTKeyListener();
|
|
441
|
+
window.addKeyListener(keyListener);
|
|
442
|
+
NEWTWindowListener winListener = new NEWTWindowListener();
|
|
443
|
+
window.addWindowListener(winListener);
|
|
444
|
+
|
|
445
|
+
DrawListener drawlistener = new DrawListener();
|
|
446
|
+
window.addGLEventListener(drawlistener);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
protected void initAnimator() {
|
|
450
|
+
if (PApplet.platform == PConstants.WINDOWS) {
|
|
451
|
+
// Force Windows to keep timer resolution high by
|
|
452
|
+
// sleeping for time which is not a multiple of 10 ms.
|
|
453
|
+
// See section "Clocks and Timers on Windows":
|
|
454
|
+
// https://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks
|
|
455
|
+
Thread highResTimerThread = new Thread(() -> {
|
|
456
|
+
try {
|
|
457
|
+
Thread.sleep(Long.MAX_VALUE);
|
|
458
|
+
} catch (InterruptedException ignore) {
|
|
366
459
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
animator.setUncaughtExceptionHandler(new GLAnimatorControl.UncaughtExceptionHandler() {
|
|
371
|
-
@Override
|
|
372
|
-
public void uncaughtException(final GLAnimatorControl animator,
|
|
373
|
-
final GLAutoDrawable drawable,
|
|
374
|
-
final Throwable cause) {
|
|
375
|
-
synchronized (drawExceptionMutex) {
|
|
376
|
-
drawException = cause;
|
|
377
|
-
drawExceptionMutex.notify();
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
drawExceptionHandler = new Thread(new Runnable() {
|
|
383
|
-
public void run() {
|
|
384
|
-
synchronized (drawExceptionMutex) {
|
|
385
|
-
try {
|
|
386
|
-
while (drawException == null) {
|
|
387
|
-
drawExceptionMutex.wait();
|
|
388
|
-
}
|
|
389
|
-
// System.err.println("Caught exception: " + drawException.getMessage());
|
|
390
|
-
if (drawException != null) {
|
|
391
|
-
Throwable cause = drawException.getCause();
|
|
392
|
-
if (cause instanceof ThreadDeath) {
|
|
393
|
-
// System.out.println("caught ThreadDeath");
|
|
394
|
-
// throw (ThreadDeath)cause;
|
|
395
|
-
} else if (cause instanceof RuntimeException) {
|
|
396
|
-
throw (RuntimeException) cause;
|
|
397
|
-
} else if (cause instanceof UnsatisfiedLinkError) {
|
|
398
|
-
throw new UnsatisfiedLinkError(cause.getMessage());
|
|
399
|
-
} else if (cause == null) {
|
|
400
|
-
throw new RuntimeException(drawException.getMessage());
|
|
401
|
-
} else {
|
|
402
|
-
throw new RuntimeException(cause);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
} catch (InterruptedException e) {
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
});
|
|
411
|
-
drawExceptionHandler.start();
|
|
460
|
+
}, "HighResTimerThread");
|
|
461
|
+
highResTimerThread.setDaemon(true);
|
|
462
|
+
highResTimerThread.start();
|
|
412
463
|
}
|
|
413
464
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
465
|
+
animator = new FPSAnimator(window, 60);
|
|
466
|
+
drawException = null;
|
|
467
|
+
animator.setUncaughtExceptionHandler((final GLAnimatorControl animator1, final GLAutoDrawable drawable, final Throwable cause) -> {
|
|
468
|
+
synchronized (drawExceptionMutex) {
|
|
469
|
+
drawException = cause;
|
|
470
|
+
drawExceptionMutex.notify();
|
|
471
|
+
}
|
|
472
|
+
});
|
|
423
473
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
474
|
+
drawExceptionHandler = new Thread(() -> {
|
|
475
|
+
synchronized (drawExceptionMutex) {
|
|
476
|
+
try {
|
|
477
|
+
while (drawException == null) {
|
|
478
|
+
drawExceptionMutex.wait();
|
|
479
|
+
}
|
|
480
|
+
// System.err.println("Caught exception: " + drawException.getMessage());
|
|
481
|
+
if (drawException != null) {
|
|
482
|
+
Throwable cause = drawException.getCause();
|
|
483
|
+
if (cause instanceof ThreadDeath) {
|
|
484
|
+
// System.out.println("caught ThreadDeath");
|
|
485
|
+
// throw (ThreadDeath)cause;
|
|
486
|
+
} else if (cause instanceof RuntimeException) {
|
|
487
|
+
throw (RuntimeException) cause;
|
|
488
|
+
} else if (cause instanceof UnsatisfiedLinkError) {
|
|
489
|
+
throw new UnsatisfiedLinkError(cause.getMessage());
|
|
490
|
+
} else if (cause == null) {
|
|
491
|
+
throw new RuntimeException(drawException.getMessage());
|
|
492
|
+
} else {
|
|
493
|
+
throw new RuntimeException(cause);
|
|
430
494
|
}
|
|
431
|
-
|
|
432
|
-
|
|
495
|
+
}
|
|
496
|
+
} catch (InterruptedException e) {
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
drawExceptionHandler.start();
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
@Override
|
|
504
|
+
public void setTitle(final String title) {
|
|
505
|
+
display.getEDTUtil().invoke(false, () -> {
|
|
506
|
+
window.setTitle(title);
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
@Override
|
|
511
|
+
public void setVisible(final boolean visible) {
|
|
512
|
+
display.getEDTUtil().invoke(false, () -> {
|
|
513
|
+
window.setVisible(visible);
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
@Override
|
|
518
|
+
public void setResizable(final boolean resizable) {
|
|
519
|
+
display.getEDTUtil().invoke(false, () -> {
|
|
520
|
+
window.setResizable(resizable);
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
@Override
|
|
525
|
+
public void setIcon(PImage icon) {
|
|
526
|
+
PGraphics.showWarning("Window icons for OpenGL sketches can only be set in settings()\n"
|
|
527
|
+
+ "using PJOGL.setIcon(filename).");
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
@Override
|
|
531
|
+
public void setAlwaysOnTop(final boolean always) {
|
|
532
|
+
display.getEDTUtil().invoke(false, () -> {
|
|
533
|
+
window.setAlwaysOnTop(always);
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
protected void initIcons() {
|
|
538
|
+
IOUtil.ClassResources res = null;
|
|
539
|
+
if (PJOGL.icons == null || PJOGL.icons.length == 0) {
|
|
540
|
+
// Default Processing icons
|
|
541
|
+
final int[] sizes = {16, 32, 48, 64, 128, 256, 512};
|
|
542
|
+
String[] iconImages = new String[sizes.length];
|
|
543
|
+
for (int i = 0; i < sizes.length; i++) {
|
|
544
|
+
iconImages[i] = "/icon/icon-" + sizes[i] + ".png";
|
|
545
|
+
}
|
|
546
|
+
res = new ClassResources(iconImages,
|
|
547
|
+
PApplet.class.getClassLoader(),
|
|
548
|
+
PApplet.class);
|
|
549
|
+
} else {
|
|
550
|
+
// Loading custom icons from user-provided files.
|
|
551
|
+
String[] iconImages = new String[PJOGL.icons.length];
|
|
552
|
+
for (int i = 0; i < PJOGL.icons.length; i++) {
|
|
553
|
+
iconImages[i] = resourceFilename(PJOGL.icons[i]);
|
|
554
|
+
}
|
|
433
555
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
@Override
|
|
438
|
-
public void run() {
|
|
439
|
-
window.setResizable(resizable);
|
|
440
|
-
}
|
|
441
|
-
});
|
|
556
|
+
res = new ClassResources(iconImages,
|
|
557
|
+
sketch.getClass().getClassLoader(),
|
|
558
|
+
sketch.getClass());
|
|
442
559
|
}
|
|
560
|
+
NewtFactory.setWindowIcons(res);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
@SuppressWarnings("resource")
|
|
564
|
+
private String resourceFilename(String filename) {
|
|
565
|
+
// The code below comes from PApplet.createInputRaw() with a few adaptations
|
|
566
|
+
InputStream stream = null;
|
|
567
|
+
try {
|
|
568
|
+
// First see if it's in a data folder. This may fail by throwing
|
|
569
|
+
// a SecurityException. If so, this whole block will be skipped.
|
|
570
|
+
File file = new File(sketch.dataPath(filename));
|
|
571
|
+
if (!file.exists()) {
|
|
572
|
+
// next see if it's just in the sketch folder
|
|
573
|
+
file = sketch.sketchFile(filename);
|
|
574
|
+
}
|
|
443
575
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
576
|
+
if (file.exists() && !file.isDirectory()) {
|
|
577
|
+
try {
|
|
578
|
+
// handle case sensitivity check
|
|
579
|
+
String filePath = file.getCanonicalPath();
|
|
580
|
+
String filenameActual = new File(filePath).getName();
|
|
581
|
+
// make sure there isn't a subfolder prepended to the name
|
|
582
|
+
String filenameShort = new File(filename).getName();
|
|
583
|
+
// if the actual filename is the same, but capitalized
|
|
584
|
+
// differently, warn the user.
|
|
585
|
+
//if (filenameActual.equalsIgnoreCase(filenameShort) &&
|
|
586
|
+
//!filenameActual.equals(filenameShort)) {
|
|
587
|
+
if (!filenameActual.equals(filenameShort)) {
|
|
588
|
+
throw new RuntimeException("This file is named "
|
|
589
|
+
+ filenameActual + " not "
|
|
590
|
+
+ filename + ". Rename the file "
|
|
591
|
+
+ "or change your code.");
|
|
592
|
+
}
|
|
593
|
+
} catch (IOException e) {
|
|
594
|
+
}
|
|
595
|
+
}
|
|
448
596
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
597
|
+
stream = new FileInputStream(file);
|
|
598
|
+
if (stream != null) {
|
|
599
|
+
stream.close();
|
|
600
|
+
return file.getCanonicalPath();
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// have to break these out because a general Exception might
|
|
604
|
+
// catch the RuntimeException being thrown above
|
|
605
|
+
} catch (IOException | SecurityException ioe) {
|
|
457
606
|
}
|
|
458
607
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
}
|
|
608
|
+
ClassLoader cl = sketch.getClass().getClassLoader();
|
|
609
|
+
|
|
610
|
+
try {
|
|
611
|
+
// by default, data files are exported to the root path of the jar.
|
|
612
|
+
// (not the data folder) so check there first.
|
|
613
|
+
stream = cl.getResourceAsStream("data/" + filename);
|
|
614
|
+
if (stream != null) {
|
|
615
|
+
String cn = stream.getClass().getName();
|
|
616
|
+
// this is an irritation of sun's java plug-in, which will return
|
|
617
|
+
// a non-null stream for an object that doesn't exist. like all good
|
|
618
|
+
// things, this is probably introduced in java 1.5. awesome!
|
|
619
|
+
// http://dev.processing.org/bugs/show_bug.cgi?id=359
|
|
620
|
+
if (!cn.equals("sun.plugin.cache.EmptyInputStream")) {
|
|
621
|
+
stream.close();
|
|
622
|
+
return "data/" + filename;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
477
625
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
626
|
+
// When used with an online script, also need to check without the
|
|
627
|
+
// data folder, in case it's not in a subfolder called 'data'.
|
|
628
|
+
// http://dev.processing.org/bugs/show_bug.cgi?id=389
|
|
629
|
+
stream = cl.getResourceAsStream(filename);
|
|
630
|
+
if (stream != null) {
|
|
631
|
+
String cn = stream.getClass().getName();
|
|
632
|
+
if (!cn.equals("sun.plugin.cache.EmptyInputStream")) {
|
|
633
|
+
stream.close();
|
|
634
|
+
return filename;
|
|
481
635
|
}
|
|
482
|
-
|
|
636
|
+
}
|
|
637
|
+
} catch (IOException e) {
|
|
483
638
|
}
|
|
484
639
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
640
|
+
try {
|
|
641
|
+
// attempt to load from a local file, used when running as
|
|
642
|
+
// an application, or as a signed applet
|
|
643
|
+
try { // first try to catch any security exceptions
|
|
489
644
|
try {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
if (file.exists() && !file.isDirectory()) {
|
|
499
|
-
try {
|
|
500
|
-
// handle case sensitivity check
|
|
501
|
-
String filePath = file.getCanonicalPath();
|
|
502
|
-
String filenameActual = new File(filePath).getName();
|
|
503
|
-
// make sure there isn't a subfolder prepended to the name
|
|
504
|
-
String filenameShort = new File(filename).getName();
|
|
505
|
-
// if the actual filename is the same, but capitalized
|
|
506
|
-
// differently, warn the user.
|
|
507
|
-
//if (filenameActual.equalsIgnoreCase(filenameShort) &&
|
|
508
|
-
//!filenameActual.equals(filenameShort)) {
|
|
509
|
-
if (!filenameActual.equals(filenameShort)) {
|
|
510
|
-
throw new RuntimeException("This file is named "
|
|
511
|
-
+ filenameActual + " not "
|
|
512
|
-
+ filename + ". Rename the file "
|
|
513
|
-
+ "or change your code.");
|
|
514
|
-
}
|
|
515
|
-
} catch (IOException e) {
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
stream = new FileInputStream(file);
|
|
520
|
-
if (stream != null) {
|
|
521
|
-
stream.close();
|
|
522
|
-
return file.getCanonicalPath();
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// have to break these out because a general Exception might
|
|
526
|
-
// catch the RuntimeException being thrown above
|
|
527
|
-
} catch (IOException ioe) {
|
|
528
|
-
} catch (SecurityException se) {
|
|
645
|
+
String path = sketch.dataPath(filename);
|
|
646
|
+
stream = new FileInputStream(path);
|
|
647
|
+
if (stream != null) {
|
|
648
|
+
stream.close();
|
|
649
|
+
return path;
|
|
650
|
+
}
|
|
651
|
+
} catch (IOException e2) {
|
|
529
652
|
}
|
|
530
653
|
|
|
531
|
-
ClassLoader cl = sketch.getClass().getClassLoader();
|
|
532
|
-
|
|
533
654
|
try {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
// a non-null stream for an object that doesn't exist. like all good
|
|
541
|
-
// things, this is probably introduced in java 1.5. awesome!
|
|
542
|
-
// http://dev.processing.org/bugs/show_bug.cgi?id=359
|
|
543
|
-
if (!cn.equals("sun.plugin.cache.EmptyInputStream")) {
|
|
544
|
-
stream.close();
|
|
545
|
-
return "data/" + filename;
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// When used with an online script, also need to check without the
|
|
550
|
-
// data folder, in case it's not in a subfolder called 'data'.
|
|
551
|
-
// http://dev.processing.org/bugs/show_bug.cgi?id=389
|
|
552
|
-
stream = cl.getResourceAsStream(filename);
|
|
553
|
-
if (stream != null) {
|
|
554
|
-
String cn = stream.getClass().getName();
|
|
555
|
-
if (!cn.equals("sun.plugin.cache.EmptyInputStream")) {
|
|
556
|
-
stream.close();
|
|
557
|
-
return filename;
|
|
558
|
-
}
|
|
559
|
-
}
|
|
655
|
+
String path = sketch.sketchPath(filename);
|
|
656
|
+
stream = new FileInputStream(path);
|
|
657
|
+
if (stream != null) {
|
|
658
|
+
stream.close();
|
|
659
|
+
return path;
|
|
660
|
+
}
|
|
560
661
|
} catch (IOException e) {
|
|
561
|
-
}
|
|
662
|
+
} // ignored
|
|
562
663
|
|
|
563
664
|
try {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
if (stream != null) {
|
|
571
|
-
stream.close();
|
|
572
|
-
return path;
|
|
573
|
-
}
|
|
574
|
-
} catch (IOException e2) {
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
try {
|
|
578
|
-
String path = sketch.sketchPath(filename);
|
|
579
|
-
stream = new FileInputStream(path);
|
|
580
|
-
if (stream != null) {
|
|
581
|
-
stream.close();
|
|
582
|
-
return path;
|
|
583
|
-
}
|
|
584
|
-
} catch (Exception e) {
|
|
585
|
-
} // ignored
|
|
586
|
-
|
|
587
|
-
try {
|
|
588
|
-
stream = new FileInputStream(filename);
|
|
589
|
-
if (stream != null) {
|
|
590
|
-
stream.close();
|
|
591
|
-
return filename;
|
|
592
|
-
}
|
|
593
|
-
} catch (IOException e1) {
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
} catch (SecurityException se) {
|
|
597
|
-
} // online, whups
|
|
598
|
-
|
|
599
|
-
} catch (Exception e) {
|
|
600
|
-
//die(e.getMessage(), e);
|
|
601
|
-
e.printStackTrace();
|
|
665
|
+
stream = new FileInputStream(filename);
|
|
666
|
+
if (stream != null) {
|
|
667
|
+
stream.close();
|
|
668
|
+
return filename;
|
|
669
|
+
}
|
|
670
|
+
} catch (IOException e1) {
|
|
602
671
|
}
|
|
603
672
|
|
|
604
|
-
|
|
673
|
+
} catch (SecurityException se) {
|
|
674
|
+
} // online, whups
|
|
675
|
+
|
|
676
|
+
} catch (Exception e) {
|
|
677
|
+
//die(e.getMessage(), e);
|
|
678
|
+
|
|
605
679
|
}
|
|
606
680
|
|
|
607
|
-
|
|
608
|
-
|
|
681
|
+
return "";
|
|
682
|
+
}
|
|
609
683
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
}
|
|
684
|
+
@Override
|
|
685
|
+
public void placeWindow(int[] location, int[] editorLocation) {
|
|
613
686
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
687
|
+
if (sketch.sketchFullScreen()) {
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
int x = window.getX() - window.getInsets().getLeftWidth();
|
|
692
|
+
int y = window.getY() - window.getInsets().getTopHeight();
|
|
693
|
+
int w = window.getWidth() + window.getInsets().getTotalWidth();
|
|
694
|
+
int h = window.getHeight() + window.getInsets().getTotalHeight();
|
|
618
695
|
|
|
619
|
-
|
|
696
|
+
if (location != null) {
|
|
620
697
|
// System.err.println("place window at " + location[0] + ", " + location[1]);
|
|
621
|
-
|
|
698
|
+
window.setTopLevelPosition(location[0], location[1]);
|
|
622
699
|
|
|
623
|
-
|
|
700
|
+
} else if (editorLocation != null) {
|
|
624
701
|
// System.err.println("place window at editor location " + editorLocation[0] + ", " + editorLocation[1]);
|
|
625
|
-
|
|
626
|
-
|
|
702
|
+
int locationX = editorLocation[0] - 20;
|
|
703
|
+
int locationY = editorLocation[1];
|
|
627
704
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
705
|
+
if (locationX - w > 10) {
|
|
706
|
+
// if it fits to the left of the window
|
|
707
|
+
window.setTopLevelPosition(locationX - w, locationY);
|
|
631
708
|
|
|
632
|
-
|
|
633
|
-
|
|
709
|
+
} else { // doesn't fit
|
|
710
|
+
/*
|
|
634
711
|
// if it fits inside the editor window,
|
|
635
712
|
// offset slightly from upper lefthand corner
|
|
636
713
|
// so that it's plunked inside the text area
|
|
@@ -640,659 +717,666 @@ public class PSurfaceJOGL implements PSurface {
|
|
|
640
717
|
if ((locationX + w > sketch.displayWidth - 33) ||
|
|
641
718
|
(locationY + h > sketch.displayHeight - 33)) {
|
|
642
719
|
// otherwise center on screen
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
}
|
|
648
|
-
*/
|
|
649
|
-
window.setTopLevelPosition(locationX, locationY);
|
|
650
|
-
}
|
|
651
|
-
} else { // just center on screen
|
|
652
|
-
// Can't use frame.setLocationRelativeTo(null) because it sends the
|
|
653
|
-
// frame to the main display, which undermines the --display setting.
|
|
654
|
-
window.setTopLevelPosition(screenRect.x + (screenRect.width - sketchWidth) / 2,
|
|
655
|
-
screenRect.y + (screenRect.height - sketchHeight) / 2);
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
Point frameLoc = new Point(x, y);
|
|
659
|
-
if (frameLoc.y < 0) {
|
|
660
|
-
// Windows actually allows you to place frames where they can't be
|
|
661
|
-
// closed. Awesome. http://dev.processing.org/bugs/show_bug.cgi?id=1508
|
|
662
|
-
window.setTopLevelPosition(frameLoc.x, 30);
|
|
720
|
+
*/
|
|
721
|
+
locationX = (sketch.displayWidth - w) / 2;
|
|
722
|
+
locationY = (sketch.displayHeight - h) / 2;
|
|
723
|
+
/*
|
|
663
724
|
}
|
|
725
|
+
*/
|
|
726
|
+
window.setTopLevelPosition(locationX, locationY);
|
|
727
|
+
}
|
|
728
|
+
} else { // just center on screen
|
|
729
|
+
// Can't use frame.setLocationRelativeTo(null) because it sends the
|
|
730
|
+
// frame to the main display, which undermines the --display setting.
|
|
731
|
+
window.setTopLevelPosition(screenRect.x + (screenRect.width - sketchWidth) / 2,
|
|
732
|
+
screenRect.y + (screenRect.height - sketchHeight) / 2);
|
|
664
733
|
}
|
|
665
734
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
window.setUndecorated(true);
|
|
673
|
-
window.setTopLevelPosition((int) displayRect.getX(), (int) displayRect.getY());
|
|
674
|
-
window.setTopLevelSize((int) displayRect.getWidth(), (int) displayRect.getHeight());
|
|
735
|
+
Point frameLoc = new Point(x, y);
|
|
736
|
+
if (frameLoc.y < 0) {
|
|
737
|
+
// Windows actually allows you to place frames where they can't be
|
|
738
|
+
// closed. Awesome. http://dev.processing.org/bugs/show_bug.cgi?id=1508
|
|
739
|
+
window.setTopLevelPosition(frameLoc.x, 30);
|
|
675
740
|
}
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
@Override
|
|
744
|
+
public void placePresent(int stopColor) {
|
|
745
|
+
float scale = getPixelScale();
|
|
746
|
+
pgl.initPresentMode(0.5f * (screenRect.width / scale - sketchWidth),
|
|
747
|
+
0.5f * (screenRect.height / scale - sketchHeight), stopColor);
|
|
748
|
+
PApplet.hideMenuBar();
|
|
749
|
+
|
|
750
|
+
window.setUndecorated(true);
|
|
751
|
+
window.setTopLevelPosition((int) displayRect.getX(), (int) displayRect.getY());
|
|
752
|
+
window.setTopLevelSize((int) displayRect.getWidth(), (int) displayRect.getHeight());
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
@Override
|
|
756
|
+
public void setupExternalMessages() {
|
|
757
|
+
external = true;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
@Override
|
|
761
|
+
public void startThread() {
|
|
762
|
+
if (animator != null) {
|
|
763
|
+
animator.start();
|
|
679
764
|
}
|
|
765
|
+
}
|
|
680
766
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
}
|
|
767
|
+
public void pauseThread() {
|
|
768
|
+
if (animator != null) {
|
|
769
|
+
animator.pause();
|
|
685
770
|
}
|
|
771
|
+
}
|
|
686
772
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
773
|
+
@Override
|
|
774
|
+
public void resumeThread() {
|
|
775
|
+
if (animator != null) {
|
|
776
|
+
animator.resume();
|
|
691
777
|
}
|
|
778
|
+
}
|
|
692
779
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
780
|
+
@Override
|
|
781
|
+
public boolean stopThread() {
|
|
782
|
+
if (drawExceptionHandler != null) {
|
|
783
|
+
drawExceptionHandler.interrupt();
|
|
784
|
+
drawExceptionHandler = null;
|
|
697
785
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
drawExceptionHandler = null;
|
|
703
|
-
}
|
|
704
|
-
if (animator != null) {
|
|
705
|
-
return animator.stop();
|
|
706
|
-
} else {
|
|
707
|
-
return false;
|
|
708
|
-
}
|
|
786
|
+
if (animator != null) {
|
|
787
|
+
return animator.stop();
|
|
788
|
+
} else {
|
|
789
|
+
return false;
|
|
709
790
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
@Override
|
|
794
|
+
public boolean isStopped() {
|
|
795
|
+
if (animator != null) {
|
|
796
|
+
return !animator.isAnimating();
|
|
797
|
+
} else {
|
|
798
|
+
return true;
|
|
717
799
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
@Override
|
|
803
|
+
public void setLocation(final int x, final int y) {
|
|
804
|
+
display.getEDTUtil().invoke(false, () -> {
|
|
805
|
+
window.setTopLevelPosition(x, y);
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
@Override
|
|
810
|
+
public void setSize(int wide, int high) {
|
|
811
|
+
if (pgl.presentMode()) {
|
|
812
|
+
return;
|
|
726
813
|
}
|
|
727
814
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
high = 1;
|
|
738
|
-
}
|
|
739
|
-
if (wide <= 0) {
|
|
740
|
-
wide = 1;
|
|
741
|
-
}
|
|
815
|
+
// When the surface is set to resizable via surface.setResizable(true),
|
|
816
|
+
// a crash may occur if the user sets the window to size zero.
|
|
817
|
+
// https://github.com/processing/processing/issues/5052
|
|
818
|
+
if (high <= 0) {
|
|
819
|
+
high = 1;
|
|
820
|
+
}
|
|
821
|
+
if (wide <= 0) {
|
|
822
|
+
wide = 1;
|
|
823
|
+
}
|
|
742
824
|
|
|
743
|
-
|
|
825
|
+
boolean changed = sketch.width != wide || sketch.height != high;
|
|
744
826
|
|
|
745
|
-
|
|
746
|
-
|
|
827
|
+
sketchWidth = wide;
|
|
828
|
+
sketchHeight = high;
|
|
747
829
|
|
|
748
|
-
|
|
749
|
-
|
|
830
|
+
sketch.setSize(wide, high);
|
|
831
|
+
graphics.setSize(wide, high);
|
|
750
832
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
}
|
|
833
|
+
if (changed) {
|
|
834
|
+
window.setSize(wide * windowScaleFactor, high * windowScaleFactor);
|
|
754
835
|
}
|
|
836
|
+
}
|
|
755
837
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
if (PApplet.platform == PConstants.MACOSX) {
|
|
762
|
-
return getCurrentPixelScale();
|
|
763
|
-
}
|
|
838
|
+
public float getPixelScale() {
|
|
839
|
+
if (graphics.pixelDensity == 1) {
|
|
840
|
+
return 1;
|
|
841
|
+
}
|
|
764
842
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
private float getCurrentPixelScale() {
|
|
769
|
-
// Even if the graphics are retina, the user might have moved the window
|
|
770
|
-
// into a non-retina monitor, so we need to check
|
|
771
|
-
window.getCurrentSurfaceScale(currentPixelScale);
|
|
772
|
-
return currentPixelScale[0];
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
public Component getComponent() {
|
|
776
|
-
return canvas;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
public void setSmooth(int level) {
|
|
780
|
-
pgl.reqNumSamples = level;
|
|
781
|
-
GLCapabilities caps = new GLCapabilities(profile);
|
|
782
|
-
caps.setAlphaBits(PGL.REQUESTED_ALPHA_BITS);
|
|
783
|
-
caps.setDepthBits(PGL.REQUESTED_DEPTH_BITS);
|
|
784
|
-
caps.setStencilBits(PGL.REQUESTED_STENCIL_BITS);
|
|
785
|
-
caps.setSampleBuffers(true);
|
|
786
|
-
caps.setNumSamples(pgl.reqNumSamples);
|
|
787
|
-
caps.setBackgroundOpaque(true);
|
|
788
|
-
caps.setOnscreen(true);
|
|
789
|
-
NativeSurface target = window.getNativeSurface();
|
|
790
|
-
MutableGraphicsConfiguration config = (MutableGraphicsConfiguration) target.getGraphicsConfiguration();
|
|
791
|
-
config.setChosenCapabilities(caps);
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
public void setFrameRate(float fps) {
|
|
795
|
-
if (fps < 1) {
|
|
796
|
-
PGraphics.showWarning(
|
|
797
|
-
"The OpenGL renderer cannot have a frame rate lower than 1.\n"
|
|
798
|
-
+ "Your sketch will run at 1 frame per second.");
|
|
799
|
-
fps = 1;
|
|
800
|
-
} else if (fps > 1000) {
|
|
801
|
-
PGraphics.showWarning(
|
|
802
|
-
"The OpenGL renderer cannot have a frame rate higher than 1000.\n"
|
|
803
|
-
+ "Your sketch will run at 1000 frames per second.");
|
|
804
|
-
fps = 1000;
|
|
805
|
-
}
|
|
806
|
-
if (animator != null) {
|
|
807
|
-
animator.stop();
|
|
808
|
-
animator.setFPS((int) fps);
|
|
809
|
-
pgl.setFps(fps);
|
|
810
|
-
animator.start();
|
|
811
|
-
}
|
|
843
|
+
if (PApplet.platform == PConstants.MACOS) {
|
|
844
|
+
return getCurrentPixelScale();
|
|
812
845
|
}
|
|
813
846
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
847
|
+
return 2;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
private float getCurrentPixelScale() {
|
|
851
|
+
// Even if the graphics are retina, the user might have moved the window
|
|
852
|
+
// into a non-retina monitor, so we need to check
|
|
853
|
+
window.getCurrentSurfaceScale(currentPixelScale);
|
|
854
|
+
return currentPixelScale[0];
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
public Component getComponent() {
|
|
858
|
+
return canvas;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
public void setSmooth(int level) {
|
|
862
|
+
pgl.reqNumSamples = level;
|
|
863
|
+
GLCapabilities caps = new GLCapabilities(profile);
|
|
864
|
+
caps.setAlphaBits(PGL.REQUESTED_ALPHA_BITS);
|
|
865
|
+
caps.setDepthBits(PGL.REQUESTED_DEPTH_BITS);
|
|
866
|
+
caps.setStencilBits(PGL.REQUESTED_STENCIL_BITS);
|
|
867
|
+
caps.setSampleBuffers(true);
|
|
868
|
+
caps.setNumSamples(pgl.reqNumSamples);
|
|
869
|
+
caps.setBackgroundOpaque(true);
|
|
870
|
+
caps.setOnscreen(true);
|
|
871
|
+
NativeSurface target = window.getNativeSurface();
|
|
872
|
+
MutableGraphicsConfiguration config = (MutableGraphicsConfiguration) target.getGraphicsConfiguration();
|
|
873
|
+
config.setChosenCapabilities(caps);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
@Override
|
|
877
|
+
public void setFrameRate(float fps) {
|
|
878
|
+
if (fps < 1) {
|
|
879
|
+
PGraphics.showWarning(
|
|
880
|
+
"The OpenGL renderer cannot have a frame rate lower than 1.\n"
|
|
881
|
+
+ "Your sketch will run at 1 frame per second.");
|
|
882
|
+
fps = 1;
|
|
883
|
+
} else if (fps > 1000) {
|
|
884
|
+
PGraphics.showWarning(
|
|
885
|
+
"The OpenGL renderer cannot have a frame rate higher than 1000.\n"
|
|
886
|
+
+ "Your sketch will run at 1000 frames per second.");
|
|
887
|
+
fps = 1000;
|
|
821
888
|
}
|
|
889
|
+
if (animator != null) {
|
|
890
|
+
animator.stop();
|
|
891
|
+
animator.setFPS((int) fps);
|
|
892
|
+
pgl.setFps(fps);
|
|
893
|
+
animator.start();
|
|
894
|
+
}
|
|
895
|
+
}
|
|
822
896
|
|
|
823
|
-
|
|
897
|
+
public void requestFocus() {
|
|
898
|
+
display.getEDTUtil().invoke(false, () -> {
|
|
899
|
+
window.requestFocus();
|
|
900
|
+
});
|
|
901
|
+
}
|
|
824
902
|
|
|
825
|
-
|
|
826
|
-
if (display.getEDTUtil().isCurrentThreadEDT()) {
|
|
827
|
-
// For some reason, the first two frames of the animator are run on the
|
|
828
|
-
// EDT, skipping rendering Processing's frame in that case.
|
|
829
|
-
return;
|
|
830
|
-
}
|
|
903
|
+
class DrawListener implements GLEventListener {
|
|
831
904
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
905
|
+
@Override
|
|
906
|
+
public void display(GLAutoDrawable drawable) {
|
|
907
|
+
if (display.getEDTUtil().isCurrentThreadEDT()) {
|
|
908
|
+
// For some reason, the first two frames of the animator are run on the
|
|
909
|
+
// EDT, skipping rendering Processing's frame in that case.
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
if (sketch.frameCount == 0) {
|
|
914
|
+
if (sketchWidth < sketchWidth0 || sketchHeight < sketchHeight0) {
|
|
915
|
+
PGraphics.showWarning("The sketch has been automatically resized to fit the screen resolution");
|
|
916
|
+
}
|
|
836
917
|
// System.out.println("display: " + window.getWidth() + " "+ window.getHeight() + " - " + sketchWidth + " " + sketchHeight);
|
|
837
|
-
|
|
838
|
-
|
|
918
|
+
requestFocus();
|
|
919
|
+
}
|
|
839
920
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
921
|
+
if (!sketch.finished) {
|
|
922
|
+
pgl.getGL(drawable);
|
|
923
|
+
int pframeCount = sketch.frameCount;
|
|
924
|
+
sketch.handleDraw();
|
|
925
|
+
if (pframeCount == sketch.frameCount || sketch.finished) {
|
|
926
|
+
// This hack allows the FBO layer to be swapped normally even if
|
|
927
|
+
// the sketch is no looping or finished because it does not call draw(),
|
|
928
|
+
// otherwise background artifacts may occur (depending on the hardware/drivers).
|
|
929
|
+
pgl.beginRender();
|
|
930
|
+
pgl.endRender(sketch.sketchWindowColor());
|
|
931
|
+
}
|
|
932
|
+
PGraphicsOpenGL.completeFinishedPixelTransfers();
|
|
933
|
+
}
|
|
853
934
|
|
|
854
|
-
|
|
855
|
-
|
|
935
|
+
if (sketch.exitCalled()) {
|
|
936
|
+
PGraphicsOpenGL.completeAllPixelTransfers();
|
|
856
937
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
938
|
+
sketch.dispose(); // calls stopThread(), which stops the animator.
|
|
939
|
+
sketch.exitActual();
|
|
940
|
+
}
|
|
941
|
+
}
|
|
861
942
|
|
|
862
|
-
|
|
943
|
+
@Override
|
|
944
|
+
public void dispose(GLAutoDrawable drawable) {
|
|
863
945
|
// sketch.dispose();
|
|
864
|
-
|
|
946
|
+
}
|
|
865
947
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
948
|
+
@Override
|
|
949
|
+
public void init(GLAutoDrawable drawable) {
|
|
950
|
+
pgl.getGL(drawable);
|
|
951
|
+
pgl.init(drawable);
|
|
952
|
+
sketch.start();
|
|
953
|
+
|
|
954
|
+
int c = graphics.backgroundColor;
|
|
955
|
+
pgl.clearColor(((c >> 16) & 0xff) / 255f,
|
|
956
|
+
((c >> 8) & 0xff) / 255f,
|
|
957
|
+
((c) & 0xff) / 255f,
|
|
958
|
+
((c >> 24) & 0xff) / 255f);
|
|
959
|
+
pgl.clear(PGL.COLOR_BUFFER_BIT);
|
|
960
|
+
}
|
|
878
961
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
962
|
+
@Override
|
|
963
|
+
public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
|
|
964
|
+
pgl.resetFBOLayer();
|
|
965
|
+
pgl.getGL(drawable);
|
|
966
|
+
float scale = PApplet.platform == PConstants.MACOS
|
|
967
|
+
? getCurrentPixelScale() : getPixelScale();
|
|
968
|
+
setSize((int) (w / scale), (int) (h / scale));
|
|
886
969
|
}
|
|
970
|
+
}
|
|
887
971
|
|
|
888
|
-
|
|
972
|
+
protected class NEWTWindowListener implements com.jogamp.newt.event.WindowListener {
|
|
889
973
|
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
974
|
+
public NEWTWindowListener() {
|
|
975
|
+
super();
|
|
976
|
+
}
|
|
893
977
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
978
|
+
@Override
|
|
979
|
+
public void windowGainedFocus(com.jogamp.newt.event.WindowEvent arg0) {
|
|
980
|
+
sketch.focused = true;
|
|
981
|
+
sketch.focusGained();
|
|
982
|
+
}
|
|
899
983
|
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
984
|
+
@Override
|
|
985
|
+
public void windowLostFocus(com.jogamp.newt.event.WindowEvent arg0) {
|
|
986
|
+
sketch.focused = false;
|
|
987
|
+
sketch.focusLost();
|
|
988
|
+
}
|
|
905
989
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
990
|
+
@Override
|
|
991
|
+
public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) {
|
|
992
|
+
sketch.exit();
|
|
993
|
+
}
|
|
910
994
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
995
|
+
@Override
|
|
996
|
+
public void windowDestroyed(com.jogamp.newt.event.WindowEvent arg0) {
|
|
997
|
+
sketch.exit();
|
|
998
|
+
}
|
|
915
999
|
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1000
|
+
@Override
|
|
1001
|
+
public void windowMoved(com.jogamp.newt.event.WindowEvent arg0) {
|
|
1002
|
+
if (external) {
|
|
1003
|
+
sketch.frameMoved(window.getX(), window.getY());
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
922
1006
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1007
|
+
@Override
|
|
1008
|
+
public void windowRepaint(com.jogamp.newt.event.WindowUpdateEvent arg0) {
|
|
1009
|
+
}
|
|
926
1010
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
}
|
|
1011
|
+
@Override
|
|
1012
|
+
public void windowResized(com.jogamp.newt.event.WindowEvent arg0) {
|
|
930
1013
|
}
|
|
1014
|
+
}
|
|
931
1015
|
|
|
932
|
-
|
|
933
|
-
|
|
1016
|
+
// NEWT mouse listener
|
|
1017
|
+
protected class NEWTMouseListener extends com.jogamp.newt.event.MouseAdapter {
|
|
934
1018
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1019
|
+
public NEWTMouseListener() {
|
|
1020
|
+
super();
|
|
1021
|
+
}
|
|
938
1022
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1023
|
+
@Override
|
|
1024
|
+
public void mousePressed(com.jogamp.newt.event.MouseEvent e) {
|
|
1025
|
+
nativeMouseEvent(e, MouseEvent.PRESS);
|
|
1026
|
+
}
|
|
943
1027
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1028
|
+
@Override
|
|
1029
|
+
public void mouseReleased(com.jogamp.newt.event.MouseEvent e) {
|
|
1030
|
+
nativeMouseEvent(e, MouseEvent.RELEASE);
|
|
1031
|
+
}
|
|
948
1032
|
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1033
|
+
@Override
|
|
1034
|
+
public void mouseClicked(com.jogamp.newt.event.MouseEvent e) {
|
|
1035
|
+
nativeMouseEvent(e, MouseEvent.CLICK);
|
|
1036
|
+
}
|
|
953
1037
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1038
|
+
@Override
|
|
1039
|
+
public void mouseDragged(com.jogamp.newt.event.MouseEvent e) {
|
|
1040
|
+
nativeMouseEvent(e, MouseEvent.DRAG);
|
|
1041
|
+
}
|
|
958
1042
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1043
|
+
@Override
|
|
1044
|
+
public void mouseMoved(com.jogamp.newt.event.MouseEvent e) {
|
|
1045
|
+
nativeMouseEvent(e, MouseEvent.MOVE);
|
|
1046
|
+
}
|
|
963
1047
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1048
|
+
@Override
|
|
1049
|
+
public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) {
|
|
1050
|
+
nativeMouseEvent(e, MouseEvent.WHEEL);
|
|
1051
|
+
}
|
|
968
1052
|
|
|
969
|
-
|
|
970
|
-
|
|
1053
|
+
@Override
|
|
1054
|
+
public void mouseEntered(com.jogamp.newt.event.MouseEvent e) {
|
|
971
1055
|
// System.out.println("enter");
|
|
972
|
-
|
|
973
|
-
|
|
1056
|
+
nativeMouseEvent(e, MouseEvent.ENTER);
|
|
1057
|
+
}
|
|
974
1058
|
|
|
975
|
-
|
|
976
|
-
|
|
1059
|
+
@Override
|
|
1060
|
+
public void mouseExited(com.jogamp.newt.event.MouseEvent e) {
|
|
977
1061
|
// System.out.println("exit");
|
|
978
|
-
|
|
979
|
-
}
|
|
1062
|
+
nativeMouseEvent(e, MouseEvent.EXIT);
|
|
980
1063
|
}
|
|
1064
|
+
}
|
|
981
1065
|
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
public NEWTKeyListener() {
|
|
986
|
-
super();
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
@Override
|
|
990
|
-
public void keyPressed(com.jogamp.newt.event.KeyEvent e) {
|
|
991
|
-
nativeKeyEvent(e, KeyEvent.PRESS);
|
|
992
|
-
}
|
|
1066
|
+
// NEWT key listener
|
|
1067
|
+
protected class NEWTKeyListener extends com.jogamp.newt.event.KeyAdapter {
|
|
993
1068
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
nativeKeyEvent(e, KeyEvent.RELEASE);
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
public void keyTyped(com.jogamp.newt.event.KeyEvent e) {
|
|
1000
|
-
nativeKeyEvent(e, KeyEvent.TYPE);
|
|
1001
|
-
}
|
|
1069
|
+
public NEWTKeyListener() {
|
|
1070
|
+
super();
|
|
1002
1071
|
}
|
|
1003
1072
|
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
& (InputEvent.SHIFT_MASK
|
|
1009
|
-
| InputEvent.CTRL_MASK
|
|
1010
|
-
| InputEvent.META_MASK
|
|
1011
|
-
| InputEvent.ALT_MASK);
|
|
1012
|
-
|
|
1013
|
-
int peButton = 0;
|
|
1014
|
-
switch (nativeEvent.getButton()) {
|
|
1015
|
-
case com.jogamp.newt.event.MouseEvent.BUTTON1:
|
|
1016
|
-
peButton = PConstants.LEFT;
|
|
1017
|
-
break;
|
|
1018
|
-
case com.jogamp.newt.event.MouseEvent.BUTTON2:
|
|
1019
|
-
peButton = PConstants.CENTER;
|
|
1020
|
-
break;
|
|
1021
|
-
case com.jogamp.newt.event.MouseEvent.BUTTON3:
|
|
1022
|
-
peButton = PConstants.RIGHT;
|
|
1023
|
-
break;
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
if (PApplet.platform == PConstants.MACOSX) {
|
|
1027
|
-
//if (nativeEvent.isPopupTrigger()) {
|
|
1028
|
-
if ((modifiers & InputEvent.CTRL_MASK) != 0) {
|
|
1029
|
-
peButton = PConstants.RIGHT;
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
int peCount = 0;
|
|
1034
|
-
if (peAction == MouseEvent.WHEEL) {
|
|
1035
|
-
// Invert wheel rotation count so it matches JAVA2D's
|
|
1036
|
-
// https://github.com/processing/processing/issues/3840
|
|
1037
|
-
peCount = -(nativeEvent.isShiftDown() ? (int) nativeEvent.getRotation()[0]
|
|
1038
|
-
: (int) nativeEvent.getRotation()[1]);
|
|
1039
|
-
} else {
|
|
1040
|
-
peCount = nativeEvent.getClickCount();
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
int scale;
|
|
1044
|
-
if (PApplet.platform == PConstants.MACOSX) {
|
|
1045
|
-
scale = (int) getCurrentPixelScale();
|
|
1046
|
-
} else {
|
|
1047
|
-
scale = (int) getPixelScale();
|
|
1048
|
-
}
|
|
1049
|
-
int sx = nativeEvent.getX() / scale;
|
|
1050
|
-
int sy = nativeEvent.getY() / scale;
|
|
1051
|
-
int mx = sx;
|
|
1052
|
-
int my = sy;
|
|
1053
|
-
|
|
1054
|
-
if (pgl.presentMode()) {
|
|
1055
|
-
mx -= (int) pgl.presentX;
|
|
1056
|
-
my -= (int) pgl.presentY;
|
|
1057
|
-
if (peAction == KeyEvent.RELEASE
|
|
1058
|
-
&& pgl.insideStopButton(sx, sy - screenRect.height / windowScaleFactor)) {
|
|
1059
|
-
sketch.exit();
|
|
1060
|
-
}
|
|
1061
|
-
if (mx < 0 || sketchWidth < mx || my < 0 || sketchHeight < my) {
|
|
1062
|
-
return;
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
MouseEvent me = new MouseEvent(nativeEvent, nativeEvent.getWhen(),
|
|
1067
|
-
peAction, peModifiers,
|
|
1068
|
-
mx, my,
|
|
1069
|
-
peButton,
|
|
1070
|
-
peCount);
|
|
1071
|
-
|
|
1072
|
-
sketch.postEvent(me);
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
protected void nativeKeyEvent(com.jogamp.newt.event.KeyEvent nativeEvent,
|
|
1076
|
-
int peAction) {
|
|
1077
|
-
int peModifiers = nativeEvent.getModifiers()
|
|
1078
|
-
& (InputEvent.SHIFT_MASK
|
|
1079
|
-
| InputEvent.CTRL_MASK
|
|
1080
|
-
| InputEvent.META_MASK
|
|
1081
|
-
| InputEvent.ALT_MASK);
|
|
1082
|
-
|
|
1083
|
-
short code = nativeEvent.getKeyCode();
|
|
1084
|
-
char keyChar;
|
|
1085
|
-
int keyCode;
|
|
1086
|
-
if (isPCodedKey(code)) {
|
|
1087
|
-
keyCode = mapToPConst(code);
|
|
1088
|
-
keyChar = PConstants.CODED;
|
|
1089
|
-
} else if (isHackyKey(code)) {
|
|
1090
|
-
// we can return only one char for ENTER, let it be \n everywhere
|
|
1091
|
-
keyCode = code == com.jogamp.newt.event.KeyEvent.VK_ENTER
|
|
1092
|
-
? PConstants.ENTER : code;
|
|
1093
|
-
keyChar = hackToChar(code, nativeEvent.getKeyChar());
|
|
1094
|
-
} else {
|
|
1095
|
-
keyCode = code;
|
|
1096
|
-
keyChar = nativeEvent.getKeyChar();
|
|
1097
|
-
}
|
|
1073
|
+
@Override
|
|
1074
|
+
public void keyPressed(com.jogamp.newt.event.KeyEvent e) {
|
|
1075
|
+
nativeKeyEvent(e, KeyEvent.PRESS);
|
|
1076
|
+
}
|
|
1098
1077
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
// public final short getKeyCode()
|
|
1103
|
-
// Returns the virtual key code using a fixed mapping to the US keyboard layout.
|
|
1104
|
-
// In contrast to key symbol, key code uses a fixed US keyboard layout and therefore is keyboard layout independent.
|
|
1105
|
-
// E.g. virtual key code VK_Y denotes the same physical key regardless whether keyboard layout QWERTY or QWERTZ is active. The key symbol of the former is VK_Y, where the latter produces VK_Y.
|
|
1106
|
-
KeyEvent ke = new KeyEvent(nativeEvent, nativeEvent.getWhen(),
|
|
1107
|
-
peAction, peModifiers,
|
|
1108
|
-
keyChar,
|
|
1109
|
-
keyCode,
|
|
1110
|
-
nativeEvent.isAutoRepeat());
|
|
1111
|
-
|
|
1112
|
-
sketch.postEvent(ke);
|
|
1113
|
-
|
|
1114
|
-
if (!isPCodedKey(code) && !isHackyKey(code)) {
|
|
1115
|
-
if (peAction == KeyEvent.PRESS) {
|
|
1116
|
-
// Create key typed event
|
|
1117
|
-
// TODO: combine dead keys with the following key
|
|
1118
|
-
KeyEvent tke = new KeyEvent(nativeEvent, nativeEvent.getWhen(),
|
|
1119
|
-
KeyEvent.TYPE, peModifiers,
|
|
1120
|
-
keyChar,
|
|
1121
|
-
0,
|
|
1122
|
-
nativeEvent.isAutoRepeat());
|
|
1123
|
-
|
|
1124
|
-
sketch.postEvent(tke);
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1078
|
+
@Override
|
|
1079
|
+
public void keyReleased(com.jogamp.newt.event.KeyEvent e) {
|
|
1080
|
+
nativeKeyEvent(e, KeyEvent.RELEASE);
|
|
1127
1081
|
}
|
|
1128
1082
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|| code == com.jogamp.newt.event.KeyEvent.VK_DOWN
|
|
1132
|
-
|| code == com.jogamp.newt.event.KeyEvent.VK_LEFT
|
|
1133
|
-
|| code == com.jogamp.newt.event.KeyEvent.VK_RIGHT
|
|
1134
|
-
|| code == com.jogamp.newt.event.KeyEvent.VK_ALT
|
|
1135
|
-
|| code == com.jogamp.newt.event.KeyEvent.VK_CONTROL
|
|
1136
|
-
|| code == com.jogamp.newt.event.KeyEvent.VK_SHIFT
|
|
1137
|
-
|| code == com.jogamp.newt.event.KeyEvent.VK_WINDOWS;
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
|
-
// Why do we need this mapping?
|
|
1141
|
-
// Relevant discussion and links here:
|
|
1142
|
-
// http://forum.jogamp.org/Newt-wrong-keycode-for-key-td4033690.html#a4033697
|
|
1143
|
-
// (I don't think this is a complete solution).
|
|
1144
|
-
private static int mapToPConst(short code) {
|
|
1145
|
-
switch (code) {
|
|
1146
|
-
case com.jogamp.newt.event.KeyEvent.VK_UP:
|
|
1147
|
-
return PConstants.UP;
|
|
1148
|
-
case com.jogamp.newt.event.KeyEvent.VK_DOWN:
|
|
1149
|
-
return PConstants.DOWN;
|
|
1150
|
-
case com.jogamp.newt.event.KeyEvent.VK_LEFT:
|
|
1151
|
-
return PConstants.LEFT;
|
|
1152
|
-
case com.jogamp.newt.event.KeyEvent.VK_RIGHT:
|
|
1153
|
-
return PConstants.RIGHT;
|
|
1154
|
-
case com.jogamp.newt.event.KeyEvent.VK_ALT:
|
|
1155
|
-
return PConstants.ALT;
|
|
1156
|
-
case com.jogamp.newt.event.KeyEvent.VK_CONTROL:
|
|
1157
|
-
return PConstants.CONTROL;
|
|
1158
|
-
case com.jogamp.newt.event.KeyEvent.VK_SHIFT:
|
|
1159
|
-
return PConstants.SHIFT;
|
|
1160
|
-
case com.jogamp.newt.event.KeyEvent.VK_WINDOWS:
|
|
1161
|
-
return java.awt.event.KeyEvent.VK_META;
|
|
1162
|
-
default:
|
|
1163
|
-
return code;
|
|
1164
|
-
}
|
|
1083
|
+
public void keyTyped(com.jogamp.newt.event.KeyEvent e) {
|
|
1084
|
+
nativeKeyEvent(e, KeyEvent.TYPE);
|
|
1165
1085
|
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent,
|
|
1089
|
+
int peAction) {
|
|
1090
|
+
int modifiers = nativeEvent.getModifiers();
|
|
1091
|
+
/*
|
|
1092
|
+
int peModifiers = modifiers &
|
|
1093
|
+
(InputEvent.SHIFT_MASK |
|
|
1094
|
+
InputEvent.CTRL_MASK |
|
|
1095
|
+
InputEvent.META_MASK |
|
|
1096
|
+
InputEvent.ALT_MASK);
|
|
1097
|
+
*/
|
|
1166
1098
|
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
private static char hackToChar(short code, char def) {
|
|
1180
|
-
switch (code) {
|
|
1181
|
-
case com.jogamp.newt.event.KeyEvent.VK_BACK_SPACE:
|
|
1182
|
-
return PConstants.BACKSPACE;
|
|
1183
|
-
case com.jogamp.newt.event.KeyEvent.VK_TAB:
|
|
1184
|
-
return PConstants.TAB;
|
|
1185
|
-
case com.jogamp.newt.event.KeyEvent.VK_ENTER:
|
|
1186
|
-
return PConstants.ENTER;
|
|
1187
|
-
case com.jogamp.newt.event.KeyEvent.VK_ESCAPE:
|
|
1188
|
-
return PConstants.ESC;
|
|
1189
|
-
case com.jogamp.newt.event.KeyEvent.VK_DELETE:
|
|
1190
|
-
return PConstants.DELETE;
|
|
1191
|
-
}
|
|
1192
|
-
return def;
|
|
1099
|
+
int peButton = 0;
|
|
1100
|
+
switch (nativeEvent.getButton()) {
|
|
1101
|
+
case com.jogamp.newt.event.MouseEvent.BUTTON1:
|
|
1102
|
+
peButton = PConstants.LEFT;
|
|
1103
|
+
break;
|
|
1104
|
+
case com.jogamp.newt.event.MouseEvent.BUTTON2:
|
|
1105
|
+
peButton = PConstants.CENTER;
|
|
1106
|
+
break;
|
|
1107
|
+
case com.jogamp.newt.event.MouseEvent.BUTTON3:
|
|
1108
|
+
peButton = PConstants.RIGHT;
|
|
1109
|
+
break;
|
|
1193
1110
|
}
|
|
1194
1111
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1112
|
+
int peCount = 0;
|
|
1113
|
+
if (peAction == MouseEvent.WHEEL) {
|
|
1114
|
+
// Invert wheel rotation count so it matches JAVA2D's
|
|
1115
|
+
// https://github.com/processing/processing/issues/3840
|
|
1116
|
+
peCount = -(nativeEvent.isShiftDown() ? (int) nativeEvent.getRotation()[0]
|
|
1117
|
+
: (int) nativeEvent.getRotation()[1]);
|
|
1118
|
+
} else {
|
|
1119
|
+
peCount = nativeEvent.getClickCount();
|
|
1120
|
+
}
|
|
1197
1121
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1122
|
+
int scale;
|
|
1123
|
+
if (PApplet.platform == PConstants.MACOS) {
|
|
1124
|
+
scale = (int) getCurrentPixelScale();
|
|
1125
|
+
} else {
|
|
1126
|
+
scale = (int) getPixelScale();
|
|
1127
|
+
}
|
|
1128
|
+
int sx = nativeEvent.getX() / scale;
|
|
1129
|
+
int sy = nativeEvent.getY() / scale;
|
|
1130
|
+
int mx = sx;
|
|
1131
|
+
int my = sy;
|
|
1132
|
+
|
|
1133
|
+
if (pgl.presentMode()) {
|
|
1134
|
+
mx -= (int) pgl.presentX;
|
|
1135
|
+
my -= (int) pgl.presentY;
|
|
1136
|
+
if (peAction == KeyEvent.RELEASE
|
|
1137
|
+
&& pgl.insideStopButton(sx, sy - screenRect.height / windowScaleFactor)) {
|
|
1138
|
+
sketch.exit();
|
|
1139
|
+
}
|
|
1140
|
+
if (mx < 0 || sketchWidth < mx || my < 0 || sketchHeight < my) {
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1200
1144
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1145
|
+
MouseEvent me = new MouseEvent(nativeEvent, nativeEvent.getWhen(),
|
|
1146
|
+
peAction, modifiers,
|
|
1147
|
+
mx, my,
|
|
1148
|
+
peButton,
|
|
1149
|
+
peCount);
|
|
1150
|
+
|
|
1151
|
+
sketch.postEvent(me);
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
protected void nativeKeyEvent(com.jogamp.newt.event.KeyEvent nativeEvent,
|
|
1155
|
+
int peAction) {
|
|
1156
|
+
int modifiers = nativeEvent.getModifiers();
|
|
1157
|
+
// int peModifiers = nativeEvent.getModifiers() &
|
|
1158
|
+
// (InputEvent.SHIFT_MASK |
|
|
1159
|
+
// InputEvent.CTRL_MASK |
|
|
1160
|
+
// InputEvent.META_MASK |
|
|
1161
|
+
// InputEvent.ALT_MASK);
|
|
1162
|
+
|
|
1163
|
+
short code = nativeEvent.getKeyCode();
|
|
1164
|
+
char keyChar;
|
|
1165
|
+
int keyCode;
|
|
1166
|
+
if (isPCodedKey(code)) {
|
|
1167
|
+
keyCode = mapToPConst(code);
|
|
1168
|
+
keyChar = PConstants.CODED;
|
|
1169
|
+
} else if (isHackyKey(code)) {
|
|
1170
|
+
// we can return only one char for ENTER, let it be \n everywhere
|
|
1171
|
+
keyCode = code == com.jogamp.newt.event.KeyEvent.VK_ENTER
|
|
1172
|
+
? PConstants.ENTER : code;
|
|
1173
|
+
keyChar = hackToChar(code, nativeEvent.getKeyChar());
|
|
1174
|
+
} else {
|
|
1175
|
+
keyCode = code;
|
|
1176
|
+
keyChar = nativeEvent.getKeyChar();
|
|
1177
|
+
}
|
|
1206
1178
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1179
|
+
// From http://jogamp.org/deployment/v2.1.0/javadoc/jogl/javadoc/com/jogamp/newt/event/KeyEvent.html
|
|
1180
|
+
// public final short getKeySymbol()
|
|
1181
|
+
// Returns the virtual key symbol reflecting the current keyboard layout.
|
|
1182
|
+
// public final short getKeyCode()
|
|
1183
|
+
// Returns the virtual key code using a fixed mapping to the US keyboard layout.
|
|
1184
|
+
// In contrast to key symbol, key code uses a fixed US keyboard layout and therefore is keyboard layout independent.
|
|
1185
|
+
// E.g. virtual key code VK_Y denotes the same physical key regardless whether keyboard layout QWERTY or QWERTZ is active. The key symbol of the former is VK_Y, where the latter produces VK_Y.
|
|
1186
|
+
KeyEvent ke = new KeyEvent(nativeEvent, nativeEvent.getWhen(),
|
|
1187
|
+
peAction, modifiers,
|
|
1188
|
+
keyChar,
|
|
1189
|
+
keyCode,
|
|
1190
|
+
nativeEvent.isAutoRepeat());
|
|
1191
|
+
|
|
1192
|
+
sketch.postEvent(ke);
|
|
1193
|
+
|
|
1194
|
+
if (!isPCodedKey(code) && !isHackyKey(code)) {
|
|
1195
|
+
if (peAction == KeyEvent.PRESS) {
|
|
1196
|
+
// Create key typed event
|
|
1197
|
+
// TODO: combine dead keys with the following key
|
|
1198
|
+
KeyEvent tke = new KeyEvent(nativeEvent, nativeEvent.getWhen(),
|
|
1199
|
+
KeyEvent.TYPE, modifiers,
|
|
1200
|
+
keyChar,
|
|
1201
|
+
0,
|
|
1202
|
+
nativeEvent.isAutoRepeat());
|
|
1203
|
+
|
|
1204
|
+
sketch.postEvent(tke);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
private static boolean isPCodedKey(short code) {
|
|
1210
|
+
return code == com.jogamp.newt.event.KeyEvent.VK_UP
|
|
1211
|
+
|| code == com.jogamp.newt.event.KeyEvent.VK_DOWN
|
|
1212
|
+
|| code == com.jogamp.newt.event.KeyEvent.VK_LEFT
|
|
1213
|
+
|| code == com.jogamp.newt.event.KeyEvent.VK_RIGHT
|
|
1214
|
+
|| code == com.jogamp.newt.event.KeyEvent.VK_ALT
|
|
1215
|
+
|| code == com.jogamp.newt.event.KeyEvent.VK_CONTROL
|
|
1216
|
+
|| code == com.jogamp.newt.event.KeyEvent.VK_SHIFT
|
|
1217
|
+
|| code == com.jogamp.newt.event.KeyEvent.VK_WINDOWS;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// Why do we need this mapping?
|
|
1221
|
+
// Relevant discussion and links here:
|
|
1222
|
+
// http://forum.jogamp.org/Newt-wrong-keycode-for-key-td4033690.html#a4033697
|
|
1223
|
+
// (I don't think this is a complete solution).
|
|
1224
|
+
private static int mapToPConst(short code) {
|
|
1225
|
+
switch (code) {
|
|
1226
|
+
case com.jogamp.newt.event.KeyEvent.VK_UP:
|
|
1227
|
+
return PConstants.UP;
|
|
1228
|
+
case com.jogamp.newt.event.KeyEvent.VK_DOWN:
|
|
1229
|
+
return PConstants.DOWN;
|
|
1230
|
+
case com.jogamp.newt.event.KeyEvent.VK_LEFT:
|
|
1231
|
+
return PConstants.LEFT;
|
|
1232
|
+
case com.jogamp.newt.event.KeyEvent.VK_RIGHT:
|
|
1233
|
+
return PConstants.RIGHT;
|
|
1234
|
+
case com.jogamp.newt.event.KeyEvent.VK_ALT:
|
|
1235
|
+
return PConstants.ALT;
|
|
1236
|
+
case com.jogamp.newt.event.KeyEvent.VK_CONTROL:
|
|
1237
|
+
return PConstants.CONTROL;
|
|
1238
|
+
case com.jogamp.newt.event.KeyEvent.VK_SHIFT:
|
|
1239
|
+
return PConstants.SHIFT;
|
|
1240
|
+
case com.jogamp.newt.event.KeyEvent.VK_WINDOWS:
|
|
1241
|
+
return java.awt.event.KeyEvent.VK_META;
|
|
1242
|
+
default:
|
|
1243
|
+
return code;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
private static boolean isHackyKey(short code) {
|
|
1248
|
+
switch (code) {
|
|
1249
|
+
case com.jogamp.newt.event.KeyEvent.VK_BACK_SPACE:
|
|
1250
|
+
case com.jogamp.newt.event.KeyEvent.VK_TAB:
|
|
1251
|
+
case com.jogamp.newt.event.KeyEvent.VK_ENTER:
|
|
1252
|
+
case com.jogamp.newt.event.KeyEvent.VK_ESCAPE:
|
|
1253
|
+
case com.jogamp.newt.event.KeyEvent.VK_DELETE:
|
|
1254
|
+
return true;
|
|
1255
|
+
}
|
|
1256
|
+
return false;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
private static char hackToChar(short code, char def) {
|
|
1260
|
+
switch (code) {
|
|
1261
|
+
case com.jogamp.newt.event.KeyEvent.VK_BACK_SPACE:
|
|
1262
|
+
return PConstants.BACKSPACE;
|
|
1263
|
+
case com.jogamp.newt.event.KeyEvent.VK_TAB:
|
|
1264
|
+
return PConstants.TAB;
|
|
1265
|
+
case com.jogamp.newt.event.KeyEvent.VK_ENTER:
|
|
1266
|
+
return PConstants.ENTER;
|
|
1267
|
+
case com.jogamp.newt.event.KeyEvent.VK_ESCAPE:
|
|
1268
|
+
return PConstants.ESC;
|
|
1269
|
+
case com.jogamp.newt.event.KeyEvent.VK_DELETE:
|
|
1270
|
+
return PConstants.DELETE;
|
|
1210
1271
|
}
|
|
1272
|
+
return def;
|
|
1273
|
+
}
|
|
1211
1274
|
|
|
1212
|
-
|
|
1213
|
-
|
|
1275
|
+
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
|
1276
|
+
class CursorInfo {
|
|
1214
1277
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
cursorNames.put(PConstants.CROSS, "cross");
|
|
1218
|
-
cursorNames.put(PConstants.WAIT, "wait");
|
|
1219
|
-
cursorNames.put(PConstants.MOVE, "move");
|
|
1220
|
-
cursorNames.put(PConstants.HAND, "hand");
|
|
1221
|
-
cursorNames.put(PConstants.TEXT, "text");
|
|
1222
|
-
}
|
|
1278
|
+
PImage image;
|
|
1279
|
+
int x, y;
|
|
1223
1280
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
}
|
|
1229
|
-
CursorInfo cursor = cursors.get(kind);
|
|
1230
|
-
if (cursor == null) {
|
|
1231
|
-
String name = cursorNames.get(kind);
|
|
1232
|
-
if (name != null) {
|
|
1233
|
-
ImageIcon icon
|
|
1234
|
-
= new ImageIcon(getClass().getResource("cursors/" + name + ".png"));
|
|
1235
|
-
PImage img = new PImage(icon.getImage());
|
|
1236
|
-
// Most cursors just use the center as the hotspot...
|
|
1237
|
-
int x = img.width / 2;
|
|
1238
|
-
int y = img.height / 2;
|
|
1239
|
-
// ...others are more specific
|
|
1240
|
-
if (kind == PConstants.ARROW) {
|
|
1241
|
-
x = 10;
|
|
1242
|
-
y = 7;
|
|
1243
|
-
} else if (kind == PConstants.HAND) {
|
|
1244
|
-
x = 12;
|
|
1245
|
-
y = 8;
|
|
1246
|
-
} else if (kind == PConstants.TEXT) {
|
|
1247
|
-
x = 16;
|
|
1248
|
-
y = 22;
|
|
1249
|
-
}
|
|
1250
|
-
cursor = new CursorInfo(img, x, y);
|
|
1251
|
-
cursors.put(kind, cursor);
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
if (cursor != null) {
|
|
1255
|
-
cursor.set();
|
|
1256
|
-
} else {
|
|
1257
|
-
PGraphics.showWarning("Cannot load cursor type: " + kind);
|
|
1258
|
-
}
|
|
1281
|
+
CursorInfo(PImage image, int x, int y) {
|
|
1282
|
+
this.image = image;
|
|
1283
|
+
this.x = x;
|
|
1284
|
+
this.y = y;
|
|
1259
1285
|
}
|
|
1260
1286
|
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
BufferedImage bimg = (BufferedImage) image.getNative();
|
|
1264
|
-
DataBufferInt dbuf = (DataBufferInt) bimg.getData().getDataBuffer();
|
|
1265
|
-
int[] ipix = dbuf.getData();
|
|
1266
|
-
ByteBuffer pixels = ByteBuffer.allocate(ipix.length * 4);
|
|
1267
|
-
pixels.asIntBuffer().put(ipix);
|
|
1268
|
-
PixelFormat format = PixelFormat.ARGB8888;
|
|
1269
|
-
final Dimension size = new Dimension(bimg.getWidth(), bimg.getHeight());
|
|
1270
|
-
PixelRectangle pixelrect = new PixelRectangle.GenericPixelRect(format, size, 0, false, pixels);
|
|
1271
|
-
final PointerIcon pi = disp.createPointerIcon(pixelrect, hotspotX, hotspotY);
|
|
1272
|
-
display.getEDTUtil().invoke(false, new Runnable() {
|
|
1273
|
-
@Override
|
|
1274
|
-
public void run() {
|
|
1275
|
-
window.setPointerVisible(true);
|
|
1276
|
-
window.setPointerIcon(pi);
|
|
1277
|
-
}
|
|
1278
|
-
});
|
|
1287
|
+
void set() {
|
|
1288
|
+
setCursor(image, x, y);
|
|
1279
1289
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
static Map<Integer, CursorInfo> cursors = new HashMap<>();
|
|
1293
|
+
static Map<Integer, String> cursorNames = Map.of(
|
|
1294
|
+
PConstants.ARROW, "arrow",
|
|
1295
|
+
PConstants.CROSS, "cross",
|
|
1296
|
+
PConstants.WAIT, "wait",
|
|
1297
|
+
PConstants.MOVE, "move",
|
|
1298
|
+
PConstants.HAND, "hand",
|
|
1299
|
+
PConstants.TEXT, "text"
|
|
1300
|
+
);
|
|
1301
|
+
|
|
1302
|
+
@Override
|
|
1303
|
+
public void setCursor(int kind) {
|
|
1304
|
+
if (!cursorNames.containsKey(kind)) {
|
|
1305
|
+
PGraphics.showWarning("Unknown cursor type: " + kind);
|
|
1306
|
+
return;
|
|
1288
1307
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1308
|
+
CursorInfo cursor = cursors.get(kind);
|
|
1309
|
+
if (cursor == null) {
|
|
1310
|
+
String name = cursorNames.get(kind);
|
|
1311
|
+
if (name != null) {
|
|
1312
|
+
ImageIcon icon
|
|
1313
|
+
= new ImageIcon(getClass().getResource("cursors/" + name + ".png"));
|
|
1314
|
+
PImage img = new PImageAWT(icon.getImage());
|
|
1315
|
+
// Most cursors just use the center as the hotspot...
|
|
1316
|
+
int x = img.width / 2;
|
|
1317
|
+
int y = img.height / 2;
|
|
1318
|
+
// ...others are more specific
|
|
1319
|
+
switch (kind) {
|
|
1320
|
+
case PConstants.ARROW:
|
|
1321
|
+
x = 10;
|
|
1322
|
+
y = 7;
|
|
1323
|
+
break;
|
|
1324
|
+
case PConstants.HAND:
|
|
1325
|
+
x = 12;
|
|
1326
|
+
y = 8;
|
|
1327
|
+
break;
|
|
1328
|
+
case PConstants.TEXT:
|
|
1329
|
+
x = 16;
|
|
1330
|
+
y = 22;
|
|
1331
|
+
break;
|
|
1332
|
+
default:
|
|
1333
|
+
break;
|
|
1334
|
+
}
|
|
1335
|
+
cursor = new CursorInfo(img, x, y);
|
|
1336
|
+
cursors.put(kind, cursor);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
if (cursor != null) {
|
|
1340
|
+
cursor.set();
|
|
1341
|
+
} else {
|
|
1342
|
+
PGraphics.showWarning("Cannot load cursor type: " + kind);
|
|
1297
1343
|
}
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
@Override
|
|
1347
|
+
public void setCursor(PImage image, int hotspotX, int hotspotY) {
|
|
1348
|
+
Display disp = window.getScreen().getDisplay();
|
|
1349
|
+
BufferedImage bimg = (BufferedImage) image.getNative();
|
|
1350
|
+
DataBufferInt dbuf = (DataBufferInt) bimg.getData().getDataBuffer();
|
|
1351
|
+
int[] ipix = dbuf.getData();
|
|
1352
|
+
ByteBuffer pixels = ByteBuffer.allocate(ipix.length * 4);
|
|
1353
|
+
pixels.asIntBuffer().put(ipix);
|
|
1354
|
+
PixelFormat format = PixelFormat.ARGB8888;
|
|
1355
|
+
final Dimension size = new Dimension(bimg.getWidth(), bimg.getHeight());
|
|
1356
|
+
PixelRectangle pixelrect = new PixelRectangle.GenericPixelRect(format, size, 0, false, pixels);
|
|
1357
|
+
final PointerIcon pi = disp.createPointerIcon(pixelrect, hotspotX, hotspotY);
|
|
1358
|
+
display.getEDTUtil().invoke(false, () -> {
|
|
1359
|
+
window.setPointerVisible(true);
|
|
1360
|
+
window.setPointerIcon(pi);
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
@Override
|
|
1365
|
+
public void showCursor() {
|
|
1366
|
+
display.getEDTUtil().invoke(false, () -> {
|
|
1367
|
+
window.setPointerVisible(true);
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
@Override
|
|
1372
|
+
public void hideCursor() {
|
|
1373
|
+
display.getEDTUtil().invoke(false, () -> {
|
|
1374
|
+
window.setPointerVisible(false);
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
@Override
|
|
1379
|
+
public boolean openLink(String url) {
|
|
1380
|
+
return ShimAWT.openLink(url);
|
|
1381
|
+
}
|
|
1298
1382
|
}
|