/// <summary> /// Tries the parse a brush side line. /// </summary> /// <param name="line">The line to be parsed.</param> /// <param name="mapBrushSide">The map brush side or null.</param> /// <returns>True if successful else false.</returns> private bool TryParseBrushSide(string line, out MapBrushSide mapBrushSide) { mapBrushSide = new MapBrushSide(); // detect brush side definition. if (line[0] == '(') { string[] values = line.Replace("(", "").Replace(")", "").Replace(" ", " ").Replace(" ", " ").Trim().Split(' '); if (values.Length != 15) { return(false); } try { MapVector3 p1 = new MapVector3(float.Parse(values[0], CultureInfo.InvariantCulture), float.Parse(values[1], CultureInfo.InvariantCulture), float.Parse(values[2], CultureInfo.InvariantCulture)); MapVector3 p2 = new MapVector3(float.Parse(values[3], CultureInfo.InvariantCulture), float.Parse(values[4], CultureInfo.InvariantCulture), float.Parse(values[5], CultureInfo.InvariantCulture)); MapVector3 p3 = new MapVector3(float.Parse(values[6], CultureInfo.InvariantCulture), float.Parse(values[7], CultureInfo.InvariantCulture), float.Parse(values[8], CultureInfo.InvariantCulture)); mapBrushSide.Plane = new MapPlane(p1, p2, p3); mapBrushSide.Material = values[9]; mapBrushSide.Offset = new MapVector2(float.Parse(values[10], CultureInfo.InvariantCulture), float.Parse(values[11], CultureInfo.InvariantCulture)); mapBrushSide.Rotation = float.Parse(values[12], CultureInfo.InvariantCulture); mapBrushSide.Scale = new MapVector2(float.Parse(values[13], CultureInfo.InvariantCulture), float.Parse(values[14], CultureInfo.InvariantCulture)); } catch (Exception) { throw new Exception("Encountered invalid brush side. The format of the map file must be slightly different, please open an issue on github if you think you did everything right."); } return(true); } return(false); }
/// <summary> /// Imports the specified world into the SabreCSG model. /// </summary> /// <param name="model">The model to import into.</param> /// <param name="world">The world to be imported.</param> /// <param name="scale">The scale modifier.</param> public static void Import(CSGModelBase model, MapWorld world) { try { model.BeginUpdate(); // create a material searcher to associate materials automatically. MaterialSearcher materialSearcher = new MaterialSearcher(); // group all the brushes together. GroupBrush groupBrush = new GameObject("Quake 1 Map").AddComponent <GroupBrush>(); groupBrush.transform.SetParent(model.transform); // iterate through all entities. for (int e = 0; e < world.Entities.Count; e++) { #if UNITY_EDITOR UnityEditor.EditorUtility.DisplayProgressBar("SabreCSG: Importing Quake 1 Map", "Converting Quake 1 Entities To SabreCSG Brushes (" + (e + 1) + " / " + world.Entities.Count + ")...", e / (float)world.Entities.Count); #endif MapEntity entity = world.Entities[e]; // iterate through all entity solids. for (int i = 0; i < entity.Brushes.Count; i++) { MapBrush brush = entity.Brushes[i]; #if UNITY_EDITOR if (world.Entities[e].ClassName == "worldspawn") { UnityEditor.EditorUtility.DisplayProgressBar("SabreCSG: Importing Quake 1 Map", "Converting Quake 1 Brushes To SabreCSG Brushes (" + (i + 1) + " / " + entity.Brushes.Count + ")...", i / (float)entity.Brushes.Count); } #endif // don't add triggers to the scene. if (brush.Sides.Count > 0 && IsSpecialMaterial(brush.Sides[0].Material)) { continue; } // build a very large cube brush. var go = model.CreateBrush(PrimitiveBrushType.Cube, Vector3.zero); var pr = go.GetComponent <PrimitiveBrush>(); BrushUtility.Resize(pr, new Vector3(8192, 8192, 8192)); // clip all the sides out of the brush. for (int j = brush.Sides.Count; j-- > 0;) { MapBrushSide side = brush.Sides[j]; Plane clip = new Plane(pr.transform.InverseTransformPoint(new Vector3(side.Plane.P1.X, side.Plane.P1.Z, side.Plane.P1.Y) / (float)s_Scale), pr.transform.InverseTransformPoint(new Vector3(side.Plane.P2.X, side.Plane.P2.Z, side.Plane.P2.Y) / (float)s_Scale), pr.transform.InverseTransformPoint(new Vector3(side.Plane.P3.X, side.Plane.P3.Z, side.Plane.P3.Y) / (float)s_Scale)); ClipUtility.ApplyClipPlane(pr, clip, false); // find the polygons associated with the clipping plane. // the normal is unique and can never occur twice as that wouldn't allow the solid to be convex. var polygons = pr.GetPolygons().Where(p => p.Plane.normal.EqualsWithEpsilonLower3(clip.normal)); foreach (var polygon in polygons) { // detect excluded polygons. if (IsExcludedMaterial(side.Material)) { polygon.UserExcludeFromFinal = true; } // detect collision-only brushes. if (IsInvisibleMaterial(side.Material)) { pr.IsVisible = false; } // find the material in the unity project automatically. Material material; // try finding the texture name with '*' replaced by '#' so '#teleport'. string materialName = side.Material.Replace("*", "#"); material = materialSearcher.FindMaterial(new string[] { materialName }); if (material == null) { Debug.Log("SabreCSG: Tried to find material '" + materialName + "' but it couldn't be found in the project."); } polygon.Material = material; // calculate the texture coordinates. int w = 256; int h = 256; if (polygon.Material != null && polygon.Material.mainTexture != null) { w = polygon.Material.mainTexture.width; h = polygon.Material.mainTexture.height; } CalculateTextureCoordinates(pr, polygon, w, h, new Vector2(side.Offset.X, -side.Offset.Y), new Vector2(side.Scale.X, side.Scale.Y), side.Rotation); } } // add the brush to the group. pr.transform.SetParent(groupBrush.transform); } } #if UNITY_EDITOR UnityEditor.EditorUtility.ClearProgressBar(); #endif } catch (Exception) { throw; } finally { model.EndUpdate(); } }