En realidad tengo una aplicación para Android 1.5 con una clase GLSurfaceView que muestra un polígono cuadrado simple en la pantalla.¿Cómo mover un cuadro OpenGL con el dedo?
Quiero aprender a agregar una nueva funcionalidad, la funcionalidad de mover el cuadrado tocándolo con el dedo. Quiero decir que cuando el usuario toca el cuadrado y mueve el dedo, el cuadrado debe pegarse al dedo, hasta que el dedo suelte la pantalla.
Cualquier tutorial/código de ejemplo/ayuda será apreciado.
Mi código:
public class MySurfaceView extends GLSurfaceView implements Renderer {
private Context context;
private Square square;
private float xrot; //X Rotation
private float yrot; //Y Rotation
private float zrot; //Z Rotation
private float xspeed; //X Rotation Speed
private float yspeed; //Y Rotation Speed
private float z = -1.15f; //Profundidad en el eje Z
private float oldX; //valor anterior de X, para rotación
private float oldY; //valor anterior de Y, para rotación
private final float TOUCH_SCALE = 0.2f; //necesario para la rotación
//create the matrix grabber object in your initialization code
private MatrixGrabber mg = new MatrixGrabber();
private boolean firstTimeDone=false; //true si la aplicación ya ha sido inicializada.
public MySurfaceView(Context context, Bitmap image) {
super(context);
this.context = context;
setEGLConfigChooser(8, 8, 8, 8, 16, 0); //fondo transparente
getHolder().setFormat(PixelFormat.TRANSLUCENT); //fondo transparente
//Transformamos esta clase en renderizadora
this.setRenderer(this);
//Request focus, para que los botones reaccionen
this.requestFocus();
this.setFocusableInTouchMode(true);
square = new Square(image);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glDisable(GL10.GL_DITHER); //dithering OFF
gl.glEnable(GL10.GL_TEXTURE_2D); //Texture Mapping ON
gl.glShadeModel(GL10.GL_SMOOTH); //Smooth Shading
gl.glClearDepthf(1.0f); //Depth Buffer Setup
gl.glEnable(GL10.GL_DEPTH_TEST); //Depth Testing ON
gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glClearColor(0,0,0,0); //fondo transparente
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
//Cargamos la textura del cubo.
square.loadGLTexture(gl, this.context);
}
public void onDrawFrame(GL10 gl) {
//Limpiamos pantalla y Depth Buffer
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
//Dibujado
gl.glTranslatef(0.0f, 0.0f, z); //Move z units into the screen
gl.glScalef(0.8f, 0.8f, 0.8f); //Escalamos para que quepa en la pantalla
//Rotamos sobre los ejes.
gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f); //X
gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f); //Y
gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f); //Z
//Dibujamos el cuadrado
square.draw(gl);
//Factores de rotación.
xrot += xspeed;
yrot += yspeed;
if (!firstTimeDone)
{
/////////////// NEW CODE FOR SCALING THE AR IMAGE TO THE DESIRED WIDTH /////////////////
mg.getCurrentProjection(gl);
mg.getCurrentModelView(gl);
float [] modelMatrix = new float[16];
float [] projMatrix = new float[16];
modelMatrix=mg.mModelView;
projMatrix=mg.mProjection;
int [] mView = new int[4];
mView[0] = 0;
mView[1] = 0;
mView[2] = 800; //width
mView[3] = 480; //height
float [] outputCoords = new float[3];
GLU.gluProject(-1.0f, -1.0f, z, modelMatrix, 0, projMatrix, 0, mView, 0, outputCoords, 0);
int i=0;
System.out.print(i);
// firstTimeDone=true;
}
}
//si el surface cambia, resetea la vista, imagino que esto pasa cuando cambias de modo portrait/landscape o sacas el teclado físico en móviles tipo Droid.
public void onSurfaceChanged(GL10 gl, int width, int height) {
if(height == 0) {
height = 1;
}
gl.glViewport(0, 0, width, height); //Reset Viewport
gl.glMatrixMode(GL10.GL_PROJECTION); //Select Projection Matrix
gl.glLoadIdentity(); //Reset Projection Matrix
//Aspect Ratio de la ventana
GLU.gluPerspective(gl, 45.0f, (float)width/(float)height, 0.1f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW); //Select Modelview Matrix
gl.glLoadIdentity(); //Reset Modelview Matrix
}
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_MOVE:
//Calculamos el cambio
float dx = x - oldX;
float dy = y - oldY;
xrot += dy * TOUCH_SCALE;
yrot += dx * TOUCH_SCALE;
//Log.w("XXXXXX", "ACTION_MOVE_NO_ZOOM");
break;
}
oldX = x;
oldY = y;
return true; //El evento ha sido manejado
}
public void zoomIn(){
z=z+0.2f;
if (z>-1.0f)
z=-1.0f;
}
public void zoomOut(){
z=z-0.2f;
if (z<-20.0f)
z=-20.0f;
}
public void rotateL(){
zrot=zrot+3.0f;
}
public void rotateR(){
zrot=zrot-3.0f;
}
public void reset()
{
xrot=0;
yrot=0;
zrot=0;
xspeed=0;
yspeed=0;
z = -5.0f;
}
}
Ésta es mi clase cuadrado:
public class Square {
//Buffer de vertices
private FloatBuffer vertexBuffer;
//Buffer de coordenadas de texturas
private FloatBuffer textureBuffer;
//Puntero de texturas
private int[] textures = new int[3];
//El item a representar
private Bitmap image;
//Definición de vertices
private float vertices[] =
{
-1.0f, -1.0f, 0.0f, //Bottom Left
1.0f, -1.0f, 0.0f, //Bottom Right
-1.0f, 1.0f, 0.0f, //Top Left
1.0f, 1.0f, 0.0f //Top Right
};
/*
private float vertices[] =
{
-0.8f, -0.8f, 0.0f, //Bottom Left
0.8f, -0.8f, 0.0f, //Bottom Right
-0.8f, 0.8f, 0.0f, //Top Left
0.8f, 0.8f, 0.0f
};
*/
//Coordenadas (u, v) de las texturas
/*
private float texture[] =
{
//Mapping coordinates for the vertices
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
*/
private float texture[] =
{
//Mapping coordinates for the vertices
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
//Inicializamos los buffers
public Square(Bitmap image) {
ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
vertexBuffer = byteBuf.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
byteBuf = ByteBuffer.allocateDirect(texture.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
textureBuffer = byteBuf.asFloatBuffer();
textureBuffer.put(texture);
textureBuffer.position(0);
this.image=image;
}
//Funcion de dibujado
public void draw(GL10 gl) {
gl.glFrontFace(GL10.GL_CCW);
//gl.glEnable(GL10.GL_BLEND);
//Bind our only previously generated texture in this case
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
//Point to our vertex buffer
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
//Enable vertex buffer
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//Draw the vertices as triangle strip
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length/3);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//gl.glDisable(GL10.GL_BLEND);
}
//Carga de texturas
public void loadGLTexture(GL10 gl, Context context) {
//Generamos un puntero de texturas
gl.glGenTextures(1, textures, 0);
//y se lo asignamos a nuestro array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
//Creamos filtros de texturas
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);
//Diferentes parametros de textura posibles GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
/*
String imagePath = "radiocd5.png";
AssetManager mngr = context.getAssets();
InputStream is=null;
try {
is = mngr.open(imagePath);
} catch (IOException e1) { e1.printStackTrace(); }
*/
//Get the texture from the Android resource directory
InputStream is=null;
/*
if (item.equals("rim"))
is = context.getResources().openRawResource(R.drawable.rueda);
else if (item.equals("selector"))
is = context.getResources().openRawResource(R.drawable.selector);
*/
/*
is = context.getResources().openRawResource(resourceId);
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
is = null;
} catch (IOException e) {
}
}
*/
Bitmap bitmap =image;
//con el siguiente código redimensionamos las imágenes que sean mas grandes de 256x256.
int newW=bitmap.getWidth();
int newH=bitmap.getHeight();
float fact;
if (newH>256 || newW>256)
{
if (newH>256)
{
fact=(float)255/(float)newH; //porcentaje por el que multiplicar para ser tamaño 256
newH=(int)(newH*fact); //altura reducida al porcentaje necesario
newW=(int)(newW*fact); //anchura reducida al porcentaje necesario
}
if (newW>256)
{
fact=(float)255/(float)newW; //porcentaje por el que multiplicar para ser tamaño 256
newH=(int)(newH*fact); //altura reducida al porcentaje necesario
newW=(int)(newW*fact); //anchura reducida al porcentaje necesario
}
bitmap=Bitmap.createScaledBitmap(bitmap, newW, newH, true);
}
//con el siguiente código transformamos imágenes no potencia de 2 en imágenes potencia de 2 (pot)
//meto el bitmap NOPOT en un bitmap POT para que no aparezcan texturas blancas.
int nextPot=256;
int h = bitmap.getHeight();
int w = bitmap.getWidth();
int offx=(nextPot-w)/2; //distancia respecto a la izquierda, para que la imagen quede centrada en la nueva imagen POT
int offy=(nextPot-h)/2; //distancia respecto a arriba, para que la imagen quede centrada en la nueva imagen POT
Bitmap bitmap2 = Bitmap.createBitmap(nextPot, nextPot, Bitmap.Config.ARGB_8888); //crea un bitmap transparente gracias al ARGB_8888
Canvas comboImage = new Canvas(bitmap2);
comboImage.drawBitmap(bitmap, offx, offy, null);
comboImage.save();
//Usamos Android GLUtils para espcificar una textura de 2 dimensiones para nuestro bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap2, 0);
//Checkeamos si el GL context es versión 1.1 y generamos los Mipmaps por Flag. Si no, llamamos a nuestra propia implementación
if(gl instanceof GL11) {
gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap2, 0);
} else {
buildMipmap(gl, bitmap2);
}
//Limpiamos los bitmaps
bitmap.recycle();
bitmap2.recycle();
}
//Nuestra implementación de MipMap. Escalamos el bitmap original hacia abajo por factor de 2 y lo asignamos como nuevo nivel de mipmap
private void buildMipmap(GL10 gl, Bitmap bitmap) {
int level = 0;
int height = bitmap.getHeight();
int width = bitmap.getWidth();
while(height >= 1 || width >= 1) {
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bitmap, 0);
if(height == 1 || width == 1) {
break;
}
level++;
height /= 2;
width /= 2;
Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true);
bitmap.recycle();
bitmap = bitmap2;
}
}
}
sí, lo he comprobado hace unas horas, y no me puede ayudar en mis necesidades – NullPointerException
¿En qué específicamente no te puede ayudar? Muestra cómo manejar las entradas y modificar la ubicación del objeto OpenGL en función de las entradas. ¿Quiso decir que quería arrastrar el objeto directamente? ¿Entonces su problema tiene más que ver con la conversión de coordenadas que con el manejo de entradas? Si ese es el caso, es posible que desee considerar el uso de una proyección ortográfica en 2d para la conversión de coordenadas universales. De lo contrario, debe hacer algunas operaciones matemáticas para calcular la posición en función de la profundidad de la cámara. – Marc
Si tiene problemas con la conversión, aquí hay un enlace SO para el mismo problema: http://stackoverflow.com/questions/7437482/gluunproject-android-opengl-es-1-1-usage – Marc