285 lines
8.2 KiB
Dart
285 lines
8.2 KiB
Dart
// ignore_for_file: invalid_annotation_target
|
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
|
|
part 'shader_preset.freezed.dart';
|
|
part 'shader_preset.g.dart';
|
|
|
|
enum ShaderPresetType { none, nvscaler, artcnn, anime4k, custom }
|
|
|
|
/// ArtCNN real-time model sizes.
|
|
enum ArtCNNModel {
|
|
/// Lightweight real-time model
|
|
c4f16,
|
|
|
|
/// Higher-quality real-time model
|
|
c4f32,
|
|
}
|
|
|
|
/// ArtCNN luma doubler variants.
|
|
enum ArtCNNVariant {
|
|
/// Neutral luma doubler
|
|
neutral,
|
|
|
|
/// Denoise and soften
|
|
denoise,
|
|
|
|
/// Denoise and sharpen
|
|
denoiseSharpen,
|
|
}
|
|
|
|
/// Quality tiers for Anime4K presets
|
|
enum Anime4KQuality {
|
|
/// Fast quality using Mode L shaders
|
|
fast,
|
|
|
|
/// High quality using Mode VL/UL shaders
|
|
hq,
|
|
}
|
|
|
|
/// Anime4K modes that define shader combinations
|
|
enum Anime4KMode {
|
|
/// Mode A: Clamp + Restore
|
|
modeA,
|
|
|
|
/// Mode B: Clamp + Restore + Upscale + Downscale
|
|
modeB,
|
|
|
|
/// Mode C: Clamp + Upscale + Downscale
|
|
modeC,
|
|
|
|
/// Mode A+A: Clamp + Restore + Restore
|
|
modeAA,
|
|
|
|
/// Mode B+B: Clamp + Restore + Restore + Upscale + Downscale
|
|
modeBB,
|
|
|
|
/// Mode C+A: Clamp + Upscale + Restore + Downscale
|
|
modeCA,
|
|
}
|
|
|
|
@freezed
|
|
sealed class Anime4KConfig with _$Anime4KConfig {
|
|
const factory Anime4KConfig({
|
|
@JsonKey(unknownEnumValue: Anime4KQuality.fast) required Anime4KQuality quality,
|
|
@JsonKey(unknownEnumValue: Anime4KMode.modeA) required Anime4KMode mode,
|
|
}) = _Anime4KConfig;
|
|
|
|
factory Anime4KConfig.fromJson(Map<String, dynamic> json) => _$Anime4KConfigFromJson(json);
|
|
}
|
|
|
|
@freezed
|
|
sealed class ArtCNNConfig with _$ArtCNNConfig {
|
|
const factory ArtCNNConfig({
|
|
@JsonKey(unknownEnumValue: ArtCNNModel.c4f16) required ArtCNNModel model,
|
|
@JsonKey(unknownEnumValue: ArtCNNVariant.neutral) required ArtCNNVariant variant,
|
|
}) = _ArtCNNConfig;
|
|
|
|
factory ArtCNNConfig.fromJson(Map<String, dynamic> json) => _$ArtCNNConfigFromJson(json);
|
|
}
|
|
|
|
@freezed
|
|
sealed class NVScalerConfig with _$NVScalerConfig {
|
|
const factory NVScalerConfig({
|
|
/// Whether to automatically skip NVScaler on HDR content
|
|
@Default(true) bool autoHdrSkip,
|
|
}) = _NVScalerConfig;
|
|
|
|
factory NVScalerConfig.fromJson(Map<String, dynamic> json) => _$NVScalerConfigFromJson(json);
|
|
}
|
|
|
|
class ShaderPreset {
|
|
final String id;
|
|
final String name;
|
|
final ShaderPresetType type;
|
|
final ArtCNNConfig? artcnnConfig;
|
|
final Anime4KConfig? anime4kConfig;
|
|
final NVScalerConfig? nvscalerConfig;
|
|
|
|
/// File name of the custom shader in the custom shaders directory
|
|
final String? fileName;
|
|
|
|
const ShaderPreset({
|
|
required this.id,
|
|
required this.name,
|
|
required this.type,
|
|
this.artcnnConfig,
|
|
this.anime4kConfig,
|
|
this.nvscalerConfig,
|
|
this.fileName,
|
|
});
|
|
|
|
/// No shader preset (off)
|
|
static const none = ShaderPreset(id: 'none', name: 'Off', type: ShaderPresetType.none);
|
|
|
|
/// NVScaler default preset with auto HDR skip
|
|
static const nvscalerDefault = ShaderPreset(
|
|
id: 'nvscaler',
|
|
name: 'NVScaler',
|
|
type: ShaderPresetType.nvscaler,
|
|
nvscalerConfig: NVScalerConfig(),
|
|
);
|
|
|
|
/// Create an ArtCNN preset with the specified model and variant
|
|
static ShaderPreset artcnnPreset(ArtCNNModel model, ArtCNNVariant variant) {
|
|
final modelName = _getArtCNNModelName(model);
|
|
final variantName = _getArtCNNVariantName(variant);
|
|
final variantId = _getArtCNNVariantId(variant);
|
|
|
|
return ShaderPreset(
|
|
id: 'artcnn_${model.name}_$variantId',
|
|
name: variant == ArtCNNVariant.neutral ? 'ArtCNN $modelName' : 'ArtCNN $modelName $variantName',
|
|
type: ShaderPresetType.artcnn,
|
|
artcnnConfig: ArtCNNConfig(model: model, variant: variant),
|
|
);
|
|
}
|
|
|
|
/// Create an Anime4K preset with the specified quality and mode
|
|
static ShaderPreset anime4kPreset(Anime4KQuality quality, Anime4KMode mode) {
|
|
final qualityName = quality == Anime4KQuality.fast ? 'Fast' : 'HQ';
|
|
final modeName = _getModeName(mode);
|
|
|
|
return ShaderPreset(
|
|
id: 'anime4k_${quality.name}_${mode.name}',
|
|
name: 'Anime4K $qualityName $modeName',
|
|
type: ShaderPresetType.anime4k,
|
|
anime4kConfig: Anime4KConfig(quality: quality, mode: mode),
|
|
);
|
|
}
|
|
|
|
static String _getModeName(Anime4KMode mode) {
|
|
switch (mode) {
|
|
case Anime4KMode.modeA:
|
|
return 'A';
|
|
case Anime4KMode.modeB:
|
|
return 'B';
|
|
case Anime4KMode.modeC:
|
|
return 'C';
|
|
case Anime4KMode.modeAA:
|
|
return 'A+A';
|
|
case Anime4KMode.modeBB:
|
|
return 'B+B';
|
|
case Anime4KMode.modeCA:
|
|
return 'C+A';
|
|
}
|
|
}
|
|
|
|
static String _getArtCNNModelName(ArtCNNModel model) {
|
|
switch (model) {
|
|
case ArtCNNModel.c4f16:
|
|
return 'C4F16';
|
|
case ArtCNNModel.c4f32:
|
|
return 'C4F32';
|
|
}
|
|
}
|
|
|
|
static String _getArtCNNVariantName(ArtCNNVariant variant) {
|
|
switch (variant) {
|
|
case ArtCNNVariant.neutral:
|
|
return 'Neutral';
|
|
case ArtCNNVariant.denoise:
|
|
return 'Denoise';
|
|
case ArtCNNVariant.denoiseSharpen:
|
|
return 'Denoise + Sharpen';
|
|
}
|
|
}
|
|
|
|
static String _getArtCNNVariantId(ArtCNNVariant variant) {
|
|
switch (variant) {
|
|
case ArtCNNVariant.neutral:
|
|
return 'neutral';
|
|
case ArtCNNVariant.denoise:
|
|
return 'dn';
|
|
case ArtCNNVariant.denoiseSharpen:
|
|
return 'ds';
|
|
}
|
|
}
|
|
|
|
String get modeDisplayName {
|
|
if (anime4kConfig != null) {
|
|
return _getModeName(anime4kConfig!.mode);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
String get artcnnModelDisplayName {
|
|
if (artcnnConfig != null) {
|
|
return _getArtCNNModelName(artcnnConfig!.model);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
static List<ShaderPreset> get allPresets {
|
|
return [
|
|
none,
|
|
nvscalerDefault,
|
|
artcnnPreset(ArtCNNModel.c4f16, ArtCNNVariant.neutral),
|
|
artcnnPreset(ArtCNNModel.c4f16, ArtCNNVariant.denoise),
|
|
artcnnPreset(ArtCNNModel.c4f16, ArtCNNVariant.denoiseSharpen),
|
|
artcnnPreset(ArtCNNModel.c4f32, ArtCNNVariant.neutral),
|
|
artcnnPreset(ArtCNNModel.c4f32, ArtCNNVariant.denoise),
|
|
artcnnPreset(ArtCNNModel.c4f32, ArtCNNVariant.denoiseSharpen),
|
|
anime4kPreset(Anime4KQuality.fast, Anime4KMode.modeA),
|
|
anime4kPreset(Anime4KQuality.fast, Anime4KMode.modeB),
|
|
anime4kPreset(Anime4KQuality.fast, Anime4KMode.modeC),
|
|
anime4kPreset(Anime4KQuality.fast, Anime4KMode.modeAA),
|
|
anime4kPreset(Anime4KQuality.fast, Anime4KMode.modeBB),
|
|
anime4kPreset(Anime4KQuality.fast, Anime4KMode.modeCA),
|
|
anime4kPreset(Anime4KQuality.hq, Anime4KMode.modeA),
|
|
anime4kPreset(Anime4KQuality.hq, Anime4KMode.modeB),
|
|
anime4kPreset(Anime4KQuality.hq, Anime4KMode.modeC),
|
|
anime4kPreset(Anime4KQuality.hq, Anime4KMode.modeAA),
|
|
anime4kPreset(Anime4KQuality.hq, Anime4KMode.modeBB),
|
|
anime4kPreset(Anime4KQuality.hq, Anime4KMode.modeCA),
|
|
];
|
|
}
|
|
|
|
static ShaderPreset? fromId(String id) {
|
|
try {
|
|
return allPresets.firstWhere((p) => p.id == id);
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
bool get isEnabled => type != ShaderPresetType.none;
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
if (identical(this, other)) return true;
|
|
return other is ShaderPreset && other.id == id;
|
|
}
|
|
|
|
@override
|
|
int get hashCode => id.hashCode;
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'id': id,
|
|
'name': name,
|
|
'type': type.name,
|
|
if (artcnnConfig != null) 'artcnnConfig': artcnnConfig!.toJson(),
|
|
if (anime4kConfig != null) 'anime4kConfig': anime4kConfig!.toJson(),
|
|
if (nvscalerConfig != null) 'nvscalerConfig': nvscalerConfig!.toJson(),
|
|
if (fileName != null) 'fileName': fileName,
|
|
};
|
|
|
|
factory ShaderPreset.fromJson(Map<String, dynamic> json) {
|
|
// Try to find by ID first for built-in presets
|
|
final id = json['id'] as String?;
|
|
if (id != null) {
|
|
final builtIn = fromId(id);
|
|
if (builtIn != null) return builtIn;
|
|
}
|
|
|
|
// Otherwise create from JSON
|
|
return ShaderPreset(
|
|
id: id ?? 'custom',
|
|
name: json['name'] as String? ?? 'Custom',
|
|
type: ShaderPresetType.values.asNameMap()[json['type']] ?? ShaderPresetType.none,
|
|
artcnnConfig: json['artcnnConfig'] != null ? ArtCNNConfig.fromJson(json['artcnnConfig']) : null,
|
|
anime4kConfig: json['anime4kConfig'] != null ? Anime4KConfig.fromJson(json['anime4kConfig']) : null,
|
|
nvscalerConfig: json['nvscalerConfig'] != null ? NVScalerConfig.fromJson(json['nvscalerConfig']) : null,
|
|
fileName: json['fileName'] as String?,
|
|
);
|
|
}
|
|
}
|