// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using SharpDX.Collections; namespace SharpDX.Direct3D9 { /// /// Shadow callback for . /// internal class IncludeShadow : CppObjectShadow { private static readonly IncludeVtbl Vtbl = new IncludeVtbl(); private readonly Dictionary frames = new Dictionary(EqualityComparer.DefaultIntPtr); private struct Frame { public Frame(Stream stream, GCHandle handle) { Stream = stream; Handle = handle; } public Stream Stream; public GCHandle Handle; public void Close() { if (Handle.IsAllocated) Handle.Free(); } } /// /// Return a pointer to the unmanaged version of this callback. /// /// The callback. /// A pointer to a shadow c++ callback public static IntPtr ToIntPtr(Include callback) { return ToCallbackPtr(callback); } /// /// Internal Include Callback /// private class IncludeVtbl : CppObjectVtbl { public IncludeVtbl() : base(2) { AddMethod(new OpenDelegate(OpenImpl)); AddMethod(new CloseDelegate(CloseImpl)); } /// /// A user-implemented method for opening and reading the contents of a shader #include file. /// /// This pointer /// A -typed value that indicates the location of the #include file. /// Name of the #include file. /// Pointer to the container that includes the #include file. /// Pointer to the buffer that Open returns that contains the include directives. This pointer remains valid until is called. /// Pointer to the number of bytes that Open returns in ppData. /// The user-implemented method should return S_OK. If Open fails when reading the #include file, the application programming interface (API) that caused Open to be called fails. This failure can occur in one of the following situations:The high-level shader language (HLSL) shader fails one of the D3D10CompileShader*** functions.The effect fails one of the D3D10CreateEffect*** functions. /// HRESULT Open([None] D3D_INCLUDE_TYPE IncludeType,[None] const char* pFileName,[None] LPCVOID pParentData,[None] LPCVOID* ppData,[None] UINT* pBytes) [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate SharpDX.Result OpenDelegate(IntPtr thisPtr, SharpDX.Direct3D9.IncludeType includeType, IntPtr fileNameRef, IntPtr pParentData, ref IntPtr dataRef, ref int bytesRef); private static SharpDX.Result OpenImpl(IntPtr thisPtr, SharpDX.Direct3D9.IncludeType includeType, IntPtr fileNameRef, IntPtr pParentData, ref IntPtr dataRef, ref int bytesRef) { unsafe { try { var shadow = ToShadow(thisPtr); var callback = (Include) shadow.Callback; Stream stream = null; Stream parentStream = null; if (shadow.frames.ContainsKey(pParentData)) parentStream = shadow.frames[pParentData].Stream; stream = callback.Open(includeType, Marshal.PtrToStringAnsi(fileNameRef), parentStream); if (stream == null) return Result.Fail; GCHandle handle; if (stream is DataStream) { // Magic shortcut if we happen to get a DataStream var data = (DataStream)stream; dataRef = data.PositionPointer; bytesRef = (int)(data.Length - data.Position); handle = new GCHandle(); } else { // Read the stream into a byte array and pin it byte[] data = SharpDX.Utilities.ReadStream(stream); handle = GCHandle.Alloc(data, GCHandleType.Pinned); dataRef = handle.AddrOfPinnedObject(); bytesRef = data.Length; } shadow.frames.Add(dataRef, new Frame(stream, handle)); return Result.Ok; } catch (SharpDXException exception) { return exception.ResultCode.Code; } catch (Exception) { return Result.Fail; } } } /// /// A user-implemented method for closing a shader #include file. /// /// /// If was successful, Close is guaranteed to be called before the API using the interface returns. /// /// This pointer /// Pointer to the buffer that contains the include directives. This is the pointer that was returned by the corresponding call. /// The user-implemented Close method should return S_OK. If Close fails when it closes the #include file, the application programming interface (API) that caused Close to be called fails. This failure can occur in one of the following situations:The high-level shader language (HLSL) shader fails one of the D3D10CompileShader*** functions.The effect fails one of the D3D10CreateEffect*** functions. /// HRESULT Close([None] LPCVOID pData) [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate SharpDX.Result CloseDelegate(IntPtr thisPtr, IntPtr pData); private static SharpDX.Result CloseImpl(IntPtr thisPtr, IntPtr pData) { try { var shadow = ToShadow(thisPtr); var callback = (Include)shadow.Callback; Frame frame; if (shadow.frames.TryGetValue(pData, out frame)) { shadow.frames.Remove(pData); callback.Close(frame.Stream); frame.Close(); } return Result.Ok; } catch (SharpDXException exception) { return exception.ResultCode.Code; } catch (Exception) { return Result.Fail; } } } protected override CppObjectVtbl GetVtbl { get { return Vtbl; } } } }