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/[Oo]bj/
Game/[Tt]emp/ 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 # User-specific files
*.suo *.suo
*.user *.user

View File

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

View File

@ -40,5 +40,11 @@ namespace TransportGame.Model
/// </summary> /// </summary>
[XmlElement("vegetationDensity")] [XmlElement("vegetationDensity")]
public Range VegetationDensity { get; set; } 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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; 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 public class TerrainGeneratorScript : MonoBehaviour
{ {
private Map map = null; private Map map = null;
public int TerrainWidth = 1024; public int TerrainWidth = 1024;
public int TerrainHeight = 1024; public int TerrainHeight = 1024;
public GameObject WaterObject; public GameObject WaterObject;
// Use this for initialization // Use this for initialization
void Start() void Start()
{ {
StartCoroutine(GenerateMap()); StartCoroutine(GenerateMap());
} }
private void GenerateTerrainThread() private void GenerateTerrainThread()
{ {
TerrainGenerator generator = new TerrainGenerator(); TerrainGenerator generator = new TerrainGenerator();
map = generator.Generate(TerrainWidth, TerrainHeight); map = generator.Generate(TerrainWidth, TerrainHeight);
} }
private Mesh GenerateWater() private Mesh GenerateWater()
{ {
Mesh water = new Mesh(); Mesh water = new Mesh();
water.name = "water"; water.name = "water";
water.vertices = new[] { water.vertices = new[] {
new Vector3(0, map.WaterLevel, 0), new Vector3(0, map.WaterLevel, 0),
new Vector3(0, map.WaterLevel, map.Height), new Vector3(0, map.WaterLevel, map.Height),
new Vector3(map.Width, map.WaterLevel, 0), new Vector3(map.Width, map.WaterLevel, 0),
new Vector3(map.Width, map.WaterLevel, map.Height) new Vector3(map.Width, map.WaterLevel, map.Height)
}; };
water.triangles = new[] { 0, 1, 2, 2, 1, 3 }; water.triangles = new[] { 0, 1, 2, 2, 1, 3 };
water.uv = new[] { water.uv = new[] {
new Vector2(0, 0), new Vector2(0, 0),
new Vector2(0, 1), new Vector2(0, 1),
new Vector2(1, 0), new Vector2(1, 0),
new Vector2(1, 1) new Vector2(1, 1)
}; };
water.RecalculateNormals(); water.RecalculateNormals();
return water; return water;
} }
private IEnumerator GenerateMap() private IEnumerator GenerateMap()
{ {
// Wait for the map generation thread // Wait for the map generation thread
foreach (var i in Task.RunAsync(GenerateTerrainThread)) foreach (var i in Task.RunAsync(GenerateTerrainThread))
yield return i; yield return i;
// Generate terrain data // Generate terrain data
TerrainData terrainData = new TerrainData(); TerrainData terrainData = new TerrainData();
terrainData.heightmapResolution = Mathf.Max(map.Height, map.Width) + 1; terrainData.heightmapResolution = Mathf.Max(map.Height, map.Width) + 1;
terrainData.size = new Vector3(map.Width, map.Biome.Height, map.Height); terrainData.size = new Vector3(map.Width, map.Biome.Height, map.Height);
terrainData.SetDetailResolution(1024, 8); terrainData.SetDetailResolution(1024, 8);
terrainData.SetHeights(0, 0, map.Heights); terrainData.SetHeights(0, 0, map.Heights);
terrainData.name = "Generated Terrain Data"; terrainData.name = "Generated Terrain Data";
yield return null; yield return null;
// Create terrain object // Create terrain object
GameObject terrain = Terrain.CreateTerrainGameObject(terrainData); GameObject terrain = Terrain.CreateTerrainGameObject(terrainData);
terrain.name = "Generated Terrain"; terrain.name = "Generated Terrain";
yield return null; yield return null;
Terrain terrainComp = terrain.GetComponent<Terrain>(); Terrain terrainComp = terrain.GetComponent<Terrain>();
terrainComp.heightmapPixelError = 1; terrainComp.heightmapPixelError = 1;
yield return null; yield return null;
// Set water // Set water
if (WaterObject != null) if (WaterObject != null)
{ {
MeshFilter waterMesh = WaterObject.GetComponent<MeshFilter>(); MeshFilter waterMesh = WaterObject.GetComponent<MeshFilter>();
waterMesh.mesh = GenerateWater(); waterMesh.mesh = GenerateWater();
} }
// Set up textures // Set up textures
} }
// Update is called once per frame // Update is called once per frame
void Update() 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 GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = Assembly-CSharp.csproj StartupItem = Assembly-CSharp.csproj
Policies = $0 Policies = $0
$0.TextStylePolicy = $1 $0.TextStylePolicy = $1

View File

@ -29,7 +29,7 @@ Global
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = Assembly-CSharp.csproj StartupItem = Assembly-CSharp.csproj
Policies = $0 Policies = $0
$0.TextStylePolicy = $1 $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 Base path: C:/Program Files/Unity/Editor/Data
Pipe name: \\.\pipe\UnityShaderCompiler-32bit-1-8304 Pipe name: \\.\pipe\UnityShaderCompiler-32bit-1-8304
Cmd: getPlatforms 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.cs" />
<Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" /> <Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
<Compile Include="Assets\Scripts\Utils\ColorHelper.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\Logger.cs" />
<Compile Include="Assets\Scripts\Utils\RandomExtensions.cs" /> <Compile Include="Assets\Scripts\Utils\RandomExtensions.cs" />
<Compile Include="Assets\Scripts\Utils\Range.cs" /> <Compile Include="Assets\Scripts\Utils\Range.cs" />