Added textures to biomes and an expression parser.

This commit is contained in:
Tiberiu Chibici 2015-05-08 12:44:25 +03:00
parent b1a8da324d
commit c80b035ce7
27 changed files with 542 additions and 81 deletions

23
.gitignore vendored
View File

@ -3,6 +3,29 @@ Game/Logs/
Game/[Oo]bj/
Game/[Tt]emp/
# Unity specific
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
# Autogenerated VS/MD solution and project files
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
# Unity3D generated meta files
*.pidb.meta
# Unity3D Generated File On Crash Reports
sysinfo.txt
# User-specific files
*.suo
*.user

View File

@ -53,6 +53,7 @@
<Compile Include="Assets\Scripts\Model\Biome.cs" />
<Compile Include="Assets\Scripts\Model\Config\TerrainGeneratorConfig.cs" />
<Compile Include="Assets\Scripts\Model\Map.cs" />
<Compile Include="Assets\Scripts\Model\Texture.cs" />
<Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
<Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.cs" />
<Compile Include="Assets\Scripts\Unity\InitializeScript.cs" />
@ -60,6 +61,7 @@
<Compile Include="Assets\Scripts\Utils\Algorithms.cs" />
<Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
<Compile Include="Assets\Scripts\Utils\ColorHelper.cs" />
<Compile Include="Assets\Scripts\Utils\Expression.cs" />
<Compile Include="Assets\Scripts\Utils\Logger.cs" />
<Compile Include="Assets\Scripts\Utils\RandomExtensions.cs" />
<Compile Include="Assets\Scripts\Utils\Range.cs" />

View File

@ -53,6 +53,7 @@
<Compile Include="Assets\Scripts\Model\Biome.cs" />
<Compile Include="Assets\Scripts\Model\Config\TerrainGeneratorConfig.cs" />
<Compile Include="Assets\Scripts\Model\Map.cs" />
<Compile Include="Assets\Scripts\Model\Texture.cs" />
<Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
<Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.cs" />
<Compile Include="Assets\Scripts\Unity\InitializeScript.cs" />
@ -60,6 +61,7 @@
<Compile Include="Assets\Scripts\Utils\Algorithms.cs" />
<Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
<Compile Include="Assets\Scripts\Utils\ColorHelper.cs" />
<Compile Include="Assets\Scripts\Utils\Expression.cs" />
<Compile Include="Assets\Scripts\Utils\Logger.cs" />
<Compile Include="Assets\Scripts\Utils\RandomExtensions.cs" />
<Compile Include="Assets\Scripts\Utils\Range.cs" />

View File

@ -40,5 +40,11 @@ namespace TransportGame.Model
/// </summary>
[XmlElement("vegetationDensity")]
public Range VegetationDensity { get; set; }
/// <summary>
/// Gets or sets an array of textures to use
/// </summary>
[XmlArray("textures")]
public Texture[] Textures { get; set; }
}
}

View File

@ -2,10 +2,17 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace Assets.Scripts.Model
namespace TransportGame.Model
{
class Texture
[XmlRoot("texture")]
public class Texture
{
[XmlAttribute("src")]
public string Source { get; set; }
[XmlAttribute("expr")]
public string Expression { get; set; }
}
}

View File

@ -8,83 +8,83 @@ using TransportGame.Business;
public class TerrainGeneratorScript : MonoBehaviour
{
private Map map = null;
private Map map = null;
public int TerrainWidth = 1024;
public int TerrainHeight = 1024;
public GameObject WaterObject;
public int TerrainWidth = 1024;
public int TerrainHeight = 1024;
public GameObject WaterObject;
// Use this for initialization
void Start()
{
StartCoroutine(GenerateMap());
}
// Use this for initialization
void Start()
{
StartCoroutine(GenerateMap());
}
private void GenerateTerrainThread()
{
TerrainGenerator generator = new TerrainGenerator();
map = generator.Generate(TerrainWidth, TerrainHeight);
}
private void GenerateTerrainThread()
{
TerrainGenerator generator = new TerrainGenerator();
map = generator.Generate(TerrainWidth, TerrainHeight);
}
private Mesh GenerateWater()
{
Mesh water = new Mesh();
water.name = "water";
water.vertices = new[] {
new Vector3(0, map.WaterLevel, 0),
new Vector3(0, map.WaterLevel, map.Height),
new Vector3(map.Width, map.WaterLevel, 0),
new Vector3(map.Width, map.WaterLevel, map.Height)
};
water.triangles = new[] { 0, 1, 2, 2, 1, 3 };
water.uv = new[] {
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 0),
new Vector2(1, 1)
};
water.RecalculateNormals();
private Mesh GenerateWater()
{
Mesh water = new Mesh();
water.name = "water";
water.vertices = new[] {
new Vector3(0, map.WaterLevel, 0),
new Vector3(0, map.WaterLevel, map.Height),
new Vector3(map.Width, map.WaterLevel, 0),
new Vector3(map.Width, map.WaterLevel, map.Height)
};
water.triangles = new[] { 0, 1, 2, 2, 1, 3 };
water.uv = new[] {
new Vector2(0, 0),
new Vector2(0, 1),
new Vector2(1, 0),
new Vector2(1, 1)
};
water.RecalculateNormals();
return water;
}
return water;
}
private IEnumerator GenerateMap()
{
// Wait for the map generation thread
private IEnumerator GenerateMap()
{
// Wait for the map generation thread
foreach (var i in Task.RunAsync(GenerateTerrainThread))
yield return i;
// Generate terrain data
TerrainData terrainData = new TerrainData();
terrainData.heightmapResolution = Mathf.Max(map.Height, map.Width) + 1;
terrainData.size = new Vector3(map.Width, map.Biome.Height, map.Height);
terrainData.SetDetailResolution(1024, 8);
terrainData.SetHeights(0, 0, map.Heights);
terrainData.name = "Generated Terrain Data";
yield return null;
// Generate terrain data
TerrainData terrainData = new TerrainData();
terrainData.heightmapResolution = Mathf.Max(map.Height, map.Width) + 1;
terrainData.size = new Vector3(map.Width, map.Biome.Height, map.Height);
terrainData.SetDetailResolution(1024, 8);
terrainData.SetHeights(0, 0, map.Heights);
terrainData.name = "Generated Terrain Data";
yield return null;
// Create terrain object
GameObject terrain = Terrain.CreateTerrainGameObject(terrainData);
terrain.name = "Generated Terrain";
yield return null;
// Create terrain object
GameObject terrain = Terrain.CreateTerrainGameObject(terrainData);
terrain.name = "Generated Terrain";
yield return null;
Terrain terrainComp = terrain.GetComponent<Terrain>();
terrainComp.heightmapPixelError = 1;
yield return null;
Terrain terrainComp = terrain.GetComponent<Terrain>();
terrainComp.heightmapPixelError = 1;
yield return null;
// Set water
if (WaterObject != null)
{
MeshFilter waterMesh = WaterObject.GetComponent<MeshFilter>();
waterMesh.mesh = GenerateWater();
}
// Set water
if (WaterObject != null)
{
MeshFilter waterMesh = WaterObject.GetComponent<MeshFilter>();
waterMesh.mesh = GenerateWater();
}
// Set up textures
}
}
// Update is called once per frame
void Update()
{
}
// Update is called once per frame
void Update()
{
}
}

View File

@ -0,0 +1,425 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace GraphingCalculator
{
public class Expression
{
#region Types
public enum TokenType
{
None, Literal, Identifier, Operator, ArgSeparator,
LParanthesis, RParanthesis, Function
};
/// <summary>
/// Represents a token
/// </summary>
protected class Token
{
public TokenType Type { get; set; }
public string Text { get; set; }
public Token(TokenType type, string text)
{
Type = type;
Text = text;
}
}
#endregion
#region Variables, properties
private string expressionString;
private bool parsed = false;
protected List<Token> Tokens { get; private set; }
protected List<Token> Postfix { get; private set; }
public Dictionary<string, float> Variables { get; private set; }
public string ExpressionString
{
get { return expressionString; }
set
{
expressionString = value;
parsed = false;
}
}
#endregion
#region Other stuff
public void AddVariable(string name, float value)
{
Variables.Add(name, value);
}
#endregion
#region Constructor
public Expression()
{
Tokens = new List<Token>();
Postfix = new List<Token>();
Variables = new Dictionary<string, float>();
Variables.Add("pi", Mathf.PI);
}
public Expression(string expr)
: this()
{
expressionString = expr;
}
#endregion
#region Parser
private void AnalyzeLex()
{
Tokens.Clear();
for (int i = 0; i < ExpressionString.Length; i++)
{
if (char.IsWhiteSpace(ExpressionString[i])) continue;
if (IsOperator(ExpressionString[i]))
{
// Handle unary minus
if (IsUnaryMinus(ExpressionString[i]))
Tokens.Add(new Token(TokenType.Operator, "u"));
else
Tokens.Add(new Token(TokenType.Operator, ExpressionString[i].ToString()));
}
else if (ExpressionString[i] == '(')
Tokens.Add(new Token(TokenType.LParanthesis, ExpressionString[i].ToString()));
else if (ExpressionString[i] == ')')
Tokens.Add(new Token(TokenType.RParanthesis, ExpressionString[i].ToString()));
else if (ExpressionString[i] == ',')
Tokens.Add(new Token(TokenType.ArgSeparator, ExpressionString[i].ToString()));
else if (Char.IsDigit(ExpressionString[i]))
Tokens.Add(new Token(TokenType.Literal, GetLiteral(ExpressionString, ref i)));
else if (Char.IsLetter(ExpressionString[i]))
Tokens.Add(new Token(TokenType.Identifier, GetIdentifier(ExpressionString, ref i)));
else throw new Exception("Unrecognized character found!");
}
}
private void ConvertPostfix()
{
Stack<Token> stack = new Stack<Token>();
for (int i = 0; i < Tokens.Count; i++)
{
Token t = Tokens[i];
switch (t.Type)
{
case TokenType.Identifier:
// Followed by '(' means function
if (i + 1 < Tokens.Count && Tokens[i + 1].Type == TokenType.LParanthesis)
stack.Push(new Token(TokenType.Function, t.Text));
// Else, variable
else Postfix.Add(t);
break;
case TokenType.Literal:
Postfix.Add(t);
break;
case TokenType.ArgSeparator:
// We pop everything from the stack until left paranthesis open
while (stack.Peek().Type != TokenType.LParanthesis)
{
Postfix.Add(stack.Pop());
if (stack.Count == 0)
throw new Exception("Syntax error! Unexpected comma.");
}
break;
case TokenType.Operator:
if (IsLeftAssociative(t.Text))
{
while (stack.Count != 0 && Precedence(t.Text) <= Precedence(stack.Peek().Text))
Postfix.Add(stack.Pop());
}
else
{
while (stack.Count != 0 && Precedence(t.Text) < Precedence(stack.Peek().Text))
Postfix.Add(stack.Pop());
}
stack.Push(t);
break;
case TokenType.LParanthesis:
stack.Push(t);
break;
case TokenType.RParanthesis:
while (stack.Peek().Type != TokenType.LParanthesis)
{
Postfix.Add(stack.Pop());
if (stack.Count == 0)
throw new Exception("Mismatched parantheses!");
}
stack.Pop(); // Pop Lparanthesis
if (stack.Count > 0 && stack.Peek().Type == TokenType.Function)
Postfix.Add(stack.Pop()); // Pop function name
break;
}
}
while (stack.Count > 0)
{
if (stack.Peek().Type == TokenType.LParanthesis)
throw new Exception("Mismatched parantheses!");
Postfix.Add(stack.Pop());
}
}
public void ParseExpression()
{
if (!parsed)
{
Tokens.Clear();
Postfix.Clear();
AnalyzeLex();
ConvertPostfix();
}
}
public float Evaluate()
{
// Parse expression first
ParseExpression();
// Expression is empty, so is result
if (Postfix.Count == 0)
return 0;
Stack<float> stack = new Stack<float>();
foreach (var t in Postfix)
{
switch (t.Type)
{
// We already replace functions, so identifiers are variables
case TokenType.Identifier:
if (!Variables.ContainsKey(t.Text))
throw new Exception("Undefined variable '" + t.Text + "'.");
stack.Push(Variables[t.Text]);
break;
case TokenType.Literal:
stack.Push(float.Parse(t.Text));
break;
case TokenType.Operator:
switch (t.Text)
{
case "u":
stack.Push(stack.Pop() * -1);
break;
case "+":
stack.Push(stack.Pop() + stack.Pop());
break;
case "-":
{
float b = stack.Pop();
float a = stack.Pop();
stack.Push(a - b);
}
break;
case "*":
stack.Push(stack.Pop() * stack.Pop());
break;
case "/":
{
float b = stack.Pop();
float a = stack.Pop();
stack.Push(a / b);
}
break;
case "%":
{
float b = stack.Pop();
float a = stack.Pop();
stack.Push(a % b);
}
break;
case "^":
{
float b = stack.Pop();
float a = stack.Pop();
stack.Push(Mathf.Pow(a, b));
}
break;
}
break;
case TokenType.Function:
EvaluateFunction(t.Text, ref stack);
break;
}
}
return stack.Pop();
}
#endregion
#region Helper routines
private bool IsUnaryMinus(char c)
{
if (c == '-')
{
// Nothing in front, definitely unary
if (Tokens.Count == 0)
return true;
// See what's in front
TokenType inFront = Tokens.Last().Type;
// If what's in front cannot be an operand, than it is unary minus
return inFront == TokenType.ArgSeparator || inFront == TokenType.LParanthesis || inFront == TokenType.Operator;
}
return false;
}
private void EvaluateFunction(string func, ref Stack<float> stack)
{
switch (func)
{
case "sin": stack.Push(Mathf.Sin(stack.Pop())); break;
case "cos": stack.Push(Mathf.Cos(stack.Pop())); break;
case "tan": stack.Push(Mathf.Tan(stack.Pop())); break;
case "ctan": stack.Push(1 / Mathf.Tan(stack.Pop())); break;
case "arcsin": stack.Push(Mathf.Asin(stack.Pop())); break;
case "asin": stack.Push(Mathf.Asin(stack.Pop())); break;
case "arccos": stack.Push(Mathf.Acos(stack.Pop())); break;
case "acos": stack.Push(Mathf.Acos(stack.Pop())); break;
case "arctan": stack.Push(Mathf.Atan(stack.Pop())); break;
case "atan": stack.Push(Mathf.Atan(stack.Pop())); break;
case "truncate":
case "floor": stack.Push(Mathf.Floor(stack.Pop())); break;
case "ceil":
case "ceiling": stack.Push(Mathf.Ceil(stack.Pop())); break;
case "sqrt": stack.Push(Mathf.Sqrt(stack.Pop())); break;
case "cbrt": stack.Push(Mathf.Pow(stack.Pop(), 1.0f / 3.0f)); break;
case "root": stack.Push(Mathf.Pow(stack.Pop(), 1 / stack.Pop())); break;
case "abs": stack.Push(Math.Abs(stack.Pop())); break;
case "max": stack.Push(Math.Max(stack.Pop(), stack.Pop())); break;
case "min": stack.Push(Math.Min(stack.Pop(), stack.Pop())); break;
case "lg": stack.Push(Mathf.Log10(stack.Pop())); break;
case "log": stack.Push(Mathf.Log(stack.Pop(), stack.Pop())); break;
case "clamp01": stack.Push(Mathf.Clamp01(stack.Pop())); break;
case "clamp": stack.Push(Mathf.Clamp(stack.Pop(), stack.Pop(), stack.Pop())); break;
case "lerp": stack.Push(Mathf.Lerp(stack.Pop(), stack.Pop(), stack.Pop())); break;
default: throw new Exception("Undefined function '" + func + "'.");
}
}
private static bool IsLeftAssociative(string op)
{
return (op != "^");
}
private static int Precedence(string op)
{
switch (op)
{
case "+":
case "-": return 1;
case "*":
case "/":
case "%": return 2;
case "u":
case "^": return 3;
default: return 0;
}
}
private static bool IsOperator(char c)
{
const string operators = "+-*/%^";
return operators.Contains(c);
}
private static string GetIdentifier(string s, ref int index)
{
int start = index;
while (index < s.Length && (char.IsLetterOrDigit(s[index]) || s[index] == '_'))
++index;
index -= 1;
return s.Substring(start, index + 1 - start);
}
private static string GetLiteral(string s, ref int index)
{
int start = index;
while (index < s.Length && (char.IsDigit(s[index]) || s[index] == '.'))
++index;
index -= 1;
return s.Substring(start, index + 1 - start);
}
#endregion
}
}

View File

@ -23,7 +23,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = Assembly-CSharp.csproj
Policies = $0
$0.TextStylePolicy = $1

View File

@ -29,7 +29,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = Assembly-CSharp.csproj
Policies = $0
$0.TextStylePolicy = $1

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,3 +1,9 @@
Base path: C:/Program Files/Unity/Editor/Data
Pipe name: \\.\pipe\UnityShaderCompiler-32bit-1-8304
Cmd: getPlatforms
Unhandled exception: Readfile from pipe failed. GLE=The pipe has been ended.
Quitting shader compiler process
Crashed!

File diff suppressed because one or more lines are too long

View File

@ -85,6 +85,7 @@
<Compile Include="Assets\Scripts\Utils\Algorithms.cs" />
<Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
<Compile Include="Assets\Scripts\Utils\ColorHelper.cs" />
<Compile Include="Assets\Scripts\Utils\Expression.cs" />
<Compile Include="Assets\Scripts\Utils\Logger.cs" />
<Compile Include="Assets\Scripts\Utils\RandomExtensions.cs" />
<Compile Include="Assets\Scripts\Utils\Range.cs" />