I have a beginner OpenGL app I made that shows a spinning taurus loaded from an obj file. It was working just fine and I showed my friends. Yesterday I opened the app and the view doesn't update anymore. If I press the home button and then tap on the app again, it will update the view so I know the main loop is active.
I went home and plugged it into android studio to confirm the render thread is firing just fine and view.requestRender(); is also being called.
I have no idea why this stopped working.
Here's my android fragment that loads the view and renderer
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
/**
* Inflate the layout for this fragment
*/
View root = inflater.inflate(R.layout.glfragment, container, false);
GLSurfaceView glview = (GLSurfaceView)root.findViewById(R.id.surface_view);
Log.i("Method", "OpenGLFragment::onCreateView()");
Context context = this.getActivity().getApplicationContext();
MyRenderer renderer = new MyRenderer(context);
glview.setEGLContextClientVersion(2);
glview.setRenderer(renderer);
glview.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
loadMeshes(context); // loads obj file into variable tourus
renderer.addToScene(tourus);
update = new GraphicsThread(glview);
update.start();
return root;
}
#Override
public void onDestroyView() {
if(update != null) {
update.quit();
}
super.onDestroyView();
}
Here's the graphics thread:
public class GraphicsThread extends Thread {
private GLSurfaceView.Renderer renderer;
private GLSurfaceView view;
private boolean isRunning;
public GraphicsThread(GLSurfaceView view) {
this.view = view;
this.isRunning = true;
}
#Override
public void run() {
while (this.isRunning) {
view.requestRender(); // I verified this loop is executed just fine
}
}
public void quit() {
this.isRunning = false;
}
}
Here's MyRenderer code
public class MyRenderer implements GLSurfaceView.Renderer {
private int program; // default shader program
private List<Mesh> drawables;
private Context context;
private long lastFrameTime;
private RenderInfo info; // MVP and Light matrices
private Bitmap bg;
public MyRenderer(Context context) {
this.drawables = new ArrayList<>();
this.context = context;
this.lastFrameTime = 0;
this.info = null;
}
#Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
info = new RenderInfo(context);
GLES20.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
GLES20.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLES20.glEnable(GLES20.GL_CULL_FACE);
}
public void onDrawFrame(GL10 unused){
// Redraw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
float elapsed = getElapsedTime();
float rot = 10.0f*elapsed;
for(Mesh m : drawables) {
m.rotateX(rot);
m.draw(info, elapsed);
}
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
if(width > 0 && height > 0) {
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
info.resizePerspective(left, right, 1, -1);
}
}
public void addToScene(Mesh mesh) {
drawables.add(mesh);
}
private float getElapsedTime() {
long currentTime = SystemClock.elapsedRealtime();
float elapsed = (float)(currentTime - lastFrameTime) / 1000.0f; //convert ms to seconds
lastFrameTime = currentTime;
return elapsed;
}
}
Finally here is how I draw my meshes. RenderInfo has world information like camera MVP matrix and lights and their matrices. Nothing related to the issue.
public void draw(RenderInfo info, float elapsed) {
if(!loaded) {
Log.d("Mesh", "failed to draw");
return;
};
final int program = info.getProgram();
int position = GLES20.glGetAttribLocation(program, "a_Position");
int normal = GLES20.glGetAttribLocation(program, "a_Normal");
int aColor = GLES20.glGetAttribLocation(program, "a_Color");
//int textcoord = GLES20.glGetAttribLocation(program, "a_TexCoordinate");
GLES20.glEnableVertexAttribArray(position);
GLES20.glVertexAttribPointer(position, 3, GLES20.GL_FLOAT, false, 3 * 4, verticesBuffer);
GLES20.glEnableVertexAttribArray(aColor);
GLES20.glVertexAttribPointer(aColor, 4, GLES20.GL_FLOAT, true, 4*4, colorBuffer);
//GLES20.glEnableVertexAttribArray(normal);
//GLES20.glVertexAttribPointer(normal, 3, GLES20.GL_FLOAT, false, 3 * 4, normalBuffer);
float[] modelMatrix = new float[16];
Matrix.setIdentityM(modelMatrix, 0);
Matrix.setRotateM(modelMatrix, 0, rotX , 1.0f, 0.0f, 0.0f);
//Matrix.setRotateM(modelMatrix, 0, rotY , 0.0f, 1.0f, 0.0f);
//Matrix.setRotateM(modelMatrix, 0, rotZ , 0.0f, 0.0f, 1.0f);
float[] mvpMatrix = info.getMVP(modelMatrix);
int MVP = GLES20.glGetUniformLocation(program, "u_MVP");
GLES20.glUniformMatrix4fv(MVP, 1, false, mvpMatrix, 0);
float[] mvMatrix = info.getMV();
int MV = GLES20.glGetUniformLocation(program, "u_MV");
GLES20.glUniformMatrix4fv(MV, 1, false, mvMatrix, 0);
int lightM = GLES20.glGetAttribLocation(program, "u_LightPos");
GLES20.glUniformMatrix4fv(lightM, 1, false, info.getLightMatrix(), 0);
int lightCol = GLES20.glGetAttribLocation(program, "u_LightCol");
GLES20.glUniform4fv(lightCol, 1, info.getLightColor(), 0);
Log.d("boogio", "u_LightCol is: " + Integer.toString(lightCol));
GLES20.glDrawElements(GLES20.GL_TRIANGLES, facesList.size() * 3, GLES20.GL_UNSIGNED_SHORT, facesBuffer);
GLES20.glDisableVertexAttribArray(position);
GLES20.glDisableVertexAttribArray(aColor);
//GLES20.glDisableVertexAttribArray(normal);
}
TL;DR: App renders fine and used to update fine. Suddenly the app doesn't update visually (no redraws). It only redraws when the app loses and regains focus for 1 frame. No idea why.
You don't post all the code, so it's impossible to reproduce the situation. All that I can do to help you is to suggest some things.
1 - Preserve context and add OpenGL check error
First of all, better to tell to the GLView to preserve set OpenGL context using the setPreservceEGLContext. In case this does not resolve the situation, it is better to enable DEBUG trace on OpenGL ES context, using setDebugFlas method.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
/**
* Inflate the layout for this fragment
*/
View root = inflater.inflate(R.layout.glfragment, container, false);
GLSurfaceView glview = (GLSurfaceView)root.findViewById(R.id.surface_view);
Log.i("Method", "OpenGLFragment::onCreateView()");
Context context = this.getActivity().getApplicationContext();
MyRenderer renderer = new MyRenderer(context);
glview.setEGLContextClientVersion(2);
// added code
glview.setDebugFlags(GLSurfaceView.DEBUG_CHECK_GL_ERROR); // enable log
glview.setPreserveEGLContextOnPause(true); // default is false
glview.setRenderer(renderer);
glview.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
loadMeshes(context); // loads obj file into variable tourus
renderer.addToScene(tourus);
update = new GraphicsThread(glview);
update.start();
return root;
}
This will add more debug information to your app in logcat (I hope you already know what it is). I aspect you will find some errors (lines with OPEN GL error .. something).
I suspect that you reopen the activity, the OpenGL context tries to use resources that are no more valid (because the OpenGL context is destroyed). A typical example of resources that you need to manage during context recreation is texture and shader programs.
2 - Check the Graphic Thread
Just add some Log debug info to Graphic Thread:
public class GraphicsThread extends Thread {
private GLSurfaceView.Renderer renderer;
private GLSurfaceView view;
private boolean isRunning;
public GraphicsThread(GLSurfaceView view) {
this.view = view;
this.isRunning = true;
Log.i("GraphicsThread", "GraphicsThread::constructor()");
}
#Override
public void run() {
while (this.isRunning) {
Log.i("GraphicsThread", "requestRender");
view.requestRender(); // I verified this loop is executed just fine
}
}
public void quit() {
this.isRunning = false;
Log.i("GraphicsThread", "GraphicsThread::quit()");
}
}
The log info on GraphicThread will help you to check if the thread works as aspected.
Some explainations
glview.setPreserveEGLContextOnPause(true); preserves resources when you destroy the context (screen rotation or activity in the background): the alternative is to recreate and reload all the resources. I suppose it was done because, in the beginning, Android Devices had no memory to preserve the GLContext when the GLView was destroyed.
RENDERMODE_CONTINUOUSLY tells to GLView to draw scene whenever it can (and this is the best way for what I know).
I hope my suggestions can help you.
Related
This is my second game application using LibGdx framework and this is my first time to use a framework in android. I'm trying to understand how to use it.I have already done with the design in the main menu and my problem is the functionality of each button to switch screen. Any link tutorial or sample codes are much appreciated thank you and advance
Here is my code
MainScreen.java
public class MainScreen extends ApplicationAdapter implements Screen {
//Screen Size
private static final int WIDTH= 720;
private static final int HEIGHT= 1280;
Viewport viewport;
private Camera camera;
private Stage stage;
private TextureRegion myTextureRegion;
private TextureRegionDrawable myTexRegionDrawable;
private ImageButton playBtn;
private Texture Background,logo,exit,credits,help,option,play;
SpriteBatch spriteBatch;
Sprite sprite;
MyGdxGame game;
public MainScreen(final MyGdxGame game) {
this.game = game;
stage = new Stage(new ScreenViewport());
Gdx.input.setInputProcessor(stage);
spriteBatch = new SpriteBatch();
camera = new PerspectiveCamera();
viewport = new ScreenViewport(camera);
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Background = new Texture(Gdx.files.internal("backgroundimage.png")); //background image
//Menu Buttons
exit = new Texture(Gdx.files.internal("menu/exit.png"));
logo = new Texture(Gdx.files.internal("menu/logo.png"));
option = new Texture(Gdx.files.internal("menu/options.png"));
help = new Texture(Gdx.files.internal("menu/help.png"));
credits = new Texture(Gdx.files.internal("menu/credits.png"));
play = new Texture(Gdx.files.internal("menu/play.png"));
sprite = new Sprite(play);
sprite.setPosition(130,360);
sprite.setSize(0,0);
myTextureRegion = new TextureRegion(play);
myTexRegionDrawable = new TextureRegionDrawable(myTextureRegion);
playBtn = new ImageButton(myTexRegionDrawable); //Set the button up
stage.addActor(playBtn); //Add the button to the stage to perform rendering and take input.
Gdx.input.setInputProcessor(stage);
playBtn.addListener(new InputListener(){
#Override
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
System.out.println("Button Pressed");
game.setScreen(new IngamedayOne());
}
#Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
return true;
}
});
stage.addActor(playBtn);
}
#Override
public void create(){
}
#Override
public void show() {
Gdx.input.setInputProcessor(stage); //Start taking input from the ui
}
#Override
public void render(float delta) {
}
#Override
public void resize(int width, int height) {
// viewport.update(width, height);
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Clear screen
spriteBatch.begin();
spriteBatch.getProjectionMatrix().setToOrtho2D(0, 0, WIDTH, HEIGHT);
spriteBatch.draw(Background,0,0);
spriteBatch.draw(exit,590,1140);
spriteBatch.draw(logo,125,600);
spriteBatch.draw(play,130,360);
spriteBatch.draw(option,170,100);
spriteBatch.draw(help,350,100);
spriteBatch.draw(credits,470,100);
stage.act(Gdx.graphics.getDeltaTime()); //Perform ui logic
spriteBatch.end();
//stage.draw(); //Draw the ui
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
Background.dispose();
logo.dispose();
exit.dispose();
}
}
My Second Screen
public class IngamedayOne extends ApplicationAdapter implements Screen {
// Constant rows and columns of the sprite sheet
private static final int FRAME_COLS = 5, FRAME_ROWS = 1;
private boolean peripheralAvailable;
// Objects used
Animation<TextureRegion> walkAnimation; // Must declare frame type (TextureRegion)
private Texture cat ,left_paw,right_paw,progressbar_background,progressbar_knob,pause,meter;
Texture carpet,desk,plants,square_carpet,shoes;
SpriteBatch spriteBatch;
Sprite sprite;
private Texture Background;
Viewport viewport;
private Camera camera;
private Stage stage;
// A variable for tracking elapsed time for the animation
float stateTime;
//Screen Size
private static final int WIDTH= 720;
private static final int HEIGHT= 1280;
public IngamedayOne() {
}
public IngamedayOne(MyGdxGame game) {
}
#Override
public void create() {
stage = new Stage();
spriteBatch = new SpriteBatch();
// Load the sprite sheet as a texture
cat = new Texture(Gdx.files.internal("cat.png"));
sprite = new Sprite(cat);
sprite.setPosition(0,0);
sprite.setSize(0,0);
peripheralAvailable = Gdx.input.isPeripheralAvailable(Input.Peripheral.Accelerometer);
camera = new PerspectiveCamera();
viewport = new ScreenViewport(camera);
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
//Display Items
carpet = new Texture("equip/carpet2.png");
desk = new Texture("equip/Desk.png");
square_carpet = new Texture("equip/Carpet.png");
plants = new Texture("equip/Plants.png");
shoes = new Texture("equip/Shoes.png");
// Progressbar
progressbar_background = new Texture("progression_map.png");
progressbar_knob = new Texture("cat_head.png");
//pause
pause = new Texture("pause.png");
meter = new Texture("meter.png");
//background
Background = new Texture(Gdx.files.internal("floor.png")); //File from assets folder
//button controller
left_paw = new Texture(Gdx.files.internal("left_paw.png"));
sprite = new Sprite(left_paw);
right_paw = new Texture(Gdx.files.internal("right_paw.png"));
sprite = new Sprite(right_paw);
// Use the split utility method to create a 2D array of TextureRegions. This is
// possible because this sprite sheet contains frames of equal size and they are
// all aligned.
TextureRegion[][] tmp = TextureRegion.split(cat, cat.getWidth() / FRAME_COLS, cat.getHeight()/ FRAME_ROWS);
// Place the regions into a 1D array in the correct order, starting from the top
// left, going across first. The Animation constructor requires a 1D array.
TextureRegion[] walkFrames = new TextureRegion[FRAME_COLS * FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++) {
for (int j = 0; j < FRAME_COLS; j++) {
walkFrames[index++] = tmp[i][j];
}
}
// Initialize the Animation with the frame interval and array of frames
walkAnimation = new Animation<TextureRegion>(0.200f, walkFrames);
// Instantiate a SpriteBatch for drawing and reset the elapsed animation
// time to 0
spriteBatch = new SpriteBatch();
stateTime = 0f;
}
#Override
public void show() {
}
#Override
public void render(float delta) {
}
#Override
public void resize(int width, int height) {
viewport.update(width, height);
}
#Override
public void render() {
// clear previous frame
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Clear screen
stateTime += Gdx.graphics.getDeltaTime(); // Accumulate elapsed animation time
// Get current frame of animation for the current stateTime
TextureRegion currentFrame = walkAnimation.getKeyFrame(stateTime, true);
spriteBatch.begin();
spriteBatch.getProjectionMatrix().setToOrtho2D(0, 0, WIDTH, HEIGHT);
spriteBatch.draw(Background,0,0);
spriteBatch.draw(square_carpet,150,2,408,800);
spriteBatch.draw(carpet,230,980,250,260);
spriteBatch.draw(desk,10,1150,160,260);
spriteBatch.draw(plants,500,700,200,260);
spriteBatch.draw(shoes,300,500,110,110);
spriteBatch.draw(meter,190,990);
spriteBatch.draw(progressbar_background,20,1170);
spriteBatch.draw(progressbar_knob,18,1170);
spriteBatch.draw(pause,580,1150);
spriteBatch.draw(left_paw,10,25);
spriteBatch.draw(right_paw,517,25);
spriteBatch.draw(currentFrame, 260, 120 ); // Draw current frame at (50, 50)
spriteBatch.end();
stage.act(); //acting a stage to calculate positions of actors etc
stage.draw(); //drawing it to render all
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() { // SpriteBatches and Textures must always be disposed
spriteBatch.dispose();
cat.dispose();
left_paw.dispose();
right_paw.dispose();
stage.dispose();
Background.dispose();
progressbar_background.dispose();
progressbar_knob.dispose();
}
}
Your game should possess only one ApplicationListener(called when your application created).
Let's suppose that is your MainScreen which extends ApplicationAdapter(Adapter class of ApplicationListener interface), then not extend your IngamedayOne class again by ApplicationAdapter. You only need to implement with Screen interface.
public class IngamedayOne implements Screen {
}
create() method comes from ApplicationListener interface so migrate your code that in inside create() method to show().
Take a look of this wiki for more clearance.
https://github.com/libgdx/libgdx/wiki/Extending-the-simple-game
You should create actors to add to your stage (in this case buttons, like an ImageButton)
and then use the setScreen() function to change screens on button presses addClickListener()
You can read more about it here:
https://github.com/libgdx/libgdx/wiki/Scene2d
Hi I am developing the game, where i need scrolling and repeating background. Following are my code:
Main Game Class:
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
BitmapFont font;
float bgX =0f;
Texture background,background2;
On Create:
public void create () {
batch = new SpriteBatch();
background = new Texture("background.png");
background2 = new Texture("background.png");
On Render:
public void render () {
batch.begin();
bgX -=1;
batch.draw(background,bgX,0,background.getWidth(),Gdx.graphics.getHeight());
batch.draw(background2,background.getWidth() + bgX,0,background.getWidth(),Gdx.graphics.getHeight());
if(bgX <- background.getWidth())
{
bgX = 0;
}
On Dispose:
public void dispose () {
batch.dispose();
background.dispose();
However i get my desired result, but after mins, the scrolling becomes really slow.
Is there any other better option?
I need, background repeating scroll from right to left and background height is equal to Gdx.graphics.getHeight()
Thank you! in advance :)
you can simply achieve this by using "translate" method in libgdx. which will give you stable and constant output. please try this example.
public class myGame extends ApplicationAdapter{
public static Sprite sprite,sprite2;
public static texture;
public spriteBatch batch;
public myGame () {
}
#Override
public void create() {
texture = new Texture(Gdx.files.internal("background.png"));
texture2 = new Texture(Gdx.files.internal("background.png"));
sprite = new Sprite(texture, 0, 0, texture.getWidth(), texture.getHeight());
sprite2 = new Sprite(texture2, 0, 0, texture.getWidth(), texture.getHeight());
sprite.setPosition(0, 0);
sprite2.setPosition(1280, 0);
batch=new spriteBatch(sprite);
}
public void bckgroundMovment()
{
sprite.translate(-1.5f, 0);
// here 1280 is the screen width
sprite2.translate(-1.5f, 0);
if (sprite.getX() < -1280) {
sprite.setPosition(1280, 0);
}
if (sprite2.getX() < -1280) {
sprite2.setPosition(1280, 0);
}
}
#Override
public void render(float delta) {
bckgroundMovment()
batch.begin()
sprite.draw(batch);
sprite2.draw(batch);
batch.end();
}
#Override
public void draw(SpriteBatch batch, float deltaTime) {
settingUp(Gdx.graphics.getDeltaTime());
sprite.draw(batch);
sprite2.draw(batch);
}
}
// it will defenitly work ..good luck
One thing that I haven't noticed in your code, or you may have neglected to add, is to call batch.end(), which should always be called after batch.begin().
I've implemented vertical/horizontal parallax backgrounds using Actors, but this should work for your approach:
public void render () {
batch.begin();
float left = bgX - 1;
float backgroundWidth = background.getWidth();
if (left <= -backgroundWidth) { // right side is now off the screen to the left
bgX += backgroundWidth; // smoothly reset position
}
bgX -= 1; // continue scrolling
batch.draw(background, bgX, 0, backgroundWidth, Gdx.graphics.getHeight());
batch.draw(background2, backgroundWidth + bgX, 0, backgroundWidth, Gdx.graphics.getHeight());
batch.end();
}
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 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.
good day... im a new programmer in android... and actually its my first time doing so...
but i have basic knowledge about java...
so here goes.. my game will have an icon that can be controlled by a joystick... and another icon that goes up and down the screen(non controllable) i want the speed to increase a little..... i have started the code but dont know where and how to start the collision.. another one is that the icon that is controllabe always passes the screen and pop out the opposite direction...
public class GameSurface1 extends SurfaceView implements SurfaceHolder.Callback {
private Context _context;
private GameThread1 _thread;
private GameControl _controls;
private GameJoystick1 _joystick;
private int y = 0;
private int xSpeed = 1;
private Bitmap _pointer, bmp;
public GameSurface1(Context context) {
super(context);
// TODO Auto-generated constructor stub
_context = context;
init();
}
private void init(){
//initialize our screen holder
SurfaceHolder holder = getHolder();
holder.addCallback( this);
//initialize our game engine
//initialize our Thread class. A call will be made to start it later
_thread = new GameThread1(holder, _context, new Handler(),this);
setFocusable(true);
_joystick = new GameJoystick1(getContext().getResources());
_pointer = (Bitmap)BitmapFactory.decodeResource(getResources(), R.drawable.icon1);
bmp = (Bitmap)BitmapFactory.decodeResource(getResources(), R.drawable.bad1);
//contols
_controls = new GameControl();
setOnTouchListener(_controls);
}
public void doDraw(Canvas canvas){
if (y == getHeight() - bmp.getHeight()) {
xSpeed = -1;
}
if (y == 0) {
xSpeed = 1;
}
y = y + xSpeed;
//update the pointer
_controls.update(null);
//draw the pointer
canvas.drawBitmap(_pointer, _controls._pointerPosition.x, _controls._pointerPosition.y, null);
//draw the joystick background
canvas.drawBitmap(_joystick.get_joystickBg(), 15,215, null);
//draw the dragable joystick
canvas.drawBitmap(_joystick.get_joystick(),_controls._touchingPoint.x - 26, _controls._touchingPoint.y - 26, null);
canvas.drawBitmap(bmp, 280, y, null);
}
//these methods are overridden from the SurfaceView super class. They are automatically called
//when a SurfaceView is created, resumed or suspended.
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {}
private boolean retry;
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
retry = true;
//code to end gameloop
_thread.state = GameThread1.STOPED;
while (retry) {
try {
//code to kill Thread
_thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
if(_thread.state==GameThread1.PAUSED){
//When game is opened again in the Android OS
_thread = new GameThread1(getHolder(), _context, new Handler(),this);
_thread.start();
}else{
//creating the game Thread for the first time
_thread.start();
}
}
ill appreciate all the help you can give...
thank you