diff -r ae942d28ec0e -r 2455ef1f5bbc javauis/m3g_akn/javasrc/javax/microedition/m3g/Graphics3D.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/m3g_akn/javasrc/javax/microedition/m3g/Graphics3D.java Wed Sep 01 12:33:18 2010 +0100 @@ -0,0 +1,863 @@ +/* +* Copyright (c) 2003 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 javax.microedition.lcdui.Graphics; +import java.util.Hashtable; +import java.util.Vector; +import com.nokia.mj.impl.rt.legacy.ToolkitInvoker; +import com.nokia.mj.impl.rt.legacy.ToolkitObserver; + + +public class Graphics3D +{ + //------------------------------------------------------------------ + // Static data + //------------------------------------------------------------------ + + public static final int ANTIALIAS = 2; + public static final int DITHER = 4; + public static final int TRUE_COLOR = 8; + + // M3G 1.1 + public static final int OVERWRITE = 16; + //------------------------------------------------------------------ + // Instance data + //------------------------------------------------------------------ + + int handle; + + private Camera camera = null; + private Vector lights = new Vector(); + + private java.lang.Object currentTarget = null; + private int offsetX, offsetY, hints = 0; + private boolean depthEnabled = true; + + // this flag is for identification of image target types + // - True for mutable off-screen images + // - False for canvas/GameCanvas framebuffer + private boolean isImageTarget; + + // this flag is for identification if MBX HW accelerator is present + // - True - MBX is NOT present + // - False - MBX is present + private boolean isProperRenderer; + + // NGA specific change. + // Identifies if 2D content drawn prior M3G content to canvas + // needs to be uploaded to canvas EGL surface before + // M3G binds to EGL surface. + private boolean eglContentValid = false; + + // NGA specific change. + // Class for storing and comparing + // clip and viewport rectangles + private class Rect + { + public int x; + public int y; + public int width; + public int height; + + public Rect() + { + x = 0; + y = 0; + width = 0; + height = 0; + } + + public Rect(int x, int y, int width, int height) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public boolean contains(Rect r) + { + return x <= r.x && y <= r.y && + (x + width) >= (r.x + r.width) && + (y + height) >= (r.y + r.height); + } + }; + + // NGA specific change. + // Viewport and clip are saved to Java side + // for checking if Background is used for clearing + // entire canvas area. + private Rect viewport; + private Rect clip; + private boolean ngaEnabled = false; + private boolean pendingGLESRelease = false; + + + //------------------------------------------------------------------ + // Constructor(s) + //------------------------------------------------------------------ + + /** + * + */ + public static final Graphics3D getInstance() + { + Interface instance = Interface.getInstance(); + synchronized (instance) + { + if (instance.isShutdownOngoing()) + { + throw new RuntimeException("Graphics3D closed"); + } + if (instance.graphics3D == null) + { + instance.graphics3D = new Graphics3D(); + } + return instance.graphics3D; + } + } + + /** + * + */ + private Graphics3D() + { + ToolkitInvoker invoker = ToolkitInvoker.getToolkitInvoker(); + this.handle = _ctor(Interface.getHandle()); + _addRef(handle); + try + { + isProperRenderer = _isProperRenderer(Interface.bindEventSource()); + } + finally + { + Interface.releaseEventSource(); + } + // NGA specific change. + // Initializes the viewport and clipping rectangles + this.viewport = new Rect(); + this.clip = new Rect(); + // Initializes NGA status - enabled or disabled + ngaEnabled = invoker.isNgaEnabled(); + } + + /** + * + */ + void doDestroyNotify() + { + this.camera = null; + this.lights = null; + } + + //------------------------------------------------------------------ + // Public methods + //------------------------------------------------------------------ + + /** + */ + public void bindTarget(java.lang.Object target) + { + bindTarget(target, true, 0); + } + + /** + * + */ + public void bindTarget(java.lang.Object target, boolean depth, int flags) + { + synchronized (Interface.getInstance()) + { + integrityCheck(); + int eventSrcHandle = 0; + if (currentTarget != null) + { + throw new IllegalStateException(); + } + + if (target == null) + { + throw new NullPointerException(); + } + try + { + // Bind event source. This need to be released. + eventSrcHandle = Interface.bindEventSource(); + if (target instanceof Graphics) + { + Graphics g = (Graphics) target; + Platform.sync(g); + + if (g.getClipWidth() > Defs.MAX_VIEWPORT_WIDTH || + g.getClipHeight() > Defs.MAX_VIEWPORT_HEIGHT) + { + throw new IllegalArgumentException(); + } + + offsetX = g.getTranslateX(); + offsetY = g.getTranslateY(); + + ToolkitInvoker invoker = ToolkitInvoker.getToolkitInvoker(); + + // NGA specific change. + if (ngaEnabled) + { + // If overwrite is set, there is no need + // to update EGL surface with 2D content + eglContentValid = (flags & OVERWRITE) > 0; + + // Clip and viewport are stored for later + // checks regarding Background clear + clip.x = g.getClipX() + offsetX; + clip.y = g.getClipY() + offsetY; + clip.width = g.getClipWidth(); + clip.height = g.getClipHeight(); + + viewport.x = clip.x; + viewport.y = clip.y; + viewport.width = clip.width; + viewport.height = clip.height; + + isImageTarget = _bindGraphics( + eventSrcHandle, + handle, + invoker.graphicsGetHandle(g), + clip.x, clip.y, + clip.width, clip.height, + depth, flags, + isProperRenderer); + } + else + { + isImageTarget = _bindGraphics( + eventSrcHandle, + handle, + invoker.graphicsGetHandle(g), + g.getClipX() + offsetX, g.getClipY() + offsetY, + g.getClipWidth(), g.getClipHeight(), + depth, flags, + isProperRenderer); + } + currentTarget = g; + } + else if (target instanceof Image2D) + { + Image2D img = (Image2D) target; + + offsetX = offsetY = 0; + + _bindImage(eventSrcHandle, handle, img.handle, depth, flags); + currentTarget = img; + } + else + { + throw new IllegalArgumentException(); + } + } + finally + { + // Release event source + Interface.releaseEventSource(); + } + hints = flags; + depthEnabled = depth; + } + } + + /** + * + */ + public void releaseTarget() + { + synchronized (Interface.getInstance()) + { + integrityCheck(); + if (currentTarget == null) + { + return; + } + + int eventSrcHandle = 0; + + try + { + // Bind event source + eventSrcHandle = Interface.bindEventSource(); + if (currentTarget instanceof Graphics) + { + Graphics g = (Graphics) currentTarget; + + ToolkitInvoker invoker = ToolkitInvoker.getToolkitInvoker(); + + // NGA specific change. + if (ngaEnabled) + { + updateEglContent(); + } + _releaseGraphics(eventSrcHandle, handle, + invoker.graphicsGetHandle(g), isImageTarget, isProperRenderer); + } + else if (currentTarget instanceof Image2D) + { + _releaseImage(eventSrcHandle, handle); + } + else + { + throw new Error(); + } + } + finally + { + currentTarget = null; + + if (ngaEnabled && + pendingGLESRelease && + eventSrcHandle != 0) + { + pendingGLESRelease = false; + _freeGLESResources(eventSrcHandle, handle); + } + + // Release event source + Interface.releaseEventSource(); + } + } + } + + /** + * + */ + public void setViewport(int x, int y, int width, int height) + { + integrityCheck(); + if (width <= 0 || height <= 0 + || width > Defs.MAX_VIEWPORT_DIMENSION + || height > Defs.MAX_VIEWPORT_DIMENSION) + { + throw new IllegalArgumentException(); + } + + // NGA specific change. + if (ngaEnabled) + { + // Update the viewport info. + viewport.x = x + offsetX; + viewport.y = y + offsetY; + viewport.width = width; + viewport.height = height; + _setViewport(handle, viewport.x, viewport.y, viewport.width, viewport.height); + } + else + { + _setViewport(handle, x + offsetX, y + offsetY, width, height); + } + } + + /** + * + */ + public void clear(Background background) + { + integrityCheck(); + if (getTarget() == null) + { + throw new java.lang.IllegalStateException( + "Graphics3D does not have a rendering target"); + } + // NGA specific change. + if (ngaEnabled) + { + checkBackgroundCleared(background); + } + try + { + _clear(Interface.bindEventSource(), + handle, background != null ? background.handle : 0); + } + finally + { + Interface.releaseEventSource(); + } + } + + /** + * + */ + public void render(World world) + { + integrityCheck(); + // NGA specific change. + if (ngaEnabled) + { + checkBackgroundCleared(world.getBackground()); + } + try + { + _renderWorld(Interface.bindEventSource(), handle, world.handle); + } + finally + { + Interface.releaseEventSource(); + } + } + + /** + * + */ + public void render(VertexBuffer vertices, + IndexBuffer primitives, + Appearance appearance, + Transform transform) + { + // Call rendering method with default visibility + render(vertices, primitives, appearance, transform, -1); + } + + /** + * + */ + public void render(VertexBuffer vertices, + IndexBuffer primitives, + Appearance appearance, + Transform transform, + int scope) + { + + // null pointer exceptions thrown automatically below + integrityCheck(); + + // NGA specific change. + if (ngaEnabled) + { + updateEglContent(); + } + try + { + _render(Interface.bindEventSource(), + handle, + vertices.handle, + primitives.handle, + appearance.handle, + transform != null ? transform.matrix : null, + scope); + } + finally + { + Interface.releaseEventSource(); + } + } + + /** + * + */ + public void render(Node node, Transform transform) + { + if (!(node instanceof Mesh + || node instanceof Sprite3D + || node instanceof Group) + && node != null) + { + throw new IllegalArgumentException(); + } + integrityCheck(); + + // NGA specific change. + if (ngaEnabled) + { + updateEglContent(); + } + try + { + _renderNode(Interface.bindEventSource(), + handle, + node.handle, + transform != null ? transform.matrix : null); + } + finally + { + Interface.releaseEventSource(); + } + } + + public void setCamera(Camera camera, Transform transform) + { + integrityCheck(); + _setCamera(handle, + camera != null ? camera.handle : 0, + transform != null ? transform.matrix : null); + + this.camera = camera; + } + + /** + */ + public int addLight(Light light, Transform transform) + { + integrityCheck(); + int index = _addLight(handle, + light.handle, + transform != null ? transform.matrix : null); + if (lights.size() < index + 1) + { + lights.setSize(index + 1); + } + lights.setElementAt(light, index); + return index; + } + + /** + * + */ + public void setLight(int index, Light light, Transform transform) + { + integrityCheck(); + _setLight(handle, + index, + light != null ? light.handle : 0, + transform != null ? transform.matrix : null); + lights.setElementAt(light, index); + } + + /** + */ + public void resetLights() + { + integrityCheck(); + _resetLights(handle); + lights.removeAllElements(); + } + + /** + * + */ + public static final Hashtable getProperties() + { + Hashtable props = new Hashtable(); + + props.put("supportAntialiasing", new java.lang.Boolean( + _isAASupported(Interface.getHandle()))); + props.put("supportTrueColor", new java.lang.Boolean(Defs.supportTrueColor)); + props.put("supportDithering", new java.lang.Boolean(Defs.supportDithering)); + props.put("supportMipmapping", new java.lang.Boolean(Defs.supportMipmapping)); + props.put("supportPerspectiveCorrection", new java.lang.Boolean(Defs.supportPerspectiveCorrection)); + props.put("supportLocalCameraLighting", new java.lang.Boolean(Defs.supportLocalCameraLighting)); + props.put("maxLights", new java.lang.Integer(Defs.MAX_LIGHTS)); + props.put("maxViewportWidth", new java.lang.Integer(Defs.MAX_VIEWPORT_WIDTH)); + props.put("maxViewportHeight", new java.lang.Integer(Defs.MAX_VIEWPORT_HEIGHT)); + props.put("maxViewportDimension", new java.lang.Integer(Defs.MAX_VIEWPORT_DIMENSION)); + props.put("maxTextureDimension", new java.lang.Integer(Defs.MAX_TEXTURE_DIMENSION)); + props.put("maxSpriteCropDimension", new java.lang.Integer(Defs.MAX_TEXTURE_DIMENSION)); + props.put("numTextureUnits", new java.lang.Integer(Defs.NUM_TEXTURE_UNITS)); + props.put("maxTransformsPerVertex", new java.lang.Integer(Defs.MAX_TRANSFORMS_PER_VERTEX)); + + // Extra properties + props.put("m3gRelease", new java.lang.String("04_wk49")); + + return props; + } + + /** + * + */ + public void setDepthRange(float near, float far) + { + integrityCheck(); + _setDepthRange(handle, near, far); + } + + // M3G 1.1 + + public Camera getCamera(Transform transform) + { + integrityCheck(); + if (transform != null) + { + _getViewTransform(handle, transform.matrix); + } + + return (Camera) Object3D.getInstance(_getCamera(handle)); + } + + public float getDepthRangeFar() + { + integrityCheck(); + return _getDepthRangeFar(handle); + } + + public float getDepthRangeNear() + { + integrityCheck(); + return _getDepthRangeNear(handle); + } + + public Light getLight(int index, Transform transform) + { + integrityCheck(); + if (index < 0 || index >= _getLightCount(handle)) + { + throw new IndexOutOfBoundsException(); + } + + return (Light) Object3D.getInstance(_getLightTransform(handle, + index, + transform != null ? transform.matrix : null)); + } + + public int getLightCount() + { + integrityCheck(); + return _getLightCount(handle); + } + + public java.lang.Object getTarget() + { + return currentTarget; + } + + public int getViewportHeight() + { + integrityCheck(); + return _getViewportHeight(handle); + } + + public int getViewportWidth() + { + integrityCheck(); + return _getViewportWidth(handle); + } + + public int getViewportX() + { + integrityCheck(); + return _getViewportX(handle) - offsetX; + } + + public int getViewportY() + { + integrityCheck(); + return _getViewportY(handle) - offsetY; + } + + public int getHints() + { + return hints; + } + + public boolean isDepthBufferEnabled() + { + return depthEnabled; + } + + // M3G 1.1 getters END + + //------------------------------------------------------------------ + // Native implementation methods + //------------------------------------------------------------------ + + // Finalization method for Symbian + final private void registeredFinalize() + { + // NOP -- handled via ToolkitObserver + } + + private void integrityCheck() + { + if (Interface.isShutdownOngoing()) + { + throw new RuntimeException("Graphics3D closed"); + } + } + + /** + * NGA specific change. + * Checks if Background is used for clearing the full graphics target area. + * If so, the 2D content prior to M3G content does not need to be + * uploaded to EGL surface. + */ + private void checkBackgroundCleared(Background bg) + { + if (!isCanvasTarget()) + { + return; + } + if (bg != null && bg.isColorClearEnabled() && !eglContentValid) + { + Graphics g = (Graphics)currentTarget; + int graphicsHandle = ToolkitInvoker.getToolkitInvoker().graphicsGetHandle(g); + int targetWidth = _getTargetWidth(graphicsHandle); + int targetHeight = _getTargetHeight(graphicsHandle); + Rect targetRect = new Rect(0, 0, targetWidth, targetHeight); + + // Checks that target is fully covered by graphics clip and viewport + eglContentValid = viewport.contains(targetRect) && clip.contains(targetRect); + } + if (!eglContentValid) + { + updateEglContent(); + } + } + + /** + * NGA specific change. + * Checks if the rendering target is a Graphics instance obtained from LCDUI Canvas. + * @return true if the target is Canvas Graphics. + */ + private boolean isCanvasTarget() + { + return (currentTarget != null) && + (currentTarget instanceof Graphics) && + !isImageTarget; + } + + /** + * NGA specific change. + * Notifies the native side that egl content need to be updated + * thanks to 2d mixture + */ + private void updateEglContent() + { + if (isCanvasTarget() && !eglContentValid) + { + Graphics g = (Graphics)currentTarget; + int graphicsHandle = ToolkitInvoker.getToolkitInvoker().graphicsGetHandle(g); + try + { + _updateEglContent(Interface.bindEventSource(), graphicsHandle); + eglContentValid = true; + } + finally + { + Interface.releaseEventSource(); + } + } + } + + void freeGraphicsMemory() + { + synchronized (Interface.getInstance()) + { + if (!ngaEnabled) + { + return; + } + + if (currentTarget == null) + { + pendingGLESRelease = false; + try + { + _freeGLESResources(Interface.bindEventSource(), handle); + } + finally + { + Interface.releaseEventSource(); + } + } + else + { + pendingGLESRelease = true; + } + } + } + + private native static int _ctor(int hInterface); + private native static void _addRef(int hObject); + + private native static int _addLight(int handle, + int hLight, + byte[] transform); + + private native static boolean _bindGraphics(int eventSourceHandle, + int handle, + int graphicsHandle, + int clipX, int clipY, + int clipW, int clipH, + boolean depth, + int hintBits, + boolean aIsProperRenderer); + private native static void _bindImage(int eventSourceHandle, int handle, int imgHandle, boolean depth, int hintBits); + + private native static void _releaseGraphics(int eventSourceHandle, + int handle, + int graphicsHandle, + boolean aIsImageTarget, + boolean aIsProperRenderer); + private native static void _releaseImage(int eventSourceHandle, int handle); + private native static void _resetLights(int handle); + + private native static void _clear(int eventSourceHandle, int handle, int hBackground); + + private native static void _render(int eventSourceHandle, + int handle, + int hVtxBuffer, + int hIdxBuffer, + int hAppearance, + byte[] transform, + int scope); + private native static void _renderNode(int eventSourceHandle, int handle, int hNode, byte[] transform); + private native static void _renderWorld(int eventSourceHandle, int handle, int hWorld); + + private native static void _setCamera(int handle, + int hCamera, + byte[] transform); + private native static void _setViewport(int handle, + int x, int y, + int width, int height); + private native static void _setLight(int handle, + int index, + int hLight, + byte[] transform); + private native static void _setDepthRange(int handle, + float near, + float far); + + // M3G 1.1 + // Maintenance release getters + + private native static void _getViewTransform(int handle, + byte[] transform); + private native static int _getCamera(int handle); + private native static int _getLightTransform(int handle, + int index, + byte[] transform); + private native static int _getLightCount(int handle); + private native static float _getDepthRangeNear(int handle); + private native static float _getDepthRangeFar(int handle); + private native static int _getViewportX(int handle); + private native static int _getViewportY(int handle); + private native static int _getViewportWidth(int handle); + private native static int _getViewportHeight(int handle); + + /* Statistics support, MUST be disabled in official releases! */ + /* + public native static int getStatistics(int[] statistics); + */ + private native static boolean _isAASupported(int handle); + + private native static boolean _isProperRenderer(int handle); + + // NGA specific changes. + private native static int _getTargetHeight(int graphicsHandle); + private native static int _getTargetWidth(int graphicsHandle); + private native static void _updateEglContent(int eventSourceHandle, + int graphicsHandle); + private native static void _freeGLESResources(int eventSourceHandle, + int handle); +}