Skip to content

Commit 56c0f02

Browse files
authored
Merge pull request #391 from Csantucci/2D-wiper-animation
Animated wipers for 2D cabs, see http://www.elvastower.com/forums/index.php?/topic/34604-2d-cabs-wipers-animation/
2 parents 4df3be7 + b509983 commit 56c0f02

File tree

4 files changed

+178
-1
lines changed

4 files changed

+178
-1
lines changed

Source/Documentation/Manual/cabs.rst

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,69 @@ ORTS_SIGNED_TRACTION_BRAKING, with the only difference that the braking
262262
force does include also the train brake force in addition to the dynamic
263263
brake force.
264264

265+
Animated 2D Wipers
266+
------------------
267+
268+
.. index::
269+
single: ORTS_2DEXTERNALWIPERS
270+
271+
This control animates the wipers as seen from a 2D cab.
272+
Animation is triggered on/off through key V.
273+
274+
Here is an example of a 2D wipers control block within the .cvf file::
275+
276+
277+
ORTSAnimatedDisplay (
278+
Type ( ORTS_2DEXTERNALWIPERS MULTI_STATE_DISPLAY )
279+
Position ( 155 0 331.875 236.25 )
280+
Graphic ( ..//..//Common.Cab//CabE464_DMI//e464Tergicristallo9.ace )
281+
ORTSCycleTime ( 1.35 )
282+
States ( 9 3 3
283+
State (
284+
Style ( 0 )
285+
SwitchVal ( 0 )
286+
)
287+
State (
288+
Style ( 0 )
289+
SwitchVal ( 0.11 )
290+
)
291+
State (
292+
Style ( 0 )
293+
SwitchVal ( 0.22 )
294+
)
295+
State (
296+
Style ( 0 )
297+
SwitchVal ( 0.33 )
298+
)
299+
State (
300+
Style ( 0 )
301+
SwitchVal ( 0.44 )
302+
)
303+
State (
304+
Style ( 0 )
305+
SwitchVal ( 0.55 )
306+
)
307+
State (
308+
Style ( 0 )
309+
SwitchVal ( 0.66 )
310+
)
311+
State (
312+
Style ( 0 )
313+
SwitchVal ( 0.77 )
314+
)
315+
State (
316+
Style ( 0 )
317+
SwitchVal ( 0.88 )
318+
)
319+
)
320+
)
321+
322+
ORTSCycleTime is expressed in seconds.
323+
The .ace file must contain only the frames related to half cycle, that is
324+
if e.g. the wiper moves from left to right and back, only the frames related
325+
to the motion from left to right have to be included. For the reverse
326+
motion the same frames are used from last to first. SwitchVal can vary from 0 to 1.
327+
265328
Further OR cab controls
266329
-----------------------
267330

Source/Orts.Formats.Msts/CabViewFile.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ public enum CABViewControlTypes
183183
ORTS_OVERCHARGE,
184184
ORTS_BATTERY,
185185
ORTS_POWERKEY,
186+
ORTS_2DEXTERNALWIPERS,
186187

187188
// TCS Controls
188189
ORTS_TCS1,
@@ -302,6 +303,7 @@ public CabViewControls(STFReader stf, string basepath)
302303
int count = stf.ReadInt(null);
303304

304305
stf.ParseBlock(new STFReader.TokenProcessor[] {
306+
new STFReader.TokenProcessor("ortsanimateddisplay", ()=>{ Add(new CVCAnimatedDisplay(stf, basepath)); }),
305307
new STFReader.TokenProcessor("dial", ()=>{ Add(new CVCDial(stf, basepath)); }),
306308
new STFReader.TokenProcessor("gauge", ()=>{ Add(new CVCGauge(stf, basepath)); }),
307309
new STFReader.TokenProcessor("lever", ()=>{ Add(new CVCDiscrete(stf, basepath)); }),
@@ -1165,6 +1167,54 @@ protected int ParseNumStyle(STFReader stf)
11651167
return style;
11661168
}
11671169
}
1170+
1171+
public class CVCAnimatedDisplay : CVCWithFrames
1172+
{
1173+
public List<double> MSStyles = new List<double>();
1174+
public float CycleTimeS;
1175+
1176+
public CVCAnimatedDisplay(STFReader stf, string basepath)
1177+
{
1178+
1179+
stf.MustMatch("(");
1180+
stf.ParseBlock(new STFReader.TokenProcessor[] {
1181+
new STFReader.TokenProcessor("type", ()=>{ ParseType(stf); }),
1182+
new STFReader.TokenProcessor("position", ()=>{ ParsePosition(stf); }),
1183+
new STFReader.TokenProcessor("scalerange", ()=>{ ParseScaleRange(stf); }),
1184+
new STFReader.TokenProcessor("graphic", ()=>{ ParseGraphic(stf, basepath); }),
1185+
new STFReader.TokenProcessor("units", ()=>{ ParseUnits(stf); }),
1186+
new STFReader.TokenProcessor("ortscycletime", ()=>{
1187+
CycleTimeS = stf.ReadFloatBlock(STFReader.UNITS.Time, null); }),
1188+
new STFReader.TokenProcessor("states", ()=>{
1189+
stf.MustMatch("(");
1190+
FramesCount = stf.ReadInt(null);
1191+
FramesX = stf.ReadInt(null);
1192+
FramesY = stf.ReadInt(null);
1193+
stf.ParseBlock(new STFReader.TokenProcessor[] {
1194+
new STFReader.TokenProcessor("state", ()=>{
1195+
stf.MustMatch("(");
1196+
stf.ParseBlock( new STFReader.TokenProcessor[] {
1197+
new STFReader.TokenProcessor("style", ()=>{ MSStyles.Add(ParseNumStyle(stf));
1198+
}),
1199+
new STFReader.TokenProcessor("switchval", ()=>{ Values.Add(stf.ReadFloatBlock(STFReader.UNITS.None, null))
1200+
; }),
1201+
});}),
1202+
});
1203+
if (Values.Count > 0) MaxValue = Values.Last();
1204+
for (int i = Values.Count; i < FramesCount; i++)
1205+
Values.Add(-10000);
1206+
}),
1207+
});
1208+
}
1209+
protected int ParseNumStyle(STFReader stf)
1210+
{
1211+
stf.MustMatch("(");
1212+
var style = stf.ReadInt(0);
1213+
stf.SkipRestOfBlock();
1214+
return style;
1215+
}
1216+
}
1217+
11681218
#endregion
11691219

11701220
#region Screen based controls

Source/Orts.Simulation/Simulation/RollingStocks/MSTSLocomotive.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4864,6 +4864,9 @@ public virtual float GetDataOf(CabViewControl cvc)
48644864
case CABViewControlTypes.ORTS_POWERKEY:
48654865
data = PowerKey ? 1 : 0;
48664866
break;
4867+
case CABViewControlTypes.ORTS_2DEXTERNALWIPERS:
4868+
data = Wiper ? 1 : 0;
4869+
break;
48674870
case CABViewControlTypes.ORTS_HOURDIAL:
48684871
float hour = (float)(Simulator.ClockTime / 3600) % 12;
48694872
if (hour < 0)

Source/RunActivity/Viewer3D/RollingStock/MSTSLocomotiveViewer.cs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,16 @@ public CabRenderer(Viewer viewer, MSTSLocomotive car)
11421142
count[(int)cvc.ControlType]++;
11431143
continue;
11441144
}
1145+
CVCAnimatedDisplay anim = cvc as CVCAnimatedDisplay;
1146+
if (anim != null)
1147+
{
1148+
CabViewAnimationsRenderer animr = new CabViewAnimationsRenderer(viewer, car, anim, _Shader);
1149+
animr.SortIndex = controlSortIndex;
1150+
CabViewControlRenderersList[i].Add(animr);
1151+
if (!ControlMap.ContainsKey(key)) ControlMap.Add(key, animr);
1152+
count[(int)cvc.ControlType]++;
1153+
continue;
1154+
}
11451155
CVCMultiStateDisplay multi = cvc as CVCMultiStateDisplay;
11461156
if (multi != null)
11471157
{
@@ -1830,6 +1840,12 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
18301840
if ((mS.MSStyles.Count > index) && (mS.MSStyles[index] == 1) && (CumulativeTime > CVCFlashTimeOn))
18311841
return;
18321842
}
1843+
1844+
PrepareFrameForIndex(frame, elapsedTime, index);
1845+
}
1846+
1847+
protected void PrepareFrameForIndex(RenderFrame frame, ElapsedTime elapsedTime, int index)
1848+
{
18331849
var dark = Viewer.MaterialManager.sunDirection.Y <= -0.085f || Viewer.Camera.IsUnderground;
18341850

18351851
Texture = CABTextureManager.GetTextureByIndexes(Control.ACEFile, index, dark, Locomotive.CabLightOn, out IsNightTexture, HasCabLightDirectory);
@@ -2269,7 +2285,7 @@ public void HandleUserInput()
22692285
/// </summary>
22702286
/// <param name="percent">Percent to be translated</param>
22712287
/// <returns>The calculated display index by the Control's Values</returns>
2272-
int PercentToIndex(float percent)
2288+
protected int PercentToIndex(float percent)
22732289
{
22742290
var index = 0;
22752291

@@ -2302,6 +2318,51 @@ int PercentToIndex(float percent)
23022318
}
23032319
}
23042320

2321+
/// <summary>
2322+
/// Discrete renderer for animated controls, like external 2D wiper
2323+
/// </summary>
2324+
public class CabViewAnimationsRenderer : CabViewDiscreteRenderer
2325+
{
2326+
private float CumulativeTime;
2327+
private readonly float CycleTimeS;
2328+
private bool AnimationOn = false;
2329+
2330+
public CabViewAnimationsRenderer(Viewer viewer, MSTSLocomotive locomotive, CVCAnimatedDisplay control, CabShader shader)
2331+
: base(viewer, locomotive, control, shader)
2332+
{
2333+
CycleTimeS = control.CycleTimeS;
2334+
}
2335+
2336+
public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
2337+
{
2338+
var animate = Locomotive.GetDataOf(Control) != 0;
2339+
if (animate)
2340+
AnimationOn = true;
2341+
2342+
int index;
2343+
var halfCycleS = CycleTimeS / 2f;
2344+
if (AnimationOn)
2345+
{
2346+
CumulativeTime += elapsedTime.ClockSeconds;
2347+
if (CumulativeTime > CycleTimeS && !animate)
2348+
AnimationOn = false;
2349+
CumulativeTime %= CycleTimeS;
2350+
2351+
if (CumulativeTime < halfCycleS)
2352+
index = PercentToIndex(CumulativeTime / halfCycleS);
2353+
else
2354+
index = PercentToIndex((CycleTimeS - CumulativeTime) / halfCycleS);
2355+
}
2356+
else
2357+
{
2358+
index = 0;
2359+
}
2360+
2361+
PrepareFrameForIndex(frame, elapsedTime, index);
2362+
}
2363+
}
2364+
2365+
23052366
/// <summary>
23062367
/// Digital Cab Control renderer
23072368
/// Uses fonts instead of graphic

0 commit comments

Comments
 (0)