From 939867934b8143016d9928f7f256d09ff65e64cd Mon Sep 17 00:00:00 2001 From: Byte Dice Date: Fri, 29 Nov 2024 19:38:43 +0100 Subject: [PATCH] significantly changed emitter params. STILL A LOT OF ERRORS. --- .../bytedice/bde_particles/Bde_particles.kt | 47 ++----- .../kotlin/com/bytedice/bde_particles/Math.kt | 39 ------ .../bde_particles/commands/GiveEmitterTool.kt | 4 +- .../bde_particles/commands/ManageEmitters.kt | 1 - .../bde_particles/particles/EmitterParams.kt | 77 ++++++++---- .../bde_particles/particles/ParamClasses.kt | 116 ++++++++--------- .../particles/ParticleEmitter.kt | 24 ++-- .../particles/ParticleIdRegister.kt | 119 ++++-------------- .../bde_particles/particles/Shapes.kt | 103 ++++++++++++++- 9 files changed, 260 insertions(+), 270 deletions(-) diff --git a/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt b/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt index 4a628cd..504964c 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/Bde_particles.kt @@ -24,6 +24,7 @@ import net.minecraft.util.ActionResult import net.minecraft.util.Hand import net.minecraft.util.TypedActionResult import net.minecraft.world.World +import org.joml.Vector2f import java.util.* @@ -34,22 +35,19 @@ import java.util.* // blockCurve array not needing "minecraft:" // Adding a parameter for an initial velocity from an origin point (you currently have to use force fields) - // Pair, Pair> - // "min center vel", "max center vel", "min edge vel", "max edge vel" // Parameters - // localOffset (Vec3f) - // velocity based, relative coordinate based, or rotation based - // localOffsetCurve (curve) - // spawnOffset (Vec3f) // originOffset (Vec3f) + // velocity based, relative coordinate based, or rotation based + + // originOffsetCurve (curve) + // spawnOffset (Vec3f) // velRot (bool) // rotates the particle to face the velocity + // spawnChance (Float) // shape: spawnOnlyOnEdge (Boolean) -// Move most (if not all) particle params to emitters. -// 3D curves (curves for all X Y Z) // Custom curve equation command args (parse from strings) // Cylinder and cone force field shape. // Better particle performance. @@ -109,7 +107,7 @@ class Bde_particles : ModInitializer { fun init() { - addToEmitterRegister("DEFAULT", EmitterParams.DEFAULT) + addToRegister("DEFAULT", EmitterParams.DEFAULT) } @@ -139,7 +137,7 @@ fun onRightClick(player: PlayerEntity, world: ServerWorld, hand: Hand) : TypedAc val handItem = player.getStackInHand(hand) val (isEmitterTool, emitterId) = ParticleEmitterTool.getToolDetails(handItem) val hitResult = raycastFromPlayer(player as ServerPlayerEntity, 200.0) - val emitterParams = getEmitterParams(emitterId) + val emitterParams = getParamsById(emitterId) if ( !isEmitterTool @@ -149,7 +147,7 @@ fun onRightClick(player: PlayerEntity, world: ServerWorld, hand: Hand) : TypedAc return TypedActionResult(ActionResult.PASS, handItem) } - val emitter = ParticleEmitter(hitResult.pos, world, emitterParams) + val emitter = ParticleEmitter(hitResult.pos, Vector2f(0.0f, 0.0f), world, emitterParams) ALL_PARTICLE_EMITTERS += emitter return TypedActionResult(ActionResult.PASS, handItem) @@ -157,35 +155,16 @@ fun onRightClick(player: PlayerEntity, world: ServerWorld, hand: Hand) : TypedAc fun emitterParamsToJson(params: EmitterParams) : Map { // TODO: map to new params - val allParticleParamsJSON: MutableList> = mutableListOf() - val particle = params.particle + val allParamsJson: MutableList> = mutableListOf() - val particleParamsJSON = mapOf( - "shape" to particle.shape, - "blockCurve" to particle.blockCurve, - "rotRandom" to particle.rotRandom, - "rotVelRandom" to particle.rotVelRandom, - "rotVelCurve" to particle.rotVelCurve, - "sizeRandom" to particle.sizeRandom, - "uniformSize" to particle.uniformSize, - "sizeCurve" to particle.sizeCurve, - "velRandom" to particle.velRandom, - "forceFields" to particle.forceFields, - "gravity" to particle.gravity, - "drag" to particle.drag, - "minVel" to particle.minVel, - "lifeTime" to particle.lifeTime + val paramsJson = mapOf( + "shape" to params.shape ) - allParticleParamsJSON.add(particleParamsJSON) + allParamsJson.add(paramsJson) val emitterParamsJSON = mapOf( "maxCount" to params.maxCount, - "spawnsPerTick" to params.spawnsPerTick, - "loopDur" to params.loopDur, - "loopDelay" to params.loopDelay, - "loopCount" to params.loopCount, - "particleTypes" to allParticleParamsJSON ) return emitterParamsJSON diff --git a/src/main/kotlin/com/bytedice/bde_particles/Math.kt b/src/main/kotlin/com/bytedice/bde_particles/Math.kt index 85e0e32..d4dfc75 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/Math.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/Math.kt @@ -137,45 +137,6 @@ fun quatToEuler(quat: Vector4f): Vector3f { } -fun randomInCircle(r: Float) : Vector2f { - val randRadius = r * sqrt(randomFloatBetween(0.0f, 1.0f)) - val randAngle = randomFloatBetween(0.0f, Math.PI.toFloat() * 2) - - val randomPos = Vector2f(randRadius * cos(randAngle), randRadius * sin(randAngle)) - return randomPos -} - - -fun randomInSphere(r: Float) : Vector3f { - val randRadius = r * Random.nextDouble().pow(1.0 / 3.0) - - val phi = Random.nextDouble(0.0, 2 * Math.PI) - - val cosTheta = Random.nextDouble(-1.0, 1.0) - val theta = acos(cosTheta) - - val x = randRadius * sin(theta) * cos(phi) - val y = randRadius * sin(theta) * sin(phi) - val z = randRadius * cos(theta) - - return Vector3f(x.toFloat(), y.toFloat(), z.toFloat()) -} - - -fun randomInRect(size: Vector2f) : Vector2f { - return Vector2f(randomFloatBetween(0.0f, size.x), randomFloatBetween(0.0f, size.y)) -} - - -fun randomInCube(size: Vector3f) : Vector3f { - return Vector3f( - randomFloatBetween(0.0f, size.x), - randomFloatBetween(0.0f, size.y), - randomFloatBetween(0.0f, size.z) - ) -} - - fun transformOffsetByQuat(offset: Vector3f, rotation: Vector4f): Vector3f { val x = offset.x val y = offset.y diff --git a/src/main/kotlin/com/bytedice/bde_particles/commands/GiveEmitterTool.kt b/src/main/kotlin/com/bytedice/bde_particles/commands/GiveEmitterTool.kt index b3c023c..6713250 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/commands/GiveEmitterTool.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/commands/GiveEmitterTool.kt @@ -1,7 +1,7 @@ package com.bytedice.bde_particles.commands import com.bytedice.bde_particles.items.ParticleEmitterTool -import com.bytedice.bde_particles.particles.emitterIdRegister +import com.bytedice.bde_particles.particles.idRegister import com.mojang.brigadier.Command import com.mojang.brigadier.CommandDispatcher import com.mojang.brigadier.arguments.StringArgumentType @@ -20,7 +20,7 @@ object GiveEmitterTool { val command = CommandManager.literal("GiveEmitterTool") .requires { source -> source.hasPermissionLevel(4) } - val allEmitterIds = emitterIdRegister.keys + val allEmitterIds = idRegister.keys val itemNameArg = CommandManager.argument("Item Name", StringArgumentType.string()) val itemTypeArg = CommandManager.argument("Item Type", ItemStackArgumentType.itemStack(registryAccess)) diff --git a/src/main/kotlin/com/bytedice/bde_particles/commands/ManageEmitters.kt b/src/main/kotlin/com/bytedice/bde_particles/commands/ManageEmitters.kt index 9e47b21..23bab20 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/commands/ManageEmitters.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/commands/ManageEmitters.kt @@ -4,7 +4,6 @@ import com.bytedice.bde_particles.emitterParamsToJson import com.bytedice.bde_particles.particles.* import com.mojang.brigadier.Command import com.mojang.brigadier.CommandDispatcher -import com.mojang.brigadier.arguments.IntegerArgumentType import com.mojang.brigadier.arguments.StringArgumentType import com.mojang.brigadier.builder.LiteralArgumentBuilder import com.mojang.brigadier.builder.RequiredArgumentBuilder diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/EmitterParams.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/EmitterParams.kt index d96e490..f627997 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/EmitterParams.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/EmitterParams.kt @@ -31,30 +31,63 @@ import org.joml.Vector3f * @param blockCurve Specifies an array of block names that the particle transitions through during its lifetime, combined with a curve to control transitions. Defaults to "minecraft:air" if empty. */ data class EmitterParams ( - var maxCount: Int = 200, - var spawnRate: Int = 1, - var spawnChance: Float = 1.0f, - var loopDur: Int = 25, - var loopDelay: Int = 0, - var loopCount: Int = 0, - var shape: SpawningShape = SpawningShape.Circle(3.0f), - var initRot: ParamClasses.PairVec3f = ParamClasses.PairVec3f(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f), - var rotVel: ParamClasses.PairVec3f = ParamClasses.PairVec3f(-0.2f, -0.2f, -0.2f, 0.2f, 0.2f, 0.2f), - var rotTowardVel: Boolean = true, - var initVel: ParamClasses.PairVec3f = ParamClasses.PairVec3f(-0.1f, 0.3f, -0.1f, 0.1f, 0.6f, 0.1f), - var initScale: ParamClasses.RandScale = ParamClasses.RandScale.Uniform(), - var scaleTowardVel: Boolean = true, - var forceFields: Array = emptyArray(), - var constVel: Vector3f = Vector3f(0.0f, -0.01f, 0.0f), - var drag: Float = 0.075f, - var minVel: Float = 0.0f, - var lifeTime: ParamClasses.PairInt = ParamClasses.PairInt(25, 40), - var rotVelCurve: ParamClasses.LerpVal = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Sqrt), - var scaleCurve: ParamClasses.LerpVal = ParamClasses.LerpVal.LerpUniform(1.0f, 0.5f, LerpCurves.Linear), - var blockCurve: Pair, LerpCurves> = Pair(arrayOf("minecraft:purple_concrete", "minecraft:purple_stained_glass"), LerpCurves.Sqrt), + // spawning + var maxCount: Int, + var spawnRate: Int, + var spawnChance: Float, + var spawnDuration: ParamClasses.Duration, + var spawnPosOffset: Vector3f, + var lifeTime: ParamClasses.PairInt, + var shape: SpawningShape, + // init transforms + var offset: ParamClasses.PairVec3f, + var initRot: ParamClasses.PairVec3f, + var rotVel: ParamClasses.PairVec3f, + var rotWithVel: Boolean, + var initVel: ParamClasses.PairVec3f, + var initCenterVel: ParamClasses.PairFloat, + var initScale: ParamClasses.PairVec3f, + var scaleWithVel: Boolean, + // velocity + var forceFields: Array, + var constVel: Vector3f, + var drag: Float, + var minVel: Float, + // curves + var offsetCurve: ParamClasses.LerpVal, + var rotVelCurve: ParamClasses.LerpVal, + var scaleCurve: ParamClasses.LerpVal, + var blockCurve: Pair, LerpCurves>, ) { companion object Presets { - val DEFAULT = EmitterParams() + val DEFAULT = EmitterParams( + maxCount = 200, + spawnRate = 1, + spawnChance = 1.0f, + spawnDuration = ParamClasses.Duration.SingleBurst(25), + spawnPosOffset = Vector3f(0.0f, 0.0f, 0.0f), + lifeTime = ParamClasses.PairInt(25, 40), + shape = SpawningShape.Circle(3.0f), + offset = ParamClasses.PairVec3f.Uniform(-0.5f, -0.5f), + initRot = ParamClasses.PairVec3f.Null, + rotVel = ParamClasses.PairVec3f.NonUniform(-0.2f, -0.2f, -0.2f, 0.2f, 0.2f, 0.2f), + rotWithVel = true, + initVel = ParamClasses.PairVec3f.Null, + initCenterVel = ParamClasses.PairFloat(0.1f, 0.3f), + initScale = ParamClasses.PairVec3f.Uniform(1.0f, 0.2f), + scaleWithVel = true, + forceFields = emptyArray(), + constVel = Vector3f(0.0f, -0.01f, 0.0f), + drag = 0.075f, + minVel = 0.0f, + offsetCurve = ParamClasses.LerpVal.NoLerpVec3f(Vector3f(-0.5f, -0.5f, -0.5f)), + rotVelCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Sqrt), + scaleCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.5f, LerpCurves.Linear), + blockCurve = Pair( + arrayOf("minecraft:purple_concrete", "minecraft:purple_stained_glass"), + LerpCurves.Sqrt + ), + ) } } \ No newline at end of file diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/ParamClasses.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/ParamClasses.kt index 3411e5c..05a2ca2 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/ParamClasses.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/ParamClasses.kt @@ -6,40 +6,24 @@ import com.bytedice.bde_particles.randomIntBetween import org.joml.Vector3f class ParamClasses { - class PairVec3f ( - private val minX: Float = 0.0f, - private val minY: Float = 0.0f, - private val minZ: Float = 0.0f, - private val maxX: Float = 1.0f, - private val maxY: Float = 1.0f, - private val maxZ: Float = 1.0f, - ) { - fun randomize() : Vector3f { - return Vector3f( - randomFloatBetween(minX, maxX), - randomFloatBetween(minY, maxY), - randomFloatBetween(minZ, maxZ), - ) - } - } - sealed class RandScale { + sealed class PairVec3f { class Uniform ( - private val min: Float = 0.0f, - private val max: Float = 1.0f, - ) : RandScale() { + private val min: Float, + private val max: Float, + ) : PairVec3f() { fun randomize() : Vector3f { val x = randomFloatBetween(min, max) return Vector3f(x, x, x) } } class NonUniform ( - private val minX: Float = 0.0f, - private val minY: Float = 0.0f, - private val minZ: Float = 0.0f, - private val maxX: Float = 1.0f, - private val maxY: Float = 1.0f, - private val maxZ: Float = 1.0f - ) : RandScale() { + private val minX: Float, + private val minY: Float, + private val minZ: Float, + private val maxX: Float, + private val maxY: Float, + private val maxZ: Float + ) : PairVec3f() { fun randomize(): Vector3f { return Vector3f( randomFloatBetween(minX, maxX), @@ -48,35 +32,29 @@ class ParamClasses { ) } } - } - class PairVec2i ( - private val minX: Int = 0, - private val minY: Int = 0, - private val maxX: Int = 1, - private val maxY: Int = 1, - ) { - fun randomize() : Pair { - return Pair( - randomIntBetween(minX, maxX), - randomIntBetween(minY, maxY), - ) - } + data object Null : PairVec3f() } class PairInt ( - private val min: Int = 0, - private val max: Int = 1, + private val min: Int, + private val max: Int, ) { fun randomize() : Int { return randomIntBetween(min, max) } } + class PairFloat( + private val min: Float, + private val max: Float, + ) { + fun randomize() : Float { return randomFloatBetween(min, max) } + } sealed class LerpVal { class LerpVec3f( - private val fromX: Float = 0.0f, - private val fromY: Float = 0.0f, - private val fromZ: Float = 0.0f, - private val toX: Float = 1.0f, - private val toY: Float = 1.0f, - private val toZ: Float = 1.0f, - private val curve: LerpCurves = LerpCurves.Linear, + private val fromX: Float, + private val fromY: Float, + private val fromZ: Float, + private val toX: Float, + private val toY: Float, + private val toZ: Float, + private val curve: LerpCurves, ) : LerpVal() { fun lerp(t: Float): Vector3f { val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curve.function(t) @@ -86,15 +64,15 @@ class ParamClasses { } } class MultiLerpVec3f( - private val fromX: Float = 0.0f, - private val fromY: Float = 0.0f, - private val fromZ: Float = 0.0f, - private val toX: Float = 1.0f, - private val toY: Float = 1.0f, - private val toZ: Float = 1.0f, - private val curveX: LerpCurves = LerpCurves.Linear, - private val curveY: LerpCurves = LerpCurves.Linear, - private val curveZ: LerpCurves = LerpCurves.Linear + private val fromX: Float, + private val fromY: Float, + private val fromZ: Float, + private val toX: Float, + private val toY: Float, + private val toZ: Float, + private val curveX: LerpCurves, + private val curveY: LerpCurves, + private val curveZ: LerpCurves ) : LerpVal() { fun lerp(t: Float): Vector3f { val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curveX.function(t) @@ -104,14 +82,15 @@ class ParamClasses { } } class LerpUniform( - private val from: Float = 0.0f, - private val to: Float = 1.0f, - private val curve: LerpCurves = LerpCurves.Linear, + private val from: Float, + private val to: Float, + private val curve: LerpCurves, ) : LerpVal() { fun lerp(t: Float): Float { return com.bytedice.bde_particles.lerp(from, to, t) * curve.function(t) } } + data class NoLerpVec3f(val value: Vector3f) : LerpVal() fun lerpToVector3f(t: Float) : Vector3f { when (this) { @@ -121,7 +100,22 @@ class ParamClasses { val x = this.lerp(t) return Vector3f(x, x, x) } + is NoLerpVec3f -> return this.value } } } + sealed class Duration { + data class SingleBurst( + val loopDur: Int + ) : Duration() + data class MultiBurst( + val loopDur: Int, + val loopDelay: Int, + val loopCount: Int, + ) : Duration() + data class InfiniteLoop( + val loopDur: Int, + val loopDelay: Int + ) : Duration() + } } \ No newline at end of file diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleEmitter.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleEmitter.kt index 207ca73..11a9f01 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleEmitter.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleEmitter.kt @@ -2,8 +2,10 @@ package com.bytedice.bde_particles.particles import net.minecraft.server.world.ServerWorld import net.minecraft.util.math.Vec3d +import org.joml.Vector2f +import org.joml.Vector3f -class ParticleEmitter(private val emitterPos: Vec3d, private val emitterWorld: ServerWorld, private val emitterParams: EmitterParams) { +class ParticleEmitter(private val pos: Vec3d, private val rot: Vector2f, private val world: ServerWorld, private val params: EmitterParams) { private var allParticles: Array = emptyArray() @@ -33,12 +35,12 @@ class ParticleEmitter(private val emitterPos: Vec3d, private val emitterWorld: S private fun addParticle() { if (loopDelayActive) { return } - repeat(this.emitterParams.spawnsPerTick) { - if (allParticles.size >= emitterParams.maxCount) { return } + repeat(params.spawnRate) { + if (allParticles.size >= params.maxCount) { return } - val particle = Particle(emitterParams.particle) - particle.init(this.emitterPos) - particle.spawn(emitterWorld) + val particle = Particle(params) + particle.init(pos, rot) + particle.spawn(world) allParticles += particle } @@ -50,30 +52,30 @@ class ParticleEmitter(private val emitterPos: Vec3d, private val emitterWorld: S // because im so damn good at cooking spaghetti // if max duration is 0 or less, skip counting, its infinite - if (emitterParams.loopDur <= 0) { return } + if (params.loopDur <= 0) { return } // if the duration is greater than max duration, add 1 loopCount // return if max loopCount is 0 // if the delay is greater than 0 then enable it - if (loopDur >= emitterParams.loopDur) { + if (loopDur >= params.loopDur) { if (loopCount == 0) { isTicking = false return } loopCount += 1 loopDur = 0 - if (emitterParams.loopDelay > 0) { loopDelayActive = true } + if (params.loopDelay > 0) { loopDelayActive = true } } // if the delay is greater than max delay, disable the delay - else if (loopDelay >= emitterParams.loopDelay) { + else if (loopDelay >= params.loopDelay) { loopDelay = 0 loopDelayActive = false } // if loopCount is greater than max loopCount then stop immediately // if max loopCount is below 0 then don't do anything, loop infinitely - if (loopCount > 0 && loopCount >= emitterParams.loopCount) { + if (loopCount > 0 && loopCount >= params.loopCount) { isTicking = false return } diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleIdRegister.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleIdRegister.kt index acdf7d8..0c40cf0 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleIdRegister.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/ParticleIdRegister.kt @@ -2,133 +2,60 @@ package com.bytedice.bde_particles.particles -import com.bytedice.bde_particles.LerpCurves -import org.joml.Vector3f + +val idRegister: MutableMap = mutableMapOf() +val forbiddenIds = arrayOf("", "NULL") -val emitterIdRegister: MutableMap = mutableMapOf() -val forbiddenIds = arrayOf("", "DEFAULT", "NULL") +fun addToRegister(id: String, params: EmitterParams) : Pair { + val newId = replaceForbiddenChars(id.replace(" ", "_")) + if (idRegister.containsKey(newId)) { return Pair(newId, false) } -fun addToEmitterRegister(id: String, params: EmitterParams) : Pair { - val newId = id.replace(" ", "_") - - if (newId in forbiddenIds && newId != "DEFAULT") { return Pair(newId, false) } - if (emitterIdRegister.containsKey(newId)) { return Pair(newId, false) } - - emitterIdRegister[id] = params + idRegister[id] = params return Pair(newId, true) } -fun removeFromEmitterRegister(id: String) : Boolean { - if (id in forbiddenIds) { return false } - if (!emitterIdRegister.containsKey(id)) { return false } +fun removeFromRegister(id: String) : Boolean { + if (id in forbiddenIds) { return false } + if (!idRegister.containsKey(id)) { return false } - emitterIdRegister.remove(id) + idRegister.remove(id) return true } -fun getEmitterParams(id: String) : EmitterParams? { - return emitterIdRegister[id] +fun getParamsById(id: String) : EmitterParams? { + return idRegister[id] } -fun updateEmitterParams(id: String, newParams: EmitterParams) { - emitterIdRegister[id] = newParams +fun updateRegistered(id: String, newParams: EmitterParams) { + idRegister[id] = newParams } -fun updateSingleEmitterParam(id: String, paramName: String, paramValue: Any) : Boolean { - val emitter = getEmitterParams(id) ?: return false - val updatedValues = updateSingleEmitterParam(emitter, paramName, paramValue) - updateEmitterParams(id, updatedValues.first) +fun updateParam(id: String, paramName: String, paramValue: Any) : Boolean { + val emitter = getParamsById(id) ?: return false + val updatedValues = updateParams(emitter, paramName, paramValue) return updatedValues.second } -fun updateSingleParticleParam(emitterId: String, paramName: String, paramValue: Any) : Boolean { // TODO: map to new params - val emitter = getEmitterParams(emitterId) ?: return false - val particle = emitter.particle - - val updatedValues = updateSingleParticleParam(particle, paramName, paramValue) - - emitter.particle = updatedValues.first - updateEmitterParams(emitterId, emitter) - - return updatedValues.second -} - - -fun updateSingleEmitterParam(params: EmitterParams, paramName: String, paramValue: Any) : Pair { // TODO: map to new params - val value: Any? = when (paramName) { - "maxCount" -> paramValue as Int - "spawnsPerTick" -> paramValue as Int - "loopDur" -> paramValue as Int - "loopDelay" -> paramValue as Int - "loopCount" -> paramValue as Int - else -> null - } - - if (value == null) { return Pair(params, false) } - +fun updateParams(params: EmitterParams, paramName: String, paramValue: Any) : Pair { // TODO: map to new params val newParams = params.copy() when (paramName) { - "maxCount" -> newParams.maxCount = value as Int - "spawnsPerTick" -> newParams.spawnsPerTick = value as Int - "loopDur" -> newParams.loopDur = value as Int - "loopDelay" -> newParams.loopDelay = value as Int - "loopCount" -> newParams.loopCount = value as Int - else -> return Pair(params, false) + "maxCount" -> newParams.maxCount = paramValue as Int } return Pair(newParams, true) } -fun updateSingleParticleParam(params: ParticleParams, paramName: String, paramValue: Any) : Pair { // TODO: map to new params - val value: Any? = when (paramName) { - "shape" -> paramValue as SpawningShape? - "blockCurve" -> paramValue as Array - "rotRandom" -> paramValue as Pair - "rotVelRandom" -> paramValue as Pair - "sizeRandom" -> paramValue as Pair - "uniformSize" -> paramValue as Boolean - "velRandom" -> paramValue as Pair - "forceFields" -> paramValue as Array - "gravity" -> paramValue as Vector3f - "drag" -> paramValue as Float - "minVel" -> paramValue as Float - "lifeTime" -> paramValue as Pair - "rotVelCurve" -> paramValue as Triple - "sizeCurve" -> paramValue as Triple - else -> null - } - - if (value == null) { return Pair(params, false) } - - val newParams = params.copy() - - when (paramName) { - "shape" -> newParams.shape = value as SpawningShape - "blockCurve" -> newParams.blockCurve = value as Array - "rotRandom" -> newParams.rotRandom = value as Pair - "rotVelRandom" -> newParams.rotVelRandom = value as Pair - "sizeRandom" -> newParams.sizeRandom = value as Pair - "uniformSize" -> newParams.uniformSize = value as Boolean - "velRandom" -> newParams.velRandom = value as Pair - "forceFields" -> newParams.forceFields = value as Array - "gravity" -> newParams.gravity = value as Vector3f - "drag" -> newParams.drag = value as Float - "minVel" -> newParams.minVel = value as Float - "lifeTime" -> newParams.lifeTime = value as Pair - "rotVelCurve" -> newParams.rotVelCurve = value as Triple - "sizeCurve" -> newParams.sizeCurve = value as Triple - else -> return Pair(params, false) - } - - return Pair(newParams, true) +fun replaceForbiddenChars(input: String): String { + val regex = "[^a-zA-Z0-9_-]".toRegex() + return input.replace(regex, "-") } \ No newline at end of file diff --git a/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt b/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt index 1d17adb..8775d9e 100644 --- a/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt +++ b/src/main/kotlin/com/bytedice/bde_particles/particles/Shapes.kt @@ -1,16 +1,111 @@ package com.bytedice.bde_particles.particles +import com.bytedice.bde_particles.randomFloatBetween +import com.bytedice.bde_particles.randomIntBetween import org.joml.Vector2f import org.joml.Vector3f +import kotlin.math.* +import kotlin.random.Random sealed class SpawningShape { - data class Circle(val radius: Float = 1.0f) : SpawningShape() - data class Rect (val size: Vector2f = Vector2f(1.0f, 1.0f)) : SpawningShape() - data class Cube (val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f)) : SpawningShape() - data class Sphere(val radius: Float = 1.0f) : SpawningShape() + class Circle(val radius: Float = 1.0f) : SpawningShape() { + fun randomWithin(): Vector3f { + val randRadius = radius * sqrt(randomFloatBetween(0.0f, 1.0f)) + val randAngle = randomFloatBetween(0.0f, Math.PI.toFloat() * 2) + + val randomPos = Vector3f(randRadius * cos(randAngle), 0.0f, randRadius * sin(randAngle)) + return randomPos + } + + fun randomOnEdge(): Vector3f { + val randAngle = randomFloatBetween(0.0f, Math.PI.toFloat() * 2) + return Vector3f(radius * cos(randAngle), 0.0f, radius * sin(randAngle)) + } + } + + class Rect(val size: Vector2f = Vector2f(1.0f, 1.0f)) : SpawningShape() { + fun randomWithin(): Vector3f { + return Vector3f(randomFloatBetween(0.0f, size.x), 0.0f, randomFloatBetween(0.0f, size.y)) + } + + fun randomOnEdge(): Vector3f { + val perimeter = 2 * (size.x + size.y) + val randPos = randomFloatBetween(0.0f, perimeter) + + return when { + randPos <= size.x -> Vector3f(randPos, 0.0f, 0.0f) + randPos <= size.x + size.y -> Vector3f(size.x, 0.0f, randPos - size.x) + randPos <= 2 * size.x + size.y -> Vector3f(size.x - (randPos - size.x - size.y), 0.0f, size.y) + else -> Vector3f(0.0f, 0.0f, size.y - (randPos - 2 * size.x - size.y)) + } + } + } + + class Cube(val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f)) : SpawningShape() { + fun randomWithin(): Vector3f { + return Vector3f( + randomFloatBetween(0.0f, size.x), + randomFloatBetween(0.0f, size.y), + randomFloatBetween(0.0f, size.z) + ) + } + + fun randomOnEdge(): Vector3f { + val edgeIndex = randomIntBetween(0, 11) // 12 edges + val randPos = randomFloatBetween(0.0f, 1.0f) + + return when (edgeIndex) { + 0 -> Vector3f(randPos * size.x, 0.0f, 0.0f) + 1 -> Vector3f(size.x, 0.0f, randPos * size.z) + 2 -> Vector3f(size.x - randPos * size.x, 0.0f, size.z) + 3 -> Vector3f(0.0f, 0.0f, size.z - randPos * size.z) + 4 -> Vector3f(randPos * size.x, size.y, 0.0f) + 5 -> Vector3f(size.x, size.y, randPos * size.z) + 6 -> Vector3f(size.x - randPos * size.x, size.y, size.z) + 7 -> Vector3f(0.0f, size.y, size.z - randPos * size.z) + 8 -> Vector3f(0.0f, randPos * size.y, 0.0f) + 9 -> Vector3f(size.x, randPos * size.y, 0.0f) + 10 -> Vector3f(size.x, randPos * size.y, size.z) + 11 -> Vector3f(0.0f, randPos * size.y, size.z) + + else -> Vector3f(0.0f, 0.0f, 0.0f) + } + } + } + + class Sphere(val radius: Float = 1.0f) : SpawningShape() { + fun randomWithin(): Vector3f { + val randRadius = radius * Random.nextDouble().pow(1.0 / 3.0) + + val phi = Random.nextDouble(0.0, 2 * Math.PI) + + val cosTheta = Random.nextDouble(-1.0, 1.0) + val theta = acos(cosTheta) + + val x = randRadius * sin(theta) * cos(phi) + val y = randRadius * sin(theta) * sin(phi) + val z = randRadius * cos(theta) + + return Vector3f(x.toFloat(), y.toFloat(), z.toFloat()) + } + + fun randomOnEdge(): Vector3f { + val phi = randomFloatBetween(0.0f, Math.PI.toFloat() * 2) + val cosTheta = randomFloatBetween(-1.0f, 1.0f) + val sinTheta = sqrt(1 - cosTheta * cosTheta) + + val x = radius * sinTheta * cos(phi) + val y = radius * sinTheta * sin(phi) + val z = radius * cosTheta + + return Vector3f(x, y, z) + } + } + data object Point : SpawningShape() } + sealed class ForceFieldShape { data class Sphere( val radius: Float = 3.0f,