Features: - VOD library with movie grouping and version detection - TV show library with season/episode organization - TMDB integration for trending shows and recently aired episodes - Recent releases section with TMDB release date sorting - Watch history tracking with continue watching - Playlist caching (12-hour TTL) for offline support - M3U playlist parsing with XStream API support - Authentication with credential storage Technical: - SwiftUI for tvOS - Actor-based services for thread safety - Persistent caching for playlists, TMDB data, and watch history - KSPlayer integration for video playback Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
111 lines
3.2 KiB
Swift
111 lines
3.2 KiB
Swift
//
|
|
// Transforms.swift
|
|
// MetalSpectrograph
|
|
//
|
|
// Created by David Conner on 9/9/15.
|
|
// Copyright © 2015 Voxxel. All rights reserved.
|
|
//
|
|
|
|
import simd
|
|
|
|
// swiftlint:disable identifier_name
|
|
extension simd_float4x4 {
|
|
static let identity = matrix_identity_float4x4
|
|
// sx 0 0 0
|
|
// 0 sy 0 0
|
|
// 0 0 sz 0
|
|
// 0 0 0 1
|
|
|
|
init(scale x: Float, y: Float, z: Float) {
|
|
self.init(diagonal: [x, y, z, 1.0])
|
|
}
|
|
|
|
// 1 0 0 tx
|
|
// 0 1 0 ty
|
|
// 0 0 1 tz
|
|
// 0 0 0 1
|
|
init(translate: SIMD3<Float>) {
|
|
self.init([1, 0.0, 0.0, translate.x],
|
|
[0.0, 1, 0.0, translate.y],
|
|
[0.0, 0.0, 1, translate.z],
|
|
[0.0, 0.0, 0, 1])
|
|
}
|
|
|
|
init(rotationX radians: Float) {
|
|
let cos = cosf(radians)
|
|
let sin = sinf(radians)
|
|
self.init([1, 0.0, 0.0, 0],
|
|
[0.0, cos, sin, 0],
|
|
[0.0, -sin, cos, 0],
|
|
[0.0, 0.0, 0, 1])
|
|
}
|
|
|
|
init(rotationY radians: Float) {
|
|
let cos = cosf(radians)
|
|
let sin = sinf(radians)
|
|
self.init([cos, 0.0, -sin, 0],
|
|
[0.0, 1, 0, 0],
|
|
[sin, 0, cos, 0],
|
|
[0.0, 0.0, 0, 1])
|
|
}
|
|
|
|
init(rotationZ radians: Float) {
|
|
let cos = cosf(radians)
|
|
let sin = sinf(radians)
|
|
self.init([cos, sin, 0.0, 0],
|
|
[-sin, cos, 0, 0],
|
|
[0.0, 0, 1, 0],
|
|
[0.0, 0.0, 0, 1])
|
|
}
|
|
|
|
public init(lookAt eye: SIMD3<Float>, center: SIMD3<Float>, up: SIMD3<Float>) {
|
|
let N = normalize(eye - center)
|
|
let U = normalize(cross(up, N))
|
|
let V = cross(N, U)
|
|
self.init(rows: [[U.x, V.x, N.x, 0.0],
|
|
[U.y, V.y, N.y, 0.0],
|
|
[U.z, V.z, N.z, 0.0],
|
|
[dot(-U, eye), dot(-V, eye), dot(-N, eye), 1.0]])
|
|
}
|
|
|
|
public init(perspective fovyRadians: Float, aspect: Float, nearZ: Float, farZ: Float) {
|
|
let cotan = 1.0 / tanf(fovyRadians / 2.0)
|
|
self.init([cotan / aspect, 0.0, 0.0, 0.0],
|
|
[0.0, cotan, 0.0, 0.0],
|
|
[0.0, 0.0, (farZ + nearZ) / (nearZ - farZ), -1],
|
|
[0.0, 0.0, (2.0 * farZ * nearZ) / (nearZ - farZ), 0])
|
|
}
|
|
|
|
public init(euler x: Float, y: Float, z: Float) {
|
|
let x = x * .pi / 180
|
|
let y = y * .pi / 180
|
|
let z = z * .pi / 180
|
|
let cx = cos(x)
|
|
let sx = sin(x)
|
|
let cy = cos(y)
|
|
let sy = sin(y)
|
|
let cz = cos(z)
|
|
let sz = sin(z)
|
|
let cxsy = cx * sy
|
|
let sxsy = sx * sy
|
|
self.init([cy * cz, -cy * sz, sy, 0.0],
|
|
[cxsy * cz + cx * sz, -cxsy * sz + cx * cz, -sx * cy, 0.0],
|
|
[-sxsy * cz + sx * sz, sxsy * sz + sx * cz, cx * cy, 0],
|
|
[0.0, 0.0, 0, 1])
|
|
}
|
|
|
|
func rotateX(radians: Float) -> simd_float4x4 {
|
|
self * simd_float4x4(rotationX: radians)
|
|
}
|
|
|
|
func rotateY(radians: Float) -> simd_float4x4 {
|
|
self * simd_float4x4(rotationY: radians)
|
|
}
|
|
|
|
func rotateZ(radians: Float) -> simd_float4x4 {
|
|
self * simd_float4x4(rotationZ: radians)
|
|
}
|
|
}
|
|
|
|
// swiftlint:enable identifier_name
|