import org.openrndr.WindowMultisample
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.DrawPrimitive
import org.openrndr.draw.shadeStyle
import org.openrndr.extra.camera.Orbital
import org.openrndr.extra.meshgenerators.buildTriangleMesh
import org.openrndr.extra.meshgenerators.extrudeContourStepsScaled
import org.openrndr.extra.noise.Random
import org.openrndr.math.Vector3
import org.openrndr.shape.Circle
import org.openrndr.shape.Path3D
import org.openrndr.shape.Segment3D
import kotlin.math.PI
import kotlin.math.cos

/**
 * Extruded Bézier tubes grown on a morphing Bézier surface.
 *
 */
fun main() {
    application {
        configure {
            width = 800
            height = 800
            multisample = WindowMultisample.SampleCount(8)
        }
        program {
            val crossSection = Circle(0.0, 0.0, 0.2).contour

            extend(Orbital()) {
                this.eye = Vector3(0.0, 3.0, 7.0)
                this.lookAt = Vector3(0.0, 0.0, 0.0)
            }

            extend {
                drawer.shadeStyle = shadeStyle {
                    fragmentTransform = """
                        x_fill = va_color;
                        x_fill.rgb *= v_viewNormal.z;
                    """.trimIndent()
                }

                val m = buildTriangleMesh {
                    val beziers = List(4) { curveId ->
                        val n = List(12) {
                            Random.simplex(it * 7.387, curveId * 5.531 + seconds * 0.05) * 10.0
                        }
                        Segment3D(
                            Vector3(n[0], n[1], n[2]),
                            Vector3(n[3], n[4], n[5]),
                            Vector3(n[6], n[7], n[8]),
                            Vector3(n[9], n[10], n[11])
                        )
                    }

                    for (i in 0 until 20) {
                        val t = i / (20.0 - 1.0)
                        val path = Path3D(
                            listOf(
                                Segment3D(
                                    beziers[0].position(t),
                                    beziers[1].position(t),
                                    beziers[2].position(t),
                                    beziers[3].position(t)
                                )
                            ), false
                        )
                        color = if(i % 2 == 0) ColorRGBa.PINK else ColorRGBa.WHITE.shade(0.1)
                        extrudeContourStepsScaled(
                            crossSection,
                            path,
                            120,
                            Vector3.UNIT_Y,
                            contourDistanceTolerance = 0.05,
                            pathDistanceTolerance = 0.05,
                            scale = { tt: Double -> 0.5 - 0.5 * cos(tt * 2 * PI)  }
                        )
                    }
                }

                drawer.vertexBuffer(m, DrawPrimitive.TRIANGLES)

                // Remember to free the memory! Otherwise, the computer will quickly run out of RAM.
                m.destroy()
            }
        }
    }
}
