Skip to content

Commit 81ffbce

Browse files
committed
Treewide: Rework input handling, frame limiter and serviceRepaints
The idea behind this is fixing a bunch of regressions caused by the newer input handling, and the better render sync code. Frame limiting is now donw by lcdui's Canvas and GameCanvas instead of MobilePlatform's over-arching flushGraphics() method, which was prone to inaccuracies if games heavily used serviceRepaints() to constantly sync the render state. Most notably, this rework fixes Sonic 1's regression of improper frame-pacing due to serviceRepaints calls (which made the framecounter and limiter think the game was running at double the framerate), at the same time it keeps the Panasonic VS3 version working because it only needs serviceRepaints to sync the upper area of the screen. Previously fixing one by messing with serviceRepaints() logic would break the other. Beyond Sonic 1, it should fix pretty much any instance of inaccurate timing in other games without reintroducing flickering in games such as Pipyakas/Boombakas, so it's related to issues #10 and #68. Furthermore, input is no longer queued into serial calls, because it's no longer needed. This helps Puzzlegeddon (#71), and Ratatouille without breaking anything else that i could find at the moment, and Ratatouille was one that previously required queuing those inputs. Heroes Lore: Wind of Soltia regressed randomly at some point and gets stuck in a white screen after pressing any key, so it can't really be tested further, although the input delay when pressing keys appears to be gone from it as well.
1 parent cb4271c commit 81ffbce

File tree

4 files changed

+21
-30
lines changed

4 files changed

+21
-30
lines changed

src/javax/microedition/lcdui/Canvas.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,15 @@ public void pointerReleased(int x, int y) { }
166166

167167
public void repaint(int x, int y, int width, int height)
168168
{
169+
Mobile.getPlatform().limitFps();
169170
try
170171
{
171172
if (!isShown() || listCommands) { return; }
172173

173174
// TODO: This might be an issue
174175
if (isPainting)
175176
{
177+
Mobile.log(Mobile.LOG_WARNING, Canvas.class.getPackage().getName() + "." + Canvas.class.getSimpleName() + ": " +"Recursive repaint attempted");
176178
// we need this to avoid stackoverflow
177179
// but it seems the underlying problem is that when paint calls
178180
// repaint, we shouldn't even land here...
@@ -208,10 +210,11 @@ public void repaint(int x, int y, int width, int height)
208210
public void serviceRepaints()
209211
{
210212
// TODO: Flesh this out properly, some games might need it.
211-
if(!isShown() || isPainting) { return; }
213+
if(!isShown()) { return; }
212214

213-
// Right now all this does is force a redraw, no queue consideration is made.
215+
// serviceRepaints has to force any pending repaints to be serviced
214216
Mobile.getPlatform().flushGraphics(platformImage, 0, 0, width, height);
217+
isPainting = false;
215218
}
216219

217220
public void setFullScreenMode(boolean mode)

src/javax/microedition/lcdui/Display.java

+2-16
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ public class Display
4646

4747
private final Queue<Runnable> serialCalls;
4848
private final Thread serialThread;
49-
private volatile boolean processingCalls;
5049

5150
private boolean isSettingCurrent = false;
5251

@@ -59,7 +58,6 @@ public Display()
5958
Mobile.setDisplay(this);
6059

6160
serialCalls = new LinkedList<>();
62-
processingCalls = true;
6361
serialThread = new Thread(this::processSerialCalls);
6462
serialThread.start();
6563
}
@@ -71,27 +69,15 @@ public void callSerially(Runnable r)
7169

7270
private void processSerialCalls()
7371
{
74-
while (processingCalls)
72+
while (true)
7573
{
76-
Runnable runnable = null;
77-
7874
synchronized (serialCalls)
7975
{
80-
if (!serialCalls.isEmpty()) { runnable = serialCalls.poll(); }
81-
82-
if (runnable != null) { runnable.run(); }
76+
if (!serialCalls.isEmpty()) { serialCalls.poll().run(); }
8377
}
8478
}
8579
}
8680

87-
public void stop() // Didn't find an use for this yet
88-
{
89-
processingCalls = false;
90-
serialThread.interrupt();
91-
try { serialThread.join(); }
92-
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
93-
}
94-
9581
public boolean flashBacklight(int duration)
9682
{
9783
try

src/javax/microedition/lcdui/game/GameCanvas.java

+4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ public void paint(Graphics g) { }
5252

5353
public void flushGraphics(int x, int y, int width, int height)
5454
{
55+
Mobile.getPlatform().limitFps();
56+
57+
if (width <= 0 || height <= 0 || x + width < 0 || y + height < 0 || x >= this.width || y >= this.height) { return; }
58+
5559
Mobile.getPlatform().flushGraphics(platformImage, x, y, width, height);
5660
}
5761

src/org/recompile/mobile/MobilePlatform.java

+10-12
Original file line numberDiff line numberDiff line change
@@ -151,34 +151,34 @@ public void resizeLCD(int width, int height)
151151

152152
public void keyPressed(int keycode)
153153
{
154-
Mobile.getDisplay().callSerially(() -> { updateKeyState(Mobile.getGameAction(keycode), 1); });
155-
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.keyPressed(keycode); }); }
154+
updateKeyState(Mobile.getGameAction(keycode), 1);
155+
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.keyPressed(keycode); }
156156
}
157157

158158
public void keyReleased(int keycode)
159159
{
160-
Mobile.getDisplay().callSerially(() -> {updateKeyState(Mobile.getGameAction(keycode), 0); });
161-
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.keyReleased(keycode); }); }
160+
updateKeyState(Mobile.getGameAction(keycode), 0);
161+
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.keyReleased(keycode); }
162162
}
163163

164164
public void keyRepeated(int keycode)
165165
{
166-
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.keyRepeated(keycode); }); }
166+
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.keyRepeated(keycode); }
167167
}
168168

169169
public void pointerDragged(int x, int y)
170170
{
171-
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.pointerDragged(x, y); }); }
171+
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.pointerDragged(x, y); }
172172
}
173173

174174
public void pointerPressed(int x, int y)
175175
{
176-
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.pointerPressed(x, y); }); }
176+
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.pointerPressed(x, y); }
177177
}
178178

179179
public void pointerReleased(int x, int y)
180180
{
181-
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { Mobile.getDisplay().callSerially(() -> {displayable.pointerReleased(x, y); }); }
181+
if ((displayable = Mobile.getDisplay().getCurrent()) != null) { displayable.pointerReleased(x, y); }
182182
}
183183

184184
private void updateKeyState(int key, int val)
@@ -298,7 +298,6 @@ public final void flushGraphics(Image img, int x, int y, int width, int height)
298298

299299
if(!showFPS.equals("Off")) { showFPS();}
300300
painter.run(); // Update the frontend's painter first to then process inputs
301-
limitFps();
302301

303302
processInputs();
304303
}
@@ -342,8 +341,9 @@ else if (pressedKeys[i] == false && previouslyPressed[i] == true)
342341
}
343342
}
344343

345-
private void limitFps()
344+
public void limitFps()
346345
{
346+
frameCount++;
347347
if(Mobile.limitFPS == 0) { lastRenderTime = System.nanoTime(); return; }
348348

349349
requiredFrametime = 1_000_000_000 / Mobile.limitFPS;
@@ -364,8 +364,6 @@ private void limitFps()
364364
// For now, the logic here works by updating the framerate counter every second
365365
private final void showFPS()
366366
{
367-
frameCount++;
368-
369367
if (System.nanoTime() - lastFpsTime >= 1_000_000_000)
370368
{
371369
fps = frameCount;

0 commit comments

Comments
 (0)