Help getting resource image into ndk/OpenGL for use as a texture?

1,616 views
Skip to first unread message

Josh

unread,
Dec 26, 2009, 11:53:40 PM12/26/09
to android-ndk
As the title says, I have a 512x512 png (title_img.png) in my
resources I want to use as a texture for an OpenGL scene in NDK/C.

I thought maybe I could pass an address through a function into my C
code and use that, but I couldn't get it to work.

I was doing:
Bitmap title_img = BitmapFactory.decodeResource(getResources(),
R.drawable.title_img);
ByteBuffer bb = ByteBuffer.allocateDirect(title_img.getRowBytes()
*title_img.getHeight());
title_img.copyPixelsToBuffer(bb);
sendBitmap(bb); // JNI function

For some reason, getHeight() is showing the image at 768x768 instead
of 512x512. I have no idea why it's doing this and don't know if it is
related to my issue. Anyway I was trying to get it into OpenGL / NDK
with

void Java_com_diodes_pulserider_EngineGLSurfaceView_sendBitmap(JNIEnv*
env, jobject thiz, jobject buf1)
{
void *bitmapptr = (*env)->GetDirectBufferAddress(env, buf1);
}

I then tried to use that bitmapptr and create a texture, bind to it,
and use glTexImage2D w/GL_RGBA. I am just getting a white poly though.

So really I have no idea if the Java which is showing 768x768 instead
of 512x512 is the problem, or if the JNI code is wrong, or if I am not
doing the OpenGL texture stuff right. I'm sure some of you guys have
wanted to use textures in your OpenGL/NDK apps and since I can't get
my code to work I would LOVE to see some working code for loading/
displaying those textures.

Thanks a million

Josh

unread,
Dec 27, 2009, 12:13:34 PM12/27/09
to android-ndk
Thought I should respond since I couldn't find ONE code example on the
net to do this. I ended up getting it working last night, and while
I'm sure my method isn't the best, perhaps it will help someone else
who is having the same issue and no support.

In the Java file, in the GLSurfaceView constructor, I'm doing:

Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.imgname);
int[] pixels = new int[bitmap.getWidth()*bitmap.getHeight()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth
(), bitmap.getHeight());
pushTexture(pixels,bitmap.getWidth(),bitmap.getHeight());

pushTexture is a native JNI function in your C code, defined as
private static native void pushTexture(int[] pixels, int w, int h); in
the Java

Now for the NDK/OpenGL C code:

int w, h, textureID;
char *cImgData;

void Java_com_your_package_EngineGLSurfaceView_pushTexture(JNIEnv*
env, jobject thiz, jintArray arr, jint w, jint h)
{
int len = w*h*4;
char *body = (*env)->GetByteArrayElements(env, arr, 0);

int w = w;
int h = h;
cImgData = malloc(len);

// This converts the ARGB data from Java into RGBA data OpenGL can
use.
for(i=0;i<len;i+=4)
{
cImgData[i] = body[i+2];
cImgData[i+1] = body[i+1];
cImgData[i+2] = body[i];
cImgData[i+3] = body[i+3];
}
}

Then after you initialize OpenGL in your C, you need to generate the
texture from this:

glGenTextures(1,(GLuint*)&textureID);
glBindTexture(GL_TEXTURE_2D,textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,w,h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, (void*)cImgData);


And there you go. I'm pretty sure there are better ways to do this,
and I'm sure my ARGB->RGBA conversion could be faster or something,
but for loading textures at the beginning of your program this seems
to work. I couldn't find a single code example of this on Google
ANYWHERE so hopefully this will help other people.

Bipin George Mathew

unread,
Dec 27, 2009, 7:39:21 PM12/27/09
to andro...@googlegroups.com, android-ndk
You should be able to find an answer about texture mapping over jni in
this thread.
http://groups.google.com/group/android-ndk/browse_thread/thread/eaf038cc50d5041e/c5874712be5382cf?lnk=gst&q=Bipin+#c5874712be5382cf

> --
>
> You received this message because you are subscribed to the Google
> Groups "android-ndk" group.
> To post to this group, send email to andro...@googlegroups.com.
> To unsubscribe from this group, send email to android-ndk...@googlegroups.com
> .
> For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en
> .
>
>

allstars

unread,
Dec 27, 2009, 10:08:05 PM12/27/09
to android-ndk
you can try to read the sample code in bootanimation
http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=cmds/bootanimation/BootAnimation.cpp;h=ce36c4b3320ae77a222a18214c2282874ae1601c;hb=HEAD


On Dec 28, 8:39 am, Bipin George Mathew <bipi...@gmail.com> wrote:
> You should be able to find an answer about texture mapping over jni in  

> this thread.http://groups.google.com/group/android-ndk/browse_thread/thread/eaf03...

Robert Green

unread,
Dec 29, 2009, 12:48:51 AM12/29/09
to android-ndk
Your image is coming in as 768x768 because your drawable is in the
original drawable folder and you're probably testing on a Droid
running native res which is 240DPI so the system takes your 160DPI
image (512x512) and scales it to 240DPI for you (768x768). How nice!
You'll want to either move the resource into drawable-nodpi (I think
that's the folder name) or use the bitmap decoder and set the option
to not scale. That's what I did. Then you won't work with Android
1.5 so you need to write a dynamic class loader to handle it. It's a
bit of a pain but only takes an hour or so to work out once you know
the problem.

Don't be fooled by testing 1.5 in an emulator. It doesn't throw the
no-method-found error that happens on a real Android 1.5 device (Hero,
et al). Just make sure to disable scaling on 1.6+ but use a dynamic
classloader to work with 1.5.

On Dec 27, 9:08 pm, allstars <allstars....@gmail.com> wrote:
> you can try to read the sample code in bootanimationhttp://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;...

Dianne Hackborn

unread,
Dec 29, 2009, 2:29:49 PM12/29/09
to andro...@googlegroups.com
On Mon, Dec 28, 2009 at 9:48 PM, Robert Green <rbgrn.net@gmail.com> wrote:
Your image is coming in as 768x768 because your drawable is in the
original drawable folder and you're probably testing on a Droid
running native res which is 240DPI so the system takes your 160DPI
image (512x512) and scales it to 240DPI for you (768x768).  How nice!
You'll want to either move the resource into drawable-nodpi (I think
that's the folder name) or use the bitmap decoder and set the option
to not scale.  That's what I did.  Then you won't work with Android
1.5 so you need to write a dynamic class loader to handle it.  It's a
bit of a pain but only takes an hour or so to work out once you know
the problem.

For textures, I would suggest putting it in raw/..., so you don't let the resource compiler process your image.  It does a lot of processing on images in drawable/ to compress them and such instead of just copying the raw data into your .apk.
 
Don't be fooled by testing 1.5 in an emulator.  It doesn't throw the
no-method-found error that happens on a real Android 1.5 device (Hero,
et al).  Just make sure to disable scaling on 1.6+ but use a dynamic
classloader to work with 1.5.

That's not good.  It absolutely should behave the same here; it is running the plain 1.5 system image.

--
Dianne Hackborn
Android framework engineer
hac...@android.com

Note: please don't send private questions to me, as I don't have time to provide private support, and so won't reply to such e-mails.  All such questions should be posted on public forums, where I and others can see and answer them.

Josh

unread,
Dec 29, 2009, 7:19:23 PM12/29/09
to android-ndk
Thanks for the replies guys. I'm still gonna use the same method
because it looks like SkBitmap isn't supported for our use? But the
raw folder instead of drawable helps for sure! :]

Josh

unread,
Dec 29, 2009, 7:39:46 PM12/29/09
to android-ndk
Ok I changed to using R.raw.imgname instead of drawable and moved my
resources there, but BitmapFactory still seems to be scaling these
bitmaps. My 64x64's are coming out at 96x96, etc. This is pretty
annoying. Is there no way that is supported by 1.5+ to get simple
bitmaps loaded & decoded with ZERO scaling?

Robert Green

unread,
Dec 30, 2009, 1:29:16 PM12/30/09
to android-ndk
I use BitmapFactory.decodeResource with the BitmapFactoryOptions
argument configured with inScaled=false. Give that a shot. The only
thing about that is that it will choose the BitmapConfig for you based
on the file type. PNG-24 will be ARGB8888 and JPG will be RGB565. I
don't know about GIFs. I never use em.

Dianne Hackborn

unread,
Dec 31, 2009, 12:43:52 AM12/31/09
to andro...@googlegroups.com
Oh you can still use the same configuration names in the raw directory -- that is, if you put it in raw-nodpi, it won't be scaled at load time to match the screen density.

You can also use reflection to call newer density-aware APIs when running in 1.6 or later.  And which method on BitmapFactory are you using?  For example, if you use decodeStream() then it won't have any density information to do scaling with.

--

You received this message because you are subscribed to the Google Groups "android-ndk" group.
To post to this group, send email to andro...@googlegroups.com.
To unsubscribe from this group, send email to android-ndk...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en.


Robert Green

unread,
Dec 31, 2009, 3:54:26 AM12/31/09
to android-ndk
Dianne,

Here's how I do things:

Texture images are in res/drawable. Can't put them in drawable-nodpi
or 1.5 wouldn't be able to find them - or so I'm told.
This works great for me.

UnscaledBitmapLoader loader =
UnscaledBitmapLoaderFactory.getUnscaledBitmapLoader();
Bitmap bitmap = loader.loadBitmap(context, resourceId, bitmapConfig);


public class CupcakeUnscaledBitmapLoader implements
UnscaledBitmapLoader {

/**
* Android 1.0-1.5 don't have any scaling. 1.6-current do. This is
for 1.0-1.5
*/
public Bitmap loadBitmap(Context context, int resourceId, Config
bitmapConfig) {
return BitmapFactory.decodeResource(context.getResources(),
resourceId);
}

}

public class DonutUnscaledBitmapLoader implements UnscaledBitmapLoader
{

/**
* This loads an unscaled bitmap in Android 1.6 and up. This will
crash 1.5 and lower.
*/
public Bitmap loadBitmap(Context context, int resourceId, Config
bitmapConfig) {
BitmapFactory.Options opts = new BitmapFactory.Options();
// Not 1.5-compliant!
opts.inScaled = false;
return BitmapFactory.decodeResource(context.getResources(),
resourceId, opts);
}

}

On Dec 30, 11:43 pm, Dianne Hackborn <hack...@android.com> wrote:
> Oh you can still use the same configuration names in the raw directory --
> that is, if you put it in raw-nodpi, it won't be scaled at load time to
> match the screen density.
>
> You can also use reflection to call newer density-aware APIs when running in
> 1.6 or later.  And which method on BitmapFactory are you using?  For
> example, if you use decodeStream() then it won't have any density
> information to do scaling with.
>
>
>
> On Tue, Dec 29, 2009 at 4:39 PM, Josh <neurocl...@gmail.com> wrote:
> > Ok I changed to using R.raw.imgname instead of drawable and moved my
> > resources there, but BitmapFactory still seems to be scaling these
> > bitmaps. My 64x64's are coming out at 96x96, etc. This is pretty
> > annoying. Is there no way that is supported by 1.5+ to get simple
> > bitmaps loaded & decoded with ZERO scaling?
>
> > --
>
> > You received this message because you are subscribed to the Google Groups
> > "android-ndk" group.
> > To post to this group, send email to andro...@googlegroups.com.
> > To unsubscribe from this group, send email to

> > android-ndk...@googlegroups.com<android-ndk%2Bunsu...@googlegroups.com>


> > .
> > For more options, visit this group at
> >http://groups.google.com/group/android-ndk?hl=en.
>
> --
> Dianne Hackborn
> Android framework engineer

> hack...@android.com

guich

unread,
Jan 8, 2010, 9:15:47 AM1/8/10
to android-ndk
Hi Josh!

> And there you go. I'm pretty sure there are better ways to do this,
> and I'm sure my ARGB->RGBA conversion could be faster or something,
> but for loading textures at the beginning of your program this seems
> to work. I couldn't find a single code example of this on Google
> ANYWHERE so hopefully this will help other people.

Thanks! You saved my life (as soon as i get the sample working :-D)

> Then after you initialize OpenGL in your C, you need to generate the
> texture from this:

Can you provide me with the opengl intialization code too?

all the best

guich

Josh

unread,
Jan 8, 2010, 9:36:36 PM1/8/10
to android-ndk
Hi guich.

The initialization code is just where you call gnEnable
(GL_TEXTURE_2D), etc. You do it once when creating the opengl scene.
If you still need more help with that, I recommend reading up on
OpenGL tutorials on line. NeHe has some OpenGL tutorials (http://
nehe.gamedev.net/), and while they aren't great as far as code goes,
and while Android doesn't support immediate mode (glBegin, glEnd, etc)
the scene initialization stuff should carry over.

-Josh

guich

unread,
Jan 9, 2010, 5:47:14 AM1/9/10
to android-ndk
Hi,

I just realized that my biggest dificulty is to show the texture on
screen. Do you know the easiest way to put a texture that has the
screen's size into the screen?

thanks

guich

Reply all
Reply to author
Forward
0 new messages