1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package net.jbeans.j3d.modeler.geometry;
24
25 /* ------------------ Import classes (packages) ------------------- *//package-summary/html">class="comment"> ------------------ Import classes (packages) ------------------- *//package-summary.html">class="comment">/* ------------------ Import classes (packages) ------------------- *//package-summary.html">class="comment"> ------------------ Import classes (packages) ------------------- */
26 import java.awt.*;
27 import java.awt.event.*;
28 import java.io.*;
29 import java.util.*;
30 import javax.media.j3d.*;
31 import javax.vecmath.*;
32
33
34 import net.jbeans.j3d.data.*;
35 import net.jbeans.j3d.modeler.geometry.util.*;
36
37 import net.jbeans.util.debug.*;
38
39
40
41
42 /***
43 * SurfaceModeler generates a suface geometry from the specified data.
44 *
45 * @version $Revision: 1.4 $
46 * @author Masahiro Takatsuka (masa@jbeans.net)
47 * @see GeometryModeler
48 */
49
50 public abstract class SurfaceModeler extends GeometryModeler {
51 private static final boolean DEBUG = Debug.getDebugFlag(SurfaceModeler.class);
52
53 private static final int INVALID_DATA = -1;
54 private static final int USE_INDICES = 0;
55 private static final int NO_INDICES = 1;
56
57 public static final int NAIVE_NORMAL = 0;
58 public static final int ADVANCE_NORMAL = 1;
59
60 static com.sun.j3d.utils.geometry.Triangulator sTriangulator = new com.sun.j3d.utils.geometry.Triangulator();
61 static com.sun.j3d.utils.geometry.Stripifier sStripifier = new com.sun.j3d.utils.geometry.Stripifier();
62
63
64 transient protected int totalIndex;
65
66
67
68 transient protected int[] essentials;
69
70 transient protected Object[] entryArray;
71
72 transient protected double[] tmp;
73 transient protected NormalGenerator normalgen;
74 transient protected GeometryInfo geomInfo;
75 transient protected double[] x;
76 transient protected double[] y;
77 transient protected double[] z;
78 transient protected double[] color;
79 transient protected double[] alpha;
80 transient protected double[][] normal;
81 transient protected double[][] tCoords;
82 transient protected int[] coordinateIndices;
83 transient protected int[] colorIndices;
84 transient protected int[] normalIndices;
85 transient protected int[] texCoordIndices;
86 transient protected int[] stripCounts;
87 transient protected int[] contourCounts;
88
89
90 transient protected Point3f[] coords3f;
91 transient protected Color3f[] colors3f;
92 transient protected Color4f[] colors4f;
93 transient protected Vector3f[] normals3f;
94 transient protected TexCoord2f[] texCoords2f;
95 transient protected TexCoord3f[] texCoords3f;
96
97 transient protected boolean hasColors = false;
98 transient protected boolean hasTCoords = false;
99
100 transient protected int coordDim = 3;
101 transient protected int colorDim = 4;
102 transient protected int normalDim = 3;
103 transient protected int tCoordDim = 2;
104
105 transient protected int primitive = GeometryInfo.POLYGON_ARRAY;
106
107
108 protected boolean computeNormalsOnUpdate;
109 protected ColorLookupTable lookupTable;
110 protected double creaseAngle;
111
112 public SurfaceModeler() {
113 super();
114 this.lookupTable = new ColorLookupTable();
115 setComputeNormalsOnUpdate(true);
116
117 initialize();
118 }
119
120 protected void initialize() {
121 this.tmp = new double[3];
122 this.normalgen = new NormalGenerator();
123 this.creaseAngle = this.normalgen.getCreaseAngle();
124 this.geomInfo = new GeometryInfo(this.primitive);
125 this.x = null;
126 this.y = null;
127 this.z = null;
128 this.color = null;
129 this.alpha = null;
130 this.normal = null;
131 this.tCoords = null;
132 initGeometry();
133 }
134
135 public void setCreaseAngle(double angle) {
136 this.creaseAngle = angle;
137 if (this.normalgen != null) {
138 this.normalgen.setCreaseAngle(this.creaseAngle);
139 }
140 }
141
142 public double getCreaseAngle() {
143 return this.creaseAngle;
144 }
145
146 protected abstract void initGeometry();
147
148 /***
149 * Get the value of computeNormalsOnUpdate.
150 * @return value of computeNormalsOnUpdate.
151 */
152 public boolean isComputeNormalsOnUpdate() {
153 return getComputeNormalsOnUpdate();
154 }
155
156 public boolean getComputeNormalsOnUpdate() {
157 return computeNormalsOnUpdate;
158 }
159
160 /***
161 * Set the value of computeNormalsOnUpdate.
162 * @param v Value to assign to computeNormalsOnUpdate.
163 */
164 public void setComputeNormalsOnUpdate(boolean v) {
165 this.computeNormalsOnUpdate = v;
166 }
167
168 public void setColorLookupTable(ColorLookupTable lookupTable) {
169 this.lookupTable = lookupTable;
170 setGeometryData();
171 }
172
173 public ColorLookupTable getLookupTable() {
174 return this.lookupTable;
175 }
176
177 public void setColorTable(Color[] colors) {
178 this.lookupTable.setColorLookupTable(colors);
179 setGeometryData();
180 }
181
182 public void setPrimitive(int primitive) {
183 switch (primitive) {
184 case GeometryInfo.POLYGON_ARRAY:
185 default:
186 primitive = GeometryInfo.POLYGON_ARRAY;
187 break;
188 case GeometryInfo.QUAD_ARRAY:
189 case GeometryInfo.TRIANGLE_ARRAY:
190 case GeometryInfo.TRIANGLE_FAN_ARRAY:
191 case GeometryInfo.TRIANGLE_STRIP_ARRAY:
192 break;
193 }
194 this.primitive = primitive;
195 }
196
197 public int getPrimitive() {
198 return this.primitive;
199 }
200
201 /***
202 * Serialization methods
203 */
204 private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
205 s.defaultReadObject();
206 initialize();
207 }
208
209 void setXCoordinates(double[] x) {
210 this.x = x;
211 }
212
213 void setYCoordinates(double[] y) {
214 this.y = y;
215 }
216
217 void setZCoordinates(double[] z) {
218 this.z = z;
219 }
220
221 void setColors(double[] color) {
222 this.color = color;
223 }
224
225 void setTransparency(double[] alpha) {
226 this.alpha = alpha;
227 }
228
229 void setNormals(double[][] normal) {
230 this.normal = normal;
231 }
232
233 void setTextureCoords(double[][] tCoords) {
234 this.tCoords = tCoords;
235 }
236
237 void setStripCounts(int[] stripcounts) {
238 this.stripCounts = stripcounts;
239 }
240
241 void setContourCounts(int[] contourcounts) {
242 this.contourCounts = contourcounts;
243 }
244
245 void setCoordinateIndices(int[] coordinateIndices) {
246 this.coordinateIndices = coordinateIndices;
247 }
248
249 void setColorIndices(int[] colorIndices) {
250 this.colorIndices = colorIndices;
251 }
252
253 void setNormalIndices(int[] normalIndices) {
254 this.normalIndices = normalIndices;
255 }
256
257 void setTextureCoordinateIndices(int[] texCoordIndices) {
258 this.texCoordIndices = texCoordIndices;
259 }
260
261 void setupGeometryInfo() {
262
263 if (DEBUG) {
264 System.out.println("primitive" + this.primitive);
265 }
266 this.geomInfo.reset(this.primitive);
267
268 int vertexCount = this.x.length;
269 double[] coords = new double[vertexCount * 3];
270 int tmpidx;
271 for (int i = 0; i < vertexCount; i++) {
272 tmpidx = i * 3;
273 coords[tmpidx ] = this.x[i];
274 coords[tmpidx + 1] = this.y[i];
275 coords[tmpidx + 2] = this.z[i];
276 }
277 this.geomInfo.setCoordinates(coords);
278
279 float[] colorValues = null;
280 if (this.color != null) {
281 this.hasColors = true;
282 if (this.alpha != null) {
283 colorValues = new float[this.color.length * 4];
284 } else {
285 colorValues = new float[this.color.length * 3];
286 }
287 for (int i = 0; i < this.color.length; i++) {
288 tmp = this.lookupTable.mapValue(this.color[i]);
289 for (int j = 0; j < 3; j++) {
290 colorValues[i * 3 + j] = (float) tmp[j];
291 }
292 if (this.alpha != null) {
293 colorValues[i + 3] = (float) this.alpha[i];
294 }
295 }
296 if (this.alpha != null) {
297 this.geomInfo.setColors4(colorValues);
298 } else {
299 this.geomInfo.setColors3(colorValues);
300 }
301 }
302
303 float[] tCoordValues = null;
304 if (this.tCoords != null) {
305 this.tCoordDim = this.tCoords[0].length;
306 this.hasTCoords = true;
307 tCoordValues = new float[this.tCoords.length * this.tCoordDim];
308
309 for (int i = 0; i < this.tCoords.length; i++) {
310 System.arraycopy(this.tCoords[i], 0, tCoordValues, i * this.tCoordDim, this.tCoordDim);
311 }
312 if (this.tCoordDim == 2) {
313 this.geomInfo.setTextureCoordinates2(tCoordValues);
314 } else {
315 this.geomInfo.setTextureCoordinates2(tCoordValues);
316 }
317 }
318
319 float[] normalValues = null;
320 if (this.normal != null) {
321 normalValues = new float[this.normal.length * 3];
322 for (int i = 0; i < this.normal.length; i++) {
323 System.arraycopy(this.normal[i], 0, normalValues, i * 3, 3);
324 }
325 this.geomInfo.setNormals(normalValues);
326 }
327
328 if (this.coordinateIndices != null) {
329 this.geomInfo.setCoordinateIndices(this.coordinateIndices);
330 }
331
332 if (this.colorIndices != null) {
333 this.geomInfo.setColorIndices(this.colorIndices);
334 }
335
336 if (this.normalIndices != null) {
337 this.geomInfo.setNormalIndices(this.normalIndices);
338 }
339
340 if (this.texCoordIndices != null) {
341 this.geomInfo.setTextureCoordinateIndices(this.texCoordIndices);
342 }
343
344 if (this.stripCounts != null) {
345 this.geomInfo.setStripCounts(this.stripCounts);
346 }
347
348 if (this.contourCounts != null) {
349 this.geomInfo.setContourCounts(this.contourCounts);
350 }
351
352
353 if (this.geomInfo.getPrimitive() == GeometryInfo.POLYGON_ARRAY) {
354 if (DEBUG) {
355 System.out.print("Triangulating...");
356 }
357 sTriangulator.triangulate(this.geomInfo);
358 if (DEBUG) {
359 System.out.println("\rTriangulating...finished");
360 }
361 }
362
363
364
365
366 if (normalValues == null) {
367 if (DEBUG) {
368 System.out.print("Generating normals...");
369 }
370 this.normalgen.generateNormals(this.geomInfo);
371 if (DEBUG) {
372 System.out.println("\rGenerating normals...finished");
373 }
374 }
375
376
377
378
379
380
381 if (false) {
382 if (DEBUG) {
383 System.out.print("Stripifiing...");
384 }
385 sStripifier.stripify(this.geomInfo);
386 this.geomInfo.recomputeIndices();
387 if (DEBUG) {
388 System.out.println("\rStripifiing...finished");
389 }
390 }
391 }
392
393 private void expandNormalRef(IndexedGeometryArray geom) {
394 Vector3f[] nrmls = geom.getNormalRef3f();
395 int indexcount = geom.getIndexCount();
396 int size = Math.max(indexcount, geom.getVertexCount());
397 if (DEBUG) {
398 System.out.println("expanded num = " + size);
399 }
400 Vector3f[] tmpnrmls = new Vector3f[size];
401 int[] nrmlInds = new int[indexcount];
402 geom.getNormalIndices(0, nrmlInds);
403 for (int i = 0; i < indexcount; i++) {
404 tmpnrmls[i] = new Vector3f(nrmls[nrmlInds[i]]);
405 nrmlInds[i] = i;
406 }
407 for (int i = indexcount; i < size; i++) {
408 tmpnrmls[i] = new Vector3f();
409 }
410 geom.setNormalRef3f(tmpnrmls);
411 geom.setNormalIndices(0, nrmlInds);
412 }
413
414 /***
415 * Construct a javax.media.j3d.GeometryArray object from geometry information.
416 */
417 protected void modelGeometry() {
418 setupGeometryInfo();
419
420
421 GeometryArray geom = this.geomInfo.getIndexedGeometryArray();
422
423 this.coords3f = ((GeometryArray) geom).getCoordRef3f();
424 if (this.computeNormalsOnUpdate) {
425 expandNormalRef((IndexedGeometryArray) geom);
426 }
427 this.normals3f = ((GeometryArray) geom).getNormalRef3f();
428
429 if (DEBUG) {
430 System.out.println("num of x = " + this.x.length);
431 System.out.println("num of coords3f = " + this.coords3f.length);
432 System.out.println("num of normals3f = " + this.normals3f.length);
433 }
434 if (this.hasColors) {
435 this.colors3f = ((GeometryArray) geom).getColorRef3f();
436 this.colors4f = ((GeometryArray) geom).getColorRef4f();
437 }
438
439 if (this.hasTCoords) {
440 if (this.tCoordDim == 2) {
441 this.texCoords2f = ((GeometryArray) geom).getTexCoordRef2f(0);
442 } else if (this.tCoordDim == 3) {
443 this.texCoords3f = ((GeometryArray) geom).getTexCoordRef3f(0);
444 }
445 }
446
447
448 setGeometry(geom);
449 }
450
451 /***
452 *
453 */
454 public void updateData(Geometry geom) {
455 int vertexCount = this.x.length;
456 for (int i = 0; i < vertexCount; i++) {
457 this.coords3f[i].x = (float) this.x[i];
458 this.coords3f[i].y = (float) this.y[i];
459 this.coords3f[i].z = (float) this.z[i];
460 }
461
462 if (this.color != null) {
463 for (int i = 0; i < this.color.length; i++) {
464 tmp = this.lookupTable.mapValue(this.color[i]);
465 if (this.alpha != null) {
466 this.colors4f[i].x = (float) tmp[0];
467 this.colors4f[i].y = (float) tmp[1];
468 this.colors4f[i].z = (float) tmp[2];
469 this.colors4f[i].w = (float) tmp[3];
470 } else {
471 this.colors3f[i].x = (float) tmp[0];
472 this.colors3f[i].y = (float) tmp[1];
473 this.colors3f[i].z = (float) tmp[2];
474 }
475 }
476 }
477
478 if (this.tCoords != null) {
479 for (int i = 0; i < this.tCoords.length; i++) {
480 if (tCoordDim == 2) {
481 this.texCoords2f[i].x = (float) this.tCoords[i][0];
482 this.texCoords2f[i].y = (float) this.tCoords[i][1];
483
484 } else {
485 this.texCoords3f[i].x = (float) this.tCoords[i][0];
486 this.texCoords3f[i].y = (float) this.tCoords[i][1];
487 this.texCoords3f[i].z = (float) this.tCoords[i][2];
488
489 }
490 }
491 }
492
493 if (this.normal != null) {
494 for (int i = 0; i < this.normal.length; i++) {
495 this.normals3f[i].x = (float) this.normal[i][0];
496 this.normals3f[i].y = (float) this.normal[i][1];
497 this.normals3f[i].z = (float) this.normal[i][2];
498 }
499 } else if (this.computeNormalsOnUpdate) {
500 this.normalgen.generateNormals((GeometryArray) geom, this.coords3f);
501 }
502 }
503
504 protected void setValueAt(int index, Object value) {
505 this.entryArray[index] = value;
506 if (DEBUG) {
507 System.out.println("setValuleAt:[" + index + "] = " + value);
508 }
509 setGeometryData();
510 }
511
512 protected boolean isDataReady() {
513 if (! checkSize()) {
514 return false;
515 }
516
517 for (int i = 0; i < this.essentials.length; i++) {
518 if (this.entryArray[this.essentials[i]] == null) {
519 return false;
520 }
521 }
522 return true;
523 }
524
525 private synchronized void setGeometryData() {
526 if (isDataReady()) {
527 boolean needsModel = needsModel();
528 setData();
529
530 if(needsModel) {
531 clearGeometry();
532 if (DEBUG) {
533 System.out.println("modeling...");
534 }
535 model();
536 } else {
537 if (DEBUG) {
538 System.out.println("updating...");
539 }
540 update();
541 }
542 }
543 }
544
545 protected abstract boolean checkSize();
546 protected abstract boolean needsModel();
547 protected abstract void setData();
548
549 private static Vector3f sV1 = new Vector3f();
550 private static Vector3f sV2 = new Vector3f();
551 private static Vector3f sNormal = new Vector3f();
552 protected static Vector3f geomCalcTriNormals(Point3f point3f, Point3f point3f1, Point3f point3f2) {
553 sV1.sub(point3f1, point3f);
554 sV2.sub(point3f2, point3f);
555 sNormal.cross(sV1, sV2);
556 sNormal.normalize();
557 return sNormal;
558 }
559 }
560