JNI를 이용하면 C++로 작성된 irrlicht 엔진을 Android 플랫폼에서도 돌아가게 할 수 있다.

인터넷 검색 및 삽질(-_-)끝에 알아낸 것들을 정리해둔다.

--------------------------------------------------------------

1. 프로그램 및 SDK 준비
 . Cygwin 설치
  - http://www.cygwin.com/
  - 설치시 git 플러그인을 같이 설치하는게 좋다.
    git를 이용해서 android로 포팅된 irrlicht 엔진 소스를 얻어오는데
    외부 프로그램으로 하려면 좀 귀찮아서... ㅡ,.ㅡ;
 . JDK 설치
  - http://www.oracle.com/technetwork/java/javase/downloads/index.html
 . Android SDK 설치
  - http://developer.android.com/sdk/index.html
 . Android NDK 설치
  - http://developer.android.com/sdk/ndk/index.html
  - NDK 설치 후 설치 경로를 시스템 환경변수 PATH에 추가시키자. 나중에 커맨드 칠때 편하다;

2. Android Irrlcht 소스 받기
 . Cygwin을 실행시킨 후 소스를 받을 디렉토리로 이동 후에 다음 커맨드를 입력한다.

git clone git://gitorious.org/irrlichtandroid/irrlichtandroid.git

 좀 기다리면 irrlichtandroid란 폴더에 소스가 다운받아져 있을 것이다.


3. Static Library로 빌드
 . irrlichtandroid/project/include/IrrCompileConfig.h 파일을 열어서 102번째 줄의 선언문을 다음같이 변경한다.

//++ ellis ++ // ANDROID NDK CAUSES TO BE HERE
//++ ellis ++ #define _IRR_POSIX_API_
//++ ellis ++ #define _IRR_COMPILE_WITH_X11_DEVICE_
//++ ellis ++ // Three lines added for android
#define _IRR_ANDROID_PLATEFORM_
#define _IRR_COMPILE_WITH_ANDROID_DEVICE_
#define _IRR_COMPILE_WITH_OGLES1_
// #define _IRR_COMPILE_WITH_OGLES2_  // <- 주석처리!
#define _DEBUG

  - OpenGL ES1 이나 ES2중 하나만 선택해야 빌드가 될텐데 일단 ES1으로 선택한다.
    (나중에 CreateDevice 함수로 Irrlicht Device를 만들때도 이때 선택한 그래픽옵션으로 만들어야 한다)

. irrlichtandroid/project/jni/Android.mk 파일을 다음과 같이 수정한다.

#
# COSOperator.cpp was removed from IRROTHEROBJ
LOCAL_PATH := $(call my-dir)
#
# 1. Build Static library (.a)
#
include $(CLEAR_VARS)
IRRMESHLOADER = CBSPMeshFileLoader.cpp CMD2MeshFileLoader.cpp CMD3MeshFileLoader.cpp CMS3DMeshFileLoader.cpp CB3DMeshFileLoader.cpp C3DSMeshFileLoader.cpp COgreMeshFileLoader.cpp COBJMeshFileLoader.cpp CColladaFileLoader.cpp CCSMLoader.cpp CDMFLoader.cpp CLMTSMeshFileLoader.cpp CMY3DMeshFileLoader.cpp COCTLoader.cpp CXMeshFileLoader.cpp CIrrMeshFileLoader.cpp CSTLMeshFileLoader.cpp CLWOMeshFileLoader.cpp CPLYMeshFileLoader.cpp
IRRMESHWRITER = CColladaMeshWriter.cpp CIrrMeshWriter.cpp CSTLMeshWriter.cpp COBJMeshWriter.cpp CPLYMeshWriter.cpp
IRRMESHOBJ = $(IRRMESHLOADER) $(IRRMESHWRITER) CSkinnedMesh.cpp CBoneSceneNode.cpp CMeshSceneNode.cpp CAnimatedMeshSceneNode.cpp CAnimatedMeshMD2.cpp CAnimatedMeshMD3.cpp CQ3LevelMesh.cpp CQuake3ShaderSceneNode.cpp
IRROBJ = CBillboardSceneNode.cpp CCameraSceneNode.cpp CDummyTransformationSceneNode.cpp CEmptySceneNode.cpp CGeometryCreator.cpp CLightSceneNode.cpp CMeshManipulator.cpp CMetaTriangleSelector.cpp COctreeSceneNode.cpp COctreeTriangleSelector.cpp CSceneCollisionManager.cpp CSceneManager.cpp CShadowVolumeSceneNode.cpp CSkyBoxSceneNode.cpp CSkyDomeSceneNode.cpp CTerrainSceneNode.cpp CTerrainTriangleSelector.cpp CVolumeLightSceneNode.cpp CCubeSceneNode.cpp CSphereSceneNode.cpp CTextSceneNode.cpp CTriangleBBSelector.cpp CTriangleSelector.cpp CWaterSurfaceSceneNode.cpp CMeshCache.cpp CDefaultSceneNodeAnimatorFactory.cpp CDefaultSceneNodeFactory.cpp
IRRPARTICLEOBJ = CParticleAnimatedMeshSceneNodeEmitter.cpp CParticleBoxEmitter.cpp CParticleCylinderEmitter.cpp CParticleMeshEmitter.cpp CParticlePointEmitter.cpp CParticleRingEmitter.cpp CParticleSphereEmitter.cpp CParticleAttractionAffector.cpp CParticleFadeOutAffector.cpp CParticleGravityAffector.cpp CParticleRotationAffector.cpp CParticleSystemSceneNode.cpp CParticleScaleAffector.cpp
IRRANIMOBJ = CSceneNodeAnimatorCameraFPS.cpp CSceneNodeAnimatorCameraMaya.cpp CSceneNodeAnimatorCollisionResponse.cpp CSceneNodeAnimatorDelete.cpp CSceneNodeAnimatorFlyCircle.cpp CSceneNodeAnimatorFlyStraight.cpp CSceneNodeAnimatorFollowSpline.cpp CSceneNodeAnimatorRotation.cpp CSceneNodeAnimatorTexture.cpp
IRRDRVROBJ = CNullDriver.cpp COGLESDriver.cpp COGLESTexture.cpp COGLESExtensionHandler.cpp
IRRDRVOBJ2 = COGLES2Driver.cpp COGLES2FixedPipelineShader.cpp COGLES2ParallaxMapRenderer.cpp COGLES2SLMaterialRenderer.cpp COGLES2ExtensionHandler.cpp COGLES2NormalMapRenderer.cpp COGLES2Renderer2D.cpp COGLES2Texture.cpp
IRRIMAGEOBJ = CColorConverter.cpp CImage.cpp CImageLoaderBMP.cpp CImageLoaderJPG.cpp CImageLoaderPCX.cpp CImageLoaderPNG.cpp CImageLoaderPSD.cpp CImageLoaderTGA.cpp CImageLoaderPPM.cpp CImageLoaderWAL.cpp CImageLoaderRGB.cpp CImageWriterBMP.cpp CImageWriterJPG.cpp CImageWriterPCX.cpp CImageWriterPNG.cpp CImageWriterPPM.cpp CImageWriterPSD.cpp CImageWriterTGA.cpp
IRRVIDEOOBJ = CVideoModeList.cpp CFPSCounter.cpp $(IRRDRVROBJ) $(IRRIMAGEOBJ)
IRRSWRENDEROBJ = CSoftwareDriver.cpp CSoftwareTexture.cpp CTRFlat.cpp CTRFlatWire.cpp CTRGouraud.cpp CTRGouraudWire.cpp CTRTextureFlat.cpp CTRTextureFlatWire.cpp CTRTextureGouraud.cpp CTRTextureGouraudAdd.cpp CTRTextureGouraudNoZ.cpp CTRTextureGouraudWire.cpp CZBuffer.cpp CTRTextureGouraudVertexAlpha2.cpp CTRTextureGouraudNoZ2.cpp CTRTextureLightMap2_M2.cpp CTRTextureLightMap2_M4.cpp CTRTextureLightMap2_M1.cpp CSoftwareDriver2.cpp CSoftwareTexture2.cpp CTRTextureGouraud2.cpp CTRGouraud2.cpp CTRGouraudAlpha2.cpp CTRGouraudAlphaNoZ2.cpp CTRTextureDetailMap2.cpp CTRTextureGouraudAdd2.cpp CTRTextureGouraudAddNoZ2.cpp CTRTextureWire2.cpp CTRTextureLightMap2_Add.cpp CTRTextureLightMapGouraud2_M4.cpp IBurningShader.cpp CTRTextureBlend.cpp CTRTextureGouraudAlpha.cpp CTRTextureGouraudAlphaNoZ.cpp CDepthBuffer.cpp CBurningShader_Raster_Reference.cpp
IRRIOOBJ = CFileList.cpp CFileSystem.cpp CLimitReadFile.cpp CMemoryFile.cpp CReadFile.cpp CWriteFile.cpp CXMLReader.cpp CXMLWriter.cpp CZipReader.cpp CPakReader.cpp CNPKReader.cpp CTarReader.cpp CMountPointReader.cpp irrXML.cpp CAttributes.cpp lzma/LzmaDec.c
IRROTHEROBJ = CIrrDeviceConsole.cpp CIrrDeviceStub.cpp CLogger.cpp Irrlicht.cpp os.cpp
IRRGUIOBJ = CGUIButton.cpp CGUICheckBox.cpp CGUIComboBox.cpp CGUIContextMenu.cpp CGUIEditBox.cpp CGUIEnvironment.cpp CGUIFileOpenDialog.cpp CGUIFont.cpp CGUIImage.cpp CGUIInOutFader.cpp CGUIListBox.cpp CGUIMenu.cpp CGUIMeshViewer.cpp CGUIMessageBox.cpp CGUIModalScreen.cpp CGUIScrollBar.cpp CGUISpinBox.cpp CGUISkin.cpp CGUIStaticText.cpp CGUITabControl.cpp CGUITable.cpp CGUIToolBar.cpp CGUIWindow.cpp CGUIColorSelectDialog.cpp CDefaultGUIElementFactory.cpp CGUISpriteBank.cpp CGUIImageList.cpp CGUITreeView.cpp
ZLIBOBJ = zlib/adler32.c zlib/compress.c zlib/crc32.c zlib/deflate.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c zlib/trees.c zlib/uncompr.c zlib/zutil.c
JPEGLIBOBJ = jpeglib/jcapimin.c jpeglib/jcapistd.c jpeglib/jccoefct.c jpeglib/jccolor.c jpeglib/jcdctmgr.c jpeglib/jchuff.c jpeglib/jcinit.c jpeglib/jcmainct.c jpeglib/jcmarker.c jpeglib/jcmaster.c jpeglib/jcomapi.c jpeglib/jcparam.c jpeglib/jcprepct.c jpeglib/jcsample.c jpeglib/jctrans.c jpeglib/jdapimin.c jpeglib/jdapistd.c jpeglib/jdatadst.c jpeglib/jdatasrc.c jpeglib/jdcoefct.c jpeglib/jdcolor.c jpeglib/jddctmgr.c jpeglib/jdhuff.c jpeglib/jdinput.c jpeglib/jdmainct.c jpeglib/jdmarker.c jpeglib/jdmaster.c jpeglib/jdmerge.c jpeglib/jdpostct.c jpeglib/jdsample.c jpeglib/jdtrans.c jpeglib/jerror.c jpeglib/jfdctflt.c jpeglib/jfdctfst.c jpeglib/jfdctint.c jpeglib/jidctflt.c jpeglib/jidctfst.c jpeglib/jidctint.c jpeglib/jmemmgr.c jpeglib/jmemnobs.c jpeglib/jquant1.c jpeglib/jquant2.c jpeglib/jutils.c jpeglib/jcarith.c jpeglib/jdarith.c jpeglib/jaricom.c
LIBPNGOBJ = libpng/png.c libpng/pngerror.c libpng/pngget.c libpng/pngmem.c libpng/pngpread.c libpng/pngread.c libpng/pngrio.c libpng/pngrtran.c libpng/pngrutil.c libpng/pngset.c libpng/pngtrans.c libpng/pngwio.c libpng/pngwrite.c libpng/pngwtran.c libpng/pngwutil.c
LIBAESGM = aesGladman/aescrypt.cpp aesGladman/aeskey.cpp aesGladman/aestab.cpp aesGladman/fileenc.cpp aesGladman/hmac.cpp aesGladman/prng.cpp aesGladman/pwd2key.cpp aesGladman/sha1.cpp aesGladman/sha2.cpp
BZIP2OBJ = bzip2/blocksort.c bzip2/huffman.c bzip2/crctable.c bzip2/randtable.c bzip2/bzcompress.c bzip2/decompress.c bzip2/bzlib.c
ANDROID = importgl.cpp CIrrDeviceAndroid.cpp
LOCAL_MODULE := irrlicht
LOCAL_ARM_MODE   := arm
LOCAL_CFLAGS := -O3 -DANDROID_NDK -DDISABLE_IMPORTGL -I./../include/ -I./include/
LOCAL_SRC_FILES := \
     $(ANDROID) \
     $(IRRVIDEOOBJ) $(IRRDRVOBJ2) \
     $(IRRMESHOBJ) $(IRROBJ) $(IRRPARTICLEOBJ) $(IRRANIMOBJ) \
     $(IRRSWRENDEROBJ) $(IRRIOOBJ) $(IRROTHEROBJ) \
     $(IRRGUIOBJ) $(ZLIBOBJ) $(JPEGLIBOBJ) $(LIBPNGOBJ) $(LIBAESGM) \
     $(BZIP2OBJ)
LOCAL_LDLIBS := -lGLESv1_CM -ldl -llog -lGLESv2
include $(BUILD_STATIC_LIBRARY)
#
# 2. Build Shared library (.so)
#
include $(CLEAR_VARS)
LOCAL_MODULE    := fakeIrrlicht
LOCAL_STATIC_LIBRARIES := irrlicht
include $(BUILD_SHARED_LIBRARY)

 . irrlichtandroid/project/jni 폴더로 이동한 후 ndk로 빌드하면 .a 파일이 생성!

ndk-bulid --jobs <CPU 코어수>

  - 멀티코어를 이용해서 빌드하면 빌드속도가 꽤 많이 단축되니 꼭 멀티코어 빌드로 하자.
    다만, 멀티코어 빌드시 별 이유없이 실패할 때가 있는데 그땐 그냥 obj 폴더를 지우고
    다시 빌드하면 된다. (아마도 버그인듯;)
 
 . 빌드가 성공하면 irrlichtandroid/project/obj/local/armeabi 폴더에 libirrlicht.a 파일이 생성되있을것이다.
   같이 생성된 so파일(libfakeIrrlicht.so)는 사용하지 않으니 무시할 것! (어차피 빈 껍데기 ㅋ)
 
 . irrlicht 프로젝트에서 사용하는 방법은 다음글에 계속.. 

2011/11/20 21:57 2011/11/20 21:57