/// <summary> /// Convienence method for setting the AiString string (and length). /// </summary> /// <param name="data">String data to set</param> /// <returns>True if the operation was successful, false otherwise.</returns> public unsafe bool SetString(String data) { if (String.IsNullOrEmpty(data)) { Length = new UIntPtr(0); fixed(byte *bytePtr = Data) MemoryHelper.ClearMemory(new IntPtr(bytePtr), 0, AiDefines.MAX_LENGTH); return(true); } //Note: aiTypes.h specifies aiString is UTF-8 encoded string. if (Encoding.UTF8.GetByteCount(data) <= AiDefines.MAX_LENGTH) { byte[] copy = Encoding.UTF8.GetBytes(data); //Write bytes to data field if (copy.Length > 0) { fixed(byte *bytePtr = Data) MemoryHelper.Write <byte>(new IntPtr(bytePtr), copy, 0, copy.Length); } Length = new UIntPtr((uint)copy.Length); return(true); } return(false); }
/// <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); }