1+ package dev.matsem.astral.playground.sketches
2+
3+ import ch.bildspur.postfx.builder.PostFX
4+ import dev.matsem.astral.core.tools.animations.AnimationHandler
5+ import dev.matsem.astral.core.tools.animations.radianSeconds
6+ import dev.matsem.astral.core.tools.animations.saw
7+ import dev.matsem.astral.core.tools.audio.beatcounter.BeatCounter
8+ import dev.matsem.astral.core.tools.audio.beatcounter.OnKick
9+ import dev.matsem.astral.core.tools.audio.beatcounter.OnSnare
10+ import dev.matsem.astral.core.tools.extensions.centerX
11+ import dev.matsem.astral.core.tools.extensions.colorModeHsb
12+ import dev.matsem.astral.core.tools.extensions.mapSin
13+ import dev.matsem.astral.core.tools.extensions.mapp
14+ import dev.matsem.astral.core.tools.extensions.pushPop
15+ import dev.matsem.astral.core.tools.extensions.quantize
16+ import dev.matsem.astral.core.tools.extensions.shorterDimension
17+ import dev.matsem.astral.core.tools.extensions.translateCenter
18+ import dev.matsem.astral.core.tools.videoexport.VideoExporter
19+ import org.koin.core.KoinComponent
20+ import org.koin.core.inject
21+ import processing.core.PApplet
22+
23+ /* *
24+ * VJ loop for SEM008 release https://soundcloud.com/semfree/sem008-offish-evasion-straight-shootingcalculated-risk-out-300922
25+ */
26+ class Sem008 : PApplet (), KoinComponent, AnimationHandler {
27+
28+ sealed class ExportConfig (
29+ val width : Int ,
30+ val height : Int ,
31+ val outputFile : String ,
32+ val travelLength : Int
33+ ) {
34+ object Square : ExportConfig(1080 , 1080 , " sem008_loop_sqr.mp4" , 200_000 )
35+ object Story : ExportConfig(1080 , 1920 , " sem008_loop_story.mp4" , 300_000 )
36+ }
37+
38+ private val exportConfig = ExportConfig .Square
39+
40+ private lateinit var fx: PostFX
41+
42+ private val beatCounter: BeatCounter by inject()
43+ private val videoExporter: VideoExporter by inject()
44+
45+ override fun provideMillis (): Int = videoExporter.videoMillis()
46+
47+ private var ures: Float = 3f
48+ private var uresTarget: Float = 3f
49+ private var vres: Float = 3f
50+ private var vresTarget: Float = 3f
51+ private var zoom: Float = 1f
52+ private var invert: Boolean = false
53+
54+ override fun settings () {
55+ size(exportConfig.width, exportConfig.height, P3D )
56+ }
57+
58+ override fun setup () {
59+ colorModeHsb()
60+ surface.setAlwaysOnTop(true )
61+ fx = PostFX (this )
62+
63+ beatCounter.addListener(OnKick , 2 ) {
64+ uresTarget = random(1f , 5f )
65+ vresTarget = random(1f , 5f )
66+ }
67+
68+ beatCounter.addListener(OnKick , 4 ) {
69+ invert = true
70+ }
71+
72+ beatCounter.addListener(OnSnare , 2 ) {
73+ zoom = random(0.7f , 1f )
74+ }
75+
76+ videoExporter.prepare(
77+ audioFilePath = " music/sem0081minclip.mp3" ,
78+ movieFps = 30f ,
79+ dryRun = true ,
80+ audioGain = 2f ,
81+ outputVideoFileName = exportConfig.outputFile
82+ ) { drawSketch() }
83+ }
84+
85+ override fun draw () = drawSketch()
86+
87+ private fun PApplet.drawSketch () {
88+ ures = lerp(ures, uresTarget, 0.2f )
89+ vres = lerp(vres, vresTarget, 0.2f )
90+
91+ clear()
92+ background(0f , 0f , 10f )
93+
94+ sphereDetail(ures.toInt(), vres.toInt())
95+
96+ pushPop {
97+ translateCenter()
98+ scale(zoom)
99+
100+ for (travel in 0 until exportConfig.travelLength step 1000 ) {
101+ strokeWeight(4f )
102+ if (travel < saw(1 / 5f ).mapp(0f , exportConfig.travelLength.toFloat())) {
103+ fill(0f , 0f , 10f )
104+ stroke(0f , 0f , 90f )
105+ } else {
106+ fill(0f , 0f , 60f )
107+ stroke(0f , 0f , 0f )
108+ }
109+
110+ pushPop {
111+ rotateZ(radianSeconds(20f ) + travel)
112+ translate(0f , 0f , millis().toFloat())
113+
114+ pushPop {
115+ translate(- centerX() * 1.2f , 0f )
116+ translate(0f , 0f , - travel.toFloat())
117+ rotateY(radianSeconds(10f ).quantize(0.05f ))
118+ rotateZ(- radianSeconds(30f ))
119+ sphere(shorterDimension() * 0.50f )
120+ }
121+
122+ pushPop {
123+ translate(centerX() * 1.2f , 0f )
124+ translate(0f , 0f , - travel.toFloat())
125+ rotateY(- radianSeconds(10f ).quantize(0.05f ))
126+ rotateZ(radianSeconds(30f ))
127+ sphere(shorterDimension() * 0.50f )
128+ }
129+ }
130+ }
131+ }
132+
133+ fx.render().apply {
134+ noise(0.3f , 0.5f )
135+ rgbSplit(50f )
136+ bloom(0.5f , 20 , 5f )
137+ pixelate(sin(radianSeconds(5f )).mapSin(width * 1f , width * 0.4f ))
138+ if (invert) {
139+ invert()
140+ invert = false
141+ }
142+ }.compose()
143+ }
144+ }
0 commit comments