Update AssetDatabase

This commit is contained in:
2026-01-27 14:39:00 +09:00
parent b505c7c1c0
commit 8a5795069f
23 changed files with 3135 additions and 53 deletions

View File

@@ -0,0 +1,70 @@
using Ghost.Core;
namespace Ghost.Editor.Core.AssetHandle.Importers;
/// <summary>
/// Example importer settings for text assets.
/// </summary>
internal class TextImporterSettings : ImporterSettings
{
public string Encoding
{
get;
set;
} = "UTF-8";
public bool TrimWhitespace
{
get;
set;
} = false;
}
/// <summary>
/// Example importer for text files (.txt, .md).
/// This is a simple test importer to demonstrate the asset import system.
/// </summary>
[AssetImporter(".txt", ".md")]
internal class TextImporter : AssetImporter<TextImporterSettings>
{
public override async Task<Result> ImportAsync(string assetPath, AssetMeta meta)
{
var settings = GetSettings(meta);
// Text files typically don't have dependencies
// If they did, you would extract them from the content here
var dependencies = new List<Guid>();
// Validate dependencies
var depResult = await ValidateDependenciesAsync(dependencies);
if (depResult.IsFailure)
{
return depResult;
}
try
{
// Read the file
var content = await File.ReadAllTextAsync(assetPath);
if (settings.TrimWhitespace)
{
content = content.Trim();
}
// TODO: Process the text content
// For example:
// - Convert to a specific format
// - Extract metadata
// - Generate assets
// - Save to output folder
// For now, just report success
return Result.Success();
}
catch (Exception ex)
{
return Result.Failure($"Failed to import text asset: {ex.Message}");
}
}
}

View File

@@ -0,0 +1,279 @@
using Ghost.Core;
using System.Text.Json;
namespace Ghost.Editor.Core.AssetHandle.Importers;
/// <summary>
/// Importer settings for texture assets.
/// </summary>
internal class TextureImporterSettings : ImporterSettings
{
/// <summary>
/// Whether to generate mipmaps for the texture.
/// </summary>
public bool GenerateMipmaps
{
get;
set;
} = true;
/// <summary>
/// Whether the texture uses sRGB color space.
/// </summary>
public bool SRGB
{
get;
set;
} = true;
/// <summary>
/// Maximum texture size. Images larger than this will be downscaled.
/// </summary>
public uint MaxSize
{
get;
set;
} = 2048;
/// <summary>
/// Texture compression format.
/// Options: "None", "BC1", "BC3", "BC7"
/// </summary>
public string CompressionFormat
{
get;
set;
} = "None";
/// <summary>
/// Texture filter mode.
/// Options: "Point", "Bilinear", "Trilinear"
/// </summary>
public string FilterMode
{
get;
set;
} = "Bilinear";
/// <summary>
/// Texture wrap mode.
/// Options: "Repeat", "Clamp", "Mirror"
/// </summary>
public string WrapMode
{
get;
set;
} = "Repeat";
}
/// <summary>
/// Importer for texture files (.png, .jpg, .jpeg, .dds, .tga, .bmp).
/// Processes image files and converts them into engine-ready texture assets.
/// </summary>
[AssetImporter(".png", ".jpg", ".jpeg", ".dds", ".tga", ".bmp")]
internal class TextureImporter : AssetImporter<TextureImporterSettings>
{
public override async Task<Result> ImportAsync(string assetPath, AssetMeta meta)
{
var settings = GetSettings(meta);
// Textures typically don't reference other assets as dependencies
// If they did (e.g., normal maps referencing base textures), extract here
var dependencies = new List<Guid>();
// Validate dependencies
var depResult = await ValidateDependenciesAsync(dependencies);
if (depResult.IsFailure)
{
return depResult;
}
try
{
// Check if file exists
if (!File.Exists(assetPath))
{
return Result.Failure($"Source texture file not found: {assetPath}");
}
// Get image dimensions (simplified - in real implementation would use image library)
var (width, height) = await GetImageDimensionsAsync(assetPath);
if (width == 0 || height == 0)
{
return Result.Failure("Failed to read image dimensions");
}
// Apply max size constraint
if (width > settings.MaxSize || height > settings.MaxSize)
{
var scale = Math.Min(settings.MaxSize / (float)width, settings.MaxSize / (float)height);
width = (uint)(width * scale);
height = (uint)(height * scale);
}
// Calculate mipmap count
uint mipLevels = 1;
if (settings.GenerateMipmaps)
{
mipLevels = CalculateMipLevels(width, height);
}
// Determine format
var format = settings.CompressionFormat == "None" ? "RGBA8" : settings.CompressionFormat;
// Create texture asset
var textureAsset = new TextureAsset(meta.Guid, Path.GetFileNameWithoutExtension(assetPath))
{
Width = width,
Height = height,
MipLevels = mipLevels,
Format = format,
IsSRGB = settings.SRGB,
SourcePath = assetPath
};
// Save the imported asset data
var saveResult = AssetDatabase.SaveImportedAsset(meta.Guid, textureAsset);
if (saveResult.IsFailure)
{
return Result.Failure($"Failed to save texture asset: {saveResult.Message}");
}
// In a real implementation, you would:
// 1. Load the image using a library like ImageSharp or StbImageSharp
// 2. Resize if needed
// 3. Generate mipmaps
// 4. Compress if needed
// 5. Save the processed texture data to the ImportedAssets folder
// 6. Update the hash in database
return Result.Success();
}
catch (Exception ex)
{
return Result.Failure($"Failed to import texture: {ex.Message}");
}
}
/// <summary>
/// Get image dimensions from file.
/// Simplified implementation - in production, use an image library.
/// </summary>
private async Task<(uint width, uint height)> GetImageDimensionsAsync(string imagePath)
{
// This is a placeholder implementation
// In a real implementation, you would use a library like:
// - ImageSharp
// - StbImageSharp
// - DirectXTex (for DDS files)
var extension = Path.GetExtension(imagePath).ToLowerInvariant();
if (extension == ".dds")
{
// For DDS files, read the header
// DDS header format: https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dds-header
return await ReadDDSHeaderAsync(imagePath);
}
else
{
// For PNG/JPG/etc, we would use an image library
// For now, return placeholder values
return await Task.FromResult<(uint, uint)>((1024, 1024));
}
}
/// <summary>
/// Read DDS file header to get dimensions.
/// </summary>
private async Task<(uint width, uint height)> ReadDDSHeaderAsync(string ddsPath)
{
try
{
await using var stream = File.OpenRead(ddsPath);
using var reader = new BinaryReader(stream);
// Read magic number (should be "DDS ")
var magic = reader.ReadUInt32();
if (magic != 0x20534444) // "DDS " in little-endian
{
return (0, 0);
}
// Read header size (should be 124)
var headerSize = reader.ReadUInt32();
if (headerSize != 124)
{
return (0, 0);
}
// Skip flags
reader.ReadUInt32();
// Read height and width
var height = reader.ReadUInt32();
var width = reader.ReadUInt32();
return (width, height);
}
catch
{
return (0, 0);
}
}
/// <summary>
/// Export a texture asset from memory to disk.
/// </summary>
public override async Task<Result> ExportAsync<T>(string assetPath, T assetData, AssetMeta meta)
{
if (assetData is not TextureAsset textureAsset)
{
return Result.Failure($"Asset data is not a TextureAsset, got {typeof(T).Name}");
}
try
{
// In a real implementation, you would:
// 1. Convert the texture data to the appropriate format
// 2. Write the image file (PNG, DDS, etc.)
// 3. Save metadata
// For now, just save metadata as JSON
var json = JsonSerializer.Serialize(textureAsset, new JsonSerializerOptions
{
WriteIndented = true
});
await File.WriteAllTextAsync(assetPath, json);
return Result.Success();
}
catch (Exception ex)
{
return Result.Failure($"Failed to export texture: {ex.Message}");
}
}
/// <summary>
/// Calculate number of mipmap levels for a given texture size.
/// </summary>
private static uint CalculateMipLevels(uint width, uint height)
{
if (width == 0 || height == 0)
{
return 0;
}
uint count = 1;
while (width > 1 || height > 1)
{
width >>= 1;
height >>= 1;
count++;
}
return count;
}
}