propane 3.3.1-java → 3.4.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.
@@ -1087,7 +1087,7 @@ public class PGraphics extends PImage implements PConstants {
1087
1087
  * obscure rendering features that cannot be implemented in a consistent
1088
1088
  * manner across renderers. Many options will often graduate to standard
1089
1089
  * features instead of hints over time.
1090
- * <br/> <br/>
1090
+ *
1091
1091
  * hint(ENABLE_OPENGL_4X_SMOOTH) - Enable 4x anti-aliasing for P3D. This
1092
1092
  * can help force anti-aliasing if it has not been enabled by the user. On
1093
1093
  * some graphics cards, this can also be set by the graphics driver's
@@ -1095,13 +1095,13 @@ public class PGraphics extends PImage implements PConstants {
1095
1095
  * be called immediately after the size() command because it resets the
1096
1096
  * renderer, obliterating any settings and anything drawn (and like size(),
1097
1097
  * re-running the code that came before it again).
1098
- * <br/> <br/>
1098
+ *
1099
1099
  * hint(DISABLE_OPENGL_2X_SMOOTH) - In Processing 1.0, Processing always
1100
1100
  * enables 2x smoothing when the P3D renderer is used. This hint disables
1101
1101
  * the default 2x smoothing and returns the smoothing behavior found in
1102
1102
  * earlier releases, where smooth() and noSmooth() could be used to enable
1103
1103
  * and disable smoothing, though the quality was inferior.
1104
- * <br/> <br/>
1104
+ *
1105
1105
  * hint(ENABLE_NATIVE_FONTS) - Use the native version fonts when they are
1106
1106
  * installed, rather than the bitmapped version from a .vlw file. This is
1107
1107
  * useful with the default (or JAVA2D) renderer setting, as it will improve
@@ -1110,7 +1110,7 @@ public class PGraphics extends PImage implements PConstants {
1110
1110
  * machine (because you have the font installed) but lousy on others'
1111
1111
  * machines if the identical font is unavailable. This option can only be
1112
1112
  * set per-sketch, and must be called before any use of textFont().
1113
- * <br/> <br/>
1113
+ *
1114
1114
  * hint(DISABLE_DEPTH_TEST) - Disable the zbuffer, allowing you to draw on
1115
1115
  * top of everything at will. When depth testing is disabled, items will be
1116
1116
  * drawn to the screen sequentially, like a painting. This hint is most
@@ -1120,14 +1120,14 @@ public class PGraphics extends PImage implements PConstants {
1120
1120
  * hint(ENABLE_DEPTH_TEST), but note that with the depth buffer cleared,
1121
1121
  * any 3D drawing that happens later in draw() will ignore existing shapes
1122
1122
  * on the screen.
1123
- * <br/> <br/>
1123
+ *
1124
1124
  * hint(ENABLE_DEPTH_SORT) - Enable primitive z-sorting of triangles and
1125
1125
  * lines in P3D and OPENGL. This can slow performance considerably, and the
1126
1126
  * algorithm is not yet perfect. Restore the default with hint(DISABLE_DEPTH_SORT).
1127
- * <br/> <br/>
1127
+ *
1128
1128
  * hint(DISABLE_OPENGL_ERROR_REPORT) - Speeds up the P3D renderer setting
1129
1129
  * by not checking for errors while running. Undo with hint(ENABLE_OPENGL_ERROR_REPORT).
1130
- * <br/> <br/>
1130
+ *
1131
1131
  * hint(ENABLE_BUFFER_READING) - Depth and stencil buffers in P2D/P3D will be
1132
1132
  * downsampled to make PGL#readPixels work with multisampling. Enabling this
1133
1133
  * introduces some overhead, so if you experience bad performance, disable
@@ -1136,17 +1136,17 @@ public class PGraphics extends PImage implements PConstants {
1136
1136
  * creating your PGraphics2D/3D. You can restore the default with
1137
1137
  * hint(DISABLE_BUFFER_READING) if you don't plan to read depth from
1138
1138
  * this PGraphics anymore.
1139
- * <br/> <br/>
1139
+ *
1140
1140
  * hint(ENABLE_KEY_REPEAT) - Auto-repeating key events are discarded
1141
1141
  * by default (works only in P2D/P3D); use this hint to get all the key events
1142
1142
  * (including auto-repeated). Call hint(DISABLE_KEY_REPEAT) to get events
1143
1143
  * only when the key goes physically up or down.
1144
- * <br/> <br/>
1144
+ *
1145
1145
  * hint(DISABLE_ASYNC_SAVEFRAME) - P2D/P3D only - save() and saveFrame()
1146
1146
  * will not use separate threads for saving and will block until the image
1147
1147
  * is written to the drive. This was the default behavior in 3.0b7 and before.
1148
1148
  * To enable, call hint(ENABLE_ASYNC_SAVEFRAME).
1149
- * <br/> <br/>
1149
+ *
1150
1150
  * As of release 0149, unhint() has been removed in favor of adding
1151
1151
  * additional ENABLE/DISABLE constants to reset the default behavior. This
1152
1152
  * prevents the double negatives, and also reinforces which hints can be
@@ -1208,12 +1208,12 @@ public class PGraphics extends PImage implements PConstants {
1208
1208
  * specifies a position in 2D and the <b>vertex()</b> function with three
1209
1209
  * parameters specifies a position in 3D. Each shape will be outlined with
1210
1210
  * the current stroke color and filled with the fill color.
1211
- * <br/> <br/>
1211
+ *
1212
1212
  * Transformations such as <b>translate()</b>, <b>rotate()</b>, and
1213
1213
  * <b>scale()</b> do not work within <b>beginShape()</b>. It is also not
1214
1214
  * possible to use other shapes, such as <b>ellipse()</b> or <b>rect()</b>
1215
1215
  * within <b>beginShape()</b>.
1216
- * <br/> <br/>
1216
+ *
1217
1217
  * The P3D renderer settings allow <b>stroke()</b> and <b>fill()</b>
1218
1218
  * settings to be altered per-vertex, however the default P2D renderer does
1219
1219
  * not. Settings such as <b>strokeWeight()</b>, <b>strokeCap()</b>, and
@@ -1358,7 +1358,7 @@ public class PGraphics extends PImage implements PConstants {
1358
1358
  * Sets a texture to be applied to vertex points. The <b>texture()</b>
1359
1359
  * function must be called between <b>beginShape()</b> and
1360
1360
  * <b>endShape()</b> and before any calls to <b>vertex()</b>.
1361
- * <br/> <br/>
1361
+ *
1362
1362
  * When textures are in use, the fill color is ignored. Instead, use tint()
1363
1363
  * to specify the color of the texture as it is applied to the shape.
1364
1364
  *
@@ -4165,7 +4165,7 @@ public class PGraphics extends PImage implements PConstants {
4165
4165
  * CENTER, and RIGHT set the display characteristics of the letters in
4166
4166
  * relation to the values for the <b>x</b> and <b>y</b> parameters of the
4167
4167
  * <b>text()</b> function.
4168
- * <br/> <br/>
4168
+ *
4169
4169
  * In Processing 0125 and later, an optional second parameter can be used
4170
4170
  * to vertically align the text. BASELINE is the default, and the vertical
4171
4171
  * alignment will be reset to BASELINE if the second parameter is not used.
@@ -4173,12 +4173,12 @@ public class PGraphics extends PImage implements PConstants {
4173
4173
  * offsets the line based on the current <b>textDescent()</b>. For multiple
4174
4174
  * lines, the final line will be aligned to the bottom, with the previous
4175
4175
  * lines appearing above it.
4176
- * <br/> <br/>
4176
+ *
4177
4177
  * When using <b>text()</b> with width and height parameters, BASELINE is
4178
4178
  * ignored, and treated as TOP. (Otherwise, text would by default draw
4179
4179
  * outside the box, since BASELINE is the default setting. BASELINE is not
4180
4180
  * a useful drawing mode for text drawn in a rectangle.)
4181
- * <br/> <br/>
4181
+ *
4182
4182
  * The vertical alignment is based on the value of <b>textAscent()</b>,
4183
4183
  * which many fonts do not specify correctly. It may be necessary to use a
4184
4184
  * hack and offset by a few pixels by hand so that the offset looks
@@ -5348,7 +5348,7 @@ public class PGraphics extends PImage implements PConstants {
5348
5348
  * Rotates a shape the amount specified by the <b>angle</b> parameter.
5349
5349
  * Angles should be specified in radians (values from 0 to TWO_PI) or
5350
5350
  * converted to radians with the <b>radians()</b> function.
5351
- * <br/> <br/>
5351
+ *
5352
5352
  * Objects are always rotated around their relative position to the origin
5353
5353
  * and positive numbers rotate objects in a clockwise direction.
5354
5354
  * Transformations apply to everything that happens after and subsequent
@@ -5356,7 +5356,7 @@ public class PGraphics extends PImage implements PConstants {
5356
5356
  * <b>rotate(HALF_PI)</b> and then <b>rotate(HALF_PI)</b> is the same as
5357
5357
  * <b>rotate(PI)</b>. All tranformations are reset when <b>draw()</b>
5358
5358
  * begins again.
5359
- * <br/> <br/>
5359
+ *
5360
5360
  * Technically, <b>rotate()</b> multiplies the current transformation
5361
5361
  * matrix by a rotation matrix. This function can be further controlled by
5362
5362
  * the <b>pushMatrix()</b> and <b>popMatrix()</b>.
@@ -5559,7 +5559,7 @@ public class PGraphics extends PImage implements PConstants {
5559
5559
  * <b>shearX(PI/2)</b> and then <b>shearX(PI/2)</b> is the same as
5560
5560
  * <b>shearX(PI)</b>. If <b>shearX()</b> is called within the
5561
5561
  * <b>draw()</b>, the transformation is reset when the loop begins again.
5562
- * <br/> <br/>
5562
+ *
5563
5563
  * Technically, <b>shearX()</b> multiplies the current transformation
5564
5564
  * matrix by a rotation matrix. This function can be further controlled by
5565
5565
  * the <b>pushMatrix()</b> and <b>popMatrix()</b> functions.
@@ -5593,7 +5593,7 @@ public class PGraphics extends PImage implements PConstants {
5593
5593
  * <b>shearY(PI/2)</b> and then <b>shearY(PI/2)</b> is the same as
5594
5594
  * <b>shearY(PI)</b>. If <b>shearY()</b> is called within the
5595
5595
  * <b>draw()</b>, the transformation is reset when the loop begins again.
5596
- * <br/> <br/>
5596
+ *
5597
5597
  * Technically, <b>shearY()</b> multiplies the current transformation
5598
5598
  * matrix by a rotation matrix. This function can be further controlled by
5599
5599
  * the <b>pushMatrix()</b> and <b>popMatrix()</b> functions.
@@ -6115,7 +6115,7 @@ public class PGraphics extends PImage implements PConstants {
6115
6115
  * transformations (scale, rotate, translate, etc.) The X value can be used
6116
6116
  * to place an object in space relative to the location of the original
6117
6117
  * point once the transformations are no longer in use.
6118
- * <br/> <br/>
6118
+ *
6119
6119
  * In the example, the <b>modelX()</b>, <b>modelY()</b>, and
6120
6120
  * <b>modelZ()</b> functions record the location of a box in space after
6121
6121
  * being placed using a series of translate and rotate commands. After
@@ -6408,7 +6408,7 @@ public class PGraphics extends PImage implements PConstants {
6408
6408
  *
6409
6409
  * Sets the width of the stroke used for lines, points, and the border
6410
6410
  * around shapes. All widths are set in units of pixels.
6411
- * <br/> <br/>
6411
+ *
6412
6412
  * When drawing with P3D, series of connected lines (such as the stroke
6413
6413
  * around a polygon, triangle, or ellipse) produce unattractive results
6414
6414
  * when a thick stroke weight is set (<a
@@ -6437,7 +6437,7 @@ public class PGraphics extends PImage implements PConstants {
6437
6437
  * are either mitered, beveled, or rounded and specified with the
6438
6438
  * corresponding parameters MITER, BEVEL, and ROUND. The default joint is
6439
6439
  * MITER.
6440
- * <br/> <br/>
6440
+ *
6441
6441
  * This function is not available with the P3D renderer, (<a
6442
6442
  * href="http://code.google.com/p/processing/issues/detail?id=123">see
6443
6443
  * Issue 123</a>). More information about the renderers can be found in the
@@ -6461,7 +6461,7 @@ public class PGraphics extends PImage implements PConstants {
6461
6461
  * Sets the style for rendering line endings. These ends are either
6462
6462
  * squared, extended, or rounded and specified with the corresponding
6463
6463
  * parameters SQUARE, PROJECT, and ROUND. The default cap is ROUND.
6464
- * <br/> <br/>
6464
+ *
6465
6465
  * This function is not available with the P3D renderer (<a
6466
6466
  * href="http://code.google.com/p/processing/issues/detail?id=123">see
6467
6467
  * Issue 123</a>). More information about the renderers can be found in the
@@ -6512,7 +6512,7 @@ public class PGraphics extends PImage implements PConstants {
6512
6512
  * is either specified in terms of the RGB or HSB color depending on the
6513
6513
  * current <b>colorMode()</b> (the default color space is RGB, with each
6514
6514
  * value in the range from 0 to 255).
6515
- * <br/> <br/>
6515
+ *
6516
6516
  * When using hexadecimal notation to specify a color, use "#" or "0x"
6517
6517
  * before the values (e.g. #CCFFAA, 0xFFCCFFAA). The # syntax uses six
6518
6518
  * digits to specify a color (the way colors are specified in HTML and
@@ -6520,7 +6520,7 @@ public class PGraphics extends PImage implements PConstants {
6520
6520
  * hexadecimal value must be specified with eight characters; the first two
6521
6521
  * characters define the alpha component and the remainder the red, green,
6522
6522
  * and blue components.
6523
- * <br/> <br/>
6523
+ *
6524
6524
  * The value for the parameter "gray" must be less than or equal to the
6525
6525
  * current maximum value as specified by <b>colorMode()</b>. The default
6526
6526
  * maximum value is 255.
@@ -6753,7 +6753,7 @@ public class PGraphics extends PImage implements PConstants {
6753
6753
  * color is either specified in terms of the RGB or HSB color depending on
6754
6754
  * the current <b>colorMode()</b> (the default color space is RGB, with
6755
6755
  * each value in the range from 0 to 255).
6756
- * <br/> <br/>
6756
+ *
6757
6757
  * When using hexadecimal notation to specify a color, use "#" or "0x"
6758
6758
  * before the values (e.g. #CCFFAA, 0xFFCCFFAA). The # syntax uses six
6759
6759
  * digits to specify a color (the way colors are specified in HTML and
@@ -6761,11 +6761,11 @@ public class PGraphics extends PImage implements PConstants {
6761
6761
  * hexadecimal value must be specified with eight characters; the first two
6762
6762
  * characters define the alpha component and the remainder the red, green,
6763
6763
  * and blue components.
6764
- * <br/> <br/>
6764
+ *
6765
6765
  * The value for the parameter "gray" must be less than or equal to the
6766
6766
  * current maximum value as specified by <b>colorMode()</b>. The default
6767
6767
  * maximum value is 255.
6768
- * <br/> <br/>
6768
+ *
6769
6769
  * To change the color of an image (or a texture), use tint().
6770
6770
  *
6771
6771
  * ( end auto-generated )
@@ -7313,13 +7313,13 @@ public class PGraphics extends PImage implements PConstants {
7313
7313
  * of the Processing window. The default background is light gray. In the
7314
7314
  * <b>draw()</b> function, the background color is used to clear the
7315
7315
  * display window at the beginning of each frame.
7316
- * <br/> <br/>
7316
+ *
7317
7317
  * An image can also be used as the background for a sketch, however its
7318
7318
  * width and height must be the same size as the sketch window. To resize
7319
7319
  * an image 'b' to the size of the sketch window, use b.resize(width, height).
7320
- * <br/> <br/>
7320
+ *
7321
7321
  * Images used as background will ignore the current <b>tint()</b> setting.
7322
- * <br/> <br/>
7322
+ *
7323
7323
  * It is not possible to use transparency (alpha) in background colors with
7324
7324
  * the main drawing surface, however they will work properly with <b>createGraphics()</b>.
7325
7325
  *
@@ -7450,13 +7450,13 @@ public class PGraphics extends PImage implements PConstants {
7450
7450
  /**
7451
7451
  * Takes an RGB or ARGB image and sets it as the background.
7452
7452
  * The width and height of the image must be the same size as the sketch.
7453
- * Use image.resize(width, height) to make short work of such a task.<br/>
7454
- * <br/>
7453
+ * Use image.resize(width, height) to make short work of such a task.
7454
+ *
7455
7455
  * Note that even if the image is set as RGB, the high 8 bits of each pixel
7456
7456
  * should be set opaque (0xFF000000) because the image data will be copied
7457
7457
  * directly to the screen, and non-opaque background images may have strange
7458
- * behavior. Use image.filter(OPAQUE) to handle this easily.<br/>
7459
- * <br/>
7458
+ * behavior. Use image.filter(OPAQUE) to handle this easily.
7459
+ *
7460
7460
  * When using 3D, this will also clear the zbuffer (if it exists).
7461
7461
  *
7462
7462
  * @param image PImage to set as background (must be same size as the sketch window)
@@ -8349,7 +8349,7 @@ public class PGraphics extends PImage implements PConstants {
8349
8349
  * Return true if this renderer should be drawn to the screen. Defaults to
8350
8350
  * returning true, since nearly all renderers are on-screen beasts. But can
8351
8351
  * be overridden for subclasses like PDF so that a window doesn't open up.
8352
- * <br/> <br/>
8352
+ *
8353
8353
  * A better name? showFrame, displayable, isVisible, visible, shouldDisplay,
8354
8354
  * what to call this?
8355
8355
  */
@@ -40,11 +40,11 @@ import java.awt.image.*;
40
40
  * fields for the <b>width</b> and <b>height</b> of the image, as well as
41
41
  * an array called <b>pixels[]</b> that contains the values for every pixel
42
42
  * in the image. The methods described below allow easy access to the
43
- * image's pixels and alpha channel and simplify the process of compositing.<br/>
44
- * <br/> using the <b>pixels[]</b> array, be sure to use the
43
+ * image's pixels and alpha channel and simplify the process of compositing.
44
+ * using the <b>pixels[]</b> array, be sure to use the
45
45
  * <b>loadPixels()</b> method on the image to make sure that the pixel data
46
- * is properly loaded.<br/>
47
- * <br/> create a new image, use the <b>createImage()</b> function. Do not
46
+ * is properly loaded.
47
+ * create a new image, use the <b>createImage()</b> function. Do not
48
48
  * use the syntax <b>new PImage()</b>.
49
49
  *
50
50
  * ( end auto-generated )
@@ -184,11 +184,11 @@ public class PImage implements PConstants, Cloneable {
184
184
  * pixel in the image. A group of methods, described below, allow easy
185
185
  * access to the image's pixels and alpha channel and simplify the process
186
186
  * of compositing.
187
- * <br/> <br/>
187
+ *
188
188
  * Before using the <b>pixels[]</b> array, be sure to use the
189
189
  * <b>loadPixels()</b> method on the image to make sure that the pixel data
190
190
  * is properly loaded.
191
- * <br/> <br/>
191
+ *
192
192
  * To create a new image, use the <b>createImage()</b> function (do not use
193
193
  * <b>new PImage()</b>).
194
194
  * ( end auto-generated )
@@ -478,7 +478,7 @@ public class PImage implements PConstants, Cloneable {
478
478
  *
479
479
  * Loads the pixel data for the image into its <b>pixels[]</b> array. This
480
480
  * function must always be called before reading from or writing to <b>pixels[]</b>.
481
- * <br/><br/> renderers may or may not seem to require <b>loadPixels()</b>
481
+ * renderers may or may not seem to require <b>loadPixels()</b>
482
482
  * or <b>updatePixels()</b>. However, the rule is that any time you want to
483
483
  * manipulate the <b>pixels[]</b> array, you must first call
484
484
  * <b>loadPixels()</b>, and after changes have been made, call
@@ -517,14 +517,14 @@ public class PImage implements PConstants, Cloneable {
517
517
  * Updates the image with the data in its <b>pixels[]</b> array. Use in
518
518
  * conjunction with <b>loadPixels()</b>. If you're only reading pixels from
519
519
  * the array, there's no need to call <b>updatePixels()</b>.
520
- * <br/><br/> renderers may or may not seem to require <b>loadPixels()</b>
520
+ * renderers may or may not seem to require <b>loadPixels()</b>
521
521
  * or <b>updatePixels()</b>. However, the rule is that any time you want to
522
522
  * manipulate the <b>pixels[]</b> array, you must first call
523
523
  * <b>loadPixels()</b>, and after changes have been made, call
524
524
  * <b>updatePixels()</b>. Even if the renderer may not seem to use this
525
525
  * function in the current Processing release, this will always be subject
526
526
  * to change.
527
- * <br/> <br/>
527
+ *
528
528
  * Currently, none of the renderers use the additional parameters to
529
529
  * <b>updatePixels()</b>, however this may be implemented in the future.
530
530
  *
@@ -151,11 +151,13 @@ public class PMatrix2D implements PMatrix {
151
151
  *
152
152
  * @throws IllegalArgumentException
153
153
  */
154
+ @Override
154
155
  public void translate(float x, float y, float z) {
155
156
  throw new IllegalArgumentException("Cannot use translate(x, y, z) on a PMatrix2D.");
156
157
  }
157
158
 
158
159
  // Implementation roughly based on AffineTransform.
160
+ @Override
159
161
  public void rotate(float angle) {
160
162
  float s = sin(angle);
161
163
  float c = cos(angle);
@@ -175,6 +177,7 @@ public class PMatrix2D implements PMatrix {
175
177
  *
176
178
  * @throws IllegalArgumentException
177
179
  */
180
+ @Override
178
181
  public void rotateX(float angle) {
179
182
  throw new IllegalArgumentException("Cannot use rotateX() on a PMatrix2D.");
180
183
  }
@@ -197,14 +200,17 @@ public class PMatrix2D implements PMatrix {
197
200
  *
198
201
  * @throws IllegalArgumentException
199
202
  */
203
+ @Override
200
204
  public void rotate(float angle, float v0, float v1, float v2) {
201
205
  throw new IllegalArgumentException("Cannot use this version of rotate() on a PMatrix2D.");
202
206
  }
203
207
 
208
+ @Override
204
209
  public void scale(float s) {
205
210
  scale(s, s);
206
211
  }
207
212
 
213
+ @Override
208
214
  public void scale(float sx, float sy) {
209
215
  m00 *= sx;
210
216
  m01 *= sy;
@@ -405,7 +405,7 @@ public class PShape implements PConstants {
405
405
  *
406
406
  * Returns a boolean value "true" if the image is set to be visible, "false"
407
407
  * if not. This is modified with the <b>setVisible()</b> parameter.
408
- * <br/> <br/>
408
+ *
409
409
  * The visibility of a shape is usually controlled by whatever program
410
410
  * created the SVG file. For instance, this parameter is controlled by
411
411
  * showing or hiding the shape in the layers palette in Adobe Illustrator.
@@ -427,7 +427,7 @@ public class PShape implements PConstants {
427
427
  *
428
428
  * Sets the shape to be visible or invisible. This is determined by the
429
429
  * value of the <b>visible</b> parameter.
430
- * <br/> <br/>
430
+ *
431
431
  * The visibility of a shape is usually controlled by whatever program
432
432
  * created the SVG file. For instance, this parameter is controlled by
433
433
  * showing or hiding the shape in the layers palette in Adobe Illustrator.
@@ -2,6 +2,7 @@ package processing.core;
2
2
 
3
3
  import java.io.BufferedReader;
4
4
  import java.io.File;
5
+ import java.io.IOException;
5
6
  import java.util.ArrayList;
6
7
  import java.util.HashMap;
7
8
  import java.util.Map;
@@ -19,444 +20,459 @@ import java.util.Map;
19
20
  */
20
21
  public class PShapeOBJ extends PShape {
21
22
 
22
- /**
23
- * Initializes a new OBJ Object with the given filename.
24
- */
25
- public PShapeOBJ(PApplet parent, String filename) {
26
- this(parent, parent.createReader(filename), getBasePath(parent, filename));
23
+ /**
24
+ * Initializes a new OBJ Object with the given filename.
25
+ *
26
+ * @param parent
27
+ * @param filename
28
+ */
29
+ public PShapeOBJ(PApplet parent, String filename) {
30
+ this(parent, parent.createReader(filename), getBasePath(parent, filename));
31
+ }
32
+
33
+ public PShapeOBJ(PApplet parent, BufferedReader reader) {
34
+ this(parent, reader, "");
35
+ }
36
+
37
+ public PShapeOBJ(PApplet parent, BufferedReader reader, String basePath) {
38
+ ArrayList<OBJFace> faces = new ArrayList<>();
39
+ ArrayList<OBJMaterial> materials = new ArrayList<>();
40
+ ArrayList<PVector> coords = new ArrayList<>();
41
+ ArrayList<PVector> normals = new ArrayList<>();
42
+ ArrayList<PVector> texcoords = new ArrayList<>();
43
+ parseOBJ(parent, basePath, reader,
44
+ faces, materials, coords, normals, texcoords);
45
+
46
+ // The OBJ geometry is stored with each face in a separate child shape.
47
+ parent = null;
48
+ family = GROUP;
49
+ addChildren(faces, materials, coords, normals, texcoords);
50
+ }
51
+
52
+ protected PShapeOBJ(OBJFace face, OBJMaterial mtl,
53
+ ArrayList<PVector> coords,
54
+ ArrayList<PVector> normals,
55
+ ArrayList<PVector> texcoords) {
56
+ family = GEOMETRY;
57
+ switch (face.vertIdx.size()) {
58
+ case 3:
59
+ kind = TRIANGLES;
60
+ break;
61
+ case 4:
62
+ kind = QUADS;
63
+ break;
64
+ default:
65
+ kind = POLYGON;
66
+ break;
27
67
  }
28
68
 
29
- public PShapeOBJ(PApplet parent, BufferedReader reader) {
30
- this(parent, reader, "");
69
+ stroke = false;
70
+ fill = true;
71
+
72
+ // Setting material properties for the new face
73
+ fillColor = rgbaValue(mtl.kd);
74
+ ambientColor = rgbaValue(mtl.ka);
75
+ specularColor = rgbaValue(mtl.ks);
76
+ shininess = mtl.ns;
77
+ if (mtl.kdMap != null) {
78
+ // If current material is textured, then tinting the texture using the
79
+ // diffuse color.
80
+ tintColor = rgbaValue(mtl.kd, mtl.d);
31
81
  }
32
82
 
33
- public PShapeOBJ(PApplet parent, BufferedReader reader, String basePath) {
34
- ArrayList<OBJFace> faces = new ArrayList<OBJFace>();
35
- ArrayList<OBJMaterial> materials = new ArrayList<OBJMaterial>();
36
- ArrayList<PVector> coords = new ArrayList<PVector>();
37
- ArrayList<PVector> normals = new ArrayList<PVector>();
38
- ArrayList<PVector> texcoords = new ArrayList<PVector>();
39
- parseOBJ(parent, basePath, reader,
40
- faces, materials, coords, normals, texcoords);
41
-
42
- // The OBJ geometry is stored with each face in a separate child shape.
43
- parent = null;
44
- family = GROUP;
45
- addChildren(faces, materials, coords, normals, texcoords);
46
- }
47
-
48
- protected PShapeOBJ(OBJFace face, OBJMaterial mtl,
49
- ArrayList<PVector> coords,
50
- ArrayList<PVector> normals,
51
- ArrayList<PVector> texcoords) {
52
- family = GEOMETRY;
53
- if (face.vertIdx.size() == 3) {
54
- kind = TRIANGLES;
55
- } else if (face.vertIdx.size() == 4) {
56
- kind = QUADS;
57
- } else {
58
- kind = POLYGON;
59
- }
60
-
61
- stroke = false;
62
- fill = true;
63
-
64
- // Setting material properties for the new face
65
- fillColor = rgbaValue(mtl.kd);
66
- ambientColor = rgbaValue(mtl.ka);
67
- specularColor = rgbaValue(mtl.ks);
68
- shininess = mtl.ns;
69
- if (mtl.kdMap != null) {
70
- // If current material is textured, then tinting the texture using the
71
- // diffuse color.
72
- tintColor = rgbaValue(mtl.kd, mtl.d);
73
- }
74
-
75
- vertexCount = face.vertIdx.size();
76
- vertices = new float[vertexCount][12];
77
- for (int j = 0; j < face.vertIdx.size(); j++) {
78
- int vertIdx, normIdx, texIdx;
79
- PVector vert, norms, tex;
80
-
81
- vert = norms = tex = null;
82
-
83
- vertIdx = face.vertIdx.get(j).intValue() - 1;
84
- vert = coords.get(vertIdx);
85
-
86
- if (j < face.normIdx.size()) {
87
- normIdx = face.normIdx.get(j).intValue() - 1;
88
- if (-1 < normIdx) {
89
- norms = normals.get(normIdx);
90
- }
91
- }
92
-
93
- if (j < face.texIdx.size()) {
94
- texIdx = face.texIdx.get(j).intValue() - 1;
95
- if (-1 < texIdx) {
96
- tex = texcoords.get(texIdx);
97
- }
98
- }
83
+ vertexCount = face.vertIdx.size();
84
+ vertices = new float[vertexCount][12];
85
+ for (int j = 0; j < face.vertIdx.size(); j++) {
86
+ int vertIdx, normIdx, texIdx;
87
+ PVector vert, norms, tex;
99
88
 
100
- vertices[j][X] = vert.x;
101
- vertices[j][Y] = vert.y;
102
- vertices[j][Z] = vert.z;
89
+ vert = norms = tex = null;
103
90
 
104
- vertices[j][PGraphics.R] = mtl.kd.x;
105
- vertices[j][PGraphics.G] = mtl.kd.y;
106
- vertices[j][PGraphics.B] = mtl.kd.z;
107
- vertices[j][PGraphics.A] = 1;
91
+ vertIdx = face.vertIdx.get(j) - 1;
92
+ vert = coords.get(vertIdx);
108
93
 
109
- if (norms != null) {
110
- vertices[j][PGraphics.NX] = norms.x;
111
- vertices[j][PGraphics.NY] = norms.y;
112
- vertices[j][PGraphics.NZ] = norms.z;
113
- }
114
-
115
- if (tex != null) {
116
- vertices[j][PGraphics.U] = tex.x;
117
- vertices[j][PGraphics.V] = tex.y;
118
- }
119
-
120
- if (mtl != null && mtl.kdMap != null) {
121
- image = mtl.kdMap;
122
- }
94
+ if (j < face.normIdx.size()) {
95
+ normIdx = face.normIdx.get(j) - 1;
96
+ if (-1 < normIdx) {
97
+ norms = normals.get(normIdx);
123
98
  }
124
- }
125
-
126
- protected void addChildren(ArrayList<OBJFace> faces,
127
- ArrayList<OBJMaterial> materials,
128
- ArrayList<PVector> coords,
129
- ArrayList<PVector> normals,
130
- ArrayList<PVector> texcoords) {
131
- int mtlIdxCur = -1;
132
- OBJMaterial mtl = null;
133
- for (int i = 0; i < faces.size(); i++) {
134
- OBJFace face = faces.get(i);
135
-
136
- // Getting current material.
137
- if (mtlIdxCur != face.matIdx || face.matIdx == -1) {
138
- // To make sure that at least we get the default material
139
- mtlIdxCur = PApplet.max(0, face.matIdx);
140
- mtl = materials.get(mtlIdxCur);
141
- }
99
+ }
142
100
 
143
- // Creating child shape for current face.
144
- PShape child = new PShapeOBJ(face, mtl, coords, normals, texcoords);
145
- addChild(child);
101
+ if (j < face.texIdx.size()) {
102
+ texIdx = face.texIdx.get(j) - 1;
103
+ if (-1 < texIdx) {
104
+ tex = texcoords.get(texIdx);
146
105
  }
106
+ }
107
+
108
+ vertices[j][X] = vert.x;
109
+ vertices[j][Y] = vert.y;
110
+ vertices[j][Z] = vert.z;
111
+
112
+ vertices[j][PGraphics.R] = mtl.kd.x;
113
+ vertices[j][PGraphics.G] = mtl.kd.y;
114
+ vertices[j][PGraphics.B] = mtl.kd.z;
115
+ vertices[j][PGraphics.A] = 1;
116
+
117
+ if (norms != null) {
118
+ vertices[j][PGraphics.NX] = norms.x;
119
+ vertices[j][PGraphics.NY] = norms.y;
120
+ vertices[j][PGraphics.NZ] = norms.z;
121
+ }
122
+
123
+ if (tex != null) {
124
+ vertices[j][PGraphics.U] = tex.x;
125
+ vertices[j][PGraphics.V] = tex.y;
126
+ }
127
+
128
+ if (mtl.kdMap != null) {
129
+ image = mtl.kdMap;
130
+ }
131
+ }
132
+ }
133
+
134
+ protected void addChildren(ArrayList<OBJFace> faces,
135
+ ArrayList<OBJMaterial> materials,
136
+ ArrayList<PVector> coords,
137
+ ArrayList<PVector> normals,
138
+ ArrayList<PVector> texcoords) {
139
+ int mtlIdxCur = -1;
140
+ OBJMaterial mtl = null;
141
+ for (int i = 0; i < faces.size(); i++) {
142
+ OBJFace face = faces.get(i);
143
+
144
+ // Getting current material.
145
+ if (mtlIdxCur != face.matIdx || face.matIdx == -1) {
146
+ // To make sure that at least we get the default material
147
+ mtlIdxCur = PApplet.max(0, face.matIdx);
148
+ mtl = materials.get(mtlIdxCur);
149
+ }
150
+
151
+ // Creating child shape for current face.
152
+ PShape child = new PShapeOBJ(face, mtl, coords, normals, texcoords);
153
+ addChild(child);
147
154
  }
155
+ }
156
+
157
+ static protected void parseOBJ(PApplet parent, String path,
158
+ BufferedReader reader,
159
+ ArrayList<OBJFace> faces,
160
+ ArrayList<OBJMaterial> materials,
161
+ ArrayList<PVector> coords,
162
+ ArrayList<PVector> normals,
163
+ ArrayList<PVector> texcoords) {
164
+ Map<String, Integer> mtlTable = new HashMap<>();
165
+ int mtlIdxCur = -1;
166
+ boolean readv, readvn, readvt;
167
+ try {
168
+
169
+ readv = readvn = readvt = false;
170
+ String line;
171
+ String gname = "object";
172
+ while ((line = reader.readLine()) != null) {
173
+ // Parse the line.
174
+ line = line.trim();
175
+ if (line.equals("") || line.indexOf('#') == 0) {
176
+ // Empty line of comment, ignore line
177
+ continue;
178
+ }
148
179
 
149
- static protected void parseOBJ(PApplet parent, String path,
150
- BufferedReader reader,
151
- ArrayList<OBJFace> faces,
152
- ArrayList<OBJMaterial> materials,
153
- ArrayList<PVector> coords,
154
- ArrayList<PVector> normals,
155
- ArrayList<PVector> texcoords) {
156
- Map<String, Integer> mtlTable = new HashMap<String, Integer>();
157
- int mtlIdxCur = -1;
158
- boolean readv, readvn, readvt;
159
- try {
160
-
161
- readv = readvn = readvt = false;
162
- String line;
163
- String gname = "object";
164
- while ((line = reader.readLine()) != null) {
165
- // Parse the line.
166
- line = line.trim();
167
- if (line.equals("") || line.indexOf('#') == 0) {
168
- // Empty line of comment, ignore line
169
- continue;
180
+ // The below patch/hack comes from Carlos Tomas Marti and is a
181
+ // fix for single backslashes in Rhino obj files
182
+ // BEGINNING OF RHINO OBJ FILES HACK
183
+ // Statements can be broken in multiple lines using '\' at the
184
+ // end of a line.
185
+ // In regular expressions, the backslash is also an escape
186
+ // character.
187
+ // The regular expression \\ matches a single backslash. This
188
+ // regular expression as a Java string, becomes "\\\\".
189
+ // That's right: 4 backslashes to match a single one.
190
+ while (line.contains("\\")) {
191
+ line = line.split("\\\\")[0];
192
+ final String s = reader.readLine();
193
+ if (s != null) {
194
+ line += s;
195
+ }
196
+ }
197
+ // END OF RHINO OBJ FILES HACK
198
+
199
+ String[] parts = line.split("\\s+");
200
+ // if not a blank line, process the line.
201
+ if (parts.length > 0) {
202
+ switch (parts[0]) {
203
+ case "v": {
204
+ // vertex
205
+ PVector tempv = new PVector(Float.valueOf(parts[1]),
206
+ Float.valueOf(parts[2]),
207
+ Float.valueOf(parts[3]));
208
+ coords.add(tempv);
209
+ readv = true;
210
+ break;
211
+ }
212
+ case "vn":
213
+ // normal
214
+ PVector tempn = new PVector(Float.valueOf(parts[1]),
215
+ Float.valueOf(parts[2]),
216
+ Float.valueOf(parts[3]));
217
+ normals.add(tempn);
218
+ readvn = true;
219
+ break;
220
+ case "vt": {
221
+ // uv, inverting v to take into account Processing's inverted Y axis
222
+ // with respect to OpenGL.
223
+ PVector tempv = new PVector(Float.valueOf(parts[1]),
224
+ 1 - Float.valueOf(parts[2]));
225
+ texcoords.add(tempv);
226
+ readvt = true;
227
+ break;
228
+ }
229
+ // Object name is ignored, for now.
230
+ case "o":
231
+ break;
232
+ case "mtllib":
233
+ if (parts[1] != null) {
234
+ String fn = parts[1];
235
+ if (!fn.contains(File.separator) && !path.equals("")) {
236
+ // Relative file name, adding the base path.
237
+ fn = path + File.separator + fn;
238
+ }
239
+ BufferedReader mreader = parent.createReader(fn);
240
+ if (mreader != null) {
241
+ parseMTL(parent, fn, path, mreader, materials, mtlTable);
242
+ mreader.close();
170
243
  }
244
+ }
245
+ break;
246
+ case "g":
247
+ gname = 1 < parts.length ? parts[1] : "";
248
+ break;
249
+ case "usemtl":
250
+ // Getting index of current active material (will be applied on
251
+ // all subsequent faces).
252
+ if (parts[1] != null) {
253
+ String mtlname = parts[1];
254
+ if (mtlTable.containsKey(mtlname)) {
255
+ Integer tempInt = mtlTable.get(mtlname);
256
+ mtlIdxCur = tempInt;
257
+ } else {
258
+ mtlIdxCur = -1;
259
+ }
260
+ }
261
+ break;
262
+ case "f":
263
+ // Face setting
264
+ OBJFace face = new OBJFace();
265
+ face.matIdx = mtlIdxCur;
266
+ face.name = gname;
267
+ for (int i = 1; i < parts.length; i++) {
268
+ String seg = parts[i];
269
+
270
+ if (seg.indexOf("/") > 0) {
271
+ String[] forder = seg.split("/");
272
+
273
+ if (forder.length > 2) {
274
+ // Getting vertex and texture and normal indexes.
275
+ if (forder[0].length() > 0 && readv) {
276
+ face.vertIdx.add(Integer.valueOf(forder[0]));
277
+ }
171
278
 
172
- // The below patch/hack comes from Carlos Tomas Marti and is a
173
- // fix for single backslashes in Rhino obj files
174
- // BEGINNING OF RHINO OBJ FILES HACK
175
- // Statements can be broken in multiple lines using '\' at the
176
- // end of a line.
177
- // In regular expressions, the backslash is also an escape
178
- // character.
179
- // The regular expression \\ matches a single backslash. This
180
- // regular expression as a Java string, becomes "\\\\".
181
- // That's right: 4 backslashes to match a single one.
182
- while (line.contains("\\")) {
183
- line = line.split("\\\\")[0];
184
- final String s = reader.readLine();
185
- if (s != null) {
186
- line += s;
279
+ if (forder[1].length() > 0 && readvt) {
280
+ face.texIdx.add(Integer.valueOf(forder[1]));
187
281
  }
188
- }
189
- // END OF RHINO OBJ FILES HACK
190
-
191
- String[] parts = line.split("\\s+");
192
- // if not a blank line, process the line.
193
- if (parts.length > 0) {
194
- if (parts[0].equals("v")) {
195
- // vertex
196
- PVector tempv = new PVector(Float.valueOf(parts[1]).floatValue(),
197
- Float.valueOf(parts[2]).floatValue(),
198
- Float.valueOf(parts[3]).floatValue());
199
- coords.add(tempv);
200
- readv = true;
201
- } else if (parts[0].equals("vn")) {
202
- // normal
203
- PVector tempn = new PVector(Float.valueOf(parts[1]).floatValue(),
204
- Float.valueOf(parts[2]).floatValue(),
205
- Float.valueOf(parts[3]).floatValue());
206
- normals.add(tempn);
207
- readvn = true;
208
- } else if (parts[0].equals("vt")) {
209
- // uv, inverting v to take into account Processing's inverted Y axis
210
- // with respect to OpenGL.
211
- PVector tempv = new PVector(Float.valueOf(parts[1]).floatValue(),
212
- 1 - Float.valueOf(parts[2]).
213
- floatValue());
214
- texcoords.add(tempv);
215
- readvt = true;
216
- } else if (parts[0].equals("o")) {
217
- // Object name is ignored, for now.
218
- } else if (parts[0].equals("mtllib")) {
219
- if (parts[1] != null) {
220
- String fn = parts[1];
221
- if (fn.indexOf(File.separator) == -1 && !path.equals("")) {
222
- // Relative file name, adding the base path.
223
- fn = path + File.separator + fn;
224
- }
225
- BufferedReader mreader = parent.createReader(fn);
226
- if (mreader != null) {
227
- parseMTL(parent, fn, path, mreader, materials, mtlTable);
228
- mreader.close();
229
- }
230
- }
231
- } else if (parts[0].equals("g")) {
232
- gname = 1 < parts.length ? parts[1] : "";
233
- } else if (parts[0].equals("usemtl")) {
234
- // Getting index of current active material (will be applied on
235
- // all subsequent faces).
236
- if (parts[1] != null) {
237
- String mtlname = parts[1];
238
- if (mtlTable.containsKey(mtlname)) {
239
- Integer tempInt = mtlTable.get(mtlname);
240
- mtlIdxCur = tempInt.intValue();
241
- } else {
242
- mtlIdxCur = -1;
243
- }
244
- }
245
- } else if (parts[0].equals("f")) {
246
- // Face setting
247
- OBJFace face = new OBJFace();
248
- face.matIdx = mtlIdxCur;
249
- face.name = gname;
250
-
251
- for (int i = 1; i < parts.length; i++) {
252
- String seg = parts[i];
253
-
254
- if (seg.indexOf("/") > 0) {
255
- String[] forder = seg.split("/");
256
-
257
- if (forder.length > 2) {
258
- // Getting vertex and texture and normal indexes.
259
- if (forder[0].length() > 0 && readv) {
260
- face.vertIdx.add(Integer.valueOf(forder[0]));
261
- }
262
-
263
- if (forder[1].length() > 0 && readvt) {
264
- face.texIdx.add(Integer.valueOf(forder[1]));
265
- }
266
-
267
- if (forder[2].length() > 0 && readvn) {
268
- face.normIdx.add(Integer.valueOf(forder[2]));
269
- }
270
- } else if (forder.length > 1) {
271
- // Getting vertex and texture/normal indexes.
272
- if (forder[0].length() > 0 && readv) {
273
- face.vertIdx.add(Integer.valueOf(forder[0]));
274
- }
275
-
276
- if (forder[1].length() > 0) {
277
- if (readvt) {
278
- face.texIdx.add(Integer.valueOf(forder[1]));
279
- } else if (readvn) {
280
- face.normIdx.add(Integer.valueOf(forder[1]));
281
- }
282
-
283
- }
284
-
285
- } else if (forder.length > 0) {
286
- // Getting vertex index only.
287
- if (forder[0].length() > 0 && readv) {
288
- face.vertIdx.add(Integer.valueOf(forder[0]));
289
- }
290
- }
291
- } else {
292
- // Getting vertex index only.
293
- if (seg.length() > 0 && readv) {
294
- face.vertIdx.add(Integer.valueOf(seg));
295
- }
296
- }
297
- }
298
-
299
- faces.add(face);
282
+
283
+ if (forder[2].length() > 0 && readvn) {
284
+ face.normIdx.add(Integer.valueOf(forder[2]));
285
+ }
286
+ } else if (forder.length > 1) {
287
+ // Getting vertex and texture/normal indexes.
288
+ if (forder[0].length() > 0 && readv) {
289
+ face.vertIdx.add(Integer.valueOf(forder[0]));
300
290
  }
301
- }
302
- }
303
291
 
304
- if (materials.size() == 0) {
305
- // No materials definition so far. Adding one default material.
306
- OBJMaterial defMtl = new OBJMaterial();
307
- materials.add(defMtl);
308
- }
292
+ if (forder[1].length() > 0) {
293
+ if (readvt) {
294
+ face.texIdx.add(Integer.valueOf(forder[1]));
295
+ } else if (readvn) {
296
+ face.normIdx.add(Integer.valueOf(forder[1]));
297
+ }
309
298
 
310
- } catch (Exception e) {
311
- e.printStackTrace();
312
- }
313
- }
299
+ }
314
300
 
315
- static protected void parseMTL(PApplet parent, String mtlfn, String path,
316
- BufferedReader reader,
317
- ArrayList<OBJMaterial> materials,
318
- Map<String, Integer> materialsHash) {
319
- try {
320
- String line;
321
- OBJMaterial currentMtl = null;
322
- while ((line = reader.readLine()) != null) {
323
- // Parse the line
324
- line = line.trim();
325
- String parts[] = line.split("\\s+");
326
- if (parts.length > 0) {
327
- // Extract the material data.
328
- if (parts[0].equals("newmtl")) {
329
- // Starting new material.
330
- String mtlname = parts[1];
331
- currentMtl = addMaterial(mtlname, materials, materialsHash);
332
- } else {
333
- if (currentMtl == null) {
334
- currentMtl = addMaterial("material" + materials.size(),
335
- materials, materialsHash);
336
- }
337
- if (parts[0].equals("map_Kd") && parts.length > 1) {
338
- // Loading texture map.
339
- String texname = parts[1];
340
- if (texname.indexOf(File.separator) == -1 && !path.equals("")) {
341
- // Relative file name, adding the base path.
342
- texname = path + File.separator + texname;
343
- }
344
-
345
- File file = new File(parent.dataPath(texname));
346
- if (file.exists()) {
347
- currentMtl.kdMap = parent.loadImage(texname);
348
- } else {
349
- System.err.println("The texture map \"" + texname + "\" "
350
- + "in the materials definition file \"" + mtlfn + "\" "
351
- + "is missing or inaccessible, make sure "
352
- + "the URL is valid or that the file has been "
353
- + "added to your sketch and is readable.");
354
- }
355
- } else if (parts[0].equals("Ka") && parts.length > 3) {
356
- // The ambient color of the material
357
- currentMtl.ka.x = Float.valueOf(parts[1]).floatValue();
358
- currentMtl.ka.y = Float.valueOf(parts[2]).floatValue();
359
- currentMtl.ka.z = Float.valueOf(parts[3]).floatValue();
360
- } else if (parts[0].equals("Kd") && parts.length > 3) {
361
- // The diffuse color of the material
362
- currentMtl.kd.x = Float.valueOf(parts[1]).floatValue();
363
- currentMtl.kd.y = Float.valueOf(parts[2]).floatValue();
364
- currentMtl.kd.z = Float.valueOf(parts[3]).floatValue();
365
- } else if (parts[0].equals("Ks") && parts.length > 3) {
366
- // The specular color weighted by the specular coefficient
367
- currentMtl.ks.x = Float.valueOf(parts[1]).floatValue();
368
- currentMtl.ks.y = Float.valueOf(parts[2]).floatValue();
369
- currentMtl.ks.z = Float.valueOf(parts[3]).floatValue();
370
- } else if ((parts[0].equals("d")
371
- || parts[0].equals("Tr")) && parts.length > 1) {
372
- // Reading the alpha transparency.
373
- currentMtl.d = Float.valueOf(parts[1]).floatValue();
374
- } else if (parts[0].equals("Ns") && parts.length > 1) {
375
- // The specular component of the Phong shading model
376
- currentMtl.ns = Float.valueOf(parts[1]).floatValue();
377
- }
301
+ } else if (forder.length > 0) {
302
+ // Getting vertex index only.
303
+ if (forder[0].length() > 0 && readv) {
304
+ face.vertIdx.add(Integer.valueOf(forder[0]));
378
305
  }
306
+ }
307
+ } else {
308
+ // Getting vertex index only.
309
+ if (seg.length() > 0 && readv) {
310
+ face.vertIdx.add(Integer.valueOf(seg));
311
+ }
379
312
  }
380
- }
381
- } catch (Exception e) {
382
- e.printStackTrace();
313
+ }
314
+ faces.add(face);
315
+ break;
316
+ default:
317
+ break;
318
+ }
383
319
  }
384
- }
320
+ }
385
321
 
386
- protected static OBJMaterial addMaterial(String mtlname,
387
- ArrayList<OBJMaterial> materials,
388
- Map<String, Integer> materialsHash) {
389
- OBJMaterial currentMtl = new OBJMaterial(mtlname);
390
- materialsHash.put(mtlname, Integer.valueOf(materials.size()));
391
- materials.add(currentMtl);
392
- return currentMtl;
393
- }
322
+ if (materials.isEmpty()) {
323
+ // No materials definition so far. Adding one default material.
324
+ OBJMaterial defMtl = new OBJMaterial();
325
+ materials.add(defMtl);
326
+ }
394
327
 
395
- protected static int rgbaValue(PVector color) {
396
- return 0xFF000000 | ((int) (color.x * 255) << 16)
397
- | ((int) (color.y * 255) << 8)
398
- | (int) (color.z * 255);
328
+ } catch (IOException | NumberFormatException e) {
399
329
  }
400
-
401
- protected static int rgbaValue(PVector color, float alpha) {
402
- return ((int) (alpha * 255) << 24)
403
- | ((int) (color.x * 255) << 16)
404
- | ((int) (color.y * 255) << 8)
405
- | (int) (color.z * 255);
406
- }
407
-
408
- // Stores a face from an OBJ file
409
- static protected class OBJFace {
410
-
411
- ArrayList<Integer> vertIdx;
412
- ArrayList<Integer> texIdx;
413
- ArrayList<Integer> normIdx;
414
- int matIdx;
415
- String name;
416
-
417
- OBJFace() {
418
- vertIdx = new ArrayList<Integer>();
419
- texIdx = new ArrayList<Integer>();
420
- normIdx = new ArrayList<Integer>();
421
- matIdx = -1;
422
- name = "";
330
+ }
331
+
332
+ static protected void parseMTL(PApplet parent, String mtlfn, String path,
333
+ BufferedReader reader,
334
+ ArrayList<OBJMaterial> materials,
335
+ Map<String, Integer> materialsHash) {
336
+ try {
337
+ String line;
338
+ OBJMaterial currentMtl = null;
339
+ while ((line = reader.readLine()) != null) {
340
+ // Parse the line
341
+ line = line.trim();
342
+ String parts[] = line.split("\\s+");
343
+ if (parts.length > 0) {
344
+ // Extract the material data.
345
+ if (parts[0].equals("newmtl")) {
346
+ // Starting new material.
347
+ String mtlname = parts[1];
348
+ currentMtl = addMaterial(mtlname, materials, materialsHash);
349
+ } else {
350
+ if (currentMtl == null) {
351
+ currentMtl = addMaterial("material" + materials.size(),
352
+ materials, materialsHash);
353
+ }
354
+ if (parts[0].equals("map_Kd") && parts.length > 1) {
355
+ // Loading texture map.
356
+ String texname = parts[1];
357
+ if (!texname.contains(File.separator) && !path.equals("")) {
358
+ // Relative file name, adding the base path.
359
+ texname = path + File.separator + texname;
360
+ }
361
+
362
+ File file = new File(parent.dataPath(texname));
363
+ if (file.exists()) {
364
+ currentMtl.kdMap = parent.loadImage(texname);
365
+ } else {
366
+ System.err.println("The texture map \"" + texname + "\" "
367
+ + "in the materials definition file \"" + mtlfn + "\" "
368
+ + "is missing or inaccessible, make sure "
369
+ + "the URL is valid or that the file has been "
370
+ + "added to your sketch and is readable.");
371
+ }
372
+ } else if (parts[0].equals("Ka") && parts.length > 3) {
373
+ // The ambient color of the material
374
+ currentMtl.ka.x = Float.valueOf(parts[1]);
375
+ currentMtl.ka.y = Float.valueOf(parts[2]);
376
+ currentMtl.ka.z = Float.valueOf(parts[3]);
377
+ } else if (parts[0].equals("Kd") && parts.length > 3) {
378
+ // The diffuse color of the material
379
+ currentMtl.kd.x = Float.valueOf(parts[1]);
380
+ currentMtl.kd.y = Float.valueOf(parts[2]);
381
+ currentMtl.kd.z = Float.valueOf(parts[3]);
382
+ } else if (parts[0].equals("Ks") && parts.length > 3) {
383
+ // The specular color weighted by the specular coefficient
384
+ currentMtl.ks.x = Float.valueOf(parts[1]);
385
+ currentMtl.ks.y = Float.parseFloat(parts[2]);
386
+ currentMtl.ks.z = Float.parseFloat(parts[3]);
387
+ } else if ((parts[0].equals("d")
388
+ || parts[0].equals("Tr")) && parts.length > 1) {
389
+ // Reading the alpha transparency.
390
+ currentMtl.d = Float.parseFloat(parts[1]);
391
+ } else if (parts[0].equals("Ns") && parts.length > 1) {
392
+ // The specular component of the Phong shading model
393
+ currentMtl.ns = Float.parseFloat(parts[1]);
394
+ }
395
+ }
423
396
  }
397
+ }
398
+ } catch (IOException | NumberFormatException e) {
424
399
  }
425
-
426
- static protected String getBasePath(PApplet parent, String filename) {
427
- // Obtaining the path
428
- File file = new File(parent.dataPath(filename));
429
- if (!file.exists()) {
430
- file = parent.sketchFile(filename);
431
- }
432
- String absolutePath = file.getAbsolutePath();
433
- return absolutePath.substring(0,
434
- absolutePath.lastIndexOf(File.separator));
400
+ }
401
+
402
+ protected static OBJMaterial addMaterial(String mtlname,
403
+ ArrayList<OBJMaterial> materials,
404
+ Map<String, Integer> materialsHash) {
405
+ OBJMaterial currentMtl = new OBJMaterial(mtlname);
406
+ materialsHash.put(mtlname, materials.size());
407
+ materials.add(currentMtl);
408
+ return currentMtl;
409
+ }
410
+
411
+ protected static int rgbaValue(PVector color) {
412
+ return 0xFF000000 | ((int) (color.x * 255) << 16)
413
+ | ((int) (color.y * 255) << 8)
414
+ | (int) (color.z * 255);
415
+ }
416
+
417
+ protected static int rgbaValue(PVector color, float alpha) {
418
+ return ((int) (alpha * 255) << 24)
419
+ | ((int) (color.x * 255) << 16)
420
+ | ((int) (color.y * 255) << 8)
421
+ | (int) (color.z * 255);
422
+ }
423
+
424
+ // Stores a face from an OBJ file
425
+ static protected class OBJFace {
426
+
427
+ ArrayList<Integer> vertIdx;
428
+ ArrayList<Integer> texIdx;
429
+ ArrayList<Integer> normIdx;
430
+ int matIdx;
431
+ String name;
432
+
433
+ OBJFace() {
434
+ vertIdx = new ArrayList<>();
435
+ texIdx = new ArrayList<>();
436
+ normIdx = new ArrayList<>();
437
+ matIdx = -1;
438
+ name = "";
435
439
  }
440
+ }
436
441
 
437
- // Stores a material defined in an MTL file.
438
- static protected class OBJMaterial {
439
-
440
- String name;
441
- PVector ka;
442
- PVector kd;
443
- PVector ks;
444
- float d;
445
- float ns;
446
- PImage kdMap;
447
-
448
- OBJMaterial() {
449
- this("default");
450
- }
442
+ static protected String getBasePath(PApplet parent, String filename) {
443
+ // Obtaining the path
444
+ File file = new File(parent.dataPath(filename));
445
+ if (!file.exists()) {
446
+ file = parent.sketchFile(filename);
447
+ }
448
+ String absolutePath = file.getAbsolutePath();
449
+ return absolutePath.substring(0,
450
+ absolutePath.lastIndexOf(File.separator));
451
+ }
452
+
453
+ // Stores a material defined in an MTL file.
454
+ static protected class OBJMaterial {
455
+
456
+ String name;
457
+ PVector ka;
458
+ PVector kd;
459
+ PVector ks;
460
+ float d;
461
+ float ns;
462
+ PImage kdMap;
463
+
464
+ OBJMaterial() {
465
+ this("default");
466
+ }
451
467
 
452
- OBJMaterial(String name) {
453
- this.name = name;
454
- ka = new PVector(0.5f, 0.5f, 0.5f);
455
- kd = new PVector(0.5f, 0.5f, 0.5f);
456
- ks = new PVector(0.5f, 0.5f, 0.5f);
457
- d = 1.0f;
458
- ns = 0.0f;
459
- kdMap = null;
460
- }
468
+ OBJMaterial(String name) {
469
+ this.name = name;
470
+ ka = new PVector(0.5f, 0.5f, 0.5f);
471
+ kd = new PVector(0.5f, 0.5f, 0.5f);
472
+ ks = new PVector(0.5f, 0.5f, 0.5f);
473
+ d = 1.0f;
474
+ ns = 0.0f;
475
+ kdMap = null;
461
476
  }
477
+ }
462
478
  }