ebiten/cmd/ebitenmonogame/gogame.cs
2020-04-24 20:48:01 +09:00

232 lines
7.7 KiB
C#

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.IO;
using {{.Namespace}}.AutoGen;
namespace {{.Namespace}}
{
// Operation must sync with driver.Operation.
enum Operation
{
Zero,
One,
SrcAlpha,
DstAlpha,
OneMinusSrcAlpha,
OneMinusDstAlpha,
}
public class GoGame : Game
{
private GraphicsDeviceManager graphics;
private IInvokable onUpdate;
private IInvokable onDraw;
private VertexBuffer vertexBuffer;
private IndexBuffer indexBuffer;
private Effect effect;
public GoGame(IInvokable onUpdate, IInvokable onDraw)
{
this.onUpdate = onUpdate;
this.onDraw = onDraw;
this.graphics = new GraphicsDeviceManager(this);
this.graphics.PreferredBackBufferWidth = 640;
this.graphics.PreferredBackBufferHeight = 480;
this.Content.RootDirectory = "Content";
this.IsMouseVisible = true;
}
protected override void LoadContent()
{
VertexElement[] elements = new VertexElement[]
{
new VertexElement(sizeof(float)*0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0),
new VertexElement(sizeof(float)*2, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
new VertexElement(sizeof(float)*4, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 1),
new VertexElement(sizeof(float)*8, VertexElementFormat.Vector4, VertexElementUsage.Color, 0),
};
this.vertexBuffer = new DynamicVertexBuffer(
this.GraphicsDevice, new VertexDeclaration(elements), 65536, BufferUsage.None);
this.GraphicsDevice.SetVertexBuffer(this.vertexBuffer);
this.indexBuffer = new DynamicIndexBuffer(
this.GraphicsDevice, IndexElementSize.SixteenBits, 65536, BufferUsage.None);
this.GraphicsDevice.Indices = this.indexBuffer;
// TODO: Add more shaders for e.g., linear filter.
this.effect = Content.Load<Effect>("Shader");
this.GraphicsDevice.RasterizerState = new RasterizerState()
{
CullMode = CullMode.None,
};
base.LoadContent();
}
internal void SetDestination(RenderTarget2D renderTarget2D, int viewportWidth, int viewportHeight)
{
this.GraphicsDevice.SetRenderTarget(renderTarget2D);
this.GraphicsDevice.Viewport = new Viewport(0, 0, viewportWidth, viewportHeight);
this.effect.Parameters["ViewportSize"].SetValue(new Vector2(viewportWidth, viewportHeight));
}
internal void SetSource(Texture2D texture2D)
{
this.effect.Parameters["Texture"].SetValue(texture2D);
}
internal void SetVertices(byte[] vertices, byte[] indices)
{
this.vertexBuffer.SetData(vertices, 0, vertices.Length);
this.indexBuffer.SetData(indices, 0, indices.Length);
}
protected override void Update(GameTime gameTime)
{
this.onUpdate.Invoke(null);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
this.onDraw.Invoke(null);
base.Draw(gameTime);
}
internal void DrawTriangles(int indexLen, int indexOffset, Blend blendSrc, Blend blendDst)
{
this.GraphicsDevice.BlendState = new BlendState()
{
AlphaSourceBlend = blendSrc,
ColorSourceBlend = blendSrc,
AlphaDestinationBlend = blendDst,
ColorDestinationBlend = blendDst,
};
foreach (EffectPass pass in this.effect.CurrentTechnique.Passes)
{
pass.Apply();
this.GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList, 0, indexOffset, indexLen / 3);
}
}
}
// This methods are called from Go world. They must not have overloads.
class GameGoBinding
{
private static Blend ToBlend(Operation operation)
{
switch (operation)
{
case Operation.Zero:
return Blend.Zero;
case Operation.One:
return Blend.One;
case Operation.SrcAlpha:
return Blend.SourceAlpha;
case Operation.DstAlpha:
return Blend.DestinationAlpha;
case Operation.OneMinusSrcAlpha:
return Blend.InverseSourceAlpha;
case Operation.OneMinusDstAlpha:
return Blend.InverseDestinationAlpha;
}
throw new ArgumentOutOfRangeException("operation", operation, "");
}
private GoGame game;
private GameGoBinding(IInvokable onUpdate, IInvokable onDraw)
{
this.game = new GoGame(onUpdate, onDraw);
}
private void Run()
{
try
{
this.game.Run();
}
finally
{
this.game.Dispose();
}
}
private RenderTarget2D NewRenderTarget2D(double width, double height)
{
return new RenderTarget2D(this.game.GraphicsDevice, (int)width, (int)height);
}
private void Dispose(Texture2D texture2D)
{
texture2D.Dispose();
}
private void ReplacePixels(RenderTarget2D renderTarget2D, byte[] pixels, double x, double y, double width, double height)
{
var rect = new Rectangle((int)x, (int)y, (int)width, (int)height);
renderTarget2D.SetData(0, rect, pixels, 0, pixels.Length);
}
private byte[] Pixels(Texture2D texture2D, double width, double height)
{
Rectangle rect = new Rectangle(0, 0, (int)width, (int)height);
byte[] data = new byte[4*(int)width*(int)height];
texture2D.GetData(0, rect, data, 0, data.Length);
return data;
}
private void SetDestination(RenderTarget2D renderTarget2D, double viewportWidth, double viewportHeight)
{
this.game.SetDestination(renderTarget2D, (int)viewportWidth, (int)viewportHeight);
}
private void SetSource(Texture2D texture2D)
{
this.game.SetSource(texture2D);
}
private void SetVertices(byte[] vertices, byte[] indices)
{
this.game.SetVertices(vertices, indices);
}
private void Draw(double indexLen, double indexOffset, double operationSrc, double operationDst)
{
this.game.DrawTriangles((int)indexLen, (int)indexOffset, ToBlend((Operation)operationSrc), ToBlend((Operation)operationDst));
}
private bool IsKeyPressed(string driverKey)
{
Keys key;
switch (driverKey)
{
case "KeyDown":
key = Keys.Down;
break;
case "KeyLeft":
key = Keys.Left;
break;
case "KeySpace":
key = Keys.Space;
break;
case "KeyRight":
key = Keys.Right;
break;
case "KeyUp":
key = Keys.Up;
break;
default:
return false;
}
return Keyboard.GetState().IsKeyDown(key);
}
}
}