The Skung Rockification of Ziggy Skungdust and the SIMD's
This commit is contained in:
118
Sources/JolkEngine/Loaders/VMeshLoader.swift
Normal file
118
Sources/JolkEngine/Loaders/VMeshLoader.swift
Normal file
@ -0,0 +1,118 @@
|
||||
import Foundation
|
||||
import Maths
|
||||
|
||||
|
||||
struct VMeshLoader: LoaderProtocol
|
||||
{
|
||||
typealias T = Mesh<VMeshVertex>
|
||||
|
||||
func load(url: URL) -> T? { try? Self.read(url: url) }
|
||||
func load(url: URL, content: inout ContentManager) -> T? { load(url: url) }
|
||||
|
||||
static func read(url: URL) throws -> T
|
||||
{
|
||||
let file = try FileHandle(forReadingFrom: url)
|
||||
|
||||
// read header fields
|
||||
let header = VMeshHeader(
|
||||
magic: try file.read(upToCount: 4),
|
||||
version: try file.read(as: UInt8.self).littleEndian,
|
||||
idxSize: try file.read(as: UInt8.self).littleEndian,
|
||||
subMeshCount: try file.read(as: UInt16.self).littleEndian,
|
||||
vertexCount: try file.read(as: UInt32.self).littleEndian,
|
||||
indexCount: try file.read(as: UInt32.self).littleEndian)
|
||||
|
||||
// header sanity checks
|
||||
guard header.magic == Data("VMSH".utf8)
|
||||
else { throw NSError() }
|
||||
guard header.version == 2
|
||||
else { throw NSError() }
|
||||
|
||||
// check index type
|
||||
let idxSize = switch header.idxSize
|
||||
{
|
||||
case 1, 2, 4: header.idxSize
|
||||
default: throw NSError()
|
||||
}
|
||||
|
||||
// fail on empty data lengths
|
||||
guard header.vertexCount > 0, header.indexCount > 0
|
||||
else { throw NSError() }
|
||||
|
||||
// read submeshes
|
||||
var subMeshes = [VMeshSubMesh](repeating: .empty, count: Int(header.subMeshCount))
|
||||
for i in 0..<Int(header.subMeshCount)
|
||||
{
|
||||
guard let nameStr = try file.read(upToCount: 24)
|
||||
else { throw NSError() }
|
||||
subMeshes[i] = .init(
|
||||
name: String(decoding: nameStr, as: UTF8.self),
|
||||
offset: try file.read(as: UInt32.self),
|
||||
count: try file.read(as: UInt32.self))
|
||||
}
|
||||
|
||||
// read vertices
|
||||
var vertices = [VMeshVertex](repeating: .empty, count: Int(header.vertexCount))
|
||||
for i in 0..<Int(header.vertexCount)
|
||||
{
|
||||
vertices[i] = .init(
|
||||
position: .init(try file.read(as: Float.self), try file.read(as: Float.self), try file.read(as: Float.self)),
|
||||
//texCoord: .init(try file.read(as: UInt16.self), try file.read(as: UInt16.self)),
|
||||
texCoord: .init(
|
||||
Float(try file.read(as: UInt16.self)) / Float(UInt16.max),
|
||||
1.0 - Float(try file.read(as: UInt16.self)) / Float(UInt16.max)),
|
||||
normal: .init(try file.read(as: Int8.self), try file.read(as: Int8.self), try file.read(as: Int8.self), try file.read(as: Int8.self)),
|
||||
tangent: .init(try file.read(as: Int8.self), try file.read(as: Int8.self), try file.read(as: Int8.self), try file.read(as: Int8.self)))
|
||||
}
|
||||
|
||||
let indices = switch idxSize
|
||||
{
|
||||
case 1: try (0..<Int(header.indexCount)).map { _ in UInt16(try file.read(as: UInt8.self)) }
|
||||
case 2: try (0..<Int(header.indexCount)).map { _ in UInt16(try file.read(as: UInt16.self)) }
|
||||
case 4: try (0..<Int(header.indexCount)).map { _ in UInt16(try file.read(as: UInt32.self)) }
|
||||
default: fatalError()
|
||||
}
|
||||
|
||||
// create & return mesh
|
||||
return .init(
|
||||
vertices: vertices, indices: indices,
|
||||
subMeshes: .init(uniqueKeysWithValues:
|
||||
subMeshes.map { ($0.name, .init(start: Int($0.offset), length: Int($0.count))) }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
struct VMeshHeader
|
||||
{
|
||||
let magic: Data?
|
||||
let version, idxSize: UInt8
|
||||
let subMeshCount: UInt16
|
||||
let vertexCount, indexCount: UInt32
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct VMeshVertex: Vertex
|
||||
{
|
||||
let position: Vec3f
|
||||
//let texCoord: SIMD2<UInt16>
|
||||
let texCoord: Vec2f
|
||||
let normal: SIMD4<Int8>
|
||||
let tangent: SIMD4<Int8>
|
||||
}
|
||||
|
||||
extension VMeshVertex
|
||||
{
|
||||
static let empty: Self = .init(position: .init(), texCoord: .init(), normal: .init(), tangent: .init())
|
||||
}
|
||||
|
||||
struct VMeshSubMesh
|
||||
{
|
||||
let name: String
|
||||
let offset: UInt32, count: UInt32
|
||||
}
|
||||
|
||||
extension VMeshSubMesh
|
||||
{
|
||||
static let empty: Self = .init(name: .init(), offset: .init(), count: .init())
|
||||
}
|
Reference in New Issue
Block a user