i am trying to convert bitmap into a libGDX Texture by converting:
Android Bitmap to byte[]
byte[] to libGDX Pixmap
libGDX Pixmap to libGDX Texture
The problem I am facing is that the bitmap which is converted to texture is drawing the sprite sheet from texture packer that is in assets folder
public void onByteArrayOfCroppedImageReciever(byte[] bytes) {
try {
pmap=new Pixmap(bytes, 0, bytes.length);
tex=new Texture(pmap);
face=new Sprite(tex);
// game.setScreen(new GameScreen(game, batcher, face));
} catch(Exception e) {
Gdx.app.log("KS", e.toString());
e.printStackTrace();
}
}
If the goal is to convert an Android Bitmap to a libgdx Texture, you don't need to use Pixmap at all. You can do it directly with the help of simple OpenGL and Android GLUtils. Try the followings; it is 100x faster than your solution. I assume that you are not in the rendering thread (you should not most likely). If you are, you don't need to call postRunnable().
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
Texture tex = new Texture(bitmap.getWidth(), bitmap.getHeight(), Format.RGBA8888);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex.getTextureObjectHandle());
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
bitmap.recycle();
// now you have the texture to do whatever you want
}
});
hmm another possibility is that you've got a threading issue. I've noticed this kind of problem when loading my own unmanaged textures on the UI thread while libgdx is doing its thing loading textures concurrently on the render thread.
If this is the problem the simple solution is to synchronize the creation of the texture with the render thread using Gdx.app.postRunnable. i.e.:
public void onByteArrayOfCroppedImageReciever(byte[] bytes) {
try {
pmap=new Pixmap(bytes, 0, bytes.length);
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
tex=new Texture(pmap);
face=new Sprite(tex);
}
});
} catch(Exception e) {
Gdx.app.log("KS", e.toString());
e.printStackTrace();
}
}
you have to code on a new thread because pixmap class takes time for byte conversion and sometimes returns a temporary pixmap in case the process hasnt finished so its better to run on a seperate thread and your problem will be solved.
Are you committed to that operational pipeline? Here's an alternate way to do the conversion you asked for:
Implement com.badlogic.gdx.graphics.TextureData to take an android.graphics.Bitmap in the constructor.
In prepare(), allocate and fill an IntBuffer using Bitmap.getPixels.
Use bitmath to swap the data in the buffer from ARGB to RGBA: (arr[i] << 8) | (arr[i]>>24)
In getType() return TextureData.TextureDataType.Compressed
In consumeCompressedData() call glTexImage2D to feed the data into the (prebound) texture.
Your pipeline above includes several copies and recompressions of pixel data; this pipeline allows you to feed your Bitmap data straight into the texture with only one copy (necessary for the byte format conversion anyway). Would that work for you?
Related
New Camera 2 API is very different from old one.Showing the manipulated camera frames to user part of pipeline is confuses me. I know there is very good explanation on Camera preview image data processing with Android L and Camera2 API but showing frames is still not clear. My question is what is the way of showing frames on screen which came from ImageReaders callback function after some processing while preserving efficiency and speed in Camera2 api pipeline?
Example Flow :
camera.add_target(imagereader.getsurface) -> on imagereaders callback do some processing -> (show that processed image on screen?)
Workaround Idea : Sending bitmaps to imageview every time new frame processed.
Edit after clarification of the question; original answer at bottom
Depends on where you're doing your processing.
If you're using RenderScript, you can connect a Surface from a SurfaceView or a TextureView to an Allocation (with setSurface), and then write your processed output to that Allocation and send it out with Allocation.ioSend(). The HDR Viewfinder demo uses this approach.
If you're doing EGL shader-based processing, you can connect a Surface to an EGLSurface with eglCreateWindowSurface, with the Surface as the native_window argument. Then you can render your final output to that EGLSurface and when you call eglSwapBuffers, the buffer will be sent to the screen.
If you're doing native processing, you can use the NDK ANativeWindow methods to write to a Surface you pass from Java and convert to an ANativeWindow.
If you're doing Java-level processing, that's really slow and you probably don't want to. But can use the new Android M ImageWriter class, or upload a texture to EGL every frame.
Or as you say, draw to an ImageView every frame, but that'll be slow.
Original answer:
If you are capturing JPEG images, you can simply copy the contents of the ByteBuffer from Image.getPlanes()[0].getBuffer() into a byte[], and then use BitmapFactory.decodeByteArray to convert it to a Bitmap.
If you are capturing YUV_420_888 images, then you need to write your own conversion code from the 3-plane YCbCr 4:2:0 format to something you can display, such as a int[] of RGB values to create a Bitmap from; unfortunately there's not yet a convenient API for this.
If you are capturing RAW_SENSOR images (Bayer-pattern unprocessed sensor data), then you need to do a whole lot of image processing or just save a DNG.
I had the same need, and wanted a quick and dirty manipulation for a demo. I was not worried about efficient processing for a final product. This was easily achieved using the following java solution.
My original code to connect the camera2 preview to a TextureView was commented-out and replaced with a surface to an ImageReader:
// Get the surface of the TextureView on the layout
//SurfaceTexture texture = mTextureView.getSurfaceTexture();
//if (null == texture) {
// return;
//}
//texture.setDefaultBufferSize(mPreviewWidth, mPreviewHeight);
//Surface surface = new Surface(texture);
// Capture the preview to the memory reader instead of a UI element
mPreviewReader = ImageReader.newInstance(mPreviewWidth, mPreviewHeight, ImageFormat.JPEG, 1);
Surface surface = mPreviewReader.getSurface();
// This part stays the same regardless of where we render
mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mCaptureRequestBuilder.addTarget(surface);
mCameraDevice.createCaptureSession(...
Then I registered a listener for the image:
mPreviewReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
if (image != null) {
Image.Plane plane = image.getPlanes()[0];
ByteBuffer buffer = plane.getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Bitmap preview = BitmapFactory.decodeByteArray(bytes, 0, buffer.capacity());
image.close();
if(preview != null ) {
// This gets the canvas for the same mTextureView we would have connected to the
// Camera2 preview directly above.
Canvas canvas = mTextureView.lockCanvas();
if (canvas != null) {
float[] colorTransform = {
0, 0, 0, 0, 0,
.35f, .45f, .25f, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 1, 0};
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.set(colorTransform); //Apply the monochrome green
ColorMatrixColorFilter colorFilter = new ColorMatrixColorFilter(colorMatrix);
Paint paint = new Paint();
paint.setColorFilter(colorFilter);
canvas.drawBitmap(preview, 0, 0, paint);
mTextureView.unlockCanvasAndPost(canvas);
}
}
}
}
}, mBackgroundPreviewHandler);
I've managed to load textures and free rotate a sphere thanks to several tutorials, questions and answers asked here but i stumbled upon the need of texture reloading at runtime (get a bitmap image, process it and then apply it as a new texture to an object). I didnt find any working solutions for my specific problem (i've read all related questions and answers).
Im quite new to OpenGL. This is my second project, my first 3D one and my first question asked here. So here it goes:
Basicaly the texture loading is done in the following function:
public void loadGLTexture(final Context context, final int texture) {
GLES20.glGenTextures(1, mTextures, 0);
if (mTextures[0] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), texture, options);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
if (mTextures[0] == 0)
{
throw new RuntimeException("Texture load fail");
}
}
While the draw is done in this function:
public void draw(float[] mvpMatrix) {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.mTextures[0]);
GLES20.glFrontFace(GLES20.GL_CW);
for (int i = 0; i < this.mTotalNumStrips; i++) {
//vertex
this.mVertexBuffer.get(i).position(0);
GLES20.glVertexAttribPointer(mPositionHandle, NUM_FLOATS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, this.mVertexBuffer.get(i));
GLES20.glEnableVertexAttribArray(mPositionHandle);
//texture
this.mTextureBuffer.get(i).position(0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, NUM_FLOATS_PER_TEXTURE,
GLES20.GL_FLOAT, false,
textureStride, this.mTextureBuffer.get(i));
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
//draw strip
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, this.mVertices.get(i).length / NUM_FLOATS_PER_VERTEX);
}
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
// Disable the client state before leaving.
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTextureCoordinateHandle);
}
In the above function i use the Strips tehnique to render a sphere. For each strip i have to load the texture and vertex data and finaly draw it.
I also have a function that should delete the textures that does nothing more than:
public void clearGLTextures(){
GLES20.glDeleteTextures(1, mTextures, 0);
}
What i want to achieve here is texture reloading so the plan was:
INITIALISE(works): loadGLTexture(initialtexture) -> loop the draw() function
RELOAD(does not work): clearGLTextures() -> loadGLTexture(newTexture) -> loop the draw() function
So not only that i cant reload the texture but also the call to clearGLTextures() seems not to work because the initialtexture remains on scren.
Any thoughts are welcome,
Thanks!
This is an example of a very common kind of problem when doing OpenGL programming on Android. Unfortunately the symptoms are very variable, so the questions are not really duplicates.
When you use GLSurfaceView, it creates a separate rendering thread. All the methods in your GLSurfaceView.Renderer implementation (onSurfaceCreated, onSurfaceChanged, onDrawFrame) are called in this rendering thread.
The second part of the puzzle is that you need a current OpenGL context to make OpenGL calls. And OpenGL contexts are current per thread. GLSurfaceView takes care of creating a context, and making it current in the rendering thread.
As a consequence, you can't make any OpenGL calls from other threads (unless you do much more work, and add complexity). The most common error is to try making OpenGL calls from the UI thread, typically when handling user input like touch events. Those calls will not work.
There are a number of options if you want to execute OpenGL calls in response to user input. For example, you can set members in the Renderer that describe the necessary state changes, and are checked in the onDraw() method. Another convenient option is using the queueEvent() method on the view, which allows you to pass in a Runnable that will later be executed in the rendering thread.
I just ran into the same problem.
Reto Koradi explained it great but I wanted to shared my solution:
I used queueEvent with a Runnable in the GLSurfaceView.
public void addTexture(final int textureResId) {
queueEvent(new Runnable() {
#Override
public void run() {
mRenderer.loadTexture(textureResId);
// or different GL thread tasks like clearing the texture
}
});
}
So i've been using ligbdx for some time, and it was really simple there to do such thing. So what i want to achieve is that when i have a large texture i would like to get a part of that texture by giving x,y (where to start cutting from) and width,height (size of cut part) and later use that part as a sprite or anything that is possible to be drawn on the andengine scene.
In libgdx it ws like that:
//loads file from assets into texture
Texture texture = new Texture(Gdx.files.internal("data/texture5.png"));
//cuts a part of it into drawable element
TextureRegion part = new TexureRegion(texture, x, y, width, height);
and part was just that section of the texture i needed to draw later on the screen. Is it really so hard to do in andengine that nowwhere on the internet i couldnt find any answer for 2h of searching? :)
I have just searched for hours and got nothing. But accidentally i tried this, and it worked. It's an old question but whatever. Maybe this can help.
ITexture texture = null;
try {
texture = new BitmapTexture(engine.getTextureManager(),
new IInputStreamOpener() {
public InputStream open() throws IOException {
return engine.getAssets().open(path);
}
});
texture.load();
} catch (IOException e) {
e.printStackTrace();
}
ITextureRegion texturePart = new TextureRegion(texture, x, y, width, height);
I have a cube, I can assign for it one texture, but I would like to assign different texture for each face. I have a 512x512 texture atlas, with four tiles, each 256x256. I use the NeHe ports, so for one texture the load is:
public void loadGLTexture(GL10 gl, Context context) {
InputStream is = context.getResources().openRawResource(R.drawable.test);
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
is = null;
} catch (IOException e) {
}
}
I have tried to find solutions, but I was not able to find with texture atlas, only with loading as much texture as I want to use, then assign them to the faces, but because of the performance it's not really good for me. I hope someone can help me!
Thanks in advance!
PS: Which is faster, creating a cube with the coordinates writing in the code, or loading a cube model from an .obj file?
I'm new to OpenGL ES and developing a simple 2D game. However, I'm confused as to how I can go about loading multiple animation frames as textures (for the player character). I've tried to load a different image every time the character is rendered, but that's too slow.
Here is my texture loading code thus far:
public void loadGLTexture(GL10 gl, Context context) {
InputStream[] is=new InputStream[3];
is[0]= context.getResources().openRawResource(R.drawable.r1);
is[1]= context.getResources().openRawResource(R.drawable.r2);
is[2]= context.getResources().openRawResource(R.drawable.r3);
try {
bitmap[0]= BitmapFactory.decodeStream(is[0]);
bitmap[1]= BitmapFactory.decodeStream(is[1]);
bitmap[2]= BitmapFactory.decodeStream(is[2]);
} finally {
try {
is[0].close();
is[1].close();
is[2].close();
is = null;
} catch (IOException e) {
}
}
gl.glGenTextures(3, textures,0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap[0], 0);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap[1], 0);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap[2], 0);
bitmap[0].recycle();
bitmap[1].recycle();
bitmap[2].recycle();
}
How can I make all three images accessible through an array?
You need to call glBindTexture before every texImage2D. Currently you are loading all three images into textures[0].
Don't try to load all textures at once. Change your function to load only one texture and just call it three times. You should be able to do:
textures[0]=loadGLTexture(GL10,context,R.drawable.r1);
textures[1]=loadGLTexture(GL10,context,R.drawable.r2);
textures[2]=loadGLTexture(GL10,context,R.drawable.r3);
You can place all the frames of animation on a single texture and use texture coordinates to select which one to use