Example10.java
上传用户:gyyuli
上传日期:2013-07-09
资源大小:3050k
文件大小:28k
源码类别:

J2ME

开发平台:

Java

  1. import javax.microedition.m3g.*;
  2. import java.util.*;
  3. public class Example10 extends ExampleBase
  4. {
  5.     // Debug output flag
  6.     private static final boolean DEBUG = false;
  7.     // Graphics3d context
  8.     private Graphics3D      g3d;
  9.     // Random generator
  10.     private Random          m_random = new Random();
  11.     // Some flags
  12.     private boolean         m_tunnelFadeOut = false;
  13.     private boolean         m_nokiaFadeOut = false; 
  14.     private boolean         m_fogOn = false;
  15.     private float           m_lightIntensity = 1.0f;
  16.     /*private GameMIDlet        m_midlet;*/
  17.     // Nokia scene params
  18.     private static final int SCENE_NOKIA_LENGTH = 33000;
  19.     private static final int SCENE_NOKIA_HIDEBUG = 22000;
  20.     // Snowflake count
  21.     private static final int NUM_SNOWFLAKES = 20;
  22.     private static final float SNOWFLAKE_SCALE = 6f;
  23.     private static final float GROUND_LEVEL = 0f;
  24.     // Bug scene length in ms
  25.     private static final int SCENE_BUG_LENGTH = 6700;
  26.     // The tunnel scene length
  27.     private static final int SCENE_TUNNEL_LENGTH = 3000;
  28.     // Current scene index
  29.     private int             m_currentScene;
  30.     // Number of scenes
  31.     private static final int SCENE_COUNT = 5;
  32.     // Scene indices
  33.     private static final int SCENE_NOKIA = 0;
  34.     private static final int SCENE_BUG = 1;
  35.     private static final int SCENE_TUNNEL = 2;
  36.     private static final int SCENE_POND = 3;
  37.     private static final int SCENE_LOWPOLY = 4;
  38.     // User IDs for the ant polygon image
  39.     private static final int UID_NOKIA_ANTIMAGE = 47364324;
  40.     // Items in the tunnel scene..
  41.     private static final int UID_TUNNEL_MESH = 116237701;
  42.     private static final int UID_TUNNEL_CAMERA = 457572229;
  43.     private static final int UID_TUNNEL_LIGHT = 131143914;
  44.     // For the pond scene
  45.     private static final int UID_POND_CAMERA1 = 653251478;
  46.     private static final int UID_POND_CAMERA2 = 124296655;
  47.     private static final int UID_POND_CAMERA3 = 901844788;
  48.     private static final int UID_POND_CAMERA4 = 468090727;
  49.     private static final int UID_POND_ANTHEAD = 296699498;
  50.     // Fov value for pond scenes
  51.     private float[]     m_cameraFOVs = {35, 25, 30, 30};
  52.     private int         m_currentCamera = 0;
  53.     // Switches for the tunnel
  54.     private static final int NO_TEXTURE = 0;
  55.     private static final int ONE_TEXTURE = 1;
  56.     private static final int DUAL_TEXTURE = 2;
  57.     private static final int TOGGLE_FOG = 3;
  58.     // We load .m3g scenes here
  59.     private World[]     m_scenes;
  60.     // Time counter
  61.     private int         m_currentTime;
  62.     // Time in millisecs
  63.     private long        m_lastFrame;
  64.     private int         m_deltaTime;
  65.     //
  66.     public Example10()
  67.     {
  68.         super(SHOW_RENDER_TIME);
  69.         /*m_midlet = m;*/
  70.     }
  71.     //
  72.     public void initialize()
  73.     {
  74.         // Create a new 3D graphics context
  75.         g3d = Graphics3D.getInstance();
  76.         try
  77.         {
  78.             // Allocate some scenes
  79.             m_scenes = new World[SCENE_COUNT];
  80.             // Load the nokia scene
  81.             m_scenes[SCENE_NOKIA] = loadScene("nokia/nokia_on_ice");
  82.             preInitNokiaScene();
  83.             // Start from the first scene
  84.             m_currentScene = SCENE_NOKIA;
  85.             m_currentTime = 0;
  86.         }
  87.         catch (Exception e)
  88.         {
  89.             e.printStackTrace();
  90.         }
  91.         //
  92.         if (DEBUG)
  93.             System.out.println("Loaded");
  94.     }
  95.     // Loads a scene with given name
  96.     private World loadScene(String name)
  97.     {
  98.         long mem = Runtime.getRuntime().freeMemory();
  99.         Object3D[] o = null;
  100.         try
  101.         {
  102.             o = load(name);
  103.         }
  104.         catch (Exception e)
  105.         {
  106.             e.printStackTrace();
  107.         }
  108.         long memNow = mem - Runtime.getRuntime().freeMemory();
  109.         if (DEBUG)
  110.         {
  111.             System.out.println("Scene took " + memNow + " bytes..");
  112.             // Show free mem
  113.             showMemory();
  114.         }
  115.         return (World) o[0];
  116.     }
  117.     public void render(Object g)
  118.     {
  119.         /*Display display = Display.getDisplay( m_midlet );
  120.         if ( display.getCurrent() == this )*/
  121.         {
  122.             long frm = System.currentTimeMillis();
  123.             // make sure we don't do a huge skip on the first frame
  124.             if (m_lastFrame == 0)
  125.             {
  126.                 m_deltaTime = 0;
  127.             }
  128.             else
  129.             {
  130.                 m_deltaTime = (int) (frm - m_lastFrame);
  131.             }
  132.             m_lastFrame = frm;
  133.             doFrame(g);
  134.             /*serviceRepaints();*/
  135.         }
  136.     }
  137.     //
  138.     public void keyPressed( int keyCode )
  139.     {
  140.         super.keyPressed(keyCode);
  141. //      int gameAction = getGameAction( keyCode );
  142.         if (m_currentScene == SCENE_NOKIA)
  143.         {
  144.             if (keyCode == KEY_5)
  145.             {
  146.                 m_nokiaFadeOut = true;
  147.             }           
  148.         }
  149.         
  150.         if (m_currentScene == SCENE_TUNNEL)
  151.         {
  152.             if (keyCode == KEY_1)
  153.             {
  154.                 switchTunnelMode(NO_TEXTURE);
  155.             }
  156.             else
  157.             if (keyCode == KEY_2)
  158.             {
  159.                 switchTunnelMode(ONE_TEXTURE);
  160.             }
  161.             else
  162.             if (keyCode == KEY_3)
  163.             {
  164.                 switchTunnelMode(DUAL_TEXTURE);
  165.             }
  166.             else
  167.             if (keyCode == KEY_4)
  168.             {
  169.                 switchTunnelMode(TOGGLE_FOG);
  170.             }
  171.             else
  172.             if (keyCode == KEY_5)
  173.             {
  174.                 m_tunnelFadeOut = true;
  175.             }
  176.         }
  177.         if (m_currentScene == SCENE_POND)
  178.         {
  179.             // Find the pond scene..
  180.             World pond = m_scenes[SCENE_POND];
  181.     
  182.             // Switch active cameras        
  183.             if (keyCode == KEY_1)
  184.             {
  185.                 Camera c = (Camera) pond.find(UID_POND_CAMERA1);
  186.                 pond.setActiveCamera(c);
  187.                 m_currentCamera = 0;
  188.             }
  189.             else
  190.             if (keyCode == KEY_2)
  191.             {
  192.                 Camera c = (Camera) pond.find(UID_POND_CAMERA2);
  193.                 pond.setActiveCamera(c);
  194.                 m_currentCamera = 1;
  195.             }
  196.             else
  197.             if (keyCode == KEY_3)
  198.             {
  199.                 Camera c = (Camera) pond.find(UID_POND_CAMERA3);
  200.                 pond.setActiveCamera(c);
  201.                 m_currentCamera = 2;
  202.             }
  203.             else
  204.             if (keyCode == KEY_4)
  205.             {
  206.                 Camera c = (Camera) pond.find(UID_POND_CAMERA4);
  207.                 pond.setActiveCamera(c);
  208.                 m_currentCamera = 3;
  209.             }
  210.             else
  211.             // Adjust current FOV factor
  212.             if (keyCode == KEY_UP)
  213.             {
  214.                 float fo = m_cameraFOVs[m_currentCamera];
  215.                 if (fo > 15)
  216.                     fo-=5;
  217.                 m_cameraFOVs[m_currentCamera] = fo;
  218.                 // Set the field-of-view
  219.                 Camera c = pond.getActiveCamera();
  220.                 c.setPerspective(fo, 1.0f, 0.1f,5);
  221.             }
  222.             else
  223.             if (keyCode == KEY_DOWN)
  224.             {
  225.                 float fo = m_cameraFOVs[m_currentCamera];
  226.                 if (fo < 45)
  227.                     fo+=5;
  228.                 m_cameraFOVs[m_currentCamera] = fo;
  229.                 // Set the field-of-view
  230.                 Camera c = pond.getActiveCamera();
  231.                 c.setPerspective(fo, 1.0f, 0.1f,5);
  232.             }
  233.         }
  234. /*
  235.         if (keyCode == KEY_0)
  236.         {
  237.             m_midlet.destroyApp( true );
  238.         }
  239. */  }
  240.     // Do something..
  241.     public void doFrame( Object g )
  242.     {
  243. //        int w = getWidth();
  244.  //       int h = getHeight();
  245.         // if we don't have a g3d context, fill screen with red color
  246.         if (g3d == null)
  247.         {
  248. //          g.setClip(0,0, w,h);
  249. //          g.setColor(100,10,15);
  250. //          g.fillRect(0,0, w,h);
  251.             return;
  252.         }
  253.         //
  254.         int delta = m_deltaTime * 3/4;
  255.         // update demo
  256.         updateDemo(m_currentTime, delta);
  257.         // bind to graphics
  258.         g3d.bindTarget(g);
  259.         // get currently displayed scene
  260.         World scn = m_scenes[m_currentScene];
  261.         scn.animate(m_currentTime);
  262.         // do something after animation
  263.         postAnimate();
  264.         g3d.render(scn);
  265.         scn = null;
  266.         // release g3d
  267.         g3d.releaseTarget();
  268.         // update timer by delta value
  269.         m_currentTime+=delta;
  270.     }
  271.     // updates the demo
  272.     private void updateDemo(int time, int delta)
  273.     {
  274.         if (m_currentScene == SCENE_NOKIA)
  275.         {
  276.             updateNokiaScene(time);
  277.         }
  278.         else
  279.         if (m_currentScene == SCENE_BUG)
  280.         {
  281.             updateBugScene(time);
  282.         }       
  283.         else
  284.         if (m_currentScene == SCENE_TUNNEL)
  285.         {
  286.             updateTunnelScene(time, delta);
  287.         }       
  288.     }
  289.     // does some post-animate() tasks
  290.     private void postAnimate()
  291.     {
  292.         /** target the camera to ant's head */
  293.         if (m_currentScene == SCENE_POND)
  294.         {
  295.             World scn = m_scenes[m_currentScene];
  296.             Camera c = scn.getActiveCamera();
  297.             c.align(null);
  298.         }
  299.     }
  300.     // Frees the old scene (destroys it's references) and frees up mem
  301.     private void freeOldScene()
  302.     {
  303.         // Get mem
  304.         long mem = Runtime.getRuntime().freeMemory();
  305.         // get the current scene
  306.         World w = m_scenes[m_currentScene];
  307.         // clear background
  308.         w.setBackground(null);
  309.         // remove all animation tracks
  310.         removeAnimTracks(w);
  311.         // remove all groups & nodes from the scene
  312.         removeAllNodes(w);
  313.         // null the scene
  314.         m_scenes[m_currentScene] = null;
  315.         // try to free some memory...
  316.         System.gc();
  317.         // Show how much we actually freed
  318.         if (DEBUG)
  319.         {
  320.             long memNow = Runtime.getRuntime().freeMemory() - mem;
  321.             System.out.println("Freed " + memNow + " bytes ...");
  322.             // Show free mem
  323.             showMemory();
  324.         }
  325.     }
  326.     private void removeAllNodes(Group g)
  327.     {
  328.         // Do while we have something to remove..
  329.         while (g.getChildCount() > 0)
  330.         {
  331.             // get the first child
  332.             Node n = g.getChild(0);
  333.             // if child is a group, clear it first..
  334.             if (n instanceof Group)
  335.             {
  336.                 Group g2 = (Group) n;
  337.                 if (g2.getChildCount() > 0)
  338.                 {
  339.                     removeAllNodes(g2);
  340.                 }
  341.             }
  342.             //
  343.             g.removeChild(n);
  344.             if (DEBUG)
  345.                 System.out.println("Node removed");
  346.         }
  347.     }
  348.     // Let's try to free up as much mem as possible...
  349.     private void removeAnimTracks(Object3D obj)
  350.     {
  351.         int numReferences = obj.getReferences(null);
  352.         if (numReferences > 0)
  353.         {
  354.             Object3D[] objArray = new Object3D[numReferences];
  355.             obj.getReferences(objArray);
  356.             //
  357.             for (int i = 0; i < numReferences; i++)
  358.             {
  359.                 //
  360.                 Object3D o = objArray[i];
  361.                 // remove possible animation tracks
  362.                 while (o.getAnimationTrackCount() > 0)
  363.                 {
  364.                     AnimationTrack an = o.getAnimationTrack(0);
  365.                     o.removeAnimationTrack(an);
  366.                     if (DEBUG)
  367.                         System.out.println("removed animation track");
  368.                 }
  369.                 //
  370.                 if (o instanceof Mesh || o instanceof SkinnedMesh)
  371.                 {
  372.                     // remove appearances etc
  373.                     removeAppearance((Mesh) o);
  374.                 }
  375.                 // trace next obj
  376.                 removeAnimTracks(o);
  377.             }
  378.         }
  379.     }
  380.     // Clear texture references to free up more mem
  381.     private void removeAppearance(Mesh m)
  382.     {
  383.         // loop through all submeshes
  384.         for (int a = 0; a < m.getSubmeshCount(); a++)
  385.         {
  386.             Appearance p = m.getAppearance(a);
  387.             if (p != null)
  388.             {
  389.                 // clear everything we can..
  390.                 p.setTexture(0, null);
  391.                 p.setMaterial(null);
  392.                 p.setPolygonMode(null);
  393.                 p.setFog(null);
  394.                 p.setCompositingMode(null);
  395.             }
  396.             // finally, remove the appearance...
  397.             m.setAppearance(a, null);
  398.         }
  399.     }
  400.     //
  401.     private void showMemory()
  402.     {
  403.         if (DEBUG)
  404.             System.out.println("Memory available : " + Runtime.getRuntime().freeMemory() + " / " + Runtime.getRuntime().totalMemory());
  405.     }
  406.     //
  407.     private void preInitNokiaScene()
  408.     {
  409.         // Search the node with the 2d bug image and hide it for now..
  410.         World nokia = m_scenes[SCENE_NOKIA];
  411.         Mesh m = (Mesh) nokia.find(UID_NOKIA_ANTIMAGE);
  412.         m.setRenderingEnable(false);
  413.         // Add some snowflakes to the scene
  414.         initSnowFlakes();
  415.     }
  416.     //
  417.     private boolean showBug = false;
  418.     private void updateNokiaScene(int time)
  419.     {
  420.         // Do not show the bug node before certain time has been reached..
  421.         if (time > SCENE_NOKIA_HIDEBUG && !showBug)
  422.         {
  423.             // Search the image node & display it
  424.             World nokia = m_scenes[SCENE_NOKIA];
  425.             Mesh m = (Mesh) nokia.find(UID_NOKIA_ANTIMAGE);
  426.             m.setRenderingEnable(true);
  427.             // Show the lil' fellah :)
  428.             showBug = true;
  429.         }
  430.         // Animate the snowflakes..
  431.         animateSnowFlakes(time);
  432.         // Switch to bug scene when
  433.         // todo: fade out nokia scene properly
  434.         if (time > SCENE_NOKIA_LENGTH || m_nokiaFadeOut)
  435.         {
  436.             //
  437.             freeOldScene();
  438.             // Load the bug scene
  439.             m_scenes[SCENE_BUG] = loadScene("nokia/otokka_jump2");
  440.             //
  441.             m_currentScene = SCENE_BUG;
  442.             m_currentTime = 0;
  443.         }
  444.     }
  445.     //
  446.     private void updateBugScene(int time)
  447.     {
  448.         // Switch to bug scene when
  449.         if (time > SCENE_BUG_LENGTH)
  450.         {
  451.             //
  452.             freeOldScene();
  453.             // Load the pond scene
  454.             m_scenes[SCENE_TUNNEL] = loadScene("nokia/tunnel");
  455.             preInitTunnelScene();
  456.             //
  457.             m_currentScene = SCENE_TUNNEL;
  458.             m_currentTime = 0;
  459.         }
  460.     }
  461.     //
  462.     private void preInitTunnelScene()
  463.     {
  464.         /** Select the world... */
  465.         World w = m_scenes[SCENE_TUNNEL];
  466.         // Find the tunnel mesh
  467.         Mesh tnl = (Mesh) w.find(UID_TUNNEL_MESH);
  468.         // Get the appearance from the mesh
  469.         Appearance ap = tnl.getAppearance(0);
  470.         // Get the vertex buffer for the tunnel mesh
  471.         VertexBuffer vb = tnl.getVertexBuffer();
  472.         // Get vertex count
  473.         int count = vb.getVertexCount();
  474.         // Create a new array for texture coordinates (for texture #2, as the object has only one texture layer defined in swerve)
  475.         tunnelTexCoords = new short[count * 2];
  476.         // Init the array with some random values
  477.         for (int a = 0 ; a < count*2; a++)
  478.         {
  479.             int i = (m_random.nextInt() & 0xFF);
  480.             tunnelTexCoords[a] = (short) i;
  481.         }
  482.         // Create a new vertex array..
  483.         tunnelTextureArray = new VertexArray(count, 2, 2);
  484.         // Copy texture coordinate values to array
  485.         tunnelTextureArray.set(0, count, tunnelTexCoords);
  486.         // Assign texture coordinates to second texture unit.
  487.         vb.setTexCoords(1, tunnelTextureArray, 0.0004f, null);
  488.         // Load texture image ...
  489.         tunnelTextureImage2 = new Image2D(Image2D.RGB, platformServices.loadImage("nokia/ttex2.png"));
  490.         // Create texmap
  491.         tunnelTexture2 = new Texture2D(tunnelTextureImage2);
  492.         // Choose blending mode for the texture layer, additive by default
  493.         tunnelTexture2.setBlending(Texture2D.FUNC_ADD);
  494.         // Backup first texture reference...
  495.         tunnelTexture1 = ap.getTexture(0);
  496.         // Update the textures...
  497.         switchTunnelMode(1);
  498.         // Create linear fog for the tunnel
  499.         tunnelFog = new Fog();
  500.         tunnelFog.setMode(Fog.LINEAR);
  501.         tunnelFog.setColor(0x006080a0);
  502.         tunnelFog.setLinear(10.0f, 25.0f);
  503.     }
  504.     //
  505.     private void updateTunnelScene(int time, int delta)
  506.     {
  507.         // 
  508.         World scn = m_scenes[SCENE_TUNNEL];
  509.         // Find the omni light
  510.         Light l = (Light) scn.find(UID_TUNNEL_LIGHT);
  511.         // Set the light's intensity
  512.         l.setIntensity(m_lightIntensity);
  513.         /** Fade out mode */
  514.         if (m_tunnelFadeOut)
  515.         {
  516.             if (DEBUG)
  517.                 System.out.println(delta);
  518.             // Drop intensity
  519.             m_lightIntensity-=(delta * 0.001f);
  520.             // Fade below zero.. Looks like we have ambient light somewhere?
  521.             if (m_lightIntensity <= -2.0f)
  522.             {
  523.                 //
  524.                 freeOldScene();
  525.     
  526.                 //
  527.                 m_scenes[SCENE_POND] = loadScene("nokia/pond_vilkutus2");
  528.                 preInitPondScene();
  529.     
  530.                 //
  531.                 m_currentScene = SCENE_POND;
  532.                 m_currentTime = 0;
  533.             }
  534.         }
  535.     }
  536.     // Switches between different texture depths
  537.     private void switchTunnelMode(int tnlMode)
  538.     {
  539.         // Select the world...
  540.         World w = m_scenes[SCENE_TUNNEL];
  541.         // Find the tunnel mesh
  542.         Mesh tnl = (Mesh) w.find(UID_TUNNEL_MESH);
  543.         // Get the appearance from the mesh
  544.         Appearance ap = tnl.getAppearance(0);
  545.         // remove textures?
  546.         if (tnlMode == NO_TEXTURE)
  547.         {
  548.             ap.setTexture(0, null);
  549.             ap.setTexture(1, null);
  550.         }
  551.         else
  552.         if (tnlMode == ONE_TEXTURE)
  553.         {
  554.             ap.setTexture(0, tunnelTexture1);
  555.             ap.setTexture(1, null);
  556.         }
  557.         else
  558.         if (tnlMode == DUAL_TEXTURE)
  559.         {
  560.             ap.setTexture(0, tunnelTexture1);
  561.             ap.setTexture(1, tunnelTexture2);
  562.         }
  563.         else
  564.         // Switch fog on/off
  565.         if (tnlMode == TOGGLE_FOG)
  566.         {
  567.             if (!m_fogOn)
  568.             {
  569.                 ap.setFog(tunnelFog);
  570.                 m_fogOn = true;
  571.             }
  572.             else
  573.             {
  574.                 ap.setFog(null);
  575.                 m_fogOn = false;
  576.             }
  577.         }
  578.     }
  579.     // Picks some cameras etc
  580.     private void preInitPondScene()
  581.     {
  582.         //
  583.         World pond = m_scenes[SCENE_POND];
  584.         // Default to first camera
  585.         Camera c = (Camera) pond.find(UID_POND_CAMERA1);
  586.         c.setPerspective(m_cameraFOVs[0], 1.0f, 0.1f,5);
  587.         //
  588.         m_currentCamera = 0;
  589.         pond.setActiveCamera(c);
  590.         // Target camera to the ant. Note that the y target axis is scene's z-axis because 
  591.         // the scene is exported from 3dsmax, in which z points up on world space
  592.         
  593.         Node n = (Node) pond.find(UID_POND_ANTHEAD);
  594.         c.setAlignment(n, Node.ORIGIN, pond, Node.Z_AXIS);
  595.         c.scale(-1, 1, -1);
  596.         // Set field-of-view and clip params by hand
  597.         c = (Camera) pond.find(UID_POND_CAMERA2);
  598.         c.setPerspective(m_cameraFOVs[1], 1.0f, 0.1f,5);
  599.         c.setAlignment(n, Node.ORIGIN, pond, Node.Z_AXIS);
  600.         c.scale(-1, 1, -1);
  601.         c = (Camera) pond.find(UID_POND_CAMERA3);
  602.         c.setPerspective(m_cameraFOVs[2], 1.0f, 0.1f,5);
  603.         c.setAlignment(n, Node.ORIGIN, pond, Node.Z_AXIS);
  604.         c.scale(-1, 1, -1);
  605.         c = (Camera) pond.find(UID_POND_CAMERA4);
  606.         c.setPerspective(m_cameraFOVs[3], 1.0f, 0.1f,5);
  607.         c.setAlignment(n, Node.ORIGIN, pond, Node.Z_AXIS);
  608.         c.scale(-1, 1, -1);
  609.     }
  610.     // Inits some snowflakes for the Nokia scene
  611.     private void initSnowFlakes()
  612.     {
  613.         // First we init a vertex array with 3 components (X,Y,Z), size of each component is byte
  614.         flakeVertexArray = new VertexArray(flakeVertices.length / 3, 3, 2);
  615.         // Now, we copy the actual XYZ coordinates to the array
  616.         flakeVertexArray.set(0, flakeVertices.length / 3, flakeVertices);
  617.         // Init a texture coordinate array with same size as the coordinate array, but only two coords for each vertex (u,v)
  618.         flakeTextureArray = new VertexArray(flakeTexCoords.length / 2, 2, 2);
  619.         // Copy actual values again
  620.         flakeTextureArray.set(0, flakeTexCoords.length / 2, flakeTexCoords);
  621.         // Next we need to create a vertex buffer, to which we'll assign the texture coordinates and XYZ coordinates
  622.         flakeVertexBuffer = new VertexBuffer();
  623.         // No scale, no bias in XYZ coordinates
  624.         flakeVertexBuffer.setPositions(flakeVertexArray, 0.01f, null);
  625.         // Assign texture coordinates to first texture unit. Again, no scale & no bias is needed
  626.         flakeVertexBuffer.setTexCoords(0, flakeTextureArray, 0.1f, null);
  627.         // Next we need to create a triangle strip array which holds the polygon definitions for the flakes
  628.         flakeTriangles = new TriangleStripArray(flakeStrip, flakeStripLengths);
  629.         /** 
  630.         *
  631.         * We could also create the triangle strip implicitly, by defining the first vertex index as zero..
  632.         * This saves some space when simple, continuous triangle strips are created.
  633.         *
  634.         * flakeTriangles = new TriangleStripArray(0, flakeStripLengths);
  635.         *
  636.         */
  637.         // First we need to create new appearance
  638.         flakeAppearance = new Appearance();
  639.         // Then we load a texture image ... We need to use alpha due to transparent pixels
  640.         flakeTextureImage = new Image2D(Image2D.RGBA, platformServices.loadImage("nokia/snowflake.png"));
  641.         // Then we create a texture map from the image
  642.         flakeTexture = new Texture2D(flakeTextureImage);
  643.         // Choose worst possible filtering type to gain more speed (actually it's already selected by default)
  644.         flakeTexture.setFiltering(Texture2D.FILTER_BASE_LEVEL, Texture2D.FILTER_NEAREST);
  645.         // Just replace the texel directly with the source for more speed
  646.         flakeTexture.setBlending(Texture2D.FUNC_REPLACE);
  647.         // Next, create a polygon mode definition
  648.         flakePolyMode = new PolygonMode();
  649.         // No, we don't need perspective correction for such small polygons
  650.         flakePolyMode.setPerspectiveCorrectionEnable(false);
  651.         // Shading should apply to whole polygon
  652.         flakePolyMode.setShading(PolygonMode.SHADE_FLAT);
  653.         // Disable visible side culling (both sides of flakes are seen)
  654.         flakePolyMode.setCulling(PolygonMode.CULL_NONE);
  655.         // Define winding as clockwise (actually it doesn't matter here since no culling is used...)
  656.         flakePolyMode.setWinding(PolygonMode.WINDING_CW);
  657.         // No, we don't want the flakes to be lit by camera light
  658.         flakePolyMode.setLocalCameraLightingEnable(false);
  659.         // Sincle no culling is used, we need to light both sides of the polygon
  660.         flakePolyMode.setTwoSidedLightingEnable(true);
  661.         // Let's define how the polygon is blended with the background
  662.         flakeCompositing = new CompositingMode();
  663.         // We want to use the alpha to blend the pixels to background
  664.         flakeCompositing.setBlending(CompositingMode.ALPHA);
  665.         // Don't write anything to alpha buffer
  666.         flakeCompositing.setAlphaWriteEnable(false);
  667.         // Set the texture map to the appearance's first texture unit
  668.         flakeAppearance.setTexture(0, flakeTexture);
  669.         // Assign the polygon mode to the appearance
  670.         flakeAppearance.setPolygonMode(flakePolyMode);
  671.         // Assign the compositing mode to the appearance
  672.         flakeAppearance.setCompositingMode(flakeCompositing);
  673.         // Get the world..
  674.         World nokia = m_scenes[SCENE_NOKIA];
  675.         // Finally, let's do some meshes from these definitions and add them to the scene
  676.         m_snowFlakes = new Mesh[NUM_SNOWFLAKES];
  677.         //
  678.         for (int a = 0; a < NUM_SNOWFLAKES; a++)
  679.         {
  680.             m_snowFlakes[a] = new Mesh(flakeVertexBuffer, flakeTriangles, flakeAppearance);
  681.             m_snowFlakes[a].translate(
  682.                 rnd(-SNOWFLAKE_SCALE, SNOWFLAKE_SCALE),
  683.                 rnd(-SNOWFLAKE_SCALE, SNOWFLAKE_SCALE),
  684.                 rnd(GROUND_LEVEL, GROUND_LEVEL + (SNOWFLAKE_SCALE/2.0f))
  685.             );
  686.             nokia.addChild(m_snowFlakes[a]);
  687.         }
  688.     }
  689.     //
  690.     private float rnd(float min, float max)
  691.     {
  692.         float p = (float) (m_random.nextInt() & 0xFFF) / 4095.0f;
  693.         float q = 1.0f - p;
  694.         return p * max + q * min;
  695.     }
  696.     // Animates the snowflakes...
  697.     private void animateSnowFlakes(int time)
  698.     {
  699.         float[] xyz = new float[3];
  700.         for (int a = 0; a < NUM_SNOWFLAKES; a++)
  701.         {
  702.             // push the new position to the flake. Note that the scene is exported from 3dsmax, thus z points up.
  703.             m_snowFlakes[a].translate(0,0, -0.1f);
  704.             // get current snowflake position
  705.             m_snowFlakes[a].getTranslation(xyz);
  706.             // move the flakes a bit
  707.             if (xyz[2] < GROUND_LEVEL)
  708.             {
  709.                 // push the new position to the flake
  710.                 m_snowFlakes[a].translate(0,0, SNOWFLAKE_SCALE/2.0f);
  711.             }
  712.         }
  713.     }
  714.     // Definitions for a snowflake
  715.     private Appearance          flakeAppearance;
  716.     private Material            flakeMaterial;
  717.     private PolygonMode         flakePolyMode;
  718.     private CompositingMode     flakeCompositing;
  719.     private Image2D             flakeTextureImage;
  720.     private Texture2D           flakeTexture;
  721.     // Arrays & buffers for snowflake
  722.     private VertexArray         flakeVertexArray;
  723.     private VertexArray         flakeTextureArray;
  724.     private VertexBuffer        flakeVertexBuffer;
  725.     private TriangleStripArray  flakeTriangles;
  726.     // Meshes
  727.     private Mesh[]              m_snowFlakes;
  728.     // Vertex coordinates for a snowflake (a simple flat quad actually)
  729.     private static final short flakeVertices[] =
  730.     {
  731.         (short) -10, (short) 0, (short)  10,
  732.         (short) -10, (short) 0, (short) -10,
  733.         (short)  10, (short) 0, (short)  10,
  734.         (short)  10, (short) 0, (short) -10
  735.     };
  736.     // Texture coordinates for the snowflake
  737.     private static final short flakeTexCoords[] =
  738.     {
  739.         (short) 0,  (short) 10,
  740.         (short) 0, (short) 0,
  741.         (short) 10, (short) 10,
  742.         (short) 10,  (short) 0,
  743.     };
  744.     // Strip lengths for a simple snowflake
  745.     private static final int flakeStripLengths[] = { 4 };
  746.     // Triangle strip for the snowflake
  747.     private static final int flakeStrip[] =
  748.     {
  749.         0, 1, 2, 3
  750.     };
  751.     //
  752.     private Appearance          tunnelAppearance;
  753.     //private Image2D           tunnelTextureImage1;
  754.     private Image2D             tunnelTextureImage2;
  755.     //
  756.     private Fog                 tunnelFog;
  757.     //
  758.     private Texture2D           tunnelTexture1;
  759.     private Texture2D           tunnelTexture2;
  760.     // Arrays & buffers for the tunnel
  761.     private VertexArray         tunnelTextureArray;
  762.     // Texture coordinates for the tunnel
  763.     private short[] tunnelTexCoords;
  764. }