mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
music player widget as a separate module
This commit is contained in:
14
.idea/artifacts/MusicPlayer.xml
generated
Normal file
14
.idea/artifacts/MusicPlayer.xml
generated
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<component name="ArtifactManager">
|
||||||
|
<artifact type="jar" name="MusicPlayer">
|
||||||
|
<output-path>$PROJECT_DIR$/assets/mods/musicplayer</output-path>
|
||||||
|
<root id="archive" name="MusicPlayer.jar">
|
||||||
|
<element id="module-output" name="MusicPlayer" />
|
||||||
|
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-test/1.8.21/kotlin-test-1.8.21.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.21/kotlin-stdlib-common-1.8.21.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.8.21/kotlin-stdlib-jdk8-1.8.21.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.8.21/kotlin-stdlib-jdk7-1.8.21.jar" path-in-jar="/" />
|
||||||
|
</root>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
23
.idea/libraries/jetbrains_kotlin_test.xml
generated
23
.idea/libraries/jetbrains_kotlin_test.xml
generated
@@ -1,13 +1,30 @@
|
|||||||
<component name="libraryTable">
|
<component name="libraryTable">
|
||||||
<library name="jetbrains.kotlin.test" type="repository">
|
<library name="jetbrains.kotlin.test" type="repository">
|
||||||
<properties maven-id="org.jetbrains.kotlin:kotlin-test:1.8.21" />
|
<properties maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21" />
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-test/1.8.21/kotlin-test-1.8.21.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-test/1.8.21/kotlin-test-1.8.21.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.21/kotlin-stdlib-common-1.8.21.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.21/kotlin-stdlib-common-1.8.21.jar!/" />
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.8.21/kotlin-stdlib-jdk8-1.8.21.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.21/kotlin-stdlib-common-1.8.21.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.8.21/kotlin-stdlib-jdk7-1.8.21.jar!/" />
|
||||||
</CLASSES>
|
</CLASSES>
|
||||||
<JAVADOC />
|
<JAVADOC>
|
||||||
<SOURCES />
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.8.21/kotlin-stdlib-jdk8-1.8.21-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.21/kotlin-stdlib-common-1.8.21-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.8.21/kotlin-stdlib-jdk7-1.8.21-javadoc.jar!/" />
|
||||||
|
</JAVADOC>
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.8.21/kotlin-stdlib-jdk8-1.8.21-sources.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21-sources.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.21/kotlin-stdlib-common-1.8.21-sources.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.8.21/kotlin-stdlib-jdk7-1.8.21-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
</component>
|
</component>
|
||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -38,7 +38,7 @@
|
|||||||
<property name="caretWidth" class="java.lang.Integer" />
|
<property name="caretWidth" class="java.lang.Integer" />
|
||||||
</properties>
|
</properties>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
<component name="SuppressKotlinCodeStyleNotification">
|
<component name="SuppressKotlinCodeStyleNotification">
|
||||||
|
|||||||
1
.idea/modules.xml
generated
1
.idea/modules.xml
generated
@@ -6,6 +6,7 @@
|
|||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/ModuleComputers/ModuleComputers.iml" filepath="$PROJECT_DIR$/ModuleComputers/ModuleComputers.iml" />
|
<module fileurl="file://$PROJECT_DIR$/ModuleComputers/ModuleComputers.iml" filepath="$PROJECT_DIR$/ModuleComputers/ModuleComputers.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/MusicPlayer/MusicPlayer.iml" filepath="$PROJECT_DIR$/MusicPlayer/MusicPlayer.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/TerrarumBuild.iml" filepath="$PROJECT_DIR$/TerrarumBuild.iml" />
|
<module fileurl="file://$PROJECT_DIR$/TerrarumBuild.iml" filepath="$PROJECT_DIR$/TerrarumBuild.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
1
.idea/runConfigurations/Terrarum.xml
generated
1
.idea/runConfigurations/Terrarum.xml
generated
@@ -10,6 +10,7 @@
|
|||||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Build Version Number" run_configuration_type="Application" />
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Build Version Number" run_configuration_type="Application" />
|
||||||
<option name="BuildArtifacts" enabled="true">
|
<option name="BuildArtifacts" enabled="true">
|
||||||
<artifact name="ModuleComputers" />
|
<artifact name="ModuleComputers" />
|
||||||
|
<artifact name="MusicPlayer" />
|
||||||
<artifact name="TerrarumBuild" />
|
<artifact name="TerrarumBuild" />
|
||||||
</option>
|
</option>
|
||||||
<option name="RunConfigurationTask" enabled="false" run_configuration_name="QuickDirtyLint" run_configuration_type="Application" />
|
<option name="RunConfigurationTask" enabled="false" run_configuration_name="QuickDirtyLint" run_configuration_type="Application" />
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Build Version Number" run_configuration_type="Application" />
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Build Version Number" run_configuration_type="Application" />
|
||||||
<option name="BuildArtifacts" enabled="true">
|
<option name="BuildArtifacts" enabled="true">
|
||||||
<artifact name="ModuleComputers" />
|
<artifact name="ModuleComputers" />
|
||||||
|
<artifact name="MusicPlayer" />
|
||||||
<artifact name="TerrarumBuild" />
|
<artifact name="TerrarumBuild" />
|
||||||
</option>
|
</option>
|
||||||
<option name="RunConfigurationTask" enabled="true" run_configuration_name="QuickDirtyLint" run_configuration_type="Application" />
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="QuickDirtyLint" run_configuration_type="Application" />
|
||||||
|
|||||||
@@ -8,16 +8,15 @@
|
|||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="ModuleComputersLib" level="project" />
|
<orderEntry type="library" name="ModuleComputersLib" level="project" />
|
||||||
<orderEntry type="module" module-name="TerrarumBuild" />
|
<orderEntry type="module" module-name="TerrarumBuild" scope="PROVIDED" />
|
||||||
<orderEntry type="library" name="graalvm-js 22.3.1" level="project" />
|
<orderEntry type="library" scope="PROVIDED" name="graalvm-js 22.3.1" level="project" />
|
||||||
<orderEntry type="library" name="TerrarumSansBitmap" level="project" />
|
<orderEntry type="library" scope="PROVIDED" name="TerrarumSansBitmap" level="project" />
|
||||||
<orderEntry type="library" name="badlogicgames.gdx" level="project" />
|
<orderEntry type="library" scope="PROVIDED" name="badlogicgames.gdx" level="project" />
|
||||||
<orderEntry type="library" name="badlogicgames.gdx.backend.lwjgl3" level="project" />
|
<orderEntry type="library" scope="PROVIDED" name="badlogicgames.gdx.backend.lwjgl3" level="project" />
|
||||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
<orderEntry type="library" scope="PROVIDED" name="KotlinJavaRuntime" level="project" />
|
||||||
<orderEntry type="library" name="jetbrains.kotlin.reflect" level="project" />
|
<orderEntry type="library" scope="PROVIDED" name="jetbrains.kotlin.reflect" level="project" />
|
||||||
<orderEntry type="library" name="jetbrains.kotlin.test" level="project" />
|
<orderEntry type="library" scope="PROVIDED" name="jetbrains.kotlin.test" level="project" />
|
||||||
<orderEntry type="library" name="io.github.classgraph" level="project" />
|
<orderEntry type="library" scope="PROVIDED" name="jetbrains.kotlinx.coroutines.core" level="project" />
|
||||||
<orderEntry type="library" name="jetbrains.kotlinx.coroutines.core" level="project" />
|
<orderEntry type="library" scope="PROVIDED" name="io.airlift.aircompressor" level="project" />
|
||||||
<orderEntry type="library" name="io.airlift.aircompressor" level="project" />
|
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
Binary file not shown.
16
MusicPlayer/MusicPlayer.iml
Normal file
16
MusicPlayer/MusicPlayer.iml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="jetbrains.kotlin.test" level="project" />
|
||||||
|
<orderEntry type="module" module-name="TerrarumBuild" scope="PROVIDED" />
|
||||||
|
<orderEntry type="library" scope="PROVIDED" name="badlogicgames.gdx" level="project" />
|
||||||
|
<orderEntry type="library" scope="PROVIDED" name="io.airlift.aircompressor" level="project" />
|
||||||
|
<orderEntry type="library" scope="PROVIDED" name="TerrarumSansBitmap" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package net.torvald.terrarum.musicplayer
|
||||||
|
|
||||||
|
import net.torvald.terrarum.IngameInstance
|
||||||
|
import net.torvald.terrarum.ModMgr
|
||||||
|
import net.torvald.terrarum.ModuleEntryPoint
|
||||||
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
|
import net.torvald.terrarum.musicplayer.gui.MusicPlayer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2023-12-23.
|
||||||
|
*/
|
||||||
|
class EntryPoint : ModuleEntryPoint() {
|
||||||
|
override fun invoke() {
|
||||||
|
ModMgr.GameExtraGuiLoader.register { ingame: TerrarumIngame -> MusicPlayer(ingame) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
package net.torvald.terrarum.musicplayer.gui
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||||
|
import com.jme3.math.FastMath
|
||||||
|
import net.torvald.reflection.extortField
|
||||||
|
import net.torvald.terrarum.*
|
||||||
|
import net.torvald.terrarum.audio.*
|
||||||
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
|
import net.torvald.terrarum.ui.BasicDebugInfoWindow
|
||||||
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
|
import kotlin.math.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2023-12-23.
|
||||||
|
*/
|
||||||
|
class MusicPlayer(private val ingame: TerrarumIngame) : UICanvas() {
|
||||||
|
|
||||||
|
override var width = 120
|
||||||
|
override var height = 28
|
||||||
|
|
||||||
|
private var capsuleHeight = 28
|
||||||
|
private var capsuleMosaicSize = capsuleHeight / 2 + 1
|
||||||
|
|
||||||
|
private val maskOffWidth = 8
|
||||||
|
|
||||||
|
private val nameFBO = FrameBuffer(Pixmap.Format.RGBA8888, 400, capsuleHeight, false)
|
||||||
|
|
||||||
|
private val baloonTexture = ModMgr.getGdxFile("musicplayer", "gui/blob.tga").let {
|
||||||
|
TextureRegionPack(it, capsuleMosaicSize, capsuleMosaicSize)
|
||||||
|
}
|
||||||
|
private val textmask = ModMgr.getGdxFile("musicplayer", "gui/textmask.tga").let {
|
||||||
|
TextureRegionPack(it, maskOffWidth, capsuleHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var mode = 0
|
||||||
|
private var modeNext = 0
|
||||||
|
private var transitionAkku = 0f
|
||||||
|
|
||||||
|
private var textScroll = 0f
|
||||||
|
|
||||||
|
private val MODE_IDLE = 0
|
||||||
|
private val MODE_NOW_PLAYING = 1
|
||||||
|
private val MODE_PLAYING = 2
|
||||||
|
private val MODE_MOUSE_UP = 64
|
||||||
|
private val MODE_SHOW_LIST = 128
|
||||||
|
|
||||||
|
private var colourEdge = Color(0xFFFFFF_40.toInt())
|
||||||
|
private val colourBack = Color.BLACK
|
||||||
|
|
||||||
|
private val colourText = Color(0xf0f0f0ff.toInt())
|
||||||
|
private val colourMeter = Color(0xf0f0f0ff.toInt())
|
||||||
|
private val colourMeter2 = Color(0xf0f0f080.toInt())
|
||||||
|
|
||||||
|
init {
|
||||||
|
setAsAlwaysVisible()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun renderUI(batch: SpriteBatch, camera: OrthographicCamera) {
|
||||||
|
batch.end()
|
||||||
|
|
||||||
|
|
||||||
|
renderNameToFBO(batch, camera, AudioMixer.musicTrack.currentTrack?.name ?: "", 0f..(width - 2*STRIP_W - capsuleHeight + maskOffWidth))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
batch.begin()
|
||||||
|
|
||||||
|
val posX = ((Toolkit.drawWidth - width) / 2).toFloat()
|
||||||
|
val posY = (App.scr.height - App.scr.tvSafeGraphicsHeight - height).toFloat()
|
||||||
|
|
||||||
|
blendNormalStraightAlpha(batch)
|
||||||
|
drawBaloon(batch, posX, posY, width.toFloat(), height - capsuleHeight.toFloat())
|
||||||
|
drawText(batch, posX, posY)
|
||||||
|
drawFreqMeter(batch, posX + width - 18, posY + height - (capsuleHeight / 2) + 1)
|
||||||
|
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun drawBaloon(batch: SpriteBatch, x: Float, y: Float, width: Float, height: Float) {
|
||||||
|
val x = x - capsuleMosaicSize
|
||||||
|
for (k in 0..3 step 3) {
|
||||||
|
batch.color = if (k == 0) colourEdge else colourBack
|
||||||
|
|
||||||
|
// top left
|
||||||
|
batch.draw(baloonTexture.get(k, 0), x, y)
|
||||||
|
// top
|
||||||
|
batch.draw(baloonTexture.get(k+1, 0), x + capsuleMosaicSize, y, width, capsuleMosaicSize.toFloat())
|
||||||
|
// top right
|
||||||
|
batch.draw(baloonTexture.get(k+2, 0), x + capsuleMosaicSize + width, y)
|
||||||
|
if (height > 0) {
|
||||||
|
// left
|
||||||
|
batch.draw(baloonTexture.get(k, 1), x, y + capsuleMosaicSize)
|
||||||
|
// centre
|
||||||
|
batch.draw(baloonTexture.get(k+1, 1), x + capsuleMosaicSize, y + capsuleMosaicSize, width, height)
|
||||||
|
// right
|
||||||
|
batch.draw(baloonTexture.get(k+2, 1), x + capsuleMosaicSize + width, y + capsuleMosaicSize)
|
||||||
|
}
|
||||||
|
// bottom left
|
||||||
|
batch.draw(baloonTexture.get(k, 2), x, y + capsuleMosaicSize + height)
|
||||||
|
// bottom
|
||||||
|
batch.draw(baloonTexture.get(k+1, 2), x + capsuleMosaicSize, y + capsuleMosaicSize + height, width, capsuleMosaicSize.toFloat())
|
||||||
|
// bottom right
|
||||||
|
batch.draw(baloonTexture.get(k+2, 2), x + capsuleMosaicSize + width, y + capsuleMosaicSize + height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun drawText(batch: SpriteBatch, posX: Float, posY: Float) {
|
||||||
|
batch.color = colourText
|
||||||
|
batch.draw(nameFBO.colorBufferTexture, posX - maskOffWidth, posY - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderNameToFBO(batch: SpriteBatch, camera: OrthographicCamera, str: String, window: ClosedFloatingPointRange<Float>) {
|
||||||
|
nameFBO.inAction(camera, batch) {
|
||||||
|
batch.inUse {
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
// draw text
|
||||||
|
gdxClearAndEnableBlend(0f, 0f, 0f, 0f)
|
||||||
|
blendNormalStraightAlpha(batch)
|
||||||
|
App.fontGameFBO.draw(batch, str, maskOffWidth.toFloat() - textScroll, 0f)
|
||||||
|
|
||||||
|
// mask off the area
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
blendAlphaMask(batch)
|
||||||
|
batch.draw(textmask.get(0, 0), window.start, 0f)
|
||||||
|
batch.draw(textmask.get(1, 0), window.start + maskOffWidth, 0f, window.endInclusive - window.start, capsuleHeight.toFloat())
|
||||||
|
batch.draw(textmask.get(2, 0), window.start + window.endInclusive + maskOffWidth, 0f)
|
||||||
|
batch.draw(textmask.get(3, 0), window.start + window.endInclusive + 2 * maskOffWidth, 0f, 1000f, capsuleHeight.toFloat())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val FFTSIZE = 1024
|
||||||
|
private val inBuf = Array(2) { FloatArray(FFTSIZE) }
|
||||||
|
private fun sin2(x: Double) = sin(x).pow(2)
|
||||||
|
private val fftWin = FloatArray(FFTSIZE) { sin2(PI * it / FFTSIZE).toFloat() } // hann
|
||||||
|
private val oldFFTmagn = DoubleArray(FFTSIZE / 2) { 0.0 }
|
||||||
|
private val chsum = ComplexArray(FloatArray(FFTSIZE * 2))
|
||||||
|
private val fftOut = ComplexArray(FloatArray(FFTSIZE * 2))
|
||||||
|
private val binHeights = FloatArray(FFTSIZE / 2)
|
||||||
|
private val FFT_SMOOTHING_FACTOR = BasicDebugInfoWindow.getSmoothingFactor(1600)
|
||||||
|
private val lowlim = -36.0f
|
||||||
|
private val STRIP_W = 9f
|
||||||
|
|
||||||
|
private val fftBinIndices = arrayOf(
|
||||||
|
0..3,
|
||||||
|
4..12,
|
||||||
|
13..39,
|
||||||
|
40..121,
|
||||||
|
122 until FFTSIZE / 2
|
||||||
|
) // 60-18000 at 1024 (https://www.desmos.com/calculator/vkxhrzfam3)
|
||||||
|
private val fftBarHeights = FloatArray(5)
|
||||||
|
|
||||||
|
override fun updateUI(delta: Float) {
|
||||||
|
val inbuf = AudioMixer.musicTrack.extortField<MixerTrackProcessor>("processor")!!.extortField<List<FloatArray>>("fout1")!!
|
||||||
|
push(inbuf[0], inBuf[0])
|
||||||
|
push(inbuf[1], inBuf[1])
|
||||||
|
for (i in 0 until FFTSIZE) {
|
||||||
|
chsum.reim[2*i] = (inBuf[0][i] + inBuf[1][i]) * fftWin[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
FFT.fftInto(chsum, fftOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun drawFreqMeter(batch: SpriteBatch, posX: Float, posY: Float) {
|
||||||
|
// apply slope to the fft bins, also converts fullscale to decibels
|
||||||
|
for (bin in binHeights.indices) {
|
||||||
|
val freqR = (TerrarumAudioMixerTrack.SAMPLING_RATED / FFTSIZE) * (bin + 1)
|
||||||
|
val magn0 = fftOut.reim[2 * bin].absoluteValue / FFTSIZE * (freqR / 10.0) // apply slope
|
||||||
|
val magn = FastMath.interpolateLinear(FFT_SMOOTHING_FACTOR, magn0, oldFFTmagn[bin])
|
||||||
|
val magnLog = fullscaleToDecibels(magn)
|
||||||
|
|
||||||
|
val h = (-(magnLog - lowlim) / lowlim * STRIP_W).toFloat().coerceAtLeast(0.5f)
|
||||||
|
|
||||||
|
binHeights[bin] = h
|
||||||
|
|
||||||
|
oldFFTmagn[bin] = magn
|
||||||
|
}
|
||||||
|
|
||||||
|
fftBinIndices.mapIndexed { i, range ->
|
||||||
|
fftBarHeights[i] = binHeights.slice(range).average().toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
batch.color = colourMeter2
|
||||||
|
fftBarHeights.forEachIndexed { index, h ->
|
||||||
|
Toolkit.fillArea(batch, posX + index*4f, posY - h, 3f, 2*h + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
batch.color = colourMeter
|
||||||
|
fftBarHeights.forEachIndexed { index, h ->
|
||||||
|
Toolkit.fillArea(batch, posX + index*4f, posY - h, 2f, 2*h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
baloonTexture.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun push(samples: FloatArray, buf: FloatArray) {
|
||||||
|
if (samples.size >= FFTSIZE) {
|
||||||
|
// overwrite
|
||||||
|
System.arraycopy(samples, samples.size - buf.size, buf, 0, buf.size)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// shift samples
|
||||||
|
System.arraycopy(buf, samples.size, buf, 0, buf.size - samples.size)
|
||||||
|
// write to the buf
|
||||||
|
System.arraycopy(samples, 0, buf, buf.size - samples.size, samples.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,6 +54,7 @@ version=0.4.0
|
|||||||
jar=
|
jar=
|
||||||
|
|
||||||
# Sha256sum of the External JAR, if any
|
# Sha256sum of the External JAR, if any
|
||||||
|
# The hash will not be checked if the game is running on the development mode
|
||||||
jarhash=
|
jarhash=
|
||||||
|
|
||||||
# Modules that must be pre-installed, separated by semicolons (;)
|
# Modules that must be pre-installed, separated by semicolons (;)
|
||||||
|
|||||||
BIN
assets/mods/musicplayer/MusicPlayer.jar
LFS
Normal file
BIN
assets/mods/musicplayer/MusicPlayer.jar
LFS
Normal file
Binary file not shown.
BIN
assets/mods/musicplayer/gui/blob.tga
LFS
Normal file
BIN
assets/mods/musicplayer/gui/blob.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/musicplayer/gui/textmask.tga
LFS
Normal file
BIN
assets/mods/musicplayer/gui/textmask.tga
LFS
Normal file
Binary file not shown.
10
assets/mods/musicplayer/metadata.properties
Normal file
10
assets/mods/musicplayer/metadata.properties
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
propername=Terrarum Music Player
|
||||||
|
description=Simple Music Player Widget
|
||||||
|
author=CuriousTo\uA75Bvald
|
||||||
|
package=net.torvald.terrarum.musicplayer
|
||||||
|
entrypoint=net.torvald.terrarum.musicplayer.EntryPoint
|
||||||
|
releasedate=2023-12-31
|
||||||
|
version=1.0.0
|
||||||
|
jar=MusicPlayer.jar
|
||||||
|
jarhash=0
|
||||||
|
dependency=basegame 0.4.0
|
||||||
@@ -481,6 +481,7 @@ public class App implements ApplicationListener {
|
|||||||
if (Gdx.app != null) {
|
if (Gdx.app != null) {
|
||||||
Gdx.app.exit();
|
Gdx.app.exit();
|
||||||
}
|
}
|
||||||
|
e.printStackTrace();
|
||||||
new GameCrashHandler(e);
|
new GameCrashHandler(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ import net.torvald.terrarum.gameitems.ItemID
|
|||||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||||
import net.torvald.terrarum.itemproperties.MaterialCodex
|
import net.torvald.terrarum.itemproperties.MaterialCodex
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
import net.torvald.terrarum.modulebasegame.worldgenerator.OregenParams
|
import net.torvald.terrarum.modulebasegame.worldgenerator.OregenParams
|
||||||
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen
|
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen
|
||||||
import net.torvald.terrarum.serialise.Common
|
import net.torvald.terrarum.serialise.Common
|
||||||
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
import net.torvald.terrarum.utils.CSVFetcher
|
import net.torvald.terrarum.utils.CSVFetcher
|
||||||
import net.torvald.terrarum.utils.JsonFetcher
|
import net.torvald.terrarum.utils.JsonFetcher
|
||||||
import net.torvald.terrarum.utils.forEachSiblings
|
import net.torvald.terrarum.utils.forEachSiblings
|
||||||
@@ -275,16 +277,16 @@ object ModMgr {
|
|||||||
digester.reset()
|
digester.reset()
|
||||||
val hash = digester.digest(File(jarFilePath).readBytes()).joinToString("","","") { it.toInt().and(255).toString(16).uppercase().padStart(2,'0') }
|
val hash = digester.digest(File(jarFilePath).readBytes()).joinToString("","","") { it.toInt().and(255).toString(16).uppercase().padStart(2,'0') }
|
||||||
|
|
||||||
if (jarHash != hash) {
|
if (!App.IS_DEVELOPMENT_BUILD && jarHash != hash) {
|
||||||
printdbg(this, "Hash expected: $jarHash, got: $hash")
|
printdbg(this, "Hash expected: $jarHash, got: $hash")
|
||||||
throw IllegalStateException("Module Jarfile hash mismatch")
|
throw IllegalStateException("Module Jarfile hash mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for module-info.java
|
// check for module-info.java
|
||||||
val moduleInfoPath = cl.getResources("module-info.class").toList().filter { it.toString().contains("$moduleName/$jar!/module-info.class") && it.toString().endsWith("module-info.class")}
|
/*val moduleInfoPath = cl.getResources("module-info.class").toList().filter { it.toString().contains("$moduleName/$jar!/module-info.class") && it.toString().endsWith("module-info.class")}
|
||||||
if (moduleInfoPath.isEmpty()) {
|
if (moduleInfoPath.isEmpty()) {
|
||||||
throw IllegalStateException("module-info not found on $moduleName")
|
throw IllegalStateException("module-info not found on $moduleName")
|
||||||
}
|
}*/
|
||||||
|
|
||||||
newClass = cl.loadClass(entryPoint)
|
newClass = cl.loadClass(entryPoint)
|
||||||
}
|
}
|
||||||
@@ -771,6 +773,14 @@ object ModMgr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object GameExtraGuiLoader {
|
||||||
|
internal val guis = ArrayList<(TerrarumIngame) -> UICanvas>()
|
||||||
|
|
||||||
|
@JvmStatic fun register(uiCreationFun: (TerrarumIngame) -> UICanvas) {
|
||||||
|
guis.add(uiCreationFun)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class JarFileLoader(urls: Array<URL>) : URLClassLoader(urls) {
|
private class JarFileLoader(urls: Array<URL>) : URLClassLoader(urls) {
|
||||||
|
|||||||
@@ -472,6 +472,11 @@ fun blendMul(batch: SpriteBatch) {
|
|||||||
batch.setBlendFunction(GL20.GL_DST_COLOR, GL20.GL_ONE_MINUS_SRC_ALPHA)
|
batch.setBlendFunction(GL20.GL_DST_COLOR, GL20.GL_ONE_MINUS_SRC_ALPHA)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun blendAlphaMask(batch: SpriteBatch) {
|
||||||
|
batch.enableBlending()
|
||||||
|
batch.setBlendFunction(GL20.GL_ZERO, GL20.GL_SRC_ALPHA)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use demultiplier shader on GL Source (foreground) if source has semitransparency
|
* Use demultiplier shader on GL Source (foreground) if source has semitransparency
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import net.torvald.terrarum.ui.Toolkit
|
|||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
class Scope : TerrarumAudioFilter() {
|
class Scope : TerrarumAudioFilter() {
|
||||||
val backbufL = Array((4096f / AUDIO_BUFFER_SIZE).roundToInt().coerceAtLeast(1)) {
|
val backbufL = Array((6144f / AUDIO_BUFFER_SIZE).roundToInt().coerceAtLeast(1)) {
|
||||||
FloatArray(AUDIO_BUFFER_SIZE)
|
FloatArray(AUDIO_BUFFER_SIZE)
|
||||||
}
|
}
|
||||||
val backbufR = Array((4096f / AUDIO_BUFFER_SIZE).roundToInt().coerceAtLeast(1)) {
|
val backbufR = Array((6144f / AUDIO_BUFFER_SIZE).roundToInt().coerceAtLeast(1)) {
|
||||||
FloatArray(AUDIO_BUFFER_SIZE)
|
FloatArray(AUDIO_BUFFER_SIZE)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,11 +64,11 @@ class Scope : TerrarumAudioFilter() {
|
|||||||
|
|
||||||
// plot dots
|
// plot dots
|
||||||
for (i in 0 until TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE) {
|
for (i in 0 until TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE) {
|
||||||
val y0 = inbuf[0][i] * 0.7
|
val y0 = +inbuf[0][i] * 2f
|
||||||
val x0 = -inbuf[1][i] * 0.7 // rotate the domain by -90 deg
|
val x0 = -inbuf[1][i] * 2f// rotate the domain by -90 deg
|
||||||
|
|
||||||
val x = (+x0*sqrt2p -y0*sqrt2p) * 1.414
|
val x = (+x0*sqrt2p -y0*sqrt2p) * 1.4142
|
||||||
val y = (-x0*sqrt2p -y0*sqrt2p) * 1.414 // further rotate by -45 deg then flip along the y axis
|
val y = (-x0*sqrt2p -y0*sqrt2p) * 1.4142 // further rotate by -45 deg then flip along the y axis
|
||||||
|
|
||||||
backbufL[0][i] = x.toFloat()
|
backbufL[0][i] = x.toFloat()
|
||||||
backbufR[0][i] = y.toFloat()
|
backbufR[0][i] = y.toFloat()
|
||||||
|
|||||||
@@ -641,7 +641,10 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
ingameUpdateThread = ThreadIngameUpdate(this)
|
ingameUpdateThread = ThreadIngameUpdate(this)
|
||||||
updateThreadWrapper = Thread(ingameUpdateThread, "Terrarum UpdateThread")
|
updateThreadWrapper = Thread(ingameUpdateThread, "Terrarum UpdateThread")
|
||||||
|
|
||||||
|
// add extra UIs from the other modules
|
||||||
|
ModMgr.GameExtraGuiLoader.guis.forEach {
|
||||||
|
uiContainer.add(it(this))
|
||||||
|
}
|
||||||
|
|
||||||
// these need to appear on top of any others
|
// these need to appear on top of any others
|
||||||
uiContainer.add(notifier)
|
uiContainer.add(notifier)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ data class MusicContainer(
|
|||||||
val name: String,
|
val name: String,
|
||||||
val file: File,
|
val file: File,
|
||||||
val gdxMusic: Music,
|
val gdxMusic: Music,
|
||||||
val songFinishedHook: (Music) -> Unit
|
internal var songFinishedHook: (Music) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val samplingRate: Int
|
val samplingRate: Int
|
||||||
val codec: String
|
val codec: String
|
||||||
@@ -142,7 +142,9 @@ class TerrarumMusicGovernor : MusicGovernor() {
|
|||||||
it.nameWithoutExtension.replace('_', ' ').split(" ").map { it.capitalize() }.joinToString(" "),
|
it.nameWithoutExtension.replace('_', ' ').split(" ").map { it.capitalize() }.joinToString(" "),
|
||||||
it,
|
it,
|
||||||
Gdx.audio.newMusic(Gdx.files.absolute(it.absolutePath))
|
Gdx.audio.newMusic(Gdx.files.absolute(it.absolutePath))
|
||||||
) { stopMusic() }
|
).also { muscon ->
|
||||||
|
muscon.songFinishedHook = { stopMusic(muscon) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (e: GdxRuntimeException) {
|
catch (e: GdxRuntimeException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
@@ -170,7 +172,16 @@ class TerrarumMusicGovernor : MusicGovernor() {
|
|||||||
|
|
||||||
private var ambientsBin: ArrayList<Int> = ArrayList(ambients.indices.toList().shuffled())
|
private var ambientsBin: ArrayList<Int> = ArrayList(ambients.indices.toList().shuffled())
|
||||||
|
|
||||||
|
private val musicStartHooks = ArrayList<(MusicContainer) -> Unit>()
|
||||||
|
private val musicStopHooks = ArrayList<(MusicContainer) -> Unit>()
|
||||||
|
|
||||||
|
fun addMusicStartHook(f: (MusicContainer) -> Unit) {
|
||||||
|
musicStartHooks.add(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addMusicStopHook(f: (MusicContainer) -> Unit) {
|
||||||
|
musicStopHooks.add(f)
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
songs.forEach {
|
songs.forEach {
|
||||||
@@ -193,18 +204,20 @@ class TerrarumMusicGovernor : MusicGovernor() {
|
|||||||
protected var ambState = 0
|
protected var ambState = 0
|
||||||
protected var ambFired = false
|
protected var ambFired = false
|
||||||
|
|
||||||
private fun stopMusic() {
|
private fun stopMusic(song: MusicContainer?) {
|
||||||
musicState = STATE_INTERMISSION
|
musicState = STATE_INTERMISSION
|
||||||
intermissionAkku = 0f
|
intermissionAkku = 0f
|
||||||
intermissionLength = 30f + 30f * Math.random().toFloat() // 30s-60s
|
intermissionLength = 30f + 30f * Math.random().toFloat() // 30s-60s
|
||||||
musicFired = false
|
musicFired = false
|
||||||
|
musicStopHooks.forEach { if (song != null) { it(song) } }
|
||||||
printdbg(this, "Intermission: $intermissionLength seconds")
|
printdbg(this, "Intermission: $intermissionLength seconds")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startMusic(song: MusicContainer) {
|
private fun startMusic(song: MusicContainer) {
|
||||||
AudioMixer.startMusic(song)
|
AudioMixer.startMusic(song)
|
||||||
printdbg(this, "Now playing: $song")
|
printdbg(this, "Now playing: $song")
|
||||||
INGAME.sendNotification("Now Playing $EMDASH ${song.name}")
|
// INGAME.sendNotification("Now Playing $EMDASH ${song.name}")
|
||||||
|
musicStartHooks.forEach { it(song) }
|
||||||
musicState = STATE_PLAYING
|
musicState = STATE_PLAYING
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +233,7 @@ class TerrarumMusicGovernor : MusicGovernor() {
|
|||||||
private fun startAmbient(song: MusicContainer) {
|
private fun startAmbient(song: MusicContainer) {
|
||||||
AudioMixer.startAmb(song)
|
AudioMixer.startAmb(song)
|
||||||
printdbg(this, "Now playing: $song")
|
printdbg(this, "Now playing: $song")
|
||||||
INGAME.sendNotification("Now Playing $EMDASH ${song.name}")
|
// INGAME.sendNotification("Now Playing $EMDASH ${song.name}")
|
||||||
ambState = STATE_PLAYING
|
ambState = STATE_PLAYING
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +298,7 @@ class TerrarumMusicGovernor : MusicGovernor() {
|
|||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
AudioMixer.requestFadeOut(AudioMixer.fadeBus, AudioMixer.DEFAULT_FADEOUT_LEN) // explicit call for fade-out when the game instance quits
|
AudioMixer.requestFadeOut(AudioMixer.fadeBus, AudioMixer.DEFAULT_FADEOUT_LEN) // explicit call for fade-out when the game instance quits
|
||||||
stopMusic()
|
stopMusic(AudioMixer.musicTrack.currentTrack)
|
||||||
stopAmbient()
|
stopAmbient()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ class UILoadList(val full: UILoadSavegame) : UICanvas() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||||
playerCells.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
playerCells.slice(playerCells.indices).forEach { it.touchUp(screenX, screenY, pointer, button) } // to prevent ConcurrentModificationException
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -418,7 +418,7 @@ class BasicDebugInfoWindow : UICanvas() {
|
|||||||
|
|
||||||
fun getSmoothingFactor(sampleCount: Int) = (1.0 - (256.0 / sampleCount))
|
fun getSmoothingFactor(sampleCount: Int) = (1.0 - (256.0 / sampleCount))
|
||||||
val PEAK_SMOOTHING_FACTOR = getSmoothingFactor(640)
|
val PEAK_SMOOTHING_FACTOR = getSmoothingFactor(640)
|
||||||
val FFT_SMOOTHING_FACTOR = getSmoothingFactor(960)
|
val FFT_SMOOTHING_FACTOR = getSmoothingFactor(1200)
|
||||||
val LAMP_SMOOTHING_FACTOR = getSmoothingFactor(3200)
|
val LAMP_SMOOTHING_FACTOR = getSmoothingFactor(3200)
|
||||||
val RMS_SMOOTHING_FACTOR = getSmoothingFactor(12000)
|
val RMS_SMOOTHING_FACTOR = getSmoothingFactor(12000)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user