9
9
*/
10
10
#endregion
11
11
12
+ using System ;
12
13
using System . Collections . Generic ;
14
+ using System . IO ;
13
15
using System . Linq ;
14
16
using OpenRA . Graphics ;
15
17
using OpenRA . Mods . Common . Graphics ;
16
18
using OpenRA . Primitives ;
17
19
18
20
namespace OpenRA . Mods . Cnc . Graphics
19
21
{
22
+ class MaskedFrame : ISpriteFrame
23
+ {
24
+ readonly ISpriteFrame inner ;
25
+ readonly ISpriteFrame mask ;
26
+ byte [ ] data ;
27
+
28
+ public MaskedFrame ( ISpriteFrame inner , ISpriteFrame mask )
29
+ {
30
+ this . inner = inner ;
31
+ this . mask = mask ;
32
+ }
33
+
34
+ public SpriteFrameType Type => inner . Type ;
35
+ public Size Size => inner . Size ;
36
+ public Size FrameSize => inner . FrameSize ;
37
+ public float2 Offset => inner . Offset ;
38
+ public bool DisableExportPadding => inner . DisableExportPadding ;
39
+
40
+ public byte [ ] Data
41
+ {
42
+ get
43
+ {
44
+ if ( data == null )
45
+ {
46
+ data = new byte [ inner . Data . Length ] ;
47
+
48
+ var channels = inner . Data . Length / mask . Data . Length ;
49
+ for ( var j = 0 ; j < mask . Data . Length ; j ++ )
50
+ if ( mask . Data [ j ] != 0 )
51
+ for ( var k = 0 ; k < channels ; k ++ )
52
+ data [ j * channels + k ] = inner . Data [ j * channels + k ] ;
53
+ }
54
+
55
+ return data ;
56
+ }
57
+ }
58
+ }
59
+
20
60
public class RemasterSpriteSequenceLoader : ClassicTilesetSpecificSpriteSequenceLoader
21
61
{
22
62
public readonly float ClassicUpscaleFactor = 5.333333f ;
@@ -173,8 +213,6 @@ public RemasterSpriteSequence(SpriteCache cache, ISpriteSequenceLoader loader, s
173
213
length = null ;
174
214
}
175
215
176
- int ? remasteredMaskToken ;
177
-
178
216
public override void ReserveSprites ( ModData modData , string tileset , SpriteCache cache , MiniYaml data , MiniYaml defaults )
179
217
{
180
218
var frames = LoadField ( Frames , data , defaults ) ;
@@ -187,8 +225,32 @@ public override void ReserveSprites(ModData modData, string tileset, SpriteCache
187
225
var blendMode = LoadField ( BlendMode , data , defaults ) ;
188
226
var premultiplied = LoadField ( RemasteredPremultiplied , data , defaults ) ;
189
227
228
+ ISpriteFrame [ ] maskFrames = null ;
229
+ Func < ISpriteFrame , int , int , ISpriteFrame > adjustFrame = null ;
190
230
if ( ! string . IsNullOrEmpty ( remasteredMaskFilename ) )
191
- remasteredMaskToken = cache . ReserveFrames ( remasteredMaskFilename , null , remasteredMaskFilenameLocation ) ;
231
+ adjustFrame = MaskFrame ;
232
+
233
+ ISpriteFrame MaskFrame ( ISpriteFrame f , int index , int total )
234
+ {
235
+ if ( maskFrames == null )
236
+ {
237
+ maskFrames = cache . LoadFramesUncached ( remasteredMaskFilename ) ;
238
+ if ( maskFrames == null )
239
+ throw new FileNotFoundException ( $ "{ remasteredMaskFilenameLocation } : { remasteredMaskFilename } not found", remasteredMaskFilename ) ;
240
+
241
+ if ( maskFrames . Length != total )
242
+ throw new YamlException ( $ "Sequence { image } .{ Name } with { total } frames cannot use mask with { maskFrames . Length } frames.") ;
243
+ }
244
+
245
+ var m = maskFrames [ index ] ;
246
+ if ( f . Size != m . Size )
247
+ throw new YamlException ( $ "Sequence { image } .{ Name } frame { index } with size { f . Size } frames cannot use mask with size { m . Size } .") ;
248
+
249
+ if ( m . Type != SpriteFrameType . Indexed8 )
250
+ throw new YamlException ( $ "Sequence { image } .{ Name } mask frame { index } must be an indexed image.") ;
251
+
252
+ return new MaskedFrame ( f , maskFrames [ index ] ) ;
253
+ }
192
254
193
255
var combineNode = data . Nodes . FirstOrDefault ( n => n . Key == Combine . Key ) ;
194
256
if ( combineNode != null )
@@ -204,11 +266,7 @@ public override void ReserveSprites(ModData modData, string tileset, SpriteCache
204
266
205
267
foreach ( var f in ParseRemasterCombineFilenames ( modData , tileset , subFrames , subData ) )
206
268
{
207
- int token ;
208
- if ( remasteredMaskToken != null )
209
- token = cache . ReserveFrames ( f . Filename , f . LoadFrames , f . Location ) ;
210
- else
211
- token = cache . ReserveSprites ( f . Filename , f . LoadFrames , f . Location , premultiplied : hasRemasteredSprite && premultiplied ) ;
269
+ var token = cache . ReserveSprites ( f . Filename , f . LoadFrames , f . Location , adjustFrame , hasRemasteredSprite && premultiplied ) ;
212
270
213
271
spritesToLoad . Add ( new SpriteReservation
214
272
{
@@ -227,11 +285,7 @@ public override void ReserveSprites(ModData modData, string tileset, SpriteCache
227
285
{
228
286
foreach ( var f in ParseRemasterFilenames ( modData , tileset , frames , data , defaults ) )
229
287
{
230
- int token ;
231
- if ( remasteredMaskToken != null )
232
- token = cache . ReserveFrames ( f . Filename , f . LoadFrames , f . Location ) ;
233
- else
234
- token = cache . ReserveSprites ( f . Filename , f . LoadFrames , f . Location , premultiplied : hasRemasteredSprite && premultiplied ) ;
288
+ var token = cache . ReserveSprites ( f . Filename , f . LoadFrames , f . Location , adjustFrame , hasRemasteredSprite && premultiplied ) ;
235
289
236
290
spritesToLoad . Add ( new SpriteReservation
237
291
{
@@ -247,136 +301,6 @@ public override void ReserveSprites(ModData modData, string tileset, SpriteCache
247
301
}
248
302
}
249
303
250
- public override void ResolveSprites ( SpriteCache cache )
251
- {
252
- if ( bounds != null )
253
- return ;
254
-
255
- Sprite depthSprite = null ;
256
- if ( depthSpriteReservation != null )
257
- depthSprite = cache . ResolveSprites ( depthSpriteReservation . Value ) . First ( s => s != null ) ;
258
-
259
- Sprite [ ] allSprites ;
260
- if ( remasteredMaskToken != null )
261
- {
262
- var maskFrames = cache . ResolveFrames ( remasteredMaskToken . Value ) ;
263
- var allFrames = spritesToLoad . SelectMany < SpriteReservation , ( SpriteReservation , ISpriteFrame ) > ( r =>
264
- {
265
- var resolved = cache . ResolveFrames ( r . Token ) ;
266
- if ( r . Frames != null )
267
- return r . Frames . Select ( f => ( r , resolved [ f ] ) ) ;
268
-
269
- return resolved . Select ( f => ( r , f ) ) ;
270
- } ) . ToArray ( ) ;
271
-
272
- var frameLength = length ?? allFrames . Length - start ;
273
- if ( maskFrames . Length != frameLength )
274
- throw new YamlException ( $ "Sequence { image } .{ Name } with { frameLength } frames cannot use mask with { maskFrames . Length } frames.") ;
275
-
276
- allSprites = new Sprite [ allFrames . Length ] ;
277
- for ( var i = 0 ; i < frameLength ; i ++ )
278
- {
279
- ( var r , var frame ) = allFrames [ start + i ] ;
280
- var mask = maskFrames [ i ] ;
281
- if ( frame . Size != mask . Size )
282
- throw new YamlException ( $ "Sequence { image } .{ Name } frame { i } with size { frame . Size } frames cannot use mask with size { mask . Size } .") ;
283
-
284
- if ( mask . Type != SpriteFrameType . Indexed8 )
285
- throw new YamlException ( $ "Sequence { image } .{ Name } mask frame { i } must be an indexed image.") ;
286
-
287
- var data = new byte [ frame . Data . Length ] ;
288
- var channels = frame . Data . Length / mask . Data . Length ;
289
- for ( var j = 0 ; j < mask . Data . Length ; j ++ )
290
- if ( mask . Data [ j ] != 0 )
291
- for ( var k = 0 ; k < channels ; k ++ )
292
- data [ j * channels + k ] = frame . Data [ j * channels + k ] ;
293
-
294
- var s = cache . SheetBuilders [ SheetBuilder . FrameTypeToSheetType ( frame . Type ) ]
295
- . Add ( data , frame . Type , frame . Size , 0 , frame . Offset ) ;
296
-
297
- var dx = r . Offset . X + ( r . FlipX ? - s . Offset . X : s . Offset . X ) ;
298
- var dy = r . Offset . Y + ( r . FlipY ? - s . Offset . Y : s . Offset . Y ) ;
299
- var dz = r . Offset . Z + s . Offset . Z + r . ZRamp * dy ;
300
- s = new Sprite ( s . Sheet , FlipRectangle ( s . Bounds , r . FlipX , r . FlipY ) , r . ZRamp , new float3 ( dx , dy , dz ) , s . Channel , r . BlendMode ) ;
301
-
302
- if ( depthSprite != null )
303
- {
304
- var cw = ( depthSprite . Bounds . Left + depthSprite . Bounds . Right ) / 2 + ( int ) ( s . Offset . X + depthSpriteOffset . X ) ;
305
- var ch = ( depthSprite . Bounds . Top + depthSprite . Bounds . Bottom ) / 2 + ( int ) ( s . Offset . Y + depthSpriteOffset . Y ) ;
306
- var w = s . Bounds . Width / 2 ;
307
- var h = s . Bounds . Height / 2 ;
308
-
309
- s = new SpriteWithSecondaryData ( s , depthSprite . Sheet , Rectangle . FromLTRB ( cw - w , ch - h , cw + w , ch + h ) , depthSprite . Channel ) ;
310
- }
311
-
312
- allSprites [ start + i ] = s ;
313
- }
314
- }
315
- else
316
- {
317
- allSprites = spritesToLoad . SelectMany ( r =>
318
- {
319
- var resolved = cache . ResolveSprites ( r . Token ) ;
320
- if ( r . Frames != null )
321
- resolved = r . Frames . Select ( f => resolved [ f ] ) . ToArray ( ) ;
322
-
323
- return resolved . Select ( s =>
324
- {
325
- if ( s == null )
326
- return null ;
327
-
328
- var dx = r . Offset . X + ( r . FlipX ? - s . Offset . X : s . Offset . X ) ;
329
- var dy = r . Offset . Y + ( r . FlipY ? - s . Offset . Y : s . Offset . Y ) ;
330
- var dz = r . Offset . Z + s . Offset . Z + r . ZRamp * dy ;
331
- var sprite = new Sprite ( s . Sheet , FlipRectangle ( s . Bounds , r . FlipX , r . FlipY ) , r . ZRamp , new float3 ( dx , dy , dz ) , s . Channel , r . BlendMode ) ;
332
- if ( depthSprite == null )
333
- return sprite ;
334
-
335
- var cw = ( depthSprite . Bounds . Left + depthSprite . Bounds . Right ) / 2 + ( int ) ( s . Offset . X + depthSpriteOffset . X ) ;
336
- var ch = ( depthSprite . Bounds . Top + depthSprite . Bounds . Bottom ) / 2 + ( int ) ( s . Offset . Y + depthSpriteOffset . Y ) ;
337
- var w = s . Bounds . Width / 2 ;
338
- var h = s . Bounds . Height / 2 ;
339
-
340
- return new SpriteWithSecondaryData ( sprite , depthSprite . Sheet , Rectangle . FromLTRB ( cw - w , ch - h , cw + w , ch + h ) , depthSprite . Channel ) ;
341
- } ) ;
342
- } ) . ToArray ( ) ;
343
- }
344
-
345
- length ??= allSprites . Length - start ;
346
-
347
- if ( alpha != null )
348
- {
349
- if ( alpha . Length == 1 )
350
- alpha = Exts . MakeArray ( length . Value , _ => alpha [ 0 ] ) ;
351
- else if ( alpha . Length != length . Value )
352
- throw new YamlException ( $ "Sequence { image } .{ Name } must define either 1 or { length . Value } Alpha values.") ;
353
- }
354
- else if ( alphaFade )
355
- alpha = Exts . MakeArray ( length . Value , i => float2 . Lerp ( 1f , 0f , i / ( length . Value - 1f ) ) ) ;
356
-
357
- // Reindex sprites to order facings anti-clockwise and remove unused frames
358
- var index = CalculateFrameIndices ( start , length . Value , stride ?? length . Value , facings , null , transpose , reverseFacings , - 1 ) ;
359
- if ( reverses )
360
- {
361
- index . AddRange ( index . Skip ( 1 ) . Take ( length . Value - 2 ) . Reverse ( ) ) ;
362
- length = 2 * length - 2 ;
363
- }
364
-
365
- if ( index . Count == 0 )
366
- throw new YamlException ( $ "Sequence { image } .{ Name } does not define any frames.") ;
367
-
368
- var minIndex = index . Min ( ) ;
369
- var maxIndex = index . Max ( ) ;
370
- if ( minIndex < 0 || maxIndex >= allSprites . Length )
371
- throw new YamlException ( $ "Sequence { image } .{ Name } uses frames between { minIndex } ..{ maxIndex } , but only 0..{ allSprites . Length - 1 } exist.") ;
372
-
373
- sprites = index . Select ( f => allSprites [ f ] ) . ToArray ( ) ;
374
- if ( shadowStart >= 0 )
375
- shadowSprites = index . Select ( f => allSprites [ f - start + shadowStart ] ) . ToArray ( ) ;
376
-
377
- bounds = sprites . Concat ( shadowSprites ?? Enumerable . Empty < Sprite > ( ) ) . Select ( OffsetSpriteBounds ) . Union ( ) ;
378
- }
379
-
380
304
protected override float GetScale ( )
381
305
{
382
306
if ( ! hasRemasteredSprite )
0 commit comments