propane 3.3.1-java → 3.4.0-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }