From b16dd971f2c10f926dcfd87dbc1b34a6c9d918b1 Mon Sep 17 00:00:00 2001 From: Ole-Morten Duesund Date: Thu, 29 Jan 2026 17:03:26 +0100 Subject: [PATCH] Add front camera texture coordinate handling - Add separate texture coordinates for front and back cameras - Front camera uses mirrored coordinates for natural selfie view - Add setFrontCamera() method to renderer for dynamic switching - Update texture coord buffer on GL thread when camera changes - CameraScreen observes isFrontCamera state to trigger updates Co-Authored-By: Claude Opus 4.5 --- .../tiltshift/effect/TiltShiftRenderer.kt | 46 +++++++++++++++++-- .../java/no/naiv/tiltshift/ui/CameraScreen.kt | 6 +++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/no/naiv/tiltshift/effect/TiltShiftRenderer.kt b/app/src/main/java/no/naiv/tiltshift/effect/TiltShiftRenderer.kt index 1b90e50..09a5bf7 100644 --- a/app/src/main/java/no/naiv/tiltshift/effect/TiltShiftRenderer.kt +++ b/app/src/main/java/no/naiv/tiltshift/effect/TiltShiftRenderer.kt @@ -36,6 +36,9 @@ class TiltShiftRenderer( @Volatile var blurParameters: BlurParameters = BlurParameters.DEFAULT + @Volatile + private var isFrontCamera: Boolean = false + // Quad vertices (full screen) private val vertices = floatArrayOf( -1f, -1f, // Bottom left @@ -44,15 +47,26 @@ class TiltShiftRenderer( 1f, 1f // Top right ) - // Texture coordinates rotated 90° for portrait mode + // Texture coordinates rotated 90° for portrait mode (back camera) // (Camera sensors are landscape-oriented, we rotate to portrait) - private val texCoords = floatArrayOf( + private val texCoordsBack = floatArrayOf( 1f, 1f, // Bottom left of screen -> bottom right of texture 1f, 0f, // Bottom right of screen -> top right of texture 0f, 1f, // Top left of screen -> bottom left of texture 0f, 0f // Top right of screen -> top left of texture ) + // Texture coordinates for front camera (mirrored + rotated) + // Front camera needs horizontal mirror for natural selfie view + private val texCoordsFront = floatArrayOf( + 0f, 1f, // Bottom left of screen + 0f, 0f, // Bottom right of screen + 1f, 1f, // Top left of screen + 1f, 0f // Top right of screen + ) + + private var currentTexCoords = texCoordsBack + override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) { GLES20.glClearColor(0f, 0f, 0f, 1f) @@ -68,10 +82,10 @@ class TiltShiftRenderer( vertexBuffer.position(0) // Create texture coordinate buffer - texCoordBuffer = ByteBuffer.allocateDirect(texCoords.size * 4) + texCoordBuffer = ByteBuffer.allocateDirect(currentTexCoords.size * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer() - .put(texCoords) + .put(currentTexCoords) texCoordBuffer.position(0) // Create camera texture @@ -101,6 +115,14 @@ class TiltShiftRenderer( // Update texture with latest camera frame surfaceTexture?.updateTexImage() + // Update texture coordinate buffer if camera changed + if (updateTexCoordBuffer) { + texCoordBuffer.clear() + texCoordBuffer.put(currentTexCoords) + texCoordBuffer.position(0) + updateTexCoordBuffer = false + } + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT) // Use shader and set parameters @@ -143,6 +165,22 @@ class TiltShiftRenderer( blurParameters = params } + /** + * Sets whether using front camera. Updates texture coordinates accordingly. + * Thread-safe - actual buffer update happens on next frame. + */ + fun setFrontCamera(front: Boolean) { + if (isFrontCamera != front) { + isFrontCamera = front + currentTexCoords = if (front) texCoordsFront else texCoordsBack + // Buffer will be updated on next draw + updateTexCoordBuffer = true + } + } + + @Volatile + private var updateTexCoordBuffer = false + /** * Releases OpenGL resources. * Must be called from GL thread. diff --git a/app/src/main/java/no/naiv/tiltshift/ui/CameraScreen.kt b/app/src/main/java/no/naiv/tiltshift/ui/CameraScreen.kt index 53e3a5d..c667bca 100644 --- a/app/src/main/java/no/naiv/tiltshift/ui/CameraScreen.kt +++ b/app/src/main/java/no/naiv/tiltshift/ui/CameraScreen.kt @@ -125,6 +125,12 @@ fun CameraScreen( glSurfaceView?.requestRender() } + // Update renderer when camera switches (front/back) + LaunchedEffect(isFrontCamera) { + renderer?.setFrontCamera(isFrontCamera) + glSurfaceView?.requestRender() + } + // Start camera when surface texture is available LaunchedEffect(surfaceTexture) { surfaceTexture?.let {