Skip to content

Commit e1588da

Browse files
committed
Rewrite texture loading
In the past, it was possible that glGenTextures is called multiple times, overwriting the existing textures.
1 parent 8a30863 commit e1588da

2 files changed

Lines changed: 93 additions & 122 deletions

File tree

Lines changed: 68 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,46 @@
11
package com.bytehamster.flowitgame;
22

3-
import javax.microedition.khronos.egl.EGLConfig;
4-
import javax.microedition.khronos.opengles.GL10;
5-
63
import android.content.Context;
74
import android.graphics.BitmapFactory;
5+
import android.opengl.GLSurfaceView.Renderer;
86
import android.opengl.GLU;
97
import android.opengl.GLUtils;
10-
import android.opengl.GLSurfaceView.Renderer;
11-
128
import android.util.Log;
139
import androidx.annotation.DrawableRes;
1410
import com.bytehamster.flowitgame.object.Drawable;
15-
import com.bytehamster.flowitgame.object.Plane;
16-
import com.bytehamster.flowitgame.object.TextureCoordinates;
1711

12+
import javax.microedition.khronos.egl.EGLConfig;
13+
import javax.microedition.khronos.opengles.GL10;
1814
import java.util.ArrayList;
1915

2016
public class GLRenderer implements Renderer {
21-
private static final int MIN_LOADING_TIME = 500;
22-
17+
private static final String TAG = "GLRenderer";
2318
private final Context myContext;
2419
private int width = 0;
2520
private int height = 0;
26-
private final int[] textures = new int[2];
27-
private Runnable onReady = null;
28-
private int loadProgress = 0;
29-
private long loadStarted = 0;
21+
private final int[] textures = new int[1];
22+
private Runnable onViewportSetupComplete = null;
3023
private final ArrayList<Drawable> objects = new ArrayList<>();
3124

3225
public GLRenderer(Context c) {
3326
myContext = c;
3427
}
3528

36-
public void onResume() {
37-
loadProgress = -1;
38-
}
39-
40-
public boolean isReady() {
41-
return loadProgress == 2;
42-
}
43-
4429
@Override
4530
public void onDrawFrame(GL10 gl) {
4631
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
4732
gl.glLoadIdentity();
4833

49-
if (loadProgress == -1) {
50-
setupViewport(gl);
51-
loadProgress = 0;
52-
loadStarted = System.currentTimeMillis();
53-
}
54-
55-
if (loadProgress == 0) {
56-
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
57-
58-
float loaderSize = getWidth() / 4;
59-
Plane loader = new Plane(getWidth() / 2 - loaderSize / 2, getHeight() / 2 - loaderSize / 2,
60-
loaderSize, loaderSize, new TextureCoordinates(0, 0, 1, 1));
61-
loader.draw(gl);
62-
63-
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[1]);
64-
65-
long loadingDuration = System.currentTimeMillis() - loadStarted;
66-
if (loadingDuration >= MIN_LOADING_TIME) {
67-
loadProgress = 1;
68-
}
69-
return; // Do not display other objects - just loading texture
70-
} else if (loadProgress == 1) {
71-
loadTexture(gl, textures[1], R.drawable.texture);
72-
gl.glDeleteTextures(1, textures, 0); // Delete loader texture from memory
73-
if (onReady != null) {
74-
onReady.run();
75-
onReady = null;
76-
}
77-
loadProgress = 2;
78-
gl.glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
79-
}
80-
81-
debugOutput(gl);
82-
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[1]);
34+
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
8335
for (Drawable o : objects) {
8436
o.draw(gl);
8537
}
8638
debugOutput(gl);
8739
}
8840

89-
private void loadTexture(GL10 gl, int position, @DrawableRes int resource) {
90-
gl.glBindTexture(GL10.GL_TEXTURE_2D, position);
91-
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, BitmapFactory.decodeResource(myContext.getResources(), resource), 0);
92-
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
93-
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
94-
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
95-
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
96-
}
97-
9841
@Override
99-
public void onSurfaceChanged(GL10 gl, int width, int height) {
100-
if (height == 0) //Prevent A Divide By Zero By
101-
height = 1; //Making Height Equal One
102-
103-
this.width = width;
104-
this.height = height;
105-
setupViewport(gl);
106-
}
107-
108-
private void setupViewport(GL10 gl) {
42+
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
43+
debugOutput(gl);
10944
gl.glEnable(GL10.GL_BLEND);
11045
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
11146

@@ -114,35 +49,81 @@ private void setupViewport(GL10 gl) {
11449
gl.glCullFace(GL10.GL_BACK);
11550
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
11651

117-
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // While loading
52+
gl.glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
11853

54+
gl.glActiveTexture(GL10.GL_TEXTURE0);
11955
gl.glEnable(GL10.GL_TEXTURE_2D);
12056
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
57+
gl.glGenTextures(textures.length, textures, 0);
58+
loadTexture(gl, 0, R.drawable.texture);
59+
debugOutput(gl);
60+
}
61+
62+
@Override
63+
public void onSurfaceChanged(GL10 gl, int width, int height) {
64+
Log.d(TAG, "setupViewport");
65+
if (height == 0) //Prevent A Divide By Zero By
66+
height = 1; //Making Height Equal One
12167

68+
this.width = width;
69+
this.height = height;
70+
71+
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
12272
gl.glMatrixMode(GL10.GL_PROJECTION);
12373
GLU.gluOrtho2D(gl, 0, width, 0, height);
12474
gl.glMatrixMode(GL10.GL_MODELVIEW);
125-
126-
gl.glGenTextures(textures.length, textures, 0);
127-
loadTexture(gl, textures[0], R.drawable.loading);
128-
loadProgress = 0;
12975
debugOutput(gl);
76+
77+
if (onViewportSetupComplete != null) {
78+
onViewportSetupComplete.run();
79+
onViewportSetupComplete = null;
80+
}
81+
}
82+
83+
private void loadTexture(GL10 gl, int position, @DrawableRes int resource) {
84+
Log.d(TAG, "loadTexture");
85+
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[position]);
86+
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, BitmapFactory.decodeResource(myContext.getResources(), resource), 0);
87+
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
88+
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
89+
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
90+
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
13091
}
13192

13293
private static void debugOutput(GL10 gl) {
13394
int code = gl.glGetError();
13495
if (code != 0) {
96+
String errorString;
97+
switch (code) {
98+
case GL10.GL_INVALID_ENUM:
99+
errorString = "GL_INVALID_ENUM";
100+
break;
101+
case GL10.GL_INVALID_VALUE:
102+
errorString = "GL_INVALID_VALUE";
103+
break;
104+
case GL10.GL_INVALID_OPERATION:
105+
errorString = "GL_INVALID_OPERATION";
106+
break;
107+
case GL10.GL_STACK_OVERFLOW:
108+
errorString = "GL_STACK_OVERFLOW";
109+
break;
110+
case GL10.GL_STACK_UNDERFLOW:
111+
errorString = "GL_STACK_UNDERFLOW";
112+
break;
113+
case GL10.GL_OUT_OF_MEMORY:
114+
errorString = "GL_OUT_OF_MEMORY";
115+
break;
116+
default:
117+
errorString = "unknown";
118+
break;
119+
}
120+
135121
StackTraceElement elem = new Exception().getStackTrace()[1];
136-
Log.e("ERROR", "Code: " + code + " in " + elem.getClassName()
122+
Log.e(TAG, "OpenGL error: " + errorString + " (" + code + ") in " + elem.getClassName()
137123
+ "/" + elem.getMethodName() + ":" + elem.getLineNumber());
138124
}
139125
}
140126

141-
@Override
142-
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
143-
144-
}
145-
146127
public float getWidth() {
147128
return width;
148129
}
@@ -155,7 +136,7 @@ public void addDrawable(Drawable d) {
155136
objects.add(d);
156137
}
157138

158-
void setOnReady(Runnable onReady) {
159-
this.onReady = onReady;
139+
void setOnViewportSetupComplete(Runnable onViewportSetupComplete) {
140+
this.onViewportSetupComplete = onViewportSetupComplete;
160141
}
161142
}

app/src/main/java/com/bytehamster/flowitgame/Main.java

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
package com.bytehamster.flowitgame;
22

3+
import android.app.Activity;
34
import android.app.ActivityManager;
45
import android.content.Context;
56
import android.graphics.Bitmap;
67
import android.graphics.BitmapFactory;
78
import android.os.Build;
89
import android.os.Bundle;
9-
import android.app.Activity;
10-
import android.os.Handler;
1110
import android.view.KeyEvent;
1211
import android.view.MotionEvent;
1312
import android.view.Window;
1413
import android.view.WindowManager;
15-
1614
import com.bytehamster.flowitgame.model.LevelPack;
1715
import com.bytehamster.flowitgame.state.ExitState;
1816
import com.bytehamster.flowitgame.state.GameState;
@@ -51,37 +49,34 @@ public void onCreate(Bundle savedInstanceState) {
5149
}
5250

5351
private void createViews() {
54-
glSurfaceView.getRenderer().setOnReady(new Runnable() {
55-
@Override
56-
public void run() {
57-
soundPool = new SoundPool(Main.this);
58-
soundPool.loadSound(R.raw.click);
59-
soundPool.loadSound(R.raw.fill);
60-
soundPool.loadSound(R.raw.won);
61-
62-
State[] states = new State[]{
63-
MainMenuState.getInstance(),
64-
ExitState.getInstance(),
65-
SettingsState.getInstance(),
66-
LevelPackSelectState.getInstance(),
67-
LevelSelectState.getInstance(),
68-
GameState.getInstance(),
69-
TutorialState.getInstance()
70-
};
71-
72-
for (State state : states) {
73-
state.initialize(glSurfaceView.getRenderer(), soundPool, Main.this);
74-
}
75-
76-
currentState = MainMenuState.getInstance();
77-
currentState.entry();
52+
glSurfaceView.getRenderer().setOnViewportSetupComplete(() -> {
53+
soundPool = new SoundPool(Main.this);
54+
soundPool.loadSound(R.raw.click);
55+
soundPool.loadSound(R.raw.fill);
56+
soundPool.loadSound(R.raw.won);
57+
58+
State[] states = new State[]{
59+
MainMenuState.getInstance(),
60+
ExitState.getInstance(),
61+
SettingsState.getInstance(),
62+
LevelPackSelectState.getInstance(),
63+
LevelSelectState.getInstance(),
64+
GameState.getInstance(),
65+
TutorialState.getInstance()
66+
};
67+
68+
for (State state : states) {
69+
state.initialize(glSurfaceView.getRenderer(), soundPool, Main.this);
7870
}
71+
72+
currentState = MainMenuState.getInstance();
73+
currentState.entry();
7974
});
8075
}
8176

8277
@Override
8378
public boolean onKeyDown(int keyCode, KeyEvent event) {
84-
if (currentState != null && glSurfaceView.getRenderer().isReady()) {
79+
if (currentState != null) {
8580
if (keyCode == KeyEvent.KEYCODE_BACK
8681
&& event.getAction() == KeyEvent.ACTION_DOWN
8782
&& event.getRepeatCount() == 0) {
@@ -93,7 +88,7 @@ public boolean onKeyDown(int keyCode, KeyEvent event) {
9388
}
9489

9590
public boolean onTouchEvent(MotionEvent event) {
96-
if (currentState != null && glSurfaceView.getRenderer().isReady()) {
91+
if (currentState != null) {
9792
currentState.onTouchEvent(event);
9893
switchState();
9994
}
@@ -112,12 +107,7 @@ private void switchState() {
112107
@Override
113108
protected void onResume() {
114109
super.onResume();
115-
116-
glSurfaceView.postDelayed(() -> {
117-
glSurfaceView.getRenderer().onResume();
118-
glSurfaceView.onResume();
119-
glSurfaceView.invalidate();
120-
}, 500);
110+
glSurfaceView.onResume();
121111
}
122112

123113
@Override

0 commit comments

Comments
 (0)