Beispiel #1
0
        public int MakeF3D(ROM rom)
        {
            int start = rom.offset;

            foreach (UInt64 cmd in header)
            {
                rom.Write64(cmd);
                rom.AddOffset(8);
            }

            List <TextureDescription> tds = map.Keys.ToList();

            tds.Sort(new TextureDescriptionComp());

            foreach (TextureDescription td in tds)
            {
                foreach (UInt64 cmd in (List <UInt64>)td)
                {
                    rom.Write64(cmd);
                    rom.AddOffset(8);
                }

                VerticesDescription vd = map[td];
                vd.MakeF3D(rom);
            }
            foreach (UInt64 cmd in footer)
            {
                rom.Write64(cmd);
                rom.AddOffset(8);
            }
            return(rom.offset - start);
        }
        static protected void PerformLevelScriptParse <State>(ROM rom, int offset, Parser <State>[] parser, State state)
        {
            rom.PushOffset(offset);

            byte curCmdIndex;

            do
            {
                curCmdIndex = rom.Read8();
                byte curCmdSize = rom.Read8(1);

                if (curCmdSize == 0)
                {
                    throw new ArgumentException("cmd size is 0, loop detected");
                }

                Parser <State> func = parser[curCmdIndex];
                func(rom, state);

                if (curCmdIndex != 0x7)
                {
                    rom.AddOffset(curCmdSize);
                }
            }while (curCmdIndex != terminateCmd);

            rom.PopOffset();
        }
Beispiel #3
0
        public int MakeF3D(ROM rom, SortedRegionList vertexBytes, ScrollFactory factory)
        {
            int start = rom.offset;

            foreach (UInt64 cmd in header)
            {
                rom.Write64(cmd);
                rom.AddOffset(8);
            }

            // TODO: This is kinda stupid assumption but we believe there are more triangles in the beginning available...
            List <ScrollingTextureDescription> tds = map.Keys.ToList();

            tds.Sort(new ScrollingTextureDescriptionComp());

            foreach (ScrollingTextureDescription td in tds)
            {
                td.MakeF3D(rom);

                // Time to do optimization magic
                List <Triangle> textureTris = map[td];

                // Create reverse map for vertices, vertices with more triangles will be used first
                Dictionary <Vertex, List <Triangle> > vertex2triMap = new Dictionary <Vertex, List <Triangle> >();
                foreach (Triangle tri in textureTris)
                {
                    for (int i = 0; i < 3; i++)
                    {
                        Vertex v = tri.vertices[i];
                        if (!vertex2triMap.TryGetValue(v, out List <Triangle> weight))
                        {
                            vertex2triMap[v] = new List <Triangle>();
                        }
                        vertex2triMap[v].Add(tri);
                    }
                }

                // You quite literally can't eat more than that
                int vertexLength = 0x30 * textureTris.Count();
                vertexBytes.CutContigRegion(vertexLength, out int vertexPosition);

                int allocVertexStart     = vertexPosition;
                int allocVertexEnd       = allocVertexStart + vertexLength;
                int writtenVerticesCount = 0;

                // Check if there are still vertices that needs to be worked with
                // Also we must make sure all lists in v2tm are not empty!
                while (vertex2triMap.Count != 0)
                {
                    int segmentedVertexStart = rom.GetSegmentedAddress(vertexPosition);

                    // vbd is main structure that holds information about used vertices space
                    VertexBufferDescription vbd = new VertexBufferDescription((UInt32)segmentedVertexStart, 0xF);

                    // Potential triangles also have weight depending on connection to other triangles and to added vertices
                    // Weight +1 for each tri that shares vertice; +vertexPresentBonus for each vbd present vertex
                    // It is recommended to have vertexPresentBonus be more than any weight that shared vertices can give
                    // This way triangle that have the most weight will have the most vertices and potentially help others
                    Dictionary <Triangle, int> potentialTris = new Dictionary <Triangle, int>();

                    // Add triangles to vbd till it won't be able to fit in the whole triangle
                    while (vbd.freeCount != 0 && vertex2triMap.Count != 0)
                    {
                        // Right now no vertices are in vbd, pick one with the heighest weight and add it to vbd
                        if (potentialTris.Count == 0)
                        {
                            // We need at least 3 vertices to draw not present tri
                            if (vbd.freeCount < 3)
                            {
                                break;
                            }

                            KeyValuePair <Vertex, List <Triangle> > pair;
                            // Let's ask for at least 5 vertices for optimal stuff, otherwise just put the worst triangle and call it
                            if (vbd.freeCount < 5)
                            {
                                pair = vertex2triMap.Aggregate((prev, cur) => prev.Value.Count < cur.Value.Count ? prev : cur);
                            }
                            else
                            {
                                pair = vertex2triMap.Aggregate((prev, cur) => prev.Value.Count > cur.Value.Count ? prev : cur);
                            }

                            Vertex          v    = pair.Key;
                            List <Triangle> tris = pair.Value;
                            if (tris.Count == 0)
                            {
                                throw new ArithmeticException("Tris count in dict can't be 0");
                            }

                            // Put current vertex and use found tris as potential next tri to add
                            vbd.AddVertex(v);

                            // Setup all potential triangles to could be added to vbd, the ones that have this vertex in common

                            foreach (Triangle tri in tris)
                            {
                                potentialTris[tri] = 0;
                            }

                            // If vertex is in common between tris, give 1 each
                            var tripairs = tris.Zip(tris.Skip(1), (a, b) => Tuple.Create(a, b));
                            foreach (Tuple <Triangle, Triangle> tripair in tripairs)
                            {
                                Triangle tri1   = tripair.Item1;
                                Triangle tri2   = tripair.Item2;
                                int      common = tri1.CountCommon(tri2);

                                potentialTris[tri1] += common;
                                potentialTris[tri2] += common;
                            }
                        }


                        // Find tri with biggest weight
                        Triangle biggestTri = potentialTris.Aggregate((prev, cur) => prev.Value > cur.Value ? prev : cur).Key;

                        // Add all triangles in vbd
                        int[] indices = new int[3];

                        for (int i = 0; i < 3; i++)
                        {
                            Vertex v     = biggestTri.vertices[i];
                            int    index = vbd.AddVertex(v, out bool isNew);
                            indices[i] = index;

                            // Fix weights of tris if a new vertex was added to vbd (not already in vbd it is)
                            if (isNew)
                            {
                                foreach (Triangle ptri in potentialTris.Keys.ToList())
                                {
                                    if (ptri.Contains(v))
                                    {
                                        potentialTris[ptri] += vertexPresentBonus;
                                    }
                                }
                            }
                        }

                        // Draw the triangle, all vertices are guaranteed to be in
                        vbd.DrawTriangle(indices);

                        // As triangle was drawn, it needs to be removed from structs that had it
                        // vertex2map & potentialTris
                        // This way triangle won't be able to appear again
                        foreach (Vertex v in biggestTri.vertices)
                        {
                            vertex2triMap[v].Remove(biggestTri);
                            if (vertex2triMap[v].Count == 0)
                            {
                                vertex2triMap.Remove(v);
                            }
                        }

                        potentialTris.Remove(biggestTri);

                        // Setup new triangles to potentialTris
                        HashSet <Triangle> newTris = new HashSet <Triangle>();
                        foreach (Vertex v in biggestTri.vertices)
                        {
                            if (vertex2triMap.TryGetValue(v, out List <Triangle> tris))
                            {
                                foreach (Triangle tri in tris)
                                {
                                    newTris.Add(tri);
                                }
                            }
                        }

                        // Also do not take into account tris that were added already
                        // If we will take them into account, bad things will happen
                        newTris.RemoveWhere(t => potentialTris.Keys.Contains(t));

                        // As new triangles appear, proceed to fix weights
                        // First of all, initialize world: create new potential tris that will be merged later with potential tris
                        // Initial value is -vertexPresentBonus as one vertex will be counted anyways
                        Dictionary <Triangle, int> newPotentialTris = new Dictionary <Triangle, int>();
                        foreach (Triangle ntri in newTris)
                        {
                            newPotentialTris[ntri] = -vertexPresentBonus;
                        }

                        // Calculate weights for vertices that were present
                        foreach (Triangle ntri in newTris)
                        {
                            foreach (Vertex v in vbd.vbuf)
                            {
                                if (ntri.Contains(v))
                                {
                                    newPotentialTris[ntri] += vertexPresentBonus;
                                }
                            }
                        }

                        // Check between triangles new/new
                        var newNewTripairs = newTris.Zip(newTris.Skip(1), (a, b) => Tuple.Create(a, b));
                        foreach (Tuple <Triangle, Triangle> tripair in newNewTripairs)
                        {
                            Triangle tri1   = tripair.Item1;
                            Triangle tri2   = tripair.Item2;
                            int      common = tri1.CountCommon(tri2);

                            newPotentialTris[tri1] += common;
                            newPotentialTris[tri2] += common;
                        }

                        // Check between triangles new/old
                        List <Triangle> oldTris        = potentialTris.Keys.ToList();
                        var             newOldTripairs = newTris.Zip(oldTris, (a, b) => Tuple.Create(a, b));
                        foreach (Tuple <Triangle, Triangle> tripair in newOldTripairs)
                        {
                            Triangle newTri = tripair.Item1;
                            Triangle oldTri = tripair.Item2;

                            int common = newTri.CountCommon(oldTri);

                            newPotentialTris[newTri] += common;
                            potentialTris[oldTri]    += common;
                        }

                        // Merge together old and new
                        foreach (KeyValuePair <Triangle, int> pair in newPotentialTris)
                        {
                            potentialTris.Add(pair.Key, pair.Value);
                        }

                        // Check if there are triangles that have all vertexes inside the vbd
                        // All such vertices could be initially drawn so just draw them
                        // Triangles with weight over 2*vertexPresetBonus have 2+1 vertices in buffer so just draw them
                        var drawnPairs = potentialTris.Where((t, w) => w >= 2 * vertexPresentBonus);
                        foreach (KeyValuePair <Triangle, int> pair in drawnPairs)
                        {
                            Triangle ftri = pair.Key;
                            for (int i = 0; i < 3; i++)
                            {
                                Vertex v     = ftri.vertices[i];
                                int    index = vbd.AddVertex(v, out bool isNew);
                                indices[i] = index;

                                // Fix weights of tris if a new vertex was added to vbd (not already in vbd it is)
                                if (isNew)
                                {
                                    throw new ArithmeticException("Triangles with high weight has new vertices!");
                                }
                            }

                            // Draw the triangle, all vertices are guaranteed to be in
                            vbd.DrawTriangle(indices);
                            potentialTris.Remove(biggestTri);
                        }

                        // Check if there are less then 2 vertices, which are required to be able to draw any tri
                        // If there is a vertex that has vertexPresentBonus weight, we good, otherwise retreat
                        if (vbd.freeCount == 1)
                        {
                            if (potentialTris.Values.ToList().FindIndex(w => w >= vertexPresentBonus) == -1)
                            {
                                break;
                            }
                        }
                    }

                    rom.PushOffset(vertexPosition);
                    vbd.MakeData(rom);
                    writtenVerticesCount += (rom.offset - vertexPosition) / 0x10;
                    vertexPosition        = rom.offset;
                    rom.PopOffset();

                    vbd.MakeF3D(rom);
                }

                if (td.scroll != null)
                {
                    // Vertices must be rounded by 3 because skelux scrolls work like that

                    /*
                     * if (writtenVerticesCount % 3 != 0)
                     * {
                     *  int leftToRoundVertices = 3 - (writtenVerticesCount % 3);
                     *  writtenVerticesCount += leftToRoundVertices;
                     *  vertexPosition += leftToRoundVertices * 0x10;
                     * }
                     */

                    int segmentedAddress        = rom.GetSegmentedAddress(allocVertexStart);
                    List <ScrollObject> scrolls = factory.GetScrolls(writtenVerticesCount, segmentedAddress, td);
                    foreach (ScrollObject scroll in scrolls)
                    {
                        scroll.WriteScroll(rom);
                    }
                }

                vertexBytes.AddRegion(vertexPosition, allocVertexEnd - vertexPosition);
            }
            foreach (UInt64 cmd in footer)
            {
                rom.Write64(cmd);
                rom.AddOffset(8);
            }
            return(rom.offset - start);
        }
Beispiel #4
0
 public void MakeData(ROM rom)
 {
     rom.Write64(lo);
     rom.Write64(hi, 8);
     rom.AddOffset(16);
 }
 protected static void Cmd07 <T>(ROM rom, T state)
 {
     rom.PopOffset();
     rom.AddOffset(8); // diff between 0x07 length and 0x06 length
 }