2015-09-14 65 views
1

我不知道如何添加觸摸或長時間點擊操作OpenGL translate和縮放參數?如何在Android OpenGL ES中應用拖放和縮放比例

目前我的編碼是在手機屏幕中間顯示一個紋理,我想用手指拖動和縮放紋理,那麼我該如何操作OpenGL翻譯和縮放參數?

這是我的主類:

import android.app.Activity; 
import android.os.Bundle; 
import android.view.WindowManager; 

public class MainActivity extends Activity { 

private Stage stage; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    //screen setting 
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); 

    setContentView(R.layout.main_layout); 
    stage = (Stage)findViewById(R.id.my_stage); 
} 

@Override 
protected void onPause() { 
    super.onPause(); 
    stage.onPause(); 
} 

@Override 
protected void onResume() { 
    super.onResume(); 
    stage.onResume(); 
} 
} 

這是我的第二個亞類:

import android.content.Context; 
import android.opengl.GLES10; 
import android.opengl.GLSurfaceView; 
import android.util.AttributeSet; 

import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 
import java.nio.FloatBuffer; 

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

public class Stage extends GLSurfaceView{ 

/* Stage width and height */ 
private float w, h; 

/* Screen width and height */ 
private int screenWidth, screenHeight; 

/* Our native vertex buffer */ 
private FloatBuffer vertexBuffer; 

private Texture tex; 

public Stage(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    setEGLConfigChooser(8, 8, 8, 8, 0, 0); 
    setRenderer(new MyRenderer()); 
    setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 

    float vertices[] = { 
      -0.5f, -0.5f, 0.0f, // 0. left-bottom 
      0.5f, -0.5f, 0.0f, // 1. right-bottom 
      -0.5f, 0.5f, 0.0f, // 2. left-top 
      0.5f, 0.5f, 0.0f // 3. right-top 
    }; 

    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); 
    vbb.order(ByteOrder.nativeOrder()); 
    vertexBuffer = vbb.asFloatBuffer(); 
    vertexBuffer.put(vertices); 
    vertexBuffer.position(0); 

    tex = new Texture(R.drawable.kdk); 

} 

private final class MyRenderer implements GLSurfaceView.Renderer { 

    public final void onDrawFrame(GL10 gl) { 

     gl.glClear(GLES10.GL_COLOR_BUFFER_BIT); 
     gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); 
     tex.prepare(gl, GL10.GL_CLAMP_TO_EDGE); 
     tex.draw(gl, (w/2), (h/2), tex.getWidth(), tex.getHeight(), 0); 

    } 

    public final void onSurfaceChanged(GL10 gl, int width, int height) { 
     gl.glClearColor(0, 0, 0, 1.0f); 

     if(width > height) { 
      h = 600; 
      w = width * h/height; 
     } else { 
      w = 600; 
      h = height * w/width; 
     } 
     screenWidth = width; 
     screenHeight = height; 

     gl.glViewport(0, 0, screenWidth, screenHeight); 
     gl.glMatrixMode(GL10.GL_PROJECTION); 
     gl.glLoadIdentity(); 
     gl.glOrthof(0, w, h, 0, -1, 1); 
     gl.glMatrixMode(GL10.GL_MODELVIEW); 
     gl.glLoadIdentity(); 
    } 

    public final void onSurfaceCreated(GL10 gl, EGLConfig config) { 
     // Set up alpha blending 
     gl.glEnable(GL10.GL_ALPHA_TEST); 
     gl.glEnable(GL10.GL_BLEND); 
     gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA); 

     // We are in 2D. Why needs depth? 
     gl.glDisable(GL10.GL_DEPTH_TEST); 

     // Enable vertex arrays (we'll use them to draw primitives). 
     gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 

     // Enable texture coordination arrays. 
     gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 

     tex.load(getContext()); 
    } 



} 

} 

這是我的第三子類:

import android.content.Context; 
import android.content.res.Resources; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.opengl.GLES10; 
import android.opengl.GLES20; 
import android.opengl.GLUtils; 
import android.util.Log; 
import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 
import java.nio.FloatBuffer; 
import javax.microedition.khronos.opengles.GL10; 

public class Texture { 

/** 
* The OpenGL ES texture name associated with this texture. 
*/ 
protected int textureId; 

/** 
* The horizontal and vertical dimensions of the image. 
*/ 
protected int width, height; 

/** 
* The resource identifier for the image we want to load. 
*/ 
int resourceId; 

/** 
* Whether or not we should generate mip maps. 
*/ 
boolean mipmaps; 

/** 
* The buffer containing texture mappings. 
*/ 
private FloatBuffer tempTextureBuffer = null; 

Texture(int resourceId, boolean mipmaps) { 
    this.resourceId = resourceId; 
    this.textureId = -1; 
    this.mipmaps = mipmaps; 
} 

Texture(int resourceId) { 
    this(resourceId, false); 
} 

/** 
* Generates a new OpenGL ES texture name (identifier). 
* @return The newly generated texture name. 
*/ 
private static final int newTextureID() { 
    int[] temp = new int[1]; 
    GLES10.glGenTextures(1, temp, 0); 
    return temp[0]; 
} 

public final int getWidth() { 
    return width; 
} 

public final int getHeight() { 
    return height; 
} 

public final void load(Context context) { 
    // Load the bitmap from resources. 
    BitmapFactory.Options opts = new BitmapFactory.Options(); 
    opts.inScaled = false; 
    Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), resourceId, opts); 

    // Update this texture instance's width and height. 
    width = bmp.getWidth(); 
    height = bmp.getHeight(); 

    // Create and bind a new texture name. 
    textureId = newTextureID(); 
    GLES10.glBindTexture(GL10.GL_TEXTURE_2D, textureId); 

    // Load the texture into our texture name. 
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0); 

    // Set magnification filter to bilinear interpolation. 
    GLES10.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 

    if(mipmaps) { 
     // If mipmaps are requested, generate mipmaps and set minification filter to trilinear filtering. 
     GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D); 
     GLES10.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_LINEAR); 
    } 
    else GLES10.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); 

    // Recycle the bitmap. 
    bmp.recycle(); 

    // If texture mapping buffer has not been initialized yet, do it now. 
    if(tempTextureBuffer == null) 
     buildTextureMapping(); 
} 

/** 
* Builds the texture mapping buffer. 
*/ 
private void buildTextureMapping() { 
    // The array of texture mapping coordinates. 
    final float texture[] = { 
      0, 0, // The first vertex 
      1, 0, // The second vertex 
      0, 1, // The third vertex 
      1, 1, // The fourth vertex 
    }; 

    // Create a native buffer out of the above array. 
    final ByteBuffer ibb = ByteBuffer.allocateDirect(texture.length * 4); 
    ibb.order(ByteOrder.nativeOrder()); 
    tempTextureBuffer = ibb.asFloatBuffer(); 
    tempTextureBuffer.put(texture); 
    tempTextureBuffer.position(0); 
} 

/** 
* Deletes the texture name and marks this instance as unloaded. 
*/ 
public final void destroy() { 
    GLES10.glDeleteTextures(1, new int[] {textureId}, 0); 

    // Setting this value to -1 indicates that it is unloaded. 
    textureId = -1; 
} 

public final boolean isLoaded() { 
    return textureId >= 0; 
} 

public final void prepare(GL10 gl, int wrap) { 
    // Enable 2D texture 
    gl.glEnable(GL10.GL_TEXTURE_2D); 

    // Bind our texture name 
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); 

    // Set texture wrap methods 
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, wrap); 
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, wrap); 

    // Enable texture coordinate arrays and load (activate) ours 
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, tempTextureBuffer); 
} 

public final void draw(GL10 gl, float x, float y, float w, float h, float rot) { 
    gl.glPushMatrix(); 
    gl.glTranslatef(x, y, 0); 
    gl.glRotatef(rot, 0, 0, 1); 
    gl.glScalef(w, h, 0); // Scaling will be performed first. 
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); 
    gl.glPopMatrix(); 
} 

} 

回答

1

你GLSurfaceView(Stage類)應該是獲得觸摸事件的類。所以,你應該將這個方法添加到它:

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    final int action = event.getAction() & MotionEvent.ACTION_MASK; 
    float x, y; 
    int pointerIndex; 

    if (action == MotionEvent.ACTION_DOWN) { 
     pointerId = event.getPointerId(0); 
     x = event.getX(); 
     y = event.getY(); 
     pointerIndex = 0; 
    } else { 
     pointerIndex = event.getActionIndex(); 
     pointerId = event.getPointerId(pointerIndex); 
     x = event.getX(pointerIndex); 
     y = event.getY(pointerIndex); 
    } 

    // Now you have your x and y, your action (up, down, etc), and pointer index. 
} 

請記住,你已經擴大您的GLSurfaceView的虛擬維度,所以你應該做同樣的X和Y(添加這個你開始使用X之前和Y):

x = x * w/screenWidth; 
y = y * h/screenHeight; 

有關的MotionEvent的更多信息(如何處理觸摸下降/上升等),請參閱Android documentation for this class

更新:

對於翻譯,你需要有四個成員變量:

  • 保存的X和Y的觸摸。
  • 保存精靈的X和Y.

最初將它們全部設置爲無效值,例如-1。當您收到ACTION_DOWN事件時,將事件x和y以及精靈X和Y保存在變量中。

在ACTION_MOVE上,如果它是-1,則檢查其中之一。如果不是,則表示您在拖動。因此,您可以獲得新保存的x和y的區別,並將其添加到保存的X和Y.這將是您的精靈的新位置。

在ACTION_UP上,只需將保存的值設置回-1(或者至少設置一個您在ACTION_MOVE上檢查的值)。

縮放比較複雜一點。您需要查找具有大於0的指針索引的ACTION_POINTER_DOWN。一旦擁有了該指針,您也可以像轉換一樣保存第二個指針的值。您還需要保存精靈的原始比例因子。然後,無論何時獲得ACTION_MOVE或ACTION_POINTER_MOVE,您都會查看兩個指針是否存在(使用-1的技巧),如果存在,請獲得它們的區別。但是這一次的差異將構成你的縮放因子,而不是位置。

+0

先生我仍然明白,那麼我應該叫這個觸摸方法嗎?更新這個tex.draw(gl,(w/2),(h/2),tex.getWidth(),tex.getHeight(),0);功能? –

+0

我已經更新了關於這樣做的說明。這裏,(w/2)和(h/2)是你的位置座標,你需要將它們保存爲一些字段,比如spriteX和spriteY。 –

+0

布爾指針索引有錯誤,它的指針索引應該是int嗎? –