Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a fast way to manipulate and buffer a screen in Windows Forms?

I am working on a game for learning purposes, I want to make it only with the .NET-Framework and a Windows Forms project in C#.

I want to get the 'screen' (Something that can be displayed on the window) as an int[]. Modify the array and reapply the altered array to the 'screen' in a buffered manner (So that it doesn't flicker).

I am currently using a Panel, which I draw a Bitmap on with Graphics. The Bitmap is converted to an int[] which I then can modify and reapply to the Bitmap and redraw. It works, but is very slow, especially because I have to scale up the image every frame because my game is only 300x160 and the screen 900x500.

Build up:

    // Renders 1 frame
    private void Render()
    {    
        // Buffer setup
        _bufferedContext = BufferedGraphicsManager.Current;
        _buffer = _bufferedContext.Allocate(panel_canvas.CreateGraphics(), new Rectangle(0, 0, _scaledWidth, _scaledHeight));

        _screen.clear();

        // Get position of player on map
        _xScroll = _player._xMap - _screen._width / 2;
        _yScroll = _player._yMap - _screen._height / 2;

        // Indirectly modifies the int[] '_pixels'
        _level.render(_xScroll, _yScroll, _screen);
        _player.render(_screen);

        // Converts the int[] into a Bitmap (unsafe method is faster)
        unsafe
        {
            fixed (int* intPtr = &_screen._pixels[0])
            {
                _screenImage = new Bitmap(_trueWidth, _trueHeight, _trueWidth * 4, PixelFormat.Format32bppRgb, new IntPtr(intPtr));
            }
        }

        // Draw generated image on buffer
        Graphics g = _buffer.Graphics;
        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;

        g.DrawImage(_screenImage, new Rectangle(0, 0, 900, 506));

        // Update panel buffered
        _buffer.Render();
    }

Is there a faster way without external libraries to make this work?

like image 536
Berntonline Avatar asked Aug 07 '15 09:08

Berntonline


People also ask

How to avoid flickering in Windows Forms c#?

use control. DoubleBuffered property. set it to true. DoubleBuffered allows Control redraws its surface using secondary buffer to avoid flickering.

What is double Buffered in c#?

Double buffering uses a memory buffer to address the flicker problems associated with multiple paint operations. When double buffering is enabled, all paint operations are first rendered to a memory buffer instead of the drawing surface on the screen.

Which property of control is used to reduce flickering when it is drawn?

Buffered graphics can reduce or eliminate flicker that is caused by progressive redrawing of parts of a displayed surface.


1 Answers

I'm not to sure about the unsafe code , But I do know about the buffered graphics manager. I think you should create a class for it instead of creating a new one every time.As well as having all of your sprites widths and heights be determined at the load instead of scaling them. That sped up my small game engine a good bit.

class Spritebatch
{
    private Graphics Gfx;
    private BufferedGraphics bfgfx;
    private BufferedGraphicsContext cntxt = BufferedGraphicsManager.Current;

    public Spritebatch(Size clientsize, Graphics gfx)
    {
        cntxt.MaximumBuffer = new Size(clientsize.Width + 1, clientsize.Height + 1);
        bfgfx = cntxt.Allocate(gfx, new Rectangle(Point.Empty, clientsize));
        Gfx = gfx;
    }

    public void Begin()
    {
        bfgfx.Graphics.Clear(Color.Black);
    }

    public void Draw(Sprite s)
    {
        bfgfx.Graphics.DrawImageUnscaled(s.Texture, new Rectangle(s.toRec.X - s.rotationOffset.Width,s.toRec.Y - s.rotationOffset.Height,s.toRec.Width,s.toRec.Height));
    }

    public void drawImage(Bitmap b, Rectangle rec)
    {
        bfgfx.Graphics.DrawImageUnscaled(b, rec);
    }

    public void drawImageClipped(Bitmap b, Rectangle rec)
    {
        bfgfx.Graphics.DrawImageUnscaledAndClipped(b, rec);
    }

    public void drawRectangle(Pen p, Rectangle rec)
    {
        bfgfx.Graphics.DrawRectangle(p, rec);
    }

    public void End()
    {
        bfgfx.Render(Gfx);
    }

}

This is a example of what I used. It's set up to mimic the Spritebatch in Xna. Drawing the images Unscaled will really increase the speed of it.Also creating one instance of the buffered graphics and Context will be faster then creating a new one every time you have to render. So I would advise you to change the line g.DrawImage(_screenImage, new Rectangle(0, 0, 900, 506)); to DrawImageUnscaled(_screenImage, new Rectangle(0, 0, 900, 506));

Edited : Example of how to scale code on sprite load

    public Sprite(Bitmap texture, float x, float y, int width, int height)
    {
        //texture is the image you originally start with.

        Bitmap b = new Bitmap(width, height);
        // Create a bitmap with the desired width and height
        using (Graphics g = Graphics.FromImage(b))
        {
            g.DrawImage(texture, 0, 0, width, height);
        }
        // get the graphics from the new image and draw the old image to it
        //scaling it to the proper width and height
        Texture = b;
        //set Texture which is the final picture to the sprite.
        //Uppercase Texture is different from lowercase
like image 133
John Thompson Avatar answered Nov 14 '22 23:11

John Thompson