Terraria v1.4.4.9
Terraria source code documentation
All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Events Macros
WaterShaderData.cs
Go to the documentation of this file.
1using System;
10using Terraria.ID;
11
13
15{
16 private struct Ripple
17 {
18 private static readonly Rectangle[] RIPPLE_SHAPE_SOURCE_RECTS = new Rectangle[3]
19 {
20 new Rectangle(0, 0, 0, 0),
21 new Rectangle(1, 1, 62, 62),
22 new Rectangle(1, 65, 62, 62)
23 };
24
25 public readonly Vector2 Position;
26
27 public readonly Color WaveData;
28
29 public readonly Vector2 Size;
30
31 public readonly RippleShape Shape;
32
33 public readonly float Rotation;
34
36
37 public Ripple(Vector2 position, Color waveData, Vector2 size, RippleShape shape, float rotation)
38 {
39 Position = position;
40 WaveData = waveData;
41 Size = size;
42 Shape = shape;
43 Rotation = rotation;
44 }
45 }
46
47 private const float DISTORTION_BUFFER_SCALE = 0.25f;
48
49 private const float WAVE_FRAMERATE = 1f / 60f;
50
51 private const int MAX_RIPPLES_QUEUED = 200;
52
53 public bool _useViscosityFilter = true;
54
56
58
59 private bool _usingRenderTargets;
60
62
63 private float _progress;
64
65 private Ripple[] _rippleQueue = new Ripple[200];
66
67 private int _rippleQueueCount;
68
69 private int _lastScreenWidth;
70
71 private int _lastScreenHeight;
72
73 public bool _useProjectileWaves = true;
74
75 private bool _useNPCWaves = true;
76
77 private bool _usePlayerWaves = true;
78
79 private bool _useRippleWaves = true;
80
81 private bool _useCustomWaves = true;
82
83 private bool _clearNextFrame = true;
84
86
88
90
91 private bool _isWaveBufferDirty = true;
92
93 private int _queuedSteps;
94
95 private const int MAX_QUEUED_STEPS = 2;
96
97 public event Action<TileBatch> OnWaveDraw;
98
99 public WaterShaderData(string passName)
100 : base(passName)
101 {
102 Main.OnRenderTargetsInitialized += InitRenderTargets;
103 Main.OnRenderTargetsReleased += ReleaseRenderTargets;
104 _rippleShapeTexture = Main.Assets.Request<Texture2D>("Images/Misc/Ripples", (AssetRequestMode)1);
105 Main.OnPreDraw += PreDraw;
106 }
107
108 public override void Update(GameTime gameTime)
109 {
110 _useViscosityFilter = Main.WaveQuality >= 3;
111 _useProjectileWaves = Main.WaveQuality >= 3;
112 _usePlayerWaves = Main.WaveQuality >= 2;
113 _useRippleWaves = Main.WaveQuality >= 2;
114 _useCustomWaves = Main.WaveQuality >= 2;
116 {
117 _progress += (float)gameTime.ElapsedGameTime.TotalSeconds * base.Intensity * 0.75f;
118 _progress %= 86400f;
120 {
121 _queuedSteps++;
122 }
123 base.Update(gameTime);
124 }
125 }
126
127 private void StepLiquids()
128 {
129 _isWaveBufferDirty = true;
130 Vector2 vector = (Main.drawToScreen ? Vector2.Zero : new Vector2(Main.offScreenRange, Main.offScreenRange));
131 Vector2 vector2 = vector - Main.screenPosition;
132 TileBatch tileBatch = Main.tileBatch;
133 GraphicsDevice graphicsDevice = Main.instance.GraphicsDevice;
134 graphicsDevice.SetRenderTarget(_distortionTarget);
135 if (_clearNextFrame)
136 {
137 graphicsDevice.Clear(new Color(0.5f, 0.5f, 0f, 1f));
138 _clearNextFrame = false;
139 }
140 DrawWaves();
142 graphicsDevice.Clear(new Color(0.5f, 0.5f, 0.5f, 1f));
143 Main.tileBatch.Begin();
144 vector2 *= 0.25f;
145 vector2.X = (float)Math.Floor(vector2.X);
146 vector2.Y = (float)Math.Floor(vector2.Y);
147 Vector2 vector3 = vector2 - _lastDistortionDrawOffset;
150 GameShaders.Misc["WaterProcessor"].Apply(new DrawData(_distortionTarget, Vector2.Zero, Color.White));
151 tileBatch.End();
152 RenderTarget2D distortionTarget = _distortionTarget;
154 _distortionTargetSwap = distortionTarget;
156 {
158 tileBatch.Begin();
159 Rectangle cachedDrawArea = LiquidRenderer.Instance.GetCachedDrawArea();
160 Rectangle rectangle = new Rectangle(0, 0, cachedDrawArea.Height, cachedDrawArea.Width);
161 Vector4 destination = new Vector4(cachedDrawArea.X + cachedDrawArea.Width, cachedDrawArea.Y, cachedDrawArea.Height, cachedDrawArea.Width);
162 destination *= 16f;
163 destination.X -= vector.X;
164 destination.Y -= vector.Y;
165 destination *= 0.25f;
166 destination.X += vector2.X;
167 destination.Y += vector2.Y;
168 graphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
169 tileBatch.Draw(_viscosityMaskChain[_activeViscosityMask], destination, rectangle, new VertexColors(Color.White), rectangle.Size(), SpriteEffects.FlipHorizontally, -(float)Math.PI / 2f);
170 tileBatch.End();
173 }
174 graphicsDevice.SetRenderTarget(null);
175 }
176
177 private void DrawWaves()
178 {
179 Vector2 screenPosition = Main.screenPosition;
180 Vector2 vector = (Main.drawToScreen ? Vector2.Zero : new Vector2(Main.offScreenRange, Main.offScreenRange));
181 Vector2 vector2 = -_lastDistortionDrawOffset / 0.25f + vector;
182 TileBatch tileBatch = Main.tileBatch;
183 _ = Main.instance.GraphicsDevice;
184 Vector2 dimensions = new Vector2(Main.screenWidth, Main.screenHeight);
185 Vector2 vector3 = new Vector2(16f, 16f);
186 tileBatch.Begin();
187 GameShaders.Misc["WaterDistortionObject"].Apply();
188 if (_useNPCWaves)
189 {
190 for (int i = 0; i < 200; i++)
191 {
192 if (Main.npc[i] == null || !Main.npc[i].active || (!Main.npc[i].wet && Main.npc[i].wetCount == 0) || !Collision.CheckAABBvAABBCollision(screenPosition, dimensions, Main.npc[i].position - vector3, Main.npc[i].Size + vector3))
193 {
194 continue;
195 }
196 NPC nPC = Main.npc[i];
197 Vector2 vector4 = nPC.Center - vector2;
198 Vector2 vector5 = nPC.velocity.RotatedBy(0f - nPC.rotation) / new Vector2(nPC.height, nPC.width);
199 float num = vector5.LengthSquared();
200 num = num * 0.3f + 0.7f * num * (1024f / (float)(nPC.height * nPC.width));
201 num = Math.Min(num, 0.08f);
202 num += (nPC.velocity - nPC.oldVelocity).Length() * 0.5f;
203 vector5.Normalize();
204 Vector2 velocity = nPC.velocity;
205 velocity.Normalize();
206 vector4 -= velocity * 10f;
207 if (!_useViscosityFilter && (nPC.honeyWet || nPC.lavaWet))
208 {
209 num *= 0.3f;
210 }
211 if (nPC.wet)
212 {
213 tileBatch.Draw(TextureAssets.MagicPixel.Value, new Vector4(vector4.X, vector4.Y, (float)nPC.width * 2f, (float)nPC.height * 2f) * 0.25f, null, new VertexColors(new Color(vector5.X * 0.5f + 0.5f, vector5.Y * 0.5f + 0.5f, 0.5f * num)), new Vector2((float)TextureAssets.MagicPixel.Width() / 2f, (float)TextureAssets.MagicPixel.Height() / 2f), SpriteEffects.None, nPC.rotation);
214 }
215 if (nPC.wetCount != 0)
216 {
217 num = nPC.velocity.Length();
218 num = 0.195f * (float)Math.Sqrt(num);
219 float num2 = 5f;
220 if (!nPC.wet)
221 {
222 num2 = -20f;
223 }
224 QueueRipple(nPC.Center + velocity * num2, new Color(0.5f, (nPC.wet ? num : (0f - num)) * 0.5f + 0.5f, 0f, 1f) * 0.5f, new Vector2(nPC.width, (float)nPC.height * ((float)(int)nPC.wetCount / 9f)) * MathHelper.Clamp(num * 10f, 0f, 1f), RippleShape.Circle);
225 }
226 }
227 }
228 if (_usePlayerWaves)
229 {
230 for (int j = 0; j < 255; j++)
231 {
232 if (Main.player[j] == null || !Main.player[j].active || (!Main.player[j].wet && Main.player[j].wetCount == 0) || !Collision.CheckAABBvAABBCollision(screenPosition, dimensions, Main.player[j].position - vector3, Main.player[j].Size + vector3))
233 {
234 continue;
235 }
236 Player player = Main.player[j];
237 Vector2 vector6 = player.Center - vector2;
238 float num3 = player.velocity.Length();
239 num3 = 0.05f * (float)Math.Sqrt(num3);
240 Vector2 velocity2 = player.velocity;
241 velocity2.Normalize();
242 vector6 -= velocity2 * 10f;
243 if (!_useViscosityFilter && (player.honeyWet || player.lavaWet))
244 {
245 num3 *= 0.3f;
246 }
247 if (player.wet)
248 {
249 tileBatch.Draw(TextureAssets.MagicPixel.Value, new Vector4(vector6.X - (float)player.width * 2f * 0.5f, vector6.Y - (float)player.height * 2f * 0.5f, (float)player.width * 2f, (float)player.height * 2f) * 0.25f, new VertexColors(new Color(velocity2.X * 0.5f + 0.5f, velocity2.Y * 0.5f + 0.5f, 0.5f * num3)));
250 }
251 if (player.wetCount != 0)
252 {
253 float num4 = 5f;
254 if (!player.wet)
255 {
256 num4 = -20f;
257 }
258 num3 *= 3f;
259 QueueRipple(player.Center + velocity2 * num4, player.wet ? num3 : (0f - num3), new Vector2(player.width, (float)player.height * ((float)(int)player.wetCount / 9f)) * MathHelper.Clamp(num3 * 10f, 0f, 1f), RippleShape.Circle);
260 }
261 }
262 }
264 {
265 for (int k = 0; k < 1000; k++)
266 {
267 Projectile projectile = Main.projectile[k];
268 if (projectile.wet && !projectile.lavaWet)
269 {
270 _ = !projectile.honeyWet;
271 }
272 else
273 _ = 0;
274 bool flag = projectile.lavaWet;
275 bool flag2 = projectile.honeyWet;
276 bool flag3 = projectile.wet;
277 if (projectile.ignoreWater)
278 {
279 flag3 = true;
280 }
281 if (!(projectile != null && projectile.active && ProjectileID.Sets.CanDistortWater[projectile.type] && flag3) || ProjectileID.Sets.NoLiquidDistortion[projectile.type] || !Collision.CheckAABBvAABBCollision(screenPosition, dimensions, projectile.position - vector3, projectile.Size + vector3))
282 {
283 continue;
284 }
285 if (projectile.ignoreWater)
286 {
287 bool num5 = Collision.LavaCollision(projectile.position, projectile.width, projectile.height);
288 flag = Collision.WetCollision(projectile.position, projectile.width, projectile.height);
289 flag2 = Collision.honey;
290 if (!(num5 || flag || flag2))
291 {
292 continue;
293 }
294 }
295 Vector2 vector7 = projectile.Center - vector2;
296 float num6 = projectile.velocity.Length();
297 num6 = 2f * (float)Math.Sqrt(0.05f * num6);
298 Vector2 velocity3 = projectile.velocity;
299 velocity3.Normalize();
300 if (!_useViscosityFilter && (flag2 || flag))
301 {
302 num6 *= 0.3f;
303 }
304 float num7 = Math.Max(12f, (float)projectile.width * 0.75f);
305 float num8 = Math.Max(12f, (float)projectile.height * 0.75f);
306 tileBatch.Draw(TextureAssets.MagicPixel.Value, new Vector4(vector7.X - num7 * 0.5f, vector7.Y - num8 * 0.5f, num7, num8) * 0.25f, new VertexColors(new Color(velocity3.X * 0.5f + 0.5f, velocity3.Y * 0.5f + 0.5f, num6 * 0.5f)));
307 }
308 }
309 tileBatch.End();
310 if (_useRippleWaves)
311 {
312 tileBatch.Begin();
313 for (int l = 0; l < _rippleQueueCount; l++)
314 {
315 Vector2 vector8 = _rippleQueue[l].Position - vector2;
316 Vector2 size = _rippleQueue[l].Size;
317 Rectangle sourceRectangle = _rippleQueue[l].SourceRectangle;
319 tileBatch.Draw(value, new Vector4(vector8.X, vector8.Y, size.X, size.Y) * 0.25f, sourceRectangle, new VertexColors(_rippleQueue[l].WaveData), new Vector2(sourceRectangle.Width / 2, sourceRectangle.Height / 2), SpriteEffects.None, _rippleQueue[l].Rotation);
320 }
321 tileBatch.End();
322 }
324 if (_useCustomWaves && this.OnWaveDraw != null)
325 {
326 tileBatch.Begin();
327 this.OnWaveDraw(tileBatch);
328 tileBatch.End();
329 }
330 }
331
332 private void PreDraw(GameTime gameTime)
333 {
336 {
337 return;
338 }
340 {
341 for (int i = 0; i < Math.Min(_queuedSteps, 2); i++)
342 {
343 StepLiquids();
344 }
345 }
347 {
348 GraphicsDevice graphicsDevice = Main.instance.GraphicsDevice;
349 graphicsDevice.SetRenderTarget(_distortionTarget);
350 graphicsDevice.Clear(new Color(0.5f, 0.5f, 0f, 1f));
351 _clearNextFrame = false;
352 _isWaveBufferDirty = false;
353 graphicsDevice.SetRenderTarget(null);
354 }
355 _queuedSteps = 0;
356 }
357
358 public override void Apply()
359 {
361 {
363 Main.graphics.GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
364 Vector2 vector = new Vector2(Main.screenWidth, Main.screenHeight) * 0.5f * (Vector2.One - Vector2.One / Main.GameViewMatrix.Zoom);
365 Vector2 vector2 = (Main.drawToScreen ? Vector2.Zero : new Vector2(Main.offScreenRange, Main.offScreenRange)) - Main.screenPosition - vector;
370 base.Apply();
371 }
372 }
373
375 {
376 int backBufferWidth = Main.instance.GraphicsDevice.PresentationParameters.BackBufferWidth;
377 int backBufferHeight = Main.instance.GraphicsDevice.PresentationParameters.BackBufferHeight;
378 bool flag = !Main.drawToScreen;
379 if (_usingRenderTargets && !flag)
380 {
382 }
383 else if (!_usingRenderTargets && flag)
384 {
385 InitRenderTargets(backBufferWidth, backBufferHeight);
386 }
388 {
389 _clearNextFrame = true;
390 }
391 }
392
393 private void InitRenderTargets(int width, int height)
394 {
395 _lastScreenWidth = width;
396 _lastScreenHeight = height;
397 width = (int)((float)width * 0.25f);
398 height = (int)((float)height * 0.25f);
399 try
400 {
401 _distortionTarget = new RenderTarget2D(Main.instance.GraphicsDevice, width, height, mipMap: false, SurfaceFormat.Color, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
402 _distortionTargetSwap = new RenderTarget2D(Main.instance.GraphicsDevice, width, height, mipMap: false, SurfaceFormat.Color, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
403 _usingRenderTargets = true;
404 _clearNextFrame = true;
405 }
406 catch (Exception ex)
407 {
408 Lighting.Mode = LightMode.Retro;
409 _usingRenderTargets = false;
410 Console.WriteLine("Failed to create water distortion render targets. " + ex);
411 }
412 }
413
414 private void ReleaseRenderTargets()
415 {
416 try
417 {
418 if (_distortionTarget != null)
419 {
421 }
422 if (_distortionTargetSwap != null)
423 {
425 }
426 }
427 catch (Exception ex)
428 {
429 Console.WriteLine("Error disposing of water distortion render targets. " + ex);
430 }
431 _distortionTarget = null;
433 _usingRenderTargets = false;
434 }
435
436 public void QueueRipple(Vector2 position, float strength = 1f, RippleShape shape = RippleShape.Square, float rotation = 0f)
437 {
438 float g = strength * 0.5f + 0.5f;
439 float num = Math.Min(Math.Abs(strength), 1f);
440 QueueRipple(position, new Color(0.5f, g, 0f, 1f) * num, new Vector2(4f * Math.Max(Math.Abs(strength), 1f)), shape, rotation);
441 }
442
443 public void QueueRipple(Vector2 position, float strength, Vector2 size, RippleShape shape = RippleShape.Square, float rotation = 0f)
444 {
445 float g = strength * 0.5f + 0.5f;
446 float num = Math.Min(Math.Abs(strength), 1f);
447 QueueRipple(position, new Color(0.5f, g, 0f, 1f) * num, size, shape, rotation);
448 }
449
450 public void QueueRipple(Vector2 position, Color waveData, Vector2 size, RippleShape shape = RippleShape.Square, float rotation = 0f)
451 {
453 {
455 }
456 else if (_rippleQueueCount < _rippleQueue.Length)
457 {
458 _rippleQueue[_rippleQueueCount++] = new Ripple(position, waveData, size, shape, rotation);
459 }
460 }
461}
void Clear(ClearOptions options, Vector4 color, float depth, int stencil)
unsafe void SetRenderTarget(RenderTargetCube renderTarget, CubeMapFace cubeMapFace)
override void Dispose([MarshalAs(UnmanagedType.U1)] bool P_0)
static readonly SamplerState PointClamp
static float Clamp(float value, float min, float max)
Definition MathHelper.cs:46
static void WriteLine()
Definition Console.cs:733
static byte Min(byte val1, byte val2)
Definition Math.cs:912
static double Sqrt(double d)
static double Abs(double value)
const double PI
Definition Math.cs:16
static double Floor(double d)
static byte Max(byte val1, byte val2)
Definition Math.cs:738
static bool WetCollision(Vector2 Position, int Width, int Height)
static bool honey
Definition Collision.cs:24
static bool LavaCollision(Vector2 Position, int Width, int Height)
static bool CheckAABBvAABBCollision(Vector2 position1, Vector2 dimensions1, Vector2 position2, Vector2 dimensions2)
Definition Collision.cs:157
bool honeyWet
Definition Entity.cs:34
Vector2 Center
Definition Entity.cs:43
Vector2 Size
Definition Entity.cs:151
Vector2 velocity
Definition Entity.cs:16
Vector2 position
Definition Entity.cs:14
Vector2 oldVelocity
Definition Entity.cs:20
byte wetCount
Definition Entity.cs:36
override void Update(GameTime gameTime)
void QueueRipple(Vector2 position, float strength, Vector2 size, RippleShape shape=RippleShape.Square, float rotation=0f)
void QueueRipple(Vector2 position, Color waveData, Vector2 size, RippleShape shape=RippleShape.Square, float rotation=0f)
void InitRenderTargets(int width, int height)
void QueueRipple(Vector2 position, float strength=1f, RippleShape shape=RippleShape.Square, float rotation=0f)
static Asset< Texture2D > MagicPixel
static Dictionary< string, MiscShaderData > Misc
ScreenShaderData UseProgress(float progress)
ScreenShaderData UseTargetPosition(Vector2 position)
ScreenShaderData UseImageOffset(Vector2 offset)
ScreenShaderData UseImage(Texture2D image, int index=0, SamplerState samplerState=null)
void Draw(Texture2D texture, Vector2 position, VertexColors colors)
Definition TileBatch.cs:127
void Begin(RasterizerState rasterizer, Matrix transformation)
Definition TileBatch.cs:115
static Vector2 sceneWaterPos
Definition Main.cs:1044
static bool drawToScreen
Definition Main.cs:600
static bool hasFocus
Definition Main.cs:1781
static bool IsGraphicsDeviceAvailable
Definition Main.cs:2928
static Main instance
Definition Main.cs:283
static int screenHeight
Definition Main.cs:1721
static Vector2 screenPosition
Definition Main.cs:1715
static SpriteViewMatrix GameViewMatrix
Definition Main.cs:227
static int offScreenRange
Definition Main.cs:836
static TileBatch tileBatch
Definition Main.cs:976
static Projectile[] projectile
Definition Main.cs:1691
static NPC[] npc
Definition Main.cs:1685
static int screenWidth
Definition Main.cs:1719
static RenderTarget2D waterTarget
Definition Main.cs:840
static IAssetRepository Assets
Definition Main.cs:209
static bool gamePaused
Definition Main.cs:1072
static Player[] player
Definition Main.cs:1803
static GraphicsDeviceManager graphics
Definition Main.cs:972
float rotation
Definition NPC.cs:501
Ripple(Vector2 position, Color waveData, Vector2 size, RippleShape shape, float rotation)