forked from MeloNX/MeloNX
Edit Settings, Make Loading View hide after game has loaded
This commit is contained in:
parent
71551adf2d
commit
09a757c445
@ -634,6 +634,7 @@
|
|||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
GCC_OPTIMIZATION_LEVEL = fast;
|
GCC_OPTIMIZATION_LEVEL = fast;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -806,6 +807,10 @@
|
|||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 0.0.8;
|
MARKETING_VERSION = 0.0.8;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||||
@ -845,6 +850,7 @@
|
|||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
GCC_OPTIMIZATION_LEVEL = fast;
|
GCC_OPTIMIZATION_LEVEL = fast;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -1017,6 +1023,10 @@
|
|||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 0.0.8;
|
MARKETING_VERSION = 0.0.8;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||||
|
Binary file not shown.
@ -12,12 +12,12 @@
|
|||||||
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>1</integer>
|
<integer>2</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>2</integer>
|
<integer>1</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>SuppressBuildableAutocreation</key>
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
@ -152,9 +152,9 @@ class Ryujinx {
|
|||||||
|
|
||||||
args.append(contentsOf: ["--memory-manager-mode", config.memoryManagerMode])
|
args.append(contentsOf: ["--memory-manager-mode", config.memoryManagerMode])
|
||||||
|
|
||||||
// args.append(contentsOf: ["--exclusive-fullscreen", String(config.fullscreen)])
|
args.append(contentsOf: ["--exclusive-fullscreen", String(true)])
|
||||||
// args.append(contentsOf: ["--exclusive-fullscreen-width", "\(Int(UIScreen.main.bounds.width))"])
|
args.append(contentsOf: ["--exclusive-fullscreen-width", "\(Int(UIScreen.main.bounds.width))"])
|
||||||
// args.append(contentsOf: ["--exclusive-fullscreen-height", "\(Int(UIScreen.main.bounds.height))"])
|
args.append(contentsOf: ["--exclusive-fullscreen-height", "\(Int(UIScreen.main.bounds.height))"])
|
||||||
// We don't need this. Ryujinx should handle it fine :3
|
// We don't need this. Ryujinx should handle it fine :3
|
||||||
|
|
||||||
if config.fullscreen {
|
if config.fullscreen {
|
||||||
@ -174,10 +174,11 @@ class Ryujinx {
|
|||||||
args.append(contentsOf: ["--resolution-scale", String(config.resscale)])
|
args.append(contentsOf: ["--resolution-scale", String(config.resscale)])
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.disableShaderCache {
|
if !config.disableShaderCache { // same with disableShaderCache
|
||||||
args.append("--disable-shader-cache")
|
args.append("--disable-shader-cache")
|
||||||
}
|
}
|
||||||
if config.disableDockedMode {
|
|
||||||
|
if !config.disableDockedMode { // disableDockedMode is actually enableDockedMode, i just have flipped it around in the settings page to make it easier to understand :3
|
||||||
args.append("--disable-docked-mode")
|
args.append("--disable-docked-mode")
|
||||||
}
|
}
|
||||||
if config.enableTextureRecompression {
|
if config.enableTextureRecompression {
|
||||||
|
@ -22,7 +22,6 @@ struct MoltenVKSettings: Codable, Hashable {
|
|||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
@State private var theWindow: UIWindow?
|
@State private var theWindow: UIWindow?
|
||||||
@State private var virtualController: GCVirtualController?
|
|
||||||
@State private var game: Game?
|
@State private var game: Game?
|
||||||
@State private var controllersList: [Controller] = []
|
@State private var controllersList: [Controller] = []
|
||||||
@State private var currentControllers: [Controller] = []
|
@State private var currentControllers: [Controller] = []
|
||||||
@ -37,6 +36,11 @@ struct ContentView: View {
|
|||||||
@AppStorage("quit") var quit: Bool = false
|
@AppStorage("quit") var quit: Bool = false
|
||||||
|
|
||||||
@State var quits: Bool = false
|
@State var quits: Bool = false
|
||||||
|
@State private var clumpOffset: CGFloat = -100
|
||||||
|
private let clumpWidth: CGFloat = 100
|
||||||
|
private let animationDuration: Double = 1.0
|
||||||
|
@State private var isAnimating = false
|
||||||
|
@State var isLoading = true
|
||||||
|
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
init() {
|
init() {
|
||||||
@ -58,18 +62,27 @@ struct ContentView: View {
|
|||||||
// MARK: - Body
|
// MARK: - Body
|
||||||
var body: some View {
|
var body: some View {
|
||||||
if let game, quits == false {
|
if let game, quits == false {
|
||||||
emulationView
|
if isLoading {
|
||||||
.onAppear() {
|
emulationView
|
||||||
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
.onAppear() {
|
||||||
timer.invalidate()
|
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
||||||
quits = quit
|
|
||||||
|
|
||||||
if quits {
|
|
||||||
quit = false
|
|
||||||
timer.invalidate()
|
timer.invalidate()
|
||||||
|
quits = quit
|
||||||
|
|
||||||
|
if quits {
|
||||||
|
quit = false
|
||||||
|
timer.invalidate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
VStack {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.onAppear() {
|
||||||
|
isAnimating = false
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mainMenuView
|
mainMenuView
|
||||||
.onAppear() {
|
.onAppear() {
|
||||||
@ -81,15 +94,80 @@ struct ContentView: View {
|
|||||||
|
|
||||||
// MARK: - View Components
|
// MARK: - View Components
|
||||||
private var emulationView: some View {
|
private var emulationView: some View {
|
||||||
ZStack {
|
GeometryReader { screenGeometry in
|
||||||
|
ZStack {
|
||||||
}
|
HStack(spacing: screenGeometry.size.width * 0.04) {
|
||||||
.onAppear {
|
if let icon = game?.icon {
|
||||||
|
Image(uiImage: icon)
|
||||||
setupEmulation()
|
.resizable()
|
||||||
|
.frame(
|
||||||
|
width: min(screenGeometry.size.width * 0.25, 250),
|
||||||
|
height: min(screenGeometry.size.width * 0.25, 250)
|
||||||
|
)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 16))
|
||||||
|
.shadow(color: .black.opacity(0.5), radius: 10, x: 0, y: 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
VStack(alignment: .leading, spacing: screenGeometry.size.height * 0.015) {
|
||||||
|
Text("Loading \(game?.titleName ?? "Game")")
|
||||||
|
.font(.system(size: min(screenGeometry.size.width * 0.04, 32)))
|
||||||
|
.foregroundColor(.white)
|
||||||
|
|
||||||
|
GeometryReader { geometry in
|
||||||
|
let containerWidth = min(screenGeometry.size.width * 0.35, 350)
|
||||||
|
|
||||||
|
ZStack(alignment: .leading) {
|
||||||
|
// Background track
|
||||||
|
Rectangle()
|
||||||
|
.cornerRadius(10)
|
||||||
|
.frame(width: containerWidth, height: min(screenGeometry.size.height * 0.015, 12))
|
||||||
|
.foregroundColor(.gray.opacity(0.3))
|
||||||
|
.shadow(color: .black.opacity(0.2), radius: 4, x: 0, y: 2)
|
||||||
|
|
||||||
|
// Animated loading bar
|
||||||
|
Rectangle()
|
||||||
|
.cornerRadius(10)
|
||||||
|
.frame(width: clumpWidth, height: min(screenGeometry.size.height * 0.015, 12))
|
||||||
|
.foregroundColor(.blue)
|
||||||
|
.shadow(color: .blue.opacity(0.5), radius: 4, x: 0, y: 2)
|
||||||
|
.offset(x: isAnimating ? containerWidth : -clumpWidth)
|
||||||
|
.animation(
|
||||||
|
Animation.linear(duration: 1.0)
|
||||||
|
.repeatForever(autoreverses: false),
|
||||||
|
value: isAnimating
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 16))
|
||||||
|
.onAppear {
|
||||||
|
isAnimating = true
|
||||||
|
|
||||||
|
setupEmulation()
|
||||||
|
|
||||||
|
|
||||||
|
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in
|
||||||
|
if get_current_fps() != 0 {
|
||||||
|
isLoading = false
|
||||||
|
isAnimating = false
|
||||||
|
timer.invalidate()
|
||||||
|
}
|
||||||
|
print(get_current_fps())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(height: min(screenGeometry.size.height * 0.015, 12))
|
||||||
|
.frame(width: min(screenGeometry.size.width * 0.35, 350))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.horizontal, screenGeometry.size.width * 0.06)
|
||||||
|
.padding(.vertical, screenGeometry.size.height * 0.05)
|
||||||
|
.position(
|
||||||
|
x: screenGeometry.size.width / 2,
|
||||||
|
y: screenGeometry.size.height * 0.5
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var mainMenuView: some View {
|
private var mainMenuView: some View {
|
||||||
MainTabView(startemu: $game, config: $config, MVKconfig: $settings, controllersList: $controllersList, currentControllers: $currentControllers, onscreencontroller: $onscreencontroller)
|
MainTabView(startemu: $game, config: $config, MVKconfig: $settings, controllersList: $controllersList, currentControllers: $currentControllers, onscreencontroller: $onscreencontroller)
|
||||||
.onAppear() {
|
.onAppear() {
|
||||||
@ -116,7 +194,6 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func setupEmulation() {
|
private func setupEmulation() {
|
||||||
virtualController?.disconnect()
|
|
||||||
patchMakeKeyAndVisible()
|
patchMakeKeyAndVisible()
|
||||||
|
|
||||||
if (currentControllers.first(where: { $0 == onscreencontroller }) != nil) {
|
if (currentControllers.first(where: { $0 == onscreencontroller }) != nil) {
|
||||||
@ -203,6 +280,8 @@ struct ContentView: View {
|
|||||||
print("Error: \(error.localizedDescription)")
|
print("Error: \(error.localizedDescription)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private func setMoltenVKSettings() {
|
private func setMoltenVKSettings() {
|
||||||
|
@ -140,7 +140,7 @@ struct GameLibraryView: View {
|
|||||||
|
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
var game = Game(containerFolder: URL(string: "none")!, fileType: .item, fileURL: URL(string: "MiiMaker")!, titleName: "Mii Maker", titleId: "0", developer: "Nintendo", version: firmwareversion)
|
let game = Game(containerFolder: URL(string: "none")!, fileType: .item, fileURL: URL(string: "MiiMaker")!, titleName: "Mii Maker", titleId: "0", developer: "Nintendo", version: firmwareversion)
|
||||||
|
|
||||||
self.startemu = game
|
self.startemu = game
|
||||||
} label: {
|
} label: {
|
||||||
@ -165,7 +165,7 @@ struct GameLibraryView: View {
|
|||||||
Text("Show MeloNX Folder")
|
Text("Show MeloNX Folder")
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "ellipsis")
|
Image(systemName: "ellipsis.circle")
|
||||||
.foregroundColor(.blue)
|
.foregroundColor(.blue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,7 +349,6 @@ struct GameLibraryView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure your Game model conforms to Codable
|
|
||||||
extension Game: Codable {
|
extension Game: Codable {
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case titleName, titleId, developer, version, fileURL
|
case titleName, titleId, developer, version, fileURL
|
||||||
|
@ -52,7 +52,7 @@ struct SettingsView: View {
|
|||||||
.tint(.blue)
|
.tint(.blue)
|
||||||
|
|
||||||
Toggle(isOn: $config.disableShaderCache) {
|
Toggle(isOn: $config.disableShaderCache) {
|
||||||
labelWithIcon("Disable Shader Cache", iconName: "memorychip")
|
labelWithIcon("Shader Cache", iconName: "memorychip")
|
||||||
}
|
}
|
||||||
.tint(.blue)
|
.tint(.blue)
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ struct SettingsView: View {
|
|||||||
.tint(.blue)
|
.tint(.blue)
|
||||||
|
|
||||||
Toggle(isOn: $config.disableDockedMode) {
|
Toggle(isOn: $config.disableDockedMode) {
|
||||||
labelWithIcon("Disable Docked Mode", iconName: "dock.rectangle")
|
labelWithIcon("Docked Mode", iconName: "dock.rectangle")
|
||||||
}
|
}
|
||||||
.tint(.blue)
|
.tint(.blue)
|
||||||
|
|
||||||
|
@ -1306,7 +1306,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
options.IgnoreMissingServices,
|
options.IgnoreMissingServices,
|
||||||
options.AspectRatio,
|
options.AspectRatio,
|
||||||
options.AudioVolume,
|
options.AudioVolume,
|
||||||
options.UseHypervisor ?? true,
|
options.UseHypervisor ?? false,
|
||||||
options.MultiplayerLanInterfaceId,
|
options.MultiplayerLanInterfaceId,
|
||||||
Common.Configuration.Multiplayer.MultiplayerMode.LdnMitm);
|
Common.Configuration.Multiplayer.MultiplayerMode.LdnMitm);
|
||||||
|
|
||||||
@ -1499,75 +1499,75 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
return new FileStream(safeHandle, FileAccess.ReadWrite);
|
return new FileStream(safeHandle, FileAccess.ReadWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GameInfo
|
public class GameInfo
|
||||||
{
|
|
||||||
public double FileSize;
|
|
||||||
public string? TitleName;
|
|
||||||
public string? TitleId;
|
|
||||||
public string? Developer;
|
|
||||||
public string? Version;
|
|
||||||
public byte[]? Icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe struct GameInfoNative
|
|
||||||
{
|
|
||||||
public ulong FileSize;
|
|
||||||
public fixed byte TitleName[512];
|
|
||||||
public ulong TitleId;
|
|
||||||
public fixed byte Developer[256];
|
|
||||||
public uint Version;
|
|
||||||
public byte* ImageData; // Changed to pointer
|
|
||||||
public uint ImageSize; // Actual size of image data
|
|
||||||
|
|
||||||
public GameInfoNative(ulong fileSize, string titleName, ulong titleId, string developer, uint version, byte[] imageData)
|
|
||||||
{
|
|
||||||
FileSize = fileSize;
|
|
||||||
TitleId = titleId;
|
|
||||||
Version = version;
|
|
||||||
|
|
||||||
fixed (byte* developerPtr = Developer)
|
|
||||||
fixed (byte* titleNamePtr = TitleName)
|
|
||||||
{
|
{
|
||||||
CopyStringToFixedArray(titleName, titleNamePtr, 512);
|
public double FileSize;
|
||||||
CopyStringToFixedArray(developer, developerPtr, 256);
|
public string? TitleName;
|
||||||
|
public string? TitleId;
|
||||||
|
public string? Developer;
|
||||||
|
public string? Version;
|
||||||
|
public byte[]? Icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageData == null || imageData.Length > 4096 * 4096)
|
public unsafe struct GameInfoNative
|
||||||
{
|
{
|
||||||
// throw new ArgumentException("Image data must not exceed 4 MB.");
|
public ulong FileSize;
|
||||||
ImageSize = (uint)0;
|
public fixed byte TitleName[512];
|
||||||
ImageData = null;
|
public ulong TitleId;
|
||||||
}
|
public fixed byte Developer[256];
|
||||||
else
|
public uint Version;
|
||||||
{
|
public byte* ImageData;
|
||||||
ImageSize = (uint)imageData.Length;
|
public uint ImageSize;
|
||||||
|
|
||||||
ImageData = (byte*)Marshal.AllocHGlobal(imageData.Length);
|
|
||||||
|
|
||||||
Marshal.Copy(imageData, 0, (IntPtr)ImageData, imageData.Length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't forget to free the allocated memory
|
public GameInfoNative(ulong fileSize, string titleName, ulong titleId, string developer, uint version, byte[] imageData)
|
||||||
public void Dispose()
|
{
|
||||||
{
|
FileSize = fileSize;
|
||||||
if (ImageData != null)
|
TitleId = titleId;
|
||||||
{
|
Version = version;
|
||||||
Marshal.FreeHGlobal((IntPtr)ImageData);
|
|
||||||
ImageData = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static void CopyStringToFixedArray(string source, byte* destination, int length)
|
|
||||||
{
|
|
||||||
var span = new Span<byte>(destination, length);
|
|
||||||
Encoding.UTF8.GetBytes(source, span);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CopyArrayToFixedArray(byte[] source, byte* destination, int maxLength)
|
fixed (byte* developerPtr = Developer)
|
||||||
{
|
fixed (byte* titleNamePtr = TitleName)
|
||||||
var span = new Span<byte>(destination, maxLength);
|
{
|
||||||
source.AsSpan().CopyTo(span);
|
CopyStringToFixedArray(titleName, titleNamePtr, 512);
|
||||||
|
CopyStringToFixedArray(developer, developerPtr, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageData == null || imageData.Length > 4096 * 4096)
|
||||||
|
{
|
||||||
|
// throw new ArgumentException("Image data must not exceed 4 MB.");
|
||||||
|
ImageSize = (uint)0;
|
||||||
|
ImageData = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImageSize = (uint)imageData.Length;
|
||||||
|
|
||||||
|
ImageData = (byte*)Marshal.AllocHGlobal(imageData.Length);
|
||||||
|
|
||||||
|
Marshal.Copy(imageData, 0, (IntPtr)ImageData, imageData.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't forget to free the allocated memory
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (ImageData != null)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal((IntPtr)ImageData);
|
||||||
|
ImageData = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void CopyStringToFixedArray(string source, byte* destination, int length)
|
||||||
|
{
|
||||||
|
var span = new Span<byte>(destination, length);
|
||||||
|
Encoding.UTF8.GetBytes(source, span);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CopyArrayToFixedArray(byte[] source, byte* destination, int maxLength)
|
||||||
|
{
|
||||||
|
var span = new Span<byte>(destination, maxLength);
|
||||||
|
source.AsSpan().CopyTo(span);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user