push to get help with matrix-based look->screen calcs
This commit is contained in:
parent
ef5fd6aa46
commit
f52880e527
7 changed files with 102 additions and 23 deletions
17
LICENSE.txt
Normal file
17
LICENSE.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
The MIT License (MIT)
|
||||
Copyright © 2021 gamma-delta
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
and associated documentation files (the “Software”), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -7,10 +7,14 @@ import at.petrak.hex.HexUtils.deserializeVec3FromNBT
|
|||
import at.petrak.hex.HexUtils.serializeToNBT
|
||||
import at.petrak.hex.casting.operators.SpellOperator
|
||||
import at.petrak.hex.hexes.HexAngle
|
||||
import at.petrak.hex.hexes.HexCoord
|
||||
import at.petrak.hex.hexes.HexDir
|
||||
import at.petrak.hex.hexes.HexPattern
|
||||
import com.mojang.math.Matrix3f
|
||||
import com.mojang.math.Vector3f
|
||||
import net.minecraft.nbt.*
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.*
|
||||
import kotlin.math.*
|
||||
|
@ -35,10 +39,8 @@ class CastingHarness private constructor(
|
|||
HexMod.LOGGER.info("Started drawing new pattern")
|
||||
this.patternDrawState = PatternDrawState.JustStarted(caster.lookAngle)
|
||||
worldPoints.add(mutableListOf(caster.lookAngle.add(caster.position())))
|
||||
CastResult.Nothing
|
||||
} else {
|
||||
CastResult.QuitCasting
|
||||
}
|
||||
CastResult.Nothing
|
||||
}
|
||||
is PatternDrawState.JustStarted -> {
|
||||
val (anchor) = patternDrawState as PatternDrawState.JustStarted
|
||||
|
@ -74,8 +76,8 @@ class CastingHarness private constructor(
|
|||
// Finish the current pattern!
|
||||
patternDrawState = PatternDrawState.BetweenPatterns
|
||||
try {
|
||||
|
||||
val operator = SpellOperator.fromPattern(pat)
|
||||
HexMod.LOGGER.info("Executing operator: $operator")
|
||||
// now execute the operator
|
||||
if (operator.argc > this.stack.size)
|
||||
throw CastException(CastException.Reason.NOT_ENOUGH_ARGS, operator.argc, this.stack.size)
|
||||
|
@ -86,6 +88,8 @@ class CastingHarness private constructor(
|
|||
val newData = operator.execute(args, this.ctx)
|
||||
this.stack.addAll(newData)
|
||||
|
||||
HexMod.LOGGER.info("Added new data to stack: ${this.stack}")
|
||||
|
||||
if (this.stack.isEmpty()) {
|
||||
return CastResult.QuitCasting
|
||||
}
|
||||
|
@ -156,7 +160,7 @@ class CastingHarness private constructor(
|
|||
|
||||
CastingHarness(stack, pds, points, ctx)
|
||||
} catch (exn: Exception) {
|
||||
HexMod.LOGGER.warn("Couldn't load harness from nbt tag, falling back to default: ${exn.message}")
|
||||
HexMod.LOGGER.warn("Couldn't load harness from nbt tag, falling back to default: $nbt: $exn")
|
||||
CastingHarness(mutableListOf(), PatternDrawState.BetweenPatterns, mutableListOf(), ctx)
|
||||
}
|
||||
}
|
||||
|
@ -164,12 +168,51 @@ class CastingHarness private constructor(
|
|||
// this is on a unit sphere, where 0 is straight ahead and 1 is straight up (or similar)
|
||||
const val HEX_GRID_SPACING = 1.0 / 8.0
|
||||
|
||||
/** Check if the two vectors are far enough apart to be more than one hex coord apart */
|
||||
private fun Vec3.hexDirBetween(look: Vec3): Optional<HexDir> {
|
||||
private fun screenToLookMat(look: Vec3): Matrix3f {
|
||||
val towardsZenith = Vec3(0.0, 1.0, 0.0).subtract(look).normalize()
|
||||
val towardsRight = look.cross(towardsZenith).normalize()
|
||||
|
||||
val ihatPrime = Vector3f(look.add(towardsRight))
|
||||
val jhatPrime = Vector3f(look.add(towardsZenith))
|
||||
val khatPrime = Vector3f(look)
|
||||
|
||||
val neo = Matrix3f()
|
||||
neo.set(0, 0, ihatPrime.x())
|
||||
neo.set(0, 1, ihatPrime.y())
|
||||
neo.set(0, 2, ihatPrime.z())
|
||||
neo.set(1, 0, jhatPrime.x())
|
||||
neo.set(1, 1, jhatPrime.y())
|
||||
neo.set(1, 2, jhatPrime.z())
|
||||
neo.set(2, 0, khatPrime.x())
|
||||
neo.set(2, 1, khatPrime.y())
|
||||
neo.set(2, 2, khatPrime.z())
|
||||
return neo
|
||||
}
|
||||
|
||||
private fun Vec3.screenAngle(offset: Vec3): Double {
|
||||
// https://gist.github.com/Alwinfy/d6f3e9b22e4432f4446a58ace8812a3c
|
||||
// no idea how any of this works
|
||||
fun pythag(x: Double, y: Double): Double = sqrt(x * x + y * y)
|
||||
|
||||
val yaw = atan2(this.x, this.z)
|
||||
val pitch = atan2(this.y, pythag(this.x, this.z))
|
||||
val zeroYaw = offset.yRot(-yaw.toFloat())
|
||||
val zeroPitch = zeroYaw.xRot(-pitch.toFloat()).normalize()
|
||||
|
||||
return atan2(asin(zeroPitch.y), asin(-zeroPitch.x))
|
||||
}
|
||||
|
||||
private fun Vec3.screenVec(offset: Vec3): Vec2 {
|
||||
val angle = this.screenAngle(offset)
|
||||
val dy = sin(angle)
|
||||
val dx = cos(angle)
|
||||
|
||||
val dist = (this.normalize().subtract(offset.normalize())).length()
|
||||
return Vec2((dx * dist).toFloat(), (dy * dist).toFloat())
|
||||
}
|
||||
|
||||
/** Check if the two vectors are far enough apart to be more than one hex coord apart */
|
||||
private fun Vec3.hexDirBetween(look: Vec3): Optional<HexDir> {
|
||||
if (look.x.absoluteValue <= 1e-30 || look.z.absoluteValue <= 1e-30)
|
||||
return Optional.empty()
|
||||
|
||||
|
@ -177,16 +220,25 @@ class CastingHarness private constructor(
|
|||
if (dist < HEX_GRID_SPACING)
|
||||
return Optional.empty()
|
||||
|
||||
val yaw = atan2(this.x, this.z)
|
||||
val pitch = atan2(this.y, pythag(this.x, this.z))
|
||||
val zeroYaw = look.yRot(-yaw.toFloat())
|
||||
val zeroPitch = zeroYaw.xRot(-pitch.toFloat()).normalize()
|
||||
|
||||
val angle = atan2(asin(zeroPitch.y), asin(-zeroPitch.x))
|
||||
// val angle = this.screenAngle(look)
|
||||
val neo = screenToLookMat(this)
|
||||
neo.invert()
|
||||
val lookScreen = Vector3f(look)
|
||||
lookScreen.transform(neo)
|
||||
HexMod.LOGGER.info(lookScreen)
|
||||
val angle = atan2(lookScreen.y(), lookScreen.x())
|
||||
// 0 is right, increases clockwise(?)
|
||||
val snappedAngle = angle.div(TAU).mod(6.0).times(6).roundToInt()
|
||||
return Optional.of(HexDir.values()[(-snappedAngle + 1).mod(6)])
|
||||
}
|
||||
|
||||
/**
|
||||
* Taking this as a look vector, get the look vector that is this vector offset
|
||||
* by the given coordinate in draw-space.
|
||||
*/
|
||||
private fun Vec3.hexOffsetFrom(offset: HexCoord): Vec3 {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
sealed class PatternDrawState {
|
||||
|
|
|
@ -13,6 +13,7 @@ import net.minecraft.world.phys.Vec3
|
|||
* * [Entity]
|
||||
* * [Double]
|
||||
* * [Vec3][net.minecraft.world.phys.Vec3] as both position and (when normalized) direction
|
||||
* * [RenderedSpell]
|
||||
* * [Unit] as our type-safe null
|
||||
* * [ArrayList<SpellDatum<*>>][ArrayList]
|
||||
* The constructor guarantees we won't pass a type that isn't one of those types.
|
||||
|
@ -30,7 +31,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
else
|
||||
payload
|
||||
} else {
|
||||
throw CastException(CastException.Reason.OP_WRONG_TYPE, U::class.java, clazz)
|
||||
throw CastException(CastException.Reason.OP_WRONG_TYPE, U::class.java, this.payload)
|
||||
}
|
||||
|
||||
fun serializeToNBT(): CompoundTag {
|
||||
|
@ -61,6 +62,13 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
return out
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
buildString {
|
||||
append("SpellDatum[")
|
||||
append(this@SpellDatum.payload.toString())
|
||||
append(']')
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun <T : Any> make(payload: T): SpellDatum<T> =
|
||||
if (!IsValidType(payload)) {
|
||||
|
@ -102,6 +110,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
Entity::class.java,
|
||||
Double::class.java,
|
||||
Vec3::class.java,
|
||||
RenderedSpell::class.java,
|
||||
Unit::class.java,
|
||||
ArrayList::class.java,
|
||||
)
|
||||
|
|
|
@ -17,7 +17,7 @@ object OpPrint : SpellOperator {
|
|||
class Spell(private val datum: SpellDatum<*>) : RenderedSpell {
|
||||
override fun cast(ctx: CastingContext) {
|
||||
ctx.caster.sendMessage(
|
||||
TextComponent(datum.toString()),
|
||||
TextComponent(if (datum.payload is Unit) "null" else datum.payload.toString()),
|
||||
Util.NIL_UUID
|
||||
)
|
||||
}
|
||||
|
|
|
@ -36,8 +36,7 @@ public class HexRenderOverlays {
|
|||
if (tag.contains(CastingHarness.TAG_POINTS)) {
|
||||
PoseStack ps = e.getMatrixStack();
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
MultiBufferSource buffers = mc.renderBuffers().bufferSource();
|
||||
|
||||
MultiBufferSource.BufferSource buffers = mc.renderBuffers().bufferSource();
|
||||
|
||||
Vec3 camPos = mc.gameRenderer.getMainCamera().getPosition();
|
||||
Vec3 eyePos = player.getEyePosition(e.getPartialTicks());
|
||||
|
@ -70,10 +69,11 @@ public class HexRenderOverlays {
|
|||
VertexConsumer buf1 = buffers.getBuffer(RenderType.LINES);
|
||||
addVertex(ps, buf1, player.position().add(player.getLookAngle()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
ps.popPose();
|
||||
buffers.endBatch();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ public class HexRenderOverlays {
|
|||
private static void addVertex(PoseStack ps, VertexConsumer buf, Vec3 vert) {
|
||||
buf.vertex(ps.last().pose(), (float) vert.x, (float) vert.y, (float) vert.z)
|
||||
.color(128, 128, 255, 255)
|
||||
.normal(0.0f, 1.0f, 0.0f)
|
||||
.endVertex();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ data class HexPattern(val startDir: HexDir, val angles: MutableList<HexAngle> =
|
|||
}
|
||||
|
||||
override fun toString(): String = buildString {
|
||||
append("[HexPattern ")
|
||||
append("HexPattern[")
|
||||
append(this@HexPattern.startDir)
|
||||
append(", ")
|
||||
append(this@HexPattern.anglesSignature())
|
||||
|
|
|
@ -34,7 +34,10 @@ public class ItemWand extends Item {
|
|||
CastingHarness harness = CastingHarness.DeserializeFromNBT(stack.getOrCreateTag(), player);
|
||||
CastResult res = harness.update();
|
||||
|
||||
if (!(res instanceof CastResult.Nothing)) {
|
||||
if (res instanceof CastResult.Nothing) {
|
||||
// Save back the context
|
||||
stack.setTag(harness.serializeToNBT());
|
||||
} else {
|
||||
if (res instanceof CastResult.Success) {
|
||||
CastResult.Success success = (CastResult.Success) res;
|
||||
success.getSpell().cast(harness.getCtx());
|
||||
|
@ -44,9 +47,6 @@ public class ItemWand extends Item {
|
|||
}
|
||||
// In any case clear the tag, we're through
|
||||
stack.setTag(new CompoundTag());
|
||||
} else {
|
||||
// Save back the context
|
||||
stack.setTag(harness.serializeToNBT());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue