From 27231b41145c6f9e31484bd76ee5dca5a3b792d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=9F=D1=80=D1=83=D1=81=D0=B0=D0=BA=D0=BE=D0=B2?= Date: Mon, 5 Oct 2020 23:29:47 +0300 Subject: [PATCH] Add SPM dependencies instead of git submodules, also add SCNView to macOS version and remove QHull and using ConvexHull instead --- GameController.swift | 84 +++ Map Generator iOS/Base.lproj/Main.storyboard | 38 +- Map Generator iOS/DelaunayView.swift | 17 +- Map Generator iOS/GameViewController.swift | 93 +-- Map Generator iOS/ViewController.swift | 71 +- Map Generator.xcodeproj/project.pbxproj | 434 ++++-------- Map Generator/AppDelegate.swift | 1 - Map Generator/Base.lproj/MainMenu.xib | 673 ------------------- Map Generator/Center.swift | 24 +- Map Generator/Corner.swift | 36 +- Map Generator/DelaunayView.swift | 10 +- Map Generator/Edge.swift | 17 +- Map Generator/GameViewController.swift | 22 + Map Generator/Info.plist | 4 +- Map Generator/Main.storyboard | 167 +++++ Map Generator/ViewController.swift | 67 +- Map GeneratorBridging-Header.h | 5 - Map-Bridging-Header.h | 16 + MeshUtils.swift | 109 +-- Shared/Lava.swift | 16 +- Shared/Map.swift | 639 +++++++++--------- Shared/Watersheds.swift | 28 +- Utils.swift | 68 +- Vector3.swift | 303 --------- Vertex.swift | 11 +- 25 files changed, 974 insertions(+), 1979 deletions(-) create mode 100644 GameController.swift delete mode 100644 Map Generator/Base.lproj/MainMenu.xib create mode 100644 Map Generator/GameViewController.swift create mode 100644 Map Generator/Main.storyboard delete mode 100644 Map GeneratorBridging-Header.h create mode 100644 Map-Bridging-Header.h delete mode 100644 Vector3.swift diff --git a/GameController.swift b/GameController.swift new file mode 100644 index 0000000..44c14b3 --- /dev/null +++ b/GameController.swift @@ -0,0 +1,84 @@ +// +// GameController.swift +// Map Generator +// +// Created by v.prusakov on 10/5/20. +// Copyright © 2020 Carl Wieland. All rights reserved. +// + +import SceneKit +import ConvexHull + +class GameController { + + let scene: SCNScene + let sceneRenderer: SCNSceneRenderer + + init(scnView: SCNView, map: Map) { + // create a new scene + let scene = SCNScene() + self.scene = scene + + let mapNode = SCNNode() + let elevationScale = 2.0; + for c in map.centers { + var points = [Vector3]() + if c.elevation.isNormal { + points.append(Vector3(c.point.x, c.point.y, c.elevation * elevationScale)) + } + for edge in c.borders { + if let v0 = edge.v0 , let v1 = edge.v1{ + if v1.elevation.isNaN || v0.elevation.isNaN || v1.elevation.isInfinite || v0.elevation.isInfinite { + continue; + } + let vec1 = Vector3(v0.point.x, v0.point.y, v0.elevation * elevationScale) + let vec2 = Vector3(v1.point.x, v1.point.y, v1.elevation * elevationScale) + + if vec1.z.isNaN || vec2.z.isNaN { + continue; + } + + points.append(vec1) + points.append(vec2) + } + + } + let filtered = points.filter{ $0.z != 0 && $0.z.isNormal } + + if filtered.count > 4 { + let iscosphere = MeshUtils.convexHullOfPoints(points) + mapNode.addChildNode(iscosphere) + } + } + scene.rootNode.addChildNode(mapNode) + + let sphere = SCNNode() + sphere.geometry = SCNSphere(radius: 1) + sphere.simdPosition = .zero + let mat = SCNMaterial() + mat.diffuse.contents = SCNColor.red + sphere.geometry!.materials = [mat] + scene.rootNode.addChildNode(sphere) + + // set the scene to the view + scnView.scene = scene + + scnView.isPlaying = true + scnView.loops = true + + // allows the user to manipulate the camera + scnView.allowsCameraControl = true + + // show statistics such as fps and timing information + scnView.showsStatistics = true + scnView.autoenablesDefaultLighting = true + + scnView.debugOptions = [.showWireframe] + + + // configure the view + scnView.backgroundColor = SCNColor.black.withAlphaComponent(0.3) + + self.sceneRenderer = scnView + } +} diff --git a/Map Generator iOS/Base.lproj/Main.storyboard b/Map Generator iOS/Base.lproj/Main.storyboard index d1d14e4..5fd519c 100644 --- a/Map Generator iOS/Base.lproj/Main.storyboard +++ b/Map Generator iOS/Base.lproj/Main.storyboard @@ -1,8 +1,10 @@ - - + + + - - + + + @@ -10,7 +12,7 @@ - + @@ -30,23 +32,23 @@ - + - + - - + @@ -56,7 +58,13 @@ - + + + + + + + @@ -74,15 +82,15 @@ - + - + - + - + diff --git a/Map Generator iOS/DelaunayView.swift b/Map Generator iOS/DelaunayView.swift index 34869af..7eeacf1 100644 --- a/Map Generator iOS/DelaunayView.swift +++ b/Map Generator iOS/DelaunayView.swift @@ -9,6 +9,7 @@ import UIKit class DelaunayView: UIView { + var regionPoints = [[CGPoint]]() var positions = [CGPoint]() var triangles = [[CGPoint]]() @@ -20,25 +21,27 @@ class DelaunayView: UIView { override func draw(_ dirtyRect: CGRect) { super.draw(dirtyRect) + let context = UIGraphicsGetCurrentContext() pointColor.setFill() - for p in positions{ + + for p in positions { context!.fillEllipse(in: DelaunayView.rectForPoint(point: p)) } lineColor.set() - for region in regionPoints{ - if region.count == 2{ + + for region in regionPoints { + if region.count == 2 { var lines = region context?.move(to: lines[0]) context?.addLine(to: lines[1]) context?.drawPath(using: .stroke) - } } - } - static let radius:CGFloat = 3; - static func rectForPoint(point:CGPoint)->CGRect{ + + static let radius: CGFloat = 3; + static func rectForPoint(point: CGPoint) -> CGRect { return CGRect(x: point.x - radius, y: point.y - radius, width: 2 * radius, height: 2 * radius) } } diff --git a/Map Generator iOS/GameViewController.swift b/Map Generator iOS/GameViewController.swift index aeb120e..2793309 100644 --- a/Map Generator iOS/GameViewController.swift +++ b/Map Generator iOS/GameViewController.swift @@ -7,8 +7,7 @@ // import SceneKit -import QuartzCore -import QHull +import ConvexHull let NUMPOINTS = 64 let radius:Float = 5.0 @@ -16,95 +15,11 @@ let radius:Float = 5.0 class GameViewController: UIViewController { @IBOutlet weak var gameView: GameView! - var map:Map! + var map: Map! + var gameController: GameController! override func viewDidLoad() { - // create a new scene - let scene = SCNScene() - - - - let mapNode = SCNNode() - let elevationScale = 2.0; - for c in map.centers { - var points = [Vector3]() - if Float(c.elevation).isNormal{ - points.append(Vector3(Float(c.point.x), Float(c.point.y), Float(c.elevation * elevationScale))) - } - for edge in c.borders{ - if let v0 = edge.v0 , let v1 = edge.v1{ - if Float(v1.elevation).isNaN || Float(v0.elevation).isNaN || Float(v1.elevation).isInfinite || Float(v0.elevation).isInfinite{ - continue; - } - let vec1 = Vector3(Float(v0.point.x), Float(v0.point.y), Float(v0.elevation * elevationScale)) - let vec2 = Vector3(Float(v1.point.x), Float(v1.point.y), Float(v1.elevation * elevationScale)) - if vec1.z.isNaN || vec2.z.isNaN{ - continue; - } - points.append(vec1) - points.append(vec2) - } - - - } - let filtered = points.filter{$0.z != 0 && $0.z.isNormal} - - if filtered.count > 4{ - let iscosphere = MeshUtils.convexHullOfPoints(points) - mapNode.addChildNode(iscosphere) - } - // let region = voronoi.region(p); - } - scene.rootNode.addChildNode(mapNode) - - - - -// var points = [Vector3]() -// -// -// -// for i in 0..<50{ -// points.append(randomPointOnSphere() * radius/2) -// } -// -// -// -// let iscosphere = MeshUtils.convexHullOfPoints(points) -// scene.rootNode.addChildNode(iscosphere) - - - let sphere = SCNNode() - sphere.geometry = SCNSphere(radius: 1) - let mat = SCNMaterial() - mat.diffuse.contents = UIColor.red - sphere.geometry!.materials = [mat] - scene.rootNode.addChildNode(sphere); - -// // animate the 3d object -// let animation = CABasicAnimation(keyPath: "rotation") -// animation.toValue = NSValue(SCNVector4: SCNVector4(x: CGFloat(0), y: CGFloat(1), z: CGFloat(0), w: CGFloat(M_PI)*2)) -// animation.duration = 10 -// animation.repeatCount = MAXFLOAT //repeat forever -//// iscosphere.addAnimation(animation, forKey: nil) - - // set the scene to the view - self.gameView!.scene = scene - - // allows the user to manipulate the camera - self.gameView!.allowsCameraControl = true -// if let camera = scene.rootNode.camera{ -// camera.automaticallyAdjustsZRange = true -// } - // show statistics such as fps and timing information - self.gameView!.showsStatistics = true - self.gameView.autoenablesDefaultLighting = true - - - // configure the view -// self.gameView!.backgroundColor = UIColor.whiteColor() - - + self.gameController = GameController(scnView: gameView, map: map) } } diff --git a/Map Generator iOS/ViewController.swift b/Map Generator iOS/ViewController.swift index fedc297..d78515b 100644 --- a/Map Generator iOS/ViewController.swift +++ b/Map Generator iOS/ViewController.swift @@ -7,16 +7,21 @@ // import UIKit -import DelaunayiOS -class ViewController: UIViewController,UIScrollViewDelegate { - @IBOutlet var scrollView:UIScrollView! - var voronoiView:DelaunayView! - var map:Map! +import Delaunay + +class ViewController: UIViewController, UIScrollViewDelegate { + + @IBOutlet var scrollView: UIScrollView! + + private let size = 100 + + var voronoiView: DelaunayView! + + var map: Map! + override func viewDidLoad() { super.viewDidLoad() - let size = 1000 - self.map = Map(size:size, numPoints: size ,seed:1, varient: 1) - map.buildMap() + arc4random_stir() self.voronoiView = DelaunayView(frame: CGRect(x: 0, y: 0, width: CGFloat(size), height: CGFloat(size))) self.voronoiView.backgroundColor = UIColor.clear @@ -26,17 +31,21 @@ class ViewController: UIViewController,UIScrollViewDelegate { self.scrollView.minimumZoomScale = 0.01 self.scrollView.delegate = self - func converter(_ p:Point)->CGPoint{ - return CGPoint(x: p.x, y: p.y) - } - func cornerConverter(_ e:Corner)->CGPoint{ - return converter(e.point) - } + self.generateMap() + } + + private func generateMap() { + self.map = nil + self.voronoiView.positions = [] + self.voronoiView.regionPoints = [] + + self.map = Map(size: size, numPoints: size ,seed:Int.random(in: 0..<100), varient: 1) + map.buildMap() for c in map.centers { self.voronoiView.positions.append(converter(c.point)) - for edge in c.borders{ + for edge in c.borders { if edge.v0 != nil && edge.v1 != nil{ var borders = [CGPoint]() @@ -44,35 +53,33 @@ class ViewController: UIViewController,UIScrollViewDelegate { borders.append(converter(edge.v1.point)) self.voronoiView.regionPoints.append(borders) } - - } -// let region = voronoi.region(p); } - -// func siteToPoint(site:Site)->CGPoint{ -// return CGPoint(x:site.coord.x,y:site.coord.y) -// } -// for triangle in voronoi.triangles{ -// let points = triangle.sites.map(siteToPoint) -// self.voronoiView.triangles.append(points) -// -// } + self.voronoiView.setNeedsDisplay() + } + + + func converter(_ p:Point)->CGPoint{ + return CGPoint(x: p.x, y: p.y) + } + func cornerConverter(_ e:Corner)->CGPoint{ + return converter(e.point) } + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - - if let dest = segue.destination as? GameViewController{ + if let dest = segue.destination as? GameViewController { dest.map = self.map } - } - - public func viewForZooming(in scrollView: UIScrollView) -> UIView? { return self.voronoiView } + @IBAction private func onRefreshButtonPressed() { + self.generateMap() + } + } diff --git a/Map Generator.xcodeproj/project.pbxproj b/Map Generator.xcodeproj/project.pbxproj index 4a18f61..38de81b 100644 --- a/Map Generator.xcodeproj/project.pbxproj +++ b/Map Generator.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -13,12 +13,8 @@ 4650D17D1AF0331000602E94 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4650D1651AF0331000602E94 /* Map.swift */; }; 4650D1921AF0331000602E94 /* Watersheds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4650D1711AF0331000602E94 /* Watersheds.swift */; }; 4650D1931AF0331000602E94 /* Watersheds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4650D1711AF0331000602E94 /* Watersheds.swift */; }; - 4650D19F1AF033CC00602E94 /* QHull.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4650D19A1AF033B900602E94 /* QHull.framework */; }; - 4650D1A01AF033D100602E94 /* QHull.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4650D19A1AF033B900602E94 /* QHull.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4650D1A81AF0348200602E94 /* PerlinNoise.m in Sources */ = {isa = PBXBuildFile; fileRef = 4650D1A71AF0348200602E94 /* PerlinNoise.m */; }; 4650D1A91AF0348200602E94 /* PerlinNoise.m in Sources */ = {isa = PBXBuildFile; fileRef = 4650D1A71AF0348200602E94 /* PerlinNoise.m */; }; - 4650D1AF1AF034B600602E94 /* Vector3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4650D1AB1AF034B600602E94 /* Vector3.swift */; }; - 4650D1B01AF034B600602E94 /* Vector3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4650D1AB1AF034B600602E94 /* Vector3.swift */; }; 4650D1B11AF034B600602E94 /* Vertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4650D1AC1AF034B600602E94 /* Vertex.swift */; }; 4650D1B21AF034B600602E94 /* Vertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4650D1AC1AF034B600602E94 /* Vertex.swift */; }; 4650D1B31AF034B600602E94 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4650D1AD1AF034B600602E94 /* Utils.swift */; }; @@ -37,8 +33,6 @@ 468551391AE9DFF20002473E /* Edge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 468551381AE9DFF20002473E /* Edge.swift */; }; 4685513A1AE9DFF20002473E /* Edge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 468551381AE9DFF20002473E /* Edge.swift */; }; 46A1BBDF1AE8B012004E3E9D /* PM_PRNG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A1BBDE1AE8B012004E3E9D /* PM_PRNG.swift */; }; - 46CB2A421AE97A4A00B29FF7 /* Delaunay.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 46D73AE41AE979C900C92256 /* Delaunay.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 46CB2A431AE97A5100B29FF7 /* DelaunayiOS.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 46D73AE81AE979C900C92256 /* DelaunayiOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 46D739E61AE96AF000C92256 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D739E51AE96AF000C92256 /* ViewController.swift */; }; 46D739E91AE96C1800C92256 /* DelaunayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D739E81AE96C1800C92256 /* DelaunayView.swift */; }; 46D739F31AE971F700C92256 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D739F21AE971F700C92256 /* AppDelegate.swift */; }; @@ -49,37 +43,19 @@ 46D73A091AE971F800C92256 /* Map_Generator_iOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D73A081AE971F800C92256 /* Map_Generator_iOSTests.swift */; }; 46D73A111AE9721800C92256 /* DelaunayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D73A101AE9721800C92256 /* DelaunayView.swift */; }; 46D73A4F1AE9729B00C92256 /* PM_PRNG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A1BBDE1AE8B012004E3E9D /* PM_PRNG.swift */; }; - 46D73AED1AE979DA00C92256 /* DelaunayiOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 46D73AE81AE979C900C92256 /* DelaunayiOS.framework */; }; - 46D73AF01AE979ED00C92256 /* Delaunay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 46D73AE41AE979C900C92256 /* Delaunay.framework */; }; 46F5A6E51AE5FC200070D933 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46F5A6E41AE5FC200070D933 /* AppDelegate.swift */; }; - 46F5A6F01AE5FC210070D933 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 46F5A6EE1AE5FC210070D933 /* MainMenu.xib */; }; 46F5A6FC1AE5FC210070D933 /* Map_GeneratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46F5A6FB1AE5FC210070D933 /* Map_GeneratorTests.swift */; }; - 8F7D76381E1FF0F800E01879 /* QHull.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8F7D76351E1FF0F800E01879 /* QHull.framework */; }; - 8F7D76391E1FF0F800E01879 /* QHull.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8F7D76351E1FF0F800E01879 /* QHull.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + DB12E04D252933C3000770D0 /* Delaunay in Frameworks */ = {isa = PBXBuildFile; productRef = DB12E04C252933C3000770D0 /* Delaunay */; }; + DB12E052252933E6000770D0 /* ConvexHull in Frameworks */ = {isa = PBXBuildFile; productRef = DB12E051252933E6000770D0 /* ConvexHull */; }; + DB12E05E2529340F000770D0 /* Delaunay in Frameworks */ = {isa = PBXBuildFile; productRef = DB12E05D2529340F000770D0 /* Delaunay */; }; + DB12E0602529340F000770D0 /* ConvexHull in Frameworks */ = {isa = PBXBuildFile; productRef = DB12E05F2529340F000770D0 /* ConvexHull */; }; + DBC1A565252B934C001EC20F /* GameController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC1A564252B934C001EC20F /* GameController.swift */; }; + DBC1A566252B934C001EC20F /* GameController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC1A564252B934C001EC20F /* GameController.swift */; }; + DBC1A570252B946C001EC20F /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC1A56F252B946C001EC20F /* GameViewController.swift */; }; + DBC1A57E252B9D0F001EC20F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DBC1A57D252B9D0F001EC20F /* Main.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 4650D1991AF033B900602E94 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4650D1941AF033B800602E94 /* QHull.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 4650D1301AF032CB00602E94; - remoteInfo = QHull; - }; - 4650D19B1AF033B900602E94 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4650D1941AF033B800602E94 /* QHull.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 4650D13B1AF032CB00602E94; - remoteInfo = QHullTests; - }; - 4650D19D1AF033C900602E94 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4650D1941AF033B800602E94 /* QHull.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 4650D12F1AF032CB00602E94; - remoteInfo = QHull; - }; 46D73A031AE971F800C92256 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 46F5A6D71AE5FC200070D933 /* Project object */; @@ -87,48 +63,6 @@ remoteGlobalIDString = 46D739ED1AE971F700C92256; remoteInfo = "Map Generator iOS"; }; - 46D73AE31AE979C900C92256 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 46D73ADC1AE979C900C92256 /* Delaunay.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 46D73A5A1AE977FF00C92256; - remoteInfo = Delaunay; - }; - 46D73AE51AE979C900C92256 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 46D73ADC1AE979C900C92256 /* Delaunay.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 46D73A651AE977FF00C92256; - remoteInfo = DelaunayTests; - }; - 46D73AE71AE979C900C92256 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 46D73ADC1AE979C900C92256 /* Delaunay.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 46D73AAB1AE9784D00C92256; - remoteInfo = DelaunayiOS; - }; - 46D73AE91AE979C900C92256 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 46D73ADC1AE979C900C92256 /* Delaunay.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 46D73AB51AE9784D00C92256; - remoteInfo = DelaunayiOSTests; - }; - 46D73AEB1AE979D500C92256 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 46D73ADC1AE979C900C92256 /* Delaunay.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 46D73AAA1AE9784D00C92256; - remoteInfo = DelaunayiOS; - }; - 46D73AEE1AE979E900C92256 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 46D73ADC1AE979C900C92256 /* Delaunay.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 46D73A591AE977FF00C92256; - remoteInfo = Delaunay; - }; 46F5A6F61AE5FC210070D933 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 46F5A6D71AE5FC200070D933 /* Project object */; @@ -136,65 +70,14 @@ remoteGlobalIDString = 46F5A6DE1AE5FC200070D933; remoteInfo = "Map Generator"; }; - 8F7D76341E1FF0F800E01879 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4650D1941AF033B800602E94 /* QHull.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 8F7EA0221D9C3055008A0C74; - remoteInfo = "QHull-macOS"; - }; - 8F7D76361E1FF0F800E01879 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4650D1941AF033B800602E94 /* QHull.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 8F7EA02A1D9C3055008A0C74; - remoteInfo = "QHull-macOSTests"; - }; - 8F7D763A1E1FF0F800E01879 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4650D1941AF033B800602E94 /* QHull.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 8F7EA0211D9C3055008A0C74; - remoteInfo = "QHull-macOS"; - }; /* End PBXContainerItemProxy section */ -/* Begin PBXCopyFilesBuildPhase section */ - 46D73A331AE9725700C92256 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 4650D1A01AF033D100602E94 /* QHull.framework in Embed Frameworks */, - 46CB2A431AE97A5100B29FF7 /* DelaunayiOS.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; - 46F5A7261AE5FC4F0070D933 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 46CB2A421AE97A4A00B29FF7 /* Delaunay.framework in Embed Frameworks */, - 8F7D76391E1FF0F800E01879 /* QHull.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ 4650D1621AF0331000602E94 /* Lava.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Lava.swift; path = Shared/Lava.swift; sourceTree = ""; }; 4650D1651AF0331000602E94 /* Map.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Map.swift; path = Shared/Map.swift; sourceTree = ""; }; 4650D1711AF0331000602E94 /* Watersheds.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Watersheds.swift; path = Shared/Watersheds.swift; sourceTree = ""; }; - 4650D1941AF033B800602E94 /* QHull.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = QHull.xcodeproj; path = ThirdParty/QHull/QHull.xcodeproj; sourceTree = ""; }; - 4650D1A51AF0348100602E94 /* Map GeneratorBridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Map GeneratorBridging-Header.h"; sourceTree = ""; }; 4650D1A61AF0348200602E94 /* PerlinNoise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PerlinNoise.h; path = Shared/PerlinNoise.h; sourceTree = ""; }; 4650D1A71AF0348200602E94 /* PerlinNoise.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PerlinNoise.m; path = Shared/PerlinNoise.m; sourceTree = ""; }; - 4650D1AB1AF034B600602E94 /* Vector3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vector3.swift; sourceTree = ""; }; 4650D1AC1AF034B600602E94 /* Vertex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vertex.swift; sourceTree = ""; }; 4650D1AD1AF034B600602E94 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 4650D1AE1AF034B600602E94 /* MeshUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeshUtils.swift; sourceTree = ""; }; @@ -218,14 +101,16 @@ 46D73A071AE971F800C92256 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46D73A081AE971F800C92256 /* Map_Generator_iOSTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Map_Generator_iOSTests.swift; sourceTree = ""; }; 46D73A101AE9721800C92256 /* DelaunayView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DelaunayView.swift; sourceTree = ""; }; - 46D73ADC1AE979C900C92256 /* Delaunay.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Delaunay.xcodeproj; path = "ThirdParty/as3delaunay-Swift/Delaunay/Delaunay.xcodeproj"; sourceTree = SOURCE_ROOT; }; 46F5A6DF1AE5FC200070D933 /* Map Generator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Map Generator.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 46F5A6E31AE5FC200070D933 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46F5A6E41AE5FC200070D933 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 46F5A6EF1AE5FC210070D933 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 46F5A6F51AE5FC210070D933 /* Map GeneratorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Map GeneratorTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 46F5A6FA1AE5FC210070D933 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46F5A6FB1AE5FC210070D933 /* Map_GeneratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Map_GeneratorTests.swift; sourceTree = ""; }; + DB12E0852529393A000770D0 /* Map-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Map-Bridging-Header.h"; sourceTree = ""; }; + DBC1A564252B934C001EC20F /* GameController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameController.swift; sourceTree = ""; }; + DBC1A56F252B946C001EC20F /* GameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; }; + DBC1A57D252B9D0F001EC20F /* Main.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -233,8 +118,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 4650D19F1AF033CC00602E94 /* QHull.framework in Frameworks */, - 46D73AED1AE979DA00C92256 /* DelaunayiOS.framework in Frameworks */, + DB12E0602529340F000770D0 /* ConvexHull in Frameworks */, + DB12E05E2529340F000770D0 /* Delaunay in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -249,8 +134,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 46D73AF01AE979ED00C92256 /* Delaunay.framework in Frameworks */, - 8F7D76381E1FF0F800E01879 /* QHull.framework in Frameworks */, + DB12E04D252933C3000770D0 /* Delaunay in Frameworks */, + DB12E052252933E6000770D0 /* ConvexHull in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -272,7 +157,6 @@ 4650D1621AF0331000602E94 /* Lava.swift */, 4650D1651AF0331000602E94 /* Map.swift */, 4650D1711AF0331000602E94 /* Watersheds.swift */, - 4650D1A51AF0348100602E94 /* Map GeneratorBridging-Header.h */, ); name = Map; sourceTree = ""; @@ -286,29 +170,9 @@ name = tests; sourceTree = ""; }; - 4650D1191AF0325000602E94 /* QHull */ = { - isa = PBXGroup; - children = ( - 4650D1941AF033B800602E94 /* QHull.xcodeproj */, - ); - name = QHull; - sourceTree = ""; - }; - 4650D1951AF033B800602E94 /* Products */ = { - isa = PBXGroup; - children = ( - 4650D19A1AF033B900602E94 /* QHull.framework */, - 4650D19C1AF033B900602E94 /* QHullTests.xctest */, - 8F7D76351E1FF0F800E01879 /* QHull.framework */, - 8F7D76371E1FF0F800E01879 /* QHull-macOSTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; 4650D1AA1AF034A600602E94 /* Utils */ = { isa = PBXGroup; children = ( - 4650D1AB1AF034B600602E94 /* Vector3.swift */, 4650D1AC1AF034B600602E94 /* Vertex.swift */, 4650D1AD1AF034B600602E94 /* Utils.swift */, 4650D1AE1AF034B600602E94 /* MeshUtils.swift */, @@ -330,13 +194,13 @@ 468551221AE9DC6B0002473E /* Shared */ = { isa = PBXGroup; children = ( + DB12E0852529393A000770D0 /* Map-Bridging-Header.h */, 46A1BBDE1AE8B012004E3E9D /* PM_PRNG.swift */, 4650D1AA1AF034A600602E94 /* Utils */, - 4650D1191AF0325000602E94 /* QHull */, - 46D73ADC1AE979C900C92256 /* Delaunay.xcodeproj */, 4685512F1AE9DF2E0002473E /* Biome.swift */, 4685511D1AE9DBE00002473E /* Graph */, 460A83F81AEF22CB000CAAD3 /* Map */, + DBC1A564252B934C001EC20F /* GameController.swift */, ); name = Shared; sourceTree = ""; @@ -344,11 +208,11 @@ 46D739EF1AE971F700C92256 /* Map Generator iOS */ = { isa = PBXGroup; children = ( + 4650D1B81AF0357500602E94 /* GameViewController.swift */, 46D739F21AE971F700C92256 /* AppDelegate.swift */, 46D739F41AE971F700C92256 /* ViewController.swift */, 46D73A101AE9721800C92256 /* DelaunayView.swift */, 4650D1B71AF0357500602E94 /* GameView.swift */, - 4650D1B81AF0357500602E94 /* GameViewController.swift */, 46D739F61AE971F800C92256 /* Main.storyboard */, 46D739F91AE971F800C92256 /* Images.xcassets */, 46D739FB1AE971F800C92256 /* LaunchScreen.xib */, @@ -382,17 +246,6 @@ name = "Supporting Files"; sourceTree = ""; }; - 46D73ADD1AE979C900C92256 /* Products */ = { - isa = PBXGroup; - children = ( - 46D73AE41AE979C900C92256 /* Delaunay.framework */, - 46D73AE61AE979C900C92256 /* DelaunayTests.xctest */, - 46D73AE81AE979C900C92256 /* DelaunayiOS.framework */, - 46D73AEA1AE979C900C92256 /* DelaunayiOSTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; 46F5A6D61AE5FC200070D933 = { isa = PBXGroup; children = ( @@ -401,6 +254,7 @@ 46D739EF1AE971F700C92256 /* Map Generator iOS */, 4650D1181AF0324000602E94 /* tests */, 46F5A6E01AE5FC200070D933 /* Products */, + DB12E05C2529340F000770D0 /* Frameworks */, ); sourceTree = ""; }; @@ -421,8 +275,9 @@ 46F5A6E41AE5FC200070D933 /* AppDelegate.swift */, 46D739E51AE96AF000C92256 /* ViewController.swift */, 46D739E81AE96C1800C92256 /* DelaunayView.swift */, - 46F5A6EE1AE5FC210070D933 /* MainMenu.xib */, 46F5A6E21AE5FC200070D933 /* Supporting Files */, + DBC1A56F252B946C001EC20F /* GameViewController.swift */, + DBC1A57D252B9D0F001EC20F /* Main.storyboard */, ); path = "Map Generator"; sourceTree = ""; @@ -452,6 +307,13 @@ name = "Supporting Files"; sourceTree = ""; }; + DB12E05C2529340F000770D0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -462,15 +324,16 @@ 46D739EA1AE971F700C92256 /* Sources */, 46D739EB1AE971F700C92256 /* Frameworks */, 46D739EC1AE971F700C92256 /* Resources */, - 46D73A331AE9725700C92256 /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( - 4650D19E1AF033C900602E94 /* PBXTargetDependency */, - 46D73AEC1AE979D500C92256 /* PBXTargetDependency */, ); name = "Map Generator iOS"; + packageProductDependencies = ( + DB12E05D2529340F000770D0 /* Delaunay */, + DB12E05F2529340F000770D0 /* ConvexHull */, + ); productName = "Map Generator iOS"; productReference = 46D739EE1AE971F700C92256 /* Map Generator iOS.app */; productType = "com.apple.product-type.application"; @@ -500,15 +363,16 @@ 46F5A6DB1AE5FC200070D933 /* Sources */, 46F5A6DC1AE5FC200070D933 /* Frameworks */, 46F5A6DD1AE5FC200070D933 /* Resources */, - 46F5A7261AE5FC4F0070D933 /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( - 46D73AEF1AE979E900C92256 /* PBXTargetDependency */, - 8F7D763B1E1FF0F800E01879 /* PBXTargetDependency */, ); name = "Map Generator"; + packageProductDependencies = ( + DB12E04C252933C3000770D0 /* Delaunay */, + DB12E051252933E6000770D0 /* ConvexHull */, + ); productName = "Map Generator"; productReference = 46F5A6DF1AE5FC200070D933 /* Map Generator.app */; productType = "com.apple.product-type.application"; @@ -566,22 +430,17 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); mainGroup = 46F5A6D61AE5FC200070D933; + packageReferences = ( + DB12E04B252933C3000770D0 /* XCRemoteSwiftPackageReference "as3delaunay-Swift" */, + DB12E050252933E6000770D0 /* XCRemoteSwiftPackageReference "SConvexHull" */, + ); productRefGroup = 46F5A6E01AE5FC200070D933 /* Products */; projectDirPath = ""; - projectReferences = ( - { - ProductGroup = 46D73ADD1AE979C900C92256 /* Products */; - ProjectRef = 46D73ADC1AE979C900C92256 /* Delaunay.xcodeproj */; - }, - { - ProductGroup = 4650D1951AF033B800602E94 /* Products */; - ProjectRef = 4650D1941AF033B800602E94 /* QHull.xcodeproj */; - }, - ); projectRoot = ""; targets = ( 46F5A6DE1AE5FC200070D933 /* Map Generator */, @@ -592,65 +451,6 @@ }; /* End PBXProject section */ -/* Begin PBXReferenceProxy section */ - 4650D19A1AF033B900602E94 /* QHull.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = QHull.framework; - remoteRef = 4650D1991AF033B900602E94 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 4650D19C1AF033B900602E94 /* QHullTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = QHullTests.xctest; - remoteRef = 4650D19B1AF033B900602E94 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 46D73AE41AE979C900C92256 /* Delaunay.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = Delaunay.framework; - remoteRef = 46D73AE31AE979C900C92256 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 46D73AE61AE979C900C92256 /* DelaunayTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = DelaunayTests.xctest; - remoteRef = 46D73AE51AE979C900C92256 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 46D73AE81AE979C900C92256 /* DelaunayiOS.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = DelaunayiOS.framework; - remoteRef = 46D73AE71AE979C900C92256 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 46D73AEA1AE979C900C92256 /* DelaunayiOSTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = DelaunayiOSTests.xctest; - remoteRef = 46D73AE91AE979C900C92256 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 8F7D76351E1FF0F800E01879 /* QHull.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = QHull.framework; - remoteRef = 8F7D76341E1FF0F800E01879 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 8F7D76371E1FF0F800E01879 /* QHull-macOSTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = "QHull-macOSTests.xctest"; - remoteRef = 8F7D76361E1FF0F800E01879 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - /* Begin PBXResourcesBuildPhase section */ 46D739EC1AE971F700C92256 /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -673,7 +473,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 46F5A6F01AE5FC210070D933 /* MainMenu.xib in Resources */, + DBC1A57E252B9D0F001EC20F /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -704,10 +504,10 @@ 4650D1B61AF034B600602E94 /* MeshUtils.swift in Sources */, 46D739F51AE971F700C92256 /* ViewController.swift in Sources */, 4650D17D1AF0331000602E94 /* Map.swift in Sources */, + DBC1A566252B934C001EC20F /* GameController.swift in Sources */, 4650D1931AF0331000602E94 /* Watersheds.swift in Sources */, 46D739F31AE971F700C92256 /* AppDelegate.swift in Sources */, 46D73A4F1AE9729B00C92256 /* PM_PRNG.swift in Sources */, - 4650D1B01AF034B600602E94 /* Vector3.swift in Sources */, 4685513A1AE9DFF20002473E /* Edge.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -728,10 +528,12 @@ 468551361AE9DFE90002473E /* Corner.swift in Sources */, 468551301AE9DF2E0002473E /* Biome.swift in Sources */, 4685512D1AE9DF280002473E /* Center.swift in Sources */, + DBC1A570252B946C001EC20F /* GameViewController.swift in Sources */, 46D739E61AE96AF000C92256 /* ViewController.swift in Sources */, 4650D1B91AF0357500602E94 /* GameView.swift in Sources */, 4650D1B31AF034B600602E94 /* Utils.swift in Sources */, 4650D1B11AF034B600602E94 /* Vertex.swift in Sources */, + DBC1A565252B934C001EC20F /* GameController.swift in Sources */, 4650D1921AF0331000602E94 /* Watersheds.swift in Sources */, 4650D1B51AF034B600602E94 /* MeshUtils.swift in Sources */, 46F5A6E51AE5FC200070D933 /* AppDelegate.swift in Sources */, @@ -739,7 +541,6 @@ 4650D17C1AF0331000602E94 /* Map.swift in Sources */, 4650D17A1AF0331000602E94 /* Lava.swift in Sources */, 46D739E91AE96C1800C92256 /* DelaunayView.swift in Sources */, - 4650D1AF1AF034B600602E94 /* Vector3.swift in Sources */, 468551391AE9DFF20002473E /* Edge.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -755,36 +556,16 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 4650D19E1AF033C900602E94 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = QHull; - targetProxy = 4650D19D1AF033C900602E94 /* PBXContainerItemProxy */; - }; 46D73A041AE971F800C92256 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 46D739ED1AE971F700C92256 /* Map Generator iOS */; targetProxy = 46D73A031AE971F800C92256 /* PBXContainerItemProxy */; }; - 46D73AEC1AE979D500C92256 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = DelaunayiOS; - targetProxy = 46D73AEB1AE979D500C92256 /* PBXContainerItemProxy */; - }; - 46D73AEF1AE979E900C92256 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = Delaunay; - targetProxy = 46D73AEE1AE979E900C92256 /* PBXContainerItemProxy */; - }; 46F5A6F71AE5FC210070D933 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 46F5A6DE1AE5FC200070D933 /* Map Generator */; targetProxy = 46F5A6F61AE5FC210070D933 /* PBXContainerItemProxy */; }; - 8F7D763B1E1FF0F800E01879 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "QHull-macOS"; - targetProxy = 8F7D763A1E1FF0F800E01879 /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -804,14 +585,6 @@ name = LaunchScreen.xib; sourceTree = ""; }; - 46F5A6EE1AE5FC210070D933 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 46F5A6EF1AE5FC210070D933 /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; - }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -828,14 +601,17 @@ "$(inherited)", ); INFOPLIST_FILE = "Map Generator iOS/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 8.3; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.balanceoni.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; - SWIFT_OBJC_BRIDGING_HEADER = "Map Generator iOS-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "Map-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -848,13 +624,16 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = "Map Generator iOS/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 8.3; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.balanceoni.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; - SWIFT_OBJC_BRIDGING_HEADER = "Map Generator iOS-Bridging-Header.h"; - SWIFT_VERSION = 3.0; + SWIFT_OBJC_BRIDGING_HEADER = "Map-Bridging-Header.h"; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -876,7 +655,11 @@ ); INFOPLIST_FILE = "Map Generator iOSTests/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.3; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.balanceoni.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -896,7 +679,11 @@ ); INFOPLIST_FILE = "Map Generator iOSTests/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.3; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.balanceoni.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -988,40 +775,47 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Release; }; 46F5A7001AE5FC210070D933 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = "Map Generator/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = "com.balanceoni.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Map GeneratorBridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "Map-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; 46F5A7011AE5FC210070D933 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = "Map Generator/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = "com.balanceoni.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Map GeneratorBridging-Header.h"; - SWIFT_VERSION = 3.0; + SWIFT_OBJC_BRIDGING_HEADER = "Map-Bridging-Header.h"; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -1039,7 +833,11 @@ "$(inherited)", ); INFOPLIST_FILE = "Map GeneratorTests/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.balanceoni.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; @@ -1057,7 +855,11 @@ "$(inherited)", ); INFOPLIST_FILE = "Map GeneratorTests/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.balanceoni.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 3.0; @@ -1114,6 +916,48 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + DB12E04B252933C3000770D0 /* XCRemoteSwiftPackageReference "as3delaunay-Swift" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SpectralDragon/as3delaunay-Swift.git"; + requirement = { + branch = master; + kind = branch; + }; + }; + DB12E050252933E6000770D0 /* XCRemoteSwiftPackageReference "SConvexHull" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SpectralDragon/SConvexHull.git"; + requirement = { + branch = develop; + kind = branch; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + DB12E04C252933C3000770D0 /* Delaunay */ = { + isa = XCSwiftPackageProductDependency; + package = DB12E04B252933C3000770D0 /* XCRemoteSwiftPackageReference "as3delaunay-Swift" */; + productName = Delaunay; + }; + DB12E051252933E6000770D0 /* ConvexHull */ = { + isa = XCSwiftPackageProductDependency; + package = DB12E050252933E6000770D0 /* XCRemoteSwiftPackageReference "SConvexHull" */; + productName = ConvexHull; + }; + DB12E05D2529340F000770D0 /* Delaunay */ = { + isa = XCSwiftPackageProductDependency; + package = DB12E04B252933C3000770D0 /* XCRemoteSwiftPackageReference "as3delaunay-Swift" */; + productName = Delaunay; + }; + DB12E05F2529340F000770D0 /* ConvexHull */ = { + isa = XCSwiftPackageProductDependency; + package = DB12E050252933E6000770D0 /* XCRemoteSwiftPackageReference "SConvexHull" */; + productName = ConvexHull; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 46F5A6D71AE5FC200070D933 /* Project object */; } diff --git a/Map Generator/AppDelegate.swift b/Map Generator/AppDelegate.swift index 778d1de..8d39ebc 100644 --- a/Map Generator/AppDelegate.swift +++ b/Map Generator/AppDelegate.swift @@ -7,7 +7,6 @@ // import Cocoa -import Delaunay @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { diff --git a/Map Generator/Base.lproj/MainMenu.xib b/Map Generator/Base.lproj/MainMenu.xib deleted file mode 100644 index 344fedf..0000000 --- a/Map Generator/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,673 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Map Generator/Center.swift b/Map Generator/Center.swift index d5013ef..b611e6f 100644 --- a/Map Generator/Center.swift +++ b/Map Generator/Center.swift @@ -7,22 +7,18 @@ // import Foundation -#if os(iOS) - import DelaunayiOS - #elseif os(OSX) - import Delaunay -#endif +import Delaunay -open class Center{ - open var index:Int = 0 - open var point:Point! - open var water:Bool = false - open var ocean:Bool = false - open var coast:Bool = false - open var border:Bool = false +open class Center { + open var index: Int = 0 + open var point: Point! + open var water: Bool = false + open var ocean: Bool = false + open var coast: Bool = false + open var border: Bool = false open var biome = Biome.grassland - open var elevation:Double = 0 - open var moisture:Double = 0 + open var elevation: Double = 0 + open var moisture: Double = 0 open var neighbors = [Center]() open var borders = [Edge]() diff --git a/Map Generator/Corner.swift b/Map Generator/Corner.swift index a61725c..ebf0849 100644 --- a/Map Generator/Corner.swift +++ b/Map Generator/Corner.swift @@ -7,30 +7,26 @@ // import Foundation -#if os(iOS) - import DelaunayiOS - #elseif os(OSX) - import Delaunay -#endif +import Delaunay public final class Corner { - final var index:Int = 0; + final var index: Int = 0 - final var point:Point!; // location - final var ocean = false; // ocean - final var water = false; // lake or ocean - final var coast = false; // touches ocean and land polygons - final var border = false; // at the edge of the map - final var elevation:Double = 0; // 0.0-1.0 - final var moisture:Double = 0; // 0.0-1.0 + final var point: Point! // location + final var ocean = false // ocean + final var water = false // lake or ocean + final var coast = false // touches ocean and land polygons + final var border = false // at the edge of the map + final var elevation: Double = 0 // 0.0-1.0 + final var moisture: Double = 0 // 0.0-1.0 - final var touches = [Center](); - final var protrudes = [Edge](); - final var adjacent = [Corner](); + final var touches = [Center]() + final var protrudes = [Edge]() + final var adjacent = [Corner]() - final var river:Int = 0; // 0 if no river, or volume of water in river - final var downslope:Corner!; // pointer to adjacent corner most downhill - final var watershed:Corner!; // pointer to coastal corner, or null - final var watershed_size:Int = 0; + final var river: Int = 0 // 0 if no river, or volume of water in river + final var downslope: Corner! // pointer to adjacent corner most downhill + final var watershed: Corner! // pointer to coastal corner, or null + final var watershed_size: Int = 0 } diff --git a/Map Generator/DelaunayView.swift b/Map Generator/DelaunayView.swift index 01630fa..d012117 100644 --- a/Map Generator/DelaunayView.swift +++ b/Map Generator/DelaunayView.swift @@ -16,12 +16,14 @@ class DelaunayView: NSView { override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) - let context = NSGraphicsContext.current()!.cgContext + + guard let context = NSGraphicsContext.current?.cgContext else { return } + pointColor.setFill() for p in positions{ context.fillEllipse(in: DelaunayView.rectForPoint(p)) } - for region in regionPoints{ + for region in regionPoints { lineColor.set() if region.count > 2{ context.addLines(between: region) @@ -30,8 +32,8 @@ class DelaunayView: NSView { } } - static let radius:CGFloat = 5; - static func rectForPoint(_ point:CGPoint)->CGRect{ + static let radius:CGFloat = 5 + static func rectForPoint(_ point: CGPoint) -> CGRect { return CGRect(x: point.x - radius, y: point.y, width: 2 * radius, height: 2 * radius) } } diff --git a/Map Generator/Edge.swift b/Map Generator/Edge.swift index f9de59e..18d415c 100644 --- a/Map Generator/Edge.swift +++ b/Map Generator/Edge.swift @@ -7,17 +7,12 @@ // import Foundation - -#if os(iOS) - import DelaunayiOS - #elseif os(OSX) - import Delaunay -#endif +import Delaunay open class Edge { - open var index:Int = 0; - open var d0:Center!, d1:Center!; // Delaunay edge - open var v0:Corner!, v1:Corner!; // Voronoi edge - open var midpoint:Point!; // halfway between v0,v1 - open var river:Int = 0; // volume of water, or 0 + open var index: Int = 0 + open var d0: Center!, d1: Center! // Delaunay edge + open var v0: Corner!, v1: Corner! // Voronoi edge + open var midpoint: Point! // halfway between v0,v1 + open var river: Int = 0 // volume of water, or 0 } diff --git a/Map Generator/GameViewController.swift b/Map Generator/GameViewController.swift new file mode 100644 index 0000000..f4cc8db --- /dev/null +++ b/Map Generator/GameViewController.swift @@ -0,0 +1,22 @@ +// +// GameViewController.swift +// Map Generator +// +// Created by v.prusakov on 10/5/20. +// Copyright © 2020 Carl Wieland. All rights reserved. +// + +import AppKit +import SceneKit + +class GameViewController: NSViewController { + + @IBOutlet weak var scnGameView: SCNView! + var map: Map! + var gameController: GameController! + + override func viewDidLoad() { + self.gameController = GameController(scnView: scnGameView, map: map) + } + +} diff --git a/Map Generator/Info.plist b/Map Generator/Info.plist index c9a544b..23fc2fb 100644 --- a/Map Generator/Info.plist +++ b/Map Generator/Info.plist @@ -26,8 +26,8 @@ $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright Copyright © 2015 Carl Wieland. All rights reserved. - NSMainNibFile - MainMenu + NSMainStoryboardFile + Main NSPrincipalClass NSApplication diff --git a/Map Generator/Main.storyboard b/Map Generator/Main.storyboard new file mode 100644 index 0000000..04be643 --- /dev/null +++ b/Map Generator/Main.storyboard @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Map Generator/ViewController.swift b/Map Generator/ViewController.swift index 0267bf4..57641b9 100644 --- a/Map Generator/ViewController.swift +++ b/Map Generator/ViewController.swift @@ -8,36 +8,59 @@ import Cocoa import Delaunay +import ConvexHull class ViewController: NSViewController { - + + @IBOutlet weak var stackView: NSStackView! + @IBOutlet weak var scrollView: NSScrollView! var voronoiView: DelaunayView! + var map: Map! + override func viewDidLoad() { super.viewDidLoad() - // Insert code here to initialize your application - let relaxed = generateRelaxed(2000, seed: 412342) - let points = relaxed(1000) - let voronoi = Voronoi(points: points, colors: nil, plotBounds: Rectangle(x: 0, y: 0, width: 2000, height: 2000)); self.voronoiView = DelaunayView(frame: CGRect(x: 0, y: 0, width: 3000, height: 3000)) - let scrollView = NSScrollView(frame:self.view.frame); - scrollView.documentView = self.voronoiView - scrollView.contentView.translatesAutoresizingMaskIntoConstraints = true - scrollView.translatesAutoresizingMaskIntoConstraints = true - self.view.addSubview(scrollView) - self.view.translatesAutoresizingMaskIntoConstraints = true - func converter(_ p:Point)->CGPoint{ - return CGPoint(x: p.x, y: p.y) - } + self.scrollView.documentView = self.voronoiView - for p in points { - self.voronoiView.positions.append(converter(p)) - let region = voronoi.region(p); - self.voronoiView.regionPoints.append(region.map(converter)) - - } + self.generateMap() + } + func converter(_ p:Point)->CGPoint{ + return CGPoint(x: p.x, y: p.y) } + private func generateMap() { + self.map = nil + self.voronoiView.positions = [] + self.voronoiView.regionPoints = [] + + // Insert code here to initialize your application + let size = 1000 + + self.map = Map(size: size, numPoints: size, seed: Int.random(in: 0..<100), varient: 1) + map.buildMap() + + for c in map.centers { + self.voronoiView.positions.append(converter(c.point)) + + for edge in c.borders { + + if edge.v0 != nil && edge.v1 != nil{ + var borders = [CGPoint]() + borders.append(converter(edge.v0.point)) + borders.append(converter(edge.v1.point)) + self.voronoiView.regionPoints.append(borders) + } + } + } + + self.voronoiView.setNeedsDisplay(self.voronoiView.bounds) + } + + override func prepare(for segue: NSStoryboardSegue, sender: Any?) { + guard let vc = segue.destinationController as? GameViewController else { return } + vc.map = map + } // Generate points at random locations @@ -56,6 +79,10 @@ class ViewController: NSViewController { return generator } + @IBAction func onRefreshButtonPressed(_ sender: Any) { + self.generateMap() + } + func generateRelaxed(_ size:Int, seed:Int)->(Int)->[Point]{ func relaxedGenerator(_ numPoints:Int)->[Point]{ diff --git a/Map GeneratorBridging-Header.h b/Map GeneratorBridging-Header.h deleted file mode 100644 index e9ed563..0000000 --- a/Map GeneratorBridging-Header.h +++ /dev/null @@ -1,5 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - -#import "PerlinNoise.h" \ No newline at end of file diff --git a/Map-Bridging-Header.h b/Map-Bridging-Header.h new file mode 100644 index 0000000..b2e0fd5 --- /dev/null +++ b/Map-Bridging-Header.h @@ -0,0 +1,16 @@ +// +// Map-Bridging-Header.h +// Map Generator +// +// Created by v.prusakov on 10/4/20. +// Copyright © 2020 Carl Wieland. All rights reserved. +// + +#ifndef Map_Bridging_Header_h +#define Map_Bridging_Header_h + + +#import "PerlinNoise.h" + +#endif /* Map_Bridging_Header_h */ + diff --git a/MeshUtils.swift b/MeshUtils.swift index 7174081..0c7688b 100644 --- a/MeshUtils.swift +++ b/MeshUtils.swift @@ -8,43 +8,27 @@ import Foundation import SceneKit -import QHull +import ConvexHull -class MeshUtils{ +class MeshUtils { - static func convexHullOfPoints(_ points:[Vector3])->SCNNode{ - var p3s = [Point3d](); - for p in points{ - p3s.append(p.toPoint3d()) - } - - let hull = QuickHull3D(); - hull.build (p3s); - hull.triangulate() -// println ("Vertices:"); - let vertices = hull.getVertices() -// for i in 0.. SCNNode { + let hull = ConvexHull.create(with: points, planeDistanceTolerance: 2) - var triangles = [CInt](); + var triangles = [Int32]() var verts = [Vertex]() - let faceIndices = hull.getFaces(); + let faceIndices = hull.faces - var cur:CInt = 0; - for i in 0..SCNGeometry{ - let data = Data(bytes: vertices, count: vertices.count * MemoryLayout.size) - let vertexSource = SCNGeometrySource(data: data, - semantic: SCNGeometrySource.Semantic.vertex, - vectorCount: vertices.count, - usesFloatComponents: true, - componentsPerVector: 3, - bytesPerComponent: MemoryLayout.size, - dataOffset: 0, // position is first member in Vertex - dataStride: MemoryLayout.size) - - let normalSource = SCNGeometrySource(data: data, - semantic: SCNGeometrySource.Semantic.normal, - vectorCount: vertices.count, - usesFloatComponents: true, - componentsPerVector: 3, - bytesPerComponent: MemoryLayout.size, - dataOffset: MemoryLayout.size, // one Float3 before normal in Vertex - dataStride: MemoryLayout.size) +func createGeometry(_ vertices: [Vertex], triangles:[Int32]) -> SCNGeometry { + let vertexSource = SCNGeometrySource(vertices: vertices.map { SCNVector3($0.position.simdVector) }) + let normalSource = SCNGeometrySource(normals: vertices.map { SCNVector3($0.normal.simdVector) }) - let colorSource = SCNGeometrySource(data: data, - semantic: SCNGeometrySource.Semantic.color, - vectorCount: vertices.count, - usesFloatComponents: true, - componentsPerVector: 3, - bytesPerComponent: MemoryLayout.size, - dataOffset: 2 * MemoryLayout.size , // 2 Float3s before tcoord in Vertex - dataStride: MemoryLayout.size) + let colors = vertices.map { SCNVector3($0.color.simdVector) } + let colorData = Data(bytes: colors, count: MemoryLayout.size * colors.count) + let colorSource = SCNGeometrySource(data: colorData, semantic: .color, vectorCount: colors.count, usesFloatComponents: true, componentsPerVector: 3, bytesPerComponent: MemoryLayout.size, dataOffset: 0, dataStride: MemoryLayout.size) - let triData = Data(bytes: triangles, count: MemoryLayout.size*triangles.count) + let triData = Data(bytes: triangles, count: MemoryLayout.size*triangles.count) - let geometryElement = SCNGeometryElement(data: triData, primitiveType: .triangles , primitiveCount:vertices.count/3 , bytesPerIndex: MemoryLayout.size) + let geometryElement = SCNGeometryElement(data: triData, primitiveType: .triangles, primitiveCount:vertices.count / 3 , bytesPerIndex: MemoryLayout.size) - return SCNGeometry(sources: [vertexSource,normalSource,colorSource], elements: [geometryElement]) -} - - -extension Vector3d{ - func toVector3()->Vector3{ - return Vector3(Float(x),Float(y),Float(z)) - } -} - -extension Vector3{ - func toPoint3d()->Point3d{ - return Point3d(x: Double(x), y: Double(y), z: Double(z)) - } + return SCNGeometry(sources: [vertexSource, normalSource, colorSource], elements: [geometryElement]) } diff --git a/Shared/Lava.swift b/Shared/Lava.swift index 3e1b46e..d554abc 100644 --- a/Shared/Lava.swift +++ b/Shared/Lava.swift @@ -7,23 +7,19 @@ // import Foundation -#if os(iOS) - import DelaunayiOS -#elseif os(OSX) - import Delaunay -#endif +import Delaunay -class Lava{ +class Lava { static let kLavaProbability = 0.2 var lava = [Int:Bool]() - func createLava(_ map:Map, randomDouble:()->Double){ - for edge in map.edges{ + func createLava(_ map: Map, randomDouble: () -> Double) { + for edge in map.edges { if edge.river != 0 && edge.d0.water && edge.d1.water && edge.d0.elevation > 0.8 && edge.d1.elevation > 0.8 && edge.d0.moisture < 0.3 && edge.d1.moisture < 0.3 - && randomDouble() < Lava.kLavaProbability{ - lava[edge.index] = true; + && randomDouble() < Lava.kLavaProbability { + lava[edge.index] = true } } } diff --git a/Shared/Map.swift b/Shared/Map.swift index a70d94b..998e006 100644 --- a/Shared/Map.swift +++ b/Shared/Map.swift @@ -7,49 +7,45 @@ // import Foundation +import Delaunay -#if os(iOS) - import DelaunayiOS - #elseif os(OSX) - import Delaunay -#endif - -class Map{ +class Map { - static let LAKE_THRESHOLD = 0.3; // 0 to 1, fraction of water corners for water polygon + static let LAKE_THRESHOLD = 0.3 // 0 to 1, fraction of water corners for water polygon // Passed in by the caller: - var Size:Double; - + var size: Double + // Island shape is controlled by the islandRandom seed and the // type of island, passed in when we set the island shape. The // islandShape function uses both of them to determine whether any // point should be water or land. - var mapShape:(_ q:Point)->Bool; + var mapShape: (_ q: Point) -> Bool // Island details are controlled by this random generator. The // initial map upon loading is always deterministic, but // subsequent maps reset this random number generator with a // random seed. - var mapRandom:PM_PRNG = PM_PRNG(); - + var mapRandom: PM_PRNG = PM_PRNG() + // Point selection is random for the original article, with Lloyd // Relaxation, but there are other ways of choosing points. Grids // in particular can be much simpler to start with, because you // don't need Voronoi at all. HOWEVER for ease of implementation, // I continue to use Voronoi here, to reuse the graph building // code. If you're using a grid, generate the graph directly. - var pointSelector:(_ numPoints:Int)->[Point]; - var numPoints:Int; + var pointSelector: (_ numPoints: Int) -> [Point] + var numPoints: Int - var points = [Point](); // Only useful during map construction - var centers = [Center](); + var points = [Point]() // Only useful during map construction + var centers = [Center]() var corners = [Corner]() var edges = [Edge]() var seed:Int - init(size:Int, numPoints:Int, seed:Int, varient:Int){ - Size = Double(size) + + init(size: Int, numPoints: Int, seed: Int, varient: Int){ + self.size = Double(size) self.numPoints = numPoints self.seed = seed pointSelector = Map.generateRelaxed(size, seed: seed) @@ -66,11 +62,11 @@ class Map{ } typealias StageStep = () -> Void - + func buildMap(){ var stages = [(String,StageStep)]() // Generate the initial random set of points - stages.append(("Placing Points...",{()->Void in + stages.append(("Placing Points...", { self.reset() self.points = self.pointSelector(self.numPoints) })) @@ -82,22 +78,22 @@ class Map{ // Voronoi polygons, a reverse map from those four points back // to the edge, a map from these four points to the points // they connect to (both along the edge and crosswise). - stages.append(("Building Graph...",{()->Void in - let voronoi = Voronoi(points: self.points, colors: nil, plotBounds: Rectangle(x: 0, y: 0, width: Double(self.Size),height: Double(self.Size))); - self.buildGraph(self.points, voronoi: voronoi); - self.improveCorners(); - voronoi.dispose(); + stages.append(("Building Graph...", { + let voronoi = Voronoi(points: self.points, colors: nil, plotBounds: Rectangle(x: 0, y: 0, width: self.size, height: self.size)) + self.buildGraph(self.points, voronoi: voronoi) + self.improveCorners() + voronoi.dispose() self.points.removeAll(keepingCapacity: true) - })); + })) - stages.append(("Assign Elevations...",{()->Void in - + stages.append(("Assign Elevations...", { + // Determine the elevations and water at Voronoi corners. - self.assignCornerElevations(); + self.assignCornerElevations() // Determine polygon and corner type: ocean, coast, land. - self.assignOceanCoastAndLand(); - + self.assignOceanCoastAndLand() + // Rescale elevations so that the highest is 1.0, and they're // distributed well. We want lower elevations to be more common // than higher elevations, in proportions approximately matching @@ -106,136 +102,124 @@ class Map{ // land area than the highest elevation, which is the very // center of a perfectly circular island. var landCorners = self.landCorners(self.corners) - self.redistributeElevations(&landCorners); + self.redistributeElevations(&landCorners) -// // Assign elevations to non-land corners -// for q in self.corners { -// if (q.ocean || q.coast) { -// q.elevation = 0.0; -// } -// } + // // Assign elevations to non-land corners + // for q in self.corners { + // if (q.ocean || q.coast) { + // q.elevation = 0.0 + // } + // } // Polygon elevations are the average of their corners - self.assignPolygonElevations(); - })); - - - - + self.assignPolygonElevations() + })) - stages.append(("Assign Moisture...",{()->Void in + stages.append(("Assign Moisture...", { // Determine downslope paths. - self.calculateDownslopes(); + self.calculateDownslopes() // Determine watersheds: for every corner, where does it flow // out into the ocean? - self.calculateWatersheds(); + self.calculateWatersheds() // Create rivers. - self.createRivers(); + self.createRivers() // Determine moisture at corners, starting at rivers // and lakes, but not oceans. Then redistribute // moisture to cover the entire range evenly from 0.0 // to 1.0. Then assign polygon moisture as the average // of the corner moisture. - self.assignCornerMoisture(); + self.assignCornerMoisture() var landCorners = self.landCorners(self.corners) - self.redistributeMoisture(&landCorners); - self.assignPolygonMoisture(); - })); + self.redistributeMoisture(&landCorners) + self.assignPolygonMoisture() + })) - stages.append(("Decorate Map...",{()->Void in - self.assignBiomes(); - })); - + stages.append(("Decorate Map...", { + self.assignBiomes() + })) - func timeIt(_ name:String, step:StageStep){ + func timeIt(_ name: String, step: StageStep) { print("Starting \(name)") - let start = Date() + + let start = CFAbsoluteTimeGetCurrent() step() - let end = Date(); - let timeInterval: Double = end.timeIntervalSince(start); // <<<<< Difference in seconds (double) + let end = CFAbsoluteTimeGetCurrent() + let timeInterval = end - start // <<<<< Difference in seconds (double) print("Finished... \(timeInterval)") } for (name, stage) in stages { - timeIt(name, step: stage); + timeIt(name, step: stage) } } // Assign a biome type to each polygon. If it has - // ocean/coast/water, then that's the biome; otherwise it depends + // ocean/coast/water, then that's the biome otherwise it depends // on low/high elevation and low/medium/high moisture. This is // roughly based on the Whittaker diagram but adapted to fit the // needs of the island map generator. - static func getBiome(_ p:Center)->Biome { + static func getBiome(_ p: Center) -> Biome { if (p.ocean) { - return .ocean; - } - else if (p.water) { - if (p.elevation < 0.1){ return .marsh}; - if (p.elevation > 0.8){return .ice}; - return .lake; - } - else if (p.coast) { - return .beach; - } - else if (p.elevation > 0.8) { + return .ocean + } else if (p.water) { + if (p.elevation < 0.1) { return .marsh } + if (p.elevation > 0.8) { return .ice } + + return .lake + } else if (p.coast) { + return .beach + } else if (p.elevation > 0.8) { if (p.moisture > 0.50){ return .snow} else if (p.moisture > 0.33){return .tundra} else if (p.moisture > 0.16){return .bare} - return Biome.scorched; - - } - else if (p.elevation > 0.6) { - if (p.moisture > 0.66){ return Biome.taiga} - else if (p.moisture > 0.33){ return .shrubland} - else{ return .temperateDesert} - } - else if (p.elevation > 0.3) { - if (p.moisture > 0.83) {return Biome.temperateRainForest} - else if (p.moisture > 0.50) {return Biome.temperateDeciduousForest} - else if (p.moisture > 0.16){return .grassland}; - return .temperateDesert; + return Biome.scorched + } else if (p.elevation > 0.6) { + if (p.moisture > 0.66) { return .taiga } + else if (p.moisture > 0.33) { return .shrubland } + else { return .temperateDesert } + } else if (p.elevation > 0.3) { + if (p.moisture > 0.83) { return .temperateRainForest } + else if (p.moisture > 0.50) {return .temperateDeciduousForest} + else if (p.moisture > 0.16){return .grassland} + return .temperateDesert } else { - if (p.moisture > 0.66) {return Biome.tropicalRainForest } - else if (p.moisture > 0.33) {return Biome.tropicalSeasonalForest } - else if (p.moisture > 0.16) {return .grassland} ; - return Biome.subtropicalDesert + if (p.moisture > 0.66) { return .tropicalRainForest } + else if (p.moisture > 0.33) { return .tropicalSeasonalForest } + else if (p.moisture > 0.16) { return .grassland} + return .subtropicalDesert } } func assignBiomes() { for p in centers { - p.biome = Map.getBiome(p); + p.biome = Map.getBiome(p) } } - - - - + // Create rivers along edges. Pick a random corner point, then // move downslope. Mark the edges and corners as rivers. func createRivers() { - for _ in 0.. 0.9){ - continue; + continue } - // Bias rivers to go west: if (q.downslope.x > q.x) continue; + // Bias rivers to go west: if (q.downslope.x > q.x) continue while (!q.coast) { if (q === q.downslope) { - break; + break } if let edge = lookupEdgeFromCorner(q, s: q.downslope){ - edge.river = edge.river + 1; + edge.river = edge.river + 1 } - q.river = q.river + 1; - q.downslope.river = q.downslope.river + 1; // TODO: fix double count - q = q.downslope; + q.river = q.river + 1 + q.downslope.river = q.downslope.river + 1 // TODO: fix double count + q = q.downslope } } } @@ -245,32 +229,32 @@ class Map{ // and lakes (not oceans). Saltwater sources have moisture but do // not spread it (we set it at the end, after propagation). func assignCornerMoisture() { - var queue = [Corner](); + var queue = [Corner]() // Fresh water for q in corners { if ((q.water || q.river > 0) && !q.ocean) { - q.moisture = q.river > 0 ? min(3.0, (0.2 * Double(q.river))) : 1.0; - queue.append(q); + q.moisture = q.river > 0 ? min(3.0, (0.2 * Double(q.river))) : 1.0 + queue.append(q) } else { - q.moisture = 0.0; + q.moisture = 0.0 } } while (queue.count > 0) { let q = queue.remove(at: 0) - + for r in q.adjacent { - let newMoisture = q.moisture * 0.9; + let newMoisture = q.moisture * 0.9 if (newMoisture > r.moisture) { - r.moisture = newMoisture; - queue.append(r); + r.moisture = newMoisture + queue.append(r) } } } // Salt water for q in corners { if (q.ocean || q.coast) { - q.moisture = 1.0; + q.moisture = 1.0 } } } @@ -280,14 +264,14 @@ class Map{ // Polygon moisture is the average of the moisture at corners func assignPolygonMoisture() { for p in centers { - var sumMoisture = 0.0; + var sumMoisture = 0.0 for q in p.corners { if (q.moisture > 1.0) { - q.moisture = 1.0; + q.moisture = 1.0 } - sumMoisture += q.moisture; + sumMoisture += q.moisture } - p.moisture = sumMoisture / Double(p.corners.count); + p.moisture = sumMoisture / Double(p.corners.count) } } @@ -296,40 +280,40 @@ class Map{ func redistributeMoisture(_ locations:inout [Corner]){ locations.sort(by: { $0.moisture < $1.moisture }) for i in 0.. 1.0){ - x = 1.0; // TODO: does this break downslopes? + x = 1.0 // TODO: does this break downslopes? } - locations[i].elevation = x; + locations[i].elevation = x + } } -} - - - + + + // Create an array of corners that are on land only, for use by // algorithms that work only on land. We return an array instead // of a vector because the redistribution algorithms want to sort // this array using Array.sortOn. - func landCorners(_ corners:[Corner])->[Corner] { - var locations = [Corner](); + func landCorners(_ corners: [Corner]) -> [Corner] { + var locations = [Corner]() for q in corners { if (!q.ocean && !q.coast) { - locations.append(q); + locations.append(q) } } - return locations; + return locations } - - // Determine elevations and water at Voronoi corners. By // construction, we have no local minima. This is important for // the downslope vectors later, which are used in the river @@ -428,21 +409,21 @@ class Map{ // up flowing out through them. Also by construction, lakes // often end up on river paths because they don't raise the // elevation as much as other terrain does. - func assignCornerElevations(){ - var queue = [Corner](); + func assignCornerElevations() { + var queue = [Corner]() for q in corners { - q.water = !inside(q.point); + q.water = !inside(q.point) } for q in corners { // The edges of the map are elevation 0 if (q.border) { - q.elevation = 0.0; - queue.append(q); + q.elevation = 0.0 + queue.append(q) } else { - q.elevation = Double.infinity; + q.elevation = Double.infinity } } // Traverse the graph and assign elevations to each point. As we @@ -451,21 +432,21 @@ class Map{ // going downhill (no local minima). while (queue.count > 0) { let q = queue.remove(at: 0) - - + + for s in q.adjacent { // Every step up is epsilon over water or 1 over land. The // number doesn't matter because we'll rescale the // elevations later. - var newElevation = 1 + q.elevation; + var newElevation = 1 + q.elevation if (!q.water && !s.water) { - newElevation += 1; + newElevation += 1 } // If this point changed, we'll add it to the queue so // that we can process its neighbors too. if (newElevation < s.elevation) { - s.elevation = newElevation; - queue.append(s); + s.elevation = newElevation + queue.append(s) } } } @@ -477,95 +458,94 @@ class Map{ // Compute polygon attributes 'ocean' and 'water' based on the // corner attributes. Count the water corners per // polygon. Oceans are all polygons connected to the edge of the - // map. In the first pass, mark the edges of the map as ocean; + // map. In the first pass, mark the edges of the map as ocean // in the second pass, mark any water-containing polygon // connected an ocean as ocean. - var queue = [Center](); - + var queue = [Center]() + var numWater = 0 - for p in centers{ - numWater = 0; + for p in centers { + numWater = 0 for q in p.corners { if (q.border) { - p.border = true; - p.ocean = true; - q.water = true; - queue.append(p); + p.border = true + p.ocean = true + q.water = true + queue.append(p) } if (q.water) { - numWater += 1; + numWater += 1 } } - p.water = (p.ocean || Double(numWater) >= Double(p.corners.count) * Map.LAKE_THRESHOLD); + p.water = (p.ocean || Double(numWater) >= Double(p.corners.count) * Map.LAKE_THRESHOLD) } while (queue.count > 0) { let p = queue.remove(at: 0) for r in p.neighbors { if (r.water && !r.ocean) { - r.ocean = true; - queue.append(r); + r.ocean = true + queue.append(r) } } } - + // Set the polygon attribute 'coast' based on its neighbors. If // it has at least one ocean and at least one land neighbor, // then this is a coastal polygon. - for p in centers{ - var numOcean = 0; - var numLand = 0; + for p in centers { + var numOcean = 0 + var numLand = 0 for r in p.neighbors { - numOcean += r.ocean ? 1 : 0; - numLand += !r.water ? 1 : 0; + numOcean += r.ocean ? 1 : 0 + numLand += !r.water ? 1 : 0 } - p.coast = (numOcean > 0) && (numLand > 0); + p.coast = (numOcean > 0) && (numLand > 0) } - - + + // Set the corner attributes based on the computed polygon // attributes. If all polygons connected to this corner are - // ocean, then it's ocean; if all are land, then it's land; + // ocean, then it's ocean if all are land, then it's land // otherwise it's coast. for q in corners { - var numOcean = 0; - var numLand = 0; + var numOcean = 0 + var numLand = 0 for p in q.touches { - numOcean += p.ocean ? 1 : 0; - numLand += !p.water ? 1 : 0; + numOcean += p.ocean ? 1 : 0 + numLand += !p.water ? 1 : 0 } - q.ocean = (numOcean == q.touches.count); - q.coast = (numOcean > 0) && (numLand > 0); - q.water = q.border || ((numLand != q.touches.count) && !q.coast); + q.ocean = (numOcean == q.touches.count) + q.coast = (numOcean > 0) && (numLand > 0) + q.water = q.border || ((numLand != q.touches.count) && !q.coast) } } // Look up a Voronoi Edge object given two adjacent Voronoi // polygons, or two adjacent Voronoi corners - func lookupEdgeFromCenter(_ p:Center, r:Center)->Edge? { + func lookupEdgeFromCenter(_ p: Center, r: Center) -> Edge? { for edge in p.borders { if (edge.d0 === r || edge.d1 === r){ - return edge; + return edge } } - return nil; + + return nil } - func lookupEdgeFromCorner(_ q:Corner, s:Corner)->Edge? { + func lookupEdgeFromCorner(_ q:Corner, s:Corner) -> Edge? { for edge in q.protrudes { if (edge.v0 === s || edge.v1 === s){ - return edge; + return edge } } - return nil; + return nil } - - // Determine whether a given point should be on the island or in the water. - func inside(_ p:Point)->Bool { - return mapShape(p); + func inside(_ p: Point)->Bool { + return mapShape(p) } - + // Although Lloyd relaxation improves the uniformity of polygon // sizes, it doesn't help with the edge lengths. Short edges can @@ -577,115 +557,116 @@ class Map{ // polygons tend to be more uniform after this step. func improveCorners() { var newCorners = [Point]() - - + // First we compute the average of the centers next to each corner. for q in corners { if (q.border) { newCorners.append(q.point) } else { - let point = Point(x: 0.0, y: 0.0); + let point = Point(x: 0.0, y: 0.0) for r in q.touches { - point.x += r.point.x; - point.y += r.point.y; + point.x += r.point.x + point.y += r.point.y } - point.x /= Double(q.touches.count); - point.y /= Double(q.touches.count); - newCorners.append(point); + point.x /= Double(q.touches.count) + point.y /= Double(q.touches.count) + newCorners.append(point) } } - + // Move the corners to the new locations. for i in 0..Corner? { - if (point == nil){ - return nil; + var cornerMap = [Int:[Corner]]() + + func makeCorner(_ point: Point?) -> Corner? { + if (point == nil) { + return nil } + for bucket in Int(point!.x) - 1...Int(point!.x)+1 { if let array = cornerMap[bucket]{ for q in array { - let dx = point!.x - q.point.x; - let dy = point!.y - q.point.y; + let dx = point!.x - q.point.x + let dy = point!.y - q.point.y if (dx*dx + dy*dy < 1e-6) { - return q; + return q } } } } - let bucket = Int(point!.x); + + let bucket = Int(point!.x) + if (cornerMap[bucket] == nil){ - cornerMap[bucket] = [Corner](); + cornerMap[bucket] = [Corner]() } - let q = Corner(); - q.index = corners.count; - corners.append(q); - q.point = point; - q.border = (Int(point!.x) == 0 || Int(point!.x) == Int(Size) || Int(point!.y) == 0 || Int(point!.y) == Int(Size)); - cornerMap[bucket]?.append(q); - return q; + + let q = Corner() + q.index = corners.count + corners.append(q) + q.point = point + q.border = (Int(point!.x) == 0 || Int(point!.x) == Int(self.size) || Int(point!.y) == 0 || Int(point!.y) == Int(self.size)) + cornerMap[bucket]?.append(q) + + return q } - // Helper functions for the following for loop; ideally these + // Helper functions for the following for loop ideally these // would be inlined func addToCenterList(_ v:inout [Center], _ x:Center?){ if x != nil{ let filtered = v.filter{$0 === x!} if filtered.count == 0 { - v.append(x!); + v.append(x!) } } } @@ -693,128 +674,130 @@ class Map{ if x != nil{ let filtered = v.filter{$0 === x!} if filtered.count == 0{ - v.append(x!); + v.append(x!) } } } - - for libedge in libedges { - let dedge = libedge.delaunayLine; - let vedge = libedge.voronoiEdge(); + for libedge in libedges { + let dedge = libedge.delaunayLine + let vedge = libedge.voronoiEdge() + // Fill the graph data. Make an Edge object corresponding to // the edge from the voronoi library. - let edge = Edge(); + let edge = Edge() edge.index = edges.count - edge.river = 0; - edges.append(edge); + edge.river = 0 + edges.append(edge) if let p1 = vedge.p0, let p2 = vedge.p1{ - edge.midpoint = Point.interpolate(p1, p2:p2, t: 0.5); + edge.midpoint = Point.interpolate(p1, p2:p2, t: 0.5) } - + // Edges point to corners. Edges point to centers. - edge.v0 = makeCorner(vedge.p0); - edge.v1 = makeCorner(vedge.p1); - edge.d0 = centerLookup[dedge.p0]; - edge.d1 = centerLookup[dedge.p1]; - + edge.v0 = makeCorner(vedge.p0) + edge.v1 = makeCorner(vedge.p1) + edge.d0 = centerLookup[dedge.p0] + edge.d1 = centerLookup[dedge.p1] + // Centers point to edges. Corners point to edges. - if (edge.d0 != nil) { edge.d0.borders.append(edge); } - if (edge.d1 != nil) { edge.d1.borders.append(edge); } - if (edge.v0 != nil) { edge.v0.protrudes.append(edge); } - if (edge.v1 != nil) { edge.v1.protrudes.append(edge); } - + if (edge.d0 != nil) { edge.d0.borders.append(edge) } + if (edge.d1 != nil) { edge.d1.borders.append(edge) } + if (edge.v0 != nil) { edge.v0.protrudes.append(edge) } + if (edge.v1 != nil) { edge.v1.protrudes.append(edge) } + // Centers point to centers. if (edge.d0 != nil && edge.d1 != nil) { - addToCenterList(&edge.d0.neighbors, edge.d1); - addToCenterList(&edge.d1.neighbors, edge.d0); + addToCenterList(&edge.d0.neighbors, edge.d1) + addToCenterList(&edge.d1.neighbors, edge.d0) } - + // Corners point to corners if (edge.v0 != nil && edge.v1 != nil) { - addToCornerList(&edge.v0.adjacent, edge.v1); - addToCornerList(&edge.v1.adjacent, edge.v0); + addToCornerList(&edge.v0.adjacent, edge.v1) + addToCornerList(&edge.v1.adjacent, edge.v0) } // Centers point to corners if (edge.d0 != nil) { - addToCornerList(&edge.d0.corners, edge.v0); - addToCornerList(&edge.d0.corners, edge.v1); + addToCornerList(&edge.d0.corners, edge.v0) + addToCornerList(&edge.d0.corners, edge.v1) } if (edge.d1 != nil) { - addToCornerList(&edge.d1.corners, edge.v0); - addToCornerList(&edge.d1.corners, edge.v1); + addToCornerList(&edge.d1.corners, edge.v0) + addToCornerList(&edge.d1.corners, edge.v1) } // Corners point to centers if (edge.v0 != nil) { - addToCenterList(&edge.v0.touches, edge.d0); - addToCenterList(&edge.v0.touches, edge.d1); + addToCenterList(&edge.v0.touches, edge.d0) + addToCenterList(&edge.v0.touches, edge.d1) } if (edge.v1 != nil) { - addToCenterList(&edge.v1.touches, edge.d0); - addToCenterList(&edge.v1.touches, edge.d1); + addToCenterList(&edge.v1.touches, edge.d0) + addToCenterList(&edge.v1.touches, edge.d1) } } } // Generate points at random locations - static func generateRandom(_ size:Int, seed:Int)->(_ numPoints:Int)->[Point] { - func generator(_ numPoints:Int)->[Point] { - let mapRandom = PM_PRNG(); + static func generateRandom(_ size: Int, seed: Int) -> (_ numPoints:Int) -> [Point] { + func generator(_ numPoints: Int) -> [Point] { + let mapRandom = PM_PRNG() mapRandom.seed = UInt(seed) var p:Point - var points = [Point](); - + var points = [Point]() + for _ in 0..(Int)->[Point]{ - func relaxedGenerator(_ numPoints:Int)->[Point]{ - - var voronoi:Voronoi - var region:[Point]; - let points = self.generateRandom(size, seed: seed)(numPoints); + static func generateRelaxed(_ size: Int, seed: Int) -> (Int) -> [Point] { + func relaxedGenerator(_ numPoints: Int) -> [Point] { + + var voronoi: Voronoi + var region: [Point] + let points = self.generateRandom(size, seed: seed)(numPoints) for _ in 0..<3 { - voronoi = Voronoi(points: points, colors: nil, plotBounds: Rectangle(x: 0, y: 0, width: size, height: size)); + voronoi = Voronoi(points: points, colors: nil, plotBounds: Rectangle(x: 0, y: 0, width: size, height: size)) for p in points { - - region = voronoi.region(p); - p.x = 0.0; - p.y = 0.0; + + region = voronoi.region(p) + p.x = 0.0 + p.y = 0.0 for q in region{ - p.x += q.x; - p.y += q.y; + p.x += q.x + p.y += q.y } - p.x /= Double(region.count); - p.y /= Double(region.count); + p.x /= Double(region.count) + p.y /= Double(region.count) } - voronoi.dispose(); + voronoi.dispose() } - return points; + return points } return relaxedGenerator } // The Perlin-based island combines perlin noise with the radius - static func makePerlin(_ seed:Int)->(_ q:Point)->Bool { + static func makePerlin(_ seed:Int) -> (_ q: Point) -> Bool { + let perlin = PerlinNoise(seed: seed) - func perlShape(_ q:Point)->Bool { - + + func perlShape(_ q: Point) -> Bool { + let c = perlin.perlin2DValue(forPoint: q.x, y: q.y) -// println("(\(q.x), \(q.y))c:\(c)") - return c > (0); - }; + // println("(\(q.x), \(q.y))c:\(c)") + return c > (0) + } return perlShape } - + } diff --git a/Shared/Watersheds.swift b/Shared/Watersheds.swift index b082a4d..3b584ea 100644 --- a/Shared/Watersheds.swift +++ b/Shared/Watersheds.swift @@ -7,31 +7,27 @@ // import Foundation -#if os(iOS) - import DelaunayiOS - #elseif os(OSX) - import Delaunay -#endif +import Delaunay -class Watersheds{ - var lowestCorner = [Int:Int](); // polygon index -> corner index - var watersheds = [Int:Int](); // polygon index -> corner index +class Watersheds { + var lowestCorner = [Int:Int]() // polygon index -> corner index + var watersheds = [Int:Int]() // polygon index -> corner index // We want to mark each polygon with the corner where water would // exit the island. - func createWatersheds(_ map:Map){ + func createWatersheds(_ map: Map) { - // Find the lowest corner of the polygon, and set that as the - // exit point for rain falling on this polygon + // Find the lowest corner of the polygon, and set that as the + // exit point for rain falling on this polygon for p in map.centers { - var s:Corner? = nil - for q in p.corners{ + var s: Corner? = nil + for q in p.corners { if (s == nil || q.elevation < s!.elevation) { - s = q; + s = q } } - lowestCorner[p.index] = (s == nil) ? -1 : s!.index; - watersheds[p.index] = (s == nil) ? -1 : (s!.watershed == nil) ? -1 : s!.watershed.index; + lowestCorner[p.index] = (s == nil) ? -1 : s!.index + watersheds[p.index] = (s == nil) ? -1 : (s!.watershed == nil) ? -1 : s!.watershed.index } } diff --git a/Utils.swift b/Utils.swift index 2a265c3..1434271 100644 --- a/Utils.swift +++ b/Utils.swift @@ -7,59 +7,29 @@ // import Foundation -func clamp(_ val:T, min:T, max:T)->T{ +import SceneKit +import ConvexHull + +#if os(macOS) +typealias SCNColor = NSColor +#else +typealias SCNColor = UIColor +#endif + +func clamp(_ val:T, min:T, max:T)->T{ return val < max ? max : (val > min ? val : min) } -func randomPointOnSphere()->Vector3{ - var x:Float = 0; - var y:Float = 0 - var z:Float = 0 +func randomPointOnSphere() -> Vector3 { + var x: Double = 0; + var y: Double = 0 + var z: Double = 0 repeat{ - x = Float.random(-1,max:1) - y = Float.random(-1,max:1) - z = Float.random(-1,max:1) - }while(x*x + y*y + z*z > 1); + x = Double.random(in: -1...1) + y = Double.random(in: -1...1) + z = Double.random(in: -1...1) + } while(x*x + y*y + z*z > 1); let size = sqrt(x*x + y*y + z*z) - return Vector3(x/size,y/size,z/size) + return Vector3(x/size, y/size, z/size) } -public extension Double { - /** - Returns a random floating point number between 0.0 and 1.0, inclusive. - By DaRkDOG - */ - public static func random() -> Double { - return Double(arc4random()) / 0xFFFFFFFF - } - - /** - Create a random num Double - :param: lower number Double - :param: upper number Double - :return: random number Double - By DaRkDOG - */ - public static func random( _ min: Double, max: Double) -> Double { - return Double.random() * (max - min) + min - } -} -public extension Float { - /** - Returns a random floating point number between 0.0 and 1.0, inclusive. - By DaRkDOG - */ - public static func random() -> Float { - return Float(arc4random()) / 0xFFFFFFFF - } - /** - Create a random num Float - :param: lower number Float - :param: upper number Float - :return: random number Float - By DaRkDOG - */ - public static func random( _ min: Float, max: Float) -> Float { - return Float.random() * (max - min) + min - } -} diff --git a/Vector3.swift b/Vector3.swift deleted file mode 100644 index 4d079bd..0000000 --- a/Vector3.swift +++ /dev/null @@ -1,303 +0,0 @@ -// -// Vertex.swift -// QuickHull -// -// Created by Carl Wieland on 4/20/15. -// Copyright (c) 2015 Carl Wieland. All rights reserved. -// - -import Foundation -public struct Vector3:CustomStringConvertible, Hashable -{ - // Static Fields - // - public static let kEpsilon:Float = 1E-05; - - // - // Fields - // - public var x:Float; - public var y:Float; - public var z:Float; - - - - // - // Static Properties - // - public static let back = Vector3(0, 0, -1) - - - public static let down = Vector3(0, -1, 0); - - - public static let forward = Vector3(0, 0, 1); - - - public static let left = Vector3(-1, 0, 0) - - public static let one = Vector3(1, 1, 1) - - public static let right = Vector3 (1, 0, 0); - - public static let up = Vector3 (0, 1, 0); - public static let zero = Vector3 (0, 0, 0); - - // - // Properties - // - public var magnitude:Float{ - return sqrt(x * x + y * y + z * z); - } - - public var normalized:Vector3{ - return Vector3.normalize(self); - } - - public var sqrMagnitude:Float{ - return x * x + y * y + z * z; - } - - // - // Indexer - // - subscript(index:Int)->Float - { - get - { - switch (index) - { - case 0: - return x; - case 1: - return y; - case 2: - return z; - default: - assert(false, "INVALID INDEX!") - } - return -1 - } - set { - switch (index) - { - case 0: - x = newValue; - case 1: - y = newValue; - case 2: - z = newValue; - - default: - assert(false, "INVALID INDEX!") - } - } - } - - // - // Constructors - // - public init(x:Float, y:Float) - { - self.x = x; - self.y = y; - self.z = 0; - } - - public init(_ x:Float,_ y:Float,_ z:Float) - { - self.x = x; - self.y = y; - self.z = z; - } - public init(x:Float, y:Float, z:Float) - { - self.x = x; - self.y = y; - self.z = z; - } - - // - // Static Methods - // - public static func angle ( _ from:Vector3, to:Vector3)->Float - { - return acos(clamp (Vector3.dot(from.normalized, rhs: to.normalized), min: -1, max: 1)) * 57.29578 - } - - public static func clampMagnitude ( _ vector:Vector3, maxLength:Float)->Vector3 - { - if (vector.sqrMagnitude > maxLength * maxLength) - { - return vector.normalized * maxLength; - } - return vector; - } - - public static func cross (_ lhs:Vector3 , rhs:Vector3 )->Vector3{ - return Vector3 (lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z, lhs.x * rhs.y - lhs.y * rhs.x); - } - - public static func distance ( _ a:Vector3, b:Vector3)->Float{ - let vector = Vector3 (a.x - b.x, a.y - b.y, a.z - b.z); - return sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z); - } - - public static func dot (_ lhs:Vector3 , rhs:Vector3 )->Float{ - return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; - } - - - public static func lerp (_ from:Vector3 , to:Vector3 , t tin:Float)->Vector3 - { - let t = clamp(tin,min: 0,max: 1); - return Vector3 (from.x + (to.x - from.x) * t, from.y + (to.y - from.y) * t, from.z + (to.z - from.z) * t); - } - - public static func magnitude (_ a:Vector3 )->Float - { - return sqrt(a.x * a.x + a.y * a.y + a.z * a.z); - } - - public static func max ( _ lhs:Vector3, rhs:Vector3)->Vector3 - { - return Vector3 (Swift.max (lhs.x, rhs.x), Swift.max (lhs.y, rhs.y), Swift.max (lhs.z, rhs.z)); - } - - public static func min ( _ lhs:Vector3, rhs:Vector3)->Vector3 - { - return Vector3 (Swift.min (lhs.x, rhs.x), Swift.min (lhs.y, rhs.y), Swift.min (lhs.z, rhs.z)); - } - - public static func moveTowards ( _ current:Vector3, target:Vector3, maxDistanceDelta:Float)->Vector3 - { - let a = target - current; - let magnitude = a.magnitude; - if (magnitude <= maxDistanceDelta || magnitude == 0) - { - return target; - } - return current + a / magnitude * maxDistanceDelta; - } - - public static func normalize ( _ value:Vector3)->Vector3 - { - let num = Vector3.magnitude (value); - if (num > 1E-05) - { - return value / num; - } - return Vector3.zero; - } - - public static func project ( _ vector:Vector3, onNormal:Vector3)->Vector3 - { - let num = Vector3.dot(onNormal, rhs: onNormal); - if (num < 1.401298E-45) - { - return Vector3.zero; - } - return onNormal * Vector3.dot(vector, rhs:onNormal) / num; - } - - public static func projectOnPlane ( _ vector:Vector3, planeNormal:Vector3 )->Vector3 - { - return vector - Vector3.project (vector, onNormal:planeNormal); - } - - public static func reflect (_ inDirection:Vector3 , inNormal:Vector3 )->Vector3 - { - return -2 * Vector3.dot(inNormal,rhs: inDirection) * inNormal + inDirection; - } - - public static func scale (_ a:Vector3 , b:Vector3 )->Vector3{ - return Vector3 (a.x * b.x, a.y * b.y, a.z * b.z); - } - - public static func sqrMagnitude (_ a:Vector3 )->Float - { - return a.x * a.x + a.y * a.y + a.z * a.z; - } - - // - // Methods - // - - public var hashValue:Int - { - return Int(x * 19) ^ Int(y * 7) << 2 ^ Int(z * 31) >> 2; - } - - public mutating func Normalize () - { - let num = Vector3.magnitude (self); - if (num > 1E-05) - { - self.scale(1.0/num) - } - else - { - self = Vector3.zero; - } - } -// - public mutating func scale (_ scale:Vector3) - { - x = x * scale.x; - y = y * scale.y; - z = z * scale.z; - } - public mutating func scale (_ scale:Float) - { - x = x * scale; - y = y * scale; - z = z * scale; - } - - public mutating func set ( _ new_x:Float, new_y:Float, new_z:Float) - { - x = new_x; - y = new_y; - z = new_z; - } - - public var description:String{ - return "(\(x), \(y), \(z))" - } - -} - - -// -// Operators -// -func + ( a:Vector3, b:Vector3)->Vector3{ - return Vector3 (a.x + b.x, a.y + b.y, a.z + b.z); -} - -func / ( a:Vector3, d:Float)->Vector3{ - return Vector3 (a.x / d, a.y / d, a.z / d); -} -public func == ( lhs:Vector3, rhs:Vector3)->Bool{ - return Vector3.sqrMagnitude (lhs - rhs) < 9.99999944E-11; -} - -func != ( lhs:Vector3, rhs:Vector3)->Bool{ - return Vector3.sqrMagnitude (lhs - rhs) >= 9.99999944E-11; -} - -func * (d:Float, a:Vector3)->Vector3{ - return Vector3 (a.x * d, a.y * d, a.z * d); -} - -func * ( a:Vector3, d:Float)->Vector3{ - return Vector3 (a.x * d, a.y * d, a.z * d); -} - -func - ( a:Vector3, b:Vector3 )->Vector3{ - return Vector3 (a.x - b.x, a.y - b.y, a.z - b.z); -} - -prefix func - (a:Vector3 )->Vector3{ - return Vector3 (-a.x, -a.y, -a.z); -} diff --git a/Vertex.swift b/Vertex.swift index ea7f53e..ccc4069 100644 --- a/Vertex.swift +++ b/Vertex.swift @@ -7,9 +7,10 @@ // import Foundation +import ConvexHull + struct Vertex{ - var position:Vector3 - var normal:Vector3 - var color:Vector3 -// var uv:Vector3 -} \ No newline at end of file + var position: Vector3 + var normal: Vector3 + var color: Vector3 +}