522 | function Dashboard:defaultAnimationDashboardStateFunc(dashboard, newValue, minValue, maxValue, isActive) |
523 | if dashboard.animName ~= nil then |
524 | if self:getAnimationExists(dashboard.animName) then |
525 | local normValue |
526 | if dashboard.minValueAnim ~= nil and dashboard.maxValueAnim ~= nil then |
527 | newValue = MathUtil.clamp(newValue, dashboard.minValueAnim, dashboard.maxValueAnim) |
528 | normValue = MathUtil.round((newValue - dashboard.minValueAnim) / (dashboard.maxValueAnim-dashboard.minValueAnim) , 3) |
529 | else |
530 | minValue = minValue or 0 |
531 | maxValue = maxValue or 1 |
532 | normValue = MathUtil.round((newValue-minValue)/(maxValue-minValue), 3) |
533 | end |
534 | self:setAnimationTime(dashboard.animName, normValue, true) |
535 | else |
536 | g_logManager:xmlWarning(self.configFileName, "Unknown animation name '%s' for dashboard!", dashboard.animName) |
537 | dashboard.animName = nil |
538 | end |
539 | end |
540 | end |
487 | function Dashboard:defaultDashboardStateFunc(dashboard, newValue, minValue, maxValue, isActive) |
488 | if dashboard.displayTypeIndex == Dashboard.TYPES.EMITTER then |
489 | Dashboard.defaultEmitterDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
490 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.NUMBER then |
491 | Dashboard.defaultNumberDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
492 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.ANIMATION then |
493 | Dashboard.defaultAnimationDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
494 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.ROT then |
495 | Dashboard.defaultRotationDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
496 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.VISIBILITY then |
497 | Dashboard.defaultVisibilityDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
498 | end |
499 | end |
544 | function Dashboard:defaultRotationDashboardStateFunc(dashboard, newValue, minValue, maxValue, isActive) |
545 | minValue = minValue or 0 |
546 | maxValue = maxValue or 1 |
547 | local alpha = (newValue-minValue)/(maxValue-minValue) |
548 | |
549 | if dashboard.rotAxis ~= nil then |
550 | local x, y, z = getRotation(dashboard.node) |
551 | |
552 | local rot = MathUtil.lerp(dashboard.minRot, dashboard.maxRot, alpha) |
553 | if dashboard.rotAxis == 1 then |
554 | x = rot |
555 | elseif dashboard.rotAxis == 2 then |
556 | y = rot |
557 | else |
558 | z = rot |
559 | end |
560 | |
561 | setRotation(dashboard.node, x, y, z) |
562 | else |
563 | local x1, y1, z1 = unpack(dashboard.minRot) |
564 | local x2, y2, z2 = unpack(dashboard.maxRot) |
565 | local x, y, z = MathUtil.lerp3(x1, y1, z1, x2, y2, z2, alpha) |
566 | setRotation(dashboard.node, x, y, z) |
567 | end |
568 | end |
274 | function Dashboard:loadDashboardFromXML(xmlFile, key, dashboard, dashboardData) |
275 | local valueType = getXMLString(xmlFile, key .. "#valueType") |
276 | if valueType ~= nil then |
277 | if valueType ~= dashboardData.valueTypeToLoad then |
278 | return false |
279 | end |
280 | elseif dashboardData.valueTypeToLoad ~= nil then |
281 | g_logManager:xmlWarning(self.configFileName, "Missing valueType for dashboard '%s'", key) |
282 | return false |
283 | end |
284 | |
285 | local displayType = getXMLString(xmlFile, key .. "#displayType") |
286 | if displayType ~= nil then |
287 | local displayTypeIndex = Dashboard.TYPES[displayType:upper()] |
288 | |
289 | if displayTypeIndex ~= nil then |
290 | dashboard.displayTypeIndex = displayTypeIndex |
291 | else |
292 | g_logManager:xmlWarning(self.configFileName, "Unknown displayType '%s' for dashboard '%s'", displayType, key) |
293 | return false |
294 | end |
295 | else |
296 | g_logManager:xmlWarning(self.configFileName, "Missing displayType for dashboard '%s'", key) |
297 | return false |
298 | end |
299 | |
300 | dashboard.doInterpolation = Utils.getNoNil(getXMLBool(xmlFile, key .. "#doInterpolation"), false) |
301 | dashboard.interpolationSpeed = getXMLFloat(xmlFile, key .. "#interpolationSpeed") or 0.005 |
302 | dashboard.idleValue = getXMLFloat(xmlFile, key .. "#idleValue") or dashboardData.idleValue or 0 |
303 | dashboard.lastInterpolationValue = 0 |
304 | |
305 | dashboard.groups = {} |
306 | local groupsStr = getXMLString(xmlFile, key .. "#groups") |
307 | local groups = StringUtil.splitString(" ", groupsStr) |
308 | for _, name in ipairs(groups) do |
309 | local group = self:getDashboardGroupByName(name) |
310 | if group ~= nil then |
311 | table.insert(dashboard.groups, group) |
312 | else |
313 | g_logManager:xmlWarning(self.configFileName, "Unable to find dashboard group '%s' for dashboard '%s'", name, key) |
314 | end |
315 | end |
316 | |
317 | if dashboard.displayTypeIndex == Dashboard.TYPES.EMITTER then |
318 | if not self:loadEmitterDashboardFromXML(xmlFile, key, dashboard) then |
319 | return false |
320 | end |
321 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.NUMBER then |
322 | if not self:loadNumberDashboardFromXML(xmlFile, key, dashboard) then |
323 | return false |
324 | end |
325 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.ANIMATION then |
326 | if not self:loadAnimationDashboardFromXML(xmlFile, key, dashboard) then |
327 | return false |
328 | end |
329 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.ROT then |
330 | if not self:loadRotationDashboardFromXML(xmlFile, key, dashboard) then |
331 | return false |
332 | end |
333 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.VISIBILITY then |
334 | if not self:loadVisibilityDashboardFromXML(xmlFile, key, dashboard) then |
335 | return false |
336 | end |
337 | end |
338 | |
339 | if dashboardData.additionalAttributesFunc ~= nil then |
340 | if not dashboardData.additionalAttributesFunc(self, xmlFile, key, dashboard) then |
341 | return false |
342 | end |
343 | end |
344 | |
345 | dashboard.valueObject = dashboardData.valueObject |
346 | dashboard.valueFunc = dashboardData.valueFunc |
347 | dashboard.valueCompare = dashboardData.valueCompare |
348 | dashboard.minFunc = dashboardData.minFunc |
349 | dashboard.maxFunc = dashboardData.maxFunc |
350 | dashboard.centerFunc = dashboardData.centerFunc |
351 | dashboard.stateFunc = dashboardData.stateFunc or Dashboard.defaultDashboardStateFunc |
352 | |
353 | dashboard.lastValue = 0 |
354 | |
355 | return true |
356 | end |
245 | function Dashboard:loadDashboardsFromXML(xmlFile, key, dashboardData) |
246 | if self.isClient then |
247 | local spec = self.spec_dashboard |
248 | |
249 | local i = 0 |
250 | while true do |
251 | local baseKey = string.format("%s.dashboard(%d)", key, i) |
252 | if not hasXMLProperty(xmlFile, baseKey) then |
253 | break |
254 | end |
255 | |
256 | local dashboard = {} |
257 | if self:loadDashboardFromXML(xmlFile, baseKey, dashboard, dashboardData) then |
258 | if dashboard.displayTypeIndex ~= Dashboard.TYPES.ROT then |
259 | table.insert(spec.dashboards, dashboard) |
260 | else |
261 | table.insert(spec.criticalDashboards, dashboard) |
262 | end |
263 | end |
264 | |
265 | i = i + 1 |
266 | end |
267 | end |
268 | |
269 | return true |
270 | end |
360 | function Dashboard:loadEmitterDashboardFromXML(xmlFile, key, dashboard) |
361 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. "#node"), self.i3dMappings) |
362 | if node ~= nil then |
363 | dashboard.node = node |
364 | |
365 | dashboard.baseColor = self:getDashboardColor(getXMLString(xmlFile, key .. "#baseColor")) |
366 | if dashboard.baseColor ~= nil then |
367 | setShaderParameter(dashboard.node, "baseColor", dashboard.baseColor[1], dashboard.baseColor[2], dashboard.baseColor[3], dashboard.baseColor[4], false) |
368 | end |
369 | |
370 | dashboard.emitColor = self:getDashboardColor(getXMLString(xmlFile, key .. "#emitColor")) |
371 | if dashboard.emitColor ~= nil then |
372 | setShaderParameter(dashboard.node, "emitColor", dashboard.emitColor[1], dashboard.emitColor[2], dashboard.emitColor[3], dashboard.emitColor[4], false) |
373 | end |
374 | |
375 | dashboard.intensity = getXMLFloat(xmlFile, key .. "#intensity") or 1 |
376 | setShaderParameter(dashboard.node, "lightControl", dashboard.idleValue, 0, 0, 0, false) |
377 | else |
378 | g_logManager:xmlWarning(self.configFileName, "Missing node for emitter dashboard '%s'", key) |
379 | return false |
380 | end |
381 | |
382 | return true |
383 | end |
387 | function Dashboard:loadNumberDashboardFromXML(xmlFile, key, dashboard) |
388 | dashboard.numbers = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#numbers"), self.i3dMappings) |
389 | |
390 | dashboard.numberColor = self:getDashboardColor(getXMLString(xmlFile, key.."#numberColor")) |
391 | if dashboard.numbers ~= nil and dashboard.numberColor ~= nil then |
392 | for node, _ in pairs(I3DUtil.getNodesByShaderParam(dashboard.numbers, "numberColor")) do |
393 | setShaderParameter(node, "numberColor", dashboard.numberColor[1], dashboard.numberColor[2], dashboard.numberColor[3], dashboard.numberColor[4], false) |
394 | end |
395 | end |
396 | |
397 | if dashboard.numbers ~= nil then |
398 | dashboard.precision = Utils.getNoNil(getXMLInt(xmlFile, key.."#precision"), 1) |
399 | dashboard.numChilds = getNumOfChildren(dashboard.numbers) |
400 | if dashboard.numChilds-dashboard.precision <= 0 then |
401 | g_logManager:xmlWarning(self.configFileName, "Not enough number meshes for vehicle hud '%s'", key) |
402 | end |
403 | dashboard.numChilds = dashboard.numChilds - dashboard.precision |
404 | dashboard.maxValue = (10 ^ (dashboard.numChilds)) - 1/(10^dashboard.precision) -- e.g. max with 2 childs and 1 float -> 10^2 - 1/10 -> 99.9 -> makes sure that display doesn't show 00.0 if value is 100 |
405 | else |
406 | g_logManager:xmlWarning(self.configFileName, "Missing numbers node for dashboard '%s'", key) |
407 | return false |
408 | end |
409 | |
410 | return true |
411 | end |
431 | function Dashboard:loadRotationDashboardFromXML(xmlFile, key, dashboard) |
432 | dashboard.node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#node"), self.i3dMappings) |
433 | if dashboard.node == nil then |
434 | g_logManager:xmlWarning(self.configFileName, "Missing 'node' for dashboard '%s'", key) |
435 | return false |
436 | end |
437 | |
438 | dashboard.rotAxis = getXMLInt(xmlFile, key.."#rotAxis") |
439 | |
440 | local minRotStr = getXMLString(xmlFile, key.."#minRot") |
441 | if minRotStr ~= nil then |
442 | if dashboard.rotAxis ~= nil then |
443 | dashboard.minRot = math.rad(tonumber(minRotStr)) |
444 | else |
445 | dashboard.minRot = StringUtil.getRadiansFromString(minRotStr, 3) |
446 | end |
447 | else |
448 | g_logManager:xmlWarning(self.configFileName, "Missing 'minRot' attribute for dashboard '%s'", key) |
449 | return false |
450 | end |
451 | |
452 | local maxRotStr = getXMLString(xmlFile, key.."#maxRot") |
453 | if maxRotStr ~= nil then |
454 | if dashboard.rotAxis ~= nil then |
455 | dashboard.maxRot = math.rad(tonumber(maxRotStr)) |
456 | else |
457 | dashboard.maxRot = StringUtil.getRadiansFromString(maxRotStr, 3) |
458 | end |
459 | else |
460 | g_logManager:xmlWarning(self.configFileName, "Missing 'maxRot' attribute for dashboard '%s'", key) |
461 | return false |
462 | end |
463 | |
464 | return true |
465 | end |
112 | function Dashboard:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
113 | if self.isClient then |
114 | local spec = self.spec_dashboard |
115 | |
116 | local groupChanged = false |
117 | for _, group in pairs(spec.groups) do |
118 | if self:getIsDashboardGroupActive(group) ~= group.isActive then |
119 | group.isActive = not group.isActive |
120 | groupChanged = true |
121 | end |
122 | end |
123 | |
124 | if groupChanged then |
125 | self:updateDashboards(spec.dashboards, dt, true) |
126 | self:updateDashboards(spec.criticalDashboards, dt, true) |
127 | else |
128 | self:updateDashboards(spec.dashboards, dt) |
129 | end |
130 | |
131 | spec.isDirty = false |
132 | end |
133 | end |
41 | function Dashboard.registerFunctions(vehicleType) |
42 | SpecializationUtil.registerFunction(vehicleType, "updateDashboards", Dashboard.updateDashboards) |
43 | SpecializationUtil.registerFunction(vehicleType, "loadDashboardGroupFromXML", Dashboard.loadDashboardGroupFromXML) |
44 | SpecializationUtil.registerFunction(vehicleType, "getIsDashboardGroupActive", Dashboard.getIsDashboardGroupActive) |
45 | SpecializationUtil.registerFunction(vehicleType, "getDashboardGroupByName", Dashboard.getDashboardGroupByName) |
46 | SpecializationUtil.registerFunction(vehicleType, "loadDashboardsFromXML", Dashboard.loadDashboardsFromXML) |
47 | SpecializationUtil.registerFunction(vehicleType, "loadDashboardFromXML", Dashboard.loadDashboardFromXML) |
48 | SpecializationUtil.registerFunction(vehicleType, "loadEmitterDashboardFromXML", Dashboard.loadEmitterDashboardFromXML) |
49 | SpecializationUtil.registerFunction(vehicleType, "loadNumberDashboardFromXML", Dashboard.loadNumberDashboardFromXML) |
50 | SpecializationUtil.registerFunction(vehicleType, "loadAnimationDashboardFromXML", Dashboard.loadAnimationDashboardFromXML) |
51 | SpecializationUtil.registerFunction(vehicleType, "loadRotationDashboardFromXML", Dashboard.loadRotationDashboardFromXML) |
52 | SpecializationUtil.registerFunction(vehicleType, "loadVisibilityDashboardFromXML", Dashboard.loadVisibilityDashboardFromXML) |
53 | SpecializationUtil.registerFunction(vehicleType, "setDashboardsDirty", Dashboard.setDashboardsDirty) |
54 | SpecializationUtil.registerFunction(vehicleType, "getDashboardValue", Dashboard.getDashboardValue) |
55 | SpecializationUtil.registerFunction(vehicleType, "getDashboardColor", Dashboard.getDashboardColor) |
56 | end |
137 | function Dashboard:updateDashboards(dashboards, dt, force) |
138 | for _, dashboard in ipairs(dashboards) do |
139 | local isActive = true |
140 | for _, group in ipairs(dashboard.groups) do |
141 | if not group.isActive then |
142 | isActive = false |
143 | break |
144 | end |
145 | end |
146 | |
147 | if dashboard.valueObject ~= nil and dashboard.valueFunc ~= nil then |
148 | local value = self:getDashboardValue(dashboard.valueObject, dashboard.valueFunc, dashboard) |
149 | if not isActive then |
150 | value = dashboard.idleValue |
151 | end |
152 | |
153 | if dashboard.doInterpolation and type(value) == "number" and value ~= dashboard.lastInterpolationValue then |
154 | local dir = MathUtil.sign(value - dashboard.lastInterpolationValue) |
155 | local limitFunc = math.min |
156 | if dir < 0 then |
157 | limitFunc = math.max |
158 | end |
159 | |
160 | value = limitFunc(dashboard.lastInterpolationValue + dashboard.interpolationSpeed * dir * dt, value) |
161 | dashboard.lastInterpolationValue = value |
162 | end |
163 | |
164 | if value ~= dashboard.lastValue or force then |
165 | dashboard.lastValue = value |
166 | |
167 | local min = self:getDashboardValue(dashboard.valueObject, dashboard.minFunc, dashboard) |
168 | if min ~= nil then |
169 | value = math.max(min, value) |
170 | end |
171 | |
172 | local max = self:getDashboardValue(dashboard.valueObject, dashboard.maxFunc, dashboard) |
173 | if max ~= nil then |
174 | value = math.min(max, value) |
175 | end |
176 | |
177 | local center = self:getDashboardValue(dashboard.valueObject, dashboard.centerFunc, dashboard) |
178 | if center ~= nil then |
179 | local maxValue = math.max(math.abs(min), math.abs(max)) |
180 | if value < center then |
181 | value = -value / min * maxValue |
182 | elseif value > center then |
183 | value = value / max * maxValue |
184 | end |
185 | |
186 | max = maxValue |
187 | min = -maxValue |
188 | end |
189 | |
190 | if dashboard.valueCompare ~= nil then |
191 | if type(dashboard.valueCompare) == "table" then |
192 | local oldValue = value |
193 | value = false |
194 | for _, compareValue in ipairs(dashboard.valueCompare) do |
195 | if oldValue == compareValue then |
196 | value = true |
197 | end |
198 | end |
199 | else |
200 | value = value == dashboard.valueCompare |
201 | end |
202 | end |
203 | |
204 | dashboard.stateFunc(self, dashboard, value, min, max, isActive) |
205 | end |
206 | elseif force then |
207 | dashboard.stateFunc(self, dashboard, true, nil, nil, isActive) |
208 | end |
209 | end |
210 | end |