예제 #1
0
        public static GeometricObjectElementCollideAlignedBoxes Read(Reader reader, Pointer offset, GeometricObjectCollide geo)
        {
            MapLoader l = MapLoader.Loader;
            GeometricObjectElementCollideAlignedBoxes s = new GeometricObjectElementCollideAlignedBoxes(offset, geo);

            if (Settings.s.engineVersion > Settings.EngineVersion.Montreal)
            {
                s.off_boxes = Pointer.Read(reader);
                s.num_boxes = reader.ReadUInt16();
                reader.ReadInt16(); // -1
            }
            else
            {
                s.num_boxes = (ushort)reader.ReadUInt32();
                s.off_boxes = Pointer.Read(reader);
            }

            if (s.off_boxes != null)
            {
                Pointer off_current = Pointer.Goto(ref reader, s.off_boxes);
                s.boxes = new IndexedAlignedBox[s.num_boxes];
                for (uint i = 0; i < s.num_boxes; i++)
                {
                    s.boxes[i]              = new IndexedAlignedBox();
                    s.boxes[i].minPoint     = reader.ReadUInt16();
                    s.boxes[i].maxPoint     = reader.ReadUInt16();
                    s.boxes[i].off_material = Pointer.Read(reader);
                    s.boxes[i].gameMaterial = GameMaterial.FromOffsetOrRead(s.boxes[i].off_material, reader);
                }
                Pointer.Goto(ref reader, off_current);
            }
            return(s);
        }
예제 #2
0
        public static GeometricObjectElementCollideSpheres Read(Reader reader, Pointer offset, GeometricObjectCollide geo)
        {
            MapLoader l = MapLoader.Loader;
            GeometricObjectElementCollideSpheres s = new GeometricObjectElementCollideSpheres(offset, geo);

            if (Settings.s.engineVersion > Settings.EngineVersion.Montreal)
            {
                s.off_spheres     = Pointer.Read(reader);
                s.num_spheres     = reader.ReadUInt16();
                s.ind_parallelBox = reader.ReadInt16(); // -1
            }
            else
            {
                s.num_spheres = (ushort)reader.ReadUInt32();
                s.off_spheres = Pointer.Read(reader);
            }

            if (s.off_spheres != null)
            {
                Pointer off_current = Pointer.Goto(ref reader, s.off_spheres);
                s.spheres = new IndexedSphere[s.num_spheres];
                for (uint i = 0; i < s.num_spheres; i++)
                {
                    s.spheres[i] = new IndexedSphere();
                    if (Settings.s.engineVersion > Settings.EngineVersion.Montreal)
                    {
                        s.spheres[i].debug_radiusAddress = Pointer.Current(reader);
                        s.spheres[i].radius       = reader.ReadSingle();
                        s.spheres[i].off_material = Pointer.Read(reader);
                        s.spheres[i].centerPoint  = reader.ReadUInt16();
                        reader.ReadUInt16();
                    }
                    else
                    {
                        s.spheres[i].centerPoint = reader.ReadUInt16();
                        reader.ReadUInt16();
                        s.spheres[i].debug_radiusAddress = Pointer.Current(reader);
                        s.spheres[i].radius       = reader.ReadSingle();
                        s.spheres[i].off_material = Pointer.Read(reader);
                    }
                    if (!geo.isBoundingVolume)
                    {
                        s.spheres[i].gameMaterial = GameMaterial.FromOffsetOrRead(s.spheres[i].off_material, reader);
                    }
                }
                Pointer.Goto(ref reader, off_current);
            }
            return(s);
        }
예제 #3
0
        public static ScriptNode Read(Reader reader, Pointer offset, Script script) {
            MapLoader l = MapLoader.Loader;
            ScriptNode sn = new ScriptNode(offset);

            sn.script = script;
            sn.param = reader.ReadUInt32();
            sn.param_ptr = Pointer.GetPointerAtOffset(offset); // if parameter is pointer
            if (Settings.s.platform == Settings.Platform.DC) reader.ReadUInt32();

            if (Settings.s.mode == Settings.Mode.Rayman3GC) {
                reader.ReadByte();
                reader.ReadByte();
                reader.ReadByte();
                sn.type = reader.ReadByte();

                reader.ReadByte();
                reader.ReadByte();
                sn.indent = reader.ReadByte();
                reader.ReadByte();
            } else {
                reader.ReadByte();
                reader.ReadByte();
                sn.indent = reader.ReadByte();
                sn.type = reader.ReadByte();
            }
            sn.nodeType = NodeType.Unknown;
            if (Settings.s.aiTypes != null) sn.nodeType = Settings.s.aiTypes.GetNodeType(sn.type);
			
            if (sn.param_ptr != null && sn.nodeType != NodeType.Unknown) {
				//l.print("ScriptNode " + offset + " - " + sn.nodeType + " (" + sn.type + ") - " + sn.param_ptr);
				if (sn.nodeType == NodeType.WayPointRef) {
					WayPoint waypoint = WayPoint.FromOffsetOrRead(sn.param_ptr, reader);
				} else if (sn.nodeType == NodeType.String) {
					Pointer.DoAt(ref reader, sn.param_ptr, () => {
						string str = reader.ReadNullDelimitedString();
						l.strings[sn.param_ptr] = str;
					});
				} else if (sn.nodeType == NodeType.ObjectTableRef) {
					// In R2 some objects have object tables that aren't listed normally, but are referenced through scripts.
				} else if (sn.nodeType == NodeType.Button) {
					EntryAction.FromOffsetOrRead(sn.param_ptr, reader);
				} else if (sn.nodeType == NodeType.GameMaterialRef) {
                    GameMaterial.FromOffsetOrRead(sn.param_ptr, reader);
                } else if (sn.nodeType == NodeType.VisualMaterial) {
                    VisualMaterial.FromOffsetOrRead(sn.param_ptr, reader);
                }
            }
            return sn;
        }
예제 #4
0
        public void Read(Reader reader)
        {
            offset = Pointer.Current(reader);
            switch (type)
            {
            case DsgVarInfoEntry.DsgVarType.Boolean:
                valueBool = reader.ReadBoolean(); break;

            case DsgVarInfoEntry.DsgVarType.Byte:
                valueByte = reader.ReadSByte(); break;

            case DsgVarInfoEntry.DsgVarType.UByte:
                valueUByte = reader.ReadByte(); break;

            case DsgVarInfoEntry.DsgVarType.Float:
                valueFloat = reader.ReadSingle(); break;

            case DsgVarInfoEntry.DsgVarType.Int:
                valueInt = reader.ReadInt32(); break;

            case DsgVarInfoEntry.DsgVarType.UInt:
                valueUInt = reader.ReadUInt32(); break;

            case DsgVarInfoEntry.DsgVarType.Short:
                valueShort = reader.ReadInt16(); break;

            case DsgVarInfoEntry.DsgVarType.UShort:
                valueUShort = reader.ReadUInt16(); break;

            case DsgVarInfoEntry.DsgVarType.Vector:
                float x = reader.ReadSingle();
                float y = reader.ReadSingle();
                float z = reader.ReadSingle();
                valueVector = new Vector3(x, y, z);
                break;

            case DsgVarInfoEntry.DsgVarType.Text:
                valueText = reader.ReadInt32(); break;

            case DsgVarInfoEntry.DsgVarType.Graph:
                valuePointer = Pointer.Read(reader);
                valueGraph   = Graph.FromOffsetOrRead(valuePointer, reader);
                break;

            case DsgVarInfoEntry.DsgVarType.WayPoint:
                valuePointer  = Pointer.Read(reader);
                valueWayPoint = WayPoint.FromOffsetOrRead(valuePointer, reader);
                break;

            case DsgVarInfoEntry.DsgVarType.GameMaterial:
                valuePointer      = Pointer.Read(reader);
                valueGameMaterial = GameMaterial.FromOffsetOrRead(valuePointer, reader);
                break;

            case DsgVarInfoEntry.DsgVarType.VisualMaterial:
                valuePointer        = Pointer.Read(reader);
                valueVisualMaterial = VisualMaterial.FromOffsetOrRead(valuePointer, reader);
                break;

            case DsgVarInfoEntry.DsgVarType.ObjectList:
                valuePointer    = Pointer.Read(reader);
                valueObjectList = ObjectList.FromOffsetOrRead(valuePointer, reader);
                break;

            case DsgVarInfoEntry.DsgVarType.List:
                valueList = new List();
                valueList.Read(reader);
                break;

            case DsgVarInfoEntry.DsgVarType.Light:
                valuePointer = Pointer.Read(reader);
                valueLight   = MapLoader.Loader.FromOffsetOrRead <LightInfo>(reader, valuePointer);
                break;

            case DsgVarInfoEntry.DsgVarType.Comport:
                valuePointer = Pointer.Read(reader);
                valueComport = MapLoader.Loader.FromOffsetOrRead <Behavior>(reader, valuePointer);
                break;

            case DsgVarInfoEntry.DsgVarType.Input:
                valuePointer = Pointer.Read(reader);
                valueInput   = EntryAction.FromOffsetOrRead(valuePointer, reader);
                break;

            // Fill these in after loading
            case DsgVarInfoEntry.DsgVarType.Perso:
                valuePointer = Pointer.Read(reader);
                // Don't fill in perso yet
                MapLoader.Loader.onPostLoad.Add(InitPostLoad);
                break;

            case DsgVarInfoEntry.DsgVarType.Action:
                valuePointer = Pointer.Read(reader);
                // Don't fill in state yet
                MapLoader.Loader.onPostLoad.Add(InitPostLoad);
                break;

            case DsgVarInfoEntry.DsgVarType.SuperObject:
                valuePointer = Pointer.Read(reader);
                // Don't fill in SO yet
                MapLoader.Loader.onPostLoad.Add(InitPostLoad);
                break;

            // TODO: Figure these out
            case DsgVarInfoEntry.DsgVarType.Caps:
                valueCaps = reader.ReadUInt32(); break;

            case DsgVarInfoEntry.DsgVarType.SOLinks:
                valueSOLinks = reader.ReadUInt32(); break;

            case DsgVarInfoEntry.DsgVarType.SoundEvent:
                valueSoundEvent = reader.ReadUInt32(); break;

            case DsgVarInfoEntry.DsgVarType.Way:
                valueWay = reader.ReadUInt32(); break;

            // Arrays
            case DsgVarInfoEntry.DsgVarType.ActionArray:
            case DsgVarInfoEntry.DsgVarType.FloatArray:
            case DsgVarInfoEntry.DsgVarType.IntegerArray:
            case DsgVarInfoEntry.DsgVarType.PersoArray:
            case DsgVarInfoEntry.DsgVarType.SoundEventArray:
            case DsgVarInfoEntry.DsgVarType.SuperObjectArray:
            case DsgVarInfoEntry.DsgVarType.TextArray:
            case DsgVarInfoEntry.DsgVarType.TextRefArray:
            case DsgVarInfoEntry.DsgVarType.VectorArray:
            case DsgVarInfoEntry.DsgVarType.WayPointArray:
            case DsgVarInfoEntry.DsgVarType.GraphArray:
            case DsgVarInfoEntry.DsgVarType.Array11:
            case DsgVarInfoEntry.DsgVarType.Array9:
                ReadArray(reader); break;
            }
        }
예제 #5
0
        public static GeometricObjectElementCollideTriangles Read(Reader reader, Pointer offset, GeometricObjectCollide geo)
        {
            MapLoader l = MapLoader.Loader;
            GeometricObjectElementCollideTriangles sm = new GeometricObjectElementCollideTriangles(offset, geo);

            sm.off_material = Pointer.Read(reader);
            if (Settings.s.game == Settings.Game.R2Revolution || Settings.s.game == Settings.Game.LargoWinch)
            {
                sm.num_triangles = reader.ReadUInt16();
                reader.ReadUInt16();
                sm.off_triangles = Pointer.Read(reader);
                if (Settings.s.game == Settings.Game.LargoWinch)
                {
                    sm.off_normals = Pointer.Read(reader);
                    sm.off_unk     = Pointer.Read(reader);
                }
            }
            else
            {
                if (Settings.s.engineVersion < Settings.EngineVersion.R3)
                {
                    sm.num_triangles = reader.ReadUInt16();
                    sm.num_mapping   = reader.ReadUInt16();
                    sm.off_triangles = Pointer.Read(reader);
                    sm.off_mapping   = Pointer.Read(reader);
                    sm.off_normals   = Pointer.Read(reader);
                    sm.off_uvs       = Pointer.Read(reader);
                    if (Settings.s.engineVersion == Settings.EngineVersion.Montreal)
                    {
                        reader.ReadUInt32();
                    }
                    if (Settings.s.game != Settings.Game.TTSE)
                    {
                        Pointer.Read(reader);                        // table of num_unk vertex indices (vertices, because max = num_vertices - 1)
                        reader.ReadUInt16();                         // num_unk
                        sm.ind_parallelBox = reader.ReadInt16();
                    }
                }
                else
                {
                    sm.off_triangles   = Pointer.Read(reader);
                    sm.off_normals     = Pointer.Read(reader);
                    sm.num_triangles   = reader.ReadUInt16();
                    sm.ind_parallelBox = reader.ReadInt16();
                    reader.ReadUInt32();
                    if (Settings.s.game != Settings.Game.Dinosaur)
                    {
                        sm.off_mapping = Pointer.Read(reader);
                        sm.off_unk     = Pointer.Read(reader);                     // num_mapping_entries * 3 floats
                        sm.off_unk2    = Pointer.Read(reader);                     // num_mapping_entries * 1 float
                        sm.num_mapping = reader.ReadUInt16();
                        reader.ReadUInt16();
                    }
                }
            }
            if (!geo.isBoundingVolume)
            {
                if (sm.off_material != null)
                {
                    sm.gameMaterial = GameMaterial.FromOffsetOrRead(sm.off_material, reader);
                }
            }
            else
            {
                // Sector superobject
            }
            Pointer.Goto(ref reader, sm.off_triangles);
            sm.triangles = new int[sm.num_triangles * 3];
            for (int j = 0; j < sm.num_triangles; j++)
            {
                sm.triangles[(j * 3) + 0] = reader.ReadInt16();
                sm.triangles[(j * 3) + 1] = reader.ReadInt16();
                sm.triangles[(j * 3) + 2] = reader.ReadInt16();
            }
            Pointer.DoAt(ref reader, sm.off_normals, () => {
                sm.normals = new Vector3[sm.num_triangles];
                for (int j = 0; j < sm.num_triangles; j++)
                {
                    float x       = reader.ReadSingle();
                    float z       = reader.ReadSingle();
                    float y       = reader.ReadSingle();
                    sm.normals[j] = new Vector3(x, y, z);
                }
            });

            if (sm.num_mapping > 0 && sm.off_mapping != null)
            {
                Pointer.Goto(ref reader, sm.off_mapping);
                sm.mapping = new int[sm.num_triangles * 3];
                for (int i = 0; i < sm.num_triangles; i++)
                {
                    sm.mapping[(i * 3) + 0] = reader.ReadInt16();
                    sm.mapping[(i * 3) + 1] = reader.ReadInt16();
                    sm.mapping[(i * 3) + 2] = reader.ReadInt16();
                }
                if (sm.off_uvs != null)
                {
                    Pointer.Goto(ref reader, sm.off_uvs);
                    sm.uvs = new Vector2[sm.num_mapping];
                    for (int i = 0; i < sm.num_mapping; i++)
                    {
                        sm.uvs[i] = new Vector2(reader.ReadSingle(), reader.ReadSingle());
                    }
                }
            }

            /*R3Pointer.Goto(ref reader, sm.off_mapping);
             * sm.mapping = new int[sm.num_triangles * 3];
             * for (int j = 0; j < sm.num_triangles; j++) {
             *  sm.mapping[(j * 3) + 0] = reader.ReadInt16();
             *  sm.mapping[(j * 3) + 1] = reader.ReadInt16();
             *  sm.mapping[(j * 3) + 2] = reader.ReadInt16();
             * }
             * R3Pointer.Goto(ref reader, sm.off_unk);
             * sm.normals = new Vector3[sm.num_mapping_entries];
             * for (int j = 0; j < sm.num_mapping_entries; j++) {
             *  float x = reader.ReadSingle();
             *  float z = reader.ReadSingle();
             *  float y = reader.ReadSingle();
             *  sm.normals[j] = new Vector3(x, y, z);
             * }*/
            return(sm);
        }
예제 #6
0
파일: R2Loader.cs 프로젝트: icup321/raymap
        async UniTask LoadLVLSNA()
        {
            loadingState = "Loading level memory";
            await WaitIfNecessary();

            Reader  reader = files_array[Mem.Lvl].reader;
            Pointer off_current;
            SNA     sna = (SNA)files_array[Mem.Lvl];

            // First read GPT
            files_array[Mem.Lvl].GotoHeader();
            reader = files_array[Mem.Lvl].reader;
            print("LVL GPT offset: " + Pointer.Current(reader));

            if (Settings.s.engineVersion == Settings.EngineVersion.Montreal)
            {
                // SDA

                /*sna.GotoSDA();
                 * print(Pointer.Current(reader));
                 * reader.ReadUInt32();
                 * reader.ReadUInt32(); // same as next
                 * uint num_strings = reader.ReadUInt32();
                 * uint indexOfTextGlobal = reader.ReadUInt32(); // dword_6EEE78
                 * uint dword_83EC58 = reader.ReadUInt32();
                 * print(num_strings + " - " + Pointer.Current(reader));
                 *
                 * // DLG
                 * sna.GotoDLG();
                 * Pointer off_strings = Pointer.Read(reader);
                 * for (int i = 0; i < num_strings; i++) {
                 *  Pointer.Read(reader);
                 * }
                 * reader.ReadUInt32();*/

                // GPT
                sna.GotoHeader();
                if (Settings.s.game != Settings.Game.PlaymobilLaura)
                {
                    Pointer.Read(reader); // sound related
                }
                Pointer.Read(reader);
                Pointer.Read(reader);
                reader.ReadUInt32();
            }
            if (Settings.s.engineVersion != Settings.EngineVersion.Montreal)
            {
                loadingState = "Reading settings for persos in fix";
                await WaitIfNecessary();

                // Fill in fix -> lvl pointers for perso's in fix
                uint      num_persoInFixPointers = reader.ReadUInt32();
                Pointer[] persoInFixPointers     = new Pointer[num_persoInFixPointers];
                for (int i = 0; i < num_persoInFixPointers; i++)
                {
                    Pointer off_perso = Pointer.Read(reader);
                    if (off_perso != null)
                    {
                        off_current = Pointer.Goto(ref reader, off_perso);
                        reader.ReadUInt32();
                        Pointer off_stdGame = Pointer.Read(reader);
                        if (off_stdGame != null)
                        {
                            if (Settings.s.engineVersion > Settings.EngineVersion.TT)
                            {
                                Pointer.Goto(ref reader, off_stdGame);
                                reader.ReadUInt32(); // type 0
                                reader.ReadUInt32(); // type 1
                                reader.ReadUInt32(); // type 2
                                Pointer off_superObject = Pointer.Read(reader);
                                Pointer.Goto(ref reader, off_current);
                                if (off_superObject == null)
                                {
                                    continue;
                                }
                            }
                            else
                            {
                                Pointer.Goto(ref reader, off_current);
                            }
                            // First read everything from the GPT
                            Pointer off_newSuperObject = null, off_nextBrother = null, off_prevBrother = null, off_father = null;
                            byte[]  matrixData = null, floatData = null, renderBits = null;
                            if (Settings.s.engineVersion > Settings.EngineVersion.TT)
                            {
                                off_newSuperObject = Pointer.Read(reader);
                                matrixData         = reader.ReadBytes(0x58);
                                renderBits         = reader.ReadBytes(4);
                                floatData          = reader.ReadBytes(4);
                                off_nextBrother    = Pointer.Read(reader);
                                off_prevBrother    = Pointer.Read(reader);
                                off_father         = Pointer.Read(reader);
                            }
                            else
                            {
                                matrixData         = reader.ReadBytes(0x58);
                                off_newSuperObject = Pointer.Read(reader);
                                Pointer.DoAt(ref reader, off_stdGame + 0xC, () => {
                                    ((SNA)off_stdGame.file).AddPointer(off_stdGame.offset + 0xC, off_newSuperObject);
                                });
                            }

                            // Then fill everything in
                            off_current = Pointer.Goto(ref reader, off_newSuperObject);
                            uint    newSOtype             = reader.ReadUInt32();
                            Pointer off_newSOengineObject = Pointer.Read(reader);
                            if (SuperObject.GetSOType(newSOtype) == SuperObject.Type.Perso)
                            {
                                persoInFixPointers[i] = off_newSOengineObject;
                                Pointer.Goto(ref reader, off_newSOengineObject);
                                Pointer off_p3dData = Pointer.Read(reader);
                                if (Settings.s.game == Settings.Game.R2Demo)
                                {
                                    ((SNA)off_p3dData.file).OverwriteData(off_p3dData.FileOffset + 0x1C, matrixData);
                                }
                                else
                                {
                                    ((SNA)off_p3dData.file).OverwriteData(off_p3dData.FileOffset + 0x18, matrixData);
                                }

                                if (Settings.s.engineVersion > Settings.EngineVersion.TT)
                                {
                                    FileWithPointers file = off_newSuperObject.file;
                                    file.AddPointer(off_newSuperObject.FileOffset + 0x14, off_nextBrother);
                                    file.AddPointer(off_newSuperObject.FileOffset + 0x18, off_prevBrother);
                                    file.AddPointer(off_newSuperObject.FileOffset + 0x1C, off_father);
                                    ((SNA)file).OverwriteData(off_newSuperObject.FileOffset + 0x30, renderBits);
                                    ((SNA)file).OverwriteData(off_newSuperObject.FileOffset + 0x38, floatData);
                                }
                            }
                            else
                            {
                                persoInFixPointers[i] = null;
                            }
                        }
                        Pointer.Goto(ref reader, off_current);
                    }
                }
            }
            loadingState = "Loading globals";
            await WaitIfNecessary();

            if (Settings.s.engineVersion > Settings.EngineVersion.Montreal)
            {
                globals.off_actualWorld          = Pointer.Read(reader);
                globals.off_dynamicWorld         = Pointer.Read(reader);
                globals.off_inactiveDynamicWorld = Pointer.Read(reader);
                globals.off_fatherSector         = Pointer.Read(reader);
                globals.off_firstSubMapPosition  = Pointer.Read(reader);
            }
            else
            {
                globals.off_actualWorld  = Pointer.Read(reader);
                globals.off_dynamicWorld = Pointer.Read(reader);
                globals.off_fatherSector = Pointer.Read(reader);
                uint soundEventIndex = reader.ReadUInt32(); // In Montreal version this is a pointer, also sound event related
                if (Settings.s.game == Settings.Game.PlaymobilLaura)
                {
                    Pointer.Read(reader);
                }
            }

            globals.num_always      = reader.ReadUInt32();
            globals.spawnablePersos = LinkedList <Perso> .ReadHeader(reader, Pointer.Current(reader), LinkedList.Type.Double);

            globals.off_always_reusableSO = Pointer.Read(reader); // There are (num_always) empty SuperObjects starting with this one.
            if (Settings.s.engineVersion > Settings.EngineVersion.Montreal)
            {
                globals.off_always_reusableUnknown1 = Pointer.Read(reader); // (num_always) * 0x2c blocks
                globals.off_always_reusableUnknown2 = Pointer.Read(reader); // (num_always) * 0x4 blocks
            }
            else
            {
                reader.ReadUInt32(); // 0x6F. In Montreal version this is a pointer to a pointer table for always
                globals.spawnablePersos.FillPointers(reader, globals.spawnablePersos.off_tail, globals.spawnablePersos.offset);
            }

            if (Settings.s.game == Settings.Game.DD)
            {
                reader.ReadUInt32();
            }
            if (Settings.s.engineVersion > Settings.EngineVersion.Montreal)
            {
                Pointer dword_4A6B1C_always_header = Pointer.Read(reader);
                Pointer dword_4A6B20_always_last   = Pointer.Read(reader);

                Pointer v28 = Pointer.Read(reader);
                Pointer v31 = Pointer.Read(reader);
                Pointer v32 = Pointer.Read(reader);
                Pointer v33 = Pointer.Read(reader);

                // These things aren't parsed, but in raycap they're null. This way we'll notice when they aren't.
                if (v28 != null)
                {
                    print("v28 is not null, it's " + v28);
                }
                if (v31 != null)
                {
                    print("v31 is not null, it's " + v31);
                }
                if (v32 != null)
                {
                    print("v32 is not null, it's " + v32);
                }
                if (v33 != null)
                {
                    print("v33 is not null, it's " + v33);
                }

                // Fill in pointers for the unknown table related to "always".
                FillLinkedListPointers(reader, dword_4A6B20_always_last, dword_4A6B1C_always_header);
            }

            // Fill in pointers for the object type tables and read them
            objectTypes = new ObjectType[3][];
            for (uint i = 0; i < 3; i++)
            {
                Pointer off_names_header = Pointer.Current(reader);
                Pointer off_names_first  = Pointer.Read(reader);
                Pointer off_names_last   = Pointer.Read(reader);
                uint    num_names        = reader.ReadUInt32();

                FillLinkedListPointers(reader, off_names_last, off_names_header);
                ReadObjectNamesTable(reader, off_names_first, num_names, i);
            }

            // Begin of engineStructure
            loadingState = "Loading engine structure";
            await WaitIfNecessary();

            print("Start of EngineStructure: " + Pointer.Current(reader));
            if (Settings.s.engineVersion > Settings.EngineVersion.Montreal)
            {
                reader.ReadByte();
                string mapName = reader.ReadString(0x1E);
                reader.ReadChars(0x1E);
                string mapName2 = reader.ReadString(0x1E);
                reader.ReadByte();
                reader.ReadBytes(0x178); // don't know what this data is
            }
            else
            {
                reader.ReadByte();
                string mapName = reader.ReadString(0x104);
                reader.ReadChars(0x104);
                string mapName2 = reader.ReadString(0x104);
                if (Settings.s.game == Settings.Game.PlaymobilLaura)
                {
                    reader.ReadChars(0x104);
                    reader.ReadChars(0x104);
                }
                string mapName3 = reader.ReadString(0x104);
                if (Settings.s.game == Settings.Game.TT)
                {
                    reader.ReadBytes(0x47F7); // don't know what this data is
                }
                else if (Settings.s.game == Settings.Game.TTSE)
                {
                    reader.ReadBytes(0x240F);
                }
                else if (Settings.s.game == Settings.Game.PlaymobilLaura)
                {
                    reader.ReadBytes(0x240F); // don't know what this data is
                }
                else                          // Hype & Alex
                {
                    reader.ReadBytes(0x2627); // don't know what this data is
                }
            }
            Pointer off_unknown_first = Pointer.Read(reader);
            Pointer off_unknown_last  = Pointer.Read(reader);
            uint    num_unknown       = reader.ReadUInt32();

            families = LinkedList <Family> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Double);

            families.FillPointers(reader, families.off_tail, families.off_head);

            if (Settings.s.game == Settings.Game.PlaymobilLaura)
            {
                LinkedList <int> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Double);
            }

            LinkedList <SuperObject> alwaysActiveCharacters = LinkedList <SuperObject> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Double);

            if (Settings.s.engineVersion > Settings.EngineVersion.Montreal)
            {
                reader.ReadUInt32();
                reader.ReadUInt32();
                reader.ReadUInt32();
                if (Settings.s.game == Settings.Game.RedPlanet || Settings.s.game == Settings.Game.R2Demo)
                {
                    reader.ReadUInt32();
                }
                Pointer off_languages = Pointer.Read(reader);
                reader.ReadUInt32();

                Pointer.DoAt(ref reader, off_languages, () => {
                    ReadLanguages(reader, off_languages, localization.num_languages);
                });

                for (uint i = 0; i < 2; i++)
                {
                    Pointer off_matrix = Pointer.Current(reader);
                    Matrix  mat        = Matrix.Read(reader, off_matrix);
                }

                reader.ReadUInt32();
                reader.ReadUInt16();

                ReadLevelNames(reader, Pointer.Current(reader), 80);
                uint num_mapNames = reader.ReadUInt32();
                Array.Resize(ref levels, (int)num_mapNames);
                reader.ReadUInt16();
                reader.ReadUInt32();
                reader.ReadUInt32();

                if (Settings.s.game == Settings.Game.DD)
                {
                    reader.ReadUInt32();
                }

                // End of engineStructure
                Pointer off_light    = Pointer.Read(reader); // the offset of a light. It's just an ordinary light.
                Pointer off_mainChar = Pointer.Read(reader); // superobject
                Pointer off_characterLaunchingSoundEvents = Pointer.Read(reader);
                if (Settings.s.game == Settings.Game.DD)
                {
                    globals.off_backgroundGameMaterial = Pointer.Read(reader);
                }
                Pointer off_shadowPolygonVisualMaterial   = Pointer.Read(reader);
                Pointer off_shadowPolygonGameMaterialInit = Pointer.Read(reader);
                Pointer off_shadowPolygonGameMaterial     = Pointer.Read(reader);
                Pointer off_textureOfTextureShadow        = Pointer.Read(reader);
                Pointer off_col_taggedFacesTable          = Pointer.Read(reader);

                for (int i = 0; i < 10; i++)
                {
                    Pointer off_elementForShadow      = Pointer.Read(reader);
                    Pointer off_geometricShadowObject = Pointer.Read(reader);
                }
                Pointer.Read(reader); // DemoSOList

                if (Settings.s.game == Settings.Game.R2Demo || Settings.s.game == Settings.Game.RedPlanet || Settings.s.mode == Settings.Mode.DonaldDuckPCDemo)
                {
                    Pointer.Read(reader);
                }

                if (Settings.s.mode == Settings.Mode.DonaldDuckPCDemo)
                {
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                }

                loadingState = "Loading level animation bank";
                //print("Animation bank: " + Pointer.Current(reader));
                await WaitIfNecessary();

                AnimationBank.Read(reader, Pointer.Current(reader), 0, 1, files_array[Mem.LvlKeyFrames], append: true);
                animationBanks[1] = animationBanks[0];
            }
            if (FileSystem.mode != FileSystem.Mode.Web)
            {
                string levelsFolder = gameDataBinFolder + ConvertPath(gameDsb.levelsDataPath) + "/";
                ((SNA)files_array[0]).CreateMemoryDump(levelsFolder + "fix.dmp", true);
                ((SNA)files_array[1]).CreateMemoryDump(levelsFolder + lvlName + "/" + lvlName + ".dmp", true);
            }

            // Read PTX
            loadingState = "Loading level textures";
            await WaitIfNecessary();

            // Can't yield inside a lambda, so we must do it the old fashioned way, with off_current
            if (sna.PTX != null)
            {
                off_current = Pointer.Goto(ref reader, sna.PTX);
                await ReadTexturesLvl(reader, Pointer.Current(reader));

                Pointer.Goto(ref reader, off_current);
            }

            /*Pointer.DoAt(ref reader, sna.PTX, () => {
             * ReadTexturesLvl(reader, Pointer.Current(reader));
             * });*/

            // Read background game material (DD only)
            globals.backgroundGameMaterial = GameMaterial.FromOffsetOrRead(globals.off_backgroundGameMaterial, reader);

            // Parse actual world & always structure
            loadingState = "Loading families";
            await WaitIfNecessary();

            ReadFamilies(reader);

            loadingState = "Creating animation bank";
            await WaitIfNecessary();

            if (Settings.s.engineVersion == Settings.EngineVersion.Montreal)
            {
                animationBanks    = new AnimationBank[2];
                animationBanks[0] = new AnimationBank(null)
                {
                    animations = new Animation.Component.AnimA3DGeneral[0]
                };
                animationBanks[1] = animationBanks[0];
            }
            else if (Settings.s.engineVersion <= Settings.EngineVersion.TT)
            {
                uint maxAnimIndex = 0;
                foreach (State s in states)
                {
                    if (s.anim_ref != null && s.anim_ref.anim_index > maxAnimIndex)
                    {
                        maxAnimIndex = s.anim_ref.anim_index;
                    }
                }
                animationBanks    = new AnimationBank[2];
                animationBanks[0] = new AnimationBank(null)
                {
                    animations = new Animation.Component.AnimA3DGeneral[maxAnimIndex + 1]
                };
                foreach (State s in states)
                {
                    if (s.anim_ref != null)
                    {
                        animationBanks[0].animations[s.anim_ref.anim_index] = s.anim_ref.a3d;
                    }
                }
                animationBanks[1] = animationBanks[0];
            }

            loadingState = "Loading superobject hierarchy";
            await WaitIfNecessary();
            await ReadSuperObjects(reader);

            loadingState = "Loading always structure";
            await WaitIfNecessary();

            ReadAlways(reader);
            loadingState = "Filling in cross-references";
            await WaitIfNecessary();

            ReadCrossReferences(reader);

            // TODO: Make more generic
            if (Settings.s.game == Settings.Game.R2)
            {
                loadingState = "Filling in comport names";
                await WaitIfNecessary();

                string path = gameDataBinFolder + "R2DC_Comports.json";

                if (!FileSystem.FileExists(path))
                {
                    path = "Assets/StreamingAssets/R2DC_Comports.json"; // Offline, the json doesn't exist, so grab it from StreamingAssets
                }

                Stream stream = FileSystem.GetFileReadStream(path);
                if (stream != null)
                {
                    ReadAndFillComportNames(stream);
                }
            }
        }
예제 #7
0
        public static GeometricObjectElementSprites Read(Reader reader, Pointer offset, GeometricObject m)
        {
            MapLoader l = MapLoader.Loader;
            GeometricObjectElementSprites s = new GeometricObjectElementSprites(offset, m);

            s.name = "Sprite @ pos " + offset;
            //l.print(s.name);

            if (Settings.s.engineVersion > Settings.EngineVersion.Montreal)
            {
                if (Settings.s.platform == Settings.Platform.DC)
                {
                    s.off_sprites = offset;
                    s.num_sprites = 1;
                }
                else
                {
                    s.off_sprites = Pointer.Read(reader);
                    s.num_sprites = reader.ReadUInt16();
                    reader.ReadInt16(); // -1
                    if (Settings.s.game != Settings.Game.R2Revolution)
                    {
                        reader.ReadUInt32();
                        if (Settings.s.game != Settings.Game.LargoWinch)
                        {
                            reader.ReadUInt32();
                        }
                    }
                }
            }
            else
            {
                s.num_sprites = (ushort)reader.ReadUInt32();
                s.off_sprites = Pointer.Read(reader);
                reader.ReadUInt32();
            }
            if (Settings.s.game == Settings.Game.R2Revolution)
            {
                Pointer.DoAt(ref reader, s.off_sprites, () => {
                    s.sprites = new IndexedSprite[s.num_sprites];
                    for (uint i = 0; i < s.num_sprites; i++)
                    {
                        s.sprites[i]            = new IndexedSprite();
                        uint type               = reader.ReadUInt32();
                        s.sprites[i].info_scale = new Vector2(reader.ReadSingle(), reader.ReadSingle());
                        if (type == 0x20)
                        {
                            // Light cookie sprite
                            uint index                              = reader.ReadUInt32();
                            R2PS2Loader ps2l                        = MapLoader.Loader as R2PS2Loader;
                            s.sprites[i].visualMaterial             = ps2l.lightCookieMaterial.Clone();
                            s.sprites[i].visualMaterial.diffuseCoef = ps2l.lightCookieColors[index];
                        }
                        else
                        {
                            s.sprites[i].off_material = Pointer.Read(reader);
                            if (s.sprites[i].off_material != null)
                            {
                                s.sprites[i].visualMaterial = VisualMaterial.FromOffsetOrRead(s.sprites[0].off_material, reader);
                            }
                        }
                    }
                });
            }
            else if (Settings.s.platform == Settings.Platform.DC)
            {
                s.sprites    = new IndexedSprite[1];
                s.sprites[0] = new IndexedSprite();
                s.sprites[0].off_material = Pointer.Read(reader);
                if (s.sprites[0].off_material != null)
                {
                    s.sprites[0].visualMaterial = VisualMaterial.FromOffsetOrRead(s.sprites[0].off_material, reader);
                }
                s.sprites[0].info_scale = new Vector2(reader.ReadSingle(), reader.ReadSingle());
                reader.ReadUInt16();
                s.sprites[0].centerPoint = reader.ReadUInt16();
                reader.ReadUInt16();
                reader.ReadUInt16();
                reader.ReadUInt16();
                reader.ReadUInt16();
            }
            else
            {
                if (s.off_sprites != null)
                {
                    Pointer.Goto(ref reader, s.off_sprites);
                    s.sprites = new IndexedSprite[s.num_sprites];
                    for (uint i = 0; i < s.num_sprites; i++)
                    {
                        s.sprites[i] = new IndexedSprite();
                        if (Settings.s.engineVersion <= Settings.EngineVersion.Montreal)
                        {
                            reader.ReadUInt32();
                        }
                        s.sprites[i].off_info = Pointer.Read(reader);
                        s.sprites[i].size     = new Vector2(reader.ReadSingle(), reader.ReadSingle());

                        if (Settings.s.engineVersion > Settings.EngineVersion.Montreal)
                        {
                            if (Settings.s.game != Settings.Game.LargoWinch)
                            {
                                s.sprites[i].constraint = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                                s.sprites[i].uv1        = new Vector2(reader.ReadSingle(), reader.ReadSingle());
                                s.sprites[i].uv2        = new Vector2(reader.ReadSingle(), reader.ReadSingle());
                            }
                            s.sprites[i].centerPoint = reader.ReadUInt16();
                            reader.ReadUInt16();
                            if (Settings.s.engineVersion < Settings.EngineVersion.R3)
                            {
                                reader.ReadUInt32();
                            }
                        }

                        if (s.sprites[i].off_info != null)
                        {
                            Pointer off_current = Pointer.Goto(ref reader, s.sprites[i].off_info);
                            reader.ReadUInt32();
                            Pointer.Read(reader);
                            Pointer.Read(reader);
                            Pointer off_info_scale   = Pointer.Read(reader);
                            Pointer off_info_unknown = Pointer.Read(reader);
                            s.sprites[i].off_material_pointer = Pointer.Read(reader);
                            Pointer.Goto(ref reader, off_current);

                            Pointer.DoAt(ref reader, off_info_scale, () => {
                                s.sprites[i].info_scale = new Vector2(reader.ReadSingle(), reader.ReadSingle());
                            });
                            Pointer.DoAt(ref reader, off_info_unknown, () => {
                                s.sprites[i].info_unknown = new Vector2(reader.ReadSingle(), reader.ReadSingle());
                            });
                            if (s.sprites[i].off_material_pointer != null)
                            {
                                off_current = Pointer.Goto(ref reader, s.sprites[i].off_material_pointer);
                                s.sprites[i].off_material = Pointer.Read(reader);
                                if (s.sprites[i].off_material != null)
                                {
                                    if (Settings.s.engineVersion < Settings.EngineVersion.R3)
                                    {
                                        s.sprites[i].gameMaterial   = GameMaterial.FromOffsetOrRead(s.sprites[i].off_material, reader);
                                        s.sprites[i].visualMaterial = s.sprites[i].gameMaterial.visualMaterial;
                                    }
                                    else
                                    {
                                        s.sprites[i].visualMaterial = VisualMaterial.FromOffsetOrRead(s.sprites[i].off_material, reader);
                                    }
                                }
                                Pointer.Goto(ref reader, off_current);
                            }
                        }
                    }
                }
            }

            return(s);
        }
        public static GeometricObjectElementTriangles Read(Reader reader, Pointer offset, GeometricObject geo)
        {
            MapLoader l = MapLoader.Loader;
            GeometricObjectElementTriangles sm = new GeometricObjectElementTriangles(offset, geo);

            sm.name = "Submesh @ pos " + offset;
            //l.print(sm.name);
            sm.backfaceCulling = !l.forceDisplayBackfaces;
            sm.off_material    = Pointer.Read(reader);
            if (Settings.s.game == Settings.Game.LargoWinch)
            {
                //sm.visualMaterial = VisualMaterial.FromOffset(sm.off_material);
                sm.visualMaterial = VisualMaterial.FromOffsetOrRead(sm.off_material, reader);
            }
            else if (Settings.s.engineVersion == Settings.EngineVersion.R3 || Settings.s.game == Settings.Game.R2Revolution)
            {
                sm.visualMaterial = VisualMaterial.FromOffset(sm.off_material);
            }
            else
            {
                sm.gameMaterial   = GameMaterial.FromOffsetOrRead(sm.off_material, reader);
                sm.visualMaterial = sm.gameMaterial.visualMaterial;
            }
            sm.visualMaterialOG = sm.visualMaterial;

            /*if (sm.visualMaterial != null && sm.visualMaterial.textures.Count > 0 && sm.visualMaterial.textures[0].off_texture != null) {
             *  sm.name += " - VisMatTex:" + sm.visualMaterial.textures[0].offset + " - TexInfo:" + sm.visualMaterial.textures[0].off_texture;
             * }*/
            if (sm.visualMaterial != null)
            {
                sm.backfaceCulling = ((sm.visualMaterial.flags & VisualMaterial.flags_backfaceCulling) != 0) && !l.forceDisplayBackfaces;
            }
            sm.num_triangles = reader.ReadUInt16();
            if (Settings.s.game == Settings.Game.R2Revolution)
            {
                sm.lightmap_index = reader.ReadInt16();
                sm.off_triangles  = Pointer.Read(reader);
            }
            else
            {
                sm.num_uvs = reader.ReadUInt16();
                if (Settings.s.engineVersion == Settings.EngineVersion.R3)
                {
                    sm.num_uvMaps     = reader.ReadUInt16();
                    sm.lightmap_index = reader.ReadInt16();
                }
                sm.off_triangles = Pointer.Read(reader);                 // 1 entry = 3 shorts. Max: num_vertices
                if (Settings.s.mode == Settings.Mode.Rayman3GC)
                {
                    reader.ReadUInt32();
                }
                sm.off_mapping_uvs = Pointer.Read(reader);         // 1 entry = 3 shorts. Max: num_weights
                sm.off_normals     = Pointer.Read(reader);         // 1 entry = 3 floats
                sm.off_uvs         = Pointer.Read(reader);         // 1 entry = 2 floats
                if (Settings.s.game == Settings.Game.LargoWinch)
                {
                    sm.off_mapping_lightmap = Pointer.Read(reader);
                    sm.num_mapping_lightmap = reader.ReadUInt16();
                    reader.ReadUInt16();
                }
                else if (Settings.s.engineVersion == Settings.EngineVersion.R3)
                {
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                }
                else if (Settings.s.engineVersion == Settings.EngineVersion.Montreal)
                {
                    reader.ReadUInt32();
                }
                if (Settings.s.game != Settings.Game.TTSE)
                {
                    sm.off_vertex_indices = Pointer.Read(reader);
                    sm.num_vertex_indices = reader.ReadUInt16();
                    sm.parallelBox        = reader.ReadUInt16();
                    reader.ReadUInt32();
                }
            }
            if (Settings.s.engineVersion == Settings.EngineVersion.R3)
            {
                if (Settings.s.game != Settings.Game.Dinosaur &&
                    Settings.s.game != Settings.Game.LargoWinch &&
                    Settings.s.mode != Settings.Mode.RaymanArenaGCDemo)
                {
                    sm.isVisibleInPortal = reader.ReadByte();
                    reader.ReadByte();
                    sm.OPT_num_mapping_entries       = reader.ReadUInt16();            // num_shorts
                    sm.OPT_off_mapping_vertices      = Pointer.Read(reader);           // shorts_offset1 (1st array of size num_shorts, max_num_vertices)
                    sm.OPT_off_mapping_uvs           = Pointer.Read(reader);           // shorts_offset2 (2nd array of size num_shorts, max: num_weights)
                    sm.OPT_num_triangleStrip         = reader.ReadUInt16();            // num_shorts2
                    sm.OPT_num_disconnectedTriangles = reader.ReadUInt16();
                    sm.OPT_off_triangleStrip         = Pointer.Read(reader);           // shorts2_offset (array of size num_shorts2)
                    sm.OPT_off_disconnectedTriangles = Pointer.Read(reader);
                    if (Settings.s.hasNames)
                    {
                        sm.name += reader.ReadString(0x34);
                    }
                }
                else
                {
                    sm.OPT_num_mapping_entries       = 0;
                    sm.OPT_off_mapping_vertices      = null;
                    sm.OPT_off_mapping_uvs           = null;
                    sm.OPT_num_triangleStrip         = 0;
                    sm.OPT_num_disconnectedTriangles = 0;
                    sm.OPT_off_triangleStrip         = null;
                    sm.OPT_off_disconnectedTriangles = null;
                    sm.isVisibleInPortal             = 1;
                    if (Settings.s.mode == Settings.Mode.RaymanArenaGCDemo)
                    {
                        sm.isVisibleInPortal = reader.ReadByte();
                        reader.ReadByte();
                        sm.OPT_num_mapping_entries = reader.ReadUInt16();                         // num_shorts
                    }
                }
            }
            else
            {
                // Defaults for Rayman 2, no optimized mesh feature
                sm.num_uvMaps = 1;
                sm.OPT_num_mapping_entries       = 0;
                sm.OPT_off_mapping_vertices      = null;
                sm.OPT_off_mapping_uvs           = null;
                sm.OPT_num_triangleStrip         = 0;
                sm.OPT_num_disconnectedTriangles = 0;
                sm.OPT_off_triangleStrip         = null;
                sm.OPT_off_disconnectedTriangles = null;
                sm.isVisibleInPortal             = 1;
            }

            // Read mapping tables
            sm.OPT_mapping_uvs = new int[sm.num_uvMaps][];
            if (sm.OPT_num_mapping_entries > 0)
            {
                Pointer.Goto(ref reader, sm.OPT_off_mapping_vertices);
                //print("Mapping offset: " + String.Format("0x{0:X}", fs.Position));
                sm.OPT_mapping_vertices = new int[sm.OPT_num_mapping_entries];
                for (int j = 0; j < sm.OPT_num_mapping_entries; j++)
                {
                    sm.OPT_mapping_vertices[j] = reader.ReadInt16();
                }
                Pointer.Goto(ref reader, sm.OPT_off_mapping_uvs);
                for (int j = 0; j < sm.num_uvMaps; j++)
                {
                    sm.OPT_mapping_uvs[j] = new int[sm.OPT_num_mapping_entries];
                }
                for (int j = 0; j < sm.OPT_num_mapping_entries; j++)
                {
                    for (int um = 0; um < sm.num_uvMaps; um++)
                    {
                        sm.OPT_mapping_uvs[um][j] = reader.ReadInt16();
                    }
                }
            }
            if (sm.num_triangles > 0)
            {
                Pointer.Goto(ref reader, sm.off_mapping_uvs);
                sm.mapping_uvs = new int[sm.num_uvMaps][];
                for (int j = 0; j < sm.num_uvMaps; j++)
                {
                    sm.mapping_uvs[j] = new int[sm.num_triangles * 3];
                }
                // Why is uv maps here the outer loop instead of inner like the other thing?
                for (int um = 0; um < sm.num_uvMaps; um++)
                {
                    for (int j = 0; j < sm.num_triangles * 3; j++)
                    {
                        sm.mapping_uvs[um][j] = reader.ReadInt16();
                    }
                }
            }

            // Read UVs
            Pointer.DoAt(ref reader, sm.off_uvs, () => {
                sm.uvs = new Vector2[sm.num_uvs];
                for (int j = 0; j < sm.num_uvs; j++)
                {
                    sm.uvs[j] = new Vector2(reader.ReadSingle(), reader.ReadSingle());
                }
            });
            // Read triangle data
            Pointer.DoAt(ref reader, sm.OPT_off_triangleStrip, () => {
                sm.OPT_triangleStrip = new int[sm.OPT_num_triangleStrip];
                for (int j = 0; j < sm.OPT_num_triangleStrip; j++)
                {
                    sm.OPT_triangleStrip[j] = reader.ReadInt16();
                }
            });
            Pointer.DoAt(ref reader, sm.OPT_off_disconnectedTriangles, () => {
                sm.OPT_disconnectedTriangles = new int[sm.OPT_num_disconnectedTriangles * 3];
                //print("Loading disconnected triangles at " + String.Format("0x{0:X}", fs.Position));
                for (int j = 0; j < sm.OPT_num_disconnectedTriangles; j++)
                {
                    sm.OPT_disconnectedTriangles[(j * 3) + 0] = reader.ReadInt16();
                    sm.OPT_disconnectedTriangles[(j * 3) + 1] = reader.ReadInt16();
                    sm.OPT_disconnectedTriangles[(j * 3) + 2] = reader.ReadInt16();
                }
            });
            if (sm.num_triangles > 0)
            {
                Pointer.Goto(ref reader, sm.off_triangles);
                sm.triangles = new int[sm.num_triangles * 3];
                //print("Loading disconnected triangles at " + String.Format("0x{0:X}", fs.Position));
                for (int j = 0; j < sm.num_triangles; j++)
                {
                    sm.triangles[(j * 3) + 0] = reader.ReadInt16();
                    sm.triangles[(j * 3) + 1] = reader.ReadInt16();
                    sm.triangles[(j * 3) + 2] = reader.ReadInt16();
                }
                if (sm.off_normals != null)
                {
                    Pointer.Goto(ref reader, sm.off_normals);
                    sm.normals = new Vector3[sm.num_triangles];
                    for (int j = 0; j < sm.num_triangles; j++)
                    {
                        float x = reader.ReadSingle();
                        float z = reader.ReadSingle();
                        float y = reader.ReadSingle();
                        sm.normals[j] = new Vector3(x, y, z);
                    }
                }
            }
            if (Settings.s.game == Settings.Game.LargoWinch && sm.lightmap_index != -1)
            {
                LWLoader lwl = MapLoader.Loader as LWLoader;
                if (lwl.lms != null && sm.lightmap_index >= 0 && sm.lightmap_index < lwl.lms.Count)
                {
                    /*if (sm.lightmap_index < l.off_lightmapUV.Length - 1) {
                     *      int amount = ((int)l.off_lightmapUV[sm.lightmap_index + 1].offset - (int)l.off_lightmapUV[sm.lightmap_index].offset);
                     *      amount = amount / 8;
                     *      l.print(offset + " - UVs: " + amount + " - " + sm.mesh.num_vertices + " - " + sm.num_mapping_entries + " - " + sm.num_uvs + " - " + sm.num_disconnected_triangles_spe + " - " + sm.num_mapping_lightmap);
                     * }*/
                    Vector2[] lightmapUVs = new Vector2[sm.num_mapping_lightmap];
                    Pointer.DoAt(ref reader, sm.off_mapping_lightmap, () => {
                        sm.mapping_lightmap = new int[sm.num_mapping_lightmap];
                        for (int i = 0; i < sm.num_mapping_lightmap; i++)
                        {
                            sm.mapping_lightmap[i] = reader.ReadInt16();
                        }
                    });
                    Pointer.DoAt(ref reader, l.off_lightmapUV[sm.lightmap_index], () => {
                        for (int j = 0; j < lightmapUVs.Length; j++)
                        {
                            lightmapUVs[j] = new Vector2(reader.ReadSingle(), reader.ReadSingle());
                        }
                    });
                    sm.AddLightmap(lwl.GetLightmap(sm.lightmap_index), lightmapUVs);
                }
            }
            return(sm);
        }