significantly changed emitter params. STILL A LOT OF ERRORS.
This commit is contained in:
@@ -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<Vec3f, Vec3f>, Pair<Vec3f, Vec3f>>
|
||||
// "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<String, Any> { // TODO: map to new params
|
||||
val allParticleParamsJSON: MutableList<Map<String, Any?>> = mutableListOf()
|
||||
val particle = params.particle
|
||||
val allParamsJson: MutableList<Map<String, Any?>> = 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<ForceField> = 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<Array<String>, 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<ForceField>,
|
||||
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<Array<String>, 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
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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<Int, Int> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -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<Particle> = 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
|
||||
}
|
||||
|
||||
@@ -2,133 +2,60 @@
|
||||
|
||||
package com.bytedice.bde_particles.particles
|
||||
|
||||
import com.bytedice.bde_particles.LerpCurves
|
||||
import org.joml.Vector3f
|
||||
|
||||
val idRegister: MutableMap<String, EmitterParams> = mutableMapOf()
|
||||
val forbiddenIds = arrayOf("", "NULL")
|
||||
|
||||
|
||||
val emitterIdRegister: MutableMap<String, EmitterParams> = mutableMapOf()
|
||||
val forbiddenIds = arrayOf("", "DEFAULT", "NULL")
|
||||
fun addToRegister(id: String, params: EmitterParams) : Pair<String, Boolean> {
|
||||
val newId = replaceForbiddenChars(id.replace(" ", "_"))
|
||||
|
||||
if (idRegister.containsKey(newId)) { return Pair(newId, false) }
|
||||
|
||||
fun addToEmitterRegister(id: String, params: EmitterParams) : Pair<String, Boolean> {
|
||||
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 {
|
||||
fun removeFromRegister(id: String) : Boolean {
|
||||
if (id in forbiddenIds) { return false }
|
||||
if (!emitterIdRegister.containsKey(id)) { 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<EmitterParams, Boolean> { // 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<EmitterParams, Boolean> { // 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<ParticleParams, Boolean> { // TODO: map to new params
|
||||
val value: Any? = when (paramName) {
|
||||
"shape" -> paramValue as SpawningShape?
|
||||
"blockCurve" -> paramValue as Array<String>
|
||||
"rotRandom" -> paramValue as Pair<Vector3f, Vector3f>
|
||||
"rotVelRandom" -> paramValue as Pair<Vector3f, Vector3f>
|
||||
"sizeRandom" -> paramValue as Pair<Vector3f, Vector3f>
|
||||
"uniformSize" -> paramValue as Boolean
|
||||
"velRandom" -> paramValue as Pair<Vector3f, Vector3f>
|
||||
"forceFields" -> paramValue as Array<ForceField>
|
||||
"gravity" -> paramValue as Vector3f
|
||||
"drag" -> paramValue as Float
|
||||
"minVel" -> paramValue as Float
|
||||
"lifeTime" -> paramValue as Pair<Int, Int>
|
||||
"rotVelCurve" -> paramValue as Triple<Vector3f, Vector3f, LerpCurves>
|
||||
"sizeCurve" -> paramValue as Triple<Vector3f, Vector3f, LerpCurves>
|
||||
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<String>
|
||||
"rotRandom" -> newParams.rotRandom = value as Pair<Vector3f, Vector3f>
|
||||
"rotVelRandom" -> newParams.rotVelRandom = value as Pair<Vector3f, Vector3f>
|
||||
"sizeRandom" -> newParams.sizeRandom = value as Pair<Vector3f, Vector3f>
|
||||
"uniformSize" -> newParams.uniformSize = value as Boolean
|
||||
"velRandom" -> newParams.velRandom = value as Pair<Vector3f, Vector3f>
|
||||
"forceFields" -> newParams.forceFields = value as Array<ForceField>
|
||||
"gravity" -> newParams.gravity = value as Vector3f
|
||||
"drag" -> newParams.drag = value as Float
|
||||
"minVel" -> newParams.minVel = value as Float
|
||||
"lifeTime" -> newParams.lifeTime = value as Pair<Int, Int>
|
||||
"rotVelCurve" -> newParams.rotVelCurve = value as Triple<Vector3f, Vector3f, LerpCurves>
|
||||
"sizeCurve" -> newParams.sizeCurve = value as Triple<Vector3f, Vector3f, LerpCurves>
|
||||
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, "-")
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user