Skip to content

Feature/android camera controls#81

Draft
diegurrio wants to merge 14 commits intomainfrom
feature/android_camera_controls
Draft

Feature/android camera controls#81
diegurrio wants to merge 14 commits intomainfrom
feature/android_camera_controls

Conversation

@diegurrio
Copy link
Copy Markdown
Collaborator

⏺ Add touch camera controls to Android renderer

Adds gesture-based camera control to the Android NativeActivity renderer via a self-contained handle_touch() function in android_main.c — no changes to scene.c.

  • 1-finger drag → orbit around vehicle (yaw + pitch, elevation clamped ±89°)
  • 2-finger pinch → zoom (proportional to orbit distance, min 2m)
  • 2-finger drag → pan orbit target along camera right/up axes
  • Finger-count transitions reset gesture state to prevent camera jumps

How to Test

  • 1-finger drag orbits smoothly without flipping at extremes
  • Pinch zooms proportionally; stops at ~2m
  • 2-finger drag pans; vehicle re-centers correctly
  • 1↔2 finger transitions produce no camera jump
  • ./gradlew assembleDebug passes
Screen_recording_20260416_222129.mp4

diegurrio and others added 8 commits April 16, 2026 22:28
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Keeps finger-0 position current so 2→1 transitions always start
from the correct touch position, not a stale value from the last
1-finger session.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Zoom now scales proportionally to orbit distance so feel is consistent
at any range. Also resets cam->up at the start of the 2-finger branch
as a safety guard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds gesture-based camera controls to the Android NativeActivity renderer by introducing a self-contained per-frame touch handler that directly updates the scene camera without modifying shared desktop camera logic.

Changes:

  • Added handle_touch() in android_main.c to support 1-finger orbit, 2-finger pinch zoom, and 2-finger pan.
  • Enabled Raylib gesture input on Android and initialized orbit state (target + previous touch tracking).
  • Added design + implementation plan documents describing the touch control approach.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
android/app/src/main/cpp/android_main.c Implements touch-driven orbit/zoom/pan camera updates for Android.
android/docs/superpowers/specs/2026-04-16-touch-controls-design.md Documents gesture behavior and architecture for Android touch controls.
android/docs/superpowers/plans/2026-04-16-touch-controls.md Step-by-step implementation plan for the touch control feature.
.claude/settings.local.json Expands allowed gh command permissions for tooling automation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .claude/settings.local.json
@MikePehel
Copy link
Copy Markdown
Contributor

MikePehel commented Apr 17, 2026

I haven't had a chance to test it properly, but just from the video I can note a few things. It looks like mtl colors aren't being loaded on the drone obj. Do you know where and how that failed? I also see a volume bar, but this won't include audio from the log files, so that can probably be stripped.

The camera movement looks intuitive, but Ramon and I just chatted the other day about a weapon wheel style selection of features like the diegetic trails, or orthographic view switching. I just want to make sure your single finger presses wouldn't conflict with a long press hold on either the left side of the screen.

@diegurrio
Copy link
Copy Markdown
Collaborator Author

diegurrio commented Apr 21, 2026

Hi @MikePehel nice to meet you.

Do you know where and how that failed?

Yup, it has to do with how Android handles assets. They need to be included in the APK and reading them from the JNI layer is a pain in the butt. I'll fix that in this PR.

I also see a volume bar, but this won't include audio from the log files, so that can probably be stripped.

Do you mean after pressing the volume button? That is normal system behavior but if you guys want to kill it I can intercept the event and handle it. I can also add that to this PR and we can decide if we keep the code. I would recommend we let the event go through and display the volume bar.

@diegurrio
Copy link
Copy Markdown
Collaborator Author

diegurrio commented Apr 21, 2026

Long press / weapon wheel: No conflict with the current implementation. The touch handler only enables GESTURE_DRAG | GESTURE_PINCH_IN | GESTURE_PINCH_OUT, so GESTURE_HOLD isn't recognized at all right now. When the weapon wheel is implemented, the touch handler would need to check touch region or gesture type before routing to the camera. It should be straightforward to add at that point.

diegurrio and others added 5 commits April 20, 2026 22:01
parse_mtl_names used fopen which silently fails inside an APK — switch
to LoadFileText/UnloadFileText so it routes through the existing
AAssetManager callback, restoring arm material colors on Android.

Wrap Raylib's onInputEvent to consume AKEYCODE_VOLUME_UP/DOWN (return 1)
before they reach the OS, preventing the system volume overlay from
appearing since the app has no audio.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restore android_app->onInputEvent on teardown to match the
SetLoadFileTextCallback(NULL) cleanup pattern.

Replace silent NULL fallback in input_handler with __android_log_print
so the guard is visible in logcat if initialization order ever changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cceeds

The real MTL loading failure was in tinyobj_parse_mtl_file (called inside
Raylib's LoadOBJ), which uses fopen directly. On Android, APK assets aren't
on the filesystem, so fopen returns NULL, tinyobj assigns material_id = -1 to
all faces, and Raylib collapses the model to a single white mesh — the
color-match in remap_materials never had anything to work with.

Fix: before vehicle_init, set the working directory to internalDataPath,
create a models/ subdirectory, and extract every model MTL from AAssetManager
to that directory. Raylib's subsequent chdir("models") then succeeds, and
tinyobj's fopen("*.mtl") finds the file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…paths

tinyobj_loader_c uses fopen() to read .mtl files, which fails on Android
because APK assets have no real filesystem path. An earlier approach staged
.mtl files to internalDataPath and patched the mtllib directive to an absolute
path, but fopen of /data/user/0/... silently fails on Pixel 10 Pro XL /
Android 16 due to bind-mount CWD vs path divergence.

New approach:
- stage_model_assets() preloads every .mtl from the APK into an in-memory
  buffer via AAssetManager at startup.
- -Wl,--wrap,fopen intercepts all fopen() calls within libhawkeye.so.
  .mtl reads return an fmemopen FILE* from the cache; everything else
  passes through to __real_fopen.

This requires no Raylib/tinyobj source modifications and is robust across
clean builds and device-specific filesystem quirks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add TOUCH_MAX_ORBIT_DIST (50.0f) to prevent pinch-out from zooming the
drone to sub-pixel size. Correct stale comment referencing the removed
hawkeye_mtl_fopen/tinyobj patch approach — the current MTL mechanism
is __wrap_fopen + fmemopen via -Wl,--wrap,fopen in CMakeLists.txt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@diegurrio diegurrio marked this pull request as draft April 21, 2026 05:17
@diegurrio diegurrio self-assigned this Apr 21, 2026
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.

3 participants