Example #1
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="name">Name of bitmap collection</param>
        /// <param name="rlist">Render list to draw into</param>
        /// <param name="bitmapsize">Bit map size</param>
        /// <param name="mipmaplevels">Mip map levels</param>
        /// <param name="textureformat">Texture format of bitmaps</param>
        /// <param name="cullface">True to cull face</param>
        /// <param name="depthtest">True to depth test</param>
        /// <param name="maxpergroup">Maximum number of bitmaps per group</param>
        /// <param name="yfixed">Set true to fix Y co-ord externally</param>
        public GLBitmaps(string name, GLRenderProgramSortedList rlist, Size bitmapsize, int mipmaplevels = 3,
                         OpenTK.Graphics.OpenGL4.SizedInternalFormat textureformat = OpenTK.Graphics.OpenGL4.SizedInternalFormat.Rgba8,
                         bool cullface = true, bool depthtest = true, int maxpergroup = int.MaxValue, bool yfixed = false)
        {
            this.name    = name;
            this.context = GLStatics.GetContext();

            int maxdepthpertexture = GL4Statics.GetMaxTextureDepth();   // limits the number of textures per 2darray
            int max = Math.Min(maxdepthpertexture, maxpergroup);        //note RI uses a VertexArray to load the matrix in, so not limited by that (max size of uniform buffer)

            matrixbuffers = new GLSetOfMatrixBufferWithGenerations(items, max);

            matrixbuffers.AddedNewGroup += AddedNewGroup;       // hook up call back to say i've made a group

            renderlist      = rlist;
            this.bitmapsize = bitmapsize;

            shader = new GLShaderPipeline(new GLPLVertexShaderMatrixQuadTexture(yfixed), new GLPLFragmentShaderTexture2DIndexed(0, alphablend: true));
            items.Add(shader);

            renderstate                    = GLRenderState.Quads();
            renderstate.CullFace           = cullface;
            renderstate.DepthTest          = depthtest;
            renderstate.ClipDistanceEnable = 1;  // we are going to cull primitives which are deleted

            texmipmaplevels    = mipmaplevels;
            this.textureformat = textureformat;
        }
Example #2
0
        /// <summary>
        /// Create a tape with element indexes. Use with a TriangleStrip
        /// The tape is segmented, and roty determines if its flat to Y or not
        /// The series of tapes with a margin between them.
        /// This provides the element index buffer indices as well
        /// Aligns the element indexes start point for each tape to modulo N to allow trianglestrip to work properly (4 normally)
        /// You pass in colour array, or null, to add colour information to tape W values.  Note colour is one less in length than points array
        /// </summary>
        /// <param name="points">Points along which the tape should go. Minimum 2 points</param>
        /// <param name="colours">Array of colours to use, per segment. Color is packed into W of Vector4 positions on every vertex of a segment</param>
        /// <param name="width">Tape width</param>
        /// <param name="segmentlength">Segment length, for each triangle pair making up the tape</param>
        /// <param name="rotationaroundyradians">Rotate the tape around its axis</param>
        /// <param name="margin">Space between each segment</param>
        /// <param name="restartindex">The element restart index to use</param>
        /// <param name="modulo">The alignment of each segment start vertex index, to align for triangle strip use</param>
        /// <returns>Return list of points, and element buffer indexes, and the indexor draw element type</returns>

        public static Tuple <List <Vector4>, List <uint>, DrawElementsType> CreateTape(Vector4[] points, Color[] colours, float width, float segmentlength = 1,
                                                                                       float rotationaroundyradians = 0,
                                                                                       float margin = 0, uint restartindex = 0xffffffff, int modulo = 4)
        {
            List <Vector4>   vec  = new List <Vector4>();
            List <uint>      eids = new List <uint>();
            DrawElementsType det  = DrawElementsType.UnsignedByte;

            if (points.Length >= 2)
            {
                uint vno = 0;

                for (int i = 0; i < points.Length - 1; i++)
                {
                    Vector4[] segment = CreateTape(points[i].ToVector3(), points[i + 1].ToVector3(), width, segmentlength, rotationaroundyradians, margin);

                    if (colours != null)
                    {
                        int w = colours[i].PackRGB();
                        for (int j = 0; j < segment.Length; j++)
                        {
                            segment[j].W = w;
                        }
                    }

                    while (vec.Count % modulo != 0)                // must be on a boundary of four for the vertex shaders which normally are used
                    {
                        vec.Add(new Vector4(1000, 2000, 3000, 1)); // dummy value we can recognise
                        vno++;
                    }

                    //  System.Diagnostics.Debug.WriteLine($"At {vno} vec {vec.Count} add {vec1.Length}");

                    vec.AddRange(segment);

                    for (int l = 0; l < segment.Length; l++)
                    {
                        eids.Add(vno++);
                    }

                    eids.Add(restartindex);
                }

                eids.RemoveAt(eids.Count - 1);  // remove last restart
                det = GL4Statics.DrawElementsTypeFromMaxEID(vno - 1);
            }

            return(new Tuple <List <Vector4>, List <uint>, DrawElementsType>(vec, eids, det));
        }
        private void IntCreatePath(GLItemsList items, GLRenderProgramSortedList rObjects, GLStorageBlock bufferfindresults)
        {
            HistoryEntry lastone = lastpos != -1 && lastpos < currentfilteredlist.Count ? currentfilteredlist[lastpos] : null;  // see if lastpos is there, and store it

            if (TravelPathEndDateEnable || TravelPathStartDateEnable)
            {
                currentfilteredlist = unfilteredlist.Where(x => (!TravelPathStartDateEnable || x.EventTimeUTC >= TravelPathStartDate) && (!TravelPathEndDateEnable || x.EventTimeUTC <= TravelPathEndDate)).ToList();
                if (currentfilteredlist.Count > MaxStars)
                {
                    currentfilteredlist = currentfilteredlist.Skip(currentfilteredlist.Count - MaxStars).ToList();
                }
            }
            else
            {
                if (unfilteredlist.Count > MaxStars)
                {
                    currentfilteredlist = unfilteredlist.Skip(currentfilteredlist.Count - MaxStars).ToList();
                }
                else
                {
                    currentfilteredlist = unfilteredlist;
                }
            }

            // do date filter on currentfilteredlist

            lastpos = lastone == null ? -1 : currentfilteredlist.IndexOf(lastone);        // may be -1, may have been removed

            var   positionsv4 = currentfilteredlist.Select(x => new Vector4((float)x.System.X, (float)x.System.Y, (float)x.System.Z, 0)).ToArray();
            var   colours     = currentfilteredlist.Select(x => x.JumpColor).ToArray();
            float seglen      = tapesize * 10;

            // a tape is a set of points (item1) and indexes to select them (item2), so we need an element index in the renderer to use.
            var tape = GLTapeObjectFactory.CreateTape(positionsv4, colours, tapesize, seglen, 0F.Radians(), margin: sunsize * 1.2f);

            if (ritape == null) // first time..
            {
                // first the tape

                var tapetex = new GLTexture2D(Properties.Resources.chevron, internalformat: OpenTK.Graphics.OpenGL4.SizedInternalFormat.Rgba8);        // tape image
                items.Add(tapetex);
                tapetex.SetSamplerMode(OpenTK.Graphics.OpenGL4.TextureWrapMode.Repeat, OpenTK.Graphics.OpenGL4.TextureWrapMode.Repeat);

                tapefrag = new GLPLFragmentShaderTextureTriStripColorReplace(1, Color.FromArgb(255, 206, 0, 0));
                var vert = new GLPLVertexShaderWorldTextureTriStrip();
                tapeshader = new GLShaderPipeline(vert, tapefrag);
                items.Add(tapeshader);

                GLRenderState rts = GLRenderState.Tri(tape.Item3, cullface: false); // set up a Tri strip, primitive restart value set from tape, no culling
                rts.DepthTest = depthtest;                                          // no depth test so always appears

                // now the renderer, set up with the render control, tape as the points, and bind a RenderDataTexture so the texture gets binded each time
                ritape         = GLRenderableItem.CreateVector4(items, OpenTK.Graphics.OpenGL4.PrimitiveType.TriangleStrip, rts, tape.Item1.ToArray(), new GLRenderDataTexture(tapetex));
                tapepointbuf   = items.LastBuffer();                                            // keep buffer for refill
                ritape.Visible = tape.Item1.Count > 0;                                          // no items, set not visible, so it won't except over the BIND with nothing in the element buffer

                ritape.CreateElementIndex(items.NewBuffer(), tape.Item2.ToArray(), tape.Item3); // finally, we are using index to select vertexes, so create an index

                rObjects.Add(tapeshader, "travelpath-tape", ritape);                            // add render to object list

                // now the stars

                starposbuf = items.NewBuffer();         // where we hold the vertexes for the suns, used by renderer and by finder

                starposbuf.AllocateFill(positionsv4);
                //Vector4[] vectors = starposbuf.ReadVector4s(0, starposbuf.Length / 16);

                sunvertex = new GLPLVertexShaderModelCoordWorldAutoscale(new Color[] { Color.Yellow, Color.FromArgb(255, 230, 230, 1) },
                                                                         autoscale: 30, autoscalemin: 1f, autoscalemax: 2f, useeyedistance: false); // below scale, 1f, above scale, scale up to x times (eyedist/scale)
                sunshader = new GLShaderPipeline(sunvertex, new GLPLStarSurfaceFragmentShader());
                items.Add(sunshader);

                var shape = GLSphereObjectFactory.CreateSphereFromTriangles(2, sunsize);

                GLRenderState rt = GLRenderState.Tri();     // render is triangles, with no depth test so we always appear
                rt.DepthTest  = depthtest;
                rt.DepthClamp = true;
                renderersun   = GLRenderableItem.CreateVector4Vector4(items, OpenTK.Graphics.OpenGL4.PrimitiveType.Triangles, rt, shape, starposbuf, 0, null, currentfilteredlist.Count, 1);
                rObjects.Add(sunshader, "travelpath-suns", renderersun);

                // find compute

                var geofind = new GLPLGeoShaderFindTriangles(bufferfindresults, 16);
                findshader = items.NewShaderPipeline(null, sunvertex, null, null, geofind, null, null, null);
                rifind     = GLRenderableItem.CreateVector4Vector4(items, OpenTK.Graphics.OpenGL4.PrimitiveType.Triangles, GLRenderState.Tri(), shape, starposbuf, ic: currentfilteredlist.Count, seconddivisor: 1);

                // Sun names, handled by textrenderer
                textrenderer = new GLBitmaps("bm-travelmap", rObjects, new Size(128, 40), depthtest: depthtest, cullface: false);
                items.Add(textrenderer);
            }
            else
            {
                tapepointbuf.AllocateFill(tape.Item1.ToArray());                                       // replace the points with a new one
                ritape.RenderState.PrimitiveRestart = GL4Statics.DrawElementsRestartValue(tape.Item3); // IMPORTANT missing bit Robert, must set the primitive restart value to the new tape size
                ritape.CreateElementIndex(ritape.ElementBuffer, tape.Item2.ToArray(), tape.Item3);     // update the element buffer
                ritape.Visible = tape.Item1.Count > 0;

                starposbuf.AllocateFill(positionsv4);           // and update the star position buffers so find and sun renderer works
                renderersun.InstanceCount = positionsv4.Length; // update the number of suns to draw.

                rifind.InstanceCount = positionsv4.Length;      // update the find list
            }

            // name bitmaps

            HashSet <object> hashset = new HashSet <object>(currentfilteredlist);       // so it can find it quickly

            textrenderer.CurrentGeneration++;                                           // setup for next generation
            textrenderer.RemoveGeneration(textrenderer.CurrentGeneration - 1, hashset); // and remove all of the previous one which are not in hashset.

            Font fnt = new Font("Arial", 8.5F);

            using (StringFormat fmt = new StringFormat())
            {
                fmt.Alignment = StringAlignment.Center;
                foreach (var isys in currentfilteredlist)
                {
                    if (textrenderer.Exist(isys) == false)                   // if does not exist already, need a new label
                    {
                        textrenderer.Add(isys, isys.System.Name, fnt, Color.White, Color.Transparent, new Vector3((float)isys.System.X, (float)isys.System.Y - 5, (float)isys.System.Z),
                                         new Vector3(20, 0, 0), new Vector3(0, 0, 0), textformat: fmt, rotatetoviewer: true, rotateelevation: false, alphafadescalar: -200, alphafadepos: 300);
                    }
                }
            }

            fnt.Dispose();
        }
        /// <summary>
        /// Creator of this draw set
        /// </summary>
        /// <param name="textures"> number of 2D textures to allow maximum (limited by GL)</param>
        /// <param name="estimateditemspergroup">Estimated objects per group, this adds on vertext buffer space to allow for mat4 alignment. Smaller means more allowance.</param>
        /// <param name="mingroups">Minimum groups to have</param>
        /// <param name="objectbuffer">Object buffer to use</param>
        /// <param name="objectvertexes">Number of object vertexes</param>
        /// <param name="objrc">The object render state control</param>
        /// <param name="objpt">The object draw primitive type</param>
        /// <param name="texturesize">The size of the label</param>
        /// <param name="textrc">The text render state</param>
        /// <param name="textureformat">The texture format for the text</param>
        /// <param name="debuglimittexture">For debug, set this to limit maximum number of entries. 0 = off</param>
        /// <returns></returns>
        public Tuple <GLRenderableItem, GLRenderableItem> Create(
            int textures,
            int estimateditemspergroup,
            int mingroups,
            GLBuffer objectbuffer, int objectvertexes, GLRenderState objrc, PrimitiveType objpt,
            Size texturesize, GLRenderState textrc, SizedInternalFormat textureformat,
            int debuglimittexture = 0)
        {
            this.objectvertexescount = objectvertexes;
            this.context             = GLStatics.GetContext();

            // Limit number of 2d textures in a single 2d array
            int maxtextper2darray = GL4Statics.GetMaxTextureDepth();

            if (debuglimittexture > 0)
            {
                maxtextper2darray = debuglimittexture;
            }

            // set up number of textmaps bound
            int maxtexturesbound = GL4Statics.GetMaxFragmentTextures();
            int textmaps         = Math.Min(textures, maxtexturesbound);

            // which then give us the number of stars we can do
            int objectcount = textmaps * maxtextper2darray;
            int groupcount  = objectcount / estimateditemspergroup;

            groupcount = Math.Max(mingroups, groupcount);               // min groups

            // System.Diagnostics.Debug.WriteLine($"GLObjectWithLabels oc {objectcount} gc {groupcount}");

            // estimate maximum vert buffer needed, allowing for extra due to the need to align the mat4
            int vertbufsize = objectcount * (GLBuffer.Vec4size + GLBuffer.Mat4size) + // for a vec4 + mat4 per object
                              groupcount * GLBuffer.Mat4size;                         // and for groupcount Mat4 fragmentation per group

            // create the vertex indirect buffer
            dataindirectbuffer = new GLVertexBufferIndirect(items, vertbufsize, GLBuffer.WriteIndirectArrayStride * groupcount, true, BufferUsageHint.DynamicDraw);

            // objects
            ObjectRenderer = GLRenderableItem.CreateVector4Vector4(items, objpt, objrc,
                                                                   objectbuffer, 0, 0,           // binding 0 is shapebuf, offset 0, no draw count yet
                                                                   dataindirectbuffer.Vertex, 0, // binding 1 is vertex's world positions, offset 0
                                                                   null, 0, 1);                  // no ic, second divisor 1
            ObjectRenderer.BaseIndexOffset      = 0;                                             // offset in bytes where commands are stored
            ObjectRenderer.MultiDrawCountStride = GLBuffer.WriteIndirectArrayStride;

            // text

            this.textures = new GLTexture2DArray[textmaps];

            for (int i = 0; i < this.textures.Length; i++)
            {
                int n = Math.Min(objectcount, maxtextper2darray);
                this.textures[i] = new GLTexture2DArray(texturesize.Width, texturesize.Height, n, textureformat, 1);
                items.Add(this.textures[i]);
                objectcount -= maxtextper2darray;
            }

            TextRenderer = GLRenderableItem.CreateMatrix4(items, PrimitiveType.Quads, textrc,
                                                          dataindirectbuffer.Vertex, 0, 0,           //attach buffer with matrices, no draw count
                                                          new GLRenderDataTexture(this.textures, 0), // binding 0 assign to our texture 2d
                                                          0, 1);                                     //no ic, and matrix divide so 1 matrix per vertex set
            TextRenderer.BaseIndexOffset      = 0;                                                   // offset in bytes where commands are stored
            TextRenderer.MultiDrawCountStride = GLBuffer.WriteIndirectArrayStride;


            return(new Tuple <GLRenderableItem, GLRenderableItem>(ObjectRenderer, TextRenderer));
        }
        /// <summary>
        /// Get a texture image in a speciic type.  Only floats or bytes are currently supported.
        /// Use inverty to correct for any inversion if your getting the data from a framebuffer texture - it appears to be inverted when written
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pxformatback">Return format.</param>
        /// <param name="level">Image level</param>
        /// <param name="inverty">If to inverty so the image is the standard windows way up (first is top) instead of openGL</param>
        /// <returns>Array of selected type</returns>
        public T[] GetTextureImageAs <T>(PixelFormat pxformatback = PixelFormat.Rgba, int level = 0, bool inverty = false)
        {
            System.Diagnostics.Debug.Assert(context == GLStatics.GetContext(), "Context incorrect");

            int elementsperpixel = GL4Statics.ElementsPerPixel(pxformatback);

            int totalelements = Width * Height * elementsperpixel;

            int elementsizeT = Marshal.SizeOf(typeof(T));

            int elementstride = elementsperpixel * Width;

            int bufsize = totalelements * elementsizeT;

            IntPtr unmanagedPointer = Marshal.AllocHGlobal(bufsize);                                                                              // get an unmanaged buffer

            GL.GetTextureImage(Id, level, pxformatback, elementsizeT == 4 ? PixelType.Float : PixelType.UnsignedByte, bufsize, unmanagedPointer); // fill
            GLStatics.Check();

            if (elementsizeT == 4)
            {
                float[] data = new float[totalelements];

                if (inverty)
                {
                    IntPtr p = unmanagedPointer;
                    for (int y = 0; y < Height; y++)
                    {
                        Marshal.Copy(p, data, (Height - 1 - y) * elementstride, elementstride);      // transfer buffer to floats
                        p += elementstride;
                    }
                }
                else
                {
                    Marshal.Copy(unmanagedPointer, data, 0, totalelements);      // transfer buffer to floats
                }

                Marshal.FreeHGlobal(unmanagedPointer);
                return(data as T[]);
            }
            else
            {
                byte[] data = new byte[totalelements];

                if (inverty)
                {
                    IntPtr p = unmanagedPointer;
                    for (int y = 0; y < Height; y++)
                    {
                        Marshal.Copy(p, data, (Height - 1 - y) * elementstride, elementstride);      // transfer buffer to floats
                        p += elementstride;
                    }
                }
                else
                {
                    Marshal.Copy(unmanagedPointer, data, 0, totalelements);      // transfer buffer to floats
                }

                Marshal.FreeHGlobal(unmanagedPointer);
                return(data as T[]);
            }
        }
Example #6
0
        // currentfilteredlist set, go..
        private void CreatePathInt(Color?tapepathdefault = null)
        {
            if (!tapeshader.Compiled || !sunshader.Compiled)
            {
                return;
            }

            // Note W here selects the colour index of the stars, 0 = first, 1 = second etc

            Vector4[] positionsv4 = currentfilteredlistsys.Select(x => new Vector4((float)x.X, (float)x.Y, (float)x.Z, 0)).ToArray();
            //   positionsv4 = positionsv4.Take(2).ToArray(); // debug

            Color[] color = new Color[currentfilteredlistsys.Count];

            if (currentfilteredlisthe != null)
            {
                for (int i = 0; i < positionsv4.Length; i++)        // if we are on a jump colour entry, then pick up its colour, otherwise use the last, unless its at the beginning
                {
                    var je = currentfilteredlisthe[i].journalEntry as IJournalJumpColor;
                    if (je != null)
                    {
                        color[i] = je.MapColorARGB;
                    }
                    else
                    {
                        color[i] = i > 0 ? color[i - 1] : Color.Green;
                    }
                }
            }
            else
            {
                for (int i = 0; i < positionsv4.Length; i++)        // for an ISystem path, we use the default color
                {
                    color[i] = tapepathdefault.Value;
                }
            }

            float seglen = tapesize * 10;

            // set the tape up

            var tape = GLTapeNormalObjectFactory.CreateTape(positionsv4, color, seglen, 0F.Radians(), margin: sunsize * 1.2f); // create tape

            // we fill in the buffer again, and reset the binding position of entry two, update the element index, set visibility
            tapepointbuf.AllocateBytes((tape.Item1.Count + tape.Item2.Count) * GLBuffer.Vec4size);
            tapepointbuf.Fill(tape.Item1.ToArray());
            tapepointbuf.Fill(tape.Item2.ToArray());
            tapepointbuf.Bind(ritape.VertexArray, 1, tapepointbuf.Positions[1], 16);               // for the second one, need to update and rebind positions. First one always at zero

            ritape.RenderState.PrimitiveRestart = GL4Statics.DrawElementsRestartValue(tape.Item4); // IMPORTANT missing bit Robert, must set the primitive restart value to the new tape size
            ritape.CreateElementIndex(ritape.ElementBuffer, tape.Item3.ToArray(), tape.Item4);     // update the element buffer, DrawCount, ElementIndexSize
            ritape.Visible = tape.Item1.Count > 0;                                                 // only visible if positions..

            starposbuf.AllocateFill(positionsv4);                                                  // and update the star position buffers so find and sun renderer works
            renderersun.InstanceCount = positionsv4.Length;                                        // update the number of suns to draw.
            renderersun.Visible       = positionsv4.Length > 0;                                    // only visible if positions..

            rifind.InstanceCount = positionsv4.Length;                                             // update the find list

            // name bitmaps

            HashSet <object> hashset = new HashSet <object>(currentfilteredlistsys);    // so it can find it quickly

            textrenderer.CurrentGeneration++;                                           // setup for next generation
            textrenderer.RemoveGeneration(textrenderer.CurrentGeneration - 1, hashset); // and remove all of the previous one which are not in hashset.

            using (StringFormat fmt = new StringFormat())
            {
                fmt.Alignment = StringAlignment.Center;
                foreach (var isys in currentfilteredlistsys)
                {
                    if (textrenderer.Exist(isys) == false)                   // if does not exist already, need a new label
                    {
                        textrenderer.Add(isys, isys.Name, Font, ForeText, BackText, new Vector3((float)isys.X + LabelOffset.X, (float)isys.Y + LabelOffset.Y, (float)isys.Z + LabelOffset.Z),
                                         LabelSize, new Vector3(0, 0, 0), textformat: fmt, rotatetoviewer: true, rotateelevation: false, alphafadescalar: -200, alphafadepos: 300);
                    }
                }
            }
        }