Android problem drawing a bitmap with opengl es - java

I'm using https://github.com/markfguerra/GLWallpaperService/ to make an android live wallpaper.
I'm trying to load a png file as fullscreen background, however currently all I get is a black screen.
I've searched for a few days now but still haven't found out the problem.
I'm doing the following:
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
}
and every frame:
public void onDrawFrame(GL10 gl)
{
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.target00074);
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
}

I would really recommend to dive into the OpenGL basics as you don't seem to know what you are doing. The screen is black because you are just uploading a texture (something you should do at initialization instead of every frame) and not actually drawing anything. You will need to define some arrays defining vertex and texture positions for a start. Refer to http://blog.jayway.com/2009/12/04/opengl-es-tutorial-for-android-%E2%80%93-part-ii-building-a-polygon/
As for the fullscreen background, you would create a single polygon with your texture

I found my solution in: http://obviam.net/index.php/texture-mapping-opengl-android-displaying-images-using-opengl-and-squares/

Two basic mistakes for when textures don't work:
Texture width/height should be a power of two, unless the device supports some extension that alleviates this requirement.
Set the TEXTURE_MIN_FILTER to something like NEAREST or LINEAR, the default is mipmapped and this produces incomplete textures unless you provide mipmaps.
Also, the texture parameter state is not global, is per texture object, so set it after binding your texture.

I realize that this answer doesn't really address the question at hand. Downvote me if you must.
If all you want to do is draw a full-screen background image, you don't need OpenGL. You aren't working in 3D and a static background image doesn't need to be updated very often (especially not 30-60 times a second!) so using OpenGL will only kill the battery. A better solution is to have a look at the relevant code examples and documentation, where you will see that all you really need to do is copy-paste the CubeWallpaper example, but change drawFrame() to look like the following:
void drawFrame() {
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
// draw something
c.drawBitmap(myBitmap, myMatrix, myPaint);
}
} finally {
if (c != null) holder.unlockCanvasAndPost(c);
}
// Reschedule the next redraw
mHandler.removeCallbacks(mDrawCube);
if (mVisible) {
mHandler.postDelayed(mDrawCube, 1000 / 25);
}
}
where myBitmap, myMatrix, and myPaint are Bitmap, Matrix, and Paint objects that have been initialized previously.
Even if my initial assumption (your image is static) is false, this way can still be much more efficient if your image doesn't change terribly often, for example twice a second or slower.
Hope this helps

Related

What is the most efficient way of rendering 2D game with the possibility of changing the resolution?

I've tried:
1.Creating a separate variable called "factor" and multiplying or dividing literally everything with it: entity velocities, object sizes, fonts, resolution etc..
(the factor is always relative to the resolution so the objects are scaled properly)
public class Player extends Entity{
float size;
public Player(needed variables) {
super(needed variables);
resize();
}
public void resize() {
/*
Resize everything.
This method is supposed to be called from a separate resizing
function located in another class when the JFrame size is changed.
the function has to play with the choice between divide or multiply
variables with the factor
*/
}
public void tick() {
x += velX*factor;
y += velY*factor;
}
etc..
}
By using this factor to multiply literally everything, it makes the code really messy and hard to read sometimes.
2.Rendering to a BufferedImage and scaling the BufferedImage to fit to the JFrame.
void render() {
//Render the game to a new BufferedImage
BufferedImage renderedFrame = new BufferedImage(1920, 1080, BufferedImage.TYPE_RGB);
renderedFrame.createGraphics();
Graphics g = renderedFrame.getGraphics();
//Render the game ....
//Scale the BufferedImage to fit the current resolution and render it to the Canvas
BufferStrategy bs = getBufferStrategy();
Graphics f = bs.getDrawGraphics();
f.drawImage(renderedFrame.getScaledInstance(1280, 720, Image.SCALE_FAST), 0, 0, null);
f.dispose();
bs.show();
}
Which makes the code much more readable but then there comes 2 problems:
Mouse input problems and resizing the BufferedImage is taking too much resources which makes the game laggy.
3.I could basically try to make a separate unit system for the game.. but then there's the same problem, when it comes to rendering strings or rectangles I'd have to multiply everything with the factor and the code is horrible after that.
Is there any better ways of rendering 2D games? If no then I'll think about moving on to OpenGL.
Thanks in advance.
The way I've done this most successfully is by scaling the graphics object. You end up with something like the following:
final int gameUnitsPerScreenDim = 32;
void render(JPanel panel, Graphics2D g2) {
double pixelHeight = panel.getHeight();
double pixelsPerGameUnit = pixelHeight / gameUnitsPerScreenDim;
g2.scale(pixelsPerGameUnit, pixelsPerGameUnit);
...
}
And then for the simulation, you use game units. How big a game unit actually is is a bit arbitrary, although if you're making a tiled game there's probably some obvious value that it should be.
Instead of using scale, you can also create an AffineTransform which lets you reuse it:
if (this.tf == null || /* image size changed since the last frame */) {
...
this.tf = AffineTransform.getScaleInstance(pxPerGu, pxPerGu);
}
g2.setTransform(this.tf);
(Calling scale creates a new AffineTransform every time you call it.)
That's even a little more efficient, although probably not by much.
(If you want, you can also use a transform to invert the y-axis and translate so the origin is at the center of the image. This makes a lot of trigonometry and stuff feel more natural. Inverting the y-axis makes working with text a pain, though.)
Also, using OpenGL is probably better. Having written a couple of simple games using Swing for fun, I don't see a good reason to do it.

ImageView spread out animation

I basically have an ImageView which got modified with Canvas and looks like a cirlce. (original image had the dimensions of a square (500x500))
Image what the starting position looks like:
http://imgur.com/bvXdLoP
(red is transparent and got removed with help of the Canvas method)
The animation should take aroud 1000 miliseconds and during this time step for step restore to the original picture. So in the end there should be a sqaure again.
In other words the cut off corners, which are the differnce between a square and a circle (and red marked in the image), get step for step restored in around 1000 milliseconds, with a sort of spreading looking animation.
Don't really have any clue on how to achieve this, so I can just share the Canvas method I used to cut off the corners (if it helps :X):
private Bitmap createCircleImage(Bitmap bitmap) {
Bitmap bmp;
bmp = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Bitmap.Config.ARGB_8888);
BitmapShader shader = new BitmapShader(bitmap,
BitmapShader.TileMode.CLAMP,
BitmapShader.TileMode.CLAMP);
float radius = bitmap.getWidth() / 2f;
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);
canvas.drawCircle(bitmap.getWidth()/2,bitmap.getHeight()/2,bitmap.getHeight()/2, paint);
return bmp;
}
Appreciate any help,
thank you!
There are many ways to achieve such behavior. For example you can create custom view and override its onDraw method such as
#Override
public void onDraw(Canvas canvas) {
canvas.drawCircle(viewWidth/2, viewHeight/2, currentRadius, paint);
}
and then you can just increase the radius little by little and invalidate the view.Since view is by default will clip on its clipBounds (you can only draw inside viewidth x viewheight rectangle unless you set it otherwise) you will get the effect that you want. And then you can tweak the interpolation to achieve smoother and more natural animation.
note: a bitmap shader is attached to the paint (you already know chow to create it). I don't include it in the code, since you shouldn't initialize it inside onDraw method for performance reason.

Sprites flicker in Andengine

I want to move some sprites from left to right with a constant slow speed. I have first tried RatioResolutionPolicy but I saw sprites were flickering a lot. Then I have changed resolutionpolicy to FixedResolutionPolicy, defined sprite textures as bitmap, scaled them and made sprites by these textures (for more detail: click here). This is better than first method but not completely good. I use setx() for moving sprites. When I change x positon for example by 2 pixels for each frame there is no problem. But for different devices that have different resolutions I must multiply 2 by a ratio. In this case sprites are flickering again, not much but it is annoying for me.
code for camera is below
#Override
public EngineOptions onCreateEngineOptions() {
WindowManager w = getWindowManager();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
Point size = new Point();
w.getDefaultDisplay().getSize(size);
V.CAMERA_WIDTH = size.x;
V.CAMERA_HEIGHT = size.y;
} else {
Display d = w.getDefaultDisplay();
V.CAMERA_WIDTH = d.getWidth();
V.CAMERA_HEIGHT = d.getHeight();
}
if (V.CAMERA_HEIGHT/V.CAMERA_WIDTH>480f/860f){
V.CAMERA_HEIGHT=V.CAMERA_WIDTH*480f/860f;
}
else {
V.CAMERA_WIDTH=V.CAMERA_HEIGHT*860f/480f;
}
V.ratio=V.CAMERA_HEIGHT/480f;
this.mCamera = new Camera(0, 0, V.CAMERA_WIDTH, V.CAMERA_HEIGHT);
final EngineOptions engineOptions = new EngineOptions(true,
ScreenOrientation.LANDSCAPE_FIXED, new FixedResolutionPolicy((int)V.CAMERA_WIDTH, (int)V.CAMERA_HEIGHT),
this.mCamera);
return engineOptions;
}
for moving sprites:
this.wallPosX -= this.speed;
this.setX(Math.round(this.wallPosX));
speed is a floating point varibale and it gets 4.4651165 for 1280x720 screen resolution. If I set it as an integer than there is no flickering, but this time sprite speed differs from device to device.
There are too many screen sizes and screen ratio's for android phones.
Use the Cropped Resolution Policy created by jgibbs. Follow Martin Varga's tutorial to get an understanding on how it works and how to implement it.
It works wonders.
Original from jgibbs
I recommend Martin's Tutorial
You shouldn't be worried about micro managing entities positional co-ordinates to suit every and any possible screen size.
I'm not sure this will fix the flickering though, that may be some other problem not related to your camera
I have noticed that this wasn't about Andengine, it was about opengl. Solution for this problem is this wonderful tool:
https://github.com/gemserk/imageprocessing

LibGdx How to repeat background?

Few days ago I figured out how to do some scrolling in LibGdx. Now I'm triying to do something related. I want to repeat the background. My scrolling follows a ship (Is an s[ace ship game). In the background there is a space photo loaded as a Texture. When the ship reach the end of the backgorund, It keeps going and there's no background anymore. I have read about wrap but I don't really understand How It works. I did that:
px=new Pixmap(Gdx.files.internal("fondo.jpg"));
background=new Texture(px);
background.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
And then, in my render method
spriteBatch.begin();
spriteBatch.draw(background,0,0,500,50);
drawShip();
spriteBatch.end();
Of course It doesn't work, It only draws the background once. I don't know how make this wrap method work. Any help?
SOLUTION
I figured It out. It's not a nice code but It works.
First I declare two Textures with the same image
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
Also I declare two variables like this to specify the X value of the position of each bck
int posXBck1=0,posXBck2=0;
Then I use that in Render()
public void calculoPosicionFondos(){
posXBck2=posXBck1+ANCHODEFONDO;
if(cam.position.x>=posXBck2+cam.viewportWidth/2){
posXBck1=posXBck2;
}
}
Where:
ANCHODEFONDO is the width of my background
Cam is an OtrhoCam.
So I said that if the cam is in bck2 (wich means that you can't see bck1 anymore) It change positions, giving bck1 de position of bck2 and, in the next render loop, recalculating bck2
Then just paint both bck in your render mode.
Like Teitus said, do not load your texture multiple times, ever! Anyway, you where on the right track with the wrapper:
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
Now you can just use the draw method with the source location. The source location is the area you choose to draw on the texture.
batch.draw(texture, x, y, srcX, srcY, srcWidth, srcHeight)
To scroll your texture from right to left all you have to do is increase srcX incrementally. So create a int that increments in the update/render method.
int sourceX = 0;
//render() method
//Increment the variable where to draw from on the image.
sourceX += 10;
//Simply draw it using that variable in the srcX.
batch.draw(YourTexture, 0, 0, sourceX, 0, screenWidth, screenHeight);
Because you are wrapping the texture it will wrap/loop and scroll indefinitely. There might be a issue with the sourceX int if the game runs for a very long time because a int can only hold 2147483647. It takes a while but you can fix it by subtracting the image width each time the number goes over the total image width.
Don't to this, please:
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
That will load your big background texture twice. That's a complete waste. If you want to keep your solution at least do:
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=bkg1;
Regarding the texture Wrapping. If your texture is 500px wide, and you draw a 500px sprite, you won't see any repetition. If you want it repeated 2 times, draw it 1000px wide with 0-2 texture coordinates.
I'm not sure how spriteBatch handles the call you posted, you could try that one, or may be use the overload that uses a texture region and set your region manually.
I see this is a pretty old question, but I think there is an easier way to accomplish background scrolling. Just use the Sprite class. Here is a snippet I use for layered background images that scroll from right to left.
public class LevelLayer
{
public float speedScalar = 1;
private List<Sprite> backgroundSprites = new ArrayList<Sprite>();
public LevelLayer()
{
}
public void addSpriteLayer(Texture texture, float startingPointX, float y, int repeats)
{
for (int k = 0; k < repeats; k++)
{
Sprite s = new Sprite(texture);
s.setX(startingPointX + (k*texture.getWidth()));
s.setY(y);
backgroundSprites.add(s);
}
}
public void render(SpriteBatch spriteBatch, float speed)
{
for (Sprite s : backgroundSprites)
{
float delta = s.getX() - (speed * speedScalar);
s.setX(delta);
s.draw(spriteBatch);
}
}
}
Then you can use the same texture or series of textures like so:
someLayer.addSpriteLayer(sideWalkTexture1, 0, 0, 15);
someLayer.addSpriteLayer(sideWalkTexture2, 15 * sideWalkTexture1.getWidth(), 0, 7);
I change background repeating sections randomly in code and make new ones or reset existing sets when they go off screen. All the layers go to a pool and get pulled randomly when a new one is needed.
SOLUTION
I figured It out. It's not a nice code but It works.
First I declare two Textures with the same image
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
Also I declare two variables like this to specify the X value of the position of each bck
int posXBck1=0,posXBck2=0;
Then I use that in Render()
public void calculoPosicionFondos(){
posXBck2=posXBck1+ANCHODEFONDO;
if(cam.position.x>=posXBck2+cam.viewportWidth/2){
posXBck1=posXBck2;
}
}
Where:
ANCHODEFONDO is the width of my background
Cam is an OtrhoCam.
So I said that if the cam is in bck2 (wich means that you can't see bck1 anymore) It change positions, giving bck1 de position of bck2 and, in the next render loop, recalculating bck2
Then just draw both bck in your render()

Am I not doing correctly or understanding double buffering on Android?

I have a function
#Override
public void run() {
while(running && (!eof)){
if(surfaceHolder.getSurface().isValid()){
Canvas canvas = surfaceHolder.lockCanvas();
paint(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
thread = null;
}
where paint(canvas) calls a bunch of other functions that draw a graph and text, for example
canvas.drawText("Time="+myRecord.getMyTime(), 100, 100, paint);
The problem I'm having is that the graph and the text, both of which should be constantly changing, don't get erased but instead keep drawing over themselves. Shouldn't my entire canvas get redrawn every time because that's how double buffering works with the lock() and unlock()? Am I not understanding this correctly? How am I supposed to do this?
You need to clear the Canvas yourself after lockCanvas() using Canvas.drawColor().
This might be relevant too:
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.
Source

Categories

Resources