Skip to content

Commit 5f288cf

Browse files
committed
optimzations for mobile (nexus 7 now at 60 fps)
1 parent 06d8333 commit 5f288cf

File tree

13 files changed

+157
-45
lines changed

13 files changed

+157
-45
lines changed

core/src/org/jrenner/fps/Assets.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public void loadAll() {
102102
// Skin changes
103103
skin.get(Label.LabelStyle.class).font = font;
104104
chatLabelStyle = new Label.LabelStyle(skin.get(Label.LabelStyle.class));
105-
chatLabelStyle.font = largeFont;
105+
chatLabelStyle.font = font;
106106
skin.get(TextButton.TextButtonStyle.class).font = largeFont;
107107
TextField.TextFieldStyle tfStyle = skin.get(TextField.TextFieldStyle.class);
108108
tfStyle.background = skin.getDrawable("button-up");
@@ -125,14 +125,19 @@ private void loadTextures() {
125125
manager.load("textures/ground1.jpg", Texture.class, textureParam);
126126
manager.load("textures/marble.jpg", Texture.class, textureParam);
127127
manager.load("textures/shadow.png", Texture.class, textureParam);
128+
129+
TextureParameter skyTextureParam = new TextureParameter();
130+
skyTextureParam.genMipMaps = false;
131+
skyTextureParam.magFilter = TextureFilter.Linear;
132+
skyTextureParam.minFilter = TextureFilter.Linear;
128133

129134
//Load Skybox
130-
manager.load("textures/skybox/xpos.png", Texture.class);
131-
manager.load("textures/skybox/xneg.png", Texture.class);
132-
manager.load("textures/skybox/ypos.png", Texture.class);
133-
manager.load("textures/skybox/yneg.png", Texture.class);
134-
manager.load("textures/skybox/zpos.png", Texture.class);
135-
manager.load("textures/skybox/zneg.png", Texture.class);
135+
manager.load("textures/skybox/xpos.png", Texture.class, skyTextureParam);
136+
manager.load("textures/skybox/xneg.png", Texture.class, skyTextureParam);
137+
manager.load("textures/skybox/ypos.png", Texture.class, skyTextureParam);
138+
manager.load("textures/skybox/yneg.png", Texture.class, skyTextureParam);
139+
manager.load("textures/skybox/zpos.png", Texture.class, skyTextureParam);
140+
manager.load("textures/skybox/zneg.png", Texture.class, skyTextureParam);
136141

137142

138143
// load Texture Atlas

core/src/org/jrenner/fps/HUD.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.badlogic.gdx.utils.Array;
1818
import com.badlogic.gdx.utils.StringBuilder;
1919
import com.badlogic.gdx.utils.TimeUtils;
20+
import org.jrenner.fps.entity.Entity;
2021
import org.jrenner.fps.net.NetManager;
2122
import org.jrenner.fps.net.packages.ChatMessage;
2223

@@ -146,7 +147,7 @@ public void changed(ChangeEvent event, Actor actor) {
146147
boolean debugHUD = true;
147148

148149
public void update() {
149-
//if (Main.frame % 10 != 0) return;
150+
if (Main.frame % 15 != 0) return;
150151
Player player = Main.inst.client.player;
151152
sb.delete(0, sb.length);
152153
sb.append("FPS: ").append(Integer.toString(Gdx.graphics.getFramesPerSecond()));
@@ -180,7 +181,8 @@ public void update() {
180181
sb.append("\n\nPhysics time: ").append(String.format("%4s", Main.physicsTime));
181182
sb.append("\nGround dist: ").append(String.format("%.4f", player.entity.distFromGround));
182183
sb.append("\nGround normal: ").append(Tools.fmt(Physics.inst.getFloorNormal(player.entity.getPosition())));
183-
sb.append("\nGroundPiece visibility: ").append(View.visibleGroundPieces).append(" / ").append(View.totalGroundPieces);
184+
sb.append("\nGroundPiece visibility: ").append(View.visibleGroundPieces).append(" / ").append(LevelBuilder.groundPieces.size);
185+
sb.append("\nEntity visibility: ").append(View.visibleEntities).append(" / ").append(Entity.list.size);
184186
}
185187
sb.append("\nPress T to chat\nPress R to respawn");
186188
label.setText(sb.toString());

core/src/org/jrenner/fps/LevelBuilder.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public LevelBuilder() {
4848
public static Array<ModelInstance> staticGeometry;
4949

5050
public static Array<ModelInstance> groundPieces;
51-
public static final float groundPieceSize = 16f;
51+
public static final float groundPieceSize = 100f;
5252

5353
public static void createLevel() {
5454
// graphical representation of the ground
@@ -102,7 +102,7 @@ public static void createLevel() {
102102
if (Main.isServer()) {
103103
Log.debug("createLevel - create static models");
104104
// server creates static models here, client will create the models when received from server upon connection
105-
createStaticModels();
105+
createStaticModels(25);
106106
}
107107

108108
Log.debug("createLevel - create boxes");
@@ -149,7 +149,7 @@ private static void setupStaticModel(Array<MeshPart> meshParts, Matrix4 matrix,
149149
Physics.inst.addStaticGeometryToWorld(obj);
150150
}
151151

152-
private static void createStaticModels() {
152+
private static void createStaticModels(int number) {
153153
staticGeometry = new Array<>();
154154
if (Main.isClient()) {
155155
mb = new ModelBuilder();
@@ -168,10 +168,9 @@ private static void createStaticModels() {
168168
//float hi = GameWorld.WORLD_WIDTH;
169169
float x = 20f;
170170
float z = 0f;
171-
int numOfStaticObjects = 8;
172-
for (int i = 0; i < numOfStaticObjects; i++) {
173-
x = MathUtils.random(10f, 100f);
174-
z = MathUtils.random(10f, 100f);
171+
for (int i = 0; i < number; i++) {
172+
x = MathUtils.random(GameWorld.WORLD_WIDTH);
173+
z = MathUtils.random(GameWorld.WORLD_DEPTH);
175174
quat.setEulerAngles(MathUtils.random(360f), MathUtils.random(360f), MathUtils.random(360f));
176175
String modelName = modelChoices.random();
177176
// bullet builds its physics shape using meshparts

core/src/org/jrenner/fps/Main.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,6 @@ private void setupNetwork() {
7676
} else if (isLocalServer()) {
7777
server = new LocalServer();
7878
}
79-
if (isServer()) {
80-
server.setupGame();
81-
}
8279
if (isClient()) {
8380
clientEventManager = new ClientEventManager();
8481
if (isLocalServer()) {

core/src/org/jrenner/fps/RollingArray.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44

55
/** An Array that will automatically remove oldest items when beyond max size */
66
public class RollingArray {
7+
8+
public RollingArray() {
9+
10+
}
11+
12+
public RollingArray(int maxSize) {
13+
this.maxSize = maxSize;
14+
}
15+
716
Array<Integer> items = new Array<>();
817
public int maxSize = 60;
918

core/src/org/jrenner/fps/Sky.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
package org.jrenner.fps;
33

4-
import com.badlogic.gdx.graphics.g3d.Material;
4+
import com.badlogic.gdx.math.Quaternion;
55
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
66

77
import com.badlogic.gdx.graphics.Texture;
@@ -72,10 +72,17 @@ public static void createSkySphere () {
7272
}
7373

7474
private static final Vector3 tmp = new Vector3();
75+
private static final Quaternion q = new Quaternion();
76+
public static float yawRotation = 0f;
77+
public static float yawRotateSpeed = 0.01f;
7578

7679
public static void update (Vector3 position) {
7780
tmp.set(position.x, position.y, position.z);
78-
modelInstance.transform.setToTranslation(tmp);
81+
modelInstance.transform.getRotation(q);
82+
yawRotation += yawRotateSpeed;
83+
q.setFromAxis(Vector3.Y, yawRotation);
84+
modelInstance.transform.set(q);
85+
modelInstance.transform.setTranslation(tmp);
7986
}
8087

8188
public static void disable () {

core/src/org/jrenner/fps/View.java

Lines changed: 87 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,19 @@
1818
import com.badlogic.gdx.math.Vector3;
1919
import com.badlogic.gdx.utils.Disposable;
2020

21+
import com.badlogic.gdx.utils.TimeUtils;
2122
import org.jrenner.fps.entity.Entity;
2223
import org.jrenner.fps.graphics.EntityModel;
2324
import org.jrenner.fps.graphics.ModelManager;
25+
import org.jrenner.fps.net.packages.ChatMessage;
2426
import org.jrenner.fps.particles.Particles;
2527

2628
public class View implements Disposable {
2729
public static View inst;
2830
private GL20 gl;
2931
public static int width, height;
3032
private PerspectiveCamera camera;
31-
private Environment environ;
33+
private Environment environ, basicEnviron;
3234
private PointLight camLight;
3335
private DirectionalLight dirLight;
3436
public HUD hud;
@@ -39,8 +41,6 @@ public class View implements Disposable {
3941

4042
private DefaultShaderProvider shaderProvider;
4143

42-
private static final int MAX_POINTLIGHTS = 1;
43-
private static final int MAX_DIRECTIONAL_LIGHTS = 2;
4444

4545
private void initShaders() {
4646
FileHandle vertexFile = Gdx.files.internal("shaders/vertex.glsl");
@@ -51,7 +51,8 @@ private void initShaders() {
5151
shaderProvider.config.numDirectionalLights = 2;
5252

5353

54-
// I don't remember what I was doing with this but it seems like it could be useful later
54+
// check shader compile logs
55+
5556
/*shader = new ShaderProgram(vertexFile, fragFile);
5657
ShaderProgram.pedantic = false;
5758
String log = shader.getLog();
@@ -69,18 +70,20 @@ public View() {
6970
gl = Gdx.graphics.getGL20();
7071
float fov = 67f;
7172
camera = new PerspectiveCamera(fov, width(), height());
72-
camera.far = 50f;
73+
// camera.far affects frustrum culling, so a shorter distance can boost performance
74+
camera.far = 60f;
7375
camera.near = 0.01f;
7476
resetCamera();
7577

7678
initShaders();
7779
modelBatch = new ModelBatch(shaderProvider);
7880

7981
environ = new Environment();
82+
basicEnviron = new Environment();
8083
camLight = new PointLight();
8184
float intensity = 100f;
8285
camLight.set(new Color(0.2f, 0.2f, 0.2f, 1f), 0f, 0f, 0f, intensity);
83-
ColorAttribute ambientLight = new ColorAttribute(ColorAttribute.AmbientLight, new Color(0.1f, 0.1f, 0.1f, 1f));
86+
ColorAttribute ambientLight = ColorAttribute.createAmbient(new Color(0.1f, 0.1f, 0.1f, 1f));
8487
environ.set(ambientLight);
8588
ColorAttribute fog = new ColorAttribute(ColorAttribute.Fog);
8689
fog.color.set(fogColor);
@@ -90,6 +93,8 @@ public View() {
9093
dirLight.set(new Color(0.3f, 0.3f, 0.35f, 1f), -0.25f, -0.75f, 0.25f);
9194
environ.add(dirLight);
9295

96+
basicEnviron.set(ColorAttribute.createAmbient(0.3f, 0.3f, 0.3f, 1f));
97+
9398
if (Toggleable.profileGL()) {
9499
Profiler.enable();
95100
}
@@ -117,7 +122,50 @@ private void updateCamera() {
117122
camera.update();
118123
}
119124

125+
long lastSwitch = -1;
126+
RollingArray renderTimes = new RollingArray();
127+
RollingArray hudTimes = new RollingArray();
128+
RollingArray entityTimes = new RollingArray();
129+
RollingArray staticTimes = new RollingArray();
130+
RollingArray boxTimes = new RollingArray();
131+
RollingArray skyTimes = new RollingArray();
132+
RollingArray groundTimes = new RollingArray();
133+
134+
private void debugRenderTimes() {
135+
// tied in with the profileGL toggleable for now
136+
long now = TimeUtils.millis();
137+
long passed = now - lastSwitch;
138+
if (passed >= 1000 || lastSwitch < 0) {
139+
float totalTime = renderTimes.getAverage();
140+
float hudTime = hudTimes.getAverage();
141+
float entityTime = entityTimes.getAverage();
142+
float staticTime = staticTimes.getAverage();
143+
float boxTime = boxTimes.getAverage();
144+
float skyTime = skyTimes.getAverage();
145+
float groundTime = groundTimes.getAverage();
146+
renderTimes.clear();
147+
hudTimes.clear();
148+
entityTimes.clear();
149+
staticTimes.clear();
150+
boxTimes.clear();
151+
skyTimes.clear();
152+
groundTimes.clear();
153+
lastSwitch = now;
154+
String text = String.format("render-times(ms), total: %.1f, hud: %.1f, entity: %.1f, static: %.1f\n" +
155+
" boxes: %.1f, sky: %.1f, ground: %.1f",
156+
totalTime, hudTime, entityTime, staticTime, boxTime, skyTime, groundTime);
157+
Main.inst.client.sendChatMessage(new ChatMessage(text));
158+
Log.debug(text);
159+
}
160+
}
161+
162+
boolean debugRenderPerformance = false;
163+
120164
public void render() {
165+
if (debugRenderPerformance) {
166+
debugRenderTimes();
167+
}
168+
long start = TimeUtils.millis();
121169
boolean profileGL = Toggleable.profileGL();
122170
updateLights();
123171
if (profileGL) {
@@ -128,42 +176,56 @@ public void render() {
128176
gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
129177
camera.up.set(Vector3.Y);
130178
updateCamera();
131-
updateSky();
132179

180+
long skyStart = TimeUtils.millis();
181+
updateSky();
133182
modelBatch.begin(camera);
134183
if (Sky.isEnabled()) {
135184
modelBatch.render(Sky.modelInstance);
136185
}
186+
skyTimes.add((int) TimeUtils.timeSinceMillis(skyStart));
137187

138188
// includes 3d models and billboards
189+
long entityStart = TimeUtils.millis();
190+
visibleEntities = 0;
139191
for (EntityModel entityModel : EntityModel.list) {
140192
entityModel.update();
141193
// don't draw self when in FPS mode
142194
if (!entityModel.isClientEntity() || Toggleable.freeCamera()) {
143-
modelBatch.render(entityModel.modelInstance, environ);
195+
if (entityVisibilityCheck(entityModel)) {
196+
visibleEntities++;
197+
modelBatch.render(entityModel.modelInstance, environ);
198+
}
144199
}
145200
}
201+
entityTimes.add((int) TimeUtils.timeSinceMillis(entityStart));
202+
203+
long boxStart = TimeUtils.millis();
146204
if (Box.instance != null) {
147205
modelBatch.render(Box.instance, environ);
148206
}
207+
boxTimes.add((int) TimeUtils.timeSinceMillis(boxStart));
208+
209+
long staticStart = TimeUtils.millis();
149210
if (LevelBuilder.staticGeometry != null) {
150211
for (ModelInstance staticGeo : LevelBuilder.staticGeometry) {
151212
modelBatch.render(staticGeo, environ);
152213
}
153214
}
215+
staticTimes.add((int) TimeUtils.timeSinceMillis(staticStart));
154216

155-
totalGroundPieces = 0;
217+
long groundStart = TimeUtils.millis();
156218
visibleGroundPieces = 0;
157219
for (ModelInstance groundPiece : LevelBuilder.groundPieces) {
158-
totalGroundPieces++;
159220
if (groundPieceVisibilityCheck(groundPiece)) {
160221
visibleGroundPieces++;
161222
modelBatch.render(groundPiece, environ);
162223
}
163224
}
225+
groundTimes.add((int) TimeUtils.timeSinceMillis(groundStart));
164226
modelBatch.end();
165227

166-
// draw particle effects in a separate batch to make depth testing work correctly
228+
// draw particle effects in a separate batch to make depth testing work better
167229
modelBatch.begin(camera);
168230
for (Shadow shadow : Shadow.list) {
169231
modelBatch.render(shadow.modelInstance, environ);
@@ -179,7 +241,13 @@ public void render() {
179241
Physics.inst.debugDraw();
180242
}
181243

244+
long hudStart = TimeUtils.millis();
182245
hud.draw();
246+
long hudTime = TimeUtils.timeSinceMillis(hudStart);
247+
hudTimes.add((int) hudTime);
248+
249+
long time = TimeUtils.timeSinceMillis(start);
250+
renderTimes.add((int) time);
183251
}
184252

185253
private void drawParticleEffects() {
@@ -287,18 +355,25 @@ public void storeSize() {
287355
height = Gdx.graphics.getHeight();
288356
}
289357

290-
public static int totalGroundPieces;
291358
public static int visibleGroundPieces;
292359
private boolean groundPieceVisibilityCheck(ModelInstance modelInst) {
293360
float halfWidth = LevelBuilder.groundPieceSize / 2f;
294361
modelInst.transform.getTranslation(tmp);
295362
// we want the center of the piece
296363
tmp.add(halfWidth, 0, halfWidth);
364+
float radius = LevelBuilder.groundPieceSize;
297365
return camera.frustum.sphereInFrustum(tmp, LevelBuilder.groundPieceSize);
298366
// this naive method is useful for debugging to see pop-in/pop-out
299367
//return camera.frustum.pointInFrustum(tmp);
300368
}
301369

370+
public static int visibleEntities;
371+
private boolean entityVisibilityCheck(EntityModel entModel) {
372+
entModel.modelInstance.transform.getTranslation(tmp);
373+
float radius = entModel.entity.getRadius();
374+
return camera.frustum.sphereInFrustum(tmp, radius);
375+
}
376+
302377
@Override
303378
public void dispose() {
304379
Tools.dispose(modelBatch);

core/src/org/jrenner/fps/entity/DynamicEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public void jump() {
119119
private int ticksPerShot = 6;
120120
private int tickCountdown;
121121
private boolean shooting;
122-
private float aimError = 0.035f;
122+
private float aimError = 0.025f;
123123

124124
public void startShoot() {
125125
shooting = true;

0 commit comments

Comments
 (0)