Click here to Skip to main content
13,148,214 members (51,896 online)
Click here to Skip to main content

Stats

127.1K views
19.1K downloads
67 bookmarked
Posted 9 Sep 2008

Blend the OGRE Graphics Engine into your WPF projects

, 9 Sep 2008
Blend a First Class Gaming Graphics Engine into your WPF application
OgreInWpf
DemoApps
DemoApps.suo
OrgreHead
OgreHead.csproj.user
Properties
Release
OgreHead.vshost.exe.manifest
SmokeyCheeseCompany
bin
Release
Properties
Libraries
MogreWpf.Interop
app.ico
MogreWpf.Interop.suo
MogreWpf.Interop.vcproj.FRED-COMPUTER.Fred.user
MogreWpf.Interop.vcproj.LESLIEG.Fred.user
OgreLib
Properties
Release
Media
DeferredShadingMedia
COPYING
deferred.glsl.program
deferred.hlsl.program
deferred.material
deferreddemo.material
DeferredShading
material
glsl
nm_notex_ps.glsl
nm_ps.glsl
nm_vs.glsl
notex_ps.glsl
ps.glsl
vs.glsl
hlsl
nm_notex_ps.hlsl
nm_ps.hlsl
nm_vs.hlsl
notex_ps.hlsl
ps.hlsl
vs.hlsl
post
glsl
Ambient_ps.glsl
GlobalLight_ps.glsl
LightMaterial_ps.glsl
LightMaterial_vs.glsl
ShowColour_ps.glsl
ShowDS_ps.glsl
ShowNormal_ps.glsl
SinglePass_ps.glsl
vs.glsl
hlsl
Ambient_ps.hlsl
GlobalLight_ps.hlsl
LightMaterial_ps.hlsl
LightMaterial_vs.hlsl
ShowColour_ps.hlsl
ShowDS_ps.hlsl
ShowNormal_ps.hlsl
SinglePass_ps.hlsl
vs.hlsl
deferred_post_debug.glsl.program
deferred_post_debug.hlsl.program
deferred_post_debug.material
deferred_post_minilight.glsl.program
deferred_post_minilight.hlsl.program
deferred_post_minilight.material
deferred_post_multipass.glsl.program
deferred_post_multipass.hlsl.program
deferred_post_multipass.material
deferred_post_onepass.glsl.program
deferred_post_onepass.hlsl.program
deferred_post_onepass.material
fonts
bluebold.ttf
bluecond.ttf
bluehigh.ttf
sample.fontdef
solo5.ttf
gui
ogregui.layout
materials
programs
AmbientOneTexture.glsl
Bloom_ps20.hlsl
Bloom_vs11.hlsl
Blur0_ps20.hlsl
Blur0_vs.glsl
Blur0_vs11.hlsl
Blur1_ps20.hlsl
Blur1_vs.glsl
Blur1_vs11.hlsl
Blur_ps.glsl
Combine_fp.cg
crowdVp.glsl
DepthShadowmap.hlsl
DepthShadowmapCasterFp.glsl
DepthShadowmapCasterVp.glsl
DepthShadowmapNormalMapReceiverFp.glsl
DepthShadowmapNormalMapReceiverVp.glsl
DepthShadowmapReceiverFp.glsl
DepthShadowmapReceiverVp.glsl
DOF_ps.cg
Example_Basic.cg
Example_Basic.hlsl
Example_BumpMapping.cg
Example_CelShading.cg
Example_Fresnel.cg
Example_Projection.cg
GlassFP.cg
Grass.cg
GrayScale.cg
hdr.cg
hdr.hlsl
hdr_bloom.glsl
hdr_downscale2x2luminence.glsl
hdr_downscale3x3.glsl
hdr_downscale3x3brightpass.glsl
hdr_finalToneMapping.glsl
hdr_tonemap_util.glsl
HeatVision.cg
instancing.cg
instancingVp.glsl
InvertFP.cg
LaplaceFP.cg
Ocean2GLSL.frag
Ocean2GLSL.vert
Ocean2HLSL_Cg.frag
Ocean2HLSL_Cg.vert
oceanGLSL.frag
oceanGLSL.vert
oceanHLSL_Cg.frag
oceanHLSL_Cg.vert
OffsetMapping.cg
OffsetMapping.hlsl
OffsetMappingFp.glsl
OffsetMappingVp.glsl
OldMovieFP.cg
OldTV.cg
PosterizeFP.cg
SharpenEdgesFP.cg
skinningTwoWeightsVp.glsl
StdQuad_vp.cg
StdQuad_vp.glsl
TilingFP.cg
varianceshadowcasterfp.cg
varianceshadowcastervp.cg
varianceshadowreceiverfp.cg
varianceshadowreceivervp.cg
scripts
Bloom.material
Example-DynTex.material
Example.material
Examples-Advanced.material
Examples.compositor
Examples.program
Glass.material
Ogre.material
OldMovie.material
OldTV.material
smoke.material
StdQuad_vp.program
textures
aureola.png
basic_droplet.png
cel_shading_diffuse.png
cel_shading_edge.png
cel_shading_specular.png
Dirt.jpg
dirt01.jpg
droplet.png
flare.png
flaretrail.png
GreenSkin.jpg
NoiseVolume.dds
Random3D.dds
smoke.png
smokecolors.png
spheremap.png
WaterNormal1.tga
WeirdEye.png
models
ogrehead.mesh
overlays
Compositor.overlay
DP3.overlay
Example-CubeMapping.overlay
Example-DynTex.overlay
Example-Water.overlay
Shadows.overlay
packs
OgreCore.zip
particle
emitted_emitter.particle
Example-Water.particle
Example.particle
smoke.particle
Release
D3DX9_37.dll
cg.dll
Mogre.dll
MogreWpf.Interop.dll
ogre.cfg
OgreHead.exe
OgreHead.vshost.exe
OgreHead.vshost.exe.manifest
OgreLib.dll
OgreMain.dll
plugins.cfg
Plugin_BSPSceneManager.dll
Plugin_CgProgramManager.dll
Plugin_OctreeSceneManager.dll
Plugin_ParticleFX.dll
RenderSystem_Direct3D9.dll
resources.cfg
SmokeyCheeseCompany.exe
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Threading;
using Mogre;

namespace OgreLib
{
    public partial class OgreImage : D3DImage,
                                     ISupportInitialize
    {
        private delegate void MethodInvoker();

        private Root _root;
        private TexturePtr _texture;
        private RenderWindow _renderWindow;
        private Camera _camera;
        private Viewport _viewport;
        private SceneManager _sceneManager;
        private RenderTarget _renTarget;
        private int _reloadRenderTargetTime;
        private bool _imageSourceValid;
        private Thread _currentThread;
        private DispatcherTimer _timer;
        private bool _eventAttatched;

        #region IDisposable Members

        public void Dispose()
        {
            IsFrontBufferAvailableChanged -= _isFrontBufferAvailableChanged;

            DetachRenderTarget(true, true);

            if (_currentThread != null)
            {
                _currentThread.Abort();
            }

            if (_root != null)
            {
                DisposeRenderTarget();
                CompositorManager.Singleton.RemoveAll();

                _root.Dispose();
                _root = null;
            }

            GC.SuppressFinalize(this);
        }

        #endregion

        #region ISupportInitialize Members

        public void BeginInit()
        {
        }

        public void EndInit()
        {
            if (AutoInitialise)
            {
                InitOgre();
            }
        }

        #endregion

        protected bool _InitOgre()
        {
            lock (this)
            {
                IntPtr hWnd = IntPtr.Zero;

                foreach (PresentationSource source in PresentationSource.CurrentSources)
                {
                    var hwndSource = (source as HwndSource);
                    if (hwndSource != null)
                    {
                        hWnd = hwndSource.Handle;
                        break;
                    }
                }

                if (hWnd == IntPtr.Zero) return false;

                CallResourceItemLoaded(new ResourceLoadEventArgs("Engine", 0));

                // load the OGRE engine
                //
                _root = new Root();

                // configure resource paths from : "resources.cfg" file
                //
                var configFile = new ConfigFile();
                configFile.Load("resources.cfg", "\t:=", true);

                // Go through all sections & settings in the file
                //
                ConfigFile.SectionIterator seci = configFile.GetSectionIterator();

                // Normally we would use the foreach syntax, which enumerates the values, 
                // but in this case we need CurrentKey too;
                while (seci.MoveNext())
                {
                    string secName = seci.CurrentKey;

                    ConfigFile.SettingsMultiMap settings = seci.Current;
                    foreach (var pair in settings)
                    {
                        string typeName = pair.Key;
                        string archName = pair.Value;
                        ResourceGroupManager.Singleton.AddResourceLocation(archName, typeName, secName);
                    }
                }

                // Configures the application and creates the Window
                // A window HAS to be created, even though we'll never use it.
                //
                bool foundit = false;
                foreach (RenderSystem rs in _root.GetAvailableRenderers())
                {
                    if (rs == null) continue;

                    _root.RenderSystem = rs;
                    String rname = _root.RenderSystem.Name;
                    if (rname == "Direct3D9 Rendering Subsystem")
                    {
                        foundit = true;
                        break;
                    }
                }

                if (!foundit)
                    return false;

                _root.RenderSystem.SetConfigOption("Full Screen", "No");
                _root.RenderSystem.SetConfigOption("Video Mode", "640 x 480 @ 32-bit colour");

                _root.Initialise(false);

                var misc = new NameValuePairList();
                misc["externalWindowHandle"] = hWnd.ToString();
                _renderWindow = _root.CreateRenderWindow("OgreImageSource Windows", 0, 0, false, misc);
                _renderWindow.IsAutoUpdated = false;

                InitResourceLoad();
                ResourceGroupManager.Singleton.InitialiseAllResourceGroups();

                this.Dispatcher.Invoke(
                    (MethodInvoker)delegate
                                       {
                                           if (CreateDefaultScene)
                                           {
                                               //----------------------------------------------------- 
                                               // 4 Create the SceneManager
                                               // 
                                               //		ST_GENERIC = octree
                                               //		ST_EXTERIOR_CLOSE = simple terrain
                                               //		ST_EXTERIOR_FAR = nature terrain (depreciated)
                                               //		ST_EXTERIOR_REAL_FAR = paging landscape
                                               //		ST_INTERIOR = Quake3 BSP
                                               //----------------------------------------------------- 
                                               _sceneManager = _root.CreateSceneManager(SceneType.ST_GENERIC, "SceneMgr");
                                               _sceneManager.AmbientLight = new ColourValue(0.5f, 0.5f, 0.5f);

                                               //----------------------------------------------------- 
                                               // 5 Create the camera 
                                               //----------------------------------------------------- 
                                               _camera = _sceneManager.CreateCamera("DefaultCamera");
                                               _camera.Position = new Vector3(0f, 0f, 100f);
                                               // Look back along -Z
                                               _camera.LookAt(new Vector3(0f, 0f, -300f));
                                               _camera.NearClipDistance = 5;
                                           }

                                           IsFrontBufferAvailableChanged += _isFrontBufferAvailableChanged;

                                           if (Initialised != null)
                                               Initialised(this, new RoutedEventArgs());

                                           ReInitRenderTarget();
                                           AttachRenderTarget(true);

                                           OnFrameRateChanged(this.FrameRate);

                                           _currentThread = null;
                                       });

                return true;
            }
        }


        public bool InitOgre()
        {
            return _InitOgre();
        }

        public Thread InitOgreAsync(ThreadPriority priority, RoutedEventHandler completeHandler)
        {
            if (completeHandler != null)
                Initialised += completeHandler;

            _currentThread = new Thread(() => _InitOgre())
                                 {
                                     Priority = priority
                                 };
            _currentThread.Start();

            return _currentThread;
        }

        public void InitOgreAsync()
        {
            InitOgreAsync(ThreadPriority.Normal, null);
        }

        public event RoutedEventHandler Initialised;
        public event EventHandler PreRender;
        public event EventHandler PostRender;

        protected void RenderFrame()
        {
            if ((_camera != null) && (_viewport == null))
            {
                _viewport = _renTarget.AddViewport(_camera);
                _viewport.BackgroundColour = new ColourValue(0.0f, 0.0f, 0.0f, 0.0f);
            }

            if (PreRender != null)
                PreRender(this, EventArgs.Empty);

            _root.RenderOneFrame();

            if (PostRender != null)
                PostRender(this, EventArgs.Empty);
        }

        protected void DisposeRenderTarget()
        {
            if (_renTarget != null)
            {
                CompositorManager.Singleton.RemoveCompositorChain(_viewport);
                _renTarget.RemoveAllListeners();
                _renTarget.RemoveAllViewports();
                _root.RenderSystem.DestroyRenderTarget(_renTarget.Name);
                _renTarget = null;
                _viewport = null;
            }

            if (_texture != null)
            {
                TextureManager.Singleton.Remove(_texture.Handle);
                _texture.Dispose();
                _texture = null;
            }
        }

        protected void ReInitRenderTarget()
        {
            DetachRenderTarget(true, false);
            DisposeRenderTarget();

            _texture = TextureManager.Singleton.CreateManual(
                "OgreImageSource RenderTarget",
                ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
                TextureType.TEX_TYPE_2D,
                (uint)ViewportSize.Width, (uint)ViewportSize.Height,
                0, Mogre.PixelFormat.PF_A8R8G8B8,
                (int)TextureUsage.TU_RENDERTARGET);

            _renTarget = _texture.GetBuffer().GetRenderTarget();

            _reloadRenderTargetTime = 0;
        }

        public Root Root
        {
            get { return _root; }
        }

        public SceneManager SceneManager
        {
            get { return _sceneManager; }
        }

        public Camera Camera
        {
            get { return _camera; }
        }

        protected virtual void AttachRenderTarget(bool attachEvent)
        {
            if (!_imageSourceValid)
            {
                Lock();
                try
                {
                    IntPtr surface;
                    _renTarget.GetCustomAttribute("DDBACKBUFFER", out surface);
                    SetBackBuffer(D3DResourceType.IDirect3DSurface9, surface);

                    _imageSourceValid = true;
                }
                finally
                {
                    Unlock();
                }
            }

            if (attachEvent)
                UpdateEvents(true);
        }

        protected virtual void DetachRenderTarget(bool detatchSurface, bool detatchEvent)
        {
            if (detatchSurface && _imageSourceValid)
            {
                Lock();
                SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero);
                Unlock();

                _imageSourceValid = false;
            }

            if (detatchEvent)
                UpdateEvents(false);
        }

        protected virtual void UpdateEvents(bool attach)
        {
            _eventAttatched = attach;
            if (attach)
            {
                if (_timer != null)
                    _timer.Tick += _rendering;
                else
                    CompositionTarget.Rendering += _rendering;
            }
            else
            {
                if (_timer != null)
                    _timer.Tick -= _rendering;
                else
                    CompositionTarget.Rendering -= _rendering;
            }
        }

        private void _isFrontBufferAvailableChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (IsFrontBufferAvailable)
                AttachRenderTarget(true); // might not succeed
            else
                // need to keep old surface attached because it's the only way to get the front buffer active event.
                DetachRenderTarget(false, true);
        }

        private void _rendering(object sender, EventArgs e)
        {
            if (_root == null) return;

            if (IsFrontBufferAvailable)
            {
                if (MogreWpf.Interop.D3D9RenderSystem.IsDeviceLost(_renderWindow))
                {
                    _renderWindow.Update(); // try restore
                    _reloadRenderTargetTime = -1;

                    if (MogreWpf.Interop.D3D9RenderSystem.IsDeviceLost(_renderWindow))
                        return;
                }

                long durationTicks = ResizeRenderTargetDelay.TimeSpan.Ticks;

                // if the new next ReInitRenderTarget() interval is up
                if (((_reloadRenderTargetTime < 0) || (durationTicks <= 0))
                    // negative time will be reloaded immediatly
                    ||
                    ((_reloadRenderTargetTime > 0) &&
                     (Environment.TickCount >= (_reloadRenderTargetTime + durationTicks))))
                {
                    ReInitRenderTarget();
                }

                if (!_imageSourceValid)
                    AttachRenderTarget(false);

                Lock();
                RenderFrame();
                AddDirtyRect(new Int32Rect(0, 0, PixelWidth, PixelHeight));
                Unlock();
            }
        }

        private void OnFrameRateChanged(int? newFrameRate)
        {
            bool wasAttached = _eventAttatched;
            UpdateEvents(false);

            if (newFrameRate == null)
            {
                if (_timer != null)
                {
                    _timer.Tick -= _rendering;
                    _timer.Stop();
                    _timer = null;
                }
            }
            else
            {
                if (_timer == null)
                    _timer = new DispatcherTimer();

                _timer.Interval = new TimeSpan(1000 / newFrameRate.Value);
                _timer.Start();
            }

            if (wasAttached)
                UpdateEvents(true);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Leslie Godwin
Technical Lead FNB Connect
South Africa South Africa
iOS Technical Lead at FNB
-

Computers are really sweet. Aren't they?
Yup they are...

I've always loved writing tools and components...never been very interested in playing games....always wanted to be able to write them though.

And, yes. I'm still pretty annoyed they discontinued the Amiga computer.

You may also be interested in...

Pro
Pro
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.170924.2 | Last Updated 9 Sep 2008
Article Copyright 2008 by Leslie Godwin
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid