AlienModel.java

/*
 * Copyright © 2012 Nokia Corporation. All rights reserved.
 * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation.
 * Oracle and Java are trademarks or registered trademarks of Oracle and/or its
 * affiliates. Other product and company names mentioned herein may be trademarks
 * or trade names of their respective owners.
 * See LICENSE.TXT for license information.
 */

package com.nokia.example.spacemission;

import javax.microedition.m3g.*;

public class AlienModel {

    static {
        Image2D enemyIm = loadImage2D("/game/alien.png");
        Image2D frozenEnemyIm = loadImage2D("/game/alien_frozen.png");
        vb = makeGeometry();
        ib = new TriangleStripArray(0, getStripLengths());
        app = makeAppearance(enemyIm);
        frozenApp = makeFrozenAppearance(frozenEnemyIm);
    }
    private static VertexBuffer vb;
    private static IndexBuffer ib;
    private Group transGroup;
    private static Appearance app;
    private static Appearance frozenApp;
    private Mesh model;

    public AlienModel(float xCoord, float zCoord) {
        model = new Mesh(vb, ib, app);
        model.setTranslation(xCoord + 0.25f, 0.25f, zCoord + 0.25f);
        model.scale(0.5f, 0.5f, 0.5f);
        model.setPickingEnable(true); // so can fire a pick ray at it
        // translation group for the model
        transGroup = new Group();
        transGroup.addChild(model);
        transGroup.addAnimationTrack(setUpAnimation());
    }

    public Group getModelGroup() {
        return transGroup;
    }

    private KeyframeSequence translateFrames() {
        KeyframeSequence ks = new KeyframeSequence(8, 3,
                                                   KeyframeSequence.SPLINE);

        // move clockwise in a circle;
        // each frame is separated by 10 sequence time units
        ks.setKeyframe(0, 0, new float[]{-0.5f, 0.0f, 0.0f});
        ks.setKeyframe(1, 10, new float[]{-0.3536f, 0.0f, 0.3536f});
        ks.setKeyframe(2, 20, new float[]{0.0f, 0.0f, 0.5f});
        ks.setKeyframe(3, 30, new float[]{0.3536f, 0.0f, 0.3536f});
        ks.setKeyframe(4, 40, new float[]{0.5f, 0.0f, 0.0f});
        ks.setKeyframe(5, 50, new float[]{0.3536f, 0.0f, -0.3536f});
        ks.setKeyframe(6, 60, new float[]{0.0f, 0.0f, -0.5f});
        ks.setKeyframe(7, 70, new float[]{-0.3536f, 0.0f, -0.3536f});

        ks.setDuration(80); // one cycle takes 80 sequence time units
        ks.setValidRange(0, 7);
        ks.setRepeatMode(KeyframeSequence.LOOP);
        return ks;
    }

    private AnimationTrack setUpAnimation() {
        // creation animation controller
        AnimationController animController = new AnimationController();
        animController.setActiveInterval(0, 0);

        // creation translation animation track
        KeyframeSequence transKS = translateFrames();
        AnimationTrack transTrack = new AnimationTrack(transKS,
                                                       AnimationTrack.TRANSLATION);
        transTrack.setController(animController);

        return transTrack;
    }

    public Mesh getModel() {
        return model;
    }

    public static Appearance getFrozenAppearance() {
        return frozenApp;
    }

// ------------------- model creation -----------------------------
    private static VertexBuffer makeGeometry() {
        //         create vertices
        short[] verts = getVerts();
        VertexArray va = new VertexArray(verts.length / 3, 3, 2);
        va.set(0, verts.length / 3, verts);

        // create normals
        byte[] norms = getNormals();
        VertexArray normArray = new VertexArray(norms.length / 3, 3, 1);
        normArray.set(0, norms.length / 3, norms);

        // create texture coordinates
        short[] tcs = getTexCoordsRev();
        VertexArray texArray = new VertexArray(tcs.length / 2, 2, 2);
        texArray.set(0, tcs.length / 2, tcs);

        float[] pbias = {(1.0f / 255.0f), (1.0f / 255.0f), (1.0f / 255.0f)};

        VertexBuffer vertexB = new VertexBuffer();
        vertexB.setPositions(va, (2.0f / 255.0f), pbias); // scale, bias
        vertexB.setNormals(normArray);
        vertexB.setTexCoords(0, texArray, (1.0f / 255.0f), null);

        return vertexB;

    } // end of makeGeometry()

    private static short[] getTexCoordsRev() {
        short[] tcs = getTexCoords();
        // t' = 255 - t (will later be scaled from 255 to 1)
        for (int i = 1; i < tcs.length; i = i + 2) {
            tcs[i] = (short) (255 - tcs[i]);
        }

        return tcs;
    } // end of getTexCoordsRev()

    private static Appearance makeAppearance(Image2D image2D) // the appearance is a mix of material and texture
    {
        Appearance appereance = new Appearance();
        appereance.setMaterial(setMatColours());

        if (image2D != null) {
            // create the Texture2D and enable mipmapping
            Texture2D tex = new Texture2D(image2D);
            tex.setFiltering(Texture2D.FILTER_NEAREST,
                             Texture2D.FILTER_NEAREST);
            tex.setWrapping(Texture2D.WRAP_CLAMP, Texture2D.WRAP_CLAMP);
            tex.setBlending(Texture2D.FUNC_MODULATE); // mix material and
            // texture
            appereance.setTexture(0, tex);
        }
        return appereance;
    } // end of makeAppearance()

    private static Appearance makeFrozenAppearance(Image2D image2D) // the appearance is a texture
    {
        Appearance frozenAppereance = new Appearance();

        if (image2D != null) {
            // create the Texture2D and enable mipmapping
            Texture2D tex = new Texture2D(image2D);
            tex.setFiltering(Texture2D.FILTER_NEAREST,
                             Texture2D.FILTER_NEAREST);
            tex.setWrapping(Texture2D.WRAP_CLAMP, Texture2D.WRAP_CLAMP);
            tex.setBlending(Texture2D.FUNC_MODULATE); // mix material and
            // texture
            frozenAppereance.setTexture(0, tex);
        }
        return frozenAppereance;
    } // end of makeFrozenAppearance()

// ------------------ model data ------------------------
    private static short[] getVerts() // return an array holding Verts [870 values / 3 = 290 points]
    {
        short[] vals = {-72, -38, -84, -72, -24, -85, -71, 3, -79, -79, 6,
            -85, -71, 3, -79, -54, -1, -78, -74, -6, -78, -54, -1, -78,
            -69, 2, -72, -30, -42, -87, -69, 2, -72, -70, 10, -65, -58,
            -25, -67, -70, 10, -65, -62, -54, -76, -67, -17, -78, -62, -54,
            -76, -72, -16, -77, -72, -32, -86, -72, -16, -77, -89, -49,
            -76, -70, 8, -68, -89, -49, -76, -82, 6, -68, -77, 4, -64, -82,
            6, -68, -79, 5, -72, -115, -38, -86, -79, 5, -72, -108, -37,
            -95, -74, 12, -78, -108, -37, -95, -71, 2, -79, -108, -37, -95,
            -74, 6, -85, -108, -37, -95, -101, -2, -75, -111, -8, -86,
            -101, -2, -75, -84, 21, -76, -84, 21, -75, -84, 21, -76, -87,
            54, -94, -84, 21, -76, -107, 53, -67, -84, 21, -76, -128, 56,
            -64, -85, 22, -74, -128, 56, -64, -81, 15, -69, -121, 81, -39,
            -81, 15, -69, -110, 110, -26, -68, 30, -45, -110, 110, -26,
            -71, 37, -19, -80, 95, -5, -71, 37, -19, -28, 84, -11, -37, 37,
            -33, -28, 84, -11, -61, 22, -70, -29, 95, -20, -61, 22, -70,
            -35, 96, -79, -56, 19, -74, -35, 96, -79, -57, 19, -76, -27,
            51, -85, -57, 19, -76, -27, 53, -95, -57, 19, -76, -49, 22,
            -76, -57, 19, -76, -70, 15, -77, -57, 19, -76, -28, -26, -72,
            -57, 19, -76, -28, -27, -67, -56, 19, -74, -28, -27, -67, -61,
            22, -70, -70, 19, -71, -61, 22, -70, -67, 15, -68, -37, 37,
            -33, -67, 15, -68, -71, 37, -19, -72, 16, -69, -71, 37, -19,
            -78, 14, -74, -68, 30, -45, -78, 14, -74, -81, 15, -69, -71,
            18, -71, -81, 15, -69, -118, -22, -72, -85, 22, -74, -118, -22,
            -72, -84, 21, -76, -118, -22, -72, -111, -8, -86, -118, -22,
            -72, -108, -37, -95, -118, -22, -72, -115, -38, -86, -118, -22,
            -72, -82, 6, -68, -71, 18, -71, -82, 6, -68, -78, 14, -74, -70,
            8, -68, -78, 14, -74, -72, -16, -77, -72, 16, -69, -72, -16,
            -77, -67, 15, -68, -67, -17, -78, -67, 15, -68, -70, 10, -65,
            -70, 19, -71, -70, 10, -65, -28, -27, -67, -30, -42, -87, -28,
            -27, -67, -54, -1, -78, -28, -26, -72, -54, -1, -78, -70, 15,
            -77, -79, 6, -85, -70, 15, -77, -72, -24, -85, -70, 15, -77,
            -71, -1, -82, -70, 15, -77, -72, 20, -79, -49, 22, -76, -72,
            20, -79, -27, 53, -95, -72, 58, -95, -27, 53, -95, -71, 100,
            -87, -27, 53, -95, -57, 100, -92, -27, 53, -95, -33, 97, -93,
            -27, 51, -85, -33, 97, -93, -35, 96, -79, -30, 108, -92, -35,
            96, -79, -50, 123, -57, -29, 95, -20, -50, 123, -57, -28, 84,
            -11, -55, 124, -41, -28, 84, -11, -72, 123, -34, -80, 95, -5,
            -72, 123, -34, -110, 110, -26, -110, 125, -44, -110, 110, -26,
            -100, 127, -54, -121, 81, -39, -100, 127, -54, -128, 56, -64,
            -99, 117, -74, -128, 56, -64, -111, 115, -74, -107, 53, -67,
            -111, 115, -74, -87, 54, -94, -80, 106, -85, -87, 54, -94, -71,
            106, -87, -87, 54, -94, -72, 58, -99, -87, 54, -94, -72, 19,
            -77, -84, 21, -75, -72, 19, -77, -101, -2, -75, -71, -3, -86,
            -101, -2, -75, -72, -24, -85, -74, 6, -85, -72, -24, -85, -71,
            2, -79, -72, -38, -84, -71, 2, -79, -72, -34, -84, -71, 2, -79,
            -89, -70, -103, -71, 2, -79, -101, -70, -90, -74, 12, -78,
            -101, -70, -90, -79, 5, -72, -109, -70, -72, -79, 5, -72, -116,
            -69, -67, -77, 4, -64, -116, -69, -67, -89, -49, -76, -110,
            -69, -61, -89, -49, -76, -102, -69, -59, -89, -49, -76, -85,
            -70, -71, -89, -49, -76, -72, -32, -86, -72, -32, -86, -72,
            -32, -86, -62, -54, -76, -52, -68, -58, -62, -54, -76, -39,
            -69, -58, -62, -54, -76, -30, -71, -53, -62, -54, -76, -27,
            -71, -60, -58, -25, -67, -27, -71, -60, -69, 2, -72, -33, -71,
            -86, -69, 2, -72, -42, -70, -90, -74, -6, -78, -42, -70, -90,
            -71, 3, -79, -55, -70, -103, -71, 3, -79, -72, -34, -84, -72,
            -38, -84, -71, 100, -87, -80, 106, -85, -71, 125, -74, -111,
            115, -74, -71, 125, -74, -111, 115, -74, -71, 125, -74, -109,
            125, -44, -71, 125, -74, -83, 125, -35, -71, 125, -74, -70,
            121, -34, -71, 125, -74, -54, 125, -37, -71, 125, -74, -50,
            123, -57, -71, 125, -74, -36, 94, -84, -71, 125, -74, -34, 94,
            -92, -71, 125, -74, -57, 101, -92, -71, 100, -87, -72, -70,
            -108, -55, -70, -103, -72, -70, -72, -42, -70, -90, -72, -70,
            -72, -33, -70, -72, -72, -70, -72, -27, -70, -46, -72, -70,
            -72, -30, -70, -39, -72, -70, -72, -39, -70, -35, -72, -70,
            -72, -56, -70, -36, -72, -70, -72, -72, -70, -37, -72, -70,
            -72, -86, -70, -36, -72, -70, -72, -102, -70, -38, -72, -70,
            -72, -110, -70, -40, -72, -70, -72, -116, -70, -45, -72, -70,
            -72, -109, -70, -72, -72, -70, -72, -101, -70, -90, -72, -70,
            -72, -89, -70, -103, -72, -70, -72, -72, -70, -108};
        return vals;
    } // end of getVerts()

    private static byte[] getNormals() // return an array holding Normals [870 values / 3 = 290 points]
    {
        byte[] vals = {64, -14, 110, 124, 2, -33, 66, -33, -105, 14, -63,
            -111, 66, -33, -105, 30, -36, -119, 116, -52, -16, 30, -36,
            -119, 117, 28, -43, -81, -94, -31, 117, 28, -43, -98, -59, 58,
            4, 9, 127, -98, -59, 58, -38, 46, 113, -94, -11, 86, -38, 46,
            113, 17, -35, 122, -17, -71, 105, 17, -35, 122, 68, 11, 108,
            71, 18, 105, 68, 11, 108, 45, -71, 96, -15, -117, 49, 45, -71,
            96, -89, -90, -19, 48, -96, 69, -89, -90, -19, 32, -39, -118,
            -61, -65, -91, 32, -39, -118, -41, 0, -121, 32, -39, -118,
            -125, 28, -7, 32, -39, -118, 44, 5, -120, -29, 38, -119, 44, 5,
            -120, -56, -60, -98, 100, -48, -64, -56, -60, -98, -47, -10,
            -119, -56, -60, -98, -65, -15, -110, -56, -60, -98, -120, -33,
            -31, -120, -42, -15, -120, -33, -31, -53, -59, 100, -108, -12,
            68, -53, -59, 100, -99, -13, 80, -103, -60, 46, -99, -13, 80,
            -44, -82, 88, -18, 36, 122, -44, -82, 88, 79, 49, 88, 92, -86,
            22, 79, 49, 88, 125, -28, 8, 124, 32, 12, 125, -28, 8, 124, -3,
            33, 125, 23, 15, 124, -3, 33, 127, -16, -11, 121, -19, 36, 127,
            -16, -11, 36, -26, -120, 127, -16, -11, 36, -101, -69, 127,
            -16, -11, 92, -7, -89, 127, -16, -11, 84, 45, -86, 127, -16,
            -11, 90, 43, 80, 125, 23, 15, 90, 43, 80, 125, -28, 8, 100,
            -80, 6, 125, -28, 8, 2, -128, 6, 92, -86, 22, 2, -128, 6, -44,
            -82, 88, -36, -81, 92, -44, -82, 88, -11, -36, 123, -103, -60,
            46, -11, -36, 123, -53, -59, 100, -11, 94, 86, -53, -59, 100,
            -108, 48, 49, -120, -42, -15, -108, 48, 49, -56, -60, -98,
            -108, 48, 49, -29, 38, -119, -108, 48, 49, 32, -39, -118, -108,
            48, 49, 48, -96, 69, -108, 48, 49, 45, -71, 96, -11, 94, 86,
            45, -71, 96, -11, -36, 123, 71, 18, 105, -11, -36, 123, 17,
            -35, 122, -36, -81, 92, 17, -35, 122, 2, -128, 6, -94, -11, 86,
            2, -128, 6, -98, -59, 58, 100, -80, 6, -98, -59, 58, 90, 43,
            80, -81, -94, -31, 90, 43, 80, 30, -36, -119, 84, 45, -86, 30,
            -36, -119, 92, -7, -89, 14, -63, -111, 92, -7, -89, 124, 2,
            -33, 92, -7, -89, 114, 7, -57, 92, -7, -89, 41, -45, -113, 36,
            -101, -69, 41, -45, -113, 36, -26, -120, -3, -13, -127, 36,
            -26, -120, -22, 2, -126, 36, -26, -120, -25, -7, -125, 36, -26,
            -120, 123, 4, -34, 121, -19, 36, 123, 4, -34, 124, -3, 33, 123,
            -5, 35, 124, -3, 33, 86, 80, 51, 124, 32, 12, 86, 80, 51, 79,
            49, 88, 68, 91, 60, 79, 49, 88, 7, 93, 88, -18, 36, 122, 7, 93,
            88, -99, -13, 80, -127, 12, 10, -99, -13, 80, -120, 16, -42,
            -108, -12, 68, -120, 16, -42, -120, -33, -31, -91, 55, 71,
            -120, -33, -31, -82, 9, -98, -65, -15, -110, -82, 9, -98, -47,
            -10, -119, -29, 25, -122, -47, -10, -119, -33, 27, -121, -47,
            -10, -119, -34, -17, -122, -47, -10, -119, -25, -19, -124, 100,
            -48, -64, -25, -19, -124, 44, 5, -120, -43, 19, -119, 44, 5,
            -120, -124, -6, 32, -125, 28, -7, -124, -6, 32, -41, 0, -121,
            -60, 14, -112, -41, 0, -121, 85, 10, -95, -41, 0, -121, 1, 40,
            -122, -41, 0, -121, -87, 43, -83, -61, -65, -91, -87, 43, -83,
            -89, -90, -19, -93, 38, -80, -89, -90, -19, -89, 78, 49, -15,
            -117, 49, -89, 78, 49, 68, 11, 108, -38, 97, 74, 68, 11, 108,
            29, 71, 103, 68, 11, 108, 54, 37, 110, 68, 11, 108, 102, 39,
            66, -17, -71, 105, 102, 39, 66, -38, 46, 113, 78, 96, 34, -38,
            46, 113, -24, 83, 95, -38, 46, 113, 4, 107, 70, -38, 46, 113,
            47, 76, 92, 4, 9, 127, 47, 76, 92, 117, 28, -43, 88, 57, -73,
            117, 28, -43, 91, 54, -72, 116, -52, -16, 91, 54, -72, 66, -33,
            -105, 6, 41, -121, 66, -33, -105, -128, 5, -2, 64, -14, 110,
            -11, 62, -112, 0, 68, -109, 12, 121, -40, -29, 124, -11, 12,
            121, -40, -29, 121, 29, 12, 121, -40, -12, 126, -20, 12, 121,
            -40, 18, 127, 5, 12, 121, -40, 3, 127, 11, 12, 121, -40, -4,
            127, 0, 12, 121, -40, 41, 114, -41, 12, 121, -40, 81, 98, -18,
            12, 121, -40, 66, 104, -36, 12, 121, -40, -7, 74, -104, -11,
            62, -112, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0,
            -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0,
            -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0,
            -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0,
            -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0,
            -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0,
            -128, 0, 0, -128, 0, 0, -128, 0};
        return vals;
    } // end of getNormals()

    private static short[] getTexCoords() // return an array holding TexCoords [580 values / 2 = 290 points]
    {
        short[] vals = {0, 43, 0, 85, 21, 43, 21, 85, 21, 43, 43, 85, 43, 43,
            43, 85, 64, 43, 64, 85, 64, 43, 85, 85, 85, 43, 85, 85, 107,
            43, 107, 85, 107, 43, 128, 85, 128, 43, 128, 85, 149, 43, 149,
            85, 149, 43, 171, 85, 171, 43, 171, 85, 192, 43, 192, 85, 192,
            43, 213, 85, 213, 43, 213, 85, 235, 43, 213, 85, 235, 85, 213,
            85, 235, 128, 213, 128, 235, 128, 213, 171, 235, 171, 213, 171,
            235, 213, 213, 171, 213, 213, 213, 171, 192, 213, 192, 171,
            192, 213, 171, 171, 171, 213, 171, 171, 149, 213, 149, 171,
            149, 213, 128, 171, 128, 213, 128, 171, 107, 213, 107, 171,
            107, 213, 85, 171, 85, 213, 85, 171, 64, 213, 64, 171, 64, 213,
            43, 171, 43, 213, 43, 171, 21, 213, 43, 171, 21, 171, 43, 171,
            21, 128, 43, 171, 43, 128, 43, 171, 64, 128, 64, 171, 64, 128,
            85, 171, 85, 128, 85, 171, 107, 128, 107, 171, 107, 128, 128,
            171, 128, 128, 128, 171, 149, 128, 149, 171, 149, 128, 171,
            171, 171, 128, 171, 171, 192, 128, 192, 171, 192, 128, 213,
            171, 192, 128, 213, 128, 192, 128, 213, 85, 192, 128, 192, 85,
            192, 128, 171, 85, 171, 128, 171, 85, 149, 128, 149, 85, 149,
            128, 128, 85, 128, 128, 128, 85, 107, 128, 107, 85, 107, 128,
            85, 85, 85, 128, 85, 85, 64, 128, 64, 85, 64, 128, 43, 85, 43,
            128, 43, 85, 21, 128, 21, 85, 21, 128, 0, 85, 21, 128, 0, 128,
            21, 128, 0, 171, 21, 171, 0, 171, 21, 213, 0, 213, 21, 213, 0,
            255, 21, 213, 21, 255, 21, 213, 43, 255, 43, 213, 43, 255, 64,
            213, 64, 255, 64, 213, 85, 255, 85, 213, 85, 255, 107, 213,
            107, 255, 107, 213, 128, 255, 128, 213, 128, 255, 149, 213,
            149, 255, 149, 213, 171, 255, 171, 213, 171, 255, 192, 213,
            192, 255, 192, 213, 213, 255, 213, 213, 213, 255, 235, 213,
            235, 255, 235, 213, 255, 255, 235, 213, 255, 213, 235, 213,
            255, 171, 235, 171, 255, 171, 235, 128, 255, 128, 235, 128,
            255, 85, 235, 85, 255, 85, 235, 43, 255, 43, 235, 43, 255, 0,
            235, 43, 235, 0, 235, 43, 213, 0, 213, 43, 213, 0, 192, 43,
            192, 0, 192, 43, 171, 0, 171, 43, 171, 0, 149, 43, 165, 0, 149,
            43, 160, 0, 149, 43, 149, 0, 149, 43, 128, 0, 128, 43, 128, 0,
            107, 43, 107, 0, 107, 43, 101, 0, 107, 43, 96, 0, 107, 43, 85,
            0, 85, 43, 85, 0, 64, 43, 64, 0, 64, 43, 43, 0, 43, 43, 43, 0,
            21, 43, 21, 0, 21, 43, 0, 0, 0, 43, 0, 255, 0, 255, 0, 255, 0,
            255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
            255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
            255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
            255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
            255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
            255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
            255, 0, 255, 0, 255, 0, 255};
        return vals;
    } // end of getTexCoords()

    private static int[] getStripLengths() // return an array holding the lengths of each triangle strip
    {
        int[] lens = {235, 23, 32};
        return lens;
    } // end of getStripLengths()

    private static Material setMatColours() // set the material's colour and shininess values
    {
        Material mat = new Material();

        mat.setColor(Material.AMBIENT, 0x0003C1C1);
        mat.setColor(Material.EMISSIVE, 0x00000000);
        mat.setColor(Material.DIFFUSE, 0xFFE9B1E8);
        mat.setColor(Material.SPECULAR, 0x00000000);
        mat.setShininess(128.0f);

        return mat;
    } // end of setMatColours()

    private static Image2D loadImage2D(String fn) {
        Image2D im = null;
        try {
            im = (Image2D) Loader.load(fn)[0];
        }
        catch (Exception e) {
            System.out.println("Cannot make image from " + fn);
        }
        return im;
    }
}