Beispiel #1
0
        //when drawing, the instances will call this method
        public void AddInstance(DrawState state)
        {
            //store the instance matrix
            state.GetWorldMatrix(out instanceMatrices[instanceCount]);

            instanceCount++;
        }
Beispiel #2
0
        /// <summary>
        /// <para>Call this method before drawing/culling an item. Match this method call with a call to TryGetPosition after the cull/draw is complete</para>
        /// <para>The <see cref="ResetPreCullItem"/> method may also be used for subsequent items that are culled, provided the world matrix hasn't changed.</para>
        /// </summary>
        /// <param name="state"></param>
        public void BeginPreCullItem(DrawState state)
        {
            this.count    = 0;
            this.countI   = 0;
            this.position = new Vector3();

            state.GetWorldMatrix(out this.matrix, out this.isIdentity);
        }
Beispiel #3
0
        /// <summary>
        /// <para>Call this method before drawing/culling an item. Match this method call with a call to TryGetBounds after the cull/draw is complete</para>
        /// <para>The <see cref="ResetPreCullItem"/> method may also be used for subsequent items that are culled, provided the world matrix hasn't changed.</para>
        /// </summary>
        /// <param name="state"></param>
        public void BeginPreCullItem(DrawState state)
        {
            this.reset = true;
            state.GetWorldMatrix(out matrix, out isIdentity);
            scale = 1;

            minBound = new Vector3();
            maxBound = new Vector3();

            if (!isIdentity)
            {
                Matrix.Invert(ref matrix, out matrix);

                scale = (float)Math.Sqrt(
                    Math.Max(Math.Max(
                                 (matrix.M11 * matrix.M11 + matrix.M21 * matrix.M21 + matrix.M31 * matrix.M31),
                                 (matrix.M12 * matrix.M12 + matrix.M22 * matrix.M22 + matrix.M32 * matrix.M32)),
                             (matrix.M13 * matrix.M13 + matrix.M23 * matrix.M23 + matrix.M33 * matrix.M33)));
            }
        }
        /// <summary></summary>
        /// <param name="state"></param>
        protected override void DrawItems(DrawState state)
        {
            //draw all items in the tree
            minBuffer[0] = boundsMin.X;
            minBuffer[1] = boundsMin.Y;
            minBuffer[2] = boundsMin.Z;

            maxBuffer[0] = boundsMax.X;
            maxBuffer[1] = boundsMax.Y;
            maxBuffer[2] = boundsMax.Z;

            if (this.count > 64 && state.Application.ThreadPool.ThreadCount > 0)
            {
                //if there are lots of items and free threads, then traverse the tree on multiple threads
                DrawItemsThread(state);
                return;
            }

            Matrix world;

            state.GetWorldMatrix(out world);

            allNodes[0].Draw(state, minBuffer, maxBuffer, 0, allChildren, allNodes, world == Matrix.Identity, this.IsOptimizedState);
        }
Beispiel #5
0
        //the child isn't drawn right now, but for every bit of geometry that is visible, the world matrix is stored
        internal void DrawChild(DrawState state)
        {
            if (modelData == null)
            {
                throw new InvalidOperationException("ModelData is null");
            }

            if (geometry == null)
            {
                SetupGeometry();
            }

            ContainmentType cullModel = ContainmentType.Contains;

            //if there is just one geometry object, then the ICullable.CullTest() call will have been suficient.
            bool skipCullTest = this.modelData != null && this.modelData.meshes.Length == 1 && this.modelData.meshes[0].geometry.Length == 1;

            if (!skipCullTest)
            {
                cullModel = state.Culler.IntersectBox(ref modelData.staticBounds.minimum, ref modelData.staticBounds.maximum);
            }

            int  geometryIndex = 0;
            bool drawn         = false;

            //loop through the model data
            if (cullModel != ContainmentType.Disjoint)
            {
                for (int m = 0; m < modelData.meshes.Length; m++)
                {
                    MeshData mesh = modelData.meshes[m];

                    ContainmentType cullMesh = cullModel;

                    //cull testing along the way
                    if (cullModel == ContainmentType.Intersects && modelData.meshes.Length > 1)
                    {
                        cullMesh = state.Culler.IntersectBox(ref mesh.staticBounds.minimum, ref mesh.staticBounds.maximum);
                    }

                    if (cullMesh != ContainmentType.Disjoint)
                    {
                        for (int g = 0; g < mesh.geometry.Length; g++)
                        {
                            GeometryData geom = mesh.geometry[g];

                            bool cullTest = true;

                            if (cullMesh == ContainmentType.Intersects && mesh.geometry.Length > 1)
                            {
                                cullTest = state.Culler.TestBox(ref geom.staticBounds.minimum, ref geom.staticBounds.maximum);
                            }

                            //finally, is the geometry visible?
                            if (cullTest)
                            {
                                //add the world matrix to the geometry set
                                GeometrySet set = this.geometry[geometryIndex];

                                if (set.count == set.instances.Length)
                                {
                                    Array.Resize(ref set.instances, set.instances.Length * 2);
                                }

                                state.GetWorldMatrix(out set.instances[set.count++]);

                                drawn = true;
                            }

                            geometryIndex++;
                        }
                    }
                    else
                    {
                        geometryIndex += mesh.geometry.Length;
                    }
                }
            }
            if (drawn)
            {
                drawCount++;
            }
        }
Beispiel #6
0
        /// <summary></summary>
        /// <param name="state"></param>
        /// <param name="maskOnly"></param>
        protected override sealed void BindShader(DrawState state, bool maskOnly)
        {
            if (this.vertices == null)
            {
                this.vertices = state.UserValues[GetType().FullName + ".vertices"] as IVertices;
                this.indices  = state.UserValues[GetType().FullName + ".indices"] as Indices <ushort>;

                this.verticesSI = state.UserValues[GetType().FullName + ".verticesSI"] as IVertices;
                this.indicesSI  = state.UserValues[GetType().FullName + ".indicesSI"] as Indices <ushort>;

                if (this.vertices == null)
                {
                    //still null, create the global vertices
                    this.vertices = new Vertices <Vector4>(
                        new Vector4(0, 0, 0, 1),
                        new Vector4(1, 0, 0, 1),
                        new Vector4(1, 1, 0, 1),
                        new Vector4(0, 1, 0, 1));

                    this.indices = new Indices <ushort>(0, 2, 1, 0, 3, 2);

                    //shader instancing..
                    List <InstanceVertex> verts = new List <InstanceVertex>();
                    List <ushort>         inds  = new List <ushort>();

                    for (int i = 0; i < NonInstancingRenderCount; i++)
                    {
                        verts.Add(new InstanceVertex(new Vector3(0, 0, 0), (float)i));
                        verts.Add(new InstanceVertex(new Vector3(1, 0, 0), (float)i));
                        verts.Add(new InstanceVertex(new Vector3(1, 1, 0), (float)i));
                        verts.Add(new InstanceVertex(new Vector3(0, 1, 0), (float)i));

                        inds.Add((ushort)(0 + i * 4));
                        inds.Add((ushort)(2 + i * 4));
                        inds.Add((ushort)(1 + i * 4));
                        inds.Add((ushort)(0 + i * 4));
                        inds.Add((ushort)(3 + i * 4));
                        inds.Add((ushort)(2 + i * 4));
                    }

                    this.verticesSI = new Vertices <InstanceVertex>(verts.ToArray());
                    this.indicesSI  = new Indices <ushort>(inds.ToArray());

                    state.UserValues[GetType().FullName + ".vertices"]   = vertices;
                    state.UserValues[GetType().FullName + ".indices"]    = indices;
                    state.UserValues[GetType().FullName + ".verticesSI"] = verticesSI;
                    state.UserValues[GetType().FullName + ".indicesSI"]  = indicesSI;
                }
            }

            if (state.SupportsHardwareInstancing && instanceCount > HardwareInstancingMinimum)
            {
                Graphics2D.InstancingSprite shader = state.GetShader <Graphics2D.InstancingSprite>();
                Matrix world;
                state.GetWorldMatrix(out world);
                shader.SetSpriteWorldMatrix(ref world);
                shader.CustomTexture = texture ?? Xen.Ex.Material.WhiteTexture.GetTexture(state);
                shader.Bind(state);
            }
            else
            {
                Graphics2D.NonInstancingSprite shader = state.GetShader <Graphics2D.NonInstancingSprite>();
                shader.CustomTexture = texture ?? Xen.Ex.Material.WhiteTexture.GetTexture(state);
                shader.Bind(state);
            }
        }
        //traverse the tree on multiple threads...
        private void DrawItemsThread(DrawState state)
        {
            minBuffer[0] = boundsMin.X;
            minBuffer[1] = boundsMin.Y;
            minBuffer[2] = boundsMin.Z;

            maxBuffer[0] = boundsMax.X;
            maxBuffer[1] = boundsMax.Y;
            maxBuffer[2] = boundsMax.Z;

            Threading.ThreadPool pool = state.Application.ThreadPool;

            if (this.threads == null)
            {
                //create the threads.
                //must be a power-of-two number of thread tasks
                threadLevel = 0;
                int threadCount = 2;
                while (pool.ThreadCount >= threadCount)
                {
                    threadCount *= 2;
                    threadLevel++;
                }

                this.threads = new ThreadDrawer[threadCount];
                for (int i = 0; i < threadCount; i++)
                {
                    this.threads[i]      = new ThreadDrawer();
                    this.threads[i].axis = threadLevel % 3;
                }
            }

            Matrix world;

            state.GetWorldMatrix(out world);
            bool isIdentity = world == Matrix.Identity;

            for (int i = 0; i < this.threads.Length; i++)
            {
                this.threads[i].children      = this.allChildren;
                this.threads[i].nodes         = this.allNodes;
                this.threads[i].idenityMatrix = isIdentity;

                this.threads[i].cullTestInstanceCount = 0;
                this.threads[i].instanceCount         = 0;

                this.threads[i].treeIsOptimized = this.IsOptimizedState;
            }

            int index = 0;

            //traverse the tree, when getting to 'threadLevel' child depth, process on a thread
            DrawItemsThread(state, 0, 0, ref index, minBuffer, maxBuffer);

            //now wait for everything to finish...
            for (int i = 0; i < this.threads.Length; i++)
            {
                threads[i].callback.WaitForCompletion();
            }

            //iterate through the items to draw
            for (int t = 0; t < this.threads.Length; t++)
            {
                //some do not require cull tests
                if (this.IsOptimizedState)
                {
                    for (int i = 0; i < threads[t].instanceCount; i++)
                    {
                        ThreadDrawnInstance inst = threads[t].instances[i];

                        uint child = inst.firstChild;
                        child <<= ChildCountShift;

                        for (ushort c = 0; c < inst.childCount; c++)
                        {
                            IDraw item = allChildren[child++];
                            if (item != null)
                            {
                                item.Draw(state);
                            }
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < threads[t].instanceCount; i++)
                    {
                        ThreadDrawnInstance inst = threads[t].instances[i];

                        uint child = inst.firstChild;
                        child <<= ChildCountShift;

                        for (ushort c = 0; c < inst.childCount; c++)
                        {
                            allChildren[child++].Draw(state);
                        }
                    }
                }

                //some do.
                for (int i = 0; i < threads[t].cullTestInstanceCount; i++)
                {
                    ThreadDrawnInstance inst = threads[t].cullTestInstances[i];

                    uint child = inst.firstChild;
                    child <<= ChildCountShift;

                    for (ushort c = 0; c < inst.childCount; c++)
                    {
                        if (allChildren[child].CullTest(state))
                        {
                            allChildren[child].Draw(state);
                        }
                        child++;
                    }
                }
            }
        }