forked from MeloNX/MeloNX
Add Game Icon
This commit is contained in:
parent
e81ee8f8bf
commit
94dc643f26
src
MeloNX
MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad
MeloNX
Ryujinx.Headless.SDL2
BIN
src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate
generated
BIN
src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate
generated
Binary file not shown.
@ -21,7 +21,10 @@ struct GameInfo {
|
|||||||
long TitleId;
|
long TitleId;
|
||||||
char Developer[256];
|
char Developer[256];
|
||||||
int Version;
|
int Version;
|
||||||
|
unsigned char* ImageData;
|
||||||
|
unsigned int ImageSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct GameInfo get_game_info(int, char*);
|
extern struct GameInfo get_game_info(int, char*);
|
||||||
// Declare the main_ryujinx_sdl function, matching the signature
|
// Declare the main_ryujinx_sdl function, matching the signature
|
||||||
int main_ryujinx_sdl(int argc, char **argv);
|
int main_ryujinx_sdl(int argc, char **argv);
|
||||||
|
@ -20,5 +20,26 @@ public struct Game: Identifiable, Equatable {
|
|||||||
var titleId: String
|
var titleId: String
|
||||||
var developer: String
|
var developer: String
|
||||||
var version: String
|
var version: String
|
||||||
var icon: Image?
|
var icon: UIImage?
|
||||||
|
|
||||||
|
func createImage(from gameInfo: GameInfo) -> UIImage? {
|
||||||
|
// Access the struct
|
||||||
|
let gameInfoValue = gameInfo
|
||||||
|
|
||||||
|
// Get the image data
|
||||||
|
let imageSize = Int(gameInfoValue.ImageSize)
|
||||||
|
guard imageSize > 0, imageSize <= 1024 * 1024 else {
|
||||||
|
print("Invalid image size.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the ImageData byte array to Swift's Data
|
||||||
|
let imageData = Data(bytes: gameInfoValue.ImageData, count: imageSize)
|
||||||
|
|
||||||
|
// Create a UIImage (or NSImage on macOS)
|
||||||
|
|
||||||
|
print(imageData)
|
||||||
|
|
||||||
|
return UIImage(data: imageData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,22 +205,24 @@ struct GameLibraryView: View {
|
|||||||
var game = Game(containerFolder: romsDirectory, fileType: .item, fileURL: fileURLCandidate, titleName: "", titleId: "", developer: "", version: "")
|
var game = Game(containerFolder: romsDirectory, fileType: .item, fileURL: fileURLCandidate, titleName: "", titleId: "", developer: "", version: "")
|
||||||
|
|
||||||
game.titleName = withUnsafePointer(to: &gameInfo.TitleName) {
|
game.titleName = withUnsafePointer(to: &gameInfo.TitleName) {
|
||||||
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
|
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
|
||||||
String(cString: $0)
|
String(cString: $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game.developer = withUnsafePointer(to: &gameInfo.Developer) {
|
game.developer = withUnsafePointer(to: &gameInfo.Developer) {
|
||||||
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
|
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
|
||||||
String(cString: $0)
|
String(cString: $0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game.titleId = String(gameInfo.TitleId)
|
game.titleId = String(gameInfo.TitleId)
|
||||||
|
|
||||||
|
|
||||||
game.version = String(gameInfo.Version)
|
game.version = String(gameInfo.Version)
|
||||||
|
|
||||||
|
game.icon = game.createImage(from: gameInfo)
|
||||||
|
|
||||||
|
|
||||||
games.append(game)
|
games.append(game)
|
||||||
} catch {
|
} catch {
|
||||||
@ -274,7 +276,7 @@ struct RecentGameCard: View {
|
|||||||
}) {
|
}) {
|
||||||
VStack(alignment: .leading, spacing: 8) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
if let icon = game.icon {
|
if let icon = game.icon {
|
||||||
icon
|
Image(uiImage: icon)
|
||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fill)
|
||||||
.frame(width: 140, height: 140)
|
.frame(width: 140, height: 140)
|
||||||
@ -321,7 +323,7 @@ struct GameListRow: View {
|
|||||||
HStack(spacing: 16) {
|
HStack(spacing: 16) {
|
||||||
// Game Icon
|
// Game Icon
|
||||||
if let icon = game.icon {
|
if let icon = game.icon {
|
||||||
icon
|
Image(uiImage: icon)
|
||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fill)
|
||||||
.frame(width: 45, height: 45)
|
.frame(width: 45, height: 45)
|
||||||
|
@ -273,7 +273,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
|
|
||||||
var gameInfo = GetGameInfo(stream, extension);
|
var gameInfo = GetGameInfo(stream, extension);
|
||||||
|
|
||||||
return new GameInfoNative(0, gameInfo.TitleName, 0, gameInfo.Developer, 0);
|
return new GameInfoNative(0, gameInfo.TitleName, 0, gameInfo.Developer, 0, gameInfo.Icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameInfo? GetGameInfo(Stream gameStream, string extension)
|
public static GameInfo? GetGameInfo(Stream gameStream, string extension)
|
||||||
@ -1376,7 +1376,7 @@ 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 double FileSize;
|
||||||
public string? TitleName;
|
public string? TitleName;
|
||||||
@ -1386,33 +1386,63 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
public byte[]? Icon;
|
public byte[]? Icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe struct GameInfoNative
|
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)
|
||||||
{
|
{
|
||||||
public ulong FileSize;
|
FileSize = fileSize;
|
||||||
public fixed byte TitleName[512];
|
TitleId = titleId;
|
||||||
public ulong TitleId;
|
Version = version;
|
||||||
public fixed byte Developer[256];
|
|
||||||
public uint Version;
|
|
||||||
|
|
||||||
public GameInfoNative(ulong fileSize, string titleName, ulong titleId, string developer, uint version)
|
fixed (byte* developerPtr = Developer)
|
||||||
|
fixed (byte* titleNamePtr = TitleName)
|
||||||
{
|
{
|
||||||
FileSize = fileSize;
|
CopyStringToFixedArray(titleName, titleNamePtr, 512);
|
||||||
TitleId = titleId;
|
CopyStringToFixedArray(developer, developerPtr, 256);
|
||||||
Version = version;
|
|
||||||
|
|
||||||
fixed (byte* developerPtr = Developer)
|
|
||||||
fixed (byte* titleNamePtr = TitleName)
|
|
||||||
{
|
|
||||||
CopyStringToFixedArray(titleName, titleNamePtr, 512);
|
|
||||||
CopyStringToFixedArray(developer, developerPtr, 256);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CopyStringToFixedArray(string source, byte* destination, int length)
|
if (imageData == null || imageData.Length > 1024 * 1024)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Image data must not exceed 1 MB.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageSize = (uint)imageData.Length;
|
||||||
|
|
||||||
|
// Allocate unmanaged memory for the image data
|
||||||
|
ImageData = (byte*)Marshal.AllocHGlobal(imageData.Length);
|
||||||
|
|
||||||
|
// Copy the image data to the allocated memory
|
||||||
|
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);
|
var span = new Span<byte>(destination, length);
|
||||||
Encoding.UTF8.GetBytes(source, span);
|
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