Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/demo/applets/WireFrame/ThreeD.java
38829 views
/*1* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031/*32* This source code is provided to illustrate the usage of a given feature33* or technique and has been deliberately simplified. Additional steps34* required for a production-quality application, such as security checks,35* input validation and proper error handling, might not be present in36* this sample code.37*/38394041import java.applet.Applet;42import java.awt.Graphics;43import java.awt.Color;44import java.awt.event.*;45import java.io.*;46import java.net.URL;474849/* A set of classes to parse, represent and display 3D wireframe models50represented in Wavefront .obj format. */51@SuppressWarnings("serial")52class FileFormatException extends Exception {5354public FileFormatException(String s) {55super(s);56}57}585960/** The representation of a 3D model */61final class Model3D {6263float vert[];64int tvert[];65int nvert, maxvert;66int con[];67int ncon, maxcon;68boolean transformed;69Matrix3D mat;70float xmin, xmax, ymin, ymax, zmin, zmax;7172Model3D() {73mat = new Matrix3D();74mat.xrot(20);75mat.yrot(30);76}7778/** Create a 3D model by parsing an input stream */79Model3D(InputStream is) throws IOException, FileFormatException {80this();81StreamTokenizer st = new StreamTokenizer(82new BufferedReader(new InputStreamReader(is, "UTF-8")));83st.eolIsSignificant(true);84st.commentChar('#');85scan:86while (true) {87switch (st.nextToken()) {88default:89break scan;90case StreamTokenizer.TT_EOL:91break;92case StreamTokenizer.TT_WORD:93if ("v".equals(st.sval)) {94double x = 0, y = 0, z = 0;95if (st.nextToken() == StreamTokenizer.TT_NUMBER) {96x = st.nval;97if (st.nextToken() == StreamTokenizer.TT_NUMBER) {98y = st.nval;99if (st.nextToken() == StreamTokenizer.TT_NUMBER) {100z = st.nval;101}102}103}104addVert((float) x, (float) y, (float) z);105while (st.ttype != StreamTokenizer.TT_EOL && st.ttype106!= StreamTokenizer.TT_EOF) {107st.nextToken();108}109} else if ("f".equals(st.sval) || "fo".equals(st.sval) || "l".110equals(st.sval)) {111int start = -1;112int prev = -1;113int n = -1;114while (true) {115if (st.nextToken() == StreamTokenizer.TT_NUMBER) {116n = (int) st.nval;117if (prev >= 0) {118add(prev - 1, n - 1);119}120if (start < 0) {121start = n;122}123prev = n;124} else if (st.ttype == '/') {125st.nextToken();126} else {127break;128}129}130if (start >= 0) {131add(start - 1, prev - 1);132}133if (st.ttype != StreamTokenizer.TT_EOL) {134break scan;135}136} else {137while (st.nextToken() != StreamTokenizer.TT_EOL138&& st.ttype != StreamTokenizer.TT_EOF) {139// no-op140}141}142}143}144is.close();145if (st.ttype != StreamTokenizer.TT_EOF) {146throw new FileFormatException(st.toString());147}148}149150/** Add a vertex to this model */151int addVert(float x, float y, float z) {152int i = nvert;153if (i >= maxvert) {154if (vert == null) {155maxvert = 100;156vert = new float[maxvert * 3];157} else {158maxvert *= 2;159float nv[] = new float[maxvert * 3];160System.arraycopy(vert, 0, nv, 0, vert.length);161vert = nv;162}163}164i *= 3;165vert[i] = x;166vert[i + 1] = y;167vert[i + 2] = z;168return nvert++;169}170171/** Add a line from vertex p1 to vertex p2 */172void add(int p1, int p2) {173int i = ncon;174if (p1 >= nvert || p2 >= nvert) {175return;176}177if (i >= maxcon) {178if (con == null) {179maxcon = 100;180con = new int[maxcon];181} else {182maxcon *= 2;183int nv[] = new int[maxcon];184System.arraycopy(con, 0, nv, 0, con.length);185con = nv;186}187}188if (p1 > p2) {189int t = p1;190p1 = p2;191p2 = t;192}193con[i] = (p1 << 16) | p2;194ncon = i + 1;195}196197/** Transform all the points in this model */198void transform() {199if (transformed || nvert <= 0) {200return;201}202if (tvert == null || tvert.length < nvert * 3) {203tvert = new int[nvert * 3];204}205mat.transform(vert, tvert, nvert);206transformed = true;207}208209/* Quick Sort implementation210*/211private void quickSort(int a[], int left, int right) {212int leftIndex = left;213int rightIndex = right;214int partionElement;215if (right > left) {216217/* Arbitrarily establishing partition element as the midpoint of218* the array.219*/220partionElement = a[(left + right) / 2];221222// loop through the array until indices cross223while (leftIndex <= rightIndex) {224/* find the first element that is greater than or equal to225* the partionElement starting from the leftIndex.226*/227while ((leftIndex < right) && (a[leftIndex] < partionElement)) {228++leftIndex;229}230231/* find an element that is smaller than or equal to232* the partionElement starting from the rightIndex.233*/234while ((rightIndex > left) && (a[rightIndex] > partionElement)) {235--rightIndex;236}237238// if the indexes have not crossed, swap239if (leftIndex <= rightIndex) {240swap(a, leftIndex, rightIndex);241++leftIndex;242--rightIndex;243}244}245246/* If the right index has not reached the left side of array247* must now sort the left partition.248*/249if (left < rightIndex) {250quickSort(a, left, rightIndex);251}252253/* If the left index has not reached the right side of array254* must now sort the right partition.255*/256if (leftIndex < right) {257quickSort(a, leftIndex, right);258}259260}261}262263private void swap(int a[], int i, int j) {264int T;265T = a[i];266a[i] = a[j];267a[j] = T;268}269270/** eliminate duplicate lines */271void compress() {272int limit = ncon;273int c[] = con;274quickSort(con, 0, ncon - 1);275int d = 0;276int pp1 = -1;277for (int i = 0; i < limit; i++) {278int p1 = c[i];279if (pp1 != p1) {280c[d] = p1;281d++;282}283pp1 = p1;284}285ncon = d;286}287static Color gr[];288289/** Paint this model to a graphics context. It uses the matrix associated290with this model to map from model space to screen space.291The next version of the browser should have double buffering,292which will make this *much* nicer */293void paint(Graphics g) {294if (vert == null || nvert <= 0) {295return;296}297transform();298if (gr == null) {299gr = new Color[16];300for (int i = 0; i < 16; i++) {301int grey = (int) (170 * (1 - Math.pow(i / 15.0, 2.3)));302gr[i] = new Color(grey, grey, grey);303}304}305int lg = 0;306int lim = ncon;307int c[] = con;308int v[] = tvert;309if (lim <= 0 || nvert <= 0) {310return;311}312for (int i = 0; i < lim; i++) {313int T = c[i];314int p1 = ((T >> 16) & 0xFFFF) * 3;315int p2 = (T & 0xFFFF) * 3;316int grey = v[p1 + 2] + v[p2 + 2];317if (grey < 0) {318grey = 0;319}320if (grey > 15) {321grey = 15;322}323if (grey != lg) {324lg = grey;325g.setColor(gr[grey]);326}327g.drawLine(v[p1], v[p1 + 1],328v[p2], v[p2 + 1]);329}330}331332/** Find the bounding box of this model */333void findBB() {334if (nvert <= 0) {335return;336}337float v[] = vert;338float _xmin = v[0], _xmax = _xmin;339float _ymin = v[1], _ymax = _ymin;340float _zmin = v[2], _zmax = _zmin;341for (int i = nvert * 3; (i -= 3) > 0;) {342float x = v[i];343if (x < _xmin) {344_xmin = x;345}346if (x > _xmax) {347_xmax = x;348}349float y = v[i + 1];350if (y < _ymin) {351_ymin = y;352}353if (y > _ymax) {354_ymax = y;355}356float z = v[i + 2];357if (z < _zmin) {358_zmin = z;359}360if (z > _zmax) {361_zmax = z;362}363}364this.xmax = _xmax;365this.xmin = _xmin;366this.ymax = _ymax;367this.ymin = _ymin;368this.zmax = _zmax;369this.zmin = _zmin;370}371}372373374/** An applet to put a 3D model into a page */375@SuppressWarnings("serial")376public class ThreeD extends Applet377implements Runnable, MouseListener, MouseMotionListener {378379Model3D md;380boolean painted = true;381float xfac;382int prevx, prevy;383float scalefudge = 1;384Matrix3D amat = new Matrix3D(), tmat = new Matrix3D();385String mdname = null;386String message = null;387388@Override389public void init() {390mdname = getParameter("model");391try {392scalefudge = Float.valueOf(getParameter("scale")).floatValue();393} catch (Exception ignored) {394// fall back to default scalefudge = 1395}396amat.yrot(20);397amat.xrot(20);398if (mdname == null) {399mdname = "model.obj";400}401resize(getSize().width <= 20 ? 400 : getSize().width,402getSize().height <= 20 ? 400 : getSize().height);403addMouseListener(this);404addMouseMotionListener(this);405}406407@Override408public void destroy() {409removeMouseListener(this);410removeMouseMotionListener(this);411}412413@Override414public void run() {415InputStream is = null;416try {417Thread.currentThread().setPriority(Thread.MIN_PRIORITY);418is = getClass().getResourceAsStream(mdname);419Model3D m = new Model3D(is);420md = m;421m.findBB();422m.compress();423float xw = m.xmax - m.xmin;424float yw = m.ymax - m.ymin;425float zw = m.zmax - m.zmin;426if (yw > xw) {427xw = yw;428}429if (zw > xw) {430xw = zw;431}432float f1 = getSize().width / xw;433float f2 = getSize().height / xw;434xfac = 0.7f * (f1 < f2 ? f1 : f2) * scalefudge;435} catch (Exception e) {436md = null;437message = e.toString();438}439try {440if (is != null) {441is.close();442}443} catch (Exception e) {444}445repaint();446}447448@Override449public void start() {450if (md == null && message == null) {451new Thread(this).start();452}453}454455@Override456public void stop() {457}458459@Override460public void mouseClicked(MouseEvent e) {461}462463@Override464public void mousePressed(MouseEvent e) {465prevx = e.getX();466prevy = e.getY();467e.consume();468}469470@Override471public void mouseReleased(MouseEvent e) {472}473474@Override475public void mouseEntered(MouseEvent e) {476}477478@Override479public void mouseExited(MouseEvent e) {480}481482@Override483public void mouseDragged(MouseEvent e) {484int x = e.getX();485int y = e.getY();486487tmat.unit();488float xtheta = (prevy - y) * 360.0f / getSize().width;489float ytheta = (x - prevx) * 360.0f / getSize().height;490tmat.xrot(xtheta);491tmat.yrot(ytheta);492amat.mult(tmat);493if (painted) {494painted = false;495repaint();496}497prevx = x;498prevy = y;499e.consume();500}501502@Override503public void mouseMoved(MouseEvent e) {504}505506@Override507public void paint(Graphics g) {508if (md != null) {509md.mat.unit();510md.mat.translate(-(md.xmin + md.xmax) / 2,511-(md.ymin + md.ymax) / 2,512-(md.zmin + md.zmax) / 2);513md.mat.mult(amat);514md.mat.scale(xfac, -xfac, 16 * xfac / getSize().width);515md.mat.translate(getSize().width / 2, getSize().height / 2, 8);516md.transformed = false;517md.paint(g);518setPainted();519} else if (message != null) {520g.drawString("Error in model:", 3, 20);521g.drawString(message, 10, 40);522}523}524525private synchronized void setPainted() {526painted = true;527notifyAll();528}529530@Override531public String getAppletInfo() {532return "Title: ThreeD \nAuthor: James Gosling? \n"533+ "An applet to put a 3D model into a page.";534}535536@Override537public String[][] getParameterInfo() {538String[][] info = {539{ "model", "path string", "The path to the model to be displayed." },540{ "scale", "float", "The scale of the model. Default is 1." }541};542return info;543}544}545546547