186 lines
5.5 KiB
Swift
186 lines
5.5 KiB
Swift
import Foundation
|
|
|
|
|
|
public protocol ContentLoaderParametersProtocol
|
|
{
|
|
associatedtype T: Resource
|
|
}
|
|
|
|
public struct ContentManager
|
|
{
|
|
private var loaders = Dictionary<String, any LoaderProtocol>()
|
|
private var resources = [any RendererResource]()
|
|
private let renderer: Renderer
|
|
private let bundle: Bundle
|
|
}
|
|
|
|
extension ContentManager
|
|
{
|
|
internal init(_ renderer: inout Renderer, bundle: Bundle)
|
|
{
|
|
self.renderer = renderer
|
|
self.bundle = bundle
|
|
}
|
|
|
|
public mutating func setLoader<T: Resource, Loader: LoaderProtocol>(extensions exts: [String], loader: Loader) where Loader.T == T
|
|
{
|
|
for i in exts
|
|
{
|
|
setLoader(extension: i, loader: loader)
|
|
}
|
|
}
|
|
|
|
public mutating func setLoader<T: Resource, Loader: LoaderProtocol>(extension ext: String, loader: Loader) where Loader.T == T
|
|
{
|
|
loaders[ext] = loader
|
|
}
|
|
|
|
public mutating func create<V: Vertex>(mesh: Mesh<V>) throws -> RenderMesh<V>
|
|
{
|
|
let rendMesh = try renderer.createMesh(mesh: mesh)
|
|
resources.append(rendMesh)
|
|
return rendMesh
|
|
}
|
|
|
|
public mutating func create(texture: Image, params: Texture2DParameters = .init()) throws -> Texture2D
|
|
{
|
|
try texture.pixels.withUnsafeBytes
|
|
{
|
|
raw in
|
|
let data = raw.baseAddress!
|
|
let rendTex = try renderer.createTexture(
|
|
data: data, width: texture.width, height: texture.height,
|
|
filter: params.magFilter, mipMode: params.mipMode)
|
|
resources.append(rendTex)
|
|
return Texture2D(id: rendTex, width: texture.width, height: texture.height)
|
|
}
|
|
}
|
|
|
|
public func getResource(_ path: String) throws -> URL
|
|
{
|
|
guard let extIndex = path.lastIndex(of: ".")
|
|
else { throw ContentError.badPath }
|
|
let name = String(path[..<extIndex]), ext = String(path[extIndex...])
|
|
guard let resourceUrl: URL = bundle.url(
|
|
forResource: name,
|
|
withExtension: ext)
|
|
else { throw ContentError.resourceNotFound }
|
|
return resourceUrl
|
|
}
|
|
|
|
public mutating func load<T: Resource>(_ path: String) throws -> T
|
|
{
|
|
let resourceUrl = try getResource(path)
|
|
|
|
let loader = loaders[resourceUrl.pathExtension.lowercased()]
|
|
guard let resource = loader?.load(url: resourceUrl)
|
|
else { throw ContentError.loadFailure }
|
|
|
|
if T.self == Mesh<VertexPositionNormalTexcoord>.self
|
|
{
|
|
guard let mesh = resource as? Mesh<VertexPositionNormalTexcoord> else { throw ContentError.loadFailure }
|
|
return mesh as! T
|
|
}
|
|
if T.self == Mesh<VertexPositionNormalColourTexcoord>.self
|
|
{
|
|
guard let mesh = resource as? Mesh<VertexPositionNormalTexcoord> else { throw ContentError.loadFailure }
|
|
return mesh as! T
|
|
}
|
|
if T.self == Image.self
|
|
{
|
|
guard let image = resource as? Image else { throw ContentError.loadFailure }
|
|
return image as! T
|
|
}
|
|
if T.self == Texture2D.self
|
|
{
|
|
guard let image = resource as? Image else { throw ContentError.loadFailure }
|
|
let texture2D = try self.create(texture: image)
|
|
return texture2D as! T
|
|
}
|
|
throw ContentError.loadFailure
|
|
}
|
|
|
|
public mutating func load<T: Resource, Params: ContentLoaderParametersProtocol>(_ path: String, params: Params) throws
|
|
-> T where Params.T == T
|
|
{
|
|
let resourceUrl = try getResource(path)
|
|
|
|
let loader = loaders[resourceUrl.pathExtension.lowercased()]
|
|
guard let resource = loader?.load(url: resourceUrl)
|
|
else { throw ContentError.loadFailure }
|
|
|
|
if T.self == Mesh<VertexPositionNormalTexcoord>.self
|
|
{
|
|
guard let mesh = resource as? Mesh<VertexPositionNormalTexcoord> else { throw ContentError.loadFailure }
|
|
return mesh as! T
|
|
}
|
|
if T.self == Mesh<VertexPositionNormalColourTexcoord>.self
|
|
{
|
|
guard let mesh = resource as? Mesh<VertexPositionNormalTexcoord> else { throw ContentError.loadFailure }
|
|
return mesh as! T
|
|
}
|
|
if T.self == Image.self
|
|
{
|
|
guard let image = resource as? Image else { throw ContentError.loadFailure }
|
|
return image as! T
|
|
}
|
|
if T.self == Texture2D.self
|
|
{
|
|
guard let image = resource as? Image else { throw ContentError.loadFailure }
|
|
let texture2D = try self.create(texture: image, params: params as! Texture2DParameters)
|
|
return texture2D as! T
|
|
}
|
|
throw ContentError.loadFailure
|
|
}
|
|
|
|
public mutating func load<T: RendererResource>(_ path: String) throws -> T
|
|
{
|
|
let resourceUrl = try getResource(path)
|
|
|
|
let loader = loaders[resourceUrl.pathExtension]
|
|
guard let resource = loader?.load(url: resourceUrl)
|
|
else { throw ContentError.loadFailure }
|
|
|
|
if T.self == RenderMesh<VertexPositionNormalTexcoord>.self
|
|
{
|
|
guard let mesh = resource as? Mesh<VertexPositionNormalTexcoord> else { throw ContentError.loadFailure }
|
|
let renderResource = try self.create(mesh: mesh)
|
|
return renderResource as! T
|
|
}
|
|
if T.self == RenderMesh<VertexPositionNormalColourTexcoord>.self
|
|
{
|
|
guard let mesh = resource as? Mesh<VertexPositionNormalColourTexcoord> else { throw ContentError.loadFailure }
|
|
let renderResource = try self.create(mesh: mesh)
|
|
return renderResource as! T
|
|
}
|
|
throw ContentError.loadFailure
|
|
}
|
|
|
|
internal mutating func releaseAll()
|
|
{
|
|
for resource in resources.reversed()
|
|
{
|
|
if resource is RenderMesh<VertexPositionNormalTexcoord>
|
|
{
|
|
renderer.deleteMesh(resource as! RenderMesh<VertexPositionNormalTexcoord>)
|
|
}
|
|
else if resource is RenderMesh<VertexPositionNormalColourTexcoord>
|
|
{
|
|
renderer.deleteMesh(resource as! RenderMesh<VertexPositionNormalColourTexcoord>)
|
|
}
|
|
else if resource is RenderTexture2D
|
|
{
|
|
renderer.deleteTexture(resource as! RenderTexture2D)
|
|
}
|
|
}
|
|
resources.removeAll()
|
|
}
|
|
}
|
|
|
|
public enum ContentError: Error
|
|
{
|
|
case badPath //else { fatalError("Malformed resource path \"\(path)\"") }
|
|
case resourceNotFound //else { fatalError("Resource \"\(path)\" doesn't exist") }
|
|
case loadFailure //else { fatalError("Failed to load resource \"\(path)\"") }
|
|
}
|