I have a control (picturebox), in which I want to draw an 2D image with the help of DirectX.
I have a display and sprite, and it works fine.
// Some code here...
_device = new Device(0, DeviceType.Hardware, pictureBox1,
CreateFlags.SoftwareVertexProcessing,
presentParams);
_sprite = new Sprite(_device);
// ...
_sprite.Draw(texture, textureSize, _center, position, Color.White);
The problem is that texture size is much larger than picturebox, and I just want to find the way to fit it there.
I tried to set device.Transform property but it doesn't help:
var transform = GetTransformationMatrix(textureSize.Width, textureSize.Height);
_device.SetTransform(TransformType.Texture0, transform);
Here is GetTransform method:
Matrix GetTransformationMatrix(float width, float height)
{
var scaleWidth = pictureBox1.Width /width ;
var scaleHeight = pictureBox1.Height / height;
var transform = new Matrix();
transform.M11 = scaleWidth;
transform.M12 = 0;
transform.M21 = 0;
transform.M22 = scaleHeight;
return transform;
}
Thanks for any solution || help.
The solution was just to use this:
var transformMatrix = Matrix.Scaling(scaleWidth, scaleHeight, 0.0F);
instead of hand-made method.
Related
Is anyone able to help me translate this method in ios to mac version? Code is written in C# in Xamarin
public static UIImage GetImageFromColor(UIColor color, float borderWidth = 1.0f)
{
var rect = new CGRect(0.0f, 0.0f, borderWidth, borderWidth);
UIGraphics.BeginImageContext(rect.Size);
var context = UIGraphics.GetCurrentContext();
context.SetFillColor(color.CGColor);
context.FillRect(rect);
var image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return image.CreateResizableImage(new UIEdgeInsets(1.0f, 1.0f, 1.0f, 1.0f));
}
UIGraphics.BeginImageContext translates to a CGBitmapContext (or CGContext depending upon what you need).
So to fill a CGBitmapContext with a color:
var size = new CGSize(width, height);
var rect = new CGRect(new CGPoint(), size);
NSImage image;
using (var context = new CGBitmapContext(IntPtr.Zero, width, height, 8, width * 4, NSColorSpace.GenericRGBColorSpace.ColorSpace, CGImageAlphaInfo.PremultipliedFirst))
{
context.SetFillColor(NSColor.Red.CGColor);
context.FillRect(rect);
using (var cgImage = context.ToImage())
{
image = new NSImage(cgImage, size);
}
}
Note: You should use using or make sure that you Dispose of the context and CGImage to avoid a memory leak
This is not a translation from the code you posted but it does exactly the same job:
public static NSImage GetImageFromColor (NSColor color, float borderWidth = 1.0f)
{
var image = new NSImage (new CGSize (borderWidth, borderWidth));
image.LockFocus ();
color.DrawSwatchInRect (new CGRect (new CGPoint (0, 0), image.Size));
image.UnlockFocus ();
return image;
}
Hope this helps.-
In a graphic application i am rendering an image to a texture, then i use that texture on a 3d model.
My problem is the following:
When the application starts everything is fine, but if i resize the view where i do the rendering and i make it bigger, the texture on the 3d model disappear (it doesnt turn black, i think that all values become 1). Making the image smaller doesnt make the texture to disappear, but it is shown incorrectly (not resized).
Here are some explanatory images:
Resize smaller
Not resized
Resize bigger, 1 pixel bigger is enough to make image disappear.
The code that generate the renderview is this:
private void CreateRenderToTexture(Panel view)
{
Texture2DDescription t2d = new Texture2DDescription()
{
Height = view.Height,
Width = view.Width,
Format = Format.R32G32B32A32_Float,
BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget, //| BindFlags.UnorderedAccess,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None,
SampleDescription = new SampleDescription(_multisample, 0),
MipLevels = 1,
Usage = ResourceUsage.Default,
ArraySize = 1,
};
_svgTexture = new Texture2D(_device, t2d);
_svgRenderView = new RenderTargetView(_device, _svgTexture);
}
private void RenderSVGToTexture()
{
_camera.SetDefaultProjection();
UpdatePerFrameBuffers();
_dc.OutputMerger.SetTargets(_depthStencil, _svgRenderView);//depth stencil has same dimension as all other buffers
_dc.ClearRenderTargetView(_svgRenderView, new Color4(1.0f, 1.0f, 1.0f));
_dc.ClearDepthStencilView(_depthStencil, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1.0f, 0);
Entity e;
if (RenderingManager.Scene.Entity2DExists("svgimage"))
{
RenderingManager.Scene.GetEntity2D("svgimage", out e);
e.Draw(_dc);
}
_swapChain.Present(0, PresentFlags.None);
}
When rendering the 3D scene i call this function before rendering the model:
private void SetTexture()
{
Entity e;
if (!RenderingManager.Scene.GetEntity3D("model3d", out e))
return;
e.ShaderType = ResourceManager.ShaderType.MAIN_MODEL;
if (ResourceManager.SVGTexture == null )
{
e.ShaderType = ResourceManager.ShaderType.PNUVNOTEX;
return;
}
SamplerDescription a = new SamplerDescription();
a.AddressU = TextureAddressMode.Wrap;
a.AddressV = TextureAddressMode.Wrap;
a.AddressW = TextureAddressMode.Wrap;
a.Filter = Filter.MinPointMagMipLinear;
SamplerState b = SamplerState.FromDescription(ResourceManager.Device, a);
ShaderResourceView svgTexResourceView = new ShaderResourceView(ResourceManager.Device, Texture2D.FromPointer(ResourceManager.SVGTexture.ComPointer));
ResourceManager.Device.ImmediateContext.PixelShader.SetShaderResource(svgTexResourceView, 0);
ResourceManager.Device.ImmediateContext.PixelShader.SetSampler(b, 0);
b.Dispose();
svgTexResourceView.Dispose();
}
Pixel shader:
Texture2D svg : register(t0);
Texture2D errorEstimate : register(t1);
SamplerState ss : register(s0);
float4 main(float4 position : SV_POSITION, float4 color : COLOR, float2 uv : UV) : SV_Target
{
return color * svg.Sample(ss, uv);// *errorEstimate.Sample(ss, uv);
}
I dont understand what i am doing wrong, i hope that you can make me see the mistake that i am doing. Thank you, and sorry for the bad english!
As it (almost) always turn out i was making a very stupid mistake.
I wasn't calling the correct resize function.
Basically in the Renderer2D class there is a DoResize function that does the resize of the 2d only buffers, while in the abstract Renderer class there is the rest of the buffers resizing. The mistake is that in the parent class i was calling the wrong base resize function!
Parent class:
protected override void DoResize(uint width, uint height)
{
if (width == 0 || height == 0)
return;
base.DoResize(width, height); //Here i was calling base.Resize (which was deprecated after a change in the application architecture)
_camera.Width = width;
_camera.Height = height;
_svgTexture.Dispose();
_svgRenderView.Dispose();
CreateRenderToTexture(_viewReference);
ResizePending = false;
}
Base class
protected virtual void DoResize(uint width, uint height)
{
Width = width;
Height = height;
_viewport = new Viewport(0, 0, Width, Height);
_renderTarget.Dispose();
if (_swapChain.ResizeBuffers(2, (int)width, (int)height, Format.Unknown, SwapChainFlags.AllowModeSwitch).IsFailure)
Console.WriteLine("An error occured while resizing buffers.");
using (var resource = Resource.FromSwapChain<Texture2D>(_swapChain, 0))
_renderTarget = new RenderTargetView(_device, resource);
_depthStencil.Dispose();
CreateDepthBuffer();
}
Maybe the code i posted can be of help for someone who is trying to do some render to texture stuff, since i see that there is always people that can't make it work :)
I am writing an application for Windows 10 using Win2D and I'm trying to draw a shape which scales dynamically to fit whatever text happens to be in it.
What I'd like to do is work out how big a particular string would be with a given CanvasTextFormat and then use that to set the size of the shape.
My problem is I can't seem to find a way of working out how big the string will be?
See code below to calculate the required size (look for "theRectYouAreLookingFor")
private void CanvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args)
{
CanvasDrawingSession drawingSession = args.DrawingSession;
float xLoc = 100.0f;
float yLoc = 100.0f;
CanvasTextFormat format = new CanvasTextFormat {FontSize = 30.0f, WordWrapping = CanvasWordWrapping.NoWrap};
CanvasTextLayout textLayout = new CanvasTextLayout(drawingSession, "Hello World!", format, 0.0f, 0.0f);
Rect theRectYouAreLookingFor = new Rect(xLoc + textLayout.DrawBounds.X, yLoc + textLayout.DrawBounds.Y, textLayout.DrawBounds.Width, textLayout.DrawBounds.Height);
drawingSession.DrawRectangle(theRectYouAreLookingFor, Colors.Green, 1.0f);
drawingSession.DrawTextLayout(textLayout, xLoc, yLoc, Colors.Yellow);
}
If you create a CanvasTextLayout with a requestedWidth of 0, like in the example of Michael Vach, you may want to disable Word Wrap in Win2D 1.23. Like:
var textLayout = new CanvasTextLayout(drawingSession, "Hello World!", fontFormat, 0.0f, 0.0f) {
WordWrapping = CanvasWordWrapping.NoWrap
};
var completeOuterSize = textLayout.LayoutBounds
(I'm not allowed to comment)
I'm trying to add shadows to my MonoGame-based 2D game. At first I just rendered semitransparent black textures to the frame, but they sometimes overlap and it looks nasty:
I tried to render all shadows into the stencil buffer first, and then use a single semitransparent texture to draw all shadows at once using the stencil buffer. However, it doesn't work as expected:
The two problems are:
The shadows are rendered into the scene
The stencil buffer is seemingly unaffected: the semitransparent black texture covers the entire screen
Here's the initialization code:
StencilCreator = new DepthStencilState
{
StencilEnable = true,
StencilFunction = CompareFunction.Always,
StencilPass = StencilOperation.Replace,
ReferenceStencil = 1
};
StencilRenderer = new DepthStencilState
{
StencilEnable = true,
StencilFunction = CompareFunction.Equal,
ReferenceStencil = 1,
StencilPass = StencilOperation.Keep
};
var projection = Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1);
var halfPixel = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
AlphaEffect = new AlphaTestEffect(GraphicsDevice)
{
DiffuseColor = Color.White.ToVector3(),
AlphaFunction = CompareFunction.Greater,
ReferenceAlpha = 0,
World = Matrix.Identity,
View = Matrix.Identity,
Projection = halfPixel * projection
};
MaskingTexture = new Texture2D(GameEngine.GraphicsDevice, 1, 1);
MaskingTexture.SetData(new[] { new Color(0f, 0f, 0f, 0.3f) });
ShadowTexture = ResourceCache.Get<Texture2D>("Skins/Common/wall-shadow");
And the following code is the body of my Draw method:
// create stencil
GraphicsDevice.Clear(ClearOptions.Stencil, Color.Black, 0f, 0);
var batch = new SpriteBatch(GraphicsDevice);
batch.Begin(SpriteSortMode.Immediate, null, null, StencilCreator, null, AlphaEffect);
foreach (Vector2 loc in ShadowLocations)
{
newBatch.Draw(
ShadowTexture,
loc,
null,
Color.White,
0f,
Vector2.Zero,
2f,
SpriteEffects.None,
0f
);
}
batch.End();
// render shadow texture through stencil
batch.Begin(SpriteSortMode.Immediate, null, null, StencilRenderer, null);
batch.Draw(MaskingTexture, GraphicsDevice.Viewport.Bounds, Color.White);
batch.End();
What could possibly be the problem? The same code worked fine in my XNA project.
I worked around the issue by using a RenderTarget2D instead of the stencil buffer. Drawing solid black shadows to a RT2D and then drawing the RT2D itself into the scene with a semitransparent color does the trick and is much simplier to implement.
I want to cut out a Part of an image.
My plan was to create a layer with a Image, but the image overflows the layer.
It should look like this example:
Any ideas? Thanks.
using (CGLayer starLayer = CGLayer.Create (g, rect.Size)) {
// set fill to blue
starLayer.Context.SetFillColor (0f, 0f, 1f, 0.4f);
starLayer.Context.AddLines (myStarPoints);
starLayer.Context.AddQuadCurveToPoint(this.points [3].X, this.points [3].Y, this.points [2].X, this.points [2].Y);
starLayer.Context.AddQuadCurveToPoint(this.points [5].X, this.points [5].Y, this.points [4].X, this.points [4].Y);
starLayer.Context.FillPath ();
double width = Math.Abs((double)(this.points [1].X - this.points [0].X));
float prop = this.tmpimage.Size.Width / (float)width;
float height = (this.tmpimage.Size.Height / prop);
double centerteeth = (Math.Sqrt (Math.Pow ((this.points [4].X - this.points [2].X), 2.0) + Math.Pow ((this.points [4].Y - this.points [2].Y), 2.0))) / 2 - (width/2);
starLayer.Context.DrawImage (new RectangleF ((float)centerteeth + this.points[2].X, this.points [2].Y, (float)width, height), this.imagerotated.CGImage);
// draw the layer onto our screen
float starYPos = 5;
float starXPos = 5;
g.DrawLayer (starLayer, new PointF (starXPos, starYPos));
}
If you are looking for a quick solution to get it done, can you use two images to accomplish what you need? (A black image, then the background) Put one UIImageView on top of another?
I usually only drop into using CoreGraphics for two reasons:
There is no other way to accomplish my goal
Using plain UIViews are not performant enough
Now I found a solution that worked for me, thank you for help anyway.
The imagesublayer is movable in the mainlayer.
Thats my solution:
CALayer imageLayer = new CALayer (Layer);
imageLayer.Frame = Layer.Bounds;
imageLayer.BackgroundColor = UIColor.Black.CGColor;
CAShapeLayer maskLayer = new CAShapeLayer();
maskLayer.FillRule = CAShapeLayer.FillRuleEvenOdd;
maskLayer.Frame = Frame;
double width = Math.Abs((double)(this.points [1].X - this.points [0].X));
float prop = this.tmpimage.Size.Width / (float)width;
float height = (this.tmpimage.Size.Height / prop);
CALayer lay = new CALayer ();
lay.Bounds = new RectangleF (0, 0, (float)width, height);
lay.Position = this.points[6];
lay.Contents = this.tmpimage.CGImage;
layers [6] = lay;
imageLayer.AddSublayer (lay);
CGPath p1 = new CGPath();
p1.MoveToPoint (this.points [2]);
p1.AddQuadCurveToPoint(this.points [3].X, this.points [3].Y, this.points [4].X, this.points [4].Y);
p1.AddQuadCurveToPoint(this.points [5].X, this.points [5].Y, this.points [2].X, this.points [2].Y);
maskLayer.Path = p1;
imageLayer.Mask = maskLayer;
Layer.AddSublayer (imageLayer);
CAShapeLayer pathLayer1 = new CAShapeLayer ();
pathLayer1.Path = maskLayer.Path;
pathLayer1.LineWidth = 0f;
pathLayer1.StrokeColor = UIColor.Clear.CGColor;
pathLayer1.FillColor = UIColor.Clear.CGColor;
Layer.AddSublayer (pathLayer1);