onSurfaceCreated() called every time orientation changes - android

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">

Related

libgdx: main menu doesn't show game class libgdx

I am a newbie in libgdx and I have a little problem with screens and main menu.
I have a mainmenu class and it work with click on actors. The code for click is:
pulsanteplay.addListener(
new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, `float y, int pointer, int button) {
System.out.println("click play");
game.setScreen(new GameClass());
return false;
}
});
and it works. If I call Gdx.app.exit(); it works. If I call the next class, works
public class SplashScreen implements Screen {
private SpriteBatch batch;
private Texture ttrSplash;
private Timer timer;
private MainMenu mainMenuScreen;
public SplashScreen() {
super();
batch = new SpriteBatch();
ttrSplash = new Texture("quadrato.png");
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(ttrSplash, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.end();
}
#Override
public void hide() { }
#Override
public void pause() { }
#Override
public void resume() { }
#Override
public void show() { }
#Override
public void resize(int width, int height) { }
#Override
public void dispose() {
ttrSplash.dispose();
batch.dispose();
}
When I call a class that extends game and have a render method don't work. The screen don't change but the events of the game class are really generated.
Someone could explain me why this? How do I fix this bad behavior?
Thanks for your attention
Have that class that extends Game just implement Screen and put your code in it's corresponding methods. A screen offers everything a Game does so you should have no trouble converting. your onCreate code can be put in the show method or the constructor of your new Screen class. Now just call setScreen() to show this screen.

Setting up Android OpenGl ES Environment fails

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);

Libgdx time lag and delta value issue ( used with Spine to run Skeleton animation)

I am using the Libgdx framework along with Spine to do Skeleton animation using Atlas and exported Json file. In the file there are many animations. I am able to load animations from the json file. But there are 2 issues :
Lag when animation starts : there is a lag of 3-4 seconds before the animation starts. I see a black screen and then the animation works.
Delta - i have some issues with the delta time. Only some animations are running from the default delta value, however if i change ( increment or decrease the delta value), different animations give different results.
Cant understand what to do ? I have searched thoroughly in the internet but haven't found the solution.
I am posting my code below:
This is my Main Class
public class AndroidLauncher extends AndroidApplication
{
SpriteBatch batch;
Texture img;
ShapeRenderer renderer;
TextureAtlas atlas;
Skeleton skeleton;
Animation animation;
float time;
Bone root;
float x,y;
View spine_view;
private Screen curScreen; // the current screen
#Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
//initialize(new Main(20), config);
spine_view=initializeForView(new ApplicationListener()
{
#Override
public void resume()
{
curScreen.resume();
}
#Override
public void resize(int width, int height)
{
}
#Override
public void render()
{
curScreen.render((Gdx.graphics.getDeltaTime()/(1.5f))); //call the rendermethod with the delta time as parameter
}
#Override
public void pause()
{
curScreen.pause();
}
#Override
public void dispose()
{
curScreen.dispose();
}
#Override
public void create()
{
Gdx.graphics.getWidth();
Gdx.graphics.getHeight();
Firstscreen temp = new Firstscreen();//just an example of the first screen to load up
setScreen(temp);
}
}, config);
LinearLayout l1 = (LinearLayout) findViewById(R.id.container);
l1.addView(spine_view);
}
public void setScreen(Screen s) {
if (curScreen != null) {
curScreen.hide();
curScreen.dispose();
}
curScreen = s;
curScreen.show();
}
}
...............................................
And this is the screen Iam rendering
public class Firstscreen implements Screen
{
SpriteBatch batch;
Texture img;
ShapeRenderer renderer;
TextureAtlas atlas;
Skeleton skeleton;
Animation animation;
float time;
Bone root;
float x,y;
int count =0;
#Override
public void render(float delta)
{
// track
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
time += delta;
animation.apply(skeleton,delta,time, false, null);
SkeletonRenderer render = new SkeletonRenderer();
batch.begin();
render.draw(batch, skeleton);
skeleton.updateWorldTransform();
batch.end();
}
#Override
public void resize(int width, int height)
{
}
#Override
public void show()
{
batch = new SpriteBatch();
renderer = new ShapeRenderer();
atlas = new TextureAtlas(Gdx.files.internal("abc.atlas"));
SkeletonJson json = new SkeletonJson(atlas);
// set the scale of skeleton
json.setScale(0.3f);
SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("skeleton.json"));
skeleton = new Skeleton(skeletonData);
skeleton.setToSetupPose();
skeleton.setSkin("Carla");
// set the position of the skeleton to render( here middle)
skeleton.setPosition((Gdx.graphics.getWidth()/2)-(x/2),( Gdx.graphics.getHeight()/2)-(y/2));
//animation = skeletonData.findAnimation("KID-LEVEL 2 - Couch potato");
animation = skeletonData.findAnimation("LEVEL 91- Around a world");
//animation = skeletonData.findAnimation("KID-LEVEL 7 - Super Hero");
}
#Override
public void hide()
{
}
#Override
public void pause()
{
}
#Override
public void resume()
{
}
#Override
public void dispose()
{
batch.dispose();
}
}
That's happens beacuse you are managing a timeline manually.
Use AnimationState instead:
Skeleton skeleton = new Skeleton(skeletonData);
// sctruct for mix animations
AnimationStateData stateData = new AnimationStateData(skeletonData);
// and state
AnimationState state = new AnimationState(stateData);
In some update method (or render, if you prefer update while rendering) call something like this:
state.update(delta);
And in the actual render method:
// apply the state to skeleton
state.apply(skeleton);
// update transformations
skeleton.updateWorldTransform();
// draw then
render.draw(batch, skeleton);
So, AnimationState isn't designed not for managing the delta only, you can play&mix animations using it:
state.setAnimation(0, "LEVEL 91- Around a world", isLoop);
To change animation speed use setTimeScale:
state.setTimeScale(0.5f); // set any time scale you want
Also, you may have some perfomance issues because you calling new SkeletonRenderer() in render method. To fix that, move this code to constructor.

How to get the GLSurface Size?

How can I get the Wisth and Height of the GLSurfaceView I am currently render in, in pixels?
may be this:
#Override
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
}
of
public class MyGLRenderer implements GLSurfaceView.Renderer

Extended SurfaceView's onDraw() method never called

I'm trying to modify the SurfaceView I use for doing a camera preview in order to display an overlaying square. However, the onDraw method of the extended SurfaceView is never called.
Here is the source :
public class CameraPreviewView extends SurfaceView {
protected final Paint rectanglePaint = new Paint();
public CameraPreviewView(Context context, AttributeSet attrs) {
super(context, attrs);
rectanglePaint.setARGB(255, 200, 0, 0);
rectanglePaint.setStyle(Paint.Style.FILL);
rectanglePaint.setStrokeWidth(2);
}
#Override
protected void onDraw(Canvas canvas){
canvas.drawRect(new Rect(10,10,200,200), rectanglePaint);
Log.w(this.getClass().getName(), "On Draw Called");
}
}
public class CameraPreview extends Activity implements SurfaceHolder.Callback{
private SurfaceHolder holder;
private Camera camera;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// We remove the status bar, title bar and make the application fullscreen
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// We set the content view to be the layout we made
setContentView(R.layout.camera_preview);
// We register the activity to handle the callbacks of the SurfaceView
CameraPreviewView surfaceView = (CameraPreviewView) findViewById(R.id.camera_surface);
holder = surfaceView.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Camera.Parameters params = camera.getParameters();
params.setPreviewSize(width, height);
camera.setParameters(params);
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
camera.startPreview();
}
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
}
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
}
}
Found it on the android-developers Google group. You simply have to add :
setWillNotDraw(false)
To the constructor. Now if someone could explain me why, that would be greatly appreciated.
Minor correction:
Adding setWillNotDraw(false) to the constructor will cause crashes, because the underlying Surface object is not created yet.
Instead, put the setWillNotDraw(false) statement into the surfaceCreated() method. This delays the call until there's a real object to work with, and works properly.
(and many thanks to the users who posted this solution, it solved a major problem for me)
Romain Guy explained it:
For efficiency, layouts do not get their onDraw() method called. To
enable it, call setWillNotDrawEnabled(false) (or set the equivalent
XML attribute to false.)
Based on all above comments I used :
Add setWillNotDraw(false) in the onAttachedToWindow() event.
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
setWillNotDraw(false);
}
and it worked.

Categories

Resources