In android-opengles,we know that any primitive can be rendered on the android screen through
OnDrawFrame(GL10 gl)
{.....}
that is rendered contineously.
as if we want to draw a triangle which is defined in triangle class
we use
triangle tri=new triangle();
OnDrawFrame(GL10 gl)
{
.
.
.
tri.draw(gl);
.
.
.
}
so,what i need is,i want to draw triangle whenever the user touches the
screen through
OnTouchEvent(MotionEvent e)
{
.
.
.
tri.draw(gl);
.
.
.
}
is it possible? or is there any alternative way?
As already mentioned you can not do that directly. No matter the thread you should not just insert the drawing at some random point in your application as you have no idea what state the rendering is actually in.
Always try to separate the logic from the drawing. In your case that seems to mean you will need an array of objects (triangles). Whenever user touches you can add a triangle object to this array and on draw the triangles can be drawn.
Now you have 2 situations with the triangles. First if you clear the buffer on every draw then the array should keep growing on touch events and each frame all of the triangles are being drawn. Second if you do not clear the buffer and simply keep drawing one object over the other then you should simply remove all objects from the array when you draw them.
In both cases there is also an option to only call the draw method when the changes are done. In this case it is most common to use a boolean value something like needsRedraw and upon true the rendering should trigger, view refreshed and needsRedraw set to false. The value needsRedraw would then again be set to true when some action is made such as another triangle added.
There are some other ways such as you may create a shared context on another thread to which the touch events will report. On this context you can create a FBO with an attached texture. The main context would then redraw this texture as full screen and the result would be the same... Still this is a harder procedure and there is no reason to implement it. Not to mention that you need to ensure these 2 threads are not the same or keep changing the current context on the thread; Also double buffering would probably be mandatory in this case so we are looking at 2 textures on the FBO, locking system and attachment/detachment system.
OpenGL ES Documents say that all GL commands for a context should be called from the same thread. In your case, Android and iOS have to send commands from the main thread. You cannot pass the command from a touch event.
My suggestion, is to have a boolean flag enabled in the touch event and use the same boolean on the main thread to draw something.
Related
I'm struggling to find the best way to draw smoothly as possible some pre-calculated trajectories of physical objects on a custom SurfaceView. So the scenario is like this:
I have a 100k entries SQLite database that stores x,y positions of about 10 objects.
I have to animate my objects using the data provided by the database while drawing trajectories.
I have to be able to interact with the SurfaceView zomming and panning appropriately through touch events.
What strategy is the best?
(a) Pre loading data and store them in 200k entries float arrays.
(a1) Then, at every draw(Canvas canvas) call extract the segment of the array with data from the initial time to the actual time, construct a Path with these points and draw it.
(a2) Same as (a1) but instead of using Path, call the Canvas.drawLines() function. That function require a float array with repetition of points so that the end point of a line will be the start point of the next line. This function may be faster than drawPath() but the array must be constructed at every iteration...
(a3) Otherwise, save drawings in a Bitmap so that at every iteration I have to draw only the entire Bitmap + the last segment of the trajectories. Only when the Matrix change redraw all stuff with the new Matrix on the Bitmap. This slow down only when touch events happens to change the Matrix requesting the entire redrawing.
(b) Live read data from database with a concurrent Thread. Then, save in a float array only the positions read. This may be a little more heavy because of the additional thread and live querying but I have to handle only smaller arrays of float (only the part I'm interested in and not all hystory).
(b1) Redraw all at every draw(Canvas canvas) call as in (a1) using Path
(b2) Redraw all at every draw(Canvas canvas) call as in (a2) using drawLines()
(b3) Save in a Bitmap to optimize drawings as in (a3)
Options (a) are better because I can smoothly draw lines using all points in database while with options (b) if the process slow down the live updating system can skip some points making the drawing less smooth. Options (b) are better bacause of the simplicity and readability of code.
I only tested options (b) but I'm wondering if I have to give a try to options (a). Keep in mind that with the trajectories growing up the draw process becomes very slow so optimization is necessary. The Bitmap strategy can solve partially the problem with long trails but I can't have a fluid experience when touch events happens...
I'm trying to incrementally draw a waveform on a canvas in a separate thread, i.e. in each loop of the thread draw only the portion recently acquired by the hardware without redrawing the whole curve.
I am not sure if I can rely on the canvas' contents retained between SurfaceHolder.unlockCanvasAndPost and SurfaceHolder.lockCanvas.
The documentation seems to be a bit ambiguous on that and my experiments give surprising results: the "old" contents is different for the canvas returned in two subsequent loops of the drawing thread. It looks as if two canvases were used alternately (but I checked - it is the same canvas but with different contents).
The simplest way which I found to reproduce this behaviour:
Import the LunarLander sample applicaton.
In the LunarView.run method insert sleep(500) instruction in the loop.
In the LunarView.doDraw method comment out the line:
canvas.drawBitmap(mBackgroundImage, 0, 0, null);, which erases the old contents.
Run the game and let the ship crash. You will see the intermediate positions of the ship but they will blink: odd and even positions will be shown alternately.
So, my question is: can we draw pictures adding changes only to the contents which has been drawn before and if so - is there any documented way of dealing with the strange behaviour described above?
The lunar landing does not cache.
It draws the background image each time (refreshing) and then draws the spaceship.
private void doDraw(Canvas canvas) {
// Draw the background image. Operations on the Canvas accumulate
// so this is like clearing the screen.
canvas.drawBitmap(mBackgroundImage, 0, 0, null);
Check your If clauses closesly. Maybe one is alternating true and false. This would cause things to draw and then not draw, in rapid succession.
Use Log if need be to output your booleans, to see if one is changing.
Failing this, this the following gaming loop instead.
http://blorb.tumblr.com/post/236799414/simple-java-android-game-loop
I am setting up a game loop. The loop is set to update at 50 FPS. Currently the only action the app does is draw screen coordinates on response to touch events. Originally I set up the draw function to only draw new touch events. This caused the text to blink. Multiple touch events blink at different times, which leads me to think that Canvas uses multiple pages behind the scenes. In an effort to get around this I made a list of every touch event that happened and on every draw call I redraw the entire list.
Please correct me if I am wrong, the lockCanvas()/unlockCanvasAndPost() calls are in essence a backbuffer swap. Reading the documentation on locking and unlocking it sounds like it is necessary to redraw the entire scene between calls unless you use lockCanvas(Rect dirty). In this case the dirty rect area needs to be redraw while the outside area is preserved.
The content of the Surface is never preserved between unlockCanvas()
and lockCanvas(), for this reason, every pixel within the Surface area
must be written. The only exception to this rule is when a dirty
rectangle is specified, in which case, non-dirty pixels will be
preserved.
I know it sounds like I've answered my own question, but according to the documentation the Surface is never preserved between calls. However this does not explain the behavior of my first implementation, which was I would tap the screen and the text would start blinking. Since I only drew the text one time, this would mean that the blinking is from swapping to the "backbuffer" which didn't get the drawText() call, and the original Surface which did not get destroyed but perhaps it is to be considered unreliable.
So, the question: Do I need to redraw all objects on each draw call? And if so, do I need to "clear" the canvas, or at the least redraw the background image also?
yes, unless you're doing a dirty redraw where you define the region that you are redrawing, every point on your canvas gets destroyed.
I want to draw something at about 30 frames per seconds on Android Canvas or other convenient object for this purpose. In my application different graphic objects are drawn and if any of the graphic object is touched, the graphic object changes its shape. I looked at the
onDraw(Canvas canvas) callback of View subclass but calling invalidate() does not help here: first I cannot control the frame rate and second if the objects are moving too fast, the motion appears jerky.
I personally dislike Android's built-in Animation classes, so I tend to do all animations with Canvas by hand. I have found the most luck with creating a list of the images you want to use in your animation and then an int variable to store the current "frame" you are on. To advance the frame, I create a thread that sleeps for, say, 30 ms and then update the frame variable accordingly. Then in whatever update handler you are using, you can just create a switch statement or something of the like, and draw the respective frame.
It may seem like a lot of work, but it really isn't. Shove it all into a class and you will love yourself for many animations to come.
I have code where I made a cube (using 12 triangles) and it moves back and forth in the z-direction.
Is there a way to render this cube (say) 5 times simultaneously just at different positions in space. As of now, I would have to create a new buffer for each cube, which seems wrong.
if CubeObj.draw() is your cube's draw function (likely a call to glVertexPointer then glDrawElements),
glPushMatrix(); //save the current matrix
glTranslatef(translatex, translatey, translatez);
//glRotatef(), glScale, etc.
CubeObj.draw();
glPopMatrix(); //restore the matrix
the glPush/PopMatrix() calls ensure that transformation commands in the block are only applied to that particular cube.
You can call your object's draw function multiple times without reconstructing the object.
That is to say, you could have another copy of the above code and change the transformation commands, and you would appear to have 2 separate cubes.
Hope this helped.
EDIT:
make sure you have a call to glLoadIdentity() at the top of your display function