774 | function Dashboard:defaultDashboardStateFunc(dashboard, newValue, minValue, maxValue, isActive) |
775 | if dashboard.displayTypeIndex == Dashboard.TYPES.EMITTER then |
776 | Dashboard.defaultEmitterDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
777 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.NUMBER then |
778 | Dashboard.defaultNumberDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
779 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.ANIMATION then |
780 | Dashboard.defaultAnimationDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
781 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.ROT then |
782 | Dashboard.defaultRotationDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
783 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.VISIBILITY then |
784 | Dashboard.defaultVisibilityDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
785 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.TEXT then |
786 | Dashboard.defaultTextDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
787 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.SLIDER then |
788 | Dashboard.defaultSliderDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
789 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.MULTI_STATE then |
790 | Dashboard.defaultMultiStateDashboardStateFunc(self, dashboard, newValue, minValue, maxValue, isActive) |
791 | end |
792 | end |
968 | function Dashboard:defaultMultiStateDashboardStateFunc(dashboard, newValue, minValue, maxValue, isActive) |
969 | if dashboard.node ~= nil then |
970 | local activeState = nil |
971 | if isActive then |
972 | for i=1, #dashboard.states do |
973 | local state = dashboard.states[i] |
974 | if type(newValue) == "table" then |
975 | for j=1, #state.values do |
976 | if newValue[state.values[j]] == true then |
977 | activeState = state |
978 | end |
979 | end |
980 | elseif type(newValue) == "number" then |
981 | for j=1, #state.values do |
982 | if state.values[j] == MathUtil.round(newValue) then |
983 | activeState = state |
984 | end |
985 | end |
986 | end |
987 | end |
988 | end |
989 | |
990 | local rotation = dashboard.defaultRotation |
991 | local translation = dashboard.defaultTranslation |
992 | local scale = dashboard.defaultScale |
993 | local visibility = dashboard.defaultVisibility |
994 | if activeState ~= dashboard.lastState then |
995 | if activeState ~= nil then |
996 | rotation = activeState.rotation or rotation |
997 | translation = activeState.translation or translation |
998 | scale = activeState.scale or scale |
999 | |
1000 | if activeState.visibility ~= nil then |
1001 | visibility = activeState.visibility |
1002 | end |
1003 | end |
1004 | |
1005 | if dashboard.doInterpolation then |
1006 | if dashboard.interpolator ~= nil then |
1007 | dashboard.interpolator:update(9999999) |
1008 | end |
1009 | |
1010 | local interpolator = ValueInterpolator.new(dashboard.node.."_dashboard", dashboard.get, dashboard.set, {translation[1], translation[2], translation[3], |
1011 | rotation[1], rotation[2], rotation[3], |
1012 | scale[1], scale[2], scale[3], |
1013 | visibility and 1 or 0}, |
1014 | dashboard.multiStateInterpolationTime) |
1015 | if interpolator ~= nil then |
1016 | dashboard.interpolator = interpolator |
1017 | dashboard.interpolator:setDeleteListenerObject(self) |
1018 | dashboard.interpolator:setFinishedFunc(function(dash) dash.interpolator = nil end, dashboard) |
1019 | end |
1020 | else |
1021 | setRotation(dashboard.node, rotation[1], rotation[2], rotation[3]) |
1022 | setTranslation(dashboard.node, translation[1], translation[2], translation[3]) |
1023 | setScale(dashboard.node, scale[1], scale[2], scale[3]) |
1024 | setVisibility(dashboard.node, visibility) |
1025 | |
1026 | if self.setCharacterTargetNodeStateDirty ~= nil then |
1027 | self:setCharacterTargetNodeStateDirty(dashboard.node) |
1028 | end |
1029 | |
1030 | if self.setMovingToolDirty ~= nil then |
1031 | self:setMovingToolDirty(dashboard.node) |
1032 | end |
1033 | end |
1034 | |
1035 | dashboard.lastState = activeState |
1036 | end |
1037 | end |
1038 | end |
812 | function Dashboard:defaultNumberDashboardStateFunc(dashboard, newValue, minValue, maxValue, isActive) |
813 | if type(newValue) == "number" then |
814 | local value = tonumber(string.format("%."..dashboard.precision.."f", newValue)) |
815 | value = math.floor(value * 10 ^ dashboard.precision) |
816 | |
817 | for i=1, #dashboard.numberNodes do |
818 | local numberNode = dashboard.numberNodes[i] |
819 | |
820 | if value > 0 then |
821 | local curNumber = value - (math.floor(value / 10)*10) |
822 | value = (value - curNumber) / 10 |
823 | dashboard.fontMaterial:setFontCharacter(numberNode, ("%d"):format(curNumber)) |
824 | setVisibility(numberNode, true) |
825 | else |
826 | dashboard.fontMaterial:setFontCharacter(numberNode, "0") |
827 | if not (isActive and i - 1 <= dashboard.precision) then |
828 | setVisibility(numberNode, false) |
829 | end |
830 | end |
831 | end |
832 | elseif type(newValue) == "string" then |
833 | local length = newValue:len() |
834 | |
835 | for i=1, #dashboard.numberNodes do |
836 | local numberNode = dashboard.numberNodes[i] |
837 | |
838 | if i <= length then |
839 | local index = length - (i - 1) |
840 | dashboard.fontMaterial:setFontCharacter(numberNode, newValue:sub(index, index)) |
841 | end |
842 | |
843 | setVisibility(numberNode, isActive) |
844 | end |
845 | end |
846 | end |
886 | function Dashboard:defaultRotationDashboardStateFunc(dashboard, newValue, minValue, maxValue, isActive) |
887 | local alpha |
888 | if type(newValue) == "boolean" then |
889 | alpha = newValue and 1 or 0 |
890 | else |
891 | if dashboard.minValueRot ~= nil and dashboard.maxValueRot ~= nil then |
892 | newValue = MathUtil.clamp(newValue, dashboard.minValueRot, dashboard.maxValueRot) |
893 | alpha = MathUtil.round((newValue - dashboard.minValueRot) / (dashboard.maxValueRot-dashboard.minValueRot) , 3) |
894 | else |
895 | minValue = minValue or 0 |
896 | maxValue = maxValue or 1 |
897 | alpha = (newValue-minValue)/(maxValue-minValue) |
898 | end |
899 | end |
900 | |
901 | if dashboard.rotAxis ~= nil then |
902 | local x, y, z = getRotation(dashboard.node) |
903 | |
904 | local rot = MathUtil.lerp(dashboard.minRot, dashboard.maxRot, alpha) |
905 | if dashboard.rotAxis == 1 then |
906 | x = rot |
907 | elseif dashboard.rotAxis == 2 then |
908 | y = rot |
909 | else |
910 | z = rot |
911 | end |
912 | |
913 | setRotation(dashboard.node, x, y, z) |
914 | |
915 | if self.setCharacterTargetNodeStateDirty ~= nil then |
916 | self:setCharacterTargetNodeStateDirty(dashboard.node) |
917 | end |
918 | |
919 | if self.setMovingToolDirty ~= nil then |
920 | self:setMovingToolDirty(dashboard.node) |
921 | end |
922 | else |
923 | local x, y, z = MathUtil.vector3ArrayLerp(dashboard.minRot, dashboard.maxRot, alpha) |
924 | setRotation(dashboard.node, x, y, z) |
925 | |
926 | if self.setCharacterTargetNodeStateDirty ~= nil then |
927 | self:setCharacterTargetNodeStateDirty(dashboard.node) |
928 | end |
929 | |
930 | if self.setMovingToolDirty ~= nil then |
931 | self:setMovingToolDirty(dashboard.node) |
932 | end |
933 | end |
934 | end |
350 | function Dashboard:loadDashboardFromXML(xmlFile, key, dashboard, dashboardData) |
351 | local valueType = xmlFile:getValue(key .. "#valueType") |
352 | if valueType ~= nil then |
353 | if valueType ~= dashboardData.valueTypeToLoad then |
354 | return false |
355 | end |
356 | elseif dashboardData.valueTypeToLoad ~= nil then |
357 | Logging.xmlWarning(self.xmlFile, "Missing valueType for dashboard '%s'", key) |
358 | return false |
359 | end |
360 | |
361 | local displayType = xmlFile:getValue(key .. "#displayType") |
362 | if displayType ~= nil then |
363 | local displayTypeIndex = Dashboard.TYPES[displayType:upper()] |
364 | |
365 | if displayTypeIndex ~= nil then |
366 | dashboard.displayTypeIndex = displayTypeIndex |
367 | else |
368 | Logging.xmlWarning(self.xmlFile, "Unknown displayType '%s' for dashboard '%s'", displayType, key) |
369 | return false |
370 | end |
371 | else |
372 | Logging.xmlWarning(self.xmlFile, "Missing displayType for dashboard '%s'", key) |
373 | return false |
374 | end |
375 | |
376 | dashboard.doInterpolation = xmlFile:getValue(key .. "#doInterpolation", false) |
377 | dashboard.interpolationSpeed = xmlFile:getValue(key .. "#interpolationSpeed", 0.005) |
378 | dashboard.idleValue = xmlFile:getValue(key .. "#idleValue", dashboardData.idleValue or 0) |
379 | dashboard.lastInterpolationValue = dashboard.idleValue |
380 | |
381 | dashboard.groups = {} |
382 | local groupsStr = xmlFile:getValue(key .. "#groups") |
383 | local groups = string.split(groupsStr, " ") |
384 | for _, name in ipairs(groups) do |
385 | local group = self:getDashboardGroupByName(name) |
386 | if group ~= nil then |
387 | table.insert(dashboard.groups, group) |
388 | else |
389 | Logging.xmlWarning(self.xmlFile, "Unable to find dashboard group '%s' for dashboard '%s'", name, key) |
390 | end |
391 | end |
392 | |
393 | if dashboard.displayTypeIndex == Dashboard.TYPES.EMITTER then |
394 | if not self:loadEmitterDashboardFromXML(xmlFile, key, dashboard) then |
395 | return false |
396 | end |
397 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.NUMBER then |
398 | if not self:loadNumberDashboardFromXML(xmlFile, key, dashboard) then |
399 | return false |
400 | end |
401 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.ANIMATION then |
402 | if not self:loadAnimationDashboardFromXML(xmlFile, key, dashboard) then |
403 | return false |
404 | end |
405 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.ROT then |
406 | if not self:loadRotationDashboardFromXML(xmlFile, key, dashboard) then |
407 | return false |
408 | end |
409 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.VISIBILITY then |
410 | if not self:loadVisibilityDashboardFromXML(xmlFile, key, dashboard) then |
411 | return false |
412 | end |
413 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.TEXT then |
414 | if not self:loadTextDashboardFromXML(xmlFile, key, dashboard) then |
415 | return false |
416 | end |
417 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.SLIDER then |
418 | if not self:loadSliderDashboardFromXML(xmlFile, key, dashboard) then |
419 | return false |
420 | end |
421 | elseif dashboard.displayTypeIndex == Dashboard.TYPES.MULTI_STATE then |
422 | if not self:loadMultiStateDashboardFromXML(xmlFile, key, dashboard) then |
423 | return false |
424 | end |
425 | end |
426 | |
427 | if dashboardData.additionalAttributesFunc ~= nil then |
428 | if not dashboardData.additionalAttributesFunc(self, xmlFile, key, dashboard) then |
429 | return false |
430 | end |
431 | end |
432 | |
433 | dashboard.valueObject = dashboardData.valueObject |
434 | dashboard.valueFunc = dashboardData.valueFunc |
435 | dashboard.valueCompare = dashboardData.valueCompare |
436 | dashboard.valueFactor = dashboardData.valueFactor |
437 | dashboard.minFunc = dashboardData.minFunc |
438 | dashboard.maxFunc = dashboardData.maxFunc |
439 | dashboard.centerFunc = dashboardData.centerFunc |
440 | dashboard.stateFunc = dashboardData.stateFunc or Dashboard.defaultDashboardStateFunc |
441 | |
442 | dashboard.lastValue = dashboard.idleValue |
443 | |
444 | return true |
445 | end |
449 | function Dashboard:loadEmitterDashboardFromXML(xmlFile, key, dashboard) |
450 | local node = xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings) |
451 | if node ~= nil then |
452 | if getHasClassId(node, ClassIds.SHAPE) then |
453 | dashboard.node = node |
454 | |
455 | -- local materialId = getMaterial(node, 0) |
456 | -- if getMaterialCustomShaderFilename(materialId):contains("glowShader.xml") |
457 | -- and getMaterialCustomShaderVariation(materialId) == "staticLight" then |
458 | -- if not getMaterialNormalMapFilename(materialId):contains("default_normal") then |
459 | -- Logging.xmlWarning(self.xmlFile, "Glow shader mesh using different normal map than default! '%s' '%s' '%s'", getName(node), getMaterialNormalMapFilename(materialId), key) |
460 | -- end |
461 | -- end |
462 | -- |
463 | -- if getMaterialCustomShaderFilename(materialId):contains("glowShader.xml") |
464 | -- and getMaterialCustomShaderVariation(materialId) == "staticLight" then |
465 | -- if not getMaterialGlossMapFilename(materialId):contains("default_vmask") and not getMaterialGlossMapFilename(materialId):contains("singleColorTexture") then |
466 | -- Logging.xmlWarning(self.xmlFile, "Glow shader mesh using different specular map than default! '%s' '%s' '%s'", getName(node), getMaterialGlossMapFilename(materialId), key) |
467 | -- end |
468 | -- end |
469 | |
470 | dashboard.baseColor = self:getDashboardColor(xmlFile, xmlFile:getValue(key .. "#baseColor")) |
471 | if dashboard.baseColor ~= nil then |
472 | setShaderParameter(dashboard.node, "baseColor", dashboard.baseColor[1], dashboard.baseColor[2], dashboard.baseColor[3], 1, false) |
473 | end |
474 | |
475 | dashboard.emitColor = self:getDashboardColor(xmlFile, xmlFile:getValue(key .. "#emitColor")) |
476 | if dashboard.emitColor ~= nil then |
477 | setShaderParameter(dashboard.node, "emitColor", dashboard.emitColor[1], dashboard.emitColor[2], dashboard.emitColor[3], 1, false) |
478 | end |
479 | |
480 | dashboard.intensity = xmlFile:getValue(key .. "#intensity", 1) |
481 | setShaderParameter(dashboard.node, "lightControl", dashboard.idleValue, 0, 0, 0, false) |
482 | else |
483 | Logging.xmlWarning(self.xmlFile, "Emitter Dashboard node is not a shape! '%s' in '%s'", getName(node), key) |
484 | return false |
485 | end |
486 | else |
487 | Logging.xmlWarning(self.xmlFile, "Missing node for emitter dashboard '%s'", key) |
488 | return false |
489 | end |
490 | |
491 | return true |
492 | end |
704 | function Dashboard:loadMultiStateDashboardFromXML(xmlFile, key, dashboard) |
705 | dashboard.node = xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings) |
706 | if dashboard.node == nil then |
707 | Logging.xmlWarning(self.xmlFile, "Missing 'node' for dashboard '%s'", key) |
708 | return false |
709 | end |
710 | |
711 | dashboard.states = {} |
712 | |
713 | self.xmlFile:iterate(key..".state", function(index, stateKey) |
714 | local state = {} |
715 | state.values = xmlFile:getValue(stateKey.."#value", nil, true) |
716 | if state.values ~= nil and #state.values > 0 then |
717 | state.rotation = xmlFile:getValue(stateKey.."#rotation", nil, true) |
718 | state.translation = xmlFile:getValue(stateKey.."#translation", nil, true) |
719 | state.scale = xmlFile:getValue(stateKey.."#scale", nil, true) |
720 | state.visibility = xmlFile:getValue(stateKey.."#visibility") |
721 | |
722 | table.insert(dashboard.states, state) |
723 | end |
724 | end) |
725 | |
726 | if #dashboard.states == 0 then |
727 | Logging.xmlWarning(self.xmlFile, "No states defined for dashboard '%s'", key) |
728 | return false |
729 | end |
730 | |
731 | dashboard.multiStateInterpolationTime = 1 / dashboard.interpolationSpeed |
732 | dashboard.interpolationSpeed = 99999 |
733 | |
734 | dashboard.lastState = nil |
735 | |
736 | dashboard.get = function() |
737 | local x, y, z = getTranslation(dashboard.node) |
738 | local rx, ry, rz = getRotation(dashboard.node) |
739 | local sx, sy, sz = getScale(dashboard.node) |
740 | local vis = getVisibility(dashboard.node) and 1 or 0 |
741 | |
742 | return x, y, z, rx, ry, rz, sx, sy, sz, vis |
743 | end |
744 | |
745 | dashboard.set = function(x, y, z, rx, ry, rz, sx, sy, sz, vis) |
746 | setTranslation(dashboard.node, x, y, z) |
747 | setRotation(dashboard.node, rx, ry, rz) |
748 | setScale(dashboard.node, sx, sy, sz) |
749 | setVisibility(dashboard.node, vis >= 0.5) |
750 | |
751 | if self.setCharacterTargetNodeStateDirty ~= nil then |
752 | self:setCharacterTargetNodeStateDirty(dashboard.node) |
753 | end |
754 | |
755 | if self.setMovingToolDirty ~= nil then |
756 | self:setMovingToolDirty(dashboard.node) |
757 | end |
758 | end |
759 | |
760 | dashboard.defaultRotation = {getRotation(dashboard.node)} |
761 | dashboard.defaultTranslation = {getTranslation(dashboard.node)} |
762 | dashboard.defaultScale = {getScale(dashboard.node)} |
763 | dashboard.defaultVisibility = getVisibility(dashboard.node) |
764 | |
765 | return true |
766 | end |
496 | function Dashboard:loadNumberDashboardFromXML(xmlFile, key, dashboard) |
497 | dashboard.numbers = xmlFile:getValue(key.."#numbers", nil, self.components, self.i3dMappings) |
498 | |
499 | dashboard.numberColor = self:getDashboardColor(xmlFile, xmlFile:getValue(key.."#numberColor")) |
500 | if dashboard.numberColor == nil then |
501 | dashboard.numberColor = {0.9, 0.9, 0.9, 1} |
502 | end |
503 | |
504 | if dashboard.numbers ~= nil then |
505 | dashboard.precision = xmlFile:getValue(key.."#precision", 1) |
506 | dashboard.numChilds = getNumOfChildren(dashboard.numbers) |
507 | |
508 | dashboard.fontMaterialName = xmlFile:getValue(key.."#font", "DIGIT") |
509 | dashboard.hasNormalMap = xmlFile:getValue(key.."#hasNormalMap", false) |
510 | dashboard.emissiveScale = xmlFile:getValue(key.."#emissiveScale", 0.2) |
511 | |
512 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key.."#hiddenAlpha") --FS19 to FS22 |
513 | |
514 | dashboard.fontMaterial = g_materialManager:getFontMaterial(dashboard.fontMaterialName, self.customEnvironment) |
515 | if dashboard.fontMaterial ~= nil then |
516 | dashboard.numberNodes = {} |
517 | if dashboard.numChilds-dashboard.precision <= 0 then |
518 | Logging.xmlWarning(self.xmlFile, "Not enough number meshes for vehicle hud '%s'", key) |
519 | return false |
520 | else |
521 | for i=1,dashboard.numChilds do |
522 | local numberNode = getChildAt(dashboard.numbers, i - 1) |
523 | if numberNode ~= nil then |
524 | dashboard.fontMaterial:assignFontMaterialToNode(numberNode, dashboard.hasNormalMap) |
525 | if dashboard.numberColor ~= nil then |
526 | dashboard.fontMaterial:setFontCharacterColor(numberNode, dashboard.numberColor[1], dashboard.numberColor[2], dashboard.numberColor[3], 1, dashboard.emissiveScale) |
527 | end |
528 | setVisibility(numberNode, false) |
529 | |
530 | table.insert(dashboard.numberNodes, numberNode) |
531 | end |
532 | end |
533 | end |
534 | else |
535 | Logging.xmlWarning(self.xmlFile, "Unknown font '%s' in '%s'", dashboard.fontMaterialName, key) |
536 | return false |
537 | end |
538 | |
539 | 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 |
540 | else |
541 | Logging.xmlWarning(self.xmlFile, "Missing numbers node for dashboard '%s'", key) |
542 | return false |
543 | end |
544 | |
545 | return true |
546 | end |
621 | function Dashboard:loadRotationDashboardFromXML(xmlFile, key, dashboard) |
622 | dashboard.node = xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings) |
623 | if dashboard.node == nil then |
624 | Logging.xmlWarning(self.xmlFile, "Missing 'node' for dashboard '%s'", key) |
625 | return false |
626 | end |
627 | |
628 | dashboard.rotAxis = xmlFile:getValue(key.."#rotAxis") |
629 | |
630 | local minRotStr = xmlFile:getValue(key.."#minRot") |
631 | if minRotStr ~= nil then |
632 | if dashboard.rotAxis ~= nil then |
633 | dashboard.minRot = math.rad(tonumber(minRotStr)) |
634 | else |
635 | dashboard.minRot = minRotStr:getRadians(3) |
636 | end |
637 | else |
638 | Logging.xmlWarning(self.xmlFile, "Missing 'minRot' attribute for dashboard '%s'", key) |
639 | return false |
640 | end |
641 | |
642 | local maxRotStr = xmlFile:getValue(key.."#maxRot") |
643 | if maxRotStr ~= nil then |
644 | if dashboard.rotAxis ~= nil then |
645 | dashboard.maxRot = math.rad(tonumber(maxRotStr)) |
646 | else |
647 | dashboard.maxRot = maxRotStr:getRadians(3) |
648 | end |
649 | else |
650 | Logging.xmlWarning(self.xmlFile, "Missing 'maxRot' attribute for dashboard '%s'", key) |
651 | return false |
652 | end |
653 | |
654 | dashboard.minValueRot = xmlFile:getValue(key.."#minValueRot") |
655 | dashboard.maxValueRot = xmlFile:getValue(key.."#maxValueRot") |
656 | |
657 | return true |
658 | end |
677 | function Dashboard:loadSliderDashboardFromXML(xmlFile, key, dashboard) |
678 | dashboard.node = xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings) |
679 | if dashboard.node == nil then |
680 | Logging.xmlWarning(self.xmlFile, "Missing 'node' for dashboard '%s'", key) |
681 | return false |
682 | end |
683 | |
684 | if not getHasClassId(dashboard.node, ClassIds.SHAPE) then |
685 | Logging.xmlWarning(self.xmlFile, "Slider Dashboard node is not a shape! '%s' in '%s'", getName(dashboard.node), key) |
686 | return false |
687 | end |
688 | |
689 | if getHasShaderParameter(dashboard.node, "sliderPos") then |
690 | setShaderParameter(dashboard.node, "sliderPos", 0, 0, 0, 0, false) |
691 | |
692 | dashboard.minValueSlider = xmlFile:getValue(key.."#minValueSlider") |
693 | dashboard.maxValueSlider = xmlFile:getValue(key.."#maxValueSlider") |
694 | else |
695 | Logging.xmlWarning(self.xmlFile, "Node '%s' does not have a 'sliderPos' shader parameter for dashboard '%s'", getName(dashboard.node), key) |
696 | return false |
697 | end |
698 | |
699 | return true |
700 | end |
550 | function Dashboard:loadTextDashboardFromXML(xmlFile, key, dashboard) |
551 | dashboard.node = xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings) |
552 | |
553 | dashboard.textColor = self:getDashboardColor(xmlFile, xmlFile:getValue(key.."#textColor")) |
554 | if dashboard.textColor == nil then |
555 | dashboard.textColor = {0.9, 0.9, 0.9, 1} |
556 | end |
557 | |
558 | dashboard.hiddenColor = self:getDashboardColor(xmlFile, xmlFile:getValue(key.."#hiddenColor")) |
559 | |
560 | if dashboard.node ~= nil then |
561 | local textAlignmentStr = xmlFile:getValue(key.."#textAlignment", "RIGHT") |
562 | dashboard.textAlignment = RenderText["ALIGN_" .. textAlignmentStr:upper()] or RenderText.ALIGN_RIGHT |
563 | |
564 | dashboard.textSize = xmlFile:getValue(key.."#textSize", 0.03) |
565 | dashboard.textScaleX = xmlFile:getValue(key.."#textScaleX", 1) |
566 | dashboard.textScaleY = xmlFile:getValue(key.."#textScaleY", 1) |
567 | dashboard.textMask = xmlFile:getValue(key.."#textMask", "00.0") |
568 | dashboard.textFormatStr, dashboard.textFormatPrecision = string.maskToFormat(dashboard.textMask) |
569 | |
570 | dashboard.fontName = xmlFile:getValue(key.."#font", "DIGIT"):upper() |
571 | dashboard.fontThickness = xmlFile:getValue(key.."#fontThickness", 1) |
572 | dashboard.emissiveScale = xmlFile:getValue(key.."#emissiveScale", 0.2) |
573 | |
574 | dashboard.fontMaterial = g_materialManager:getFontMaterial(dashboard.fontName, self.customEnvironment) |
575 | if dashboard.fontMaterial ~= nil then |
576 | dashboard.characterLine = dashboard.fontMaterial:createCharacterLine(dashboard.node, |
577 | dashboard.textMask:len(), |
578 | dashboard.textSize, |
579 | dashboard.textColor, |
580 | dashboard.hiddenColor, |
581 | dashboard.emissiveScale, |
582 | dashboard.textScaleX, |
583 | dashboard.textScaleY, |
584 | dashboard.textAlignment, |
585 | nil, |
586 | dashboard.fontThickness) |
587 | |
588 | dashboard.fontMaterial:updateCharacterLine(dashboard.characterLine, dashboard.textMask) |
589 | else |
590 | Logging.xmlWarning(self.xmlFile, "Unknown font '%s' in '%s'", dashboard.fontName, key) |
591 | return false |
592 | end |
593 | |
594 | setVisibility(dashboard.node, false) |
595 | else |
596 | Logging.xmlWarning(self.xmlFile, "Missing node for dashboard '%s'", key) |
597 | return false |
598 | end |
599 | |
600 | return true |
601 | end |
1115 | function Dashboard.registerDashboardXMLPaths(schema, basePath, availableValueTypes) |
1116 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#valueType", string.format("Value type name (Available: %s)", availableValueTypes or "no valueTypes available here")) |
1117 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#displayType", "Display type name") |
1118 | schema:register(XMLValueType.BOOL, basePath .. ".dashboard(?)#doInterpolation", "Do interpolation", false) |
1119 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#interpolationSpeed", "Interpolation speed", 0.005) |
1120 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#idleValue", "Idle value", 0) |
1121 | |
1122 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#groups", "List of groups") |
1123 | |
1124 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".dashboard(?)#node", "(EMITTER | ROT | VISIBILITY) Node") |
1125 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#baseColor", "(EMITTER) Base color (DashboardColor OR BrandColor OR r g b a)") |
1126 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#emitColor", "(EMITTER) Emit color (DashboardColor OR BrandColor OR r g b a)") |
1127 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#intensity", "(EMITTER) Intensity", 1) |
1128 | |
1129 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".dashboard(?)#numbers", "(NUMBER) Numbers node") |
1130 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#numberColor", "(NUMBER) Numbers color (DashboardColor OR BrandColor OR r g b a)") |
1131 | schema:register(XMLValueType.INT, basePath .. ".dashboard(?)#precision", "(NUMBER) Precision", 1) |
1132 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#font", "(NUMBER) Name of font to apply to mesh", "DIGIT") |
1133 | schema:register(XMLValueType.BOOL, basePath .. ".dashboard(?)#hasNormalMap", "(NUMBER) Normal map will be applied to number decals", false) |
1134 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#emissiveScale", "(NUMBER) Scale of emissive map", 0.2) |
1135 | |
1136 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#textColor", "(TEXT) Font color (DashboardColor OR BrandColor OR r g b a)") |
1137 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#hiddenColor", "(TEXT) Color of hidden character (if defined a '0' in this color is display instead of nothing)") |
1138 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#textAlignment", "(TEXT) Alignment of text (LEFT | RIGHT | CENTER)", "RIGHT") |
1139 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#textSize", "(TEXT) Size of font in meter", 0.03) |
1140 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#fontThickness", "(TEXT) Thickness factor for font characters", 1.0) |
1141 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#textScaleX", "(TEXT) Global X scale of text", 1) |
1142 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#textScaleY", "(TEXT) Global Y scale of text", 1) |
1143 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#textMask", "(TEXT) Font Mask", "00.0") |
1144 | |
1145 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#animName", "(ANIMATION) Animation name") |
1146 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#minValueAnim", "(ANIMATION) Min. reference value for animation") |
1147 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#maxValueAnim", "(ANIMATION) Max. reference value for animation") |
1148 | |
1149 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#rotAxis", "(ROT) Rotation axis") |
1150 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#minRot", "(ROT) Min. rotation (Rotation value if rotAxis is given | Rotation Vector of rotAxis is not given)") |
1151 | schema:register(XMLValueType.STRING, basePath .. ".dashboard(?)#maxRot", "(ROT) Min. rotation (Rotation value if rotAxis is given | Rotation Vector of rotAxis is not given)") |
1152 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#minValueRot", "(ROT) Min. reference value for rotation") |
1153 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#maxValueRot", "(ROT) Max. reference value for rotation") |
1154 | |
1155 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#minValueSlider", "(SLIDER) Min. reference value for slider") |
1156 | schema:register(XMLValueType.FLOAT, basePath .. ".dashboard(?)#maxValueSlider", "(SLIDER) Max. reference value for slider") |
1157 | |
1158 | schema:register(XMLValueType.VECTOR_N, basePath .. ".dashboard(?).state(?)#value", "(MULTI_STATE) One or multiple values separated by space to activate the state") |
1159 | schema:register(XMLValueType.VECTOR_ROT, basePath .. ".dashboard(?).state(?)#rotation", "(MULTI_STATE) Rotation while state is active") |
1160 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. ".dashboard(?).state(?)#translation", "(MULTI_STATE) Translation while state is active") |
1161 | schema:register(XMLValueType.VECTOR_SCALE, basePath .. ".dashboard(?).state(?)#scale", "(MULTI_STATE) Scale while state is active") |
1162 | schema:register(XMLValueType.BOOL, basePath .. ".dashboard(?).state(?)#visibility", "(MULTI_STATE) Visibility while state is active") |
1163 | end |
66 | function Dashboard.registerFunctions(vehicleType) |
67 | SpecializationUtil.registerFunction(vehicleType, "updateDashboards", Dashboard.updateDashboards) |
68 | SpecializationUtil.registerFunction(vehicleType, "loadDashboardGroupFromXML", Dashboard.loadDashboardGroupFromXML) |
69 | SpecializationUtil.registerFunction(vehicleType, "getIsDashboardGroupActive", Dashboard.getIsDashboardGroupActive) |
70 | SpecializationUtil.registerFunction(vehicleType, "getDashboardGroupByName", Dashboard.getDashboardGroupByName) |
71 | SpecializationUtil.registerFunction(vehicleType, "loadDashboardsFromXML", Dashboard.loadDashboardsFromXML) |
72 | SpecializationUtil.registerFunction(vehicleType, "loadDashboardFromXML", Dashboard.loadDashboardFromXML) |
73 | SpecializationUtil.registerFunction(vehicleType, "loadEmitterDashboardFromXML", Dashboard.loadEmitterDashboardFromXML) |
74 | SpecializationUtil.registerFunction(vehicleType, "loadNumberDashboardFromXML", Dashboard.loadNumberDashboardFromXML) |
75 | SpecializationUtil.registerFunction(vehicleType, "loadTextDashboardFromXML", Dashboard.loadTextDashboardFromXML) |
76 | SpecializationUtil.registerFunction(vehicleType, "loadAnimationDashboardFromXML", Dashboard.loadAnimationDashboardFromXML) |
77 | SpecializationUtil.registerFunction(vehicleType, "loadRotationDashboardFromXML", Dashboard.loadRotationDashboardFromXML) |
78 | SpecializationUtil.registerFunction(vehicleType, "loadVisibilityDashboardFromXML", Dashboard.loadVisibilityDashboardFromXML) |
79 | SpecializationUtil.registerFunction(vehicleType, "loadSliderDashboardFromXML", Dashboard.loadSliderDashboardFromXML) |
80 | SpecializationUtil.registerFunction(vehicleType, "loadMultiStateDashboardFromXML", Dashboard.loadMultiStateDashboardFromXML) |
81 | SpecializationUtil.registerFunction(vehicleType, "setDashboardsDirty", Dashboard.setDashboardsDirty) |
82 | SpecializationUtil.registerFunction(vehicleType, "getDashboardValue", Dashboard.getDashboardValue) |
83 | SpecializationUtil.registerFunction(vehicleType, "getDashboardColor", Dashboard.getDashboardColor) |
84 | end |
203 | function Dashboard:updateDashboards(dashboards, dt, force) |
204 | for i=1, #dashboards do |
205 | local dashboard = dashboards[i] |
206 | local isActive = true |
207 | for j=1, #dashboard.groups do |
208 | if not dashboard.groups[j].isActive then |
209 | isActive = false |
210 | break |
211 | end |
212 | end |
213 | |
214 | if dashboard.valueObject ~= nil and dashboard.valueFunc ~= nil then |
215 | local value = self:getDashboardValue(dashboard.valueObject, dashboard.valueFunc, dashboard) |
216 | |
217 | if dashboard.valueFactor ~= nil and type(value) == "number" then |
218 | value = value * dashboard.valueFactor |
219 | end |
220 | |
221 | if not isActive then |
222 | value = dashboard.idleValue |
223 | end |
224 | |
225 | if dashboard.doInterpolation and type(value) == "number" and value ~= dashboard.lastInterpolationValue then |
226 | local dir = MathUtil.sign(value - dashboard.lastInterpolationValue) |
227 | local limitFunc = math.min |
228 | if dir < 0 then |
229 | limitFunc = math.max |
230 | end |
231 | |
232 | value = limitFunc(dashboard.lastInterpolationValue + dashboard.interpolationSpeed * dir * dt, value) |
233 | dashboard.lastInterpolationValue = value |
234 | end |
235 | |
236 | if value ~= dashboard.lastValue or force then |
237 | dashboard.lastValue = value |
238 | |
239 | local min, max |
240 | if type(value) == "number" then |
241 | -- for idle values while not active we ignore the limits |
242 | min = self:getDashboardValue(dashboard.valueObject, dashboard.minFunc, dashboard) |
243 | if min ~= nil and isActive then |
244 | value = math.max(min, value) |
245 | end |
246 | |
247 | max = self:getDashboardValue(dashboard.valueObject, dashboard.maxFunc, dashboard) |
248 | if max ~= nil and isActive then |
249 | value = math.min(max, value) |
250 | end |
251 | |
252 | local center = self:getDashboardValue(dashboard.valueObject, dashboard.centerFunc, dashboard) |
253 | if center ~= nil then |
254 | local maxValue = math.max(math.abs(min), math.abs(max)) |
255 | if value < center then |
256 | value = -value / min * maxValue |
257 | elseif value > center then |
258 | value = value / max * maxValue |
259 | end |
260 | |
261 | max = maxValue |
262 | min = -maxValue |
263 | end |
264 | end |
265 | |
266 | if dashboard.valueCompare ~= nil then |
267 | if type(dashboard.valueCompare) == "table" then |
268 | local oldValue = value |
269 | value = false |
270 | for _, compareValue in ipairs(dashboard.valueCompare) do |
271 | if oldValue == compareValue then |
272 | value = true |
273 | end |
274 | end |
275 | else |
276 | value = value == dashboard.valueCompare |
277 | end |
278 | end |
279 | |
280 | dashboard.stateFunc(self, dashboard, value, min, max, isActive) |
281 | end |
282 | elseif force then |
283 | dashboard.stateFunc(self, dashboard, true, nil, nil, isActive) |
284 | end |
285 | end |
286 | end |