public void LoadFrom(Level level, int index) { DLF_IO_INTER inter = level.ArxLevelNative.DLF.inters[index]; name = ArxIOHelper.GetString(inter.name); string interPath = name.ToLowerInvariant(); int graphPos = interPath.IndexOf("graph"); interPath = interPath.Substring(graphPos); int lastDot = interPath.LastIndexOf('.'); interPath = interPath.Substring(0, lastDot); var ftlPath = Path.Combine(EditorSettings.DataDir, "game", ArxIOHelper.ArxPathToPlatformPath(interPath + ".ftl")); if (File.Exists(ftlPath)) { FTL_IO ftl = new FTL_IO(); using (var fs = new FileStream(ftlPath, FileMode.Open, FileAccess.Read)) using (var unp = FTL_IO.EnsureUnpacked(fs)) { ftl.ReadFrom(unp); } var mesh = ftl.CreateMesh(); var mf = gameObject.AddComponent <MeshFilter>(); mf.sharedMesh = mesh; var mr = gameObject.AddComponent <MeshRenderer>(); mr.sharedMaterial = MaterialsDatabase.TEST; } //depending on what the path is load item, npc, fix, camera or marker if (interPath.Contains("items")) { } else if (interPath.Contains("npc")) { } else if (interPath.Contains("fix")) { } else if (interPath.Contains("camera")) { } else if (interPath.Contains("marker")) { } transform.localPosition = inter.pos.ToVector3(); transform.localEulerAngles = inter.angle.ToEuler(); }
static void SaveMesh(Level level) { // create texture containers HashSet <string> uniqueTexturePaths = new HashSet <string>(); foreach (var kv in level.EditableLevelMesh.MaterialMeshes) { if (kv.Value.PrimitiveCount > 0) //only add if we have primitives for this material { //TODO: remove that later //var texPath = kv.Key.TexturePath.Replace(EditorSettings.DataDir, ""); uniqueTexturePaths.Add(kv.Key.TexturePath); } } var fts = level.ArxLevelNative.FTS; fts.textureContainers = new ArxNative.IO.FTS.FTS_IO_TEXTURE_CONTAINER[uniqueTexturePaths.Count]; int i = 1; //nothing speaks against just using a normal index for tc, i dont know why they ever used random ints, has to be 1 based Dictionary <string, int> texPathToTc = new Dictionary <string, int>(); foreach (var path in uniqueTexturePaths) { int index = i++; var texPath = path.Replace(EditorSettings.DataDir, ""); fts.textureContainers[index - 1].fic = ArxIOHelper.GetBytes(texPath, 256); texPathToTc[path] = fts.textureContainers[index - 1].tc = index; } //create cells int sizex = fts.sceneHeader.sizex; int sizez = fts.sceneHeader.sizez; LevelCell[] cells = new LevelCell[sizex * sizez]; for (int z = 0, index = 0; z < sizez; z++) { for (int x = 0; x < sizex; x++, index++) { //int index = ArxIOHelper.XZToCellIndex(x, z, sizex, sizez); var cell = new LevelCell(x, z); cells[index] = cell; } } //add primitives to cells Vector2Int maxPos = new Vector2Int(sizex - 1, sizez - 1); //if clamp is inclusive we have to sub 1 foreach (var kv in level.EditableLevelMesh.MaterialMeshes) { foreach (var prim in kv.Value.Primitives) { var cellpos = GetPrimitiveCellPos(prim); cellpos.Clamp(Vector2Int.zero, maxPos); var cell = cells[ArxIOHelper.XZToCellIndex(cellpos.x, cellpos.y, sizex, sizez)]; cell.AddPrimitive(kv.Key, prim); } } List <FTS_IO_EP_DATA>[] roomPolyDatas = new List <FTS_IO_EP_DATA> [fts.rooms.Length]; for (i = 0; i < fts.rooms.Length; ++i) { roomPolyDatas[i] = new List <FTS_IO_EP_DATA>(); } List <uint> lightColors = new List <uint>(); //put primitves into polys in their cells for (int z = 0, index = 0; z < sizez; z++) { for (int x = 0; x < sizex; x++, index++) { //int index = ArxIOHelper.XZToCellIndex(x, z, sizex, sizez); var myCell = cells[index]; var ftsCell = fts.cells[index]; ftsCell.sceneInfo.nbpoly = myCell.primitives.Count; ftsCell.polygons = new FTS_IO_EERIEPOLY[myCell.primitives.Count]; for (i = 0; i < myCell.primitives.Count; i++) { var tup = myCell.primitives[i]; var mat = tup.Item1; var prim = tup.Item2; var poly = new FTS_IO_EERIEPOLY(); //copy data over poly.area = prim.area; poly.norm = new SavedVec3(prim.norm); poly.norm2 = new SavedVec3(prim.norm2); poly.paddy = prim.paddy; poly.room = prim.room; poly.type = prim.polyType; //this is completely ignoring mat polytype atm, but it should be sync with prim type anyway if (poly.room >= 0) { var polyData = new FTS_IO_EP_DATA(); polyData.cell_x = (short)x; polyData.cell_z = (short)z; polyData.idx = (short)i; roomPolyDatas[poly.room].Add(polyData); } //copy vertices poly.vertices = new ArxNative.IO.FTS.FTS_IO_VERTEX[4]; poly.normals = new SavedVec3[4]; for (int j = 0; j < 4; j++) //always save all 4 vertices regardless of if its a triangle or quad { var vert = prim.vertices[j]; var natVert = new ArxNative.IO.FTS.FTS_IO_VERTEX(); natVert.posX = vert.position.x; natVert.posY = vert.position.y; natVert.posZ = vert.position.z; natVert.texU = vert.uv.x; natVert.texV = 1 - vert.uv.y; poly.normals[j] = new SavedVec3(vert.normal); poly.vertices[j] = natVert; } lightColors.Add(ArxIOHelper.ToBGRA(prim.vertices[0].color)); lightColors.Add(ArxIOHelper.ToBGRA(prim.vertices[1].color)); lightColors.Add(ArxIOHelper.ToBGRA(prim.vertices[2].color)); if (poly.type.HasFlag(ArxNative.PolyType.QUAD)) { lightColors.Add(ArxIOHelper.ToBGRA(prim.vertices[3].color)); } //set material stuff poly.tex = texPathToTc[mat.TexturePath];//keyerrors should not be possible on this poly.transval = mat.TransVal; //polytype is set from primitive ftsCell.polygons[i] = poly; } fts.cells[index] = ftsCell; } } for (i = 0; i < fts.rooms.Length; i++) { fts.rooms[i].polygons = roomPolyDatas[i].ToArray(); } //update llf var llf = level.ArxLevelNative.LLF; llf.lightingHeader.numLights = lightColors.Count; llf.lightColors = lightColors.ToArray(); //below does the same as toArray, just wondering if toArray is faster or manually assigning it /* * llf.lightColors = new uint[lightColors.Count]; * for (i = 0; i < lightColors.Count; i++) * { * llf.lightColors[i] = lightColors[i]; * } */ }
static void LoadMesh(Level lvl) { int loadedPolys = 0; Stopwatch sw = new Stopwatch(); sw.Start(); int lightIndex = 0; var fts = lvl.ArxLevelNative.FTS; Dictionary <int, int> tcToIndex = new Dictionary <int, int>(); //texture indices for (int i = 0; i < fts.textureContainers.Length; i++) { tcToIndex[fts.textureContainers[i].tc] = i; } //TODO: use external placeholder texture so it can be set to 0 on export var notFoundMaterialKey = new EditorMaterial(EditorSettings.DataDir + "graph\\interface\\misc\\default[icon].bmp", PolyType.GLOW, 0); for (int c = 0; c < fts.cells.Length; c++) { var cell = fts.cells[c]; loadedPolys += cell.polygons.Length; for (int p = 0; p < cell.polygons.Length; p++) { var poly = cell.polygons[p]; var matKey = notFoundMaterialKey; if (tcToIndex.TryGetValue(poly.tex, out int textureIndex)) { string texArxPath = ArxIOHelper.GetString(fts.textureContainers[textureIndex].fic); string texPath = TextureDatabase.GetRealTexturePath(EditorSettings.DataDir + texArxPath); matKey = new EditorMaterial(texPath, poly.type, poly.transval); //TODO: speed up by using a pool of some sort? } MaterialMesh mm = lvl.EditableLevelMesh.GetMaterialMesh(matKey); EditablePrimitiveInfo prim = new EditablePrimitiveInfo { polyType = poly.type, norm = poly.norm.ToVector3(), norm2 = poly.norm2.ToVector3(), area = poly.area, room = poly.room, paddy = poly.paddy }; int vertCount = prim.VertexCount; for (int i = 0; i < vertCount; i++) { var vert = poly.vertices[i]; prim.vertices[i] = new EditableVertexInfo(new Vector3(vert.posX, vert.posY, vert.posZ), new Vector2(vert.texU, 1 - vert.texV), poly.normals[i].ToVector3(), ArxIOHelper.FromBGRA(lvl.ArxLevelNative.LLF.lightColors[lightIndex++])); } if (prim.IsTriangle) { //load 4th vertex manually as it has no lighting value and would break lighting otherwise var lastVert = poly.vertices[3]; prim.vertices[3] = new EditableVertexInfo(new Vector3(lastVert.posX, lastVert.posY, lastVert.posZ), new Vector2(lastVert.texU, 1 - lastVert.texV), poly.normals[3].ToVector3(), Color.white); } mm.AddPrimitive(prim); } } foreach (var kv in lvl.EditableLevelMesh.MaterialMeshes) { kv.Value.UpdateMesh(); } UnityEngine.Debug.Log("total load time: " + sw.Elapsed); UnityEngine.Debug.Log("Loaded polys: " + loadedPolys); }