passing instructions from UI thread to Rendering thread (GLSurfaceView) - android

The Setup : A RelativeLayout with a GLSurfaceView and a Button as shown in the image..
The Problem: Lets say I have other triangle models (The one in the picture being the initial model)... I wish to change the models cyclically on click of the button. Since button is on the UI thread and glSurfaceView runs on a separate thread, I don't exactly know how to pass the info/instruction to it. I know there is this thing called Handler in Android which might be useful in this case... But I need some help here..
Edit: If Handler is the right way, I need to know how to add Looper to that Handler... The documentation says add looper.prepare() at the start of run() method.. But the glSurfaceView creates thread implicitly, resulting in no run() method directly available..

I don't think it is necessary to use handlers to solve this issue but you may need to adjust the way you organise your classes.
Here is an example of an organisational structure that might solve your issue:
Activity Class
public class MainActivity extends Activity {
private int modelNumber = 0;
private ArrayList<Model> models = new ArrayList<Model>();
private YourRendererClass renderer;
#Override
public void onCreate(Bundle savedInstanceState) {
...
// Setup GLSurfaceView
GLSurfaceView surface = new GLSurfaceView(this);
setContentView(surface);
renderer = new YourRendererClass();
surface.setRenderer(renderer);
// Set up models
models.add(new Model(x, y, size etc..));
models.add(new Model(x, y, size etc..));
models.add(new Model(x, y, size etc..));
etc.
// Display first model
renderer.setCurrentModel(models.get(modelNumber));
...
}
// Called by the button press:
// Use android:onClick="onClick"
// in your layout xml file within button
public void onClick(View view){
// Make it loop round
modelNumber++;
if(modelNumber>=models.size()){
modelNumber=0;
}
// Display current model
renderer.setCurrentModel(models.get(modelNumber));
}
}
Renderer Class
public class YourRendererClass implements Renderer {
private Model currentModel;
#Override
public void onDrawFrame(GL10 gl) {
// ** Your existing set-up code **//
// Draw model
if (currentModel!=null){
currentModel.draw(gl);
}
}
public void setCurrentModel(Model model){
currentModel = model;
}
}
Model class
public class Model {
// Holds model information
private int size;
private int x;
private int y;
// etc...
public model(int x, int y, int size etc...){
this.x=x;
this.y=y;
this.size=size;
// etc....
}
public void draw(GL10 gl) {
// ** Draw model based on model information fields above **
}
}
The above code is untested as I don't have access to your drawing code but the structure should work if implemented correctly. I've tried to make it clear where you'll have to insert your own code to make it work. In particular I wasn't sure what defines each of your different models so you'll need to include sufficient local variables within the Model class to define them.
I hope my answer helps, let me know if you have any questions.
Tim

You should look at queueEvent! It's a very convenient way to pass informations from UI Thread to renderer Thread:
queueEvent(new Runnable(){
#Override
public void run() {
mRenderer.method();
}});

Related

Using a value from json file in Libgdx

I want to use a value from a json file
Here is the Json file
{
"button" : [
{
"x" : 50.0
},
{
"x" : 150.0
}
]
}
I have the following classes
(Button Class)
public class Button extends Sprite{
float x;
public Button() {
super(new Texture("button.png"));
}
#Override
public void setX(float x) {
this.x = x;
}
}
(Data Class)
public class Data {
public Array<Button> buttons;
public void load() {
buttons = new Array<Button>();
Json json = new Json();
json.setTypeName(null);
json.setUsePrototypes(false);
json.setIgnoreUnknownFields(true);
json.setOutputType(JsonWriter.OutputType.json);
json.fromJson(Data.class, Gdx.files.internal("buttons.json"));
}
}
(Main Class)
public class GameMain extends ApplicationAdapter {
SpriteBatch batch;
Data data;
#Override
public void create () {
batch = new SpriteBatch();
data = new Data();
data.load();
for(Button b : data.buttons) {
b.setX(b.x);
}
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
for(Button b : data.buttons) {
b.draw(batch);
}
batch.end();
}
}
I want to draw buttons in specific x positions that is held in json file
but it gives me nothing .
What is wrong in my code ?
Any ideas ?
at the end of load() you haven't asign the results. Just add buttons = :
public void load() {
//instead of this line:
//buttons = new Array<Button>();
Json json = new Json();
json.setTypeName(null);
json.setUsePrototypes(false);
json.setIgnoreUnknownFields(true);
json.setOutputType(JsonWriter.OutputType.json);
// set buttons here:
buttons = json.fromJson(Data.class, Gdx.files.internal("buttons.json"));
}
Your Data class loads another instance of a Data class and doesn't assign it to anything. It's circular and doesn't make sense. The load method should be static, return a Data object (which is what the last line of your current load method provides), and not be trying to instantiate an empty buttons array that goes unused.
Your button class hides both the x field and the setX method of the superclass, making it impossible to change the actual X position of the sprite that is used when it is drawn. Sprite already has an x parameter, so you should not be adding your own. If you merely remove those two things from your Button class, it should work.
That said, you should not be loading another copy of the same texture for each button. That's a waste of memory and texture swapping. And unless you are very careful about disposing the textures "owned" by these sprites, you are also leaking memory.

How to be sure that all views got created

I'm working with AsyncTask and in one of the background threads I've created, I have to know the size of a given View.
But sometimes this view is yet to be created.
So the question is: at which part of Activity's life cycle I can be sure that all the views are already in place and with the dimensions defined?
PS: My code is inside a Fragment and I already tried onResume() method.
custom the view which you want to get size:
public class SizeFetchableView extends YourView{
//constructors...
private SizeFetchListener mSizeFetchListener;
public void setSizeFetchListener(SizeFetchListener l){
mSizeFetchListener = l;
}
public void onLayout(boolean isChanged,int l,int t,int r,int b){
super.onLayout(l,t,r,b);
if(mSizeFetchListener!=null){
mSizeFetchListener.onFetchSize(this,isChanged,getWith(),getHeight());
}
}
public interface SizeFetchListener{
public void onFetchSize(View view,boolean isChanged,int w,int h);
}
}
so,you can use SizeFetchListener to get the view size in the first time,but your thread logic which depend on the size,must waiting the fetch size interface invoke.
public class Task extends Thread implements SizeFetchListener{
SizeFetchableView mSizeFetchableView;
public Task(SizeFetchableView v){
mSizeFetchableView=v;
mSizeFetchableView.setSizeFetchListner(this);
}
public void onFetchSize(View view,boolean isChanged,int w,int h){
//and this time ,you can start you thread if not,or continue you logic who waiting the size
}
}
//please forgive my bad english.Thanks

OpenGL ES and Thread Structure

I have the following (simplified) rig so far:
MyActivity.java:
public class MyActivity extends Activity {
public GLSurfaceView myGLView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myGLView = new MyGLSurfaceView(this);
setContentView(myGLView);
}
}
MyGLSurfaceView.java:
public class MyGLSurfaceView extends GLSurfaceView {
private MyRenderer mMyRenderer = new MyRenderer();
private MyThread mMyThread = new MyThread();
public MyView(Context context) {
super(context);
setRenderer(mGameRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
mGameThread.setRunning(true);
}
}
MyRenderer.java:
public class GameRenderer implements GLSurfaceView.Renderer {
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// ...
}
}
MyThread.java:
Here I'm doing all initializations, creating objects and so on.
public class MyThread extends Thread {
private MyObject mMyObject = new MyObject();
public MyThread {
// ...
mMyObject.setRot();
this.start();
}
public void run() {
// Fixed Timestep Loop goes here
mMyObject.getRot();
}
}
MyObject.java:
This is a sample object which holds different fileds and methods.
public class MyObject {
private double mRot;
// Getters & Setters
protected double getRot() { return mRot; }
protected void setRot() {
// ... Do calculations
}
public void draw() {
// OGL Instructions go here
gl.glRotatef(1.2f, 0, 0, setRot());
}
}
Now the problem I was running into is the following: (I guess, I missed something very basic and simple :) )
As stated above, I'm creating my object instances in the MyThread class. The Thread is created in the MyGLSurface class, same goes for the Renderer. Now, that I have that two threads I can't figure out, how to use that one instance and their methods in that two separate threads.
I tried different approaches, but nothing did work. So in my opinion I made a mistake in the class design. I mean, I don't just want to get it running (that'd be quite easy), but I want to know how to do it correctly.
The main problem is actually that I can't access the MyObject's instance and simply use the draw() method in the renderer - because I don't get it.
I thought, it would be possible to call the draw() method of MyObject within the rendering thread without the need of using a singleton and so on. So simply referencing the instance to it. But somehow that seemed weird and dirty (besides that it doesn't work for me).
I tried dozens of different approaches, but I really need a bump into the right direction. I'm quite familar with OOP, but here I might really miss something.
In that many samples I found on the web (stackoverflow, Replica Island, different tutorial sites, Google I/O, DevCentral, etc.) they either didn't use a multithreaded system or they split it directly (GL objects from regular objects).
Any hint into the right direction would be much appreciated!
Another example to peruse:
https://code.google.com/p/android-breakout/
The wiki and code comments discuss the threading issues inherent in using GLSurfaceView. In particular, the game does as much setup as it can before the Renderer thread starts; once it's running, as much work as possible is done on that thread. The game state objects are effectively "owned" by the renderer thread, and the Activity is owned by the UI thread, so any "off-thread" interactions are handled by sending messages rather than making direct method calls. For example, see the handling of touch events.
It's good that you're thinking about this -- you either need synchronization or careful object discipline to avoid nasty race conditions.
See also: android game loop vs updating in the rendering thread
The nice thing about GLSurfaceView is that it creates the OpenGL rendering thread for you, so you don't need to create one yourself. The main UI thread will call the OnDraw() method in your view class and that's all the threads you need. If you really want to create your own thread for OpenGL rendering, use TextureView instead of GLSurfaceView. Here is an article that I think will help:
http://software.intel.com/en-us/articles/porting-opengl-games-to-android-on-intel-atom-processors-part-1

Passing Android Acceleromter values from MainActivity to My GameView class

I am working on a game involving measuring accelerometer values and manipulating my character's position based on those values. I am only working with the X axis. I initiate my accelerometer manager in my main activity, but I need to use these values in another class. Obviously these values are constantly changing. How could I pass these values to my GameView class?
You can save them as static members of your activity, or pass them to GameView class each time there's a change in them (new value)
If you've used a sensorlistener you might think about moving that logic to the GameView class. Not totally sure without looking at your code though. Do you have any samples?
Why not do it the Android way? :)
When you implement a touch listener, you do something set like this:
myView.setOnTouchlistener(this):
This tells the view to call you back when it's touched. Here's how to do your own:
Define an interface and use a callback to let the class know that a value has changed.
public interface AccelerometerUpdateListener {
void onUpdate(int arg1, string arg2); ..<----add arguments you want to pass back
}
In your Activity:
public class MainActivity extends Activity implements AccelerometerUpdateListener {
ArrayList<AccelerometerUpdateListener > listeners = new ArrayList<AccelerometerUpdateListener >();
...
#Override
public void onCreate(Bundle savedInstanceState)
{
...
myGameClass.setResponseReceivedistener(this);
...
}
public void setUpdateListener(AccelerometerUpdateListener listener){
if (!listeners.contains(listener){
listeners.add(listener);
}
}
public void removeUpdateListener(AccelerometerUpdateListener listener){
if (listeners.contains(listener){
listeners.remove(listener);
}
}
When you update the values
for (AccelerometerUpdateListener listener:listeners){
listener.onUpdate(arg1, arg2);
}
In your receiving class:
public class MyGameClass implements AccelerometerUpdateListener {
...
#Override
public void onUpdate(int arg1, string arg2){
// do whatever you need to do
}
All from memory so please excuse typos.

Another "Cannot make static reference..." Question

I am trying to write an Activity that has some views, a fillView() method that sets the views (which is not static because it must utilize getContentResolver), and a static method that makes a random choice from a cursor and then runs the fillView() method.
I had problems with this due to fillView not being static and pickRandom being static, so I tried to initialzize an instance of the class, but now it crashes on the line instance.fillView();
Sample code below. Any help would be appreciated. Perhaps there is a much easier way to accomplish what I am trying to do.
Thanks,
Josh
public class myView extends Activity implements OnClickListener {
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.myView);
fillView();
}
public void fillView(){
//creates views, runs cursor and applies results to the view created
}
public static void pickRandom() {
// runs cursor, picks random entry, next I want to apply the result to
// view, so I run...
myView v = new myView();
v.fillView();
}
Make a static instance variable and set in in oncreate:
private static myView instance;
oncreate()
instance = this;
static pickrandom()
instance.fillView();
in your pickRandom you try to create new instance of your class. Instead of this you should do the following:
this.fillView();
I don't see any purpose you have your pickRandom static.
If, however, you need it for some reason you can pass a reference to your view like this:
public static void pickRandom(myView v) {
// runs cursor, picks random entry, next I want to apply the result to
// view, so I run...
v.fillView();
}

Categories

Resources