Files
OpenEmuKit/Source/OESystemShaderStore.swift
2023-01-10 10:23:33 +11:00

168 lines
6.6 KiB
Swift

// Copyright (c) 2021, OpenEmu Team
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the OpenEmu Team nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import Foundation
/// The main object used for managing shaders and parameters assigned to a system.
@objc public class OESystemShaderStore: NSObject {
private let store: UserDefaults
private let shaders: OEShaderStore
public init(store: UserDefaults, shaders: OEShaderStore) {
self.store = store
self.shaders = shaders
super.init()
}
@objc public func shader(withShader shader: OEShaderModel, forSystem identifier: String) -> OESystemShaderModel {
OESystemShaderModel(shader: shader, identifier: identifier, store: store)
}
@objc public func shader(forSystem identifier: String) -> OESystemShaderModel {
findSystemShader(identifier)
}
/// Returns the name of the shader for the specified system, falling back to the default shader if none is set.
@objc public func shaderName(forSystem identifier: String) -> String {
findShader(forSystem: identifier).name
}
/// Reset to the default shader for the specified system.
@objc public func resetShader(forSystem identifier: String) {
store.removeObject(forKey: makeSystemKey(identifier))
}
/// Set the default shader for the specified system.
/// - Parameters:
/// - shader: The shader to assign to the system..
/// - identifier: The identifier of the system.
@objc public func setShader(_ shader: OEShaderModel, forSystem identifier: String) {
store.set(shader.name, forKey: makeSystemKey(identifier))
}
// MARK: - Internal methods
// These are used to avoid deprecation warnings within OpenEmuKit
func findSystemShader(_ identifier: String) -> OESystemShaderModel {
OESystemShaderModel(shader: findShader(forSystem: identifier), identifier: identifier, store: store)
}
func findShader(forSystem identifier: String) -> OEShaderModel {
if let name = store.string(forKey: makeSystemKey(identifier)),
let model = shaders[name] {
return model
}
return shaders.defaultShader
}
// MARK: - Helpers
func makeSystemKey(_ identifier: String) -> String { "videoShader.\(identifier)" }
// MARK: - Shader parameter storage
public func read(parametersForShader name: String, identifier: String) -> String? {
store.read(parametersForShader: name, identifier: identifier)
}
public func write(parameters params: String, forShader name: String, identifier: String) {
store.write(parameters: params, forShader: name, identifier: identifier)
}
public func remove(parametersForShader name: String, identifier: String) {
store.remove(parametersForShader: name, identifier: identifier)
}
}
protocol ShaderModelStore {
/// Read the customised shader parameters for the shader and system identifer.
func read(parametersForShader name: String, identifier: String) -> String?
/// Write the customised shader parameters for the shader and system identifer.
func write(parameters params: String, forShader name: String, identifier: String)
/// Remove the customised shader parameters for the shader and system identifer.
func remove(parametersForShader name: String, identifier: String)
}
extension UserDefaults: ShaderModelStore {
func read(parametersForShader name: String, identifier: String) -> String? {
string(forKey: makeSystemKey(name, identifier))
}
func write(parameters params: String, forShader name: String, identifier: String) {
set(params, forKey: makeSystemKey(name, identifier))
}
func remove(parametersForShader name: String, identifier: String) {
removeObject(forKey: makeSystemKey(name, identifier))
}
func makeSystemKey(_ shader: String, _ identifier: String) -> String {
"videoShader.\(identifier).\(shader).params"
}
}
@objc public class OESystemShaderModel: NSObject {
public let shader: OEShaderModel
public let system: String
let store: ShaderModelStore
init(shader: OEShaderModel, identifier: String, store: ShaderModelStore) {
self.shader = shader
self.system = identifier
self.store = store
super.init()
}
public var parameters: [String: Double]? {
if let state = store.read(parametersForShader: shader.name, identifier: system) {
var res = [String: Double]()
for param in state.split(separator: ";") {
let vals = param.split(separator: "=")
if vals.count == 2,
let d = Double(vals[1]) {
res[String(vals[0])] = d
}
}
return res
}
return nil
}
public func write(parameters params: [ShaderParamValue]) {
let state = params
.filter { !$0.isInitial }
.map { "\($0.name)=\($0.value)" }
if state.isEmpty {
store.remove(parametersForShader: shader.name, identifier: system)
} else {
store.write(parameters: state.joined(separator: ";"), forShader: shader.name, identifier: system)
}
}
}