Esempio n. 1
0
        /// <summary>
        /// Writes the managed data to the native value.
        /// </summary>
        /// <param name="thisPtr">Optional pointer to the memory that will hold the native value.</param>
        /// <param name="nativeValue">Output native value</param>
        void IMarshalable <Node, AiNode> .ToNative(IntPtr thisPtr, out AiNode nativeValue)
        {
            nativeValue                = new AiNode(); // --------------------------------
            nativeValue.Name           = new AiString(m_name);
            nativeValue.Transformation = AssimpConv.ConvertTransformToAssimp(m_transform);
            nativeValue.Parent         = IntPtr.Zero;

            nativeValue.NumMeshes = (uint)m_meshes.Count;
            nativeValue.Meshes    = IntPtr.Zero;
#if WITH_NODE_METADATA
            nativeValue.MetaData = IntPtr.Zero;
#endif

            if (nativeValue.NumMeshes > 0)
            {
                nativeValue.Meshes = MemoryHelper.ToNativeArray <int>(m_meshes.ToArray());
            }

            //Now descend through the children
            nativeValue.NumChildren = (uint)m_children.Count;

            int numChildren = (int)nativeValue.NumChildren;
            int stride      = IntPtr.Size;

            IntPtr childrenPtr = IntPtr.Zero;

            if (numChildren > 0)
            {
                childrenPtr = MemoryHelper.AllocateMemory(numChildren * IntPtr.Size);

                for (int i = 0; i < numChildren; i++)
                {
                    IntPtr currPos = MemoryHelper.AddIntPtr(childrenPtr, stride * i);
                    Node   child   = m_children[i];

                    IntPtr childPtr = IntPtr.Zero;

                    //Recursively create the children and its children
                    if (child != null)
                    {
                        childPtr = ToNativeRecursive(thisPtr, child);
                    }

                    //Write the child's node ptr to our array
                    MemoryHelper.Write <IntPtr>(currPos, ref childPtr);
                }
            }

            //Finally finish writing to the native struct
            nativeValue.Children = childrenPtr;
        }
Esempio n. 2
0
        /// <summary>
        /// Writes DDS formatted data to a stream. Image data is expected to be DXGI-compliant data, but an effort is made to write out D3D9-compatible headers when possible.
        /// </summary>
        /// <param name="output">Output stream.</param>
        /// <param name="mipChains">Mipmap chains to write. Each mipmap chain represents a single face (so > 1 represents an array texture or a Cubemap). All faces must have
        /// equivalent dimensions and each chain must have the same number of mipmaps.</param>
        /// <param name="format">DXGI format the image data is stored as.</param>
        /// <param name="texDim">Dimension of the texture to write.</param>
        /// <param name="flags">Flags to control how the DDS data is saved.</param>
        /// <returns>True if writing the data was successful, false if otherwise.</returns>
        public static bool Write(Stream output, List <MipChain> mipChains, DXGIFormat format, TextureDimension texDim, DDSFlags flags = DDSFlags.None)
        {
            if (output == null || !output.CanWrite || mipChains == null || mipChains.Count == 0 || mipChains[0].Count == 0 || format == DXGIFormat.Unknown)
            {
                return(false);
            }

            //Extract details
            int     width, height, depth, arrayCount, mipCount;
            MipData firstMip = mipChains[0][0];

            width      = firstMip.Width;
            height     = firstMip.Height;
            depth      = firstMip.Depth;
            arrayCount = mipChains.Count;
            mipCount   = mipChains[0].Count;

            if (!ValidateInternal(mipChains, format, texDim))
            {
                return(false);
            }

            //Setup a transfer buffer
            StreamTransferBuffer buffer = new StreamTransferBuffer(firstMip.RowPitch, false);

            //Write out header
            if (!WriteHeader(output, buffer, texDim, format, width, height, depth, arrayCount, mipCount, flags))
            {
                return(false);
            }

            //Iterate over each array face...
            for (int i = 0; i < arrayCount; i++)
            {
                MipChain mipChain = mipChains[i];

                //Iterate over each mip face...
                for (int mipLevel = 0; mipLevel < mipCount; mipLevel++)
                {
                    MipData mip = mipChain[mipLevel];

                    //Compute pitch, based on MSDN programming guide. We will write out these pitches rather than the supplied in order to conform to the recomendation
                    //that we compute pitch based on format
                    int realMipWidth, realMipHeight, dstRowPitch, dstSlicePitch, bytesPerPixel;
                    ImageHelper.ComputePitch(format, mip.Width, mip.Height, out dstRowPitch, out dstSlicePitch, out realMipWidth, out realMipHeight, out bytesPerPixel);

                    //Ensure write buffer is sufficiently sized for a single scanline
                    if (buffer.Length < dstRowPitch)
                    {
                        buffer.Resize(dstRowPitch, false);
                    }

                    //Sanity check
                    if (dstRowPitch < mip.RowPitch)
                    {
                        return(false);
                    }

                    IntPtr srcPtr = mip.Data;

                    //Advance stream one slice at a time...
                    for (int slice = 0; slice < mip.Depth; slice++)
                    {
                        int    bytesToWrite = dstSlicePitch;
                        IntPtr sPtr         = srcPtr;

                        //Copy scanline into temp buffer, write to output
                        for (int row = 0; row < realMipHeight; row++)
                        {
                            MemoryHelper.CopyMemory(buffer.Pointer, sPtr, dstRowPitch);
                            buffer.WriteBytes(output, dstRowPitch);
                            bytesToWrite -= dstRowPitch;

                            //Advance to next scanline in source data
                            sPtr = MemoryHelper.AddIntPtr(sPtr, mip.RowPitch);
                        }

                        //Pad slice if necessary
                        if (bytesToWrite > 0)
                        {
                            MemoryHelper.ClearMemory(buffer.Pointer, 0, bytesToWrite);
                            buffer.WriteBytes(output, bytesToWrite);
                        }

                        //Advance source pointer to next slice
                        srcPtr = MemoryHelper.AddIntPtr(srcPtr, mip.SlicePitch);
                    }
                }
            }

            return(true);
        }
Esempio n. 3
0
        private IntPtr ToNativeRecursive(IntPtr parentPtr, Node node)
        {
            if (node == null)
            {
                return(IntPtr.Zero);
            }

            int sizeofNative = MemoryHelper.SizeOf <AiNode>();

            //Allocate the memory that will hold the node
            IntPtr nodePtr = MemoryHelper.AllocateMemory(sizeofNative);

            //First fill the native struct
            AiNode nativeValue = new AiNode();

            nativeValue.Name           = new AiString(node.m_name);
            nativeValue.Transformation = AssimpConv.ConvertTransformToAssimp(node.m_transform);
            nativeValue.Parent         = parentPtr;

            nativeValue.NumMeshes = (uint)node.m_meshes.Count;
            nativeValue.Meshes    = MemoryHelper.ToNativeArray <int>(node.m_meshes.ToArray());
#if WITH_NODE_METADATA
            nativeValue.MetaData = IntPtr.Zero;
#endif

            //Now descend through the children
            nativeValue.NumChildren = (uint)node.m_children.Count;

            int numChildren = (int)nativeValue.NumChildren;
            int stride      = IntPtr.Size;

            IntPtr childrenPtr = IntPtr.Zero;

            if (numChildren > 0)
            {
                childrenPtr = MemoryHelper.AllocateMemory(numChildren * IntPtr.Size);

                for (int i = 0; i < numChildren; i++)
                {
                    IntPtr currPos = MemoryHelper.AddIntPtr(childrenPtr, stride * i);
                    Node   child   = node.m_children[i];

                    IntPtr childPtr = IntPtr.Zero;

                    //Recursively create the children and its children
                    if (child != null)
                    {
                        childPtr = ToNativeRecursive(nodePtr, child);
                    }

                    //Write the child's node ptr to our array
                    MemoryHelper.Write <IntPtr>(currPos, ref childPtr);
                }
            }

            //Finall finish writing to the native struct, and write the whole thing to the memory we allocated previously
            nativeValue.Children = childrenPtr;

            MemoryHelper.Write <AiNode>(nodePtr, ref nativeValue);

            return(nodePtr);
        }
Esempio n. 4
0
        /// <summary>
        /// Reads DDS formatted data from a stream. Image data is always returned as DXGI-Compliant
        /// format, therefore some old legacy formats will automatically be converted.
        /// </summary>
        /// <param name="input">Input stream.</param>
        /// <param name="flags">Flags to control how the DDS data is loaded.</param>
        /// <returns>Loaded image data, or null if the data failed to load.</returns>
        public static DDSContainer Read(Stream input, DDSFlags flags = DDSFlags.None)
        {
            StreamTransferBuffer buffer = new StreamTransferBuffer();

            Header   header;
            Header10?headerExt;

            //Reads + validates header(s)
            if (!ReadHeader(input, buffer, out header, out headerExt))
            {
                return(null);
            }

            //Gather up metadata
            List <MipChain>  mipChains   = null;
            DXGIFormat       format      = DXGIFormat.Unknown;
            TextureDimension texDim      = TextureDimension.Two;
            ConversionFlags  convFlags   = ConversionFlags.None;
            bool             legacyDword = (flags & DDSFlags.LegacyDword) == DDSFlags.LegacyDword ? true : false;

            int width      = Math.Max((int)header.Width, 1);
            int height     = Math.Max((int)header.Height, 1);
            int depth      = Math.Max((int)header.Depth, 1);
            int mipCount   = (int)header.MipMapCount;
            int arrayCount = 1;

            //Has extended header, a modern DDS
            if (headerExt.HasValue)
            {
                Header10 extendedHeader = headerExt.Value;
                arrayCount = (int)extendedHeader.ArraySize;
                format     = extendedHeader.Format;

                switch (extendedHeader.ResourceDimension)
                {
                case D3D10ResourceDimension.Texture1D:
                {
                    texDim = TextureDimension.One;

                    if (height > 1 || depth > 1)
                    {
                        return(null);
                    }
                }
                break;

                case D3D10ResourceDimension.Texture2D:
                {
                    if ((extendedHeader.MiscFlags & Header10Flags.TextureCube) == Header10Flags.TextureCube)
                    {
                        //Specifies # of cubemaps, so to get total # of faces must multiple by 6
                        arrayCount *= 6;

                        texDim = TextureDimension.Cube;
                    }
                    else
                    {
                        texDim = TextureDimension.Two;
                    }

                    if (depth > 1)
                    {
                        return(null);
                    }
                }
                break;

                case D3D10ResourceDimension.Texture3D:
                {
                    texDim = TextureDimension.Three;

                    if (arrayCount > 1 || (header.Caps2 & HeaderCaps2.Volume) != HeaderCaps2.Volume)
                    {
                        return(null);
                    }
                }
                break;
                }
            }
            else
            {
                //Otherwise, read legacy DDS and possibly convert data

                //Check volume flag
                if ((header.Caps2 & HeaderCaps2.Volume) == HeaderCaps2.Volume)
                {
                    texDim = TextureDimension.Three;
                }
                else
                {
                    //legacy DDS could not express 1D textures, so either a cubemap or a 2D non-array texture

                    if ((header.Caps2 & HeaderCaps2.Cubemap) == HeaderCaps2.Cubemap)
                    {
                        //Must have all six faces. DirectX 8 and above always would write out all 6 faces
                        if ((header.Caps2 & HeaderCaps2.Cubemap_AllFaces) != HeaderCaps2.Cubemap_AllFaces)
                        {
                            return(null);
                        }

                        arrayCount = 6;
                        texDim     = TextureDimension.Cube;
                    }
                    else
                    {
                        texDim = TextureDimension.Two;
                    }
                }

                format = FormatConverter.DetermineDXGIFormat(header.PixelFormat, flags, out convFlags);
            }

            //Modify conversion flags, if necessary
            FormatConverter.ModifyConversionFormat(ref format, ref convFlags, flags);

            //If palette image, the palette will be the first thing
            int[] palette = null;
            if (FormatConverter.HasConversionFlag(convFlags, ConversionFlags.Pal8))
            {
                palette = new int[256];
                int palSize = palette.Length * sizeof(int);
                buffer.ReadBytes(input, palSize);

                if (buffer.LastReadByteCount != palSize)
                {
                    return(null);
                }

                MemoryHelper.CopyBytes <int>(buffer.ByteArray, 0, palette, 0, palette.Length);
            }

            //Now read data based on available mip/arrays
            mipChains = new List <MipChain>(arrayCount);

            byte[] scanline     = buffer.ByteArray;
            IntPtr scanlinePtr  = buffer.Pointer;
            bool   noPadding    = (flags & DDSFlags.NoPadding) == DDSFlags.NoPadding ? true : false;
            bool   isCompressed = FormatConverter.IsCompressed(format);
            bool   errored      = false;

            try
            {
                //Iterate over each array face...
                for (int i = 0; i < arrayCount; i++)
                {
                    MipChain mipChain = new MipChain(mipCount);
                    mipChains.Add(mipChain);

                    //Iterate over each mip face...
                    for (int mipLevel = 0; mipLevel < mipCount; mipLevel++)
                    {
                        //Calculate mip dimensions
                        int mipWidth  = width;
                        int mipHeight = height;
                        int mipDepth  = depth;
                        ImageHelper.CalculateMipmapLevelDimensions(mipLevel, ref mipWidth, ref mipHeight, ref mipDepth);

                        //Compute pitch, based on MSDN programming guide which says PitchOrLinearSize is unreliable and to calculate based on format.
                        //"real" mip width/height is the given mip width/height for all non-compressed, compressed images it will be smaller since each block
                        //is a 4x4 region of pixels.
                        int realMipWidth, realMipHeight, dstRowPitch, dstSlicePitch, bytesPerPixel;
                        ImageHelper.ComputePitch(format, mipWidth, mipHeight, out dstRowPitch, out dstSlicePitch, out realMipWidth, out realMipHeight, out bytesPerPixel, legacyDword);

                        int srcRowPitch   = dstRowPitch;
                        int srcSlicePitch = dstSlicePitch;

                        //Are we converting from a legacy format, possibly?
                        if (!headerExt.HasValue)
                        {
                            int legacySize = FormatConverter.LegacyFormatBitsPerPixelFromConversionFlag(convFlags);
                            if (legacySize != 0)
                            {
                                srcRowPitch   = (realMipWidth * legacySize + 7) / 8;
                                srcSlicePitch = srcRowPitch * realMipHeight;
                            }
                        }

                        //If output data is requested not to have padding, recompute destination pitches
                        if (noPadding)
                        {
                            dstRowPitch   = bytesPerPixel * realMipWidth;
                            dstSlicePitch = dstRowPitch * realMipHeight;
                        }

                        //Setup memory to hold the loaded image
                        MipData mipSurface = new MipData(mipWidth, mipHeight, mipDepth, dstRowPitch, dstSlicePitch);
                        mipChain.Add(mipSurface);

                        //Ensure read buffer is sufficiently sized for a single scanline
                        if (buffer.Length < srcRowPitch)
                        {
                            buffer.Resize(srcRowPitch, false);
                        }

                        IntPtr dstPtr = mipSurface.Data;

                        //Advance stream one slice at a time...
                        for (int slice = 0; slice < mipDepth; slice++)
                        {
                            long   slicePos = input.Position;
                            IntPtr dPtr     = dstPtr;

                            //Copy scanline into temp buffer, do any conversions, copy to output
                            for (int row = 0; row < realMipHeight; row++)
                            {
                                int numBytesRead = input.Read(scanline, 0, srcRowPitch);
                                if (numBytesRead != srcRowPitch)
                                {
                                    errored = true;
                                    System.Diagnostics.Debug.Assert(false);
                                    return(null);
                                }

                                //Copy scanline, optionally convert data
                                FormatConverter.CopyScanline(dPtr, dstRowPitch, scanlinePtr, srcRowPitch, format, convFlags, palette);

                                //Increment dest pointer to next row
                                dPtr = MemoryHelper.AddIntPtr(dPtr, dstRowPitch);
                            }

                            //Advance stream and destination pointer to the next slice
                            input.Position = slicePos + srcSlicePitch;
                            dstPtr         = MemoryHelper.AddIntPtr(dstPtr, dstSlicePitch);
                        }
                    }
                }
            }
            finally
            {
                //If errored, clean up any mip surfaces we allocated...no null entries should have been made either
                if (errored)
                {
                    DisposeMipChains(mipChains);
                }
            }

            if (!ValidateInternal(mipChains, format, texDim))
            {
                System.Diagnostics.Debug.Assert(false);
                return(null);
            }

            return(new DDSContainer(mipChains, format, texDim));
        }