Browse Source

Extracted ImageBrush/VisualBrush parts from Direct2D backend

pull/301/head
Nikita Tsukanov 11 years ago
parent
commit
141ce87960
  1. 5
      Perspex.sln
  2. 14
      Shared/RenderHelpers/RenderHelpers.projitems
  3. 13
      Shared/RenderHelpers/RenderHelpers.shproj
  4. 174
      Shared/RenderHelpers/TileBrushImplHelper.cs
  5. 4
      src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs
  6. 94
      src/Windows/Perspex.Direct2D1/Media/ImageBrushImpl.cs
  7. 92
      src/Windows/Perspex.Direct2D1/Media/TileBrushImpl.cs
  8. 73
      src/Windows/Perspex.Direct2D1/Media/VisualBrushImpl.cs
  9. 3
      src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj

5
Perspex.sln

@ -104,12 +104,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BindingTest", "samples\Bind
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlTestApplicationPcl", "samples\XamlTestApplicationPcl\XamlTestApplicationPcl.csproj", "{EA113F1A-D8D7-4142-9948-353270E7EBAE}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "Shared\RenderHelpers\RenderHelpers.shproj", "{3C4C0CB4-0C0F-4450-A37B-148C84FF905F}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{db070a10-bf39-4752-8456-86e9d5928478}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{54f237d5-a70a-4752-9656-0c70b1a7b047}*SharedItemsImports = 4
Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -289,5 +293,6 @@ Global
{8EF392D5-1416-45AA-9956-7CBBC3229E8A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{EA113F1A-D8D7-4142-9948-353270E7EBAE} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{3C4C0CB4-0C0F-4450-A37B-148C84FF905F} = {A689DEF5-D50F-4975-8B72-124C9EB54066}
EndGlobalSection
EndGlobal

14
Shared/RenderHelpers/RenderHelpers.projitems

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>3c4c0cb4-0c0f-4450-a37b-148c84ff905f</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>Perspex.RenderHelpers</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)TileBrushImplHelper.cs" />
</ItemGroup>
</Project>

13
Shared/RenderHelpers/RenderHelpers.shproj

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>3c4c0cb4-0c0f-4450-a37b-148c84ff905f</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="RenderHelpers.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

174
Shared/RenderHelpers/TileBrushImplHelper.cs

@ -0,0 +1,174 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Perspex;
using Perspex.Media;
using Perspex.Rendering;
using Perspex.Layout;
namespace Perspex.RenderHelpers
{
class TileBrushImplHelper
{
public Size IntermediateSize { get; }
public Rect DestinationRect { get; }
private readonly TileMode _tileMode;
private readonly Rect _sourceRect;
private readonly Vector _scale;
private readonly Vector _translate;
private readonly Size _imageSize;
private readonly VisualBrush _visualBrush;
private readonly ImageBrush _imageBrush;
public bool IsValid { get; }
public TileBrushImplHelper(TileBrush brush, Size targetSize)
{
_imageBrush = brush as ImageBrush;
_visualBrush = brush as VisualBrush;
if (_imageBrush != null)
{
if (_imageBrush.Source == null)
return;
_imageSize = new Size(_imageBrush.Source.PixelWidth, _imageBrush.Source.PixelHeight);
IsValid = true;
}
else if (_visualBrush != null)
{
var visual = _visualBrush.Visual;
if (visual == null)
return;
var layoutable = visual as ILayoutable;
if (layoutable?.IsArrangeValid == false)
{
layoutable.Measure(Size.Infinity);
layoutable.Arrange(new Rect(layoutable.DesiredSize));
}
//I have no idea why are we using layoutable after `as` cast, but it was in original VisualBrush code by @grokys
_imageSize = layoutable.Bounds.Size;
IsValid = true;
}
else
return;
_tileMode = brush.TileMode;
_sourceRect = brush.SourceRect.ToPixels(_imageSize);
DestinationRect = brush.DestinationRect.ToPixels(targetSize);
_scale = brush.Stretch.CalculateScaling(DestinationRect.Size, _sourceRect.Size);
_translate = CalculateTranslate(brush, _sourceRect, DestinationRect, _scale);
IntermediateSize = CalculateIntermediateSize(_tileMode, targetSize, DestinationRect.Size);
}
public void DrawIntermediate(DrawingContext ctx)
{
Rect drawRect;
var transform = CalculateIntermediateTransform(
_tileMode,
_sourceRect,
DestinationRect,
_scale,
_translate,
out drawRect);
using (ctx.PushClip(drawRect))
using (ctx.PushPostTransform(transform))
{
if (_imageBrush != null)
{
var bmpRc = new Rect(0, 0, _imageBrush.Source.PixelWidth, _imageBrush.Source.PixelHeight);
ctx.DrawImage(_imageBrush.Source, 1, bmpRc, bmpRc);
}
else if (_visualBrush != null)
{
ctx.FillRectangle(Brushes.Black, new Rect(new Point(0, 0), IntermediateSize));
ctx.Render(_visualBrush.Visual);
}
}
}
/// <summary>
/// Calculates a _translate based on a <see cref="TileBrush"/>, a source and destination
/// rectangle and a _scale.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="sourceRect">The source rectangle.</param>
/// <param name="destinationRect">The destination rectangle.</param>
/// <param name="scale">The _scale factor.</param>
/// <returns>A vector with the X and Y _translate.</returns>
public static Vector CalculateTranslate(
TileBrush brush,
Rect sourceRect,
Rect destinationRect,
Vector scale)
{
var x = 0.0;
var y = 0.0;
var size = sourceRect.Size*scale;
switch (brush.AlignmentX)
{
case AlignmentX.Center:
x += (destinationRect.Width - size.Width)/2;
break;
case AlignmentX.Right:
x += destinationRect.Width - size.Width;
break;
}
switch (brush.AlignmentY)
{
case AlignmentY.Center:
y += (destinationRect.Height - size.Height)/2;
break;
case AlignmentY.Bottom:
y += destinationRect.Height - size.Height;
break;
}
return new Vector(x, y);
}
public static Matrix CalculateIntermediateTransform(
TileMode tileMode,
Rect sourceRect,
Rect destinationRect,
Vector scale,
Vector translate,
out Rect drawRect)
{
var transform = Matrix.CreateTranslation(-sourceRect.Position)*
Matrix.CreateScale(scale)*
Matrix.CreateTranslation(translate);
Rect dr;
if (tileMode == TileMode.None)
{
dr = destinationRect;
transform *= Matrix.CreateTranslation(destinationRect.Position);
}
else
{
dr = new Rect(destinationRect.Size);
}
drawRect = dr;
return transform;
}
static Size CalculateIntermediateSize(
TileMode tileMode,
Size targetSize,
Size destinationSize) => tileMode == TileMode.None ? targetSize : destinationSize;
}
}

4
src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs

@ -312,11 +312,11 @@ namespace Perspex.Direct2D1.Media
}
else if (imageBrush != null)
{
return new ImageBrushImpl(imageBrush, _renderTarget, destinationSize);
return new TileBrushImpl(imageBrush, _renderTarget, destinationSize);
}
else if (visualBrush != null)
{
return new VisualBrushImpl(visualBrush, _renderTarget, destinationSize);
return new TileBrushImpl(visualBrush, _renderTarget, destinationSize);
}
else
{

94
src/Windows/Perspex.Direct2D1/Media/ImageBrushImpl.cs

@ -1,94 +0,0 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Perspex.Media;
using SharpDX.Direct2D1;
namespace Perspex.Direct2D1.Media
{
public class ImageBrushImpl : TileBrushImpl
{
public ImageBrushImpl(
ImageBrush brush,
SharpDX.Direct2D1.RenderTarget target,
Size targetSize)
{
if (brush.Source == null)
{
return;
}
var image = ((BitmapImpl)brush.Source.PlatformImpl).GetDirect2DBitmap(target);
var imageSize = new Size(brush.Source.PixelWidth, brush.Source.PixelHeight);
var tileMode = brush.TileMode;
var sourceRect = brush.SourceRect.ToPixels(imageSize);
var destinationRect = brush.DestinationRect.ToPixels(targetSize);
var scale = brush.Stretch.CalculateScaling(destinationRect.Size, sourceRect.Size);
var translate = CalculateTranslate(brush, sourceRect, destinationRect, scale);
var intermediateSize = CalculateIntermediateSize(tileMode, targetSize, destinationRect.Size);
var brtOpts = CompatibleRenderTargetOptions.None;
// TODO: There are times where we don't need to draw an intermediate bitmap. Identify
// them and directly use 'image' in those cases.
using (var intermediate = new BitmapRenderTarget(target, brtOpts, intermediateSize))
{
Rect drawRect;
var transform = CalculateIntermediateTransform(
tileMode,
sourceRect,
destinationRect,
scale,
translate,
out drawRect);
intermediate.BeginDraw();
intermediate.PushAxisAlignedClip(drawRect.ToDirect2D(), AntialiasMode.Aliased);
intermediate.Transform = transform.ToDirect2D();
intermediate.DrawBitmap(image, 1, BitmapInterpolationMode.Linear);
intermediate.PopAxisAlignedClip();
intermediate.EndDraw();
this.PlatformBrush = new BitmapBrush(
target,
intermediate.Bitmap,
GetBitmapBrushProperties(brush),
GetBrushProperties(brush, destinationRect));
}
}
private BitmapBrush CreateDirectBrush(
ImageBrush brush,
SharpDX.Direct2D1.RenderTarget target,
Bitmap image,
Rect sourceRect,
Rect destinationRect)
{
var tileMode = brush.TileMode;
var scale = brush.Stretch.CalculateScaling(destinationRect.Size, sourceRect.Size);
var translate = CalculateTranslate(brush, sourceRect, destinationRect, scale);
var transform = Matrix.CreateTranslation(-sourceRect.Position) *
Matrix.CreateScale(scale) *
Matrix.CreateTranslation(translate);
var opts = new BrushProperties
{
Transform = transform.ToDirect2D(),
Opacity = (float)brush.Opacity,
};
var bitmapOpts = new BitmapBrushProperties
{
ExtendModeX = GetExtendModeX(tileMode),
ExtendModeY = GetExtendModeY(tileMode),
};
return new BitmapBrush(target, image, bitmapOpts, opts);
}
private BitmapBrush CreateIndirectBrush()
{
throw new NotImplementedException();
}
}
}

92
src/Windows/Perspex.Direct2D1/Media/TileBrushImpl.cs

@ -6,94 +6,38 @@ using Perspex.Layout;
using Perspex.Media;
using SharpDX;
using SharpDX.Direct2D1;
using Perspex.RenderHelpers;
namespace Perspex.Direct2D1.Media
{
public class TileBrushImpl : BrushImpl
public sealed class TileBrushImpl : BrushImpl
{
/// <summary>
/// Calculates a translate based on a <see cref="TileBrush"/>, a source and destination
/// rectangle and a scale.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="sourceRect">The source rectangle.</param>
/// <param name="destinationRect">The destination rectangle.</param>
/// <param name="scale">The scale factor.</param>
/// <returns>A vector with the X and Y translate.</returns>
protected static Vector CalculateTranslate(
public TileBrushImpl(
TileBrush brush,
Rect sourceRect,
Rect destinationRect,
Vector scale)
SharpDX.Direct2D1.RenderTarget target,
Size targetSize)
{
var x = 0.0;
var y = 0.0;
var size = sourceRect.Size * scale;
var helper = new TileBrushImplHelper(brush, targetSize);
if (!helper.IsValid)
return;
switch (brush.AlignmentX)
using (var intermediate = new BitmapRenderTarget(target, CompatibleRenderTargetOptions.None, helper.IntermediateSize.ToSharpDX()))
{
case AlignmentX.Center:
x += (destinationRect.Width - size.Width) / 2;
break;
case AlignmentX.Right:
x += destinationRect.Width - size.Width;
break;
using (var ctx = new RenderTarget(intermediate).CreateDrawingContext())
helper.DrawIntermediate(ctx);
PlatformBrush = new BitmapBrush(
target,
intermediate.Bitmap,
GetBitmapBrushProperties(brush),
GetBrushProperties(brush, helper.DestinationRect));
}
switch (brush.AlignmentY)
{
case AlignmentY.Center:
y += (destinationRect.Height - size.Height) / 2;
break;
case AlignmentY.Bottom:
y += destinationRect.Height - size.Height;
break;
}
return new Vector(x, y);
}
protected static Size2F CalculateIntermediateSize(
TileMode tileMode,
Size targetSize,
Size destinationSize)
{
var result = tileMode == TileMode.None ? targetSize : destinationSize;
return result.ToSharpDX();
}
protected static Matrix CalculateIntermediateTransform(
TileMode tileMode,
Rect sourceRect,
Rect destinationRect,
Vector scale,
Vector translate,
out Rect drawRect)
{
var transform = Matrix.CreateTranslation(-sourceRect.Position) *
Matrix.CreateScale(scale) *
Matrix.CreateTranslation(translate);
Rect dr;
if (tileMode == TileMode.None)
{
dr = destinationRect;
transform *= Matrix.CreateTranslation(destinationRect.Position);
}
else
{
dr = new Rect(destinationRect.Size);
}
drawRect = dr;
return transform;
}
protected static BrushProperties GetBrushProperties(TileBrush brush, Rect destinationRect)
{
var tileMode = brush.TileMode;
return new BrushProperties
{
Opacity = (float)brush.Opacity,

73
src/Windows/Perspex.Direct2D1/Media/VisualBrushImpl.cs

@ -1,73 +0,0 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Perspex.Layout;
using Perspex.Media;
using Perspex.Rendering;
using SharpDX;
using SharpDX.Direct2D1;
namespace Perspex.Direct2D1.Media
{
public class VisualBrushImpl : TileBrushImpl
{
public VisualBrushImpl(
VisualBrush brush,
SharpDX.Direct2D1.RenderTarget target,
Size targetSize)
{
var visual = brush.Visual;
if (visual == null)
{
return;
}
var layoutable = visual as ILayoutable;
if (layoutable?.IsArrangeValid == false)
{
layoutable.Measure(Size.Infinity);
layoutable.Arrange(new Rect(layoutable.DesiredSize));
}
var tileMode = brush.TileMode;
var sourceRect = brush.SourceRect.ToPixels(layoutable.Bounds.Size);
var destinationRect = brush.DestinationRect.ToPixels(targetSize);
var scale = brush.Stretch.CalculateScaling(destinationRect.Size, sourceRect.Size);
var translate = CalculateTranslate(brush, sourceRect, destinationRect, scale);
var intermediateSize = CalculateIntermediateSize(tileMode, targetSize, destinationRect.Size);
var brtOpts = CompatibleRenderTargetOptions.None;
// TODO: There are times where we don't need to draw an intermediate bitmap. Identify
// them and directly use 'image' in those cases.
using (var intermediate = new BitmapRenderTarget(target, brtOpts, intermediateSize))
{
Rect drawRect;
var transform = CalculateIntermediateTransform(
tileMode,
sourceRect,
destinationRect,
scale,
translate,
out drawRect);
var renderer = new RenderTarget(intermediate);
using (var ctx = renderer.CreateDrawingContext())
using (ctx.PushClip(drawRect))
using (ctx.PushPostTransform(transform))
{
intermediate.Clear(new Color4(0));
ctx.Render(visual);
}
this.PlatformBrush = new BitmapBrush(
target,
intermediate.Bitmap,
GetBitmapBrushProperties(brush),
GetBrushProperties(brush, destinationRect));
}
}
}
}

3
src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj

@ -79,9 +79,7 @@
<Compile Include="Media\RadialGradientBrushImpl.cs" />
<Compile Include="Media\LinearGradientBrushImpl.cs" />
<Compile Include="Media\PerspexTextRenderer.cs" />
<Compile Include="Media\ImageBrushImpl.cs" />
<Compile Include="Media\TileBrushImpl.cs" />
<Compile Include="Media\VisualBrushImpl.cs" />
<Compile Include="Media\SolidColorBrushImpl.cs" />
<Compile Include="Media\StreamGeometryContextImpl.cs" />
<Compile Include="Media\GeometryImpl.cs" />
@ -113,6 +111,7 @@
<Name>Perspex.SceneGraph</Name>
</ProjectReference>
</ItemGroup>
<Import Project="..\..\..\Shared\RenderHelpers\RenderHelpers.projitems" Label="Shared" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\..\packages\SharpDX.2.6.3\build\SharpDX.targets" Condition="Exists('..\..\..\packages\SharpDX.2.6.3\build\SharpDX.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

Loading…
Cancel
Save