commonMain.ru.casperix.demo_platform.point.PointController.kt Maven / Gradle / Ivy
package ru.casperix.demo_platform.point
import ru.casperix.demo_platform.renderer.RenderConfig
import ru.casperix.demo_platform.renderer.RenderConfig.POINT_BACK
import ru.casperix.demo_platform.renderer.RenderConfig.POINT_DEFAULT
import ru.casperix.demo_platform.renderer.RenderConfig.POINT_FOCUSED
import ru.casperix.demo_platform.renderer.RenderConfig.lineThick
import ru.casperix.demo_platform.renderer.RenderConfig.pointDiameter
import ru.casperix.input.*
import ru.casperix.math.color.Colors
import ru.casperix.math.geometry.Line2f
import ru.casperix.math.vector.float32.Vector2f
import ru.casperix.renderer.Renderer2D
import ru.casperix.renderer.material.SimpleMaterial
import ru.casperix.signals.concrete.Signal
@ExperimentalUnsignedTypes
class PointController {
val BACK_COLORS = listOf(Colors.RED, Colors.LIME, Colors.BLUE, Colors.YELLOW, Colors.CYAN, Colors.FUCHSIA, Colors.WHITE)
var girdAlignStep: Float? = null
var drawBack = true
val groups = mutableListOf>()
var focused: Point? = null
var selected: Point? = null
var pointDragged = Signal()
operator fun plusAssign(points: List) {
groups += points
}
fun input(event: InputEvent) {
if (event is PointerEvent) {
val cursor = screenToScene(event.position)
if (event is PointerDown) {
selected = getNearPoint(event.position)
} else if (event is PointerMove) {
selected?.also {
it.position = solvePosition(cursor)
pointDragged.set(it)
}
} else if (event is PointerUp) {
selected = null
} else {
focused = getNearPoint(event.position)
}
}
}
private fun solvePosition(position: Vector2f): Vector2f {
val girdAlignStep = girdAlignStep ?: return position
return (position / girdAlignStep).round() * girdAlignStep
}
private fun getNearPoint(screenPosition: Vector2f): Point? {
val camera = RenderConfig.camera
val range = camera.zoom * 100f
val cursor = screenToScene(screenPosition)
val points = groups.flatten()
return points
.map { Pair(it, it.position.distTo(cursor)) }
.filter { it.second < range }
.minByOrNull { it.second }?.first
}
private fun screenToScene(value: Vector2f): Vector2f {
val camera = RenderConfig.camera
return camera.transform.unproject(value)
}
fun render(renderer: Renderer2D) {
if (drawBack) {
groups.forEach { group ->
group.forEachIndexed { index, point ->
val a = group[index]
val b = group[(index + 1) % group.size]
renderer.drawLine(POINT_BACK, Line2f(a.position, b.position), lineThick * 8f)
}
}
}
groups.forEach { group ->
group.forEachIndexed { index, point ->
val backColor = BACK_COLORS[index % BACK_COLORS.size]
val color = if (selected == point || focused == point) {
POINT_FOCUSED
} else {
POINT_DEFAULT
}
renderer.drawCircle(
SimpleMaterial(backColor),
point.position,
pointDiameter * 0.75f,
pointDiameter * 1f
)
renderer.drawCircle(
SimpleMaterial(color),
point.position,
pointDiameter * 0f,
pointDiameter * 0.75f
)
// if (point.mode == PointMode.DIRECTION) {
// renderer.drawLine(CONTROL_POINT_BACK, Line2f(Vector2f.ZERO, point.position), lineThick * 8f)
// }
}
}
}
}