Add radial mode, UI controls, front camera, update to API 35
- Add radial/elliptical blur mode with aspect ratio control - Add UI sliders for blur intensity, falloff, and shape - Add front camera support with flip button - Update minimum SDK to API 35 (Android 15) - Enable landscape orientation (fullSensor) - Rename app to "Naiv Tilt Shift Camera" - Set APK output name to naiv-tilt-shift - Add project specification document Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e8a5fa4811
commit
d3ca23b71c
11 changed files with 679 additions and 94 deletions
|
|
@ -1,20 +1,34 @@
|
|||
package no.naiv.tiltshift.effect
|
||||
|
||||
/**
|
||||
* Blur mode for tilt-shift effect.
|
||||
*/
|
||||
enum class BlurMode {
|
||||
LINEAR, // Horizontal band of focus with blur above and below
|
||||
RADIAL // Central focus point with blur radiating outward
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters controlling the tilt-shift blur effect.
|
||||
*
|
||||
* @param mode The blur mode (linear or radial)
|
||||
* @param angle The rotation angle of the blur gradient in radians (0 = horizontal blur bands)
|
||||
* @param positionX The horizontal center of the in-focus region (0.0 to 1.0)
|
||||
* @param positionY The vertical center of the in-focus region (0.0 to 1.0)
|
||||
* @param size The size of the in-focus region (0.0 to 1.0, as fraction of screen height)
|
||||
* @param blurAmount The intensity of the blur effect (0.0 to 1.0)
|
||||
* @param falloff Transition sharpness from focused to blurred (0.0 = sharp edge, 1.0 = gradual)
|
||||
* @param aspectRatio Ellipse aspect ratio for radial mode (1.0 = circle, <1 = tall, >1 = wide)
|
||||
*/
|
||||
data class BlurParameters(
|
||||
val mode: BlurMode = BlurMode.LINEAR,
|
||||
val angle: Float = 0f,
|
||||
val positionX: Float = 0.5f,
|
||||
val positionY: Float = 0.5f,
|
||||
val size: Float = 0.3f,
|
||||
val blurAmount: Float = 0.8f
|
||||
val blurAmount: Float = 0.8f,
|
||||
val falloff: Float = 0.5f,
|
||||
val aspectRatio: Float = 1.0f
|
||||
) {
|
||||
companion object {
|
||||
val DEFAULT = BlurParameters()
|
||||
|
|
@ -24,6 +38,10 @@ data class BlurParameters(
|
|||
const val MAX_SIZE = 0.8f
|
||||
const val MIN_BLUR = 0.0f
|
||||
const val MAX_BLUR = 1.0f
|
||||
const val MIN_FALLOFF = 0.1f
|
||||
const val MAX_FALLOFF = 1.0f
|
||||
const val MIN_ASPECT = 0.3f
|
||||
const val MAX_ASPECT = 3.0f
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -56,4 +74,18 @@ data class BlurParameters(
|
|||
fun withBlurAmount(amount: Float): BlurParameters {
|
||||
return copy(blurAmount = amount.coerceIn(MIN_BLUR, MAX_BLUR))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy with the falloff clamped to valid range.
|
||||
*/
|
||||
fun withFalloff(newFalloff: Float): BlurParameters {
|
||||
return copy(falloff = newFalloff.coerceIn(MIN_FALLOFF, MAX_FALLOFF))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy with the aspect ratio clamped to valid range.
|
||||
*/
|
||||
fun withAspectRatio(ratio: Float): BlurParameters {
|
||||
return copy(aspectRatio = ratio.coerceIn(MIN_ASPECT, MAX_ASPECT))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,11 +23,14 @@ class TiltShiftShader(private val context: Context) {
|
|||
|
||||
// Uniform locations
|
||||
private var uTextureLocation: Int = 0
|
||||
private var uModeLocation: Int = 0
|
||||
private var uAngleLocation: Int = 0
|
||||
private var uPositionXLocation: Int = 0
|
||||
private var uPositionYLocation: Int = 0
|
||||
private var uSizeLocation: Int = 0
|
||||
private var uBlurAmountLocation: Int = 0
|
||||
private var uFalloffLocation: Int = 0
|
||||
private var uAspectRatioLocation: Int = 0
|
||||
private var uResolutionLocation: Int = 0
|
||||
|
||||
/**
|
||||
|
|
@ -61,11 +64,14 @@ class TiltShiftShader(private val context: Context) {
|
|||
|
||||
// Get uniform locations
|
||||
uTextureLocation = GLES20.glGetUniformLocation(programId, "uTexture")
|
||||
uModeLocation = GLES20.glGetUniformLocation(programId, "uMode")
|
||||
uAngleLocation = GLES20.glGetUniformLocation(programId, "uAngle")
|
||||
uPositionXLocation = GLES20.glGetUniformLocation(programId, "uPositionX")
|
||||
uPositionYLocation = GLES20.glGetUniformLocation(programId, "uPositionY")
|
||||
uSizeLocation = GLES20.glGetUniformLocation(programId, "uSize")
|
||||
uBlurAmountLocation = GLES20.glGetUniformLocation(programId, "uBlurAmount")
|
||||
uFalloffLocation = GLES20.glGetUniformLocation(programId, "uFalloff")
|
||||
uAspectRatioLocation = GLES20.glGetUniformLocation(programId, "uAspectRatio")
|
||||
uResolutionLocation = GLES20.glGetUniformLocation(programId, "uResolution")
|
||||
|
||||
// Clean up shaders (they're linked into program now)
|
||||
|
|
@ -85,11 +91,14 @@ class TiltShiftShader(private val context: Context) {
|
|||
GLES20.glUniform1i(uTextureLocation, 0)
|
||||
|
||||
// Set effect parameters
|
||||
GLES20.glUniform1i(uModeLocation, if (params.mode == BlurMode.RADIAL) 1 else 0)
|
||||
GLES20.glUniform1f(uAngleLocation, params.angle)
|
||||
GLES20.glUniform1f(uPositionXLocation, params.positionX)
|
||||
GLES20.glUniform1f(uPositionYLocation, params.positionY)
|
||||
GLES20.glUniform1f(uSizeLocation, params.size)
|
||||
GLES20.glUniform1f(uBlurAmountLocation, params.blurAmount)
|
||||
GLES20.glUniform1f(uFalloffLocation, params.falloff)
|
||||
GLES20.glUniform1f(uAspectRatioLocation, params.aspectRatio)
|
||||
GLES20.glUniform2f(uResolutionLocation, width.toFloat(), height.toFloat())
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue