/// <summary>
        /// Creates a material with the given name and shader
        /// </summary>
        /// <param name="name"></param>
        /// <param name="shadername"></param>
        /// <returns></returns>
        public Material CreateMaterial(string name, string shadername)
        {
            // Check if it's already loaded
            Material material;
            if (materialmap.TryGetValue(name, out material)) return material;

            // Create it
            material = new Material(Owner.GetComponent<Renderer>());
            material.Name = name;
            material.Shader = GetShader(shadername);
            materialmap.Add(name, material);
            return material;
        }
        /// <summary>
        /// Sets the current active material, returns true if a material switch occured
        /// </summary>
        /// <param name="material"></param>
        public void SetActiveMaterial(Material material, bool shadow = false, bool forceswitch = false, bool noapply = false)
        {
            // Null check
            if (material == null)
            {
                activematerial = null;
                activematerialshadow = false;
                return;
            }

            // Should we ignore optimisations?
            if (activematerial == null || forceswitch)
            {
                activematerial = material;
                Shader shader = shadow ? material.ShadowShader : material.Shader;
                if (shader == null)
                {
                    activematerial = null;
                    activematerialshadow = false;
                    return;
                }
                shader.Activate(context);
                if (!noapply) material.Apply(shadow);
                frame_materialswitches++;
                frame_shaderswitches++;
                return;
            }

            // Did the material change?
            if (material != activematerial)
            {
                // Did the shader change?
                Shader oldshader = shadow ? activematerial.ShadowShader : activematerial.Shader;
                Shader newshader = shadow ? material.ShadowShader : material.Shader;
                if (newshader == null)
                {
                    activematerial = null;
                    activematerialshadow = false;
                    return;
                }
                if (oldshader != newshader)
                {
                    // Activate new shader
                    newshader.Activate(context);
                    frame_shaderswitches++;
                }

                // Apply
                activematerial = material;
                activematerialshadow = shadow;
                if (!noapply) material.Apply(shadow);
                frame_materialswitches++;
            }
        }
        private Material LoadMaterial(string name)
        {
            // Check the file exists
            string filename = string.Format("materials/{0}.txt", name);
            if (!File.Exists(filename))
            {
                Console.WriteLine("Failed to load material {0} (file not found)!", name);
                return null;
            }

            // Load it
            string source = File.ReadAllText(filename);
            Console.WriteLine("Loading material {0}...", name);
            JObject root = JObject.Parse(source);

            // Define material and loop each parameter
            Material material = new Material(Owner.GetComponent<Renderer>());
            material.Name = name;
            foreach (var obj in root)
            {
                switch (obj.Key)
                {
                    case "shader":
                        material.Shader = GetShader((string)obj.Value);
                        if (material.Shader == null)
                        {
                            Console.WriteLine("Error loading material {0} - failed to load shader {1}!", name, (string)obj.Value);
                            return null;
                        }
                        break;
                    case "shadowshader":
                        material.ShadowShader = GetShader((string)obj.Value);
                        if (material.ShadowShader == null)
                        {
                            Console.WriteLine("Error loading material {0} - failed to load shader {1}!", name, (string)obj.Value);
                            return null;
                        }
                        break;
                    case "culling":
                        string val = (string)obj.Value;
                        switch (val)
                        {
                            case "frontface":
                                material.CullingMode = Owner.GetComponent<Renderer>().Culling_Frontface;
                                break;
                            case "backface":
                                material.CullingMode = Owner.GetComponent<Renderer>().Culling_Backface;
                                break;
                            case "none":
                                material.CullingMode = Owner.GetComponent<Renderer>().Culling_None;
                                break;
                        }
                        break;
                    default:
                        if (obj.Value.Type == JTokenType.Array)
                        {
                            int cnt = (obj.Value as JArray).Count;
                            if (cnt == 3)
                                material.SetParameter(obj.Key, new Vector3((float)obj.Value[0], (float)obj.Value[1], (float)obj.Value[2]));
                            else if (cnt == 2)
                                material.SetParameter(obj.Key, new Vector2((float)obj.Value[0], (float)obj.Value[1]));
                            else
                                Console.WriteLine("Parameter '{0}' in material {1} is not understood!", obj.Key, name);
                        }
                        else if (obj.Value.Type == JTokenType.Float)
                            material.SetParameter(obj.Key, (float)obj.Value);
                        else if (obj.Value.Type == JTokenType.String)
                        {
                            string value = (string)obj.Value;
                            if (value.Length == 0)
                                Console.WriteLine("Parameter '{0}' in material {1} is an emoty string!", obj.Key, name);
                            else
                            {
                                // What type of object is it trying to indicate?
                                if (value[0] == '$')
                                {
                                    // Is it a scripted texture?
                                    string texturedata = value.Substring(1);
                                    string[] script = null;
                                    if (texturedata.Contains("$"))
                                    {
                                        string[] texturearray = texturedata.Split('$');
                                        if (texturearray.Length != 2)
                                        {
                                            Console.WriteLine("Parameter '{0}' in material {1} has bad scripted texture data!");
                                        }
                                        else
                                        {
                                            texturedata = texturearray[1];
                                            if (texturearray[0].Contains(":"))
                                                script = texturearray[0].Split(':');
                                            else
                                                script = new string[] { texturearray[0] };
                                        }
                                    }

                                    // Texture
                                    Texture2D tex = GetTexture(texturedata);
                                    if (tex == null)
                                        Console.WriteLine("Parameter '{0}' in material {1} referenced an invalid texture!", obj.Key, name);
                                    else
                                    {
                                        // Apply script
                                        if (script != null && script.Length >= 1)
                                        {
                                            switch (script[0])
                                            {
                                                case "normalmap_from_heightmap":
                                                    var device = Owner.GetComponent<Renderer>().Device;
                                                    Texture2D output = new Texture2D(device, tex.Description);
                                                    output.DebugName = tex.DebugName + "_normals";
                                                    float height = 1.0f;
                                                    if (script.Length > 1) float.TryParse(script[1], out height);
                                                    Result result = Texture2D.ComputeNormalMap(device.ImmediateContext, tex, output, (NormalMapFlags)0, Channel.Red, height);
                                                    if (result.IsFailure)
                                                        Console.WriteLine("Failed to convert heightmap at '{0}' to normalmap in material {1}!", texturedata, name);
                                                    else
                                                        tex = output;
                                                    break;
                                            }
                                        }

                                        // Apply parameter
                                        material.SetParameter(obj.Key, tex);
                                    }
                                }
                                else if (value[0] == '@')
                                {
                                    // Sampler
                                    switch (value.Substring(1))
                                    {
                                        case "wrap_linear":
                                            material.SetParameter(obj.Key, Owner.GetComponent<Renderer>().Sampler_Wrap);
                                            break;
                                        case "clamp_linear":
                                            material.SetParameter(obj.Key, Owner.GetComponent<Renderer>().Sampler_Clamp_Linear);
                                            break;
                                    }
                                }
                                else
                                    Console.WriteLine("Parameter '{0}' in material {1} is not understood!", obj.Key, name);
                            }
                        }
                        break;
                }
            }

            // Return it
            return material;
        }
        public void OnInitialise(InitialiseMessage msg)
        {
            // Initialise scene manager
            Console.WriteLine("Initialising scene manager...");

            // Initialise messages
            queuemsg = new PopulateRenderQueue();
            queuemsg.SceneManager = this;
            cameramsg = new PopulateCameraList();
            cameramsg.Cameras = new OrderedList<Camera>(new CameraComparer());
            cameramsg.ShadowCasters = new HashSet<ShadowCaster>();
            lightmsg = new PopulateLightList();
            lightmsg.Lights = new OrderedList<Light>(new LightComparer());
            psysmsg = new PopulateParticleSystemList();
            psysmsg.ParticleSystems = new List<ParticleSystem>();

            // Create render queue
            workitempool = new ResourcePool<RenderWorkItem>();
            renderqueue = new OrderedList<RenderWorkItem>(new RenderWorkItemComparer());
            effectqueue = new OrderedList<PostProcessEffect>(new PostProcessEffectComparer());

            // Setup GBuffer
            Renderer renderer = Owner.GetComponent<Renderer>();
            gbuffer = renderer.CreateRenderTarget(1, "GBuffer");
            gbuffer.ClearColour = new Color4(0.0f, 0.0f, 0.0f, 0.0f);
            gbuffer.AddDepthComponent();
            gbuffer_colour = gbuffer.AddTextureComponent();
            gbuffer_normal = gbuffer.AddTextureComponent(SlimDX.DXGI.Format.R32G32B32A32_Float);
            gbuffer_position = gbuffer.AddTextureComponent(SlimDX.DXGI.Format.R32G32B32A32_Float);
            gbuffer_material = gbuffer.AddTextureComponent(SlimDX.DXGI.Format.R32G32B32A32_Float);
            gbuffer.Finish();

            // Setup light accumulation buffer
            lightaccum = renderer.CreateRenderTarget(1, "LightAccum");
            lightaccum.ClearColour = new Color4(1.0f, 0.0f, 0.0f, 0.0f);
            lightaccum_diffuse = lightaccum.AddTextureComponent(SlimDX.DXGI.Format.R32G32B32A32_Float);
            lightaccum_specular = lightaccum.AddTextureComponent(SlimDX.DXGI.Format.R32G32B32A32_Float);
            lightaccum.Finish();

            // Setup particle accumulation buffer
            particleaccum = renderer.CreateRenderTarget(1, "ParticleAccum");
            particleaccum.ClearColour = new Color4(0.0f, 0.0f, 0.0f, 0.0f);
            particleaccum_colour = particleaccum.AddTextureComponent();
            particleaccum.Finish();

            // Setup swap buffers
            swapA = renderer.CreateRenderTarget(1, "SwapA");
            swapA_colour = swapA.AddTextureComponent();
            swapA.Finish();
            swapB = renderer.CreateRenderTarget(1, "SwapB");
            swapB_colour = swapB.AddTextureComponent();
            swapB.Finish();

            // Setup materials
            MaterialSystem matsys = Owner.GetComponent<MaterialSystem>();
            mat_blit = matsys.CreateMaterial("blit", "blit");
            mat_blit.SetParameter("smpTexture", renderer.Sampler_Clamp);
            mat_blitlight = matsys.CreateMaterial("blit_light", "blit_light");
            mat_blitlight.SetParameter("smpTexture", renderer.Sampler_Clamp);
            mat_blitlight.SetParameter("texColour", gbuffer.GetTexture(gbuffer_colour));
            mat_blitlight.SetParameter("texDiffuseLight", lightaccum.GetTexture(lightaccum_diffuse));
            mat_blitlight.SetParameter("texSpecularLight", lightaccum.GetTexture(lightaccum_specular));

            // Setup lights
            mat_lights = new Dictionary<LightType, Material>();
            mat_lights.Add(LightType.Ambient, matsys.CreateMaterial("light_ambient", "light_ambient"));
            mat_lights.Add(LightType.Directional, matsys.CreateMaterial("light_directional", "light_directional"));
            mat_lights.Add(LightType.Point, matsys.CreateMaterial("light_point", "light_point"));
            foreach (Material mat in mat_lights.Values)
            {
                mat.SetParameter("texNormal", gbuffer.GetTexture(gbuffer_normal));
                mat.SetParameter("texPosition", gbuffer.GetTexture(gbuffer_position));
                mat.SetParameter("texMaterial", gbuffer.GetTexture(gbuffer_material));
                mat.SetParameter("smpTexture", renderer.Sampler_Clamp);
            }

            // Setup meshes
            mesh_fs = MeshBuilder.BuildFullscreenQuad();
            mesh_skybox = MeshBuilder.BuildCube();
        }
        /// <summary>
        /// Queues a draw order
        /// </summary>
        /// <param name="mesh"></param>
        /// <param name="submesh"></param>
        /// <param name="material"></param>
        /// <param name="transform"></param>
        public void QueueDraw(Mesh mesh, int submesh, Material material, Matrix transform)
        {
            // Create the work item
            RenderWorkItem item = workitempool.Request();
            item.Mesh = mesh;
            item.SubmeshIndex = submesh;
            item.Material = material;
            item.Transform = transform;

            // Add to queue
            renderqueue.Add(item);
        }
        private Actor LoadModel(JToken source)
        {
            // Create the actor
            Actor actor = new Actor(Owner.MessagePool);

            // Add the required components to it
            Transform transform = actor.AddComponent<Transform>();

            // Load generic transform
            LoadTransform(transform, source);

            // Load model
            if (source["model"] != null)
            {
                string model = (string)source["model"];
                SBMLoader loader = new SBMLoader("models/" + model + ".sbm");
                string err;
                if (!loader.Load(out err))
                {
                    Console.WriteLine("Failed to load model '{0}'! ({1})", model, err);
                    return null;
                }

                // Is there more than 1 mesh?
                if (loader.MeshCount > 1)
                {
                    for (int i = 0; i < loader.MeshCount; i++)
                    {
                        Actor tmp = new Actor(Owner.MessagePool);
                        tmp.AddComponent<Transform>();
                        MeshRenderer renderer = tmp.AddComponent<MeshRenderer>();
                        Mesh mesh;
                        string[] materialnames;
                        loader.GetMesh(i, out mesh, out materialnames);
                        Material[] materials = new Material[materialnames.Length];
                        for (int j = 0; j < materials.Length; j++)
                        {
                            materials[j] = Owner.GetComponent<MaterialSystem>().GetMaterial(materialnames[j]);
                            if (materials[j] == null) Console.WriteLine("Failed to load material '{0}'!", materialnames[j]);
                        }
                        renderer.Mesh = mesh;
                        renderer.Materials = materials;
                        tmp.Parent = actor;
                        tmp.Init();
                    }
                }
                else
                {
                    MeshRenderer renderer = actor.AddComponent<MeshRenderer>();
                    Mesh mesh;
                    string[] materialnames;
                    loader.GetMesh(0, out mesh, out materialnames);
                    Material[] materials = new Material[materialnames.Length];
                    for (int j = 0; j < materials.Length; j++)
                        materials[j] = Owner.GetComponent<MaterialSystem>().GetMaterial(materialnames[j]);
                    renderer.Mesh = mesh;
                    renderer.Materials = materials;
                }
            }

            // Initialise and return
            actor.Init();
            return actor;
        }