I'm writing an app in Kotlin, which displays 2D object on user's phone. When I execute my code, I get Java.lang.nullpointerexceptionRun. Sadly, I don't know how to fix this issue. Run output:
E/com.a3dmodelap: Invalid ID 0x00000000 . E/AndroidRuntime: FATAL EXCEPTION: GLThread 633 Process: com.a3dmodelapp, PID: 7503 java.lang.NullPointerException: Attempt to invoke virtual method ' int android.graphics.Bitmap.getWidth()' on a null object reference at com.a3dmodelapp.Texture.load(Texture.kt: 80 ) at com.a3dmodelapp.Stage$MyRenderer.onSurfaceCreated(Stage.kt: 91 ) at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java: 1541 ) at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java: 1272 )
So basically it fails at this line (Texture.kt:80):
Quote:
width = bmp.getWidth()

I'm new to Kotin and already spent hours trying to fix it. Would greatly appreciate the help. Here's the code in Texture class:
private var width : Int = 0 private var height : Int = 0 var resourceId = 0 constructor(resourceId: Int, mipmaps: Boolean ) this .resourceId = resourceId this .textureId = -1 this .mipmaps = mipmaps constructor(resourceId: Int) { this (resourceId, false ) Texture(resourceId, false ) fun getWidth(): Int return width fun getHeight(): Int return height fun load(context: Context) val opts = BitmapFactory.Options() opts.inScaled = false val bmp = BitmapFactory.decodeResource(context.getResources(), resourceId, opts) width = bmp.getWidth() height = bmp.getHeight() UPDATE: It seems that resourceId is the problem. bmp variable is null, because of resourceId being 0. Followed my code step by step and I can't figure out where the problem may be. Right down below I provide more in depth walktrough of resourceId variable.
In Stage class I have a call to the constructor:
tex = Texture(getResources().getIdentifier(img, " drawable" , context?.getPackageName())) After checking, it is basically the same as this:
tex = Texture( 2131165330 )
So that means it's calling the second constructor in Texture class:
constructor(resourceId: Int) Texture(resourceId, false ) And then the first one:
constructor(resourceId: Int, mipmaps: Boolean ) this .resourceId = resourceId this .textureId = -1 this .mipmaps = mipmaps resourceId shouldn't be equal to 0, but to 2131165330 (I've checked and it is being set in the first constructor). I don't know why it's equal to 0
UPDATE 2
Below I provide you Stage class (the most relevant to me lines of code have been bolded):
class Stage(context: Context?, attrs: AttributeSet?) : GLSurfaceView(context, attrs) { private var w = 0 . 0F private var h = 0 . 0F private var screenHeight = 0 private var screenWidth = 0 private lateinit var vertexBuffer: FloatBuffer private lateinit var tex: Texture private var img = " " private var xPos = 0 . 0F private var yPos = 0 . 0F private var r = 0 . 0F init { setEGLConfigChooser( 8 , 8 , 8 , 8 , 0 , 0 ) setRenderer(MyRenderer()) val vertices = floatArrayOf( -0. 5f , -0. 5f , 0 . 0f , 0 . 5f , -0. 5f , 0 . 0f , -0. 5f , 0 . 5f , 0 . 0f , 0 . 5f , 0 . 5f , 0 . 0f , val vbb: ByteBuffer = ByteBuffer.allocateDirect(vertices.size * 4 ) vbb.order(ByteOrder.nativeOrder()) vertexBuffer = vbb.asFloatBuffer() vertexBuffer.put(vertices) vertexBuffer.position( 0 ) img = " football" tex = Texture(getResources().getIdentifier(img, " drawable" , context?.getPackageName())) private inner class MyRenderer : Renderer { override fun onDrawFrame(gl: GL10) { gl.glClear(GLES10.GL_COLOR_BUFFER_BIT) tex.prepare(gl, GL10.GL_CLAMP_TO_EDGE) gl.glVertexPointer( 3 , GL10.GL_FLOAT, 0 , vertexBuffer) tex.draw(gl, xPos, yPos, tex.getWidth()*r, tex.getHeight()*r, 0f ) override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) { gl.glClearColor( 0f , 0f , 0f , 1 . 0f ) if (width > height) { h = 600F w = width * h / height } else { w = 600F h = height * w / width screenWidth = width screenHeight = height xPos = w/2 yPos = h/2 r= 1F gl.glViewport( 0 , 0 , screenWidth, screenHeight) gl.glMatrixMode(GL10.GL_PROJECTION) gl.glLoadIdentity() gl.glOrthof( 0f , w, h, 0f , -1f, 1f ) gl.glMatrixMode(GL10.GL_MODELVIEW) gl.glLoadIdentity() override fun onSurfaceCreated(gl: GL10?, p1: EGLConfig?) { // Set up alpha blending gl?.apply { glEnable(GL10.GL_ALPHA_TEST) glEnable(GL10.GL_BLEND) glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA) // We are in 2D, so no need depth glDisable(GL10.GL_DEPTH_TEST) // Enable vertex arrays (we'll use them to draw primitives). glEnableClientState(GL10.GL_VERTEX_ARRAY) gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY) tex.load(getContext()) UPDATE 3
I think I've found where the issue is, but I don't know how to solve it. Right here I'm making a call to the second constructor:
tex = Texture(getResources().getIdentifier(img, " drawable" , context?.getPackageName()))
In the second constructor, I call the first one, but it doesn't make any sense, because it doesn't save values back to the Stage class. What I want to do is create something like this:
constructor(resourceId: Int) this (resourceId, false ) In Java it would work perfectly fine, but here in Kotlin it doesn't. This is the only line that needs work, because if I make a call like the one provided below everything works just fine:
tex = Texture(getResources().getIdentifier(img, " drawable" , context?.getPackageName()), false )
What I have tried:
I've spent hours trying to solve this with no success
I would expect one (or several) texture files inside the drawable folder, and then a "drawable.myTextureFileName" in your Texture creating statement tex = Texture(...);

EDIT: have been reading some more; my first paragraph seems incorrect now. However, is your texture really called "img" ? rather than a filename with a typical image extension? Maybe try once again, with some .png file or similar.

BTW: when you improve your question (which is OK) you should also reply to an appropriate solution or comment in order to send a signal to others. Just changing the question creates no signal to anyone...
some ideas:
- do you have a file called "football" inside the "drawable" folder?
- have you tried with a more appropriate filename, with one of the standard image extensions (such as .png)?
- are you using "configuration-specific alternatives"? if so look here ( https://stackoverflow.com/questions/23375593/how-do-i-load-a-texture-from-a-config-file ) and make sure you also have such file in the default drawable.

Now I ran out of ideas.
-
constructor(resourceId: Int): this (resourceId, false )
Reason why I had to do this: I was calling another constructor, but I wasn't saving values back to the Stage class and that's why resourceId was equal to 0.
I really do appreciate your help! Thank you so much!
  • Read the question carefully.
  • Understand that English isn't everyone's first language so be lenient of bad spelling and grammar.
  • If a question is poorly phrased then either ask for clarification, ignore it, or edit the question and fix the problem. Insults are not welcome.
  • Don't tell someone to read the manual. Chances are they have and don't get it. Provide an answer or move on to the next question. Let's work to help developers, not make them feel stupid.
  •