public static void SaveToFile(string filename, Document document, ExportForm form, string format) { form.ProgressBar.Invoke((MethodInvoker)(() => form.ProgressBar.Maximum = 10000)); AssimpProvider.SaveToFile(filename, document.Map, format); form.ProgressLog.Invoke((MethodInvoker)(() => form.ProgressLog.AppendText("\nDone!"))); form.ProgressBar.Invoke((MethodInvoker)(() => form.ProgressBar.Value = 10000)); }
public static void SaveToFile(string filename, Document document, ExportForm form) { var map = document.Map; string filepath = System.IO.Path.GetDirectoryName(filename); filename = System.IO.Path.GetFileName(filename); filename = System.IO.Path.GetFileNameWithoutExtension(filename) + ".rmesh"; string lmPath = System.IO.Path.GetFileNameWithoutExtension(filename) + "_lm"; List <Lightmap.LMFace> faces; int lmCount; List <Lightmap.Light> lights; Lightmap.Lightmapper.Render(document, form, out faces, out lmCount); Lightmap.Light.FindLights(map, out lights); lights.RemoveAll(l => !l.HasSprite); IEnumerable <Face> transparentFaces = map.WorldSpawn.Find(x => x is Solid).OfType <Solid>().SelectMany(x => x.Faces).Where(x => { if (x.Texture?.Texture == null) { return(false); } if (!x.Texture.Texture.HasTransparency()) { return(false); } if (x.Texture.Name.Contains("tooltextures")) { return(false); } return(true); }); IEnumerable <Face> invisibleCollisionFaces = map.WorldSpawn.Find(x => x is Solid).OfType <Solid>().SelectMany(x => x.Faces).Where(x => x.Texture.Name.ToLowerInvariant() == "tooltextures/invisible_collision"); Lightmap.Lightmapper.SaveLightmaps(document, lmCount, filepath + "/" + lmPath, false); lmPath = System.IO.Path.GetFileName(lmPath); List <Waypoint> waypoints = map.WorldSpawn.Find(x => x.ClassName != null && x.ClassName.ToLower() == "waypoint").OfType <Entity>().Select(x => new Waypoint(x)).ToList(); IEnumerable <Entity> soundEmitters = map.WorldSpawn.Find(x => x.ClassName != null && x.ClassName.ToLower() == "soundemitter").OfType <Entity>(); IEnumerable <Entity> props = map.WorldSpawn.Find(x => x.ClassName != null && x.ClassName.ToLower() == "model").OfType <Entity>(); IEnumerable <Entity> screens = map.WorldSpawn.Find(x => x.ClassName != null && x.ClassName.ToLower() == "screen").OfType <Entity>(); FileStream stream = new FileStream(filepath + "/" + filename, FileMode.Create); BinaryWriter br = new BinaryWriter(stream); //header br.WriteB3DString("RoomMesh"); //textures List <Tuple <string, RMeshLoadFlags, RMeshBlendFlags, byte> > textures = new List <Tuple <string, RMeshLoadFlags, RMeshBlendFlags, byte> >(); RMeshLoadFlags loadFlag = RMeshLoadFlags.COLOR; RMeshBlendFlags blendFlag = RMeshBlendFlags.DIFFUSE; foreach (LMFace face in faces) { if (!textures.Any(x => x.Item1 == face.Texture)) { textures.Add(new Tuple <string, RMeshLoadFlags, RMeshBlendFlags, byte>(face.Texture, loadFlag, blendFlag, 0)); } } loadFlag = RMeshLoadFlags.ALPHA; blendFlag = RMeshBlendFlags.NORMAL; foreach (Face face in transparentFaces) { if (!textures.Any(x => x.Item1 == face.Texture.Name)) { textures.Add(new Tuple <string, RMeshLoadFlags, RMeshBlendFlags, byte>(face.Texture.Name, loadFlag, blendFlag, 0)); } } //mesh int vertCount; int vertOffset; int triCount; //TODO: find a clever way of splitting up meshes with the same texture //into several for collision optimization. //Making each face its own collision object is too slow, and merging all of //them together is not optimal either. int texCount = 0; for (int i = 0; i < textures.Count; i++) { texCount += faces.Where(x => x.Texture == textures[i].Item1).Select(x => x.LmIndex).Distinct().Count(); texCount += transparentFaces.Any(x => x.Texture.Name == textures[i].Item1) ? 1 : 0; } br.Write((Int32)texCount); for (int i = 0; i < textures.Count; i++) { string texName = Directories.GetTextureExtension(textures[i].Item1); for (int lmInd = 0; lmInd < lmCount; lmInd++) { LMFace[] tLmFaces = faces.FindAll(x => x.Texture == textures[i].Item1 && x.LmIndex == lmInd).ToArray(); Face[] tTrptFaces = transparentFaces.Where(x => x.Texture.Name == textures[i].Item1).ToArray(); vertCount = 0; vertOffset = 0; triCount = 0; if (tLmFaces.Length > 0) { foreach (LMFace face in tLmFaces) { vertCount += face.Vertices.Count; triCount += face.GetTriangleIndices().Count() / 3; } byte flag = 1; br.Write(flag); string currLmPath = lmPath + (lmCount > 1 ? "_" + lmInd.ToString() : ""); currLmPath += ".png"; br.WriteB3DString(currLmPath); flag = 1; br.Write(flag); br.WriteB3DString(texName); if (vertCount > UInt16.MaxValue) { throw new Exception("Vertex overflow: " + texName); } br.Write((Int32)vertCount); foreach (LMFace face in tLmFaces) { for (int j = 0; j < face.Vertices.Count; j++) { br.Write(face.Vertices[j].Location.X); br.Write(face.Vertices[j].Location.Z); br.Write(face.Vertices[j].Location.Y); br.Write(face.Vertices[j].DiffU); br.Write(face.Vertices[j].DiffV); float lmMul = (lmCount > 1) ? 2.0f : 1.0f; float uSub = ((lmInd % 2) > 0) ? 0.5f : 0.0f; float vSub = ((lmInd / 2) > 0) ? 0.5f : 0.0f; br.Write((face.Vertices[j].LMU - uSub) * lmMul); br.Write((face.Vertices[j].LMV - vSub) * lmMul); br.Write((byte)255); //r br.Write((byte)255); //g br.Write((byte)255); //b } } br.Write((Int32)triCount); foreach (LMFace face in tLmFaces) { foreach (uint ind in face.GetTriangleIndices()) { br.Write((Int32)(ind + vertOffset)); } vertOffset += face.Vertices.Count; } } else if (lmInd == 0 && tTrptFaces.Length > 0) { foreach (Face face in tTrptFaces) { vertCount += face.Vertices.Count; triCount += face.GetTriangleIndices().Count() / 3; } byte flag = 0; br.Write(flag); flag = 3; br.Write(flag); br.WriteB3DString(texName); if (vertCount > UInt16.MaxValue) { throw new Exception("Vertex overflow!"); } br.Write((Int32)vertCount); foreach (Face face in tTrptFaces) { for (int j = 0; j < face.Vertices.Count; j++) { br.Write((float)face.Vertices[j].Location.X); br.Write((float)face.Vertices[j].Location.Z); br.Write((float)face.Vertices[j].Location.Y); br.Write((float)face.Vertices[j].TextureU); br.Write((float)face.Vertices[j].TextureV); br.Write(0.0f); br.Write(0.0f); br.Write((byte)255); //r br.Write((byte)255); //g br.Write((byte)255); //b } } br.Write((Int32)triCount); foreach (Face face in tTrptFaces) { foreach (uint ind in face.GetTriangleIndices()) { br.Write((Int32)(ind + vertOffset)); } vertOffset += face.Vertices.Count; } } } } vertCount = 0; vertOffset = 0; triCount = 0; if (invisibleCollisionFaces.Count() > 0) { br.Write((Int32)1); foreach (Face face in invisibleCollisionFaces) { vertCount += face.Vertices.Count; triCount += face.GetTriangleIndices().Count() / 3; } if (vertCount > UInt16.MaxValue) { throw new Exception("Vertex overflow!"); } br.Write((Int32)vertCount); foreach (Face face in invisibleCollisionFaces) { for (int j = 0; j < face.Vertices.Count; j++) { br.Write((float)face.Vertices[j].Location.X); br.Write((float)face.Vertices[j].Location.Z); br.Write((float)face.Vertices[j].Location.Y); } } br.Write((Int32)triCount); foreach (Face face in invisibleCollisionFaces) { foreach (uint ind in face.GetTriangleIndices()) { br.Write((Int32)(ind + vertOffset)); } vertOffset += face.Vertices.Count; } } else { br.Write((Int32)0); } br.Write((Int32)(lights.Count + waypoints.Count + soundEmitters.Count() + props.Count() + screens.Count())); foreach (Light light in lights) { br.WriteB3DString("light"); br.Write(light.Origin.X); br.Write(light.Origin.Z); br.Write(light.Origin.Y); br.Write(light.Range); string lcolor = light.Color.X + " " + light.Color.Y + " " + light.Color.Z; br.Write((Int32)lcolor.Length); for (int k = 0; k < lcolor.Length; k++) { br.Write((byte)lcolor[k]); } br.Write(light.Intensity); } foreach (Waypoint wp in waypoints) { br.WriteB3DString("waypoint"); br.Write(wp.Location.X); br.Write(wp.Location.Z); br.Write(wp.Location.Y); } foreach (Entity soundEmitter in soundEmitters) { br.WriteB3DString("soundemitter"); br.Write((float)soundEmitter.Origin.X); br.Write((float)soundEmitter.Origin.Z); br.Write((float)soundEmitter.Origin.Y); br.Write((Int32)int.Parse(soundEmitter.EntityData.GetPropertyValue("sound"))); br.Write(float.Parse(soundEmitter.EntityData.GetPropertyValue("range"))); } foreach (Entity prop in props) { br.WriteB3DString("model"); string modelName = prop.EntityData.GetPropertyValue("file") ?? ""; if (!modelName.Contains('.')) { modelName = System.IO.Path.GetFileName(Directories.GetModelPath(modelName)) ?? (modelName + ".x"); } br.WriteB3DString(modelName); br.Write((float)prop.Origin.X); br.Write((float)prop.Origin.Z); br.Write((float)prop.Origin.Y); Coordinate rotation = prop.EntityData.GetPropertyCoordinate("angles"); br.Write((float)rotation.X); br.Write((float)rotation.Y); br.Write((float)rotation.Z); Coordinate scale = prop.EntityData.GetPropertyCoordinate("scale"); br.Write((float)scale.X); br.Write((float)scale.Y); br.Write((float)scale.Z); } foreach (Entity screen in screens) { br.WriteB3DString("screen"); br.Write((float)screen.Origin.X); br.Write((float)screen.Origin.Z); br.Write((float)screen.Origin.Y); br.WriteB3DString(screen.EntityData.GetPropertyValue("imgpath")); } br.Dispose(); stream.Dispose(); form.ProgressLog.Invoke((MethodInvoker)(() => form.ProgressLog.AppendText("\nDone!"))); form.ProgressBar.Invoke((MethodInvoker)(() => form.ProgressBar.Value = 10000)); }
public static void SaveToFile(string filename, Document document, ExportForm form) { var map = document.Map; string filepath = System.IO.Path.GetDirectoryName(filename); filename = System.IO.Path.GetFileName(filename); filename = System.IO.Path.GetFileNameWithoutExtension(filename) + ".rm2"; string lmPath = System.IO.Path.GetFileNameWithoutExtension(filename) + "_lm"; List <Lightmap.LMFace> faces; int lmCount; List <Lightmap.Light> lights; Lightmap.Lightmapper.Render(document, form, out faces, out lmCount); Lightmap.Light.FindLights(map, out lights); IEnumerable <Face> transparentFaces = map.WorldSpawn.Find(x => x is Solid).OfType <Solid>().SelectMany(x => x.Faces).Where(x => { if (x.Texture?.Texture == null) { return(false); } if (!x.Texture.Texture.HasTransparency()) { return(false); } if (x.Texture.Name.Contains("tooltextures")) { return(false); } return(true); }); IEnumerable <Face> invisibleCollisionFaces = map.WorldSpawn.Find(x => x is Solid).OfType <Solid>().SelectMany(x => x.Faces).Where(x => x.Texture.Name.ToLowerInvariant() == "tooltextures/invisible_collision"); Lightmap.Lightmapper.SaveLightmaps(document, lmCount, filepath + "/" + lmPath, true); lmPath = System.IO.Path.GetFileName(lmPath); List <Waypoint> waypoints = map.WorldSpawn.Find(x => x.ClassName != null && x.ClassName.ToLower() == "waypoint").OfType <Entity>().Select(x => new Waypoint(x)).ToList(); IEnumerable <Entity> props = map.WorldSpawn.Find(x => x.ClassName != null && x.ClassName.ToLower() == "model").OfType <Entity>(); form.ProgressLog.Invoke((MethodInvoker)(() => form.ProgressLog.AppendText("\nDetermining waypoint visibility..."))); form.ProgressBar.Invoke((MethodInvoker)(() => form.ProgressBar.Value = 9100)); for (int i = 0; i < waypoints.Count; i++) { for (int j = 0; j < waypoints.Count; j++) { if (j > i) { waypoints[i].Connections.Add(j); } else if (j < i) { if (waypoints[j].Connections.Contains(i)) { waypoints[i].Connections.Add(j); } } } foreach (Lightmap.LMFace face in faces) { for (int j = 0; j < waypoints[i].Connections.Count; j++) { int connection = waypoints[i].Connections[j]; if (connection < i) { continue; } LineF line1 = new LineF(waypoints[i].Location, waypoints[connection].Location); LineF line2 = new LineF(waypoints[connection].Location, waypoints[i].Location); if (face.GetIntersectionPoint(line1) != null || face.GetIntersectionPoint(line2) != null) { waypoints[i].Connections.RemoveAt(j); j--; } } } } FileStream stream = new FileStream(filepath + "/" + filename, FileMode.Create); BinaryWriter br = new BinaryWriter(stream); //header br.Write((byte)'.'); br.Write((byte)'R'); br.Write((byte)'M'); br.Write((byte)'2'); //textures List <Tuple <string, byte> > textures = new List <Tuple <string, byte> >(); byte flag = (byte)RM2TextureLoadFlag.Opaque; foreach (Lightmap.LMFace face in faces) { if (!textures.Any(x => x.Item1 == face.Texture)) { textures.Add(new Tuple <string, byte>(face.Texture, flag)); } } flag = (byte)RM2TextureLoadFlag.Alpha; foreach (Face face in transparentFaces) { if (!textures.Any(x => x.Item1 == face.Texture.Name)) { textures.Add(new Tuple <string, byte>(face.Texture.Name, flag)); } } br.Write((byte)RM2Chunks.Textures); br.Write((byte)lmCount); br.Write((byte)textures.Count); foreach (Tuple <string, byte> tex in textures) { br.WriteByteString(tex.Item1); br.Write(tex.Item2); } //mesh int vertCount; int vertOffset; int triCount; for (int i = 0; i < textures.Count; i++) { for (int lmInd = 0; lmInd < lmCount; lmInd++) { IEnumerable <Lightmap.LMFace> tLmFaces = faces.FindAll(x => x.Texture == textures[i].Item1 && x.LmIndex == lmInd); vertCount = 0; vertOffset = 0; triCount = 0; if (tLmFaces.Count() > 0) { foreach (Lightmap.LMFace face in tLmFaces) { vertCount += face.Vertices.Count; triCount += face.GetTriangleIndices().Count() / 3; } br.Write((byte)RM2Chunks.VisibleGeometry); br.Write((byte)i); if (lmCount > 1) { br.Write((byte)lmInd); } if (vertCount > UInt16.MaxValue) { throw new Exception("Vertex overflow!"); } br.Write((UInt16)vertCount); foreach (Lightmap.LMFace face in tLmFaces) { for (int j = 0; j < face.Vertices.Count; j++) { br.Write(face.Vertices[j].Location.X); br.Write(face.Vertices[j].Location.Z); br.Write(face.Vertices[j].Location.Y); //br.Write((byte)255); //r //br.Write((byte)255); //g //br.Write((byte)255); //b br.Write(face.Vertices[j].DiffU); br.Write(face.Vertices[j].DiffV); float lmMul = (lmCount > 1) ? 2.0f : 1.0f; float uSub = ((lmInd % 2) > 0) ? 0.5f : 0.0f; float vSub = ((lmInd / 2) > 0) ? 0.5f : 0.0f; br.Write((face.Vertices[j].LMU - uSub) * lmMul); br.Write((face.Vertices[j].LMV - vSub) * lmMul); } } br.Write((UInt16)triCount); foreach (Lightmap.LMFace face in tLmFaces) { foreach (uint ind in face.GetTriangleIndices()) { br.Write((UInt16)(ind + vertOffset)); } vertOffset += face.Vertices.Count; } } } IEnumerable <Face> tTrptFaces = transparentFaces.Where(x => x.Texture.Name == textures[i].Item1); vertCount = 0; vertOffset = 0; triCount = 0; if (tTrptFaces.Count() > 0) { foreach (Face face in tTrptFaces) { vertCount += face.Vertices.Count; triCount += face.GetTriangleIndices().Count() / 3; } br.Write((byte)RM2Chunks.VisibleGeometry); br.Write((byte)i); if (vertCount > UInt16.MaxValue) { throw new Exception("Vertex overflow!"); } br.Write((UInt16)vertCount); foreach (Face face in tTrptFaces) { for (int j = 0; j < face.Vertices.Count; j++) { br.Write((float)face.Vertices[j].Location.X); br.Write((float)face.Vertices[j].Location.Z); br.Write((float)face.Vertices[j].Location.Y); //vertex color is not used since we don't do vertex lighting anymore //br.Write((byte)255); //r //br.Write((byte)255); //g //br.Write((byte)255); //b br.Write((float)face.Vertices[j].TextureU); br.Write((float)face.Vertices[j].TextureV); br.Write(0.0f); br.Write(0.0f); } } br.Write((UInt16)triCount); foreach (Face face in tTrptFaces) { foreach (uint ind in face.GetTriangleIndices()) { br.Write((UInt16)(ind + vertOffset)); } vertOffset += face.Vertices.Count; } } } vertCount = 0; vertOffset = 0; triCount = 0; if (invisibleCollisionFaces.Count() > 0) { foreach (Face face in invisibleCollisionFaces) { vertCount += face.Vertices.Count; triCount += face.GetTriangleIndices().Count() / 3; } br.Write((byte)RM2Chunks.InvisibleGeometry); if (vertCount > UInt16.MaxValue) { throw new Exception("Vertex overflow!"); } br.Write((UInt16)vertCount); foreach (Face face in invisibleCollisionFaces) { for (int j = 0; j < face.Vertices.Count; j++) { br.Write((float)face.Vertices[j].Location.X); br.Write((float)face.Vertices[j].Location.Z); br.Write((float)face.Vertices[j].Location.Y); } } br.Write((UInt16)triCount); foreach (Face face in invisibleCollisionFaces) { foreach (uint ind in face.GetTriangleIndices()) { br.Write((UInt16)(ind + vertOffset)); } vertOffset += face.Vertices.Count; } } foreach (Lightmap.Light light in lights) { br.Write((byte)RM2Chunks.PointLight); br.Write(light.Origin.X); br.Write(light.Origin.Z); br.Write(light.Origin.Y); br.Write(light.Range); br.Write((byte)light.Color.X); br.Write((byte)light.Color.Y); br.Write((byte)light.Color.Z); br.Write(light.Intensity); } foreach (Waypoint wp in waypoints) { br.Write((byte)RM2Chunks.Waypoint); br.Write(wp.Location.X); br.Write(wp.Location.Z); br.Write(wp.Location.Y); for (int i = 0; i < wp.Connections.Count; i++) { br.Write((byte)(wp.Connections[i] + 1)); } br.Write((byte)0); } foreach (Entity prop in props) { br.Write((byte)RM2Chunks.Prop); br.WriteByteString(System.IO.Path.GetFileNameWithoutExtension(prop.EntityData.GetPropertyValue("file"))); br.Write((float)prop.Origin.X); br.Write((float)prop.Origin.Z); br.Write((float)prop.Origin.Y); Coordinate rotation = prop.EntityData.GetPropertyCoordinate("angles"); br.Write((float)rotation.X); br.Write((float)rotation.Y); br.Write((float)rotation.Z); Coordinate scale = prop.EntityData.GetPropertyCoordinate("scale"); br.Write((float)scale.X); br.Write((float)scale.Y); br.Write((float)scale.Z); } br.Dispose(); stream.Dispose(); form.ProgressLog.Invoke((MethodInvoker)(() => form.ProgressLog.AppendText("\nDone!"))); form.ProgressBar.Invoke((MethodInvoker)(() => form.ProgressBar.Value = 10000)); }