42 import java.applet.Applet;
43 import java.awt.Graphics;
44 import java.awt.Color;
45 import java.awt.event.*;
52 @SuppressWarnings(
"serial")
53 class FileFormatException extends Exception {
55 public FileFormatException(String s) {
71 float xmin, xmax, ymin, ymax, zmin, zmax;
80 Model3D(InputStream is)
throws IOException, FileFormatException {
82 StreamTokenizer st =
new StreamTokenizer(
83 new BufferedReader(
new InputStreamReader(is,
"UTF-8")));
84 st.eolIsSignificant(
true);
88 switch (st.nextToken()) {
91 case StreamTokenizer.TT_EOL:
93 case StreamTokenizer.TT_WORD:
94 if (
"v".equals(st.sval)) {
95 double x = 0, y = 0, z = 0;
96 if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
98 if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
100 if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
105 addVert((
float) x, (
float) y, (
float) z);
106 while (st.ttype != StreamTokenizer.TT_EOL && st.ttype
107 != StreamTokenizer.TT_EOF) {
110 }
else if (
"f".equals(st.sval) ||
"fo".equals(st.sval) ||
"l".
116 if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
119 add(prev - 1, n - 1);
125 }
else if (st.ttype ==
'/') {
132 add(start - 1, prev - 1);
134 if (st.ttype != StreamTokenizer.TT_EOL) {
138 while (st.nextToken() != StreamTokenizer.TT_EOL
139 && st.ttype != StreamTokenizer.TT_EOF) {
146 if (st.ttype != StreamTokenizer.TT_EOF) {
147 throw new FileFormatException(st.toString());
152 int addVert(
float x,
float y,
float z) {
157 vert =
new float[maxvert * 3];
160 float nv[] =
new float[maxvert * 3];
161 System.arraycopy(vert, 0, nv, 0, vert.length);
173 void add(
int p1,
int p2) {
175 if (p1 >= nvert || p2 >= nvert) {
181 con =
new int[maxcon];
184 int nv[] =
new int[maxcon];
185 System.arraycopy(con, 0, nv, 0, con.length);
194 con[i] = (p1 << 16) | p2;
200 if (transformed || nvert <= 0) {
203 if (tvert ==
null || tvert.length < nvert * 3) {
204 tvert =
new int[nvert * 3];
206 mat.transform(vert, tvert, nvert);
212 private void quickSort(
int a[],
int left,
int right) {
213 int leftIndex = left;
214 int rightIndex = right;
221 partionElement = a[(left + right) / 2];
224 while (leftIndex <= rightIndex) {
228 while ((leftIndex < right) && (a[leftIndex] < partionElement)) {
235 while ((rightIndex > left) && (a[rightIndex] > partionElement)) {
240 if (leftIndex <= rightIndex) {
241 swap(a, leftIndex, rightIndex);
250 if (left < rightIndex) {
251 quickSort(a, left, rightIndex);
257 if (leftIndex < right) {
258 quickSort(a, leftIndex, right);
264 private void swap(
int a[],
int i,
int j) {
275 quickSort(con, 0, ncon - 1);
278 for (
int i = 0; i < limit; i++) {
294 void paint(Graphics g) {
295 if (vert ==
null || nvert <= 0) {
301 for (
int i = 0; i < 16; i++) {
302 int grey = (int) (170 * (1 - Math.pow(i / 15.0, 2.3)));
303 gr[i] =
new Color(grey, grey, grey);
310 if (lim <= 0 || nvert <= 0) {
313 for (
int i = 0; i < lim; i++) {
315 int p1 = ((T >> 16) & 0xFFFF) * 3;
316 int p2 = (T & 0xFFFF) * 3;
317 int grey = v[p1 + 2] + v[p2 + 2];
326 g.setColor(gr[grey]);
328 g.drawLine(v[p1], v[p1 + 1],
339 float _xmin = v[0], _xmax = _xmin;
340 float _ymin = v[1], _ymax = _ymin;
341 float _zmin = v[2], _zmax = _zmin;
342 for (
int i = nvert * 3; (i -= 3) > 0;) {
376 @SuppressWarnings(
"serial")
378 implements Runnable, MouseListener, MouseMotionListener {
381 boolean painted =
true;
384 float scalefudge = 1;
385 Matrix3D amat =
new Matrix3D(), tmat =
new Matrix3D();
386 String mdname =
null;
387 String message =
null;
391 mdname = getParameter(
"model");
393 scalefudge = Float.valueOf(getParameter(
"scale")).floatValue();
394 }
catch (Exception ignored) {
399 if (mdname ==
null) {
400 mdname =
"model.obj";
402 resize(getSize().width <= 20 ? 400 : getSize().width,
403 getSize().height <= 20 ? 400 : getSize().height);
404 addMouseListener(
this);
405 addMouseMotionListener(
this);
410 removeMouseListener(
this);
411 removeMouseMotionListener(
this);
416 InputStream is =
null;
418 Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
419 is = getClass().getResourceAsStream(mdname);
420 Model3D m =
new Model3D(is);
424 float xw = m.xmax - m.xmin;
425 float yw = m.ymax - m.ymin;
426 float zw = m.zmax - m.zmin;
433 float f1 = getSize().width / xw;
434 float f2 = getSize().height / xw;
435 xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;
436 }
catch (Exception e) {
438 message = e.toString();
444 }
catch (Exception e) {
451 if (md ==
null && message ==
null) {
452 new Thread(
this).start();
489 float xtheta = (prevy - y) * 360.0f / getSize().width;
490 float ytheta = (x - prevx) * 360.0f / getSize().height;
511 md.mat.translate(-(md.xmin + md.xmax) / 2,
512 -(md.ymin + md.ymax) / 2,
513 -(md.zmin + md.zmax) / 2);
515 md.mat.scale(xfac, -xfac, 16 * xfac / getSize().width);
516 md.mat.translate(getSize().width / 2, getSize().height / 2, 8);
517 md.transformed =
false;
520 }
else if (message !=
null) {
521 g.drawString(
"Error in model:", 3, 20);
522 g.drawString(message, 10, 40);
533 return "Title: ThreeD \nAuthor: James Gosling? \n"
534 +
"An applet to put a 3D model into a page.";
540 {
"model",
"path string",
"The path to the model to be displayed." },
541 {
"scale",
"float",
"The scale of the model. Default is 1." }