128 lines
3.2 KiB
Swift
128 lines
3.2 KiB
Swift
import Foundation
|
|
import OrderedCollections
|
|
|
|
|
|
extension ObjMaterial
|
|
{
|
|
func convert(content: UnsafeMutablePointer<ContentManager>? = nil) -> Material
|
|
{
|
|
var m = Material()
|
|
m.id = self.name
|
|
m.diffuse = self.diffuse.setAlpha(self.alpha)
|
|
if ![ .colour, .lambert, .shadowOnly ].contains(self.model)
|
|
{
|
|
m.specular = self.specular
|
|
m.specularExp = self.specularExp
|
|
}
|
|
else
|
|
{
|
|
m.specularExp = self.specularExp
|
|
}
|
|
if let content = content
|
|
{
|
|
if let albedo = self.diffuseMap
|
|
{
|
|
let filter = albedo.flags.contains(.blendHoriz) || albedo.flags.contains(.blendVert)
|
|
m.texture = (try? content.pointee.load(albedo.path,
|
|
params: Texture2DParameters(
|
|
minFilter: filter ? .linear : .point,
|
|
magFilter: filter ? .linear : .point,
|
|
wrapMode: albedo.flags.contains(.clamp) ? .clampBorder : .repeating,
|
|
mipMode: .linear)))?.id ?? RenderTexture2D.empty
|
|
}
|
|
}
|
|
return m
|
|
}
|
|
}
|
|
|
|
public struct ObjLoader: LoaderProtocol
|
|
{
|
|
typealias V = VertexPositionNormalColourTexcoord
|
|
public typealias T = Mesh<VertexPositionNormalColourTexcoord>
|
|
|
|
public init() {}
|
|
|
|
public func load(url: URL) -> T?
|
|
{
|
|
return try? Self.read(model: try ObjReader.read(url: url), content: nil)
|
|
}
|
|
|
|
public func load(url: URL, content: inout ContentManager) -> T?
|
|
{
|
|
return try? Self.read(model: try ObjReader.read(url: url), content: &content)
|
|
}
|
|
|
|
public static func read(model: ObjModel, content: UnsafeMutablePointer<ContentManager>?) throws -> T
|
|
{
|
|
var subMeshes = OrderedDictionary<String, T.SubMesh>()
|
|
var materials = OrderedDictionary<String, Material>()
|
|
var vertices = [V]()
|
|
var indices = [UInt16]()
|
|
|
|
for (key, mtl) in model.materials
|
|
{
|
|
materials[key] = mtl.convert(content: content)
|
|
}
|
|
|
|
let readIndex =
|
|
{ (v: ObjModel.Index) -> UInt16 in
|
|
let colour = model.colours.isEmpty ? .white : Colour(
|
|
r: model.colours[v.p][0],
|
|
g: model.colours[v.p][1],
|
|
b: model.colours[v.p][2]).linear
|
|
let vertex = V(
|
|
position: model.positions[v.p],
|
|
colour: colour,
|
|
normal: model.normals[v.n],
|
|
texCoord: model.texCoords[v.t])
|
|
if let index = vertices.firstIndex(of: vertex)
|
|
{
|
|
indices.append(UInt16(index))
|
|
return UInt16(index)
|
|
}
|
|
else
|
|
{
|
|
let index = UInt16(vertices.count)
|
|
indices.append(index)
|
|
vertices.append(vertex)
|
|
return index
|
|
}
|
|
}
|
|
|
|
for object in model.objects.filter({ $0.key != "Collision3D" })
|
|
{
|
|
var id = 0
|
|
for mesh: ObjModel.Mesh in object.value.meshes
|
|
{
|
|
let start = indices.count
|
|
for face: ObjModel.Face in mesh.faces
|
|
{
|
|
switch face
|
|
{
|
|
case .triangle(let v1, let v2, let v3):
|
|
for v in [ v1, v2, v3 ] { _ = readIndex(v) }
|
|
case .quad(let v1, let v2, let v3, let v4):
|
|
let n1 = readIndex(v1)
|
|
_ = readIndex(v2)
|
|
indices.append(readIndex(v3))
|
|
_ = readIndex(v4)
|
|
indices.append(n1)
|
|
case .ngon(_): fallthrough
|
|
default: break
|
|
}
|
|
}
|
|
let length = indices.count - start
|
|
if length > 0
|
|
{
|
|
subMeshes["\(object.key)_\(id)"] = .init(
|
|
start: start, length: length,
|
|
material: materials.index(forKey: mesh.material) ?? -1)
|
|
}
|
|
id += 1
|
|
}
|
|
}
|
|
|
|
return Mesh(vertices: vertices, indices: indices, subMeshes: subMeshes, materials: materials.values.map { $0 })
|
|
}
|
|
}
|