Beispiel #1
0
        public void Build(bool stencilShadows, bool logDetails)
        {
            // Ok, here's where we transfer the vertices and indexes to the shared buffers
            VertexDeclaration   dcl   = vertexData.vertexDeclaration;
            VertexBufferBinding binds = vertexData.vertexBufferBinding;

            // create index buffer, and lock
            if (logDetails)
            {
                log.InfoFormat("GeometryBucket.Build: Creating index buffer indexType {0} indexData.indexCount {1}",
                               indexType, indexData.indexCount);
            }
            indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer(indexType, indexData.indexCount, BufferUsage.StaticWriteOnly);
            IntPtr indexBufferIntPtr = indexData.indexBuffer.Lock(BufferLocking.Discard);

            // create all vertex buffers, and lock
            ushort b;
            ushort posBufferIdx = dcl.FindElementBySemantic(VertexElementSemantic.Position).Source;

            List <List <VertexElement> > bufferElements = new List <List <VertexElement> >();

            unsafe {
                byte *[] destBufferPtrs = new byte *[binds.BindingCount];
                for (b = 0; b < binds.BindingCount; ++b)
                {
                    int vertexCount = vertexData.vertexCount;
                    if (logDetails)
                    {
                        log.InfoFormat("GeometryBucket.Build b {0}, binds.BindingCount {1}, vertexCount {2}, dcl.GetVertexSize(b) {3}",
                                       b, binds.BindingCount, vertexCount, dcl.GetVertexSize(b));
                    }
                    // Need to double the vertex count for the position buffer
                    // if we're doing stencil shadows
                    if (stencilShadows && b == posBufferIdx)
                    {
                        vertexCount = vertexCount * 2;
                        if (vertexCount > maxVertexIndex)
                        {
                            throw new Exception("Index range exceeded when using stencil shadows, consider " +
                                                "reducing your region size or reducing poly count");
                        }
                    }
                    HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer(dcl.GetVertexSize(b), vertexCount, BufferUsage.StaticWriteOnly);
                    binds.SetBinding(b, vbuf);
                    IntPtr pLock = vbuf.Lock(BufferLocking.Discard);
                    destBufferPtrs[b] = (byte *)pLock.ToPointer();
                    // Pre-cache vertex elements per buffer
                    bufferElements.Add(dcl.FindElementBySource(b));
                }

                // iterate over the geometry items
                int         indexOffset  = 0;
                IEnumerator iter         = queuedGeometry.GetEnumerator();
                Vector3     regionCenter = parent.Parent.Parent.Center;
                int *       pDestInt     = (int *)indexBufferIntPtr.ToPointer();
                ushort *    pDestUShort  = (ushort *)indexBufferIntPtr.ToPointer();
                foreach (QueuedGeometry geom in queuedGeometry)
                {
                    // copy indexes across with offset
                    IndexData srcIdxData = geom.geometry.indexData;
                    IntPtr    srcIntPtr  = srcIdxData.indexBuffer.Lock(BufferLocking.ReadOnly);
                    if (indexType == IndexType.Size32)
                    {
                        int *pSrcInt = (int *)srcIntPtr.ToPointer();
                        for (int i = 0; i < srcIdxData.indexCount; i++)
                        {
                            *pDestInt++ = (*pSrcInt++) + indexOffset;
                        }
                    }
                    else
                    {
                        ushort *pSrcUShort = (ushort *)(srcIntPtr.ToPointer());
                        for (int i = 0; i < srcIdxData.indexCount; i++)
                        {
                            *pDestUShort++ = (ushort)((*pSrcUShort++) + indexOffset);
                        }
                    }
                    srcIdxData.indexBuffer.Unlock();

                    // Now deal with vertex buffers
                    // we can rely on buffer counts / formats being the same
                    VertexData          srcVData = geom.geometry.vertexData;
                    VertexBufferBinding srcBinds = srcVData.vertexBufferBinding;
                    for (b = 0; b < binds.BindingCount; ++b)
                    {
                        // Iterate over vertices
                        destBufferPtrs[b] = CopyVertices(srcBinds.GetBuffer(b), destBufferPtrs[b], bufferElements[b], geom, regionCenter);
                    }
                    indexOffset += geom.geometry.vertexData.vertexCount;
                }
            }

            // unlock everything
            indexData.indexBuffer.Unlock();
            for (b = 0; b < binds.BindingCount; ++b)
            {
                binds.GetBuffer(b).Unlock();
            }

            // If we're dealing with stencil shadows, copy the position data from
            // the early half of the buffer to the latter part
            if (stencilShadows)
            {
                unsafe
                {
                    HardwareVertexBuffer buf = binds.GetBuffer(posBufferIdx);
                    IntPtr src  = buf.Lock(BufferLocking.Normal);
                    byte * pSrc = (byte *)src.ToPointer();
                    // Point dest at second half (remember vertexcount is original count)
                    byte *pDst = pSrc + buf.VertexSize * vertexData.vertexCount;

                    int count = buf.VertexSize * buf.VertexCount;
                    while (count-- > 0)
                    {
                        *pDst++ = *pSrc++;
                    }
                    buf.Unlock();

                    // Also set up hardware W buffer if appropriate
                    RenderSystem rend = Root.Instance.RenderSystem;
                    if (null != rend && rend.Caps.CheckCap(Capabilities.VertexPrograms))
                    {
                        buf = HardwareBufferManager.Instance.CreateVertexBuffer(sizeof(float), vertexData.vertexCount * 2, BufferUsage.StaticWriteOnly, false);
                        // Fill the first half with 1.0, second half with 0.0
                        float *pW = (float *)buf.Lock(BufferLocking.Discard).ToPointer();
                        for (int v = 0; v < vertexData.vertexCount; ++v)
                        {
                            *pW++ = 1.0f;
                        }
                        for (int v = 0; v < vertexData.vertexCount; ++v)
                        {
                            *pW++ = 0.0f;
                        }
                        buf.Unlock();
                        vertexData.hardwareShadowVolWBuffer = buf;
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="lockedBuffer"></param>
        protected unsafe void DistributeControlPoints(IntPtr lockedBuffer)
        {
            // Insert original control points into expanded mesh
            int uStep = 1 << uLevel;
            int vStep = 1 << vLevel;

            void * pSrc = Marshal.UnsafeAddrOfPinnedArrayElement(controlPointBuffer, 0).ToPointer();
            void * pDest;
            int    vertexSize = declaration.GetVertexSize(0);
            float *pSrcReal, pDestReal;
            int *  pSrcRGBA, pDestRGBA;

            VertexElement elemPos     = declaration.FindElementBySemantic(VertexElementSemantic.Position);
            VertexElement elemNorm    = declaration.FindElementBySemantic(VertexElementSemantic.Normal);
            VertexElement elemTex0    = declaration.FindElementBySemantic(VertexElementSemantic.TexCoords, 0);
            VertexElement elemTex1    = declaration.FindElementBySemantic(VertexElementSemantic.TexCoords, 1);
            VertexElement elemDiffuse = declaration.FindElementBySemantic(VertexElementSemantic.Diffuse);

            for (int v = 0; v < meshHeight; v += vStep)
            {
                // set dest by v from base
                pDest = (void *)((byte *)(lockedBuffer.ToPointer()) + (vertexSize * meshWidth * v));

                for (int u = 0; u < meshWidth; u += uStep)
                {
                    // Copy Position
                    pSrcReal  = (float *)((byte *)pSrc + elemPos.Offset);
                    pDestReal = (float *)((byte *)pDest + elemPos.Offset);
                    *pDestReal++ = *pSrcReal++;
                    *pDestReal++ = *pSrcReal++;
                    *pDestReal++ = *pSrcReal++;

                    // Copy Normals
                    if (elemNorm != null)
                    {
                        pSrcReal  = (float *)((byte *)pSrc + elemNorm.Offset);
                        pDestReal = (float *)((byte *)pDest + elemNorm.Offset);
                        *pDestReal++ = *pSrcReal++;
                        *pDestReal++ = *pSrcReal++;
                        *pDestReal++ = *pSrcReal++;
                    }

                    // Copy Diffuse
                    if (elemDiffuse != null)
                    {
                        pSrcRGBA  = (int *)((byte *)pSrc + elemDiffuse.Offset);
                        pDestRGBA = (int *)((byte *)pDest + elemDiffuse.Offset);
                        *pDestRGBA++ = *pSrcRGBA++;
                    }

                    // Copy texture coords
                    if (elemTex0 != null)
                    {
                        pSrcReal  = (float *)((byte *)pSrc + elemTex0.Offset);
                        pDestReal = (float *)((byte *)pDest + elemTex0.Offset);
                        for (int dim = 0; dim < VertexElement.GetTypeCount(elemTex0.Type); dim++)
                        {
                            *pDestReal++ = *pSrcReal++;
                        }
                    }
                    if (elemTex1 != null)
                    {
                        pSrcReal  = (float *)((byte *)pSrc + elemTex1.Offset);
                        pDestReal = (float *)((byte *)pDest + elemTex1.Offset);
                        for (int dim = 0; dim < VertexElement.GetTypeCount(elemTex1.Type); dim++)
                        {
                            *pDestReal++ = *pSrcReal++;
                        }
                    }

                    // Increment source by one vertex
                    pSrc = (void *)((byte *)(pSrc) + vertexSize);
                    // Increment dest by 1 vertex * uStep
                    pDest = (void *)((byte *)(pDest) + (vertexSize * uStep));
                } // u
            }     // v
        }
Beispiel #3
0
        /// <summary>
        ///     Sets up the surface by defining it's control points, type and initial subdivision level.
        /// </summary>
        /// <remarks>
        ///     This method initialises the surface by passing it a set of control points. The type of curves to be used
        ///     are also defined here, although the only supported option currently is a bezier patch. You can also
        ///     specify a global subdivision level here if you like, although it is recommended that the parameter
        ///     is left as AUTO_LEVEL, which means the system decides how much subdivision is required (based on the
        ///     curvature of the surface).
        /// </remarks>
        /// <param name="controlPointArray">
        ///     An array containing the vertex data which define control points of the curves
        ///     rather than actual vertices. Note that you are expected to provide not
        ///     just position information, but potentially normals and texture coordinates too.
        ///     The array is internally treated as a contiguous memory buffer without any gaps between the elements.
        ///     The format of the buffer is defined in the VertexDeclaration parameter.
        /// </param>
        /// <param name="declaration">
        ///     VertexDeclaration describing the contents of the buffer.
        ///     Note this declaration must _only_ draw on buffer source 0!
        /// </param>
        /// <param name="width">Specifies the width of the patch in control points.</param>
        /// <param name="height">Specifies the height of the patch in control points.</param>
        /// <param name="type">The type of surface.</param>
        /// <param name="uMaxSubdivisionLevel">
        ///     If you want to manually set the top level of subdivision,
        ///     do it here, otherwise let the system decide.
        /// </param>
        /// <param name="vMaxSubdivisionLevel">
        ///     If you want to manually set the top level of subdivision,
        ///     do it here, otherwise let the system decide.
        /// </param>
        /// <param name="visibleSide">Determines which side of the patch (or both) triangles are generated for.</param>
        public void DefineSurface(Array controlPointArray, VertexDeclaration declaration, int width, int height,
                                  PatchSurfaceType type, int uMaxSubdivisionLevel, int vMaxSubdivisionLevel,
                                  VisibleSide visibleSide)
        {
            if (height == 0 || width == 0)
            {
                return;                 // Do nothing - garbage
            }

            //pin the input to have a pointer
            Memory.UnpinObject(controlPointArray);
            this.controlPointBuffer = Memory.PinObject(controlPointArray);

            this.type          = type;
            this.controlWidth  = width;
            this.controlHeight = height;
            this.controlCount  = width * height;
            this.declaration   = declaration;

            // Copy positions into Vector3 vector
            this.controlPoints.Clear();
            var elem     = declaration.FindElementBySemantic(VertexElementSemantic.Position);
            var vertSize = declaration.GetVertexSize(0);

#if !AXIOM_SAFE_ONLY
            unsafe
#endif
            {
                var pVert = this.controlPointBuffer;
                for (var i = 0; i < this.controlCount; i++)
                {
                    var pReal = (pVert + ((i * vertSize) + elem.Offset)).ToFloatPointer();
                    this.controlPoints.Add(new Vector3(pReal[0], pReal[1], pReal[2]));
                }
            }
            this.side = visibleSide;

            // Determine max level
            // Initialize to 100% detail
            this.subdivisionFactor = 1.0f;

            if (uMaxSubdivisionLevel == AUTO_LEVEL)
            {
                this.uLevel = this.maxULevel = GetAutoULevel();
            }
            else
            {
                this.uLevel = this.maxULevel = uMaxSubdivisionLevel;
            }

            if (vMaxSubdivisionLevel == AUTO_LEVEL)
            {
                this.vLevel = this.maxVLevel = GetAutoVLevel();
            }
            else
            {
                this.vLevel = this.maxVLevel = vMaxSubdivisionLevel;
            }

            // Derive mesh width / height
            this.meshWidth  = (LevelWidth(this.maxULevel) - 1) * ((this.controlWidth - 1) / 2) + 1;
            this.meshHeight = (LevelWidth(this.maxVLevel) - 1) * ((this.controlHeight - 1) / 2) + 1;

            // Calculate number of required vertices / indexes at max resolution
            this.requiredVertexCount = this.meshWidth * this.meshHeight;
            var iterations = (this.side == VisibleSide.Both) ? 2 : 1;
            this.requiredIndexCount = (this.meshWidth - 1) * (this.meshHeight - 1) * 2 * iterations * 3;

            // Calculate bounds based on control points
            var min         = Vector3.Zero;
            var max         = Vector3.Zero;
            var maxSqRadius = 0.0f;
            var first       = true;

            for (var i = 0; i < this.controlPoints.Count; i++)
            {
                var vec = this.controlPoints[i];
                if (first)
                {
                    min         = max = vec;
                    maxSqRadius = vec.LengthSquared;
                    first       = false;
                }
                else
                {
                    min.Floor(vec);
                    max.Ceil(vec);
                    maxSqRadius = Utility.Max(vec.LengthSquared, maxSqRadius);
                }
            }

            // set the bounds of the patch
            this.aabb.SetExtents(min, max);
            this.boundingSphereRadius = Utility.Sqrt(maxSqRadius);
        }
Beispiel #4
0
        /// <summary>
        ///     Sets up the surface by defining it's control points, type and initial subdivision level.
        /// </summary>
        /// <remarks>
        ///     This method initialises the surface by passing it a set of control points. The type of curves to be used
        ///     are also defined here, although the only supported option currently is a bezier patch. You can also
        ///     specify a global subdivision level here if you like, although it is recommended that the parameter
        ///     is left as AUTO_LEVEL, which means the system decides how much subdivision is required (based on the
        ///     curvature of the surface).
        /// </remarks>
        /// <param name="controlPoints">
        ///     A pointer to a buffer containing the vertex data which defines control points
        ///     of the curves rather than actual vertices. Note that you are expected to provide not
        ///     just position information, but potentially normals and texture coordinates too. The
        ///     format of the buffer is defined in the VertexDeclaration parameter.
        /// </param>
        /// <param name="decl">
        ///     VertexDeclaration describing the contents of the buffer.
        ///     Note this declaration must _only_ draw on buffer source 0!
        /// </param>
        /// <param name="width">Specifies the width of the patch in control points.</param>
        /// <param name="height">Specifies the height of the patch in control points.</param>
        /// <param name="type">The type of surface.</param>
        /// <param name="uMaxSubdivisionLevel">
        ///     If you want to manually set the top level of subdivision,
        ///     do it here, otherwise let the system decide.
        /// </param>
        /// <param name="vMaxSubdivisionLevel">
        ///     If you want to manually set the top level of subdivision,
        ///     do it here, otherwise let the system decide.
        /// </param>
        /// <param name="side">Determines which side of the patch (or both) triangles are generated for.</param>
        public unsafe void DefineSurface(System.Array controlPointBuffer, VertexDeclaration declaration, int width, int height,
                                         PatchSurfaceType type, int uMaxSubdivisionLevel, int vMaxSubdivisionLevel, VisibleSide visibleSide)
        {
            if (height == 0 || width == 0)
            {
                return; // Do nothing - garbage
            }

            this.type               = type;
            this.controlWidth       = width;
            this.controlHeight      = height;
            this.controlCount       = width * height;
            this.controlPointBuffer = controlPointBuffer;
            this.declaration        = declaration;

            // Copy positions into Vector3 vector
            controlPoints.Clear();
            VertexElement elem     = declaration.FindElementBySemantic(VertexElementSemantic.Position);
            int           vertSize = declaration.GetVertexSize(0);
            byte *        pVert    = (byte *)Marshal.UnsafeAddrOfPinnedArrayElement(controlPointBuffer, 0);
            float *       pReal    = null;

            for (int i = 0; i < controlCount; i++)
            {
                pReal = (float *)(pVert + elem.Offset);
                controlPoints.Add(new Vector3(pReal[0], pReal[1], pReal[2]));
                pVert += vertSize;
            }

            this.side = visibleSide;

            // Determine max level
            // Initialise to 100% detail
            subdivisionFactor = 1.0f;

            if (uMaxSubdivisionLevel == AUTO_LEVEL)
            {
                uLevel = maxULevel = GetAutoULevel();
            }
            else
            {
                uLevel = maxULevel = uMaxSubdivisionLevel;
            }

            if (vMaxSubdivisionLevel == AUTO_LEVEL)
            {
                vLevel = maxVLevel = GetAutoVLevel();
            }
            else
            {
                vLevel = maxVLevel = vMaxSubdivisionLevel;
            }

            // Derive mesh width / height
            meshWidth  = (LevelWidth(maxULevel) - 1) * ((controlWidth - 1) / 2) + 1;
            meshHeight = (LevelWidth(maxVLevel) - 1) * ((controlHeight - 1) / 2) + 1;

            // Calculate number of required vertices / indexes at max resolution
            requiredVertexCount = meshWidth * meshHeight;
            int iterations = (side == VisibleSide.Both)? 2 : 1;

            requiredIndexCount = (meshWidth - 1) * (meshHeight - 1) * 2 * iterations * 3;

            // Calculate bounds based on control points
            Vector3 min         = Vector3.Zero;
            Vector3 max         = Vector3.Zero;
            float   maxSqRadius = 0.0f;
            bool    first       = true;

            for (int i = 0; i < controlPoints.Count; i++)
            {
                Vector3 vec = controlPoints[i];
                if (first)
                {
                    min         = max = vec;
                    maxSqRadius = vec.LengthSquared;
                    first       = false;
                }
                else
                {
                    min.Floor(vec);
                    max.Ceil(vec);
                    maxSqRadius = MathUtil.Max(vec.LengthSquared, maxSqRadius);
                }
            }

            // set the bounds of the patch
            aabb.SetExtents(min, max);
            boundingSphereRadius = MathUtil.Sqrt(maxSqRadius);
        }