diff --git a/COLLADA/COLLADA.xcodeproj/project.pbxproj b/COLLADA/COLLADA.xcodeproj/project.pbxproj index 297a8ab..c9bf3ba 100644 --- a/COLLADA/COLLADA.xcodeproj/project.pbxproj +++ b/COLLADA/COLLADA.xcodeproj/project.pbxproj @@ -10,6 +10,8 @@ C005E0221BE1CC3300F1BD3C /* COLLADA.h in Headers */ = {isa = PBXBuildFile; fileRef = C005E0211BE1CC3300F1BD3C /* COLLADA.h */; settings = {ATTRIBUTES = (Public, ); }; }; C005E0291BE1CC3300F1BD3C /* COLLADA.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C005E01E1BE1CC3300F1BD3C /* COLLADA.framework */; }; C005E02E1BE1CC3300F1BD3C /* COLLADATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C005E02D1BE1CC3300F1BD3C /* COLLADATests.swift */; }; + C04449C31BE3422A00ABF046 /* COLLADA.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04449C21BE3422A00ABF046 /* COLLADA.swift */; }; + C04449C51BE5142200ABF046 /* Source.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04449C41BE5142200ABF046 /* Source.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -29,6 +31,8 @@ C005E0281BE1CC3300F1BD3C /* COLLADATests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = COLLADATests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C005E02D1BE1CC3300F1BD3C /* COLLADATests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = COLLADATests.swift; sourceTree = ""; }; C005E02F1BE1CC3300F1BD3C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C04449C21BE3422A00ABF046 /* COLLADA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = COLLADA.swift; sourceTree = ""; }; + C04449C41BE5142200ABF046 /* Source.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Source.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -73,6 +77,8 @@ children = ( C005E0211BE1CC3300F1BD3C /* COLLADA.h */, C005E0231BE1CC3300F1BD3C /* Info.plist */, + C04449C21BE3422A00ABF046 /* COLLADA.swift */, + C04449C41BE5142200ABF046 /* Source.swift */, ); path = COLLADA; sourceTree = ""; @@ -194,6 +200,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + C04449C51BE5142200ABF046 /* Source.swift in Sources */, + C04449C31BE3422A00ABF046 /* COLLADA.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -305,6 +313,7 @@ C005E0331BE1CC3300F1BD3C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -317,12 +326,14 @@ PRODUCT_BUNDLE_IDENTIFIER = me.erynwells.graphics.COLLADA; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; C005E0341BE1CC3300F1BD3C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -379,6 +390,7 @@ C005E0341BE1CC3300F1BD3C /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; C005E0351BE1CC3300F1BD3C /* Build configuration list for PBXNativeTarget "COLLADATests" */ = { isa = XCConfigurationList; @@ -387,6 +399,7 @@ C005E0371BE1CC3300F1BD3C /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/COLLADA/COLLADA/COLLADA.swift b/COLLADA/COLLADA/COLLADA.swift new file mode 100644 index 0000000..e2a139d --- /dev/null +++ b/COLLADA/COLLADA/COLLADA.swift @@ -0,0 +1,129 @@ +// +// COLLADA.swift +// COLLADA +// +// Created by Eryn Wells on 10/29/15. +// Copyright © 2015 Eryn Wells. All rights reserved. +// + +import Foundation + +private enum Node: String { + case Geometry = "geometry" + case LibraryGeometries = "library_geometries" + case Vertices = "vertices" +} + +public class Scene: Object { + public enum Error: ErrorType { + case MissingRootElement + } + + private let document: NSXMLDocument + + public lazy var geometries: [Geometry] = { + do { + return try self.xml.elementsForName(Node.LibraryGeometries.rawValue).flatMap { + try $0.elementsForName(Node.Geometry.rawValue).map { + try Geometry(element: $0) + } + } + } catch { + return [] + } + }() + + init(document: NSXMLDocument) throws { + self.document = document + if let root = document.rootElement() { + try super.init(element: root) + } else { + try super.init(element: nil) + throw Error.MissingRootElement + } + } +} + +public class Geometry: Object { +} + +public class Mesh: Object { + private lazy var vertices: NSXMLElement! = { + return self.xml.elementsForName("vertices").first + }() +} + +public class Polygons: Object { + +} + +public class Object { + public enum Error: ErrorType { + case MissingElement + case MultipleElementsWithSameID + } + + // TODO: When the Swift compiler gets its shit together and lets you throw from init() without all stored properties being initialized, change these to `let` and clean up the initializer. + public private(set) var elements = [NSXMLElement]() + public private(set) var elementsByID = [String: NSXMLElement]() + + let xml: NSXMLElement! + + init(element: NSXMLElement!) throws { + xml = element + guard xml != nil else { throw Error.MissingElement } + + for node in element.children ?? [] { + if node.kind != .ElementKind { + continue + } + if let element = node as? NSXMLElement { + elements.append(element) + } + } + + for element in elements { + if let id = element.attributeForName("id")?.stringValue { + if elementsByID[id] != nil { + throw Error.MultipleElementsWithSameID + } + elementsByID[id] = element + } + } + } + + public var id: String? { + return xml.attributeForName("id")?.stringValue + } + + public var name: String? { + return xml.attributeForName("name")?.stringValue + } + + private func idWithoutHash(id: String) -> String { + if id.hasPrefix("#") { + let indexAfterHash = id.startIndex.advancedBy(1) + return id.substringFromIndex(indexAfterHash) + } else { + return id + } + } +} + +extension NSXMLElement { + func stringValueForAttributeWithName(name: String) -> String? { + if let value = self.attributeForName(name)?.stringValue { + return value + } else { + return nil + } + } + + func unsignedIntValueForAttributeWithName(name: String) -> UInt? { + if let value = stringValueForAttributeWithName(name) { + return UInt(value) + } else { + return nil + } + } +} \ No newline at end of file diff --git a/COLLADA/COLLADA/Source.swift b/COLLADA/COLLADA/Source.swift new file mode 100644 index 0000000..11fe733 --- /dev/null +++ b/COLLADA/COLLADA/Source.swift @@ -0,0 +1,92 @@ +// +// Source.swift +// COLLADA +// +// Created by Eryn Wells on 10/31/15. +// Copyright © 2015 Eryn Wells. All rights reserved. +// + +import Foundation +import Math + +private enum Node: String { + case Accessor = "accessor" + case FloatArray = "float_array" + case Source = "source" + case TechniqueCommon = "technique_common" +} + +enum SourceError: ErrorType { + case MissingAccessor +} + +protocol Source: SequenceType { } + +class FloatSource: Object, Source { + // TODO: When the Swift compiler gets its shit together and lets you throw from init() without all stored properties being initialized, change these to `let` and clean up the initializer. + private var accessor: Accessor! = nil + + override init(element: NSXMLElement!) throws { + try super.init(element: element) + if let techniqueNode = element.elementsForName(Node.TechniqueCommon.rawValue).first, + accessorNode = techniqueNode.elementsForName(Node.Accessor.rawValue).first { + accessor = try Accessor(element: accessorNode) + } else { + throw SourceError.MissingAccessor + } + } +} + +extension FloatSource: SequenceType { + typealias Element = [String: Float] + typealias Generator = AnyGenerator<[String: Float]> + + func generate() -> Generator { + return anyGenerator { () -> Element? in + return nil + } + } +} + +class Vertices: Object { + +} + +class Accessor: Object { + typealias Param = (name: String, type: String) + + enum Error: ErrorType { + case MissingSource + case MissingCount + case MissingStride + case MissingParamName + case MissingParamType + } + + // TODO: When the Swift compiler gets its shit together and lets you throw from init() without all stored properties being initialized, change these to `let` and clean up the initializer. + private(set) var source: String! = nil + private(set) var count: UInt! = nil + private(set) var stride: UInt! = nil + private(set) var params: [Param]! = nil + + override init(element: NSXMLElement!) throws { + try super.init(element: element) + + source = element.stringValueForAttributeWithName("source") + guard source != nil else { throw Error.MissingSource } + + count = element.unsignedIntValueForAttributeWithName("count") + guard count != nil else { throw Error.MissingCount } + + stride = element.unsignedIntValueForAttributeWithName("stride") + guard stride != nil else { throw Error.MissingStride } + + params = try element.elementsForName("param").map { + let name = $0.stringValueForAttributeWithName("name") + let type = $0.stringValueForAttributeWithName("type") + guard name != nil else { throw Error.MissingParamName } + guard type != nil else { throw Error.MissingParamType } + return (name: name!, type: type!) + } + } +} \ No newline at end of file