我正在尝试使用SharpDX使用DirectX创建一个简单的迷宫式2D程序。
为此,我想制作位图,我可以在屏幕上渲染墙壁,走廊,迷宫外等等。
但是,我似乎无法弄清楚如何将现有图像文件加载到SharpDX库中的Bitmap类中,或者如何从头创建一个新的此类Bitmap类。
由于所有类都被称为直接映射到DirectX类型,我想这只是意味着我需要学习更多DirectX,但我希望有一个简单的例子可以告诉我我需要做什么。 / p>
如果我必须从头开始构建一个新的Bitmap并绘制它,我可以做到这一点,获得我需要的像素并不困难,但我似乎无法弄清楚那部分。
有没有人对SharpDX库有任何经验,可以给我一些指示?
答案 0 :(得分:10)
你应该直接问这个问题到Sharpdx项目的“问题”标签,因为我能够从那里给你一个快速回复(你很幸运我有时会从网上检查它的用法;)) 。如果您正式提出这个问题,我可以对库进行改进,并在问题数据库中记录您的请求。
关于您的特定问题,目前尚不清楚您使用的是哪种DirectX API。我假设您使用的是Direct2D?
如果是,则没有API直接从文件加载SharpDX.Direct2D1.Bitmap(我将此方法添加到API)。我刚刚上传了正在执行此操作的bitmap sample。
/// <summary>
/// Loads a Direct2D Bitmap from a file using System.Drawing.Image.FromFile(...)
/// </summary>
/// <param name="renderTarget">The render target.</param>
/// <param name="file">The file.</param>
/// <returns>A D2D1 Bitmap</returns>
public static Bitmap LoadFromFile(RenderTarget renderTarget, string file)
{
// Loads from file using System.Drawing.Image
using (var bitmap = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(file))
{
var sourceArea = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height);
var bitmapProperties = new BitmapProperties(new PixelFormat(Format.R8G8B8A8_UNorm, AlphaMode.Premultiplied));
var size = new System.Drawing.Size(bitmap.Width, bitmap.Height);
// Transform pixels from BGRA to RGBA
int stride = bitmap.Width * sizeof(int);
using (var tempStream = new DataStream(bitmap.Height * stride, true, true))
{
// Lock System.Drawing.Bitmap
var bitmapData = bitmap.LockBits(sourceArea, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
// Convert all pixels
for (int y = 0; y < bitmap.Height; y++)
{
int offset = bitmapData.Stride*y;
for (int x = 0; x < bitmap.Width; x++)
{
// Not optimized
byte B = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte G = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte R = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte A = Marshal.ReadByte(bitmapData.Scan0, offset++);
int rgba = R | (G << 8) | (B << 16) | (A << 24);
tempStream.Write(rgba);
}
}
bitmap.UnlockBits(bitmapData);
tempStream.Position = 0;
return new Bitmap(renderTarget, size, tempStream, stride, bitmapProperties);
}
}
}
正如你所说,SharpDX可以访问原始低级别的DirectX API(不像XNA那样提供更高级别的API),所以你肯定需要了解程序原始DirectX如何使用SharpDX。
答案 1 :(得分:0)
当我使用SlimDX时,我遇到了同样的问题(使用Direct2D加载位图)并找到了一个类似的解决方案,它取消了嵌入式循环并且需要的代码少一些;将它转换为SharpDX是一件简单的事情。 (我希望我可以告诉你我在哪里找到了原版,但它已经好几年了,显然我没有记录来源。就我所知道的而言,它可以直接用于SlimDX样本。)
我保留了名称空间,因此您可以准确了解每种类型的定义。此外,一些参数(特别是PixelFormat的参数)是灵活的;和他们一起玩,并使用适合你的任何东西。
private Bitmap Load(string filename) { System.Drawing.Bitmap bmp = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(filename); System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits( new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); SharpDX.DataStream stream = new SharpDX.DataStream(bmpData.Scan0, bmpData.Stride * bmpData.Height, true, false); SharpDX.Direct2D1.PixelFormat pFormat = new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied); SharpDX.Direct2D1.BitmapProperties bmpProps = new SharpDX.Direct2D1.BitmapProperties(pFormat); SharpDX.Direct2D1.Bitmap result = new SharpDX.Direct2D1.Bitmap( m_renderTarget, new SharpDX.Size2(bmp.Width, bmp.Height), stream, bmpData.Stride, bmpProps); bmp.UnlockBits(bmpData); stream.Dispose(); bmp.Dispose(); return result; }
正如您所看到的,它将位图流锁定为Alexandre的方法(在相关的SharpDX示例项目中使用),但不是手动复制每个像素,构造函数本身会在后台复制流。我没有将性能与Alexandre提出的方法进行比较,所以我不能告诉你哪种方法更快,但是这个方法对我的目的而言足够快,而且代码很干净。
(很抱歉缺少语法高亮显示;&lt; code&gt;标记由于某种原因会将我的代码段分成几部分。)
答案 2 :(得分:0)
这是VB中Alexandre的方法:
'/// <summary>
'/// Loads a Direct2D Bitmap from a file using System.Drawing.Image.FromFile(...)
'/// </summary>
'/// <param name="renderTarget">The render target.</param>
'/// <param name="file">The file.</param>
'/// <returns>A D2D1 Bitmap</returns>
Public Shared Function LoadFromFile(renderTarget As RenderTarget, file As String) As SharpDX.Direct2D1.Bitmap
'// Loads from file using System.Drawing.Image
Using bitmap As System.Drawing.Bitmap = System.Drawing.Image.FromFile(file)
Dim sourceArea As New System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height)
Dim BitmapProperties As New BitmapProperties(New Direct2D1.PixelFormat(DXGI.Format.R8G8B8A8_UNorm, AlphaMode.Premultiplied))
Dim Size As New System.Drawing.Size(bitmap.Width, bitmap.Height)
Dim b As Byte
Dim g As Byte
Dim r As Byte
Dim a As Byte
Dim rgba As Int32
'// Transform pixels from BGRA to RGBA
Dim stride As Int32 = bitmap.Width * 4
Using tempStream As New DataStream(bitmap.Height * stride, True, True)
'// Lock System.Drawing.Bitmap
Dim bitmapData As System.Drawing.Imaging.BitmapData = bitmap.LockBits(sourceArea, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb)
'// Convert all pixels
For y As Int32 = 0 To bitmap.Height - 1
Dim offset As Int32 = bitmapData.Stride * y
For x As Int32 = 0 To bitmap.Width - 1
'// Not optimized
b = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
g = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
r = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
a = Marshal.ReadByte(bitmapData.Scan0, offset)
offset += 1
rgba = r Or (g << 8) Or (b << 16) Or (a << 24)
tempStream.Write(rgba)
Next
Next
bitmap.UnlockBits(bitmapData)
tempStream.Position = 0
Return New Bitmap(renderTarget, New Size2(Size.Width, Size.Height), tempStream, stride, BitmapProperties)
End Using
End Using
End Function
答案 3 :(得分:0)
这是汤姆(Tom)在VB中的示例,做了一些修改。
Private Function ConvertBitmap(m_renderTarget As RenderTarget, bmp As System.Drawing.Bitmap) As SharpDX.Direct2D1.Bitmap
Dim bmpData As System.Drawing.Imaging.BitmapData = bmp.LockBits(
New System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb)
Dim stream As New SharpDX.DataStream(bmpData.Scan0, bmpData.Stride * bmpData.Height, True, False)
Dim pFormat As New SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied)
Dim bmpProps As New SharpDX.Direct2D1.BitmapProperties(pFormat)
Dim Result As New SharpDX.Direct2D1.Bitmap(
m_renderTarget,
New SharpDX.Size2(bmp.Width, bmp.Height),
stream,
bmpData.Stride,
bmpProps)
bmp.UnlockBits(bmpData)
stream.Dispose()
bmp.Dispose()
Return Result
End Function
通过在函数调用中提供rendertarget和bitmap,我可以在Lambda语句中使用该函数将damap放置在D2dControl提供的资源缓存中(在NuGet中可用)。另外,由于我将位图作为资源加载到我的项目中,因此我可以简单地在函数调用中提供它们:
Public Sub New()
...
resCache.Add("MainBitmap", Function(t As RenderTarget) ConvertBitmap(t, My.Resources.ProjectUtumno_full))
End Sub
Public Overrides Sub Render(target As RenderTarget)
target.Clear(New RawColor4(1.0F, 1.0F, 1.0F, 1.0F))
...
target.DrawBitmap(resCache("MainBitmap"), 1.0F, New BitmapInterpolationMode())
end sub