Skip to content

Replace JavaFX with SDL2 + OpenGL ES 2.0 via JNI#1

Draft
Copilot wants to merge 6 commits intopos2_PosBoundsfrom
copilot/replace-javafx-with-sdl2-opengles
Draft

Replace JavaFX with SDL2 + OpenGL ES 2.0 via JNI#1
Copilot wants to merge 6 commits intopos2_PosBoundsfrom
copilot/replace-javafx-with-sdl2-opengles

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 2, 2026

JavaFX is unavailable on most smartphones; SDL2 + GLES2 is universal across desktops and Android. This replaces the ~100 lines of JavaFX usage across two files with a thin JNI bridge, preserving all physics/threading logic unchanged.

New files

  • susuwu/SdlGles2.java — JNI bridge: init, destroy, pollQuit, glClear*, swapWindow, setWindowTitle, drawFilledPolygon
  • susuwu/sdl_gles2_jni.c — C implementation via SDL2 + GLES2; includes minimal vertex/fragment shaders (pixel→clip-space with Y-flip to match JavaFX canvas orientation)

FishSim.java

  • Drops extends Application; main() calls new FishSim().run(args) directly
  • AnimationTimer/Timeline render loop → SDL event loop with Thread.sleep(1) frame limiter
  • Timeline/KeyFrame physics loop → ScheduledExecutorService (ms-precision) for separateFps, background thread for separateUnbound; synchronous/async modes unchanged
  • Fish.render(GraphicsContext)Fish.render() via SdlGles2.drawFilledPolygon: same pentagon vertices {0,-10},{-5,10},{-2,0},{2,0},{5,10} triangulated as fan {0,1,2},{0,2,3},{0,3,4}, rotated in Java then passed as screen-space floats
  • javafx.scene.paint.Color → nested FishSim.Color with color(r,g,b), getRed/Green/Blue()isSimilarTo() logic unchanged

SimUsages.java

  • Constructor drops Pane param; no display object needed
  • Platform.runLater(fpsTextRefresh) → direct call (SDL2 has no UI-thread restriction)
  • Text.setText(str)SdlGles2.setWindowTitle("Fish Simulation (Boids) - " + str)

Build scripts (susuwu/build.sh, build.sh)

  • Removes PATH_TO_FX / --module-path / --add-modules javafx.*
  • Adds native compilation step:
    cc -shared -fPIC sdl_gles2_jni.c -o libsdl_gles2_jni.so \
        -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux \
        $(pkg-config --cflags --libs sdl2) -lGLESv2
  • Adds apt install libsdl2-dev libgles2-mesa-dev; adds -Djava.library.path=. to JVM flags
  • .gitignore updated to exclude *.so/*.dll/*.dylib

All pure-Java files (Calculus, Forces, Pos*, ImmutablePos*, PosBounds*, ClassBounds) are untouched.

Original prompt

Goal

Replace all JavaFX usage with SDL2 + OpenGL ES 2.0 via JNI wrappers, so FishSim can execute on all desktops and smartphones (JavaFX is not available on most smartphones, but GLES2 is universal).

Context

The JavaFX usage is limited to fewer than 100 lines across only 2 files:

  • susuwu/FishSim.java — uses javafx.application.Application, Stage, Scene, Canvas, GraphicsContext2D, AnimationTimer, Timeline, KeyFrame, Duration, Color, Pane
  • susuwu/SimUsages.java — uses javafx.application.Platform.runLater(), javafx.scene.layout.Pane, javafx.scene.paint.Color, javafx.scene.text.Text

All other files (Calculus.java, Forces.java, Pos.java, Pos2.java, ImmutablePos.java, ImmutablePos2.java, PosBounds.java, ImmutablePosBounds.java, ClassBounds.java) are pure Java with zero JavaFX dependency — these must remain unchanged.

What to change

1. Create a JNI wrapper for SDL2 + GLES2

Add a new file susuwu/SdlGles2.java (or similar name) which provides a thin JNI bridge to SDL2 and OpenGL ES 2.0. This should provide:

  • Window creation/destruction (replaces Stage, Scene)
  • GLES2 rendering context (replaces Canvas, GraphicsContext2D)
  • Main loop / event pump (replaces AnimationTimer, Timeline, KeyFrame)
  • Basic drawing primitives: clear screen, fill triangles/polygons with color (replaces gc.save/translate/rotate/setFill/beginPath/moveTo/lineTo/closePath/fill/restore)
  • Text rendering (replaces javafx.scene.text.Text) — can be very simple/minimal

Also add the corresponding C/JNI native source file(s) (e.g., susuwu/sdl_gles2_jni.c) that implement the native methods using SDL2 and GLES2 headers.

2. Modify susuwu/FishSim.java

  • Remove all import javafx.* statements
  • Replace extends Application with a plain public class with a main() that initializes SDL2 window + GLES2 context via the JNI wrapper
  • Replace start(Stage primaryStage) logic: init SDL2 window, create GLES2 context, then enter the main loop
  • Replace AnimationTimer / Timeline animation loops with a simple while(!quit) SDL event + render loop (SDL_PollEvent / SDL_GL_SwapWindow), calling updateFish() and renderFish() at the configured rates
  • Replace GraphicsContext gc rendering in Fish::render() with GLES2 draw calls (glClear, drawing colored triangles for fish shapes using the same vertex coordinates: {0,-10}, {-5,10}, {-2,0}, {2,0}, {5,10})
  • Replace javafx.scene.paint.Color with a simple color class or double[]{r,g,b} / float[]{r,g,b,a}. The Fish constructor currently takes Color.color(r,g,b) and isSimilarTo() uses color.getRed(), color.getGreen(), color.getBlue() — these must still work
  • Replace Canvas.clearRect() with glClear(GL_COLOR_BUFFER_BIT)
  • Preserve all physics logic exactly: PhysicsMode enum, updateFish(), renderFish() (just the draw calls change), Fish.applyFlockingRules(), applySeparation(), applyAlignment(), applyCohesion(), applyWallAvoidance(), update(), setPos(), isSimilarTo(), getPosDiff()
  • Preserve ReentrantLock usage, ExecutorService, and all threading logic
  • Preserve setResolution() logic
  • The stop() method should call SDL_Quit and executor.shutdown()

3. Modify susuwu/SimUsages.java

  • Remove all import javafx.* statements
  • Remove the Pane constructor parameter — replace with whatever the SDL2 JNI wrapper uses
  • Replace javafx.scene.text.Text with SDL2/GLES2 text rendering (can be very basic — e.g., render to window title via SDL_SetWindowTitle, or use a minimal bitmap font renderer)
  • Remove Platform.runLater() — in SDL2 the text update can happen directly on the render thread
  • Replace Color.WHITE with the equivalent
  • Preserve all measurement logic (startRefresh, postRefresh, startRender, postRender, startPhysics, postPhysics, fpsTextRefresh, FpsTextMode enum) exactly

4. Update susuwu/build.sh

  • Remove the PATH_TO_FX / openjfx / --module-path / --add-modules javafx.* logic
  • Add compilation of the C JNI native code: compile sdl_gles2_jni.c into a shared library (.so / .dll / .dylib) using cc or gcc with -lSDL2 -lGLESv2 (or appropriate flags)
  • Add apt install libsdl2-dev (or equivalent) for the SDL2 dependency
  • Update the java invocation to include -Djava.library.path=. (or wherever the .so is) so JNI can find the native library
  • Keep the GITHUB_ACTIONS conditional and exit $?

5. Do NOT modify these files (they have zero JavaFX dependency):

  • susuwu/Calculus.java
  • susuwu/Forces.java
  • susuwu/Pos.java
  • susuwu/Pos2.java
  • susuwu/ImmutablePos.java
  • susuwu/ImmutablePos2.java
  • susuwu/PosBounds.java
  • susuwu/ImmutablePosBounds.java
  • susuwu/ClassBounds.java

Key constraints

  • Must preserve the existing attribution/license headers (just update filenames if needed)
  • Must preserve all physics simulation behavior identically
  • Must preserve PhysicsMode...

This pull request was created from Copilot chat.

Agent-Logs-Url: https://github.com/SwuduSusuwu/SusuJava/sessions/77ade638-4784-4228-a897-83c9d8a0222a

Co-authored-by: SwuduSusuwu <168943815+SwuduSusuwu@users.noreply.github.com>
Copilot AI changed the title [WIP] Replace JavaFX usage with SDL2 and OpenGL ES 2.0 via JNI wrappers Replace JavaFX with SDL2 + OpenGL ES 2.0 via JNI Apr 2, 2026
Copilot AI requested a review from SwuduSusuwu April 2, 2026 16:38
@`./susuwu/FishSim.java`: @`boundsResolutionFactor`: if small resolution then factor = 2.0, if huge resolution then factor = 1.2, until invisible (unshown) `Fish` have resource use lowered
@SwuduSusuwu
Copy link
Copy Markdown
Owner

SwuduSusuwu commented Apr 3, 2026

@copilot
No regressions on Ubuntu.
Improvements: CPU use was java was ~62% CPU (~379000 RES), gnome-shell ~12%, xwayland ~8%. Now is java ~24% (~276000 RES), gnome-shell ~22%, xwayland ~6%. Did not expect such inprovements, since SimUsages.java showed renderMs was less than half of physicsMs, but guess SDL2's scheduler improves CPU use, but lowers RES (RAM) use.

@SwuduSusuwu
Copy link
Copy Markdown
Owner

SwuduSusuwu commented Apr 3, 2026

@copilot
Cannot review until Termux environment problem has solution:

~/SusuJava $ ./build.sh
Error: Unable to locate package libsdl2-dev
Error: Unable to locate package libgles2-mesa-dev
MESA: error: ZINK: failed to choose pdev
libEGL warning: egl: failed to create dri2 screen

. Guess the packages are not the problem (Termux has sdl2, not libsdl2-dev, so installed sdl2 for now), since without the packages libEGL warning: egl: failed to create dri2 screen should not print, so guess the problem is with Termux's connection to the Wayland server: wish for suggestions on how to troubleshoot this.

Copy link
Copy Markdown
Owner

@SwuduSusuwu SwuduSusuwu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Purpose was to include support for Termux: but can not test this on Termux due to environment problems.
No regressions on Ubuntu (performance improves), so will approve this for now.

@SwuduSusuwu SwuduSusuwu force-pushed the copilot/replace-javafx-with-sdl2-opengles branch from 0a59933 to cd6c603 Compare April 8, 2026 04:35
@`./susuwu/FishSim.java`: @`enum PhysicsMode`, @`void run(String[] args)`: document how (with `GLES2`, if `monitorRefreshMode = separateUnbound`) `SimUsages.drawNS` includes time for vertical sync, plus propose future solutions (`SDL_GL_SetSwapInterval(0);`, or subtract `GlClear()` time from `SimUsages.drawNS`.)
Is followup to: commit 09d1a88 (Replace JavaFX with SDL2+GLES2 via JNI wrappers), which replaces `javafx` with `GLES2`.
@`./susuwu/SimUsages.java`: +`preSynchro()`, +`postSynchro()`.

Is followup to: commit HEAD~1 (@`FishSim.java`: document SimUsages includes vsync), which suggests this solution.
@`susuwu/FishSim.java`: introduce `SimUsages.preSynchro()` before `SdlGles2.glClear()`, then `SimUsages.postSynchro()`
Is followup to: commit HEAD~1 (@`SimUsages.java`: +`{pre,post}Synchro()`).
Is followup to: commit HEAD~2 (@`FishSim.java`: document SimUsages includes vsync), whose "TODO:" lists this removes.
@SwuduSusuwu SwuduSusuwu force-pushed the copilot/replace-javafx-with-sdl2-opengles branch from 8ead24b to d0ab352 Compare April 9, 2026 02:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants