I want to learn how to use OpenGL for Android. Therefore I followed this guide to set up the environment.
I have done everything like they say:
I got a OpenGLActivity which initiates my MyGLSurfaceView:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
glSurfaceView = new MyGLSurfaceView(this);
setContentView(R.layout.activity_open_gl);
}
This is my MyGLSurfaceView:
class MyGLSurfaceView extends GLSurfaceView {
private final MyGLRenderer mRenderer;
public MyGLSurfaceView(Context context) {
super(context);
// Create an OpenGL ES 2.0 context
setEGLContextClientVersion(2);
mRenderer = new MyGLRenderer();
// Set the Renderer for drawing on the GLSurfaceView
setRenderer(mRenderer);
}
}
And Thats my MyGLRenderder class which should set the background to black:
public class MyGLRenderer implements Renderer {
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
public void onDrawFrame(GL10 unused) {
// Redraw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
}
And I've added this line to my AndroidManifest.xml (right at the beginning, before <application> tag)
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
The problem is that the background isn't black, its white.
Am I missing something?
You're not actually displaying your OpenGL view. In this code here:
glSurfaceView = new MyGLSurfaceView(this);
setContentView(R.layout.activity_open_gl);
you're setting the content view to be a view from your layout, while you're not using the GLSurfaceView you just created. It should be:
glSurfaceView = new MyGLSurfaceView(this);
setContentView(glSurfaceView);
Related
I am trying for weeks to render a vlc streaming to OpenGL on Android.
I guess I am missing something. Here is what I have so far.
This is my custom class:
public class VLCVideoView extends SurfaceView implements SurfaceHolder.Callback, IVideoPlayer, GLSurfaceView.Renderer
My initialization on VLC:
try {
// Create a new media player
libvlc = LibVLC.getInstance();
libvlc.setHardwareAcceleration(LibVLC.HW_ACCELERATION_FULL);
libvlc.eventVideoPlayerActivityCreated(true);
libvlc.setSubtitlesEncoding("");
libvlc.setAout(LibVLC.AOUT_OPENSLES);
libvlc.setVout(LibVLC.VOUT_OPEGLES2);
//libvlc.setVout(LibVLC.VOUT_ANDROID_SURFACE);
libvlc.setTimeStretching(true);
libvlc.setChroma("RV32");
libvlc.setVerboseMode(true);
LibVLC.restart(context);
holder.setFormat(PixelFormat.RGBA_8888);
mSurface = holder.getSurface();
libvlc.attachSurface(mSurface, this);
Implemented the entire GLSurfaceView.Renderer methods:
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
#Override
public void onSurfaceChanged(GL10 gl, int width, int height)
#Override
public void onDrawFrame(GL10 gl)
As well, as:
#Override
protected void onDraw(Canvas canvas) for the VLCVideoView
{
if (mSurface!= null)
{
try {
Canvas surfaceCanvas = mSurface.lockCanvas(null);
if(surfaceCanvas != null)
{
super.onDraw(surfaceCanvas);
mSurface.unlockCanvasAndPost(surfaceCanvas);
}
} catch (Surface.OutOfResourcesException excp) {
excp.printStackTrace();
}
}
}
I have a rotating cube being draw, but instead of having the streaming frames as textures, it simple appears streaming on a flat surface.
Any clue?
I'm trying to put an object on camera view using open gl, it works good on emulator but when I test it on real android device the camera view or open gl object does not be shown.
this is my MainActivity class
public class MainActivity extends Activity {
// Our variables
CameraPreview cv;
GLSurfaceView glView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final int index = getIntent().getIntExtra("index", 0);
/* Set the screen orientation to landscape, because
* the camera preview will be in landscape, and if we
* don't do this, then we will get a streached image.*/
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// requesting to turn the title OFF
requestWindowFeature(Window.FEATURE_NO_TITLE);
// making it full screen
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
glView = new GLSurfaceView(this);
glView.setZOrderOnTop(true);
glView.getHolder().setFormat( PixelFormat.TRANSLUCENT );
glView.setRenderer(new GlRenderer(this, index));
// Now set this as the main view.
setContentView( glView );
Load();
}
public void Load(){
// Try to get the camera
Camera c = getCameraInstance();
// If the camera was received, create the app
if (c != null){
// Create a new camera view and add it to the layout
cv = new CameraPreview(this,c);
cv.setZOrderOnTop(false);
if(glView != null){
// Set the layout as the apps content view
addContentView( cv, new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT ) );
}
}
// If the camera was not received, close the app
else {
Toast toast = Toast.makeText(getApplicationContext(),
"Unable to find camera. Closing.", Toast.LENGTH_SHORT);
toast.show();
finish();
}
}
/* This method is strait for the Android API */
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open();// attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
e.printStackTrace();
}
return c; // returns null if camera is unavailable
}
/* Override the onPause method so that we
* can release the camera when the app is closing.
*/
#Override
protected void onPause() {
super.onPause();
if (cv != null){
cv.onPause();
cv = null;
}
}
/* We call Load in our Resume method, because
* the app will close if we call it in onCreate
*/
#Override
protected void onResume(){
super.onResume();
}
}
and this is the GlRenderer class
public class GlRenderer implements Renderer {
private Square square; // the square
private Context context;
private int imageIndex;
/** Constructor to set the handed over context */
public GlRenderer(Context context, int index) {
this.context = context;
imageIndex = index;
// initialise the square
this.square = new Square(imageIndex);
}
#Override
public void onDrawFrame(GL10 gl) {
// clear Screen and Depth Buffer
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Reset the Modelview Matrix
gl.glLoadIdentity();
// Drawing
gl.glTranslatef(0.0f, -1.0f, -4.5f); // move 5 units INTO the screen
gl.glRotatef(-90, 1, 0, 0);
// otherwise it will be too large
square.draw(gl); // Draw the triangle
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
if(height == 0) { //Prevent A Divide By Zero By
height = 1; //Making Height Equal One
}
gl.glViewport(0, 0, width, height); //Reset The Current Viewport
gl.glMatrixMode(GL10.GL_PROJECTION); //Select The Projection Matrix
gl.glLoadIdentity(); //Reset The Projection Matrix
//Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW); //Select The Modelview Matrix
gl.glLoadIdentity(); //Reset The Modelview Matrix
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Load the texture for the square
square.loadGLTexture(gl, this.context);
gl.glEnable(GL10.GL_TEXTURE_2D); //Enable Texture Mapping ( NEW )
gl.glShadeModel(GL10.GL_SMOOTH); //Enable Smooth Shading
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClearDepthf(1.0f); //Depth Buffer Setup
gl.glEnable(GL10.GL_DEPTH_TEST); //Enables Depth Testing
gl.glDepthFunc(GL10.GL_LEQUAL); //The Type Of Depth Testing To Do
//Really Nice Perspective Calculations
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
}
I think the main problem is in my open gl code. because when I run the app on real devices the camera view gets displayed for a short time until the open gl object overlays on it. Anyhow I put both classes. In AndroidManifest I chose API 7 as the minimum SDK and both the CAMERA permission and camera hardware feature is added
Fortunately I found the answer. I added these lines:
setContentView( glView , new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
addContentView( cv, new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT ) );
glView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
I have my class:
public class CustomDrawableView extends View{
private ShapeDrawable shapeDrawable;
public CustomDrawableView(Context context) {
super(context);
shapeDrawable = new ShapeDrawable(new OvalShape());
shapeDrawable.getPaint().setColor(Color.GREEN);
shapeDrawable.setBounds(20,20,20,20);
}
protected void onDraw(Canvas canvas){
shapeDrawable.draw(canvas);
}
}
Then in the main activity I have this code in the oncreate function:
private CustomDrawableView customDrawableView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
customDrawableView = new CustomDrawableView(this);
setContentView(customDrawableView);
}
For some reason, it doesn't draw though. I have my CustomDrawableView class which I have created an instance of in the oncreate method in mainactiviy. I have set the content view to the instance of my class too.
Also, is this a good way to create graphics for a game I want to make. Thanks
Check this call:
shapeDrawable.setBounds(20,20,20,20);
the parameters are left, top, right, bottom, so it effectively sets the size of the drawable to 0.
I'm implementing the GLSurfaceView.Renderer like so:
public class GL20Renderer implements GLSurfaceView.Renderer {
private static GL20Renderer mInstance = new GL20Renderer();
private GL20Renderer() {}
public static GL20Renderer getInstance() {
return mInstance;
}
#Override
public void onDrawFrame(GL10 gl) {
Log.e("App", "onDrawFrame()");
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.e("App", "onSurfaceChanged()");
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Log.e("App", "onSurfaceCreated()");
}
}
This class is implemented in the MainActivity:
public class MainActivity extends Activity {
private GLSurfaceView mGLView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
// Create a GLSurfaceView instance and set it as the ContentView for this Activity
mGLView = new GL20SurfaceView(this);
setContentView(mGLView);
}
#Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}
#Override
protected void onResume() {
super.onResume();
mGLView.onResume();
}
}
GL20SurfaceView is:
public class GL20SurfaceView extends GLSurfaceView {
public GL20SurfaceView(Context context) {
super(context);
// Create an OpenGL ES 2.0 context.
setEGLContextClientVersion(2);
// Set the Renderer for drawing on the GLSurfaceView
setRenderer(GL20Renderer.getInstance());
}
}
Very simple as you can see.
When I now start the App, the onSurfaceCreated() method is correctly called, follow by one call of onSurfaceChanged().
Problem now is: Whenever the device orientation changes, I get another call of onSurfaceCreated() followed by onSurfaceChanged().
In my understanding, the onSurfaceCreated() method is called whenever a new surface needs to be created. My question is: Why does it do that whenever I change just the device orientation? Shouldn't it be sufficient that only a onSurfaceChanged() call is triggered in order to adjust the viewport?
Note that I don't put my device to sleep when changing the orientation.
DO this way
<activity
android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
/>
The one of advantages of OpenGL that you draw regards to screen size. It gives you ability to handle all Android resolutions.
I'm not sure how it works with GL20 (sure the same like GL10).
As I know in onSurfaceChanged provides several configurations for OpenGL based on length/width of your screen.
For example glViewport
It is necessary to call glViewport handler when GL view dimensions are modified.
Only if you have width = height is unnecessary but its other story.
as exampe
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// prevent 0 divide
if(height == 0) {
height=1;
}
screenWidth = width;
screenHeight = height;
ratio = (float) width/height;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(0, width, 0, height, -10f, 10f);
gl.glViewport(0, 0, screenWidth, screenHeight);
If you want to avoid that, add to Manifest.xml:
<activity android:name="Activity"
android:configChanges="screenSize|orientation">
So I have this class which extends an activity. But I want to draw something on the screen, so I need to make a canvas. However I can't extends View, because it's an activity allready. What should I do?
My activity has the onClick method which I use to do some stuff, but what I wanna do is draw a simple image when I call the onClick method as well.
Thanks.
public class Stuff extends Activity implements OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
(...)
}
#Override
public void onClick(View arg0) {
(...)
}
STEP 1: create a class by extends View as:
public class DrawView extends View {
public float currentX=40;
public float currentY=50;
public DrawView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint=new Paint();
paint.setColor(Color.RED);
canvas.drawCircle(currentX, currentY, 25, paint);
}
}
STEP 2: In Your Stuff Activity :
public class Stuff extends Activity implements OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout root=(LinearLayout) findViewById(R.id.root);
(...)
}
#Override
public void onClick(View arg0) {
//DRAW YOUR VIEW ON BUTTON CLICK
final DrawView drawView=new DrawView(this);
drawView.setMinimumWidth(300);
drawView.setMinimumHeight(500);
drawView.currentX=200;
drawView.currentY=200;
drawView.invalidate();
root.addView(drawView);
(...)
}
STEP 3: Your Activity main.xml as :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#99FFCC"
android:id="#+id/root">
</LinearLayout>
and finally try to search on google before asking question here.thanks
You can declare an inner class within ur activity for ex refer this code:
public class GraphicsTest extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new GraphicsTestView(this));
}
private static class GraphicsTestView extends View
{
private ShapeDrawable mDrawable =
new ShapeDrawable();
/* Drawable's are objects which can be drawn on a Canvas
ShapeDrawable is used to draw primitive shapes such as:
ArcShape, OvalShape, PathShape, RectShape, RoundRectShape
A Canvas is the object provided by Android on which
a view tries to draw itself. In addition to ShapeDrawable,
there are other subclasses of Drawable like PictureDrawable,
RotateDrawable, ScaleDrawable, ClipDrawable,GradientDrawable, etc
Some of these we will see when we consider the XML approach to
graphics
*/
public GraphicsTestView (Context context)
{
super(context);
setFocusable(true);
this.mDrawable.getPaint().setColor(0xFFFF0000);
//argb where a is alpha (transparency)
}
#Override
protected void onDraw(Canvas canvas)
/* the onDraw method is where a view draws itself
this is our first time overriding it.
*/
{
int x = 10;
int y = 10;
int width = 300;
int height = 50;
this.mDrawable.setBounds(x, y, x + width, y + height);
this.mDrawable.draw(canvas);
ArcShape arc = new ArcShape(45,90); //start angle, sweep angle
ShapeDrawable test = new ShapeDrawable(arc);
Paint p = test.getPaint();
p.setColor(0xFF00FFFF);
p.setStyle(Paint.Style.STROKE);
test.setBounds(10, 70, 310, 370);
//Top-Left, Bottom Right of rectangle to draw into
test.draw(canvas);
}
}
}
Are you saying you want to get the layout view in your XML file? You can draw the views in it, get your code to call it and view it, and then set the images to respond when clicked.
In your onCreate method, after super.onCreate(savedInstanceState); add this setContentView(R.id.layoutname)
For example
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
As for the onClickListener, you can set the views to implement it like this since you already implement it in the Activity.
// set this after "setContentView(R.layout.main);"
b1 = (Button)findViewById(R.id.main);
b1.setOnClickListener(this);