コード例 #1
0
        public override void drawTrack(Midi.Track midiTrack, TrackProps trackProps, MaterialProps texMaterial)
        {
            float songPosP;

            base.drawTrack(midiTrack, trackProps, texMaterial, out songPosP);
            trackProps.TrackView.OcTree.drawGeo(Project.Props.Camera);
        }
コード例 #2
0
    /// <summary> Parse a DataBlock into a MaterialProps. Any missing variables will be set to their default value. </summary>
    /// <param name="dataBlock"></param>
    /// <returns></returns>
    public static MaterialProps Parse(List <string> dataBlock)
    {
        MaterialProps res = MaterialProps.Default();

        if (dataBlock.Count > 1)
        {
            float parsedValue;
            if (dataBlock.Count > (int)MatProp.maxForce && TryGetFloat(dataBlock[(int)MatProp.maxForce], out parsedValue))
            {
                res.maxForce = (int)parsedValue;
            }
            if (dataBlock.Count > (int)MatProp.maxForceDist && TryGetFloat(dataBlock[(int)MatProp.maxForceDist], out parsedValue))
            {
                res.maxForceDist = parsedValue;
            }
            if (dataBlock.Count > (int)MatProp.yieldDist && TryGetFloat(dataBlock[(int)MatProp.yieldDist], out parsedValue))
            {
                if (float.IsNaN(parsedValue))
                {
                    parsedValue = float.MaxValue;
                }
                res.yieldDist = parsedValue;
            }
            if (dataBlock.Count > (int)MatProp.hapticMagn && TryGetFloat(dataBlock[(int)MatProp.hapticMagn], out parsedValue))
            {
                res.hapticForce = (int)parsedValue;
            }
            if (dataBlock.Count > (int)MatProp.hapticDur && TryGetFloat(dataBlock[(int)MatProp.hapticDur], out parsedValue))
            {
                res.hapticDur = (int)parsedValue;
            }
        }
        return(res);
    }
コード例 #3
0
 public override Material BuildMaterialFromProperties(MaterialProps mp)
 {
     // check if the material is already cached
     if (!_existingMaterials.TryGetValue(mp, out var material))
     {
         // otherwise create a new material and cache it
         if (mp.AlphaBlended)
         {
             material = BuildMaterialBlended(mp.SrcBlendMode, mp.DstBlendMode);
         }
         else if (mp.AlphaTest)
         {
             material = BuildMaterialTested(mp.AlphaCutoff);
         }
         else
         {
             material = BuildMaterial();
         }
         if (mp.Textures.MainFilePath != null)
         {
             material.mainTexture = _textureManager.LoadTexture(mp.Textures.MainFilePath);
             if (NormalGeneratorIntensity != null)
             {
                 material.SetTexture("_BumpMap", GenerateNormalMap((Texture2D)material.mainTexture, NormalGeneratorIntensity.Value));
             }
         }
         if (mp.Textures.BumpFilePath != null)
         {
             material.SetTexture("_BumpMap", _textureManager.LoadTexture(mp.Textures.BumpFilePath));
         }
         _existingMaterials[mp] = material;
     }
     return(material);
 }
コード例 #4
0
 public override Material BuildMaterialFromProperties(MaterialProps mp)
 {
     // check if the material is already cached
     if (!_existingMaterials.TryGetValue(mp, out var material))
     {
         // otherwise create a new material and cache it
         if (mp.AlphaBlended)
         {
             material = BuildMaterialBlended(mp.SrcBlendMode, mp.DstBlendMode);
         }
         else if (mp.AlphaTest)
         {
             material = BuildMaterialTested(mp.AlphaCutoff);
         }
         else
         {
             material = BuildMaterial();
         }
         if (mp.Textures.MainFilePath != null)
         {
             material.mainTexture = _textureManager.LoadTexture(mp.Textures.MainFilePath);
         }
         _existingMaterials[mp] = material;
     }
     return(material);
 }
コード例 #5
0
        MaterialProps MeshPropertiesToMaterialProperties(Core.Material mtl)
        {
            // Create the material properties.
            var mp = new MaterialProps();

            if (true)
            {
                if (mtl.AlphaTest != 0.0) // if flags contain the alpha test flag
                {
                    mp.AlphaTest   = true;
                    mp.AlphaCutoff = (float)mtl.AlphaTest / 255F;
                }
            }
            else
            {
                mp.AlphaBlended = false;
                mp.AlphaTest    = false;
            }
            // Apply textures.
            if (mtl.Textures != null)
            {
                mp.Textures = ConfigureTextureProperties(mtl.Textures);
            }
            return(mp);
        }
コード例 #6
0
    //----------------------------------------------------------------------------------
    // Material Property loading

    #region MaterialProps

    /// <summary> Load the hard-coded properties of the material </summary>
    /// <param name="ofMaterial"></param>
    public void LoadMaterialProps(VirtualMaterial ofMaterial)
    {
        //SenseGlove_Debugger.Log("Loading material props of " + ofMaterial.ToString());
        if (ofMaterial != VirtualMaterial.Custom)
        {
            MaterialProps thisProps = new MaterialProps();
            switch (ofMaterial)
            {
            case VirtualMaterial.Rubber:
                thisProps.maxForce     = 65;
                thisProps.maxForceDist = 0.02f;
                thisProps.yieldDist    = float.MaxValue;
                thisProps.hapticForce  = 60;
                thisProps.hapticDur    = 200;
                break;

            case VirtualMaterial.Steel:
                thisProps.maxForce     = 100;
                thisProps.maxForceDist = 0.00f;
                thisProps.yieldDist    = float.MaxValue;
                thisProps.hapticForce  = 0;
                thisProps.hapticDur    = 0;
                break;

            case VirtualMaterial.Egg:
                thisProps.maxForce     = 90;
                thisProps.maxForceDist = 0.01f;
                thisProps.yieldDist    = 0.02f;
                thisProps.hapticForce  = 0;
                thisProps.hapticDur    = 0;
                break;
            }
            this.LoadMaterialProps(thisProps);
        }
    }
コード例 #7
0
 /// <summary> Actually apply materialProps to this Material.  </summary>
 /// <param name="props"></param>
 private void LoadMaterialProps(MaterialProps props)
 {
     this.maxForce        = props.maxForce;
     this.maxForceDist    = props.maxForceDist;
     this.yieldDistance   = props.yieldDist;
     this.hapticMagnitude = props.hapticForce;
     this.hapticDuration  = props.hapticDur;
 }
コード例 #8
0
    //----------------------------------------------------------------------------------
    // Material Property loading

    #region MaterialProps

    /// <summary> Load material properties from an external database file. </summary>
    private void LoadMaterialProps()
    {
        if (this.materialDataBase != null && this.materialName.Length > 0)
        {
            //SenseGlove_Debugger.Log("Loading " + this.materialName + " from a local database file " + this.materialDataBase.name);
            MaterialProps props = SenseGloveMats.MaterialLibraries.GetMaterial(this.materialName);
            this.LoadMaterialProps(props);
        }
    }
コード例 #9
0
 public override Material BuildMaterialFromProperties(MaterialProps mp)
 {
     // check if the material is already cached
     if (!_existingMaterials.TryGetValue(mp, out var material))
     {
         // otherwise create a new material and cache it
         if (mp.AlphaBlended)
         {
             material = BuildMaterialBlended(mp.SrcBlendMode, mp.DstBlendMode);
         }
         else if (mp.AlphaTest)
         {
             material = BuildMaterialTested(mp.AlphaCutoff);
         }
         else
         {
             material = BuildMaterial();
         }
         if (mp.Textures.MainFilePath != null && material.HasProperty("_MainTex"))
         {
             material.SetTexture("_MainTex", _textureManager.LoadTexture(mp.Textures.MainFilePath));
         }
         if (mp.Textures.DetailFilePath != null && material.HasProperty("_DetailTex"))
         {
             material.SetTexture("_DetailTex", _textureManager.LoadTexture(mp.Textures.DetailFilePath));
         }
         if (mp.Textures.DarkFilePath != null && material.HasProperty("_DarkTex"))
         {
             material.SetTexture("_DarkTex", _textureManager.LoadTexture(mp.Textures.DarkFilePath));
         }
         if (mp.Textures.GlossFilePath != null && material.HasProperty("_GlossTex"))
         {
             material.SetTexture("_GlossTex", _textureManager.LoadTexture(mp.Textures.GlossFilePath));
         }
         if (mp.Textures.GlowFilePath != null && material.HasProperty("_Glowtex"))
         {
             material.SetTexture("_Glowtex", _textureManager.LoadTexture(mp.Textures.GlowFilePath));
         }
         if (mp.Textures.BumpFilePath != null && material.HasProperty("_BumpTex"))
         {
             material.SetTexture("_BumpTex", _textureManager.LoadTexture(mp.Textures.BumpFilePath));
         }
         if (material.HasProperty("_Metallic"))
         {
             material.SetFloat("_Metallic", 0f);
         }
         if (material.HasProperty("_Glossiness"))
         {
             material.SetFloat("_Glossiness", 0f);
         }
         _existingMaterials[mp] = material;
     }
     return(material);
 }
コード例 #10
0
    /// <summary> Retrieve a 'default' material. </summary>
    /// <returns></returns>
    public static MaterialProps Default()
    {
        MaterialProps res = new MaterialProps();

        res.maxForce     = 100;
        res.maxForceDist = 0;
        res.yieldDist    = float.MaxValue;
        res.hapticDur    = 100;
        res.hapticForce  = 100;
        return(res);
    }
コード例 #11
0
ファイル: ObjectTestPack.cs プロジェクト: BclEx/object-assets
        static void MakeTexture(string path)
        {
            var textureManager  = new TextureManager(Asset);
            var materialManager = new MaterialManager(textureManager);
            var obj             = GameObject.Find("Cube"); // CreatePrimitive(PrimitiveType.Cube);
            var meshRenderer    = obj.GetComponent <MeshRenderer>();
            var materialProps   = new MaterialProps
            {
                Textures = new MaterialTextures {
                    MainFilePath = path
                },
            };

            meshRenderer.material = materialManager.BuildMaterialFromProperties(materialProps);
        }
コード例 #12
0
        MaterialProps MeshLodDataToMaterialProperties(SiMeshLod data)
        {
            // Create the material properties.
            var mp = new MaterialProps();
            var tp = new MaterialTextures();

            foreach (var material in data.Materials)
            {
                if (tp.MainFilePath == null)
                {
                    tp.MainFilePath = material.Texture;
                }
            }
            mp.Textures = tp;
            return(mp);
        }
コード例 #13
0
ファイル: LoadAsset.cs プロジェクト: libcs/game-estates
        static GameObject MakeTexture(string path, int idx)
        {
            var textureManager  = new TextureManager(AssetPack);
            var materialManager = new MaterialManager(textureManager);
            var obj             = GameObject.CreatePrimitive(PrimitiveType.Plane);

            obj.name = path.Replace("/", "");
            obj.transform.localPosition += new Vector3(10 * (idx % 10), 0, 10 * (idx / 10));
            var meshRenderer  = obj.GetComponent <MeshRenderer>();
            var materialProps = new MaterialProps
            {
                Textures = new MaterialTextures {
                    MainFilePath = path
                },
            };

            meshRenderer.material = materialManager.BuildMaterialFromProperties(materialProps);
            return(obj);
        }
コード例 #14
0
        public override void drawTrack(Midi.Track midiTrack, TrackProps trackProps, MaterialProps texMaterial)
        {
            float songPosP;

            base.drawTrack(midiTrack, trackProps, texMaterial, out songPosP);
            List <Midi.Note> noteList = midiTrack.Notes;

            //List<Midi.Note> noteList = getNotes(0, midiTrack, songDrawProps);
            if (noteList.Count == 0)
            {
                return;
            }

            //this.trackProps = trackProps;

            fx.Parameters["LineType"].SetValue((int)LineType);
            fx.Parameters["HlSize"].SetValue(VpHlSize / 2.0f);
            float radius = (float)VpLineWidth / 2.0f;

            fx.Parameters["Radius"].SetValue(radius);
            fx.Parameters["InnerHlSize"].SetValue(0.0f);

            fx.CurrentTechnique = fx.Techniques["Line"];
            fx.Parameters["DiscardAtOnce"].SetValue(true);
            fx.CurrentTechnique.Passes[0].Apply();
            trackProps.TrackView.OcTree.drawGeo(Project.Props.Camera);
            fx.Parameters["DiscardAtOnce"].SetValue(false);
            fx.CurrentTechnique.Passes[0].Apply();
            trackProps.TrackView.OcTree.drawGeo(Project.Props.Camera);

            DepthStencilState oldDss = GraphicsDevice.DepthStencilState;

            GraphicsDevice.DepthStencilState = DepthStencilState.None;
            drawHighLights(midiTrack, trackProps, songPosP);
            GraphicsDevice.DepthStencilState = oldDss;
        }
コード例 #15
0
        MaterialProps SiAVObjectPropertiesToMaterialProperties(SiAVObject obj)
        {
            // Find relevant properties.
            SiTexturingProperty texturingProperty = null;

            foreach (var propRef in obj.Properties)
            {
                var prop = _file.Blocks[propRef.Value];
                if (prop is SiTexturingProperty)
                {
                    texturingProperty = (SiTexturingProperty)prop;
                }
            }

            // Create the material properties.
            var mp = new MaterialProps();

            // Apply textures.
            if (texturingProperty != null)
            {
                mp.Textures = ConfigureTextureProperties(texturingProperty);
            }
            return(mp);
        }
コード例 #16
0
ファイル: OcTree.cs プロジェクト: yousernaym/vm
        public void createGeo(Midi.Track midiTrack, TrackProps trackProps, TrackProps globalTrackProps, MaterialProps texMaterial)
        {
            _createGeoChunk(out _geo, _bbox, midiTrack, trackProps, texMaterial);
            return;

            if (_nodes != null)
            {
                foreach (var node in _nodes)
                {
                    if (node == null)
                    {
                        continue;
                    }
                    node.createGeo(midiTrack, trackProps, globalTrackProps, texMaterial);
                }
            }
        }
コード例 #17
0
 public abstract Material BuildMaterialFromProperties(MaterialProps mp);
コード例 #18
0
        MaterialProps NiAVObjectPropertiesToMaterialProperties(NiAVObject obj)
        {
            // Find relevant properties.
            NiTexturingProperty texturingProperty = null;
            //NiMaterialProperty materialProperty = null;
            NiAlphaProperty alphaProperty = null;

            foreach (var propRef in obj.Properties)
            {
                var prop = _obj.Blocks[propRef.Value];
                if (prop is NiTexturingProperty)
                {
                    texturingProperty = (NiTexturingProperty)prop;
                }
                //else if (prop is NiMaterialProperty) materialProperty = (NiMaterialProperty)prop;
                else if (prop is NiAlphaProperty)
                {
                    alphaProperty = (NiAlphaProperty)prop;
                }
            }

            // Create the material properties.
            var mp = new MaterialProps();

            if (alphaProperty != null)
            {
                #region AlphaProperty Cheat Sheet

                /*
                 * 14 bits used:
                 *
                 * 1 bit for alpha blend bool
                 * 4 bits for src blend mode
                 * 4 bits for dest blend mode
                 * 1 bit for alpha test bool
                 * 3 bits for alpha test mode
                 * 1 bit for zwrite bool ( opposite value )
                 *
                 * Bit 0 : alpha blending enable
                 * Bits 1-4 : source blend mode
                 * Bits 5-8 : destination blend mode
                 * Bit 9 : alpha test enable
                 * Bit 10-12 : alpha test mode
                 * Bit 13 : no sorter flag ( disables triangle sorting ) ( Unity ZWrite )
                 *
                 * blend modes (glBlendFunc):
                 * 0000 GL_ONE
                 * 0001 GL_ZERO
                 * 0010 GL_SRC_COLOR
                 * 0011 GL_ONE_MINUS_SRC_COLOR
                 * 0100 GL_DST_COLOR
                 * 0101 GL_ONE_MINUS_DST_COLOR
                 * 0110 GL_SRC_ALPHA
                 * 0111 GL_ONE_MINUS_SRC_ALPHA
                 * 1000 GL_DST_ALPHA
                 * 1001 GL_ONE_MINUS_DST_ALPHA
                 * 1010 GL_SRC_ALPHA_SATURATE
                 *
                 * test modes (glAlphaFunc):
                 * 000 GL_ALWAYS
                 * 001 GL_LESS
                 * 010 GL_EQUAL
                 * 011 GL_LEQUAL
                 * 100 GL_GREATER
                 * 101 GL_NOTEQUAL
                 * 110 GL_GEQUAL
                 * 111 GL_NEVER
                 */
                #endregion
                var flags    = alphaProperty.Flags;
                var oldflags = flags;
                var srcbm    = (byte)(BitConverter.GetBytes(flags >> 1)[0] & 15);
                var dstbm    = (byte)(BitConverter.GetBytes(flags >> 5)[0] & 15);
                mp.ZWrite = BitConverter.GetBytes(flags >> 15)[0] == 1; // smush
                if (Utils.ContainsBitFlags(flags, 0x01))                // if flags contain the alpha blend flag at bit 0 in byte 0
                {
                    mp.AlphaBlended = true;
                    mp.SrcBlendMode = FigureBlendMode(srcbm);
                    mp.DstBlendMode = FigureBlendMode(dstbm);
                }
                else if (Utils.ContainsBitFlags(flags, 0x100)) // if flags contain the alpha test flag
                {
                    mp.AlphaTest   = true;
                    mp.AlphaCutoff = (float)alphaProperty.Threshold / 255;
                }
            }
            else
            {
                mp.AlphaBlended = false;
                mp.AlphaTest    = false;
            }
            // Apply textures.
            if (texturingProperty != null)
            {
                mp.Textures = ConfigureTextureProperties(texturingProperty);
            }
            return(mp);
        }
コード例 #19
0
        public override void createGeoChunk(out Geo geo, BoundingBox bbox, Midi.Track midiTrack, TrackProps trackProps, MaterialProps texMaterial)
        {
            BarGeo barGeo = new BarGeo();

            geo = barGeo;
            List <Midi.Note> noteList = midiTrack.Notes;

            if (noteList.Count == 0)
            {
                return;
            }

            float halfNoteHeight = Project.Props.NoteHeight / 2;
            int   instanceIndex  = 0;

            for (int n = 0; n < noteList.Count; n++)
            {
                Midi.Note note = noteList[n];
                if (note.start > Project.Notes.SongLengthT) //only if audio ends before the notes end
                {
                    continue;
                }
                Vector2 noteStart = Project.getScreenPos(note.start, note.pitch);
                Vector2 noteEnd   = Project.getScreenPos(note.stop, note.pitch);

                //Create bounding boxes
                Vector3 boxMin = new Vector3(noteStart.X, noteStart.Y - halfNoteHeight, 0);
                Vector3 boxMax = new Vector3(noteEnd.X, noteEnd.Y + halfNoteHeight, 0);
                geo.bboxes.Add(new BoundingBoxEx(boxMin, boxMax));

                //Create inctance data
                Vector2 topLeft_world = new Vector2(noteStart.X, noteStart.Y - halfNoteHeight);
                Vector2 size_world    = new Vector2(noteEnd.X - noteStart.X, halfNoteHeight * 2 - 0.001f);
                Vector2 topLeft_tex   = topLeft_world;
                Vector2 size_tex      = size_world;

                Texture2D texture = texMaterial.TexProps.Texture;
                if (texture != null)
                {
                    Vector2 texSize = new Vector2(texture.Width, texture.Height);
                    calcRectTexCoords(out topLeft_tex, out size_tex, texSize, topLeft_world, size_world, texMaterial);
                }
                instanceVerts[instanceIndex].destRect = new Vector4(topLeft_world.X, topLeft_world.Y, size_world.X, size_world.Y);
                instanceVerts[instanceIndex].srcRect  = new Vector4(topLeft_tex.X, topLeft_tex.Y, size_tex.X, size_tex.Y);
                if (++instanceIndex >= MaxInstances - 1)
                {
                    createVb(ref instanceIndex, barGeo);
                }
            }
            if (instanceIndex > 0)
            {
                createVb(ref instanceIndex, barGeo);
            }
        }
コード例 #20
0
        //static string GetName<T>(T item) where T : class
        //{
        //	return typeof(T).GetProperties()[0].Name;
        //}

        public override void createGeoChunk(out Geo geo, BoundingBox bbox, Midi.Track midiTrack, TrackProps trackProps, MaterialProps texMaterial)
        {
            LineGeo lineGeo = new LineGeo();

            geo = lineGeo;
            if (LineWidth == 0)
            {
                return;
            }
            List <Midi.Note> noteList = midiTrack.Notes;

            //List<Midi.Note> noteList = getNotes(0, midiTrack, songDrawProps);
            if (noteList.Count == 0)
            {
                return;
            }

            int   vertIndex                  = 3;
            int   hLineVertIndex             = 0;
            int   completeNoteListIndex      = midiTrack.Notes.IndexOf(noteList[0]);
            float vpLineWidth                = VpLineWidth;
            float maxNumBboxesPerScreenWidth = 1000;
            float bboxMinSqLength            = (float)Math.Pow(Project.Props.Camera.ViewportSize.X / maxNumBboxesPerScreenWidth, 2);

            //for (int i = 0; i < 100; i++)
            //{
            //	vertIndex = 30000;
            //	createLineSegment(ref vertIndex, ref hLineVertIndex, lineGeo, vpLineWidth);
            //}
            //return;
            for (int n = 0; n < noteList.Count; n++)
            {
                //Get current note
                Midi.Note note = noteList[n], nextNote;
                if (note.start > Project.Notes.SongLengthT) //only  if audio ends before the notes end
                {
                    continue;
                }

                if (n < noteList.Count - 1)
                {
                    nextNote = noteList[n + 1];
                }
                else if (completeNoteListIndex < midiTrack.Notes.Count - 1)
                {
                    nextNote = midiTrack.Notes[completeNoteListIndex + 1];
                }
                else
                {
                    nextNote = note;
                }

                Vector2 noteStart = Project.getScreenPos(note.start, note.pitch);
                float   noteEnd   = Project.getScreenPos(note.stop, note.pitch).X;

                Vector2 nextNoteStart = Project.getScreenPos(nextNote.start, nextNote.pitch);
                if (noteEnd > nextNoteStart.X && completeNoteListIndex < midiTrack.Notes.Count - 1)
                {
                    noteEnd = nextNoteStart.X;
                }

                bool endOfSegment = false;
                if ((float)(nextNote.start - note.stop) > Qn_gapThreshold * Project.Notes.TicksPerBeat || note == nextNote)
                {
                    if (nextNoteStart.X != noteStart.X)
                    {
                        nextNoteStart.Y = (int)MathHelper.Lerp(noteStart.Y, nextNoteStart.Y, (float)(noteEnd - noteStart.X) / (nextNoteStart.X - noteStart.X));
                    }
                    nextNoteStart.X = noteEnd;
                    endOfSegment    = true;
                }

                float startDraw = noteStart.X;
                float endDraw   = nextNoteStart.X;

                //Don't draw if length is 0
                if (startDraw == endDraw)
                {
                    continue;
                }

                float curvature = calcLinearLineAngle(n, trackProps.TrackView.Curve);
                //if (n > 0)
                //{
                //	float prevCurvature = calcLinearLineAngle(n - 1, trackProps.TrackView.Curve);
                //	if (prevCurvature > curvature)
                //		curvature = (prevCurvature + curvature) / 2;    //Prevent too big jumps between levels of tesselation which will cause sharp bends
                //}
                if (n < noteList.Count - 1)
                {
                    curvature = Math.Max(curvature, calcLinearLineAngle(n + 1, trackProps.TrackView.Curve));
                }

                //curvature /= (float)Math.PI; //Map to [0,1]
                curvature = Math.Min(curvature, 0.97f * (float)Math.PI); //Clip below 180 degrees to avoid extreme tesselation
                curvature = (float)Math.Pow(curvature, 2.25) * 1000;
                float step;
                if (curvature == 0)
                {
                    step = (endDraw - startDraw) * 0.999f; //Only one point for the note
                }
                else
                {
                    step = 1 / curvature;
                }

                if (step >= endDraw - startDraw)
                {
                    step = (endDraw - startDraw);// * 0.999f;
                }
                int iterations = (int)((endDraw - startDraw) / step);
                if (iterations < 0)
                {
                    throw new OverflowException($"Too many vertices for note {n}, track {trackProps.TrackView.TrackNumber}.");
                }
                step = (endDraw - startDraw) / (iterations + 1);

                Vector3 bboxStart = Vector3.Zero;

                for (float x = startDraw; x <= endDraw + 0.00001f; x += step)
                {
                    Vector3 center, normal, vertexOffset;
                    getCurvePoint(out center, out normal, out vertexOffset, step, x, trackProps, vpLineWidth);
                    //normal.X = curvature/10f;
                    lineVerts[vertIndex].normal = lineVerts[vertIndex + 1].normal = normal;

                    //Create vertices
                    //adjustCurvePoint(center, vertexOffset, -1, trackProps, lineVerts, vertIndex, step, vpLineWidth);
                    //adjustCurvePoint(center, vertexOffset, 1, trackProps, lineVerts, vertIndex + 1, step, vpLineWidth);

                    //curvature = trackProps.TrackView.Curve.EvaluateCurvature(Project.getTimeT(x));
                    //center.Y = curvature / 10;
                    lineVerts[vertIndex].pos     = center - vertexOffset;
                    lineVerts[vertIndex + 1].pos = center + vertexOffset;
                    lineVerts[vertIndex].center  = lineVerts[vertIndex + 1].center = center;
                    float normStepFromNoteStart = (x - startDraw) / (nextNoteStart.X - noteStart.X);
                    //lineVerts[vertIndex].normStepFromNoteStart = lineVerts[vertIndex + 1].normStepFromNoteStart = normStepFromNoteStart;
                    lineVerts[vertIndex].normPos     = new Vector2(normStepFromNoteStart, 0);
                    lineVerts[vertIndex + 1].normPos = new Vector2(normStepFromNoteStart, 1);

                    if (texMaterial.TexProps.Texture != null)
                    {
                        calcTexCoords(out lineVerts[vertIndex].texCoords, out lineVerts[vertIndex + 1].texCoords, texMaterial.TexProps, x - startDraw, normStepFromNoteStart, vpLineWidth, lineVerts[vertIndex].pos, lineVerts[vertIndex + 1].pos);
                    }

                    if (LineType == VisualMusic.LineType.Ribbon)
                    {
                        float hLineStart = center.X;
                        float hLineEnd   = hLineStart;
                        do
                        {
                            hLineEnd += step;
                        } while ((int)center.Y == (int)Project.getCurveScreenY((float)hLineEnd + step, trackProps.TrackView.Curve) && hLineEnd < endDraw);
                        if (hLineEnd > hLineStart + vpLineWidth / 2)
                        {
                            hLineVerts[hLineVertIndex++] = lineVerts[vertIndex];
                            hLineVerts[hLineVertIndex++] = lineVerts[vertIndex + 1];
                        }
                        //float horizontalFactor = Math.Abs(normal.Y);
                        //float horizontalLimit = 0.98f;
                        //float minThickness = 0.001f;
                        //if (horizontalFactor > horizontalLimit)
                        //{ //todo use vertexoffset for non-ribbon instead of normal
                        //	horizontalFactor = (horizontalFactor - horizontalLimit) / (1 - horizontalLimit);  //[horizontalFactor, 1] -> [0, 1]
                        //	lineVerts[vertIndex].pos.Y -= minThickness * horizontalFactor * Math.Sign(normal.X);
                        //}
                    }

                    if (x == startDraw && vertIndex > 3)
                    {
                        lineVerts[vertIndex].pos     = lineVerts[vertIndex - 2].pos;
                        lineVerts[vertIndex + 1].pos = lineVerts[vertIndex - 1].pos;
                    }

                    //Create bounding box
                    if (bboxStart == Vector3.Zero)
                    {
                        bboxStart = lineVerts[vertIndex].center;
                    }
                    Vector3 bboxEnd = lineVerts[vertIndex].center;
                    if (Vector3.DistanceSquared(bboxStart, bboxEnd) > bboxMinSqLength)
                    {
                        Vector3 bboxCenter = (bboxStart + bboxEnd) / 2;
                        geo.bboxes.Add(new BoundingBoxEx(bboxCenter, bboxEnd - bboxCenter, bboxEnd - lineVerts[vertIndex].pos, new Vector3(0, 0, 0)));
                        bboxStart = bboxEnd;
                    }

                    vertIndex += 2;

                    if (vertIndex >= MaxLineVerts - 2 || hLineVertIndex >= MaxHLineVerts - 2)
                    {
                        createLineSegment(ref vertIndex, ref hLineVertIndex, lineGeo, vpLineWidth);
                        x -= step;
                    }
                    //break;
                }

                if (!(bool)Continuous)
                {
                    endOfSegment = true; //One draw call per note. Can be used to avoid glitches between notes because of instant IN.normStepFromNoteStart interpolation from 1 to 0.
                }
                if (endOfSegment)
                {
                    createLineSegment(ref vertIndex, ref hLineVertIndex, lineGeo, vpLineWidth);
                }

                completeNoteListIndex++;
            }
            createLineSegment(ref vertIndex, ref hLineVertIndex, lineGeo, vpLineWidth);
        }