!B (Sandbox) (CE-21795) Importing models with multisubmaterials via fbx switches...
[CRYENGINE.git] / Code / Tools / Statoscope / Statoscope / EventReader.cs
blobab55ee6ea647c01f32e24d6090135a774e96aed9
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using System.Text;
7 using System.Runtime.InteropServices;
8 using System.Reflection;
10 namespace Statoscope
12 enum EventId
14 EI_DefineClass = 0,
15 EI_BeginInterval,
16 EI_EndInterval,
17 EI_ModifyInterval,
18 EI_ModifyIntervalBit,
21 class EventPropertyDesc
23 public EFrameElementType type;
24 public FieldInfo field;
26 public EventPropertyDesc(EFrameElementType type, FieldInfo field)
28 this.type = type;
29 this.field = field;
33 class EventClassDesc
35 public readonly Type propertiesType;
36 public readonly EventPropertyDesc[] properties;
38 public EventClassDesc(Type propertiesType, EventPropertyDesc[] properties)
40 this.propertiesType = propertiesType;
41 this.properties = properties;
45 class EventReader
47 Dictionary<UInt64, PendingInterval> m_pendingIntervals = new Dictionary<UInt64, PendingInterval>();
48 byte m_nextEventSequence = 0;
49 Int64 m_lastTimestamp = 0;
51 Dictionary<UInt32, EventClassDesc> m_classDescs = new Dictionary<UInt32, EventClassDesc>();
52 Dictionary<UInt32, IIntervalSink> m_sinks = new Dictionary<uint, IIntervalSink>();
54 public EventReader(IIntervalSink[] intervalSinks)
56 foreach (IIntervalSink sink in intervalSinks)
57 m_sinks[sink.ClassId] = sink;
60 public void ReadEvents(IBinaryLogDataStream stream)
62 UInt32 eventStreamLen = stream.ReadUInt32();
63 int eventStreamPos = 0;
64 for (eventStreamPos = 0; eventStreamPos < (int)eventStreamLen; )
66 byte eventId = stream.ReadByte();
67 byte sequence = stream.ReadByte();
68 UInt16 eventLengthInWords = stream.ReadUInt16();
69 Int64 timeStamp = stream.ReadInt64();
71 if (sequence != m_nextEventSequence)
72 throw new ApplicationException("Event sequence mismatch");
73 if (timeStamp < m_lastTimestamp)
74 throw new ApplicationException("Timestamps go backwards");
76 ++m_nextEventSequence;
77 m_lastTimestamp = timeStamp;
79 int eventLength = eventLengthInWords * 4 - 12;
81 switch ((EventId)eventId)
83 case EventId.EI_DefineClass: ReadDefineClass(timeStamp, eventLength, stream); break;
84 case EventId.EI_BeginInterval: ReadBeginInterval(timeStamp, eventLength, stream); break;
85 case EventId.EI_EndInterval: ReadEndInterval(timeStamp, eventLength, stream); break;
86 case EventId.EI_ModifyInterval: ReadModifyInterval(timeStamp, eventLength, stream); break;
87 case EventId.EI_ModifyIntervalBit: ReadModifyIntervalBit(timeStamp, eventLength, stream); break;
88 default: throw new ApplicationException("Unknown event type");
91 eventStreamPos += eventLengthInWords * 4;
94 if (eventStreamPos != eventStreamLen)
95 throw new ApplicationException("Event stream is corrupt");
98 private void ReadDefineClass(Int64 timeStamp, int eventLength, IBinaryLogDataStream stream)
100 UInt32 classId = stream.ReadUInt32();
101 UInt32 numElements = stream.ReadUInt32();
103 byte[] descBytes = stream.ReadBytes(eventLength - 8);
105 IIntervalSink sink = m_sinks[classId];
106 Type propType = sink.PropertiesType;
108 EventPropertyDesc[] properties = new EventPropertyDesc[numElements];
110 int p = 0;
111 for (UInt32 elementIdx = 0; elementIdx < numElements; ++elementIdx)
113 byte typeId = descBytes[p++];
115 int nullTermIdx = Array.IndexOf<byte>(descBytes, 0, p);
116 string name = System.Text.Encoding.ASCII.GetString(descBytes, p, (nullTermIdx >= 0 ? nullTermIdx : descBytes.Length) - p);
117 p = nullTermIdx + 1;
119 // Find a field with the same name in the C# type
120 FieldInfo field = propType.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
121 properties[elementIdx] = new EventPropertyDesc((EFrameElementType)typeId, field);
124 m_classDescs[classId] = new EventClassDesc(propType, properties);
127 private void ReadBeginInterval(Int64 timeStamp, int eventLength, IBinaryLogDataStream stream)
129 UInt64 ivId = stream.ReadUInt64();
130 UInt32 classId = stream.ReadUInt32();
132 EventClassDesc classDesc = m_classDescs[classId];
134 var pi = new PendingInterval();
136 Interval iv = (Interval)Activator.CreateInstance(classDesc.propertiesType);
137 iv.StartUs = timeStamp;
138 iv.EndUs = Int64.MaxValue;
140 pi.classId = classId;
141 pi.sink = m_sinks[classId];
143 byte[] values = stream.ReadBytes(eventLength - 12);
145 int p = 0;
146 for (int i = 0, c = classDesc.properties.Length; i < c; ++i)
148 object val;
150 switch (classDesc.properties[i].type)
152 case EFrameElementType.Float:
153 val = EndianBitConverter.ToSingle(values, p, stream.Endianness);
154 p += 4;
155 break;
157 case EFrameElementType.Int:
158 val = EndianBitConverter.ToInt32(values, p, stream.Endianness);
159 p += 4;
160 break;
162 case EFrameElementType.String:
164 int nullTerm = Array.IndexOf<byte>(values, 0, p);
165 string s = System.Text.Encoding.ASCII.GetString(values, p, nullTerm - p);
166 p = (nullTerm + 4) & ~3;
167 val = s;
169 break;
171 case EFrameElementType.Int64:
172 val = EndianBitConverter.ToInt64(values, p, stream.Endianness);
173 p += 8;
174 break;
176 default:
177 throw new ApplicationException("Unhandled property type");
180 if (classDesc.properties[i].field != null)
181 classDesc.properties[i].field.SetValue(iv, val);
184 pi.iv = iv;
185 m_pendingIntervals[ivId] = pi;
187 pi.sink.OnBegunInterval(ivId, iv);
190 private void ReadModifyInterval(Int64 timeStamp, int eventLength, IBinaryLogDataStream stream)
192 UInt64 ivId = stream.ReadUInt64();
193 UInt32 classId = stream.ReadUInt32();
194 UInt32 field = stream.ReadUInt32();
195 UInt32 fieldId = field & 0x7fffffff;
196 UInt32 splitInterval = field & 0x80000000;
198 byte[] values = stream.ReadBytes(eventLength - 16);
200 if (m_pendingIntervals.ContainsKey(ivId))
202 EventClassDesc classDesc = m_classDescs[classId];
203 PendingInterval pi = m_pendingIntervals[ivId];
204 Interval iv = pi.iv;
206 if (splitInterval != 0)
208 iv.EndUs = timeStamp;
210 Interval ivClone = (Interval)iv.Clone();
212 pi.sink.OnFinalisedInterval(ivId, iv, true);
214 iv = ivClone;
215 pi.iv = iv;
216 iv.StartUs = timeStamp;
217 iv.EndUs = Int64.MaxValue;
220 EEndian srcEndian = stream.Endianness;
222 object val = null;
223 switch (classDesc.properties[fieldId].type)
225 case EFrameElementType.Float:
226 val = EndianBitConverter.ToSingle(values, 0, srcEndian);
227 break;
229 case EFrameElementType.Int:
230 val = EndianBitConverter.ToInt32(values, 0, srcEndian);
231 break;
233 case EFrameElementType.String:
235 int nullTerm = Array.IndexOf<byte>(values, 0, 0);
236 string s = System.Text.Encoding.ASCII.GetString(values, 0, nullTerm);
237 val = s;
239 break;
241 case EFrameElementType.Int64:
242 val = EndianBitConverter.ToInt64(values, 0, srcEndian);
243 break;
245 default:
246 throw new ApplicationException("Unhandled property type");
249 if (classDesc.properties[fieldId].field != null)
250 classDesc.properties[fieldId].field.SetValue(iv, val);
252 if (splitInterval != 0)
254 pi.sink.OnBegunInterval(ivId, iv);
257 else
259 //throw new ApplicationException("Unknown interval");
263 private void ReadModifyIntervalBit(Int64 timeStamp, int eventLength, IBinaryLogDataStream stream)
265 UInt64 ivId = stream.ReadUInt64();
266 UInt32 classId = stream.ReadUInt32();
267 UInt32 field = stream.ReadUInt32();
268 UInt32 fieldId = field & 0x7fffffff;
269 UInt32 splitInterval = field & 0x80000000;
271 byte[] values = stream.ReadBytes(eventLength - 16);
273 if (m_pendingIntervals.ContainsKey(ivId))
275 EventClassDesc classDesc = m_classDescs[classId];
276 PendingInterval pi = m_pendingIntervals[ivId];
277 Interval iv = pi.iv;
279 if (splitInterval != 0)
281 iv.EndUs = timeStamp;
283 Interval ivClone = (Interval)iv.Clone();
285 pi.sink.OnFinalisedInterval(ivId, iv, true);
287 iv = ivClone;
288 pi.iv = iv;
289 iv.StartUs = timeStamp;
290 iv.EndUs = Int64.MaxValue;
293 EEndian srcEndian = stream.Endianness;
295 object valMask = null, valOr = null;
296 switch (classDesc.properties[fieldId].type)
298 case EFrameElementType.Int:
299 valMask = EndianBitConverter.ToInt32(values, 0, srcEndian);
300 valOr = EndianBitConverter.ToInt32(values, 4, srcEndian);
301 break;
303 case EFrameElementType.Int64:
304 valMask = EndianBitConverter.ToInt64(values, 0, srcEndian);
305 valOr = EndianBitConverter.ToInt64(values, 8, srcEndian);
306 break;
308 default:
309 throw new ApplicationException("Unhandled property type");
312 if (classDesc.properties[fieldId].field != null)
314 object oldVal = classDesc.properties[fieldId].field.GetValue(iv);
316 switch (classDesc.properties[fieldId].type)
318 case EFrameElementType.Int:
319 classDesc.properties[fieldId].field.SetValue(iv, ((int)oldVal & (int)valMask) | ((int)valOr));
320 break;
322 case EFrameElementType.Int64:
323 classDesc.properties[fieldId].field.SetValue(iv, ((long)oldVal & (long)valMask) | ((long)valOr));
324 break;
328 if (splitInterval != 0)
330 pi.sink.OnBegunInterval(ivId, iv);
333 else
335 //throw new ApplicationException("Unknown interval");
339 private void ReadEndInterval(Int64 timeStamp, int eventLength, IBinaryLogDataStream stream)
341 UInt64 ivId = stream.ReadUInt64();
343 if (m_pendingIntervals.ContainsKey(ivId))
345 PendingInterval pi = m_pendingIntervals[ivId];
346 Interval iv = pi.iv;
348 iv.EndUs = timeStamp;
349 pi.sink.OnFinalisedInterval(ivId, iv, false);
351 m_pendingIntervals.Remove(ivId);
355 class PendingInterval
357 public UInt32 classId;
359 public Interval iv;
360 public IIntervalSink sink;