javauis/m3g_akn/javasrc/javax/microedition/m3g/Interface.java
branchRCL_3
changeset 14 04becd199f91
child 19 71c436fe3ce0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/m3g_akn/javasrc/javax/microedition/m3g/Interface.java	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,442 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+package javax.microedition.m3g;
+
+import java.lang.ref.WeakReference;
+import java.util.Hashtable;
+import com.nokia.mj.impl.rt.legacy.ToolkitInvoker;
+import com.nokia.mj.impl.rt.legacy.ToolkitObserver;
+import com.nokia.mj.impl.rt.support.Finalizer;
+import com.nokia.mj.impl.rt.legacy.MemoryUtil;
+
+/**
+ * M3G interface object. An interface is automatically created for
+ * each MIDlet using the 3D API to keep track of Java-side object
+ * lifetimes etc.
+ */
+class Interface implements ToolkitObserver
+{
+    //------------------------------------------------------------------
+    // Static data
+    //------------------------------------------------------------------
+
+    // Common class enumeration for Java and native code
+
+    private static final int ANIMATION_CONTROLLER = 0x01;
+    private static final int ANIMATION_TRACK      = 0x02;
+    private static final int APPEARANCE           = 0x03;
+    private static final int BACKGROUND           = 0x04;
+    private static final int CAMERA               = 0x05;
+    private static final int COMPOSITING_MODE     = 0x06;
+    private static final int FOG                  = 0x07;
+    private static final int GROUP                = 0x08;
+    private static final int IMAGE_2D             = 0x09;
+    private static final int INDEX_BUFFER         = 0x0A;
+    private static final int KEYFRAME_SEQUENCE    = 0x0B;
+    private static final int LIGHT                = 0x0C;
+    private static final int LOADER               = 0x0D;
+    private static final int MATERIAL             = 0x0E;
+    private static final int MESH                 = 0x0F;
+    private static final int MORPHING_MESH        = 0x10;
+    private static final int POLYGON_MODE         = 0x11;
+    private static final int RENDER_CONTEXT       = 0x12;
+    private static final int SKINNED_MESH         = 0x13;
+    private static final int SPRITE_3D            = 0x14;
+    private static final int TEXTURE_2D           = 0x15;
+    private static final int VERTEX_ARRAY         = 0x16;
+    private static final int VERTEX_BUFFER        = 0x17;
+    private static final int WORLD                = 0x18;
+
+    // Once created, the interface singleton currently remains in
+    // memory until VM exit.  By using a WeakReference here, with hard
+    // references stored in each object, it could be GC'd when no more
+    // objects exist, but that probably isn't worth the extra memory
+    // overhead.
+    private static Hashtable s_instances = new Hashtable();
+
+    //------------------------------------------------------------------
+    // Instance data
+    //------------------------------------------------------------------
+
+    private int toolkitHandle;
+    // Global handle-to-Object3D map used to both find the Java
+    // counterparts of objects returned from the native methods, and
+    // keep certain objects from being garbage collected.
+    private final Hashtable liveObjects;
+    // Indicates shutdown status
+    private boolean shutdown;
+    // Singleton Graphics3D instance
+    Graphics3D graphics3D;
+    // Event source native handle
+    private int eventSrcHandle;
+    // Reference count for the event source
+    private int eventSrcHandleRefCount;
+    // Handle of the native interface object.
+    private int handle;
+    private Finalizer mFinalizer;
+
+    static
+    {
+        com.nokia.mj.impl.rt.support.Jvm.loadSystemLibrary("javam3g");
+    }
+
+    //------------------------------------------------------------------
+    // Constructors
+    //------------------------------------------------------------------
+
+    private Interface(int toolkitHandle)
+    {
+        this.toolkitHandle = toolkitHandle;
+        liveObjects = new Hashtable();
+        graphics3D = null;
+        shutdown = false;
+        // initialize event source
+        ToolkitInvoker invoker = ToolkitInvoker.getToolkitInvoker();
+        invoker.addObserver(invoker.getToolkit(), this);
+        int UIServerHandle = invoker.getUIEventServerHandle();
+        eventSrcHandle = _initEventSource(UIServerHandle);
+        eventSrcHandleRefCount = 0;
+        // Check init status
+        if (eventSrcHandle <= 0)
+        {
+            throw new OutOfMemoryError();
+        }
+
+        handle = _ctor(eventSrcHandle);
+        mFinalizer = new Finalizer()
+        {
+            public void finalizeImpl()
+            {
+                doFinalize();
+            }
+        };
+    }
+
+    //------------------------------------------------------------------
+    // Package methods
+    //------------------------------------------------------------------
+
+    /**
+     * Returns the M3G interface instance for the current MIDlet.
+     */
+    synchronized static final Interface getInstance()
+    {
+        if (Interface.s_instances == null)
+        {
+            throw new RuntimeException("Graphics3D closed");
+        }
+        ToolkitInvoker invoker = ToolkitInvoker.getToolkitInvoker();
+        int toolkitHandle = invoker.toolkitGetHandle(invoker.getToolkit());
+
+        Object instance = s_instances.get(new Integer(toolkitHandle));
+        if (instance == null)
+        {
+            instance = new Interface(toolkitHandle);
+            s_instances.put(new Integer(toolkitHandle), instance);
+        }
+        return (Interface) instance;
+    }
+
+    /**
+     * Returns the native handle of the current Interface instance.
+     */
+    static final int getHandle()
+    {
+        return getInstance().handle;
+    }
+
+    /**
+     * Finds an Object3D in the global handle-to-object map. Also
+     * removes dead objects (that is, null references) from the map
+     * upon encountering them.
+     */
+    static final Object3D findObject(int handle)
+    {
+        Interface self = getInstance();
+        Integer iHandle = new Integer(handle);
+        Object ref = self.liveObjects.get(iHandle);
+
+        if (ref != null)
+        {
+            Object3D obj = (Object3D)((WeakReference)ref).get();
+            if (obj == null)
+            {
+                self.liveObjects.remove(iHandle);
+            }
+            return obj;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the Java object representing a native object, or
+     * creates a new proxy/peer if one doesn't exist yet.
+     */
+    static final Object3D getObjectInstance(int handle)
+    {
+        // A zero handle equals null
+        if (handle == 0)
+        {
+            return null;
+        }
+        // Then try to find an existing Java representative for the
+        // object
+        Object3D obj = findObject(handle);
+        if (obj != null)
+        {
+            return obj;
+        }
+        // Not found, create a new Java object. Note that only
+        // non-abstract classes can possibly be returned.
+        switch (_getClassID(handle))
+        {
+        case ANIMATION_CONTROLLER:
+            return new AnimationController(handle);
+        case ANIMATION_TRACK:
+            return new AnimationTrack(handle);
+        case APPEARANCE:
+            return new Appearance(handle);
+        case BACKGROUND:
+            return new Background(handle);
+        case CAMERA:
+            return new Camera(handle);
+        case COMPOSITING_MODE:
+            return new CompositingMode(handle);
+        case FOG:
+            return new Fog(handle);
+        case GROUP:
+            return new Group(handle);
+        case IMAGE_2D:
+            return new Image2D(handle);
+        case INDEX_BUFFER:
+            return new TriangleStripArray(handle);
+        case KEYFRAME_SEQUENCE:
+            return new KeyframeSequence(handle);
+        case LIGHT:
+            return new Light(handle);
+            //case LOADER:
+        case MATERIAL:
+            return new Material(handle);
+        case MESH:
+            return new Mesh(handle);
+        case MORPHING_MESH:
+            return new MorphingMesh(handle);
+        case POLYGON_MODE:
+            return new PolygonMode(handle);
+            //case RENDER_CONTEXT:
+        case SKINNED_MESH:
+            return new SkinnedMesh(handle);
+        case SPRITE_3D:
+            return new Sprite3D(handle);
+        case TEXTURE_2D:
+            return new Texture2D(handle);
+        case VERTEX_ARRAY:
+            return new VertexArray(handle);
+        case VERTEX_BUFFER:
+            return new VertexBuffer(handle);
+        case WORLD:
+            return new World(handle);
+        default:
+            throw new Error();
+        }
+    }
+
+    /**
+     * Registers an object with this interface. The object is added
+     * to the global handle-to-object map, and the native finalization
+     * callback is set up. The handle of the object must already be
+     * set at this point!
+     */
+    static final void register(Object obj, int handle)
+    {
+        if (obj == null || handle <= 0)
+        {
+            throw new RuntimeException("Invalid native handle");
+        }
+        Platform.registerFinalizer(obj);
+        getInstance().liveObjects.put(new Integer(handle),
+                                      new WeakReference(obj));
+    }
+
+    /**
+     * Forces removal of an object from the handle-to-object map.
+     */
+    static final void deregister(Object obj, int handle)
+    {
+        Interface instance = null;
+        try
+        {
+            instance = Interface.getInstance();
+        }
+        catch (Exception e)
+        {
+            return;
+        }
+        instance.liveObjects.remove(new Integer(handle));
+        try
+        {
+            Platform.finalizeObject(Interface.bindEventSource(), handle);
+        }
+        finally
+        {
+            Interface.releaseEventSource();
+        }
+    }
+
+    /**
+     *  Bind native event source.
+     *  @return Event source handle
+     */
+    static final int bindEventSource()
+    {
+        Interface instance = Interface.getInstance();
+        synchronized (instance)
+        {
+            if (instance.isShutdownOngoing())
+            {
+                throw new RuntimeException("Graphics3D closed");
+            }
+            instance.eventSrcHandleRefCount++;
+            return instance.getEventSourceHandle();
+        }
+    }
+
+    /**
+     *  Release native event source
+     */
+    static final void releaseEventSource()
+    {
+        Interface instance = Interface.getInstance();
+        synchronized (instance)
+        {
+            instance.eventSrcHandleRefCount--;
+            if (instance.eventSrcHandleRefCount <= 0)
+            {
+                instance.eventSrcHandleRefCount = 0;
+                instance.notifyAll();
+            }
+        }
+    }
+
+    /**
+     *  Sets shutdown indication flag. Actual native
+     *  cleanup occurs when liveObjects count is zero
+     */
+    static void signalShutdown()
+    {
+        Interface instance = Interface.getInstance();
+        synchronized (instance)
+        {
+            instance.shutdown = true;
+        }
+    }
+
+    /**
+     * Check if shtudown is ongoing
+     * @return <code>true</code> if shutdown is ongoing.
+     */
+    static boolean isShutdownOngoing()
+    {
+        Interface instance = Interface.getInstance();
+        synchronized (instance)
+        {
+            return instance.shutdown;
+        }
+    }
+
+    /**
+     * Returns handle for native event source stored
+     * in given Interaface instance
+     */
+    final int getEventSourceHandle()
+    {
+        return eventSrcHandle;
+    }
+
+
+    //------------------------------------------------------------------
+    // Private methods
+    //------------------------------------------------------------------
+
+    private void doFinalize()
+    {
+        if (mFinalizer != null)
+        {
+            registeredFinalize();
+            mFinalizer = null;
+        }
+    }
+
+    /**
+     * @see ToolkitObserver#destroyNotify()
+     */
+    public void destroyNotify()
+    {
+        registeredFinalize();
+    }
+
+    // Native finalization hook, for Symbian only
+    synchronized final private void registeredFinalize()
+    {
+        while (eventSrcHandleRefCount > 0)
+        {
+            try
+            {
+                wait();
+            }
+            catch (InterruptedException e)
+            {
+            }
+        }
+        Interface.signalShutdown();
+        if (graphics3D != null)
+        {
+            graphics3D.doDestroyNotify();
+            graphics3D = null;
+        }
+        if ((eventSrcHandle != 0) && (handle != 0))
+        {
+            // Finalize M3G interface
+            Platform.finalizeInterface(handle, eventSrcHandle);
+
+            // Finalize event source and remove singeleton reference
+            _finalizeEventSource(eventSrcHandle);
+            Interface.s_instances.remove(new Integer(toolkitHandle));
+            Interface.s_instances = null;
+            // reset handles
+            handle = 0;
+            eventSrcHandle = 0;
+        }
+        MemoryUtil.freeNativeMemory();
+    }
+
+    // Native constructor
+    private static native int _ctor(int eventSrcHandle);
+
+    // Native class ID resolver
+    private static native int _getClassID(int hObject);
+
+    // Native event source constructor
+    private static native int _initEventSource(int UIServerHandle);
+
+    // Native event source finalization
+    private static native void _finalizeEventSource(int eventSrcHandle);
+}