Better bezier curve, more work on /ctf

This commit is contained in:
UnknownShadow200 2017-07-20 15:19:24 +10:00
parent 282edd2ca3
commit b48c6d52f1
5 changed files with 92 additions and 34 deletions

View File

@ -42,7 +42,7 @@ namespace MCGalaxy.Blocks.Physics {
args.Type1 = PhysicsArgs.Wait; args.Value1 = 1;
args.Type2 = PhysicsArgs.Dissipate; args.Value2 = 100;
lvl.AddUpdate(bAbove, Block.Fireworks, false);
lvl.AddUpdate(bAbove, Block.Fireworks);
lvl.AddUpdate(C.b, Block.StillLava, false, args);
args.Data = C.data.Data;
C.data = args;

View File

@ -19,6 +19,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using MCGalaxy.Games;
using MCGalaxy.Maths;
namespace MCGalaxy.Commands.Fun {
public sealed class CmdCTF : Command {
@ -107,11 +108,31 @@ namespace MCGalaxy.Commands.Fun {
cfg.RedSpawnX = p.Pos.X; cfg.RedSpawnY = p.Pos.Y; cfg.RedSpawnZ = p.Pos.Z;
Player.Message(p, "Set spawn of red team to your position.");
UpdateConfig(p, cfg);
} else if (property.CaselessEq("blueflag")) {
Player.Message(p, "Place or delete a block to set blue team's flag.");
p.MakeSelection(1, null, BlueFlagCallback);
} else if (property.CaselessEq("redflag")) {
Player.Message(p, "Place or delete a block to set red team's flag.");
p.MakeSelection(1, null, RedFlagCallback);
} else {
Help(p, "set");
}
}
static bool BlueFlagCallback(Player p, Vec3S32[] marks, object state, ExtBlock block) {
CTFConfig cfg = RetrieveConfig(p);
cfg.BlueFlagX = marks[0].X; cfg.BlueFlagY = marks[0].Y; cfg.BlueFlagZ = marks[0].Z;
UpdateConfig(p, cfg);
return false;
}
static bool RedFlagCallback(Player p, Vec3S32[] marks, object state, ExtBlock block) {
CTFConfig cfg = RetrieveConfig(p);
cfg.RedFlagX = marks[0].X; cfg.RedFlagY = marks[0].Y; cfg.RedFlagZ = marks[0].Z;
UpdateConfig(p, cfg);
return false;
}
static CTFConfig RetrieveConfig(Player p) {
CTFConfig cfg = new CTFConfig();
cfg.SetDefaults(p.level);

View File

@ -23,6 +23,9 @@ namespace MCGalaxy.Commands.Building {
public override string name { get { return "bezier"; } }
protected override string PlaceMessage { get { return "Place or break two blocks to determine the endpoints, then another for the control point"; } }
public override int MarksCount { get { return 3; } }
public override CommandAlias[] Aliases {
get { return new[] { new CommandAlias("curve") }; }
}
protected override DrawOp GetDrawOp(DrawArgs dArgs) {
return new BezierDrawOp();

View File

@ -32,23 +32,57 @@ namespace MCGalaxy.Drawing.Ops {
}
public override void Perform(Vec3S32[] marks, Brush brush, DrawOpOutput output) {
int steps = 20;
Vec3F32 p0 = marks[0], p2 = marks[1], p1 = marks[2];
steps *= (int)((p1 - p0).Length + (p1 - p2).Length);
points.Add(marks[0]);
TesselateCurve(marks[0], marks[2], marks[1], 0);
float t = 0, invT = 1, delta = 1.0f / steps;
for (int i = 0; i <= steps; i++) {
Vec3F32 B = invT * invT * p0 + 2 * invT * t * p1 + t * t * p2;
output(Place(Round(B.X), Round(B.Y), Round(B.Z), brush));
t += delta; invT -= delta;
List<Vec3S32> buffer = new List<Vec3S32>();
for (int i = 0; i < points.Count - 1; i++) {
LineDrawOp.DrawLine(points[i].X, points[i].Y, points[i].Z, 1000000,
points[i+1].X, points[i+1].Y, points[i+1].Z, buffer);
foreach (Vec3S32 P in buffer) {
output(Place((ushort)P.X, (ushort)P.Y, (ushort)P.Z, brush));
}
}
}
static ushort Round(float value) {
List<Vec3S32> points = new List<Vec3S32>();
const float objspace_flatness_squared = 0.35f * 0.35f;
// Based off stbtt__tesselate_curve from https://github.com/nothings/stb/blob/master/stb_truetype.h
void TesselateCurve(Vec3F32 p0, Vec3F32 p1, Vec3F32 p2, int n) {
// midpoint
Vec3F32 m;
m.X = (p0.X + 2 * p1.X + p2.X) * 0.25f;
m.Y = (p0.Y + 2 * p1.Y + p2.Y) * 0.25f;
m.Z = (p0.Z + 2 * p1.Z + p2.Z) * 0.25f;
// versus directly drawn line
Vec3F32 d;
d.X = (p0.X + p2.X) * 0.5f - m.X;
d.Y = (p0.Y + p2.Y) * 0.5f - m.Y;
d.Z = (p0.Z + p2.Z) * 0.5f - m.Z;
if (n > 16) return; // 65536 segments on one curve better be enough!
// half-pixel error allowed... need to be smaller if AA
if (d.X * d.X + d.Y * d.Y + d.Z * d.Z > objspace_flatness_squared) {
Vec3F32 p0_p1 = new Vec3F32((p0.X + p1.X) * 0.5f, (p0.Y + p1.Y) * 0.5f, (p0.Z + p1.Z) * 0.5f);
TesselateCurve(p0, p0_p1, m, n + 1);
Vec3F32 p1_p2 = new Vec3F32((p1.X + p2.X) * 0.5f, (p1.Y + p2.Y) * 0.5f, (p1.Z + p2.Z) * 0.5f);
TesselateCurve(m, p1_p2, p2, n + 1);
} else {
// TODO: do we need to round properly here or not
points.Add(new Vec3S32((int)p2.X, (int)p2.Y, (int)p2.Z));
}
}
/*static ushort Round(float value) {
int valueI = (int)value;
int floored = value < valueI ? valueI - 1 : valueI;
float frac = (value % 1.0f);
return (ushort)(floored + (frac > 0.5f ? 1 : 0));
}
}*/
}
}