Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
cz-dev-ge committed Aug 27, 2021
0 parents commit b42d228
Show file tree
Hide file tree
Showing 6 changed files with 474 additions and 0 deletions.
111 changes: 111 additions & 0 deletions GraphicsDeviceService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/// <summary>
/// Helper class responsible for creating and managing the GraphicsDevice.
/// All GraphicsDeviceControl instances share the same GraphicsDeviceService,
/// so even though there can be many controls, there will only ever be a
/// single underlying GraphicsDevice. This implements the standard
/// IGraphicsDeviceService interface, which provides notification events for
/// when the device is reset or disposed.
/// </summary>
public class GraphicsDeviceService : IGraphicsDeviceService
{
// Singleton device service instance.
private static GraphicsDeviceService singletonInstance;

// Keep track of how many controls are sharing the singletonInstance.
private static int referenceCount;

/// <summary>
/// Gets the single instance of the service class for the application.
/// </summary>
public static GraphicsDeviceService Instance
{
get
{
if (singletonInstance == null)
singletonInstance = new GraphicsDeviceService();
return singletonInstance;
}
}

// Store the current device settings.
private PresentationParameters parameters;

/// <summary>
/// Gets the current graphics device.
/// </summary>
public GraphicsDevice GraphicsDevice { get; private set; }

// IGraphicsDeviceService events.
public event EventHandler<EventArgs> DeviceCreated;
public event EventHandler<EventArgs> DeviceDisposing;
public event EventHandler<EventArgs> DeviceReset;
public event EventHandler<EventArgs> DeviceResetting;

/// <summary>
/// Constructor is private, because this is a singleton class:
/// client controls should use the public AddRef method instead.
/// </summary>
GraphicsDeviceService() { }

/// <summary>
/// Creates the GraphicsDevice for the service.
/// </summary>
private void CreateDevice(IntPtr windowHandle)
{
parameters = new PresentationParameters();

// since we're using render targets anyway, the
// backbuffer size is somewhat irrelevant
parameters.BackBufferWidth = 480;
parameters.BackBufferHeight = 320;
parameters.BackBufferFormat = SurfaceFormat.Color;
parameters.DeviceWindowHandle = windowHandle;
parameters.DepthStencilFormat = DepthFormat.Depth24Stencil8;
parameters.IsFullScreen = false;

GraphicsDevice = new GraphicsDevice(
GraphicsAdapter.DefaultAdapter,
GraphicsProfile.HiDef,
parameters);

if (DeviceCreated != null)
DeviceCreated(this, EventArgs.Empty);
}

/// <summary>
/// Gets a reference to the singleton instance.
/// </summary>
public static GraphicsDeviceService AddRef(IntPtr windowHandle)
{
// Increment the "how many controls sharing the device"
// reference count.
if (Interlocked.Increment(ref referenceCount) == 1)
{
// If this is the first control to start using the
// device, we must create the device.
Instance.CreateDevice(windowHandle);
}

return singletonInstance;
}

/// <summary>
/// Releases a reference to the singleton instance.
/// </summary>
public void Release()
{
// Decrement the "how many controls sharing the device"
// reference count.
if (Interlocked.Decrement(ref referenceCount) == 0)
{
// If this is the last control to finish using the
// device, we should dispose the singleton instance.
if (DeviceDisposing != null)
DeviceDisposing(this, EventArgs.Empty);

GraphicsDevice.Dispose();

GraphicsDevice = null;
}
}
}
19 changes: 19 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2010 Nick Gravelyn, Microsoft

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
135 changes: 135 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Overview

This is a repository preserving example code by [Nick Gravelyn](https://www.nickgravelyn.com/) did some blog post on XNA in the Microsoft Docs. As long as it's there, the original post can be found in the [Microsoft Docs Blog Archive](https://docs.microsoft.com/en-us/archive/blogs/nicgrave/rendering-with-xna-framework-4-0-inside-of-a-wpf-application). Originally there was no license included. By mail and in [this issue at MerjTek's WPF integration](https://github.com/MerjTek/MerjTek.WpfIntegration/issues/1#issuecomment-902622749) he kindly answered the code may be considered MIT or Microsoft Public License, so I put it here under MIT.

This repository allows for using the code without legal concerns which may occur with the missing license in the blog post.


# Example Code

There was more example code included in the blogpost, which is preserved here.


## Example 1

```csharp
// What importers or processors should we load?
private const string xnaVersion =
", Version=4.0.0.0, PublicKeyToken=6d5c3888ef60e27d";
private static readonly string[] pipelineAssemblies =
{
"Microsoft.Xna.Framework.Content.Pipeline.AudioImporters" + xnaVersion,
"Microsoft.Xna.Framework.Content.Pipeline.EffectImporter" + xnaVersion,
"Microsoft.Xna.Framework.Content.Pipeline.FBXImporter" + xnaVersion,
"Microsoft.Xna.Framework.Content.Pipeline.TextureImporter" + xnaVersion,
"Microsoft.Xna.Framework.Content.Pipeline.VideoImporters" + xnaVersion,
"Microsoft.Xna.Framework.Content.Pipeline.XImporter" + xnaVersion,
};
```


## Example 2

```csharp
using Microsoft.Build.Evaluation;
```


## Example 3

```csharp
// MSBuild objects used to dynamically build content.
private ProjectCollection projectCollection;
private Project msBuildProject;
```

## Example 4

```csharp
/// <summary>
/// Creates a temporary MSBuild content project in memory.
/// </summary>
void CreateBuildProject()
{
string projectPath =
Path.Combine(buildDirectory, "content.contentproj");
string outputPath = Path.Combine(buildDirectory, "bin");

// Create the project collection
projectCollection = new ProjectCollection();

// Hook up our custom error logger.
errorLogger = new ErrorLogger();
projectCollection.RegisterLogger(errorLogger);

// Create the build project.
msBuildProject = new Project(projectCollection);
msBuildProject.FullPath = projectPath;

// set up the properties we care about
msBuildProject.SetProperty("XnaPlatform", "Windows");
msBuildProject.SetProperty("XnaFrameworkVersion", "v4.0");
msBuildProject.SetProperty("XnaProfile", "HiDef");
msBuildProject.SetProperty("Configuration", "Release");
msBuildProject.SetProperty("OutputPath", outputPath);

// Register any custom importers or processors.
foreach (string pipelineAssembly in pipelineAssemblies)
{
msBuildProject.AddItem("Reference", pipelineAssembly);
}

// Include the standard targets file that defines
// how to build XNA Framework content.
msBuildProject.Xml.AddImport(
"$(MSBuildExtensionsPath)\\Microsoft\\XNA Game Studio\\v4.0\\" +
"Microsoft.Xna.GameStudio.ContentPipeline.targets");
}
```


## Example 5

```csharp
/// <summary>
/// Adds a new content file to the MSBuild project. The importer and
/// processor are optional: if you leave the importer null, it will
/// be autodetected based on the file extension, and if you leave the
/// processor null, data will be passed through without any processing.
/// </summary>
public void Add(
string filename, string name,
string importer, string processor)
{
// set up the metadata for this item
var metadata = new SortedList<string,string>();
metadata.Add("Link", Path.GetFileName(filename));
metadata.Add("Name", name);

if (!string.IsNullOrEmpty(importer))
metadata.Add("Importer", importer);

if (!string.IsNullOrEmpty(processor))
metadata.Add("Processor", processor);

// add the item
msBuildProject.AddItem("Compile", filename, metadata);
}
```


## Example 6

```csharp
/// <summary>
/// Removes all content files from the MSBuild project.
/// </summary>
public void Clear()
{
// select all compiled objects in the project and remove them
var compileObjects = from i in project.Items
where i.ItemType == "Compile"
select i;
project.RemoveItems(compileObjects);
}
```
105 changes: 105 additions & 0 deletions XnaControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
public partial class XnaControl : UserControl
{
private GraphicsDeviceService graphicsService;
private XnaImageSource imageSource;

/// <summary>
/// Gets the GraphicsDevice behind the control.
/// </summary>
public GraphicsDevice GraphicsDevice
{
get { return graphicsService.GraphicsDevice; }
}

/// <summary>
/// Invoked when the XnaControl needs to be redrawn.
/// </summary>
public Action<GraphicsDevice> DrawFunction;

public XnaControl()
{
InitializeComponent();

// hook up an event to fire when the control has finished loading
Loaded += new RoutedEventHandler(XnaControl_Loaded);
}

~XnaControl()
{
imageSource.Dispose();

// release on finalizer to clean up the graphics device
if (graphicsService != null)
graphicsService.Release();
}

void XnaControl_Loaded(object sender, RoutedEventArgs e)
{
// if we're not in design mode, initialize the graphics device
if (DesignerProperties.GetIsInDesignMode(this) == false)
{
InitializeGraphicsDevice();
}
}

protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
// if we're not in design mode, recreate the
// image source for the new size
if (DesignerProperties.GetIsInDesignMode(this) == false &&
graphicsService != null)
{
// recreate the image source
imageSource.Dispose();
imageSource = new XnaImageSource(
GraphicsDevice, (int)ActualWidth, (int)ActualHeight);
rootImage.Source = imageSource.WriteableBitmap;
}

base.OnRenderSizeChanged(sizeInfo);
}

private void InitializeGraphicsDevice()
{
if (graphicsService == null)
{
// add a reference to the graphics device
graphicsService = GraphicsDeviceService.AddRef(
(PresentationSource.FromVisual(this) as HwndSource).Handle);

// create the image source
imageSource = new XnaImageSource(
GraphicsDevice, (int)ActualWidth, (int)ActualHeight);
rootImage.Source = imageSource.WriteableBitmap;

// hook the rendering event
CompositionTarget.Rendering += CompositionTarget_Rendering;
}
}

/// <summary>
/// Draws the control and allows subclasses to override
/// the default behavior of delegating the rendering.
/// </summary>
protected virtual void Render()
{
// invoke the draw delegate so someone will draw something pretty
if (DrawFunction != null)
DrawFunction(GraphicsDevice);
}

void CompositionTarget_Rendering(object sender, EventArgs e)
{
// set the image source render target
GraphicsDevice.SetRenderTarget(imageSource.RenderTarget);

// allow the control to draw
Render();

// unset the render target
GraphicsDevice.SetRenderTarget(null);

// commit the changes to the image source
imageSource.Commit();
}
}
6 changes: 6 additions & 0 deletions XnaControl.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<UserControl x:Class="MyApp.XnaControl"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
MinHeight="50" MinWidth="50" Background="CornflowerBlue">
<Image x:Name="rootImage" />
</UserControl>
Loading

0 comments on commit b42d228

Please sign in to comment.