返回提交历史
Modified
Common/DeathDomainBackdropTextureSystem.cs
+106
-19
Modified
Common/DeathDomainVisualSystem.cs
+39
-100
XFEstudio/DeathMod
统一死亡领域背景缩放与世界采样
9314916
代码差异
2 个文件
+145
-119
@@ -22,6 +22,14 @@ internal sealed class DeathDomainBackdropTextureSystem : ModSystem
22
22
* (DeathNecklace.MaxCoreLevel - 1)) * 2f;
23
23
24
24
private static readonly Texture2D?[] layers = new Texture2D?[3];
25
private static readonly float[] expandedSourceX = new float[3];
26
private static readonly float[] expandedSourceY = new float[3];
27
private static readonly float[] expandedSourceWidth = new float[3];
28
private static readonly float[] expandedSourceHeight = new float[3];
29
private static ulong expandedFrameTick = ulong.MaxValue;
30
private static Vector2 expandedDestination;
31
private static float expandedDestinationWidth = 1f;
32
private static float expandedDestinationHeight = 1f;
25
33
26
34
internal static Texture2D GetLayer(int index)
27
35
{
@@ -29,6 +37,83 @@ internal sealed class DeathDomainBackdropTextureSystem : ModSystem
29
37
return layers[index] ??= CreateLayer(index);
30
38
}
31
39
40
/// <summary>
41
/// Returns the single world-space frame used by a fully manifested Death
42
/// Domain. Every smaller mask (necklace aperture, weapon wound and wing
43
/// trail) samples this frame and merely clips it, preventing the scenery
44
/// inside a cut from being enlarged to fit that cut.
45
/// </summary>
46
internal static void GetExpandedDomainSourceFrame(int layer,
47
out float sourceOffsetX, out float sourceOffsetY,
48
out float viewWidth, out float viewHeight)
49
{
50
EnsureExpandedDomainFrame();
51
layer = Math.Clamp(layer, 0, layers.Length - 1);
52
sourceOffsetX = expandedSourceX[layer];
53
sourceOffsetY = expandedSourceY[layer];
54
viewWidth = expandedSourceWidth[layer];
55
viewHeight = expandedSourceHeight[layer];
56
}
57
58
/// <summary>
59
/// Returns the rectangle occupied by the fully manifested domain in the
60
/// active world SpriteBatch's pre-transform coordinate space. This is also
61
/// the normalization frame for every world-space domain mask, so game zoom
62
/// cannot make weapon or wing cuts drift away from the necklace backdrop.
63
/// </summary>
64
internal static void GetExpandedDomainDrawBounds(
65
out Vector2 destination,
66
out float destinationWidth,
67
out float destinationHeight)
68
{
69
EnsureExpandedDomainFrame();
70
destination = expandedDestination;
71
destinationWidth = expandedDestinationWidth;
72
destinationHeight = expandedDestinationHeight;
73
}
74
75
private static void EnsureExpandedDomainFrame()
76
{
77
// A crescent or merged trail can contain thousands of vertices. Cache
78
// the inverse view transform and all three source plates once per game
79
// update instead of repeating a matrix inversion for every vertex.
80
if (expandedFrameTick == Main.GameUpdateCount)
81
return;
82
expandedFrameTick = Main.GameUpdateCount;
83
84
Matrix inverse = Matrix.Invert(Main.GameViewMatrix.TransformationMatrix);
85
Vector2 topLeft = Vector2.Transform(Vector2.Zero, inverse);
86
Vector2 topRight = Vector2.Transform(
87
new Vector2(Main.screenWidth, 0f), inverse);
88
Vector2 bottomLeft = Vector2.Transform(
89
new Vector2(0f, Main.screenHeight), inverse);
90
Vector2 bottomRight = Vector2.Transform(
91
new Vector2(Main.screenWidth, Main.screenHeight), inverse);
92
float left = Math.Min(Math.Min(topLeft.X, topRight.X),
93
Math.Min(bottomLeft.X, bottomRight.X));
94
float right = Math.Max(Math.Max(topLeft.X, topRight.X),
95
Math.Max(bottomLeft.X, bottomRight.X));
96
float top = Math.Min(Math.Min(topLeft.Y, topRight.Y),
97
Math.Min(bottomLeft.Y, bottomRight.Y));
98
float bottom = Math.Max(Math.Max(topLeft.Y, topRight.Y),
99
Math.Max(bottomLeft.Y, bottomRight.Y));
100
expandedDestination = new Vector2(left, top);
101
expandedDestinationWidth = Math.Max(1f, right - left);
102
expandedDestinationHeight = Math.Max(1f, bottom - top);
103
104
Vector2 sourceAperture = new(
105
Math.Max(1, Main.screenWidth),
106
Math.Max(1, Main.screenHeight));
107
Vector2 sourceAnchor = Main.screenPosition + sourceAperture * 0.5f;
108
for (int layer = 0; layer < layers.Length; layer++)
109
{
110
GetSourceFrame(layer, sourceAnchor, sourceAperture,
111
out expandedSourceX[layer], out expandedSourceY[layer],
112
out expandedSourceWidth[layer],
113
out expandedSourceHeight[layer]);
114
}
115
}
116
32
117
/// <summary>
33
118
/// Maps a world point into the exact parallax plate framing used by the Death
34
119
/// Necklace. Weapon crescents and persistent wounds use this instead of raw
@@ -56,25 +141,29 @@ internal sealed class DeathDomainBackdropTextureSystem : ModSystem
56
141
new Vector2(ReferenceDomainDiameter));
57
142
58
143
/// <summary>
59
/// Uses the active owner's Death Necklace aperture when one exists. A
60
/// descended domain is sampled against exactly the current viewport; a
61
/// circular domain uses the same reference aperture as the necklace. Every
62
/// weapon mask belonging to that owner therefore reveals the same parallax
63
/// pixel at the same world position.
144
/// Uses the fully manifested Death Necklace framing at all times. The owner
145
/// and fallback anchor remain part of the call contract because masks are
146
/// owner-scoped, but neither may rescale or recenter the shared backdrop.
147
/// Every mask therefore reveals the same parallax pixel at the same visible
148
/// world position before, during and after manifestation.
64
149
/// </summary>
65
150
internal static Vector2 GetMatchingDomainUv(int layer, Vector2 world,
66
151
int owner, Vector2 fallbackAnchor)
67
152
{
68
Vector2 anchor = fallbackAnchor;
69
Vector2 aperture = new(ReferenceDomainDiameter);
70
if (owner >= 0 && owner < Main.maxPlayers
71
&& Main.player[owner] is Player player && player.active)
72
{
73
anchor = player.Center;
74
DeathDomainVisualSystem.TryGetMatchingBackdropAperture(owner,
75
out anchor, out aperture);
76
}
77
return GetWorldUv(layer, world, anchor, aperture);
153
_ = owner;
154
_ = fallbackAnchor;
155
GetExpandedDomainDrawBounds(out Vector2 destination,
156
out float destinationWidth, out float destinationHeight);
157
GetExpandedDomainSourceFrame(layer,
158
out float sourceOffsetX, out float sourceOffsetY,
159
out float viewWidth, out float viewHeight);
160
Vector2 worldTopLeft = Main.screenPosition + destination;
161
Vector2 normalized = new(
162
(world.X - worldTopLeft.X) / destinationWidth,
163
(world.Y - worldTopLeft.Y) / destinationHeight);
164
return new Vector2(
165
(sourceOffsetX + normalized.X * viewWidth) / LayerWidth,
166
(sourceOffsetY + normalized.Y * viewHeight) / LayerHeight);
78
167
}
79
168
80
169
internal static float GetLayerOpacity(int layer)
@@ -155,13 +244,10 @@ internal sealed class DeathDomainBackdropTextureSystem : ModSystem
155
244
return;
156
245
}
157
246
158
Vector2 worldCenter = Main.screenPosition
159
+ new Vector2(Main.screenWidth, Main.screenHeight) * 0.5f;
160
Vector2 aperture = new(Main.screenWidth, Main.screenHeight);
161
247
for (int layer = 0; layer < 3; layer++)
162
248
{
163
249
Texture2D texture = GetLayer(layer);
164
GetSourceFrame(layer, worldCenter, aperture,
250
GetExpandedDomainSourceFrame(layer,
165
251
out float sourceX, out float sourceY,
166
252
out float sourceWidth, out float sourceHeight);
167
253
int width = Math.Clamp((int)MathF.Round(sourceWidth), 1,
@@ -228,6 +314,7 @@ internal sealed class DeathDomainBackdropTextureSystem : ModSystem
228
314
229
315
public override void Unload()
230
316
{
317
expandedFrameTick = ulong.MaxValue;
231
318
Texture2D?[] oldLayers = (Texture2D?[])layers.Clone();
232
319
Array.Clear(layers);
233
320
if (Main.dedServ)
@@ -84,37 +84,6 @@ internal class DeathDomainVisualSystem : ModSystem
84
84
ClearAnimationState();
85
85
}
86
86
87
/// <summary>
88
/// Supplies the same aperture currently used to draw an owner's necklace
89
/// domain. Weapon masks query this instead of re-deriving full-screen state,
90
/// so future domain unlock rules cannot make the two backgrounds diverge.
91
/// </summary>
92
internal static bool TryGetMatchingBackdropAperture(int owner,
93
out Vector2 anchorWorld, out Vector2 apertureSize)
94
{
95
anchorWorld = owner >= 0 && owner < Main.maxPlayers
96
&& Main.player[owner].active
97
? Main.player[owner].Center
98
: Main.screenPosition
99
+ new Vector2(Main.screenWidth, Main.screenHeight) * 0.5f;
100
apertureSize = new Vector2(
101
DeathDomainBackdropTextureSystem.ReferenceDomainDiameter);
102
if (owner < 0 || owner >= Main.maxPlayers)
103
return false;
104
105
DeathDomainVisualSystem instance = ModContent
106
.GetInstance<DeathDomainVisualSystem>();
107
if (instance.domainAnimation[owner] <= 0.001f)
108
return false;
109
if (instance.descentAnimation[owner] >= 0.999f)
110
{
111
anchorWorld = Main.screenPosition
112
+ new Vector2(Main.screenWidth, Main.screenHeight) * 0.5f;
113
apertureSize = new Vector2(Main.screenWidth, Main.screenHeight);
114
}
115
return true;
116
}
117
118
87
public override void PostDrawTiles()
119
88
{
120
89
Player localPlayer = Main.LocalPlayer;
@@ -301,7 +270,14 @@ internal class DeathDomainVisualSystem : ModSystem
301
270
302
271
int bands = Math.Max(1, (int)Math.Ceiling(extent * 2f / preferredBandHeight));
303
272
float bandHeight = extent * 2f / bands;
304
Vector2 worldCenter = center + Main.screenPosition;
273
DeathDomainBackdropTextureSystem.GetExpandedDomainDrawBounds(
274
out Vector2 expandedDestination,
275
out float expandedDestinationWidth,
276
out float expandedDestinationHeight);
277
float expandedDestinationRight = expandedDestination.X
278
+ expandedDestinationWidth;
279
float expandedDestinationBottom = expandedDestination.Y
280
+ expandedDestinationHeight;
305
281
// Draw one complete layer at a time. This retains proper alpha compositing
306
282
// while allowing SpriteBatch to group hundreds of clipped scan bands into
307
283
// only three texture batches instead of switching textures for every row.
@@ -314,8 +290,9 @@ internal class DeathDomainVisualSystem : ModSystem
314
290
_ => MathHelper.Lerp(0.78f, 0.96f, mastery) * reveal
315
291
};
316
292
Texture2D texture = DeathDomainBackdropTextureSystem.GetLayer(layer);
317
GetBackdropSource(layer, texture, worldCenter, 1f, 1f, out float sourceOffsetX,
318
out float sourceOffsetY, out float viewWidth, out float viewHeight);
293
DeathDomainBackdropTextureSystem.GetExpandedDomainSourceFrame(layer,
294
out float sourceOffsetX, out float sourceOffsetY,
295
out float viewWidth, out float viewHeight);
319
296
320
297
for (int index = 0; index < bands; index++)
321
298
{
@@ -338,16 +315,31 @@ internal class DeathDomainVisualSystem : ModSystem
338
315
if (left >= right)
339
316
continue;
340
317
341
float normalizedLeft = MathHelper.Clamp((left + extent) / (extent * 2f), 0f, 1f);
342
float normalizedRight = MathHelper.Clamp((right + extent) / (extent * 2f), 0f, 1f);
343
float normalizedTop = MathHelper.Clamp((scanY - bandHeight * 0.5f + extent) / (extent * 2f), 0f, 1f);
344
float normalizedBottom = MathHelper.Clamp((scanY + bandHeight * 0.5f + extent) / (extent * 2f), 0f, 1f);
318
float drawLeft = Math.Max(expandedDestination.X,
319
center.X + left);
320
float drawRight = Math.Min(expandedDestinationRight,
321
center.X + right);
322
float drawTop = Math.Max(expandedDestination.Y,
323
center.Y + scanY - bandHeight * 0.5f);
324
float drawBottom = Math.Min(expandedDestinationBottom,
325
center.Y + scanY + bandHeight * 0.5f);
326
if (drawLeft >= drawRight || drawTop >= drawBottom)
327
continue;
328
329
float normalizedLeft = (drawLeft - expandedDestination.X)
330
/ expandedDestinationWidth;
331
float normalizedRight = (drawRight - expandedDestination.X)
332
/ expandedDestinationWidth;
333
float normalizedTop = (drawTop - expandedDestination.Y)
334
/ expandedDestinationHeight;
335
float normalizedBottom = (drawBottom - expandedDestination.Y)
336
/ expandedDestinationHeight;
345
337
DrawBackdropBand(
346
338
batch,
347
339
texture,
348
new Vector2(center.X + left, center.Y + scanY - bandHeight * 0.5f),
349
right - left,
350
bandHeight,
340
new Vector2(drawLeft, drawTop),
341
drawRight - drawLeft,
342
drawBottom - drawTop,
351
343
sourceOffsetX + normalizedLeft * viewWidth,
352
344
sourceOffsetY + normalizedTop * viewHeight,
353
345
Math.Max(0.5f, (normalizedRight - normalizedLeft) * viewWidth),
@@ -608,7 +600,7 @@ internal class DeathDomainVisualSystem : ModSystem
608
600
bool drawBackdrop,
609
601
bool drawBoundary)
610
602
{
611
GetUntransformedScreenBounds(
603
DeathDomainBackdropTextureSystem.GetExpandedDomainDrawBounds(
612
604
out Vector2 destination,
613
605
out float destinationWidth,
614
606
out float destinationHeight);
@@ -711,11 +703,6 @@ internal class DeathDomainVisualSystem : ModSystem
711
703
rightEdges[band] = right;
712
704
}
713
705
714
Vector2 worldCenter = Main.screenPosition
715
+ new Vector2(Main.screenWidth, Main.screenHeight) * 0.5f;
716
float referenceDiameter = DeathDomainBackdropTextureSystem.ReferenceDomainDiameter;
717
float horizontalScale = Main.screenWidth / referenceDiameter;
718
float verticalScale = Main.screenHeight / referenceDiameter;
719
706
float destinationRight = destination.X + destinationWidth;
720
707
float destinationBottom = destination.Y + destinationHeight;
721
708
for (int layer = 0; layer < 3; layer++)
@@ -727,7 +714,7 @@ internal class DeathDomainVisualSystem : ModSystem
727
714
_ => MathHelper.Lerp(0.78f, 0.96f, mastery) * reveal
728
715
};
729
716
Texture2D texture = DeathDomainBackdropTextureSystem.GetLayer(layer);
730
GetBackdropSource(layer, texture, worldCenter, horizontalScale, verticalScale,
717
DeathDomainBackdropTextureSystem.GetExpandedDomainSourceFrame(layer,
731
718
out float sourceOffsetX, out float sourceOffsetY,
732
719
out float viewWidth, out float viewHeight);
733
720
@@ -769,11 +756,9 @@ internal class DeathDomainVisualSystem : ModSystem
769
756
770
757
private static void DrawFullScreenBackdrop(SpriteBatch batch, float mastery, float reveal)
771
758
{
772
Vector2 worldCenter = Main.screenPosition + new Vector2(Main.screenWidth, Main.screenHeight) * 0.5f;
773
float referenceDiameter = (160f + DeathNecklace.RadiusGrowthPerLevel * (DeathNecklace.MaxCoreLevel - 1)) * 2f;
774
float horizontalScale = Main.screenWidth / referenceDiameter;
775
float verticalScale = Main.screenHeight / referenceDiameter;
776
GetUntransformedScreenBounds(out Vector2 destination, out float destinationWidth, out float destinationHeight);
759
DeathDomainBackdropTextureSystem.GetExpandedDomainDrawBounds(
760
out Vector2 destination, out float destinationWidth,
761
out float destinationHeight);
777
762
for (int layer = 0; layer < 3; layer++)
778
763
{
779
764
float opacity = layer switch
@@ -783,7 +768,7 @@ internal class DeathDomainVisualSystem : ModSystem
783
768
_ => MathHelper.Lerp(0.78f, 0.96f, mastery) * reveal
784
769
};
785
770
Texture2D texture = DeathDomainBackdropTextureSystem.GetLayer(layer);
786
GetBackdropSource(layer, texture, worldCenter, horizontalScale, verticalScale,
771
DeathDomainBackdropTextureSystem.GetExpandedDomainSourceFrame(layer,
787
772
out float sourceOffsetX, out float sourceOffsetY, out float viewWidth, out float viewHeight);
788
773
789
774
DrawBackdropBand(
@@ -1027,52 +1012,6 @@ internal class DeathDomainVisualSystem : ModSystem
1027
1012
return (float)(value - Math.Floor(value));
1028
1013
}
1029
1014
1030
private static void GetUntransformedScreenBounds(
1031
out Vector2 destination,
1032
out float destinationWidth,
1033
out float destinationHeight)
1034
{
1035
// This pass shares Terraria's active world SpriteBatch. Map the physical
1036
// viewport back through that batch's transform so the full-screen domain
1037
// still lands on the exact screen bounds at every game zoom. Taking all
1038
// four corners also keeps the viewport covered if another mod rotates or
1039
// shears the world view.
1040
Matrix inverse = Matrix.Invert(Main.GameViewMatrix.TransformationMatrix);
1041
Vector2 topLeft = Vector2.Transform(Vector2.Zero, inverse);
1042
Vector2 topRight = Vector2.Transform(new Vector2(Main.screenWidth, 0f), inverse);
1043
Vector2 bottomLeft = Vector2.Transform(new Vector2(0f, Main.screenHeight), inverse);
1044
Vector2 bottomRight = Vector2.Transform(new Vector2(Main.screenWidth, Main.screenHeight), inverse);
1045
float left = Math.Min(Math.Min(topLeft.X, topRight.X), Math.Min(bottomLeft.X, bottomRight.X));
1046
float right = Math.Max(Math.Max(topLeft.X, topRight.X), Math.Max(bottomLeft.X, bottomRight.X));
1047
float top = Math.Min(Math.Min(topLeft.Y, topRight.Y), Math.Min(bottomLeft.Y, bottomRight.Y));
1048
float bottom = Math.Max(Math.Max(topLeft.Y, topRight.Y), Math.Max(bottomLeft.Y, bottomRight.Y));
1049
destination = new Vector2(left, top);
1050
destinationWidth = Math.Max(1f, right - left);
1051
destinationHeight = Math.Max(1f, bottom - top);
1052
}
1053
1054
private static void GetBackdropSource(
1055
int layer,
1056
Texture2D texture,
1057
Vector2 worldCenter,
1058
float horizontalScale,
1059
float verticalScale,
1060
out float sourceOffsetX,
1061
out float sourceOffsetY,
1062
out float viewWidth,
1063
out float viewHeight)
1064
{
1065
_ = texture;
1066
DeathDomainBackdropTextureSystem.GetSourceFrame(layer, worldCenter,
1067
new Vector2(
1068
DeathDomainBackdropTextureSystem.ReferenceDomainDiameter
1069
* horizontalScale,
1070
DeathDomainBackdropTextureSystem.ReferenceDomainDiameter
1071
* verticalScale),
1072
out sourceOffsetX, out sourceOffsetY,
1073
out viewWidth, out viewHeight);
1074
}
1075
1076
1015
private static void DrawDomainRippleWaves(SpriteBatch batch, Vector2 center,
1077
1016
float radius, float time, float mastery, float pulse)
1078
1017
{