質問: ### 前提・質問内容 Androidのプログラミングに興味を持って趣味でJavaを触り 手探りでまだまだ知識は浅く日々勉強しながら、調べながらも 簡単なアプリは作ってみたりもしました。 そんな時にOpenGL ESというものがあることを知って 興味を持ったので早速やってみたいと思って以下の2つの書籍を購入しました。 「マルチプラットフォームのためのOpenGL ES入門 基礎編」 「マルチプラットフォームのためのOpenGL ES入門 応用編」 上記の本はサンプルファイル(Eclipseで作られている)が付録についており それを基にして学んでいくスタイルです。 そのサンプルプログラムを見て思ったのですが 上記の本のプログラミングはすべてC言語で記載されている上に 補助関数として筆者が作成した関数まであるそうです。 私はAndroid Studioを用いているのでEclipseを取り込んでビルドすると エラーの無間地獄にはまってしまいエラー解決は断念しました。 となると一から作る必要があると思うのですが 私は趣味でプログラミングをしている身で JavaしかやっていないためC言語はほとんどわかりません。 そのため「基礎編」の一番しょっぱなのサンプルである スケルトンプログラム(初期化しただけの真っ暗な画面)からお手上げ状態です。 そこで質問としてお聞きしたいのはC言語で記載されているものを どうやったらJavaで動かすことができるかです。 まずはスケルトンプログラムが動かないことには進まないと思うので どうやったらC言語で書かれているものを基に 一からJavaで作ることができるのか教えていただけたらと思います。 ### 該当のソースコード 以下が書籍の基礎編のスケルトンプログラムに必要な ヘッダファイルとC言語のファイルです。 「マルチプラットフォームのためのOpenGL ES入門 基礎編」より引用しました。 support.h↓ ``` #ifndef OpenGL_ES_20_support_h #define OpenGL_ES_20_support_h #include #include #include #include #include #include #ifdef __APPLE__ #ifdef __OBJC__ #define CSTR2NSSTRING(c_str) [[NSString alloc] initWithUTF8String:c_str] // Objective-C source #define __log(message) NSLog(@message) #define __logf(fmt, ...) NSLog(@fmt, __VA_ARGS__) #else // C Source #define __log(message) printf("%s\n", message) #define __logf(fmt, ...) printf(fmt "\n", __VA_ARGS__) #endif #else // ANDROID #include #define __LOG_TAG "GLES20" #define __log(msg) __android_log_print(ANDROID_LOG_DEBUG, __LOG_TAG, "%s", msg) #define __logf(...) __android_log_print(ANDROID_LOG_DEBUG, __LOG_TAG, __VA_ARGS__) #endif /** * アプリを強制停止させる(対応してないextension解説等) */ #define GLAPP_FLAG_ABORT (0x1 << 2) struct GLApplication; /** * アプリの初期化を行う */ typedef void (*GLApplication_initialize)(struct GLApplication *app); /** * アプリの非同期処理を行う */ typedef void (*GLApplication_async)(struct GLApplication *app); /** * レンダリングエリアが変更された */ typedef void (*GLApplication_surface_changed)(struct GLApplication *app); /** * アプリのレンダリングを行う * 毎秒60回前後呼び出される。 */ typedef void (*GLApplication_rendering)(struct GLApplication *app); /** * アプリのデータ削除を行う */ typedef void (*GLApplication_destroy)(struct GLApplication *app); /** * アプリに与えられるデータ * プラットフォームごとに適当な拡張を行なっている。 */ typedef struct GLApplication { /** * View(レンダリングターゲット)の幅 */ int surface_width; /** * View(レンダリングターゲット)の高さ */ int surface_height; /** * アプリ実行フラグ */ int flags; /** * プラットフォーム固有データを格納する。 * サンプルアプリから扱う必要はない。 */ void* platform; /** * 初期化関数 */ GLApplication_initialize initialize; /** * 非同期処理 */ GLApplication_async async; /** * サーフェイスサイズ変更関数 */ GLApplication_surface_changed resized; /** * レンダリング関数 */ GLApplication_rendering rendering; /** * 解放関数 */ GLApplication_destroy destroy; /** * サンプルごとの拡張データ保持用変数。 * 自由に構造体等をallocして利用する。 * XXX_destroy時に必ずfreeを行うこと。 */ void* extension; } GLApplication; /** * ファイルのフルパス -> ファイル名に変換する('/'区切り専用) */ extern char* util_getFileName(char* __file__); /** * ダイアログを出して実行を停止する */ extern void GLApplication_abortWithMessage(GLApplication *app, const char* message); /** * アプリ実行を停止している場合はapp_TRUE */ extern bool GLApplication_isAbort(GLApplication *app); /** * ファイル系サポート関数 */ #include "support_RawData.h" /** * GL系サポート関数宣言 */ #include "support_gl.h" #endif ``` sample_skelton.c↓ ``` #include "support.h" /** * アプリの初期化を行う */ void sample_Skelton_initialize(GLApplication *app) { __log("initialize"); } /** * レンダリングエリアが変更された */ void sample_Skelton_resized(GLApplication *app) { __logf("resized(%d x %d)", app->surface_width, app->surface_height); } /** * アプリのレンダリングを行う * 毎秒60回前後呼び出される。 */ void sample_Skelton_rendering(GLApplication *app) { // __log("rendering"); } /** * アプリのデータ削除を行う */ void sample_Skelton_destroy(GLApplication *app) { __log("destroy"); } ```
回答: AndroidではOpenGL ESのAPIが提供されてます。Javaで書けます(シェーダコード除く)。 リファレンスはこちら。 私は数年前にOpenGL ES2.0での実装経験しかありませんが、こんな感じで書きます。 手元のソースから抜粋: ``` // ActivityとView : import android.opengl.GLSurfaceView; : public class GameActivity extends Activity { // GLビュー private GLView glView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); : // GLビュー glView = new GLView(stageData, screenMode, animation); : } private class GLView extends GLSurfaceView { // メインのレンダラ private GameRenderer gr; public GLView(ClusterStageData stageData, int screenMode, boolean animation) { super(GameActivity.this); gr = new GameRenderer(GameActivity.this, stageData, screenMode, animation, new GLColor(0.0076f, 0.0076f, 0.2025f, 1.0f)); setEGLContextClientVersion(2); setRenderer(gr); } } } ``` ``` // レンダラ : import android.opengl.GLES20; import android.opengl.GLSurfaceView.Renderer; import android.opengl.GLUtils; import android.opengl.Matrix; : final class GameRenderer implements Renderer { /** * 頂点シェーダ。変換行列*座標データの形式 */ private static final String VERTEX_SHADER_CODE = "attribute vec4 vPos;" + "uniform mat4 vModelviewM;" + "attribute vec4 uvPos;" + "uniform mat4 uvTranslateM;" + "varying vec2 uvFPos;" + "void main() {" + "gl_Position = vModelviewM * vPos;" + "uvFPos = vec2(uvTranslateM * uvPos);" + "}"; : @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { GLES20.glClearColor(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), bgColor.getAlpha()); // シェーダを作成し、プログラム開始 int vertexShader = Utility.loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_CODE); int fragmentShader = Utility.loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_CODE); : } : @Override public void onDrawFrame(GL10 gl) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); GLES20.glUseProgram(program); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTexture); : } : } ``` 流れとしては`android.opengl.GLSurfaceView`に描画時に呼ばれる`onDrawFrame`などを提供する`android.opengl.GLSurfaceView.Renderer`の実装を渡す感じです。 そしてレンダラの中でOpenGL ESのAPIを色々使います。ここまでの流れはGoogleなどで検索すればたくさん出てくると思います。 以降は、私もやりたいことのCのソースやOpenGL ESのリファレンスとにらめっこしてJavaで実装していったという感じです。基本的にはCと同じ名前のAPIがあるので、それを使えば大丈夫です。 最近はAndroidのAPIはOpenGL ES3.2まで対応しているようなので違う部分があるかもしれませんし、実装方法も変わってるかもしれませんが、私も趣味でいじった程度なのであまり詳しくありません...。