2012年8月18日土曜日

Android NDK で ffmpeg ライブラリをビルド

とりあえず、手順だけメモ。
色々納得できないので、要継続調査。

  • NEON 有効
  • スタティックライブラリ生成
  • ダイナミックライブラリ生成
  • x264 ライブラリを利用

git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg

commit 7e49474aa02e93ba2d80b330cba1ec38f4c4f3ee
Date:   Sat Aug 18 05:02:58 2012 +0200

configure を修正

$ git diff configure
diff --git a/configure b/configure
index 679fae0..1591f4f 100755
--- a/configure
+++ b/configure
@@ -1949,7 +1949,7 @@ cc_default="gcc"
 cxx_default="g++"
 host_cc_default="gcc"
 install="install"
-ln_s="ln -sf"
+ln_s="cp -f"
 nm_default="nm"
 objformat="elf"
 pkg_config_default=pkg-config
@@ -3956,7 +3956,7 @@ YASM=$yasmexe
 DEPYASM=$yasmexe
 AR=$ar
 RANLIB=$ranlib
-CP=cp -p
+CP=cp -fp
 LN_S=$ln_s
 STRIP=$strip
 CPPFLAGS=$CPPFLAGS

configure 実行

TEMPDIR=`cygpath -m /tmp` \
./configure \
--sysroot=`cygpath -m $SYSROOT` \
--cross-prefix=arm-linux-androideabi- \
--enable-cross-compile \
--target-os=linux \
--arch=arm \
--cpu=cortex-a8 \
--extra-cflags='-I../x264 -mfloat-abi=softfp -mfpu=neon' \
--extra-ldflags='-L../x264 -Wl,--fix-cortex-a8' \
--enable-libx264 \
--enable-shared \
--disable-stripping \
--enable-gpl \
--enable-version3 \
--disable-doc \
--disable-htmlpages \
--disable-manpages \
--disable-podpages \
--disable-txtpages \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-avdevice \
--disable-network \
--disable-devices \
--disable-protocols \
--enable-protocol=file

config.h を修正

#define CC_IDENT "gcc 4.4.3^M (GCC)"
↓
#define CC_IDENT "gcc 4.4.3 (GCC)"

config.mak を修正

CC_IDENT=gcc 4.4.3^M (GCC)
↓
CC_IDENT=gcc 4.4.3 (GCC)

ビルド実行

make -j4
「-j4」は、並列ビルドオプション。

インストール

install -m 644 libavfilter/libavfilter.a "/usr/local/lib"
install -m 755 libavfilter/libavfilter.so "/usr/local/lib/libavfilter.so.3.10.100"

install -m 644 libavformat/libavformat.a "/usr/local/lib"
install -m 755 libavformat/libavformat.so "/usr/local/lib/libavformat.so.54.25.100"

install -m 644 libavcodec/libavcodec.a "/usr/local/lib"
install -m 755 libavcodec/libavcodec.so "/usr/local/lib/libavcodec.so.54.53.100"

install -m 644 libpostproc/libpostproc.a "/usr/local/lib"
install -m 755 libpostproc/libpostproc.so "/usr/local/lib/libpostproc.so.52.0.100"

install -m 644 libswresample/libswresample.a "/usr/local/lib"
install -m 755 libswresample/libswresample.so "/usr/local/lib/libswresample.so.0.15.100"

install -m 644 libswscale/libswscale.a "/usr/local/lib"
install -m 755 libswscale/libswscale.so "/usr/local/lib/libswscale.so.2.1.101"

install -m 644 libavutil/libavutil.a "/usr/local/lib"
install -m 755 libavutil/libavutil.so "/usr/local/lib/libavutil.so.51.70.100"

install -m 644 libavfilter/asrc_abuffer.h libavfilter/avcodec.h libavfilter/avfilter.h libavfilter/avfiltergraph.h libavfilter/buffersink.h libavfilter/buffersrc.h libavfilter/version.h "/usr/local/include/libavfilter"
install -m 644 libavfilter/libavfilter.pc "/usr/local/lib/pkgconfig"

install -m 644 libavformat/avformat.h libavformat/avio.h libavformat/version.h "/usr/local/include/libavformat"
install -m 644 libavformat/libavformat.pc "/usr/local/lib/pkgconfig"

install -m 644 libavcodec/avcodec.h libavcodec/avfft.h libavcodec/dxva2.h libavcodec/old_codec_ids.h libavcodec/vaapi.h libavcodec/vda.h libavcodec/vdpau.h libavcodec/version.h libavcodec/xvmc.h "/usr/local/include/libavcodec"
install -m 644 libavcodec/libavcodec.pc "/usr/local/lib/pkgconfig"

install -m 644 libpostproc/postprocess.h "/usr/local/include/libpostproc"
install -m 644 libpostproc/libpostproc.pc "/usr/local/lib/pkgconfig"

install -m 644 libswresample/swresample.h "/usr/local/include/libswresample"
install -m 644 libswresample/libswresample.pc "/usr/local/lib/pkgconfig"

install -m 644 libswscale/swscale.h libswscale/version.h "/usr/local/include/libswscale"
install -m 644 libswscale/libswscale.pc "/usr/local/lib/pkgconfig"

install -m 644 libavutil/adler32.h libavutil/aes.h libavutil/attributes.h libavutil/audio_fifo.h libavutil/audioconvert.h libavutil/avassert.h libavutil/avstring.h libavutil/avutil.h libavutil/base64.h libavutil/blowfish.h libavutil/bprint.h libavutil/bswap.h libavutil/common.h libavutil/cpu.h libavutil/crc.h libavutil/error.h libavutil/eval.h libavutil/fifo.h libavutil/file.h libavutil/imgutils.h libavutil/intfloat.h libavutil/intfloat_readwrite.h libavutil/intreadwrite.h libavutil/lfg.h libavutil/log.h libavutil/lzo.h libavutil/mathematics.h libavutil/md5.h libavutil/mem.h libavutil/dict.h libavutil/opt.h libavutil/parseutils.h libavutil/pixdesc.h libavutil/pixfmt.h libavutil/random_seed.h libavutil/rational.h libavutil/samplefmt.h libavutil/sha.h libavutil/time.h libavutil/timecode.h libavutil/timestamp.h libavutil/version.h libavutil/xtea.h libavutil/avconfig.h "/usr/local/include/libavutil"
install -m 644 libavutil/libavutil.pc "/usr/local/lib/pkgconfig"

Android NDK で x264 ライブラリをビルド

git clone git://git.videolan.org/x264.git
cd x264
CFLAGS='-march=armv7-a -mtune=cortex-a8 -mfloat-abi=softfp -mfpu=neon' \
LDFLAGS='-Wl,--fix-cortex-a8' \
./configure --disable-cli --enable-shared --enable-static --host=arm-linux-androideabi --cross-prefix=arm-linux-androideabi-
make -j4
NEON を利用する。(-mfpu=neon)
実行ファイルは、生成しない。(--disable-cli)
ダイナミックリンクライブラリを生成。(--enable-shared)
スタティックリンクライブラリを生成。(--enable-static)
並列ビルド(-j4)

ビルドしたバージョン
commit 5f615f7f93d830e55e6fe4f04d214b93d8cb4b53
Date:   Tue Jul 10 14:10:44 2012 -0700

2012年8月13日月曜日

Android NDK で COLLADA DOM を使ってみる【基本設定編】

目的

Android NDK で COLLADA dom ライブラリをビルド - TOP」でビルドした、COLLADA DOM ライブラリを、実際に使ってみる。

最初は、基本的な設定を行う。これらの設定は、NativeActivity を利用して、C/C++ だけで、Android のアプリを作成するために行う。

はじめに

COLLADA DOM ライブラリは、ビルド済みで、同一ワークスペースに存在する前提とする。
COLLADA DOM で読み込む、モデルデータファイルは、Blender のエクスポートを利用して出力した。
出力されたモデルデータのバージョンは 1.4.1 となっている。

当方、C/C++ の知識は、「お遊びレベル」で、Android での「プログラミング経験無し」、さらには、「COLLADA DOMって何?おいしいの?」っていう状態ゆえに、内容については、参考程度と心得られたし。あしからず。

プロジェクト作成

「Android Application Project」を作成

「File」メニュー⇒「New」⇒「Other」を選択。
「Android」⇒「Android Application Project」を選択し、「Next」ボタンを押下。

「New Android Application」ダイアログ

Application Name:「ColladaSandbox」
Project Name:「ColladaSandbox」
Package Name:「foobar.colladasandbox」
Build SDK:「Android 2.3.1 (API 9)」
Minimum Required SDK:「API 9: Android 2.3 (Gingerbread)」
「Next」ボタンを押下。

「Configure Launcher Icon」ダイアログ

値を、任意に変更して(デフォルトのままでも可)、「Next」ボタンを押下。

「Create Activity」ダイアログ

「Create Activity」チェックボックスを外す。
(Java の Activity は利用せず、C の NativeActivity だけで実装するための設定。)
「Finish」ボタンを押下。

「C++ Project」へ変換


「ColladaSandbox」プロジェクトを選択し、「File」メニュー⇒「New」⇒「Other」を選択。
 「C/C++」⇒「Convert to a C/C++ Project (Adds C/C++ Nature)」を選択し、「Next」ボタンを押下。

Convert to C or C++:「C++ Project」を選択
Project options:「Specify project type」チェックボックスをチェックする。
Project type:「Makefile project」を選択
Toolchains:「-- Other Toolchain --」を選択
「Finish」ボタンを押下。

「C/C++」パースペクティブに変更

「Window」メニュー⇒「Perspective」⇒「Other」を選択。
「C/C++」を選択し、「OK」ボタンを押下。

ビルド設定

「ColladaSandbox」プロジェクトを選択し、「File」メニュー⇒「New」⇒「Folder」を選択。
Folder name:「jni」
「Finish」ボタンを押下。

「ColladaSandbox」プロジェクトを選択し、「Project」メニュー⇒「Properties」を選択

「C/C++ Build」


「Builder Settings」タブ
「Use default build command」チェックボックスのチェックを外す。
Build command:「${CYGWIN_HOME}/bin/bash ${NDKROOT}/ndk-build NDK_DEBUG=1 V=1」
Build directory:「${workspace_loc:/ColladaSandbox/jni}」
(「Workspace...」ボタンを押下、「ColladaSandbox」プロジェクトの「jni」ディレクトリを選択して、「OK」ボタンを押下。)

「Behaviour」タブ
Use parallel build:チェックする。
Use parallel jobs:4
(ビルド処理を並列化する。マルチコアマシンの場合に設定)
Build (Incremental build):チェックボックスは、チェックしたまま、デフォルトの"all"文字列を削除して、空にする。
「OK」ボタンを押下。

「C/C++ General」⇒「Paths and Symbols」

「Includes」タブ
Include の設定は、必須ではないが、補完機能などが利用できるので、設定しておく。
設定するパスは、ターゲットにする SDK のバージョンや、標準C++ライブラリなどによって異なる。

・「Assembly」
何も無し

・「GNU C」
${NDKROOT}/platforms/android-9/arch-arm/usr/include
${NDKROOT}/sources/android/native_app_glue

・「GNU C++」
${NDKROOT}/platforms/android-9/arch-arm/usr/include
${NDKROOT}/sources/cxx-stl/gnu-libstdc++/include
${NDKROOT}/sources/android/native_app_glue
/ColladaDom/jni/include
/ColladaDom/jni/include/1.4

ColladaDom のインクルード定義は、「Is a workspace path」チェックボックスをチェックした状態で追加した。「Workspace」ボタンを押下して選択すると、自動的にチェックが付く。


アプリ設定

「AndroidManifest.xml」ファイルを開く。

「Application」タブ

「ApplicationAttributes」エリア
Debuggable:「true」
Has code:「false」

「Application Nodes」エリア
・「Activity」定義を追加
「Add」ボタンを押下。
「Activity」を選択し、「OK」ボタンを押下。
「Activity」属性に以下の値を設定。
Name:「android.app.NativeActivity」

・アプリのライブラリ名定義を追加
「Activity」を選択して、「Add」ボタンを押下。
「Meta Data」を選択して、「OK」ボタンを押下。
「Meta Data」属性 Name:「android.app.lib_name」
「Meta Data」属性に以下の値を設定。
Value:「ColladaSandbox」
(ビルド後にできる、libColladaSandbox.so ファイルの lib と .so を除いた値を設定する)

・「Intent Filter」定義を追加
「Add」ボタンを押下。
「Intent Filter」を選択し、「OK」ボタンを押下。
属性の設定は、無し。

・「Action」定義を追加
「Intent Filter」を選択して、「Add」ボタンを押下。
「Action」を選択して、「OK」ボタンを押下。
「Action」属性に以下の値を設定。
Name:「android.intent.action.MAIN」

・「Category」定義を追加
「Intent Filter」を選択して、「Add」ボタンを押下。
「Category」を選択して、「OK」ボタンを押下。
「Category」属性に以下の値を設定。
Name:「android.intent.category.LAUNCHER」


「Permissions」タブ

パーミッションには、アプリで必要なものを設定する。
今回は、SDカードにファイルを書き出すための、パーミッションを設定する。
「Add」ボタンを押下。
「Uses Permission」を選択して、「OK」ボタンを押下。
「Uses Permission」属性に以下の値を設定。
Name:「android.permission.WRITE_EXTERNAL_STORAGE」

設定後の「AndroidManifest.xml」は、こんな風になった。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="foobar.colladasandbox"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="15" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application android:label="@string/app_name"
        android:icon="@drawable/ic_launcher"
        android:theme="@style/AppTheme" android:hasCode="false" android:debuggable="true">
        <activity android:name="android.app.NativeActivity">
            <meta-data android:name="android.app.lib_name" android:value="ColladaSandbox"/>
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

    </application>

</manifest>


Android NDK で COLLADA DOM を使ってみる【実践編】

目的

Android NDK で COLLADA dom ライブラリをビルド - TOP」でビルドした、COLLADA DOM ライブラリを、実際に使ってみる。

Android ネイティブアプリ作成の基本的なことは、習得済みという前提で、COLLADA DOM ライブラリを利用する部分だけを、ピックアップして説明する。
ただし、今回は、ファイルのロードと、セーブのみ。OpenGL ES での表示は、行わないこととする。

基本的な設定については、「Android NDK で COLLADA DOM を使ってみる【基本設定編】」に記載してある。

モデルデータ

モデルデータは、Blender で生成したものを利用する。
他にも、「COLLADA Model Bank」のサイトで、モデルデータをダウンロードするなどの手段がある。

ファイル名は、「sample.dae」とし、「assets」ディレクトリに格納することとする。

Makefile 作成

Android.mk ファイルの方は、COLLADA DOM のインクルードパスおよび、ライブラリパスが、フルパス指定になっているので、各自の環境に合わせて修正する必要がある。

【jni/Application.mk】

APP_MODULES := ColladaSandbox
APP_ABI := armeabi-v7a
APP_PLATFORM := android-9
APP_STL := gnustl_static

【jni/Android.mk】

LOCAL_PATH := $(call my-dir)

#
# ColladaSandbox
#
include $(CLEAR_VARS)
LOCAL_MODULE := ColladaSandbox
LOCAL_ARM_MODE := arm
LOCAL_CPPFLAGS := -fexceptions
# COLLADA_DOM_SUPPORT141 を定義しないと、DAE.load() 実行時に次のようなエラーとなる。
# 「libc(7688): Fatal signal 11 (SIGSEGV) at 0x656c6962 (code=1)」
LOCAL_CPPFLAGS += -DCOLLADA_DOM_SUPPORT141

LOCAL_SRC_FILES := $(wildcard *.c *.cpp)
LOCAL_C_INCLUDES := \
    E:/work/Repositories/git/ColladaDom/ColladaDom/jni/include \
    E:/work/Repositories/git/ColladaDom/ColladaDom/jni/include/1.4 \
    E:/work/Repositories/git/ColladaDom/ColladaDom/jni/external-libs/boost

LOCAL_STATIC_LIBRARIES := \
    android_native_app_glue

LOCAL_LDLIBS := \
    -LE:/work/Repositories/git/ColladaDom/ColladaDom/obj/local/armeabi-v7a \
    -lcollada_dom \
    -lcollada_STLDatabase \
    -lcollada_stdErrPlugin \
    -lpcrecpp \
    -lpcre \
    -ltinyxml \
    -lminizip \
    -lboost_filesystem \
    -lboost_system \
    -llog \
    -landroid \
    -lEGL \
    -lGLESv1_CM \
    -lz \
    -lgnustl_static

include $(BUILD_SHARED_LIBRARY)

$(call import-module,android/native_app_glue)

COLLADA DOM ログ出力

COLLADA DOM には、エラー出力機能をプラグインできる機能がある、デフォルトでは、標準出力にログが出る。
そのログを、LogCat に出力するように、プラグインを作成する。
ただ、今のところ、ログが出力されたところを、見たことが無い・・・

【jni/LogCatErrorHandler.h】

/*
 * LogCatErrorHandler.h
 */

#ifndef LOGCATERRORHANDLER_H_
#define LOGCATERRORHANDLER_H_
#include <dae/daeErrorHandler.h>
namespace AndroidUtility {

class DLLSPEC LogCatErrorHandler: public daeErrorHandler {
public:
    LogCatErrorHandler();
    virtual
    ~LogCatErrorHandler();

public:
    void
    handleError(daeString msg);
    void
    handleWarning(daeString msg);
};

} /* namespace AndroidUtility */
#endif /* LOGCATERRORHANDLER_H_ */

【jni/LogCatErrorHandler.cpp】

/*
 * LogCatErrorHandler.cpp
 */

#include <android/log.h>
#include <dae/daeTypes.h>
#include "LogCatErrorHandler.h"

#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "LogCatErrorHandler", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "LogCatErrorHandler", __VA_ARGS__))

namespace AndroidUtility {

LogCatErrorHandler::LogCatErrorHandler() {
}

LogCatErrorHandler::~LogCatErrorHandler() {
}

void LogCatErrorHandler::handleError(daeString msg) {
    LOGE("%s", msg);
}

void LogCatErrorHandler::handleWarning(daeString msg) {
    LOGW("%s", msg);
}
}
/* namespace AndroidUtility */

メイン処理

メイン処理は、NDK に付属する「native_app_glue」を利用する、これは、「native_activity」をラッピングし、より手軽に実装できるようにしたもの。
実装は、NDK に付属してきたサンプルプロジェクト「native-activity」の「main.c」を変更して行った。
160行目あたりにサブ処理を呼び出す部分がある。

【jni/main.c】

/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
/*
 * AbsoluteArea has modified this file.
 * The original license is provided above for reference and legal purposes.
 */

#include <jni.h>
#include <errno.h>

#include <EGL/egl.h>
#include <GLES/gl.h>

#include <android/log.h>
#include <android_native_app_glue.h>

#include "Sub.h"

#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "main", __VA_ARGS__))

struct saved_state {
    float angle;
    int32_t x;
    int32_t y;
};

struct engine {
    struct android_app* app;

    int animating;
    EGLDisplay display;
    EGLSurface surface;
    EGLContext context;
    int32_t width;
    int32_t height;
    struct saved_state state;
};

static int engine_init_display(struct engine* engine) {
    const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE,
            8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE };
    EGLint w, h, dummy, format;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;

    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(display, 0, 0);
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
    eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
    ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);

    surface = eglCreateWindowSurface(display, config, engine->app->window,
            NULL);
    context = eglCreateContext(display, config, NULL, NULL);

    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
        LOGW("Unable to eglMakeCurrent");
        return -1;
    }

    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);

    engine->display = display;
    engine->context = context;
    engine->surface = surface;
    engine->width = w;
    engine->height = h;
    engine->state.angle = 0;

    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
    glEnable(GL_CULL_FACE);
    glShadeModel(GL_SMOOTH);
    glDisable(GL_DEPTH_TEST);

    return 0;
}

static void engine_draw_frame(struct engine* engine) {
    if (engine->display == NULL) {
        return;
    }
    glClearColor(((float) engine->state.x) / engine->width, engine->state.angle,
            ((float) engine->state.y) / engine->height, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    eglSwapBuffers(engine->display, engine->surface);
}

static void engine_term_display(struct engine* engine) {
    if (engine->display != EGL_NO_DISPLAY) {
        eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
                EGL_NO_CONTEXT);
        if (engine->context != EGL_NO_CONTEXT) {
            eglDestroyContext(engine->display, engine->context);
        }
        if (engine->surface != EGL_NO_SURFACE) {
            eglDestroySurface(engine->display, engine->surface);
        }
        eglTerminate(engine->display);
    }
    engine->animating = 0;
    engine->display = EGL_NO_DISPLAY;
    engine->context = EGL_NO_CONTEXT;
    engine->surface = EGL_NO_SURFACE;
}

static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
    struct engine* engine = (struct engine*) app->userData;
    switch (cmd) {
    case APP_CMD_SAVE_STATE:
        engine->app->savedState = malloc(sizeof(struct saved_state));
        *((struct saved_state*) engine->app->savedState) = engine->state;
        engine->app->savedStateSize = sizeof(struct saved_state);
        break;
    case APP_CMD_INIT_WINDOW:
        if (engine->app->window != NULL) {
            engine_init_display(engine);
            engine_draw_frame(engine);
        }
        break;
    case APP_CMD_TERM_WINDOW:
        engine_term_display(engine);
        break;
    case APP_CMD_LOST_FOCUS:
        engine->animating = 0;
        engine_draw_frame(engine);
        break;
    }
}

void android_main(struct android_app* state) {
    struct engine engine;
    app_dummy();
    memset(&engine, 0, sizeof(engine));
    state->userData = &engine;
    state->onAppCmd = engine_handle_cmd;
    engine.app = state;

    if (state->savedState != NULL) {
        engine.state = *(struct saved_state*) state->savedState;
    }

    /* COLLADA DOM LOAD AND SAVE */
    init(state->activity->assetManager);
    loadModel();
    saveModel(state->activity->externalDataPath);
    cleanup();

    while (1) {
        int ident;
        int events;
        struct android_poll_source* source;
        while ((ident = ALooper_pollAll(engine.animating ? 0 : -1, NULL,
                &events, (void**) &source)) >= 0) {
            if (source != NULL) {
                source->process(state, source);
            }
            if (state->destroyRequested != 0) {
                engine_term_display(&engine);
                return;
            }
        }
        if (engine.animating) {
            engine_draw_frame(&engine);
        }
    }
}

サブ処理

サブ処理には、COLLADA DOM の操作部分を記述してある。

【jni/Sub.h】

/*
 * Sub.h
 */

#ifndef SUB_H_
#define SUB_H_
#include <android/asset_manager.h>
#ifdef __cplusplus
#include "LogCatErrorHandler.h"
using namespace AndroidUtility;

class Sub {
private:
    DAE *dae;
    AAssetManager *asset_manager;
public:
    Sub(AAssetManager *asset_manager);
    ~Sub();
    void loadModel();
    void saveModel(const char *externalDataPath);
};

extern "C" {
#endif /* __cplusplus */

extern void init(AAssetManager *asset_manager);
extern void loadModel();
extern void saveModel(const char *externalDataPath);
extern void cleanup();

#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SUB_H_ */

【jni/Sub.cpp】

/*
 * Sub.cpp
 */

#include <stdio.h>
#include <dae.h>
#include <dom/domCOLLADA.h>
#include <android/log.h>
#include <android/asset_manager.h>
#include "Sub.h"
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "Sub", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "Sub", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "Sub", __VA_ARGS__))
using namespace AndroidUtility;

/*
 * Sub class
 */
Sub::Sub(AAssetManager *asset_manager) {
    this->asset_manager = asset_manager;
    dae = new DAE();
}

Sub::~Sub() {
    delete dae;
}

void Sub::loadModel() {
    // Asset から、モデルデータを読み込む
    AAsset *model = AAssetManager_open(asset_manager, "sample.dae", AASSET_MODE_UNKNOWN);
    size_t size = AAsset_getLength(model);
    char *buffer = new char[size + 1];
    AAsset_read(model, buffer, size);

    LOGI("Before geometry count [%d]", dae->getDatabase()->getElementCount(NULL, "geometry", NULL));

    // 第一引数の URI は、データの識別子であり、unload の引数や、load、save 時のファイル名にもなる。
    // ただし、第二引数に、読込み済みモデルデータを渡した場合、ファイルからではなく、第二引数のデータを利用する。
    int iRet = dae->load("file:///sample.dae", buffer);
    if(DAE_OK != iRet) {
        // 読込みに失敗した場合
        LOGE("Load error [%d]", iRet);
        return;
    }

    LOGI("After geometry count [%d]", dae->getDatabase()->getElementCount(NULL, "geometry", NULL));

    delete buffer;
    AAsset_close(model);
}

void Sub::saveModel(const char *externalDataPath) {
    // ICONIA TAB A700 の「externalDataPath」は、
    // "/mnt/sdcard/Android/data/foobar.colladasandbox/files"になっている。
    LOGI("externalDataPath=%s", externalDataPath);
    char *uri;
    // 保存場所は、環境に合わせて変更すること。
    sprintf(uri, "file://%s%s", externalDataPath, "/../../../../sample2.dae");
    LOGI("saveURI=%s", uri);
    int iRet = dae->saveAs(uri, "file:///sample.dae", true);
    LOGI("iRet [%d], %s", iRet, strerror(errno));
    if(DAE_OK != iRet) {
        // なぜだか、保存に失敗しても、DAE_OK が返ってくる。なんでだんべ・・・
        LOGE("Failed to save the file.");
    }
}

/*
 * 以下、main.c から呼び出される関数
 */

Sub *sub;

extern "C" {
void init(AAssetManager *asset_manager) {
    sub = new Sub(asset_manager);
    // COLLADA DOM に、エラーハンドラを設定
    // ただ、今のところ、メッセージが出力された所を、見たことが無い・・・
    LogCatErrorHandler *errHandler = new LogCatErrorHandler();
    daeErrorHandler::setErrorHandler(errHandler);
    // ログを出力してみる
    daeErrorHandler::get()->handleWarning("LogCatErrorHandler READY!!!");
}

void loadModel() {
    sub->loadModel();
}

void saveModel(const char *externalDataPath) {
    sub->saveModel(externalDataPath);
}

void cleanup() {
    // アプリケーションが、終了する前の大掃除
    DAE::cleanup();
}

}

最終的にプロジェクトツリーは、こんな風になった。

2012年8月11日土曜日

Android NDK で COLLADA dom ライブラリをビルド - tinyxml ビルド用設定


Android NDK で COLLADA dom ライブラリをビルド - pcre ビルド用設定


Android NDK で COLLADA dom ライブラリをビルド - minizip ビルド用設定


Android NDK で COLLADA dom ライブラリをビルド - boost ビルド用設定


Android NDK で COLLADA dom ライブラリをビルド - ビルド用プロジェクトを作成


Android NDK で COLLADA dom ライブラリをビルド - 必要なもの


Android NDK で COLLADA dom ライブラリをビルド - TOP


Android NDK で COLLADA dom ライブラリをビルド - ビルド実行


2012年8月4日土曜日

ICONIA TAB A700 の USB ドライバインストールで泣いた

書いておいてなんだが。この方法は、お勧めできない。真似しちゃダメ、ゼッタイ。

環境
Windows Vista Business 64ビット SP2


 ICONIA TAB A700 を、Tegra3 研究開発用に買ってきたのだが、肝心の UBS ドライバをインストールできない。
発売後、しばらく acer の日本語ページには、USB ドライバがなく、ドライバをインストールする前、耐え切れずに USB 接続をしてしまった、せいかもしれない。

しかも、ドライバのインストーラーのエラー表示では、XP およびWindows7 以外には、対応していないようにも、読み取れた。「けっ、Vista は味噌っかすかよっ!」って。
でも、インストール途中で、インストールディレクトリをのぞくと、Vista のドライバも入っているぞと。

で、強硬手段に打って出た。
エラー表示ダイアログを閉じると、インストール先のファイルが、きれいさっぱり消されてしまうので、
開いたままにして。
デバイスマネージャから、A700 デバイスのドライバを更新を実行。
ドライバを手動で選択するようにして、上記のインストール先を指定して実行。
これで、とりあえずはドライバがインストールできる。
ただし、アンインストールとかできなくなる。

自己責任でどうぞ。