using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
namespace ADOFAIRenderer.Data;
///
/// Settings of one render: resolution, frame rates, encoding and advanced options. Serialized to JSON in the preset
/// files (PresetManager). renders with a copy ().
///
[SuppressMessage("ReSharper", "RedundantDefaultMemberInitializer")]
public class RenderConfig
{
///
/// Game frames simulated per second of render time (the game clock advances 1 / RenderFPS seconds per frame).
/// Values above render extra frames between video frames, which are not captured
/// (the game state then advances in smaller time steps).
///
public double RenderFPS { get; set; }
///
/// Frame rate of the output video. The effective rate is min(VideoFPS, RenderFPS).
///
public double VideoFPS { get; set; }
/// Width of the rendered frames and the output video in pixels (also reported by the Screen.width patch).
public int RenderWidth { get; set; }
/// Height of the rendered frames and the output video in pixels (also reported by the Screen.height patch).
public int RenderHeight { get; set; }
/// Video encoder settings.
public VideoEncodingConfig VideoConfig { get; set; } = new();
/// Audio rendering and encoder settings.
public AudioEncodingConfig AudioConfig { get; set; } = new();
/// Advanced options (random seed, spectrum processing, tile hiding, container, planet colors).
public AdvancedConfig AdvancedConfig { get; set; } = new();
/// Seconds of render time recorded after the end condition first holds (default 15).
public double DelayAfterEnd { get; set; } = 15;
/// Whether the judgement texts (hit accuracy texts) are shown during the render (scrHitTextManagerPatch). Default false.
public bool ShowJudgementText { get; set; } = false;
///
/// Copies every value of into this object; the nested configs are copied value by value
/// into the existing nested objects. Does nothing when is null.
///
public void CopyFrom(RenderConfig? source)
{
if (source == null) return;
RenderFPS = source.RenderFPS;
VideoFPS = source.VideoFPS;
RenderWidth = source.RenderWidth;
RenderHeight = source.RenderHeight;
DelayAfterEnd = source.DelayAfterEnd;
ShowJudgementText = source.ShowJudgementText;
VideoConfig.CopyFrom(source.VideoConfig);
AudioConfig.CopyFrom(source.AudioConfig);
AdvancedConfig.CopyFrom(source.AdvancedConfig);
}
/// Returns a deep copy (nested configs are new objects).
public RenderConfig Clone()
{
var clone = new RenderConfig();
clone.CopyFrom(this);
return clone;
}
}
/// Advanced render options.
[SuppressMessage("ReSharper", "RedundantDefaultMemberInitializer")]
public class AdvancedConfig
{
///
/// Seed for UnityEngine.Random set before the game scene loads, so random visual effects repeat between renders;
/// null leaves the random state unchanged.
///
public int? RandomSeed { get; set; } = null;
///
/// When true, AudioSource.GetSpectrumData is answered from the offline song audio at the render time
/// (AudioSpectrumGenerator), so audio-reactive visuals follow the rendered audio. Default true.
///
public bool ProcessAudio { get; set; } = true;
///
/// When true, the level's floor tiles (including hold meshes and the portal particles of the level's floors) and the
/// planets are hidden during the render, so only the background and decorations remain (scnGamePatch, scrFloorPatch,
/// RenderManager.OnLastUpdate). Default false.
///
public bool NonTile { get; set; } = false;
///
/// When true, the game's bloom (VideoBloom) computes its blur size as if the frame were 720 pixels high, so the
/// blur passes on the 198-pixel-high bloom buffer are the same as in a 720p frame at any render height
/// (VideoBloomPatch). Default false.
///
public bool HighResBloomCorrection { get; set; } = false;
/// File extension of the default output file name, without the dot (e.g. "mkv", "mp4"); selects the container.
public string FileExtension { get; set; } = "mkv";
/// Color of the fire (red) planet during the render; null keeps the user's setting. Serialized as "#RRGGBBAA".
[JsonConverter(typeof(ColorJsonConverter))]
public Color? firePlanetColor = null;
/// Color of the ice (blue) planet during the render; null keeps the user's setting. Serialized as "#RRGGBBAA".
[JsonConverter(typeof(ColorJsonConverter))]
public Color? icePlanetColor = null;
///
/// Color of the third (wind, planetGreen) planet during the render (PlanetarySystemPatch); null keeps the game's color.
/// Serialized as "#RRGGBBAA".
///
[JsonConverter(typeof(ColorJsonConverter))]
public Color? windPlanetColor = null;
/// Copies every value of ; does nothing when it is null.
public void CopyFrom(AdvancedConfig? source)
{
if (source == null) return;
RandomSeed = source.RandomSeed;
ProcessAudio = source.ProcessAudio;
NonTile = source.NonTile;
HighResBloomCorrection = source.HighResBloomCorrection;
FileExtension = source.FileExtension;
firePlanetColor = source.firePlanetColor;
icePlanetColor = source.icePlanetColor;
windPlanetColor = source.windPlanetColor;
}
/// Returns a copy of this object.
public AdvancedConfig Clone()
{
var clone = new AdvancedConfig();
clone.CopyFrom(this);
return clone;
}
}
/// Video encoder settings (passed to FFmpegNativeEncoder.EncoderSettings).
public class VideoEncodingConfig
{
/// Video codec (default H.264). Also selects the audio codec (CodecUtil.AudioCodecMatch).
public Codec Codec { get; set; } = Codec.H264;
/// Bitrate control mode (default CBR).
public RateControlMode RateControlMode { get; set; } = RateControlMode.CBR;
/// Target video bitrate in kbps for CBR and VBR (default 30000 = 30 Mbps).
public int Bitrate { get; set; } = 30000;
/// Peak video bitrate in kbps for VBR, used when larger than Bitrate (otherwise 1.5 × Bitrate). Default 50000.
public int MaxBitrate { get; set; } = 50000;
///
/// Quality value for CQP: lower is higher quality. Clamped to the range of the selected encoder; a negative value
/// selects 18. Default 18.
///
// ReSharper disable once InconsistentNaming
public int QP { get; set; } = 18;
/// Keyframe interval in seconds (GOP length = round(effective video FPS × interval) frames, at least 1). Default 2.
public double KeyframeInterval { get; set; } = 2.0;
/// When true, only software (CPU) encoders are tried; hardware encoders are skipped.
public bool ForceSoftwareEncoder { get; set; }
/// Copies every value of ; does nothing when it is null.
public void CopyFrom(VideoEncodingConfig? source)
{
if (source == null) return;
Codec = source.Codec;
RateControlMode = source.RateControlMode;
Bitrate = source.Bitrate;
MaxBitrate = source.MaxBitrate;
QP = source.QP;
KeyframeInterval = source.KeyframeInterval;
ForceSoftwareEncoder = source.ForceSoftwareEncoder;
}
/// Returns a copy of this object.
public VideoEncodingConfig Clone()
{
var clone = new VideoEncodingConfig();
clone.CopyFrom(this);
return clone;
}
}
///
/// Audio rendering and encoder settings. Non-positive values of the numeric settings read back as their defaults
/// (48000 Hz, 2 channels, 256000 bps).
///
public class AudioEncodingConfig
{
private int _audioSampleRate = 48000;
private int _audioChannels = 2;
private int _audioBitrate = 256000;
/// When true, the song and sound effects are mixed offline and encoded as an audio stream. Default true.
public bool RenderAudio { get; set; } = true;
///
/// Output sample rate in Hz (default 48000). A rate the audio codec does not support in the mod
/// (CodecUtil.AvailableSampleRate) is replaced with 48000 when the render starts.
///
public int AudioSampleRate
{
get => _audioSampleRate <= 0 ? 48000 : _audioSampleRate;
set => _audioSampleRate = value <= 0 ? 48000 : value;
}
/// Number of output audio channels (default 2).
public int AudioChannels
{
get => _audioChannels <= 0 ? 2 : _audioChannels;
set => _audioChannels = value <= 0 ? 2 : value;
}
/// Audio bitrate in bits per second (default 256000 = 256 kbps). Unit differs from the video bitrate (kbps).
public int AudioBitrate
{
get => _audioBitrate <= 0 ? 256000 : _audioBitrate;
set => _audioBitrate = value <= 0 ? 256000 : value;
}
/// Copies every value of ; does nothing when it is null.
public void CopyFrom(AudioEncodingConfig? source)
{
if (source == null) return;
RenderAudio = source.RenderAudio;
AudioSampleRate = source.AudioSampleRate;
AudioChannels = source.AudioChannels;
AudioBitrate = source.AudioBitrate;
}
/// Returns a copy of this object.
public AudioEncodingConfig Clone()
{
var clone = new AudioEncodingConfig();
clone.CopyFrom(this);
return clone;
}
}