OpenGL版スライドパズルサンプルapk

ひとまずOpenGL版のスライドパズルサンプルの配布用apkを置きました。
Android端末のブラウザで以下にアクセスすると、ダウンロード・インストールできます。
http://www015.upp.so-net.ne.jp/chiaki_sugimoto/android/SlidePuzzle.apk
SlidePuzzle1としてインストールされます。アプリを起動すると、シャッフルされた画面が出るので、解答を求めて指でスライドしていきます。
またAndroid端末のmenuボタンを押すとGiveUPとShuffleのメニューが出るので、現在の画面状態からの解答プレビューを見たい時はGiveUPを、現在の画面状態からのシャッフルを行いたい時はShuffleを選択してください。
尚今回のように、AndroidMarket以外に配置した配布用署名付きapkをインストールするためには、Android端末側で以下の設定が必要です。
☆「設定」→「アプリケーション」→「提供元不明のアプリ」にチェックを入れる。(GDDPhoneはこの設定ですが、DevPhoneやその他製品により異なると思います)

AndroidMarketに出すわけではなく、あくまで自己メモを兼ねたサンプルなので、写真の自由選択やタイマーといったオプションはなく、至ってシンプルです。あと、GiveUp時の解答プレビューは最短経路ではありませんのであしからず。

SurfaceView版とView版も暇を見つけて、順次追加アップしたいと思います。

前回からの差分は、
・縦横の画面サイズをGDDPhone用専用(数値固定)から機種非依存(数値取得)に変更
・GiveUpモードとShuffleモードの追加

SlidePuzzle.javaにもメニューボタン等の変更が入りましたが、重要なポイントを含むSlidePuzzle_GLSurfaceView.javaの方だけ、メモとしてアップします。


package com.chiaki.example;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Random;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.opengl.GLUtils;
import android.view.KeyEvent;
import android.view.MotionEvent;

public class SlidePuzzle_GLSurfaceView extends GLSurfaceView implements GLSurfaceView.Renderer {
    private Random rand=new Random();
    private Bitmap image;            
    private static int[]  data=new int[25]; 
	private FloatBuffer[] vertexBuff = new FloatBuffer[25];
	private FloatBuffer textureBuff = null;
	private int[] textureId;
	private static int freeIdx;
	private static ArrayList<String> res;
	static ListIterator<String> ite;
	private static int pos;
	private static String reskey = null;
	private static boolean last_flg = false;
    private BitmapFactory.Options options;
    private Context context;
    
	public SlidePuzzle_GLSurfaceView(Context context) {
		super(context);
        initialize(context);
        for (int i=0;i<25;i++) data[i]=i;
    }
	
	private void initialize(Context context) {
	    setFocusable(true);      
	    setFocusableInTouchMode(true); 
		setFocusable(true);
		this.setRenderer( this );
		ByteBuffer[] byteBuffer = new ByteBuffer[25];

		for (int i = 0; i < 25; i++){
			byteBuffer[i] = ByteBuffer.allocateDirect(4 * 3 * 4);
			byteBuffer[i].order(ByteOrder.nativeOrder());
			vertexBuff[i] = byteBuffer[i].asFloatBuffer();			
		}
		
		ByteBuffer t_byteBuffer = ByteBuffer.allocateDirect(4 * 2 * 4);
		t_byteBuffer.order(ByteOrder.nativeOrder());
		textureBuff = t_byteBuffer.asFloatBuffer();

		textureBuff.put(new float[] {
				0.0f, 1.0f,		//左下
				1.0f, 1.0f,		//右下
				0.0f, 0.0f,		//左上
				1.0f, 0.0f,		//右上
		});
		textureBuff.position(0);	

        Resources r=context.getResources();
        int resID=R.drawable.picture;
        image = BitmapFactory.decodeResource(r,resID); 
        res = new ArrayList<String>();
	}

	private void loadTexture( GL10 gl ){
        int width = image.getWidth();
        int height = image.getHeight();
        int[][] pixels = new int[25][(width/5) * (height/5)+1];
        
        int img_pixels[] = new int[width * height];
        for (int i = 0; i < 25; i++){
            pixels[i] = new int[(width/5) * (height/5)];        	
        }
        image.getPixels(img_pixels, 0, width, 0, 0, width, height);

        for (int y = 0; y < height/5; y++) {
            for (int x = 0; x < width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[0][x + y * (width/5)] = pixel;
            }
            for (int x = width/5; x < 2*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[1][(x - width/5) + y * (width/5)] = pixel;
            }
            for (int x = 2*width/5; x < 3*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[2][(x - 2*width/5) + y * (width/5)] = pixel;
            }
            for (int x = 3*width/5; x < 4*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[3][(x - 3*width/5) + y * (width/5)] = pixel;
            }
            for (int x = 4*width/5; x < width; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[4][(x - 4*width/5) + y * (width/5)] = pixel;
            }
        }
        for (int y = height/5; y < 2*height/5; y++) {
            for (int x = 0; x < width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[5][x + (y - height/5) * (width/5)] = pixel;
            }
            for (int x = width/5; x < 2*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[6][(x - width/5) + (y - height/5) * (width/5)] = pixel;
            }
            for (int x = 2*width/5; x < 3*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[7][(x - 2*width/5) + (y - height/5) * (width/5)] = pixel;
            }
            for (int x = 3*width/5; x < 4*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[8][(x - 3*width/5) + (y - height/5) * (width/5)] = pixel;
            }
            for (int x = 4*width/5; x < width; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[9][(x - 4*width/5) + (y - height/5) * (width/5)] = pixel;
            }
        }
        for (int y = 2*height/5; y < 3*height/5; y++) {
            for (int x = 0; x < width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[10][x + (y - 2*height/5) * (width/5)] = pixel;
            }
            for (int x = width/5; x < 2*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[11][(x - width/5) + (y - 2*height/5) * (width/5)] = pixel;
            }
            for (int x = 2*width/5; x < 3*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[12][(x - 2*width/5) + (y - 2*height/5) * (width/5)] = pixel;
            }
            for (int x = 3*width/5; x < 4*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[13][(x - 3*width/5) + (y - 2*height/5) * (width/5)] = pixel;
            }
            for (int x = 4*width/5; x < width; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[14][(x - 4*width/5) + (y - 2*height/5) * (width/5)] = pixel;
            }
        }
        for (int y = 3*height/5; y < 4*height/5; y++) {
            for (int x = 0; x < width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[15][x + (y - 3*height/5) * (width/5)] = pixel;
            }
            for (int x = width/5; x < 2*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[16][(x - width/5) + (y - 3*height/5) * (width/5)] = pixel;
            }
            for (int x = 2*width/5; x < 3*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[17][(x - 2*width/5) + (y - 3*height/5) * (width/5)] = pixel;
            }
            for (int x = 3*width/5; x < 4*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[18][(x - 3*width/5) + (y - 3*height/5) * (width/5)] = pixel;
            }
            for (int x = 4*width/5; x < width; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[19][(x - 4*width/5) + (y - 3*height/5) * (width/5)] = pixel;
            }
        }
        for (int y = 4*height/5; y < height; y++) {
            for (int x = 0; x < width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[20][x + (y - 4*height/5) * (width/5)] = pixel;
            }
            for (int x = width/5; x < 2*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[21][(x - width/5) + (y - 4*height/5) * (width/5)] = pixel;
            }
            for (int x = 2*width/5; x < 3*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[22][(x - 2*width/5) + (y - 4*height/5) * (width/5)] = pixel;
            }
            for (int x = 3*width/5; x < 4*width/5; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[23][(x - 3*width/5) + (y - 4*height/5) * (width/5)] = pixel;
            }
            for (int x = 4*width/5; x < width; x++) {
                int pixel = img_pixels[x + y * width];
                pixels[24][(x - 4*width/5) + (y - 4*height/5) * (width/5)] = pixel;
            }
        }

        Bitmap[] bitmap = new Bitmap[25];
        for (int i = 0; i < 25; i++){
        	bitmap[i] = Bitmap.createBitmap(width/5, height/5, Bitmap.Config.ARGB_8888);
            bitmap[i].setPixels(pixels[i], 0, width/5, 0, 0, width/5, height/5);                	
            bitmap[i] =  Bitmap.createScaledBitmap(bitmap[i], 128, 128, true); 
        }
        
        int[] textures = new int[25];
        gl.glGenTextures(25, textures, 0);
        image.recycle();	
        textureId = new int[25];
        for (int i = 0; i < 25; i++){
            textureId[i] = textures[i];
            gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId[i]);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
                    GL10.GL_NEAREST);	
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
                    GL10.GL_LINEAR);	
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
                    GL10.GL_CLAMP_TO_EDGE);	
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
                    GL10.GL_CLAMP_TO_EDGE);
            gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
                    GL10.GL_REPLACE);	        
            GLUtils.texImage2D( GL10.GL_TEXTURE_2D, 0, bitmap[i], 0 );
            bitmap[i].recycle();	
        }
	}

	@Override
    public void onResume(){
    	super.onResume();
    	this.onResume();
    }

    @Override
    public void onPause(){
    	super.onPause();
    	this.onPause();
    }

    private int displayWidth;
    private int displayHeight;
	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
	    displayWidth = getWidth();
	    displayHeight = getHeight();

    	gl.glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );	
    	gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
 
    	gl.glShadeModel( GL10.GL_FLAT );	
    	gl.glEnableClientState( GL10.GL_VERTEX_ARRAY );	
    	gl.glEnableClientState( GL10.GL_TEXTURE_COORD_ARRAY );
    	gl.glEnable( GL10.GL_TEXTURE_2D );	
    	  	
	    GLU.gluOrtho2D(gl, -1.0f, 1.0f, -1.0f, 1.0f);
	    
        loadPicture();	    
		this.loadTexture( gl );    		
	}

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

	@Override
	public void onDrawFrame(GL10 gl) {
        boolean complete=true;
        for (int i=0;i<25;i++) {
            if (data[i]!=i) complete=false;
        }
        if (complete){
            for (ite = res.listIterator(res.size()); ite.hasPrevious();){
            	ite.remove();
            }
        }
		ByteBuffer[] byteBuffer = new ByteBuffer[25];
		for (int i = 0; i < 25; i++){
	 		byteBuffer[i] = ByteBuffer.allocateDirect(4 * 3 * 4);
			byteBuffer[i].order(ByteOrder.nativeOrder());
			vertexBuff[i] = byteBuffer[i].asFloatBuffer();
		}
		float tl_x = -1.0f;
		float tl_y = -1.0f;
		float tr_x = 1.0f;
		float tr_y = -1.0f;
		float ul_x = -1.0f;
		float ul_y = 1.0f;
		float ur_x = 1.0f;
		float ur_y = 1.0f;
		
		float ratiox = 2.0f/5;
		float ratioy = (2.0f/5)*((1.0f*displayWidth)/(1.0f*displayHeight));
		tl_x = (ratiox * -0.5f);
		tl_y = (ratioy * -0.5f);
		tr_x = (ratiox * 0.5f);
		tr_y = (ratioy * -0.5f);
		ul_x = (ratiox * -0.5f);
		ul_y = (ratioy * 0.5f);
		ur_x = (ratiox * 0.5f);
		ur_y = (ratioy * 0.5f);
		float [] x = new float[25];
		float [] y = new float[25];
		for (int i = 0; i < 25; i++){
			if (i%5 == 0){
				x[i] = -1.0f;				
			}else if(i%5 == 1){
				x[i] = -1.0f/2.0f;
			}else if(i%5 == 2){
				x[i] = 0;
			}else if(i%5 == 3){
				x[i] = 1.0f/2.0f;
			}else if(i%5 == 4){
				x[i] = 1.0f;
			}
		}	
		for (int i = 0; i < 25; i++){
			if (i/5 == 0){
				y[i] = 1.0f;				
			}else if(i/5 == 1){
				y[i] = 1.0f/2.0f;
			}else if(i/5 == 2){
				y[i] = 0;
			}else if(i/5 == 3){
				y[i] = -1.0f/2.0f;
			}else if(i/5 == 4){
				y[i] = -1.0f;
			}
		}	
		for (int i = 0; i < 25; i++){
	    	if (getmode() == KeyEvent.KEYCODE_DPAD_UP || getmode() == KeyEvent.KEYCODE_DPAD_DOWN){
        		if ((i <= (5*gettouchY() + gettouchX()) && i > (5*getfreeY() + getfreeX()) && (i == (5*getfreeY() + getfreeX())+5 || i == (5*getfreeY() + getfreeX())+10 || i == (5*getfreeY() + getfreeX())+15 || i == (5*getfreeY() + getfreeX())+20) && getslide_ysum() <= 60 && getslide_ysum() >= 0) ||(i >= (5*gettouchY() + gettouchX()) && i < (5*getfreeY() + getfreeX()) && (i == (5*getfreeY() + getfreeX())-5 || i == (5*getfreeY() + getfreeX())-10 || i == (5*getfreeY() + getfreeX())-15 || i == (5*getfreeY() + getfreeX())-20) && getslide_ysum() > -60 && getslide_ysum() < 0)){
	    			vertexBuff[i].put(new float[] {
    		                tl_x+x[i]*(2.0f/2.5f), tl_y+y[i]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(getslide_ysum()*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f,
    		                tr_x+x[i]*(2.0f/2.5f), tl_y+y[i]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(getslide_ysum()*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f,
    		                ul_x+x[i]*(2.0f/2.5f), ul_y+y[i]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(getslide_ysum()*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f,
    		                ur_x+x[i]*(2.0f/2.5f), ur_y+y[i]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(getslide_ysum()*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f});
    				vertexBuff[i].position(0);	    				
	    		}else{
	    			vertexBuff[i].put(new float[] {
    		                tl_x+x[i]*(2.0f/2.5f), tl_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
    		                tr_x+x[i]*(2.0f/2.5f), tr_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
    		                ul_x+x[i]*(2.0f/2.5f), ul_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
    		                ur_x+x[i]*(2.0f/2.5f), ur_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f});
    				vertexBuff[i].position(0);	    				
	    		}
   				int[] textureId_tmp = new int[25];
                if (getslide_ysum() >= 60 || getslide_ysum() <= -60){
                	if (getslide_ysum() >= 60){
           	    		for (int j=touchY;j>freeY;j--) {
           	    			slidePiece(getmode(), 0);       	    					
           	    		}                		
                	}else if (getslide_ysum() <= -60){
           	    		for (int j=freeY;j>touchY;j--) {
           	    			slidePiece(getmode(), 0);       	    					
           	    		}                		
                	}
       	    		for (int j = 0; j < 25; j++){
       	    			textureId_tmp[j] = textureId[data[j]];
       	    		}
       	    		for (int j = 0; j < 25; j++){
       	    			textureId[j] = textureId[j];
       	    		}
       			    s_touchX = 0;
       			    s_touchY = 0;
       			    e_touchX = 0;
       			    e_touchY = 0;
       			    slide_x = 0;
       			    slide_y = 0;
       			    slide_xsum = 0;
       			    slide_ysum = 0;
       			    reach_flg = true;
                }
	    	}else if (getmode() == KeyEvent.KEYCODE_DPAD_RIGHT || getmode() == KeyEvent.KEYCODE_DPAD_LEFT){
	    		if ((i < (5*getfreeY() + getfreeX()) && i >= (5*gettouchY() + gettouchX()) && getslide_xsum() <= 60 && getslide_xsum() >= 0) || (i > (5*getfreeY() + getfreeX()) && i <= (5*gettouchY() + gettouchX()) && getslide_xsum() >= -60 && getslide_xsum() <= 0)){
	    			vertexBuff[i].put(new float[] {
    		                tl_x+x[i]*(2.0f/2.5f)+(getslide_xsum()*(1.0f/(1.0f*displayWidth/2.0f))), tl_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
    		                tr_x+x[i]*(2.0f/2.5f)+(getslide_xsum()*(1.0f/(1.0f*displayWidth/2.0f))), tr_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
    		                ul_x+x[i]*(2.0f/2.5f)+(getslide_xsum()*(1.0f/(1.0f*displayWidth/2.0f))), ul_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
    		                ur_x+x[i]*(2.0f/2.5f)+(getslide_xsum()*(1.0f/(1.0f*displayWidth/2.0f))), ur_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f});
    				vertexBuff[i].position(0);	    				
	    		}else{
	    			vertexBuff[i].put(new float[] {
    		                tl_x+x[i]*(2.0f/2.5f), tl_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
    		                tr_x+x[i]*(2.0f/2.5f), tr_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
    		                ul_x+x[i]*(2.0f/2.5f), ul_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
    		                ur_x+x[i]*(2.0f/2.5f), ur_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f});
    				vertexBuff[i].position(0);	    				
	    		}
   				int[] textureId_tmp = new int[25];
                if (getslide_xsum() >= 60 || getslide_xsum() <= -60){
                	if (getslide_xsum() >= 60){
           	    		for (int j=freeX;j>touchX;j--) {
           	    			slidePiece(getmode(), 0);       	    					
           	    		}                		
                	}else if (getslide_xsum() <= -60){
           	    		for (int j=touchX;j>freeX;j--) {
           	    			slidePiece(getmode(), 0);       	    					
           	    		}                		
                	}
       	    		for (int j = 0; j < 25; j++){
       	    			textureId_tmp[j] = textureId[data[j]];
       	    		}
       	    		for (int j = 0; j < 25; j++){
       	    			textureId[j] = textureId[j];
       	    		}
       			    s_touchX = 0;
       			    s_touchY = 0;
       			    e_touchX = 0;
       			    e_touchY = 0;
       			    slide_x = 0;
       			    slide_y = 0;
       			    slide_xsum = 0;
       			    slide_ysum = 0;
       			    reach_flg = true;
                }
	    	}else{
    			vertexBuff[i].put(new float[] {
		                tl_x+x[i]*(2.0f/2.5f), tl_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
		                tr_x+x[i]*(2.0f/2.5f), tr_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
		                ul_x+x[i]*(2.0f/2.5f), ul_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
		                ur_x+x[i]*(2.0f/2.5f), ur_y+y[i]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f});
				vertexBuff[i].position(0);	    				
	    	}
		}
		
		if (getres_flg() && !complete){
			if (ite.hasPrevious() || (!(ite.hasPrevious()) && last_flg)){
				if ((pos == 0 || pos >= 60 || pos <= -60) && !last_flg){
		    		reskey = (String) ite.previous();
			        ite.remove();
				}
				if (reskey.equals("KeyEvent.KEYCODE_DPAD_UP")){
		    		if (pos < 60){
		    			for (int i = 0; i < 10; i++){
				    		pos++;		    				
		    			}
			            freeIdx=0;
			            for (; freeIdx<25; freeIdx++) {
			                if (data[freeIdx]==24) break;
			            }
		    			vertexBuff[freeIdx+5].put(new float[] {
	    		                tl_x+x[freeIdx+5]*(2.0f/2.5f), tl_y+y[freeIdx+5]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(pos*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f,
	    		                tr_x+x[freeIdx+5]*(2.0f/2.5f), tl_y+y[freeIdx+5]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(pos*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f,
	    		                ul_x+x[freeIdx+5]*(2.0f/2.5f), ul_y+y[freeIdx+5]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(pos*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f,
	    		                ur_x+x[freeIdx+5]*(2.0f/2.5f), ur_y+y[freeIdx+5]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(pos*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f});
	    				vertexBuff[freeIdx+5].position(0);		    			
		    		}
				    if (pos >= 60){
					    slidePiece(KeyEvent.KEYCODE_DPAD_UP, 1);
					    pos = 0;
				    }
		    	}else if (reskey.equals("KeyEvent.KEYCODE_DPAD_DOWN")){
		    		if (pos > -60){
		    			for (int i = 0; i < 10; i++){
				    		pos--;		    				
		    			}
			            freeIdx=0;
			            for (; freeIdx<25; freeIdx++) {
			                if (data[freeIdx]==24) break;
			            }
		    			vertexBuff[freeIdx-5].put(new float[] {
	    		                tl_x+x[freeIdx-5]*(2.0f/2.5f), tl_y+y[freeIdx-5]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(pos*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f,
	    		                tr_x+x[freeIdx-5]*(2.0f/2.5f), tl_y+y[freeIdx-5]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(pos*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f,
	    		                ul_x+x[freeIdx-5]*(2.0f/2.5f), ul_y+y[freeIdx-5]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(pos*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f,
	    		                ur_x+x[freeIdx-5]*(2.0f/2.5f), ur_y+y[freeIdx-5]*(2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))+(pos*(1.0f/(1.0f*displayHeight/2.0f))), 0.0f});
	    				vertexBuff[freeIdx-5].position(0);	    						    			
		    		}
				    if (pos <= -60){
					    slidePiece(KeyEvent.KEYCODE_DPAD_DOWN, 1);
					    pos = 0;
				    }	
		    	}else if (reskey.equals("KeyEvent.KEYCODE_DPAD_LEFT")){
		    		if (pos > -60){
		    			for (int i = 0; i < 10; i++){
				    		pos--;		    				
		    			}
			            freeIdx=0;
			            for (; freeIdx<25; freeIdx++) {
			                if (data[freeIdx]==24) break;
			            }
		    			vertexBuff[freeIdx+1].put(new float[] {
	    		                tl_x+x[freeIdx+1]*(2.0f/2.5f)+(pos*(1.0f/(1.0f*displayWidth/2.0f))), tl_y+y[freeIdx+1]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
	    		                tr_x+x[freeIdx+1]*(2.0f/2.5f)+(pos*(1.0f/(1.0f*displayWidth/2.0f))), tr_y+y[freeIdx+1]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
	    		                ul_x+x[freeIdx+1]*(2.0f/2.5f)+(pos*(1.0f/(1.0f*displayWidth/2.0f))), ul_y+y[freeIdx+1]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
	    		                ur_x+x[freeIdx+1]*(2.0f/2.5f)+(pos*(1.0f/(1.0f*displayWidth/2.0f))), ur_y+y[freeIdx+1]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f});
	    				vertexBuff[freeIdx+1].position(0);
		    		}
				    if (pos <= -60){
					    slidePiece(KeyEvent.KEYCODE_DPAD_LEFT, 1);
					    pos = 0;
				    }	
		    	}else if(reskey.equals("KeyEvent.KEYCODE_DPAD_RIGHT")){
		    		if (pos < 60){
		    			for (int i = 0; i < 10; i++){
				    		pos++;		    				
		    			}
			            freeIdx=0;
			            for (; freeIdx<25; freeIdx++) {
			                if (data[freeIdx]==24) break;
			            }
		    			vertexBuff[freeIdx-1].put(new float[] {
	    		                tl_x+x[freeIdx-1]*(2.0f/2.5f)+(pos*(1.0f/(1.0f*displayWidth/2.0f))), tl_y+y[freeIdx-1]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
	    		                tr_x+x[freeIdx-1]*(2.0f/2.5f)+(pos*(1.0f/(1.0f*displayWidth/2.0f))), tr_y+y[freeIdx-1]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
	    		                ul_x+x[freeIdx-1]*(2.0f/2.5f)+(pos*(1.0f/(1.0f*displayWidth/2.0f))), ul_y+y[freeIdx-1]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f,
	    		                ur_x+x[freeIdx-1]*(2.0f/2.5f)+(pos*(1.0f/(1.0f*displayWidth/2.0f))), ur_y+y[freeIdx-1]*((2.0f/2.5f)*((1.0f*displayWidth)/(1.0f*displayHeight))), 0.0f});
	    				vertexBuff[freeIdx-1].position(0);
		    		}
				    if (pos >= 60){
					    slidePiece(KeyEvent.KEYCODE_DPAD_RIGHT, 1);
					    pos = 0;
				    }	
    		    }
				if (!ite.hasPrevious()){
					last_flg = true;
				}
			}else {
				reskey = null;
				last_flg = false;
			}
			boolean flg = false;
	        for (int i=0;i<25;i++) {
	            if (data[i]!=i){
	            	flg = true;
	            }
	        }
	        if (!flg){
		        complete=true;
	            for (ite = res.listIterator(res.size()); ite.hasPrevious();){
	            	ite.previous();
	            	ite.remove();
	            }
	        }
		}else{
		    res_flg = false;
		}
		
		gl.glClear( GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT );	
        gl.glActiveTexture( GL10.GL_TEXTURE0 );

        for (int i = 0; i < 25; i++){
        	if (data[i] == 24){
        		
        	}else{
        		gl.glBindTexture( GL10.GL_TEXTURE_2D, textureId[data[i]] );
                gl.glPushMatrix();
        		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuff[i] );
        		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            	gl.glEnableClientState( GL10.GL_TEXTURE_COORD_ARRAY );	
            	gl.glEnable( GL10.GL_TEXTURE_2D );	
        		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuff );
        		gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);
        		gl.glPopMatrix();        		
        	}
        }
        if (complete) {
        }  
	}

  public void loadPicture() {
	  	context = getContext();
        Resources r=context.getResources();
        int resID=R.drawable.picture;
		options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(r,resID, options); 
		int scaleW = options.outWidth / displayHeight + 1;
		int scaleH = options.outHeight / displayWidth + 1;
		int scale = Math.max(scaleW, scaleH);
		options.inJustDecodeBounds = false;
		options.inSampleSize = scale;
        image = BitmapFactory.decodeResource(r,resID, options); 
        image =  Bitmap.createScaledBitmap(image, displayWidth, displayWidth, true); 
        
        int[] DIR={
            KeyEvent.KEYCODE_DPAD_UP,
            KeyEvent.KEYCODE_DPAD_DOWN,
            KeyEvent.KEYCODE_DPAD_LEFT,
            KeyEvent.KEYCODE_DPAD_RIGHT
        };
        int before = -1;
        int current = -1;
        for (int i=99;i>=0;i--) {
        	current = (rand.nextInt()>>>1)%4;
        	if (before == -1 || (before == 0 && current != 1) || (before == 1 && current != 0) || (before == 2 && current != 3) || (before == 3 && current != 2)){
        		slidePiece(DIR[current], 0);        		
                before = current;
        	}else{
        		i++;
        	}
        }        
    }

    static void slidePiece(int key, int flg) {
        freeIdx=0;
        for (; freeIdx<25; freeIdx++) {
            if (data[freeIdx]==24) break;
        }

    	if (flg == 0){
            if (key==KeyEvent.KEYCODE_DPAD_UP && freeIdx/5<4) {
            	res.add("KeyEvent.KEYCODE_DPAD_DOWN");    		
            } else if (key==KeyEvent.KEYCODE_DPAD_DOWN && freeIdx/5>0) {
            	res.add("KeyEvent.KEYCODE_DPAD_UP");    		
            } else if (key==KeyEvent.KEYCODE_DPAD_LEFT && freeIdx%5<4) {
            	res.add("KeyEvent.KEYCODE_DPAD_RIGHT");
            } else if (key==KeyEvent.KEYCODE_DPAD_RIGHT && freeIdx%5>0) {
            	res.add("KeyEvent.KEYCODE_DPAD_LEFT");    		
        	}    		
    	}
                
        if (key==KeyEvent.KEYCODE_DPAD_UP && freeIdx/5<4) {
            data[freeIdx]=data[freeIdx+5];
            data[freeIdx+5]=24;
        } else if (key==KeyEvent.KEYCODE_DPAD_DOWN && freeIdx/5>0) {
            data[freeIdx]=data[freeIdx-5];
            data[freeIdx-5]=24;
        } else if (key==KeyEvent.KEYCODE_DPAD_LEFT && freeIdx%5<4) {
            data[freeIdx]=data[freeIdx+1];
            data[freeIdx+1]=24;
        } else if (key==KeyEvent.KEYCODE_DPAD_RIGHT && freeIdx%5>0) {
            data[freeIdx]=data[freeIdx-1];
            data[freeIdx-1]=24;
        }
    }    
    
    static void Shuffle(){
        int[] DIR={
                KeyEvent.KEYCODE_DPAD_UP,
                KeyEvent.KEYCODE_DPAD_DOWN,
                KeyEvent.KEYCODE_DPAD_LEFT,
                KeyEvent.KEYCODE_DPAD_RIGHT
            };
            int before = -1;
            int current = -1;
            for (int i=99;i>=0;i--) {
                Random rand=new Random();
            	current = (rand.nextInt()>>>1)%4;
            	if (before == -1 || (before == 0 && current != 1 && current != 0) || (before == 1 && current != 0 && current != 1) || (before == 2 && current != 3 && current != 2) || (before == 3 && current != 2 && current != 3)){
            		slidePiece(DIR[current], 0);        		
                    before = current;
            	}else {
            		i++;
            	}
            }       
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

	    switch( event.getAction() ){
	   	     
   	    case MotionEvent.ACTION_DOWN :
   	    	s_touchX = 0;
   	    	s_touchY = 0;
   	    	e_touchX = 0;
   	    	e_touchY = 0;

   	    	s_touchX = (int) event.getX();
   	    	s_touchY = (int) event.getY();

   	    	touchX=(int)(event.getX()-(getWidth()-displayWidth)/2)/60;
   	    	touchY=(int)(event.getY()-(getHeight()-displayWidth)/2)/60;

   	    	if (touchX<0 || 5<=touchX) return true;
   	    	if (touchY<0 || 5<=touchY) return true;
            
   	    	freeX=0;
   	    	freeY=0;
   	    	for (int i=0;i<25;i++) {
   	    		if (data[i]==24) {
   	    			freeX=i%5;
   	    			freeY=i/5;
   	    			break;
   	    		}
   	    	}
         	
   	    	if (touchX==freeX) {
   	    		if (freeY<touchY) {
   	    			mode = KeyEvent.KEYCODE_DPAD_UP;
   	    		} else if (freeY>touchY) {
   	    			mode = KeyEvent.KEYCODE_DPAD_DOWN;
   	    		}
   	    	} else if (touchY==freeY) {
   	    		if (freeX<touchX) {
   	    			mode = KeyEvent.KEYCODE_DPAD_LEFT;
   	    		} else if (freeX>touchX) {
   	    			mode = KeyEvent.KEYCODE_DPAD_RIGHT;
   	    		}
   	    	}
   	    	break;

	    case MotionEvent.ACTION_MOVE :
   	    	e_touchX = (int) event.getX();
   	    	e_touchY = (int) event.getY();
            slide_x = e_touchX - s_touchX;
            slide_y = s_touchY - e_touchY;
            if (getslide_x() > 60){
            	slide_x = 60;
            }
            if (getslide_x() < -60){
            	slide_x = -60;
            }
            if (getslide_y() > 60){
            	slide_y = 60;
            }
            if (getslide_y() < -60){
            	slide_y = -60;
            }
            if ((getslide_xsum() <= 60 && getslide_xsum() >=0) || (getslide_xsum() <= 0 && getslide_xsum() >= -60)){
                slide_xsum =getslide_xsum() + getslide_x();
            }
            if ((getslide_ysum() >= 0 && getslide_ysum() <= 60) || (getslide_ysum() <= 0 && getslide_ysum() >= -60)){
                slide_ysum =getslide_ysum() + getslide_y();
            }
            s_touchX = e_touchX;
            s_touchY = e_touchY;

            if (getreach_flg() == true){
		    	s_touchX = 0;
		    	s_touchY = 0;
		    	e_touchX = 0;
		    	e_touchY = 0;
		    	slide_x = 0;
		    	slide_y = 0;
		    	slide_xsum = 0;
		    	slide_ysum = 0;
		    	mode = -1;   
		    	reach_flg = false;
            }
	    	break;

	    case MotionEvent.ACTION_UP :
		    	s_touchX = 0;
		    	s_touchY = 0;
		    	e_touchX = 0;
		    	e_touchY = 0;
		    	slide_x = 0;
		    	slide_y = 0;
		    	slide_xsum = 0;
		    	slide_ysum = 0;
		    	mode = -1;
		    	reach_flg = false;
		    	break;
	    }			

        return true;
    }  

    public static void showResult(){
		res_flg = true;
		last_flg = false;
		pos = 0;
		ite = res.listIterator(res.size());
    }
    
    @Override 
    public boolean onKeyDown(int keyCode,KeyEvent event) {
        slidePiece(keyCode, 0);
        return super.onKeyDown(keyCode,event);
    }

    public int getmode(){
    	return mode;
    }
    
    public int getslide_x(){
    	return slide_x;
    }
    
    public int getslide_y(){
    	return slide_y;
    }

    public int getslide_xsum(){
    	return slide_xsum;
    }
    
    public int getslide_ysum(){
    	return slide_ysum;
    }

    public int gettouchX(){
    	return touchX;
    }

    public int gettouchY(){
    	return touchY;
    }
    
    public int getfreeX(){
    	return freeX;
    }

    public int getfreeY(){
    	return freeY;
    }
    public boolean getreach_flg(){
    	return reach_flg;
    }
    public boolean getres_flg(){
    	return res_flg;
    }
	private int slide_x;
	private int slide_y;
	private int mode = -1;
	private int touchX;
	private int touchY;
	private int freeX;
	private int freeY;
	private int s_touchX = 0;
   	private int s_touchY = 0;
   	private int e_touchX = 0;
   	private int e_touchY = 0;
   	private int slide_xsum = 0;
   	private int slide_ysum = 0;
   	private boolean reach_flg = false;
   	private static boolean res_flg = false;
}