I can..
>Use Touch event to rotate the object
>Use GL10 to render the object using openGL ES 1.0
>Everything is great
Now I want to be able to zoom in and out with two fingers for a “pinch in” action. I I found some good tutorials and sample codes, but it is mainly used for ImageViews. I am still a semi newbie to Android, and I don’t fully understand how to make this zoom function work for GLSurfaceView.
The following is my current Code written for the Activity class. The first touch handler is the zoom event I found through the tutorial designed for ImageView (I use it because I think it will be a simple transition). The second handler is for rotation Event, it works normally.
Thank you in advance, I hope this article can help others to solve the same problem.
If any edits or additions are needed, I will be on standby at any time.
// Activity for rendering 3D object openGL ES 1.0
public class GL_ExampleActivity extends Activity
{
private GLSurfaceView surface;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
surface = new GL_ExampleSurfaceView(this);
setContentView(surface);
}
@Override
protected void onPause()
{
// TODO Auto-generated method stub
super.onPause();
surface.onPause();
}
@Override
protected void onResume()
{
/ / TODO Auto-generated method stub
super.onResume();
surface.onResume();
}
}
class GL_ExampleSurfaceView extends GLSurfaceView< br /> {
private static final String TAG = "Touch";
Matrix matrix_new = new Matrix();
Matrix last_matrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
private final float SCALE_FACTOR = 180.0f / 320 ;
private GLRenderer renderer;
private float previous_x;
private float previous_y;
public GL_ExampleSurf aceView(Context context)
{
super(context);
renderer = new GLRenderer();
setRenderer(renderer);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
@Override
public boolean onTouchEvent(MotionEvent e)
{
// handler for drag and zoom events
switch (e.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
last_matrix.set(matrix_new);
start.set( e.getX(), e.getY());
Log.d(TAG, "mode=DRAG");
mode = DRAG;
//requestRender();
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = finger_distance(e);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist> 10f)
{
last_matrix.set(matrix_new);
finger_distance_midpoint(mid, e);
mode = ZOOM;
Log.d(TAG , "mode=ZOOM");
}
//requestRender();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.d(TAG, "mode=NONE");
//requestRender();
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
{
matrix_new.set(last_matrix);
matrix_new.postTranslate(e.getX()-start.x, e.getY()-start. y);
}
else if (m ode == ZOOM)
{
float newDist = finger_distance(e);
Log.d(TAG, "newDist=" + newDist);
if (newDist> 10f)
{
matrix_new.set(last_matrix);
float scale = newDist / oldDist;
matrix_new.postScale(scale, scale, mid.x, mid.y);
}
}
//requestRender();
break;
}
//view.setImageMatrix(matrix_new);
// handler for rotation event, y and x axis
float x = e.getX();
float y = e.getY();
< br /> switch (e.getAction())
{
case MotionEvent.ACTION_MOVE:
float dx = x-previous_x;
float dy = y-previous_y;
if (y> getHeight() / 2)
{
dx = dx * -1 ;
}
if (x{
dy = dy * -1 ;
}
renderer.angle_x += dx * SCALE_FACTOR;
renderer.angle_y += dy * SCALE_FACTOR;
requestRender();
}
previous_x = x;
previous_y = y;
return true ;
}
private float finger_distance(MotionEvent e)
{
float x = e.getX(0)-e.getX(1) ;
float y = e.getY(0)-e.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
< br /> private void finger_distance_midpoint(PointF point, MotionEvent e)
{
float x = e.getX(0) + e.getX(1);< br /> float y = e.getY(0) + e.getY(1);
point.set(x / 2, y / 2);
}
}
Thanks again…
Another One solution is to apply a scaling factor to the projection matrix to produce the desired effect. To achieve this, just multiply the left, right, top, and bottom distances of the projection matrix by such a ratio before drawing.
gl.glFrustumf(width/2*zoom, width/2*zoom, height/2*zoom, height/2*zoom, 1, -1);
(Note, if you use an orthogonal matrix , You will use glOrthof instead)
If you are interested, you can find more information about the projection matrix here
I use standard vertices, colors And the point buffer shows a 3D object.
I can..
>Use touch events to rotate the object
>Use GL10 to render the object using openGL ES 1.0< br>>Everything is great
Now I want to be able to zoom in and out with two fingers for a “pinch in” action. I found some good tutorials and sample codes, but it is mainly used for ImageViews . I am still a semi-newbie to Android, and I don’t fully understand how to make this zoom function applicable to GLSurfaceView.
Below is the code I currently write for the Activity class. The first touch handler I passed as The zoom event found in the tutorial designed by ImageView (I use it because I think it will be a simple conversion). The second handler is for the rotation event and it works fine.
Thank you in advance , I hope this article can help others solve the same problem.
If any edits or additions are needed, I will be on standby at any time.
// Activity for rendering 3D object openGL ES 1.0
public class GL_Exampl eActivity extends Activity
{
private GLSurfaceView surface;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate( savedInstanceState);
surface = new GL_ExampleSurfaceView(this);
setContentView(surface);
}
@Override
protected void onPause ()
{
// TODO Auto-generated method stub
super.onPause();
surface.onPause();
}
@Override
protected void onResume()
{
// TODO Auto-generated method stub
super.onResume();
surface.onResume();
}
}
class GL_ExampleSurfaceView extends GLSurfaceView
{
private static final String TAG = "Touch";
Matrix matrix_new = new Matrix();
Matrix last_matrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
private final float SCALE_FACTOR = 180.0f / 320 ;
private GLRenderer renderer;
private float previous_x;
private float previous_y;
public GL_ExampleSurfaceView(Context context)
{
super( context);
renderer = new GLRenderer();
setRenderer(renderer);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
@Override
public boolean onTouchEvent(MotionEvent e)
{
// handler for drag and zoom events
switch (e.getAction() & MotionEvent.ACTION_MASK )
{
case MotionEvent.ACTI ON_DOWN:
last_matrix.set(matrix_new);
start.set(e.getX(), e.getY());
Log.d(TAG, "mode=DRAG") ;
mode = DRAG;
//requestRender();
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = finger_distance(e);
Log .d(TAG, "oldDist=" + oldDist);
if (oldDist> 10f)
{
last_matrix.set(matrix_new);
finger_distance_midpoint(mid, e);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
//requestRender();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.d(TAG, "mode=NONE");
//requestRender();
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
{
matrix_new.set(last_matrix);
matrix_new.postTranslate(e.getX()-start.x, e.getY()-start.y) ;
}
else if (mode == ZOOM)
{
float newDist = finger_distance(e);
Log.d(TAG, "newDist=" + newDist);
if (newDist> 10f)
{
matrix_new.set(last_matrix);
float scale = newDist / oldDist;
matrix_new.postScale(scale, scale, mid.x, mid.y);
}
}
//requestRender();
break;
}
//view.setImageMatrix(matrix_new);
// handler for rotation event, y and x axis
float x = e.getX();
float y = e.getY();
switch (e. getAction())
{
case MotionEvent.ACTION_MOVE:
float dx = x-previous_x;
float dy = y-previous_y;
if (y> getHeight() / 2)
{
dx = dx * -1 ;
}
if (x{
dy = dy * -1 ;
}
renderer.angle_x += dx * SCALE_FACTOR;
renderer.angle_y += dy * SCALE_FACTOR;
requestRender();
}
previous_x = x;
previous_y = y;
return true;
}
private float finger_distance(MotionEvent e)
{
float x = e.getX(0)-e.getX(1);
float y = e.getY(0)-e.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void finger_distance_midpoint(PointF point, MotionEvent e)
{
float x = e.getX(0) + e.getX(1);
float y = e.getY(0) + e.getY(1);
point.set(x / 2, y / 2);
}
}
Thanks again…
There are two obvious ways to solve this problem. If you Just want to increase the size of a single object, you can use glScalef when drawing objects. Using scalef is easy and relatively simple, but it does not fully meet your requirements.
Another solution is Apply a scaling factor to the projection matrix to produce the desired effect. To achieve this, just multiply the left, right, top, and bottom distances of the projection matrix by such a ratio before drawing.
gl.glFrustumf(width/2*zoom, width/2*zoom, height/2*zoom, height/2*zoom, 1, -1);
(Note that if you use an orthogonal matrix, you will use glOrthof instead)
If you are interested, you can find more information about the projection matrix here