Gondwana Game Engine Development (master) - 2.6.1
Gondwana is a cross-platform 2.5D game and rendering engine written in C#/.NET 8. It provides fine-grained control over rendering, timing, and scene composition, with built-in support for parallax, z-ordering, pixel overhang, collision detection, and particle effects. Gondwana targets desktop and web platforms using SkiaSharp for graphics and pluggable audio backends for desktop and browser targets.
Loading...
Searching...
No Matches
TilesheetFactory.cs
3using SkiaSharp;
4
6
10internal static class TilesheetFactory
11{
12 #region factory methods
13
14 internal static Tilesheet FromBitmap(string name, SKBitmap bitmap) => new(name, bitmap);
15
16 internal static Tilesheet FromStream(string name, Stream stream) => new(name, stream);
17
18 internal static Tilesheet FromImageFile(string name, string imageFilePath) => new(name, imageFilePath);
19
20 internal static Tilesheet FromAssetsFile(AssetsFile assetsFile, string entryName) => new(assetsFile, entryName);
21
22 internal static Tilesheet FromDefinitionFile(string gtsPath)
23 {
24 if (string.IsNullOrWhiteSpace(gtsPath))
25 throw new ArgumentException("GTS path must be a non-empty string.", nameof(gtsPath));
26
27 var fullPath = Path.GetFullPath(gtsPath);
28 if (!File.Exists(fullPath))
29 throw new FileNotFoundException($"GTS file not found: {fullPath}", fullPath);
30
31 var definition = TilesheetDefinitionSerializer.Load(fullPath);
32 return FromDefinition(definition, Path.GetDirectoryName(fullPath));
33 }
34
35 internal static Tilesheet FromDefinition(TilesheetDefinition definition,
36 string? baseDirectory = null,
37 AssetsFile? defaultAssetsFile = null)
38 {
39 ArgumentNullException.ThrowIfNull(definition);
40
41 var tilesheet = CreateTilesheet(
42 definition,
43 addDefaultRegion: false,
44 baseDirectory,
45 defaultAssetsFile);
46
47 foreach (var region in definition.Regions)
48 {
49 var runtimeRegion = tilesheet.AddRegion(
50 region.Name,
51 region.Area,
52 region.TileSize,
53 region.TilePadding,
54 region.RegionMargin,
55 region.Overhang,
56 region.CollisionAdjust,
57 region.CollisionType);
58
59 // A missing frame value inherits the region default. A present value is
60 // an explicit override, even when it currently equals that default.
61 foreach (var frame in region.Frames ?? [])
62 {
63 if (frame.CollisionAdjust is { } adjust)
64 {
65 runtimeRegion.SetFrameCollisionAdjust(
66 frame.XTile,
67 frame.YTile,
68 adjust);
69 }
70
71 if (frame.CollisionType is { } collisionType)
72 {
73 runtimeRegion.SetFrameCollisionType(
74 frame.XTile,
75 frame.YTile,
76 collisionType);
77 }
78 }
79 }
80
81 if (definition.Mask is not null)
82 {
83 tilesheet.ApplyMask(
84 new SKColor(
85 definition.Mask.Red,
86 definition.Mask.Green,
87 definition.Mask.Blue,
88 definition.Mask.Alpha),
89 definition.Mask.Tolerance);
90 }
91 else if (definition.PremultiplyAlpha)
92 {
93 tilesheet.ApplyPremultiplyAlpha();
94 }
95
96 tilesheet.DefinitionProvenance = definition.LoadStamp?.Materialized(definition,
97 () => TilesheetDefinitionSerializer.FromTilesheet(tilesheet));
98 return tilesheet;
99 }
100
101 internal static Tilesheet FromDefinitionAsset(AssetsFile assetsFile, string gtsEntryName)
102 {
103 ArgumentNullException.ThrowIfNull(assetsFile);
104
105 if (string.IsNullOrWhiteSpace(gtsEntryName))
106 {
107 throw new ArgumentException(
108 "GTS asset entry name must be a non-empty string.",
109 nameof(gtsEntryName));
110 }
111
112 using var stream = assetsFile.Get(AssetTypes.TilesheetDefinition, gtsEntryName);
113
114 if (stream is null)
115 {
116 throw new InvalidOperationException(
117 $"Tilesheet definition asset '{gtsEntryName}' could not be found in AssetsFile '{assetsFile.SourcePath}'.");
118 }
119
120 var definition = TilesheetDefinitionSerializer.Load(stream);
121
122 definition.Source = TilesheetDefinitionSource.None();
123 if (!string.IsNullOrWhiteSpace(assetsFile.SourcePath))
124 {
125 definition.Source = TilesheetDefinitionSource.PackedDefinitionFile(
126 assetsFile.SourcePath,
127 gtsEntryName);
128 }
129
130 definition.LoadStamp = new(definition, assetsFilePath: assetsFile.SourcePath, entryName: gtsEntryName);
131
132 var baseDirectory = string.IsNullOrWhiteSpace(assetsFile.SourcePath)
133 ? null
134 : Path.GetDirectoryName(Path.GetFullPath(assetsFile.SourcePath));
135
136 return FromDefinition(
137 definition,
138 baseDirectory,
139 defaultAssetsFile: assetsFile);
140 }
141
142 #endregion factory methods
143
144 #region private methods
145
146 private static Tilesheet CreateTilesheet(
147 TilesheetDefinition definition,
148 bool addDefaultRegion,
149 string? baseDirectory = null,
150 AssetsFile? defaultAssetsFile = null)
151 {
152 var image = definition.Image
153 ?? throw new InvalidOperationException(
154 "TilesheetDefinition must specify an image source.");
155
156 ValidateImageDefinition(image, defaultAssetsFile);
157
158 if (!string.IsNullOrWhiteSpace(image.FilePath))
159 {
160 return new Tilesheet(
161 definition.Name,
162 ResolvePath(image.FilePath, baseDirectory),
163 addDefaultRegion);
164 }
165
166 AssetsFile assetsFile;
167
168 if (!string.IsNullOrWhiteSpace(image.AssetsFilePath))
169 {
170 assetsFile = LoadExistingAssetsFile(
171 ResolvePath(image.AssetsFilePath, baseDirectory));
172 }
173 else
174 {
175 assetsFile = defaultAssetsFile!;
176 }
177
178 var tilesheet = new Tilesheet(
179 assetsFile,
180 image.AssetEntryName!,
181 addDefaultRegion);
182
183 // The asset entry identifies the image; it is not necessarily the logical
184 // name assigned to the tilesheet by the GTS definition.
185 tilesheet.Name = definition.Name;
186
187 return tilesheet;
188 }
189
190 private static void ValidateImageDefinition(TilesheetImageDefinition image, AssetsFile? defaultAssetsFile)
191 {
192 var hasFilePath = !string.IsNullOrWhiteSpace(image.FilePath);
193 var hasAssetsFilePath = !string.IsNullOrWhiteSpace(image.AssetsFilePath);
194 var hasAssetEntryName = !string.IsNullOrWhiteSpace(image.AssetEntryName);
195
196 if (hasFilePath && (hasAssetsFilePath || hasAssetEntryName))
197 {
198 throw new InvalidOperationException(
199 "TilesheetDefinition image source is ambiguous. Image.FilePath cannot be combined with Image.AssetsFilePath or Image.AssetEntryName.");
200 }
201
202 if (hasAssetsFilePath && !hasAssetEntryName)
203 {
204 throw new InvalidOperationException(
205 "TilesheetDefinition image specifies an AssetsFilePath but does not specify an AssetEntryName.");
206 }
207
208 if (hasFilePath)
209 return;
210
211 if (!hasAssetEntryName)
212 {
213 throw new InvalidOperationException(
214 "TilesheetDefinition must specify either Image.FilePath or Image.AssetEntryName.");
215 }
216
217 if (!hasAssetsFilePath && defaultAssetsFile is null)
218 {
219 throw new InvalidOperationException(
220 "TilesheetDefinition image specifies an AssetEntryName but does not specify an AssetsFilePath, and no default AssetsFile was provided.");
221 }
222 }
223
224 private static AssetsFile LoadExistingAssetsFile(string path)
225 {
226 if (string.IsNullOrWhiteSpace(path))
227 throw new ArgumentException("Assets file path must be a non-empty string.", nameof(path));
228
229 var fullPath = Path.GetFullPath(path);
230 var loaded = AssetsFile.AllAssetsFiles.FirstOrDefault(file =>
231 !string.IsNullOrWhiteSpace(file.SourcePath) && string.Equals(Path.GetFullPath(file.SourcePath), fullPath,
232 OperatingSystem.IsWindows() ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal));
233 if (loaded is not null) return loaded;
234 if (!File.Exists(fullPath))
235 throw new FileNotFoundException($"Assets file not found: {fullPath}", fullPath);
236
237 return AssetsFile.LoadOrCreate(fullPath);
238 }
239
240 private static string ResolvePath(string path, string? baseDirectory)
241 {
242 if (Path.IsPathRooted(path) || string.IsNullOrWhiteSpace(baseDirectory))
243 return path;
244
245 return Path.GetFullPath(Path.Combine(baseDirectory, path));
246 }
247
248 #endregion private methods
249}
string? SourcePath
Gets the archive's reconstructible origin, including an optional stream origin.
Stream? Get(AssetTypes type, string name)
Retrieves a stream for the specified asset type and name.
List< TilesheetRegionDefinition > Regions
Gets or sets the list of region definitions that define subdivisions within the tilesheet.
TilesheetMaskDefinition? Mask
Gets or sets the mask definition for color transparency, or null if no mask is applied.
string Name
Gets or sets the name of the tilesheet.
bool PremultiplyAlpha
Gets or sets a value indicating whether alpha should be premultiplied when loading the tilesheet imag...
string? AssetsFilePath
Gets or sets the path to the assets file containing the tilesheet image.
string? AssetEntryName
Gets or sets the name of the specific entry within an assets file that contains the tilesheet image.
string? FilePath
Gets or sets the direct file path to the tilesheet image.
byte Tolerance
Gets or sets the tolerance value for color matching, allowing colors within a range to be considered ...
byte Alpha
Gets or sets the alpha (opacity) component of the mask color (0-255).
byte Blue
Gets or sets the blue component of the mask color (0-255).
byte Red
Gets or sets the red component of the mask color (0-255).
byte Green
Gets or sets the green component of the mask color (0-255).
AssetTypes
Defines the types of assets that can be stored and managed by the engine.
Definition AssetTypes.cs:8
@ TilesheetDefinition
Represents a tilesheet definition file (.gts) for Gondwana.Drawing.Tilesheets.GTS....
Definition AssetTypes.cs:47