propane 3.9.0-java → 3.10.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +2 -2
  4. data/README.md +3 -3
  5. data/Rakefile +6 -6
  6. data/lib/java/japplemenubar/JAppleMenuBar.java +88 -0
  7. data/lib/java/japplemenubar/libjAppleMenuBar.jnilib +0 -0
  8. data/lib/java/monkstone/ColorUtil.java +127 -0
  9. data/lib/java/monkstone/MathToolModule.java +287 -0
  10. data/lib/java/monkstone/PropaneLibrary.java +46 -0
  11. data/lib/java/monkstone/core/LibraryProxy.java +136 -0
  12. data/lib/java/monkstone/fastmath/DegLutTables.java +111 -0
  13. data/lib/java/monkstone/fastmath/Deglut.java +71 -0
  14. data/lib/java/monkstone/fastmath/package-info.java +6 -0
  15. data/lib/java/monkstone/filechooser/Chooser.java +39 -0
  16. data/{src/main → lib}/java/monkstone/noise/FastTerrain.java +0 -0
  17. data/{src/main → lib}/java/monkstone/noise/Noise.java +0 -0
  18. data/{src/main → lib}/java/monkstone/noise/NoiseGenerator.java +0 -0
  19. data/{src/main → lib}/java/monkstone/noise/NoiseMode.java +0 -0
  20. data/lib/java/monkstone/noise/OpenSimplex2F.java +881 -0
  21. data/lib/java/monkstone/noise/OpenSimplex2S.java +1106 -0
  22. data/{src/main → lib}/java/monkstone/noise/SmoothTerrain.java +0 -0
  23. data/lib/java/monkstone/slider/CustomHorizontalSlider.java +164 -0
  24. data/lib/java/monkstone/slider/CustomVerticalSlider.java +178 -0
  25. data/lib/java/monkstone/slider/SimpleHorizontalSlider.java +145 -0
  26. data/lib/java/monkstone/slider/SimpleSlider.java +166 -0
  27. data/lib/java/monkstone/slider/SimpleVerticalSlider.java +157 -0
  28. data/lib/java/monkstone/slider/Slider.java +61 -0
  29. data/lib/java/monkstone/slider/SliderBar.java +245 -0
  30. data/lib/java/monkstone/slider/SliderGroup.java +56 -0
  31. data/lib/java/monkstone/slider/WheelHandler.java +35 -0
  32. data/lib/java/monkstone/vecmath/GfxRender.java +86 -0
  33. data/lib/java/monkstone/vecmath/JRender.java +56 -0
  34. data/lib/java/monkstone/vecmath/ShapeRender.java +87 -0
  35. data/lib/java/monkstone/vecmath/package-info.java +20 -0
  36. data/lib/java/monkstone/vecmath/vec2/Vec2.java +802 -0
  37. data/lib/java/monkstone/vecmath/vec2/package-info.java +6 -0
  38. data/lib/java/monkstone/vecmath/vec3/Vec3.java +727 -0
  39. data/lib/java/monkstone/vecmath/vec3/package-info.java +6 -0
  40. data/lib/java/monkstone/videoevent/CaptureEvent.java +27 -0
  41. data/lib/java/monkstone/videoevent/MovieEvent.java +32 -0
  42. data/lib/java/monkstone/videoevent/package-info.java +20 -0
  43. data/lib/java/processing/awt/PGraphicsJava2D.java +3040 -0
  44. data/lib/java/processing/awt/PImageAWT.java +377 -0
  45. data/lib/java/processing/awt/PShapeJava2D.java +387 -0
  46. data/lib/java/processing/awt/PSurfaceAWT.java +1581 -0
  47. data/lib/java/processing/awt/ShimAWT.java +581 -0
  48. data/lib/java/processing/core/PApplet.java +15156 -0
  49. data/lib/java/processing/core/PConstants.java +523 -0
  50. data/lib/java/processing/core/PFont.java +1126 -0
  51. data/lib/java/processing/core/PGraphics.java +8600 -0
  52. data/lib/java/processing/core/PImage.java +3377 -0
  53. data/lib/java/processing/core/PMatrix.java +208 -0
  54. data/lib/java/processing/core/PMatrix2D.java +562 -0
  55. data/lib/java/processing/core/PMatrix3D.java +890 -0
  56. data/lib/java/processing/core/PShape.java +3561 -0
  57. data/lib/java/processing/core/PShapeOBJ.java +483 -0
  58. data/lib/java/processing/core/PShapeSVG.java +2016 -0
  59. data/lib/java/processing/core/PStyle.java +63 -0
  60. data/lib/java/processing/core/PSurface.java +198 -0
  61. data/lib/java/processing/core/PSurfaceNone.java +431 -0
  62. data/lib/java/processing/core/PVector.java +1066 -0
  63. data/lib/java/processing/core/ThinkDifferent.java +115 -0
  64. data/lib/java/processing/data/DoubleDict.java +850 -0
  65. data/lib/java/processing/data/DoubleList.java +928 -0
  66. data/lib/java/processing/data/FloatDict.java +847 -0
  67. data/lib/java/processing/data/FloatList.java +936 -0
  68. data/lib/java/processing/data/IntDict.java +807 -0
  69. data/lib/java/processing/data/IntList.java +936 -0
  70. data/lib/java/processing/data/JSONArray.java +1260 -0
  71. data/lib/java/processing/data/JSONObject.java +2282 -0
  72. data/lib/java/processing/data/JSONTokener.java +435 -0
  73. data/lib/java/processing/data/LongDict.java +802 -0
  74. data/lib/java/processing/data/LongList.java +937 -0
  75. data/lib/java/processing/data/Sort.java +46 -0
  76. data/lib/java/processing/data/StringDict.java +613 -0
  77. data/lib/java/processing/data/StringList.java +800 -0
  78. data/lib/java/processing/data/Table.java +4936 -0
  79. data/lib/java/processing/data/TableRow.java +198 -0
  80. data/lib/java/processing/data/XML.java +1156 -0
  81. data/lib/java/processing/dxf/RawDXF.java +404 -0
  82. data/lib/java/processing/event/Event.java +125 -0
  83. data/lib/java/processing/event/KeyEvent.java +70 -0
  84. data/lib/java/processing/event/MouseEvent.java +114 -0
  85. data/lib/java/processing/event/TouchEvent.java +57 -0
  86. data/lib/java/processing/javafx/PGraphicsFX2D.java +32 -0
  87. data/lib/java/processing/javafx/PSurfaceFX.java +173 -0
  88. data/lib/java/processing/net/Client.java +744 -0
  89. data/lib/java/processing/net/Server.java +388 -0
  90. data/lib/java/processing/opengl/FontTexture.java +378 -0
  91. data/lib/java/processing/opengl/FrameBuffer.java +513 -0
  92. data/lib/java/processing/opengl/LinePath.java +627 -0
  93. data/lib/java/processing/opengl/LineStroker.java +681 -0
  94. data/lib/java/processing/opengl/PGL.java +3483 -0
  95. data/lib/java/processing/opengl/PGraphics2D.java +615 -0
  96. data/lib/java/processing/opengl/PGraphics3D.java +281 -0
  97. data/lib/java/processing/opengl/PGraphicsOpenGL.java +13753 -0
  98. data/lib/java/processing/opengl/PJOGL.java +2008 -0
  99. data/lib/java/processing/opengl/PShader.java +1484 -0
  100. data/lib/java/processing/opengl/PShapeOpenGL.java +5269 -0
  101. data/lib/java/processing/opengl/PSurfaceJOGL.java +1385 -0
  102. data/lib/java/processing/opengl/Texture.java +1696 -0
  103. data/lib/java/processing/opengl/VertexBuffer.java +88 -0
  104. data/lib/java/processing/opengl/cursors/arrow.png +0 -0
  105. data/lib/java/processing/opengl/cursors/cross.png +0 -0
  106. data/lib/java/processing/opengl/cursors/hand.png +0 -0
  107. data/lib/java/processing/opengl/cursors/license.txt +27 -0
  108. data/lib/java/processing/opengl/cursors/move.png +0 -0
  109. data/lib/java/processing/opengl/cursors/text.png +0 -0
  110. data/lib/java/processing/opengl/cursors/wait.png +0 -0
  111. data/lib/java/processing/opengl/shaders/ColorFrag.glsl +32 -0
  112. data/lib/java/processing/opengl/shaders/ColorVert.glsl +34 -0
  113. data/lib/java/processing/opengl/shaders/LightFrag.glsl +33 -0
  114. data/lib/java/processing/opengl/shaders/LightVert.glsl +151 -0
  115. data/lib/java/processing/opengl/shaders/LineFrag.glsl +32 -0
  116. data/lib/java/processing/opengl/shaders/LineVert.glsl +100 -0
  117. data/lib/java/processing/opengl/shaders/MaskFrag.glsl +40 -0
  118. data/lib/java/processing/opengl/shaders/PointFrag.glsl +32 -0
  119. data/lib/java/processing/opengl/shaders/PointVert.glsl +56 -0
  120. data/lib/java/processing/opengl/shaders/TexFrag.glsl +37 -0
  121. data/lib/java/processing/opengl/shaders/TexLightFrag.glsl +37 -0
  122. data/lib/java/processing/opengl/shaders/TexLightVert.glsl +157 -0
  123. data/lib/java/processing/opengl/shaders/TexVert.glsl +38 -0
  124. data/lib/java/processing/pdf/PGraphicsPDF.java +581 -0
  125. data/lib/java/processing/svg/PGraphicsSVG.java +378 -0
  126. data/lib/propane/app.rb +8 -13
  127. data/lib/propane/version.rb +1 -1
  128. data/mvnw +3 -3
  129. data/mvnw.cmd +2 -2
  130. data/pom.rb +7 -2
  131. data/pom.xml +14 -2
  132. data/propane.gemspec +2 -2
  133. data/src/main/java/monkstone/FastNoiseModuleJava.java +127 -0
  134. data/src/main/java/monkstone/MathToolModule.java +30 -30
  135. data/src/main/java/monkstone/PropaneLibrary.java +2 -0
  136. data/src/main/java/monkstone/SmoothNoiseModuleJava.java +127 -0
  137. data/src/main/java/monkstone/fastmath/DegLutTables.java +15 -15
  138. data/src/main/java/monkstone/filechooser/Chooser.java +1 -1
  139. data/src/main/java/monkstone/noise/OpenSimplex2F.java +752 -820
  140. data/src/main/java/monkstone/noise/OpenSimplex2S.java +1138 -1106
  141. data/src/main/java/monkstone/slider/WheelHandler.java +1 -1
  142. data/src/main/java/monkstone/vecmath/JRender.java +6 -6
  143. data/src/main/java/monkstone/vecmath/vec2/Vec2.java +20 -19
  144. data/src/main/java/monkstone/vecmath/vec3/Vec3.java +12 -12
  145. data/src/main/java/processing/awt/PGraphicsJava2D.java +11 -3
  146. data/src/main/java/processing/core/PApplet.java +89 -89
  147. data/src/main/java/processing/core/PConstants.java +155 -163
  148. data/src/main/java/processing/opengl/PJOGL.java +6 -5
  149. data/vendors/Rakefile +1 -1
  150. metadata +136 -19
@@ -0,0 +1,388 @@
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
+
26
+ package processing.net;
27
+
28
+ import processing.core.*;
29
+
30
+ import java.io.*;
31
+ import java.lang.reflect.*;
32
+ import java.net.*;
33
+
34
+
35
+ /**
36
+ * ( begin auto-generated from Server.xml )
37
+ *
38
+ * A server sends and receives data to and from its associated clients
39
+ * (other programs connected to it). When a server is started, it begins
40
+ * listening for connections on the port specified by the <b>port</b>
41
+ * parameter. Computers have many ports for transferring data and some are
42
+ * commonly used so be sure to not select one of these. For example, web
43
+ * servers usually use port 80 and POP mail uses port 110.
44
+ *
45
+ *
46
+ * @webref net
47
+ * @usage application
48
+ * @brief The server class is used to create server objects which send and receives data to and from its associated clients (other programs connected to it).
49
+ * @instanceName server any variable of type Server
50
+ */
51
+ public class Server implements Runnable {
52
+ PApplet parent;
53
+ Method serverEventMethod;
54
+
55
+ volatile Thread thread;
56
+ ServerSocket server;
57
+ int port;
58
+
59
+ protected final Object clientsLock = new Object[0];
60
+ /** Number of clients currently connected. */
61
+ public int clientCount;
62
+ /** Array of client objects, useful length is determined by clientCount. */
63
+ public Client[] clients;
64
+
65
+
66
+ /**
67
+ * @param parent typically use "this"
68
+ * @param port port used to transfer data
69
+ */
70
+ public Server(PApplet parent, int port) {
71
+ this(parent, port, null);
72
+ }
73
+
74
+
75
+ /**
76
+ * @param parent typically use "this"
77
+ * @param port port used to transfer data
78
+ * @param host when multiple NICs are in use, the ip (or name) to bind from
79
+ */
80
+ public Server(PApplet parent, int port, String host) {
81
+ this.parent = parent;
82
+ this.port = port;
83
+
84
+ try {
85
+ if (host == null) {
86
+ server = new ServerSocket(this.port);
87
+ } else {
88
+ server = new ServerSocket(this.port, 10, InetAddress.getByName(host));
89
+ }
90
+ //clients = new Vector();
91
+ clients = new Client[10];
92
+
93
+ thread = new Thread(this);
94
+ thread.start();
95
+
96
+ parent.registerMethod("dispose", this);
97
+
98
+ // reflection to check whether host applet has a call for
99
+ // public void serverEvent(Server s, Client c);
100
+ // which is called when a new guy connects
101
+ try {
102
+ serverEventMethod =
103
+ parent.getClass().getMethod("serverEvent", Server.class, Client.class);
104
+ } catch (Exception e) {
105
+ // no such method, or an error.. which is fine, just ignore
106
+ }
107
+
108
+ } catch (IOException e) {
109
+ //e.printStackTrace();
110
+ thread = null;
111
+ throw new RuntimeException(e);
112
+ //errorMessage("<init>", e);
113
+ }
114
+ }
115
+
116
+
117
+ /**
118
+ * ( begin auto-generated from Server_disconnect.xml )
119
+ *
120
+ * Disconnect a particular client.
121
+ *
122
+ *
123
+ * @brief Disconnect a particular client.
124
+ * @webref server:server
125
+ * @param client the client to disconnect
126
+ */
127
+ public void disconnect(Client client) {
128
+ client.stop();
129
+ synchronized (clientsLock) {
130
+ int index = clientIndex(client);
131
+ if (index != -1) {
132
+ removeIndex(index);
133
+ }
134
+ }
135
+ }
136
+
137
+
138
+ protected void removeIndex(int index) {
139
+ synchronized (clientsLock) {
140
+ clientCount--;
141
+ // shift down the remaining clients
142
+ for (int i = index; i < clientCount; i++) {
143
+ clients[i] = clients[i + 1];
144
+ }
145
+ // mark last empty var for garbage collection
146
+ clients[clientCount] = null;
147
+ }
148
+ }
149
+
150
+
151
+ protected void disconnectAll() {
152
+ synchronized (clientsLock) {
153
+ for (int i = 0; i < clientCount; i++) {
154
+ try {
155
+ clients[i].stop();
156
+ } catch (Exception e) {
157
+ // ignore
158
+ }
159
+ clients[i] = null;
160
+ }
161
+ clientCount = 0;
162
+ }
163
+ }
164
+
165
+
166
+ protected void addClient(Client client) {
167
+ synchronized (clientsLock) {
168
+ if (clientCount == clients.length) {
169
+ clients = (Client[]) PApplet.expand(clients);
170
+ }
171
+ clients[clientCount++] = client;
172
+ }
173
+ }
174
+
175
+
176
+ protected int clientIndex(Client client) {
177
+ synchronized (clientsLock) {
178
+ for (int i = 0; i < clientCount; i++) {
179
+ if (clients[i] == client) {
180
+ return i;
181
+ }
182
+ }
183
+ return -1;
184
+ }
185
+ }
186
+
187
+
188
+ /**
189
+ * ( begin auto-generated from Server_active.xml )
190
+ *
191
+ * Returns true if this server is still active and hasn't run
192
+ * into any trouble.
193
+ *
194
+ *
195
+ * @webref server:server
196
+ * @brief Return true if this server is still active.
197
+ */
198
+ public boolean active() {
199
+ return thread != null;
200
+ }
201
+
202
+
203
+ static public String ip() {
204
+ try {
205
+ return InetAddress.getLocalHost().getHostAddress();
206
+ } catch (UnknownHostException e) {
207
+
208
+ return null;
209
+ }
210
+ }
211
+
212
+
213
+ // the last index used for available. can't just cycle through
214
+ // the clients in order from 0 each time, because if client 0 won't
215
+ // shut up, then the rest of the clients will never be heard from.
216
+ int lastAvailable = -1;
217
+
218
+ /**
219
+ * ( begin auto-generated from Server_available.xml )
220
+ *
221
+ * Returns the next client in line with a new message.
222
+ *
223
+ *
224
+ * @brief Returns the next client in line with a new message.
225
+ * @webref server
226
+ * @usage application
227
+ */
228
+ public Client available() {
229
+ synchronized (clientsLock) {
230
+ int index = lastAvailable + 1;
231
+ if (index >= clientCount) index = 0;
232
+
233
+ for (int i = 0; i < clientCount; i++) {
234
+ int which = (index + i) % clientCount;
235
+ Client client = clients[which];
236
+ //Check for valid client
237
+ if (!client.active()){
238
+ removeIndex(which); //Remove dead client
239
+ i--; //Don't skip the next client
240
+ //If the client has data make sure lastAvailable
241
+ //doesn't end up skipping the next client
242
+ which--;
243
+ //fall through to allow data from dead clients
244
+ //to be retreived.
245
+ }
246
+ if (client.available() > 0) {
247
+ lastAvailable = which;
248
+ return client;
249
+ }
250
+ }
251
+ }
252
+ return null;
253
+ }
254
+
255
+
256
+ /**
257
+ * ( begin auto-generated from Server_stop.xml )
258
+ *
259
+ * Disconnects all clients and stops the server.
260
+ *
261
+ *
262
+ * <h3>Advanced</h3>
263
+ * Use this to shut down the server if you finish using it while your applet
264
+ * is still running. Otherwise, it will be automatically be shut down by the
265
+ * host PApplet using dispose(), which is identical.
266
+ * @brief Disconnects all clients and stops the server.
267
+ * @webref server
268
+ * @usage application
269
+ */
270
+ public void stop() {
271
+ dispose();
272
+ }
273
+
274
+
275
+ /**
276
+ * Disconnect all clients and stop the server: internal use only.
277
+ */
278
+ public void dispose() {
279
+ thread = null;
280
+
281
+ if (clients != null) {
282
+ disconnectAll();
283
+ clientCount = 0;
284
+ clients = null;
285
+ }
286
+
287
+ try {
288
+ if (server != null) {
289
+ server.close();
290
+ server = null;
291
+ }
292
+ } catch (IOException e) {
293
+
294
+ }
295
+ }
296
+
297
+
298
+ @Override
299
+ public void run() {
300
+ while (Thread.currentThread() == thread) {
301
+ try {
302
+ Socket socket = server.accept();
303
+ Client client = new Client(parent, socket);
304
+ synchronized (clientsLock) {
305
+ addClient(client);
306
+ if (serverEventMethod != null) {
307
+ try {
308
+ serverEventMethod.invoke(parent, this, client);
309
+ } catch (Exception e) {
310
+ System.err.println("Disabling serverEvent() for port " + port);
311
+ Throwable cause = e;
312
+ // unwrap the exception if it came from the user code
313
+ if (e instanceof InvocationTargetException && e.getCause() != null) {
314
+ cause = e.getCause();
315
+ }
316
+ cause.printStackTrace();
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
+
328
+ thread = null;
329
+ }
330
+ }
331
+ }
332
+
333
+
334
+ /**
335
+ * ( begin auto-generated from Server_write.xml )
336
+ *
337
+ * Writes a value to all the connected clients. It sends bytes out from the
338
+ * Server object.
339
+ *
340
+ *
341
+ * @webref server
342
+ * @brief Writes data to all connected clients
343
+ * @param data data to write
344
+ */
345
+ public void write(int data) { // will also cover char
346
+ synchronized (clientsLock) {
347
+ int index = 0;
348
+ while (index < clientCount) {
349
+ if (clients[index].active()) {
350
+ clients[index].write(data);
351
+ index++;
352
+ } else {
353
+ removeIndex(index);
354
+ }
355
+ }
356
+ }
357
+ }
358
+
359
+
360
+ public void write(byte data[]) {
361
+ synchronized (clientsLock) {
362
+ int index = 0;
363
+ while (index < clientCount) {
364
+ if (clients[index].active()) {
365
+ clients[index].write(data);
366
+ index++;
367
+ } else {
368
+ removeIndex(index);
369
+ }
370
+ }
371
+ }
372
+ }
373
+
374
+
375
+ public void write(String data) {
376
+ synchronized (clientsLock) {
377
+ int index = 0;
378
+ while (index < clientCount) {
379
+ if (clients[index].active()) {
380
+ clients[index].write(data);
381
+ index++;
382
+ } else {
383
+ removeIndex(index);
384
+ }
385
+ }
386
+ }
387
+ }
388
+ }
@@ -0,0 +1,378 @@
1
+ /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
+
3
+ /*
4
+ Part of the Processing project - http://processing.org
5
+
6
+ Copyright (c) 2012-15 The Processing Foundation
7
+ Copyright (c) 2004-12 Ben Fry and Casey Reas
8
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
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, version 2.1.
13
+
14
+ This library is distributed in the hope that it will be useful,
15
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
+ Lesser General Public License for more details.
18
+
19
+ You should have received a copy of the GNU Lesser General
20
+ Public License along with this library; if not, write to the
21
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22
+ Boston, MA 02111-1307 USA
23
+ */
24
+
25
+ package processing.opengl;
26
+
27
+ import processing.core.PApplet;
28
+ import processing.core.PConstants;
29
+ import processing.core.PFont;
30
+ import processing.core.PGraphics;
31
+ import processing.core.PImage;
32
+
33
+ import java.util.HashMap;
34
+
35
+ /**
36
+ * All the infrastructure needed for optimized font rendering
37
+ * in OpenGL. Basically, this special class is needed because
38
+ * fonts in Processing are handled by a separate PImage for each
39
+ * glyph. For performance reasons, all these glyphs should be
40
+ * stored in a single OpenGL texture (otherwise, rendering a
41
+ * string of text would involve binding and un-binding several
42
+ * textures.
43
+ * PFontTexture manages the correspondence between individual
44
+ * glyphs and the large OpenGL texture containing them. Also,
45
+ * in the case that the font size is very large, one single
46
+ * OpenGL texture might not be enough to store all the glyphs,
47
+ * so PFontTexture also takes care of spreading a single font
48
+ * over several textures.
49
+ * @author Andres Colubri
50
+ */
51
+ class FontTexture implements PConstants {
52
+ protected PGL pgl;
53
+ protected boolean is3D;
54
+
55
+ protected int minSize;
56
+ protected int maxSize;
57
+ protected int offsetX;
58
+ protected int offsetY;
59
+ protected int lineHeight;
60
+ protected Texture[] textures = null;
61
+ protected PImage[] images = null;
62
+ protected int lastTex;
63
+ protected TextureInfo[] glyphTexinfos;
64
+ protected HashMap<PFont.Glyph, TextureInfo> texinfoMap;
65
+
66
+ public FontTexture(PGraphicsOpenGL pg, PFont font, boolean is3D) {
67
+ pgl = pg.pgl;
68
+ this.is3D = is3D;
69
+
70
+ initTexture(pg, font);
71
+ }
72
+
73
+
74
+ protected void allocate() {
75
+ // Nothing to do here: the font textures will allocate
76
+ // themselves.
77
+ }
78
+
79
+
80
+ protected void dispose() {
81
+ for (Texture texture : textures) {
82
+ texture.dispose();
83
+ }
84
+ }
85
+
86
+
87
+ protected void initTexture(PGraphicsOpenGL pg, PFont font) {
88
+ lastTex = -1;
89
+
90
+ int spow = PGL.nextPowerOfTwo(font.getSize());
91
+ minSize = PApplet.min(PGraphicsOpenGL.maxTextureSize,
92
+ PApplet.max(PGL.MIN_FONT_TEX_SIZE, spow));
93
+ maxSize = PApplet.min(PGraphicsOpenGL.maxTextureSize,
94
+ PApplet.max(PGL.MAX_FONT_TEX_SIZE, 2 * spow));
95
+
96
+ if (maxSize < spow) {
97
+ PGraphics.showWarning("The font size is too large to be properly " +
98
+ "displayed with OpenGL");
99
+ }
100
+
101
+ addTexture(pg);
102
+
103
+ offsetX = 0;
104
+ offsetY = 0;
105
+ lineHeight = 0;
106
+
107
+ texinfoMap = new HashMap<>();
108
+ glyphTexinfos = new TextureInfo[font.getGlyphCount()];
109
+ addAllGlyphsToTexture(pg, font);
110
+ }
111
+
112
+
113
+ public boolean addTexture(PGraphicsOpenGL pg) {
114
+ int w, h;
115
+ boolean resize;
116
+
117
+ w = maxSize;
118
+ if (-1 < lastTex && textures[lastTex].glHeight < maxSize) {
119
+ // The height of the current texture is less than the maximum, this
120
+ // means we can replace it with a larger texture.
121
+ h = PApplet.min(2 * textures[lastTex].glHeight, maxSize);
122
+ resize = true;
123
+ } else {
124
+ h = minSize;
125
+ resize = false;
126
+ }
127
+
128
+ Texture tex;
129
+ if (is3D) {
130
+ // Bilinear sampling ensures that the texture doesn't look pixelated
131
+ // either when it is magnified or minified...
132
+ tex = new Texture(pg, w, h,
133
+ new Texture.Parameters(ARGB, Texture.BILINEAR, false));
134
+ } else {
135
+ // ...however, the effect of bilinear sampling is to add some blurriness
136
+ // to the text in its original size. In 2D, we assume that text will be
137
+ // shown at its original size, so linear sampling is chosen instead (which
138
+ // only affects minimized text).
139
+ tex = new Texture(pg, w, h,
140
+ new Texture.Parameters(ARGB, Texture.LINEAR, false));
141
+ }
142
+
143
+ if (textures == null) {
144
+ textures = new Texture[1];
145
+ textures[0] = tex;
146
+ images = new PImage[1];
147
+ images[0] = pg.wrapTexture(tex);
148
+ lastTex = 0;
149
+ } else if (resize) {
150
+ // Replacing old smaller texture with larger one.
151
+ // But first we must copy the contents of the older
152
+ // texture into the new one.
153
+ Texture tex0 = textures[lastTex];
154
+ tex.put(tex0);
155
+ textures[lastTex] = tex;
156
+
157
+ pg.setCache(images[lastTex], tex);
158
+ images[lastTex].width = tex.width;
159
+ images[lastTex].height = tex.height;
160
+ } else {
161
+ // Adding new texture to the list.
162
+ lastTex = textures.length;
163
+ Texture[] tempTex = new Texture[lastTex + 1];
164
+ PApplet.arrayCopy(textures, tempTex, textures.length);
165
+ tempTex[lastTex] = tex;
166
+ textures = tempTex;
167
+
168
+ PImage[] tempImg = new PImage[textures.length];
169
+ PApplet.arrayCopy(images, tempImg, images.length);
170
+ tempImg[lastTex] = pg.wrapTexture(tex);
171
+ images = tempImg;
172
+ }
173
+
174
+ // Make sure that the current texture is bound.
175
+ tex.bind();
176
+
177
+ return resize;
178
+ }
179
+
180
+
181
+ public void begin() {
182
+ }
183
+
184
+
185
+ public void end() {
186
+ for (Texture texture : textures) {
187
+ pgl.disableTexturing(texture.glTarget);
188
+ }
189
+ }
190
+
191
+
192
+ public PImage getTexture(TextureInfo info) {
193
+ return images[info.texIndex];
194
+ }
195
+
196
+
197
+ // Add all the current glyphs to opengl texture.
198
+ public void addAllGlyphsToTexture(PGraphicsOpenGL pg, PFont font) {
199
+ // loop over current glyphs.
200
+ for (int i = 0; i < font.getGlyphCount(); i++) {
201
+ addToTexture(pg, i, font.getGlyph(i));
202
+ }
203
+ }
204
+
205
+
206
+ public void updateGlyphsTexCoords() {
207
+ // loop over current glyphs.
208
+ for (TextureInfo tinfo : glyphTexinfos) {
209
+ if (tinfo != null && tinfo.texIndex == lastTex) {
210
+ tinfo.updateUV();
211
+ }
212
+ }
213
+ }
214
+
215
+
216
+ public TextureInfo getTexInfo(PFont.Glyph glyph) {
217
+ TextureInfo info = texinfoMap.get(glyph);
218
+ return info;
219
+ }
220
+
221
+
222
+ public TextureInfo addToTexture(PGraphicsOpenGL pg, PFont.Glyph glyph) {
223
+ int n = glyphTexinfos.length;
224
+ if (n == 0) {
225
+ glyphTexinfos = new TextureInfo[1];
226
+ }
227
+ addToTexture(pg, n, glyph);
228
+ return glyphTexinfos[n];
229
+ }
230
+
231
+
232
+ public boolean contextIsOutdated() {
233
+ boolean outdated = false;
234
+ for (Texture texture : textures) {
235
+ if (texture.contextIsOutdated()) {
236
+ outdated = true;
237
+ }
238
+ }
239
+ if (outdated) {
240
+ for (Texture texture : textures) {
241
+ texture.dispose();
242
+ }
243
+ }
244
+ return outdated;
245
+ }
246
+
247
+ // public void draw() {
248
+ // Texture tex = textures[lastTex];
249
+ // pgl.drawTexture(tex.glTarget, tex.glName,
250
+ // tex.glWidth, tex.glHeight,
251
+ // 0, 0, tex.glWidth, tex.glHeight);
252
+ // }
253
+
254
+
255
+ // Adds this glyph to the opengl texture in PFont.
256
+ protected void addToTexture(PGraphicsOpenGL pg, int idx, PFont.Glyph glyph) {
257
+ // We add one pixel to avoid issues when sampling the font texture at
258
+ // fractional screen positions. I.e.: the pixel on the screen only contains
259
+ // half of the font rectangle, so it would sample half of the color from the
260
+ // glyph area in the texture, and the other half from the contiguous pixel.
261
+ // If the later contains a portion of the neighbor glyph and the former
262
+ // doesn't, this would result in a shaded pixel when the correct output is
263
+ // blank. This is a consequence of putting all the glyphs in a common
264
+ // texture with bilinear sampling.
265
+ int w = 1 + glyph.width + 1;
266
+ int h = 1 + glyph.height + 1;
267
+
268
+ // Converting the pixels array from the PImage into a valid RGBA array for
269
+ // OpenGL.
270
+ int[] rgba = new int[w * h];
271
+ int t = 0;
272
+ int p = 0;
273
+ if (PGL.BIG_ENDIAN) {
274
+ java.util.Arrays.fill(rgba, 0, w, 0xFFFFFF00); // Set the first row to blank pixels.
275
+ t = w;
276
+ for (int y = 0; y < glyph.height; y++) {
277
+ rgba[t++] = 0xFFFFFF00; // Set the leftmost pixel in this row as blank
278
+ for (int x = 0; x < glyph.width; x++) {
279
+ rgba[t++] = 0xFFFFFF00 | glyph.image.pixels[p++];
280
+ }
281
+ rgba[t++] = 0xFFFFFF00; // Set the rightmost pixel in this row as blank
282
+ }
283
+ java.util.Arrays.fill(rgba, (h - 1) * w, h * w, 0xFFFFFF00); // Set the last row to blank pixels.
284
+ } else {
285
+ java.util.Arrays.fill(rgba, 0, w, 0x00FFFFFF); // Set the first row to blank pixels.
286
+ t = w;
287
+ for (int y = 0; y < glyph.height; y++) {
288
+ rgba[t++] = 0x00FFFFFF; // Set the leftmost pixel in this row as blank
289
+ for (int x = 0; x < glyph.width; x++) {
290
+ rgba[t++] = (glyph.image.pixels[p++] << 24) | 0x00FFFFFF;
291
+ }
292
+ rgba[t++] = 0x00FFFFFF; // Set the rightmost pixel in this row as blank
293
+ }
294
+ java.util.Arrays.fill(rgba, (h - 1) * w, h * w, 0x00FFFFFF); // Set the last row to blank pixels.
295
+ }
296
+
297
+ // Is there room for this glyph in the current line?
298
+ if (offsetX + w > textures[lastTex].glWidth) {
299
+ // No room, go to the next line:
300
+ offsetX = 0;
301
+ offsetY += lineHeight;
302
+ }
303
+ lineHeight = Math.max(lineHeight, h);
304
+
305
+ boolean resized = false;
306
+ if (offsetY + lineHeight > textures[lastTex].glHeight) {
307
+ // We run out of space in the current texture, so we add a new texture:
308
+ resized = addTexture(pg);
309
+ if (resized) {
310
+ // Because the current texture has been resized, we need to
311
+ // update the UV coordinates of all the glyphs associated to it:
312
+ updateGlyphsTexCoords();
313
+ } else {
314
+ // A new texture has been created. Reseting texture coordinates
315
+ // and line.
316
+ offsetX = 0;
317
+ offsetY = 0;
318
+ lineHeight = 0;
319
+ }
320
+ }
321
+
322
+ TextureInfo tinfo = new TextureInfo(lastTex, offsetX, offsetY, w, h, rgba);
323
+ offsetX += w;
324
+
325
+ if (idx == glyphTexinfos.length) {
326
+ TextureInfo[] temp = new TextureInfo[glyphTexinfos.length + 1];
327
+ System.arraycopy(glyphTexinfos, 0, temp, 0, glyphTexinfos.length);
328
+ glyphTexinfos = temp;
329
+ }
330
+
331
+ glyphTexinfos[idx] = tinfo;
332
+ texinfoMap.put(glyph, tinfo);
333
+ }
334
+
335
+
336
+ class TextureInfo {
337
+ int texIndex;
338
+ int width;
339
+ int height;
340
+ int[] crop;
341
+ float u0, u1;
342
+ float v0, v1;
343
+ int[] pixels;
344
+
345
+ TextureInfo(int tidx, int cropX, int cropY, int cropW, int cropH,
346
+ int[] pix) {
347
+ texIndex = tidx;
348
+ crop = new int[4];
349
+ // The region of the texture corresponding to the glyph is surrounded by a
350
+ // 1-pixel wide border to avoid artifacts due to bilinear sampling. This
351
+ // is why the additions and subtractions to the crop values.
352
+ crop[0] = cropX + 1;
353
+ crop[1] = cropY + 1 + cropH - 2;
354
+ crop[2] = cropW - 2;
355
+ crop[3] = -cropH + 2;
356
+ pixels = pix;
357
+ updateUV();
358
+ updateTex();
359
+ }
360
+
361
+
362
+ void updateUV() {
363
+ width = textures[texIndex].glWidth;
364
+ height = textures[texIndex].glHeight;
365
+
366
+ u0 = (float)crop[0] / (float)width;
367
+ u1 = u0 + (float)crop[2] / (float)width;
368
+ v0 = (float)(crop[1] + crop[3]) / (float)height;
369
+ v1 = v0 - (float)crop[3] / (float)height;
370
+ }
371
+
372
+
373
+ void updateTex() {
374
+ textures[texIndex].setNative(pixels, crop[0] - 1, crop[1] + crop[3] - 1,
375
+ crop[2] + 2, -crop[3] + 2);
376
+ }
377
+ }
378
+ }