Пример #1
0
        protected override void Initialise()
        {
            //draw target camera.
            Camera3D camera = new Camera3D();

            camera.LookAt(Vector3.Zero, new Vector3(0, 0, 4), Vector3.UnitY);


            //create the draw target texture
            //actual graphics resources are not created yet...
            drawToTexture = new DrawTargetTexture2D(camera, 128, 128, SurfaceFormat.Color, DepthFormat.Depth24Stencil8);

            //make the texture clear colour different from the screen, so it's more obvious
            drawToTexture.ClearBuffer.ClearColour = Color.WhiteSmoke;

            //add a sphere from tutorial 03 to the texture
            drawToTexture.Add(new Tutorial_03.SphereDrawer(Vector3.Zero));



            Vector2 sizeInPixels = new Vector2(512, 512);

            //NEW CODE
            //create the helper element, but don't give it a texture yet..
            displayElement = new TexturedElement(sizeInPixels);



            //create the drawToScreen object..
            drawToScreen = new DrawTargetScreen(this, camera);
            drawToScreen.ClearBuffer.ClearColour = Color.CornflowerBlue;

            //add the helper element to the screen
            drawToScreen.Add(displayElement);
        }
Пример #2
0
        //NEW CODE
        protected override void Initialise()
        {
            //draw targets usually need a camera.
            Camera3D camera = new Camera3D();

            //look at the sphere, which will be at 0,0,0
            camera.LookAt(Vector3.Zero, new Vector3(0, 0, 4), Vector3.UnitY);


            //create the draw target texture in the same way the DrawSphere sample created the draw target screen
            //creates a 128x128 texture (the pixelation should be visible)
            drawToTexture = new DrawTargetTexture2D(camera, 128, 128, SurfaceFormat.Color, DepthFormat.Depth24Stencil8);

            //make the texture clear colour different from the screen, so it's more obvious
            drawToTexture.ClearBuffer.ClearColour = Color.WhiteSmoke;

            //create the sphere (reused from Tutorial_03)
            Tutorial_03.SphereDrawer sphere = new Tutorial_03.SphereDrawer(Vector3.Zero);

            //Note, the sphere is added to the drawToTexture, not the drawToScreen
            drawToTexture.Add(sphere);


            //now, create the drawToScreen object..

            //The same camera is being used, although it doesn't have to be.
            //The 2D element helper class that will be used will automatically push it's own 2D Camera when
            //drawing, to keep itself consistent.
            drawToScreen = new DrawTargetScreen(this, camera);
            drawToScreen.ClearBuffer.ClearColour = Color.CornflowerBlue;


            Vector2 sizeInPixels = new Vector2(512, 512);

            //Now create a 2D helper element that will display the texture on screen

            Xen.Ex.Graphics2D.TexturedElement displayTexture = null;

            //this helper class can directly take a DrawTargetTexture2D as a texture parameter.
            //This saves some effort here.

            //drawToTexture's Texture2D can be accessed with drawToTexture.GetTexture(),
            //in a similar way to XNA render targets.

            //However, at this point, drawToTexture.GetTexture() will be null - as the draw
            //target has yet to be drawn to.

            //drawToTexture.Warm() can be called, which will create the resources now.
            //However calling Warm() doesn't totally solve the problem because the texture
            //will change when content needs reloading (this happens after a device reset, etc)

            //The 2D helper element takes care of this itself.
            //Content loading/reloading and dealing with GetTexture() will be covered in the next example.
            //for now, the helper class will handle things.
            displayTexture = new TexturedElement(drawToTexture, sizeInPixels);

            //add it to the screen
            drawToScreen.Add(displayTexture);
        }
Пример #3
0
        /// <summary>
        /// Construct the texture downsampler
        /// </summary>
        /// <param name="source">Source texture to read</param>
        /// <param name="target">Target texture to write to</param>
        /// <param name="intermediate">Intermediate texture (if null, will be created as required)</param>
        /// <param name="intermediate2">Second intermediate texture (if null, will be created as required)</param>
        /// <param name="targetWidth">target width to downsample to</param>
        /// <param name="targetHeight">target height to downsample to</param>
        public TextureDownsample(DrawTargetTexture2D source, DrawTargetTexture2D target, ref DrawTargetTexture2D intermediate, ref DrawTargetTexture2D intermediate2, int targetWidth, int targetHeight)
        {
            if (source == null ||
                target == null)
            {
                throw new ArgumentNullException();
            }

            if (targetWidth <= 0 ||
                targetHeight <= 0)
            {
                throw new ArgumentException("Invalid target size");
            }

            if (DrawTarget.FormatChannels(source.SurfaceFormat) != DrawTarget.FormatChannels(target.SurfaceFormat))
            {
                throw new ArgumentException("source.SurfaceFormat has a different number of channels than target.SurfaceFormat");
            }

            if (targetWidth > target.Width ||
                targetHeight > target.Height)
            {
                throw new ArgumentException("Size is larger than target");
            }

            if (targetWidth > source.Width ||
                targetHeight > source.Height)
            {
                throw new ArgumentException("Size is larger than source");
            }

            if (intermediate != null)
            {
                if (target.SurfaceFormat != intermediate.SurfaceFormat)
                {
                    throw new ArgumentException("target.SurfaceFormat != intermediate.SurfaceFormat");
                }
                if (intermediate == intermediate2)
                {
                    throw new ArgumentException("intermediate == intermediate2");
                }
            }
            if (intermediate2 != null)
            {
                if (target.SurfaceFormat != intermediate2.SurfaceFormat)
                {
                    throw new ArgumentException("target.SurfaceFormat != intermediate2.SurfaceFormat");
                }
            }

            int w = source.Width;
            int h = source.Height;

            int targetMultipleWidth  = targetWidth;
            int targetMultipleHeight = targetHeight;

            while (targetMultipleWidth * 2 <= w)
            {
                targetMultipleWidth *= 2;
            }
            while (targetMultipleHeight * 2 <= h)
            {
                targetMultipleHeight *= 2;
            }

            DrawTargetTexture2D current = null;
            Rectangle           sRegion = new Rectangle(0, 0, 0, 0);

            //first pass may require that the source is sized down to a multiple of the target size

            if ((double)targetWidth / (double)w <= 0.5 &&
                (double)targetHeight / (double)h <= 0.5 &&
                (targetMultipleWidth != w || targetMultipleHeight != h))
            {
                DrawTargetTexture2D go = this.PickRT(ref intermediate, ref intermediate2, source, targetMultipleWidth, targetMultipleHeight, target.SurfaceFormat);

                Vector2 size = new Vector2((float)targetMultipleWidth, (float)targetMultipleHeight);

                TexturedElement te = new TexturedElement(source, size, false);
                te.TextureCrop = new Rectangle(0, 0, w, h);

                go.Add(te);
                passes.Add(go);
                current = go;
                w       = targetMultipleWidth;
                h       = targetMultipleHeight;
            }

            //downsample on the larger axis, either 2x, 4x or 8x downsampling, until reached the target size

            while (target.Equals(current) == false)
            {
                DrawTargetTexture2D localSource = current ?? source;

                double difW = (double)targetWidth / (double)w;
                double difH = (double)targetHeight / (double)h;

                sRegion.Width  = w;
                sRegion.Height = h;
                sRegion.Y      = localSource.Height - h;

                //both width/height difference are less than 50% smaller, so a linear interpolation will do fine
                if (difW > 0.5 &&
                    difH > 0.5)
                {
                    //write directly to the target
                    DrawTargetTexture2D go      = target.Clone(false, false, false);
                    Vector2             te_size = new Vector2((float)targetWidth, (float)targetHeight);
                    TexturedElement     te      = new TexturedElement(localSource, te_size, false);

                    go.AddModifier(new ScissorModifier(0, go.Height - targetHeight, targetWidth, go.Height, go));
                    te.TextureCrop = sRegion;

                    go.Add(te);
                    passes.Add(go);
                    current = go;

                    continue;
                }

                bool   horizontal = difW < difH;
                double dif        = Math.Min(difW, difH);
                int    size       = horizontal ? w : h;

                Vector2 dir = new Vector2(0, 0);
                if (horizontal)
                {
                    dir.X = 1.0f / localSource.Width;
                }
                else
                {
                    dir.Y = 1.0f / localSource.Height;
                }

                if (dif > 0.25)                 // cutoff for using 2 samples
                {
                    DrawTargetTexture2D go;
                    int new_width  = w;
                    int new_height = h;
                    if (horizontal)
                    {
                        new_width /= 2;
                    }
                    else
                    {
                        new_height /= 2;
                    }

                    if (new_width == targetWidth && new_height == targetHeight)
                    {
                        go = target.Clone(false, false, false);
                    }
                    else
                    {
                        go = PickRT(ref intermediate, ref intermediate2, localSource, new_width, new_height, target.SurfaceFormat);
                    }

                    Vector2       se_size = new Vector2((float)new_width, (float)new_height);
                    ShaderElement se      = new ShaderElement(new Downsample2(), se_size, false);

                    go.AddModifier(new ScissorModifier(0, go.Height - new_height, new_width, go.Height, go));

                    se.TextureCrop = sRegion;

                    go.Add(new Drawer(dir, se, localSource));
                    passes.Add(go);

                    w = new_width;
                    h = new_height;

                    current = go;
                    continue;
                }

                if (dif > 0.125)                 // cutoff for using 4 samples
                {
                    DrawTargetTexture2D go;
                    int new_width  = w;
                    int new_height = h;
                    if (horizontal)
                    {
                        new_width /= 4;
                    }
                    else
                    {
                        new_height /= 4;
                    }

                    if (new_width == targetWidth && new_height == targetHeight)
                    {
                        go = target.Clone(false, false, false);
                    }
                    else
                    {
                        go = PickRT(ref intermediate, ref intermediate2, localSource, new_width, new_height, target.SurfaceFormat);
                    }

                    Vector2       se_size = new Vector2((float)new_width, (float)new_height);
                    ShaderElement se      = new ShaderElement(new Downsample4(), se_size, false);

                    go.AddModifier(new ScissorModifier(0, go.Height - new_height, new_width, go.Height, go));

                    se.TextureCrop = sRegion;

                    go.Add(new Drawer(dir, se, localSource));
                    passes.Add(go);

                    w = new_width;
                    h = new_height;

                    current = go;
                    continue;
                }

                // cutoff for using 8 samples
                {
                    DrawTargetTexture2D go;
                    int new_width  = w;
                    int new_height = h;
                    if (horizontal)
                    {
                        new_width /= 8;
                    }
                    else
                    {
                        new_height /= 8;
                    }

                    if (new_width == targetWidth && new_height == targetHeight)
                    {
                        go = target.Clone(false, false, false);
                    }
                    else
                    {
                        go = PickRT(ref intermediate, ref intermediate2, localSource, new_width, new_height, target.SurfaceFormat);
                    }

                    Vector2       se_size = new Vector2((float)new_width, (float)new_height);
                    ShaderElement se      = new ShaderElement(new Downsample8(), se_size, false);

                    go.AddModifier(new ScissorModifier(0, go.Height - new_height, new_width, go.Height, go));

                    se.TextureCrop = sRegion;

                    go.Add(new Drawer(dir, se, localSource));
                    passes.Add(go);

                    w = new_width;
                    h = new_height;

                    current = go;
                    continue;
                }
            }
        }
Пример #4
0
        protected override void Initialise()
        {
            //setup ambient lighting
            this.ambientLight               = new MaterialLightCollection();
            ambientLight.LightingEnabled    = true;
            ambientLight.AmbientLightColour = new Vector3(0.25f, 0.25f, 0.25f);
            ambientLight.AddDirectionalLight(false, new Vector3(-1, -1, 0), new Vector3(2, 2, 2));           // add some backlighting

            //setup the shadow render camera
            Camera3D shadowCamera = new Camera3D();

            shadowCamera.LookAt(new Vector3(1, 1, 3), new Vector3(-15, 20, 20), new Vector3(0, 0, 1));

            //set the clip plane distances
            shadowCamera.Projection.FarClip      = 40;
            shadowCamera.Projection.NearClip     = 20;
            shadowCamera.Projection.FieldOfView *= 0.25f;


            //8bit is actually enough accuracy for this sample (given the limited range of the shadow)
            SurfaceFormat textureFormat = SurfaceFormat.Color;
            const int     resolution    = 512;

            //create the shadow map texture:
            drawShadowDepth = new DrawTargetTexture2D(shadowCamera, resolution, resolution, textureFormat, DepthFormat.Depth24);
            drawShadowDepth.ClearBuffer.ClearColour = Color.White;

            //for the shadow technique used, the shadow buffer is blurred.
            //this requires an intermediate render target on the PC
            DrawTargetTexture2D blurIntermediate = null;

#if !XBOX360
            //not required on the xbox if the render target is small enough to fit in EDRAM in one tile
            blurIntermediate = new DrawTargetTexture2D(shadowCamera, resolution, resolution, textureFormat);
#endif
            //create a blur filter
            shadowDepthBlurFilter = new Xen.Ex.Filters.BlurFilter(Xen.Ex.Filters.BlurFilterFormat.SevenSampleBlur, 1.0f, drawShadowDepth, blurIntermediate);

            //create the scene camera
            Camera3D camera = new Camera3D();
            camera.LookAt(new Vector3(0, 0, 3), new Vector3(10, 10, 6), new Vector3(0, 0, 1));
            camera.Projection.FieldOfView *= 0.55f;

            //create the draw target.
            drawToScreen = new DrawTargetScreen(this, camera);
            drawToScreen.ClearBuffer.ClearColour = Color.Black;

            //the 'scene'
            //A DrawList from Tutorial 23 is used here, this stores the 'scene',
            //which is just a set of actors and the ground
            Tutorials.Tutorial_23.DrawList scene = new Tutorials.Tutorial_23.DrawList();

            for (int x = 0; x < 2; x++)
            {
                for (int y = 0; y < 2; y++)
                {
                    //create the actor instances
                    if (x != 0 || y != 0)
                    {
                        scene.Add(new Actor(this.Content, new Vector3(x * 6 - 3, y * 6 - 3, 0), (x + y * 2 + 1) * 0.1f, 4 - x * 2 - y));
                    }
                }
            }

            //add the ground
            GroundDisk ground = new GroundDisk(this.Content, 10, ambientLight);
            scene.Add(ground);


            //setup the draw targets...


            //create the shader provider
            ShadowOutputShaderProvider shadowOutputShaderProvider = new ShadowOutputShaderProvider();

            //add a ShadowMapDrawer to the shadow map texture
            drawShadowDepth.Add(new ShadowMapDrawer(scene, shadowOutputShaderProvider));

            //setup the scene to be drawn to the screen
            //draw the scene normally (no shadow, just ambient)
            drawToScreen.Add(scene);

            //then draw the scene with a shadow (blended on top)
            drawToScreen.Add(new ShadowedSceneDrawer(scene, shadowOutputShaderProvider, drawShadowDepth));

            //add a nice faded background
            Tutorial_20.BackgroundGradient background = new Tutorial_20.BackgroundGradient(Color.WhiteSmoke, Color.Black);
            background.DrawAtMaxZDepth = true;
            drawToScreen.Add(background);


            //create a textured element that will display the shadow map texture
            TexturedElement shadowDepthDisplay = new TexturedElement(drawShadowDepth, new Vector2(256, 256));
            shadowDepthDisplay.VerticalAlignment = VerticalAlignment.Top;
            this.drawToScreen.Add(shadowDepthDisplay);
        }
Пример #5
0
        void IParticleProcessor.Initalise(ParticleSystemTypeData typeData, IParticleProcessor[] allProcessors, bool useColourValues, uint maxLifeTimeSteps, uint timeStepHz, uint maxExpectedCount)
        {
            this.processorData = typeData.RuntimeLogicData.GpuParticleProcessorData;

            //compute resolution to fit the particle count
            this.resolutionX = 2;
            this.resolutionY = 2;

            while (true)
            {
                int count = resolutionX * resolutionY;
                if (count >= maxExpectedCount)
                {
                    break;
                }
                if (resolutionY >= resolutionX)
                {
                    resolutionX *= 2;
                }
                else
                {
                    resolutionY *= 2;
                }
            }

            resolutionXF = (float)resolutionX;
            resolutionYF = (float)resolutionY;

            this.particleTypeData = typeData;

            this.allProcessors      = allProcessors;
            this.renderPasses       = new GpuParticleRenderPass[4];
            this.shaderRandomValues = new Random();

            this.maxParticleTimeStep = maxLifeTimeSteps;
            this.systemStepDeltaTime = 1.0f / ((float)timeStepHz);

            bool usesUserValues = typeData.RuntimeLogicData.SystemUsesUserValues;
            bool usesLifeOrAge  = typeData.RuntimeLogicData.SystemUsesLifeOrAgeValues;

            this.usesLifeStorage = usesLifeOrAge;

            SurfaceFormat vec4Format = SurfaceFormat.HalfVector4;

            if (!ParticleSystem.gpuVTexHalfVec4supported)
            {
                vec4Format = SurfaceFormat.Vector4;
            }

            this.positionSizeBufferA     = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format);
            this.velocityRotationBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format);

            if (useColourValues)
            {
                this.colourBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format);
            }
            if (usesUserValues)
            {
                this.userBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format);
            }

#if XBOX360
            //technically doing this can produce bugs when the buffers combine to be greater than 10MiB
            //(approx ~320,000 particles)
            //This can happen as the textures are updated in tiles, and it's possible for a particle
            //to be shifted across a tile and recieve an invalid update. However the majority of the time,
            //this would only cause a particle to be a frame behind or ahead. Worst case is the particle
            //either dissapears or is duplicated.

            //it is considered a worthwhile tradeoff for half the render target memory usage

            this.positionSizeBufferB     = positionSizeBufferA;
            this.velocityRotationBufferB = velocityRotationBufferA;
            this.colourBufferB           = colourBufferA;
            this.userBufferB             = userBufferA;
#else
            this.positionSizeBufferB     = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format);
            this.velocityRotationBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format);

            if (useColourValues)
            {
                this.colourBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format);
            }
            if (usesUserValues)
            {
                this.userBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format);
            }
#endif

            //setup the render target groups (MRT)
            DrawTargetTexture2D[] targets = new DrawTargetTexture2D[2 + (useColourValues ? 1 : 0) + (usesUserValues ? 1 : 0)];

            targets[0] = positionSizeBufferA;
            targets[1] = velocityRotationBufferA;
            if (useColourValues)
            {
                targets[2] = colourBufferA;
            }
            if (usesUserValues)
            {
                targets[targets.Length - 1] = userBufferA;
            }

            this.mrtGroupA = new DrawTargetTexture2DGroup(camera, targets);

            targets[0] = positionSizeBufferB;
            targets[1] = velocityRotationBufferB;
            if (useColourValues)
            {
                targets[2] = colourBufferB;
            }
            if (usesUserValues)
            {
                targets[targets.Length - 1] = userBufferB;
            }

            this.mrtGroupB = new DrawTargetTexture2DGroup(camera, targets);


            this.mrtGroupA.ClearBuffer.Enabled = false;
            this.mrtGroupB.ClearBuffer.Enabled = false;


            if (usesLifeOrAge)
            {
                SurfaceFormat ageFormat = SurfaceFormat.HalfVector2;

                if (!ParticleSystem.gpuVTexHalfVec2supported)
                {
                    ageFormat = SurfaceFormat.HalfVector4;

                    if (!ParticleSystem.gpuVTexHalfVec4supported)
                    {
                        ageFormat = SurfaceFormat.Vector4;
                    }
                }

#if XBOX360
                lifeStoreBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, ageFormat);
                lifeStoreBufferB = lifeStoreBufferA;
                lifeStoreBufferA.ClearBuffer.Enabled = false;

                lifeStoreBufferA.Add(new TexturedElement(lifeStoreBufferA, Vector2.One, true));
#else
                lifeStoreBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, ageFormat);
                lifeStoreBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, ageFormat);
                lifeStoreBufferA.ClearBuffer.Enabled = false;
                lifeStoreBufferB.ClearBuffer.Enabled = false;

                //setup so that when a store buffer is drawn, it copies in the other buffer.

                lifeStoreBufferA.Add(new TexturedElement(lifeStoreBufferB, Vector2.One, true));
                lifeStoreBufferB.Add(new TexturedElement(lifeStoreBufferA, Vector2.One, true));
#endif
            }


            this.scissorTest = new Xen.Graphics.Modifier.ScissorModifier(0, 0, 1, 1);

            //scissor off the MRT, as it uses a fullsize quad to run the particle logic for every particle
            this.mrtGroupA.AddModifier(scissorTest);
            this.mrtGroupB.AddModifier(scissorTest);

            //this is the pass that runs per-frame logic on the particles
            this.backgroundFillPass = new ShaderElement(this.processorData.FrameShader, new Vector2(1, 1), true);

            this.mrtGroupA.Add(backgroundFillPass);
            this.mrtGroupB.Add(backgroundFillPass);

            this.mrtGroupA.Add(this);
            this.mrtGroupB.Add(this);

            if (usesLifeOrAge)
            {
                this.lifeStoreBufferA.Add(this);
#if !XBOX360
                this.lifeStoreBufferB.Add(this);
#endif
            }
        }
Пример #6
0
        protected override void Initialise()
        {
            Resource.EnableResourceTracking();

            //setup the view camera first
            //--------------------------------------

            viewCamera = new Xen.Ex.Camera.FirstPersonControlledCamera3D(this.UpdateManager);
            viewCamera.Projection.FieldOfView *= 0.65f;
            viewCamera.MovementSensitivity    *= 0.05f;
            viewCamera.LookAt(new Vector3(-3, 4, 2), new Vector3(6, 6, 2), new Vector3(0, 1, 0));
            viewCamera.Projection.NearClip = 0.1f;

            //shadow map setup:
            //--------------------------------------

            const float shadowArea          = 4;
            const int   shadowMapResolution = 1024;

            //setup the shadow map rendering camera
            shadowCamera = new Camera3D();

            //setup the shadow map projection to roughly cover the character
            shadowCamera.Projection.Orthographic = true;
            shadowCamera.Projection.NearClip     = shadowArea * 2;
            shadowCamera.Projection.FarClip      = -shadowArea * 2;
            shadowCamera.Projection.Region       = new Vector4(1, -1.8f, -1, 0.2f) * shadowArea;

            //setup the shadow map draw target

            //find a desirable format for the shadow map,
            SurfaceFormat format = SurfaceFormat.Color;

            //ideally use a high precision format, but only if it's supported. Avoid full 32bit float
            if (DrawTargetTexture2D.SupportsFormat(SurfaceFormat.Rg32))
            {
                format = SurfaceFormat.Rg32;                                                                                                            //ushort * 2
            }
            else if (DrawTargetTexture2D.SupportsFormat(SurfaceFormat.HalfVector2))
            {
                format = SurfaceFormat.HalfVector2;                                                                                     //fp16 * 2
            }
            else if (DrawTargetTexture2D.SupportsFormat(SurfaceFormat.HalfVector4))
            {
                format = SurfaceFormat.HalfVector4;                                                                                 //fp16 * 4
            }
            //create the shadow map
            shadowMap = new DrawTargetTexture2D(shadowCamera, shadowMapResolution, shadowMapResolution, format, DepthFormat.Depth24);
            shadowMap.ClearBuffer.ClearColour = Color.White;

            //setup the shadow map drawer..
            shadowDrawer = new Tutorial_25.ShadowMapDrawer(null, new Tutorial_25.ShadowOutputShaderProvider());
            this.shadowMap.Add(shadowDrawer);



            //create the main draw targets.
            //--------------------------------------

            drawToScreen = new DrawTargetScreen(this, new Camera2D());
            drawToScreen.ClearBuffer.ClearColourEnabled = false;

            drawToRenderTarget = new DrawTargetTexture2D(viewCamera, this.WindowWidth, this.WindowHeight, SurfaceFormat.Color, DepthFormat.Depth24Stencil8, false, MultiSampleType.FourSamples, RenderTargetUsage.PlatformContents);
            drawToRenderTarget.ClearBuffer.ClearColourEnabled = false;

            //setup the bloom draw targets
            //--------------------------------------

            //scale to reduce the size of the bloom target, compared to main render target
            const int bloomDownsample = 8;              //eight times smaller

            bloomRenderTarget = new DrawTargetTexture2D(new Camera2D(), Math.Max(1, drawToRenderTarget.Width / bloomDownsample), Math.Max(1, drawToRenderTarget.Height / bloomDownsample), SurfaceFormat.Color);
            bloomRenderTarget.ClearBuffer.ClearColourEnabled = false;

            bloomIntermediateRenderTarget = null;
#if WINDOWS
            //the bloom intermediate target is not needed on the xbox, as the full bloom target fits in EDRAM
            bloomIntermediateRenderTarget = new DrawTargetTexture2D(viewCamera, bloomRenderTarget.Width, bloomRenderTarget.Height, SurfaceFormat.Color);
            bloomIntermediateRenderTarget.ClearBuffer.ClearColourEnabled = false;
#endif
            //setup the blur filter, with a large 31 sample radius.
            bloomBlurPass = new Xen.Ex.Filters.BlurFilter(Xen.Ex.Filters.BlurFilterFormat.ThirtyOneSampleBlur_FilteredTextureFormat, 1.0f, bloomRenderTarget, bloomIntermediateRenderTarget);


            //setup the character model
            this.model         = new ModelInstance();           //(the model is setup in LoadContent)
            this.modelRotation = new DrawRotated(model);
            this.modelRotation.RotationAngle = 3;

            //add the model to be drawn
            drawToRenderTarget.Add(modelRotation);

            //setup the shaders
            this.characterRenderShader      = new Shaders.Character();
            this.characterBlendRenderShader = new Shaders.CharacterBlend();

            //setup the output and bloom shaders
            outputShader = new Shaders.RgbmDecode();
            drawToScreen.Add(new ShaderElement(outputShader, new Vector2(1, 1), true));

            bloomPassShader = new Shaders.RgbmDecodeBloomPass();
            bloomRenderTarget.Add(new ShaderElement(bloomPassShader, new Vector2(1, 1), true));

            //add a background to be drawn
            drawToRenderTarget.Add(new BackgroundDrawer());


            //setup the debug image displays
            //--------------------------------------

            this.rgmbTextureAlphaShader  = new Shaders.AlphaWrite();
            this.bloomTextureDisplay     = new TexturedElement(this.bloomRenderTarget, new Vector2(0.2f, 0.2f), true);
            this.rgbmTextureDisplay      = new TexturedElement(this.drawToRenderTarget, new Vector2(0.2f, 0.2f), true);
            this.rgbmTextureAlphaDisplay = new ShaderElement(this.rgmbTextureAlphaShader, new Vector2(0.2f, 0.2f), true);

            this.rgbmTextureAlphaDisplay.Position = new Vector2(0.7f, 0.2f);
            this.rgbmTextureDisplay.Position      = new Vector2(0.7f, 0.4f);
            this.bloomTextureDisplay.Position     = new Vector2(0.7f, 0.6f);

            this.drawToScreen.Add(this.rgbmTextureDisplay);
            this.drawToScreen.Add(this.rgbmTextureAlphaDisplay);
            this.drawToScreen.Add(this.bloomTextureDisplay);

            //setup the render config
            this.configEditor = new RenderConfigEditor(this.Content);

            this.drawToScreen.Add(configEditor);
            this.UpdateManager.Add(configEditor);


            //add a statistics overlay.
            drawStats = new Xen.Ex.Graphics2D.Statistics.DrawStatisticsDisplay(this.UpdateManager);
            drawToScreen.Add(drawStats);
        }