656 | function MotionPathEffectManager.createMotionPathEffectXMLSchema() |
657 | if MotionPathEffectManager.xmlSchema == nil then |
658 | local schema = XMLSchema.new("mapMotionPathEffects") |
659 | |
660 | local effectKey = "motionPathEffects.motionPathEffect(?)" |
661 | |
662 | schema:register(XMLValueType.STRING, effectKey .. "#effectClass", "Effect class name") |
663 | schema:register(XMLValueType.STRING, effectKey .. "#effectType", "Effect type name (can be multiple)") |
664 | |
665 | schema:register(XMLValueType.STRING, effectKey .. "#filename", "Path to effects i3d file") |
666 | |
667 | -- the following parameters are only for script to generate the effect meshes and not used by the game |
668 | schema:register(XMLValueType.NODE_INDEX, effectKey .. ".effectGeneration#rootNode", "(Only for automatic mesh generation) Mesh root node in maya file which has sub shapes") |
669 | schema:register(XMLValueType.VECTOR_ROT, effectKey .. ".effectGeneration#minRot", "(Only for automatic mesh generation) Min. random rotation") |
670 | schema:register(XMLValueType.VECTOR_ROT, effectKey .. ".effectGeneration#maxRot", "(Only for automatic mesh generation) Max. random rotation") |
671 | schema:register(XMLValueType.VECTOR_SCALE, effectKey .. ".effectGeneration#minScale", "(Only for automatic mesh generation) Min. random scale") |
672 | schema:register(XMLValueType.VECTOR_SCALE, effectKey .. ".effectGeneration#maxScale", "(Only for automatic mesh generation) Max. random scale") |
673 | schema:register(XMLValueType.STRING, effectKey .. ".effectGeneration#useFoliage", "(Only for automatic mesh generation) Name of foliage") |
674 | schema:register(XMLValueType.INT, effectKey .. ".effectGeneration#useFoliageStage", "(Only for automatic mesh generation) Foliage growth state") |
675 | schema:register(XMLValueType.INT, effectKey .. ".effectGeneration#useFoliageLOD", "(Only for automatic mesh generation) LOD to use") |
676 | |
677 | MotionPathEffect.registerEffectDefinitionXMLPaths(schema, effectKey .. ".typeDefinition") |
678 | TypedMotionPathEffect.registerEffectDefinitionXMLPaths(schema, effectKey .. ".typeDefinition") |
679 | CutterMotionPathEffect.registerEffectDefinitionXMLPaths(schema, effectKey .. ".typeDefinition") |
680 | CultivatorMotionPathEffect.registerEffectDefinitionXMLPaths(schema, effectKey .. ".typeDefinition") |
681 | PlowMotionPathEffect.registerEffectDefinitionXMLPaths(schema, effectKey .. ".typeDefinition") |
682 | WindrowerMotionPathEffect.registerEffectDefinitionXMLPaths(schema, effectKey .. ".typeDefinition") |
683 | |
684 | schema:register(XMLValueType.NODE_INDEX, effectKey .. ".effectMeshes.effectMesh(?)#node", "Index path in effect i3d") |
685 | schema:register(XMLValueType.NODE_INDEX, effectKey .. ".effectMeshes.effectMesh(?)#sourceNode", "(Only for automatic mesh generation) Index path to source object in maya file") |
686 | schema:register(XMLValueType.INT, effectKey .. ".effectMeshes.effectMesh(?)#rowLength", "Number of meshes on X axis (on effect texture)", 30) |
687 | schema:register(XMLValueType.INT, effectKey .. ".effectMeshes.effectMesh(?)#numRows", "Number of meshes on Y axis (on effect texture)", 12) |
688 | schema:register(XMLValueType.INT, effectKey .. ".effectMeshes.effectMesh(?)#skipPositions", "Number of skipped meshes on X axis", 0) |
689 | schema:register(XMLValueType.INT, effectKey .. ".effectMeshes.effectMesh(?)#numVariations", "Number of sub random variations", 1) |
690 | schema:register(XMLValueType.VECTOR_SCALE, effectKey .. ".effectMeshes.effectMesh(?)#boundingBox", "(Only for automatic mesh generation) Size of bounding box") |
691 | schema:register(XMLValueType.VECTOR_TRANS, effectKey .. ".effectMeshes.effectMesh(?)#boundingBoxCenter", "(Only for automatic mesh generation) Center of bounding box") |
692 | |
693 | schema:register(XMLValueType.NODE_INDEX, effectKey .. ".effectMeshes.effectMesh(?).lod(?)#sourceNode", "(Only for automatic mesh generation) Custom node for LOD") |
694 | schema:register(XMLValueType.FLOAT, effectKey .. ".effectMeshes.effectMesh(?).lod(?)#distance", "(Only for automatic mesh generation) Distance of LOD") |
695 | schema:register(XMLValueType.INT, effectKey .. ".effectMeshes.effectMesh(?).lod(?)#skipPositions", "(Only for automatic mesh generation) Custom skip positions") |
696 | |
697 | MotionPathEffectManager.registerCustomShaderSettingXMLPaths(schema, effectKey .. ".effectMeshes.effectMesh(?)") |
698 | MotionPathEffect.registerEffectMeshXMLPaths(schema, effectKey .. ".effectMeshes.effectMesh(?)") |
699 | TypedMotionPathEffect.registerEffectMeshXMLPaths(schema, effectKey .. ".effectMeshes.effectMesh(?)") |
700 | CutterMotionPathEffect.registerEffectMeshXMLPaths(schema, effectKey .. ".effectMeshes.effectMesh(?)") |
701 | CultivatorMotionPathEffect.registerEffectMeshXMLPaths(schema, effectKey .. ".effectMeshes.effectMesh(?)") |
702 | PlowMotionPathEffect.registerEffectMeshXMLPaths(schema, effectKey .. ".effectMeshes.effectMesh(?)") |
703 | WindrowerMotionPathEffect.registerEffectMeshXMLPaths(schema, effectKey .. ".effectMeshes.effectMesh(?)") |
704 | |
705 | schema:register(XMLValueType.NODE_INDEX, effectKey .. ".effectMaterials#rootNode", "(Only for automatic mesh generation) Node which will be copied over the effect i3d file (position index in i3d is then '0|1')") |
706 | schema:register(XMLValueType.NODE_INDEX, effectKey .. ".effectMaterials.effectMaterial(?)#node", "Material node") |
707 | schema:register(XMLValueType.NODE_INDEX, effectKey .. ".effectMaterials.effectMaterial(?).lod(?)#node", "LOD node") |
708 | schema:register(XMLValueType.STRING, effectKey .. ".effectMaterials.effectMaterial(?).textures#diffuse", "Path to custom diffuse map to apply") |
709 | schema:register(XMLValueType.STRING, effectKey .. ".effectMaterials.effectMaterial(?).textures#normal", "Path to custom normal map to apply") |
710 | schema:register(XMLValueType.STRING, effectKey .. ".effectMaterials.effectMaterial(?).textures#specular", "Path to custom specular map to apply") |
711 | |
712 | MotionPathEffectManager.registerCustomShaderSettingXMLPaths(schema, effectKey .. ".effectMaterials.effectMaterial(?)") |
713 | MotionPathEffect.registerEffectMaterialXMLPaths(schema, effectKey .. ".effectMaterials.effectMaterial(?)") |
714 | TypedMotionPathEffect.registerEffectMaterialXMLPaths(schema, effectKey .. ".effectMaterials.effectMaterial(?)") |
715 | CutterMotionPathEffect.registerEffectMaterialXMLPaths(schema, effectKey .. ".effectMaterials.effectMaterial(?)") |
716 | CultivatorMotionPathEffect.registerEffectMaterialXMLPaths(schema, effectKey .. ".effectMaterials.effectMaterial(?)") |
717 | PlowMotionPathEffect.registerEffectMaterialXMLPaths(schema, effectKey .. ".effectMaterials.effectMaterial(?)") |
718 | WindrowerMotionPathEffect.registerEffectMaterialXMLPaths(schema, effectKey .. ".effectMaterials.effectMaterial(?)") |
719 | |
720 | MotionPathEffectManager.registerCustomShaderSettingXMLPaths(schema, effectKey .. ".customShaderDefaults") |
721 | |
722 | MotionPathEffectManager.xmlSchema = schema |
723 | end |
724 | end |
300 | function MotionPathEffectManager:loadCustomShaderSettingsFromXML(target, xmlFile, key) |
301 | target.customShaderVariation = xmlFile:getValue(key .. ".customShaderVariation#name") |
302 | |
303 | target.customShaderMaps = {} |
304 | xmlFile:iterate(key .. ".customShaderMap", function(index, parameterKey) |
305 | local customShaderMap = {} |
306 | customShaderMap.name = xmlFile:getValue(parameterKey .. "#name") |
307 | customShaderMap.filename = xmlFile:getValue(parameterKey .. "#filename") |
308 | customShaderMap.filename = Utils.getFilename(customShaderMap.filename, self.baseDirectory) |
309 | if customShaderMap.name ~= nil and customShaderMap.filename ~= nil then |
310 | customShaderMap.texture = createMaterialTextureFromFile(customShaderMap.filename, true, false) |
311 | if customShaderMap.texture ~= nil then |
312 | table.insert(target.customShaderMaps, customShaderMap) |
313 | end |
314 | else |
315 | Logging.xmlError(xmlFile, "Failed to load custom shader map from '%s'", parameterKey) |
316 | end |
317 | end) |
318 | |
319 | target.customShaderParameters = {} |
320 | xmlFile:iterate(key .. ".customShaderParameter", function(index, parameterKey) |
321 | local customShaderParameter = {} |
322 | customShaderParameter.name = xmlFile:getValue(parameterKey .. "#name") |
323 | customShaderParameter.value = xmlFile:getValue(parameterKey .. "#value", "0 0 0 0", true) |
324 | if customShaderParameter.name ~= nil and customShaderParameter.value ~= nil then |
325 | table.insert(target.customShaderParameters, customShaderParameter) |
326 | else |
327 | Logging.xmlError(xmlFile, "Failed to load custom shader parameter from '%s'", parameterKey) |
328 | end |
329 | end) |
330 | end |
97 | function MotionPathEffectManager:loadMotionPathEffectsXML(filename, baseDirectory, customEnvironment) |
98 | local xmlFilename = Utils.getFilename(filename, baseDirectory) |
99 | local xmlFile = XMLFile.load("mapMotionPathEffects", xmlFilename, MotionPathEffectManager.xmlSchema) |
100 | if xmlFile ~= nil then |
101 | self.xmlFiles[xmlFile] = true |
102 | |
103 | xmlFile.xmlReferences = 0 |
104 | |
105 | local i = 0 |
106 | while true do |
107 | local motionPathEffectKey = string.format("motionPathEffects.motionPathEffect(%d)", i) |
108 | if not xmlFile:hasProperty(motionPathEffectKey) then |
109 | break |
110 | end |
111 | |
112 | local motionPathEffect = {} |
113 | |
114 | local effectClassName = xmlFile:getValue(motionPathEffectKey .. "#effectClass", "MotionPathEffect") |
115 | if effectClassName ~= nil then |
116 | local effectClass = g_effectManager:getEffectClass(effectClassName) |
117 | if effectClass == nil then |
118 | if customEnvironment ~= nil and customEnvironment ~= "" then |
119 | effectClass = g_effectManager:getEffectClass(customEnvironment.."."..effectClassName) |
120 | end |
121 | if effectClass == nil then |
122 | -- Fallback to the old method if no registered class is found |
123 | effectClass = ClassUtil.getClassObject(effectClassName) |
124 | end |
125 | end |
126 | if effectClass ~= nil then |
127 | effectClass.loadEffectDefinitionFromXML(motionPathEffect, xmlFile, motionPathEffectKey .. ".typeDefinition") |
128 | |
129 | motionPathEffect.effectClass = effectClass |
130 | motionPathEffect.effectClassName = effectClassName |
131 | |
132 | motionPathEffect.effectTypes = {} |
133 | motionPathEffect.effectTypeStr = xmlFile:getValue(motionPathEffectKey .. "#effectType", "DEFAULT") |
134 | local effectTypes = motionPathEffect.effectTypeStr:split(" ") |
135 | for j=1, #effectTypes do |
136 | table.insert(motionPathEffect.effectTypes, effectTypes[j]:upper()) |
137 | end |
138 | |
139 | motionPathEffect.filename = xmlFile:getValue(motionPathEffectKey .. "#filename") |
140 | |
141 | if motionPathEffect.filename ~= nil then |
142 | xmlFile.xmlReferences = xmlFile.xmlReferences + 1 |
143 | motionPathEffect.filename = Utils.getFilename(motionPathEffect.filename, baseDirectory) |
144 | |
145 | local arguments = { |
146 | motionPathEffect = motionPathEffect, |
147 | xmlFile = xmlFile, |
148 | motionPathEffectKey = motionPathEffectKey, |
149 | baseDirectory = baseDirectory |
150 | } |
151 | local sharedLoadRequestId = g_i3DManager:loadSharedI3DFileAsync(motionPathEffect.filename, false, false, self.motionPathEffectI3DFileLoaded, self, arguments) |
152 | table.insert(self.sharedLoadRequestIds, sharedLoadRequestId) |
153 | else |
154 | Logging.xmlError(xmlFile, "Missing filename for motion path effect '%s'", motionPathEffectKey) |
155 | end |
156 | |
157 | else |
158 | Logging.xmlError(xmlFile, "Unknown motion path effect class '%s' in '%s'", effectClassName, motionPathEffectKey) |
159 | end |
160 | end |
161 | |
162 | i = i + 1 |
163 | end |
164 | |
165 | if xmlFile.xmlReferences == 0 then |
166 | self.xmlFiles[xmlFile] = nil |
167 | xmlFile:delete() |
168 | end |
169 | end |
170 | end |
174 | function MotionPathEffectManager:motionPathEffectI3DFileLoaded(i3dNode, failedReason, args) |
175 | local motionPathEffect = args.motionPathEffect |
176 | local xmlFile = args.xmlFile |
177 | local motionPathEffectKey = args.motionPathEffectKey |
178 | local baseDirectory = args.baseDirector |
179 | |
180 | if i3dNode ~= nil and i3dNode ~= 0 then |
181 | local loadedMeshes = {} |
182 | |
183 | motionPathEffect.effectMeshes = {} |
184 | xmlFile:iterate(motionPathEffectKey .. ".effectMeshes.effectMesh", function(index, key) |
185 | local node = xmlFile:getValue(key .. "#node", nil, i3dNode) |
186 | if node ~= nil and loadedMeshes[node] == nil then |
187 | local effectMesh = {} |
188 | effectMesh.node = node |
189 | effectMesh.rowLength = xmlFile:getValue(key .. "#rowLength", 30) |
190 | effectMesh.numRows = xmlFile:getValue(key .. "#numRows", 12) |
191 | effectMesh.skipPositions = xmlFile:getValue(key .. "#skipPositions", 0) |
192 | effectMesh.numVariations = xmlFile:getValue(key .. "#numVariations", 1) |
193 | if effectMesh.numVariations > 1 then |
194 | effectMesh.usedVariations = {} |
195 | for i=1, effectMesh.numVariations do |
196 | effectMesh.usedVariations[i] = false |
197 | end |
198 | end |
199 | |
200 | effectMesh.parent = motionPathEffect |
201 | |
202 | self:loadCustomShaderSettingsFromXML(effectMesh, xmlFile, key) |
203 | |
204 | motionPathEffect.effectClass.loadEffectMeshFromXML(effectMesh, xmlFile, key) |
205 | |
206 | effectMesh.growthStates = motionPathEffect.growthStates |
207 | table.insert(motionPathEffect.effectMeshes, effectMesh) |
208 | loadedMeshes[node] = true |
209 | else |
210 | if node == nil then |
211 | Logging.xmlError(xmlFile, "Failed to load effect mesh node from xml (%s)", key) |
212 | else |
213 | Logging.xmlError(xmlFile, "Failed to load effect mesh node from xml. Node already used. (%s)", key) |
214 | end |
215 | end |
216 | end) |
217 | |
218 | motionPathEffect.effectMaterials = {} |
219 | xmlFile:iterate(motionPathEffectKey .. ".effectMaterials.effectMaterial", function(index, key) |
220 | local node = xmlFile:getValue(key .. "#node", nil, i3dNode) |
221 | if node ~= nil then |
222 | local effectMaterial = {} |
223 | effectMaterial.node = node |
224 | effectMaterial.materialId = getMaterial(node, 0) |
225 | effectMaterial.parent = motionPathEffect |
226 | |
227 | effectMaterial.lod = {} |
228 | xmlFile:iterate(key .. ".lod", function(_, lodKey) |
229 | local lodNode = xmlFile:getValue(lodKey .. "#node", nil, i3dNode) |
230 | if lodNode ~= nil then |
231 | table.insert(effectMaterial.lod, getMaterial(lodNode, 0)) |
232 | end |
233 | end) |
234 | |
235 | effectMaterial.customDiffuse = xmlFile:getValue(key .. ".textures#diffuse") |
236 | if effectMaterial.customDiffuse ~= nil then |
237 | effectMaterial.customDiffuse = Utils.getFilename(effectMaterial.customDiffuse, baseDirectory) |
238 | effectMaterial.materialId = setMaterialDiffuseMapFromFile(effectMaterial.materialId, effectMaterial.customDiffuse, true, true, false) |
239 | end |
240 | |
241 | effectMaterial.customNormal = xmlFile:getValue(key .. ".textures#normal") |
242 | if effectMaterial.customNormal ~= nil then |
243 | effectMaterial.customNormal = Utils.getFilename(effectMaterial.customNormal, baseDirectory) |
244 | effectMaterial.materialId = setMaterialNormalMapFromFile(effectMaterial.materialId, effectMaterial.customDiffuse, true, false, false) |
245 | end |
246 | |
247 | effectMaterial.customSpecular = xmlFile:getValue(key .. ".textures#specular") |
248 | if effectMaterial.customSpecular ~= nil then |
249 | effectMaterial.customSpecular = Utils.getFilename(effectMaterial.customSpecular, baseDirectory) |
250 | effectMaterial.materialId = setMaterialGlossMapFromFile(effectMaterial.materialId, effectMaterial.customSpecular, true, true, false) |
251 | end |
252 | |
253 | setMaterial(node, effectMaterial.materialId, 0) |
254 | |
255 | self:loadCustomShaderSettingsFromXML(effectMaterial, xmlFile, key) |
256 | |
257 | motionPathEffect.effectClass.loadEffectMaterialFromXML(effectMaterial, xmlFile, key) |
258 | |
259 | table.insert(motionPathEffect.effectMaterials, effectMaterial) |
260 | else |
261 | Logging.xmlError(xmlFile, "Failed to load effect material from xml (%s)", key) |
262 | end |
263 | end) |
264 | |
265 | self:loadCustomShaderSettingsFromXML(motionPathEffect, xmlFile, motionPathEffectKey .. ".customShaderDefaults") |
266 | |
267 | for j=1, #motionPathEffect.effectMeshes do |
268 | unlink(motionPathEffect.effectMeshes[j].node) |
269 | end |
270 | |
271 | for j=1, #motionPathEffect.effectMaterials do |
272 | unlink(motionPathEffect.effectMaterials[j].node) |
273 | end |
274 | |
275 | for i=1, #motionPathEffect.effectTypes do |
276 | local effectType = motionPathEffect.effectTypes[i] |
277 | if self.effectsByType[effectType] == nil then |
278 | self.effectsByType[effectType] = {} |
279 | end |
280 | table.insert(self.effectsByType[effectType], motionPathEffect) |
281 | end |
282 | |
283 | table.insert(self.effects, motionPathEffect) |
284 | |
285 | delete(i3dNode) |
286 | end |
287 | |
288 | xmlFile.xmlReferences = xmlFile.xmlReferences - 1 |
289 | if xmlFile.xmlReferences == 0 then |
290 | self.xmlFiles[xmlFile] = nil |
291 | xmlFile:delete() |
292 | end |
293 | end |
581 | function MotionPathEffectManager:setEffectCustomMapOnNode(node, name, textureEntityId) |
582 | local material = getMaterial(node, 0) |
583 | if textureEntityId ~= nil then |
584 | local newMaterial = setMaterialCustomMap(material, name, textureEntityId, false) |
585 | if newMaterial ~= material then |
586 | for i=1, #MotionPathEffectManager.MOTION_PATH_SHADER_PARAMS do |
587 | local x, y, z, w = getShaderParameter(node, MotionPathEffectManager.MOTION_PATH_SHADER_PARAMS[i]) |
588 | self.shaderParamCopyBuffer[i][1] = x |
589 | self.shaderParamCopyBuffer[i][2] = y |
590 | self.shaderParamCopyBuffer[i][3] = z |
591 | self.shaderParamCopyBuffer[i][4] = w |
592 | end |
593 | |
594 | |
595 | |
596 | setMaterial(node, newMaterial, 0) |
597 | |
598 | for i=1, #MotionPathEffectManager.MOTION_PATH_SHADER_PARAMS do |
599 | local x, y, z, w = self.shaderParamCopyBuffer[i][1], self.shaderParamCopyBuffer[i][2], self.shaderParamCopyBuffer[i][3], self.shaderParamCopyBuffer[i][4] |
600 | setShaderParameter(node, MotionPathEffectManager.MOTION_PATH_SHADER_PARAMS[i], x, y, z, w) |
601 | end |
602 | end |
603 | end |
604 | end |
504 | function MotionPathEffectManager:setEffectShaderParameter(node, name, x, y, z, w, shared) |
505 | if getHasClassId(node, ClassIds.SHAPE) then |
506 | local _x, _y, _z, _w = getShaderParameter(node, name) |
507 | setShaderParameter(node, name, x or _x, y or _y, z or _z, w or _w, shared) |
508 | end |
509 | |
510 | local numChildren = getNumOfChildren(node) |
511 | if numChildren > 0 then |
512 | for i=1, numChildren do |
513 | local child = getChildAt(node, i-1) |
514 | if getHasClassId(child, ClassIds.SHAPE) then |
515 | local _x, _y, _z, _w = getShaderParameter(child, name) |
516 | setShaderParameter(child, name, x or _x, y or _y, z or _z, w or _w, shared) |
517 | end |
518 | end |
519 | end |
520 | end |