Skip to content

Commit 3ab5894

Browse files
committed
Automatic merge of T1.6-rc4-32-g196d83e86 and 15 pull requests
- Pull request #1104 at 9c7cdbf: Handle simple adhesion within the axle module - Pull request #1086 at e10390b: Add Settings Exporter tool (copy settings to INI, etc) - Pull request #1091 at 7fc8de1: Automatic speed control - Pull request #1110 at 387388e: Fix Activity Runner persists after loading exception - Pull request #1115 at 270f22f: Do not activate ETS switch if no suitable cars are attached - Pull request #1120 at ba3c47f: Automatically Calculate Friction Values if Missing - Pull request #1121 at 91d2d26: Manually Override Articulation - Pull request #1130 at 251a677: Fix F9 points to an incorrect car ID. - Pull request #1132 at 934d29e: Fixes For Correct Questionable Braking Parameters - Pull request #1133 at 8dc00d5: Minor Fix for Brake Pipe Charging - Pull request #1136 at 6f1b82f: Fix Curve Resistance Calculation - Pull request #1082 at 5845a1a: Allow variable water level in glass gauge - Pull request #1081 at 689494b: Brake cuts power unification - Pull request #1124 at fab5457: Built-in PBL2 brake controller - Pull request #1128 at 58de4c3: Particle Emitter Overhaul
17 parents 57486b1 + 196d83e + 9c7cdbf + e10390b + 7fc8de1 + 387388e + 270f22f + ba3c47f + 91d2d26 + 251a677 + 934d29e + 8dc00d5 + 6f1b82f + 5845a1a + 689494b + fab5457 + 58de4c3 commit 3ab5894

File tree

9 files changed

+120
-21
lines changed

9 files changed

+120
-21
lines changed

Source/Documentation/Manual/physics.rst

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,6 +2499,9 @@ the one shown below::
24992499
ORTSMaxParticles ( 2500 )
25002500
ORTSRateMultiplier ( 1.0 )
25012501
ORTSUseChaoticRandomization ( false )
2502+
2503+
ORTSGraphic ( "smokemain.ace" )
2504+
ORTSGraphicAtlasLayout ( 4 4 )
25022505
)
25032506

25042507
The code block consists of the following elements:
@@ -2527,6 +2530,8 @@ The code block consists of the following elements:
25272530
single: ORTSMaxParticles
25282531
single: ORTSRateMultiplier
25292532
single: ORTSUseChaoticRandomization
2533+
single: ORTSGraphic
2534+
single: ORTSGraphicAtlasLayout
25302535

25312536
After including these settings, additional *optional* parameters unique to OR can
25322537
be included to further customize effect emitters:
@@ -2535,7 +2540,7 @@ be included to further customize effect emitters:
25352540
in the right/left, up/down, and front/back emission location of a particle (default units
25362541
are meters). Useful for non-circular exhaust ports, as it allows one particle emitter
25372542
to be used to spawn particles from an area, rather than a single point. Note that
2538-
``ORTSPositionVariation ( 1m 0m 0m )`` would allow particles to emit 1 meter right and
2543+
``ORTSPositionVariation ( x y z )`` would allow particles to emit 1 meter right and
25392544
1 meter left of the initial position, for a total variation of 2 meters. Similar is
25402545
true of all other parameters related to randomness, the total variation is double what's
25412546
specified. Feature is disabled by default.
@@ -2630,6 +2635,21 @@ be included to further customize effect emitters:
26302635
randomziation algorithm changes the random values by a small amount for each iteration. The "chaotic"
26312636
algorithm tends to make exhaust that is more spread out and discontinuous, which may be desireable in
26322637
some cases.
2638+
- ``ORTSGraphic ( "tex" )`` -- Gives the name and path to the texture that should be used to render
2639+
particles from this emitter. The default texture is "smokemain.ace" for steam-type emitters and
2640+
"dieselsmoke.ace" for diesel-type emitters. If the texture cannot be found from the engine's/wagon's
2641+
folder, then the ``GLOBAL\TEXTURES`` folder is checked, and if the texture is not there the ``Content``
2642+
folder included with OR is checked. Allowed texture formats are ``.png, .jpg, .bmp, .gif, .ace, or .dds``.
2643+
A path to a texture can also be used, such as ``ORTSGraphic ( "..\\SmokeTextures\\steam.dds" )``, to search
2644+
for textures not in the same folder as the engine or wagon.
2645+
- ``ORTSGraphicAtlasLayout ( w h )`` -- Particle textures generally include multiple sprites in a single file
2646+
to allow for randomization of each particle's appearance. In MSTS, this was a sprite atlas 4 wide and 4 high,
2647+
for a total of 16 variations on the particle graphic. When using custom particle textures, it may be desired
2648+
to use a custom sprite sheet that is not 4x4, in which case the atlas layout can be set by ``ORTSGraphicAtlasLayout``.
2649+
For example, a sprite sheet with 4 variations on the particle texture all in a row (4x1) can be represented by
2650+
``ORTSGraphicAtlasLayout ( 4 1 )``. Note that each sprite should be a perfect square as each particle is
2651+
rendered as a square. Rectangular textures will be stretched/squished. Do not change the atlas setting unless you
2652+
are certain of the texture used, as improper settings will be very aesthetically unpleasing.
26332653

26342654

26352655
.. index::
@@ -2649,7 +2669,7 @@ matter:
26492669
)
26502670

26512671
- ``ORTSPosition ( x y z )`` -- defines the width, height, length location of the emitter (in meters by default)
2652-
- ``ORTSInitialVelocity ( x y z )`` -- defines the right, up, forward components of emission direction
2672+
- ``ORTSInitialVelocity ( x y z )`` -- defines the (+/-) right/left, up/down, forward/backward components of emission direction
26532673
(unitless, the particle speed is multiplied by this vector to determine the 3D velocity of particles.
26542674
Speed can be divided by inserting values less than 1, or multiplied by inserting values greater than 1.)
26552675
- And ``ORTSParticleDiameter ( d )`` -- gives the nozzle width (in meters by default), which sets the initial

Source/Orts.Simulation/Simulation/RollingStocks/MSTSWagon.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4715,7 +4715,7 @@ public class ParticleEmitterData
47154715

47164716
public float SpeedLimitMpS = 150.0f;
47174717

4718-
public float NozzleDiameterM;
4718+
public float NozzleDiameterM = 0.1f;
47194719
public float NozzleAreaM2 = -1; // If left at -1, will be initialized later
47204720

47214721
public float RateFactor = 1.0f;
@@ -4733,6 +4733,10 @@ public class ParticleEmitterData
47334733

47344734
public bool ChaoticRandomization = false; // Changes the style of RNG used for particle motion
47354735

4736+
public string Graphic;
4737+
public int AtlasWidth = 4;
4738+
public int AtlasHeight = 4;
4739+
47364740
public ParticleEmitterData(STFReader stf)
47374741
{
47384742
stf.MustMatch("(");
@@ -4779,6 +4783,13 @@ public ParticleEmitterData(STFReader stf)
47794783
new STFReader.TokenProcessor("ortsmaxparticles", ()=>{ MaxParticles = stf.ReadIntBlock(null); }),
47804784
new STFReader.TokenProcessor("ortsratemultiplier", ()=>{ RateFactor = stf.ReadFloatBlock(STFReader.UNITS.None, null); }),
47814785
new STFReader.TokenProcessor("ortsusechaoticrandomization", ()=>{ ChaoticRandomization = stf.ReadBoolBlock(true); }),
4786+
new STFReader.TokenProcessor("ortsgraphic", ()=>{ Graphic = stf.ReadStringBlock(null); }),
4787+
new STFReader.TokenProcessor("ortsgraphicatlaslayout", ()=>{
4788+
stf.MustMatch("(");
4789+
AtlasWidth = Math.Max(stf.ReadInt(null), 1);
4790+
AtlasHeight = Math.Max(stf.ReadInt(null), 1);
4791+
stf.SkipRestOfBlock();
4792+
}),
47824793
});
47834794
}
47844795
}

Source/RunActivity/Content/ParticleEmitterShader.fx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ float emitSize;
3333
float2 cameraTileXY;
3434
float currentTime;
3535

36-
static float2 texCoords[4] = { float2(0, 0), float2(0.25f, 0), float2(0.25f, 0.25f), float2(0, 0.25f) };
36+
static float2 texCoords[4] = { float2(0, 0), float2(1.0f, 0), float2(1.0f, 1.0f), float2(0, 1.0f) };
3737
static float3 offsets[4] = { float3(-0.5f, 0.5f, 0), float3(0.5f, 0.5f, 0), float3(0.5f, -0.5f, 0), float3(-0.5f, -0.5f, 0) };
3838

3939
float4 Fog;
4040

4141
// Textures
4242
texture particle_Tex;
43+
float2 texAtlasSize;
4344

4445
// Texture settings
4546
sampler ParticleSamp = sampler_state
@@ -142,9 +143,11 @@ VERTEX_OUTPUT VSParticles(in VERTEX_INPUT In)
142143

143144
Out.TexCoord = texCoords[vertIdx];
144145
float texAtlasPosition = In.TileXY_Vertex_ID.w;
145-
int atlasX = texAtlasPosition % 4;
146-
int atlasY = texAtlasPosition / 4;
147-
Out.TexCoord += float2(0.25f * atlasX, 0.25f * atlasY);
146+
int atlasX = texAtlasPosition % texAtlasSize.x;
147+
int atlasY = texAtlasPosition / texAtlasSize.y;
148+
Out.TexCoord.x /= texAtlasSize.x;
149+
Out.TexCoord.y /= texAtlasSize.y;
150+
Out.TexCoord += float2(atlasX / texAtlasSize.x, atlasY / texAtlasSize.y);
148151

149152
Out.Color_Age.rgb = In.Color_Random.rgb;
150153

Source/RunActivity/Viewer3D/Materials.cs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,14 @@ public Texture2D Get(string path, Texture2D defaultTexture, bool required = fals
6565
return defaultTexture;
6666

6767
path = path.ToLowerInvariant();
68+
var ext = Path.GetExtension(path);
69+
6870
if (!Textures.ContainsKey(path))
6971
{
7072
try
7173
{
7274
Texture2D texture;
73-
if (Path.GetExtension(path) == ".dds")
75+
if (ext == ".dds")
7476
{
7577
if (File.Exists(path))
7678
{
@@ -89,10 +91,10 @@ public Texture2D Get(string path, Texture2D defaultTexture, bool required = fals
8991
else return defaultTexture;
9092
}
9193
}
92-
else if (Path.GetExtension(path) == ".ace")
94+
else if (ext == ".ace")
9395
{
9496
var alternativeTexture = Path.ChangeExtension(path, ".dds");
95-
97+
9698
if (File.Exists(alternativeTexture))
9799
{
98100
DDSLib.DDSFromFile(alternativeTexture, GraphicsDevice, true, out texture);
@@ -145,7 +147,30 @@ Texture2D invalid()
145147
}
146148
}
147149
else
148-
return defaultTexture;
150+
{
151+
using (var stream = File.OpenRead(path))
152+
{
153+
if (ext == ".gif" || ext == ".jpg" || ext == ".png")
154+
texture = Texture2D.FromStream(GraphicsDevice, stream);
155+
else if (ext == ".bmp")
156+
{
157+
using (var image = System.Drawing.Image.FromStream(stream))
158+
{
159+
using (var memoryStream = new MemoryStream())
160+
{
161+
image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
162+
memoryStream.Seek(0, SeekOrigin.Begin);
163+
texture = Texture2D.FromStream(GraphicsDevice, memoryStream);
164+
}
165+
}
166+
}
167+
else
168+
{
169+
Trace.TraceWarning("Unsupported texture format: {0}", path);
170+
return defaultTexture;
171+
}
172+
}
173+
}
149174

150175
Textures.Add(path, texture);
151176
return texture;

Source/RunActivity/Viewer3D/ParticleEmitter.cs

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222

2323
using System;
2424
using System.Collections.Generic;
25+
using System.Diagnostics;
26+
using System.IO;
2527
using Microsoft.Xna.Framework;
2628
using Microsoft.Xna.Framework.Graphics;
27-
using ORTS.Common;
2829
using Orts.Simulation.RollingStocks;
2930
using Orts.Viewer3D.RollingStock;
31+
using ORTS.Common;
3032

3133
namespace Orts.Viewer3D
3234
{
@@ -39,6 +41,7 @@ public class ParticleEmitterViewer
3941
public readonly float ParticleVolumeM3 = 0.001f;
4042
public readonly ParticleEmitterPrimitive Emitter;
4143

44+
public string TexturePath;
4245
ParticleEmitterMaterial Material;
4346

4447
#if DEBUG_EMITTER_INPUT
@@ -66,15 +69,40 @@ public ParticleEmitterViewer(Viewer viewer, ParticleEmitterData data, MSTSWagonV
6669
// Particles expand over time, this is just the initial volume, useful for calculating initial velocity
6770
ParticleVolumeM3 = 4.0f / 3.0f * MathHelper.Pi * ((EmitterData.NozzleDiameterM * EmitterData.NozzleDiameterM * EmitterData.NozzleDiameterM) / 8.0f);
6871
Emitter = new ParticleEmitterPrimitive(this, data, car, worldPosition);
72+
73+
if (!String.IsNullOrEmpty(EmitterData.Graphic))
74+
TexturePath = EmitterData.Graphic;
6975
#if DEBUG_EMITTER_INPUT
7076
EmitterID = ++EmitterIDIndex;
7177
InputCycle = Viewer.Random.Next(InputCycleLimit);
7278
#endif
73-
}
79+
}
7480

75-
public void Initialize(string textureName)
81+
public void Initialize(string defaultTextureName)
7682
{
77-
Material = (ParticleEmitterMaterial)Viewer.MaterialManager.Load("ParticleEmitter", textureName);
83+
bool customTexture = false;
84+
85+
if (!String.IsNullOrEmpty(TexturePath))
86+
customTexture = true;
87+
else
88+
TexturePath = defaultTextureName;
89+
90+
// Texture location preference is eng/wag folder -> MSTS GLOBAL\TEXTURES folder -> OR CONTENT folder
91+
if (File.Exists(Path.Combine(Path.GetDirectoryName(Emitter.CarViewer.Car.WagFilePath), TexturePath)))
92+
TexturePath = Path.Combine(Path.GetDirectoryName(Emitter.CarViewer.Car.WagFilePath), TexturePath);
93+
else if (File.Exists(Path.Combine(Viewer.Simulator.BasePath + @"\GLOBAL\TEXTURES\", TexturePath)))
94+
TexturePath = Path.Combine(Viewer.Simulator.BasePath + @"\GLOBAL\TEXTURES\", TexturePath);
95+
else if (customTexture && File.Exists(Path.Combine(Viewer.ContentPath, TexturePath)))
96+
TexturePath = Path.Combine(Viewer.ContentPath, TexturePath);
97+
else // Fall back to default texture in CONTENT folder
98+
{
99+
TexturePath = Path.Combine(Viewer.ContentPath, defaultTextureName);
100+
101+
if (customTexture)
102+
Trace.TraceWarning("Could not find particle graphic {0} at {1}", TexturePath, Path.Combine(Path.GetDirectoryName(Emitter.CarViewer.Car.WagFilePath), TexturePath));
103+
}
104+
105+
Material = (ParticleEmitterMaterial)Viewer.MaterialManager.Load("ParticleEmitter", TexturePath);
78106
}
79107

80108
/// <summary>
@@ -335,6 +363,8 @@ struct ParticleVertex
335363
internal float ParticleDuration;
336364
internal Color ParticleColor;
337365

366+
internal int SpriteCount;
367+
338368
internal float CompressionFactor = 1.0f;
339369

340370
internal WorldPosition WorldPosition;
@@ -373,6 +403,8 @@ public ParticleEmitterPrimitive(ParticleEmitterViewer particleViewer, ParticleEm
373403
ParticleDuration = 3;
374404
ParticleColor = Color.White;
375405

406+
SpriteCount = EmitterData.AtlasWidth * EmitterData.AtlasHeight;
407+
376408
CarViewer = car;
377409
WorldPosition = worldPosition;
378410

@@ -548,6 +580,7 @@ public void Update(float currentTime, ElapsedTime elapsedTime)
548580
rotY.Normalize();
549581

550582
float initialSpeed = XNAInitialVelocity.Length();
583+
Vector3 carVelocity = new Vector3(CarViewer.Velocity[0], CarViewer.Velocity[1], -CarViewer.Velocity[2]);
551584

552585
float time = currentTime - elapsedTime.ClockSeconds;
553586

@@ -559,12 +592,11 @@ public void Update(float currentTime, ElapsedTime elapsedTime)
559592

560593
int nextFreeParticle = (FirstFreeParticle + 1) % EmitterData.MaxParticles;
561594
int vertex = FirstFreeParticle * VerticesPerParticle;
562-
int texture = Viewer.Random.Next(16); // Randomizes emissions.
595+
int texture = Viewer.Random.Next(SpriteCount); // Randomizes particle texture to any texture on the sheet.
563596
// Alpha value of color is just a random number, not used (maybe allow for alpha changes?)
564597
Color color_Random = new Color(ParticleColor.R, ParticleColor.G, ParticleColor.B, (int)((float)Viewer.Random.NextDouble() * 255f));
565598

566599
Vector3 position = EmitterData.PositionM;
567-
Vector3 carVelocity = new Vector3(CarViewer.Velocity[0], CarViewer.Velocity[1], -CarViewer.Velocity[2]);
568600

569601
Vector3 initialVelocity = XNAInitialVelocity;
570602
Vector3 finalVelocity = XNAFinalVelocity;
@@ -764,6 +796,7 @@ public override void Render(GraphicsDevice graphicsDevice, IEnumerable<RenderIte
764796
var emitter = (ParticleEmitterPrimitive)item.RenderPrimitive;
765797
shader.EmitSize = emitter.EmitSize;
766798
shader.Texture = Texture;
799+
shader.TextureAtlasSizeXY = new Vector2(emitter.EmitterData.AtlasWidth, emitter.EmitterData.AtlasHeight);
767800
shader.SetMatrix(Matrix.Identity, ref XNAViewMatrix, ref XNAProjectionMatrix);
768801
ShaderPasses.Current.Apply();
769802
item.RenderPrimitive.Draw(graphicsDevice);

Source/RunActivity/Viewer3D/RollingStock/MSTSDieselLocomotiveViewer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public MSTSDieselLocomotiveViewer(Viewer viewer, MSTSDieselLocomotive car)
4141
// Now all the particle drawers have been setup, assign them textures based
4242
// on what emitters we know about.
4343

44-
string dieselTexture = viewer.Simulator.BasePath + @"\GLOBAL\TEXTURES\dieselsmoke.ace";
44+
string dieselTexture = "dieselsmoke.ace";
4545

4646

4747
// Diesel Exhaust

Source/RunActivity/Viewer3D/RollingStock/MSTSSteamLocomotiveViewer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public MSTSSteamLocomotiveViewer(Viewer viewer, MSTSSteamLocomotive car)
8080
{
8181
// Now all the particle drawers have been setup, assign them textures based
8282
// on what emitters we know about.
83-
string steamTexture = viewer.Simulator.BasePath + @"\GLOBAL\TEXTURES\smokemain.ace";
83+
string steamTexture = "smokemain.ace";
8484

8585
foreach (var emitter in ParticleDrawers)
8686
{

Source/RunActivity/Viewer3D/RollingStock/MSTSWagonViewer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ public MSTSWagonViewer(Viewer viewer, MSTSWagon car)
115115
: base(viewer, car)
116116
{
117117

118-
string steamTexture = viewer.Simulator.BasePath + @"\GLOBAL\TEXTURES\smokemain.ace";
119-
string dieselTexture = viewer.Simulator.BasePath + @"\GLOBAL\TEXTURES\dieselsmoke.ace";
118+
string steamTexture = "smokemain.ace";
119+
string dieselTexture = "dieselsmoke.ace";
120120

121121
// Particle Drawers called in Wagon so that wagons can also have steam effects.
122122
ParticleDrawers = (

Source/RunActivity/Viewer3D/Shaders.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ public class ParticleEmitterShader : Shader
468468
EffectParameter wvp;
469469
EffectParameter invView;
470470
EffectParameter texture;
471+
EffectParameter textureAtlasSize;
471472
EffectParameter lightVector;
472473
EffectParameter fog;
473474

@@ -486,6 +487,11 @@ public Texture2D Texture
486487
set { texture.SetValue(value); }
487488
}
488489

490+
public Vector2 TextureAtlasSizeXY
491+
{
492+
set { textureAtlasSize.SetValue(value); }
493+
}
494+
489495
public float EmitSize
490496
{
491497
set { emitSize.SetValue(value); }
@@ -505,6 +511,7 @@ public ParticleEmitterShader(GraphicsDevice graphicsDevice)
505511
invView = Parameters["invView"];
506512
tileXY = Parameters["cameraTileXY"];
507513
texture = Parameters["particle_Tex"];
514+
textureAtlasSize = Parameters["texAtlasSize"];
508515
lightVector = Parameters["LightVector"];
509516
fog = Parameters["Fog"];
510517
}

0 commit comments

Comments
 (0)