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