Blitting from one surface to another

Hello everyone.

At first, let me thank you for this great lib.
I like how you could easily switch between MDX, OpenTK and Software without changing any line of code.

I'm fairly new to game development, so please bear with me.

I've got a simple problem but I can't find any proper solution after poking around in the example code you provide.
What I want to do is this:

I've got a big *.png file which hold my tileset.
And I've got a 2 dimensional array which holds tileIDs which translate to rectangular pieces in the big png file.
Now I need to build up a surface assembled from all these pieces of the png I need.

I think I missed something here, but the only solution that I found so far looks something like this:
1. Load the png holding all my tiles into a surface
2. Iterate through my array with tileIDs/Coordinates
2.a Create a rectangle for each tileID
2.b Create a surface for each tile via pngSurface.CarveSubSurface(tileRect);
2.c Push this tiny surface into an array

That leaves me with an array of 100 surfaces on a 10x10 (320x320Pixel) Map.
Now in my render method I need to iterate through this array everytime calling tiles[i].Draw(x*colum, y*row);

There's sure a better solution that I missed, but I can't find it. :(

In SDL I just copy all the the stuff I need from a position on surfaceA to a position on surfaceB and the show this surface in then render area.

I hope, someone could point me in the right direction...

Regards,
Zimble, Germany

Ok, found out how to do

Ok, found out how to do it.

Switch the RenderTarget to a surface and render everything there.
Than switch back RenderTarget to my DisplayWindow.

Unfortunately I'm running in the same problems as some other guy here.
After switching back to DisplayWindow I cannot draw Surfaces anymore when I'm running in MDX mode. The screen remains blank. OpenGL&Drawing both work fine.
However I can draw Rectangles and stuff via Display.DrawRect() on the blank surface.

Seems like my previous surfaces somehow loose connection to the Display RenderTarget.
So I did some further testing:

1. Created DisplayWindow and set as RenderTarget
2. Created a surface with a png and drawed it in the DisplayWindow - works fine as expected
3. Switched RenderTarget to another surface and back - DisplayWindow doe not show anything anymore

Then I did another test. I created a DisplayWindow, showed some stuff, switched RenderTargets like before, but AFTER switching I created a new surface from a png and tried to show this on the DisplayWindow. Guess what? - It worked! :)

Looks like the previously created surfaces somehow loose connection to their renderTarget(DisplayWindow) when you switch to Surface and then back to display Window.

Edit: Some further testing (see below example)
When you comment pictureSurface.Draw() out, the screen is black with a green rect as expected. If you press C the renderTarget is switched and then new created pictureSurface2 is shown. Works.

If you leave pictureSurface in the code, it is shown until you hit C and switch Targets. After that the display goes blank (except the green rect). If the pictureSurface is somehow broken, I would've expected this. But shouldn't then my intact pictureSurface2 be shown like it was before when I commented the first Surface out?
Strange...

       static DisplayWindow displayWindow1;
        static Surface pictureSurface;
        static Surface pictureSurface2;
       
        static void Main()
        {

            using (AgateSetup setup = new AgateSetup())
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);

                setup.AskUser = true;
                setup.Initialize(true, false, false);
                if (setup.Cancel) return;

                Form someForm = new Form();
                someForm.Size = new System.Drawing.Size(800, 600);
                someForm.Show();

                displayWindow1 = new DisplayWindow(someForm);

                pictureSurface = new Surface(Application.StartupPath + "\\Image.png");

                while (someForm.Visible)
                {
                    if (ERY.AgateLib.Keyboard.Keys[KeyCode.C])
                    {
                        SwitchSurfaces();
                        ERY.AgateLib.Keyboard.ReleaseAllKeys();
                    }
                    Display.RenderTarget = displayWindow1;
                    Display.BeginFrame();
                    Display.Clear();

                    pictureSurface.Draw(); /* comment this out or leave it in */
                    if(pictureSurface2 != null)
                        pictureSurface2.Draw();
                    Display.DrawRect(100, 200, 100, 100, ERY.AgateLib.Geometry.Color.Green);

                    Display.EndFrame();
                    Core.KeepAlive();
                    System.Threading.Thread.Sleep(10);
                }                
 
            }
           
        }
        public static void SwitchSurfaces()
        {
            Display.RenderTarget = pictureSurface;
            Display.BeginFrame();
            Display.DrawRect(100, 100, 100, 100, ERY.AgateLib.Geometry.Color.Red);
            Display.EndFrame();
            Display.RenderTarget = displayWindow1;
            pictureSurface2 = new Surface(Application.StartupPath + "\\Image.png");

        }

Surface has a Draw(Rectangle

Surface has a Draw(Rectangle sourceRect, Rectangle destRect) overload, so you can draw tiles directly from a large image that has all your tiles on it. Actually, I would recommend you do that instead of creating separate surfaces for each tile, because DirectX and OpenGL both get better performance when there is fewer textures to switch between. AgateLib is also optimized for subsequent draws from the same surface. Also, is there a reason you're using an intermediate surface to draw to?

As far as the MDX render-to-surface issue, I think it works in some cases and not others, as it seems like you've discovered. I *think* it's fixed in the SVN repository, but I will use your code as another test.

Thanks kanato I'll have a

Thanks kanato

I'll have a look in the SVN-Version and see if that works.

About the Draw(srcRect, dstRect) method:
Maybe I'm misunderstanding something here.
But this method works on one Surface. So I load my png file with all the tiles into a surface (which then is the size of the png). On this surface I could use the Draw(Rect,Rect) methode to copy a part of the surface to another location of the same surface. But this would overwrite any previous surface data (and thus parts of the png-image) at this location.

Or consider a GUI lib.
What I've done in sdl.net was:
Created a panel(which inherits from surface) and added some controls on it. Each control had it's own surface representing the visuals of the control. The Panel.Refresh() function took the surfaces from all controls and copied them to their respective locations on the panel-surface.
In my main app I could then just take the assembled surface from Panel and show it on the screen.

I'm not quite sure how to do something like this with your lib. Seems I miss something here and there is a completly different approach which I can't figure out atm.

Anyway, keep up the good work :)

Draw(Rect,Rect) works like

Draw(Rect,Rect) works like all the other Draw overloads, it draws the contents of the surface to whatever the current render target is (set by Display.RenderTarget). It won't overwrite pixels on the same surface unless Display.RenderTarget is set to the same surface you're drawing from.

For your GUI lib example, you could just have the Panel.Refresh copy everything directly to the screen. But if there is a great deal of complex rendering for the GUI controls, such as lots of text layout, then copying to an intermediate surface like you are doing may give better performance.

I'm glad you like the library :) Let me know if you have other issues, or suggestions or anything.

Damn, you're absolutely

Damn, you're absolutely right.
I was so focused on my method involving two surface that I didn't see the obvious - rendering my tiles directly to screen.

Now I need to crawl under some rock to hide me from the shame...

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.