I'm writing a 2d tile-based engine. Currently, my drawing routine uses the C# Drawing library to redraw every visible tile every time the screen refreshes. I got scrolling and zooming to work, and everything looks the way I want it to. But the routine is slow. Now I'm trying to improve it. I've a couple of questions:
First, I think redrawing the tiles at every refresh is unnecessary (since they never change). Right now I'm trying to change the algorithm so that it writes the whole map to a single bitmap at initialization, and then cuts the correct portion of the bitmap when it's time to draw. Do you think this is the right way to go?
(I also considered leaving the image in the background and just scrolling over it. But then I decided that I don't want to draw stuff that's outside of the field-of-view. However, perhaps that is cheaper than cutting/pasting? A memory vs time issue?)
Second, as far as I understand the C# Drawing routines do not use the full power of the GPU. I think I should try to do the drawing in OpenGL (or DirectX, but I prefer the former, since it is multiplatform). Will that help? Do you know any tiling (or general pixel-drawing) tutorial for OpenGL? A book reference could also help.
I also don't do multi-threading at the moment (in fact I only have a vague idea of what that is). Should I try to multi-thread the drawer? Or would OpenGL make multi-threading for graphics redundant?
Thanks.
What application framework are you planning to use? Techniques for efficient drawing are very different between WinForms (Win32) and WPF.
You are correct that .NET drawing routines do not take full advantage of the GPU. Using DirectX or OpenGL, one immediate optimization would be to preload all of your image tiles (or at least, all of the tiles you need for the immediate view area plus a little more) into GPU memory using image lists or display lists. You would then draw the tiles on a surface by index - draw tile N at x,y. This is usually much faster than drawing on a GPU surface using bitmaps stored in main system memory, since the bitmap pixels have to be copied to the GPU for each tile drawn and that uses up a lot of time. Drawing by index also uses a lot less GPU memory whenever you can use the same image tile in multiple places in the output.
OpenGL vs DirectX is your choice, but IMO DirectX has been evolving at a faster rate providing more hardware accelerated functions than OpenGL. OpenGL drivers on Windows also have a reputation for being neglected by hardware vendors. Their primary focus is on their DirectX drivers.
Give some thought to whether you really need OpenGL or DirectX for your 2D tile application. Requiring OpenGL or DirectX will reduce the number of machines, particularly older machines, that can run your app. OpenGL and DirectX may be overkill. You can do a lot with plain old GDI if you're smart about it.
Stay away from multithreading until you have a really good reason to go there and you have some experience with threading. Multithreading offers the reward of some performance boosts for some computing situations, but also brings with it new headaches and new performance problems. Make sure the benefit is significant before you sign up for all these new headaches.
In general, moving pixels around on the screen is usually not a good match for multithreading. You've got only one display device (in most cases) so hitting it with multiple threads trying to change pixels at the same time doesn't work well. To borrow an expression from project management: If a woman can create a baby in 9 months, can you use 9 women to create 1 baby in 1 month? ;>
Work on identifying parts of your system that do not need to access the same resources or devices. Those are better candidates for running in parallel threads than blitting tiles to the screen.
The best optimization is to discover work that does not need to be done - reducing the number of times tiles are redrawn for example, or changing to an indexed model so the tiles can be drawn from GPU memory instead of system memory.
If you want to use OpenGL your best bet for 2d would be SDL.
Using OpenGL with C# will never be that portable simply due to the fact it would use .NET wrappers.
XNA is a great tool for writing games in C#, it should provide a lot more speed and flexibility then SDL does (especially the .net port) plus more features (however more bulk).
For your cutting or scrolling question, the best route would be scrolling.
Memory is much less of an issue than CPU when you're drawing using GDI+ (what System.Drawing uses). You could always split the map up into sections and scroll those then load when necessary if it's that big.
I'm not familiar with OpenGL, but I've written a tile based engine in ManagedDX (later ported to XNA). ManagedDX is depricated, but there's the SlimDX project which is still under active development.
With DX, you can load each individual tile into a Texture. (Using Texture.FromFile() or Texture.FromStream() for example), and have a single Sprite instance draw them. This performs pretty well. I group the textures in a simple class with a Point or Vector2 for their locations, set them only when the location changes rather than every time the draw method is called. I cache tiles in memory only for the immediate screen and one or two tiles beyond, there's no need for more than that as the file IO is quick enough to fetch new tiles as it's scrolled.
struct Tile
{
public Point Location;
public Texture Texture;
}
Device device;
Sprite sprite;
List<Tile> tiles = new List<Tile>();
.ctor() {
this.device = new Device(...)
this.sprite = new Sprite(this.device);
}
void Draw() {
this.device.Clear(ClearFlags.Target, Color.CornflowerBlue, 1.0f, 0);
this.device.BeginScene();
this.sprite.Begin(SpriteFlags.AlphaBlend);
foreach (Tile tile in this.tiles) {
this.sprite.Draw2D(tile.Texture,
new Point(0, 0), 0.0f, tile.Location, Color.White);
}
this.sprite.End();
this.device.EndScene();
this.device.Present();
}
Related
I am writing a program to imitate Natural Physics. I want to know whether there is a better way to draw an object other than overriding the OnDraw method, and FillRectangle(x,y,1,1) for each pixel.
Is there a way to do a similar action using DirectX or OpenGL? Because to my knowledge the Graphics does not utilize the video card of ones computer (please correct me if I am wrong).
Saying this I would like some thoughts in relation to creating a 3D environment using mathematical calculations to work out the relative quadrant sizes so that objects appear to be farther away then in reality (as a monitor is only 2D), or closer.
Yes. Drawing pixel by pixel with FillRectangle will be very inefficient and slow things down a huge amount. As you say, you should use a graphics rendering system such as DirectX or OpenGL. The choice of which is up to you. If you do a simple search on the web you will find many tutorials on how to get started with 3d graphics.
OpenGL focuses on "Draw me this object in space", and it will take care of rendering it, taking advantage of your graphics card if possible. You do not worry about the pixels, you specify dimensions, camera angles, shaders etc.
You can draw pixels with OpenGL, but that is not the 'correct' way to draw 3d graphics with it.
EDIT in response to Vasa's questions:
I believe OpenGL does what's best based on your graphics card capabilities and drivers. In general OpenGL isn't going to be your best option for drawing direct pixels. BUT remember that
Pixels are different sizes on different machines. Are you expecting to just live with this? Or live with a big display on low-res screens and a tiny one on high-res screens? There may be multiplications involved. If you use literal pixels then once you start multiplying for different screens you are going to get artefacts and inaccuracies.
You want a direct mapping of X to pixels. OpenGL uses float values. They aren't integer 1 to 1 mappings, but they do use a direct proportion. If you choose a scale then OpenGL is not going to suddenly start distorting ratios.
The important thing is proportions not absolute pixels. Although I accept that it's possible for your case to be different.
See this for 2d drawing:
http://basic4gl.wikispaces.com/2D+Drawing+in+OpenGL
So I've been trying to wrap my head around shaders in 2D in XNA.
http://msdn.microsoft.com/en-us/library/bb313868(v=xnagamestudio.31).aspx
This link above stated that I needed to use SpriteSortMode.Immediate, which is a problem for me because I have developed a parallax system that relies on deferred rendering (SpriteSortMode.BackToFront).
Can someone explain to me the significance of SpriteSortMode in shaders, if Immediate is mandatory, anything I can do to maintain my current system, and anything else in general to help me understand this better?
In addition, my game runs off of multiple SpriteBatch.Begin()/End() calls (for drawing background, then the game, then the foreground and HUD and etc). I've noticed that the Bloom example does not work in that case, and I am guessing it has something to do with this.
In general, I've been having some trouble understanding these concepts. I know what a shader is and how it works, but I don't know how it interacts with XNA and what goes on there. I would really appreciate some enlightenment. :)
Thanks SO!
The sort mode will matter if you are attempting to do something non-trivial like render layered transparency or make use of a depth buffer. I'm going to assume you want to do something non-trivial since you want to use a pixel shader to accomplish it.
SpriteSortMode.Immediate will draw things in exactly the order of the draw calls. If you use another mode, SpriteBatch will group the draw calls to the video card by texture if it can. This is for performance reasons.
Keep in mind that every time you call SpriteBatch.Begin you are applying a new pixel shader and discarding the one previously set. (Even if the new one is just SpriteBatch's standard pixel shader that applies a Tint color.) Additionally, remember that by calling SpriteBatch.End you are telling the video card to execute all of the current SpriteBatch commands.
This means that you could potentially keep your existing sorting method, if your fancy pixel shaders are of limited scope. In other words, draw your background with one Effect and then your foreground and characters with another. Each Begin/End call to SpriteBatch can be treated separately.
If your goal is to apply one Effect (such as heat waves or bloom) to everything on the screen you have another option. You could choose to render all of your graphics onto a RenderTarget that you create instead of directly to the video card's backbuffer. If you do this, at the end of your rendering section you can call GraphicsDevice.SetRenderTarget(null) and paint your completed image to the backbuffer with a custom shader that applies to the entire scene.
I'm not one hundred percent sure on how much the sprite sorting mode effects shaders, i would think it would vary depending on what you were using the shader for.
as for bloom if you're using multiple begin and ends (which you really want to minimise if you can). you can create a render target the size of the screen, draw everything as you are now. then at the very end, take that render target back (using graphicsdevice.SetRenderTarget(null);) then draw your full screen render target (at 0,0 position) with the bloom shader, that way you will bloom the entire scene, regardless of the components of the scene using various sort modes.
I have developed a quite large application using MFC. Naturaly, I used GDI for drawing, CCmdTarget for event routing, and the document-view architecture.
It was a convenient development path.
Now, the client is interested in converting this application to .Net.
I would prefer (and they too) writing the new product in C#.
The application displays and interacts with thousands of graphic objects, so
I figured going with GDI+, although seems natuaral, can cause performance issues,
So I am thinking of using OpenGL, specifically - OpenTK - as the graphics library (it's 2D).
I know that OpenGL works differently that these Windows APIs, which rely on Invalidation of portion of the screen. OpenGL has a rendering loop which constantly draws to the screen.
My question is:
Is this an acceptable way to go, thinking of:
performance - will the users need special graphics cards (hardware?). It is graphics intensive, but it's not a high-end game
printing and print preview - are these things complex to achienve?
multiple selection and context menus
Is this library goes well inside windows forms?
I don't think so. Use WPF if you can or DirectX if you can't.
I know it might not be fair but if I'm programming on .NET (microsoft) on windows (microsoft) I'd rather use DirectX ... which is also from microsoft.
As a side note: don't reinvent the wheel. Recoding user controls in open-gl can be very time consuming, if you do make sure you have a good reason.
In my experience developing CAD-like software, the benefits of OpenGL and DirectX are fast depth testing, smooth rotation and panning, lighting and powerful texture capabilities. Obviously there are other benefits but, despite what most tutorials would lead you to believe, implementing a rendering system using either of these APIs is a significant undertaking and should not be taken lightly.
Specifically:
If it is a 2D app and you already have it implemented in GDI then switching to GDI+ will be much easier. Additionally, on modern hardware, 2D GDI or GDI+ can be about as fast as 2D OpenGL or DirectX. And ultimately, the end-user probably won't notice the difference, especially with double buffered support in GDI+.
You do not need (and probably don't want) a continuous rendering loop for your app. In OpenGL and DirectX you can explicitly invalidate the window when your scene changes.
If you go with OpenGL or DirectX you will need to consider putting your objects into display lists or vertex arrays (buffers) for fast drawing. This is not difficult but managing objects in this way adds complexity to the system and will most likely significantly change the architecture of your rendering system.
Printing in either OpenGL or DirectX can also be tedious. On the one hand you can render to a bitmap and print that out. However, for high quality images you may want vectorized images instead, which are difficult to produce with either of these rendering frameworks.
I would also stay away from writing GUIs in OpenGL or DirectX...unless you're really looking for a challenge ;~)
Finally, and this is just an annoyance from an install perspective, the Managed DirectX run-time library that must be installed on the user's machine is around 100 MB.
I have no experience with C#, but I have once built a layer system for a drawing program that used openGL for rendering.
To make this layer I asked openGL for the current framebuffer and converted it to an image to use as a texture under the current canvas. So I guess from there its pretty easy to go to printing and print preview.
Direct X and Open GL much faster than GDI+.
You can also use an TAO framework as an alternative to OpenTK.
Is there another way to render graphics in C# beyond GDI+ and XNA?
(For the development of a tile map editor.)
SDL.NET is the solution I've come to love. If you need 3D on top of it, you can use Tao.OpenGL to render inside it. It's fast, industry standard (SDL, that is), and cross-platform.
Yes, I have written a Windows Forms control that wraps DirectX 9.0 and provides direct pixel level manipulation of the video surface.
I actually wrote another post on Stack Overflow asking if there are other better approaches: Unsafe C# and pointers for 2D rendering, good or bad?
While it is relatively high performance, it requires the unsafe compiler option as it uses pointers to access the memory efficiently. Hence the reason for this earlier post.
This is a high level of the required steps:
Download the DirectX SDK.
Create a new C# Windows Forms project and reference the installed
Microsoft DirectX assembly.
Initialize a new DirectX Device object with Presentation Parameters
(windowed, back buffering, etc.) you require.
Create the Device, taking care to record the surface "Pitch" and
current display mode (bits per pixel).
When you need to display something, Lock the backbuffer
surface and store the returned pointer to the start of surface
memory.
Use pointer arithmetic, calculate the actual pixel position in the
data based on the surface pitch,
bits per pixel and the actual x/y pixel coordinate.
In my case for simplicity I am sticking to 32 bpp, meaning setting a pixel is as simple as: *(surfacePointer + (y * pitch + x))=Color.FromARGB(255,0,0);
When finished drawing, Unlock the back buffer surface. Present the surface.
Repeat from step 5 as required.
Be aware that taking this approach you need to be very careful about checking the current display mode (pitch and bits per pxiel) of the target surface. Also you will need to have a strategy in place to deal with window resizing or changes of screen format while your program is running.
Managed DirectX (Microsoft.DirectX namespace) for faster 3D graphics. It's a solid .NET wrapper over DirectX API, which comes with a bit of performance hit for creating .NET objects and marshalling. Unless you are writing a full featured modern 3D engine, it will work fine.
Window Presentation Foundation (WPF) (Windows.Media namespace) - best choice for 2D graphics. Also has limited 3D abilities. Aimed to replace Windows Forms with vector, hardware accelerated resolution-independent framework. Very convenient, supports several flavours of custom controls, resources, data binding, events and commands... also has a few WTFs. Speed is usually faster than GDI and slower than DirectX, and depends greatly on how you do things (seen something to work 60 times faster after rewriting in a sensible way). We had a success implementing 3 1280x1024 screens full of real-time indicators, graphs and plots on a single (and not the best) PC.
You could try looking into WPF, using Visual Studio and/or Expression Blend. I'm not sure how sophisticated you're trying to get, but it should be able to handle a simple editor. Check out this MSDN Article for more info.
You might look into the Cairo graphics library. The Mono project has bindings for C#.
Cairo is an option. I'm currently rewriting my mapping software using both GDI+ and Cairo. It has a tile map generator, among other features.
I've been doing some Johnny Chung Lee-style Wiimote programming, and am running into problems with the Wiimote's relatively narrow field-of-view and limit of four points. I've bought a Creative Live! camera with an 85-degree field of view and a high resolution.
My prototype application is written in C#, and I'd like to stay there.
So, my question: I'd like to find a C#.Net camera / vision library that lets me track points - probably LEDs - in the camera's field of view. In the future, I'd like to move to R/G/B point tracking so as to allow more points to be tracked and distinguished more easily. Any suggestions?
You could check out the Emgu.CV library which is a .NET (C#) wrapper for OpenCV. OpenCV is considered by many, including myself, to be the best (free) computer vision library.
Check out AForge.Net.. It seems to be a powerful library.
With a normal camera, the task of identifying and tracking leds is quite more challanging, because of all the other objects which are visibile.
I suggest that you try to maximize the contrast by reducing the exposure (thus turning of auto-exposure), if that's possible in the driver: you should aim for a value where your leds have still an high intensity in the image (>200) while not being overexposed (<255). You should then be able to threshold your image correctly and get higher quality results.
If the image is still too cluttered to be analyzed easily and efficiently, you may use infrared leds, remove the IR-block filter on the camera (if your camera has it), and maybe add an "Infrared Pass / Visible Light blocking" filter: you should then have bright spots only where the leds are, but you will not bee able to use color. There may be issues with the image quality though.
When tracking things like lights, especially if they are a special color, I recommend you apply a blur filter to the footage first. This blends out colors nicely, a while less accurate, will use less CPU and there's less threshold adjustments you have to do.