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?) {
gl?.apply {
glEnable(GL10.GL_ALPHA_TEST)
glEnable(GL10.GL_BLEND)
glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA)
glDisable(GL10.GL_DEPTH_TEST)
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
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.
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...