UWP - How to create a CompositionSurfaceBrush with a repeated pattern - c#

I would like to have a Panel with a Background that shows a repeated pattern (e.g. dots, evenly separated of 30 pixels).
So far, I managed to create a subclass of XamlCompositionBrushBase that allows we to create my own shape (e.g. a single dot). but I am failing to understand how to repeat this pattern.
This is my custom Brush:
public sealed class DottedBackgroundBrush : XamlCompositionBrushBase
{
public DottedBackgroundBrush()
{
}
protected override void OnConnected()
{
// Delay creating composition resources until they're required.
if (CompositionBrush == null)
{
var compositor = Window.Current.Compositor;
// Actual Width/Height are going to be returned in effective pixels which
// is going to differ from the size of the bitmap that we'll render from the XAML.
var width = 400;
var height = 400;
// Make our visual:
var spriteVisual = compositor.CreateSpriteVisual();
spriteVisual.Size = new Vector2(width, height);
CanvasDevice device = CanvasDevice.GetSharedDevice();
var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, device);
CompositionSurfaceBrush drawingBrush = compositor.CreateSurfaceBrush();
var drawingSurface = graphicsDevice.CreateDrawingSurface(
new Size(width, height),
DirectXPixelFormat.B8G8R8A8UIntNormalized,
DirectXAlphaMode.Premultiplied);
using (var ds = CanvasComposition.CreateDrawingSession(drawingSurface))
{
ds.Clear(Colors.Transparent);
ds.DrawCircle(new Vector2(10, 10), 5, Colors.Black, 3);
}
drawingBrush.Surface = drawingSurface;
CompositionBrush = drawingBrush;
}
}
protected override void OnDisconnected()
{
// Dispose of composition resources when no longer in use.
if (CompositionBrush != null)
{
CompositionBrush.Dispose();
CompositionBrush = null;
}
}
}
How can I enable the circle to be replicated indefinitely, instead of having as single instance?

For this, you want to create a CompositionEffectBrush as your main brush, using a Win2D BorderEffect - which does the actual tiling - and set it's source to be your SurfaceBrush.
Example (adapted from a repo of mine so it might be a bit roundabouts)
public class TilingBrush : XamlCompositionBrushBase
{
protected Compositor _compositor => Window.Current.Compositor;
protected CompositionBrush _imageBrush = null;
protected IDisposable _surfaceSource = null;
protected override void OnConnected()
{
base.OnConnected();
if (CompositionBrush == null)
{
CreateEffectBrush();
Render();
}
}
protected override void OnDisconnected()
{
base.OnDisconnected();
this.CompositionBrush?.Dispose();
this.CompositionBrush = null;
ClearResources();
}
private void ClearResources()
{
_imageBrush?.Dispose();
_imageBrush = null;
_surfaceSource?.Dispose();
_surfaceSource = null;
}
private void UpdateBrush()
{
if (CompositionBrush != null && _imageBrush != null)
{
((CompositionEffectBrush)CompositionBrush).SetSourceParameter(nameof(BorderEffect.Source), _imageBrush);
}
}
protected ICompositionSurface CreateSurface()
{
double width = 20;
double height = 20;
CanvasDevice device = CanvasDevice.GetSharedDevice();
var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(_compositor, device);
var drawingSurface = graphicsDevice.CreateDrawingSurface(
new Size(width, height),
DirectXPixelFormat.B8G8R8A8UIntNormalized,
DirectXAlphaMode.Premultiplied);
/* Create Drawing Session is not thread safe - only one can ever be active at a time per app */
using (var ds = CanvasComposition.CreateDrawingSession(drawingSurface))
{
ds.Clear(Colors.Transparent);
ds.DrawCircle(new Vector2(10, 10), 5, Colors.Black, 3);
}
return drawingSurface;
}
private void Render()
{
ClearResources();
try
{
var src = CreateSurface();
_surfaceSource = src as IDisposable;
var surfaceBrush = _compositor.CreateSurfaceBrush(src);
surfaceBrush.VerticalAlignmentRatio = 0.0f;
surfaceBrush.HorizontalAlignmentRatio = 0.0f;
surfaceBrush.Stretch = CompositionStretch.None;
_imageBrush = surfaceBrush;
UpdateBrush();
}
catch
{
// no image for you, soz.
}
}
private void CreateEffectBrush()
{
using (var effect = new BorderEffect
{
Name = nameof(BorderEffect),
ExtendY = CanvasEdgeBehavior.Wrap,
ExtendX = CanvasEdgeBehavior.Wrap,
Source = new CompositionEffectSourceParameter(nameof(BorderEffect.Source))
})
using (var _effectFactory = _compositor.CreateEffectFactory(effect))
{
this.CompositionBrush = _effectFactory.CreateBrush();
}
}
}
For the longest time I've meant to add it to the WindowsCommunityToolkit, but for the longest time I've been slamming into bugs with the Visual Layer that stop me. This particular case should work fine however.

Related

How to detect, if a bezier curve intersects a specified ellipse?

I have a custom control that renders a bezier line from the top-left to the bottom-right corner. I would like to modify the hit test behavior so that the control is only "hit", if hovering over or near the bezier curve, but FillContainsWithDetail doesn't return the expected results.
What am I missing?
Here's a derived example class:
public class BezierControl : FrameworkElement
{
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
if (_geometry == null) return null;
var p = hitTestParameters.HitPoint;
EllipseGeometry expandedHitTestArea = new EllipseGeometry(p, 10.0, 10.0);
var intersection = expandedHitTestArea.FillContainsWithDetail(_geometry);
if (intersection > IntersectionDetail.Empty)
{
return new PointHitTestResult(this, hitTestParameters.HitPoint);
}
return null;
}
private StreamGeometry _geometry;
private StreamGeometry getGeometry()
{
var result = new StreamGeometry();
using (var context = result.Open())
{
var start = new Point(0, 0);
var startCp = new Point(10, 0);
var end = new Point(this.ActualWidth, this.ActualHeight);
var endCp = new Point(this.ActualWidth - 10, this.ActualHeight);
context.BeginFigure(start, false, false);
context.BezierTo(startCp, endCp, end, true, false);
}
result.Freeze();
return result;
}
protected override void OnRender(DrawingContext dc)
{
base.OnRender(dc);
if (_geometry == null) _geometry = getGeometry();
dc.DrawGeometry(null, _pen, _geometry);
}
private Pen _pen = new Pen(Brushes.Red, 1.0);
}
EDIT: The approved answer below is fine, but it also lead me to another alternative - or showed me why my attempted solution was failing: I was creating the geometry like this:
context.BeginFigure(bezier.Start, false, false);
The first bool parameter is called isFilled. Setting this to true allows intersecting between _geometry and expandedHitTestArea.
Before noticing this, I implemented the accepted answer below and decided to create the widenedGeometry lazily for performance reasons. Which now gets me wondering: from a performance perspective, which approach is better? Or, is this negligible in this case, because geometries are inexpensive anyway?
You don't need that EllipseGeometry. Just check if the hit point is inside a widened path geometry of the original geometry (which may of course also be created once when _geometry is created):
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
if (_geometry != null)
{
var widenedGeometry = _geometry.GetWidenedPathGeometry(new Pen(null, 20));
if (widenedGeometry.FillContains(hitTestParameters.HitPoint))
{
return new PointHitTestResult(this, hitTestParameters.HitPoint);
}
}
return null;
}

Updating GMap.NET Marker Image in C#

I can change my markers position with
markers.Markers[2].Position = new PointLatLng(30.0000, 30.00000);
but how can i change marker icon with setting a varible like above?
I am declaring points as
GMap.NET.WindowsForms.GMapMarker marker3 =
new GMap.NET.WindowsForms.Markers.GMarkerGoogle(
new GMap.NET.PointLatLng(30.0000, 30.00000),
new Bitmap("images/2.png"));
thanks...
To solve this problem, i contacted the creator of the library: radioman.
He referred some code called 'GMarkerArrow.' Here is the code:
namespace Demo.WindowsForms.CustomMarkers
{
using System;
using System.Drawing;
using System.Runtime.Serialization;
using GMap.NET;
using GMap.NET.WindowsForms;
[Serializable]
public class GMarkerArrow : GMapMarker, ISerializable
{
[NonSerialized]
public Brush Fill = new SolidBrush(Color.FromArgb(155, Color.Blue));
//[NonSerialized]
//public Pen Pen = new Pen(Brushes.Blue, 5);
static readonly Point[] Arrow = new Point[] { new Point(-7, 7), new Point(0, -22), new Point(7, 7), new Point(0, 2) };
public float Bearing = 0;
private float scale = 1;
public float Scale
{
get
{
return scale;
}
set
{
scale = value;
Size = new System.Drawing.Size((int)(14 * scale), (int)(14 * scale));
Offset = new System.Drawing.Point(-Size.Width / 2, (int)(-Size.Height / 1.4));
}
}
public GMarkerArrow(PointLatLng p)
: base(p)
{
Scale = (float)1.4;
}
public override void OnRender(Graphics g)
{
//g.DrawRectangle(Pen, new System.Drawing.Rectangle(LocalPosition.X, LocalPosition.Y, Size.Width, Size.Height));
{
g.TranslateTransform(ToolTipPosition.X, ToolTipPosition.Y);
var c = g.BeginContainer();
{
g.RotateTransform(Bearing - Overlay.Control.Bearing);
g.ScaleTransform(Scale, Scale);
g.FillPolygon(Fill, Arrow);
}
g.EndContainer(c);
g.TranslateTransform(-ToolTipPosition.X, -ToolTipPosition.Y);
}
}
public override void Dispose()
{
//if(Pen != null)
//{
// Pen.Dispose();
// Pen = null;
//}
if (Fill != null)
{
Fill.Dispose();
Fill = null;
}
base.Dispose();
}
#region ISerializable Members
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
}
protected GMarkerArrow(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endregion
}
}
Save this as GMarkerArrow.cs and add it to your project.
Add this to your Form1 code:
using Demo.WindowsForms.CustomMarkers;
Now you can use the new marker via following:
GMarkerArrow marker1 = new GMarkerArrow(new PointLatLng(-30, -40));
marker1.ToolTipText = "blablabla";
marker1.ToolTip.Fill = Brushes.Black;
marker1.ToolTip.Foreground = Brushes.White;
marker1.ToolTip.Stroke = Pens.Black;
marker1.Bearing = 30; // Rotation angle
marker1.Fill = new SolidBrush(Color.FromArgb(155, Color.Blue)); // Arrow color
markers.Markers.Add(marker1);
gMapControl1.Overlays.Add(markers);
Also i want to thanks #rdoubleui , thanks you sir.
I hope this helps to everyone.
GMapOverlay markersOverlay;
private void AddOrUpdateMarker(string tag, double lat, double lng, Image NewImage)
{
Bitmap bmpmarker = (Bitmap)NewImage;
var marker = markersOverlay.Markers.FirstOrDefault(m => m.Tag == tag);
if(marker!=null)
{
markersOverlay.Markers.Remove(marker);
gMapControl1.Refresh();
marker = new GMarkerGoogle(new PointLatLng(lat, lng), bmpmarker);
marker.Tag = tag;
markersOverlay.Markers.Add(marker);
gMapControl1.Refresh();
}
else
{
marker = new GMarkerGoogle(new PointLatLng(lat, lng), bmpmarker);
marker.Tag = tag;
markersOverlay.Markers.Add(marker);
gMapControl1.Refresh();
}
}
The problem updating the image of that marker is that the Image property is not publicly accessible, therefore you can not update the image that way.
There are two possibilities: first one is to replace the marker reference with a new one giving you the opportunity to set a new image and copying the position of the current marker. However that is not the clean way as you unnecessarily create a whole bunch of references only to dispose them right away depending on the use case. If it's a one-time update, then this approach is fine.
The preferable way is to derive from GMapMarker as the Google marker does (you can use that as a template, leaving out the whole google specific icon logic). Are you familiar with the concept of deriving? It will require some more effort but will be worth it, could help with that.
Also your main reference is probably the project's github page.
EDIT
using System.Drawing;
public class GImageMarker : GMapMarker
{
public Bitmap Bitmap { get; set; }
public GImageMarker(PointLatLng p, Bitmap Bitmap)
: base(p)
{
this.Bitmap = Bitmap;
Size = new System.Drawing.Size(Bitmap.Width, Bitmap.Height);
Offset = new Point(-Size.Width / 2, -Size.Height);
}
public override void OnRender(Graphics g)
{
g.DrawImage(Bitmap, LocalPosition.X, LocalPosition.Y, Size.Width, Size.Height);
}
}

C# Graphics Object is currently in use elsewhere

I created a game based on a totorial to start learning, I am rendering my game with renderScreen(), when I moved my window on screen I have got this exception "Object is currently in use elsewhere". I know the reason of error but I could not fix it as I do not know how to do that.
What can I do ? Forgive me if question is stupid.
engine.cs
//MEMBERS
public static Graphics drawHandle;
private Thread renderThread;
public engine(Graphics g)
{
drawHandle = g;
}
private object bufferLock = new object();
public void init()
{
renderThread = new Thread(new ThreadStart(renderScreen));
renderThread.Start();
}
public void stop()
{
renderThread.Abort();
}
public static Bitmap frame = new Bitmap(Globals.CANVAS_WIDTH, Globals.CANVAS_HEIGHT);
Rectangle rect = new Rectangle(0, 0, frame.Width, frame.Height);
private void renderScreen()
{
int framesRendered = 0;
long startTime = Environment.TickCount;
Graphics frameGraphics = Graphics.FromImage(frame);
Unit1 unit1 = new Unit1("test1");
Unit1 unit2 = new Unit1("test2");unit2.x = 250; unit2.y = 100;
Globals.GameUnitsList.Add(unit1); Globals.GameUnitsList.Add(unit2);
while (true)
{
//BACKGROUND
frameGraphics.FillRectangle(new SolidBrush(Color.DarkBlue),0,0, Globals.CANVAS_WIDTH, Globals.CANVAS_HEIGHT);
//BOXES
Rectangle rect = new Rectangle(unit1.x, unit1.y, 50, 50);
unit1.rectangle = rect;
unit1.fillColor = Brushes.LightBlue;
unit1.hitPoints = 100;
unit1.Health = 10;
frameGraphics.FillRectangle(unit1.fillColor, unit1.rectangle);
frameGraphics.FillRectangle(unit1.fillColor, unit1.rectangle);
Rectangle rect2 = new Rectangle(unit2.x, unit2.y, 50, 50);
unit2.rectangle = rect2;
unit2.fillColor = Brushes.LightBlue;
unit2.hitPoints = 100;
unit2.Health = 50;
frameGraphics.FillRectangle(unit2.fillColor, unit2.rectangle);
frameGraphics.FillRectangle(unit2.fillColor, unit2.rectangle);
//HEALTH BAR
HealthBar hb = new HealthBar();
hb.barColor = Brushes.YellowGreen;
hb.damageColor = Brushes.Red;
frameGraphics.FillRectangle(hb.damageColor, hb.Draw(unit1, unit1.x, unit1.y)[1]);
frameGraphics.FillRectangle(hb.barColor, hb.Draw(unit1, unit1.x, unit1.y)[0]);
HealthBar hb2 = new HealthBar();
hb2.barColor = Brushes.YellowGreen;
hb2.damageColor = Brushes.Red;
frameGraphics.FillRectangle(hb2.damageColor, hb2.Draw(unit2, unit2.x, unit2.y)[1]);
frameGraphics.FillRectangle(hb2.barColor, hb2.Draw(unit2, unit2.x, unit2.y)[0]);
//UNIT NAMES
frameGraphics.DrawString(unit1.unitName, new Font("Arial", 24, FontStyle.Bold), Brushes.Yellow, unit1.x + 50, unit1.y + 50);
frameGraphics.DrawString(unit2.unitName, new Font("Arial", 24, FontStyle.Bold), Brushes.Yellow, unit2.x + 50, unit2.y + 50);
drawHandle.DrawImage(frame, 0, 0);
//BENCHMARKING
if (Environment.TickCount >= startTime + 750)
{
framesRendered++;
}
if (Environment.TickCount>=startTime+1000)
{
Console.WriteLine("Gomi-Invade Plan Game:"+framesRendered +"fps "+ Environment.TickCount);
framesRendered = 0;
startTime = Environment.TickCount;
}
}
}
gamewindow.cs
...
public static GameWindow gameW;
Game game = new Game();
...
//I have this code inside it but is this wrong ?
private void canvas_Paint(object sender, PaintEventArgs e)
{
Graphics g = canvas.CreateGraphics();
game.startGraphics(g);
}
...
game.cs
private engine Gengine;
public void startGraphics(Graphics g)
{
Gengine = new GomiEngine(g);
Gengine.init();
}
public void stopGame()
{
Gengine.stop();
}
You cannot render screen in your own thread, you need to call invalidate in invoke which will enqueue windows message to windows message loop which will be processed on main thread.
private void DoWorkInThread(object sender, EventArgs e)
{
while (true)
{
lock(this)
{
//update member properties
}
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate void ()
{
//this.Invalidate(); //if you don't need to render every frame, invalidate is better then refresh
this.Refresh(); //call refresh for immediate update
});
}
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
lock(this)
{
//read your member which are modifies by the thread
}
//do rendering
e.Graphics.Draw(...);
}

Memory Leaks : ListView with Bitmaps

I have a clearly memory leak problem and I need some help/advices to solve it.
My scenario has a simple ListView that displays image and title. This image is a bitmap Image downloaded from server.
After scrolling up and down so FAST this ListView crashes my app, and if i inspect the console i have a OOM Exception like that:
[art] Clamp target GC heap from 111MB to 96MB
[art] Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 0% free, 95MB/96MB, paused 1.187ms total 38.840ms
To avoid that OOM i implemented a LRUCache and DiskCache for store downloaded bitmaps into device, and get this files instead download images again.
This is my ListView Adapter:
public class LazyLoadAdapter : BaseAdapter
{
Activity _activity;
List _products;
BitmapCache cache;
ImageView _imgView;
Dictionary<string, Task> pendingFetch = new Dictionary<string, Task> ();
Bitmap NoMapPicture;
public LazyLoadAdapter(Activity activity, List<CouponExchange> products)
{
_activity = activity;
_products = products;
NoMapPicture = PrepareNoMapPicture (Resource.Drawable.default_coupon);
this.cache = BitmapCache.CreateCache (activity, "MapCache");
}
public override int Count
{
get { return _products.Count; }
}
public override Java.Lang.Object GetItem(int position)
{
return position;
}
public override long GetItemId(int position)
{
return position;
}
public override Android.Views.View GetView(int position, Android.Views.View convertView, Android.Views.ViewGroup parent)
{
if (convertView == null)
{
convertView = _activity.LayoutInflater.Inflate(Resource.Layout.ShopItemList, parent, false);
}
CouponExchange product = _products[position];
TextView txtProductName = convertView.FindViewById<TextView>(Resource.Id.textView24);
txtProductName.Text = product.CouponTitle;
TextView txtProductCost = convertView.FindViewById<TextView>(Resource.Id.textView24b);
txtProductCost.Text = product.Cost.ToString();
_imgView = convertView.FindViewById<ImageView>(Resource.Id.imgProduct);
GetPersonPicture (product.CouponImageUrl);
return convertView;
}
Bitmap DownloadoCacher (string url)
{
Bitmap map = null;
using(map){
map = cache.TryGet2 (url);
if (map!=null)
return map;
byte[] bytes;
using (var wc = new WebClient ()) {
bytes = wc.DownloadData (url);
};
if (bytes != null && bytes.Length > 0) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.InJustDecodeBounds = true;
map = DecodeSampledBitmapFromResource (bytes, 400, 200);
} else {
return map;
}
cache.AddOrUpdate (url, map, TimeSpan.FromDays (1));
return map;
};
}
public static Bitmap DecodeSampledBitmapFromResource(byte[] bytes,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.InJustDecodeBounds = true;
BitmapFactory.DecodeByteArray(bytes, 0, bytes.Length, options);
// Calculate inSampleSize
options.InSampleSize = CalculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.InJustDecodeBounds = false;
return BitmapFactory.DecodeByteArray(bytes, 0, bytes.Length, options);
}
public static int CalculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
int height = options.OutHeight;
int width = options.OutWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
int halfHeight = height / 2;
int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
Bitmap PrepareNoMapPicture (int baseImage)
{
return BitmapFactory.DecodeResource (_activity.Resources, baseImage);
}
Bitmap GetPersonPicture (string url){
if (_imgView == null)
return null;
Bitmap map = null;
using (map) {
map = cache.TryGet2 (url);
if (map!=null) {
_imgView.SetImageBitmap (map);
} else {
_imgView.SetImageBitmap (NoMapPicture);
Action doMapSetting = () => {
_activity.RunOnUiThread (() => {
if (map == null){
map = cache.TryGet2 (url);
}
_imgView.SetImageBitmap (map);
});
};
if (pendingFetch.ContainsKey (url))
pendingFetch [url].ContinueWith (t => doMapSetting (), TaskContinuationOptions.ExecuteSynchronously);
else
pendingFetch[url] = SerialScheduler.Factory.StartNew (() => {
map = DownloadoCacher (url);
doMapSetting ();
});
}
return map;
};
}
Once images are downloaded, my cache gets images from device file.
After scroll up and down so fast, cacheDisk try get images from files and throws OOM Exception:
try {
bmp = Android.Graphics.BitmapFactory.DecodeFile (Path.Combine (basePath, key));
} catch (Exception e) {
var err = e.Message;
return null;
}
All replies would be appreciate. Thanks you
I use this Picasso Binding library for Xamarin :
https://github.com/jacksierkstra/Picasso
This powerful image downloading and caching library allows you to simplify your Image management.
Official documentation :
http://square.github.io/picasso/
Hope this helps

Need SlimDX to display images quickly

I need to display images very quickly (about 60 FPS). Picturebox/Panel doesn't do the job at higher resolutions, so I am now turning to SlimDX, which I hope is the right move.
As SlimDX uses Directx, and DirectX uses the GPU, I should be able to do it very quickly. From my understanding, the GPU works with images a lot faster than with the CPU.
I am doing this:
MessagePump.Run(form, () =>
{
device.BeginScene();
sprite.Begin(SlimDX.Direct3D9.SpriteFlags.None);
tx = SlimDX.Direct3D9.Texture.FromStream(device, (new MemoryStream(reader.ReadBytes(reader.ReadInt32()))), SlimDX.Direct3D9.Usage.None, SlimDX.Direct3D9.Pool.Managed);
sprite.Draw(tx, Color.Transparent);
sprite.End();
device.EndScene();
device.Present();
});
And initializing everything:
var form = new RenderForm("Test");
form.Width = 1280;
form.Height = 720;
SlimDX.Direct3D9.PresentParameters presentParams = new SlimDX.Direct3D9.PresentParameters
{
BackBufferWidth = form.Width,
BackBufferHeight = form.Height,
DeviceWindowHandle = form.Handle,
PresentFlags = SlimDX.Direct3D9.PresentFlags.None,
BackBufferCount = 0,
PresentationInterval = SlimDX.Direct3D9.PresentInterval.Immediate,
SwapEffect = SlimDX.Direct3D9.SwapEffect.Discard,
BackBufferFormat = SlimDX.Direct3D9.Format.A8R8G8B8,
Windowed = true,
};
device = new SlimDX.Direct3D9.Device(new SlimDX.Direct3D9.Direct3D(), 0, SlimDX.Direct3D9.DeviceType.Hardware, form.Handle, SlimDX.Direct3D9.CreateFlags.HardwareVertexProcessing, presentParams);
device.Viewport = new SlimDX.Direct3D9.Viewport(0, 0, form.Width, form.Height);
SlimDX.Direct3D9.Sprite sprite;
SlimDX.Direct3D9.Texture tx;
sprite = new SlimDX.Direct3D9.Sprite(device);
tx = new SlimDX.Direct3D9.Texture(device, form.Width, form.Height, 0, SlimDX.Direct3D9.Usage.None, SlimDX.Direct3D9.Format.X8R8G8B8, SlimDX.Direct3D9.Pool.Managed);
There are two problems with this:
it's extremely slow; picturebox is much faster
it shows the image incorrectly (it's zoomed in)
You need to cache the textures, as making them every frame is slow. E.g.
public class CacheObjects
{
static List cacheSCBrushes = new List();
public static SolidColorBrush GetColorBrush(Color4 Color, Direct2D.RenderTarget renderTGT)
{
// ERROR: Not supported in C#: OnErrorStatement
SolidColorBrush returnBrush = null;
bool found = false;
foreach (void br_loopVariable in cacheSCBrushes) {
br = br_loopVariable;
if (br.Color.Red == Color.Red) {
if (br.Color.Green == Color.Green) {
if (br.Color.Blue == Color.Blue) {
if (br.Color.Alpha == Color.Alpha) {
found = true;
returnBrush = br;
exit for;
}
}
}
}
}
if (!found) {
returnBrush = new SolidColorBrush(renderTGT, Color);
cacheSCBrushes.Add(returnBrush);
}
return returnBrush;
}
public static void ClearCache()
{
foreach (void Brush_loopVariable in cacheSCBrushes) {
Brush = Brush_loopVariable;
Brush.Dispose();
}
}
}
If that is impossible, [In a seperate thread], load the next 5 textures...Rendering is fast, object creation is slow.
public void LoadTexture () {
//Load the next 5 here
}

Categories

Resources