Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Garbage data during rendering  (Read 4734 times)

0 Members and 2 Guests are viewing this topic.

Megatron

  • Newbie
  • *
  • Posts: 22
    • View Profile
Garbage data during rendering
« on: April 23, 2010, 10:37:56 pm »
Hi,

I'm trying to use a RenderWindow inside a Windows Forms application. I decided to try making a custom control that I could easily inherit from to change the rendering behvaiour and place it easily on a windows form. Here's the basic code for the Control

Code: [Select]
Thread renderingThread;
        RenderWindow renderingWindow;
        Sprite Background;
        BattleStatus battlestatus = BattleStatus.Unknown;
        string testSpriteSheet = @"A:\KHMP\KHMP\KHMP\Resources\Images\Sprites\Characters\InBattle\kasier_.png";
        public const int X_RES = 800;
        public const int Y_RES = 600;
        SFML.Graphics.Image characterSpriteSheet;
        AnimatedSprite sprite = null;

         public SFMLPanel(string backgroundImage)
        {
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            battlestatus = BattleStatus.Starting;
            this.Size = new System.Drawing.Size(X_RES, Y_RES);
            renderingWindow = new RenderWindow(this.Handle);
            renderingWindow.Closed += new EventHandler(renderingWindow_Closed);
            renderingWindow.Resized += new EventHandler<SizeEventArgs>(renderingWindow_Resized);
            renderingWindow.KeyPressed += new EventHandler<SFML.Window.KeyEventArgs>(renderingWindow_KeyPressed);
            renderingWindow.SetFramerateLimit(Globals.FRAMES_PER_SECOND_LIMIT);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            Background = new Sprite(new SFML.Graphics.Image(@"A:\KHMP\KHMP\KHMP\Resources\Images\BattleBackgrounds\forest.png"));
            Background.Scale = new Vector2((float)X_RES / (float)Background.Image.Width, (float)Y_RES / (float)Background.Image.Height);

            Text = new String2D("Hi");
            Text.Position = new Vector2(25.0f, 25.0f);
            Text.Color = color;

            //Setup Sprites
            characterSpriteSheet = new SFML.Graphics.Image(testSpriteSheet);
            characterSheet = new SpriteSheet(characterSpriteSheet, 4, 11);
            Sprite characterSprite = new Sprite(characterSpriteSheet);

            sprite = new AnimatedSprite(characterSpriteSheet, 0, 0, true, 4, 11);
            sprite.SetLoopSpeed(5);
            sprite.Play(0, 3);
            battlestatus = BattleStatus.InProgress;
            renderingThread = new Thread(new ThreadStart(RenderingLoop));
            renderingThread.Start();
        }

         protected virtual void RenderingLoop()
        {
            while (battlestatus != BattleStatus.Ended && renderingWindow.IsOpened())
            {
                renderingWindow.DispatchEvents();
                renderingWindow.Clear();
                renderingWindow.Draw(Background);
                renderingWindow.Draw(sprite);
                renderingWindow.Display();
            }
        }
}


I'm not including the even handlers as they're not being invoked, so they arent part of the problem. AnimatedSprite is a class that takes a sprite sheet and lets you specify the range of cells on the sheet to render. I know this class works, and I know the above code should work becuase when i do something in the same manner as above on an independent render window it works correctly.

 The problems that's occuring is this: The control is being placed, and the while loops is being called, but the display on the control keeps rapidly flickering between this

http://garyoak.com/PublicProjects/Games/GarbageData1.jpg
and this
http://garyoak.com/PublicProjects/Games/GarbageData2.jpg

(I think there might be more garbage data screen that its flickering between, but those were the two I was able to catch). You can sort of see the image thats supposed to be the background (the green grass) in the 2nd screen shot.
I tried some of the other approaches I saw on here (liek taking a standard control and overiding it OnPaint event to display the RenderWindow, but it had the same effect)

Any ideas on whats going wrong?

Thanks

Spodi

  • Full Member
  • ***
  • Posts: 150
    • View Profile
    • http://www.netgore.com/
Garbage data during rendering
« Reply #1 on: April 23, 2010, 11:53:36 pm »
For one, if you are going to be rendering in a separate thread, you will have to join it back to the main thread when you do anything that involves the controls. Safest bet would just to render in the main thread. Only reason why I can think of moving the rendering to a separate thread is if it is so slow that it lags the GUI (<20 FPS or so).

Second, you shouldn't need to set double-buffering if you set it up correctly (unless your rendering is insanely slow, such as <2 FPS). Whenever the contents become invalidated, your want to redraw completely. SFML already buffers, too.

Third, you should use the OnPaint() approach. It will give you a constant refreshing, and is probably the most sturdy approach since you are just painting in the routine the control expects the painting to happen in. To do this, set the style in the constructor as:

Code: [Select]
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);

Then set the OnPaint event to something like:

Code: [Select]
       /// <summary>
        /// Paints the screen.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs"/> that contains the event data.</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            // Check if the game is running
            bool isOpened;
            try
            {
                isOpened = _game.IsOpened();
            }
            catch (AccessViolationException)
            {
                // SFML likes to throw an AccessViolationException when the game is disposed
                isOpened = false;
            }

            try
            {
                // If the game is running, handle the next frame. Otherwise, close the form.
                if (isOpened)
                    _game.HandleFrame();
                else
                    Close();
            }
            finally
            {
                // Invalidate the whole screen so that it will be fully redrawn as soon as possible
                Invalidate();
            }
        }


If that still doesn't do the trick for some reason, upload a copy of the whole project and I will check it out.

Megatron

  • Newbie
  • *
  • Posts: 22
    • View Profile
Garbage data during rendering
« Reply #2 on: April 24, 2010, 02:37:31 am »
That did the trick thanks... but now my events arent firing. Any ideas? I've tried the following

this.KeyDown += new KeyEventHandler(SFMLPanel_KeyDown);
            this.KeyPress += new KeyPressEventHandler(SFMLPanel_KeyPress);

renderingWindow.KeyPressed += new EventHandler<SFML.Window.KeyEventArgs>(renderingWindow_KeyPressed);

but none of those events are being triggered.

Spodi

  • Full Member
  • ***
  • Posts: 150
    • View Profile
    • http://www.netgore.com/
Garbage data during rendering
« Reply #3 on: April 24, 2010, 06:49:03 am »
I assume "this" is the form. If so, you probably need to enable KeyPreview. Though you should probably just use SFML's input events.

If that doesn't help, here is my form code for a form container used as the render target:

Code: [Select]
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using log4net;

namespace DemoGame.Client
{
    /// <summary>
    /// The <see cref="Form"/> that is used to contain the game screen.
    /// </summary>
    public class GameForm : Form
    {
        static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        readonly DemoGame _game;

        /// <summary>
        /// Initializes a new instance of the <see cref="GameForm"/> class.
        /// </summary>
        public GameForm()
        {
            // ReSharper disable DoNotCallOverridableMethodsInConstructor

            // Set up our form
            StartPosition = FormStartPosition.CenterScreen;
            FormBorderStyle = FormBorderStyle.FixedSingle;
            AutoScaleMode = AutoScaleMode.Font;
            Text = "NetGore";
            ClientSize = new Size((int)GameData.ScreenSize.X, (int)GameData.ScreenSize.Y);
            MaximizeBox = false;

            SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);

            // Create the game
            _game = new DemoGame(Handle);

            // ReSharper restore DoNotCallOverridableMethodsInConstructor
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Form.Closing"/> event.
        /// </summary>
        /// <param name="e">A <see cref="T:System.ComponentModel.CancelEventArgs"/> that contains the event data.</param>
        protected override void OnClosing(CancelEventArgs e)
        {
            try
            {
                bool isOpened;
                try
                {
                    isOpened = _game.IsOpened();
                }
                catch (AccessViolationException)
                {
                    // SFML likes to throw an AccessViolationException when the game is disposed
                    isOpened = false;
                }

                // If the game was not closed, close it and abort so the main loop can take care of it
                if (isOpened)
                {
                    try
                    {
                        _game.Dispose();
                    }
                    catch (Exception ex)
                    {
                        const string errmsg = "Exception thrown when trying to dispose the game: {0}";
                        if (log.IsWarnEnabled)
                            log.WarnFormat(errmsg, ex);
                        Debug.Fail(string.Format(errmsg, ex));
                    }
                }
            }
            finally
            {
                base.OnClosing(e);
            }
        }

        /// <summary>
        /// Paints the screen.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs"/> that contains the event data.</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            // Check if the game is running
            bool isOpened;
            try
            {
                isOpened = _game.IsOpened();
            }
            catch (AccessViolationException)
            {
                // SFML likes to throw an AccessViolationException when the game is disposed
                isOpened = false;
            }

            try
            {
                // If the game is running, handle the next frame. Otherwise, close the form.
                if (isOpened)
                    _game.HandleFrame();
                else
                    Close();
            }
            finally
            {
                // Invalidate the whole screen so that it will be fully redrawn as soon as possible
                Invalidate();
            }
        }

        /// <summary>
        /// Processes a command key.
        /// </summary>
        /// <param name="msg">A <see cref="T:System.Windows.Forms.Message"/>, passed by reference, that represents the
        /// Win32 message to process.</param>
        /// <param name="keyData">One of the <see cref="T:System.Windows.Forms.Keys"/> values that represents
        /// the key to process.</param>
        /// <returns>
        /// true if the keystroke was processed and consumed by the control; otherwise, false to allow further processing.
        /// </returns>
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            // Prevents the form menu from showing when pressing alt
            if (keyData == (Keys.RButton | Keys.ShiftKey | Keys.Alt))
                return true;

            // Prevents closing the form via alt+F4
            if (keyData == (Keys.Alt | Keys.F4))
                return true;

            return base.ProcessCmdKey(ref msg, keyData);
        }
    }
}

 

anything