在J2ME里可以使用M3G(即JSR184)可选包来开发3D应用,大家都知道。而我想把J2ME上开发的3D游戏移植到ANDROID上,如果直接用OpenGL ES,由于它没有M3G中封装好的一些责成的框架和算法,需要自己重新开发的东西比较多,所以想要是能直接在ANDROID中用M3G就好了。
在网上找了一些资料,有一个帖子给出了如下示例代码,由两个文件组成:
M3GTestView.java (作为被显示的View):
package org.vgvp.m3g;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.m3g.Appearance;
import javax.microedition.m3g.Camera;
import javax.microedition.m3g.Graphics3D;
import javax.microedition.m3g.Group;
import javax.microedition.m3g.Image2D;
import javax.microedition.m3g.IndexBuffer;
import javax.microedition.m3g.Light;
import javax.microedition.m3g.Mesh;
import javax.microedition.m3g.Texture2D;
import javax.microedition.m3g.TriangleStripArray;
import javax.microedition.m3g.VertexArray;
import javax.microedition.m3g.VertexBuffer;
import javax.microedition.m3g.World;import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;public class M3GTestView extends SurfaceView implements SurfaceHolder.Callback{ private final float TOUCH_SCALE_FACTOR=180.0f/320; protected SurfaceHolder mHolder; protected RenderThreadX mRenderThread; private float mPreviousX=0.0f; private float mPreviousY=0.0f; public M3GTestView(Context context){ super(context); setFocusable(true); requestFocus(); mHolder = getHolder(); //南京航空航天大学 臧春杰 mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.d("HelloWorld", "surfaceChanged"); } public void surfaceCreated(SurfaceHolder holder) { mRenderThread = new RenderThreadX(this); mRenderThread.start(); } public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true; while (retry) { try { mRenderThread.join(); retry = false; } catch (InterruptedException e) { } } mRenderThread.endEGL(); } public boolean onTouchEvent(MotionEvent e) { float x = e.getX(); float y = e.getY(); switch (e.getAction()) { case MotionEvent.ACTION_MOVE: { float dx = x - mPreviousX; float dy = y - mPreviousY; float xAngle=dx*TOUCH_SCALE_FACTOR; float yAngle=dy*TOUCH_SCALE_FACTOR; mRenderThread.reDrawScene(xAngle,yAngle); } } mPreviousX = x; mPreviousY = y; return true; }}class RenderThreadX extends Thread
{ /** Handle to the surface manager object we interact with */ private SurfaceHolder mSurfaceHolder; private M3GTestView mView; private boolean mRun = false; private EGL10 egl; private EGLDisplay display; private EGLSurface surface; private GL10 gl; private EGLContext glc; // JSR184 private World mWorld = null; private Camera mCamera; private Graphics3D mG3d; private Light mLight; private Light mLight_Ab; private Group mAllMesh; private Image2D[] image2D; private Texture2D[] texture;
public RenderThreadX(M3GTestView view) { super(); mView = view; mSurfaceHolder = mView.mHolder; mG3d = Graphics3D.getInstance(); mWorld=new World(); mCamera=new Camera(); mLight = new Light(); mLight_Ab = new Light(); } public void run() { initMesh(); initEGL(); DrawScene(); SwapBuffer(); } private void initMesh(){ int width = mView.getWidth(); int height = mView.getHeight(); float aspect = (float)width/(float)height; mCamera.setPerspective(60, aspect, 1, 100); mCamera.setTranslation(0, 0, 10); mWorld.addChild(mCamera); mWorld.setActiveCamera(mCamera); mAllMesh = new Group(); mWorld.addChild(mAllMesh); Mesh blueMesh = MeshFactory3D.createCube(); Mesh cubeMesh = null; cubeMesh = (Mesh)blueMesh.duplicate(); mAllMesh.addChild(cubeMesh); cubeMesh.postRotate(45, 1, 1, 1); } private void initEGL(){ egl = (EGL10) EGLContext.getEGL(); display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); int[] version = new int[2]; egl.eglInitialize(display, version); int[] configSpec = { EGL10.EGL_RED_SIZE, 5, EGL10.EGL_GREEN_SIZE, 6, EGL10.EGL_BLUE_SIZE, 5, EGL10.EGL_ALPHA_SIZE, 0, EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_STENCIL_SIZE, 0, EGL10.EGL_NONE}; EGLConfig[] configs = new EGLConfig[1]; int[] numConfig = new int[1]; egl.eglChooseConfig(display, configSpec, configs, 1, numConfig); EGLConfig config = configs[0]; glc = egl.eglCreateContext(display, config,EGL10.EGL_NO_CONTEXT, null); surface = egl.eglCreateWindowSurface(display, config, mView.getHolder(), null); egl.eglMakeCurrent(display, surface, surface, glc); Log.d("EGL", "EGL CONFIG SET END" ); gl = (GL10) (glc.getGL()); gl.glViewport(0, 0, mView.getWidth(), mView.getHeight()); Log.d("EGL","mView.getWidth() = "+mView.getWidth()+", mView.getHeight() = "+mView.getHeight()); gl.glHint(GL10.GL_POLYGON_SMOOTH_HINT , GL10.GL_NICEST); // anti-alias } public void endEGL() { Log.d("EGL","endEGL"); // Free OpenGL resources egl.eglMakeCurrent(display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); egl.eglDestroySurface(display, surface); egl.eglDestroyContext(display, glc); egl.eglTerminate(display); } protected void SwapBuffer(){ egl.eglSwapBuffers(display, surface); } // RenderScene public void DrawScene() { mG3d.render(mWorld); } public void reDrawScene(float xAngel,float yAngel){ mAllMesh.postRotate(xAngel,0.0f,1.0f,0.0f); mAllMesh.postRotate(yAngel,1.0f,0.0f,0.0f); }}class MeshFactory3D { /** * Constructor has private access because class contains static * methods exclusively. */ private MeshFactory3D() {} public static Mesh createCube() { VertexBuffer vertexBuffer = new VertexBuffer(); byte[] positions = { -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, // front 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, // back 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, // right -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, // left -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, // top -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1 // bottom };
VertexArray vertexPositions = new VertexArray(positions.length/3, 3, 1); vertexPositions.set(0, positions.length/3, positions);
vertexBuffer.setPositions(vertexPositions, 1, null); int[] triangleLengths = {4, 4, 4, 4, 4, 4}; IndexBuffer triangleInfo=new TriangleStripArray(0,triangleLengths); return new Mesh(vertexBuffer, triangleInfo,new Appearance()); }}
TestM3G.java (作为主Activity) :
package org.vgvp.m3g;import android.app.Activity;
import android.os.Bundle;public class TestM3G extends Activity { M3GTestView view = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
view = new M3GTestView(this);
setContentView(view);
}}
(AndroidManifest.xml略)并且在JAVA Build Path中添加了jsr-184.jar包,可以成功编译生成。但是跟踪执行发现,当程序运行到mG3d = Graphics3D.getInstance();这句时出现运行时错误。用adb logcat输出的相关错误栈信息如下:E/AndroidRuntime( 1716): Uncaught handler: thread main exiting due to uncaught exceptionE/AndroidRuntime( 1716): java.lang.ExceptionInInitializerErrorE/AndroidRuntime( 1716): at org.vgvp.m3g.RenderThreadX.<init>(M3GTestView.java:192)… …E/AndroidRuntime( 1716): Caused by: java.lang.UnsatisfiedLinkError: cacheFIDE/AndroidRuntime( 1716): at javax.microedition.m3g.Engine.cacheFID(Native Method)E/AndroidRuntime( 1716): at javax.microedition.m3g.Graphics3D.<clinit>(Graphics3D.java:791)E/AndroidRuntime( 1716): ... 26 more有哪位大虾能告诉我这是什么原因?在ANDROID里到底怎么能用上M3G呢?
在网上找了一些资料,有一个帖子给出了如下示例代码,由两个文件组成:
M3GTestView.java (作为被显示的View):
package org.vgvp.m3g;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.m3g.Appearance;
import javax.microedition.m3g.Camera;
import javax.microedition.m3g.Graphics3D;
import javax.microedition.m3g.Group;
import javax.microedition.m3g.Image2D;
import javax.microedition.m3g.IndexBuffer;
import javax.microedition.m3g.Light;
import javax.microedition.m3g.Mesh;
import javax.microedition.m3g.Texture2D;
import javax.microedition.m3g.TriangleStripArray;
import javax.microedition.m3g.VertexArray;
import javax.microedition.m3g.VertexBuffer;
import javax.microedition.m3g.World;import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;public class M3GTestView extends SurfaceView implements SurfaceHolder.Callback{ private final float TOUCH_SCALE_FACTOR=180.0f/320; protected SurfaceHolder mHolder; protected RenderThreadX mRenderThread; private float mPreviousX=0.0f; private float mPreviousY=0.0f; public M3GTestView(Context context){ super(context); setFocusable(true); requestFocus(); mHolder = getHolder(); //南京航空航天大学 臧春杰 mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.d("HelloWorld", "surfaceChanged"); } public void surfaceCreated(SurfaceHolder holder) { mRenderThread = new RenderThreadX(this); mRenderThread.start(); } public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true; while (retry) { try { mRenderThread.join(); retry = false; } catch (InterruptedException e) { } } mRenderThread.endEGL(); } public boolean onTouchEvent(MotionEvent e) { float x = e.getX(); float y = e.getY(); switch (e.getAction()) { case MotionEvent.ACTION_MOVE: { float dx = x - mPreviousX; float dy = y - mPreviousY; float xAngle=dx*TOUCH_SCALE_FACTOR; float yAngle=dy*TOUCH_SCALE_FACTOR; mRenderThread.reDrawScene(xAngle,yAngle); } } mPreviousX = x; mPreviousY = y; return true; }}class RenderThreadX extends Thread
{ /** Handle to the surface manager object we interact with */ private SurfaceHolder mSurfaceHolder; private M3GTestView mView; private boolean mRun = false; private EGL10 egl; private EGLDisplay display; private EGLSurface surface; private GL10 gl; private EGLContext glc; // JSR184 private World mWorld = null; private Camera mCamera; private Graphics3D mG3d; private Light mLight; private Light mLight_Ab; private Group mAllMesh; private Image2D[] image2D; private Texture2D[] texture;
public RenderThreadX(M3GTestView view) { super(); mView = view; mSurfaceHolder = mView.mHolder; mG3d = Graphics3D.getInstance(); mWorld=new World(); mCamera=new Camera(); mLight = new Light(); mLight_Ab = new Light(); } public void run() { initMesh(); initEGL(); DrawScene(); SwapBuffer(); } private void initMesh(){ int width = mView.getWidth(); int height = mView.getHeight(); float aspect = (float)width/(float)height; mCamera.setPerspective(60, aspect, 1, 100); mCamera.setTranslation(0, 0, 10); mWorld.addChild(mCamera); mWorld.setActiveCamera(mCamera); mAllMesh = new Group(); mWorld.addChild(mAllMesh); Mesh blueMesh = MeshFactory3D.createCube(); Mesh cubeMesh = null; cubeMesh = (Mesh)blueMesh.duplicate(); mAllMesh.addChild(cubeMesh); cubeMesh.postRotate(45, 1, 1, 1); } private void initEGL(){ egl = (EGL10) EGLContext.getEGL(); display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); int[] version = new int[2]; egl.eglInitialize(display, version); int[] configSpec = { EGL10.EGL_RED_SIZE, 5, EGL10.EGL_GREEN_SIZE, 6, EGL10.EGL_BLUE_SIZE, 5, EGL10.EGL_ALPHA_SIZE, 0, EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_STENCIL_SIZE, 0, EGL10.EGL_NONE}; EGLConfig[] configs = new EGLConfig[1]; int[] numConfig = new int[1]; egl.eglChooseConfig(display, configSpec, configs, 1, numConfig); EGLConfig config = configs[0]; glc = egl.eglCreateContext(display, config,EGL10.EGL_NO_CONTEXT, null); surface = egl.eglCreateWindowSurface(display, config, mView.getHolder(), null); egl.eglMakeCurrent(display, surface, surface, glc); Log.d("EGL", "EGL CONFIG SET END" ); gl = (GL10) (glc.getGL()); gl.glViewport(0, 0, mView.getWidth(), mView.getHeight()); Log.d("EGL","mView.getWidth() = "+mView.getWidth()+", mView.getHeight() = "+mView.getHeight()); gl.glHint(GL10.GL_POLYGON_SMOOTH_HINT , GL10.GL_NICEST); // anti-alias } public void endEGL() { Log.d("EGL","endEGL"); // Free OpenGL resources egl.eglMakeCurrent(display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); egl.eglDestroySurface(display, surface); egl.eglDestroyContext(display, glc); egl.eglTerminate(display); } protected void SwapBuffer(){ egl.eglSwapBuffers(display, surface); } // RenderScene public void DrawScene() { mG3d.render(mWorld); } public void reDrawScene(float xAngel,float yAngel){ mAllMesh.postRotate(xAngel,0.0f,1.0f,0.0f); mAllMesh.postRotate(yAngel,1.0f,0.0f,0.0f); }}class MeshFactory3D { /** * Constructor has private access because class contains static * methods exclusively. */ private MeshFactory3D() {} public static Mesh createCube() { VertexBuffer vertexBuffer = new VertexBuffer(); byte[] positions = { -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, // front 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, // back 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, // right -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, // left -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, // top -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1 // bottom };
VertexArray vertexPositions = new VertexArray(positions.length/3, 3, 1); vertexPositions.set(0, positions.length/3, positions);
vertexBuffer.setPositions(vertexPositions, 1, null); int[] triangleLengths = {4, 4, 4, 4, 4, 4}; IndexBuffer triangleInfo=new TriangleStripArray(0,triangleLengths); return new Mesh(vertexBuffer, triangleInfo,new Appearance()); }}
TestM3G.java (作为主Activity) :
package org.vgvp.m3g;import android.app.Activity;
import android.os.Bundle;public class TestM3G extends Activity { M3GTestView view = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
view = new M3GTestView(this);
setContentView(view);
}}
(AndroidManifest.xml略)并且在JAVA Build Path中添加了jsr-184.jar包,可以成功编译生成。但是跟踪执行发现,当程序运行到mG3d = Graphics3D.getInstance();这句时出现运行时错误。用adb logcat输出的相关错误栈信息如下:E/AndroidRuntime( 1716): Uncaught handler: thread main exiting due to uncaught exceptionE/AndroidRuntime( 1716): java.lang.ExceptionInInitializerErrorE/AndroidRuntime( 1716): at org.vgvp.m3g.RenderThreadX.<init>(M3GTestView.java:192)… …E/AndroidRuntime( 1716): Caused by: java.lang.UnsatisfiedLinkError: cacheFIDE/AndroidRuntime( 1716): at javax.microedition.m3g.Engine.cacheFID(Native Method)E/AndroidRuntime( 1716): at javax.microedition.m3g.Graphics3D.<clinit>(Graphics3D.java:791)E/AndroidRuntime( 1716): ... 26 more有哪位大虾能告诉我这是什么原因?在ANDROID里到底怎么能用上M3G呢?
原帖作者已经给出的程序源码就是我帖出的这些,只字未提如何实现底层的内容,说明肯定是有现成的库。 你这句话提醒我了,我直接把WTK里的JSR184包放到ANDROID工程的BUILD PATH中肯定不行啊,看来一定有针对ANDROID平台的JSR184包