5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Live2DWallpaperに背景を表示する

Last updated at Posted at 2015-10-01

開発環境

Live2D Android SDK 2.0.05_1のliveWallpaperプロジェクト
MacでEclipse4.2

Androidの壁紙の背景設定

「Live2D Android SDKで壁紙の設定方法がわからない」と困っている人がいたのでちょっとやり方を調べてみました。
 → How to set image as background in Live Wallpaper?

SurfaceViewを使っているので背景表示もOpenGLでやる必要があります。
ちなみにLive2DのAndroid版はOpenGL1.0を使ってました(OpenGL2.0を使ってないのは、古い端末に対応するための名残り?)

SampleApp1プロジェクトからコピーして、比較的簡単に実装する方法がわかったのでメモしておきます。
liveWallpaperでのやり方を書きますが、SDK内のsimpleプロジェクトも同様な手順で背景表示できます。

liveWallpaperの修正手順

1)sample/sampleApp1からsrc/jp/live2d/utils/androidをコピーする

2)sample/sampleApp1からsrc/jp/live2d/sample/LAppDefine.javaをコピーする

3)sample/sampleApp1からassets/image/back_class_normal.pngをコピーする

img_packageexplorer.png

4)LiveWallpaperService.javaを修正(修正箇所はAdd Codeとコメント入れました)

LiveWallpaperService.java
/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */
package jp.live2d.sample;


import jp.live2d.utils.android.FileManager;
import android.view.MotionEvent;
import net.rbgrn.android.glwallpaperservice.*;

public class LiveWallpaperService extends GLWallpaperService {

	public LiveWallpaperService() {
		super();
	}

	public Engine onCreateEngine() {
		MyEngine engine = new MyEngine();
		return engine;
	}

	class MyEngine extends GLEngine {
		Live2DRenderer renderer;

		public MyEngine() {
			super();
			// handle prefs, other initialization
			renderer = new Live2DRenderer(getApplicationContext());
			setRenderer(renderer);
			setRenderMode(RENDERMODE_CONTINUOUSLY);
			// Add Code Start
			FileManager.init(getApplicationContext());
			// Add Code End
		}

		@Override
		public void onTouchEvent(MotionEvent event) {
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				break;
			case MotionEvent.ACTION_UP:
				renderer.resetDrag();
				break;
			case MotionEvent.ACTION_MOVE:
				renderer.drag(event.getX(), event.getY());
				break;
			case MotionEvent.ACTION_CANCEL:
				break;
			}
		}

		public void onDestroy() {
			super.onDestroy();
			if (renderer != null) {
				renderer.release();
			}
			renderer = null;
		}
	}
}

5)Live2DRenderer.javaを修正(修正箇所はAdd Codeとコメント入れました)
 gl.glOrthof()を2回使い無理やりな気がするのでOpenGL的には正しくないかもですが、一応これでAndroidアプリが作れるかと思います。

Live2DRenderer.java
/**
 *
 *  You can modify and use this source freely
 *  only for the development of application related Live2D.
 *
 *  (c) Live2D Inc. All rights reserved.
 */
 package jp.live2d.sample;

import java.io.IOException;
import java.io.InputStream;

import jp.live2d.android.Live2DModelAndroid;
import jp.live2d.android.UtOpenGL;
import jp.live2d.framework.L2DPhysics;
import jp.live2d.framework.L2DStandardID;
import jp.live2d.framework.L2DTargetPoint;
import jp.live2d.motion.Live2DMotion;
import jp.live2d.motion.MotionQueueManager;
import jp.live2d.utils.android.FileManager;
import jp.live2d.utils.android.SimpleImage;
import android.content.Context;
import android.content.res.AssetManager;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import net.rbgrn.android.glwallpaperservice.*;

public class Live2DRenderer implements GLWallpaperService.Renderer
{
	Context con;

	Live2DModelAndroid	live2DModel ;
	Live2DMotion motion;
	MotionQueueManager motionMgr;
	L2DTargetPoint dragMgr;
	L2DPhysics physics;

	final String MODEL_PATH = "epsilon/Epsilon.moc" ;
	final String TEXTURE_PATHS[] =
		{
			"epsilon/Epsilon.1024/texture_00.png" ,
			"epsilon/Epsilon.1024/texture_01.png" ,
			"epsilon/Epsilon.1024/texture_02.png"
		} ;
	final String MOTION_PATH="epsilon/motions/Epsilon_idle_01.mtn";
	final String PHYSICS_PATH="epsilon/Epsilon.physics.json";

	float glWidth=0;
	float glHeight=0;

	// Add Code Start
	private SimpleImage bg;// BackGround Image
	private float modelWidth = 0;
	private float aspect = 0;
	// Add Code End

	public Live2DRenderer(Context context)
	{
		con = context;
		dragMgr=new L2DTargetPoint();
		motionMgr=new MotionQueueManager();
	}


	public void onDrawFrame(GL10 gl) {
        // Your rendering code goes here
		gl.glMatrixMode(GL10.GL_MODELVIEW ) ;
		gl.glLoadIdentity() ;
		gl.glClear( GL10.GL_COLOR_BUFFER_BIT ) ;
		// Add Code Start
		bg.draw(gl);	// background image draw
		// Live2D model adjust
		gl.glScalef(2.4f, 2.4f, 2.4f); // scale(x, y, z)
		gl.glTranslatef(0.0f, -0.3f, 0.0f);	// position(x, y, z)
		gl.glOrthof(0 ,	modelWidth , modelWidth / aspect , 0 , 0.5f , -0.5f ) ;
		// Add Code End

		live2DModel.loadParam();

		if(motionMgr.isFinished())
		{
			motionMgr.startMotion(motion, false);
		}
		else
		{
			motionMgr.updateParam(live2DModel);
		}

		live2DModel.saveParam();

		dragMgr.update();

		float dragX=dragMgr.getX();
		float dragY=dragMgr.getY();
		live2DModel.addToParamFloat(L2DStandardID.PARAM_ANGLE_X, dragX*30);
		live2DModel.addToParamFloat(L2DStandardID.PARAM_ANGLE_Y, dragY*30);
		live2DModel.addToParamFloat(L2DStandardID.PARAM_BODY_ANGLE_X, dragX*10);

		physics.updateParam(live2DModel);

		live2DModel.setGL( gl ) ;

		live2DModel.update() ;
		live2DModel.draw() ;

    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {
		gl.glViewport( 0 , 0 , width , height ) ;

		gl.glMatrixMode( GL10.GL_PROJECTION ) ;
		gl.glLoadIdentity() ;

		// Add Code Start
		modelWidth = live2DModel.getCanvasWidth();
		aspect = (float)width/height;
//		gl.glOrthof(
//				0 ,
//				modelWidth ,
//				modelWidth * height / width,
//				0 ,
//				0.5f ,	-0.5f
//				) ;
//		gl.glOrthof(0, modelWidth, modelWidth * height / width, 0, 0.5f, -0.5f);
		// background image adjust
		gl.glOrthof(-2.0f ,	2.0f , -2.0f ,2.0f , 0.5f , -0.5f ) ;
		// Add Code End

		glWidth=width;
		glHeight=height;
    }

    public void onSurfaceCreated(GL10 gl, EGLConfig config)
    {
    	AssetManager mngr = con.getAssets();
		try
		{
			InputStream in = mngr.open( MODEL_PATH ) ;
			live2DModel = Live2DModelAndroid.loadModel( in ) ;
			in.close() ;
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}

		try
		{
			// Add Code Start
			setupBackground(gl);
			// Add Code End

			//texture
			for (int i = 0 ; i < TEXTURE_PATHS.length ; i++ )
			{
				InputStream in = mngr.open( TEXTURE_PATHS[i] ) ;
				int texNo = UtOpenGL.loadTexture(gl , in , true ) ;
				live2DModel.setTexture( i , texNo ) ;
				in.close();
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}

		try
		{
			InputStream in = mngr.open( MOTION_PATH ) ;
			motion = Live2DMotion.loadMotion( in ) ;
			in.close() ;

			in=mngr.open(PHYSICS_PATH);
			physics=L2DPhysics.load(in);
			in.close();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
    }

    /**
     * Called when the engine is destroyed. Do any necessary clean up because
     * at this point your renderer instance is now done for.
     */
    public void release() {
    }

    public void resetDrag()
    {
    	dragMgr.set(0, 0);
    }


    public void drag(float x,float y)
    {
    	float screenX=x/glWidth*2-1;
    	float screenY=-y/glHeight*2+1;

//    	Log.i("", "x:"+screenX+" y:"+screenY);

    	dragMgr.set(screenX,screenY);
    }

	/*
	 * BackGround Image Setting
	 * @param context
	 */
	private void setupBackground(GL10 context) {
		try {
			InputStream in = FileManager.open(LAppDefine.BACK_IMAGE_NAME);
			bg=new SimpleImage(context,in);
			bg.setDrawRect(
					LAppDefine.VIEW_LOGICAL_MAX_LEFT,
					LAppDefine.VIEW_LOGICAL_MAX_RIGHT,
					LAppDefine.VIEW_LOGICAL_MAX_BOTTOM,
					LAppDefine.VIEW_LOGICAL_MAX_TOP);

			// uv area
			bg.setUVRect(0.0f,1.0f,0.0f,1.0f);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

img_wallpaper.png

あとはassets配下に違う画像を入れて、LAppDefine.javaのBACK_IMAGE_NAMEの変更すれば背景画像を変えられます。

おまけ

ちなみにSimpleプロジェクトの方だとソースは以下のように修正すると背景が表示されます。
(SampleApp1からコピーしてくるものは同じ)

SampleActivity.java
package jp.live2d.sample;

import jp.live2d.Live2D;
import jp.live2d.utils.android.FileManager;
import android.app.Activity;
import android.os.Bundle;

public class SampleActivity extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        Live2D.init();

        FileManager.init(this.getApplicationContext());

        SampleGLSurfaceView 	view = new SampleGLSurfaceView(this) ;
        setContentView( view ) ;
    }

}
SampleGLSurfaceView.java
package jp.live2d.sample;

import java.io.IOException;
import java.io.InputStream;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import jp.live2d.android.Live2DModelAndroid;
import jp.live2d.android.UtOpenGL;
import jp.live2d.util.UtSystem;
import jp.live2d.utils.android.FileManager;
import jp.live2d.utils.android.SimpleImage;
import android.content.Context;
import android.opengl.GLSurfaceView;

public class SampleGLSurfaceView extends GLSurfaceView
{
	private SampleGLRenderer		renderer ;
	private SimpleImage bg;// 背景の描画
	private float modelWidth = 0;
	private float aspect = 0;

	public SampleGLSurfaceView(Context context )
	{
		super(context);

		renderer = new SampleGLRenderer() ;
		setRenderer( renderer ) ;
	}


	class SampleGLRenderer implements Renderer
	{
		private Live2DModelAndroid	live2DModel ;
		private final String MODEL_PATH = "haru/haru.moc" ;
		private final String TEXTURE_PATHS[] =
			{
				"haru/haru.1024/texture_00.png" ,
				"haru/haru.1024/texture_01.png" ,
				"haru/haru.1024/texture_02.png"
			} ;

		@Override
		public void onDrawFrame(GL10 gl)
		{
			gl.glMatrixMode(GL10.GL_MODELVIEW ) ;
			gl.glLoadIdentity() ;
			gl.glClear( GL10.GL_COLOR_BUFFER_BIT ) ;
			// background draw
			bg.draw(gl);

			// Live2Dモデル調整
			gl.glScalef(2.8f, 2.8f, 2.8f);
			gl.glTranslatef(0.0f, -0.3f, 0.0f);
			gl.glOrthof(0 ,	modelWidth , modelWidth / aspect , 0 , 0.5f , -0.5f ) ;

			double t = (UtSystem.getUserTimeMSec()/1000.0) * 2 * Math.PI  ;// 1秒ごとに2π(1周期)増える
			double cycle=3.0;// パラメータが一周する時間(秒)
			double sin=Math.sin( t/cycle );// -1から1の間を周期ごとに変化する
			live2DModel.setParamFloat( "PARAM_ANGLE_X" , (float) (30 * sin) ) ;// PARAM_ANGLE_Xのパラメータが[cycle]秒ごとに-30から30まで変化する

			live2DModel.setGL( gl ) ;

			live2DModel.update() ;
			live2DModel.draw() ;
		}


		@Override
		public void onSurfaceChanged(GL10 gl, int width, int height)
		{
			// ビューポートはデバイスの幅と合わせる。画面全体に表示される。
			gl.glViewport( 0 , 0 , width , height ) ;

			// 簡易的にプロジェクション行列一つですべての変換を行う。
			gl.glMatrixMode( GL10.GL_PROJECTION ) ;
			gl.glLoadIdentity() ;

			modelWidth = live2DModel.getCanvasWidth();// モデラーで設定したキャンバス幅
			aspect = (float)width/height;
			//modelWidth=2400.0, aspect=0.6642066, modelWidth /aspect = 3613.33356218
			// 描画範囲の設定 引数はleft,right,bottom,topの順
//			gl.glOrthof(0 ,	modelWidth , modelWidth / aspect , 0 , 0.5f , -0.5f ) ;
			// background 用に調整
			gl.glOrthof(-2.0f ,	2.0f , -2.0f ,2.0f , 0.5f , -0.5f ) ;
		}


		@Override
		public void onSurfaceCreated(GL10 gl, EGLConfig config)
		{
			//  モデルの初期化
			try
			{
				// 背景の作成
				setupBackground(gl);


				InputStream in = getContext().getAssets().open( MODEL_PATH ) ;
				live2DModel = Live2DModelAndroid.loadModel( in ) ;
				in.close() ;

				for (int i = 0 ; i < TEXTURE_PATHS.length ; i++ )
				{
					InputStream tin = getContext().getAssets().open( TEXTURE_PATHS[i] ) ;
					int texNo = UtOpenGL.loadTexture(gl , tin , true ) ;
					live2DModel.setTexture( i , texNo ) ;
				}
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}

		/*
		 * 背景の設定
		 * @param context
		 */
		private void setupBackground(GL10 context) {
			try {
				InputStream in = FileManager.open(LAppDefine.BACK_IMAGE_NAME);
//				InputStream in = getContext().getAssets().open( LAppDefine.BACK_IMAGE_NAME ) ;
				bg=new SimpleImage(context,in);
				// 描画範囲。画面の最大表示範囲に合わせる
				bg.setDrawRect(
						LAppDefine.VIEW_LOGICAL_MAX_LEFT,
						LAppDefine.VIEW_LOGICAL_MAX_RIGHT,
						LAppDefine.VIEW_LOGICAL_MAX_BOTTOM,
						LAppDefine.VIEW_LOGICAL_MAX_TOP);

				// 画像を使用する範囲(uv)
				bg.setUVRect(0.0f,1.0f,0.0f,1.0f);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}


5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?