made particles compatible with updated param data. Though not the new ones. STILL FILLED WITH ERRORS
This commit is contained in:
@@ -42,9 +42,11 @@ import java.util.*
|
||||
// velocity based, relative coordinate based, or rotation based
|
||||
// localOffsetCurve (curve)
|
||||
// spawnOffset (Vec3f)
|
||||
// originOffset (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)
|
||||
@@ -108,8 +110,6 @@ class Bde_particles : ModInitializer {
|
||||
|
||||
fun init() {
|
||||
addToEmitterRegister("DEFAULT", EmitterParams.DEFAULT)
|
||||
addToEmitterRegister("FIRE_GEYSER", EmitterParams.FIRE_GEYSER)
|
||||
addToEmitterRegister("RING_EXPLOSION", EmitterParams.RING_EXPLOSION)
|
||||
}
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ fun onRightClick(player: PlayerEntity, world: ServerWorld, hand: Hand) : TypedAc
|
||||
}
|
||||
|
||||
|
||||
fun emitterParamsToJson(params: EmitterParams) : Map<String, Any> {
|
||||
fun emitterParamsToJson(params: EmitterParams) : Map<String, Any> { // TODO: map to new params
|
||||
val allParticleParamsJSON: MutableList<Map<String, Any?>> = mutableListOf()
|
||||
val particle = params.particle
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ import java.awt.Color
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
|
||||
// TODO: completely redesign
|
||||
|
||||
|
||||
// CLOSE THIS FILE IMMEDIATELY, YOU ARE ENTERING EGYPTIAN (pyramid) AND ITALIAN (spaghetti) TERRITORY
|
||||
|
||||
val curves = arrayOf("LINEAR", "SQRT", "EXPONENT", "CUBIC", "SINE", "COSINE", "INVERSE", "LOG", "EXP", "BOUNCE")
|
||||
|
||||
@@ -23,6 +23,9 @@ import java.awt.Color
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
|
||||
// TODO: completely redesign
|
||||
|
||||
|
||||
// ManageEmitters
|
||||
// <create / remove / config / list>
|
||||
// create
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.joml.Vector3f
|
||||
* @param minVel The minimum speed a particle must maintain. Particles slower than this value are stopped. Values <= 0 disable this check.
|
||||
* @param lifeTime Specifies the range for particle lifetime, in ticks. Values below 1 prevent particles from spawning.
|
||||
* @param rotVelCurve A curve defining how rotational velocity evolves during the particle's lifetime. Multiplies the `rotVel` values.
|
||||
* @param sizeCurve A curve defining how the particle's size evolves over its lifetime. Multiplies the `initScale` values.
|
||||
* @param scaleCurve A curve defining how the particle's size evolves over its lifetime. Multiplies the `initScale` values.
|
||||
* @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 (
|
||||
@@ -48,9 +48,9 @@ data class EmitterParams (
|
||||
var constVel: Vector3f = Vector3f(0.0f, -0.01f, 0.0f),
|
||||
var drag: Float = 0.075f,
|
||||
var minVel: Float = 0.0f,
|
||||
var lifeTime: ParamClasses.PairVec2i = ParamClasses.PairVec2i(0, 0, 1, 1),
|
||||
var lifeTime: ParamClasses.PairInt = ParamClasses.PairInt(25, 40),
|
||||
var rotVelCurve: ParamClasses.LerpVal = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Sqrt),
|
||||
var sizeCurve: ParamClasses.LerpVal = ParamClasses.LerpVal.LerpUniform(1.0f, 0.5f, LerpCurves.Linear),
|
||||
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),
|
||||
)
|
||||
{
|
||||
|
||||
@@ -62,6 +62,12 @@ class ParamClasses {
|
||||
)
|
||||
}
|
||||
}
|
||||
class PairInt (
|
||||
private val min: Int = 0,
|
||||
private val max: Int = 1,
|
||||
) {
|
||||
fun randomize() : Int { return randomIntBetween(min, max) }
|
||||
}
|
||||
sealed class LerpVal {
|
||||
class LerpVec3f(
|
||||
private val fromX: Float = 0.0f,
|
||||
@@ -106,5 +112,16 @@ class ParamClasses {
|
||||
return com.bytedice.bde_particles.lerp(from, to, t) * curve.function(t)
|
||||
}
|
||||
}
|
||||
|
||||
fun lerpToVector3f(t: Float) : Vector3f {
|
||||
when (this) {
|
||||
is LerpVec3f -> return this.lerp(t)
|
||||
is MultiLerpVec3f -> return this.lerp(t)
|
||||
is LerpUniform -> {
|
||||
val x = this.lerp(t)
|
||||
return Vector3f(x, x, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.bytedice.bde_particles.particles
|
||||
import com.bytedice.bde_particles.*
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import org.joml.Vector2f
|
||||
import org.joml.Vector3f
|
||||
import org.joml.Vector4f
|
||||
import kotlin.math.*
|
||||
@@ -15,14 +16,20 @@ class Particle(private val emitterParams: EmitterParams) {
|
||||
private val initOffset = Vector3f(-0.5f, -0.5f, -0.5f)
|
||||
private var offset = Vector3f(0.0f, 0.0f, 0.0f)
|
||||
private var pos = Vec3d(0.0, 0.0, 0.0)
|
||||
private var entityRot = Vector2f(0.0f, 0.0f)
|
||||
|
||||
private var rot = randomBetweenVector3f(particleParams.rotRandom.first, particleParams.rotRandom.second)
|
||||
private val rotVel = randomBetweenVector3f(particleParams.rotVelRandom.first, particleParams.rotVelRandom.second)
|
||||
private var vel = randomBetweenVector3f(particleParams.velRandom.first, particleParams.velRandom.second)
|
||||
private var scale = randomBetweenVector3f(particleParams.sizeRandom.first, particleParams.sizeRandom.second)
|
||||
private var rot = emitterParams.initRot.randomize()
|
||||
private val rotVel = emitterParams.rotVel.randomize()
|
||||
private var vel = emitterParams.initVel.randomize()
|
||||
|
||||
private val scaleAny: Any = when (emitterParams.initScale) {
|
||||
is ParamClasses.RandScale.Uniform -> { (emitterParams.initScale as ParamClasses.RandScale.Uniform).randomize() }
|
||||
is ParamClasses.RandScale.NonUniform -> { (emitterParams.initScale as ParamClasses.RandScale.NonUniform).randomize() }
|
||||
}
|
||||
private var scale = if (scaleAny is Vector3f) { scaleAny } else { Vector3f(scaleAny as Float, scaleAny, scaleAny) }
|
||||
|
||||
private var blockDisplay: DisplayEntity? = null
|
||||
private var lifeTime = randomIntBetween(particleParams.lifeTime.first, particleParams.lifeTime.second)
|
||||
private var lifeTime = emitterParams.lifeTime.randomize()
|
||||
|
||||
var isDead = false
|
||||
private var timeAlive = 0
|
||||
@@ -30,17 +37,11 @@ class Particle(private val emitterParams: EmitterParams) {
|
||||
private var isInit = false
|
||||
|
||||
|
||||
fun init(pos: Vec3d) {
|
||||
fun init(pos: Vec3d, rot: Vector2f) { // TODO: replace initOffset with originOffset param
|
||||
this.pos = pos
|
||||
this.entityRot = rot
|
||||
|
||||
if ( particleParams.uniformSize ) {
|
||||
val randomUniform = randomFloatBetween(particleParams.sizeRandom.first.x, particleParams.sizeRandom.second.x)
|
||||
scale.x = randomUniform
|
||||
scale.y = randomUniform
|
||||
scale.z = randomUniform
|
||||
}
|
||||
|
||||
val shape = particleParams.shape
|
||||
val shape = emitterParams.shape
|
||||
val newSpawnPos: Vector3f
|
||||
|
||||
when (shape) {
|
||||
@@ -53,11 +54,12 @@ class Particle(private val emitterParams: EmitterParams) {
|
||||
|
||||
offset = newSpawnPos
|
||||
|
||||
val (quatRot, newOffset) = calcTransformOffset(rot, initOffset, scale)
|
||||
val (quatRot, newOffset) = calcTransformOffset(this.rot, initOffset, scale)
|
||||
|
||||
val properties = DisplayEntityProperties(
|
||||
pos = this.pos,
|
||||
blockType = particleParams.blockCurve[0],
|
||||
rot = rot,
|
||||
blockType = emitterParams.blockCurve.first[0], // TODO: curve this
|
||||
translation = newOffset.add(offset),
|
||||
leftRotation = quatRot,
|
||||
scale = scale,
|
||||
@@ -104,66 +106,6 @@ class Particle(private val emitterParams: EmitterParams) {
|
||||
|
||||
private fun calcNewProperties() : DisplayEntityProperties {
|
||||
|
||||
fun calcBlockCurve(timeAliveClamped: Float) : String {
|
||||
val newBlockIdx = round(lerp(0.0f, particleParams.blockCurve.lastIndex.toFloat(), timeAliveClamped)).toInt()
|
||||
return particleParams.blockCurve[newBlockIdx]
|
||||
}
|
||||
|
||||
fun sphereSdfVel(forceField: ForceField) : Vector3f {
|
||||
if (forceField.shape !is ForceFieldShape.Sphere) { return Vector3f(0.0f, 0.0f, 0.0f) }
|
||||
val shape = forceField.shape
|
||||
|
||||
val sdfVal = sdfSphere(forceField.pos, shape.radius, offset)
|
||||
val normalizedSdf = normalizeSdf(sdfVal, shape.radius)
|
||||
val velDir = Vector3f(offset).sub(forceField.pos).normalize()
|
||||
val velMul = if (sdfVal > 0) { 0.0f }
|
||||
else { lerp(shape.force.second, shape.force.second, 1 - normalizedSdf) }
|
||||
|
||||
return velDir.mul(velMul)
|
||||
}
|
||||
|
||||
fun cubeSdfVel(forceField: ForceField) : Vector3f {
|
||||
if (forceField.shape !is ForceFieldShape.Cube) { return Vector3f(0.0f, 0.0f, 0.0f) }
|
||||
val shape = forceField.shape
|
||||
|
||||
val sdfVal = sdfCube(forceField.pos, shape.size, offset)
|
||||
val velDir = if (sdfVal < 0) { shape.forceDir }
|
||||
else { Vector3f(0.0f, 0.0f, 0.0f) }
|
||||
|
||||
return velDir
|
||||
}
|
||||
|
||||
fun calcRot(timeAliveClamped: Float) : Vector3f {
|
||||
val newRot = Vector3f(rot)
|
||||
val newVel = Vector3f(rotVel)
|
||||
val rotCurve = particleParams.rotVelCurve
|
||||
|
||||
newVel.mul(interpolateCurve(rotCurve.first, rotCurve.second, timeAliveClamped, rotCurve.third))
|
||||
newRot.add(newVel)
|
||||
return newRot
|
||||
}
|
||||
|
||||
fun calcOffset() : Pair<Vector3f, Vector3f> {
|
||||
var vel = Vector3f(vel)
|
||||
vel = vel.add(particleParams.gravity)
|
||||
vel = vel.mul(1.0f - particleParams.drag)
|
||||
|
||||
if (abs(vel.x) < particleParams.minVel) { vel.x = 0.0f }
|
||||
if (abs(vel.y) < particleParams.minVel) { vel.y = 0.0f }
|
||||
if (abs(vel.z) < particleParams.minVel) { vel.z = 0.0f }
|
||||
|
||||
var newOffset = Vector3f(offset)
|
||||
newOffset = newOffset.add(vel)
|
||||
return Pair(vel, newOffset)
|
||||
}
|
||||
|
||||
fun calcSize(timeAliveClamped: Float) : Vector3f {
|
||||
val scale = Vector3f(scale)
|
||||
val sizeCurve = particleParams.sizeCurve
|
||||
scale.mul(interpolateCurve(sizeCurve.first, sizeCurve.second, timeAliveClamped, sizeCurve.third))
|
||||
return scale
|
||||
}
|
||||
|
||||
val timeAliveClamped = (timeAlive.toFloat() / lifeTime.toFloat()).coerceIn(0.0f, 1.0f)
|
||||
|
||||
val newBlock = calcBlockCurve(timeAliveClamped)
|
||||
@@ -175,7 +117,7 @@ class Particle(private val emitterParams: EmitterParams) {
|
||||
offset = newOffset
|
||||
rot = newRot
|
||||
|
||||
for (forceField in particleParams.forceFields) {
|
||||
for (forceField in emitterParams.forceFields) {
|
||||
if (forceField.shape is ForceFieldShape.Sphere) { vel.add(sphereSdfVel(forceField)) }
|
||||
else if (forceField.shape is ForceFieldShape.Cube) { vel.add(cubeSdfVel(forceField)) }
|
||||
}
|
||||
@@ -196,7 +138,72 @@ class Particle(private val emitterParams: EmitterParams) {
|
||||
}
|
||||
|
||||
|
||||
private fun calcBlockCurve(t: Float) : String {
|
||||
val newBlockIdx = round(lerp(0.0f, emitterParams.blockCurve.first.lastIndex.toFloat(), t)).toInt()
|
||||
return emitterParams.blockCurve.first[newBlockIdx]
|
||||
}
|
||||
|
||||
|
||||
private fun sphereSdfVel(forceField: ForceField) : Vector3f {
|
||||
if (forceField.shape !is ForceFieldShape.Sphere) { return Vector3f(0.0f, 0.0f, 0.0f) }
|
||||
val shape = forceField.shape
|
||||
|
||||
val sdfVal = sdfSphere(forceField.pos, shape.radius, offset)
|
||||
val normalizedSdf = normalizeSdf(sdfVal, shape.radius)
|
||||
val velDir = Vector3f(offset).sub(forceField.pos).normalize()
|
||||
val velMul = if (sdfVal > 0) { 0.0f }
|
||||
else { lerp(shape.force.second, shape.force.second, 1 - normalizedSdf) }
|
||||
|
||||
return velDir.mul(velMul)
|
||||
}
|
||||
|
||||
|
||||
private fun cubeSdfVel(forceField: ForceField) : Vector3f {
|
||||
if (forceField.shape !is ForceFieldShape.Cube) { return Vector3f(0.0f, 0.0f, 0.0f) }
|
||||
val shape = forceField.shape
|
||||
|
||||
val sdfVal = sdfCube(forceField.pos, shape.size, offset)
|
||||
val velDir = if (sdfVal < 0) { shape.dir.mul(shape.force) }
|
||||
else { Vector3f(0.0f, 0.0f, 0.0f) }
|
||||
|
||||
return velDir
|
||||
}
|
||||
// TODO: cone & cylinder SDF
|
||||
|
||||
|
||||
private fun calcRot(t: Float) : Vector3f {
|
||||
val newRot = Vector3f(rot)
|
||||
val newVel = Vector3f(rotVel)
|
||||
|
||||
newVel.mul(emitterParams.rotVelCurve.lerpToVector3f(t))
|
||||
newRot.add(newVel)
|
||||
return newRot
|
||||
}
|
||||
|
||||
|
||||
private fun calcOffset() : Pair<Vector3f, Vector3f> {
|
||||
var vel = Vector3f(vel)
|
||||
vel = vel.add(emitterParams.constVel)
|
||||
vel = vel.mul(1.0f - emitterParams.drag)
|
||||
|
||||
if (abs(vel.x) < emitterParams.minVel) { vel.x = 0.0f }
|
||||
if (abs(vel.y) < emitterParams.minVel) { vel.y = 0.0f }
|
||||
if (abs(vel.z) < emitterParams.minVel) { vel.z = 0.0f }
|
||||
|
||||
var newOffset = Vector3f(offset)
|
||||
newOffset = newOffset.add(vel)
|
||||
return Pair(vel, newOffset)
|
||||
}
|
||||
|
||||
|
||||
private fun calcSize(t: Float) : Vector3f {
|
||||
val newScale = Vector3f(scale)
|
||||
newScale.mul(emitterParams.scaleCurve.lerpToVector3f(t))
|
||||
return scale
|
||||
}
|
||||
|
||||
|
||||
fun kill() {
|
||||
blockDisplay?.kill()
|
||||
if (!isDead) { blockDisplay?.kill() }
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ fun updateSingleEmitterParam(id: String, paramName: String, paramValue: Any) : B
|
||||
}
|
||||
|
||||
|
||||
fun updateSingleParticleParam(emitterId: String, paramName: String, paramValue: Any) : Boolean {
|
||||
fun updateSingleParticleParam(emitterId: String, paramName: String, paramValue: Any) : Boolean { // TODO: map to new params
|
||||
val emitter = getEmitterParams(emitterId) ?: return false
|
||||
val particle = emitter.particle
|
||||
|
||||
@@ -62,7 +62,7 @@ fun updateSingleParticleParam(emitterId: String, paramName: String, paramValue:
|
||||
}
|
||||
|
||||
|
||||
fun updateSingleEmitterParam(params: EmitterParams, paramName: String, paramValue: Any) : Pair<EmitterParams, Boolean> {
|
||||
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
|
||||
@@ -89,7 +89,7 @@ fun updateSingleEmitterParam(params: EmitterParams, paramName: String, paramValu
|
||||
}
|
||||
|
||||
|
||||
fun updateSingleParticleParam(params: ParticleParams, paramName: String, paramValue: Any) : Pair<ParticleParams, Boolean> {
|
||||
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>
|
||||
|
||||
@@ -18,17 +18,17 @@ sealed class ForceFieldShape {
|
||||
) : ForceFieldShape()
|
||||
data class Cube(
|
||||
val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f),
|
||||
val dir: Vector3f = Vector3f(0.0f, 0.0f, -1.0f),
|
||||
val force: Pair<Float, Float> = Pair(0.0f, 0.02f)
|
||||
val dir: Vector3f = Vector3f(0.0f, 1.0f, 0.0f),
|
||||
val force: Float = 0.02f
|
||||
) : ForceFieldShape()
|
||||
data class Cone(
|
||||
val size: Vector2f = Vector2f(1.0f, 1.0f),
|
||||
val dir: Vector3f = Vector3f(0.0f, 0.0f, -1.0f),
|
||||
val dir: Vector3f = Vector3f(0.0f, 1.0f, 0.0f),
|
||||
val force: Pair<Float, Float> = Pair(0.0f, 0.02f)
|
||||
)
|
||||
data class Cylinder(
|
||||
val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f),
|
||||
val dir: Vector3f = Vector3f(0.0f, 0.0f, -1.0f),
|
||||
val force: Pair<Float, Float> = Pair(0.0f, 0.02f)
|
||||
val dir: Vector3f = Vector3f(0.0f, 1.0f, 0.0f),
|
||||
val force: Float = 0.02f
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user