using System;
using System.CodeDom;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using WolvenKit.CR2W.Types;

namespace WolvenKit.CR2W.SRT
{
    [StructLayout(LayoutKind.Explicit, Size = 12)]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public struct Vec3
    {
        [FieldOffset(0)]
        private float x1;
        [FieldOffset(4)]
        private float y1;
        [FieldOffset(8)]
        private float z1;

        public float x { get => x1; set => x1 = value; }
        public float y { get => y1; set => y1 = value; }
        public float z { get => z1; set => z1 = value; }

        public override string ToString() => $"[{x},{y},{z}]";
    }





    ///////////////////////////////////////////////////////////////////////  
    //  Structure SCollisionObject
    //
    //	There are two collision object types: sphere and capsules; m_vCenter1 and
    //	m_vCenter2 will be equal for spheres.
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public struct SCollisionObject
    {
        private string pUserString;
        private Vec3 vCenter1;
        private Vec3 vCenter2;
        private float fRadius;

        public string m_pUserString { get => pUserString; set => pUserString = value; }               // any data entered by the artist in the Modeler app
        public Vec3 m_vCenter1 { get => vCenter1; set => vCenter1 = value; }                     // center of sphere or one end of a capsule
        public Vec3 m_vCenter2 { get => vCenter2; set => vCenter2 = value; }                     // other end of capsule or same as m_vCenter1 if sphere
        public float m_fRadius { get => fRadius; set => fRadius = value; }                   // radius of the sphere or capsule

        public override string ToString() => pUserString;
    }

    ///////////////////////////////////////////////////////////////////////  
    //  Structure SVerticalBillboards
    //
    //	All of the data needed to house 360-degree billboard cutouts as 
    //	generated by the Compiler app.
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public struct SVerticalBillboards
	{

		float m_fWidth;                // width of the billboard, governed by tree extents		
		float m_fTopPos;               // top-most point of the billboard, governed by tree height
		float m_fBottomPos;            // bottom-most point, can be below zero for trees with roots, etc.
		int m_nNumBillboards;      // number of 360-degree billboards generated by Compiler app

        float[] m_pTexCoords;         // 4 entries per image (left u, bottom v, width u, height v)
		byte[] m_pRotated;              // one entry per image, 1 = rotated, 0 = standard

		// the Compiler app can generate non-rectangular cutouts, reducing the fill requirements at the
		// cost of added vertices; these vertices are 
		int m_nNumCutoutVertices;
        float[] m_pCutoutVertices;        // # elements = 2 * m_nNumCutoutVertices [ (x,y) pairs ];
													// [x,y] values are range [0,1] as percent across height & width

		int m_nNumCutoutIndices;
        ushort[] m_pCutoutIndices;      // # elements = m_nNumCutoutIndices, indexed triangles

        #region Properties
        public float FWidth { get => m_fWidth; set => m_fWidth = value; }
        public float FTopPos { get => m_fTopPos; set => m_fTopPos = value; }
        public float FBottomPos { get => m_fBottomPos; set => m_fBottomPos = value; }
        public int NNumBillboards { get => m_nNumBillboards; set => m_nNumBillboards = value; }

        public float[] PTexCoords { get => m_pTexCoords; set => m_pTexCoords = value; }
        public byte[] PRotated { get => m_pRotated; set => m_pRotated = value; }
        public int NNumCutoutVertices { get => m_nNumCutoutVertices; set => m_nNumCutoutVertices = value; }
        public float[] PCutoutVertices { get => m_pCutoutVertices; set => m_pCutoutVertices = value; }
        public int NNumCutoutIndices { get => m_nNumCutoutIndices; set => m_nNumCutoutIndices = value; }
        public ushort[] PCutoutIndices { get => m_pCutoutIndices; set => m_pCutoutIndices = value; }
        #endregion
    }

    ///////////////////////////////////////////////////////////////////////  
    //  Structure SHorizontalBillboard
    //
    //	Housing for the much-simpler horizontal billboard (no cutouts or
    //	multiple views used)
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public struct SHorizontalBillboard
	{
        bool m_bPresent;                 // true if an overhead billboard was exported using Compiler
        Vec3[] m_avPositions;          // four sets of (xyz) to render the overhead square
        float[] m_afTexCoords;            // 4 * (s,t) pairs of diffuse/normal texcoords

        public bool BPresent { get => m_bPresent; set => m_bPresent = value; }
        public Vec3[] AvPositions { get => m_avPositions; set => m_avPositions = value; }
        public float[] AfTexCoords { get => m_afTexCoords; set => m_afTexCoords = value; }
    }

    ///////////////////////////////////////////////////////////////////////  
    //  Enumeration ERenderPass
    //
    //	Three main render passes are supported by the SDK by default:
    //
    //		- Main (forward rendering lit, or deferred MRT)
    //		- Depth-only prepass
    //		- Shadow cast

    public enum ERenderPass
    {
        RENDER_PASS_MAIN,
        RENDER_PASS_DEPTH_PREPASS,
        RENDER_PASS_SHADOW_CAST,
        RENDER_PASS_COUNT
    }

    [TypeConverter(typeof(ExpandableObjectConverter))]
    public class SGeometry
    {
        public int NNum3dRenderStates { get; set; }
        public bool BDepthOnlyIncluded { get; set; }
        public bool BShadowCastIncluded { get; set; }
        public string StrShaderPath { get; set; }
        public SRenderState[] P3dRenderStateMain { get; set; }
        public SRenderState[] P3dRenderStateDepth { get; set; }
        public SRenderState[] P3dRenderStateShadow { get; set; }
        public SRenderState ABillboardRenderStateMain { get; set; }
        public SRenderState ABillboardRenderStateDepth { get; set; }
        public SRenderState ABillboardRenderStateShadow { get; set; }
        public int NNumLods { get; set; }
        public SLod[] PLods { get; set; }
        public SVerticalBillboards SVertBBs { get; set; }
        public SHorizontalBillboard SHorzBB { get; set; }

        public override string ToString() => $"{StrShaderPath}";
    }

    ///////////////////////////////////////////////////////////////////////  
    //  Structure SLod
    //[StructLayout(LayoutKind.Explicit, Size = 24, Pack = 1)]
    //public struct SLod
    //   {
    //       [FieldOffset(0)] int m_nNumDrawCalls;
    //       [FieldOffset(4)] CPaddedPtr<SDrawCall> m_pDrawCalls;   // typecast to SDrawCall*

    //       [FieldOffset(12)] int m_nNumBones;
    //       [FieldOffset(16)] CPaddedPtr<SBone> m_pBones;       // typecast to SBone*

    //       public int NNumDrawCalls { get => m_nNumDrawCalls; set => m_nNumDrawCalls = value; }
    //       public CPaddedPtr<SDrawCall> PDrawCalls { get => m_pDrawCalls; set => m_pDrawCalls = value; }
    //       public int NNumBones { get => m_nNumBones; set => m_nNumBones = value; }
    //       public CPaddedPtr<SBone> PBones { get => m_pBones; set => m_pBones = value; }
    //   }

    [TypeConverter(typeof(ExpandableObjectConverter))]
    public class SLod
    {
        public int NNumDrawCalls { get; set; }
        public SDrawCall[] PDrawCalls { get; set; }
        public int NNumBones { get; set; }
        public SBone[] PBones { get; set; }
    }

    ///////////////////////////////////////////////////////////////////////  
    //  Structure SDrawCall

    // structure is serialized in Parser.cpp
    //   [StructLayout(LayoutKind.Explicit, Size = 40, Pack = 1)]
    //public struct SDrawCall
    //{
    //       // render state
    //       [FieldOffset(0)] CPaddedPtr<SRenderState> m_pRenderState;      // typecast to SRenderState*
    //       [FieldOffset(8)] int m_nRenderStateIndex;

    //       // vertices
    //       [FieldOffset(12)] int m_nNumVertices;
    //       [FieldOffset(16)] CPaddedPtr<byte> m_pVertexData;       // mixed types, but can typecast to st_byte*

    //       // indices
    //       [FieldOffset(24)] int m_nNumIndices;
    //       [FieldOffset(28)] bool m_b32BitIndices;
    //       [FieldOffset(32)] CPaddedPtr<byte> m_pIndexData;       // can typecast to st_byte*, then to st_uint32* or st_uint16*,  // depending on m_b32BitIndices

    //	public CPaddedPtr<SRenderState> PRenderState { get => m_pRenderState; set => m_pRenderState = value; }
    //       public int NRenderStateIndex { get => m_nRenderStateIndex; set => m_nRenderStateIndex = value; }
    //       public int NNumVertices { get => m_nNumVertices; set => m_nNumVertices = value; }
    //       public CPaddedPtr<byte> PVertexData { get => m_pVertexData; set => m_pVertexData = value; }
    //       public int NNumIndices { get => m_nNumIndices; set => m_nNumIndices = value; }
    //       public bool B32BitIndices { get => m_b32BitIndices; set => m_b32BitIndices = value; }
    //       public CPaddedPtr<byte> PIndexData { get => m_pIndexData; set => m_pIndexData = value; }

    //   };

    public class SVertexProperty
    {
        public EVertexProperty PropertyName { get; set; }
        public EVertexFormat PropertyFormat { get; set; }
        public bool UseFloatValuesForBytes { get; set; }
        public int ValueCount => ValueOffsets.Count;
        public List<float> FloatValues { get; set; }
        public List<byte> ByteValues { get; set; }
        public List<sbyte> ValueOffsets { get; set; }
        public SVertexProperty() {
            PropertyFormat = EVertexFormat.VERTEX_FORMAT_UNASSIGNED;
            UseFloatValuesForBytes = false;
            ValueOffsets = new List<sbyte>();

            FloatValues = new List<float>();
            ByteValues = new List<byte>();
        }
    }

    public class SVertex
    {
        public SVertexProperty[] VertexProperties { get; set; }
        public SVertex()
        {
            VertexProperties = new SVertexProperty[(int)EVertexProperty.VERTEX_PROPERTY_COUNT + 1];
            for (int i = 0; i < VertexProperties.Length; ++i)
            {
                VertexProperties[i] = new SVertexProperty();
                VertexProperties[i].PropertyName = (EVertexProperty)i;
                switch ((EVertexProperty)i)
                {
                    case EVertexProperty.VERTEX_PROPERTY_TANGENT:
                    case EVertexProperty.VERTEX_PROPERTY_NORMAL:
                        VertexProperties[i].UseFloatValuesForBytes = true;
                        break;
                    default:
                        break;
                }
            }
        }
        public void SetValue(int propIndex, int valueIndex, sbyte valueOffset, EVertexFormat valueFormat)
        {
            if (VertexProperties[propIndex].PropertyFormat != EVertexFormat.VERTEX_FORMAT_UNASSIGNED && VertexProperties[propIndex].PropertyFormat != valueFormat)
            {
                throw new Exception($"Incorrect format! [{((EVertexProperty)propIndex).ToString()}] Old type: {VertexProperties[propIndex].PropertyFormat}, new type: {valueFormat}.");
            }
            VertexProperties[propIndex].PropertyFormat = valueFormat;
            // kinda resize
            while (VertexProperties[propIndex].ValueOffsets.Count() < valueIndex + 1)
                VertexProperties[propIndex].ValueOffsets.Add(-1);
            VertexProperties[propIndex].ValueOffsets[valueIndex] = valueOffset;
        }
        public void SetFloatValue(int propIndex, int valueIndex, sbyte valueOffset, float value)
        {
            SetValue(propIndex, valueIndex, valueOffset, EVertexFormat.VERTEX_FORMAT_FULL_FLOAT);
            // kinda resize
            SetFloatValue_Internal(propIndex, valueIndex, value);
        }
        // set float value but doesn't change value type
        private void SetFloatValue_Internal(int propIndex, int valueIndex, float value)
        {
            while (VertexProperties[propIndex].FloatValues.Count() < valueIndex + 1)
                VertexProperties[propIndex].FloatValues.Add(float.NaN);
            VertexProperties[propIndex].FloatValues[valueIndex] = value;
        }
        public void SetHalfValue(int propIndex, int valueIndex, sbyte valueOffset, float value)
        {
            SetValue(propIndex, valueIndex, valueOffset, EVertexFormat.VERTEX_FORMAT_HALF_FLOAT);
            // kinda resize
            while (VertexProperties[propIndex].FloatValues.Count() < valueIndex + 1)
                VertexProperties[propIndex].FloatValues.Add(float.NaN);
            VertexProperties[propIndex].FloatValues[valueIndex] = value;
        }
        public void SetByteValue(int propIndex, int valueIndex, sbyte valueOffset, byte value)
        {
            SetValue(propIndex, valueIndex, valueOffset, EVertexFormat.VERTEX_FORMAT_BYTE);
            // kinda resize
            while (VertexProperties[propIndex].ByteValues.Count() < valueIndex + 1)
                VertexProperties[propIndex].ByteValues.Add(0);
            VertexProperties[propIndex].ByteValues[valueIndex] = value;

            int int_val = value;
            float float_val = ((float)int_val / 255.0f - 0.5f) * 2.0f;
            SetFloatValue_Internal(propIndex, valueIndex, float_val);
        }
        public void SetByteValueFromFloat(int propIndex, int valueIndex)
        {

            if (valueIndex + 1 > VertexProperties[propIndex].FloatValues.Count)
            {
                return;
            }
            if (valueIndex + 1 > VertexProperties[propIndex].ByteValues.Count)
            {
                VertexProperties[propIndex].ByteValues.Add(0);
            }
            int int_val = (int)Math.Round( (VertexProperties[propIndex].FloatValues[valueIndex] * 0.5f + 0.5f) * 255f );
            VertexProperties[propIndex].ByteValues[valueIndex] = (byte)int_val;
        }
    }

    [TypeConverter(typeof(ExpandableObjectConverter))]
    public class SDrawCall
    {
        public SRenderState PRenderState { get; set; }
        public int NRenderStateIndex { get; set; }
        public int NNumVertices { get; set; }
        public SVertex[] PVertexData { get; set; }
        public int NNumIndices { get; set; }
        public bool B32BitIndices { get; set; }
        public Int32[] PIndexData { get; set; }
    };

    ///////////////////////////////////////////////////////////////////////  
    //  Structure SBone
    [StructLayout(LayoutKind.Explicit, Size = 48)]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public struct SBone
	{
		[FieldOffset(0)] int m_nID;
		[FieldOffset(4)] int m_nParentID;
		[FieldOffset(8)] Vec3 m_vStart;
		[FieldOffset(20)] Vec3 m_vEnd;
		[FieldOffset(32)] float m_fRadius;
		[FieldOffset(36)] float m_fMass;
		[FieldOffset(40)] float m_fMassWithChildren;
		[FieldOffset(44)] bool m_bBreakable;

        public int NID { get => m_nID; set => m_nID = value; }
        public int NParentID { get => m_nParentID; set => m_nParentID = value; }
        public Vec3 VStart { get => m_vStart; set => m_vStart = value; }
        public Vec3 VEnd { get => m_vEnd; set => m_vEnd = value; }
        public float FRadius { get => m_fRadius; set => m_fRadius = value; }
        public float FMass { get => m_fMass; set => m_fMass = value; }
        public float FMassWithChildren { get => m_fMassWithChildren; set => m_fMassWithChildren = value; }
        public bool BBreakable { get => m_bBreakable; set => m_bBreakable = value; }
    }


	///////////////////////////////////////////////////////////////////////  
	//  Enumeration ETextureLayer
	//
	//	Used to access texture layers in SRenderState but also used as texture
	//	registers in shaders.

	enum ETextureLayer
	{
		TL_DIFFUSE,
		TL_NORMAL,
		TL_DETAIL_DIFFUSE,
		TL_DETAIL_NORMAL,
		TL_SPECULAR_MASK,
		TL_TRANSMISSION_MASK,
		TL_AUX_ATLAS1,
		TL_AUX_ATLAS2,

		TL_NUM_TEX_LAYERS
	}

    //[StructLayout(LayoutKind.Explicit, Size = 8)]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public struct CPaddedPtr
    {
        //[FieldOffset(0)]
        private int idx;

        //[FieldOffset(4)]
        private int pad;

        private int Idx { get => idx; set => idx = value; }
        public int Pad { get => pad; set => pad = value; }
        public string Val { get; set; }

        public void Read(BinaryReader br, List<string> stringtable)
        {
            idx = br.ReadInt32();
            pad = br.ReadInt32();

            Val = stringtable[idx];
        }

        public void Write(BinaryWriter bw, List<string> stringtable)
        {
            int id = 0;
            for (int i = 0; i < stringtable.Count; i++)
            {
                if (Val == stringtable[i])
                    id = i;
            }
            bw.Write(id);
            bw.Write(pad);
        }

        public override string ToString() => string.IsNullOrEmpty(Val) ? "" : Val;
    }

    ///////////////////////////////////////////////////////////////////////  
    //  Structure SRenderState
    //
    //	Every draw call is associated with a SRenderState object which holds
    //	numerous effect states. A lot of these are determined by the Effect LOD
    //	dialog in the Compiler application.

    // Note that any changes to SRenderState's CStringPtr member variables will necessitate an 
    // update to CCore::DeleteGeometry() and SwapEndianRenderState in Parser.cpp

    //[StructLayout(LayoutKind.Explicit, Size = 720, Pack = 1)]
    //[StructLayout(LayoutKind.Sequential, Pack = 1)]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public struct SRenderState
	{
		// specify the # of shadow maps to use in the example cascaded shadow map system
		//      enum EShadowConfig
		//{
		//	SHADOW_CONFIG_OFF,
		//	SHADOW_CONFIG_1_MAP,
		//	SHADOW_CONFIG_2_MAPS,
		//	SHADOW_CONFIG_3_MAPS,
		//	SHADOW_CONFIG_4_MAPS
		//}

		// textures
		/*[FieldOffset(0)]*/ /*[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)ETextureLayer.TL_NUM_TEX_LAYERS)]*/ CPaddedPtr[] m_apTextures;

        // lighting model
        /*[FieldOffset(64)]*/ ELightingModel m_eLightingModel;

        // ambient
        /*[FieldOffset(68)]*/ Vec3 m_vAmbientColor;
        /*[FieldOffset(80)]*/ ELightingEffect m_eAmbientContrast;
        /*[FieldOffset(84)]*/ float m_fAmbientContrastFactor;
       /* [FieldOffset(88)]*/ bool m_bAmbientOcclusion;

        // diffuse
        /*[FieldOffset(92)]*/ Vec3 m_vDiffuseColor;
       /* [FieldOffset(104)] */float m_fDiffuseScalar;
        /*[FieldOffset(108)]*/ bool m_bDiffuseAlphaMaskIsOpaque;

        // detail
        /*[FieldOffset(112)]*/ ELightingEffect m_eDetailLayer;

        // specular
        /*[FieldOffset(116)] */ELightingEffect m_eSpecular;
        /*[FieldOffset(120)]*/ float m_fShininess;
        /*[FieldOffset(124)]*/ Vec3 m_vSpecularColor;

        // transmission
        /*[FieldOffset(136)]*/ ELightingEffect m_eTransmission;
        /*[FieldOffset(140)]*/ Vec3 m_vTransmissionColor;
        /*[FieldOffset(152)]*/ float m_fTransmissionShadowBrightness;
        /*[FieldOffset(156)]*/ float m_fTransmissionViewDependency;

        // branch seam smoothing
        /*[FieldOffset(160)]*/ ELightingEffect m_eBranchSeamSmoothing;
        /*[FieldOffset(164)]*/ float m_fBranchSeamWeight;

        // LOD parameters
        /*[FieldOffset(168)]*/ ELodMethod m_eLodMethod;
        /*[FieldOffset(172)]*/ bool m_bFadeToBillboard;
        /*[FieldOffset(173)]*/ bool m_bVertBillboard;
        /*[FieldOffset(174)]*/ bool m_bHorzBillboard;

        // render states
        /*[FieldOffset(176)]*/ EShaderGenerationMode m_eShaderGenerationMode;
        /*[FieldOffset(180)]*/ bool m_bUsedAsGrass;
        /*[FieldOffset(184)] */ECullType m_eFaceCulling;
        /*[FieldOffset(188)]*/ bool m_bBlending;
        /*[FieldOffset(192)]*/ ELightingEffect m_eAmbientImageLighting;
        /*[FieldOffset(196)]*/ ELightingEffect m_eHueVariation;

        // fog
       /* [FieldOffset(200)]*/ EFogCurve m_eFogCurve;                  // determines how fog effect is distributed over distance
        /*[FieldOffset(204)]*/ EFogColorType m_eFogColorStyle;             // determines how the fog color is determined (e.g. gradually 
                                                                       // fog to a single color or to a complex value)
                                                                       // shadows
        /*[FieldOffset(208)]*/ bool m_bCastsShadows;
        /*[FieldOffset(209)]*/ bool m_bReceivesShadows;
        /*[FieldOffset(210)] */bool m_bShadowSmoothing;

        // alpha effects
        /*[FieldOffset(212)]*/ float m_fAlphaScalar;

        // wind
       /* [FieldOffset(216)] */EWindLod m_eWindLod;

        // non-lighting shaders
       /* [FieldOffset(220)]*/ ERenderPass m_eRenderPass;

        // geometry types
        /*[FieldOffset(224)] */bool m_bBranchesPresent;
        /*[FieldOffset(225)]*/ bool m_bFrondsPresent;
        /*[FieldOffset(226)]*/ bool m_bLeavesPresent;
        /*[FieldOffset(227)]*/ bool m_bFacingLeavesPresent;
        /*[FieldOffset(228)]*/ bool m_bRigidMeshesPresent;

        // vertex format data
        /*[FieldOffset(229)]*/ SVertexDecl m_sVertexDecl;

        // misc
        /*[FieldOffset(704)]*/ CPaddedPtr m_pDescription;
        /*[FieldOffset(712)]*/ CPaddedPtr m_pUserData;

        #region Properties
        public CPaddedPtr[] ApTextures { get => m_apTextures; set => m_apTextures = value; }
        public ELightingModel ELightingModel { get => m_eLightingModel; set => m_eLightingModel = value; }
        public Vec3 VAmbientColor { get => m_vAmbientColor; set => m_vAmbientColor = value; }
        public ELightingEffect EAmbientContrast { get => m_eAmbientContrast; set => m_eAmbientContrast = value; }
        public float FAmbientContrastFactor { get => m_fAmbientContrastFactor; set => m_fAmbientContrastFactor = value; }
        public bool BAmbientOcclusion { get => m_bAmbientOcclusion; set => m_bAmbientOcclusion = value; }
        public Vec3 VDiffuseColor { get => m_vDiffuseColor; set => m_vDiffuseColor = value; }
        public float FDiffuseScalar { get => m_fDiffuseScalar; set => m_fDiffuseScalar = value; }
        public bool BDiffuseAlphaMaskIsOpaque { get => m_bDiffuseAlphaMaskIsOpaque; set => m_bDiffuseAlphaMaskIsOpaque = value; }
        public ELightingEffect EDetailLayer { get => m_eDetailLayer; set => m_eDetailLayer = value; }
        public ELightingEffect ESpecular { get => m_eSpecular; set => m_eSpecular = value; }
        public float FShininess { get => m_fShininess; set => m_fShininess = value; }
        public Vec3 VSpecularColor { get => m_vSpecularColor; set => m_vSpecularColor = value; }
        public ELightingEffect ETransmission { get => m_eTransmission; set => m_eTransmission = value; }
        public Vec3 VTransmissionColor { get => m_vTransmissionColor; set => m_vTransmissionColor = value; }
        public float FTransmissionShadowBrightness { get => m_fTransmissionShadowBrightness; set => m_fTransmissionShadowBrightness = value; }
        public float FTransmissionViewDependency { get => m_fTransmissionViewDependency; set => m_fTransmissionViewDependency = value; }
        public ELightingEffect EBranchSeamSmoothing { get => m_eBranchSeamSmoothing; set => m_eBranchSeamSmoothing = value; }
        public float FBranchSeamWeight { get => m_fBranchSeamWeight; set => m_fBranchSeamWeight = value; }
        public ELodMethod ELodMethod { get => m_eLodMethod; set => m_eLodMethod = value; }
        public bool BFadeToBillboard { get => m_bFadeToBillboard; set => m_bFadeToBillboard = value; }
        public bool BVertBillboard { get => m_bVertBillboard; set => m_bVertBillboard = value; }
        public bool BHorzBillboard { get => m_bHorzBillboard; set => m_bHorzBillboard = value; }
        public EShaderGenerationMode EShaderGenerationMode { get => m_eShaderGenerationMode; set => m_eShaderGenerationMode = value; }
        public bool BUsedAsGrass { get => m_bUsedAsGrass; set => m_bUsedAsGrass = value; }
        public ECullType EFaceCulling { get => m_eFaceCulling; set => m_eFaceCulling = value; }
        public bool BBlending { get => m_bBlending; set => m_bBlending = value; }
        public ELightingEffect EAmbientImageLighting { get => m_eAmbientImageLighting; set => m_eAmbientImageLighting = value; }
        public ELightingEffect EHueVariation { get => m_eHueVariation; set => m_eHueVariation = value; }
        public EFogCurve EFogCurve { get => m_eFogCurve; set => m_eFogCurve = value; }
        public EFogColorType EFogColorStyle { get => m_eFogColorStyle; set => m_eFogColorStyle = value; }
        public bool BCastsShadows { get => m_bCastsShadows; set => m_bCastsShadows = value; }
        public bool BReceivesShadows { get => m_bReceivesShadows; set => m_bReceivesShadows = value; }
        public bool BShadowSmoothing { get => m_bShadowSmoothing; set => m_bShadowSmoothing = value; }
        public float FAlphaScalar { get => m_fAlphaScalar; set => m_fAlphaScalar = value; }
        public EWindLod EWindLod { get => m_eWindLod; set => m_eWindLod = value; }
        public ERenderPass ERenderPass { get => m_eRenderPass; set => m_eRenderPass = value; }
        public bool BBranchesPresent { get => m_bBranchesPresent; set => m_bBranchesPresent = value; }
        public bool BFrondsPresent { get => m_bFrondsPresent; set => m_bFrondsPresent = value; }
        public bool BLeavesPresent { get => m_bLeavesPresent; set => m_bLeavesPresent = value; }
        public bool BFacingLeavesPresent { get => m_bFacingLeavesPresent; set => m_bFacingLeavesPresent = value; }
        public bool BRigidMeshesPresent { get => m_bRigidMeshesPresent; set => m_bRigidMeshesPresent = value; }
        public SVertexDecl SVertexDecl { get => m_sVertexDecl; set => m_sVertexDecl = value; }
        public CPaddedPtr PDescription { get => m_pDescription; set => m_pDescription = value; }
        public CPaddedPtr PUserData { get => m_pUserData; set => m_pUserData = value; }

        // ? can be zeros, but have some other bytes in vanilla .srt
        public List<byte> WolvenKit_AlignedBytes { get; set; }
        private int WolvenKit_AlignedBytesPosition;
        #endregion

        public void Read(BinaryReader br, List<string> stringtable)
        {
            if (WolvenKit_AlignedBytes == null)
                WolvenKit_AlignedBytes = new List<byte>();
            WolvenKit_AlignedBytes.Clear();
            var startpos = br.BaseStream.Position;

            m_apTextures = new CPaddedPtr[(int)ETextureLayer.TL_NUM_TEX_LAYERS];
            for (int i = 0; i < (int)ETextureLayer.TL_NUM_TEX_LAYERS ; i++)
            {
                m_apTextures[i].Read(br, stringtable);
            }
            m_eLightingModel = (ELightingModel)br.ReadInt32();
            m_vAmbientColor = ReadStruct<Vec3>(br);
            m_eAmbientContrast = (ELightingEffect)br.ReadInt32();
            m_fAmbientContrastFactor = br.ReadSingle();
            m_bAmbientOcclusion = br.ReadBoolean();
            ParseUntilAligned(br);

            // diffuse
             m_vDiffuseColor = ReadStruct<Vec3>(br);
            m_fDiffuseScalar = br.ReadSingle();
            m_bDiffuseAlphaMaskIsOpaque = br.ReadBoolean();
            ParseUntilAligned(br);

            // detail
            m_eDetailLayer = (ELightingEffect)br.ReadInt32();

            // specular
             m_eSpecular = (ELightingEffect)br.ReadInt32();
            m_fShininess = br.ReadSingle();
            m_vSpecularColor = ReadStruct<Vec3>(br);

            // transmission
            m_eTransmission = (ELightingEffect)br.ReadInt32();
            m_vTransmissionColor = ReadStruct<Vec3>(br);
            m_fTransmissionShadowBrightness = br.ReadSingle();
            m_fTransmissionViewDependency = br.ReadSingle();

            // branch seam smoothing
            m_eBranchSeamSmoothing = (ELightingEffect)br.ReadInt32();
            m_fBranchSeamWeight = br.ReadSingle();

            // LOD parameters
            m_eLodMethod = (ELodMethod)br.ReadInt32();
            m_bFadeToBillboard = br.ReadBoolean(); 
            m_bVertBillboard = br.ReadBoolean(); 
            m_bHorzBillboard = br.ReadBoolean();
            ParseUntilAligned(br);

            // render states
            m_eShaderGenerationMode = (EShaderGenerationMode)br.ReadInt32();
            m_bUsedAsGrass = br.ReadBoolean();
            ParseUntilAligned(br);
            m_eFaceCulling = (ECullType)br.ReadInt32();
            m_bBlending = br.ReadBoolean();
            ParseUntilAligned(br);
            m_eAmbientImageLighting = (ELightingEffect)br.ReadInt32();
             m_eHueVariation = (ELightingEffect)br.ReadInt32();

            // fog
             m_eFogCurve = (EFogCurve)br.ReadInt32();
             m_eFogColorStyle = (EFogColorType)br.ReadInt32();
            m_bCastsShadows = br.ReadBoolean();
            m_bReceivesShadows = br.ReadBoolean(); 
            m_bShadowSmoothing = br.ReadBoolean();
            ParseUntilAligned(br);

            // alpha effects
            m_fAlphaScalar = br.ReadSingle();

            // wind
            m_eWindLod = (EWindLod)br.ReadInt32();

            // non-lighting shaders
             m_eRenderPass = (ERenderPass)br.ReadInt32();

            // geometry types
            m_bBranchesPresent = br.ReadBoolean();
            m_bFrondsPresent = br.ReadBoolean();
            m_bLeavesPresent = br.ReadBoolean();
            m_bFacingLeavesPresent = br.ReadBoolean(); 
            m_bRigidMeshesPresent = br.ReadBoolean(); 

            // vertex format data
            m_sVertexDecl = ReadStruct<SVertexDecl>(br);
            ParseUntilAligned(br);

            // misc
            m_pDescription.Read(br, stringtable);
            m_pUserData.Read(br, stringtable);



            var endpos = br.BaseStream.Position;
            var readbytes = endpos - startpos;
            if (readbytes != 720)
                throw new NotImplementedException(); 
        }

        

        public override string ToString() => m_pDescription.ToString();

        internal void Write(BinaryWriter file, List<string> stringtable)
        {
            WolvenKit_AlignedBytesPosition = 0;
            for (int i = 0; i < (int)ETextureLayer.TL_NUM_TEX_LAYERS; i++)
            {
                m_apTextures[i].Write(file, stringtable);
            }
            file.Write((Int32)m_eLightingModel);
            WriteStruct<Vec3>(m_vAmbientColor, file.BaseStream);
            file.Write((Int32)m_eAmbientContrast);
            file.Write(m_fAmbientContrastFactor);
            file.Write(m_bAmbientOcclusion);
			WriteUntilAligned(file);
			

            // diffuse
            WriteStruct<Vec3>(m_vDiffuseColor, file.BaseStream);
            file.Write(m_fDiffuseScalar);
            file.Write(m_bDiffuseAlphaMaskIsOpaque);
            WriteUntilAligned(file);

            // detail
            file.Write((int)m_eDetailLayer);

            // specular
            file.Write((int)m_eSpecular);
            file.Write(m_fShininess);
            WriteStruct<Vec3>(m_vSpecularColor, file.BaseStream);

            // transmission
            file.Write((int)m_eTransmission);
            WriteStruct<Vec3>(m_vTransmissionColor, file.BaseStream);
            file.Write(m_fTransmissionShadowBrightness);
            file.Write(m_fTransmissionViewDependency);

            // branch seam smoothing
            file.Write((int)m_eBranchSeamSmoothing);
            file.Write(m_fBranchSeamWeight);

            // LOD parameters
            file.Write((int)m_eLodMethod);
            file.Write(m_bFadeToBillboard);
            file.Write(m_bVertBillboard);
            file.Write(m_bHorzBillboard);
            WriteUntilAligned(file);

            // render states
            file.Write((int)m_eShaderGenerationMode);
            file.Write(m_bUsedAsGrass);
            WriteUntilAligned(file);
            file.Write((int)m_eFaceCulling);
            file.Write(m_bBlending);
            WriteUntilAligned(file);
            file.Write((int)m_eAmbientImageLighting);
            file.Write((int)m_eHueVariation);

            // fog
            file.Write((int)m_eFogCurve);
            file.Write((int)m_eFogColorStyle);
            file.Write(m_bCastsShadows);
            file.Write(m_bReceivesShadows);
            file.Write(m_bShadowSmoothing);
            WriteUntilAligned(file);

            // alpha effects
            file.Write(m_fAlphaScalar);

            // wind
            file.Write((int)m_eWindLod);

            // non-lighting shaders
            file.Write((int)m_eRenderPass);

            // geometry types
            file.Write(m_bBranchesPresent);
            file.Write(m_bFrondsPresent);
            file.Write(m_bLeavesPresent);
            file.Write(m_bFacingLeavesPresent);
            file.Write(m_bRigidMeshesPresent);

            // vertex format data
            WriteStruct<SVertexDecl>(m_sVertexDecl, file.BaseStream);
            WriteUntilAligned(file);

            // misc
            m_pDescription.Write(file, stringtable);
            m_pUserData.Write(file, stringtable);
        }

        private T ReadStruct<T>(BinaryReader br) where T : struct
        {
            var size = Marshal.SizeOf<T>();

            var m_temp = new byte[size];
            br.BaseStream.Read(m_temp, 0, size);

            var handle = GCHandle.Alloc(m_temp, GCHandleType.Pinned);
            var item = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());

            handle.Free();

            return item;
        }
        private void WriteStruct<T>(T value, Stream stream) where T : struct
        {
            var m_temp = new byte[Marshal.SizeOf<T>()];
            var handle = GCHandle.Alloc(m_temp, GCHandleType.Pinned);

            Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(), true);
            stream.Write(m_temp, 0, m_temp.Length);

            handle.Free();
        }
        private void ParseUntilAligned(BinaryReader br, bool save = true)
        {
            // read padding
            int uiPadSize = 4 - (int)br.BaseStream.Position % 4;
            if (uiPadSize < 4)
            {
                while (uiPadSize > 0)
                {
                    byte b = br.ReadByte();
                    if (save)
                        WolvenKit_AlignedBytes.Add(b);
                    uiPadSize -= 1;
                }
            }
        }
        private void WriteUntilAligned(BinaryWriter bw, bool load = true)
        {
            // read padding
            int uiPadSize = 4 - (int)bw.BaseStream.Position % 4;
            if (uiPadSize < 4)
            {
                while (uiPadSize > 0)
                {
                    byte b = 0x00;
                    if (load)
                    {
                        b = WolvenKit_AlignedBytes.ElementAtOrDefault(WolvenKit_AlignedBytesPosition);
                        WolvenKit_AlignedBytesPosition += 1;
                    }
                    bw.Write(b);
                    uiPadSize -= 1;
                }
            }
        }
    }

	///////////////////////////////////////////////////////////////////////  
	//  Structure SVertexDecl
	//
	//	Depending on the compilation mode chosen in the Compiler app, vertex
	//	declarations may be variable from draw call to draw call. This structure
	//	houses a portable definition of the vertex declaration.

	[StructLayout(LayoutKind.Sequential, Pack = 1)] //Size = 472
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public struct SVertexDecl
	{
		[StructLayout(LayoutKind.Sequential, Pack = 1)] //Size = 14
        [TypeConverter(typeof(ExpandableObjectConverter))]
        public struct SProperty
		{

			sbyte m_uiStream;
            EVertexFormat m_eFormat;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)EVertexComponent.VERTEX_COMPONENT_COUNT)] EVertexProperty[] m_aeProperties/*[VERTEX_COMPONENT_COUNT]*/;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)EVertexComponent.VERTEX_COMPONENT_COUNT)] EVertexComponent[] m_aePropertyComponents/*[VERTEX_COMPONENT_COUNT]*/;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)EVertexComponent.VERTEX_COMPONENT_COUNT)] sbyte[] m_auiVertexOffsets/*[VERTEX_COMPONENT_COUNT]*/;

            #region Properties
            public EVertexProperty[] AeProperties { get => m_aeProperties; set => m_aeProperties = value; }
            public EVertexComponent[] AePropertyComponents { get => m_aePropertyComponents; set => m_aePropertyComponents = value; }
            public sbyte[] AuiVertexOffsets { get => m_auiVertexOffsets; set => m_auiVertexOffsets = value; }
            public sbyte UiStream { get => m_uiStream; set => m_uiStream = value; }
            public EVertexFormat EFormat { get => m_eFormat; set => m_eFormat = value; }
            #endregion
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)] //Size = 13
        [TypeConverter(typeof(ExpandableObjectConverter))]
        public struct SAttribute
		{

			EVertexFormat m_eFormat;                                   // all four components in attribute have to be the same format
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)EVertexComponent.VERTEX_COMPONENT_COUNT)] EVertexAttribute[] m_aeAttribs/*[VERTEX_COMPONENT_COUNT]*/;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)EVertexComponent.VERTEX_COMPONENT_COUNT)] EVertexComponent[] m_aeAttribComponents/*[VERTEX_COMPONENT_COUNT]*/;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)EVertexComponent.VERTEX_COMPONENT_COUNT)] sbyte[] m_auiOffsets/*[VERTEX_COMPONENT_COUNT]*/;           // in bytes, offset of each component from beginning of whole vertex 

            #region Properties
            public EVertexAttribute[] AeAttribs { get => m_aeAttribs; set => m_aeAttribs = value; }
            public EVertexComponent[] AeAttribComponents { get => m_aeAttribComponents; set => m_aeAttribComponents = value; }
            public sbyte[] AuiOffsets { get => m_auiOffsets; set => m_auiOffsets = value; }
            public EVertexFormat EFormat { get => m_eFormat; set => m_eFormat = value; }
            #endregion
        }

        // mesh instancing support; mostly for PS Vita platform
        //enum EInstanceType
        //{
        //    INSTANCES_3D_TREES,
        //    INSTANCES_GRASS,
        //    INSTANCES_BILLBOARDS,
        //    INSTANCES_NONE
        //}

        // utility for setting manually
        //[StructLayout(LayoutKind.Sequential, Pack = 4)]
        //public struct SAttribDesc
        //{
        //	sbyte m_uiStream;
        //          EVertexAttribute m_eAttrib;
        //          EVertexFormat m_eFormat;
        //          sbyte m_uiNumComponents; // e.g., 3 for (x,y,z)

        //          public struct SAttributeComponent
        //	{
        //		EVertexProperty m_eProperty;
        //              EVertexComponent m_eComponent;
        //	}
        //	SAttributeComponent[] m_asAttributes/*[VERTEX_COMPONENT_COUNT]*/;
        //}





        // vertex data organized by attributes
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)EVertexAttribute.VERTEX_ATTRIB_COUNT)] SProperty[] m_asProperties/*[VERTEX_ATTRIB_COUNT]*/;

        // same vertex data, but organized by properties
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)EVertexProperty.VERTEX_PROPERTY_COUNT)] SAttribute[] m_asAttributes/*[VERTEX_PROPERTY_COUNT]*/;

        // shared by both organizations
        sbyte m_uiVertexSize;


        #region Properties
        public SProperty[] AsProperties { get => m_asProperties; set => m_asProperties = value; }
        public SAttribute[] AsAttributes { get => m_asAttributes; set => m_asAttributes = value; }
        public sbyte UiVertexSize { get => m_uiVertexSize; set => m_uiVertexSize = value; }
        #endregion
    }

    ///////////////////////////////////////////////////////////////////////  
    //  A word on terminology regarding vertex declarations in this SDK. There
    //	are several key terms that need to be clearly defined. Take a vertex 
    //	shader input declaration like the following in HLSL syntax:
    //
    //	struct SVertexDecl
    //	{
    //	  float3  vSlot0  : POSITION;	// xyz = position.xyz
    //    float4  vSlot1  : TEXCOORD0;	// xy = diffuse texcoords, z = amb occ, w = normal.z
    //  };
    //
    //	Using the second line, vSlot1, of the structure as an example, we wish to
    //  define the following terms (appear in double-quotes):
    //
    //		o The entire float4 group taken collectively is termed a "vertex attribute."
    //      o TEXCOORD0 is the vertex's "semantic," as the term defined is in the HLSL 
    //		  and Cg docs.
    //		o "Component" refers any single x, y, z, or w in the slot.
    //      o The four components hold diffuse texcoords, ambient occlusion, and partial 
    //		  normal "properties."  Not to be confused with "attribute," as there may be multiple
    //        properties in a single attribute, or a single property may be split across
    //        multiple attributes.
    //		o "Format" refers to how the data was stored in the vertex buffer (e.g.
    //		   byte, half float, full float) { not visible in this decl }
    //
    //	The structure taken as a whole is the "vertex declaration."


    ///////////////////////////////////////////////////////////////////////  
    //  Enumeration EVertexProperty
    //
    //	Contains a list of all vertex properties that may be used by the SpeedTree
    //	vertex buffers and shaders. Note that some are geometry-specific and,
    //	depending on the compilation mode chosen in the Compiler app, may or
    //	may not appear in the vertex decl for each draw call.
    //
    //	Details for each vertex property can be queried using 
    //	CCore::GetVertexPropertyDesc().
    //
    //	The typedef below forces the enumeration to use 8 bits instead of
    //	32. It helps to keep SVertexDecl small.

    public enum EVertexProperty/*Untyped*/ : sbyte
	{
		VERTEX_PROPERTY_UNASSIGNED = -1,

		// these can affect the shape of the tree and therefore come first; this
		// can reduce vertex fetches when rendering depth & shadow passes
		VERTEX_PROPERTY_POSITION,                       // 3 components
		VERTEX_PROPERTY_DIFFUSE_TEXCOORDS,              // 2 components
		VERTEX_PROPERTY_NORMAL,                         // 3 components (normal impacts the wind algorithm)
		VERTEX_PROPERTY_LOD_POSITION,                   // 3 components
		VERTEX_PROPERTY_GEOMETRY_TYPE_HINT,             // 1 component
		VERTEX_PROPERTY_LEAF_CARD_CORNER,               // 3 components (corner x, corner y, z-fight offset)
		VERTEX_PROPERTY_LEAF_CARD_LOD_SCALAR,           // 1 component
		VERTEX_PROPERTY_LEAF_CARD_SELF_SHADOW_OFFSET,   // 1 component
		VERTEX_PROPERTY_WIND_BRANCH_DATA,               // 4 components
		VERTEX_PROPERTY_WIND_EXTRA_DATA,                // 3 components
		VERTEX_PROPERTY_WIND_FLAGS,                     // 1 component
		VERTEX_PROPERTY_LEAF_ANCHOR_POINT,              // 3 components
		VERTEX_PROPERTY_BONE_ID,                        // 1 component

		// these do not affect the shape of the tree and come later
		VERTEX_PROPERTY_BRANCH_SEAM_DIFFUSE,            // 3 components (s, t, weight)
		VERTEX_PROPERTY_BRANCH_SEAM_DETAIL,             // 2 components (s, t)
		VERTEX_PROPERTY_DETAIL_TEXCOORDS,               // 2 components
		VERTEX_PROPERTY_TANGENT,                        // 3 components
		VERTEX_PROPERTY_LIGHTMAP_TEXCOORDS,             // 2 components
		VERTEX_PROPERTY_AMBIENT_OCCLUSION,              // 1 component
		VERTEX_PROPERTY_MISC_SEMANTIC = VERTEX_PROPERTY_AMBIENT_OCCLUSION,

        VERTEX_PROPERTY_PAD,
        VERTEX_PROPERTY_COUNT = VERTEX_PROPERTY_PAD
    };
    //typedef Enumeration<EVertexPropertyUntyped, st_int8> EVertexProperty;


    ///////////////////////////////////////////////////////////////////////  
    //  Structure SVertexPropertyDesc
    //
    //	Holds details about each vertex property as returned by
    //	CCore::GetVertexPropertyDesc().

#pragma warning disable CS0169 // ~~~[[maybe_unused]] c++ compiler attribute
#pragma warning disable IDE0051
    public struct SVertexPropertyDesc
	{
		int m_nNumComponents;
		string m_pFullName;
		string m_pShortName;
	};
#pragma warning restore CS0169 // ~~~[[maybe_unused]] c++ compiler attribute
#pragma warning restore IDE0051


    ///////////////////////////////////////////////////////////////////////  
    //  Enumeration EPixelProperty
    //
    //	Contains a list of all pixel shader properties that may be used by the 
    //	SpeedTree shaders. While this is housed in the Core SDK library, it
    //	is primarily used by the SRT Exporter housed in the Compiler app.
    //
    //	Details for each vertex property can be queried using 
    //	CCore::GetPixelPropertyDesc().
    //
    //	The typedef below forces the enumeration to use 8 bits instead of
    //	32. It helps to keep SVertexDecl small.

    public enum EPixelProperty : sbyte
	{
		PIXEL_PROPERTY_POSITION,
		PIXEL_PROPERTY_FOG_SCALAR,
		PIXEL_PROPERTY_FOG_COLOR,
		PIXEL_PROPERTY_DIFFUSE_TEXCOORDS,
		PIXEL_PROPERTY_DETAIL_TEXCOORDS,
		PIXEL_PROPERTY_PER_VERTEX_LIGHTING_COLOR,
		PIXEL_PROPERTY_NORMAL_MAP_VECTOR,
		PIXEL_PROPERTY_NORMAL,
		PIXEL_PROPERTY_BINORMAL,
		PIXEL_PROPERTY_TANGENT,
		PIXEL_PROPERTY_SPECULAR_HALF_VECTOR,
		PIXEL_PROPERTY_PER_VERTEX_SPECULAR_DOT,
		PIXEL_PROPERTY_PER_VERTEX_AMBIENT_CONTRAST,
		PIXEL_PROPERTY_FADE_TO_BILLBOARD,
		PIXEL_PROPERTY_TRANSMISSION_FACTOR,
		PIXEL_PROPERTY_RENDER_EFFECT_FADE,
		PIXEL_PROPERTY_AMBIENT_OCCLUSION,
		PIXEL_PROPERTY_BRANCH_SEAM_DIFFUSE,
		PIXEL_PROPERTY_BRANCH_SEAM_DETAIL,
		PIXEL_PROPERTY_SHADOW_DEPTH,
		PIXEL_PROPERTY_SHADOW_MAP_0_PROJECTION,
		PIXEL_PROPERTY_SHADOW_MAP_1_PROJECTION,
		PIXEL_PROPERTY_SHADOW_MAP_2_PROJECTION,
		PIXEL_PROPERTY_SHADOW_MAP_3_PROJECTION,
		PIXEL_PROPERTY_HUE_VARIATION,
		PIXEL_PROPERTY_COUNT
	};


    ///////////////////////////////////////////////////////////////////////  
    //  Structure SPixelPropertyDesc
    //
    //	Holds details about each pixel property as returned by
    //	CCore::GetPixelPropertyDesc().

#pragma warning disable CS0169 // ~~~[[maybe_unused]] c++ compiler attribute
#pragma warning disable IDE0051
    struct SPixelPropertyDesc
	{
		int m_nNumComponents;
		string m_pFullName;
		string m_pShortName;
	};
#pragma warning restore CS0169 // ~~~[[maybe_unused]] c++ compiler attribute
#pragma warning restore IDE0051

    ///////////////////////////////////////////////////////////////////////  
    //  Enumeration EVertexAttribute
    //
    //	List the 16 available vertex attributes. Each can hold 4 floats. Each
    //	platform supported in the SDK will turn these into platform-specific
    //	vertex shader input semantics like POSITION or TEXCOORD[0-15].
    //
    //	The typedef below forces the enumeration to use 8 bits instead of
    //	32. It helps to keep SVertexDecl small.

    public enum EVertexAttribute/*Untyped*/ : sbyte
	{
		VERTEX_ATTRIB_UNASSIGNED = -1,

		VERTEX_ATTRIB_0,
		VERTEX_ATTRIB_1,
		VERTEX_ATTRIB_2,
		VERTEX_ATTRIB_3,
		VERTEX_ATTRIB_4,
		VERTEX_ATTRIB_5,
		VERTEX_ATTRIB_6,
		VERTEX_ATTRIB_7,
		VERTEX_ATTRIB_8,
		VERTEX_ATTRIB_9,
		VERTEX_ATTRIB_10,
		VERTEX_ATTRIB_11,
		VERTEX_ATTRIB_12,
		VERTEX_ATTRIB_13,
		VERTEX_ATTRIB_14,
		VERTEX_ATTRIB_15,

		VERTEX_ATTRIB_COUNT,
		VERTEX_DECL_END = VERTEX_ATTRIB_COUNT
	};
    //typedef Enumeration<EVertexAttributeUntyped, st_int8> EVertexAttribute;


    ///////////////////////////////////////////////////////////////////////  
    //  Enumeration EVertexComponent
    //
    //	Simple enumeration for accessing individual components for attributes.
    //
    //	The typedef below forces the enumeration to use 8 bits instead of
    //	32. It helps to keep SVertexDecl small.

    public enum EVertexComponent/*Untyped*/ : sbyte
	{
		VERTEX_COMPONENT_UNASSIGNED = -1,

		VERTEX_COMPONENT_X,
		VERTEX_COMPONENT_Y,
		VERTEX_COMPONENT_Z,
		VERTEX_COMPONENT_W,
		VERTEX_COMPONENT_COUNT
	};
	//typedef Enumeration<EVertexComponentUntyped, st_int8> EVertexComponent;


	///////////////////////////////////////////////////////////////////////  
	//  Enumeration EVertexFormat
	//
	//	List of the three data types used to house vertex data.
	//
	//	The typedef below forces the enumeration to use 8 bits instead of
	//	32. It helps to keep SVertexDecl::SAttribDesc small.

	public enum EVertexFormat/*Untyped*/ : sbyte
	{
		VERTEX_FORMAT_UNASSIGNED = -1,

		VERTEX_FORMAT_FULL_FLOAT,       // 32-bit floats
		VERTEX_FORMAT_HALF_FLOAT,       // 16-bit floats
		VERTEX_FORMAT_BYTE,             // 8-bit values
		VERTEX_FORMAT_COUNT
	};
	//typedef Enumeration<EVertexFormatUntyped, st_int8> EVertexFormat;




	///////////////////////////////////////////////////////////////////////  
	//  Enumerations associated with SRenderState

	public enum ELightingModel
    {
        LIGHTING_MODEL_PER_VERTEX,
        LIGHTING_MODEL_PER_PIXEL,
        LIGHTING_MODEL_PER_VERTEX_X_PER_PIXEL, // transitional state, forward rendering only
        LIGHTING_MODEL_DEFERRED
    }

    public enum ELightingEffect
    {
        EFFECT_OFF,
        EFFECT_ON,
        EFFECT_OFF_X_ON // transitional state
    }

    public enum ELodMethod
    {
        LOD_METHOD_POP,
        LOD_METHOD_SMOOTH
    }

    public enum ECullType
    {
        CULLTYPE_NONE,
        CULLTYPE_BACK,
        CULLTYPE_FRONT
    }

    public enum EFogCurve
    {
        FOG_CURVE_NONE,             // no fog effect
        FOG_CURVE_LINEAR,
        FOG_CURVE_EXP,
        FOG_CURVE_EXP2,
        FOG_CURVE_USER
    }

    public enum EFogColorType
    {
        FOG_COLOR_TYPE_CONSTANT,
        FOG_COLOR_TYPE_DYNAMIC
    }

    public enum EWindLod
    {
        WIND_LOD_NONE,
        WIND_LOD_GLOBAL,
        WIND_LOD_BRANCH,
        WIND_LOD_FULL,

        // transitional states (affect shaders only), 'X' in name denotes cross fade
        WIND_LOD_NONE_X_GLOBAL,
        WIND_LOD_NONE_X_BRANCH,
        WIND_LOD_NONE_X_FULL,
        WIND_LOD_GLOBAL_X_BRANCH,
        WIND_LOD_GLOBAL_X_FULL,
        WIND_LOD_BRANCH_X_FULL
    }

    // used by the Compiler app when writing shaders
    public enum EWindEffect
    {
        WIND_EFFECT_LEAF_WIND_1,
        WIND_EFFECT_LEAF_WIND_2
    }

    // these generation modes match one-for-one with the Compiler app's "Merge materials" compilation option
    public enum EShaderGenerationMode
    {
        SHADER_GEN_MODE_STANDARD,
        SHADER_GEN_MODE_ACROSS_GEOMETRIES,
        SHADER_GEN_MODE_AGGRESSIVE_ROUND_UP,
        SHADER_GEN_MODE_AGGRESSIVE_ROUND_DOWN,
        SHADER_GEN_MODE_SPEEDTREE_5X_STYLE,
        SHADER_GEN_MODE_UNIFIED_SHADERS,
        SHADER_GEN_MODE_UNREAL_ENGINE_4,
        SHADER_GEN_MODE_COUNT
    }
}
