-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
27 Prototype character portarit (#28)
- Loading branch information
1 parent
3bc69de
commit b6b699c
Showing
15 changed files
with
1,263 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
app/src/main/java/com/daniil/shevtsov/idle/feature/portrait/view/BezierExtensions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package com.daniil.shevtsov.idle.feature.portrait.view | ||
|
||
import androidx.compose.ui.geometry.Offset | ||
|
||
data class BezierState( | ||
val start: Offset, | ||
val support: Offset, | ||
val support2: Offset? = null, | ||
val finish: Offset, | ||
) | ||
|
||
fun BezierState.points() = listOfNotNull( | ||
start, | ||
finish, | ||
support, | ||
support2, | ||
) | ||
|
||
fun List<Offset>.toBezierState() = BezierState( | ||
start = get(0), | ||
finish = get(1), | ||
support = get(2), | ||
support2 = getOrNull(3), | ||
) | ||
|
||
fun BezierState.multiply( | ||
x: Float = 1f, | ||
y: Float = 1f | ||
): BezierState = points().map { point -> | ||
point.copy( | ||
x = point.x.times(x), | ||
y = point.y.times(y) | ||
) | ||
}.toBezierState() | ||
|
||
fun BezierState.add( | ||
x: Float = 0f, | ||
y: Float = 0f | ||
): BezierState = points().map { point -> | ||
point.copy( | ||
x = point.x + x, | ||
y = point.y + y, | ||
) | ||
}.toBezierState() |
93 changes: 93 additions & 0 deletions
93
app/src/main/java/com/daniil/shevtsov/idle/feature/portrait/view/Core.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package com.daniil.shevtsov.idle.feature.portrait.view | ||
|
||
import androidx.compose.ui.geometry.Offset | ||
import androidx.compose.ui.geometry.Rect | ||
import androidx.compose.ui.geometry.Size | ||
import kotlin.math.pow | ||
import kotlin.math.sqrt | ||
import kotlin.random.Random | ||
|
||
fun Rect.shrink(percent: Float): Rect { | ||
return shrink( | ||
widthPercent = percent, heightPercent = percent | ||
) | ||
} | ||
|
||
enum class Anchor { | ||
Center | ||
} | ||
|
||
fun Rect.move( | ||
position: Offset, | ||
anchor: Anchor = Anchor.Center, | ||
) = Rect( | ||
offset = position.translate( | ||
x = -width / 2, | ||
y = -height / 2, | ||
), | ||
size = size, | ||
) | ||
|
||
fun Rect.shrink( | ||
widthPercent: Float = 1f, | ||
heightPercent: Float = 1f, | ||
): Rect { | ||
val newWidth = width * widthPercent | ||
val newHeight = height * heightPercent | ||
|
||
return Rect( | ||
offset = topLeft.translate( | ||
x = (width - newWidth) / 2, | ||
y = (height - newHeight) / 2, | ||
), | ||
size = Size(newWidth, newHeight) | ||
) | ||
} | ||
|
||
fun Offset.translate( | ||
value: Float, | ||
) = translate( | ||
x = value, | ||
y = value, | ||
) | ||
|
||
fun Offset.translate( | ||
x: Float = 0f, | ||
y: Float = 0f, | ||
) = copy( | ||
x = this.x + x, | ||
y = this.y + y, | ||
) | ||
|
||
fun Offset.distanceTo(offset: Offset) = sqrt((offset.x - x).pow(2) + (offset.y - y).pow(2)) | ||
|
||
fun Offset.coerceIn(bounds: Rect) = Offset( | ||
x = x.coerceIn(bounds.left, bounds.right), | ||
y = y.coerceIn(bounds.top, bounds.bottom) | ||
) | ||
|
||
fun Offset.times( | ||
x: Float = 1f, | ||
y: Float = 1f | ||
) = Offset( | ||
x = this.x * x, | ||
y = this.y * y, | ||
) | ||
|
||
fun Offset.div( | ||
x: Float = 1f, | ||
y: Float = 1f | ||
) = Offset( | ||
x = this.x / x, | ||
y = this.y / y, | ||
) | ||
|
||
fun Random.nextFloatInRange( | ||
min: Float = Float.MIN_VALUE, | ||
max: Float = Float.MAX_VALUE, | ||
) = min + nextFloat() * (max - min) | ||
|
||
fun BodyPart.toRect() = Rect( | ||
position, | ||
size, | ||
) |
62 changes: 62 additions & 0 deletions
62
app/src/main/java/com/daniil/shevtsov/idle/feature/portrait/view/DrawScopeExtensions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package com.daniil.shevtsov.idle.feature.portrait.view | ||
|
||
import androidx.compose.ui.geometry.Rect | ||
import androidx.compose.ui.graphics.Color | ||
import androidx.compose.ui.graphics.Path | ||
import androidx.compose.ui.graphics.drawscope.DrawScope | ||
import androidx.compose.ui.graphics.drawscope.Stroke | ||
|
||
fun DrawScope.drawArea( | ||
area: Rect, | ||
color: Color = Color.Red, | ||
strokeWidth: Float = 3f, | ||
) { | ||
drawRect( | ||
color, | ||
style = Stroke(width = strokeWidth), | ||
topLeft = area.topLeft, | ||
size = area.size | ||
) | ||
} | ||
|
||
fun DrawScope.drawBodyPart(part: BodyPart) { | ||
drawRect(part.color, topLeft = part.position, size = part.size) | ||
} | ||
|
||
fun DrawScope.drawBezierPoints( | ||
bezierState: BezierState, | ||
pointColor: Color = Color.Green, | ||
supportColor: Color = Color.Red, | ||
pointRadius: Float = 16f, | ||
) { | ||
drawCircle(pointColor, center = bezierState.start, radius = pointRadius) | ||
drawCircle(pointColor, center = bezierState.finish, radius = pointRadius) | ||
drawCircle(supportColor, center = bezierState.support, radius = pointRadius) | ||
if (bezierState.support2 != null) { | ||
drawCircle(supportColor, center = bezierState.support2, radius = pointRadius) | ||
} | ||
} | ||
|
||
fun Path.drawQuadraticBezier(state: BezierState) { | ||
with(state) { | ||
moveTo(start.x, start.y) | ||
if (state.support2 == null) { | ||
quadraticBezierTo( | ||
support.x, | ||
support.y, | ||
finish.x, | ||
finish.y, | ||
) | ||
} else { | ||
cubicTo( | ||
support.x, | ||
support.y, | ||
support2!!.x, | ||
support2.y, | ||
finish.x, | ||
finish.y, | ||
) | ||
} | ||
|
||
} | ||
} |
115 changes: 115 additions & 0 deletions
115
app/src/main/java/com/daniil/shevtsov/idle/feature/portrait/view/Portrait.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package com.daniil.shevtsov.idle.feature.portrait.view | ||
|
||
import androidx.compose.foundation.Canvas | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.Row | ||
import androidx.compose.foundation.layout.size | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.geometry.Offset | ||
import androidx.compose.ui.geometry.Rect | ||
import androidx.compose.ui.geometry.Size | ||
import androidx.compose.ui.graphics.Color | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.dp | ||
import com.daniil.shevtsov.idle.feature.portrait.view.face.drawNose | ||
import com.daniil.shevtsov.idle.feature.portrait.view.face.drawPortrait | ||
|
||
@Preview( | ||
widthDp = 800, | ||
heightDp = 800 | ||
) | ||
@Composable | ||
fun PortraitPreview() { | ||
val previewSize = 400.dp | ||
|
||
val previewMode = PreviewMode.Portaits | ||
|
||
val state = PreviewState( | ||
mode = previewMode, | ||
shouldShowFaceAreas = false, | ||
shouldShowNoseAreas = false, | ||
shouldShowEyeAreas = false, | ||
) | ||
|
||
when (state.mode) { | ||
PreviewMode.Nose -> { | ||
Canvas(modifier = Modifier, onDraw = { | ||
val nose = BodyPart( | ||
position = Offset(size.width / 2 - size.width / 4, 0f), | ||
size = Size(size.width / 2, size.height), | ||
color = Color.Gray | ||
) | ||
drawNose(nose, state) | ||
}) | ||
} | ||
PreviewMode.Portaits -> { | ||
Column { | ||
repeat(2) { | ||
Row { | ||
repeat(2) { | ||
Portrait( | ||
previewState = state, | ||
modifier = Modifier.size(previewSize) | ||
) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Composable | ||
fun Portrait( | ||
previewState: PreviewState, | ||
modifier: Modifier = Modifier, | ||
) { | ||
Canvas(modifier = modifier, onDraw = { | ||
drawPortrait(previewState) | ||
}) | ||
} | ||
|
||
data class GeneratingConfig( | ||
val faceArea: Rect, | ||
val eyesArea: Rect, | ||
val noseArea: Rect, | ||
val mouthArea: Rect, | ||
) | ||
|
||
data class BodyPart( | ||
val position: Offset, | ||
val size: Size, | ||
val color: Color, | ||
) | ||
|
||
data class FacePartsSize( | ||
val eye: Size, | ||
val nose: Size, | ||
val mouth: Size, | ||
) | ||
|
||
data class PortraitState( | ||
val head: BodyPart, | ||
val leftEye: BodyPart, | ||
val rightEye: BodyPart, | ||
val nose: BodyPart, | ||
val mouth: BodyPart, | ||
) | ||
|
||
|
||
enum class PreviewMode { | ||
Portaits, | ||
Nose, | ||
} | ||
|
||
data class PreviewState( | ||
val mode: PreviewMode, | ||
val shouldShowFaceAreas: Boolean, | ||
val shouldShowNoseAreas: Boolean, | ||
val shouldShowEyeAreas: Boolean, | ||
) | ||
|
||
|
||
|
||
|
Oops, something went wrong.