AppearanceTest.java Source code

Java tutorial

Introduction

Here is the source code for AppearanceTest.java

Source

/**********************************************************
 Copyright (C) 2001    Daniel Selman
    
 First distributed with the book "Java 3D Programming"
 by Daniel Selman and published by Manning Publications.
 http://manning.com/selman
    
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation, version 2.
    
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
    
 The license can be found on the WWW at:
 http://www.fsf.org/copyleft/gpl.html
    
 Or by writing to:
 Free Software Foundation, Inc.,
 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    
 Authors can be contacted at:
 Daniel Selman: daniel@selman.org
    
 If you make changes you think others would like, please 
 contact one of the authors or someone at the 
 www.j3d.org web site.
 **************************************************************/

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Frame;
import java.awt.GraphicsConfigTemplate;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;

import javax.media.j3d.AmbientLight;
import javax.media.j3d.Appearance;
import javax.media.j3d.AudioDevice;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.Bounds;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.Group;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.LineAttributes;
import javax.media.j3d.Locale;
import javax.media.j3d.Material;
import javax.media.j3d.NodeComponent;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.PointAttributes;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.QuadArray;
import javax.media.j3d.RenderingAttributes;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TexCoordGeneration;
import javax.media.j3d.Texture;
import javax.media.j3d.Texture2D;
import javax.media.j3d.TextureAttributes;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TransparencyAttributes;
import javax.media.j3d.View;
import javax.media.j3d.ViewPlatform;
import javax.media.j3d.VirtualUniverse;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;

import com.sun.j3d.audioengines.javasound.JavaSoundMixer;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior;
import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.image.TextureLoader;

/**
 * Allows the various Java 3D Appearance components to be specified
 * interactively and applies the Appearance to an object in a scene.
 * <p>
 * This example can only be run as an application as it uses a MenuBar which can
 * only be associated with a Frame (in AWT)
 */
public class AppearanceTest extends Java3dApplet {
    private static int m_kWidth = 400;

    private static int m_kHeight = 400;

    private Frame m_Frame = null;

    private Appearance m_Appearance = null;

    private AppearanceComponent[] m_ComponentArray = null;

    public AppearanceTest() {
        m_Appearance = new Appearance();

        TextureComponent.setComponent(this);

        m_ComponentArray = new AppearanceComponent[] { new PolygonComponent(m_Appearance),
                new ColoringComponent(m_Appearance), new LineComponent(m_Appearance),
                new MaterialComponent(m_Appearance), new PointComponent(m_Appearance),
                new RenderingComponent(m_Appearance), new TransparencyComponent(m_Appearance),
                new TextureComponent(m_Appearance), new TextureAttributesComponent(m_Appearance),
                new TexGenComponent(m_Appearance) };
    }

    protected void addCanvas3D(Canvas3D c3d) {
        if (m_Frame != null) {
            MenuBar menuBar = new MenuBar();

            for (int n = 0; n < m_ComponentArray.length; n++)
                menuBar.add(m_ComponentArray[n].createMenu());

            m_Frame.setMenuBar(menuBar);
        }

        setLayout(new BorderLayout());
        add(c3d, BorderLayout.CENTER);
        doLayout();
    }

    protected double getScale() {
        return 0.1;
    }

    protected BranchGroup createSceneBranchGroup() {
        BranchGroup objRoot = super.createSceneBranchGroup();

        TransformGroup zoomTg = new TransformGroup();
        zoomTg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        zoomTg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

        // attach a navigation behavior to the position of the viewer
        KeyNavigatorBehavior key = new KeyNavigatorBehavior(zoomTg);
        key.setSchedulingBounds(createApplicationBounds());
        key.setEnable(true);
        objRoot.addChild(key);

        // create a TransformGroup to flip the hand onto its end and enlarge it.
        TransformGroup objTrans1 = new TransformGroup();
        Transform3D tr = new Transform3D();
        objTrans1.getTransform(tr);
        tr.setEuler(new Vector3d(0.5 * Math.PI, 0.6, 0));
        objTrans1.setTransform(tr);

        // Set up the global lights
        Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f);
        Vector3f lDir1 = new Vector3f(-1.0f, -1.0f, -1.0f);
        Color3f alColor = new Color3f(0.2f, 0.2f, 0.2f);

        AmbientLight aLgt = new AmbientLight(alColor);
        aLgt.setInfluencingBounds(getApplicationBounds());
        DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1);
        lgt1.setInfluencingBounds(getApplicationBounds());

        objRoot.addChild(aLgt);
        objRoot.addChild(lgt1);

        int nScale = 50;

        Box box = new Box(nScale, nScale, nScale, Primitive.GENERATE_NORMALS | Primitive.GENERATE_TEXTURE_COORDS,
                m_Appearance);

        Shape3D frontFace = box.getShape(Box.LEFT);

        // create a new left face so we can
        // assign per-vertex colors

        GeometryArray geometry = new QuadArray(4, GeometryArray.COORDINATES | GeometryArray.NORMALS
                | GeometryArray.COLOR_4 | GeometryArray.TEXTURE_COORDINATE_2);

        nScale = 40;

        final float[] verts = {
                // left face
                -1.0f * nScale, -1.0f * nScale, 1.0f * nScale, -1.0f * nScale, 1.0f * nScale, 1.0f * nScale,
                -1.0f * nScale, 1.0f * nScale, -1.0f * nScale, -1.0f * nScale, -1.0f * nScale, -1.0f * nScale };

        final float[] colors = {
                // left face
                1, 0, 0, 0, 0, 1, 0, 0.2f, 0, 0, 1, 0.8f, 0, 0, 0, 1, };

        float[] tcoords = {
                // left
                1, 0, 1, 1, 0, 1, 0, 0 };

        Vector3f normalVector = new Vector3f(-1.0f, 0.0f, 0.0f);

        geometry.setColors(0, colors, 0, 4);

        for (int n = 0; n < 4; n++)
            geometry.setNormal(n, normalVector);

        geometry.setTextureCoordinates(0, tcoords, 0, 4);

        geometry.setCoordinates(0, verts);

        frontFace.setGeometry(geometry);

        // connect the scenegraph
        objTrans1.addChild(box);
        zoomTg.addChild(objTrans1);
        objRoot.addChild(zoomTg);

        return objRoot;
    }

    public static void main(String[] args) {
        AppearanceTest appearanceTest = new AppearanceTest();
        appearanceTest.saveCommandLineArguments(args);

        Frame frame = (Frame) new MainFrame(appearanceTest, m_kWidth, m_kHeight);

        appearanceTest.m_Frame = frame;
        appearanceTest.initJava3d();
    }
}

/*******************************************************************************
 * Copyright (C) 2001 Daniel Selman
 * 
 * First distributed with the book "Java 3D Programming" by Daniel Selman and
 * published by Manning Publications. http://manning.com/selman
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, version 2.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html
 * 
 * Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite
 * 330, Boston, MA 02111-1307, USA.
 * 
 * Authors can be contacted at: Daniel Selman: daniel@selman.org
 * 
 * If you make changes you think others would like, please contact one of the
 * authors or someone at the www.j3d.org web site.
 ******************************************************************************/

//*****************************************************************************
/**
 * Java3dApplet
 * 
 * Base class for defining a Java 3D applet. Contains some useful methods for
 * defining views and scenegraphs etc.
 * 
 * @author Daniel Selman
 * @version 1.0
 */
//*****************************************************************************

abstract class Java3dApplet extends Applet {
    public static int m_kWidth = 300;

    public static int m_kHeight = 300;

    protected String[] m_szCommandLineArray = null;

    protected VirtualUniverse m_Universe = null;

    protected BranchGroup m_SceneBranchGroup = null;

    protected Bounds m_ApplicationBounds = null;

    //   protected com.tornadolabs.j3dtree.Java3dTree m_Java3dTree = null;

    public Java3dApplet() {
    }

    public boolean isApplet() {
        try {
            System.getProperty("user.dir");
            System.out.println("Running as Application.");
            return false;
        } catch (Exception e) {
        }

        System.out.println("Running as Applet.");
        return true;
    }

    public URL getWorkingDirectory() throws java.net.MalformedURLException {
        URL url = null;

        try {
            File file = new File(System.getProperty("user.dir"));
            System.out.println("Running as Application:");
            System.out.println("   " + file.toURL());
            return file.toURL();
        } catch (Exception e) {
        }

        System.out.println("Running as Applet:");
        System.out.println("   " + getCodeBase());

        return getCodeBase();
    }

    public VirtualUniverse getVirtualUniverse() {
        return m_Universe;
    }

    //public com.tornadolabs.j3dtree.Java3dTree getJ3dTree() {
    //return m_Java3dTree;
    //   }

    public Locale getFirstLocale() {
        java.util.Enumeration e = m_Universe.getAllLocales();

        if (e.hasMoreElements() != false)
            return (Locale) e.nextElement();

        return null;
    }

    protected Bounds getApplicationBounds() {
        if (m_ApplicationBounds == null)
            m_ApplicationBounds = createApplicationBounds();

        return m_ApplicationBounds;
    }

    protected Bounds createApplicationBounds() {
        m_ApplicationBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
        return m_ApplicationBounds;
    }

    protected Background createBackground() {
        Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f));
        back.setApplicationBounds(createApplicationBounds());
        return back;
    }

    public void initJava3d() {
        //   m_Java3dTree = new com.tornadolabs.j3dtree.Java3dTree();
        m_Universe = createVirtualUniverse();

        Locale locale = createLocale(m_Universe);

        BranchGroup sceneBranchGroup = createSceneBranchGroup();

        ViewPlatform vp = createViewPlatform();
        BranchGroup viewBranchGroup = createViewBranchGroup(getViewTransformGroupArray(), vp);

        createView(vp);

        Background background = createBackground();

        if (background != null)
            sceneBranchGroup.addChild(background);

        //      m_Java3dTree.recursiveApplyCapability(sceneBranchGroup);
        //   m_Java3dTree.recursiveApplyCapability(viewBranchGroup);

        locale.addBranchGraph(sceneBranchGroup);
        addViewBranchGroup(locale, viewBranchGroup);

        onDoneInit();
    }

    protected void onDoneInit() {
        //   m_Java3dTree.updateNodes(m_Universe);
    }

    protected double getScale() {
        return 1.0;
    }

    public TransformGroup[] getViewTransformGroupArray() {
        TransformGroup[] tgArray = new TransformGroup[1];
        tgArray[0] = new TransformGroup();

        // move the camera BACK a little...
        // note that we have to invert the matrix as
        // we are moving the viewer
        Transform3D t3d = new Transform3D();
        t3d.setScale(getScale());
        t3d.setTranslation(new Vector3d(0.0, 0.0, -20.0));
        t3d.invert();
        tgArray[0].setTransform(t3d);

        return tgArray;
    }

    protected void addViewBranchGroup(Locale locale, BranchGroup bg) {
        locale.addBranchGraph(bg);
    }

    protected Locale createLocale(VirtualUniverse u) {
        return new Locale(u);
    }

    protected BranchGroup createSceneBranchGroup() {
        m_SceneBranchGroup = new BranchGroup();
        return m_SceneBranchGroup;
    }

    protected View createView(ViewPlatform vp) {
        View view = new View();

        PhysicalBody pb = createPhysicalBody();
        PhysicalEnvironment pe = createPhysicalEnvironment();

        AudioDevice audioDevice = createAudioDevice(pe);

        if (audioDevice != null) {
            pe.setAudioDevice(audioDevice);
            audioDevice.initialize();
        }

        view.setPhysicalEnvironment(pe);
        view.setPhysicalBody(pb);

        if (vp != null)
            view.attachViewPlatform(vp);

        view.setBackClipDistance(getBackClipDistance());
        view.setFrontClipDistance(getFrontClipDistance());

        Canvas3D c3d = createCanvas3D();
        view.addCanvas3D(c3d);
        addCanvas3D(c3d);

        return view;
    }

    protected PhysicalBody createPhysicalBody() {
        return new PhysicalBody();
    }

    protected AudioDevice createAudioDevice(PhysicalEnvironment pe) {
        JavaSoundMixer javaSoundMixer = new JavaSoundMixer(pe);

        if (javaSoundMixer == null)
            System.out.println("create of audiodevice failed");

        return javaSoundMixer;
    }

    protected PhysicalEnvironment createPhysicalEnvironment() {
        return new PhysicalEnvironment();
    }

    protected float getViewPlatformActivationRadius() {
        return 100;
    }

    protected ViewPlatform createViewPlatform() {
        ViewPlatform vp = new ViewPlatform();
        vp.setViewAttachPolicy(View.RELATIVE_TO_FIELD_OF_VIEW);
        vp.setActivationRadius(getViewPlatformActivationRadius());

        return vp;
    }

    protected Canvas3D createCanvas3D() {
        GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D();
        gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED);
        GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();

        Canvas3D c3d = new Canvas3D(gd[0].getBestConfiguration(gc3D));
        c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d));

        return c3d;
    }

    protected int getCanvas3dWidth(Canvas3D c3d) {
        return m_kWidth;
    }

    protected int getCanvas3dHeight(Canvas3D c3d) {
        return m_kHeight;
    }

    protected double getBackClipDistance() {
        return 100.0;
    }

    protected double getFrontClipDistance() {
        return 1.0;
    }

    protected BranchGroup createViewBranchGroup(TransformGroup[] tgArray, ViewPlatform vp) {
        BranchGroup vpBranchGroup = new BranchGroup();

        if (tgArray != null && tgArray.length > 0) {
            Group parentGroup = vpBranchGroup;
            TransformGroup curTg = null;

            for (int n = 0; n < tgArray.length; n++) {
                curTg = tgArray[n];
                parentGroup.addChild(curTg);
                parentGroup = curTg;
            }

            tgArray[tgArray.length - 1].addChild(vp);
        } else
            vpBranchGroup.addChild(vp);

        return vpBranchGroup;
    }

    protected void addCanvas3D(Canvas3D c3d) {
        setLayout(new BorderLayout());
        add(c3d, BorderLayout.CENTER);
        doLayout();
    }

    protected VirtualUniverse createVirtualUniverse() {
        return new VirtualUniverse();
    }

    protected void saveCommandLineArguments(String[] szArgs) {
        m_szCommandLineArray = szArgs;
    }

    protected String[] getCommandLineArguments() {
        return m_szCommandLineArray;
    }
}

class LineComponent extends AppearanceComponent {
    public LineComponent(Appearance app) {
        super(app);
    }

    protected int[] getCapabilities() {
        return new int[] { LineAttributes.ALLOW_ANTIALIASING_WRITE, LineAttributes.ALLOW_PATTERN_WRITE,
                LineAttributes.ALLOW_WIDTH_WRITE };
    }

    protected NodeComponent createComponent() {
        return (NodeComponent) new LineAttributes();
    }

    protected void setAppearanceCapability() {
        m_Appearance.setCapability(Appearance.ALLOW_LINE_ATTRIBUTES_WRITE);
    }

    protected void assignToAppearance() {
        m_Appearance.setLineAttributes((LineAttributes) m_NodeComponent);
    }

    protected void assignNullToAppearance() {
        m_Appearance.setLineAttributes(null);
    }

    protected String getName() {
        return "Line";
    }

    protected String[] getMenuItemNames() {
        return new String[] { "-", "Antialiasing", "-", "On", "Off", "-", "Pattern", "-", "Dash", "DashDot", "Dot",
                "Solid", "-", "Width", "-", "1", "2", "5", "10" };
    }

    private LineAttributes getLineAttributes() {
        return (LineAttributes) m_NodeComponent;
    }

    public void onOn() {
        getLineAttributes().setLineAntialiasingEnable(true);
    }

    public void onOff() {
        getLineAttributes().setLineAntialiasingEnable(false);
    }

    public void onDash() {
        getLineAttributes().setLinePattern(LineAttributes.PATTERN_DASH);
    }

    public void onDashDot() {
        getLineAttributes().setLinePattern(LineAttributes.PATTERN_DASH_DOT);
    }

    public void onDot() {
        getLineAttributes().setLinePattern(LineAttributes.PATTERN_DOT);
    }

    public void onSolid() {
        getLineAttributes().setLinePattern(LineAttributes.PATTERN_SOLID);
    }

    public void on1() {
        getLineAttributes().setLineWidth(1);
    }

    public void on2() {
        getLineAttributes().setLineWidth(2);
    }

    public void on5() {
        getLineAttributes().setLineWidth(5);
    }

    public void on10() {
        getLineAttributes().setLineWidth(10);
    }
}

class MaterialComponent extends AppearanceComponent {
    public MaterialComponent(Appearance app) {
        super(app);
    }

    protected int[] getCapabilities() {
        return new int[] { Material.ALLOW_COMPONENT_WRITE };
    }

    protected NodeComponent createComponent() {
        return (NodeComponent) new Material();
    }

    protected void setAppearanceCapability() {
        m_Appearance.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
    }

    protected void assignToAppearance() {
        m_Appearance.setMaterial((Material) m_NodeComponent);
    }

    protected void assignNullToAppearance() {
        m_Appearance.setMaterial(null);
    }

    protected String getName() {
        return "Material";
    }

    protected String[] getMenuItemNames() {
        return new String[] { "-", "Ambient", "-", "A_White", "A_Black", "A_Blue", "-", "Diffuse", "-", "D_White",
                "D_Black", "D_Blue", "-", "Emissive", "-", "E_White", "E_Black", "E_Blue", "-", "Specular", "-",
                "S_White", "S_Black", "S_Blue", "-", "Lighting", "-", "On", "Off", "-", "Shininess", "-", "1",
                "70", };
    }

    private Material getMaterial() {
        return (Material) m_NodeComponent;
    }

    public void onA_White() {
        getMaterial().setAmbientColor(1, 1, 1);
    }

    public void onA_Black() {
        getMaterial().setAmbientColor(0, 0, 0);
    }

    public void onA_Blue() {
        getMaterial().setAmbientColor(0, 0, 1);
    }

    public void onE_White() {
        getMaterial().setEmissiveColor(1, 1, 1);
    }

    public void onE_Black() {
        getMaterial().setEmissiveColor(0, 0, 0);
    }

    public void onE_Blue() {
        getMaterial().setEmissiveColor(0, 0, 1);
    }

    public void onD_White() {
        getMaterial().setDiffuseColor(1, 1, 1);
    }

    public void onD_Black() {
        getMaterial().setDiffuseColor(0, 0, 0);
    }

    public void onD_Blue() {
        getMaterial().setDiffuseColor(0, 0, 1);
    }

    public void onS_White() {
        getMaterial().setSpecularColor(1, 1, 1);
    }

    public void onS_Black() {
        getMaterial().setSpecularColor(0, 0, 0);
    }

    public void onS_Blue() {
        getMaterial().setSpecularColor(0, 0, 1);
    }

    public void onOn() {
        getMaterial().setLightingEnable(true);
    }

    public void onOff() {
        getMaterial().setLightingEnable(false);
    }

    public void on1() {
        getMaterial().setShininess(1);
    }

    public void on70() {
        getMaterial().setShininess(70);
    }
}

class PointComponent extends AppearanceComponent {
    public PointComponent(Appearance app) {
        super(app);
    }

    protected int[] getCapabilities() {
        return new int[] { PointAttributes.ALLOW_ANTIALIASING_WRITE, PointAttributes.ALLOW_SIZE_WRITE };
    }

    protected NodeComponent createComponent() {
        return (NodeComponent) new PointAttributes();
    }

    protected void setAppearanceCapability() {
        m_Appearance.setCapability(Appearance.ALLOW_POINT_ATTRIBUTES_WRITE);
    }

    protected void assignToAppearance() {
        m_Appearance.setPointAttributes((PointAttributes) m_NodeComponent);
    }

    protected void assignNullToAppearance() {
        m_Appearance.setPointAttributes(null);
    }

    protected String getName() {
        return "Point";
    }

    protected String[] getMenuItemNames() {
        return new String[] { "-", "Antialiasing", "-", "On", "Off", "-", "Size", "-", "1", "5", "10" };
    }

    private PointAttributes getPointAttributes() {
        return (PointAttributes) m_NodeComponent;
    }

    public void onOn() {
        getPointAttributes().setPointAntialiasingEnable(true);
    }

    public void onOff() {
        getPointAttributes().setPointAntialiasingEnable(false);
    }

    public void on1() {
        getPointAttributes().setPointSize(1);
    }

    public void on5() {
        getPointAttributes().setPointSize(5);
    }

    public void on10() {
        getPointAttributes().setPointSize(10);
    }
}

class PolygonComponent extends AppearanceComponent {
    public PolygonComponent(Appearance app) {
        super(app);
    }

    protected int[] getCapabilities() {
        return new int[] { PolygonAttributes.ALLOW_CULL_FACE_WRITE, PolygonAttributes.ALLOW_MODE_WRITE,
                PolygonAttributes.ALLOW_NORMAL_FLIP_WRITE, PolygonAttributes.ALLOW_OFFSET_WRITE };
    }

    protected NodeComponent createComponent() {
        return (NodeComponent) new PolygonAttributes();
    }

    protected void setAppearanceCapability() {
        m_Appearance.setCapability(Appearance.ALLOW_POLYGON_ATTRIBUTES_WRITE);
    }

    protected void assignToAppearance() {
        m_Appearance.setPolygonAttributes((PolygonAttributes) m_NodeComponent);
    }

    protected void assignNullToAppearance() {
        m_Appearance.setPolygonAttributes(null);
    }

    protected String getName() {
        return "Polygon";
    }

    protected String[] getMenuItemNames() {
        return new String[] { "-", "Cull", "-", "Back", "Front", "None", "-", "Mode", "-", "Fill", "Line", "Point",
                "-", "Normal", "-", "Flip_ON", "Flip_OFF", "-", "Offset", "-", "0", "10", "50", "200" };
    }

    private PolygonAttributes getPolygonAttributes() {
        return (PolygonAttributes) m_NodeComponent;
    }

    public void onBack() {
        getPolygonAttributes().setCullFace(PolygonAttributes.CULL_BACK);
    }

    public void onFront() {
        getPolygonAttributes().setCullFace(PolygonAttributes.CULL_FRONT);
    }

    public void onNone() {
        getPolygonAttributes().setCullFace(PolygonAttributes.CULL_NONE);
    }

    public void onFill() {
        getPolygonAttributes().setPolygonMode(PolygonAttributes.POLYGON_FILL);
    }

    public void onLine() {
        getPolygonAttributes().setPolygonMode(PolygonAttributes.POLYGON_LINE);
    }

    public void onPoint() {
        getPolygonAttributes().setPolygonMode(PolygonAttributes.POLYGON_POINT);
    }

    public void onFlip_ON() {
        getPolygonAttributes().setBackFaceNormalFlip(true);
    }

    public void onFlip_OFF() {
        getPolygonAttributes().setBackFaceNormalFlip(false);
    }

    public void on0() {
        getPolygonAttributes().setPolygonOffset(0);
    }

    public void on10() {
        getPolygonAttributes().setPolygonOffset(10);
    }

    public void on50() {
        getPolygonAttributes().setPolygonOffset(50);
    }

    public void on200() {
        getPolygonAttributes().setPolygonOffset(200);
    }
}

class RenderingComponent extends AppearanceComponent {
    public RenderingComponent(Appearance app) {
        super(app);
    }

    protected int[] getCapabilities() {
        return new int[] { RenderingAttributes.ALLOW_ALPHA_TEST_FUNCTION_WRITE,
                RenderingAttributes.ALLOW_ALPHA_TEST_VALUE_WRITE, RenderingAttributes.ALLOW_DEPTH_ENABLE_READ };
    }

    protected NodeComponent createComponent() {
        return (NodeComponent) new RenderingAttributes();
    }

    protected void setAppearanceCapability() {
        m_Appearance.setCapability(Appearance.ALLOW_RENDERING_ATTRIBUTES_WRITE);
    }

    protected void assignToAppearance() {
        m_Appearance.setRenderingAttributes((RenderingAttributes) m_NodeComponent);
    }

    protected void assignNullToAppearance() {
        m_Appearance.setRenderingAttributes(null);
    }

    protected String getName() {
        return "Rendering";
    }

    protected String[] getMenuItemNames() {
        return new String[] { "-", "AlphaTest", "-", "ALWAYS", "NEVER", "EQUAL", "NOT_EQUAL", "LESS",
                "LESS_OR_EQUAL", "GREATER", "GREATER_OR_EQUAL", "-", "AlphaTest Value", "-", "0", "0point5", "1",
                "-", "Depth Buffer", "-", "On", "Off", "-", "Depth Buffer Write", "-", "Enable", "Disable", };
    }

    private RenderingAttributes getRenderingAttributes() {
        return (RenderingAttributes) m_NodeComponent;
    }

    public void onALWAYS() {
        getRenderingAttributes().setAlphaTestFunction(RenderingAttributes.ALWAYS);
    }

    public void onNEVER() {
        getRenderingAttributes().setAlphaTestFunction(RenderingAttributes.NEVER);
    }

    public void onEQUAL() {
        getRenderingAttributes().setAlphaTestFunction(RenderingAttributes.EQUAL);
    }

    public void onNOT_EQUAL() {
        getRenderingAttributes().setAlphaTestFunction(RenderingAttributes.NOT_EQUAL);
    }

    public void onLESS() {
        getRenderingAttributes().setAlphaTestFunction(RenderingAttributes.LESS);
    }

    public void onLESS_OR_EQUAL() {
        getRenderingAttributes().setAlphaTestFunction(RenderingAttributes.LESS_OR_EQUAL);
    }

    public void onGREATER() {
        getRenderingAttributes().setAlphaTestFunction(RenderingAttributes.GREATER);
    }

    public void onGREATER_OR_EQUAL() {
        getRenderingAttributes().setAlphaTestFunction(RenderingAttributes.GREATER_OR_EQUAL);
    }

    public void on0() {
        getRenderingAttributes().setAlphaTestValue(0);
    }

    public void on0point5() {
        getRenderingAttributes().setAlphaTestValue(0.5f);
    }

    public void on1() {
        getRenderingAttributes().setAlphaTestValue(1);
    }

    public void onOn() {
        getRenderingAttributes().setDepthBufferEnable(true);
    }

    public void onOff() {
        getRenderingAttributes().setDepthBufferEnable(false);
    }

    public void onEnable() {
        getRenderingAttributes().setDepthBufferWriteEnable(true);
    }

    public void onDisable() {
        getRenderingAttributes().setDepthBufferWriteEnable(false);
    }
}

class TexGenComponent extends AppearanceComponent {
    TexCoordGeneration m_TexCoordGeneration = null;

    final float m_PlaneFactor = 0.02f;

    public TexGenComponent(Appearance app) {
        super(app);
    }

    protected int[] getCapabilities() {
        return new int[] { TexCoordGeneration.ALLOW_ENABLE_WRITE };
    }

    protected NodeComponent createComponent() {
        return (NodeComponent) new TexCoordGeneration(TexCoordGeneration.OBJECT_LINEAR,
                TexCoordGeneration.TEXTURE_COORDINATE_3);
    }

    protected void setAppearanceCapability() {
        m_Appearance.setCapability(Appearance.ALLOW_TEXGEN_WRITE);
    }

    protected void assignToAppearance() {
        m_TexCoordGeneration = new TexCoordGeneration();
        m_TexCoordGeneration.duplicateNodeComponent(m_NodeComponent);
        m_Appearance.setTexCoordGeneration(m_TexCoordGeneration);
    }

    protected void assignNullToAppearance() {
        m_Appearance.setTexCoordGeneration(null);
    }

    protected String getName() {
        return "TexCoordGen";
    }

    protected String[] getMenuItemNames() {
        return new String[] { "-", "Enable", "-", "On", "Off", "-", "GenMode", "-", "EYE_LINEAR", "OBJECT_LINEAR",
                "SPHERE_MAP", "-", "Format", "-", "TEXTURE_COORDINATE_2", "TEXTURE_COORDINATE_3", "-", "Plane R",
                "-", "R_1_0_0_0", "R_0_1_0_5", "R_0_0_1_0", "R_0_0_0_1", "-", "Plane S", "-", "S_1_0_0_0",
                "S_0_1_0_5", "S_0_0_1_0", "S_0_0_0_1", "-", "Plane T", "-", "T_1_0_0_0", "T_0_1_0_5", "T_0_0_1_0",
                "T_0_0_0_1", };
    }

    private TexCoordGeneration getTexCoordGeneration() {
        return (TexCoordGeneration) m_NodeComponent;
    }

    public void onOn() {
        getTexCoordGeneration().setEnable(true);
        assignToAppearance();
    }

    public void onOff() {
        getTexCoordGeneration().setEnable(false);
        assignToAppearance();
    }

    public void onEYE_LINEAR() {
        getTexCoordGeneration().setGenMode(TexCoordGeneration.EYE_LINEAR);
        assignToAppearance();
    }

    public void onOBJECT_LINEAR() {
        getTexCoordGeneration().setGenMode(TexCoordGeneration.OBJECT_LINEAR);
        assignToAppearance();
    }

    public void onSPHERE_MAP() {
        getTexCoordGeneration().setGenMode(TexCoordGeneration.SPHERE_MAP);
        assignToAppearance();
    }

    public void onTEXTURE_COORDINATE_2() {
        getTexCoordGeneration().setFormat(TexCoordGeneration.TEXTURE_COORDINATE_2);
        assignToAppearance();
    }

    public void onTEXTURE_COORDINATE_3() {
        getTexCoordGeneration().setFormat(TexCoordGeneration.TEXTURE_COORDINATE_3);
        assignToAppearance();
    }

    public void onR_1_0_0_0() {
        getTexCoordGeneration().setPlaneR(new Vector4f(m_PlaneFactor, 0, 0, 0));
        assignToAppearance();
    }

    public void onR_0_1_0_5() {
        getTexCoordGeneration().setPlaneR(new Vector4f(0, m_PlaneFactor, 0, 0.5f));
        assignToAppearance();
    }

    public void onR_0_0_1_0() {
        getTexCoordGeneration().setPlaneR(new Vector4f(0, 0, m_PlaneFactor, 0));
        assignToAppearance();
    }

    public void onR_0_0_0_1() {
        getTexCoordGeneration().setPlaneR(new Vector4f(0, 0, 0, m_PlaneFactor));
        assignToAppearance();
    }

    public void onS_1_0_0_0() {
        getTexCoordGeneration().setPlaneS(new Vector4f(m_PlaneFactor, 0, 0, 0));
        assignToAppearance();
    }

    public void onS_0_1_0_5() {
        getTexCoordGeneration().setPlaneS(new Vector4f(0, m_PlaneFactor, 0, 0.5f));
        assignToAppearance();
    }

    public void onS_0_0_1_0() {
        getTexCoordGeneration().setPlaneS(new Vector4f(0, 0, m_PlaneFactor, 0));
        assignToAppearance();
    }

    public void onS_0_0_0_1() {
        getTexCoordGeneration().setPlaneS(new Vector4f(0, 0, 0, m_PlaneFactor));
        assignToAppearance();
    }

    public void onT_1_0_0_0() {
        getTexCoordGeneration().setPlaneT(new Vector4f(m_PlaneFactor, 0, 0, 0));
        assignToAppearance();
    }

    public void onT_0_1_0_5() {
        getTexCoordGeneration().setPlaneT(new Vector4f(0, m_PlaneFactor, 0, 0.5f));
        assignToAppearance();
    }

    public void onT_0_0_1_0() {
        getTexCoordGeneration().setPlaneT(new Vector4f(0, 0, m_PlaneFactor, 0));
        assignToAppearance();
    }

    public void onT_0_0_0_1() {
        getTexCoordGeneration().setPlaneT(new Vector4f(0, 0, 0, m_PlaneFactor));
        assignToAppearance();
    }
}

class TextureAttributesComponent extends AppearanceComponent {
    public TextureAttributesComponent(Appearance app) {
        super(app);
    }

    protected int[] getCapabilities() {
        return new int[] { TextureAttributes.ALLOW_BLEND_COLOR_WRITE, TextureAttributes.ALLOW_MODE_WRITE,
                TextureAttributes.ALLOW_TRANSFORM_WRITE, };
    }

    protected NodeComponent createComponent() {
        return (NodeComponent) new TextureAttributes();
    }

    protected void setAppearanceCapability() {
        m_Appearance.setCapability(Appearance.ALLOW_TEXTURE_ATTRIBUTES_WRITE);
    }

    protected void assignToAppearance() {
        m_Appearance.setTextureAttributes((TextureAttributes) m_NodeComponent);
    }

    protected void assignNullToAppearance() {
        m_Appearance.setTextureAttributes(null);
    }

    protected String getName() {
        return "TextureAttributes";
    }

    protected String[] getMenuItemNames() {
        return new String[] { "-", "Mode", "-", "MODULATE", "DECAL", "BLEND", "REPLACE", "-", "Blend Color", "-",
                "T_White_Alpha_0point3", "T_Black_Alpha_0point7", "T_Blue_Alpha_1", "-", "Transform", "-",
                "0_degrees", "X_30_degrees", "Y_30_degrees", "Z_30_degrees", "-", "Perspective Correction", "-",
                "NICEST", "FASTEST" };
    }

    private TextureAttributes getTextureAttributes() {
        return (TextureAttributes) m_NodeComponent;
    }

    public void onMODULATE() {
        getTextureAttributes().setTextureMode(TextureAttributes.MODULATE);
    }

    public void onDECAL() {
        getTextureAttributes().setTextureMode(TextureAttributes.DECAL);
    }

    public void onBLEND() {
        getTextureAttributes().setTextureMode(TextureAttributes.BLEND);
    }

    public void onREPLACE() {
        getTextureAttributes().setTextureMode(TextureAttributes.REPLACE);
    }

    public void onT_White_Alpha_0point3() {
        getTextureAttributes().setTextureBlendColor(1, 1, 1, 0.3f);
    }

    public void onT_Black_Alpha_0point7() {
        getTextureAttributes().setTextureBlendColor(0, 0, 0, 0.7f);
    }

    public void onT_Blue_Alpha_1() {
        getTextureAttributes().setTextureBlendColor(0, 0, 1, 1);
    }

    public void on0_degrees() {
        Transform3D t3d = new Transform3D();
        getTextureAttributes().setTextureTransform(t3d);
    }

    public void onX_30_degrees() {
        Transform3D t3d = new Transform3D();
        t3d.rotX(Math.toRadians(30));
        getTextureAttributes().setTextureTransform(t3d);
    }

    public void onY_30_degrees() {
        Transform3D t3d = new Transform3D();
        t3d.rotY(Math.toRadians(30));
        getTextureAttributes().setTextureTransform(t3d);
    }

    public void onZ_30_degrees() {
        Transform3D t3d = new Transform3D();
        t3d.rotZ(Math.toRadians(30));
        getTextureAttributes().setTextureTransform(t3d);
    }

    public void onNICEST() {
        getTextureAttributes().setPerspectiveCorrectionMode(TextureAttributes.NICEST);
    }

    public void onFASTEST() {
        getTextureAttributes().setPerspectiveCorrectionMode(TextureAttributes.FASTEST);
    }
}

class TextureComponent extends AppearanceComponent {
    // hack, so we have an image observer when we load Textures
    public static Component m_Component = null;

    private Texture m_Texture = null;

    public TextureComponent(Appearance app) {
        super(app);
    }

    public static void setComponent(Component comp) {
        m_Component = comp;
    }

    protected int[] getCapabilities() {
        return new int[] { Texture.ALLOW_ENABLE_WRITE, };
    }

    protected NodeComponent createComponent() {
        TextureLoader texLoader = new TextureLoader("texture00.jpg", m_Component);
        ImageComponent2D image = texLoader.getImage();
        Texture2D tex2D = new Texture2D(Texture.MULTI_LEVEL_MIPMAP, Texture.RGBA, image.getWidth(),
                image.getHeight());

        for (int n = 0; n <= 6; n++) {
            texLoader = new TextureLoader("texture0" + n + ".jpg", m_Component);
            tex2D.setImage(n, texLoader.getImage());
        }

        return (NodeComponent) tex2D;
    }

    protected void setAppearanceCapability() {
        m_Appearance.setCapability(Appearance.ALLOW_TEXTURE_WRITE);
    }

    protected void assignToAppearance() {
        m_Texture = (Texture) new Texture2D();
        m_Texture = (Texture) m_NodeComponent.cloneNodeComponent(true);
        m_Appearance.setTexture(m_Texture);
    }

    protected void assignNullToAppearance() {
        m_Appearance.setTexture(null);
    }

    protected String getName() {
        return "Texture";
    }

    protected String[] getMenuItemNames() {
        return new String[] { "-", "Boundary Color", "-", "White", "Black", "BlueTransparent", "-",
                "Boundary Mode S", "-", "S_CLAMP", "S_WRAP", "-", "Boundary Mode T", "-", "T_CLAMP", "T_WRAP", "-",
                "Enable", "-", "On", "Off", "-", "Image", "-", "Texture0", "Texture1", "Texture2", "-", "MagFilter",
                "-", "Mag_FASTEST", "Mag_NICEST", "Mag_BASE_LEVEL_POINT", "Mag_BASE_LEVEL_LINEAR", "-", "MinFilter",
                "-", "Min_FASTEST", "Min_NICEST", "Min_BASE_LEVEL_POINT", "Min_BASE_LEVEL_LINEAR",
                "Min_MULTI_LEVEL_POINT", "Min_MULTI_LEVEL_LINEAR", "-", "MipMap Mode", "-", "BASE_LEVEL",
                "MULTI_LEVEL_MIPMAP", };
    }

    private Texture getTexture() {
        return (Texture) m_NodeComponent;
    }

    public void onWhite() {
        getTexture().setBoundaryColor(1, 1, 1, 0);
        assignToAppearance();
    }

    public void onBlack() {
        getTexture().setBoundaryColor(0, 0, 0, 0);
        assignToAppearance();
    }

    public void onBlueTransparent() {
        getTexture().setBoundaryColor(0, 0, 1, 0.5f);
        assignToAppearance();
    }

    public void onS_CLAMP() {
        getTexture().setBoundaryModeS(Texture.CLAMP);
        assignToAppearance();
    }

    public void onS_WRAP() {
        getTexture().setBoundaryModeS(Texture.WRAP);
        assignToAppearance();
    }

    public void onT_CLAMP() {
        getTexture().setBoundaryModeT(Texture.CLAMP);
        assignToAppearance();
    }

    public void onT_WRAP() {
        getTexture().setBoundaryModeT(Texture.WRAP);
        assignToAppearance();
    }

    public void onOn() {
        getTexture().setEnable(true);
        assignToAppearance();
    }

    public void onOff() {
        getTexture().setEnable(false);
        assignToAppearance();
    }

    public void onTexture0() {
        TextureLoader texLoader = null;

        for (int n = 0; n <= 6; n++) {
            texLoader = new TextureLoader("texture0" + n + ".jpg", m_Component);
            getTexture().setImage(n, texLoader.getImage());
        }

        assignToAppearance();
    }

    public void onTexture1() {
        TextureLoader texLoader = null;

        for (int n = 0; n <= 6; n++) {
            texLoader = new TextureLoader("texture1" + n + ".jpg", m_Component);
            getTexture().setImage(n, texLoader.getImage());
        }

        assignToAppearance();
    }

    public void onTexture2() {
        TextureLoader texLoader = null;

        for (int n = 0; n <= 6; n++) {
            texLoader = new TextureLoader("texture2" + n + ".gif", m_Component);
            getTexture().setImage(n, texLoader.getImage());
        }

        assignToAppearance();
    }

    public void onMag_FASTEST() {
        getTexture().setMagFilter(Texture.FASTEST);
        assignToAppearance();
    }

    public void onMag_NICEST() {
        getTexture().setMagFilter(Texture.NICEST);
        assignToAppearance();
    }

    public void onMag_BASE_LEVEL_POINT() {
        getTexture().setMagFilter(Texture.BASE_LEVEL_POINT);
        assignToAppearance();
    }

    public void onMag_BASE_LEVEL_LINEAR() {
        getTexture().setMagFilter(Texture.BASE_LEVEL_LINEAR);
        assignToAppearance();
    }

    public void onMin_FASTEST() {
        getTexture().setMinFilter(Texture.FASTEST);
        assignToAppearance();
    }

    public void onMin_NICEST() {
        getTexture().setMinFilter(Texture.NICEST);
        assignToAppearance();
    }

    public void onMin_BASE_LEVEL_POINT() {
        getTexture().setMinFilter(Texture.BASE_LEVEL_POINT);
        assignToAppearance();
    }

    public void onMin_BASE_LEVEL_LINEAR() {
        getTexture().setMinFilter(Texture.BASE_LEVEL_LINEAR);
        assignToAppearance();
    }

    public void onMin_MULTI_LEVEL_POINT() {
        getTexture().setMinFilter(Texture.MULTI_LEVEL_POINT);
        assignToAppearance();
    }

    public void onMin_MULTI_LEVEL_LINEAR() {
        getTexture().setMinFilter(Texture.MULTI_LEVEL_LINEAR);
        assignToAppearance();
    }

    public void onBASE_LEVEL() {
        getTexture().setMipMapMode(Texture.BASE_LEVEL);
        assignToAppearance();
    }

    public void onMULTI_LEVEL_MIPMAP() {
        getTexture().setMipMapMode(Texture.MULTI_LEVEL_MIPMAP);
        assignToAppearance();
    }
}

class TransparencyComponent extends AppearanceComponent {
    public TransparencyComponent(Appearance app) {
        super(app);
    }

    protected int[] getCapabilities() {
        return new int[] { TransparencyAttributes.ALLOW_MODE_WRITE, TransparencyAttributes.ALLOW_VALUE_WRITE };
    }

    protected NodeComponent createComponent() {
        return (NodeComponent) new TransparencyAttributes();
    }

    protected void setAppearanceCapability() {
        m_Appearance.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE);
    }

    protected void assignToAppearance() {
        m_Appearance.setTransparencyAttributes((TransparencyAttributes) m_NodeComponent);
    }

    protected void assignNullToAppearance() {
        m_Appearance.setTransparencyAttributes(null);
    }

    protected String getName() {
        return "Transparency";
    }

    protected String[] getMenuItemNames() {
        return new String[] { "-", "Transparency", "-", "0", "0point2", "0point5", "0point8", "1", "-", "Mode", "-",
                "NONE", "FASTEST", "NICEST", "SCREEN_DOOR", "BLENDED" };
    }

    private TransparencyAttributes getTransparencyAttributes() {
        return (TransparencyAttributes) m_NodeComponent;
    }

    public void on0() {
        getTransparencyAttributes().setTransparency(0);
    }

    public void on0point2() {
        getTransparencyAttributes().setTransparency(0.2f);
    }

    public void on0point5() {
        getTransparencyAttributes().setTransparency(0.5f);
    }

    public void on0point8() {
        getTransparencyAttributes().setTransparency(0.8f);
    }

    public void on1() {
        getTransparencyAttributes().setTransparency(1);
    }

    public void onNONE() {
        getTransparencyAttributes().setTransparencyMode(TransparencyAttributes.NONE);
    }

    public void onFASTEST() {
        getTransparencyAttributes().setTransparencyMode(TransparencyAttributes.FASTEST);
    }

    public void onNICEST() {
        getTransparencyAttributes().setTransparencyMode(TransparencyAttributes.NICEST);
    }

    public void onSCREEN_DOOR() {
        getTransparencyAttributes().setTransparencyMode(TransparencyAttributes.SCREEN_DOOR);
    }

    public void onBLENDED() {
        getTransparencyAttributes().setTransparencyMode(TransparencyAttributes.BLENDED);
    }
}

abstract class AppearanceComponent implements ActionListener {
    protected NodeComponent m_NodeComponent = null;

    protected Appearance m_Appearance = null;

    public AppearanceComponent(Appearance app) {
        m_Appearance = app;

        m_NodeComponent = createComponent();

        int[] capsArray = getCapabilities();

        if (capsArray != null) {
            for (int n = 0; n < capsArray.length; n++)
                m_NodeComponent.setCapability(capsArray[n]);
        }

        setAppearanceCapability();
        assignToAppearance();
    }

    abstract protected int[] getCapabilities();

    abstract protected void setAppearanceCapability();

    abstract protected NodeComponent createComponent();

    abstract protected void assignToAppearance();

    abstract protected void assignNullToAppearance();

    abstract protected String getName();

    abstract protected String[] getMenuItemNames();

    public Menu createMenu() {
        String szName = getName();
        String[] itemArray = getMenuItemNames();
        ActionListener listener = this;

        Menu menu = new Menu(szName);

        MenuItem menuItem = new MenuItem("Null");
        menuItem.addActionListener(listener);
        menu.add(menuItem);

        menuItem = new MenuItem("Non_Null");
        menuItem.addActionListener(listener);
        menu.add(menuItem);

        for (int n = 0; n < itemArray.length; n++) {
            menuItem = new MenuItem(itemArray[n]);
            menuItem.addActionListener(listener);
            menu.add(menuItem);
        }

        return menu;
    }

    public void onNull() {
        assignNullToAppearance();
    }

    public void onNon_Null() {
        assignToAppearance();
    }

    public void actionPerformed(ActionEvent event) {
        // (primitive) menu command dispatch
        Class classObject = getClass();

        Method[] methodArray = classObject.getMethods();

        for (int n = methodArray.length - 1; n >= 0; n--) {
            if (("on" + event.getActionCommand()).equals(methodArray[n].getName())) {
                try {
                    methodArray[n].invoke(this, null);
                } catch (InvocationTargetException ie) {
                    System.err.println("Warning. Menu handler threw exception: " + ie.getTargetException());
                } catch (Exception e) {
                    System.err.println("Warning. Menu dispatch exception: " + e);
                }

                return;
            }
        }
    }
}

class ColoringComponent extends AppearanceComponent {
    public ColoringComponent(Appearance app) {
        super(app);
    }

    protected int[] getCapabilities() {
        return new int[] { ColoringAttributes.ALLOW_COLOR_WRITE, ColoringAttributes.ALLOW_SHADE_MODEL_WRITE };
    }

    protected NodeComponent createComponent() {
        return (NodeComponent) new ColoringAttributes();
    }

    protected void setAppearanceCapability() {
        m_Appearance.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);
    }

    protected void assignToAppearance() {
        m_Appearance.setColoringAttributes((ColoringAttributes) m_NodeComponent);
    }

    protected void assignNullToAppearance() {
        m_Appearance.setColoringAttributes(null);
    }

    protected String getName() {
        return "Coloring";
    }

    protected String[] getMenuItemNames() {
        return new String[] { "-", "Color", "-", "Red", "Green", "Blue", "-", "Shade Model", "-", "Fastest",
                "Nicest", "Flat", "Gouraud" };
    }

    private ColoringAttributes getColoringAttributes() {
        return (ColoringAttributes) m_NodeComponent;
    }

    public void onRed() {
        getColoringAttributes().setColor(1, 0, 0);
    }

    public void onGreen() {
        getColoringAttributes().setColor(0, 1, 0);
    }

    public void onBlue() {
        getColoringAttributes().setColor(0, 0, 1);
    }

    public void onFastest() {
        getColoringAttributes().setShadeModel(ColoringAttributes.FASTEST);
    }

    public void onNicest() {
        getColoringAttributes().setShadeModel(ColoringAttributes.NICEST);
    }

    public void onFlat() {
        getColoringAttributes().setShadeModel(ColoringAttributes.SHADE_FLAT);
    }

    public void onGouraud() {
        getColoringAttributes().setShadeModel(ColoringAttributes.SHADE_GOURAUD);
    }
}

//File: hand1.obj

/*
    
    
# Mon Jun 02 17:09:33 1997
#
#
    
g hand1
v -0.551223 0.307562 -3.946050
v -0.215465 0.030475 -3.703516
v -0.059140 0.068255 -1.551531
v -0.487235 0.455792 -4.006029
v -0.168743 0.090975 -3.755638
v -0.338689 0.569450 -4.244848
v -0.639211 0.502297 -4.165243
v -0.760687 0.647871 -4.482797
v -0.529792 0.073768 -3.945949
v -0.707612 0.258064 -4.192451
v -0.866004 0.446161 -4.511733
v -0.367733 -0.147323 -4.191223
v -0.717413 0.071719 -4.433171
v -0.893823 0.253971 -4.589350
v -0.172976 -0.188212 -3.754734
v -0.089148 -0.103984 -1.450071
v -0.234491 -0.100206 -3.756646
v -0.131305 -0.032994 -1.531782
v -0.589492 0.641054 -4.376035
v -0.050594 -0.257375 -4.417058
v 0.208857 -0.205637 -4.768191
v 0.007882 -0.231806 -4.028160
v 0.230232 -0.186379 -4.335583
v 0.390435 -0.043258 -4.060836
v 0.002626 -0.129308 -1.430840
v -0.058465 -0.217994 -3.717670
v 0.087189 -0.100005 -1.425612
v 0.044163 -0.171797 -3.707954
v 0.044240 0.657156 -4.536777
v -0.137070 0.604272 -4.344090
v 0.041139 0.604901 -4.118776
v -0.080844 0.531805 -3.993031
v 0.165095 0.484110 -3.906230
v -0.081629 0.087632 -3.782753
v -0.013872 0.088823 -1.554481
v 0.008630 0.041677 -3.708195
v 0.070162 0.059225 -1.467241
v 0.349126 0.784380 -4.327246
v 0.192656 0.707311 -4.316467
v 0.240026 0.669896 -4.092967
v 0.614077 0.770599 -4.245997
v 0.448901 0.789330 -4.242595
v 0.390683 0.635870 -4.050064
v 0.823568 1.030378 -5.230011
v 0.583262 0.935220 -4.789198
v 0.936485 1.075914 -5.144932
v 0.708930 0.972489 -4.713959
v 1.079595 1.050653 -5.079602
v 0.863290 0.942616 -4.657226
v 0.731356 0.950572 -5.335061
v 0.698927 0.816156 -5.569689
v 0.452954 0.862935 -4.860037
v 0.354245 0.777679 -5.103039
v 0.109515 -0.020305 -1.439012
v 0.321579 0.190660 -3.847763
v 0.056950 -0.068344 -3.678991
v 0.551677 0.397382 -4.027330
v 0.748943 0.261978 -4.201552
v 0.797463 0.611225 -4.241810
v 0.934536 0.472987 -4.298673
v 0.919641 0.370477 -5.597496
v 1.079582 0.375487 -5.341094
v 1.225601 0.456396 -5.207421
v 0.593068 0.043314 -5.202118
v 0.711852 0.101000 -4.865152
v 0.871615 0.211454 -4.690717
v 1.063296 0.399320 -4.647913
v 1.342637 0.585582 -5.122607
v 1.150690 0.608137 -4.641154
v 1.366648 0.748651 -5.071675
v 0.745367 0.246406 -5.988852
v 0.494019 -0.022198 -5.740361
v 0.141480 -0.193021 -5.470416
v 0.693354 0.148862 -6.455598
v 0.458179 -0.058425 -6.342125
v 0.092861 -0.121753 -6.334044
v 0.001903 0.615014 -5.359071
v 0.310613 0.694999 -5.659912
v 0.602326 0.700149 -5.960638
v 0.014377 0.478587 -6.304075
v 0.335968 0.619833 -6.312831
v 0.600780 0.612337 -6.446789
v -0.303419 0.594566 -6.098518
v -0.599974 0.655996 -6.132385
v -0.241202 0.626083 -5.200386
v -0.457099 0.677790 -5.161324
v -0.259616 -0.163854 -6.116562
v -0.183392 -0.223625 -5.241480
v -0.635209 0.061396 -6.121774
v -0.504788 -0.103060 -5.122423
v -0.950019 0.234128 -5.837874
v -0.810067 0.092804 -5.080121
v -1.144829 0.478824 -5.746136
v -0.998398 0.334709 -5.084644
v -0.994164 0.856674 -5.773610
v -0.863354 0.756330 -5.102725
v -0.801998 0.842826 -5.870856
v -0.671650 0.764754 -5.123487
v 1.045049 0.802118 -4.632644
v 1.252493 0.924338 -5.055513
v -0.995449 0.583125 -5.083862
v -1.137996 0.713069 -5.735577
v 1.598002 0.816988 -5.564189
v 1.599381 0.700758 -5.624741
v 1.532017 0.614642 -5.716787
v 1.715526 0.933794 -5.717422
v 1.699604 0.816034 -5.787023
v 1.629737 0.731598 -5.898082
v 1.883043 1.059492 -5.899169
v 1.855109 0.932664 -5.998640
v 1.774384 0.842472 -6.140775
v 1.424351 0.559021 -5.523375
v 1.505227 0.658051 -5.434678
v 1.502338 0.787710 -5.373565
v 1.297397 0.577850 -5.903827
v 1.425129 0.560695 -5.822476
v 1.155962 0.509306 -5.718982
v 1.300644 0.494656 -5.623770
v 1.509245 0.835318 -6.384689
v 1.646807 0.801147 -6.286009
v 1.406474 0.713747 -6.133959
v 1.525574 0.687385 -6.031679
v 1.380351 1.065119 -5.565239
v 1.564172 1.172023 -5.714888
v 1.780605 1.304970 -5.893034
v 1.255719 1.087198 -5.619839
v 1.438416 1.182678 -5.766468
v 1.652418 1.312790 -5.952035
v 1.154437 1.043031 -5.702960
v 1.320461 1.134701 -5.855917
v 1.512782 1.262635 -6.051604
v 1.003945 1.036752 -5.521133
v 1.104476 1.081637 -5.435655
v 1.236055 1.056913 -5.374795
v 1.089111 0.843044 -5.888583
v 1.089661 0.962064 -5.803318
v 1.230625 0.966122 -6.097103
v 1.242952 1.066407 -5.981094
v 1.362597 1.098246 -6.323909
v 1.405432 1.196541 -6.191591
v 0.929064 0.824679 -5.709339
v 0.934340 0.953520 -5.615597
v 1.859089 1.203879 -5.868989
v 1.664971 1.072200 -5.695913
v 1.510868 0.957577 -5.544997
v 1.391678 0.940769 -5.352942
v 1.170557 0.692380 -5.926214
v 1.027666 0.653090 -5.757548
v 0.869972 0.619560 -5.748698
v 1.295478 0.827279 -6.155195
v 1.403801 0.956111 -6.395917
v 1.981874 0.878914 -6.465936
v 1.802272 0.826665 -6.577847
v 1.615752 0.851027 -6.620514
v 2.128560 0.944598 -6.721747
v 1.907593 0.869058 -6.790360
v 1.708489 0.849226 -6.769275
v 2.238363 1.116521 -6.349912
v 2.094190 1.105140 -6.141595
v 2.237261 1.035889 -6.535950
v 2.075505 0.976585 -6.291769
v 1.727506 1.346013 -6.328338
v 1.936762 1.311864 -6.600124
v 1.576315 1.256378 -6.447272
v 1.741231 1.205721 -6.680005
v 1.483882 1.132384 -6.546886
v 1.595348 1.106596 -6.700094
v 2.143625 1.363027 -6.343407
v 2.083770 1.364678 -6.472173
v 1.997907 1.370713 -6.136065
v 1.880283 1.392692 -6.219747
v 2.220069 1.245977 -6.358671
v 2.223785 1.204368 -6.587201
v 2.097329 1.131385 -6.757537
v 1.644286 0.966614 -6.763514
v 1.867680 1.032451 -6.812611
v 0.883363 0.124343 -7.228944
v 0.646839 -0.024425 -7.259110
v 0.390212 -0.005959 -7.292361
v 1.070393 0.135169 -7.703971
v 0.802047 0.006235 -7.763816
v 0.511476 0.026061 -7.813804
v 1.163011 0.161832 -8.064369
v 0.918797 0.093289 -8.161346
v 0.636154 0.076768 -8.160398
v 0.269275 -0.049054 -6.787587
v 0.524823 -0.050661 -6.806285
v 0.744409 0.117607 -6.839493
v 0.827585 0.571806 -7.238711
v 1.016438 0.562215 -7.711038
v 1.115469 0.520019 -8.067395
v 0.573132 0.588769 -7.270417
v 0.731449 0.578986 -7.772986
v 0.865027 0.502425 -8.164807
v 0.338782 0.438496 -7.299040
v 0.460865 0.446711 -7.820236
v 0.590458 0.430524 -8.163703
v 0.208617 0.434283 -6.784674
v 0.437333 0.591011 -6.807528
v 0.678646 0.577267 -6.844694
v 0.947532 0.372788 -7.222228
v 0.797216 0.376391 -6.856188
v 0.734974 0.417910 -6.504792
v 1.142651 0.368565 -7.694477
v 1.195867 0.347815 -8.107895
v 0.272439 0.191555 -7.307303
v 0.163854 0.163934 -6.807784
v 0.050485 0.143298 -6.551455
v 0.390845 0.216656 -7.842326
v 0.587957 0.247899 -8.218260
v -0.187159 -0.021301 -8.489817
v -0.144520 -0.066015 -8.115219
v -0.135056 -0.086523 -7.519433
v -0.455856 -0.036286 -8.505733
v -0.424768 -0.127085 -8.081474
v -0.379623 -0.149656 -7.480232
v -0.721089 0.002465 -8.418228
v -0.711949 -0.032964 -8.033904
v -0.633023 -0.036474 -7.439595
v -0.083764 -0.101907 -6.888419
v -0.321252 -0.155635 -6.827525
v -0.570598 -0.013135 -6.792706
v -0.205536 0.346922 -8.488331
v -0.478068 0.389386 -8.503635
v -0.741261 0.375015 -8.416031
v -0.166164 0.372104 -8.112885
v -0.454556 0.470532 -8.077909
v -0.734413 0.413380 -8.030973
v -0.161420 0.377122 -7.515023
v -0.412007 0.496828 -7.474960
v -0.653762 0.440220 -7.436335
v -0.124968 0.400042 -6.878002
v -0.359615 0.536135 -6.818819
v -0.582637 0.502600 -6.791322
v -0.736234 0.212481 -7.423101
v -0.655151 0.259193 -6.812274
v -0.663333 0.364684 -6.389957
v -0.775997 0.191334 -8.463245
v -0.822719 0.196893 -8.024588
v -0.031942 0.130966 -6.924860
v -0.055396 0.134692 -7.532089
v -0.056604 0.146553 -8.134798
v -0.157928 0.161766 -8.546125
v -1.836226 1.016590 -7.410828
v -1.627684 0.872918 -7.538481
v -1.370280 0.758218 -7.595252
v -1.747767 0.932613 -7.142950
v -1.528535 0.732919 -7.246038
v -1.256016 0.658972 -7.340291
v -1.538345 0.794709 -6.746178
v -1.346968 0.594312 -6.836720
v -1.106538 0.540492 -6.926594
v -1.327304 0.638226 -6.296957
v -1.144801 0.423090 -6.386161
v -0.907648 0.349198 -6.500935
v -1.381548 1.162123 -6.749738
v -1.167106 1.131764 -6.834267
v -1.001718 0.954827 -6.919466
v -1.579033 1.276060 -7.151250
v -1.336962 1.223187 -7.246882
v -1.140912 1.040889 -7.333368
v -1.682336 1.295016 -7.423892
v -1.479018 1.212733 -7.544489
v -1.266431 1.072053 -7.592119
v -1.173291 1.003628 -6.309747
v -0.980917 0.984092 -6.395974
v -0.826961 0.810684 -6.501183
v -0.978037 0.704393 -6.955856
v -1.119137 0.806439 -7.374477
v -1.298471 0.903687 -7.643332
v -0.811802 0.542748 -6.562383
v -1.320080 0.864534 -6.271852
v -1.536038 1.021683 -6.715133
v -1.746360 1.149667 -7.118443
v -1.808232 1.181964 -7.439637
v 2.071132 1.255908 -6.105393
v 1.505985 0.975476 -6.611821
v 0.931009 0.299286 -8.285854
v -0.474965 0.178488 -8.633644
v -1.589683 1.061216 -7.631387
v 0.763920 0.520049 -6.078023
# 281 vertices
    
# 0 texture vertices
    
# 0 normals
    
usemtl hand
f 2 4 1
f 5 4 2
f 3 5 2
f 5 6 4
f 1 10 9
f 1 7 10
f 7 11 10
f 7 8 11
f 10 12 9
f 12 10 13
f 10 14 13
f 10 11 14
f 12 17 9
f 12 15 17
f 18 15 16
f 15 18 17
f 9 2 1
f 9 17 2
f 18 2 17
f 2 18 3
f 19 4 6
f 7 4 19
f 8 7 19
f 7 1 4
f 20 22 12
f 23 22 20
f 21 23 20
f 23 24 22
f 16 26 25
f 16 15 26
f 15 22 26
f 15 12 22
f 25 28 27
f 25 26 28
f 22 28 26
f 28 22 24
f 30 31 29
f 32 31 30
f 6 32 30
f 32 33 31
f 5 32 6
f 32 5 34
f 5 35 34
f 5 3 35
f 34 33 32
f 33 34 36
f 35 36 34
f 36 35 37
f 39 40 38
f 31 40 39
f 29 31 39
f 31 33 40
f 42 43 41
f 40 43 42
f 38 40 42
f 40 33 43
f 45 46 44
f 46 45 47
f 38 47 45
f 47 38 42
f 46 49 48
f 46 47 49
f 47 41 49
f 47 42 41
f 44 52 45
f 44 50 52
f 50 53 52
f 50 51 53
f 52 38 45
f 38 52 39
f 52 29 39
f 52 53 29
f 36 55 33
f 55 36 56
f 37 56 36
f 56 37 54
f 56 24 55
f 24 56 28
f 27 56 54
f 56 27 28
f 33 57 43
f 33 55 57
f 55 58 57
f 55 24 58
f 57 41 43
f 41 57 59
f 58 59 57
f 59 58 60
f 62 64 61
f 64 62 65
f 63 65 62
f 65 63 66
f 65 21 64
f 21 65 23
f 66 23 65
f 23 66 24
f 66 58 24
f 58 66 67
f 63 67 66
f 67 63 68
f 67 60 58
f 60 67 69
f 68 69 67
f 69 68 70
f 61 72 71
f 61 64 72
f 64 73 72
f 64 21 73
f 71 75 74
f 71 72 75
f 72 76 75
f 72 73 76
f 53 77 29
f 77 53 78
f 51 78 53
f 78 51 79
f 78 80 77
f 80 78 81
f 79 81 78
f 81 79 82
f 83 77 80
f 77 83 85
f 83 86 85
f 83 84 86
f 85 29 77
f 29 85 30
f 86 30 85
f 30 86 6
f 73 87 76
f 87 73 88
f 21 88 73
f 88 21 20
f 88 89 87
f 89 88 90
f 20 90 88
f 90 20 12
f 90 91 89
f 91 90 92
f 90 13 92
f 90 12 13
f 91 94 93
f 91 92 94
f 92 14 94
f 92 13 14
f 95 98 97
f 95 96 98
f 8 98 96
f 98 8 19
f 97 86 84
f 97 98 86
f 19 86 98
f 86 19 6
f 59 49 41
f 49 59 99
f 59 69 99
f 59 60 69
f 99 48 49
f 48 99 100
f 99 70 100
f 99 69 70
f 8 101 11
f 8 96 101
f 96 102 101
f 96 95 102
f 101 14 11
f 14 101 94
f 101 93 94
f 101 102 93
f 103 107 106
f 103 104 107
f 105 107 104
f 107 105 108
f 107 109 106
f 109 107 110
f 108 110 107
f 110 108 111
f 63 113 68
f 63 112 113
f 112 104 113
f 112 105 104
f 68 114 70
f 68 113 114
f 113 103 114
f 113 104 103
f 115 118 117
f 115 116 118
f 105 118 116
f 118 105 112
f 117 62 61
f 117 118 62
f 112 62 118
f 62 112 63
f 120 121 119
f 121 120 122
f 111 122 120
f 122 111 108
f 122 115 121
f 115 122 116
f 108 116 122
f 116 108 105
f 123 127 126
f 123 124 127
f 124 128 127
f 124 125 128
f 126 130 129
f 126 127 130
f 127 131 130
f 127 128 131
f 44 133 132
f 44 46 133
f 48 133 46
f 133 48 134
f 132 126 129
f 132 133 126
f 134 126 133
f 126 134 123
f 135 138 137
f 135 136 138
f 136 130 138
f 136 129 130
f 137 140 139
f 137 138 140
f 138 131 140
f 138 130 131
f 51 142 141
f 51 50 142
f 50 132 142
f 50 44 132
f 141 136 135
f 141 142 136
f 142 129 136
f 142 132 129
f 109 144 106
f 109 143 144
f 125 144 143
f 144 125 124
f 106 145 103
f 106 144 145
f 124 145 144
f 145 124 123
f 100 134 48
f 134 100 146
f 70 146 100
f 146 70 114
f 146 123 134
f 123 146 145
f 114 145 146
f 145 114 103
f 135 148 141
f 135 147 148
f 147 117 148
f 147 115 117
f 141 149 51
f 141 148 149
f 148 61 149
f 148 117 61
f 115 150 121
f 115 147 150
f 135 150 147
f 150 135 137
f 121 151 119
f 121 150 151
f 137 151 150
f 151 137 139
f 120 152 111
f 152 120 153
f 119 153 120
f 153 119 154
f 152 156 155
f 152 153 156
f 153 157 156
f 153 154 157
f 158 161 160
f 158 159 161
f 159 110 161
f 159 109 110
f 160 152 155
f 160 161 152
f 161 111 152
f 161 110 111
f 162 140 131
f 140 162 164
f 162 165 164
f 162 163 165
f 164 139 140
f 139 164 166
f 164 167 166
f 164 165 167
f 168 171 170
f 168 169 171
f 163 171 169
f 171 163 162
f 171 125 170
f 125 171 128
f 162 128 171
f 128 162 131
f 172 169 168
f 169 172 173
f 158 173 172
f 173 158 160
f 169 174 163
f 169 173 174
f 160 174 173
f 174 160 155
f 157 176 156
f 157 175 176
f 167 176 175
f 176 167 165
f 176 155 156
f 155 176 174
f 176 163 174
f 176 165 163
f 177 181 180
f 177 178 181
f 178 182 181
f 178 179 182
f 181 183 180
f 183 181 184
f 181 185 184
f 181 182 185
f 186 75 76
f 75 186 187
f 179 187 186
f 187 179 178
f 187 74 75
f 74 187 188
f 178 188 187
f 188 178 177
f 189 193 192
f 189 190 193
f 191 193 190
f 193 191 194
f 192 196 195
f 192 193 196
f 193 197 196
f 193 194 197
f 81 198 80
f 198 81 199
f 82 199 81
f 199 82 200
f 199 195 198
f 195 199 192
f 200 192 199
f 192 200 189
f 200 201 189
f 201 200 202
f 200 203 202
f 200 82 203
f 202 177 201
f 177 202 188
f 202 74 188
f 202 203 74
f 177 204 201
f 177 180 204
f 183 204 180
f 204 183 205
f 204 189 201
f 189 204 190
f 204 191 190
f 204 205 191
f 195 207 198
f 195 206 207
f 179 207 206
f 207 179 186
f 198 208 80
f 198 207 208
f 186 208 207
f 208 186 76
f 206 182 179
f 182 206 209
f 206 196 209
f 206 195 196
f 209 185 182
f 185 209 210
f 209 197 210
f 209 196 197
f 211 215 214
f 211 212 215
f 213 215 212
f 215 213 216
f 215 217 214
f 217 215 218
f 216 218 215
f 218 216 219
f 220 216 213
f 216 220 221
f 76 221 220
f 221 76 87
f 221 219 216
f 219 221 222
f 87 222 221
f 222 87 89
f 223 227 226
f 223 224 227
f 225 227 224
f 227 225 228
f 227 229 226
f 229 227 230
f 228 230 227
f 230 228 231
f 230 232 229
f 232 230 233
f 231 233 230
f 233 231 234
f 233 80 232
f 80 233 83
f 233 84 83
f 233 234 84
f 222 235 219
f 235 222 236
f 222 237 236
f 222 89 237
f 236 231 235
f 231 236 234
f 237 234 236
f 234 237 84
f 217 239 238
f 217 218 239
f 219 239 218
f 239 219 235
f 239 225 238
f 225 239 228
f 239 231 228
f 239 235 231
f 220 208 76
f 208 220 240
f 213 240 220
f 240 213 241
f 208 232 80
f 208 240 232
f 240 229 232
f 240 241 229
f 241 226 229
f 226 241 242
f 241 212 242
f 241 213 212
f 242 223 226
f 223 242 243
f 242 211 243
f 242 212 211
f 244 248 247
f 244 245 248
f 246 248 245
f 248 246 249
f 248 250 247
f 250 248 251
f 249 251 248
f 251 249 252
f 250 254 253
f 250 251 254
f 252 254 251
f 254 252 255
f 253 91 93
f 253 254 91
f 254 89 91
f 254 255 89
f 256 260 259
f 256 257 260
f 258 260 257
f 260 258 261
f 260 262 259
f 262 260 263
f 260 264 263
f 260 261 264
f 97 265 95
f 265 97 266
f 84 266 97
f 266 84 267
f 265 257 256
f 265 266 257
f 267 257 266
f 257 267 258
f 249 268 252
f 268 249 269
f 249 270 269
f 249 246 270
f 269 258 268
f 258 269 261
f 269 264 261
f 269 270 264
f 255 237 89
f 237 255 271
f 252 271 255
f 271 252 268
f 271 84 237
f 84 271 267
f 268 267 271
f 267 268 258
f 102 253 93
f 253 102 272
f 102 265 272
f 102 95 265
f 272 250 253
f 250 272 273
f 272 256 273
f 272 265 256
f 259 273 256
f 273 259 274
f 262 274 259
f 274 262 275
f 273 247 250
f 273 274 247
f 274 244 247
f 274 275 244
f 172 159 158
f 159 172 276
f 172 170 276
f 172 168 170
f 276 109 159
f 109 276 143
f 170 143 276
f 143 170 125
f 151 154 119
f 154 151 277
f 151 166 277
f 151 139 166
f 154 175 157
f 154 277 175
f 277 167 175
f 277 166 167
f 197 278 210
f 197 194 278
f 191 278 194
f 278 191 205
f 278 185 210
f 185 278 184
f 278 183 184
f 278 205 183
f 223 279 224
f 223 243 279
f 211 279 243
f 279 211 214
f 279 225 224
f 225 279 238
f 279 217 238
f 279 214 217
f 262 280 275
f 262 263 280
f 264 280 263
f 280 264 270
f 280 244 275
f 244 280 245
f 270 245 280
f 245 270 246
f 74 281 71
f 74 203 281
f 82 281 203
f 281 82 79
f 71 149 61
f 71 281 149
f 79 149 281
f 149 79 51
# 552 elements
    
    
*/