23 | function PipeEffect:loadEffectAttributes(xmlFile, key, node, i3dNode, i3dMapping) |
24 | if not PipeEffect:superClass().loadEffectAttributes(self, xmlFile, key, node, i3dNode, i3dMapping) then |
25 | return false |
26 | end |
27 | |
28 | self.maxBending = Utils.getNoNil(Effect.getValue(xmlFile, key, getXMLFloat, node, "maxBending"), 0.25) |
29 | self.shapeScaleSpread = {StringUtil.getVectorFromString(Utils.getNoNil(Effect.getValue(xmlFile, key, getXMLString, node, "shapeScaleSpread"), "0.6 1 1 0"))} |
30 | |
31 | local uvScaleSpeedFreqAmp = Effect.getValue(xmlFile, key, getXMLString, node, "uvScaleSpeedFreqAmp") |
32 | if uvScaleSpeedFreqAmp ~= nil then |
33 | self.uvScaleSpeedFreqAmp = {StringUtil.getVectorFromString(uvScaleSpeedFreqAmp)} |
34 | end |
35 | |
36 | local positionUpdateNodesStr = Effect.getValue(xmlFile, key, getXMLString, node, "positionUpdateNodes") |
37 | if positionUpdateNodesStr ~= nil then |
38 | local nodeStrs = StringUtil.splitString(" ", StringUtil.trim(positionUpdateNodesStr)) |
39 | self.positionUpdateNodes = {} |
40 | for _, nodeStr in pairs(nodeStrs) do |
41 | local updateNode = I3DUtil.indexToObject(Utils.getNoNil(node, self.rootNodes), nodeStr, i3dMapping) |
42 | if updateNode ~= nil then |
43 | table.insert(self.positionUpdateNodes, updateNode) |
44 | end |
45 | end |
46 | end |
47 | |
48 | self.updateDistance = Utils.getNoNil(Effect.getValue(xmlFile, key, getXMLBool, node, "updateDistance"), true) |
49 | self.extraDistance = Utils.getNoNil(Effect.getValue(xmlFile, key, getXMLFloat, node, "extraDistance"), 0) |
50 | |
51 | self.worldTarget = {0,0,0} |
52 | self.controlPoint = {StringUtil.getVectorFromString(Utils.getNoNil(Effect.getValue(xmlFile, key, getXMLString, node, "controlPoint"), "10 0.25 0 0"))} |
53 | self.controlPointY = 0 |
54 | self.distance = 0 |
55 | |
56 | return true |
57 | end |
88 | function PipeEffect:setDistance(distance, terrain) |
89 | setVisibility(self.node, distance > 0) |
90 | if self.updateDistance and getHasShaderParameter(self.node, "controlPoint") then |
91 | distance = distance + self.extraDistance |
92 | local _, dirY, _ = localDirectionToWorld(self.node, 0, 1, 0) |
93 | self.controlPointY = dirY*self.maxBending |
94 | self.distance = distance |
95 | |
96 | -- check the distance to the calculated point and correct the distance that is sent to the shader |
97 | local mCos = math.cos(self.controlPointY) |
98 | local mSin = math.sin(self.controlPointY) |
99 | local y = MathUtil.dotProduct(0, 0, distance, 0.0, mCos, -mSin) |
100 | local z = MathUtil.dotProduct(0, 0, distance, 0.0, mSin, mCos) |
101 | local realDistance = MathUtil.vector2Length(y, z) |
102 | distance = distance + (distance - realDistance) |
103 | |
104 | setShaderParameter(self.node, "controlPoint", distance-PipeEffect.SAFETY_OFFSET, self.controlPointY, 0, 0, false) |
105 | end |
106 | end |
110 | function PipeEffect:setFillType(fillType) |
111 | local success = PipeEffect:superClass().setFillType(self, fillType) |
112 | if success then |
113 | if getHasShaderParameter(self.node, "shapeScaleSpread") then |
114 | setShaderParameter(self.node, "shapeScaleSpread", self.shapeScaleSpread[1], self.shapeScaleSpread[2], self.shapeScaleSpread[3], self.shapeScaleSpread[4], false) |
115 | end |
116 | if self.uvScaleSpeedFreqAmp ~= nil and getHasShaderParameter(self.node, "uvScaleSpeedFreqAmp") then |
117 | setShaderParameter(self.node, "uvScaleSpeedFreqAmp", self.uvScaleSpeedFreqAmp[1], self.uvScaleSpeedFreqAmp[2], self.uvScaleSpeedFreqAmp[3], self.uvScaleSpeedFreqAmp[4], false) |
118 | end |
119 | if getHasShaderParameter(self.node, "controlPoint") then |
120 | setShaderParameter(self.node, "controlPoint", self.controlPoint[1], self.controlPoint[2], 0, 0, false) |
121 | end |
122 | end |
123 | |
124 | return success |
125 | end |
61 | function PipeEffect:update(dt) |
62 | PipeEffect:superClass().update(self, dt) |
63 | |
64 | if self.distance > 0 then |
65 | -- calculate world targets in update loop, otherwise update nodes wont be updated in multiplayer |
66 | local mCos = math.cos(self.controlPointY) |
67 | local mSin = math.sin(self.controlPointY) |
68 | local y = MathUtil.dotProduct(0, 0, self.distance, 0.0, mCos, -mSin) |
69 | local z = MathUtil.dotProduct(0, 0, self.distance, 0.0, mSin, mCos) |
70 | |
71 | -- recalculate the discharge point with the new distance |
72 | y = MathUtil.dotProduct(0, 0, self.distance, 0.0, mCos, -mSin) |
73 | z = MathUtil.dotProduct(0, 0, self.distance, 0.0, mSin, mCos) |
74 | |
75 | local wx, wy, wz = localToWorld(self.node, 0, y, z) |
76 | self.worldTarget[1], self.worldTarget[2], self.worldTarget[3] = wx, wy, wz |
77 | end |
78 | |
79 | if self.positionUpdateNodes ~= nil then |
80 | for _, node in pairs(self.positionUpdateNodes) do |
81 | setWorldTranslation(node, self.worldTarget[1], self.worldTarget[2], self.worldTarget[3]) |
82 | end |
83 | end |
84 | end |