Created
August 29, 2018 13:32
-
-
Save jessefreeman/3d52ceecc1d3eaa7d76a19dc3e53d28e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Microsoft.Xna.Framework; | |
using Microsoft.Xna.Framework.Graphics; | |
using PixelVisionRunner; | |
using PixelVisionSDK; | |
using PixelVisionSDK.Utils; | |
namespace MonoGameRunner.Data | |
{ | |
public class DisplayTarget : IDisplayTarget | |
{ | |
private GraphicsDeviceManager graphicManager; | |
private Texture2D renderTexture; | |
private SpriteBatch spriteBatch; | |
private int _totalPixels; | |
private int totalPixels | |
{ | |
get { return _totalPixels; } | |
set | |
{ | |
if (cachedPixels.Length != value) | |
{ | |
// Now it's time to resize our cahcedPixels array. We calculate the total number of pixels by multiplying the width by the | |
// height. We'll use this array to make sure we have enough pixels to correctly render the DisplayChip's own pixel data. | |
Array.Resize(ref cachedPixels, value); | |
} | |
_totalPixels = value; | |
} | |
} | |
private int bgColorID; | |
private int[] pixelData; | |
private int colorRef; | |
private IColor[] colorsData; | |
private int i; | |
private IColor colorData; | |
public Color[] cachedColors = new Color[0]; | |
protected Color[] cachedPixels = new Color[0]; | |
protected int totalCachedColors; | |
private Rectangle visibleRect; | |
private readonly GraphicsDeviceManager _graphicsDeviceManager; | |
private int _monitorWidth = 640; | |
private int _monitorHeight = 640; | |
// TODO think we just need to pass in the active game and not the entire runner? | |
public DisplayTarget(GraphicsDeviceManager graphicManager, int width, int height, int scale = 1, bool fullscreen = false) | |
{ | |
this.graphicManager = graphicManager; | |
this.graphicManager.HardwareModeSwitch = false; | |
spriteBatch = new SpriteBatch(graphicManager.GraphicsDevice); | |
_monitorWidth = width.Clamp(64, 640); | |
_monitorHeight = height.Clamp(64, 480); | |
monitorScale = scale; | |
} | |
private int _monitorScale = 1; | |
public int monitorScale | |
{ | |
get { return _monitorScale; } | |
set { _monitorScale = value.Clamp(1, 6); } | |
} | |
public Vector2 scale = new Vector2(1, 1); | |
public Vector2 offset; | |
private GameWindow window; | |
public void ResetResolution(IEngine activeEngine, bool fullscreen, bool matchResolution, bool stretch) | |
{ | |
var displayChip = activeEngine.displayChip; | |
var gameWidth = displayChip.width; | |
var gameHeight = displayChip.height; | |
var overScanX = displayChip.overscanXPixels; | |
var overScanY = displayChip.overscanYPixels; | |
renderTexture?.Dispose(); | |
renderTexture = new Texture2D(graphicManager.GraphicsDevice, gameWidth, gameHeight); | |
// Calculate the game's resolution | |
visibleRect.Width = renderTexture.Width - overScanX; | |
visibleRect.Height = renderTexture.Height - overScanY; | |
var tmpMonitorScale = fullscreen ? 1 : monitorScale; | |
// Calculate the monitor's resolution | |
var displayWidth = fullscreen ? GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width : (_monitorWidth * | |
tmpMonitorScale); | |
var displayHeight = fullscreen ? GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height : _monitorHeight * tmpMonitorScale; | |
// Calculate the game scale | |
// TODO need to figure out scale | |
scale.X = (float)displayWidth / visibleRect.Width; | |
scale.Y = (float)displayHeight/ visibleRect.Height; | |
if (!stretch) | |
{ | |
// To preserve the aspect ratio, | |
// use the smaller scale factor. | |
scale.X = Math.Min(scale.X, scale.Y); | |
scale.Y = scale.X; | |
} | |
offset.X = (displayWidth - (visibleRect.Width * scale.X)) * .5f; | |
offset.Y = (displayHeight - (visibleRect.Height * scale.Y)) * .5f; | |
if (matchResolution && !fullscreen) | |
{ | |
displayWidth = Math.Min(displayWidth, (int) (visibleRect.Width * scale.X)); | |
displayHeight = Math.Min(displayHeight, (int) (visibleRect.Height * scale.Y)); | |
offset.X = 0; | |
offset.Y = 0; | |
} | |
Console.WriteLine("Reset Res Fullscreen " + fullscreen + " "+displayWidth+"x"+displayHeight); | |
// Apply changes | |
graphicManager.IsFullScreen = fullscreen; | |
graphicManager.PreferredBackBufferWidth = displayWidth; | |
graphicManager.PreferredBackBufferHeight = displayHeight; | |
graphicManager.ApplyChanges(); | |
// Update the controller to use the correct mouse scale | |
activeEngine.controllerChip.MouseScale(scale.X, scale.Y); | |
// Set the new number of pixels | |
totalPixels = displayChip.totalPixels; | |
} | |
public void Render(IEngine activeEngine) | |
{ | |
if (activeEngine == null) return; | |
// The first part of rendering Pixel Vision 8's DisplayChip is to get all of the current pixel data during the current frame. Each | |
// Integer in this Array contains an ID we can use to match up to the cached colors we created when setting up the Runner. | |
pixelData = activeEngine.displayChip.pixels; //.displayPixelData; | |
// Need to make sure we are using the latest colors. | |
if (activeEngine.colorChip.invalid) | |
CacheColors(activeEngine); | |
// Now it's time to loop through all of the DisplayChip's pixel data. | |
for (i = 0; i < totalPixels; i++) | |
{ | |
// Here we get a reference to the color we are trying to look up from the pixelData array. Then we compare that ID to what we | |
// have in the cachedPixels. If the color is out of range, we use the cachedTransparentColor. If the color exists in the cache we use that. | |
colorRef = pixelData[i]; | |
// Replace transparent colors with bg for next pass | |
if (colorRef < 0 || (colorRef >= totalCachedColors)) | |
{ | |
colorRef = bgColorID; | |
} | |
cachedPixels[i] = cachedColors[colorRef]; | |
// As you can see, we are using a protected field called cachedPixels. When we call ResetResolution, we resize this array to make sure that | |
// it matches the length of the DisplayChip's pixel data. By keeping a reference to this Array and updating each color instead of rebuilding | |
// it, we can significantly increase the render performance of the Runner. | |
} | |
renderTexture.SetData(cachedPixels); | |
spriteBatch.Begin(samplerState: SamplerState.PointClamp); | |
spriteBatch.Draw(renderTexture, offset, visibleRect, Color.White, 0f, Vector2.Zero, scale, SpriteEffects.None, 1f); | |
spriteBatch.End(); | |
} | |
/// <summary> | |
/// To optimize the Runner, we need to save a reference to each color in the ColorChip as native Unity Colors. The | |
/// cached | |
/// colors will improve rendering performance later when we cover the DisplayChip's pixel data into a format the | |
/// Texture2D | |
/// can display. | |
/// </summary> | |
public void CacheColors(IEngine activeEngine) | |
{ | |
// We also want to cache the ScreenBufferChip's background color. The background color is an ID that references one of the ColorChip's colors. | |
bgColorID = activeEngine.colorChip.backgroundColor; | |
// The ColorChip can return an array of ColorData. ColorData is an internal data structure that Pixel Vision 8 uses to store | |
// color information. It has properties for a Hex representation as well as RGB. | |
colorsData = activeEngine.colorChip.colors; | |
// To improve performance, we'll save a reference to the total cashed colors directly to the Runner's totalCachedColors field. | |
// Also, we'll create a new array to store native Unity Color classes. | |
totalCachedColors = colorsData.Length; | |
if (cachedColors.Length != totalCachedColors) | |
Array.Resize(ref cachedColors, totalCachedColors); | |
// Now it's time to loop through each of the colors and convert them from ColorData to Color instances. | |
for (i = 0; i < totalCachedColors; i++) | |
{ | |
// Converting ColorData to Unity Colors is relatively straight forward by simply passing the ColorData's RGB properties into | |
// the Unity Color class's constructor and saving it to the cachedColors array. | |
colorData = colorsData[i]; | |
// TODO is there a better way to do this without having to update all 256 colors? | |
cachedColors[i] = new Color(colorData.r, colorData.g, colorData.b); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment