/// <summary> /// Initializes a new instance of the <see cref="GorgonInputLayout"/> class. /// </summary> /// <param name="graphics">The video adapter interface used to create this input layout.</param> /// <param name="name">Name of the object.</param> /// <param name="shader">Vertex shader to bind the layout with.</param> /// <param name="elements">The input elements to assign to this layout.</param> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="name"/>, <paramref name="graphics"/>, <paramref name="shader"/>, or the <paramref name="elements"/> parameter is <b>null</b>.</exception> /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="name"/>, or the <paramref name="elements"/> parameter is empty.</exception> /// <exception cref="ArgumentException">Thrown when an element with the same context, slot and index appears more than once in the <paramref name="elements"/> parameter.</exception> public GorgonInputLayout(GorgonGraphics graphics, string name, GorgonVertexShader shader, IEnumerable <GorgonInputElement> elements) { if (name == null) { throw new ArgumentNullException(nameof(name)); } if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentEmptyException(nameof(name)); } Name = name; // Make a copy so we don't allow changing of the original reference. _elements = elements?.ToArray() ?? throw new ArgumentNullException(nameof(elements)); if (_elements.Length == 0) { throw new ArgumentEmptyException(nameof(elements)); } _slotSizes = new Dictionary <int, int>(); // Check for duplicated elements. for (int i = 0; i < _elements.Length; ++i) { FindDuplicateElements(_elements, _elements[i], i, nameof(elements)); } Graphics = graphics ?? throw new ArgumentNullException(nameof(graphics)); Shader = shader ?? throw new ArgumentNullException(nameof(shader)); UpdateVertexSize(); BuildD3DLayout(); this.RegisterDisposable(graphics); }
/// <summary> /// Function to build an input layout using the fields from a value type. /// </summary> /// <typeparam name="T">The type to evaluate. This must be an unmanaged value type.</typeparam> /// <param name="graphics">The graphics interface used to create the input layout.</param> /// <param name="shader">Vertex shader to bind the layout with.</param> /// <returns>A new <see cref="GorgonInputLayout"/> for the type passed to <typeparamref name="T"/>.</returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="graphics"/>, or the <paramref name="shader"/> parameter is <b>null</b>.</exception> /// <exception cref="ArgumentException">Thrown when an element with the same context, slot and index appears more than once in the members of the <typeparamref name="T"/> type.</exception> /// <exception cref="GorgonException">Thrown when the type specified by <typeparamref name="T"/> is not safe for use with native functions (see <see cref="GorgonReflectionExtensions.IsFieldSafeForNative"/>). /// <para>-or-</para> /// <para>Thrown when the type specified by <typeparamref name="T"/> does not contain any public members.</para> /// <para>-or-</para> /// <para>Thrown if the type specified by <typeparamref name="T"/> does not have a <see cref="LayoutKind"/> of <see cref="LayoutKind.Sequential"/> or <see cref="LayoutKind.Explicit"/>.</para> /// </exception> /// <remarks> /// <para> /// This will build a new <see cref="GorgonInputLayout"/> using the fields within a value type (<c>struct</c>). Each of the members that are to be included in the layout must be decorated with a /// <see cref="InputElementAttribute"/>. If a member is not decorated with this attribute, then it will be ignored. /// </para> /// <para> /// The type parameter <typeparamref name="T"/> must be an unmanaged value type (<c>struct</c>), reference types are not supported. The members of the type must also be public fields. Properties are not /// supported. Futhermore, the struct must be decorated with a <see cref="StructLayoutAttribute"/> that defines a <see cref="LayoutKind"/> of <see cref="LayoutKind.Sequential"/> or /// <see cref="LayoutKind.Explicit"/>. This is necessary to ensure that the member of the value type are in the correct order when writing to a <see cref="GorgonVertexBuffer"/> or when /// generating a <see cref="GorgonInputLayout"/> from a type. /// </para> /// <para> /// If the type specified by <typeparamref name="T"/> has members that are not primitive types or value types with a <see cref="StructLayoutAttribute"/>, or the member has a /// <see cref="MarshalAsAttribute"/>, then an exception is thrown. Gorgon does not support marshalling of complex types for vertices. /// </para> /// <para> /// The types of the fields must be one of the following types: /// <para> /// <list type="bullet"> /// <item> /// <description><see cref="byte"/></description> /// </item> /// <item> /// <description><see cref="sbyte"/></description> /// </item> /// <item> /// <description><see cref="short"/></description> /// </item> /// <item> /// <description><see cref="ushort"/></description> /// </item> /// <item> /// <description><see cref="int"/></description> /// </item> /// <item> /// <description><see cref="uint"/></description> /// </item> /// <item> /// <description><see cref="long"/></description> /// </item> /// <item> /// <description><see cref="ulong"/></description> /// </item> /// <item> /// <description><see cref="float"/></description> /// </item> /// <item> /// <description><c>Vector2</c></description> /// </item> /// <item> /// <description><c>Vector3</c></description> /// </item> /// <item> /// <description><c>Vector4</c></description> /// </item> /// <item> /// <description><see cref="GorgonColor"/></description> /// </item> /// </list> /// </para> /// If the type of the member does not match, an exception will be thrown. /// </para> /// </remarks> /// <seealso cref="GorgonReflectionExtensions.IsFieldSafeForNative"/> public static GorgonInputLayout CreateUsingType <T>(GorgonGraphics graphics, GorgonVertexShader shader) where T : unmanaged => CreateUsingType(graphics, typeof(T), shader);
/// <summary> /// Function to build an input layout using the fields from a value type. /// </summary> /// <param name="graphics">The graphics interface used to create the input layout.</param> /// <param name="type">The type to evaluate.</param> /// <param name="shader">Vertex shader to bind the layout with.</param> /// <returns>A new <see cref="GorgonInputLayout"/> for the type passed to <paramref name="type"/>.</returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="graphics"/>, <paramref name="type"/> or the <paramref name="shader"/> parameter is <b>null</b>.</exception> /// <exception cref="ArgumentException">Thrown when an element with the same context, slot and index appears more than once in the members of the <paramref name="type"/>. /// <para>-or-</para> /// <para>Thrown if the <paramref name="type"/> does not have a <see cref="LayoutKind"/> of <see cref="LayoutKind.Sequential"/> or <see cref="LayoutKind.Explicit"/>.</para> /// </exception> /// <exception cref="GorgonException">Thrown when the type specified by <paramref name="type"/> is not safe for use with native functions (see <see cref="GorgonReflectionExtensions.IsFieldSafeForNative"/>). /// <para>-or-</para> /// <para>Thrown when the type specified by <paramref name="type"/> does not contain any public members.</para> /// </exception> /// <remarks> /// <para> /// This will build a new <see cref="GorgonInputLayout"/> using the fields within a value type (<c>struct</c>). Each of the members that are to be included in the layout must be decorated with a /// <see cref="InputElementAttribute"/>. If a member is not decorated with this attribute, then it will be ignored. /// </para> /// <para> /// The <paramref name="type"/> parameter must be an unmanaged value type (<c>struct</c>), reference types are not supported. The members of the type must also be public fields. Properties are not /// supported. Futhermore, the struct must be decorated with a <see cref="StructLayoutAttribute"/> that defines a <see cref="LayoutKind"/> of <see cref="LayoutKind.Sequential"/> or /// <see cref="LayoutKind.Explicit"/>. This is necessary to ensure that the member of the value type are in the correct order when writing to a <see cref="GorgonVertexBuffer"/> or when /// generating a <see cref="GorgonInputLayout"/> from a type. /// </para> /// <para> /// If the type specified by <paramref name="type"/> has members that are not primitive types or value types with a <see cref="StructLayoutAttribute"/>, or the member has a /// <see cref="MarshalAsAttribute"/>, then an exception is thrown. Gorgon does not support marshalling of complex types for vertices. /// </para> /// <para> /// The types of the fields must be one of the following types: /// <para> /// <list type="bullet"> /// <item> /// <description><see cref="byte"/></description> /// </item> /// <item> /// <description><see cref="sbyte"/></description> /// </item> /// <item> /// <description><see cref="short"/></description> /// </item> /// <item> /// <description><see cref="ushort"/></description> /// </item> /// <item> /// <description><see cref="int"/></description> /// </item> /// <item> /// <description><see cref="uint"/></description> /// </item> /// <item> /// <description><see cref="long"/></description> /// </item> /// <item> /// <description><see cref="ulong"/></description> /// </item> /// <item> /// <description><see cref="float"/></description> /// </item> /// <item> /// <description><c>Vector2</c></description> /// </item> /// <item> /// <description><c>Vector3</c></description> /// </item> /// <item> /// <description><c>Vector4</c></description> /// </item> /// <item> /// <description><see cref="GorgonColor"/></description> /// </item> /// </list> /// </para> /// If the type of the member does not match, an exception will be thrown. /// </para> /// </remarks> /// <seealso cref="GorgonReflectionExtensions.IsFieldSafeForNative"/> public static GorgonInputLayout CreateUsingType(GorgonGraphics graphics, Type type, GorgonVertexShader shader) { if (graphics == null) { throw new ArgumentNullException(nameof(graphics)); } if (type == null) { throw new ArgumentNullException(nameof(type)); } if ((type.IsAutoLayout) || ((!type.IsLayoutSequential) && (!type.IsExplicitLayout))) { throw new ArgumentException(string.Format(Resources.GORGFX_ERR_LAYOUT_NOT_SEQUENTIAL_EXPLICIT, type.FullName)); } if (shader == null) { throw new ArgumentNullException(nameof(shader)); } int byteOffset = 0; List <(FieldInfo Field, InputElementAttribute InputElement)> members = GetFieldInfoList(type); if (members.Count == 0) { throw new GorgonException(GorgonResult.CannotCreate, string.Format(Resources.GORGFX_ERR_VERTEX_NO_FIELDS, type.FullName)); } var elements = new GorgonInputElement[members.Count]; for (int i = 0; i < elements.Length; i++) { (FieldInfo Field, InputElementAttribute InputElement) = members[i]; BufferFormat format = InputElement.Format; string contextName = InputElement.Context; // Try to determine the format from the type. if ((format == BufferFormat.Unknown) && (!_typeMapping.TryGetValue(Field.FieldType, out format))) { throw new GorgonException(GorgonResult.CannotCreate, string.Format(Resources.GORGFX_ERR_LAYOUT_INVALID_ELEMENT_TYPE, Field.FieldType.FullName)); } var element = new GorgonInputElement(contextName, format, (InputElement.AutoOffset ? byteOffset : InputElement.Offset), InputElement.Index, InputElement.Slot, InputElement.Instanced, InputElement.Instanced ? InputElement.InstanceCount : 0); FindDuplicateElements(elements, element, i, nameof(element)); elements[i] = element; byteOffset += element.SizeInBytes; } return(new GorgonInputLayout(graphics, type.Name, shader, elements)); }
/// <summary> /// Function to set the current vertex shader on the pipeline. /// </summary> /// <param name="vertexShader">The vertex shader to assign.</param> /// <returns>The fluent interface for this builder.</returns> public GorgonPipelineStateBuilder VertexShader(GorgonVertexShader vertexShader) { _workState.VertexShader = vertexShader; return(this); }