Skip to content

feat(accessibility): Barrel Zoom for 3D shooters - #1741

Open
feilen wants to merge 2 commits into
utkarshdalal:masterfrom
feilen:feat/barrel-zoom
Open

feat(accessibility): Barrel Zoom for 3D shooters#1741
feilen wants to merge 2 commits into
utkarshdalal:masterfrom
feilen:feat/barrel-zoom

Conversation

@feilen

@feilen feilen commented Jul 19, 2026

Copy link
Copy Markdown

Description

  • Makes it more comfortable to play 3D or FPS games on a tiny screen!
  • Accessability feature which accepts strength, VFOV, and cylindrical ratio as tunables.
  • Allows for a sort of center-zoom which trends towards 'angle-area' to 'screen area' ratio being 1:1, instead of the sides of the screen taking up more space overall.
  • Hides all tunables when the feature is disabled
  • GL and Vulkan implementations

Limitations

  • Currently does not compose with other screen effects meaningfully - probably could (need to think over which effects should go in what order - e.g. FXAA should go first but FSR should go after)
  • Does not remap mouse or touch input (doesn't matter for perspective-heavy games which typically use mouse-look/controller)

Recording

out.mp4

Type of Change

  • Bug fix
  • Performance / stability improvement
  • Compatibility improvements
  • Other (requires prior approval)
    • Accessibility change

Checklist

  • If I have access to #code-changes, I have discussed this change there and it has been green-lighted. If I do not have access, I have still provided clear context in this PR. If I skip both, I accept that this change may face delays in review, may not be reviewed at all, or may be closed.
  • This change aligns with the current project scope (core functionality, stability, or performance). If not, it has been explicitly approved beforehand.
  • I have attached a recording of the change.
  • I have read and agree to the contribution guidelines in CONTRIBUTING.md.

Summary by cubic

Add Barrel Zoom (configurable barrel distortion) to screen effects. Improves comfort for 3D/FPS on small screens by centering zoom and reducing edge stretch.

  • New Features
    • UI: toggle and sliders for Strength, VFOV, and Cylindrical Ratio; controls hidden when disabled; values persisted in ScreenEffectsConfig.
    • Rendering: GL adds BarrelDistortionEffect; Vulkan adds EFFECT_MASK_BARREL_DISTORTION, extends VulkanRenderer#setEffect(...) and JNI with barrel params, and updates window shaders and push constants.
    • Cursor: keeps cursor rendering correct when Barrel Zoom is enabled.
    • Defaults/ranges: Strength 0–100% (mapped 0–1), VFOV 40°–120° (via tan), Cyl Ratio 0.5–1.5; sensible defaults.
    • Caveats: limited composition with some effects (ordering TBD; e.g., FXAA before, FSR after); input mapping unchanged.

Written for commit 86bd0a4. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added an optional Barrel Zoom (Barrel Distortion) screen effect.
    • Added UI controls for Strength, Vertical FOV, and Cylindrical Ratio.
    • Effect updates are applied live and saved for future sessions.
    • Reset restores the default barrel distortion values and disables the effect.
    • Included compatibility for cursor rendering and support across the available rendering modes.

- Makes it more comfortable to play 3D or FPS games on a tiny screen!
- Accessability feature which accepts strength, VFOV, and cylindrical ratio as tunables.
- Allows for a sort of center-zoom which trends towards 'angle-area' to 'screen area' ratio being 1:1, instead of the sides of the screen
  taking up more space overall.
- Hides all tunables when the feature is disabled
- GL and Vulkan implementations

- Currently does not compose with other screen effects meaningfully - probably could (need to think over which effects should go in what
  order - e.g. FXAA should go first but FSR should go after)
- Does not remap mouse or touch input (doesn't matter for perspective-heavy games which typically use mouse-look/controller)
@feilen
feilen requested a review from utkarshdalal as a code owner July 19, 2026 04:02
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds configurable barrel distortion to screen effects, including UI controls, persisted settings, OpenGL and Vulkan rendering paths, JNI plumbing, push constants, and shader-based UV remapping.

Changes

Barrel distortion screen effect

Layer / File(s) Summary
Configuration and screen-effects controls
app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt, app/src/main/java/app/gamenative/ui/component/ScreenEffectsPanel.kt, app/src/main/java/app/gamenative/ui/component/dialog/ScreenEffectDialog.kt, app/src/main/res/values/strings.xml
Adds barrel distortion settings, persistence, defaults, reset behavior, localized labels, and controls across the screen-effects interfaces.
OpenGL barrel distortion implementation
app/src/main/java/com/winlator/renderer/effects/BarrelDistortionEffect.java, app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt
Adds the configurable OpenGL effect, clamps shader uniforms, computes derived height values, and applies the effect when enabled.
Vulkan effect parameter plumbing
app/src/main/java/com/winlator/renderer/VulkanRenderer.java, app/src/main/cpp/winlator/vulkan_jni.cpp, app/src/main/cpp/winlator/VulkanRendererContext.h, app/src/main/cpp/winlator/VulkanRendererContext.cpp
Extends effect APIs, JNI calls, native state, push constants, and draw-command recording with barrel distortion parameters.
Vulkan barrel distortion shader path
app/src/main/cpp/winlator/window.vert, app/src/main/cpp/winlator/window.frag
Computes barrel UV interpolants in the vertex shader and conditionally resamples the texture using them in the fragment shader.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ScreenEffectsConfig
  participant VulkanRenderer
  participant JNI
  participant VulkanRendererContext
  participant VulkanShaders
  ScreenEffectsConfig->>VulkanRenderer: Apply barrel settings
  VulkanRenderer->>JNI: Pass barrel parameters
  JNI->>VulkanRendererContext: Update native effect state
  VulkanRendererContext->>VulkanShaders: Upload push constants
  VulkanShaders->>VulkanShaders: Compute and sample distorted UVs
Loading

Possibly related PRs

Suggested reviewers: utkarshdalal, phobos665

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.70% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the change and highlights the main feature: Barrel Zoom accessibility for 3D shooters.
Description check ✅ Passed The description follows the template well, with Description, Recording, Type of Change, and Checklist sections filled in.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@feilen feilen changed the title Barrel Zoom implementation feat(accessibility): Barrel Zoom for 3D shooters Jul 19, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/java/app/gamenative/ui/component/ScreenEffectsPanel.kt`:
- Around line 895-897: Update ScreenEffectsPanel’s resetEffects() to also set
enableBarrelDistortion to false. In the rendered Column, add the
barrel-distortion ScreenEffectToggleRow and its matching AnimatedVisibility
slider block, mirroring the implementation in GLScreenEffectsTabContent or
ScreenEffectsTabContent so users can toggle and adjust the existing
barrel-distortion state.

In `@app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt`:
- Around line 176-185: Update the barrel distortion branch in the apply logic to
retrieve the existing BarrelDistortionEffect through
composer.getEffect(BarrelDistortionEffect::class.java), falling back to a new
instance only when absent, then continue updating its strength, height, and
cylindricalRatio before adding it to effects.

In `@app/src/main/java/com/winlator/renderer/effects/BarrelDistortionEffect.java`:
- Around line 41-46: Update BarrelDistortionEffect.onUse so the height uniform
uses the same lower-bound-only behavior as VulkanRendererContext.setEffect:
clamp height to a minimum of 0.05 without imposing an upper bound. Leave the
strength and cylindricalRatio handling unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f3da31c3-5e78-4c70-aa69-c8c5f338ef03

📥 Commits

Reviewing files that changed from the base of the PR and between c70ad6e and b3596bc.

⛔ Files ignored due to path filters (2)
  • app/src/legacy/jniLibs/arm64-v8a/libvulkan_renderer.so is excluded by !**/*.so
  • app/src/modern/jniLibs/arm64-v8a/libvulkan_renderer.so is excluded by !**/*.so
📒 Files selected for processing (11)
  • app/src/main/cpp/winlator/VulkanRendererContext.cpp
  • app/src/main/cpp/winlator/VulkanRendererContext.h
  • app/src/main/cpp/winlator/vulkan_jni.cpp
  • app/src/main/cpp/winlator/window.frag
  • app/src/main/cpp/winlator/window.vert
  • app/src/main/java/app/gamenative/ui/component/ScreenEffectsPanel.kt
  • app/src/main/java/app/gamenative/ui/component/dialog/ScreenEffectDialog.kt
  • app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt
  • app/src/main/java/com/winlator/renderer/VulkanRenderer.java
  • app/src/main/java/com/winlator/renderer/effects/BarrelDistortionEffect.java
  • app/src/main/res/values/strings.xml

Comment thread app/src/main/java/app/gamenative/ui/component/ScreenEffectsPanel.kt
Comment thread app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt
Comment thread app/src/main/java/com/winlator/renderer/effects/BarrelDistortionEffect.java Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 13 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/main/cpp/winlator/window.frag">

<violation number="1" location="app/src/main/cpp/winlator/window.frag:298">
P1: Barrel distortion overwrites the brightness/contrast/gamma adjustments applied just above it. The barrel branch re-samples from the raw texture (`texSampler`), discarding the color adjustments that were already applied to `rgb` on line 297. Users who enable barrel zoom will lose their brightness, contrast, and gamma settings entirely.

Suggestion: re-apply `applyColorAdjustments(rgb)` after the barrel sample, or move the barrel distortion before the color-adjustment step.</violation>
</file>

<file name="app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt">

<violation number="1" location="app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt:180">
P2: The FOV slider range (40–120°) extends beyond the range that actually takes effect, because `BarrelDistortionEffect.onUse()` clamps the `height` uniform to `[-1.0, 1.0]`. Since `height = tan(VFOV / 2)`, values above VFOV = 90° produce `tan(VFOV/2) > 1.0` and get clamped down to 1.0 — making FOV=100°, FOV=110°, and FOV=120° produce the identical result as FOV=90°. The effective range is therefore 0–90°, so the upper slider bound of 120° is misleading and may confuse users who try higher values expecting a visible difference.

Consider either capping the UI range to 0–90° to match the effect's effective range, or adjusting the shader clamp in `BarrelDistortionEffect.onUse()` to accept values above 1.0 if higher FOVs are intended to have an effect.</violation>
</file>

Tip: cubic used a learning from your PR history. Let your coding agent read cubic learnings directly with the cubic MCP.

Re-trigger cubic

if (hasEffect(EFFECT_MASK_NTSC)) rgb = applyNTSC(uv, rgb);
if (hasEffect(EFFECT_MASK_BARREL_DISTORTION)) {
vec3 puv = dot(vUVDotBarrel, vUVDotBarrel) * vec3(-0.5, -0.5, -1.0) + vUVBarrel;
rgb = texture(texSampler, puv.xy / puv.z).rgb;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Barrel distortion overwrites the brightness/contrast/gamma adjustments applied just above it. The barrel branch re-samples from the raw texture (texSampler), discarding the color adjustments that were already applied to rgb on line 297. Users who enable barrel zoom will lose their brightness, contrast, and gamma settings entirely.

Suggestion: re-apply applyColorAdjustments(rgb) after the barrel sample, or move the barrel distortion before the color-adjustment step.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/cpp/winlator/window.frag, line 298:

<comment>Barrel distortion overwrites the brightness/contrast/gamma adjustments applied just above it. The barrel branch re-samples from the raw texture (`texSampler`), discarding the color adjustments that were already applied to `rgb` on line 297. Users who enable barrel zoom will lose their brightness, contrast, and gamma settings entirely.

Suggestion: re-apply `applyColorAdjustments(rgb)` after the barrel sample, or move the barrel distortion before the color-adjustment step.</comment>

<file context>
@@ -284,7 +293,12 @@ void main() {
         if (hasEffect(EFFECT_MASK_NTSC))  rgb = applyNTSC(uv, rgb);
+        if (hasEffect(EFFECT_MASK_BARREL_DISTORTION)) {
+            vec3 puv = dot(vUVDotBarrel, vUVDotBarrel) * vec3(-0.5, -0.5, -1.0) + vUVBarrel;
+            rgb = texture(texSampler, puv.xy / puv.z).rgb;
+        }
     }
</file context>

Comment thread app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt
Comment thread app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt Outdated
Comment thread app/src/main/cpp/winlator/VulkanRendererContext.cpp
Comment thread app/src/main/java/app/gamenative/ui/component/ScreenEffectsPanel.kt
if (config.enableBarrelDistortion && abs(config.barrelDistortionStrength) > 0.001f) {
val barrelEffect = BarrelDistortionEffect().apply {
strength = config.barrelDistortionStrength / 100f
height = tan(config.barrelDistortionFov * ScreenEffectsConfig.DEGREES_TO_RADIANS / 2f)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: The FOV slider range (40–120°) extends beyond the range that actually takes effect, because BarrelDistortionEffect.onUse() clamps the height uniform to [-1.0, 1.0]. Since height = tan(VFOV / 2), values above VFOV = 90° produce tan(VFOV/2) > 1.0 and get clamped down to 1.0 — making FOV=100°, FOV=110°, and FOV=120° produce the identical result as FOV=90°. The effective range is therefore 0–90°, so the upper slider bound of 120° is misleading and may confuse users who try higher values expecting a visible difference.

Consider either capping the UI range to 0–90° to match the effect's effective range, or adjusting the shader clamp in BarrelDistortionEffect.onUse() to accept values above 1.0 if higher FOVs are intended to have an effect.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt, line 180:

<comment>The FOV slider range (40–120°) extends beyond the range that actually takes effect, because `BarrelDistortionEffect.onUse()` clamps the `height` uniform to `[-1.0, 1.0]`. Since `height = tan(VFOV / 2)`, values above VFOV = 90° produce `tan(VFOV/2) > 1.0` and get clamped down to 1.0 — making FOV=100°, FOV=110°, and FOV=120° produce the identical result as FOV=90°. The effective range is therefore 0–90°, so the upper slider bound of 120° is misleading and may confuse users who try higher values expecting a visible difference.

Consider either capping the UI range to 0–90° to match the effect's effective range, or adjusting the shader clamp in `BarrelDistortionEffect.onUse()` to accept values above 1.0 if higher FOVs are intended to have an effect.</comment>

<file context>
@@ -153,6 +173,16 @@ fun applyScreenEffectsConfig(renderer: GLRenderer, config: ScreenEffectsConfig)
+    if (config.enableBarrelDistortion && abs(config.barrelDistortionStrength) > 0.001f) {
+        val barrelEffect = BarrelDistortionEffect().apply {
+            strength = config.barrelDistortionStrength / 100f
+            height = tan(config.barrelDistortionFov * ScreenEffectsConfig.DEGREES_TO_RADIANS / 2f)
+            cylindricalRatio = config.barrelDistortionCylindricalRatio
+        }
</file context>

Comment thread app/src/main/java/com/winlator/renderer/VulkanRenderer.java
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
app/src/main/java/app/gamenative/ui/component/ScreenEffectsPanel.kt (1)

895-898: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add the barrel-distortion controls to ScreenEffectsPanel.

This panel now loads, applies, persists, and resets barrel-distortion state, but its rendered toggle list still ends at NTSC. Users therefore cannot enable or adjust barrel distortion from this entry point; mirror the toggle and adjustment block already present in the sibling screen-effects composables.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/java/app/gamenative/ui/component/ScreenEffectsPanel.kt` around
lines 895 - 898, Add the barrel-distortion toggle and adjustment controls to the
rendered control list in ScreenEffectsPanel, following the existing
implementation in the sibling screen-effects composables. Place them after the
NTSC controls and bind them to the existing barrel-distortion state, ensuring
users can enable, adjust, persist, and reset the values already handled by the
panel.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/main/java/com/winlator/renderer/effects/BarrelDistortionEffect.java`:
- Around line 41-42: Remove the backticks surrounding the `@Override` annotation
in BarrelDistortionEffect.onUse so it is valid Java syntax and compilation
succeeds.

---

Duplicate comments:
In `@app/src/main/java/app/gamenative/ui/component/ScreenEffectsPanel.kt`:
- Around line 895-898: Add the barrel-distortion toggle and adjustment controls
to the rendered control list in ScreenEffectsPanel, following the existing
implementation in the sibling screen-effects composables. Place them after the
NTSC controls and bind them to the existing barrel-distortion state, ensuring
users can enable, adjust, persist, and reset the values already handled by the
panel.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 93f77d00-7ee5-4d4c-8df4-7e0b0f57ea8a

📥 Commits

Reviewing files that changed from the base of the PR and between b3596bc and 86bd0a4.

📒 Files selected for processing (3)
  • app/src/main/java/app/gamenative/ui/component/ScreenEffectsPanel.kt
  • app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt
  • app/src/main/java/com/winlator/renderer/effects/BarrelDistortionEffect.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/main/java/app/gamenative/ui/util/ScreenEffectsConfig.kt

Comment on lines +41 to +42
`@Override`
protected void onUse(ShaderMaterial material, GLRenderer renderer) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="app/src/main/java/com/winlator/renderer/effects/BarrelDistortionEffect.java"
if rg -n '^[[:space:]]*`@Override`' "$file"; then
  echo "Invalid backtick-wrapped Java annotation found"
  exit 1
fi

Repository: utkarshdalal/GameNative

Length of output: 227


Remove the backticks around @Override. This makes BarrelDistortionEffect.java invalid Java and breaks compilation.

🧰 Tools
🪛 PMD (7.26.0)

[High] 41-41: Parse Error: LexException: Lexical error in file 'app/src/main/java/com/winlator/renderer/effects/BarrelDistortionEffect.java' at line 41, column 5: "`" (96), after : "" (in lexical state DEFAULT)

(Parse Error)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/java/com/winlator/renderer/effects/BarrelDistortionEffect.java`
around lines 41 - 42, Remove the backticks surrounding the `@Override` annotation
in BarrelDistortionEffect.onUse so it is valid Java syntax and compilation
succeeds.

Source: Linters/SAST tools

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.

1 participant