316 | function FillVolume:loadFillVolume(xmlFile, key, entry) |
317 | local spec = self.spec_fillVolume |
318 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key .. "#index", key .. "#node") -- FS17 |
319 | |
320 | entry.baseNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key .. "#node"), self.i3dMappings) |
321 | if entry.baseNode == nil then |
322 | print("Warning: fillVolume '"..tostring(key).."' has an invalid 'node' in '"..self.configFileName.."'!") |
323 | return false |
324 | end |
325 | |
326 | local fillUnitIndex = getXMLInt(xmlFile, key.."#fillUnitIndex") |
327 | entry.fillUnitIndex = fillUnitIndex |
328 | if fillUnitIndex == nil then |
329 | print("Warning: fillVolume '"..tostring(key).."' has no 'fillUnitIndex' given in '"..self.configFileName.."'!") |
330 | return false |
331 | end |
332 | if not self:getFillUnitExists(fillUnitIndex) then |
333 | print("Warning: fillVolume '"..tostring(key).."' has an invalid 'fillUnitIndex' in '"..self.configFileName.."'!") |
334 | return false |
335 | end |
336 | |
337 | entry.fillUnitFactor = Utils.getNoNil(getXMLFloat(xmlFile, key.."#fillUnitFactor"), 1.0) |
338 | |
339 | if spec.fillUnitFillVolumeMapping[fillUnitIndex] == nil then |
340 | spec.fillUnitFillVolumeMapping[fillUnitIndex] = {fillVolumes={}, sumFactors=0} |
341 | end |
342 | table.insert(spec.fillUnitFillVolumeMapping[fillUnitIndex].fillVolumes, entry) |
343 | spec.fillUnitFillVolumeMapping[fillUnitIndex].sumFactors = entry.fillUnitFactor |
344 | |
345 | entry.allSidePlanes = Utils.getNoNil(getXMLBool(xmlFile, key .. "#allSidePlanes"), true) |
346 | |
347 | local defaultFillTypeStr = getXMLString(xmlFile, key .. "#defaultFillType") |
348 | if defaultFillTypeStr ~= nil then |
349 | local defaultFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(defaultFillTypeStr) |
350 | if defaultFillTypeIndex == nil then |
351 | print("Warning: Invalid defaultFillType '"..tostring(defaultFillTypeStr).."' for '"..tostring(key).."' in '"..self.configFileName.."'") |
352 | return false |
353 | else |
354 | entry.defaultFillType = defaultFillTypeIndex |
355 | end |
356 | else |
357 | entry.defaultFillType = self:getFillUnitFirstSupportedFillType(fillUnitIndex) |
358 | end |
359 | |
360 | local forcedVolumeFillTypeStr = getXMLString(xmlFile, key .. "#defaultFillType") |
361 | if forcedVolumeFillTypeStr ~= nil then |
362 | local forcedVolumeFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(forcedVolumeFillTypeStr) |
363 | if forcedVolumeFillTypeIndex ~= nil then |
364 | entry.forcedVolumeFillType = forcedVolumeFillTypeIndex |
365 | else |
366 | print("Warning: Invalid forcedVolumeFillType '"..tostring(forcedVolumeFillTypeStr).."' for '"..tostring(key).."' in '"..self.configFileName.."'") |
367 | return false |
368 | end |
369 | end |
370 | |
371 | entry.maxDelta = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxDelta"), 1.0) |
372 | entry.maxSurfaceAngle = math.rad( Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxAllowedHeapAngle"), 35) ) |
373 | |
374 | entry.maxPhysicalSurfaceAngle = math.rad(35) |
375 | entry.maxSubDivEdgeLength = Utils.getNoNil(getXMLFloat(xmlFile, key.."#maxSubDivEdgeLength"), 0.9) |
376 | |
377 | entry.uvPosition = {0, 0, 0} |
378 | |
379 | entry.deformers = {} |
380 | local j = 0 |
381 | while true do |
382 | local deformerKey = string.format("%s.deformNode(%d)", key, j) |
383 | if not hasXMLProperty(xmlFile, deformerKey) then |
384 | break |
385 | end |
386 | |
387 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, deformerKey .. "#index", deformerKey .. "#node") -- FS17 |
388 | |
389 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, deformerKey .. "#node"), self.i3dMappings) |
390 | if node ~= nil then |
391 | local initPos = {localToLocal(node, entry.baseNode, 0,0,0)} |
392 | local deformer = {node = node, initPos = initPos, posX = initPos[1], posZ = initPos[3], polyline = nil, volume = entry.volume, baseNode = entry.baseNode} |
393 | table.insert(entry.deformers, deformer) |
394 | spec.fillVolumeDeformersByNode[node] = deformer |
395 | end |
396 | j = j + 1 |
397 | end |
398 | |
399 | entry.lastFillType = FillType.UNKNOWN |
400 | |
401 | return true |
402 | end |
452 | function FillVolume:loadFillVolumeHeightNode(xmlFile, key, entry) |
453 | entry.isDirty = false |
454 | |
455 | entry.fillVolumeIndex = getXMLInt(xmlFile, key.."#fillVolumeIndex") or 1 |
456 | |
457 | if self.spec_fillVolume.volumes[entry.fillVolumeIndex] == nil then |
458 | g_logManager:xmlWarning(self.configFileName, "Invalid fillVolumeIndex '%d' for heightNode '%s'. Igoring heightNode!", entry.fillVolumeIndex, key) |
459 | return false |
460 | end |
461 | |
462 | entry.refNodes = {} |
463 | local i = 0 |
464 | while true do |
465 | local nodeKey = key .. string.format(".refNode(%d)", i) |
466 | if not hasXMLProperty(xmlFile, nodeKey) then |
467 | break |
468 | end |
469 | |
470 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, nodeKey .. "#index", nodeKey .. "#node") -- FS17 to FS19 |
471 | |
472 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, nodeKey.."#node"), self.i3dMappings) |
473 | if node ~= nil then |
474 | table.insert(entry.refNodes, {refNode = node}) |
475 | else |
476 | g_logManager:xmlWarning(self.configFileName, "Missing node for '%s'", nodeKey) |
477 | end |
478 | |
479 | i = i + 1 |
480 | end |
481 | |
482 | entry.nodes = {} |
483 | i = 0 |
484 | while true do |
485 | local nodeKey = key .. string.format(".node(%d)", i) |
486 | if not hasXMLProperty(xmlFile, nodeKey) then |
487 | break |
488 | end |
489 | |
490 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, nodeKey .. "#index", nodeKey .. "#node") -- FS17 to FS19 |
491 | |
492 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, nodeKey.."#node"), self.i3dMappings) |
493 | if node ~= nil then |
494 | local nodeEntry = {} |
495 | nodeEntry.node = node |
496 | nodeEntry.baseScale = { StringUtil.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, nodeKey.."#baseScale"), "1 1 1")) } |
497 | nodeEntry.scaleAxis = { StringUtil.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, nodeKey.."#scaleAxis"), "0 0 0")) } |
498 | nodeEntry.scaleMax = { StringUtil.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, nodeKey.."#scaleMax"), "0 0 0")) } |
499 | nodeEntry.basePosition = { getTranslation(node) } |
500 | nodeEntry.transAxis = { StringUtil.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, nodeKey.."#transAxis"), "0 0 0")) } |
501 | nodeEntry.transMax = { StringUtil.getVectorFromString(Utils.getNoNil(getXMLString(xmlFile, nodeKey.."#transMax"), "0 0 0")) } |
502 | nodeEntry.orientateToWorldY = Utils.getNoNil(getXMLBool(xmlFile, nodeKey.."#orientateToWorldY"), false) |
503 | table.insert(entry.nodes, nodeEntry) |
504 | else |
505 | g_logManager:xmlWarning(self.configFileName, "Missing node for '%s'", nodeKey) |
506 | end |
507 | |
508 | i = i + 1 |
509 | end |
510 | |
511 | return true |
512 | end |
406 | function FillVolume:loadFillVolumeInfo(xmlFile, key, entry) |
407 | entry.nodes = {} |
408 | local i = 0 |
409 | while true do |
410 | local infoKey = key .. string.format(".node(%d)", i) |
411 | if not hasXMLProperty(xmlFile, infoKey) then |
412 | break |
413 | end |
414 | |
415 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, infoKey .. "#index", infoKey .. "#node") -- FS17 to FS19 |
416 | |
417 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, infoKey .. "#node"), self.i3dMappings) |
418 | if node ~= nil then |
419 | local nodeEntry = {} |
420 | |
421 | nodeEntry.node = node |
422 | nodeEntry.width = Utils.getNoNil(getXMLFloat(xmlFile, infoKey .. "#width"), 1.0) |
423 | nodeEntry.length = Utils.getNoNil(getXMLFloat(xmlFile, infoKey .. "#length"), 1.0) |
424 | |
425 | nodeEntry.fillVolumeHeightIndex = getXMLInt(xmlFile, infoKey .. "#fillVolumeHeightIndex") |
426 | nodeEntry.priority = Utils.getNoNil(getXMLInt(xmlFile, infoKey .. "#priority"), 1) |
427 | nodeEntry.minHeight = getXMLFloat(xmlFile, infoKey .. "#minHeight") |
428 | nodeEntry.maxHeight = getXMLFloat(xmlFile, infoKey .. "#maxHeight") |
429 | nodeEntry.minFillLevelPercentage = getXMLFloat(xmlFile, infoKey .. "#minFillLevelPercentage") |
430 | nodeEntry.maxFillLevelPercentage = getXMLFloat(xmlFile, infoKey .. "#maxFillLevelPercentage") |
431 | |
432 | nodeEntry.heightForTranslation = getXMLFloat(xmlFile, infoKey .. "#heightForTranslation") |
433 | nodeEntry.translationStart = StringUtil.getVectorNFromString(getXMLString(xmlFile, infoKey .. "#translationStart"), 3) |
434 | nodeEntry.translationEnd = StringUtil.getVectorNFromString(getXMLString(xmlFile, infoKey .. "#translationEnd"), 3) |
435 | nodeEntry.translationAlpha = 0 |
436 | |
437 | table.insert(entry.nodes, nodeEntry) |
438 | else |
439 | g_logManager:xmlWarning(self.configFileName, "Missing node for '%s'", infoKey) |
440 | end |
441 | |
442 | i = i + 1 |
443 | end |
444 | |
445 | table.sort(entry.nodes, function(a, b) return a.priority > b.priority end) |
446 | |
447 | return true |
448 | end |
584 | function FillVolume:onFillUnitFillLevelChanged(fillUnitIndex, fillLevelDelta, fillType, toolType, fillPositionData, appliedDelta) |
585 | local spec = self.spec_fillVolume |
586 | |
587 | local mapping = spec.fillUnitFillVolumeMapping[fillUnitIndex] |
588 | if mapping == nil then |
589 | return |
590 | end |
591 | |
592 | local fillLevel = self:getFillUnitFillLevel(fillUnitIndex) |
593 | |
594 | fillType = self:getFillUnitFillType(fillUnitIndex) |
595 | |
596 | for _, volume in ipairs(mapping.fillVolumes) do |
597 | local baseNode = volume.baseNode |
598 | local volumeNode = volume.volume |
599 | if baseNode == nil or volumeNode == nil then |
600 | return |
601 | end |
602 | |
603 | if volume.forcedFillType ~= nil then |
604 | fillType = volume.forcedFillType |
605 | end |
606 | if fillLevel == 0 then |
607 | volume.forcedFillType = nil |
608 | end |
609 | |
610 | if fillType ~= volume.lastFillType then |
611 | local maxPhysicalSurfaceAngle |
612 | local fillType = g_fillTypeManager:getFillTypeByIndex(fillType) |
613 | if fillType ~= nil then |
614 | maxPhysicalSurfaceAngle = fillType.maxPhysicalSurfaceAngle |
615 | end |
616 | if maxPhysicalSurfaceAngle ~= nil then |
617 | if volume.volume ~= nil then |
618 | setFillPlaneMaxPhysicalSurfaceAngle(volume.volume, maxPhysicalSurfaceAngle) |
619 | end |
620 | end |
621 | end |
622 | |
623 | setVisibility(volume.volume, fillLevel > 0) |
624 | |
625 | local material = nil |
626 | if fillType ~= FillType.UNKNOWN and fillType ~= volume.lastFillType then |
627 | local usedFillType = fillType |
628 | if volume.forcedVolumeFillType ~= nil then |
629 | usedFillType = volume.forcedVolumeFillType |
630 | end |
631 | material = g_materialManager:getMaterial(usedFillType, "fillplane", 1) |
632 | end |
633 | |
634 | if fillType ~= FillType.UNKNOWN and fillType ~= volume.lastFillType then |
635 | if material == nil and volume.defaultFillType ~= nil then |
636 | material = g_materialManager:getMaterial(volume.defaultFillType, "fillplane", 1) |
637 | end |
638 | |
639 | if material ~= nil then |
640 | setMaterial(volume.volume, material, 0) |
641 | end |
642 | end |
643 | |
644 | if fillPositionData ~= nil then |
645 | local availableFillNodes = {} |
646 | |
647 | if fillPositionData.nodes ~= nil then |
648 | local neededPriority = fillPositionData.nodes[1].priority |
649 | |
650 | while table.getn(availableFillNodes) == 0 and neededPriority >= 1 do |
651 | |
652 | for _,node in pairs(fillPositionData.nodes) do |
653 | if node.priority >= neededPriority then |
654 | local doInsert = true |
655 | |
656 | if node.minHeight ~= nil or node.maxHeight ~= nil then |
657 | |
658 | local height = -math.huge |
659 | if node.fillVolumeHeightIndex ~= nil and spec.heightNodes[node.fillVolumeHeightIndex] ~= nil then |
660 | for _,refNode in pairs(spec.heightNodes[node.fillVolumeHeightIndex].refNodes) do |
661 | local x,_,z = localToLocal(refNode.refNode, baseNode, 0,0,0) |
662 | height = math.max(height, getFillPlaneHeightAtLocalPos(volumeNode, x,z)) |
663 | end |
664 | else |
665 | local x,_,z = localToLocal(node.node, baseNode, 0,0,0) |
666 | height = math.max(height, getFillPlaneHeightAtLocalPos(volumeNode, x,z)) |
667 | end |
668 | |
669 | if node.minHeight ~= nil and height < node.minHeight then |
670 | doInsert = false |
671 | end |
672 | if node.maxHeight ~= nil and height > node.maxHeight then |
673 | doInsert = false |
674 | end |
675 | |
676 | if node.heightForTranslation ~= nil then |
677 | if height > node.heightForTranslation then |
678 | node.translationAlpha = node.translationAlpha + 0.01 |
679 | local x,y,z = MathUtil.vector3ArrayLerp(node.translationStart, node.translationEnd, node.translationAlpha) |
680 | setTranslation(node.node, x,y,z) |
681 | else |
682 | node.translationAlpha = node.translationAlpha - 0.01 |
683 | end |
684 | node.translationAlpha = MathUtil.clamp(node.translationAlpha, 0, 1) |
685 | end |
686 | |
687 | end |
688 | |
689 | if node.minFillLevelPercentage ~= nil or node.maxFillLevelPercentage ~= nil then |
690 | local percentage = fillLevel / self:getFillUnitCapacity(fillUnitIndex) |
691 | |
692 | if node.minFillLevelPercentage ~= nil and percentage < node.minFillLevelPercentage then |
693 | doInsert = false |
694 | end |
695 | if node.maxFillLevelPercentage ~= nil and percentage > node.maxFillLevelPercentage then |
696 | doInsert = false |
697 | end |
698 | end |
699 | |
700 | if doInsert then |
701 | table.insert(availableFillNodes, node) |
702 | end |
703 | end |
704 | end |
705 | if table.getn(availableFillNodes) > 0 then |
706 | break |
707 | end |
708 | neededPriority = neededPriority - 1 |
709 | end |
710 | else |
711 | table.insert(availableFillNodes, fillPositionData) |
712 | end |
713 | |
714 | local numFillNodes = table.getn(availableFillNodes) |
715 | |
716 | local avgX, avgZ = 0, 0 |
717 | |
718 | for i=1,numFillNodes do |
719 | local node = availableFillNodes[i] |
720 | |
721 | local x0,y0,z0 = getWorldTranslation(node.node) |
722 | local d1x,d1y,d1z = localDirectionToWorld(node.node, node.width,0,0) |
723 | local d2x,d2y,d2z = localDirectionToWorld(node.node, 0,0,node.length) |
724 | |
725 | if VehicleDebug.state == VehicleDebug.DEBUG then |
726 | drawDebugLine( x0,y0,z0, 1,0,0, x0+d1x, y0+d1y, z0+d1z, 1,0,0 ) |
727 | drawDebugLine( x0,y0,z0, 0,0,1, x0+d2x, y0+d2y, z0+d2z, 0,0,1 ) |
728 | drawDebugPoint( x0,y0,z0, 1,1,1,1 ) |
729 | drawDebugPoint( x0+d1x, y0+d1y, z0+d1z, 1,0,0,1 ) |
730 | drawDebugPoint( x0+d2x, y0+d2y, z0+d2z, 0,0,1,1 ) |
731 | end |
732 | x0 = x0 - (d1x + d2x) / 2 |
733 | y0 = y0 - (d1y + d2y) / 2 |
734 | z0 = z0 - (d1z + d2z) / 2 |
735 | fillPlaneAdd(volume.volume, appliedDelta/numFillNodes, x0,y0,z0, d1x,d1y,d1z, d2x,d2y,d2z) |
736 | |
737 | local newX, _, newZ = localToLocal(node.node, volume.volume, 0, 0, 0) |
738 | avgX, avgZ = avgX+newX, avgZ+newZ |
739 | end |
740 | |
741 | local newX = avgX / numFillNodes |
742 | local newZ = avgZ / numFillNodes |
743 | if math.abs(newX-spec.lastPositionInfoSent[1]) > FillVolume.SEND_PRECISION or math.abs(newZ-spec.lastPositionInfoSent[2]) > FillVolume.SEND_PRECISION then |
744 | spec.lastPositionInfoSent[1] = newX |
745 | spec.lastPositionInfoSent[2] = newZ |
746 | |
747 | self:raiseDirtyFlags(spec.dirtyFlag) |
748 | end |
749 | else |
750 | local x,y,z = localToWorld(volume.volume, 0,0,0) |
751 | local d1x,d1y,d1z = localDirectionToWorld(volume.volume, 0.1,0,0) |
752 | local d2x,d2y,d2z = localDirectionToWorld(volume.volume, 0,0,0.1) |
753 | |
754 | if not self.isServer then |
755 | if spec.lastPositionInfo[1] ~= 0 and spec.lastPositionInfo[2] ~= 0 then |
756 | x, y, z = localToWorld(volume.volume, spec.lastPositionInfo[1], 0, spec.lastPositionInfo[2]) |
757 | end |
758 | end |
759 | |
760 | local steps = MathUtil.clamp(math.floor(appliedDelta/400), 1, 25) |
761 | for i=1, steps do |
762 | fillPlaneAdd(volume.volume, appliedDelta/steps, x,y,z, d1x,d1y,d1z, d2x,d2y,d2z) |
763 | end |
764 | end |
765 | |
766 | local heightNodes = spec.fillVolumeIndexToHeightNode[volume.index] |
767 | if heightNodes ~= nil then |
768 | for _, heightNode in ipairs(heightNodes) do |
769 | heightNode.isDirty = true |
770 | end |
771 | end |
772 | |
773 | for _,deformer in pairs(volume.deformers) do |
774 | deformer.isDirty = true |
775 | end |
776 | |
777 | volume.lastFillType = fillType |
778 | end |
779 | end |
62 | function FillVolume:onLoad(savegame) |
63 | local spec = self.spec_fillVolume |
64 | |
65 | local fillVolumeConfigurationId = Utils.getNoNil(self.configurations["fillVolume"], 1) |
66 | local configKey = string.format("vehicle.fillVolume.fillVolumeConfigurations.fillVolumeConfiguration(%d).volumes", fillVolumeConfigurationId -1) |
67 | ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.fillVolume.fillVolumeConfigurations.fillVolumeConfiguration", fillVolumeConfigurationId , self.components, self) |
68 | |
69 | spec.volumes = {} |
70 | spec.fillVolumeDeformersByNode = {} |
71 | spec.fillUnitFillVolumeMapping = {} |
72 | local i = 0 |
73 | while true do |
74 | local key = string.format("%s.volume(%d)", configKey, i) |
75 | if not hasXMLProperty(self.xmlFile, key) then |
76 | break |
77 | end |
78 | local entry = {} |
79 | if self:loadFillVolume(self.xmlFile, key, entry) then |
80 | table.insert(spec.volumes, entry) |
81 | entry.index = #spec.volumes |
82 | end |
83 | i = i + 1 |
84 | end |
85 | |
86 | -- create fill units |
87 | for _, mapping in ipairs(spec.fillUnitFillVolumeMapping) do |
88 | for _, fillVolume in ipairs(mapping.fillVolumes) do |
89 | fillVolume.fillUnitFactor = fillVolume.fillUnitFactor / mapping.sumFactors |
90 | end |
91 | end |
92 | |
93 | for _, fillVolume in ipairs(spec.volumes) do |
94 | local capacity = self:getFillUnitCapacity(fillVolume.fillUnitIndex) |
95 | local fillVolumeCapacity = capacity * fillVolume.fillUnitFactor |
96 | fillVolume.volume = createFillPlaneShape(fillVolume.baseNode, "fillPlane", fillVolumeCapacity, fillVolume.maxDelta, fillVolume.maxSurfaceAngle, fillVolume.maxPhysicalSurfaceAngle, fillVolume.maxSubDivEdgeLength, fillVolume.allSidePlanes) |
97 | if fillVolume.volume == nil or fillVolume.volume == 0 then |
98 | print("Warning: fillVolume '"..tostring(getName(fillVolume.baseNode)).."' could not create actual fillVolume in '"..self.configFileName.."'! Simplifying the mesh could help") |
99 | else |
100 | setVisibility(fillVolume.volume, false) |
101 | |
102 | for i=#fillVolume.deformers, 1, -1 do |
103 | local deformer = fillVolume.deformers[i] |
104 | deformer.polyline = findPolyline(fillVolume.volume, deformer.posX, deformer.posZ) |
105 | if deformer.polyline == nil and deformer.polyline ~= -1 then |
106 | print("Warning: Could not find 'polyline' for '"..tostring(getName(deformer.node)).."' in '"..self.configFileName.."'") |
107 | table.remove(fillVolume.deformers, i) |
108 | end |
109 | end |
110 | |
111 | link(fillVolume.baseNode, fillVolume.volume) |
112 | end |
113 | end |
114 | |
115 | spec.loadInfos = {} |
116 | local i = 0 |
117 | while true do |
118 | local key = string.format("vehicle.fillVolume.loadInfos.loadInfo(%d)", i) |
119 | if not hasXMLProperty(self.xmlFile, key) then |
120 | break |
121 | end |
122 | local entry = {} |
123 | if self:loadFillVolumeInfo(self.xmlFile, key, entry) then |
124 | table.insert(spec.loadInfos, entry) |
125 | end |
126 | i = i + 1 |
127 | end |
128 | |
129 | spec.unloadInfos = {} |
130 | local i = 0 |
131 | while true do |
132 | local key = string.format("vehicle.fillVolume.unloadInfos.unloadInfo(%d)", i) |
133 | if not hasXMLProperty(self.xmlFile, key) then |
134 | break |
135 | end |
136 | local entry = {} |
137 | if self:loadFillVolumeInfo(self.xmlFile, key, entry) then |
138 | table.insert(spec.unloadInfos, entry) |
139 | end |
140 | i = i + 1 |
141 | end |
142 | |
143 | spec.heightNodes = {} |
144 | spec.fillVolumeIndexToHeightNode = {} |
145 | local i = 0 |
146 | while true do |
147 | local key = string.format("vehicle.fillVolume.heightNodes.heightNode(%d)", i) |
148 | if not hasXMLProperty(self.xmlFile, key) then |
149 | break |
150 | end |
151 | local entry = {} |
152 | if self:loadFillVolumeHeightNode(self.xmlFile, key, entry) then |
153 | table.insert(spec.heightNodes, entry) |
154 | |
155 | if spec.fillVolumeIndexToHeightNode[entry.fillVolumeIndex] == nil then |
156 | spec.fillVolumeIndexToHeightNode[entry.fillVolumeIndex] = {} |
157 | end |
158 | table.insert(spec.fillVolumeIndexToHeightNode[entry.fillVolumeIndex], entry) |
159 | end |
160 | i = i + 1 |
161 | end |
162 | |
163 | spec.lastPositionInfo = {0, 0} |
164 | spec.lastPositionInfoSent = {0, 0} |
165 | spec.dirtyFlag = self:getNextDirtyFlag() |
166 | end |
217 | function FillVolume:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
218 | if self.isClient then |
219 | local spec = self.spec_fillVolume |
220 | |
221 | -- deform (fill)volume |
222 | for _,volume in pairs(spec.volumes) do |
223 | for _,deformer in ipairs(volume.deformers) do |
224 | if deformer.isDirty and deformer.polyline ~= nil and deformer.polyline ~= -1 then |
225 | deformer.isDirty = false |
226 | local posX, _, posZ = localToLocal(deformer.node, deformer.baseNode, 0,0,0) |
227 | if math.abs(posX - deformer.posX) > 0.0001 or math.abs(posZ - deformer.posZ) > 0.0001 then |
228 | deformer.lastPosX = posX |
229 | deformer.lastPosZ = posZ |
230 | local dx = posX - deformer.initPos[1] |
231 | local dz = posZ - deformer.initPos[3] |
232 | setPolylineTranslation(volume.volume, deformer.polyline, dx,dz) |
233 | end |
234 | end |
235 | end |
236 | |
237 | local uvScrollSpeedX, uvScrollSpeedY, uvScrollSpeedZ = self:getFillVolumeUVScrollSpeed(volume.index) |
238 | if uvScrollSpeedX ~= 0 or uvScrollSpeedY ~= 0 or uvScrollSpeedZ ~= 0 then |
239 | volume.uvPosition[1] = volume.uvPosition[1] + uvScrollSpeedX*dt |
240 | volume.uvPosition[2] = volume.uvPosition[2] + uvScrollSpeedY*dt |
241 | volume.uvPosition[3] = volume.uvPosition[3] + uvScrollSpeedZ*dt |
242 | setShaderParameter(volume.volume, "uvOffset", volume.uvPosition[1], volume.uvPosition[2], volume.uvPosition[3], 0, false) |
243 | end |
244 | end |
245 | |
246 | -- update heightNodes |
247 | for _,heightNode in pairs(spec.heightNodes) do |
248 | if heightNode.isDirty then |
249 | heightNode.isDirty = false |
250 | |
251 | local baseNode = spec.volumes[heightNode.fillVolumeIndex].baseNode |
252 | local volumeNode = spec.volumes[heightNode.fillVolumeIndex].volume |
253 | |
254 | if baseNode ~= nil and volumeNode ~= nil then |
255 | |
256 | local minHeight = math.huge |
257 | local maxHeight = -math.huge |
258 | local maxHeightWorld = -math.huge |
259 | for _,refNode in pairs(heightNode.refNodes) do |
260 | local x,_,z = localToLocal(refNode.refNode, baseNode, 0,0,0) |
261 | local height = getFillPlaneHeightAtLocalPos(volumeNode, x,z) |
262 | minHeight = math.min(minHeight, height) |
263 | maxHeight = math.max(maxHeight, height) |
264 | local _,yw,_ = localToWorld(baseNode, x,height,z) |
265 | maxHeightWorld = math.max(maxHeightWorld, yw) |
266 | end |
267 | |
268 | heightNode.currentMinHeight = minHeight |
269 | heightNode.currentMaxHeight = maxHeight |
270 | heightNode.currentMaxHeightWorld = maxHeightWorld |
271 | |
272 | for _,node in pairs(heightNode.nodes) do |
273 | |
274 | local sx = node.scaleAxis[1]*minHeight |
275 | local sy = node.scaleAxis[2]*minHeight |
276 | local sz = node.scaleAxis[3]*minHeight |
277 | if node.scaleMax[1] > 0 then |
278 | sx = math.min(node.scaleMax[1], sx) |
279 | end |
280 | if node.scaleMax[2] > 0 then |
281 | sy = math.min(node.scaleMax[2], sy) |
282 | end |
283 | if node.scaleMax[3] > 0 then |
284 | sz = math.min(node.scaleMax[3], sz) |
285 | end |
286 | local tx = node.transAxis[1]*minHeight |
287 | local ty = node.transAxis[2]*minHeight |
288 | local tz = node.transAxis[3]*minHeight |
289 | if node.transMax[1] > 0 then |
290 | tx = math.min(node.transMax[1], tx) |
291 | end |
292 | if node.transMax[2] > 0 then |
293 | ty = math.min(node.transMax[2], ty) |
294 | end |
295 | if node.transMax[3] > 0 then |
296 | tz = math.min(node.transMax[3], tz) |
297 | end |
298 | |
299 | setScale(node.node, node.baseScale[1]+sx, node.baseScale[2]+sy, node.baseScale[3]+sz) |
300 | setTranslation(node.node, node.basePosition[1]+tx, node.basePosition[2]+ty, node.basePosition[3]+tz) |
301 | |
302 | if node.orientateToWorldY then |
303 | local _,dy,_ = localDirectionToWorld(getParent(node.node), 0,1,0) |
304 | local alpha = math.acos(dy) |
305 | setRotation(node.node, alpha,0,0) |
306 | end |
307 | end |
308 | end |
309 | end |
310 | end |
311 | end |
312 | end |