add Gwen UI input processor and renderer implementations (ported)

This commit is contained in:
Gered 2013-08-24 13:56:15 -04:00
parent 6e13c6434e
commit a5a83dd7dc
3 changed files with 434 additions and 0 deletions

View file

@ -177,6 +177,8 @@
<Compile Include="Content\Types\ImageLoader.cs" />
<Compile Include="Content\Types\TextureLoader.cs" />
<Compile Include="Content\Types\SpriteFontLoader.cs" />
<Compile Include="UI\GwenInputProcessor.cs" />
<Compile Include="UI\GwenSpriteBatchRenderer.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<ItemGroup>
@ -199,6 +201,7 @@
<Folder Include="Processes\" />
<Folder Include="Content\" />
<Folder Include="Content\Types\" />
<Folder Include="UI\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\Fonts\Vera.ttf" />

View file

@ -0,0 +1,221 @@
using System;
using Blarg.GameFramework.Input;
namespace Blarg.GameFramework.UI
{
public class GwenInputProcessor : IKeyboardListener, IMouseListener, ITouchListener
{
Gwen.Control.Canvas _canvas;
bool _isEnabled;
public GwenInputProcessor(Gwen.Control.Canvas canvas)
{
if (canvas == null)
throw new ArgumentNullException("canvas");
_canvas = canvas;
}
#region Enable / Disable
public bool Enabled
{
get { return _isEnabled; }
set { _isEnabled = Enable(value); }
}
private bool Enable(bool enable)
{
if (_isEnabled != enable)
{
var keyboard = Framework.Keyboard;
var mouse = Framework.Mouse;
var touchscreen = Framework.TouchScreen;
if (enable)
{
if (keyboard != null)
keyboard.RegisterListener(this);
if (mouse != null)
mouse.RegisterListener(this);
if (touchscreen != null)
touchscreen.RegisterListener(this);
}
else
{
if (keyboard != null)
keyboard.UnregisterListener(this);
if (mouse != null)
mouse.UnregisterListener(this);
if (touchscreen != null)
touchscreen.UnregisterListener(this);
}
}
return enable;
}
#endregion
#region Keyboard Events
public bool OnKeyDown(Key key)
{
char ch = ConvertKeyToChar(key);
if (Gwen.Input.InputHandler.DoSpecialKeys(_canvas, ch))
return false;
var gwenKey = ConvertToGwenKey(key);
return _canvas.Input_Key(gwenKey, true);
}
public bool OnKeyUp(Key key)
{
var gwenKey = ConvertToGwenKey(key);
return _canvas.Input_Key(gwenKey, false);
}
#endregion
#region Mouse Events
public bool OnMouseButtonDown(MouseButton button, int x, int y)
{
int gwenButton = (int)button;
int scaledX = (int)((float)x / _canvas.Scale);
int scaledY = (int)((float)y / _canvas.Scale);
// trigger mouse move event for button events to ensure GWEN
// knows where the button event occured at
bool movedResult = _canvas.Input_MouseMoved(scaledX, scaledY, 0, 0);
bool clickResult = _canvas.Input_MouseButton(gwenButton, true);
// TODO: is this really the right way to do this .. ?
return (movedResult || clickResult);
}
public bool OnMouseButtonUp(MouseButton button, int x, int y)
{
int gwenButton = (int)button;
int scaledX = (int)((float)x / _canvas.Scale);
int scaledY = (int)((float)y / _canvas.Scale);
// trigger mouse move event for button events to ensure GWEN
// knows where the button event occured at
bool movedResult = _canvas.Input_MouseMoved(scaledX, scaledY, 0, 0);
bool clickResult = _canvas.Input_MouseButton(gwenButton, false);
// TODO: is this really the right way to do this .. ?
return (movedResult || clickResult);
}
public bool OnMouseMove(int x, int y, int deltaX, int deltaY)
{
// Gwen's input handling only processes coordinates in terms of scale = 1.0f
int scaledX = (int)((float)x / _canvas.Scale);
int scaledY = (int)((float)y / _canvas.Scale);
int scaledDeltaX = (int)((float)deltaX / _canvas.Scale);
int scaledDeltaY = (int)((float)deltaY / _canvas.Scale);
return _canvas.Input_MouseMoved(scaledX, scaledY, scaledDeltaX, scaledDeltaY);
}
#endregion
#region Touchscreen Events
public bool OnTouchDown(int id, int x, int y, bool isPrimary)
{
if (!isPrimary)
return false;
// Gwen's input handling only processes coordinates in terms of scale = 1.0f
int scaledX = (int)((float)x / _canvas.Scale);
int scaledY = (int)((float)y / _canvas.Scale);
bool movedResult = _canvas.Input_MouseMoved(scaledX, scaledY, 0, 0);
bool clickResult = _canvas.Input_MouseButton(0, true);
// TODO: is this really the right way to do this .. ?
return (movedResult || clickResult);
}
public bool OnTouchUp(int id, bool isPrimary)
{
if (!isPrimary)
return false;
bool clickResult = _canvas.Input_MouseButton(0, false);
// we do this so that GWEN isn't left thinking that the "mouse" is
// hovering over whatever we were just clicking/touching. This is
// done because obviously with a touchscreen, you don't hover over
// anything unless you are clicking/touching...
bool movedResult = _canvas.Input_MouseMoved(-1, -1, 0, 0);
// TODO: is this really the right way to do this .. ?
return (movedResult || clickResult);
}
public bool OnTouchMove(int id, int x, int y, int deltaX, int deltaY, bool isPrimary)
{
if (!isPrimary)
return false;
// Gwen's input handling only processes coordinates in terms of scale = 1.0f
int scaledX = (int)((float)x / _canvas.Scale);
int scaledY = (int)((float)y / _canvas.Scale);
int scaledDeltaX = (int)((float)deltaX / _canvas.Scale);
int scaledDeltaY = (int)((float)deltaY / _canvas.Scale);
bool movedResult = _canvas.Input_MouseMoved(scaledX, scaledY, scaledDeltaX, scaledDeltaY);
bool clickResult = _canvas.Input_MouseButton(0, true);
// TODO: is this really the right way to do this .. ?
return (movedResult || clickResult);
}
#endregion
#region Misc
private char ConvertKeyToChar(Key key)
{
if (key >= Key.A && key <= Key.Z)
return (char)('a' + ((int)key - (int)Key.A));
else
return ' ';
}
private Gwen.Key ConvertToGwenKey(Key key)
{
switch (key)
{
case Key.Backspace: return Gwen.Key.Backspace;
case Key.Enter: return Gwen.Key.Return;
case Key.Escape: return Gwen.Key.Escape;
case Key.Tab: return Gwen.Key.Tab;
case Key.Space: return Gwen.Key.Space;
case Key.Up: return Gwen.Key.Up;
case Key.Down: return Gwen.Key.Down;
case Key.Left: return Gwen.Key.Left;
case Key.Right: return Gwen.Key.Right;
case Key.Home: return Gwen.Key.Home;
case Key.End: return Gwen.Key.End;
case Key.Delete: return Gwen.Key.Delete;
case Key.LeftCtrl: return Gwen.Key.Control;
case Key.LeftAlt: return Gwen.Key.Alt;
case Key.LeftShift: return Gwen.Key.Shift;
case Key.RightCtrl: return Gwen.Key.Control;
case Key.RightAlt: return Gwen.Key.Alt;
case Key.RightShift: return Gwen.Key.Shift;
}
return Gwen.Key.Invalid;
}
#endregion
}
}

View file

@ -0,0 +1,210 @@
using System;
using Blarg.GameFramework.Content;
using Blarg.GameFramework.Graphics;
namespace Blarg.GameFramework.UI
{
public class GwenSpriteBatchRenderer : Gwen.Renderer.Base
{
const string LOG_TAG = "GWEN";
ContentManager _contentManager;
GraphicsDevice _graphicsDevice;
SpriteBatch _spriteBatch;
public GwenSpriteBatchRenderer(ContentManager contentManager, GraphicsDevice graphicsDevice)
{
if (contentManager == null)
throw new ArgumentNullException("contentManager");
if (graphicsDevice == null)
throw new ArgumentNullException("graphicsDevice");
_contentManager = contentManager;
_graphicsDevice = graphicsDevice;
Alpha = Color.AlphaOpaque;
}
#region Begin / End
public void PreRender(SpriteBatch spriteBatch)
{
if (spriteBatch == null)
throw new ArgumentNullException("spriteBatch");
_spriteBatch = spriteBatch;
}
public void PostRender()
{
_spriteBatch = null;
}
public override void Begin()
{
if (_spriteBatch == null)
throw new InvalidOperationException();
base.Begin();
}
public override void End()
{
base.End();
}
#endregion
#region Rendering States / Properties
public float Alpha { get; set; }
public override void StartClip()
{
var rect = ClipRegion;
int left = (int)((float)rect.X * Scale);
int top = (int)((float)rect.Y * Scale);
int right = (int)((float)(rect.X + rect.Width) * Scale);
int bottom = (int)((float)(rect.Y + rect.Height) * Scale);
_spriteBatch.BeginClipping(left, top, right, bottom);
}
public override void EndClip()
{
_spriteBatch.EndClipping();
}
private void AdjustColorForAlpha(ref Color color)
{
color.A *= Alpha;
}
#endregion
#region General Rendering Operations
public override void DrawFilledRect(Gwen.Rectangle rect)
{
Translate(rect);
var renderColor = new Color((int)DrawColor.R, (int)DrawColor.G, (int)DrawColor.B, (int)DrawColor.A);
AdjustColorForAlpha(ref renderColor);
// TODO: this solid color texture should probably be grabbed using a color
// that has A = 1.0 always otherwise any kind of fading, etc. will
// result in many different solid color's ending up in the solid color
// texture cache (due to all the different A values!)
var colorTexture = _graphicsDevice.GetSolidColorTexture(ref renderColor);
_spriteBatch.Render(colorTexture, rect.X, rect.Y, rect.Width, rect.Height);
}
#endregion
#region Textured Rendering
public override void LoadTexture(Gwen.Texture t)
{
Framework.Logger.Info(LOG_TAG, "SpriteBatchRenderer loading texture \"{0}\".", t.Name);
var texture = _contentManager.Get<Texture>(t.Name);
t.RendererData = texture;
t.Width = texture.Width;
t.Height = texture.Height;
}
public override void FreeTexture(Gwen.Texture t)
{
// right now we don't care, ContentManager.RemoveAlLContent() can and will take care of this
// (Gwen doesn't really load too many resources that I think we really need to care about this)
}
public override void DrawTexturedRect(Gwen.Texture t, Gwen.Rectangle targetRect, float u1, float v1, float u2, float v2)
{
if (t.RendererData == null)
throw new InvalidOperationException();
Translate(targetRect);
var texture = (Texture)t.RendererData;
var renderColor = Color.White;
AdjustColorForAlpha(ref renderColor);
_spriteBatch.Render(texture, targetRect.X, targetRect.Y, targetRect.Width, targetRect.Height, u1, v1, u2, v2, ref renderColor);
}
public override Gwen.Color PixelColor(Gwen.Texture texture, uint x, uint y, Gwen.Color defaultColor)
{
if (texture.RendererData == null)
return defaultColor;
// This method is really only used by Gwen to figure out various "system" colors
// at initialization time. Pixel colors are read from the renderer skin texture
// pretty sure no other textures are ever used with this method. Unless some
// future custom control eventually is needed to read pixel colors...
//
// We load the image using ContentManager, but it won't be released... at least
// not until the next ContentManager.RemoveAllContent() call (not done by this class)
// I feel that this is fine given the above about only one texture (and therefore
// only one image) being ever read by this method.
var image = _contentManager.Get<Image>(texture.Name);
var pixelColor = image.GetColorAt((int)x, (int)y);
return Gwen.Color.FromArgb(pixelColor.IntA, pixelColor.IntR, pixelColor.IntG, pixelColor.IntB);
}
#endregion
#region Font Rendering
public override bool LoadFont(Gwen.Font font)
{
Framework.Logger.Info(LOG_TAG, "SpriteBatchRenderer loading font \"{0}\".", font.FaceName);
int size = font.Size;
var spriteFont = _contentManager.Get<SpriteFont>(font.FaceName, size);
font.RendererData = spriteFont;
return true;
}
public override void FreeFont(Gwen.Font font)
{
// right now we don't care, ContentManager.RemoveAlLContent() can and will take care of this
// (Gwen doesn't really load too many resources that I think we really need to care about this)
}
public override void RenderText(Gwen.Font font, Gwen.Point position, string text)
{
Translate(position);
var spriteFont = (SpriteFont)font.RendererData;
var renderColor = new Color((int)DrawColor.R, (int)DrawColor.G, (int)DrawColor.B, (int)DrawColor.A);
AdjustColorForAlpha(ref renderColor);
_spriteBatch.Render(spriteFont, position.X, position.Y, ref renderColor, Scale, text);
}
public override Gwen.Point MeasureText(Gwen.Font font, string text)
{
// HACK: is this supposed to work this way? seems that MeasureText
// can (and will) get called from Gwen's classes before a call
// to LoadFont is made...
if (font.RendererData == null)
LoadFont(font);
if (font.RendererData == null)
throw new Exception("Failed to load font.");
var spriteFont = (SpriteFont)font.RendererData;
int width;
int height;
spriteFont.MeasureString(out width, out height, text);
return new Gwen.Point(width, height);
}
#endregion
}
}