private void ReadMeshFromSDC() { if (optimizedObject?.Value == null) { return; } PS2OptimizedSDCStructure sdc = optimizedObject.Value; int sdcIndex = 0; for (int i = 0; i < num_elements; i++) { if (element_types[i] != 1) { continue; } PS2OptimizedSDCStructureElement sdcEl = sdc.elements[sdcIndex]; GeometricObjectElementTriangles mainEl = elements[i] as GeometricObjectElementTriangles; if (mainEl.visualMaterial == null) { mainEl.visualMaterial = sdc.visualMaterials[sdcIndex]; } //MapLoader.Loader.print(name + " - " + mainEl.visualMaterial.offset); if (sdc.visualMaterials[sdcIndex] != mainEl.visualMaterial) { Debug.LogWarning("SDC and Main materials did not match!"); } mainEl.sdc = sdcEl; sdcIndex++; } }
public void MorphVertices(GeometricObjectElementTriangles el, float lerp) { // Use UpdateMeshVertices if possible! Only use this for special cases if (OPT_unityMesh != null) { Vector3[] new_vertices = OPT_unityMesh.vertices; for (int j = 0; j < OPT_num_mapping_entries; j++) { Vector3 from = geo.vertices[OPT_mapping_vertices[j]]; Vector3 to = el.geo.vertices[el.OPT_mapping_vertices[j]]; new_vertices[j] = Vector3.LerpUnclamped(from, to, lerp); } OPT_unityMesh.vertices = new_vertices; } if (unityMesh != null) { Vector3[] new_vertices = unityMesh.vertices; for (int j = 0; j < num_triangles; j++) { int i0 = triangles[(j * 3) + 0], o0 = el.triangles[(j * 3) + 0], m0 = (j * 3) + 0; // Old index, mapped index int i1 = triangles[(j * 3) + 1], o1 = el.triangles[(j * 3) + 1], m1 = (j * 3) + 1; int i2 = triangles[(j * 3) + 2], o2 = el.triangles[(j * 3) + 2], m2 = (j * 3) + 2; new_vertices[m0] = Vector3.LerpUnclamped(geo.vertices[i0], el.geo.vertices[o0], lerp); new_vertices[m1] = Vector3.LerpUnclamped(geo.vertices[i1], el.geo.vertices[o1], lerp); new_vertices[m2] = Vector3.LerpUnclamped(geo.vertices[i2], el.geo.vertices[o2], lerp); } unityMesh.vertices = new_vertices; } }
public IGeometricObjectElement Clone(GeometricObject geo) { GeometricObjectElementTriangles sm = (GeometricObjectElementTriangles)MemberwiseClone(); sm.geo = geo; sm.Reset(); return(sm); }
private static void ReadMeshFromATO(Reader reader, GeometricObject m) { // Revolution only: Before creating the gameobject, read the actual model data from the ATO if (Settings.s.game == Settings.Game.R2Revolution) { MapLoader l = MapLoader.Loader; List <GeometricObject> meshObjects = new List <GeometricObject>(); for (uint i = 0; i < m.num_elements; i++) { if (m.element_types[i] == 1) { R2PS2Loader ps2l = (R2PS2Loader)l; meshObjects.Add(ps2l.ato.meshes[ps2l.ato.meshes.Length - 1 - ps2l.meshesRead - meshObjects.Count]); } } if (meshObjects.Count > 0) { int currentSubblock = 0; int curNumVertices = 0; bool tryMapping = true; if (m.vertices == null) { m.num_vertices = (ushort)meshObjects.Sum(mesh => mesh.num_vertices); m.vertices = new Vector3[m.num_vertices]; m.normals = new Vector3[m.num_vertices]; tryMapping = false; } for (int i = 0; i < meshObjects.Count; i++) { GeometricObject mo = meshObjects[i]; while (currentSubblock < m.num_elements && m.element_types[currentSubblock] != 1) { currentSubblock++; } GeometricObjectElementTriangles me = (GeometricObjectElementTriangles)m.elements[currentSubblock]; GeometricObjectElementTriangles moe = ((GeometricObjectElementTriangles)mo.elements[0]); if (!tryMapping) { Array.Copy(mo.vertices, 0, m.vertices, curNumVertices, mo.num_vertices); if (mo.normals != null) { Array.Copy(mo.normals, 0, m.normals, curNumVertices, mo.num_vertices); } me.OPT_mapping_vertices = Enumerable.Range(curNumVertices, mo.num_vertices).ToArray(); curNumVertices += mo.num_vertices; } else { me.OPT_mapping_vertices = new int[moe.OPT_num_mapping_entries]; for (int j = 0; j < mo.vertices.Length; j++) { me.OPT_mapping_vertices[j] = Array.IndexOf(m.vertices, mo.vertices[j]); if (me.OPT_mapping_vertices[j] == -1 || me.OPT_mapping_vertices[j] != Array.IndexOf(m.vertices, mo.vertices[j])) { Debug.LogError("Failed matching vertices between Renderware and OpenSpace"); } } } me.OPT_disconnectedTriangles = moe.OPT_disconnectedTriangles; me.OPT_num_disconnectedTriangles = moe.OPT_num_disconnectedTriangles; me.triangles = null; me.num_triangles = 0; me.num_uvMaps = moe.num_uvMaps; me.num_uvs = moe.num_uvs; me.uvs = moe.uvs; me.OPT_mapping_uvs = moe.OPT_mapping_uvs; me.OPT_num_mapping_entries = moe.OPT_num_mapping_entries; me.vertexColors = moe.vertexColors; currentSubblock++; if (me.lightmap_index != -1) { R2PS2Loader ps2l = ((R2PS2Loader)l); string id_r = me.lightmap_index.ToString("D3") + "." + 0; //l.print(id_r + " - " + me.num_disconnected_triangles + " - " + m.num_vertices + " - " + mo.num_vertices); Texture2D lm = ps2l.GetLightmap(id_r); if (me.visualMaterial != null) { if (lm != null) { string id_g = me.lightmap_index.ToString("D3") + "." + 1; string id_b = me.lightmap_index.ToString("D3") + "." + 2; Texture2D lm_g = ps2l.GetLightmap(id_g); Texture2D lm_b = ps2l.GetLightmap(id_b); if (lm_g != null && lm_b != null) { for (int j = 0; j < lm.width; j++) { for (int k = 0; k < lm.height; k++) { Color r = lm.GetPixel(j, k); Color g = lm_g.GetPixel(j, k); Color b = lm_b.GetPixel(j, k); lm.SetPixel(j, k, new Color(r.a, g.a, b.a, 1f)); } } lm.Apply(); } } else { lm = new Texture2D(1, 1); lm.SetPixel(0, 0, Color.white); lm.wrapMode = TextureWrapMode.Clamp; lm.filterMode = FilterMode.Bilinear; lm.Apply(); } Vector2[] lightmapUVs = new Vector2[mo.num_vertices]; Pointer.DoAt(ref reader, ps2l.off_lightmapUV[me.lightmap_index], () => { for (int j = 0; j < mo.num_vertices; j++) { lightmapUVs[j] = new Vector2(reader.ReadSingle(), reader.ReadSingle()); } }); me.AddLightmap(lm, lightmapUVs); } } } ((R2PS2Loader)l).meshesRead += (uint)meshObjects.Count; } } }
public static GeometricObject Read(Reader reader, Pointer offset) { MapLoader l = MapLoader.Loader; //l.print("Geometric Object: " + offset); GeometricObject m = new GeometricObject(offset); if (Settings.s.game == Settings.Game.LargoWinch) { uint flags = reader.ReadUInt32(); m.num_vertices = reader.ReadUInt16(); m.num_elements = reader.ReadUInt16(); m.off_element_types = Pointer.Read(reader); m.off_elements = Pointer.Read(reader); m.off_vertices = Pointer.Read(reader); m.off_normals = Pointer.Read(reader); reader.ReadSingle(); reader.ReadSingle(); reader.ReadSingle(); reader.ReadSingle(); m.lookAtMode = reader.ReadUInt32(); } else if (Settings.s.game == Settings.Game.R2Revolution) { m.off_element_types = Pointer.Read(reader); m.off_elements = Pointer.Read(reader); uint flags = reader.ReadUInt32(); reader.ReadSingle(); reader.ReadSingle(); reader.ReadSingle(); reader.ReadSingle(); m.off_mapping = Pointer.Read(reader); m.num_vertices = reader.ReadUInt16(); m.num_elements = reader.ReadUInt16(); m.off_vertices = Pointer.Read(reader); m.off_normals = Pointer.Read(reader); m.lookAtMode = flags & 3; } else { if (Settings.s.engineVersion <= Settings.EngineVersion.Montreal) { m.num_vertices = (ushort)reader.ReadUInt32(); } m.off_vertices = Pointer.Read(reader); m.off_normals = Pointer.Read(reader); if (Settings.s.engineVersion < Settings.EngineVersion.R3) { m.off_materials = Pointer.Read(reader); } else { m.off_blendWeights = Pointer.Read(reader); } if (Settings.s.mode != Settings.Mode.RaymanArenaGC && Settings.s.mode != Settings.Mode.RaymanArenaGCDemo && Settings.s.game != Settings.Game.RM && Settings.s.mode != Settings.Mode.DonaldDuckPKGC && !(Settings.s.platform == Settings.Platform.PS2 && Settings.s.engineVersion == Settings.EngineVersion.R3)) { reader.ReadInt32(); } if (Settings.s.engineVersion <= Settings.EngineVersion.Montreal) { m.num_elements = (ushort)reader.ReadUInt32(); } m.off_element_types = Pointer.Read(reader); m.off_elements = Pointer.Read(reader); reader.ReadInt32(); reader.ReadInt32(); if (Settings.s.engineVersion == Settings.EngineVersion.R2) { reader.ReadInt32(); reader.ReadInt32(); } if (Settings.s.game == Settings.Game.Dinosaur) { reader.ReadInt32(); reader.ReadInt32(); reader.ReadInt32(); } if (Settings.s.engineVersion > Settings.EngineVersion.Montreal) { m.lookAtMode = reader.ReadUInt32(); //if (m.lookAtMode != 0) l.print(m.lookAtMode); m.num_vertices = reader.ReadUInt16(); m.num_elements = reader.ReadUInt16(); reader.ReadInt32(); reader.ReadSingle(); // bounding volume radius reader.ReadSingle(); // x reader.ReadSingle(); // z reader.ReadSingle(); // y reader.ReadInt32(); if (Settings.s.engineVersion == Settings.EngineVersion.R3) { reader.ReadInt32(); if (!(Settings.s.platform == Settings.Platform.PS2 && (Settings.s.game == Settings.Game.RM || Settings.s.game == Settings.Game.RA))) { reader.ReadInt16(); if (Settings.s.platform == Settings.Platform.PS2) { reader.ReadInt16(); reader.ReadUInt32(); } } } } else { reader.ReadInt32(); reader.ReadInt32(); reader.ReadSingle(); reader.ReadSingle(); reader.ReadSingle(); reader.ReadSingle(); } } m.name = "Mesh @ " + offset; if (Settings.s.hasNames) { m.name = reader.ReadString(0x32); } if (Settings.s.platform == Settings.Platform.PS2 && Settings.s.engineVersion >= Settings.EngineVersion.R3) { reader.Align(0x4); reader.ReadUInt32(); reader.ReadUInt32(); m.optimizedObject = new Pointer <PS2OptimizedSDCStructure>(reader, resolve: false); reader.ReadUInt32(); reader.ReadUInt32(); if (Settings.s.game == Settings.Game.R3) { m.ps2IsSinus = reader.ReadUInt32(); } } // Vertices Pointer.DoAt(ref reader, m.off_vertices, () => { m.vertices = new Vector3[m.num_vertices]; for (int i = 0; i < m.num_vertices; i++) { float x = reader.ReadSingle(); float z = reader.ReadSingle(); float y = reader.ReadSingle(); m.vertices[i] = new Vector3(x, y, z); } }); // Normals Pointer.DoAt(ref reader, m.off_normals, () => { m.normals = new Vector3[m.num_vertices]; for (int i = 0; i < m.num_vertices; i++) { float x = reader.ReadSingle(); float z = reader.ReadSingle(); float y = reader.ReadSingle(); m.normals[i] = new Vector3(x, y, z); } }); Pointer.DoAt(ref reader, m.off_blendWeights, () => { m.blendWeights = new float[4][]; /*reader.ReadUInt32(); // 0 * R3Pointer off_blendWeightsStart = R3Pointer.Read(reader); * R3Pointer.Goto(ref reader, off_blendWeightsStart);*/ for (int i = 0; i < 4; i++) { Pointer off_blendWeights = Pointer.Read(reader); Pointer.DoAt(ref reader, off_blendWeights, () => { m.blendWeights[i] = new float[m.num_vertices]; for (int j = 0; j < m.num_vertices; j++) { m.blendWeights[i][j] = reader.ReadSingle(); } }); } reader.ReadUInt32(); reader.ReadUInt32(); reader.ReadUInt32(); reader.ReadUInt32(); }); Pointer.DoAt(ref reader, m.off_mapping, () => { // Revolution only reader.ReadUInt32(); Pointer.Read(reader); Pointer off_mappingBlocks = Pointer.Read(reader); Pointer.Read(reader); Pointer.Read(reader); ushort num_mappingBlocks = reader.ReadUInt16(); reader.ReadUInt16(); Pointer.DoAt(ref reader, off_mappingBlocks, () => { m.mapping = new int[num_mappingBlocks][]; for (int i = 0; i < num_mappingBlocks; i++) { Pointer off_mapping = Pointer.Read(reader); Pointer.DoAt(ref reader, off_mapping, () => { m.mapping[i] = new int[m.num_vertices]; for (int j = 0; j < m.num_vertices; j++) { m.mapping[i][j] = reader.ReadUInt16(); if (m.mapping[i][j] >= m.num_vertices) { l.print(m.offset); } } }); } }); }); // Read element types & initialize arrays Pointer.Goto(ref reader, m.off_element_types); m.element_types = new ushort[m.num_elements]; m.elements = new IGeometricObjectElement[m.num_elements]; for (uint i = 0; i < m.num_elements; i++) { m.element_types[i] = reader.ReadUInt16(); } // Process elements for (uint i = 0; i < m.num_elements; i++) { Pointer.Goto(ref reader, m.off_elements + (i * 4)); Pointer block_offset = Pointer.Read(reader); Pointer.Goto(ref reader, block_offset); switch (m.element_types[i]) { case 1: // Material m.elements[i] = GeometricObjectElementTriangles.Read(reader, block_offset, m); break; case 3: // Sprite m.elements[i] = GeometricObjectElementSprites.Read(reader, block_offset, m); break; case 13: case 15: m.bones = DeformSet.Read(reader, block_offset, m); m.elements[i] = m.bones; break; default: m.elements[i] = null; /*1 = indexedtriangles * 2 = facemap * 3 = sprite * 4 = TMesh * 5 = points * 6 = lines * 7 = spheres * 8 = alignedboxes * 9 = cones * 13 = deformationsetinfo*/ l.print("Unknown geometric element type " + m.element_types[i] + " at offset " + block_offset); break; } } ReadMeshFromATO(reader, m); if (Settings.s.platform == Settings.Platform.PS2 && Settings.s.engineVersion == Settings.EngineVersion.R3) { m.optimizedObject?.Resolve(reader, onPreRead: opt => opt.isSinus = m.ps2IsSinus); m.ReadMeshFromSDC(); } m.InitGameObject(); return(m); }
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); }