public void UpdateBuffer(BufferedGeometryData buffer, Vector3 viewPos, Matrix worldMat,
                                 IAtom[] atoms)
        {
            int stride = buffer.vBuffers[0].Stride;
            int objs   = buffer.vBuffers[0].NumElements;

            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            long pos = 0;

            foreach (IAtom atom in atoms)
            {
                // transform atom point to world-space
                Vector3 atomPos  = new Vector3((float)atom.X3d, (float)atom.Y3d, (float)atom.Z3d);
                Vector4 atomPosT = Vector3.Transform(atomPos, worldMat);
                // calc V to view pos
                Vector3 atomToView = new Vector3(atomPosT.X, atomPosT.Y, atomPosT.Z) - viewPos;
                atomToView.Normalize();
                Vector3 atomNewPos = (atomToView * 0.3f) + atomPos;

                data.Seek(pos, SeekOrigin.Begin);
                data.Write(atomNewPos.X);
                data.Write(atomNewPos.Y);
                data.Write(atomNewPos.Z);

                pos += stride;
            }

            buffer.vBuffers[0].Buffer.Unlock();
        }
        public override void CreateGeometryForObjects(Device device, ICollection <IAtom> objs,
                                                      GeomDataBufferStream geomStream, int stream,
                                                      ref BufferedGeometryData buffer, CompleteOutputDescription coDesc)
        {
            // fillable fields
            int positionPos = -1;
            int sizePos     = -1;
            int diffusePos  = -1;

            // match field locations
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                        {
                            positionPos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "DIFFUSE")
                        {
                            diffusePos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "SIZEFLOAT")
                        {
                            sizePos = geomStream.FieldPositions[gf];
                        }
                        break;
                    }
                }
            }

            // create buffers
            buffer                    = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers           = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0]        = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Buffer = new VertexBuffer(typeof(MetaBlobsEffect.PointVertex), objs.Count, device, Usage.None, VertexFormats.Position | VertexFormats.PointSize | VertexFormats.Diffuse, Pool.SystemMemory);

            /*new VertexBuffer(device, geomStream.Stride * objs.Count,
             *                                       Usage.WriteOnly, geomStream.Format, Pool.SystemMemory);*/
            buffer.vBuffers[0].Stride      = geomStream.Stride;
            buffer.vBuffers[0].NumElements = objs.Count;
            buffer.vBuffers[0].Format      = geomStream.Format;
            buffer.DataValidity            = BufferedGeometryData.DataValidityType.Source;
            buffer.Target = BufferedGeometryData.DataTarget.Geometry;

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            // fill fields

            // create points
            AtomShadingDesc aShading = coDesc.AtomShadingDesc;
            long            pos      = 0;

            foreach (IAtom atom in objs)
            {
                int period = 1;
                if (atom.Properties.ContainsKey("Period"))
                {
                    period = (int)atom.Properties["Period"];
                }

                if (positionPos != -1)
                {
                    data.Seek(pos + positionPos, SeekOrigin.Begin);
                    data.Write((float)atom.X3d);
                    data.Write((float)atom.Y3d);
                    data.Write((float)atom.Z3d);
                }
                if (sizePos != -1)
                {
                    data.Seek(pos + sizePos, SeekOrigin.Begin);
                    data.Write((float)period);
                }
                if (diffusePos != -1)
                {
                    IMoleculeMaterialLookup   lookup   = aShading.MoleculeMaterials;
                    IMoleculeMaterialTemplate matTemp  = lookup.ResolveBySymbol(atom.Symbol);
                    IMoleculeMaterial         material = null;
                    if (matTemp != null)
                    {
                        material = matTemp.BySymbol;
                    }
                    else
                    {
                        PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
                        if (pe != null)
                        {
                            material = lookup.GetBySeries(pe.ChemicalSerie);
                        }
                    }
                    if (material != null)
                    {
                        data.Seek(pos + diffusePos, SeekOrigin.Begin);
                        //data.Write((float)material.BaseColor.ToArgb());
                        if (material.BaseColor.R > 0)
                        {
                            data.Write(255f / material.BaseColor.R);
                        }
                        else
                        {
                            data.Write((float)0);
                        }
                        if (material.BaseColor.G > 0)
                        {
                            data.Write(255f / material.BaseColor.G);
                        }
                        else
                        {
                            data.Write((float)0);
                        }
                        if (material.BaseColor.B > 0)
                        {
                            data.Write(255f / material.BaseColor.B);
                        }
                        else
                        {
                            data.Write((float)0);
                        }
                    }
                }
                pos += geomStream.Stride;
            }
            buffer.vBuffers[0].Buffer.Unlock();
        }
        public override void CreateGeometryForObjects(Device device, ICollection <IBond> objs,
                                                      GeomDataBufferStream geomStream, int stream,
                                                      ref BufferedGeometryData buffer, CompleteOutputDescription coDesc)
        {
            // fillable fields
            int positionPos = -1;
            int normalPos   = -1;
            int diffusePos  = -1;
            int texPos      = -1;

            // match field locations
            //int[] fieldsPos = new int[fields.Length];
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                        {
                            positionPos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "NORMAL")
                        {
                            normalPos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "DIFFUSE")
                        {
                            diffusePos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "TEXTURE0")
                        {
                            texPos = geomStream.FieldPositions[gf];
                        }
                        //fieldsPos[i] = geomStream.FieldPositions[gf];
                        break;
                    }
                }
            }

            // count bond orders via preview data
            int numActualBonds = 0;

            foreach (IBond bond in objs)
            {
                numActualBonds += (int)bond.Order;
            }

            int numVerts = 0;

            if (coDesc.BondShadingDesc.BlendEndClrs)
            {
                numVerts = numActualBonds * 2;
            }
            else
            {
                numVerts = numActualBonds * 4;
            }

            // create buffers
            buffer                         = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers                = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0]             = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Stride      = geomStream.Stride;
            buffer.vBuffers[0].NumElements = numVerts;
            buffer.vBuffers[0].Format      = geomStream.Format;

            buffer.iBuffers                  = new BufferedGeometryData.IndexData[1];
            buffer.iBuffers[0]               = new BufferedGeometryData.IndexData();
            buffer.iBuffers[0].Desc          = BufferedGeometryData.IndexData.Description.Geometry;
            buffer.iBuffers[0].NumPrimitives = numVerts / 2;
            buffer.iBuffers[0].PrimType      = PrimitiveType.LineList;

            buffer.vBuffers[0].NumElements = numVerts;
            buffer.vBuffers[0].Buffer      = new VertexBuffer(device, geomStream.Stride * numVerts,
                                                              Usage.WriteOnly, geomStream.Format, Pool.Managed);

            // write bonds to buffer
            Vector3 direction, directionUV;

            IAtom[]           atoms;
            Vector3[]         atomsPos;
            IMoleculeMaterial materialA, materialB;

            Vector3[]       bondInstances = null;
            float           midPos;
            BondShadingDesc bShading = coDesc.BondShadingDesc;

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            long pos = 0;

            foreach (IBond bond in objs)
            {
                GenericBondSetup(bond, false, bShading, out direction, out directionUV,
                                 out atoms, out atomsPos, out materialA, out materialB);

                // calc bond positioning / instances
                GenericBondCalcPositions(bond, bShading, direction, directionUV,
                                         atoms, atomsPos, 0.1f, out bondInstances,
                                         out midPos, true);

                // draw bond instances
                for (int bInst = 0; bInst < bondInstances.Length; bInst += 2)
                {
                    if (bShading.BlendEndClrs)
                    {
                        GenericDrawBondSolidBlended(bondInstances[bInst], bondInstances[bInst + 1],
                                                    materialA, materialB, data, ref pos, geomStream.Stride, positionPos, diffusePos);
                        //GenericDrawBondDashedBlended(bondInstances[bInst], bondInstances[bInst + 1],
                        //                            materialA, materialB);
                    }
                    else
                    {
                        Vector3 sectA = directionUV * midPos;

                        // convert into points (2 lines)
                        if (positionPos != -1)
                        {
                            data.Seek(pos + positionPos, SeekOrigin.Begin);
                            data.Write(bondInstances[bInst].X);
                            data.Write(bondInstances[bInst].Y);
                            data.Write(bondInstances[bInst].Z);

                            data.Seek(pos + geomStream.Stride + positionPos, SeekOrigin.Begin);
                            Vector3 p = bondInstances[bInst] + sectA;
                            data.Write(p.X);
                            data.Write(p.Y);
                            data.Write(p.Z);

                            data.Seek(pos + geomStream.Stride + geomStream.Stride + positionPos, SeekOrigin.Begin);
                            data.Write(p.X);
                            data.Write(p.Y);
                            data.Write(p.Z);

                            data.Seek(pos + geomStream.Stride + geomStream.Stride + geomStream.Stride + positionPos, SeekOrigin.Begin);
                            data.Write(bondInstances[bInst + 1].X);
                            data.Write(bondInstances[bInst + 1].Y);
                            data.Write(bondInstances[bInst + 1].Z);
                        }
                        if (diffusePos != -1)
                        {
                            data.Seek(pos + diffusePos, SeekOrigin.Begin);
                            int clr = materialA.BaseColor.ToArgb();
                            data.Write(clr);

                            data.Seek(pos + geomStream.Stride + diffusePos, SeekOrigin.Begin);
                            data.Write(clr);

                            clr = materialB.BaseColor.ToArgb();
                            data.Seek(pos + geomStream.Stride + geomStream.Stride + diffusePos, SeekOrigin.Begin);
                            data.Write(clr);

                            data.Seek(pos + geomStream.Stride + geomStream.Stride + geomStream.Stride + diffusePos, SeekOrigin.Begin);
                            data.Write(clr);
                        }

                        pos += geomStream.Stride * 4;
                    }
                }
            }

            buffer.vBuffers[0].Buffer.Unlock();
        }
        public override void UpdateFrameData(BufferedGeometryData[] geomData, GraphicsPipeline3D pipeline)
        {
            PointVertex[] blobPoints = (PointVertex[])geomData[0].vBuffers[0].Buffer.Lock(0, LockFlags.None);
            numPoints = blobPoints.Length;

            if (needsReset)
                OnReset();

            FillBlobVB(pipeline.WorldMatrix * pipeline.ViewMatrix, pipeline.ProjectionMatrix, ref blobPoints);
            
            geomData[0].vBuffers[0].Buffer.Unlock();
        }
        public override void CreateGeometryForObjects(Device device, ICollection<IAtom> objs,
                                                      GeomDataBufferStream geomStream, int stream,
                                                      ref BufferedGeometryData buffer, CompleteOutputDescription coDesc)
        {
            // fillable fields
            int positionPos = -1;
            int normalPos = -1;
            int diffusePos = -1;

            // match field locations
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                            positionPos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "NORMAL")
                            normalPos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "DIFFUSE")
                            diffusePos = geomStream.FieldPositions[gf];
                        break;
                    }
                }
            }

            // actually create the metaball triangles or points
            IVolume[] volumes = new IVolume[objs.Count];
            int sIdx = 0;
            AtomShadingDesc aShading = coDesc.AtomShadingDesc;
            IMoleculeMaterialLookup lookup = aShading.MoleculeMaterials;
            foreach (IAtom atom in objs)
            {
                IMoleculeMaterialTemplate matTemp = lookup.ResolveBySymbol(atom.Symbol);
                IMoleculeMaterial material = null;
                if (matTemp != null)
                    material = matTemp.BySymbol;
                else
                {
                    PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
                    if (pe != null)
                        material = lookup.GetBySeries(pe.ChemicalSerie);
                }

                volumes[sIdx++] = new Metaball(new Vector3((float)atom.X3d, (float)atom.Y3d, (float)atom.Z3d), 0.17f, material.BaseColor);
            }

            // process volume into triangles
            GenericVolumeScene scene = new GenericVolumeScene(volumes);
            int[] triangles = null;
            Vector3[] vertices;
            Color[] colours;
            Vector3[] normals = null;

            if (!pointsOnly)
            {
                IsosurfaceGenerator3D.GenerateSimpleMesh(scene, new Vector3(), scene.EstimateVolumeMaxSize(), 40, false, out triangles, out vertices, out colours);
                MeshOptimzer.GenerateTriPointNormals(triangles, vertices, out normals);
            }
            else
                IsosurfaceGenerator3D.GenerateSimplePointOutline(scene, new Vector3(), scene.EstimateVolumeMaxSize(), 40, out vertices, out colours);

            // create buffers
            buffer = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0] = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Buffer = new VertexBuffer(device, geomStream.Stride * vertices.Length,
                                                         Usage.WriteOnly, geomStream.Format, Pool.Managed);
            buffer.vBuffers[0].Stride = geomStream.Stride;
            buffer.vBuffers[0].NumElements = vertices.Length;
            buffer.vBuffers[0].Format = geomStream.Format;

            buffer.iBuffers = new BufferedGeometryData.IndexData[1];
            buffer.iBuffers[0] = new BufferedGeometryData.IndexData();
            buffer.iBuffers[0].Desc = BufferedGeometryData.IndexData.Description.Geometry;
            if (pointsOnly)
            {
                buffer.iBuffers[0].NumPrimitives = vertices.Length;
                buffer.iBuffers[0].PrimType = PrimitiveType.PointList;
                buffer.Light = false;
            }
            else
            {
                buffer.iBuffers[0].NumPrimitives = triangles.Length / 3;
                buffer.iBuffers[0].PrimType = PrimitiveType.TriangleList;
                buffer.iBuffers[0].Buffer = new IndexBuffer(typeof(int), triangles.Length, device, Usage.WriteOnly, Pool.Managed);
            }

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            // fill fields

            int clr = Color.FromArgb(255, 255, 255).ToArgb();
            long pos = 0;
            for (int i = 0; i < vertices.Length; i++)
            {
                if (positionPos != -1)
                {
                    data.Seek(pos + positionPos, SeekOrigin.Begin);
                    data.Write(vertices[i].X);
                    data.Write(vertices[i].Y);
                    data.Write(vertices[i].Z);
                }
                if (normalPos != -1 && !pointsOnly)
                {
                    data.Seek(pos + normalPos, SeekOrigin.Begin);
                    data.Write(normals[i].X);
                    data.Write(normals[i].Y);
                    data.Write(normals[i].Z);
                }
                if (diffusePos != -1)
                {
                    data.Seek(pos + diffusePos, SeekOrigin.Begin);
                    data.Write(colours[i].ToArgb());
                }
                //verts[i].Color = colours[i].ToArgb();
                pos += geomStream.Stride;
            }

            buffer.vBuffers[0].Buffer.Unlock();

            if (!pointsOnly)
                buffer.iBuffers[0].Buffer.SetData(triangles, 0, LockFlags.None);

            // dispose of temp data
        }
        public override void CreateGeometryForObjects(Device device, ICollection<IAtom> objs,
                                                      GeomDataBufferStream geomStream, int stream,
                                                      ref BufferedGeometryData buffer, CompleteOutputDescription coDesc)
        {
            if (spriteTexture == null)
            {
                Stream texstm = Assembly.GetExecutingAssembly().GetManifestResourceStream("NuGenSVisualLib.Resources.Atom.PNG");
                spriteTexture = TextureLoader.FromStream(device, texstm);
            }

            // fillable fields
            int positionPos = -1;
            int sizePos = -1;
            int diffusePos = -1;

            // match field locations
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                            positionPos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "DIFFUSE")
                            diffusePos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "POINTSIZE")
                            sizePos = geomStream.FieldPositions[gf];
                        break;
                    }
                }
            }

            // create buffers
            buffer = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0] = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Buffer = new VertexBuffer(typeof(PointSprite), objs.Count, device, Usage.WriteOnly,
                                                         geomStream.Format, Pool.Managed);
                /*new VertexBuffer(device, geomStream.Stride * objs.Count,
                                                         Usage.None, geomStream.Format, Pool.Managed);*/
            buffer.vBuffers[0].Stride = geomStream.Stride;
            buffer.vBuffers[0].NumElements = objs.Count;
            buffer.vBuffers[0].Format = geomStream.Format;

            buffer.iBuffers = new BufferedGeometryData.IndexData[1];
            buffer.iBuffers[0] = new BufferedGeometryData.IndexData();
            buffer.iBuffers[0].Desc = BufferedGeometryData.IndexData.Description.Sprites;
            buffer.iBuffers[0].NumPrimitives = objs.Count;
            buffer.iBuffers[0].PrimType = PrimitiveType.PointList;

            buffer.iBuffers[0].Textures = new Texture[] { spriteTexture };

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            AtomShadingDesc aShading = coDesc.AtomShadingDesc;

            long pos = 0;
            foreach (IAtom atom in objs)
            {
                if (positionPos != -1)
                {
                    data.Seek(pos + positionPos, SeekOrigin.Begin);
                    data.Write((float)atom.X3d);
                    data.Write((float)atom.Y3d);
                    data.Write((float)atom.Z3d);
                }
                if (sizePos != -1)
                {
                    data.Seek(pos + sizePos, SeekOrigin.Begin);
                    int period = 1;
                    if (atom.Properties.ContainsKey("Period"))
                        period = (int)atom.Properties["Period"];
                    data.Write((float)period * 0.4f);
                }
                if (diffusePos != -1)
                {
                    IMoleculeMaterialLookup lookup = aShading.MoleculeMaterials;
                    IMoleculeMaterialTemplate matTemp = lookup.ResolveBySymbol(atom.Symbol);
                    IMoleculeMaterial material = null;
                    if (matTemp != null)
                        material = matTemp.BySymbol;
                    else
                    {
                        PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
                        if (pe != null)
                            material = lookup.GetBySeries(pe.ChemicalSerie);
                    }

                    data.Seek(pos + diffusePos, SeekOrigin.Begin);
                    data.Write(material.BaseColor.ToArgb());
                }
                pos += geomStream.Stride;
            }

            /*Dictionary<int, List<int>> atomSizeGroups = new Dictionary<int, List<int>>();
            // first split into group counts
            int aIdx = 0;
            foreach (IAtom[] atoms in atomSets)
            {
                foreach (IAtom atom in atoms)
                {
                    int period = 1;
                    if (atom.Properties.ContainsKey("Period"))
                        period = (int)atom.Properties["Period"];

                    List<int> groupAtoms = null;
                    if (!atomSizeGroups.TryGetValue(period, out groupAtoms))
                        atomSizeGroups.Add(period, groupAtoms = new List<int>());

                    groupAtoms.Add(aIdx++);
                }
            }

            int vertsIdx = 0;
            Dictionary<int, List<int>>.Enumerator group = atomSizeGroups.GetEnumerator();
            sBuffer.groupLengths = new int[atomSizeGroups.Count];
            sBuffer.groupSizes = new int[atomSizeGroups.Count];
            sBuffer.groupStarts = new int[atomSizeGroups.Count];
            int bIdx = 0;
            while (group.MoveNext())
            {
                int groupPeriod = group.Current.Key;
                List<int> groupMembers = group.Current.Value;
                aIdx = 0;
                int gIdx = 0;
                sBuffer.groupSizes[bIdx] = groupPeriod;
                sBuffer.groupStarts[bIdx] = vertsIdx;
                sBuffer.groupLengths[bIdx] = groupMembers.Count;
                foreach (IAtom[] atoms in atomSets)
                {
                    foreach (IAtom atom in atoms)
                    {
                        if (aIdx == groupMembers[gIdx])
                        {
                            IMoleculeMaterialLookup lookup = aShading.MoleculeMaterials;
                            IMoleculeMaterialTemplate matTemp = lookup.ResolveBySymbol(atom.Symbol);
                            IMoleculeMaterial material = null;
                            if (matTemp != null)
                                material = matTemp.BySymbol;
                            else
                            {
                                PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
                                if (pe != null)
                                    material = lookup.GetBySeries(pe.ChemicalSerie);
                            }

                            atomVerts[vertsIdx].Position = new Vector3((float)atom.X3d, (float)atom.Y3d, (float)atom.Z3d);
                            atomVerts[vertsIdx].Color = material.BaseColor.ToArgb();
                            vertsIdx++;
                            gIdx++;
                        }
                        if (gIdx == groupMembers.Count)
                            break;
                        aIdx++;
                    }
                    if (gIdx == groupMembers.Count)
                        break;
                }
                bIdx++;
            }*/
            buffer.vBuffers[0].Buffer.Unlock();
        }
 public virtual void UpdateFrameData(BufferedGeometryData[] geomData, GraphicsPipeline3D pipeline) { }
Beispiel #8
0
        public override void CreateGeometryForObjects(Device device, ICollection <IAtom> objs,
                                                      GeomDataBufferStream geomStream, int stream,
                                                      ref BufferedGeometryData buffer, CompleteOutputDescription coDesc)
        {
            // fillable fields
            int positionPos = -1;
            int normalPos   = -1;
            int diffusePos  = -1;

            // match field locations
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                        {
                            positionPos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "NORMAL")
                        {
                            normalPos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "DIFFUSE")
                        {
                            diffusePos = geomStream.FieldPositions[gf];
                        }
                        break;
                    }
                }
            }

            // actually create the metaball triangles or points
            IVolume[]               volumes  = new IVolume[objs.Count];
            int                     sIdx     = 0;
            AtomShadingDesc         aShading = coDesc.AtomShadingDesc;
            IMoleculeMaterialLookup lookup   = aShading.MoleculeMaterials;

            foreach (IAtom atom in objs)
            {
                IMoleculeMaterialTemplate matTemp  = lookup.ResolveBySymbol(atom.Symbol);
                IMoleculeMaterial         material = null;
                if (matTemp != null)
                {
                    material = matTemp.BySymbol;
                }
                else
                {
                    PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
                    if (pe != null)
                    {
                        material = lookup.GetBySeries(pe.ChemicalSerie);
                    }
                }

                volumes[sIdx++] = new Metaball(new Vector3((float)atom.X3d, (float)atom.Y3d, (float)atom.Z3d), 0.17f, material.BaseColor);
            }

            // process volume into triangles
            GenericVolumeScene scene = new GenericVolumeScene(volumes);

            int[]     triangles = null;
            Vector3[] vertices;
            Color[]   colours;
            Vector3[] normals = null;

            if (!pointsOnly)
            {
                IsosurfaceGenerator3D.GenerateSimpleMesh(scene, new Vector3(), scene.EstimateVolumeMaxSize(), 40, false, out triangles, out vertices, out colours);
                MeshOptimzer.GenerateTriPointNormals(triangles, vertices, out normals);
            }
            else
            {
                IsosurfaceGenerator3D.GenerateSimplePointOutline(scene, new Vector3(), scene.EstimateVolumeMaxSize(), 40, out vertices, out colours);
            }

            // create buffers
            buffer                    = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers           = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0]        = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Buffer = new VertexBuffer(device, geomStream.Stride * vertices.Length,
                                                         Usage.WriteOnly, geomStream.Format, Pool.Managed);
            buffer.vBuffers[0].Stride      = geomStream.Stride;
            buffer.vBuffers[0].NumElements = vertices.Length;
            buffer.vBuffers[0].Format      = geomStream.Format;

            buffer.iBuffers         = new BufferedGeometryData.IndexData[1];
            buffer.iBuffers[0]      = new BufferedGeometryData.IndexData();
            buffer.iBuffers[0].Desc = BufferedGeometryData.IndexData.Description.Geometry;
            if (pointsOnly)
            {
                buffer.iBuffers[0].NumPrimitives = vertices.Length;
                buffer.iBuffers[0].PrimType      = PrimitiveType.PointList;
                buffer.Light = false;
            }
            else
            {
                buffer.iBuffers[0].NumPrimitives = triangles.Length / 3;
                buffer.iBuffers[0].PrimType      = PrimitiveType.TriangleList;
                buffer.iBuffers[0].Buffer        = new IndexBuffer(typeof(int), triangles.Length, device, Usage.WriteOnly, Pool.Managed);
            }

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            // fill fields

            int  clr = Color.FromArgb(255, 255, 255).ToArgb();
            long pos = 0;

            for (int i = 0; i < vertices.Length; i++)
            {
                if (positionPos != -1)
                {
                    data.Seek(pos + positionPos, SeekOrigin.Begin);
                    data.Write(vertices[i].X);
                    data.Write(vertices[i].Y);
                    data.Write(vertices[i].Z);
                }
                if (normalPos != -1 && !pointsOnly)
                {
                    data.Seek(pos + normalPos, SeekOrigin.Begin);
                    data.Write(normals[i].X);
                    data.Write(normals[i].Y);
                    data.Write(normals[i].Z);
                }
                if (diffusePos != -1)
                {
                    data.Seek(pos + diffusePos, SeekOrigin.Begin);
                    data.Write(colours[i].ToArgb());
                }
                //verts[i].Color = colours[i].ToArgb();
                pos += geomStream.Stride;
            }

            buffer.vBuffers[0].Buffer.Unlock();

            if (!pointsOnly)
            {
                buffer.iBuffers[0].Buffer.SetData(triangles, 0, LockFlags.None);
            }

            // dispose of temp data
        }
        public override void CreateGeometryForObjects(Device device, ICollection <IAtom> objs, GeomDataBufferStream geomStream,
                                                      int stream, ref BufferedGeometryData buffer,
                                                      CompleteOutputDescription coDesc)
        {
            // fillable fields
            int positionPos = -1;
            int normalPos   = -1;
            int diffusePos  = -1;
            int texPos      = -1;

            // match field locations
            //int[] fieldsPos = new int[fields.Length];
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                        {
                            positionPos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "NORMAL")
                        {
                            normalPos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "DIFFUSE")
                        {
                            diffusePos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "TEXTURE0")
                        {
                            texPos = geomStream.FieldPositions[gf];
                        }
                        //fieldsPos[i] = geomStream.FieldPositions[gf];
                        break;
                    }
                }
            }

            int numVerts = sphereDetail1 * sphereDetail2 * 6;
            int numTris  = sphereDetail1 * sphereDetail2 * 2;

            // create buffers
            buffer                    = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers           = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0]        = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Buffer = new VertexBuffer(device, geomStream.Stride * numVerts * objs.Count,
                                                         Usage.WriteOnly, geomStream.Format, Pool.Managed);
            buffer.vBuffers[0].Stride      = geomStream.Stride;
            buffer.vBuffers[0].NumElements = objs.Count * numVerts;
            buffer.vBuffers[0].Format      = geomStream.Format;

            buffer.iBuffers                  = new BufferedGeometryData.IndexData[1];
            buffer.iBuffers[0]               = new BufferedGeometryData.IndexData();
            buffer.iBuffers[0].Desc          = BufferedGeometryData.IndexData.Description.Geometry;
            buffer.iBuffers[0].NumPrimitives = objs.Count * numTris;
            buffer.iBuffers[0].PrimType      = PrimitiveType.TriangleList;

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            // fill fields
            bool newWay = true;

            if (!newWay)
            {
                // create template sphere
                SphereMathHelper.SphereN sphere = SphereMathHelper.CalcSphereWNormals(sphereDetail1, sphereDetail2, 1.0f, new Vector3(), true);

                // clone and scale template for each size required
                Vector3 center = new Vector3();
                Dictionary <int, Vector3[]> spheres  = new Dictionary <int, Vector3[]>();
                AtomShadingDesc             aShading = coDesc.AtomShadingDesc;

                //int vertsIdx = 0;
                long pos = 0;
                foreach (IAtom atom in objs)
                {
                    int period = 1;
                    if (atom.Properties.ContainsKey("Period"))
                    {
                        period = (int)atom.Properties["Period"];
                    }

                    // check for existing
                    if (!spheres.ContainsKey(period))
                    {
                        // scale template
                        float     size      = period * _Scaling;
                        Vector4[] vertices  = Vector3.Transform(sphere.Positions, Matrix.Scaling(size, size, size));
                        Vector3[] vertices3 = new Vector3[vertices.Length];
                        for (int i = 0; i < vertices.Length; i++)
                        {
                            vertices3[i] = new Vector3(vertices[i].X, vertices[i].Y, vertices[i].Z);
                        }
                        spheres.Add(period, vertices3);
                    }
                    Vector3[] sphereData = spheres[period];

                    // write to buffer
                    IMoleculeMaterialLookup   lookup   = aShading.MoleculeMaterials;
                    IMoleculeMaterialTemplate matTemp  = lookup.ResolveBySymbol(atom.Symbol);
                    IMoleculeMaterial         material = null;
                    if (matTemp != null)
                    {
                        material = matTemp.BySymbol;
                    }
                    else
                    {
                        PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
                        if (pe != null)
                        {
                            material = lookup.GetBySeries(pe.ChemicalSerie);
                        }
                    }

                    // copy sphere
                    Vector3 atomSpace = new Vector3((float)atom.X3d, (float)atom.Y3d, (float)atom.Z3d);

                    /*Vector4 clr = new Vector4((float)material.BaseColor.R / 255f, (float)material.BaseColor.G / 255f,
                     *                        (float)material.BaseColor.B / 255f, (float)material.BaseColor.A / 255f);*/
                    int clr = material.BaseColor.ToArgb();
                    for (int v = 0; v < sphereData.Length; v++)
                    {
                        if (positionPos != -1)
                        {
                            Vector3 position = sphereData[v] + atomSpace;
                            data.Seek(pos + positionPos, SeekOrigin.Begin);
                            data.Write(position.X);
                            data.Write(position.Y);
                            data.Write(position.Z);
                        }
                        if (texPos != -1)
                        {
                            data.Seek(pos + texPos, SeekOrigin.Begin);
                            data.Write(0f); //sphere.TexCoords[v].X);
                            data.Write(0f); //sphere.TexCoords[v].Y);
                        }
                        if (normalPos != -1)
                        {
                            data.Seek(pos + normalPos, SeekOrigin.Begin);
                            data.Write(sphere.Normals[v].X);
                            data.Write(sphere.Normals[v].Y);
                            data.Write(sphere.Normals[v].Z);
                        }
                        if (diffusePos != -1)
                        {
                            data.Seek(pos + diffusePos, SeekOrigin.Begin);

                            /*data.Write(clr.X);
                            *  data.Write(clr.Y);
                            *  data.Write(clr.Z);
                            *  data.Write(clr.W);*/
                            data.Write((Int32)clr);
                        }
                        pos += geomStream.Stride;
                    }
                }
            }
            else
            {
                Vector3[] Positions, normals;
                Vector2[] texCoords;
                SphereMathHelper.CreateSphereTriangles(new Vector3(), 1, sphereDetail1, out Positions,
                                                       out normals, out texCoords);

                // clone and scale template for each size required
                Vector3 center = new Vector3();
                Dictionary <int, Vector3[]> spheres  = new Dictionary <int, Vector3[]>();
                AtomShadingDesc             aShading = coDesc.AtomShadingDesc;

                int  vertsIdx = 0;
                long pos      = 0;
                foreach (IAtom atom in objs)
                {
                    int period = 1;
                    if (atom.Properties.ContainsKey("Period"))
                    {
                        period = (int)atom.Properties["Period"];
                    }

                    // check for existing
                    if (!spheres.ContainsKey(period))
                    {
                        // scale template
                        float     size      = period * _Scaling;
                        Vector4[] vertices  = Vector3.Transform(Positions, Matrix.Scaling(size, size, size));
                        Vector3[] vertices3 = new Vector3[vertices.Length];
                        for (int i = 0; i < vertices.Length; i++)
                        {
                            vertices3[i] = new Vector3(vertices[i].X, vertices[i].Y, vertices[i].Z);
                        }
                        spheres.Add(period, vertices3);
                    }
                    Vector3[] sphereData = spheres[period];

                    // write to buffer
                    IMoleculeMaterialLookup   lookup   = aShading.MoleculeMaterials;
                    IMoleculeMaterialTemplate matTemp  = lookup.ResolveBySymbol(atom.Symbol);
                    IMoleculeMaterial         material = null;
                    if (matTemp != null)
                    {
                        material = matTemp.BySymbol;
                    }
                    else
                    {
                        PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
                        if (pe != null)
                        {
                            material = lookup.GetBySeries(pe.ChemicalSerie);
                        }
                    }

                    // copy sphere
                    Vector3 atomSpace = new Vector3((float)atom.X3d, (float)atom.Y3d, (float)atom.Z3d);
                    int     clr       = material.BaseColor.ToArgb();
                    for (int v = 0; v < sphereData.Length; v++)
                    {
                        if (positionPos != -1)
                        {
                            Vector3 position = sphereData[v] + atomSpace;
                            data.Seek(pos + positionPos, SeekOrigin.Begin);
                            data.Write(position.X);
                            data.Write(position.Y);
                            data.Write(position.Z);
                        }
                        if (texPos != -1)
                        {
                            data.Seek(pos + texPos, SeekOrigin.Begin);
                            data.Write(texCoords[v].X);
                            data.Write(texCoords[v].Y);
                        }
                        if (normalPos != -1)
                        {
                            data.Seek(pos + normalPos, SeekOrigin.Begin);
                            data.Write(normals[v].X);
                            data.Write(normals[v].Y);
                            data.Write(normals[v].Z);
                        }
                        if (diffusePos != -1)
                        {
                            data.Seek(pos + diffusePos, SeekOrigin.Begin);

                            /*data.Write(clr.X);
                            *  data.Write(clr.Y);
                            *  data.Write(clr.Z);
                            *  data.Write(clr.W);*/
                            data.Write((Int32)clr);
                        }
                        pos += geomStream.Stride;
                    }
                }
            }

            buffer.vBuffers[0].Buffer.Unlock();
        }
        public override void CreateGeometryForObjects(Device device, ICollection <IAtom> objs,
                                                      GeomDataBufferStream geomStream, int stream,
                                                      ref BufferedGeometryData buffer, CompleteOutputDescription coDesc)
        {
            // fillable fields
            int positionPos = -1;
            int sizePos     = -1;

            // match field locations
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                        {
                            positionPos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "POINTSIZE")
                        {
                            sizePos = geomStream.FieldPositions[gf];
                        }
                        break;
                    }
                }
            }

            // pre-scan for index groups
            Dictionary <string, List <int> > groups = new Dictionary <string, List <int> >();
            int aIdx = 0;

            foreach (IAtom atom in objs)
            {
                if (!groups.ContainsKey(atom.Symbol))
                {
                    groups[atom.Symbol] = new List <int>();
                }
                groups[atom.Symbol].Add(aIdx++);
            }

            // create buffers
            buffer                    = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers           = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0]        = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Buffer = new VertexBuffer(typeof(PointSprite), objs.Count, device, Usage.WriteOnly,
                                                         geomStream.Format, Pool.Managed);
            buffer.vBuffers[0].Stride      = geomStream.Stride;
            buffer.vBuffers[0].NumElements = objs.Count;
            buffer.vBuffers[0].Format      = geomStream.Format;

            buffer.DataValidity = BufferedGeometryData.DataValidityType.View;

            ChemSymbolTextures cTex = ChemSymbolTextures.Instance;

            buffer.iBuffers = new BufferedGeometryData.IndexData[groups.Count];

            int gIdx = 0;

            foreach (KeyValuePair <string, List <int> > group in groups)
            {
                buffer.iBuffers[gIdx]               = new BufferedGeometryData.IndexData();
                buffer.iBuffers[gIdx].Desc          = BufferedGeometryData.IndexData.Description.Sprites;
                buffer.iBuffers[gIdx].NumPrimitives = group.Value.Count;
                buffer.iBuffers[gIdx].PrimType      = PrimitiveType.PointList;
                buffer.iBuffers[gIdx].Textures      = new Texture[] { cTex[group.Key] };

                buffer.iBuffers[gIdx].Buffer = new IndexBuffer(typeof(int), group.Value.Count, device,
                                                               Usage.WriteOnly, Pool.Managed);
                int[] indices = (int[])buffer.iBuffers[gIdx].Buffer.Lock(0, LockFlags.None);
                for (int i = 0; i < indices.Length; i++)
                {
                    indices[i] = group.Value[i];
                }
                buffer.iBuffers[gIdx].Buffer.Unlock();

                gIdx++;
            }

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            AtomShadingDesc aShading = coDesc.AtomShadingDesc;

            long pos = 0;

            foreach (IAtom atom in objs)
            {
                if (positionPos != -1)
                {
                    data.Seek(pos + positionPos, SeekOrigin.Begin);
                    data.Write((float)atom.X3d);
                    data.Write((float)atom.Y3d);
                    data.Write((float)atom.Z3d);
                }
                if (sizePos != -1)
                {
                    data.Seek(pos + sizePos, SeekOrigin.Begin);
                    int period = 1;
                    if (atom.Properties.ContainsKey("Period"))
                    {
                        period = (int)atom.Properties["Period"];
                    }
                    data.Write((float)period * 0.2f);
                }
                pos += geomStream.Stride;
            }
            buffer.vBuffers[0].Buffer.Unlock();
        }
Beispiel #11
0
        public override void CreateGeometryForObjects(Device device, ICollection <IBond> objs,
                                                      GeomDataBufferStream geomStream, int stream,
                                                      ref BufferedGeometryData buffer, CompleteOutputDescription coDesc)
        {
            // fillable fields
            int positionPos = -1;
            int normalPos   = -1;
            int diffusePos  = -1;
            int texPos      = -1;

            // match field locations
            //int[] fieldsPos = new int[fields.Length];
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                        {
                            positionPos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "NORMAL")
                        {
                            normalPos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "DIFFUSE")
                        {
                            diffusePos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "TEXTURE0")
                        {
                            texPos = geomStream.FieldPositions[gf];
                        }
                        //fieldsPos[i] = geomStream.FieldPositions[gf];
                        break;
                    }
                }
            }

            // count bond orders via preview data
            int numActualBonds = 0;

            foreach (IBond bond in objs)
            {
                numActualBonds += (int)bond.Order;
            }

            if (!coDesc.BondShadingDesc.BlendEndClrs)
            {
                numActualBonds *= 2;
            }

            int numTriangles = objs.Count * (numSides * 2);

            SphereMathHelper.EndType endType = SphereMathHelper.EndType.Open;
            float offset = 0.0f;

            switch (coDesc.BondShadingDesc.EndType)
            {
            case BondShadingDesc.BondEndTypes.Open:
                break;

            case BondShadingDesc.BondEndTypes.Closed:
                numTriangles += numActualBonds * (numSides * 2);
                endType       = SphereMathHelper.EndType.Flat;
                break;

            case BondShadingDesc.BondEndTypes.Point:
                offset        = 0.05f;
                numTriangles += numActualBonds * (numSides * 2);
                endType       = SphereMathHelper.EndType.Flat;
                break;

            case BondShadingDesc.BondEndTypes.Rounded:
                offset        = 0.075f;
                numTriangles += numActualBonds * (numSides * 6);
                endType       = SphereMathHelper.EndType.Rounded;
                break;
            }

            // build template bond
            Vector3[] tCylinderPoints, tCylinderEndPoints1, tCylinderEndPoints2;
            Vector3[] tCylinderNormals, tCylinderEndNormals1, tCylinderEndNormals2;
            int[]     tCylinderTris, tCylinderEndTris1, tCylinderEndTris2;

            SphereMathHelper.CalcCylinderTriangles(numSides, 1, 1.0f, new Vector3(0, 0, 0), new Vector3(0, 0, 1),
                                                   true, endType, offset, out tCylinderPoints,
                                                   out tCylinderNormals, out tCylinderTris, out tCylinderEndPoints1,
                                                   out tCylinderEndNormals1, out tCylinderEndTris1,
                                                   out tCylinderEndPoints2, out tCylinderEndNormals2,
                                                   out tCylinderEndTris2);
            int numActualVerts = tCylinderPoints.Length + tCylinderEndPoints1.Length + tCylinderEndPoints2.Length;
            int numActualTris  = tCylinderTris.Length + tCylinderEndTris1.Length + tCylinderEndTris2.Length;

            // create buffers
            buffer                         = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers                = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0]             = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Stride      = geomStream.Stride;
            buffer.vBuffers[0].NumElements = numActualVerts;
            buffer.vBuffers[0].Format      = geomStream.Format;

            buffer.vBuffers[0].NumElements = numActualVerts * numActualBonds;
            buffer.vBuffers[0].Buffer      = new VertexBuffer(device, geomStream.Stride * numActualTris * numActualBonds * 3,
                                                              Usage.WriteOnly, geomStream.Format, Pool.Managed);

            buffer.iBuffers                  = new BufferedGeometryData.IndexData[1];
            buffer.iBuffers[0]               = new BufferedGeometryData.IndexData();
            buffer.iBuffers[0].Desc          = BufferedGeometryData.IndexData.Description.Geometry;
            buffer.iBuffers[0].NumPrimitives = numActualTris;
            buffer.iBuffers[0].PrimType      = PrimitiveType.TriangleList;

            buffer.iBuffers[0].NumPrimitives = (numActualTris * numActualBonds) / 3;

            /*buffer.iBuffers[0].Buffer = new IndexBuffer(typeof(int), numActualTris * numActualBonds, device,
             *                                          Usage.WriteOnly, Pool.Managed);*/

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            // write bonds to buffer
            Vector3 direction, directionUV;

            IAtom[]           atoms;
            Vector3[]         atomsPos;
            IMoleculeMaterial matA, matB;

            foreach (IBond bond in objs)
            {
                BondLinesBufferCreator.GenericBondSetup(bond, true, coDesc.BondShadingDesc, out direction,
                                                        out directionUV, out atoms, out atomsPos, out matA,
                                                        out matB);

                // calc bond positioning / instances
                Vector3[] bondInstances = null;
                float     midPos;
                BondLinesBufferCreator.GenericBondCalcPositions(bond, coDesc.BondShadingDesc, direction,
                                                                directionUV, atoms, atomsPos, 0.15f,
                                                                out bondInstances, out midPos, false);

                long pos = 0;
                for (int bInst = 0; bInst < bondInstances.Length; bInst += 2)
                {
                    // translation
                    Matrix translate = Matrix.Translation(bondInstances[bInst]);

                    // rotation
                    double x = direction.X;
                    double y = direction.Y;
                    double z = direction.Z;

                    double alpha = (z == 0) ? Math.PI / 2 : Math.Atan(x / z);
                    double r     = (alpha == 0) ? z : x / Math.Sin(alpha);
                    float  sign  = 1f;
                    if (z != 0)
                    {
                        sign *= Math.Sign(z);
                    }
                    else if (x != 0)
                    {
                        sign *= Math.Sign(x);
                    }
                    if (y != 0)
                    {
                        sign *= Math.Sign(y);
                    }
                    double theta = -sign *Math.Abs((r == 0)?Math.PI / 2 : Math.Atan(y / r));

                    Matrix rotation = Matrix.RotationX((float)theta) * Matrix.RotationY((float)alpha);

                    // scaling
                    float zScale;
                    if (coDesc.BondShadingDesc.BlendEndClrs)
                    {
                        zScale = (bondInstances[1] - bondInstances[0]).Length();//(atomsPos[1] - atomsPos[0]).Length();//direction.Length();
                    }
                    else
                    {
                        zScale = midPos;
                    }
                    float  xyScale = 0.05f; // thickness
                    Matrix scale   = Matrix.Scaling(xyScale, xyScale, zScale);

                    // rotate & translate ends
                    if (tCylinderEndPoints1 != null)
                    {
                        Matrix    endFinal       = Matrix.Scaling(xyScale, xyScale, 1f) * rotation * translate;
                        Vector4[] tfEndTriangles = Vector3.Transform(tCylinderEndPoints1, endFinal);
                        // first end
                        for (int point = 0; point < tCylinderEndTris1.Length; point++)
                        {
                            int pointIdx = tCylinderEndTris1[point];
                            if (positionPos != -1)
                            {
                                data.Seek(pos + positionPos, SeekOrigin.Begin);
                                data.Write(tfEndTriangles[pointIdx].X);
                                data.Write(tfEndTriangles[pointIdx].Y);
                                data.Write(tfEndTriangles[pointIdx].Z);
                            }
                            if (normalPos != -1)
                            {
                                data.Seek(pos + normalPos, SeekOrigin.Begin);
                                data.Write(tCylinderEndNormals1[pointIdx].X);
                                data.Write(tCylinderEndNormals1[pointIdx].Y);
                                data.Write(tCylinderEndNormals1[pointIdx].Z);
                            }
                            if (diffusePos != -1)
                            {
                                data.Seek(pos + diffusePos, SeekOrigin.Begin);
                                data.Write(matA.BaseColor.ToArgb());
                            }
                            pos += geomStream.Stride;
                        }
                        // second end
                        endFinal = Matrix.Scaling(xyScale, xyScale, 1f) * rotation *
                                   Matrix.Translation(bondInstances[bInst + 1]);
                        tfEndTriangles = Vector3.Transform(tCylinderEndPoints2, endFinal);
                        // first end
                        for (int point = 0; point < tCylinderEndTris2.Length; point++)
                        {
                            int pointIdx = tCylinderEndTris2[point];
                            if (positionPos != -1)
                            {
                                data.Seek(pos + positionPos, SeekOrigin.Begin);
                                data.Write(tfEndTriangles[pointIdx].X);
                                data.Write(tfEndTriangles[pointIdx].Y);
                                data.Write(tfEndTriangles[pointIdx].Z);
                            }
                            if (normalPos != -1)
                            {
                                data.Seek(pos + normalPos, SeekOrigin.Begin);
                                data.Write(tCylinderEndNormals2[pointIdx].X);
                                data.Write(tCylinderEndNormals2[pointIdx].Y);
                                data.Write(tCylinderEndNormals2[pointIdx].Z);
                            }
                            if (diffusePos != -1)
                            {
                                data.Seek(pos + diffusePos, SeekOrigin.Begin);
                                data.Write(matB.BaseColor.ToArgb());
                            }
                            pos += geomStream.Stride;
                        }
                    }

                    Matrix final = scale * rotation * translate;

                    if (coDesc.BondShadingDesc.BlendEndClrs)
                    {
                        DrawSolidBondBlended(tCylinderPoints, tCylinderNormals, tCylinderTris,
                                             matA, matB, final, data, positionPos, normalPos,
                                             diffusePos, ref pos, geomStream.Stride, rotation);
                    }
                    else
                    {
                        float bLen2 = (bondInstances[bInst + 1] - (bondInstances[bInst] + (directionUV * midPos))).Length();

                        DrawSolidBondDistinct(tCylinderPoints, tCylinderNormals, tCylinderTris,
                                              matA, matB, final, data, xyScale, bLen2, rotation,
                                              bondInstances[bInst], directionUV, midPos, positionPos,
                                              normalPos, diffusePos, ref pos, geomStream.Stride);
                    }
                }
            }
        }
        public override void CreateGeometryForObjects(Device device, ICollection<IBond> objs,
                                                      GeomDataBufferStream geomStream, int stream,
                                                      ref BufferedGeometryData buffer, CompleteOutputDescription coDesc)
        {
            // fillable fields
            int positionPos = -1;
            int normalPos = -1;
            int diffusePos = -1;
            int texPos = -1;

            // match field locations
            //int[] fieldsPos = new int[fields.Length];
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                            positionPos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "NORMAL")
                            normalPos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "DIFFUSE")
                            diffusePos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "TEXTURE0")
                            texPos = geomStream.FieldPositions[gf];
                        //fieldsPos[i] = geomStream.FieldPositions[gf];
                        break;
                    }
                }
            }

            // count bond orders via preview data
            int numActualBonds = 0;
            foreach (IBond bond in objs)
            {
                numActualBonds += (int)bond.Order;
            }

            if (!coDesc.BondShadingDesc.BlendEndClrs)
                numActualBonds *= 2;

            int numTriangles = objs.Count * (numSides * 2);

            SphereMathHelper.EndType endType = SphereMathHelper.EndType.Open;
            float offset = 0.0f;
            switch (coDesc.BondShadingDesc.EndType)
            {
                case BondShadingDesc.BondEndTypes.Open:
                    break;
                case BondShadingDesc.BondEndTypes.Closed:
                    numTriangles += numActualBonds * (numSides * 2);
                    endType = SphereMathHelper.EndType.Flat;
                    break;
                case BondShadingDesc.BondEndTypes.Point:
                    offset = 0.05f;
                    numTriangles += numActualBonds * (numSides * 2);
                    endType = SphereMathHelper.EndType.Flat;
                    break;
                case BondShadingDesc.BondEndTypes.Rounded:
                    offset = 0.075f;
                    numTriangles += numActualBonds * (numSides * 6);
                    endType = SphereMathHelper.EndType.Rounded;
                    break;
            }

            // build template bond
            Vector3[] tCylinderPoints, tCylinderEndPoints1, tCylinderEndPoints2;
            Vector3[] tCylinderNormals, tCylinderEndNormals1, tCylinderEndNormals2;
            int[] tCylinderTris, tCylinderEndTris1, tCylinderEndTris2;

            SphereMathHelper.CalcCylinderTriangles(numSides, 1, 1.0f, new Vector3(0, 0, 0), new Vector3(0, 0, 1),
                                                   true, endType, offset, out tCylinderPoints,
                                                   out tCylinderNormals, out tCylinderTris, out tCylinderEndPoints1,
                                                   out tCylinderEndNormals1, out tCylinderEndTris1,
                                                   out tCylinderEndPoints2, out tCylinderEndNormals2,
                                                   out tCylinderEndTris2);
            int numActualVerts = tCylinderPoints.Length + tCylinderEndPoints1.Length + tCylinderEndPoints2.Length;
            int numActualTris = tCylinderTris.Length + tCylinderEndTris1.Length + tCylinderEndTris2.Length;

            // create buffers
            buffer = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0] = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Stride = geomStream.Stride;
            buffer.vBuffers[0].NumElements = numActualVerts;
            buffer.vBuffers[0].Format = geomStream.Format;

            buffer.vBuffers[0].NumElements = numActualVerts * numActualBonds;
            buffer.vBuffers[0].Buffer = new VertexBuffer(device, geomStream.Stride * numActualTris * numActualBonds * 3,
                                                         Usage.WriteOnly, geomStream.Format, Pool.Managed);

            buffer.iBuffers = new BufferedGeometryData.IndexData[1];
            buffer.iBuffers[0] = new BufferedGeometryData.IndexData();
            buffer.iBuffers[0].Desc = BufferedGeometryData.IndexData.Description.Geometry;
            buffer.iBuffers[0].NumPrimitives = numActualTris;
            buffer.iBuffers[0].PrimType = PrimitiveType.TriangleList;

            buffer.iBuffers[0].NumPrimitives = (numActualTris * numActualBonds) / 3;
            /*buffer.iBuffers[0].Buffer = new IndexBuffer(typeof(int), numActualTris * numActualBonds, device,
                                                        Usage.WriteOnly, Pool.Managed);*/

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            // write bonds to buffer
            Vector3 direction, directionUV;
            IAtom[] atoms;
            Vector3[] atomsPos;
            IMoleculeMaterial matA, matB;

            foreach (IBond bond in objs)
            {
                BondLinesBufferCreator.GenericBondSetup(bond, true, coDesc.BondShadingDesc, out direction,
                                                        out directionUV, out atoms, out atomsPos, out matA,
                                                        out matB);

                // calc bond positioning / instances
                Vector3[] bondInstances = null;
                float midPos;
                BondLinesBufferCreator.GenericBondCalcPositions(bond, coDesc.BondShadingDesc, direction,
                                                                directionUV, atoms, atomsPos, 0.15f,
                                                                out bondInstances, out midPos, false);

                long pos = 0;
                for (int bInst = 0; bInst < bondInstances.Length; bInst += 2)
                {
                    // translation
                    Matrix translate = Matrix.Translation(bondInstances[bInst]);

                    // rotation
                    double x = direction.X;
                    double y = direction.Y;
                    double z = direction.Z;

                    double alpha = (z == 0) ? Math.PI / 2 : Math.Atan(x / z);
                    double r = (alpha == 0) ? z : x / Math.Sin(alpha);
                    float sign = 1f;
                    if (z != 0)
                        sign *= Math.Sign(z);
                    else if (x != 0)
                        sign *= Math.Sign(x);
                    if (y != 0)
                        sign *= Math.Sign(y);
                    double theta = -sign * Math.Abs((r == 0) ? Math.PI / 2 : Math.Atan(y / r));

                    Matrix rotation = Matrix.RotationX((float)theta) * Matrix.RotationY((float)alpha);

                    // scaling
                    float zScale;
                    if (coDesc.BondShadingDesc.BlendEndClrs)
                        zScale = (bondInstances[1] - bondInstances[0]).Length();//(atomsPos[1] - atomsPos[0]).Length();//direction.Length();
                    else
                        zScale = midPos;
                    float xyScale = 0.05f; // thickness
                    Matrix scale = Matrix.Scaling(xyScale, xyScale, zScale);

                    // rotate & translate ends
                    if (tCylinderEndPoints1 != null)
                    {
                        Matrix endFinal = Matrix.Scaling(xyScale, xyScale, 1f) * rotation * translate;
                        Vector4[] tfEndTriangles = Vector3.Transform(tCylinderEndPoints1, endFinal);
                        // first end
                        for (int point = 0; point < tCylinderEndTris1.Length; point++)
                        {
                            int pointIdx = tCylinderEndTris1[point];
                            if (positionPos != -1)
                            {
                                data.Seek(pos + positionPos, SeekOrigin.Begin);
                                data.Write(tfEndTriangles[pointIdx].X);
                                data.Write(tfEndTriangles[pointIdx].Y);
                                data.Write(tfEndTriangles[pointIdx].Z);
                            }
                            if (normalPos != -1)
                            {
                                data.Seek(pos + normalPos, SeekOrigin.Begin);
                                data.Write(tCylinderEndNormals1[pointIdx].X);
                                data.Write(tCylinderEndNormals1[pointIdx].Y);
                                data.Write(tCylinderEndNormals1[pointIdx].Z);
                            }
                            if (diffusePos != -1)
                            {
                                data.Seek(pos + diffusePos, SeekOrigin.Begin);
                                data.Write(matA.BaseColor.ToArgb());
                            }
                            pos += geomStream.Stride;
                        }
                        // second end
                        endFinal = Matrix.Scaling(xyScale, xyScale, 1f) * rotation *
                                   Matrix.Translation(bondInstances[bInst + 1]);
                        tfEndTriangles = Vector3.Transform(tCylinderEndPoints2, endFinal);
                        // first end
                        for (int point = 0; point < tCylinderEndTris2.Length; point++)
                        {
                            int pointIdx = tCylinderEndTris2[point];
                            if (positionPos != -1)
                            {
                                data.Seek(pos + positionPos, SeekOrigin.Begin);
                                data.Write(tfEndTriangles[pointIdx].X);
                                data.Write(tfEndTriangles[pointIdx].Y);
                                data.Write(tfEndTriangles[pointIdx].Z);
                            }
                            if (normalPos != -1)
                            {
                                data.Seek(pos + normalPos, SeekOrigin.Begin);
                                data.Write(tCylinderEndNormals2[pointIdx].X);
                                data.Write(tCylinderEndNormals2[pointIdx].Y);
                                data.Write(tCylinderEndNormals2[pointIdx].Z);
                            }
                            if (diffusePos != -1)
                            {
                                data.Seek(pos + diffusePos, SeekOrigin.Begin);
                                data.Write(matB.BaseColor.ToArgb());
                            }
                            pos += geomStream.Stride;
                        }
                    }

                    Matrix final = scale * rotation * translate;

                    if (coDesc.BondShadingDesc.BlendEndClrs)
                    {
                        DrawSolidBondBlended(tCylinderPoints, tCylinderNormals, tCylinderTris,
                                             matA, matB, final, data, positionPos, normalPos,
                                             diffusePos, ref pos, geomStream.Stride, rotation);
                    }
                    else
                    {
                        float bLen2 = (bondInstances[bInst + 1] - (bondInstances[bInst] + (directionUV * midPos))).Length();

                        DrawSolidBondDistinct(tCylinderPoints, tCylinderNormals, tCylinderTris,
                                              matA, matB, final, data, xyScale, bLen2, rotation,
                                              bondInstances[bInst], directionUV, midPos, positionPos,
                                              normalPos, diffusePos, ref pos, geomStream.Stride);
                    }
                }
            }
        }
        public override void CreateGeometryForObjects(Device device, ICollection<IAtom> objs,
                                                      GeomDataBufferStream geomStream, int stream,
                                                      ref BufferedGeometryData buffer, CompleteOutputDescription coDesc)
        {
            // fillable fields
            int positionPos = -1;
            int sizePos = -1;
            int diffusePos = -1;

            // match field locations
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                            positionPos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "DIFFUSE")
                            diffusePos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "SIZEFLOAT")
                            sizePos = geomStream.FieldPositions[gf];
                        break;
                    }
                }
            }

            // create buffers
            buffer = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0] = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Buffer = new VertexBuffer(typeof(MetaBlobsEffect.PointVertex), objs.Count, device, Usage.None, VertexFormats.Position | VertexFormats.PointSize | VertexFormats.Diffuse, Pool.SystemMemory);
                /*new VertexBuffer(device, geomStream.Stride * objs.Count,
                                                         Usage.WriteOnly, geomStream.Format, Pool.SystemMemory);*/
            buffer.vBuffers[0].Stride = geomStream.Stride;
            buffer.vBuffers[0].NumElements = objs.Count;
            buffer.vBuffers[0].Format = geomStream.Format;
            buffer.DataValidity = BufferedGeometryData.DataValidityType.Source;
            buffer.Target = BufferedGeometryData.DataTarget.Geometry;

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            // fill fields

            // create points
            AtomShadingDesc aShading = coDesc.AtomShadingDesc;
            long pos = 0;
            foreach (IAtom atom in objs)
            {
                int period = 1;
                if (atom.Properties.ContainsKey("Period"))
                    period = (int)atom.Properties["Period"];

                if (positionPos != -1)
                {
                    data.Seek(pos + positionPos, SeekOrigin.Begin);
                    data.Write((float)atom.X3d);
                    data.Write((float)atom.Y3d);
                    data.Write((float)atom.Z3d);
                }
                if (sizePos != -1)
                {
                    data.Seek(pos + sizePos, SeekOrigin.Begin);
                    data.Write((float)period);
                }
                if (diffusePos != -1)
                {
                    IMoleculeMaterialLookup lookup = aShading.MoleculeMaterials;
                    IMoleculeMaterialTemplate matTemp = lookup.ResolveBySymbol(atom.Symbol);
                    IMoleculeMaterial material = null;
                    if (matTemp != null)
                        material = matTemp.BySymbol;
                    else
                    {
                        PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
                        if (pe != null)
                            material = lookup.GetBySeries(pe.ChemicalSerie);
                    }
                    if (material != null)
                    {
                        data.Seek(pos + diffusePos, SeekOrigin.Begin);
                        //data.Write((float)material.BaseColor.ToArgb());
                        if (material.BaseColor.R > 0)
                            data.Write(255f / material.BaseColor.R);
                        else
                            data.Write((float)0);
                        if (material.BaseColor.G > 0)
                            data.Write(255f / material.BaseColor.G);
                        else
                            data.Write((float)0);
                        if (material.BaseColor.B > 0)
                            data.Write(255f / material.BaseColor.B);
                        else
                            data.Write((float)0);
                    }
                }
                pos += geomStream.Stride;
            }
            buffer.vBuffers[0].Buffer.Unlock();
        }
        public override void CreateGeometryForObjects(Device device, ICollection <IAtom> objs,
                                                      GeomDataBufferStream geomStream, int stream,
                                                      ref BufferedGeometryData buffer, CompleteOutputDescription coDesc)
        {
            if (spriteTexture == null)
            {
                Stream texstm = Assembly.GetExecutingAssembly().GetManifestResourceStream("NuGenSVisualLib.Resources.Atom.PNG");
                spriteTexture = TextureLoader.FromStream(device, texstm);
            }

            // fillable fields
            int positionPos = -1;
            int sizePos     = -1;
            int diffusePos  = -1;

            // match field locations
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                        {
                            positionPos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "DIFFUSE")
                        {
                            diffusePos = geomStream.FieldPositions[gf];
                        }
                        else if (fields[i].Usage == "POINTSIZE")
                        {
                            sizePos = geomStream.FieldPositions[gf];
                        }
                        break;
                    }
                }
            }

            // create buffers
            buffer                    = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers           = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0]        = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Buffer = new VertexBuffer(typeof(PointSprite), objs.Count, device, Usage.WriteOnly,
                                                         geomStream.Format, Pool.Managed);

            /*new VertexBuffer(device, geomStream.Stride * objs.Count,
             *                                       Usage.None, geomStream.Format, Pool.Managed);*/
            buffer.vBuffers[0].Stride      = geomStream.Stride;
            buffer.vBuffers[0].NumElements = objs.Count;
            buffer.vBuffers[0].Format      = geomStream.Format;

            buffer.iBuffers                  = new BufferedGeometryData.IndexData[1];
            buffer.iBuffers[0]               = new BufferedGeometryData.IndexData();
            buffer.iBuffers[0].Desc          = BufferedGeometryData.IndexData.Description.Sprites;
            buffer.iBuffers[0].NumPrimitives = objs.Count;
            buffer.iBuffers[0].PrimType      = PrimitiveType.PointList;

            buffer.iBuffers[0].Textures = new Texture[] { spriteTexture };

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            AtomShadingDesc aShading = coDesc.AtomShadingDesc;

            long pos = 0;

            foreach (IAtom atom in objs)
            {
                if (positionPos != -1)
                {
                    data.Seek(pos + positionPos, SeekOrigin.Begin);
                    data.Write((float)atom.X3d);
                    data.Write((float)atom.Y3d);
                    data.Write((float)atom.Z3d);
                }
                if (sizePos != -1)
                {
                    data.Seek(pos + sizePos, SeekOrigin.Begin);
                    int period = 1;
                    if (atom.Properties.ContainsKey("Period"))
                    {
                        period = (int)atom.Properties["Period"];
                    }
                    data.Write((float)period * 0.4f);
                }
                if (diffusePos != -1)
                {
                    IMoleculeMaterialLookup   lookup   = aShading.MoleculeMaterials;
                    IMoleculeMaterialTemplate matTemp  = lookup.ResolveBySymbol(atom.Symbol);
                    IMoleculeMaterial         material = null;
                    if (matTemp != null)
                    {
                        material = matTemp.BySymbol;
                    }
                    else
                    {
                        PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
                        if (pe != null)
                        {
                            material = lookup.GetBySeries(pe.ChemicalSerie);
                        }
                    }

                    data.Seek(pos + diffusePos, SeekOrigin.Begin);
                    data.Write(material.BaseColor.ToArgb());
                }
                pos += geomStream.Stride;
            }

            /*Dictionary<int, List<int>> atomSizeGroups = new Dictionary<int, List<int>>();
             * // first split into group counts
             * int aIdx = 0;
             * foreach (IAtom[] atoms in atomSets)
             * {
             *  foreach (IAtom atom in atoms)
             *  {
             *      int period = 1;
             *      if (atom.Properties.ContainsKey("Period"))
             *          period = (int)atom.Properties["Period"];
             *
             *      List<int> groupAtoms = null;
             *      if (!atomSizeGroups.TryGetValue(period, out groupAtoms))
             *          atomSizeGroups.Add(period, groupAtoms = new List<int>());
             *
             *      groupAtoms.Add(aIdx++);
             *  }
             * }
             *
             * int vertsIdx = 0;
             * Dictionary<int, List<int>>.Enumerator group = atomSizeGroups.GetEnumerator();
             * sBuffer.groupLengths = new int[atomSizeGroups.Count];
             * sBuffer.groupSizes = new int[atomSizeGroups.Count];
             * sBuffer.groupStarts = new int[atomSizeGroups.Count];
             * int bIdx = 0;
             * while (group.MoveNext())
             * {
             *  int groupPeriod = group.Current.Key;
             *  List<int> groupMembers = group.Current.Value;
             *  aIdx = 0;
             *  int gIdx = 0;
             *  sBuffer.groupSizes[bIdx] = groupPeriod;
             *  sBuffer.groupStarts[bIdx] = vertsIdx;
             *  sBuffer.groupLengths[bIdx] = groupMembers.Count;
             *  foreach (IAtom[] atoms in atomSets)
             *  {
             *      foreach (IAtom atom in atoms)
             *      {
             *          if (aIdx == groupMembers[gIdx])
             *          {
             *              IMoleculeMaterialLookup lookup = aShading.MoleculeMaterials;
             *              IMoleculeMaterialTemplate matTemp = lookup.ResolveBySymbol(atom.Symbol);
             *              IMoleculeMaterial material = null;
             *              if (matTemp != null)
             *                  material = matTemp.BySymbol;
             *              else
             *              {
             *                  PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
             *                  if (pe != null)
             *                      material = lookup.GetBySeries(pe.ChemicalSerie);
             *              }
             *
             *              atomVerts[vertsIdx].Position = new Vector3((float)atom.X3d, (float)atom.Y3d, (float)atom.Z3d);
             *              atomVerts[vertsIdx].Color = material.BaseColor.ToArgb();
             *              vertsIdx++;
             *              gIdx++;
             *          }
             *          if (gIdx == groupMembers.Count)
             *              break;
             *          aIdx++;
             *      }
             *      if (gIdx == groupMembers.Count)
             *          break;
             *  }
             *  bIdx++;
             * }*/
            buffer.vBuffers[0].Buffer.Unlock();
        }
        public override void CreateGeometryForObjects(Device device, ICollection<IAtom> objs, GeomDataBufferStream geomStream,
                                                      int stream, ref BufferedGeometryData buffer,
                                                      CompleteOutputDescription coDesc)
        {
            // fillable fields
            int positionPos = -1;
            int normalPos = -1;
            int diffusePos = -1;
            int texPos = -1;

            // match field locations
            //int[] fieldsPos = new int[fields.Length];
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                            positionPos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "NORMAL")
                            normalPos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "DIFFUSE")
                            diffusePos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "TEXTURE0")
                            texPos = geomStream.FieldPositions[gf];
                        //fieldsPos[i] = geomStream.FieldPositions[gf];
                        break;
                    }
                }
            }

            int numVerts = sphereDetail1 * sphereDetail2 * 6;
            int numTris = sphereDetail1 * sphereDetail2 * 2;

            // create buffers
            buffer = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0] = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Buffer = new VertexBuffer(device, geomStream.Stride * numVerts * objs.Count,
                                                         Usage.WriteOnly, geomStream.Format, Pool.Managed);
            buffer.vBuffers[0].Stride = geomStream.Stride;
            buffer.vBuffers[0].NumElements = objs.Count * numVerts;
            buffer.vBuffers[0].Format = geomStream.Format;

            buffer.iBuffers = new BufferedGeometryData.IndexData[1];
            buffer.iBuffers[0] = new BufferedGeometryData.IndexData();
            buffer.iBuffers[0].Desc = BufferedGeometryData.IndexData.Description.Geometry;
            buffer.iBuffers[0].NumPrimitives = objs.Count * numTris;
            buffer.iBuffers[0].PrimType = PrimitiveType.TriangleList;

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            // fill fields
            bool newWay = true;
            if (!newWay)
            {
                // create template sphere
                SphereMathHelper.SphereN sphere = SphereMathHelper.CalcSphereWNormals(sphereDetail1, sphereDetail2, 1.0f, new Vector3(), true);

                // clone and scale template for each size required
                Vector3 center = new Vector3();
                Dictionary<int, Vector3[]> spheres = new Dictionary<int, Vector3[]>();
                AtomShadingDesc aShading = coDesc.AtomShadingDesc;

                //int vertsIdx = 0;
                long pos = 0;
                foreach (IAtom atom in objs)
                {
                    int period = 1;
                    if (atom.Properties.ContainsKey("Period"))
                        period = (int)atom.Properties["Period"];

                    // check for existing
                    if (!spheres.ContainsKey(period))
                    {
                        // scale template
                        float size = period * _Scaling;
                        Vector4[] vertices = Vector3.Transform(sphere.Positions, Matrix.Scaling(size, size, size));
                        Vector3[] vertices3 = new Vector3[vertices.Length];
                        for (int i = 0; i < vertices.Length; i++)
                        {
                            vertices3[i] = new Vector3(vertices[i].X, vertices[i].Y, vertices[i].Z);
                        }
                        spheres.Add(period, vertices3);
                    }
                    Vector3[] sphereData = spheres[period];

                    // write to buffer
                    IMoleculeMaterialLookup lookup = aShading.MoleculeMaterials;
                    IMoleculeMaterialTemplate matTemp = lookup.ResolveBySymbol(atom.Symbol);
                    IMoleculeMaterial material = null;
                    if (matTemp != null)
                        material = matTemp.BySymbol;
                    else
                    {
                        PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
                        if (pe != null)
                            material = lookup.GetBySeries(pe.ChemicalSerie);
                    }

                    // copy sphere
                    Vector3 atomSpace = new Vector3((float)atom.X3d, (float)atom.Y3d, (float)atom.Z3d);
                    /*Vector4 clr = new Vector4((float)material.BaseColor.R / 255f, (float)material.BaseColor.G / 255f,
                                              (float)material.BaseColor.B / 255f, (float)material.BaseColor.A / 255f);*/
                    int clr = material.BaseColor.ToArgb();
                    for (int v = 0; v < sphereData.Length; v++)
                    {
                        if (positionPos != -1)
                        {
                            Vector3 position = sphereData[v] + atomSpace;
                            data.Seek(pos + positionPos, SeekOrigin.Begin);
                            data.Write(position.X);
                            data.Write(position.Y);
                            data.Write(position.Z);
                        }
                        if (texPos != -1)
                        {
                            data.Seek(pos + texPos, SeekOrigin.Begin);
                            data.Write(0f);//sphere.TexCoords[v].X);
                            data.Write(0f);//sphere.TexCoords[v].Y);
                        }
                        if (normalPos != -1)
                        {
                            data.Seek(pos + normalPos, SeekOrigin.Begin);
                            data.Write(sphere.Normals[v].X);
                            data.Write(sphere.Normals[v].Y);
                            data.Write(sphere.Normals[v].Z);
                        }
                        if (diffusePos != -1)
                        {
                            data.Seek(pos + diffusePos, SeekOrigin.Begin);
                            /*data.Write(clr.X);
                            data.Write(clr.Y);
                            data.Write(clr.Z);
                            data.Write(clr.W);*/
                            data.Write((Int32)clr);
                        }
                        pos += geomStream.Stride;
                    }
                }
            }
            else
            {
                Vector3[] Positions, normals;
                Vector2[] texCoords;
                SphereMathHelper.CreateSphereTriangles(new Vector3(), 1, sphereDetail1, out Positions,
                                                       out normals, out texCoords);

                // clone and scale template for each size required
                Vector3 center = new Vector3();
                Dictionary<int, Vector3[]> spheres = new Dictionary<int, Vector3[]>();
                AtomShadingDesc aShading = coDesc.AtomShadingDesc;

                int vertsIdx = 0;
                long pos = 0;
                foreach (IAtom atom in objs)
                {
                    int period = 1;
                    if (atom.Properties.ContainsKey("Period"))
                        period = (int)atom.Properties["Period"];

                    // check for existing
                    if (!spheres.ContainsKey(period))
                    {
                        // scale template
                        float size = period * _Scaling;
                        Vector4[] vertices = Vector3.Transform(Positions, Matrix.Scaling(size, size, size));
                        Vector3[] vertices3 = new Vector3[vertices.Length];
                        for (int i = 0; i < vertices.Length; i++)
                        {
                            vertices3[i] = new Vector3(vertices[i].X, vertices[i].Y, vertices[i].Z);
                        }
                        spheres.Add(period, vertices3);
                    }
                    Vector3[] sphereData = spheres[period];

                    // write to buffer
                    IMoleculeMaterialLookup lookup = aShading.MoleculeMaterials;
                    IMoleculeMaterialTemplate matTemp = lookup.ResolveBySymbol(atom.Symbol);
                    IMoleculeMaterial material = null;
                    if (matTemp != null)
                        material = matTemp.BySymbol;
                    else
                    {
                        PeriodicTableElement pe = (PeriodicTableElement)atom.Properties["PeriodicTableElement"];
                        if (pe != null)
                            material = lookup.GetBySeries(pe.ChemicalSerie);
                    }

                    // copy sphere
                    Vector3 atomSpace = new Vector3((float)atom.X3d, (float)atom.Y3d, (float)atom.Z3d);
                    int clr = material.BaseColor.ToArgb();
                    for (int v = 0; v < sphereData.Length; v++)
                    {
                        if (positionPos != -1)
                        {
                            Vector3 position = sphereData[v] + atomSpace;
                            data.Seek(pos + positionPos, SeekOrigin.Begin);
                            data.Write(position.X);
                            data.Write(position.Y);
                            data.Write(position.Z);
                        }
                        if (texPos != -1)
                        {
                            data.Seek(pos + texPos, SeekOrigin.Begin);
                            data.Write(texCoords[v].X);
                            data.Write(texCoords[v].Y);
                        }
                        if (normalPos != -1)
                        {
                            data.Seek(pos + normalPos, SeekOrigin.Begin);
                            data.Write(normals[v].X);
                            data.Write(normals[v].Y);
                            data.Write(normals[v].Z);
                        }
                        if (diffusePos != -1)
                        {
                            data.Seek(pos + diffusePos, SeekOrigin.Begin);
                            /*data.Write(clr.X);
                            data.Write(clr.Y);
                            data.Write(clr.Z);
                            data.Write(clr.W);*/
                            data.Write((Int32)clr);
                        }
                        pos += geomStream.Stride;
                    }
                }
            }

            buffer.vBuffers[0].Buffer.Unlock();
        }
        public override void CreateGeometryForObjects(Device device, ICollection<IBond> objs,
                                                      GeomDataBufferStream geomStream, int stream,
                                                      ref BufferedGeometryData buffer, CompleteOutputDescription coDesc)
        {
            // fillable fields
            int positionPos = -1;
            int normalPos = -1;
            int diffusePos = -1;
            int texPos = -1;

            // match field locations
            //int[] fieldsPos = new int[fields.Length];
            for (int i = 0; i < fields.Length; i++)
            {
                for (int gf = 0; gf < geomStream.Fields.Length; gf++)
                {
                    if (fields[i].Format == geomStream.Fields[gf])
                    {
                        if (fields[i].Usage == "POSITION")
                            positionPos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "NORMAL")
                            normalPos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "DIFFUSE")
                            diffusePos = geomStream.FieldPositions[gf];
                        else if (fields[i].Usage == "TEXTURE0")
                            texPos = geomStream.FieldPositions[gf];
                        //fieldsPos[i] = geomStream.FieldPositions[gf];
                        break;
                    }
                }
            }

            // count bond orders via preview data
            int numActualBonds = 0;
            foreach (IBond bond in objs)
            {
                numActualBonds += (int)bond.Order;
            }

            int numVerts = 0;
            if (coDesc.BondShadingDesc.BlendEndClrs)
                numVerts = numActualBonds * 2;
            else
                numVerts = numActualBonds * 4;

            // create buffers
            buffer = new BufferedGeometryData(device, objs.Count);
            buffer.vBuffers = new BufferedGeometryData.VertexData[1];
            buffer.vBuffers[0] = new BufferedGeometryData.VertexData();
            buffer.vBuffers[0].Stride = geomStream.Stride;
            buffer.vBuffers[0].NumElements = numVerts;
            buffer.vBuffers[0].Format = geomStream.Format;

            buffer.iBuffers = new BufferedGeometryData.IndexData[1];
            buffer.iBuffers[0] = new BufferedGeometryData.IndexData();
            buffer.iBuffers[0].Desc = BufferedGeometryData.IndexData.Description.Geometry;
            buffer.iBuffers[0].NumPrimitives = numVerts / 2;
            buffer.iBuffers[0].PrimType = PrimitiveType.LineList;

            buffer.vBuffers[0].NumElements = numVerts;
            buffer.vBuffers[0].Buffer = new VertexBuffer(device, geomStream.Stride * numVerts,
                                                         Usage.WriteOnly, geomStream.Format, Pool.Managed);

            // write bonds to buffer
            Vector3 direction, directionUV;
            IAtom[] atoms;
            Vector3[] atomsPos;
            IMoleculeMaterial materialA, materialB;
            Vector3[] bondInstances = null;
            float midPos;
            BondShadingDesc bShading = coDesc.BondShadingDesc;

            // lock stream
            GraphicsStream data = buffer.vBuffers[0].Buffer.Lock(0, 0, LockFlags.None);

            long pos = 0;
            foreach (IBond bond in objs)
            {
                GenericBondSetup(bond, false, bShading, out direction, out directionUV,
                                 out atoms, out atomsPos, out materialA, out materialB);

                // calc bond positioning / instances
                GenericBondCalcPositions(bond, bShading, direction, directionUV,
                                         atoms, atomsPos, 0.1f, out bondInstances,
                                         out midPos, true);

                // draw bond instances
                for (int bInst = 0; bInst < bondInstances.Length; bInst += 2)
                {
                    if (bShading.BlendEndClrs)
                    {
                        GenericDrawBondSolidBlended(bondInstances[bInst], bondInstances[bInst + 1],
                                                    materialA, materialB, data, ref pos, geomStream.Stride, positionPos, diffusePos);
                        //GenericDrawBondDashedBlended(bondInstances[bInst], bondInstances[bInst + 1],
                        //                            materialA, materialB);
                    }
                    else
                    {
                        Vector3 sectA = directionUV * midPos;

                        // convert into points (2 lines)
                        if (positionPos != -1)
                        {
                            data.Seek(pos + positionPos, SeekOrigin.Begin);
                            data.Write(bondInstances[bInst].X);
                            data.Write(bondInstances[bInst].Y);
                            data.Write(bondInstances[bInst].Z);

                            data.Seek(pos + geomStream.Stride + positionPos, SeekOrigin.Begin);
                            Vector3 p = bondInstances[bInst] + sectA;
                            data.Write(p.X);
                            data.Write(p.Y);
                            data.Write(p.Z);

                            data.Seek(pos + geomStream.Stride + geomStream.Stride + positionPos, SeekOrigin.Begin);
                            data.Write(p.X);
                            data.Write(p.Y);
                            data.Write(p.Z);

                            data.Seek(pos + geomStream.Stride + geomStream.Stride + geomStream.Stride + positionPos, SeekOrigin.Begin);
                            data.Write(bondInstances[bInst + 1].X);
                            data.Write(bondInstances[bInst + 1].Y);
                            data.Write(bondInstances[bInst + 1].Z);
                        }
                        if (diffusePos != -1)
                        {
                            data.Seek(pos + diffusePos, SeekOrigin.Begin);
                            int clr = materialA.BaseColor.ToArgb();
                            data.Write(clr);

                            data.Seek(pos + geomStream.Stride + diffusePos, SeekOrigin.Begin);
                            data.Write(clr);

                            clr = materialB.BaseColor.ToArgb();
                            data.Seek(pos + geomStream.Stride + geomStream.Stride + diffusePos, SeekOrigin.Begin);
                            data.Write(clr);

                            data.Seek(pos + geomStream.Stride + geomStream.Stride + geomStream.Stride + diffusePos, SeekOrigin.Begin);
                            data.Write(clr);
                        }

                        pos += geomStream.Stride * 4;
                    }
                }
            }

            buffer.vBuffers[0].Buffer.Unlock();
        }