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
+ sealed 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 ;
@@ -67,8 +107,6 @@ public class RemasterSpriteSequence : ClassicTilesetSpecificSpriteSequence
67
107
[ Desc ( "Sprite data is already pre-multiplied by alpha channel." ) ]
68
108
protected static readonly SpriteSequenceField < bool > RemasteredPremultiplied = new ( nameof ( RemasteredPremultiplied ) , true ) ;
69
109
70
- static readonly int [ ] FirstFrame = { 0 } ;
71
-
72
110
bool hasRemasteredSprite = true ;
73
111
74
112
IEnumerable < ReservationInfo > ParseRemasterFilenames ( ModData modData , string tileset , int [ ] frames , MiniYaml data , MiniYaml defaults )
@@ -175,8 +213,6 @@ public RemasterSpriteSequence(SpriteCache cache, ISpriteSequenceLoader loader, s
175
213
length = null ;
176
214
}
177
215
178
- int ? remasteredMaskToken ;
179
-
180
216
public override void ReserveSprites ( ModData modData , string tileset , SpriteCache cache , MiniYaml data , MiniYaml defaults )
181
217
{
182
218
var frames = LoadField ( Frames , data , defaults ) ;
@@ -189,13 +225,37 @@ public override void ReserveSprites(ModData modData, string tileset, SpriteCache
189
225
var blendMode = LoadField ( BlendMode , data , defaults ) ;
190
226
var premultiplied = LoadField ( RemasteredPremultiplied , data , defaults ) ;
191
227
228
+ ISpriteFrame [ ] maskFrames = null ;
229
+ Func < ISpriteFrame , int , int , ISpriteFrame > adjustFrame = null ;
192
230
if ( ! string . IsNullOrEmpty ( remasteredMaskFilename ) )
193
- 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
+ }
194
254
195
255
var combineNode = data . Nodes . FirstOrDefault ( n => n . Key == Combine . Key ) ;
196
256
if ( combineNode != null )
197
257
{
198
- for ( var i = 0 ; i < combineNode . Value . Nodes . Count ; i ++ )
258
+ for ( var i = 0 ; i < combineNode . Value . Nodes . Length ; i ++ )
199
259
{
200
260
var subData = combineNode . Value . Nodes [ i ] . Value ;
201
261
var subOffset = LoadField ( Offset , subData , NoData ) ;
@@ -206,11 +266,7 @@ public override void ReserveSprites(ModData modData, string tileset, SpriteCache
206
266
207
267
foreach ( var f in ParseRemasterCombineFilenames ( modData , tileset , subFrames , subData ) )
208
268
{
209
- int token ;
210
- if ( remasteredMaskToken != null )
211
- token = cache . ReserveFrames ( f . Filename , f . LoadFrames , f . Location ) ;
212
- else
213
- token = cache . ReserveSprites ( f . Filename , f . LoadFrames , f . Location , hasRemasteredSprite && premultiplied ) ;
269
+ var token = cache . ReserveSprites ( f . Filename , f . LoadFrames , f . Location , adjustFrame , hasRemasteredSprite && premultiplied ) ;
214
270
215
271
spritesToLoad . Add ( new SpriteReservation
216
272
{
@@ -229,11 +285,7 @@ public override void ReserveSprites(ModData modData, string tileset, SpriteCache
229
285
{
230
286
foreach ( var f in ParseRemasterFilenames ( modData , tileset , frames , data , defaults ) )
231
287
{
232
- int token ;
233
- if ( remasteredMaskToken != null )
234
- token = cache . ReserveFrames ( f . Filename , f . LoadFrames , f . Location ) ;
235
- else
236
- token = cache . ReserveSprites ( f . Filename , f . LoadFrames , f . Location , hasRemasteredSprite && premultiplied ) ;
288
+ var token = cache . ReserveSprites ( f . Filename , f . LoadFrames , f . Location , adjustFrame , hasRemasteredSprite && premultiplied ) ;
237
289
238
290
spritesToLoad . Add ( new SpriteReservation
239
291
{
@@ -249,136 +301,6 @@ public override void ReserveSprites(ModData modData, string tileset, SpriteCache
249
301
}
250
302
}
251
303
252
- public override void ResolveSprites ( SpriteCache cache )
253
- {
254
- if ( bounds != null )
255
- return ;
256
-
257
- Sprite depthSprite = null ;
258
- if ( depthSpriteReservation != null )
259
- depthSprite = cache . ResolveSprites ( depthSpriteReservation . Value ) . First ( s => s != null ) ;
260
-
261
- Sprite [ ] allSprites ;
262
- if ( remasteredMaskToken != null )
263
- {
264
- var maskFrames = cache . ResolveFrames ( remasteredMaskToken . Value ) ;
265
- var allFrames = spritesToLoad . SelectMany < SpriteReservation , ( SpriteReservation , ISpriteFrame ) > ( r =>
266
- {
267
- var resolved = cache . ResolveFrames ( r . Token ) ;
268
- if ( r . Frames != null )
269
- return r . Frames . Select ( f => ( r , resolved [ f ] ) ) ;
270
-
271
- return resolved . Select ( f => ( r , f ) ) ;
272
- } ) . ToArray ( ) ;
273
-
274
- var frameLength = length ?? allFrames . Length - start ;
275
- if ( maskFrames . Length != frameLength )
276
- throw new YamlException ( $ "Sequence { image } .{ Name } with { frameLength } frames cannot use mask with { maskFrames . Length } frames.") ;
277
-
278
- allSprites = new Sprite [ allFrames . Length ] ;
279
- for ( var i = 0 ; i < frameLength ; i ++ )
280
- {
281
- ( var r , var frame ) = allFrames [ start + i ] ;
282
- var mask = maskFrames [ i ] ;
283
- if ( frame . Size != mask . Size )
284
- throw new YamlException ( $ "Sequence { image } .{ Name } frame { i } with size { frame . Size } frames cannot use mask with size { mask . Size } .") ;
285
-
286
- if ( mask . Type != SpriteFrameType . Indexed8 )
287
- throw new YamlException ( $ "Sequence { image } .{ Name } mask frame { i } must be an indexed image.") ;
288
-
289
- var data = new byte [ frame . Data . Length ] ;
290
- var channels = frame . Data . Length / mask . Data . Length ;
291
- for ( var j = 0 ; j < mask . Data . Length ; j ++ )
292
- if ( mask . Data [ j ] != 0 )
293
- for ( var k = 0 ; k < channels ; k ++ )
294
- data [ j * channels + k ] = frame . Data [ j * channels + k ] ;
295
-
296
- var s = cache . SheetBuilders [ SheetBuilder . FrameTypeToSheetType ( frame . Type ) ]
297
- . Add ( data , frame . Type , frame . Size , 0 , frame . Offset ) ;
298
-
299
- var dx = r . Offset . X + ( r . FlipX ? - s . Offset . X : s . Offset . X ) ;
300
- var dy = r . Offset . Y + ( r . FlipY ? - s . Offset . Y : s . Offset . Y ) ;
301
- var dz = r . Offset . Z + s . Offset . Z + r . ZRamp * dy ;
302
- s = new Sprite ( s . Sheet , FlipRectangle ( s . Bounds , r . FlipX , r . FlipY ) , r . ZRamp , new float3 ( dx , dy , dz ) , s . Channel , r . BlendMode ) ;
303
-
304
- if ( depthSprite != null )
305
- {
306
- var cw = ( depthSprite . Bounds . Left + depthSprite . Bounds . Right ) / 2 + ( int ) ( s . Offset . X + depthSpriteOffset . X ) ;
307
- var ch = ( depthSprite . Bounds . Top + depthSprite . Bounds . Bottom ) / 2 + ( int ) ( s . Offset . Y + depthSpriteOffset . Y ) ;
308
- var w = s . Bounds . Width / 2 ;
309
- var h = s . Bounds . Height / 2 ;
310
-
311
- s = new SpriteWithSecondaryData ( s , depthSprite . Sheet , Rectangle . FromLTRB ( cw - w , ch - h , cw + w , ch + h ) , depthSprite . Channel ) ;
312
- }
313
-
314
- allSprites [ start + i ] = s ;
315
- }
316
- }
317
- else
318
- {
319
- allSprites = spritesToLoad . SelectMany ( r =>
320
- {
321
- var resolved = cache . ResolveSprites ( r . Token ) ;
322
- if ( r . Frames != null )
323
- resolved = r . Frames . Select ( f => resolved [ f ] ) . ToArray ( ) ;
324
-
325
- return resolved . Select ( s =>
326
- {
327
- if ( s == null )
328
- return null ;
329
-
330
- var dx = r . Offset . X + ( r . FlipX ? - s . Offset . X : s . Offset . X ) ;
331
- var dy = r . Offset . Y + ( r . FlipY ? - s . Offset . Y : s . Offset . Y ) ;
332
- var dz = r . Offset . Z + s . Offset . Z + r . ZRamp * dy ;
333
- var sprite = new Sprite ( s . Sheet , FlipRectangle ( s . Bounds , r . FlipX , r . FlipY ) , r . ZRamp , new float3 ( dx , dy , dz ) , s . Channel , r . BlendMode ) ;
334
- if ( depthSprite == null )
335
- return sprite ;
336
-
337
- var cw = ( depthSprite . Bounds . Left + depthSprite . Bounds . Right ) / 2 + ( int ) ( s . Offset . X + depthSpriteOffset . X ) ;
338
- var ch = ( depthSprite . Bounds . Top + depthSprite . Bounds . Bottom ) / 2 + ( int ) ( s . Offset . Y + depthSpriteOffset . Y ) ;
339
- var w = s . Bounds . Width / 2 ;
340
- var h = s . Bounds . Height / 2 ;
341
-
342
- return new SpriteWithSecondaryData ( sprite , depthSprite . Sheet , Rectangle . FromLTRB ( cw - w , ch - h , cw + w , ch + h ) , depthSprite . Channel ) ;
343
- } ) ;
344
- } ) . ToArray ( ) ;
345
- }
346
-
347
- length ??= allSprites . Length - start ;
348
-
349
- if ( alpha != null )
350
- {
351
- if ( alpha . Length == 1 )
352
- alpha = Exts . MakeArray ( length . Value , _ => alpha [ 0 ] ) ;
353
- else if ( alpha . Length != length . Value )
354
- throw new YamlException ( $ "Sequence { image } .{ Name } must define either 1 or { length . Value } Alpha values.") ;
355
- }
356
- else if ( alphaFade )
357
- alpha = Exts . MakeArray ( length . Value , i => float2 . Lerp ( 1f , 0f , i / ( length . Value - 1f ) ) ) ;
358
-
359
- // Reindex sprites to order facings anti-clockwise and remove unused frames
360
- var index = CalculateFrameIndices ( start , length . Value , stride ?? length . Value , facings , null , transpose , reverseFacings , - 1 ) ;
361
- if ( reverses )
362
- {
363
- index . AddRange ( index . Skip ( 1 ) . Take ( length . Value - 2 ) . Reverse ( ) ) ;
364
- length = 2 * length - 2 ;
365
- }
366
-
367
- if ( index . Count == 0 )
368
- throw new YamlException ( $ "Sequence { image } .{ Name } does not define any frames.") ;
369
-
370
- var minIndex = index . Min ( ) ;
371
- var maxIndex = index . Max ( ) ;
372
- if ( minIndex < 0 || maxIndex >= allSprites . Length )
373
- throw new YamlException ( $ "Sequence { image } .{ Name } uses frames between { minIndex } ..{ maxIndex } , but only 0..{ allSprites . Length - 1 } exist.") ;
374
-
375
- sprites = index . Select ( f => allSprites [ f ] ) . ToArray ( ) ;
376
- if ( shadowStart >= 0 )
377
- shadowSprites = index . Select ( f => allSprites [ f - start + shadowStart ] ) . ToArray ( ) ;
378
-
379
- bounds = sprites . Concat ( shadowSprites ?? Enumerable . Empty < Sprite > ( ) ) . Select ( OffsetSpriteBounds ) . Union ( ) ;
380
- }
381
-
382
304
protected override float GetScale ( )
383
305
{
384
306
if ( ! hasRemasteredSprite )
0 commit comments