2020-07-15 19:01:28 +00:00
|
|
|
|
using Microsoft.Xna.Framework;
|
|
|
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
|
|
|
using System;
|
2020-07-16 15:34:10 +00:00
|
|
|
|
using System.Collections.Generic;
|
2020-07-15 19:01:28 +00:00
|
|
|
|
|
|
|
|
|
namespace SemiColinGames {
|
|
|
|
|
public sealed class TreeScene : IScene {
|
|
|
|
|
|
2020-07-16 15:34:10 +00:00
|
|
|
|
const int MAX_SEGMENTS = 1000;
|
|
|
|
|
const int MAX_VERTICES = MAX_SEGMENTS * 6; // 2 triangles per segment
|
2020-07-15 19:01:28 +00:00
|
|
|
|
|
2020-07-15 19:56:56 +00:00
|
|
|
|
private readonly Color backgroundColor = Color.SkyBlue;
|
|
|
|
|
private readonly GraphicsDevice graphics;
|
|
|
|
|
private readonly BasicEffect basicEffect;
|
|
|
|
|
|
2020-07-16 15:34:10 +00:00
|
|
|
|
private VertexPositionColor[] vertices;
|
2020-07-15 19:56:56 +00:00
|
|
|
|
private VertexBuffer vertexBuffer;
|
2020-07-15 19:01:28 +00:00
|
|
|
|
|
|
|
|
|
public TreeScene(GraphicsDevice graphics) {
|
|
|
|
|
this.graphics = graphics;
|
2020-07-15 19:56:56 +00:00
|
|
|
|
|
|
|
|
|
basicEffect = new BasicEffect(graphics) {
|
|
|
|
|
World = Matrix.CreateTranslation(0, 0, 0),
|
|
|
|
|
View = Matrix.CreateLookAt(Vector3.Backward, Vector3.Zero, Vector3.Up),
|
2020-07-16 15:34:10 +00:00
|
|
|
|
VertexColorEnabled = true,
|
2020-11-18 17:08:45 +00:00
|
|
|
|
Projection = Matrix.CreateOrthographicOffCenter(
|
|
|
|
|
-1920 / 2, 1920 / 2, -1080 / 4, 1080 * 3 / 4, -1, 1)
|
2020-07-15 19:56:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
2020-07-16 15:34:10 +00:00
|
|
|
|
vertices = new VertexPositionColor[MAX_VERTICES];
|
2020-07-15 19:56:56 +00:00
|
|
|
|
vertexBuffer = new VertexBuffer(
|
2020-07-16 15:34:10 +00:00
|
|
|
|
graphics, typeof(VertexPositionColor), MAX_VERTICES, BufferUsage.WriteOnly);
|
2020-07-15 19:01:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-15 19:17:19 +00:00
|
|
|
|
~TreeScene() {
|
|
|
|
|
Dispose();
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-15 19:01:28 +00:00
|
|
|
|
public void Dispose() {
|
2020-07-15 19:56:56 +00:00
|
|
|
|
vertexBuffer.Dispose();
|
2020-07-15 19:01:28 +00:00
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 15:34:10 +00:00
|
|
|
|
public struct Trapezoid {
|
|
|
|
|
public Vector2 p1, p2, p3, p4;
|
2020-07-21 15:03:02 +00:00
|
|
|
|
|
|
|
|
|
public void Rotate(float angle) {
|
|
|
|
|
p1 = p1.Rotate(angle);
|
|
|
|
|
p2 = p2.Rotate(angle);
|
|
|
|
|
p3 = p3.Rotate(angle);
|
|
|
|
|
p4 = p4.Rotate(angle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Translate(Vector2 position) {
|
|
|
|
|
p1 = Vector2.Add(p1, position);
|
|
|
|
|
p2 = Vector2.Add(p2, position);
|
|
|
|
|
p3 = Vector2.Add(p3, position);
|
|
|
|
|
p4 = Vector2.Add(p4, position);
|
|
|
|
|
}
|
2020-07-16 15:34:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 19:18:30 +00:00
|
|
|
|
public class TreeNode {
|
2020-11-16 19:42:51 +00:00
|
|
|
|
// Ideal orientation, relative to its parent.
|
|
|
|
|
public readonly float Orientation;
|
|
|
|
|
// Orientation in world space.
|
|
|
|
|
public float WorldOrientation;
|
|
|
|
|
|
|
|
|
|
public readonly float Length;
|
|
|
|
|
public readonly float InWidth;
|
|
|
|
|
public readonly float OutWidth;
|
2020-07-16 19:18:30 +00:00
|
|
|
|
public readonly List<TreeNode> Children;
|
2020-11-16 19:42:51 +00:00
|
|
|
|
|
|
|
|
|
// Position of in-vertex in world space.
|
2020-07-16 19:18:30 +00:00
|
|
|
|
public Vector2 Position;
|
|
|
|
|
|
|
|
|
|
public TreeNode(float orientation, float length, float inWidth, float outWidth) :
|
2020-07-16 19:34:22 +00:00
|
|
|
|
this(orientation, length, inWidth, outWidth, new List<TreeNode>()) {
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-18 17:08:45 +00:00
|
|
|
|
public TreeNode(float orientation, float length, float inWidth, float outWidth,
|
|
|
|
|
TreeNode child) :
|
2020-07-16 19:34:22 +00:00
|
|
|
|
this(orientation, length, inWidth, outWidth, new List<TreeNode>() { child }) {
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-18 17:08:45 +00:00
|
|
|
|
public TreeNode(float orientation, float length, float inWidth, float outWidth,
|
|
|
|
|
TreeNode child1, TreeNode child2) :
|
2020-07-16 19:34:22 +00:00
|
|
|
|
this(orientation, length, inWidth, outWidth, new List<TreeNode>() { child1, child2 }) {
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-18 17:08:45 +00:00
|
|
|
|
public TreeNode(float orientation, float length, float inWidth, float outWidth,
|
|
|
|
|
TreeNode child1, TreeNode child2, TreeNode child3) :
|
|
|
|
|
this(orientation, length, inWidth, outWidth,
|
|
|
|
|
new List<TreeNode>() { child1, child2, child3 }) {
|
2020-07-16 19:34:22 +00:00
|
|
|
|
}
|
2020-07-16 19:18:30 +00:00
|
|
|
|
|
2020-11-18 17:08:45 +00:00
|
|
|
|
public TreeNode(float orientation, float length, float inWidth, float outWidth,
|
|
|
|
|
List<TreeNode> children) {
|
2020-07-16 19:18:30 +00:00
|
|
|
|
Orientation = orientation;
|
2020-11-16 19:42:51 +00:00
|
|
|
|
WorldOrientation = orientation;
|
2020-07-16 19:18:30 +00:00
|
|
|
|
Length = length;
|
|
|
|
|
InWidth = inWidth;
|
|
|
|
|
OutWidth = outWidth;
|
|
|
|
|
Children = children;
|
|
|
|
|
Position = Vector2.Zero;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-15 19:01:28 +00:00
|
|
|
|
public void Draw(bool isRunningSlowly, IWorld iworld, bool paused) {
|
2020-07-16 19:18:30 +00:00
|
|
|
|
var tree =
|
2020-11-16 19:42:51 +00:00
|
|
|
|
new TreeNode(0.0f, 100, 10, 6,
|
|
|
|
|
new TreeNode(0.0f, 100, 10, 6,
|
2020-07-16 19:34:22 +00:00
|
|
|
|
new TreeNode(-0.2f, 100, 10, 6,
|
|
|
|
|
new TreeNode(-0.3f, 100, 6, 4,
|
|
|
|
|
new TreeNode(-0.1f, 100, 6, 4,
|
2020-07-16 19:18:30 +00:00
|
|
|
|
new TreeNode(-0.3f, 150, 4, 2),
|
|
|
|
|
new TreeNode(0.2f, 200, 4, 2),
|
2020-07-16 19:34:22 +00:00
|
|
|
|
new TreeNode(0.5f, 100, 4, 2))),
|
|
|
|
|
new TreeNode(0.5f, 100, 6, 4,
|
|
|
|
|
new TreeNode(-0.1f, 100, 6, 4,
|
2020-07-16 19:18:30 +00:00
|
|
|
|
new TreeNode(-0.1f, 150, 4, 2),
|
2020-07-16 19:34:22 +00:00
|
|
|
|
new TreeNode(0.2f, 200, 4, 2))))));
|
2020-07-16 15:34:10 +00:00
|
|
|
|
|
2020-07-15 19:01:28 +00:00
|
|
|
|
graphics.Clear(backgroundColor);
|
2020-07-15 19:56:56 +00:00
|
|
|
|
|
2020-07-16 15:34:10 +00:00
|
|
|
|
var segments = new List<Trapezoid>();
|
|
|
|
|
|
2020-07-16 19:18:30 +00:00
|
|
|
|
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
|
|
|
|
|
queue.AddLast(tree);
|
2020-11-16 19:42:51 +00:00
|
|
|
|
Debug.WriteLine("---------------------");
|
2020-07-16 19:18:30 +00:00
|
|
|
|
while (queue.Count > 0) {
|
|
|
|
|
TreeNode parent = queue.First.Value;
|
|
|
|
|
queue.RemoveFirst();
|
2020-11-16 19:42:51 +00:00
|
|
|
|
Vector2 outVector = new Vector2(0, parent.Length).Rotate(parent.WorldOrientation);
|
2020-07-16 19:18:30 +00:00
|
|
|
|
Vector2 outPosition = Vector2.Add(parent.Position, outVector);
|
2020-07-21 15:03:02 +00:00
|
|
|
|
|
2020-11-16 19:42:51 +00:00
|
|
|
|
outVector.Normalize();
|
|
|
|
|
Vector2 wind = new Vector2(1.0f, 0.0f);
|
|
|
|
|
float windAmount = Vector2.Dot(wind, outVector);
|
|
|
|
|
Debug.WriteLine("" + windAmount);
|
|
|
|
|
|
2020-07-21 15:03:02 +00:00
|
|
|
|
// We want a trapezoid with 4 points. A is the in position, B is the out position.
|
|
|
|
|
// The TreeNode.Length is the distance from A to B.
|
2020-07-21 17:11:50 +00:00
|
|
|
|
//
|
2020-07-21 15:03:02 +00:00
|
|
|
|
// We come up with the points relative to A being the origin, then rotate the trapezoid
|
|
|
|
|
// by its orientation, and translate the result to A's actual position.
|
|
|
|
|
//
|
|
|
|
|
// 3---B---4 <-- length = outWidth
|
|
|
|
|
// / | \
|
|
|
|
|
// / | \
|
|
|
|
|
// 1------A------2 <-- length = inWidth
|
|
|
|
|
|
2020-07-21 17:11:50 +00:00
|
|
|
|
// This fudge factor lengthens the sides a bit longer to prevent small discontinuities
|
|
|
|
|
// in the rendered result.
|
|
|
|
|
// TODO: remove this sideLengthFudge.
|
|
|
|
|
float sideLengthFudge = 1.05f;
|
2020-07-16 19:18:30 +00:00
|
|
|
|
Trapezoid t = new Trapezoid();
|
2020-07-21 15:03:02 +00:00
|
|
|
|
t.p1 = new Vector2(-parent.InWidth, 0);
|
|
|
|
|
t.p2 = new Vector2(parent.InWidth, 0);
|
2020-07-21 17:11:50 +00:00
|
|
|
|
t.p3 = new Vector2(-parent.OutWidth, parent.Length * sideLengthFudge);
|
|
|
|
|
t.p4 = new Vector2(parent.OutWidth, parent.Length * sideLengthFudge);
|
2020-11-16 19:42:51 +00:00
|
|
|
|
t.Rotate(parent.WorldOrientation);
|
2020-07-21 15:03:02 +00:00
|
|
|
|
t.Translate(parent.Position);
|
|
|
|
|
|
2020-07-16 15:34:10 +00:00
|
|
|
|
segments.Add(t);
|
2020-07-16 19:18:30 +00:00
|
|
|
|
foreach (TreeNode child in parent.Children) {
|
|
|
|
|
child.Position = outPosition;
|
2020-11-16 19:42:51 +00:00
|
|
|
|
float orientation = parent.WorldOrientation + child.Orientation;
|
|
|
|
|
child.WorldOrientation = orientation;
|
2020-07-16 19:18:30 +00:00
|
|
|
|
queue.AddLast(child);
|
|
|
|
|
}
|
2020-07-16 15:34:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Color color = Color.SaddleBrown;
|
|
|
|
|
for (int i = 0; i < segments.Count; i++) {
|
|
|
|
|
Trapezoid t = segments[i];
|
|
|
|
|
vertices[i * 6] = new VertexPositionColor(new Vector3(t.p1.X, t.p1.Y, 0), color);
|
|
|
|
|
vertices[i * 6 + 1] = new VertexPositionColor(new Vector3(t.p2.X, t.p2.Y, 0), color);
|
|
|
|
|
vertices[i * 6 + 2] = new VertexPositionColor(new Vector3(t.p3.X, t.p3.Y, 0), color);
|
|
|
|
|
vertices[i * 6 + 3] = new VertexPositionColor(new Vector3(t.p2.X, t.p2.Y, 0), color);
|
|
|
|
|
vertices[i * 6 + 4] = new VertexPositionColor(new Vector3(t.p3.X, t.p3.Y, 0), color);
|
|
|
|
|
vertices[i * 6 + 5] = new VertexPositionColor(new Vector3(t.p4.X, t.p4.Y, 0), color);
|
|
|
|
|
}
|
2020-07-15 19:56:56 +00:00
|
|
|
|
|
|
|
|
|
graphics.SetVertexBuffer(vertexBuffer);
|
2020-07-16 15:34:10 +00:00
|
|
|
|
vertexBuffer.SetData(vertices);
|
|
|
|
|
|
2020-07-15 19:56:56 +00:00
|
|
|
|
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes) {
|
|
|
|
|
pass.Apply();
|
2020-07-16 15:34:10 +00:00
|
|
|
|
graphics.DrawPrimitives(PrimitiveType.TriangleList, 0, segments.Count * 2);
|
2020-07-15 19:56:56 +00:00
|
|
|
|
}
|
2020-07-15 19:01:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|