using SFML.Graphics;
using SFML.System;
using SFML.Window;
namespace Otter {
///
/// Class used for rendering graphics.
///
public class Draw {
#region Static Fields
static internal SpriteBatch SpriteBatch = new SpriteBatch();
static internal RenderStates renderStates = RenderStates.Default;
static RectangleShape tempRect = new RectangleShape();
static CircleShape tempCircle = new CircleShape();
#endregion
#region Static Methods
static internal void Drawable(Drawable drawable, RenderStates states) {
SpriteBatch.End();
Target.Draw(drawable, states);
if (Game.Instance.countRendering) Game.Instance.RenderCount++;
}
static internal void Drawable(Vertex[] vertices, RenderStates states) {
SpriteBatch.End();
Target.Draw(vertices, states);
if (Game.Instance.countRendering) Game.Instance.RenderCount++;
}
static internal void Spritebatch(VertexArray vertices, RenderStates states) {
Target.Draw(vertices, states);
if (Game.Instance.countRendering) Game.Instance.RenderCount++;
}
static internal void Batchable(VertexArray vertices, RenderStates states) {
SpriteBatch.Begin();
SpriteBatch.Draw(vertices, states);
}
///
/// Renders a Graphic to the current target Surface.
///
/// The Graphic to render.
/// The x offset to position the Graphic at.
/// The y offset to position the Graphic at.
static public void Graphic(Graphic graphic, float x = 0, float y = 0) {
graphic.Render(x, y);
}
///
/// Renders an Entity.
///
/// The Entity to render.
public static void Entity(Entity e) {
e.RenderInternal();
}
///
/// Renders an Entity at a specified X Y position.
///
/// The Entity to render.
/// The X position to place the Entity for rendering.
/// The Y position to place the Entity for rendering.
public static void Entity(Entity e, float x = 0, float y = 0) {
var tempX = e.X;
var tempY = e.Y;
e.SetPosition(x, y);
Entity(e);
e.SetPosition(tempX, tempY);
}
///
/// Draws simple Text. Should only be used for debugging as this creates Text Graphics each time it's called!
///
/// The string to display.
/// The size of the Text.
/// The X position to render the Text from.
/// The Y position to render the Text from.
public static void Text(string str, int size, float x = 0, float y = 0) {
Draw.Graphic(new Text(str, size), x, y);
}
///
/// Renders a clipped Image to the current target Surface.
///
/// the Image to render.
/// The portion of the Image to render.
/// The x offset to position the Image at.
/// The y offset to position the Image at.
static public void ImageClip(Image image, Rectangle clip, float x = 0, float y = 0) {
var tempRect = image.ClippingRegion;
image.ClippingRegion = clip;
image.Render(x, y);
image.ClippingRegion = tempRect;
}
///
/// Draws an Image in parts to form a horizontally waving image.
///
/// The image to draw.
/// How many steps to iterate through for the wave.
/// The timer the wave should act with.
/// The rate which the wave should move at.
/// How far the wave will offset the image.
/// How frequent the wave should repeat.
/// The x position to draw the image from.
/// The y position to draw the image from.
static public void ImageWaveX(Image image, int step, float timer, float rate, float amp, float freq, float x = 0, float y = 0) {
for (var yy = 0; yy < image.Height; yy += step) {
yy = (int)Util.Clamp(yy, image.Height);
var xx = (int)Util.SinScale(timer * rate + yy * freq, -amp, amp);
ImageClip(image, new Rectangle(0, yy, image.Width, step), x + xx, y);
}
}
///
/// Draws an Image in parts to form a vertically waving image.
///
/// The image to draw.
/// How many steps to iterate through for the wave.
/// The timer the wave should act with.
/// The rate which the wave should move at.
/// How far the wave will offset the image.
/// How frequent the wave should repeat.
/// The x position to draw the image from.
/// The y position to draw the image from.
static public void ImageWaveY(Image image, int step, float timer, float rate, float amp, float freq, float x = 0, float y = 0) {
for (var xx = 0; xx < image.Width; xx += step) {
xx = (int)Util.Clamp(xx, image.Width);
var yy = (int)Util.SinScale(timer * rate + xx * freq, -amp, amp);
ImageClip(image, new Rectangle(xx, 0, step, image.Height), x, y + yy);
}
}
///
/// Change the Surface that is being rendered to.
///
/// The new target Surface.
static public void SetTarget(Surface target) {
if (Target != target) {
SpriteBatch.End();
}
Target = target;
}
///
/// Reset the Surface that is being rendered to back to the default for the current Game.
///
static public void ResetTarget() {
if (Target != GameTarget) {
SpriteBatch.End();
}
Target = GameTarget;
}
///
/// Draws a circle. Recommended to use only for debugging purposes.
///
/// The X position of the top left of the circle.
/// The Y position of the top left of the circle.
/// The radius of the circle.
/// The fill color of the circle.
/// The outline color of the circle.
/// The outline thickness of the circle.
static public void Circle(float x, float y, int radius, Color fill = null, Color outline = null, float outlineThickness = 0) {
tempCircle.Radius = radius;
tempCircle.Position = new Vector2f(x, y);
if (fill == null) {
tempCircle.FillColor = Color.White.SFMLColor;
}
else {
tempCircle.FillColor = fill.SFMLColor;
}
tempCircle.OutlineThickness = outlineThickness;
if (outline == null) {
tempCircle.OutlineColor = Color.None.SFMLColor;
}
else {
tempCircle.OutlineColor = outline.SFMLColor;
}
Target.Draw(tempCircle);
}
///
/// Draws a circle. Recommended to use only for debugging purposes.
///
/// The X position of the top left of the circle.
/// The Y position of the top left of the circle.
/// The radius of the circle.
/// The fill color of the circle.
static public void Circle(float x, float y, float radius, Color color) {
tempCircle.Radius = radius;
tempCircle.Position = new Vector2f(x, y);
tempCircle.FillColor = color.SFMLColor;
Target.Draw(tempCircle);
}
///
/// Draws a rectangle. Recommended to use only for debugging purposes.
///
/// The X position of the top left of the rectangle.
/// The Y position of the top left of the rectangle.
/// The width of the rectangle.
/// The height of the rectangle.
/// The fill color of the rectangle.
/// The outline color of the rectangle.
/// The outline thickness of the rectangle.
static public void Rectangle(float x, float y, float width, float height, Color fill = null, Color outline = null, float outlineThickness = 0) {
tempRect.Size = new Vector2f(width, height);
tempRect.Position = new Vector2f(x, y);
if (outline == null) {
tempRect.OutlineColor = Color.None.SFMLColor;
}
else {
tempRect.OutlineColor = outline.SFMLColor;
}
tempRect.OutlineThickness = outlineThickness;
if (fill == null) {
tempRect.FillColor = Color.White.SFMLColor;
}
else {
tempRect.FillColor = fill.SFMLColor;
}
Target.Draw(tempRect);
}
///
/// Draws a line using an OpenGL line.
///
/// The X position of the first point.
/// The Y position of the first point.
/// The X position of the second point.
/// The Y position of the second point.
/// The color of the line.
static public void Line(float x1, float y1, float x2, float y2, Color color) {
VertexArray vertices = new VertexArray(PrimitiveType.Lines);
vertices.Append(new Vertex(new Vector2f(x1, y1), color.SFMLColor));
vertices.Append(new Vertex(new Vector2f(x2, y2), color.SFMLColor));
Drawable(vertices, RenderStates.Default);
}
///
/// Draws a line with a thickness using a quad.
///
/// The X position of the first point.
/// The Y position of the first point.
/// The X position of the second point.
/// The Y position of the second point.
/// The color of the line.
/// The thickness of the line.
static public void Line(float x1, float y1, float x2, float y2, Color color, float thickness) {
VertexArray vertices = new VertexArray(PrimitiveType.Quads);
var line = new Vector2(x2 - x1, y2 - y1);
var normalUp = new Vector2(y1 - y2, x2 - x1);
var normalDown = new Vector2(y2 - y1, x1 - x2);
normalUp.Normalize(thickness * 0.5f);
normalDown.Normalize(thickness * 0.5f);
float vx, vy;
vx = (float)(x1 + normalUp.X);
vy = (float)(y1 + normalUp.Y);
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
vx = (float)(x1 + normalDown.X);
vy = (float)(y1 + normalDown.Y);
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
vx = (float)(x2 + normalDown.X);
vy = (float)(y2 + normalDown.Y);
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
vx = (float)(x2 + normalUp.X);
vy = (float)(y2 + normalUp.Y);
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
Drawable(vertices, RenderStates.Default);
}
///
/// Draws a line with rounded ends.
///
/// The X position of the first point.
/// The Y position of the first point.
/// The X position of the second point.
/// The Y position of the second point.
/// The color of the line.
/// The thickness of the line.
static public void RoundedLine(float x1, float y1, float x2, float y2, Color color, float thickness) {
VertexArray vertices = new VertexArray(PrimitiveType.TrianglesFan);
int rotationSteps = 10;
var line = new Vector2(x2 - x1, y2 - y1);
var normalUp = new Vector2(y1 - y2, x2 - x1);
var normalDown = new Vector2(y2 - y1, x1 - x2);
normalUp.Normalize(thickness * 0.5f);
normalDown.Normalize(thickness * 0.5f);
var nextPoint = new Vector2();
float vx, vy;
vx = x1;
vy = y1;
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
vx = (float)(x1 + normalUp.X);
vy = (float)(y1 + normalUp.Y);
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
nextPoint.X = normalUp.X;
nextPoint.Y = normalUp.Y;
for (int i = 0; i < rotationSteps; i++) {
nextPoint = Util.Rotate(nextPoint, -180 / rotationSteps);
vx = (float)(x1 + nextPoint.X);
vy = (float)(y1 + nextPoint.Y);
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
}
vx = (float)(x1 + normalDown.X);
vy = (float)(y1 + normalDown.Y);
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
vx = (float)(x2 + normalDown.X);
vy = (float)(y2 + normalDown.Y);
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
for (int i = 0; i < rotationSteps; i++) {
nextPoint = Util.Rotate(nextPoint, -180 / rotationSteps);
vx = (float)(x2 + nextPoint.X);
vy = (float)(y2 + nextPoint.Y);
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
}
vx = (float)(x2 + normalUp.X);
vy = (float)(y2 + normalUp.Y);
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
vx = (float)(x1 + normalUp.X);
vy = (float)(y1 + normalUp.Y);
vertices.Append(new Vertex(new Vector2f(vx, vy), color.SFMLColor));
Drawable(vertices, RenderStates.Default);
}
#endregion
#region Public Properties
///
/// The current target Surface to render to.
///
static public Surface Target { get; internal set; }
///
/// The surface that current Game is rendering to.
///
static public Surface GameTarget { get; internal set; }
#endregion
}
}