reworked a bunch of stuff. Contains errors
This commit is contained in:
@@ -27,6 +27,37 @@ import net.minecraft.world.World
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// Allowing the use of regular Minecraft particles instead of just BDEs.
|
||||||
|
// Better command auto-completion. (and change names of args)
|
||||||
|
// force field "config" option
|
||||||
|
// 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)
|
||||||
|
// velRot (bool)
|
||||||
|
// rotates the particle to face the velocity
|
||||||
|
// spawnChance (Float)
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// Global max particles variable.
|
||||||
|
// gamerule max particles
|
||||||
|
|
||||||
|
// Emitter groups (multiple emitters for EmitterTool)
|
||||||
|
// Private functions/classes
|
||||||
|
|
||||||
|
|
||||||
var ALL_PARTICLE_EMITTERS: Array<ParticleEmitter> = emptyArray()
|
var ALL_PARTICLE_EMITTERS: Array<ParticleEmitter> = emptyArray()
|
||||||
val sessionUuid: UUID = UUID.randomUUID()
|
val sessionUuid: UUID = UUID.randomUUID()
|
||||||
|
|
||||||
|
|||||||
@@ -12,18 +12,18 @@ import kotlin.math.*
|
|||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
class InterpolationCurves(val function: (Float) -> Float) {
|
class LerpCurves(val function: (Float) -> Float) {
|
||||||
companion object {
|
companion object {
|
||||||
val LINEAR = InterpolationCurves { y -> y }
|
val Linear = LerpCurves { y -> y }
|
||||||
val SQRT = InterpolationCurves { y -> sqrt(y) }
|
val Sqrt = LerpCurves { y -> sqrt(y) }
|
||||||
val EXPONENT = InterpolationCurves { y -> y.pow(2.0f) }
|
val Exponent = LerpCurves { y -> y.pow(2.0f) }
|
||||||
val CUBIC = InterpolationCurves { y -> y.pow(3.0f) }
|
val Cubic = LerpCurves { y -> y.pow(3.0f) }
|
||||||
val SINE = InterpolationCurves { y -> sin(y * PI.toFloat() / 2) }
|
val Sine = LerpCurves { y -> sin(y * PI.toFloat() / 2) }
|
||||||
val COSINE = InterpolationCurves { y -> 1 - cos(y * PI.toFloat() / 2) }
|
val Cosine = LerpCurves { y -> 1 - cos(y * PI.toFloat() / 2) }
|
||||||
val INVERSE = InterpolationCurves { y -> 1 - y }
|
val Inverse = LerpCurves { y -> 1 - y }
|
||||||
val LOG = InterpolationCurves { y -> if (y > 0) ln(y + 1) else 0f }
|
val Log = LerpCurves { y -> if (y > 0) ln(y + 1) else 0f }
|
||||||
val EXP = InterpolationCurves { y -> exp(y) - 1 }
|
val Exp = LerpCurves { y -> exp(y) - 1 }
|
||||||
val BOUNCE = InterpolationCurves { y ->
|
val Bounce = LerpCurves { y ->
|
||||||
val n1 = 7.5625f
|
val n1 = 7.5625f
|
||||||
val d1 = 2.75f
|
val d1 = 2.75f
|
||||||
when {
|
when {
|
||||||
@@ -43,7 +43,7 @@ class InterpolationCurves(val function: (Float) -> Float) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun custom(equation: (Float) -> Float) = InterpolationCurves(equation)
|
fun custom(equation: (Float) -> Float) = LerpCurves(equation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ fun lerp(x: Float, y: Float, t: Float) : Float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun interpolateCurve(start: Vector3f, end: Vector3f, t: Float, curve: InterpolationCurves): Vector3f {
|
fun interpolateCurve(start: Vector3f, end: Vector3f, t: Float, curve: LerpCurves): Vector3f {
|
||||||
val clampedT = t.coerceIn(0.0f, 1.0f)
|
val clampedT = t.coerceIn(0.0f, 1.0f)
|
||||||
|
|
||||||
val curvedT = curve.function(clampedT)
|
val curvedT = curve.function(clampedT)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.bytedice.bde_particles.commands
|
package com.bytedice.bde_particles.commands
|
||||||
|
|
||||||
import com.bytedice.bde_particles.InterpolationCurves
|
import com.bytedice.bde_particles.LerpCurves
|
||||||
import com.bytedice.bde_particles.particles.*
|
import com.bytedice.bde_particles.particles.*
|
||||||
import com.mojang.brigadier.Command
|
import com.mojang.brigadier.Command
|
||||||
import com.mojang.brigadier.arguments.BoolArgumentType
|
import com.mojang.brigadier.arguments.BoolArgumentType
|
||||||
@@ -127,7 +127,7 @@ class ArgConfigParticleKeys {
|
|||||||
.then(CommandManager.argument("Radius", FloatArgumentType.floatArg())
|
.then(CommandManager.argument("Radius", FloatArgumentType.floatArg())
|
||||||
.executes { context ->
|
.executes { context ->
|
||||||
val radius = FloatArgumentType.getFloat(context, "Radius")
|
val radius = FloatArgumentType.getFloat(context, "Radius")
|
||||||
val feedback = updateParticleParam(context, "shape", SpawningShape.CIRCLE(radius))
|
val feedback = updateParticleParam(context, "shape", SpawningShape.Circle(radius))
|
||||||
context.source.sendFeedback( { feedback }, false)
|
context.source.sendFeedback( { feedback }, false)
|
||||||
Command.SINGLE_SUCCESS
|
Command.SINGLE_SUCCESS
|
||||||
}
|
}
|
||||||
@@ -139,7 +139,7 @@ class ArgConfigParticleKeys {
|
|||||||
.executes { context ->
|
.executes { context ->
|
||||||
val w = FloatArgumentType.getFloat(context, "Width")
|
val w = FloatArgumentType.getFloat(context, "Width")
|
||||||
val h = FloatArgumentType.getFloat(context, "Height")
|
val h = FloatArgumentType.getFloat(context, "Height")
|
||||||
val feedback = updateParticleParam(context, "shape", SpawningShape.RECT(Vector2f(w, h)))
|
val feedback = updateParticleParam(context, "shape", SpawningShape.Rect(Vector2f(w, h)))
|
||||||
context.source.sendFeedback( { feedback }, false)
|
context.source.sendFeedback( { feedback }, false)
|
||||||
Command.SINGLE_SUCCESS
|
Command.SINGLE_SUCCESS
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ class ArgConfigParticleKeys {
|
|||||||
val x = FloatArgumentType.getFloat(context, "X")
|
val x = FloatArgumentType.getFloat(context, "X")
|
||||||
val y = FloatArgumentType.getFloat(context, "Y")
|
val y = FloatArgumentType.getFloat(context, "Y")
|
||||||
val z = FloatArgumentType.getFloat(context, "Z")
|
val z = FloatArgumentType.getFloat(context, "Z")
|
||||||
val feedback = updateParticleParam(context, "shape", SpawningShape.CUBE(Vector3f(x, y, z)))
|
val feedback = updateParticleParam(context, "shape", SpawningShape.Cube(Vector3f(x, y, z)))
|
||||||
context.source.sendFeedback( { feedback }, false)
|
context.source.sendFeedback( { feedback }, false)
|
||||||
Command.SINGLE_SUCCESS
|
Command.SINGLE_SUCCESS
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ class ArgConfigParticleKeys {
|
|||||||
.then(CommandManager.argument("Radius", FloatArgumentType.floatArg())
|
.then(CommandManager.argument("Radius", FloatArgumentType.floatArg())
|
||||||
.executes { context ->
|
.executes { context ->
|
||||||
val radius = FloatArgumentType.getFloat(context, "Radius")
|
val radius = FloatArgumentType.getFloat(context, "Radius")
|
||||||
val feedback = updateParticleParam(context, "shape", SpawningShape.SPHERE(radius))
|
val feedback = updateParticleParam(context, "shape", SpawningShape.Sphere(radius))
|
||||||
context.source.sendFeedback( { feedback }, false)
|
context.source.sendFeedback( { feedback }, false)
|
||||||
Command.SINGLE_SUCCESS
|
Command.SINGLE_SUCCESS
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ class ArgConfigParticleKeys {
|
|||||||
)
|
)
|
||||||
.then(CommandManager.literal("point")
|
.then(CommandManager.literal("point")
|
||||||
.executes { context ->
|
.executes { context ->
|
||||||
val feedback = updateParticleParam(context, "shape", SpawningShape.POINT)
|
val feedback = updateParticleParam(context, "shape", SpawningShape.Point)
|
||||||
context.source.sendFeedback( { feedback }, false)
|
context.source.sendFeedback( { feedback }, false)
|
||||||
Command.SINGLE_SUCCESS
|
Command.SINGLE_SUCCESS
|
||||||
}
|
}
|
||||||
@@ -415,19 +415,19 @@ class ArgConfigParticleKeys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getCurveByString(str: String) : InterpolationCurves {
|
fun getCurveByString(str: String) : LerpCurves {
|
||||||
return when (str) {
|
return when (str) {
|
||||||
"LINEAR" -> InterpolationCurves.LINEAR
|
"LINEAR" -> LerpCurves.Linear
|
||||||
"SQRT" -> InterpolationCurves.SQRT
|
"SQRT" -> LerpCurves.Sqrt
|
||||||
"EXPONENT" -> InterpolationCurves.EXPONENT
|
"EXPONENT" -> LerpCurves.Exponent
|
||||||
"CUBIC" -> InterpolationCurves.CUBIC
|
"CUBIC" -> LerpCurves.Cubic
|
||||||
"SINE" -> InterpolationCurves.SINE
|
"SINE" -> LerpCurves.Sine
|
||||||
"COSINE" -> InterpolationCurves.COSINE
|
"COSINE" -> LerpCurves.Cosine
|
||||||
"INVERSE" -> InterpolationCurves.INVERSE
|
"INVERSE" -> LerpCurves.Inverse
|
||||||
"LOG" -> InterpolationCurves.LOG
|
"LOG" -> LerpCurves.Log
|
||||||
"EXP" -> InterpolationCurves.EXP
|
"EXP" -> LerpCurves.Exp
|
||||||
"BOUNCE" -> InterpolationCurves.BOUNCE
|
"BOUNCE" -> LerpCurves.Bounce
|
||||||
else -> InterpolationCurves.LINEAR
|
else -> LerpCurves.Linear
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,7 +538,7 @@ fun forceFieldAddSphereExec(context: CommandContext<ServerCommandSource>) : Int
|
|||||||
val minForce = FloatArgumentType.getFloat(context, "Min Force")
|
val minForce = FloatArgumentType.getFloat(context, "Min Force")
|
||||||
val maxForce = FloatArgumentType.getFloat(context, "Max Force")
|
val maxForce = FloatArgumentType.getFloat(context, "Max Force")
|
||||||
|
|
||||||
val shape = ForceFieldShape.SPHERE(radius, Pair(minForce, maxForce))
|
val shape = ForceFieldShape.Sphere(radius, Pair(minForce, maxForce))
|
||||||
val forceField = forceFieldGenericParams(context, shape)
|
val forceField = forceFieldGenericParams(context, shape)
|
||||||
|
|
||||||
val currentParams = getEmitterParams(emitterIdVal)
|
val currentParams = getEmitterParams(emitterIdVal)
|
||||||
@@ -567,7 +567,7 @@ fun forceFieldAddCubeExec(context: CommandContext<ServerCommandSource>) : Int {
|
|||||||
val zForce = FloatArgumentType.getFloat(context, "Z Force")
|
val zForce = FloatArgumentType.getFloat(context, "Z Force")
|
||||||
val emitterIdVal = StringArgumentType.getString(context, "Registered Emitter ID")
|
val emitterIdVal = StringArgumentType.getString(context, "Registered Emitter ID")
|
||||||
|
|
||||||
val shape = ForceFieldShape.CUBE(Vector3f(xSize, ySize, zSize), Vector3f(xForce, yForce, zForce))
|
val shape = ForceFieldShape.Cube(Vector3f(xSize, ySize, zSize), Vector3f(xForce, yForce, zForce))
|
||||||
val forceField = forceFieldGenericParams(context, shape)
|
val forceField = forceFieldGenericParams(context, shape)
|
||||||
|
|
||||||
val currentParams = getEmitterParams(emitterIdVal)
|
val currentParams = getEmitterParams(emitterIdVal)
|
||||||
|
|||||||
@@ -1,42 +1,60 @@
|
|||||||
package com.bytedice.bde_particles.particles
|
package com.bytedice.bde_particles.particles
|
||||||
|
|
||||||
|
import com.bytedice.bde_particles.LerpCurves
|
||||||
|
import org.joml.Vector3f
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EmitterParams defines the parameters for controlling how particles are emitted,
|
* EmitterParams defines the parameters for controlling how particles are emitted,
|
||||||
* including settings for looping, spawn frequency, and maximum particle count.
|
* including settings for looping, spawn frequency, and maximum particle count.
|
||||||
*
|
*
|
||||||
* @param maxCount The maximum number of particles that can exist. If set to 0 or below, no particles will spawn.
|
* @param maxCount The maximum number of particles that can exist at any time. If set to 0 or below, no particles will spawn.
|
||||||
* @param spawnsPerTick The number of particles spawned per tick. If set to 0 or below, no particles will spawn.
|
* @param spawnRate The number of particles to spawn each tick. If set to 0 or below, no particles will spawn.
|
||||||
* @param loopDur The duration for which the loop runs, in ticks. A value 0 or below means the loop is infinite, and `loopDelay` and `loopCount` will be ignored.
|
* @param spawnChance The chance for a particle to spawn. 0.5 means a particle has a 50% chance of spawning. Values are between 0.0 and 1.0.
|
||||||
* @param loopDelay The delay between each loop cycle, in ticks. Negative values are treated as 0, meaning no delay.
|
* @param loopDur The duration, in ticks, that each emission loop lasts. A value of 0 or below makes the loop infinite, ignoring `loopDelay` and `loopCount`.
|
||||||
* @param loopCount The number of times the loop will repeat. 0 means it will shoot a single burst of particles. A value below 0 means it will repeat indefinitely.
|
* @param loopDelay The delay, in ticks, between consecutive loops. Negative values are treated as 0 (no delay).
|
||||||
* @param particle The particle params of the particle that will spawn.
|
* @param loopCount The number of times the loop repeats. A value of 0 results in a single burst of particles. Values below 0 make the loop repeat indefinitely.
|
||||||
|
* @param shape The spawning shape for the particles, such as `SpawningShape.Sphere()`.
|
||||||
|
* @param initRot Specifies the initial random rotation range for the particles, in degrees, for the X, Y, and Z axes.
|
||||||
|
* @param rotVel Specifies the random range for rotational velocity, in degrees per tick, for the X, Y, and Z axes.
|
||||||
|
* @param rotTowardVel If true, particles will face the direction of velocity. It uses `initRot` as an offset rotation and ignores `rotVel`.
|
||||||
|
* @param initVel Specifies the random range for the initial velocity, in units per tick, for the X, Y, and Z axes.
|
||||||
|
* @param initScale Defines the random range for the initial particle size.
|
||||||
|
* @param scaleTowardVel If true, particles will scale to the direction of velocity.
|
||||||
|
* @param forceFields An array of force fields applied to particles, affecting their motion during their lifetime.
|
||||||
|
* @param constVel A constant velocity vector applied to particles each tick, useful for effects like gravity.
|
||||||
|
* @param drag A drag coefficient that slows down particle velocity over time. Calculated as `velocity * (1.0 - drag)`.
|
||||||
|
* @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 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 (
|
data class EmitterParams (
|
||||||
var maxCount: Int = 200,
|
var maxCount: Int = 200,
|
||||||
var spawnsPerTick: Int = 1,
|
var spawnRate: Int = 1,
|
||||||
var loopDur: Int = 25,
|
var spawnChance: Float = 1.0f,
|
||||||
var loopDelay: Int = 0,
|
var loopDur: Int = 25,
|
||||||
var loopCount: Int = 0,
|
var loopDelay: Int = 0,
|
||||||
var particle: ParticleParams = ParticleParams.DEFAULT,
|
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.PairVec2i = ParamClasses.PairVec2i(0, 0, 1, 1),
|
||||||
|
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 blockCurve: Pair<Array<String>, LerpCurves> = Pair(arrayOf("minecraft:purple_concrete", "minecraft:purple_stained_glass"), LerpCurves.Sqrt),
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
companion object Presets {
|
companion object Presets {
|
||||||
val DEFAULT = EmitterParams()
|
val DEFAULT = EmitterParams()
|
||||||
val FIRE_GEYSER = EmitterParams(
|
|
||||||
200,
|
|
||||||
1,
|
|
||||||
25,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
ParticleParams.FIRE_GEYSER
|
|
||||||
)
|
|
||||||
val RING_EXPLOSION = EmitterParams(
|
|
||||||
200,
|
|
||||||
150,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
ParticleParams.RING_EXPLOSION
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,5 +5,5 @@ import org.joml.Vector3f
|
|||||||
data class ForceField (
|
data class ForceField (
|
||||||
val name: String = "DEFAULT",
|
val name: String = "DEFAULT",
|
||||||
val pos: Vector3f = Vector3f(0.0f, 5.0f, 0.0f),
|
val pos: Vector3f = Vector3f(0.0f, 5.0f, 0.0f),
|
||||||
val shape: ForceFieldShape = ForceFieldShape.SPHERE()
|
val shape: ForceFieldShape = ForceFieldShape.Sphere()
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package com.bytedice.bde_particles.particles
|
||||||
|
|
||||||
|
import com.bytedice.bde_particles.LerpCurves
|
||||||
|
import com.bytedice.bde_particles.randomFloatBetween
|
||||||
|
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 {
|
||||||
|
class Uniform (
|
||||||
|
private val min: Float = 0.0f,
|
||||||
|
private val max: Float = 1.0f,
|
||||||
|
) : RandScale() {
|
||||||
|
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() {
|
||||||
|
fun randomize(): Vector3f {
|
||||||
|
return Vector3f(
|
||||||
|
randomFloatBetween(minX, maxX),
|
||||||
|
randomFloatBetween(minY, maxY),
|
||||||
|
randomFloatBetween(minZ, maxZ),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
) : LerpVal() {
|
||||||
|
fun lerp(t: Float): Vector3f {
|
||||||
|
val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curve.function(t)
|
||||||
|
val y = com.bytedice.bde_particles.lerp(fromY, toY, t) * curve.function(t)
|
||||||
|
val z = com.bytedice.bde_particles.lerp(fromZ, toZ, t) * curve.function(t)
|
||||||
|
return Vector3f(x, y, z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
|
) : LerpVal() {
|
||||||
|
fun lerp(t: Float): Vector3f {
|
||||||
|
val x = com.bytedice.bde_particles.lerp(fromX, toX, t) * curveX.function(t)
|
||||||
|
val y = com.bytedice.bde_particles.lerp(fromY, toY, t) * curveY.function(t)
|
||||||
|
val z = com.bytedice.bde_particles.lerp(fromZ, toZ, t) * curveZ.function(t)
|
||||||
|
return Vector3f(x, y, z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class LerpUniform(
|
||||||
|
private val from: Float = 0.0f,
|
||||||
|
private val to: Float = 1.0f,
|
||||||
|
private val curve: LerpCurves = LerpCurves.Linear,
|
||||||
|
) : LerpVal() {
|
||||||
|
fun lerp(t: Float): Float {
|
||||||
|
return com.bytedice.bde_particles.lerp(from, to, t) * curve.function(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ import kotlin.math.*
|
|||||||
// TODO: consider moving most params to emitter (such as shape, and forceFields) to store less data
|
// TODO: consider moving most params to emitter (such as shape, and forceFields) to store less data
|
||||||
|
|
||||||
|
|
||||||
class Particle(private val particleParams: ParticleParams) {
|
class Particle(private val emitterParams: EmitterParams) {
|
||||||
private val initOffset = Vector3f(-0.5f, -0.5f, -0.5f)
|
private val initOffset = Vector3f(-0.5f, -0.5f, -0.5f)
|
||||||
private var offset = Vector3f(0.0f, 0.0f, 0.0f)
|
private var offset = Vector3f(0.0f, 0.0f, 0.0f)
|
||||||
private var pos = Vec3d(0.0, 0.0, 0.0)
|
private var pos = Vec3d(0.0, 0.0, 0.0)
|
||||||
@@ -44,11 +44,11 @@ class Particle(private val particleParams: ParticleParams) {
|
|||||||
val newSpawnPos: Vector3f
|
val newSpawnPos: Vector3f
|
||||||
|
|
||||||
when (shape) {
|
when (shape) {
|
||||||
is SpawningShape.CIRCLE -> { val posInCircle = randomInCircle(shape.radius); newSpawnPos = Vector3f(posInCircle.x, 0.0f, posInCircle.y) }
|
is SpawningShape.Circle -> { val posInCircle = randomInCircle(shape.radius); newSpawnPos = Vector3f(posInCircle.x, 0.0f, posInCircle.y) }
|
||||||
is SpawningShape.SPHERE -> { newSpawnPos = randomInSphere(shape.radius) }
|
is SpawningShape.Sphere -> { newSpawnPos = randomInSphere(shape.radius) }
|
||||||
is SpawningShape.RECT -> { val posInRect = randomInRect(shape.size); newSpawnPos = Vector3f(posInRect.x, 0.0f, posInRect.y) }
|
is SpawningShape.Rect -> { val posInRect = randomInRect(shape.size); newSpawnPos = Vector3f(posInRect.x, 0.0f, posInRect.y) }
|
||||||
is SpawningShape.CUBE -> { newSpawnPos = randomInCube(shape.size) }
|
is SpawningShape.Cube -> { newSpawnPos = randomInCube(shape.size) }
|
||||||
is SpawningShape.POINT -> { newSpawnPos = Vector3f(0.0f, 0.0f, 0.0f) }
|
is SpawningShape.Point -> { newSpawnPos = Vector3f(0.0f, 0.0f, 0.0f) }
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = newSpawnPos
|
offset = newSpawnPos
|
||||||
@@ -110,7 +110,7 @@ class Particle(private val particleParams: ParticleParams) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun sphereSdfVel(forceField: ForceField) : Vector3f {
|
fun sphereSdfVel(forceField: ForceField) : Vector3f {
|
||||||
if (forceField.shape !is ForceFieldShape.SPHERE) { return Vector3f(0.0f, 0.0f, 0.0f) }
|
if (forceField.shape !is ForceFieldShape.Sphere) { return Vector3f(0.0f, 0.0f, 0.0f) }
|
||||||
val shape = forceField.shape
|
val shape = forceField.shape
|
||||||
|
|
||||||
val sdfVal = sdfSphere(forceField.pos, shape.radius, offset)
|
val sdfVal = sdfSphere(forceField.pos, shape.radius, offset)
|
||||||
@@ -123,7 +123,7 @@ class Particle(private val particleParams: ParticleParams) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun cubeSdfVel(forceField: ForceField) : Vector3f {
|
fun cubeSdfVel(forceField: ForceField) : Vector3f {
|
||||||
if (forceField.shape !is ForceFieldShape.CUBE) { return Vector3f(0.0f, 0.0f, 0.0f) }
|
if (forceField.shape !is ForceFieldShape.Cube) { return Vector3f(0.0f, 0.0f, 0.0f) }
|
||||||
val shape = forceField.shape
|
val shape = forceField.shape
|
||||||
|
|
||||||
val sdfVal = sdfCube(forceField.pos, shape.size, offset)
|
val sdfVal = sdfCube(forceField.pos, shape.size, offset)
|
||||||
@@ -176,8 +176,8 @@ class Particle(private val particleParams: ParticleParams) {
|
|||||||
rot = newRot
|
rot = newRot
|
||||||
|
|
||||||
for (forceField in particleParams.forceFields) {
|
for (forceField in particleParams.forceFields) {
|
||||||
if (forceField.shape is ForceFieldShape.SPHERE) { vel.add(sphereSdfVel(forceField)) }
|
if (forceField.shape is ForceFieldShape.Sphere) { vel.add(sphereSdfVel(forceField)) }
|
||||||
else if (forceField.shape is ForceFieldShape.CUBE) { vel.add(cubeSdfVel(forceField)) }
|
else if (forceField.shape is ForceFieldShape.Cube) { vel.add(cubeSdfVel(forceField)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val (quatRot, transformOffset) = calcTransformOffset(newRot, initOffset, newScale)
|
val (quatRot, transformOffset) = calcTransformOffset(newRot, initOffset, newScale)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
package com.bytedice.bde_particles.particles
|
package com.bytedice.bde_particles.particles
|
||||||
|
|
||||||
import com.bytedice.bde_particles.InterpolationCurves
|
import com.bytedice.bde_particles.LerpCurves
|
||||||
import org.joml.Vector3f
|
import org.joml.Vector3f
|
||||||
|
|
||||||
|
|
||||||
@@ -103,8 +103,8 @@ fun updateSingleParticleParam(params: ParticleParams, paramName: String, paramVa
|
|||||||
"drag" -> paramValue as Float
|
"drag" -> paramValue as Float
|
||||||
"minVel" -> paramValue as Float
|
"minVel" -> paramValue as Float
|
||||||
"lifeTime" -> paramValue as Pair<Int, Int>
|
"lifeTime" -> paramValue as Pair<Int, Int>
|
||||||
"rotVelCurve" -> paramValue as Triple<Vector3f, Vector3f, InterpolationCurves>
|
"rotVelCurve" -> paramValue as Triple<Vector3f, Vector3f, LerpCurves>
|
||||||
"sizeCurve" -> paramValue as Triple<Vector3f, Vector3f, InterpolationCurves>
|
"sizeCurve" -> paramValue as Triple<Vector3f, Vector3f, LerpCurves>
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,8 +125,8 @@ fun updateSingleParticleParam(params: ParticleParams, paramName: String, paramVa
|
|||||||
"drag" -> newParams.drag = value as Float
|
"drag" -> newParams.drag = value as Float
|
||||||
"minVel" -> newParams.minVel = value as Float
|
"minVel" -> newParams.minVel = value as Float
|
||||||
"lifeTime" -> newParams.lifeTime = value as Pair<Int, Int>
|
"lifeTime" -> newParams.lifeTime = value as Pair<Int, Int>
|
||||||
"rotVelCurve" -> newParams.rotVelCurve = value as Triple<Vector3f, Vector3f, InterpolationCurves>
|
"rotVelCurve" -> newParams.rotVelCurve = value as Triple<Vector3f, Vector3f, LerpCurves>
|
||||||
"sizeCurve" -> newParams.sizeCurve = value as Triple<Vector3f, Vector3f, InterpolationCurves>
|
"sizeCurve" -> newParams.sizeCurve = value as Triple<Vector3f, Vector3f, LerpCurves>
|
||||||
else -> return Pair(params, false)
|
else -> return Pair(params, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
package com.bytedice.bde_particles.particles
|
|
||||||
|
|
||||||
import com.bytedice.bde_particles.InterpolationCurves
|
|
||||||
import org.joml.Vector3f
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ParticleParams defines the parameters for particle behavior, including shape, size, velocity, and other physics properties.
|
|
||||||
*
|
|
||||||
* @param shape The shape of the particle's spawning area, `null` is a single point.
|
|
||||||
* @param blockCurve An array of block names that gets cycled through during the particle's lifetime. Empty defaults to "minecraft:air".
|
|
||||||
* @param rotRandom The random ***initial*** rotation range for the particle's rotation in X, Y, and Z axes.
|
|
||||||
* @param rotVelRandom The random velocity for particle rotation in the X, Y, and Z axes.
|
|
||||||
* @param sizeRandom The random ***initial*** size range for the particle. If `uniformSize` is true, this will be uniform (cubic).
|
|
||||||
* @param uniformSize If true, particles will have a uniform (cubic) size. Otherwise, their sizes on different axis can vary.
|
|
||||||
* @param velRandom The random ***initial*** velocity range for the particle in the X, Y, and Z axes.
|
|
||||||
* @param forceFields An array of force fields applied to the particle.
|
|
||||||
* @param gravity A constant force applied to the particle every tick. It's often used as gravity.
|
|
||||||
* @param drag A drag force that affects the speed overtime. The formula is (velocity * (1.0 - drag))
|
|
||||||
* @param minVel If particles travel slower than this their speed is automatically 0. Values less than or equal to 0 mean the particle can travel at any speed.
|
|
||||||
* @param lifeTime A range for the particle's lifetime in ticks. A value below 1 will result in the particle not spawning.
|
|
||||||
* @param rotVelCurve A curve which the rotation velocity gets multiplied by during the particle's lifetime.
|
|
||||||
* @param sizeCurve A curve which the size gets multiplied by during the particle's lifetime.
|
|
||||||
*/
|
|
||||||
data class ParticleParams (
|
|
||||||
var shape: SpawningShape = SpawningShape.CIRCLE(3.0f),
|
|
||||||
var blockCurve: Array<String> = arrayOf("minecraft:purple_concrete", "minecraft:purple_stained_glass"),
|
|
||||||
var rotRandom: Pair<Vector3f, Vector3f> = Pair(Vector3f(0.0f, 0.0f, 0.0f), Vector3f(360.0f, 360.0f, 360.0f)),
|
|
||||||
var rotVelRandom: Pair<Vector3f, Vector3f> = Pair(Vector3f(-0.2f, -0.2f, -0.2f), Vector3f(0.2f, 0.2f, 0.2f)),
|
|
||||||
var sizeRandom: Pair<Vector3f, Vector3f> = Pair(Vector3f(0.5f, 0.5f, 0.5f), Vector3f(1.0f, 1.0f, 1.0f)),
|
|
||||||
var uniformSize: Boolean = true,
|
|
||||||
var velRandom: Pair<Vector3f, Vector3f> = Pair(Vector3f(-0.1f, 0.3f, -0.1f), Vector3f(0.1f, 0.6f, 0.1f)),
|
|
||||||
var forceFields: Array<ForceField> = emptyArray(),
|
|
||||||
var gravity: Vector3f = Vector3f(0.0f, -0.01f, 0.0f),
|
|
||||||
var drag: Float = 0.075f,
|
|
||||||
var minVel: Float = 0.0f,
|
|
||||||
var lifeTime: Pair<Int, Int> = Pair(15, 45),
|
|
||||||
var rotVelCurve: Triple<Vector3f, Vector3f, InterpolationCurves> = Triple(Vector3f(1.0f, 1.0f, 1.0f), Vector3f(0.0f, 0.0f, 0.0f), InterpolationCurves.SQRT),
|
|
||||||
var sizeCurve: Triple<Vector3f, Vector3f, InterpolationCurves> = Triple(Vector3f(1.0f, 1.0f, 1.0f), Vector3f(0.5f, 0.5f, 0.5f), InterpolationCurves.LINEAR),
|
|
||||||
) {
|
|
||||||
companion object Presets {
|
|
||||||
val DEFAULT = ParticleParams()
|
|
||||||
val FIRE_GEYSER = ParticleParams(
|
|
||||||
SpawningShape.POINT,
|
|
||||||
arrayOf("minecraft:shroomlight", "minecraft:orange_concrete", "minecraft:orange_stained_glass", "minecraft:gray_stained_glass", "minecraft:light_gray_stained_glass"),
|
|
||||||
Pair(Vector3f(0.0f, 0.0f, 0.0f), Vector3f(360.0f, 360.0f, 360.0f)),
|
|
||||||
Pair(Vector3f(-0.2f, -0.2f, -0.2f), Vector3f(0.2f, 0.2f, 0.2f)),
|
|
||||||
Pair(Vector3f(0.5f, 0.5f, 0.5f), Vector3f(1.0f, 1.0f, 1.0f)),
|
|
||||||
true,
|
|
||||||
Pair(Vector3f(-0.1f, 0.4f, -0.1f), Vector3f(0.1f, 0.8f, 0.1f)),
|
|
||||||
emptyArray(),
|
|
||||||
Vector3f(0.0f, -0.01f, 0.0f),
|
|
||||||
0.075f,
|
|
||||||
0.0f,
|
|
||||||
Pair(15, 45),
|
|
||||||
Triple(Vector3f(1.0f, 1.0f, 1.0f), Vector3f(0.0f, 0.0f, 0.0f), InterpolationCurves.SQRT),
|
|
||||||
Triple(Vector3f(1.0f, 1.0f, 1.0f), Vector3f(0.5f, 0.5f, 0.5f), InterpolationCurves.SQRT)
|
|
||||||
)
|
|
||||||
val RING_EXPLOSION = ParticleParams(
|
|
||||||
SpawningShape.CIRCLE(0.1f),
|
|
||||||
arrayOf("minecraft:shroomlight", "minecraft:orange_concrete", "minecraft:orange_stained_glass", "minecraft:gray_stained_glass", "minecraft:light_gray_stained_glass"),
|
|
||||||
Pair(Vector3f(0.0f, 0.0f, 0.0f), Vector3f(360.0f, 360.0f, 360.0f)),
|
|
||||||
Pair(Vector3f(-0.2f, -0.2f, -0.2f), Vector3f(0.2f, 0.2f, 0.2f)),
|
|
||||||
Pair(Vector3f(10.0f, 10.0f, 10.0f), Vector3f(15.0f, 15.0f, 15.0f)),
|
|
||||||
true,
|
|
||||||
Pair(Vector3f(0.0f, 0.0f, 0.0f), Vector3f(0.0f, 0.0f, 0.0f)),
|
|
||||||
arrayOf(ForceField("init", Vector3f(0.0f, -0.0001f, 0.0f), ForceFieldShape.SPHERE(0.1f, Pair(4.0f, 4.0f)))),
|
|
||||||
Vector3f(0.0f, 0.0f, 0.0f),
|
|
||||||
0.0075f,
|
|
||||||
0.0f,
|
|
||||||
Pair(50, 100),
|
|
||||||
Triple(Vector3f(1.0f, 1.0f, 1.0f), Vector3f(0.0f, 0.0f, 0.0f), InterpolationCurves.SQRT),
|
|
||||||
Triple(Vector3f(0.0f, 0.0f, 0.0f), Vector3f(3.0f, 3.0f, 3.0f), InterpolationCurves.SQRT)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,20 +4,31 @@ import org.joml.Vector2f
|
|||||||
import org.joml.Vector3f
|
import org.joml.Vector3f
|
||||||
|
|
||||||
sealed class SpawningShape {
|
sealed class SpawningShape {
|
||||||
data class CIRCLE(val radius: Float = 1.0f) : SpawningShape()
|
data class Circle(val radius: Float = 1.0f) : SpawningShape()
|
||||||
data class RECT (val size: Vector2f = Vector2f(1.0f, 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 Cube (val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f)) : SpawningShape()
|
||||||
data class SPHERE(val radius: Float = 1.0f) : SpawningShape()
|
data class Sphere(val radius: Float = 1.0f) : SpawningShape()
|
||||||
data object POINT : SpawningShape()
|
data object Point : SpawningShape()
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class ForceFieldShape {
|
sealed class ForceFieldShape {
|
||||||
data class SPHERE(
|
data class Sphere(
|
||||||
val radius: Float = 3.0f,
|
val radius: Float = 3.0f,
|
||||||
val force: Pair<Float, Float> = Pair(0.0f, 0.02f),
|
val force: Pair<Float, Float> = Pair(0.0f, 0.02f),
|
||||||
) : ForceFieldShape()
|
) : ForceFieldShape()
|
||||||
data class CUBE(
|
data class Cube(
|
||||||
val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f),
|
val size: Vector3f = Vector3f(1.0f, 1.0f, 1.0f),
|
||||||
val forceDir: Vector3f = Vector3f(0.0f, 0.0f, 0.0f)
|
val dir: Vector3f = Vector3f(0.0f, 0.0f, -1.0f),
|
||||||
|
val force: Pair<Float, Float> = Pair(0.0f, 0.02f)
|
||||||
) : ForceFieldShape()
|
) : ForceFieldShape()
|
||||||
|
data class Cone(
|
||||||
|
val size: Vector2f = Vector2f(1.0f, 1.0f),
|
||||||
|
val dir: Vector3f = Vector3f(0.0f, 0.0f, -1.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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user