I am adding two different images on win2d canvas in different points and different size and run application display two images perfect points set to display. Then how I am select image and move on canvas.
Win2D is an immediate mode graphics library (from Wikipedia)
Immediate mode rendering is a style for application programming interfaces of graphics libraries, in which client calls directly cause rendering of graphics objects to the display. It does not preclude the use of double-buffering. In contrast to retained mode, lists of objects to be rendered are not saved by the API library. Instead, the application must re-issue all drawing commands required to describe the entire scene each time a new frame is required, regardless of actual changes. This method provides the maximum amount of control and flexibility to the application program.
So it's up to you to keep the reference of any object you want to modify, because once it's drawn it is lost.
So define your CanvasBitmap as a global resource or create some type of ResourceLocator. Then create a your own class that stores x,y,width,height kinda like a custom object;
public class GenericItem
{
public CanvasBitmap b;
public int x;
public int y;
public int w;
public int h;
}
Modified Example from Win2D:
CanvasBitmap cat, mouse;
GenericItem gi_cat;
load your bitmaps in:
async Task CreateResourcesAsync(CanvasControl sender)
{
cat = await CanvasBitmap.LoadAsync(sender, "ShawnsCat.jpg");
mouse = await CanvasBitmap.LoadAsync(sender, "Mouse.png");
// create your GenericItem here
gi_cat = new GenericItem();
// fill in your x,y,width,height,bitmap
}
now draw
void myWidget_Draw(CanvasControl sender, CanvasDrawEventArgs args)
{
args.DrawingSession.DrawImage(gi_cat.b, gi_cat.x, gi_cat.y);
}
now you can modify gi_cat.x gi_cat.y and whatever property you added.
gi_cat.x = 500;
gi_cat.y = 250;
and you can cause a redraw calling the Invalidate Method on the canvas control.
name_of_your_canvas.Invalidate();
which will cause the canvas control to redraw with the new position.
Basically you have to handle everything yourself. If you looking for a DOM like approach then just use the regular Canvas control available in XAML.
I have a pretty in depth Win2D Walkthrough here :
Win2D Getting Started: Windows Universal Application
Related
I'm trying to build a simple RPG using the C# Windows Forms (as I had recently stumbled upon a fun tutorial demonstrating this ability. I have two items:
A 'Character' object that has been placed IN game:
In-game character--GUI
I also have a code-generated Draw Object, a tree--built in-game:
public void MainFormPaint(object sender, PaintEventArgs e)
{
//Drawing a tree, to create transparency
Image Tree_2 = Image.FromFile("[Directory to PNG].png");
Tree_2.Tag = "Tree";
e.Graphics.DrawImage(Tree_2,50,50,200,200);
}
...which generates this:
Code-generated Tree Object
Seeing as I cannot detect the object by some means similar to:
Character.Bounds.Intersectswith([insert_my_picture].Bounds);
this leaves me kind of baffled, and I'm not sure what to do. I want to detect this collision, so that I can stop movement. However, I'm not sure how to check for an 'empty spot' next to me or any object for that matter that's code-generated. It's important to note that this image is code-generated to maintain the graphic's transparency (as apparently there are problems placing objects in the form and maintaining transparency with overlaying objects).
Thank you for your help!
As the graphic was drawn at runtime, I was needing to generate a Rectangle:
Rectangle firstTree = new Rectangle();
...in the public variables area, and then created it on paint event.
public void MainFormPaint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(Tree_Obj,50,50,200,200);
firstTree.X = 50;
firstTree.Y = 50;
firstTree.Width = 200;
firstTree.Height=200;
}
The full, encapsulating bounds were only for trial. Problem solved!
I would like to show 1 million locations on a map based on OpenStreetMap.
I work on C# VS2013 and GMAP.NET WPF. But, when I added markers for each location, the map cannot be shown up because the marker is a bitmap image.
And 1 million markers consume too much memory on my laptop (with 8 GB mem).
The code is:
public void add_marker(List<Tuple<double, double>> latLongList, ref GMapControl myMap)
{
System.Windows.Media.Imaging.BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri(#"C:\djx_2014_6_3\my_projects\test_gmap_dot_net\GMap_WPF\try1\try_gmap_wpf\try_gmap_wpf\images\map_marker.png", UriKind.Absolute);
bitmapImage.DecodePixelHeight = 5;
bitmapImage.DecodePixelWidth = 5;
bitmapImage.EndInit();
foreach(var v in latLongList)
{
GMap.NET.PointLatLng point = new GMap.NET.PointLatLng(v.Item1, v.Item2);
GMapMarker marker = new GMapMarker(point);
System.Windows.Controls.Image image = new System.Windows.Controls.Image();
image.Source = bitmapImage;
marker.Shape = image;
marker.ZIndex = 5;
myMap.Markers.Add(marker);
}
}
I do not want to use the image as markers but I cannot find out how to use default marker in openStreetMap.
Any help would be appreciated.
WPF wasn't designed to be used for things like this. First of all you're creating a Bitmap for each tag, which is a user control and comes with some pretty heavy overhead for GUI hit-testing and binding etc. Secondly, WPF renders with DirectX, which means at some point all that data has to be set up with vertex buffers and uploaded into the graphics card. If you use data binding or try to create separate UI elements then this is going to take a lot of initial set-up time and memory, as you have already discovered. And if you try to draw them yourself (e.g. by creating your own user control and overriding OnRender) then it can be even worse, since all that work is now being done every frame (apart from buffered stuff which still incurs the initial setup anyway so you're back to square one).
If I had to do this myself I would start by organizing the data set with an appropriate 2D structure such as a k-d tree, an R*-tree or even a basic quad-tree. This will allow you to quickly determine at any given moment which markers are in the view frustum.
Next, I would add the appropriate bindings to scrollbars etc so that I could monitor exactly where the current view frustum was, and then each frame I would update the list of visible tags based on that. So long as you don't have more than a few thousand objects comes into view at once you should be ok, otherwise you'll have to stagger the updates over multiple frames with a queue.
If that doesn't suit your needs then you really have only two options left: 1) generate the raw bitmap data yourself manually, or 2) use a more suitable technology.
My Aim:
I'd like to have the ability to retrieve the colour on the screen including the cursor, from certain coordinates.
In other words, I suppose you could say I'd like to retrieve the colour of the cursor (or at least, a certain point/pixel on the cursor).
My Difficulty:
I have some code already to retrieve the colour on the screen from certain coordinates, however I believe it does not include the cursor. I believe this to be because the method I'm using takes a screenshot (without the cursor), and reads colour from that.
My Current Code:
public static Color RetrieveColour(Point Coordinates)
{
//Use this 'image' to create a Graphics class.
using (Graphics Destination = Graphics.FromImage(ScreenPixel))
{
//Creates a graphic from the specified handler to a window.
//In this case, it uses a handler which has been initialised to zero.
using (Graphics Source = Graphics.FromHwnd(IntPtr.Zero))
{
//Handler from the source device context.
IntPtr HandlerSourceDC = Source.GetHdc();
//Handler to the destination device context.
IntPtr HandlerDC = Destination.GetHdc();
//BitBlt is responsible for doing the copying.
//Returns a non-zero value for upon success.
int retval = BitBlt(HandlerDC, 0, 0, 1, 1, HandlerSourceDC, Coordinates.X, Coordinates.Y, (int)CopyPixelOperation.SourceCopy);
//Release the handlers.
Destination.ReleaseHdc();
Source.ReleaseHdc();
}
}
//Retrieve the colour of the pixel at the specified coordinates.
return ScreenPixel.GetPixel(0, 0);
}
I should probably add, it should work with non-Windows cursors. By this I mean custom cursors from other applications (if that has any bearing on future answers).
As far as I am currently aware, the only way that you'd be able to do this is if you were to create a custom driver that can act as an intermediary between the user.
I haven't read much of it, but you might want to look into this project
http://www.codeproject.com/KB/cs/DesktopCaptureWithMouse.aspx?display=Print
Previously posted here: C# - Capturing the Mouse cursor image
How do I draw a line and assign events to it? I would like to draw a custom shape, but it should act like a normal Control, and have properties and events. E.g.:
button1_Click(object sender, EventArgs e)
{
DrawLine(width, height, location, location, color, panelToDrawShapeOn, nameThisShape);
}
nameThisShape_Click(object sender, EventArgs e)
{
MessageBox.Show("Click event raised.");
}
private void DrawLine(int width, int height, int location, int location, Color color, Panel panel, string controlName)
{
// Code to draw shape and setup events for it.
}
To confirm, I do know how to draw shapes using GDI+ but the problem is, they are static, and I can't "interact" with them, and no amount of searching has led me to the right place to find out how to interact with the shapes that I draw.
You're not going to be able to treat custom-drawn shapes as you would controls. As you've found, GDI+ is an immediate mode graphics system (as opposed a retained mode system). This means that if you want a persistent scene graph full of shapes to be rendered, you need to create and manage that yourself. Then, you would hook the events of interest on the control that's the drawing target and handle them by doing hit tests on your list of renderable objects (e.g., to find what shape, if any, the mouse is over).
Writing that code can be a lot of work, but you can find libraries to help you. For instance, in one of my work projects, we used a computational geometry library called JTS for the geometry representation and hit test code. If you want to avoid third-party libraries, you may get part of the way there with the Region class, which will at least give you hit tests.
I think I am fundamentally misunderstanding the way render targets work. In my understanding RenderTargets are just Textures that the spritebatch draw calls draw to.
So I tried this code to render GUI windows in order to make sure they can only draw in their client area and its cropped outside that.
for (int i = Controls.Count - 1; i >= 0; i--)
{
RenderTarget2D oldTarget;
if (graphics.GetRenderTargets().Count() == 0) oldTarget = null;
else oldTarget = (RenderTarget2D)graphics.GetRenderTargets()[0].RenderTarget; // Get the old target being used.
graphics.SetRenderTarget(canvas); //set the target to a temporary RT
graphics.Clear(Color.Black); // Clear it
Control c = Controls[i]; // Get the current control (a form in this case)
c.Draw(spriteBatch, gameTime); // Draw it to the temp RT
graphics.SetRenderTarget(oldTarget); // Set the RT back to the main RT
Vector2 dest = c.DrawCoOrds(); // Gets the draw coordinates of the control
spriteBatch.Begin();
spriteBatch.Draw(canvas, new Rectangle((int)dest.X, (int)dest.Y, c.Bounds.Width, c.Bounds.Height), new Rectangle((int)dest.X, (int)dest.Y, c.Bounds.Width, c.Bounds.Height), Color.White);
// take the rect from the temp RT and draw it to the main RT.
spriteBatch.End();
}
However this code only draws the last form in the list which means it must be clearing the main RT somehow but i dont understand why. I only call clear when the RT is set to the temp canvas.
i think the best method to draw gui controls is with ScissorRectangle, because lets draw only inside that rectangle, that can be the client area of the gui control.
MSDN: GraphicsDevice.ScissorRectangle
You need to enable this funcionality through a RasterizerState.
RasterizerState ScissorState = new RasterizerState()
{
ScissorTestEnabled = true;
}
Before you draw, call SpriteBatch.Begin with this state.
A video of my own gui running in a xbox360 :)
How did you create your render target and back buffer? By default you can't write to a render target multiple times after changing to a different render target. This is why:
http://blogs.msdn.com/b/shawnhar/archive/2007/11/21/rendertarget-changes-in-xna-game-studio-2-0.aspx
You can change the default behavior by creating your render targets with RenderTargetUsage.PreserveContents., and the back buffer by overriding GraphicsDeviceManager.PrepareDeviceSettings., changing GraphicsDeviceInformation.PresentationParameters.RenderTargetUsage, as described in the link. Although I believe overriding those settings is done differently in XNA 4.
All that being said, changing away from the default behavior has performance considerations, and is not recommended. You should find a way to do this differently. One possibility would be to create a separate render target for each of your windows, draw all of them, switch to the back buffer and draw the render targets to it.
A better option would be to use the scissor rectangle rasterizer state as proposed by #Blau.