Files
CavesOfSwift/Sources/JolkEngine/Loaders/ObjLoader.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 })
}
}