Initial work on a perlin noise brush.

This commit is contained in:
UnknownShadow200 2016-05-08 10:29:09 +10:00
parent 3052c098e7
commit 595c8206ef
5 changed files with 159 additions and 45 deletions

View File

@ -40,7 +40,7 @@ namespace MCGalaxy.Drawing.Brushes {
{ "checkered", CheckeredBrush.Process }, { "rainbow", RainbowBrush.Process }, { "checkered", CheckeredBrush.Process }, { "rainbow", RainbowBrush.Process },
{ "bwrainbow", BWRainbowBrush.Process }, { "striped", StripedBrush.Process }, { "bwrainbow", BWRainbowBrush.Process }, { "striped", StripedBrush.Process },
{ "replace", ReplaceBrush.Process }, { "replacenot", ReplaceNotBrush.Process }, { "replace", ReplaceBrush.Process }, { "replacenot", ReplaceNotBrush.Process },
{ "random", RandomBrush.Process }, { "random", RandomBrush.Process }, { "noise", NoiseBrush.Process },
}; };
public static Dictionary<string, string[]> BrushesHelp = new Dictionary<string, string[]> { public static Dictionary<string, string[]> BrushesHelp = new Dictionary<string, string[]> {
@ -48,7 +48,7 @@ namespace MCGalaxy.Drawing.Brushes {
{ "checkered", CheckeredBrush.HelpString }, { "rainbow", RainbowBrush.HelpString }, { "checkered", CheckeredBrush.HelpString }, { "rainbow", RainbowBrush.HelpString },
{ "bwrainbow", BWRainbowBrush.HelpString }, { "striped", StripedBrush.HelpString }, { "bwrainbow", BWRainbowBrush.HelpString }, { "striped", StripedBrush.HelpString },
{ "replace", ReplaceBrush.HelpString }, { "replacenot", ReplaceNotBrush.HelpString }, { "replace", ReplaceBrush.HelpString }, { "replacenot", ReplaceNotBrush.HelpString },
{ "random", RandomBrush.HelpString }, { "random", RandomBrush.HelpString }, { "noise", NoiseBrush.HelpString },
}; };
} }

View File

@ -0,0 +1,77 @@
/*
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
using MCGalaxy.Commands;
using MCGalaxy.Drawing.Ops;
namespace MCGalaxy.Drawing.Brushes {
public abstract class FrequencyBrush : Brush {
protected static ExtBlock[] GetBlocks(Player p, string[] parts,
int[] count, Predicate<string> filter,
Predicate<string> handler) {
ExtBlock[] blocks = new ExtBlock[parts.Length];
for (int i = 0; i < blocks.Length; i++) {
blocks[i].Type = Block.Zero;
count[i] = filter(parts[i]) ? 1 : 0;
}
for (int i = 0; i < parts.Length; i++ ) {
// Brush specific args
if (!filter(parts[i])) {
if (!handler(parts[i])) return null;
continue;
}
byte extType = 0;
int sepIndex = parts[i].IndexOf('/');
string block = sepIndex >= 0 ? parts[i].Substring(0, sepIndex) : parts[i];
byte type = DrawCmd.GetBlock(p, block, out extType);
if (type == Block.Zero) return null;
blocks[i].Type = type; blocks[i].ExtType = extType;
if (sepIndex < 0) continue;
int chance;
if (!int.TryParse(parts[i].Substring(sepIndex + 1), out chance)
|| chance <= 0 || chance > 10000) {
Player.Message(p, "frequency must be an integer between 1 and 10,000."); return null;
}
count[i] = chance;
}
return blocks;
}
protected static ExtBlock[] Combine(ExtBlock[] toAffect, int[] count) {
int sum = 0;
for (int i = 0; i < count.Length; i++) sum += count[i];
if (toAffect.Length == 1) sum += 1;
ExtBlock[] blocks = new ExtBlock[sum];
for (int i = 0, index = 0; i < toAffect.Length; i++) {
for (int j = 0; j < count[i]; j++)
blocks[index++] = toAffect[i];
}
// For one block argument, leave every other block untouched.
if (toAffect.Length == 1)
blocks[blocks.Length - 1] = new ExtBlock(Block.Zero, 0);
return blocks;
}
}
}

View File

@ -0,0 +1,76 @@
/*
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
using MCGalaxy.Commands;
using MCGalaxy.Drawing.Ops;
using MCGalaxy.Generator;
namespace MCGalaxy.Drawing.Brushes {
public sealed class NoiseBrush : FrequencyBrush {
readonly ExtBlock[] blocks;
readonly ImprovedNoise noise;
public NoiseBrush(ExtBlock[] blocks) {
this.blocks = blocks;
noise = new ImprovedNoise(new Random());
noise.Octaves = 4;
}
public override string Name { get { return "Noise"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1/frequency] [block2]..",
"%HDraws by selecting blocks from the given [blocks] using perlin noise.",
"%Hfrequency is optional (defaults to 1), and specifies the number of times " +
"the block should appear (as a fraction of the total of all the frequencies).",
};
public static Brush Process(BrushArgs args) {
if (args.Message == "")
return new NoiseBrush(new[] { new ExtBlock(args.Type, args.ExtType),
new ExtBlock(Block.Zero, 0) });
string[] parts = args.Message.Split(' ');
int[] count = new int[parts.Length];
ExtBlock[] toAffect = GetBlocks(args.Player, parts, count, P => true, null);
if (toAffect == null) return null;
ExtBlock[] blocks = Combine(toAffect, count);
return new NoiseBrush(blocks);
}
int next;
public override byte NextBlock(DrawOp op) {
float N = noise.NormalisedNoise(op.Coords.X, op.Coords.Y, op.Coords.Z);
N = (N + 1) * 0.5f; // rescale to [0, 1];
next = (int)(N * blocks.Length);
if (next < 0) next = 0;
if (next >= blocks.Length) next = blocks.Length - 1;
return blocks[next].Type;
}
public override byte NextExtBlock(DrawOp op) {
return blocks[next].ExtType;
}
}
}

View File

@ -22,7 +22,7 @@ using MCGalaxy.Drawing.Ops;
namespace MCGalaxy.Drawing.Brushes { namespace MCGalaxy.Drawing.Brushes {
public sealed class RandomBrush : Brush { public sealed class RandomBrush : FrequencyBrush {
readonly ExtBlock[] blocks; readonly ExtBlock[] blocks;
readonly int seed; readonly int seed;
@ -49,54 +49,13 @@ namespace MCGalaxy.Drawing.Brushes {
string[] parts = args.Message.Split(' '); string[] parts = args.Message.Split(' ');
int[] count = new int[parts.Length]; int[] count = new int[parts.Length];
ExtBlock[] toAffect = GetBlocks(args.Player, parts.Length, parts, count); ExtBlock[] toAffect = GetBlocks(args.Player, parts, count, P => true, null);
if (toAffect == null) return null; if (toAffect == null) return null;
ExtBlock[] blocks = Combine(toAffect, count); ExtBlock[] blocks = Combine(toAffect, count);
return new RandomBrush(blocks); return new RandomBrush(blocks);
} }
static ExtBlock[] GetBlocks(Player p, int max, string[] parts, int[] count) {
ExtBlock[] blocks = new ExtBlock[max];
for (int i = 0; i < blocks.Length; i++) {
blocks[i].Type = Block.Zero;
count[i] = 1;
}
for (int i = 0; i < max; i++ ) {
byte extType = 0;
int sepIndex = parts[i].IndexOf('/');
string block = sepIndex >= 0 ? parts[i].Substring(0, sepIndex) : parts[i];
byte type = DrawCmd.GetBlock(p, block, out extType);
if (type == Block.Zero) return null;
blocks[i].Type = type; blocks[i].ExtType = extType;
if (sepIndex < 0) continue;
int chance;
if (!int.TryParse(parts[i].Substring(sepIndex + 1), out chance) || chance <= 0 || chance > 10000) {
Player.Message(p, "frequency must be an integer between 1 and 10,000."); return null;
}
count[i] = chance;
}
return blocks;
}
static ExtBlock[] Combine(ExtBlock[] toAffect, int[] count) {
int sum = 0;
for (int i = 0; i < count.Length; i++) sum += count[i];
if (toAffect.Length == 1) sum += 1;
ExtBlock[] blocks = new ExtBlock[sum];
for (int i = 0, index = 0; i < toAffect.Length; i++) {
for (int j = 0; j < count[i]; j++)
blocks[index++] = toAffect[i];
}
// For one block argument, leave everything else untouched.
if (toAffect.Length == 1)
blocks[blocks.Length - 1] = new ExtBlock(Block.Zero, 0);
return blocks;
}
int next; int next;
const int mask = 0x7fffffff; const int mask = 0x7fffffff;
public override byte NextBlock(DrawOp op) { public override byte NextBlock(DrawOp op) {

View File

@ -431,6 +431,8 @@
<Compile Include="Database\SQLite\SQLiteParameterisedQuery.cs" /> <Compile Include="Database\SQLite\SQLiteParameterisedQuery.cs" />
<Compile Include="Drawing\Brushes\Brush.cs" /> <Compile Include="Drawing\Brushes\Brush.cs" />
<Compile Include="Drawing\Brushes\CheckeredBrush.cs" /> <Compile Include="Drawing\Brushes\CheckeredBrush.cs" />
<Compile Include="Drawing\Brushes\FrequencyBrush.cs" />
<Compile Include="Drawing\Brushes\NoiseBrush.cs" />
<Compile Include="Drawing\Brushes\PasteBrush.cs" /> <Compile Include="Drawing\Brushes\PasteBrush.cs" />
<Compile Include="Drawing\Brushes\RainbowBrush.cs" /> <Compile Include="Drawing\Brushes\RainbowBrush.cs" />
<Compile Include="Drawing\Brushes\RandomBrush.cs" /> <Compile Include="Drawing\Brushes\RandomBrush.cs" />