예제 #1
0
        // villsa 9/15/11
        private void SetupThingArrow()
        {
            const int totalvertices = 6;

            WorldVertex[] tv = new WorldVertex[totalvertices];

            tv[0] = new WorldVertex(0.0f, 0.0f, 0.5f);
            tv[1] = new WorldVertex(0.0f, 1.35f, 0.5f);
            tv[2] = new WorldVertex(0.0f, 1.35f, 0.5f);
            tv[3] = new WorldVertex(0.175f, 1.1f, 0.5f);
            tv[4] = new WorldVertex(0.0f, 1.35f, 0.5f);
            tv[5] = new WorldVertex(-0.175f, 1.1f, 0.5f);

            // Create vertexbuffer
            thingarrow = new VertexBuffer(General.Map.Graphics.Device, WorldVertex.Stride * totalvertices,
                                          Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default);
            DataStream bufferstream = thingarrow.Lock(0, WorldVertex.Stride * totalvertices, LockFlags.Discard);

            bufferstream.WriteRange <WorldVertex>(tv);
            thingarrow.Unlock();
            bufferstream.Dispose();
        }
        // Called when all resource must be reloaded
        public void ReloadResource()
        {
            foreach (KeyValuePair <int, SurfaceBufferSet> set in sets)
            {
                // Rebuild vertex buffers
                for (int i = 0; i < set.Value.buffersizes.Count; i++)
                {
                    // Make the new buffer!
                    VertexBuffer b = new VertexBuffer(General.Map.Graphics.Device, FlatVertex.Stride * set.Value.buffersizes[i],
                                                      Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default);

                    // Start refilling the buffer with sector geometry
                    int        vertexoffset = 0;
                    DataStream bstream      = b.Lock(0, FlatVertex.Stride * set.Value.buffersizes[i], LockFlags.Discard);
                    foreach (SurfaceEntry e in set.Value.entries)
                    {
                        if (e.bufferindex == i)
                        {
                            // Fill buffer
                            bstream.Seek(e.vertexoffset * FlatVertex.Stride, SeekOrigin.Begin);
                            bstream.WriteRange(e.floorvertices);
                            bstream.WriteRange(e.ceilvertices);
                        }
                    }

                    // Unlock buffer
                    b.Unlock();
                    bstream.Dispose();

                    // Add to list
                    set.Value.buffers[i] = b;
                }
            }

            resourcesunloaded = false;
        }
예제 #3
0
        // This updates the text if needed
        public void Update(float translatex, float translatey, float scalex, float scaley)
        {
            // Check if transformation changed and needs to be updated
            if (transformcoords && (translatex != lasttranslatex || translatey != lasttranslatey ||
                                    scalex != lastscalex || scaley != lastscaley))
            {
                lasttranslatex = translatex;         //mxd
                lasttranslatey = translatey;         //mxd
                lastscalex     = scalex;             //mxd
                lastscaley     = scaley;             //mxd
                updateneeded   = true;
            }

            // Update if needed
            if (updateneeded || textureupdateneeded)
            {
                // Only build when there are any vertices
                if (text.Length > 0)
                {
                    // Transform?
                    Vector2D abspos = (transformcoords ? location.GetTransformed(translatex, translatey, scalex, scaley) : location);

                    // Update text and texture sizes
                    if (textsize.IsEmpty || texturesize.IsEmpty)
                    {
                        textorigin      = new PointF(4, 3);
                        textrect        = new RectangleF(textorigin, General.Interface.MeasureString(text, font));
                        textrect.Width  = (float)Math.Round(textrect.Width);
                        textrect.Height = (float)Math.Round(textrect.Height);
                        bgrect          = new RectangleF(0, 0, textrect.Width + textorigin.X * 2, textrect.Height + textorigin.Y * 2);

                        // Store calculated text size...
                        textsize = new SizeF(textrect.Width + textorigin.X * 2, textrect.Height + textorigin.Y * 2);

                        // Make PO2 image, for speed and giggles...
                        texturesize = new Size(General.NextPowerOf2((int)textsize.Width), General.NextPowerOf2((int)textsize.Height));

                        switch (alignx)
                        {
                        case TextAlignmentX.Center: bgrect.X = (texturesize.Width - bgrect.Width) / 2; break;

                        case TextAlignmentX.Right: bgrect.X = texturesize.Width - bgrect.Width; break;
                        }

                        switch (aligny)
                        {
                        case TextAlignmentY.Middle: bgrect.Y = (texturesize.Height - bgrect.Height) / 2; break;

                        case TextAlignmentY.Bottom: bgrect.Y = texturesize.Height - bgrect.Height; break;
                        }

                        textrect.X += bgrect.X;
                        textrect.Y += bgrect.Y;
                    }

                    // Align the text horizontally
                    float beginx = 0;
                    switch (alignx)
                    {
                    case TextAlignmentX.Left: beginx = abspos.x; break;

                    case TextAlignmentX.Center: beginx = abspos.x - texturesize.Width * 0.5f; break;

                    case TextAlignmentX.Right: beginx = abspos.x - texturesize.Width; break;
                    }

                    // Align the text vertically
                    float beginy = 0;
                    switch (aligny)
                    {
                    case TextAlignmentY.Top: beginy = abspos.y; break;

                    case TextAlignmentY.Middle: beginy = abspos.y - texturesize.Height * 0.5f; break;

                    case TextAlignmentY.Bottom: beginy = abspos.y - texturesize.Height; break;
                    }

                    //mxd. Skip when not on screen...
                    RectangleF abssize    = new RectangleF(beginx, beginy, texturesize.Width, texturesize.Height);
                    Size       windowsize = General.Map.Graphics.RenderTarget.ClientSize;
                    skiprendering = (abssize.Right < 0.1f) || (abssize.Left > windowsize.Width) || (abssize.Bottom < 0.1f) || (abssize.Top > windowsize.Height);
                    if (skiprendering)
                    {
                        return;
                    }

                    //mxd. Update texture if needed
                    if (textureupdateneeded)
                    {
                        // Get rid of old texture
                        if (texture != null)
                        {
                            texture.Dispose();
                            texture = null;
                        }

                        // Create label image
                        Bitmap img = CreateLabelImage(text, font, color, backcolor, drawbg, textrect, bgrect, texturesize, textorigin);
                        //texturesize = img.Size;

                        // Create texture
                        MemoryStream memstream = new MemoryStream((img.Size.Width * img.Size.Height * 4) + 4096);
                        img.Save(memstream, ImageFormat.Bmp);
                        memstream.Seek(0, SeekOrigin.Begin);

                        texture = Texture.FromStream(General.Map.Graphics.Device, memstream, (int)memstream.Length,
                                                     img.Size.Width, img.Size.Height, 1, Usage.None, Format.Unknown,
                                                     Pool.Managed, General.Map.Graphics.PostFilter, General.Map.Graphics.MipGenerateFilter, 0);
                    }

                    //mxd. Create the buffer
                    if (textbuffer == null || textbuffer.Disposed)
                    {
                        textbuffer = new VertexBuffer(General.Map.Graphics.Device, 4 * FlatVertex.Stride,
                                                      Usage.Dynamic | Usage.WriteOnly, VertexFormat.None, Pool.Default);
                    }

                    //mxd. Lock the buffer
                    using (DataStream stream = textbuffer.Lock(0, 4 * FlatVertex.Stride, LockFlags.Discard | LockFlags.NoSystemLock))
                    {
                        FlatQuad quad = new FlatQuad(PrimitiveType.TriangleStrip, beginx, beginy, beginx + texturesize.Width, beginy + texturesize.Height);
                        stream.WriteRange(quad.Vertices);
                    }

                    // Done filling the vertex buffer
                    textbuffer.Unlock();
                }
                else
                {
                    // No faces in polygon
                    textsize      = SizeF.Empty;              //mxd
                    texturesize   = Size.Empty;               //mxd
                    skiprendering = true;                     //mxd
                }

                // Text updated
                updateneeded        = false;
                textureupdateneeded = false;                 //mxd
            }
        }
예제 #4
0
        // This sets up the thing cage
        private void SetupThingCage()
        {
            const int totalvertices = 36;

            WorldVertex[] tv = new WorldVertex[totalvertices];
            float         x0 = -1.0f;
            float         x1 = 1.0f;
            float         y0 = -1.0f;
            float         y1 = 1.0f;
            float         z0 = 0.0f;
            float         z1 = 1.0f;
            float         u0 = 0.0f;
            float         u1 = 1.0f;
            float         v0 = 0.0f;
            float         v1 = 1.0f;
            int           c  = -1;

            // Front
            tv[0] = new WorldVertex(x0, y0, z0, c, u0, v0);
            tv[1] = new WorldVertex(x0, y0, z1, c, u0, v1);
            tv[2] = new WorldVertex(x1, y0, z0, c, u1, v0);
            tv[3] = new WorldVertex(x1, y0, z0, c, u1, v0);
            tv[4] = new WorldVertex(x0, y0, z1, c, u0, v1);
            tv[5] = new WorldVertex(x1, y0, z1, c, u1, v1);

            // Right
            tv[6]  = new WorldVertex(x1, y0, z0, c, u0, v0);
            tv[7]  = new WorldVertex(x1, y0, z1, c, u0, v1);
            tv[8]  = new WorldVertex(x1, y1, z0, c, u1, v0);
            tv[9]  = new WorldVertex(x1, y1, z0, c, u1, v0);
            tv[10] = new WorldVertex(x1, y0, z1, c, u0, v1);
            tv[11] = new WorldVertex(x1, y1, z1, c, u1, v1);

            // Back
            tv[12] = new WorldVertex(x1, y1, z0, c, u0, v0);
            tv[13] = new WorldVertex(x1, y1, z1, c, u0, v1);
            tv[14] = new WorldVertex(x0, y1, z0, c, u1, v0);
            tv[15] = new WorldVertex(x0, y1, z0, c, u1, v0);
            tv[16] = new WorldVertex(x1, y1, z1, c, u0, v1);
            tv[17] = new WorldVertex(x0, y1, z1, c, u1, v1);

            // Left
            tv[18] = new WorldVertex(x0, y1, z0, c, u0, v1);
            tv[19] = new WorldVertex(x0, y1, z1, c, u0, v0);
            tv[20] = new WorldVertex(x0, y0, z1, c, u1, v0);
            tv[21] = new WorldVertex(x0, y1, z0, c, u1, v0);
            tv[22] = new WorldVertex(x0, y0, z1, c, u0, v1);
            tv[23] = new WorldVertex(x0, y0, z0, c, u1, v1);

            // Top
            tv[24] = new WorldVertex(x0, y0, z1, c, u0, v0);
            tv[25] = new WorldVertex(x0, y1, z1, c, u0, v1);
            tv[26] = new WorldVertex(x1, y0, z1, c, u1, v0);
            tv[27] = new WorldVertex(x1, y0, z1, c, u1, v0);
            tv[28] = new WorldVertex(x0, y1, z1, c, u0, v1);
            tv[29] = new WorldVertex(x1, y1, z1, c, u1, v1);

            // Bottom
            tv[30] = new WorldVertex(x1, y0, z0, c, u1, v0);
            tv[31] = new WorldVertex(x0, y1, z0, c, u0, v1);
            tv[32] = new WorldVertex(x0, y0, z0, c, u0, v0);
            tv[33] = new WorldVertex(x1, y0, z0, c, u1, v0);
            tv[34] = new WorldVertex(x1, y1, z0, c, u1, v1);
            tv[35] = new WorldVertex(x0, y1, z0, c, u0, v1);

            // Create vertexbuffer
            thingcage = new VertexBuffer(General.Map.Graphics.Device, WorldVertex.Stride * totalvertices,
                                         Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default);
            DataStream bufferstream = thingcage.Lock(0, WorldVertex.Stride * totalvertices, LockFlags.Discard);

            bufferstream.WriteRange <WorldVertex>(tv);
            thingcage.Unlock();
            bufferstream.Dispose();
        }
예제 #5
0
        // This updates the text if needed
        internal void Update(float translatex, float translatey, float scalex, float scaley)
        {
            RectangleF absview;
            float      beginx = 0;
            float      beginy = 0;

            byte[]     textbytes;
            DataStream stream;

            // Check if transformation changed and needs to be updated
            if (transformcoords)
            {
                if ((translatex != lasttranslatex) ||
                    (translatey != lasttranslatey) ||
                    (scalex != lastscalex) ||
                    (scaley != lastscaley))
                {
                    updateneeded = true;
                }
            }

            // Update if needed
            if (updateneeded)
            {
                // Only build when there are any vertices
                if (text.Length > 0)
                {
                    // Do we have to make a new buffer?
                    if ((textbuffer == null) || (text.Length > capacity))
                    {
                        // Dispose previous
                        if (textbuffer != null)
                        {
                            textbuffer.Dispose();
                        }

                        // Determine new capacity
                        if (capacity < text.Length)
                        {
                            capacity = text.Length;
                        }

                        // Create the buffer
                        textbuffer = new VertexBuffer(General.Map.Graphics.Device,
                                                      capacity * 12 * FlatVertex.Stride,
                                                      Usage.Dynamic | Usage.WriteOnly,
                                                      VertexFormat.None, Pool.Default);
                    }

                    // Transform?
                    if (transformcoords)
                    {
                        // Calculate absolute coordinates
                        Vector2D lt = new Vector2D(rect.Left, rect.Top);
                        Vector2D rb = new Vector2D(rect.Right, rect.Bottom);
                        lt      = lt.GetTransformed(translatex, translatey, scalex, scaley);
                        rb      = rb.GetTransformed(translatex, translatey, scalex, scaley);
                        absview = new RectangleF(lt.x, lt.y, rb.x - lt.x, rb.y - lt.y);
                    }
                    else
                    {
                        // Fixed coordinates
                        absview = rect;
                    }

                    // Calculate text dimensions
                    size = General.Map.Graphics.Font.GetTextSize(text, scale);

                    // Align the text horizontally
                    switch (alignx)
                    {
                    case TextAlignmentX.Left: beginx = absview.X; break;

                    case TextAlignmentX.Center: beginx = absview.X + (absview.Width - size.Width) * 0.5f; break;

                    case TextAlignmentX.Right: beginx = absview.X + absview.Width - size.Width; break;
                    }

                    // Align the text vertically
                    switch (aligny)
                    {
                    case TextAlignmentY.Top: beginy = absview.Y; break;

                    case TextAlignmentY.Middle: beginy = absview.Y + (absview.Height - size.Height) * 0.5f; break;

                    case TextAlignmentY.Bottom: beginy = absview.Y + absview.Height - size.Height; break;
                    }

                    // Get the ASCII bytes for the text
                    textbytes = Encoding.ASCII.GetBytes(text);

                    // Lock the buffer
                    stream = textbuffer.Lock(0, capacity * 12 * FlatVertex.Stride,
                                             LockFlags.Discard | LockFlags.NoSystemLock);

                    // Go for all chars in text to create the backgrounds
                    float textx = beginx;
                    foreach (byte b in textbytes)
                    {
                        General.Map.Graphics.Font.SetupVertices(stream, b, scale, backcolor.ToInt(),
                                                                ref textx, beginy, size.Height, 0.5f);
                    }

                    // Go for all chars in text to create the text
                    textx = beginx;
                    foreach (byte b in textbytes)
                    {
                        General.Map.Graphics.Font.SetupVertices(stream, b, scale, color.ToInt(),
                                                                ref textx, beginy, size.Height, 0.0f);
                    }

                    // Done filling the vertex buffer
                    textbuffer.Unlock();
                    stream.Dispose();

                    // Calculate number of triangles
                    numfaces = text.Length * 4;
                }
                else
                {
                    // No faces in polygon
                    numfaces = 0;
                    size     = new SizeF(0f, 0f);
                }

                // Text updated
                updateneeded = false;
            }
        }
예제 #6
0
        // This adds or updates sector geometry into a buffer.
        // Modiies the list of SurfaceEntries with the new surface entry for the stored geometry.
        public void UpdateSurfaces(SurfaceEntryCollection entries, SurfaceUpdate update)
        {
            // Free entries when number of vertices has changed
            if ((entries.Count > 0) && (entries.totalvertices != update.numvertices))
            {
                FreeSurfaces(entries);
                entries.Clear();
            }

            if ((entries.Count == 0) && (update.numvertices > 0))
            {
                                #if DEBUG
                if ((update.floorvertices == null) || (update.ceilvertices == null))
                {
                    General.Fail("We need both floor and ceiling vertices when the number of vertices changes!");
                }
                                #endif

                // If we have no entries yet, we have to make them now
                int vertsremaining = update.numvertices;
                while (vertsremaining > 0)
                {
                    // Determine for how many vertices in this entry
                    int vertsinentry = (vertsremaining > MAX_VERTICES_PER_SECTOR) ? MAX_VERTICES_PER_SECTOR : vertsremaining;

                    // Lookup the set that holds entries for this number of vertices
                    SurfaceBufferSet set = GetSet(vertsinentry);

                    // Make sure we can get a new entry in this set
                    EnsureFreeBufferSpace(set, 1);

                    // Get a new entry in this set
                    SurfaceEntry e = set.holes[set.holes.Count - 1];
                    set.holes.RemoveAt(set.holes.Count - 1);
                    set.entries.Add(e);

                    // Fill the entry data
                    e.floorvertices = new FlatVertex[vertsinentry];
                    e.ceilvertices  = new FlatVertex[vertsinentry];
                    Array.Copy(update.floorvertices, update.numvertices - vertsremaining, e.floorvertices, 0, vertsinentry);
                    Array.Copy(update.ceilvertices, update.numvertices - vertsremaining, e.ceilvertices, 0, vertsinentry);
                    e.floortexture = update.floortexture;
                    e.ceiltexture  = update.ceiltexture;

                    entries.Add(e);
                    vertsremaining -= vertsinentry;
                }
            }
            else
            {
                // We re-use the same entries, just copy over the updated data
                int vertsremaining = update.numvertices;
                foreach (SurfaceEntry e in entries)
                {
                    if (update.floorvertices != null)
                    {
                        Array.Copy(update.floorvertices, update.numvertices - vertsremaining, e.floorvertices, 0, e.numvertices);
                        e.floortexture = update.floortexture;
                    }

                    if (update.ceilvertices != null)
                    {
                        Array.Copy(update.ceilvertices, update.numvertices - vertsremaining, e.ceilvertices, 0, e.numvertices);
                        e.ceiltexture = update.ceiltexture;
                    }

                    vertsremaining -= e.numvertices;
                }
            }

            entries.totalvertices = update.numvertices;

            // Time to update or create the buffers
            foreach (SurfaceEntry e in entries)
            {
                SurfaceBufferSet set = GetSet(e.numvertices);

                // Update bounding box
                e.UpdateBBox();

                if (!resourcesunloaded)
                {
                    // Lock the buffer
                    DataStream   bstream;
                    VertexBuffer vb = set.buffers[e.bufferindex];
                    if (vb.Tag == null)
                    {
                        // Note: DirectX warns me that I am not using LockFlags.Discard or LockFlags.NoOverwrite here,
                        // but we don't have much of a choice since we want to update our data and not destroy other data
                        bstream = vb.Lock(0, set.buffersizes[e.bufferindex] * FlatVertex.Stride, LockFlags.None);
                        vb.Tag  = bstream;
                        lockedbuffers.Add(vb);
                    }
                    else
                    {
                        bstream = (DataStream)vb.Tag;
                    }

                    // Write the vertices to buffer
                    bstream.Seek(e.vertexoffset * FlatVertex.Stride, SeekOrigin.Begin);
                    bstream.WriteRange(e.floorvertices);
                    bstream.WriteRange(e.ceilvertices);
                }
            }
        }
예제 #7
0
        // This ensures there is enough space for a given number of free entries (also adds new bufers if needed)
        private void EnsureFreeBufferSpace(SurfaceBufferSet set, int freeentries)
        {
            DataStream   bstream = null;
            VertexBuffer vb      = null;

            // Check if we have to add entries
            int addentries = freeentries - set.holes.Count;

            // Begin resizing buffers starting with the last in this set
            int bufferindex = set.buffers.Count - 1;

            // Calculate the maximum number of entries we can put in a new buffer
            // Note that verticesperentry is the number of vertices multiplied by 2, because
            // we have to store both the floor and ceiling
            int verticesperentry    = set.numvertices * 2;
            int maxentriesperbuffer = MAX_VERTICES_PER_BUFFER / verticesperentry;

            // Make a new bufer when the last one is full
            if ((bufferindex > -1) && (set.buffersizes[bufferindex] >= (maxentriesperbuffer * verticesperentry)))
            {
                bufferindex = -1;
            }

            while (addentries > 0)
            {
                // Create a new buffer?
                if ((bufferindex == -1) || (bufferindex > (set.buffers.Count - 1)))
                {
                    // Determine the number of entries we will be making this buffer for
                    int bufferentries = (addentries > maxentriesperbuffer) ? maxentriesperbuffer : addentries;

                    // Calculate the number of vertices that will be
                    int buffernumvertices = bufferentries * verticesperentry;

                    if (!resourcesunloaded)
                    {
                        // Make the new buffer!
                        vb = new VertexBuffer(General.Map.Graphics.Device, FlatVertex.Stride * buffernumvertices,
                                              Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default);

                        // Add it.
                        set.buffers.Add(vb);
                    }
                    else
                    {
                        // We can't make a vertexbuffer right now
                        set.buffers.Add(null);
                    }

                    // Also add available entries as holes, because they are not used yet.
                    set.buffersizes.Add(buffernumvertices);
                    for (int i = 0; i < bufferentries; i++)
                    {
                        set.holes.Add(new SurfaceEntry(set.numvertices, set.buffers.Count - 1, i * verticesperentry));
                    }

                    // Done
                    addentries -= bufferentries;
                }
                // Reallocate a buffer
                else
                {
                    // Trash the old buffer
                    if (set.buffers[bufferindex].Tag != null)
                    {
                        bstream = (DataStream)set.buffers[bufferindex].Tag;
                        set.buffers[bufferindex].Unlock();
                        bstream.Dispose();
                        set.buffers[bufferindex].Tag = null;
                    }

                    if ((set.buffers[bufferindex] != null) && !resourcesunloaded)
                    {
                        set.buffers[bufferindex].Dispose();
                    }

                    // Get the entries that are in this buffer only
                    List <SurfaceEntry> theseentries = new List <SurfaceEntry>();
                    foreach (SurfaceEntry e in set.entries)
                    {
                        if (e.bufferindex == bufferindex)
                        {
                            theseentries.Add(e);
                        }
                    }

                    // Determine the number of entries we will be making this buffer for
                    int bufferentries = ((theseentries.Count + addentries) > maxentriesperbuffer) ? maxentriesperbuffer : (theseentries.Count + addentries);

                    // Calculate the number of vertices that will be
                    int buffernumvertices = bufferentries * verticesperentry;

                    if (!resourcesunloaded)
                    {
                        // Make the new buffer and lock it
                        vb = new VertexBuffer(General.Map.Graphics.Device, FlatVertex.Stride * buffernumvertices,
                                              Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default);
                        bstream = vb.Lock(0, FlatVertex.Stride * theseentries.Count * verticesperentry, LockFlags.Discard);
                    }

                    // Start refilling the buffer with sector geometry
                    int vertexoffset = 0;
                    foreach (SurfaceEntry e in theseentries)
                    {
                        if (!resourcesunloaded)
                        {
                            // Fill buffer
                            bstream.WriteRange(e.floorvertices);
                            bstream.WriteRange(e.ceilvertices);
                        }

                        // Set the new location in the buffer
                        e.vertexoffset = vertexoffset;

                        // Move on
                        vertexoffset += verticesperentry;
                    }

                    if (!resourcesunloaded)
                    {
                        // Unlock buffer
                        vb.Unlock();
                        bstream.Dispose();
                        set.buffers[bufferindex] = vb;
                    }
                    else
                    {
                        // No vertex buffer at this time, sorry
                        set.buffers[bufferindex] = null;
                    }

                    // Set the new buffer and add available entries as holes, because they are not used yet.
                    set.buffersizes[bufferindex] = buffernumvertices;
                    set.holes.Clear();
                    for (int i = 0; i < bufferentries - theseentries.Count; i++)
                    {
                        set.holes.Add(new SurfaceEntry(set.numvertices, bufferindex, i * verticesperentry + vertexoffset));
                    }

                    // Done
                    addentries -= bufferentries;
                }

                // Always continue in next (new) buffer
                bufferindex = set.buffers.Count;
            }
        }
예제 #8
0
        // This adds or updates sector geometry into a buffer.
        // Always specify the entry when a previous entry was already given for that sector!
        // Sector must set the floorvertices and ceilvertices members on the entry.
        // Returns the new surface entry for the stored geometry, floorvertices and ceilvertices will be preserved.
        public SurfaceEntry UpdateSurfaces(SurfaceEntry entry)
        {
            if (entry.floorvertices.Length != entry.ceilvertices.Length)
            {
                General.Fail("Floor vertices has different length from ceiling vertices!");
            }

            int numvertices = entry.floorvertices.Length;

            // Free entry when number of vertices have changed
            if ((entry.numvertices != numvertices) && (entry.numvertices != -1))
            {
                FreeSurfaces(entry);
            }

            // Check if we can render this at all
            if (numvertices > 0)
            {
                SurfaceBufferSet set = GetSet(numvertices);

                // Update bounding box
                entry.UpdateBBox();

                // Check if we need a new entry
                if (entry.numvertices == -1)
                {
                    EnsureFreeBufferSpace(set, 1);
                    SurfaceEntry nentry = set.holes[set.holes.Count - 1];
                    set.holes.RemoveAt(set.holes.Count - 1);
                    nentry.ceilvertices  = entry.ceilvertices;
                    nentry.floorvertices = entry.floorvertices;
                    nentry.floortexture  = entry.floortexture;
                    nentry.ceiltexture   = entry.ceiltexture;
                    nentry.bbox          = entry.bbox;
                    set.entries.Add(nentry);
                    entry = nentry;
                }

                if (!resourcesunloaded)
                {
                    // Lock the buffer
                    DataStream   bstream;
                    VertexBuffer vb = set.buffers[entry.bufferindex];
                    if (vb.Tag == null)
                    {
                        // Note: DirectX warns me that I am not using LockFlags.Discard or LockFlags.NoOverwrite here,
                        // but we don't care (we don't have much of a choice since we want to update our data)
                        bstream = vb.Lock(0, set.buffersizes[entry.bufferindex] * FlatVertex.Stride, LockFlags.None);
                        vb.Tag  = bstream;
                        lockedbuffers.Add(vb);
                    }
                    else
                    {
                        bstream = (DataStream)vb.Tag;
                    }

                    // Write the vertices to buffer
                    bstream.Seek(entry.vertexoffset * FlatVertex.Stride, SeekOrigin.Begin);
                    bstream.WriteRange(entry.floorvertices);
                    bstream.WriteRange(entry.ceilvertices);
                }
            }

            return(entry);
        }