How to use getobjectproperty method in pyatom

Best Python code snippet using pyatom_python

stk_track.py

Source:stk_track.py Github

copy

Full Screen

1#!BPY2# Copyright (c) 2020 SuperTuxKart author(s)3#4# Permission is hereby granted, free of charge, to any person obtaining a copy5# of this software and associated documentation files (the "Software"), to deal6# in the Software without restriction, including without limitation the rights7# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell8# copies of the Software, and to permit persons to whom the Software is9# furnished to do so, subject to the following conditions:10#11# The above copyright notice and this permission notice shall be included in all12# copies or substantial portions of the Software.13#14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE17# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20# SOFTWARE.21import bpy, datetime, sys, os, struct, math, string, re, random, shutil, traceback22from mathutils import *23from . import stk_utils, stk_panel, stk_track_utils24def writeIPO(self, f, anim_data):25 #dInterp = {IpoCurve.InterpTypes.BEZIER: "bezier",26 # IpoCurve.InterpTypes.LINEAR: "linear",27 # IpoCurve.InterpTypes.CONST: "const" }28 #dExtend = {IpoCurve.ExtendTypes.CONST: "const",29 # IpoCurve.ExtendTypes.EXTRAP: "extrap",30 # IpoCurve.ExtendTypes.CYCLIC_EXTRAP: "cyclic_extrap",31 # IpoCurve.ExtendTypes.CYCLIC: "cyclic" }32 if anim_data and anim_data.action:33 ipo = anim_data.action.fcurves34 else:35 return36 # ==== Possible values returned by blender ====37 # fcurves[0].data_path38 # location, rotation_euler, scale39 # fcurves[0].extrapolation40 # CONSTANT, LINEART41 # fcurves[0].keyframe_points[0].interpolation42 # CONSTANT, LINEAR, BEZIER43 # Swap Y and Z axis44 axes = ['X', 'Z', 'Y']45 for curve in ipo:46 if curve.data_path == 'location':47 name = "Loc" + axes[curve.array_index]48 elif curve.data_path == 'rotation_euler':49 name = "Rot" + axes[curve.array_index]50 elif curve.data_path == 'scale':51 name = "Scale" + axes[curve.array_index]52 else:53 if "pose.bones" not in curve.data_path: # we ignore bone curves54 self.log.report({'WARNING'}, "Unknown curve type " + curve.data_path)55 continue56 extrapolation = "const"57 for modifier in curve.modifiers:58 if modifier.type == 'CYCLES':59 extrapolation = "cyclic"60 break61 # If any point is bezier we'll export as Bezier62 interpolation = "linear"63 for bez in curve.keyframe_points:64 if bez.interpolation=='BEZIER':65 interpolation = "bezier"66 break67 # Rotations are stored in randians68 if name[:3]=="Rot":69 factor=-57.29577951 # 180/PI70 else:71 factor=172 f.write(" <curve channel=\"%s\" interpolation=\"%s\" extend=\"%s\">\n"% \73 (name, interpolation, extrapolation))74 #(name, dInterp[curve.interpolation], dExtend[curve.extend]))75 warning_shown = False76 for bez in curve.keyframe_points:77 if interpolation=="bezier":78 if bez.interpolation=='BEZIER':79 f.write(" <p c=\"%.3f %.3f\" h1=\"%.3f %.3f\" h2=\"%.3f %.3f\"/>\n"%\80 (bez.co[0],factor*bez.co[1],81 bez.handle_left[0], factor*bez.handle_left[1],82 bez.handle_right[0], factor*bez.handle_right[1]))83 else:84 # point with linear IPO in bezier curve85 f.write(" <p c=\"%.3f %.3f\" h1=\"%.3f %.3f\" h2=\"%.3f %.3f\"/>\n"%\86 (bez.co[0], factor*bez.co[1],87 bez.co[0] - 1, factor*bez.co[1],88 bez.co[0] + 1, factor*bez.co[1]))89 if not warning_shown:90 try:91 self.log.report({'WARNING'}, "You have an animation curve which contains a mix of mixture of Bezier and " +92 "linear interpolation, please convert everything to Bezier for best results")93 except:94 pass95 warning_shown = True96 else:97 f.write(" <p c=\"%.3f %.3f\"/>\n"%(bez.co[0],98 factor*bez.co[1]))99 f.write(" </curve>\n")100# ------------------------------------------------------------------------------101# Checks if there are any animated textures in any of the objects in the102# list l.103def checkForAnimatedTextures(self, lObjects):104 lAnimTextures = []105 for obj in lObjects:106 use_anim_texture = stk_utils.getObjectProperty(obj, "enable_anim_texture", "false")107 if use_anim_texture != 'true': continue108 anim_texture = stk_utils.getObjectProperty(obj, "anim_texture", None)109 if anim_texture is None or len(anim_texture) == 0:110 try:111 self.log.report({'WARNING'}, "object %s has an invalid animated-texture configuration" % obj.name)112 except:113 pass114 continue115 #if anim_texture == 'stk_animated_mudpot_a.png':116 print('Animated texture {} in {}.'.format(anim_texture, obj.name))117 dx = stk_utils.getObjectProperty(obj, "anim_dx", 0)118 dy = stk_utils.getObjectProperty(obj, "anim_dy", 0)119 dt = stk_utils.getObjectProperty(obj, "anim_dt", 0)120 use_anim_texture_by_step = stk_utils.getObjectProperty(obj, "enable_anim_by_step", "false")121 lAnimTextures.append( (anim_texture, dx, dy, dt, use_anim_texture_by_step) )122 return lAnimTextures123# ------------------------------------------------------------------------------124def writeAnimatedTextures(f, lAnimTextures):125 for (name, dx, dy, dt, use_anime_texture_by_step) in lAnimTextures:126 sdt=""127 if use_anime_texture_by_step == "true":128 sdt = ' animByStep="true" dt="%.3f" '%float(dt)129 dy = 1.0/dy130 sdx=""131 if dx: sdx = " dx=\"%.5f\" "%float(dx)132 sdy=""133 if dy: sdy = " dy=\"%.5f\" "%float(dy)134 if name is None or len(name) == 0:135 continue136 f.write(" <animated-texture name=\"%s\"%s%s%s/>\n"%(name, sdx, sdy, sdt) )137# ==============================================================================138# The actual exporter. It is using a class mainly to store some information139# between calls to different functions, e.g. a cache of exported objects.140class TrackExport:141 # Exports the models as spm object in local coordinate, i.e. with the object142 # center at (0,0,0).143 def exportLocalSPM(self, obj, sPath, name, applymodifiers=True):144 # If the name contains a ".spm" the model is assumed to be part of145 # the standard objects included in STK, so there is no need to146 # export the model.147 if re.search("\.spm$", name): return name148 name = name + ".spm"149 # If the object was already exported, we don't have to do it again.150 if name in self.dExportedObjects: return name151 obj.select_set(True)152 try:153 bpy.ops.screen.spm_export(localsp=True, filepath=sPath+"/"+name, selection_type="selected", \154 export_tangent=stk_utils.getSceneProperty(bpy.context.scene, 'precalculate_tangents', 'false') == 'true',155 applymodifiers=applymodifiers)156 except:157 self.log.report({'ERROR'}, "Failed to export " + name)158 obj.select_set(False)159 self.dExportedObjects[name]=1160 return name161 # ----------------------------------------------------------------------162 def writeTrackFile(self, sPath, nsBase):163 print("Writing track file --> \t")164 #start_time = bsys.time()165 scene = bpy.context.scene166 name = stk_utils.getSceneProperty(scene, "name", "Name of Track")167 groups = stk_utils.getSceneProperty(scene, "groups", "standard" )168 if 'is_wip_track' in scene and scene['is_wip_track'] == 'true':169 groups = 'wip-track'170 is_arena = stk_utils.getSceneProperty(scene, "arena", "n" )171 if not is_arena:172 is_arena="n"173 is_arena = not (is_arena[0]=="n" or is_arena[0]=="N" or \174 is_arena[0]=="f" or is_arena[0]=="F" )175 is_soccer = stk_utils.getSceneProperty(scene, "soccer", "n" )176 if not is_soccer:177 is_soccer="n"178 is_soccer = not (is_soccer[0]=="n" or is_soccer[0]=="N" or \179 is_soccer[0]=="f" or is_soccer[0]=="F" )180 is_ctf = stk_utils.getSceneProperty(scene, "ctf", "n" )181 if not is_ctf:182 is_ctf="n"183 is_ctf = not (is_ctf[0]=="n" or is_ctf[0]=="N" or \184 is_ctf[0]=="f" or is_ctf[0]=="F" )185 is_cutscene = stk_utils.getSceneProperty(scene, "cutscene", "false") == "true"186 is_internal = stk_utils.getSceneProperty(scene, "internal", "n" )187 is_internal = (is_internal == "true")188 if is_cutscene:189 is_internal = True190 push_back = stk_utils.getSceneProperty(scene, "pushback", "true" )191 push_back = (push_back != "false")192 auto_rescue = stk_utils.getSceneProperty(scene, "autorescue", "true" )193 auto_rescue = (auto_rescue != "false")194 designer = stk_utils.getSceneProperty(scene, "designer", "" )195 # Support for multi-line descriptions:196 designer = designer.replace("\\n", "\n")197 if not designer:198 designer = stk_utils.getSceneProperty(scene, "description", "")199 if designer:200 self.log.report({'WARNING'}, "The 'Description' field is deprecated, please use 'Designer'")201 else:202 designer="?"203 music = stk_utils.getSceneProperty(scene, "music", "")204 screenshot = stk_utils.getSceneProperty(scene, "screenshot", "")205 smooth_normals = stk_utils.getSceneProperty(scene, "smooth_normals", "false")206 #has_bloom = (stk_utils.getSceneProperty(scene, "bloom", "false") == "true")207 bloom_threshold = stk_utils.getSceneProperty(scene, "bloom_threshold", "0.75")208 #has_lens_flare = (stk_utils.getSceneProperty(scene, "sunlensflare", "false") == "true")209 has_shadows = (stk_utils.getSceneProperty(scene, "shadows", "false") == "true")210 day_time = stk_utils.getSceneProperty(scene, "duringday", "day")211 #has_colorlevel = (stk_utils.getSceneProperty(scene, "colorlevel", "false") == "true")212 #colorlevel_inblack = stk_utils.getSceneProperty(scene, "colorlevel_inblack", "0.0")213 #colorlevel_ingamma = stk_utils.getSceneProperty(scene, "colorlevel_ingamma", "1.0")214 #colorlevel_inwhite = stk_utils.getSceneProperty(scene, "colorlevel_inwhite", "255.0")215 colorlevel_outblack = stk_utils.getSceneProperty(scene, "colorlevel_outblack", "0.0")216 colorlevel_outwhite = stk_utils.getSceneProperty(scene, "colorlevel_outwhite", "255.0")217 default_num_laps = int(stk_utils.getSceneProperty(scene, "default_num_laps",3))218 with open(sPath + "/track.xml", "w", encoding="utf8", newline="\n") as f:219 f.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")220 f.write("<track name = \"%s\"\n"%name)221 f.write(" version = \"7\"\n")222 f.write(" groups = \"%s\"\n"%groups)223 f.write(" designer = \"%s\"\n"%designer)224 if music:225 f.write(" music = \"%s\"\n"%music)226 else:227 self.log.report({'WARNING'}, "No music file defined. Default music will be used.")228 if is_arena:229 f.write(" arena = \"Y\"\n")230 max_arena_players = 0231 for obj in bpy.data.objects:232 stktype = stk_utils.getObjectProperty(obj, "type", "").strip().upper()233 if obj.type=="EMPTY" and stktype[:5]=="START":234 if is_ctf and stk_utils.getObjectProperty(obj, "ctf_only", "false").lower() == "true":235 continue236 max_arena_players += 1237 f.write(" max-arena-players = \"%d\"\n" % max_arena_players)238 if is_soccer:239 f.write(" soccer = \"Y\"\n")240 if is_ctf:241 f.write(" ctf = \"Y\"\n")242 if is_cutscene:243 f.write(" cutscene = \"Y\"\n")244 if is_internal:245 f.write(" internal = \"Y\"\n")246 if not push_back:247 f.write(" push-back = \"N\"\n")248 if not auto_rescue:249 f.write(" auto-rescue = \"N\"\n")250 if screenshot:251 f.write(" screenshot = \"%s\"\n"%screenshot)252 else:253 self.log.report({'WARNING'}, "No screenshot defined")254 f.write(" smooth-normals = \"%s\"\n" % smooth_normals)255 f.write(" default-number-of-laps = \"%d\"\n" % default_num_laps)256 reverse = stk_utils.getSceneProperty(scene, "reverse", "false")257 if reverse == "true":258 f.write(" reverse = \"Y\"\n")259 else:260 f.write(" reverse = \"N\"\n")261 #if has_bloom:262 # f.write(" bloom = \"Y\"\n")263 # f.write(" bloom-threshold = \"%s\"\n" % bloom_threshold)264 #else:265 # f.write(" bloom = \"N\"\n")266 #if has_colorlevel:267 # f.write(" color-level-in = \"" + str(colorlevel_inblack) + " " + str(colorlevel_ingamma) + " " + str(colorlevel_inwhite) + "\"\n")268 # f.write(" color-level-out = \"" + str(colorlevel_outblack) + " " + str(colorlevel_outwhite) + "\"\n")269 #if has_lens_flare:270 # f.write(" lens-flare = \"Y\"\n")271 #else:272 # f.write(" lens-flare = \"N\"\n")273 if day_time == "day":274 f.write(" is-during-day = \"Y\"\n")275 else:276 f.write(" is-during-day = \"N\"\n")277 if has_shadows:278 f.write(" shadows = \"Y\"\n")279 else:280 f.write(" shadows = \"N\"\n")281 f.write(">\n")282 f.write("</track>\n")283 #print bsys.time() - start_time, "seconds"284 # --------------------------------------------------------------------------285 # Writes the animation for objects using IPOs:286 def writeAnimationWithIPO(self, f, name, obj, ipo, objectType="animation"):287 # An animated object can set the 'name' property, then this name will288 # be used to name the exported object (instead of the python name289 # which might be a default name with a number). Additionally, names290 # are cached so it can be avoided to export two or more identical291 # objects.292 parent = obj.parent293 flags = []294 # For now: armature animations are assumed to be looped295 if parent and parent.type=="ARMATURE":296 first_frame = bpy.context.scene.frame_start297 last_frame = bpy.context.scene.frame_end298 frame_start = []299 frame_end = []300 for i in range(first_frame, last_frame + 1):301 for curr in bpy.context.scene.timeline_markers:302 if curr.frame == i:303 marker_name = curr.name.lower()304 if marker_name == "start":305 frame_start.append(i - 1)306 if marker_name == "end":307 frame_end.append(i - 1)308 if len(frame_start) > 0 and len(frame_end) > 0:309 flags.append('frame-start="%s"' % ' '.join(str(x) for x in frame_start))310 flags.append('frame-end="%s"' % ' '.join(str(x) for x in frame_end))311 is_cyclic = False312 if parent.animation_data is not None and parent.animation_data.action is not None and \313 parent.animation_data.action.fcurves is not None:314 for curve in parent.animation_data.action.fcurves:315 for modifier in curve.modifiers:316 if modifier.type == 'CYCLES':317 is_cyclic = True318 break319 if is_cyclic:320 break321 if is_cyclic:322 flags.append('looped="y"')323 interaction = stk_utils.getObjectProperty(obj, "interaction", 'static')324 flags.append('interaction="%s"' % interaction)325 # phyiscs only object can only have exact shape326 if interaction == "physicsonly":327 flags.append('shape="exact"')328 else:329 shape = stk_utils.getObjectProperty(obj, "shape", "")330 if shape and interaction != 'ghost':331 flags.append('shape="%s"'%shape)332 if not ipo: ipo=[]333 lodstring = self.getModelDefinitionString(obj)334 if len(lodstring) > 0:335 flags.append(lodstring)336 type = stk_utils.getObjectProperty(obj, "type", "")337 if type != "lod_instance":338 flags.append('model="%s"' % name)339 if interaction == 'reset':340 flags.append('reset="y"')341 elif interaction == 'explode':342 flags.append('explode="y"')343 elif interaction == 'flatten':344 flags.append('flatten="y"')345 if stk_utils.getObjectProperty(obj, "driveable", "false") == "true":346 flags.append('driveable="true"')347 if stk_utils.getObjectProperty(obj, "forcedbloom", "false") == "true":348 flags.append('forcedbloom="true"')349 if stk_utils.getObjectProperty(obj, "shadowpass", "true") == "false":350 flags.append('shadow-pass="false"')351 if len(stk_utils.getObjectProperty(obj, "outline", "")) > 0:352 flags.append('glow="%s"'%stk_utils.getObjectProperty(obj, "outline", ""))353 if stk_utils.getObjectProperty(obj, "displacing", "false") == "true":354 flags.append('displacing="true"')355 #if stk_utils.getObjectProperty(obj, "skyboxobject", "false") == "true":356 # flags.append('renderpass="skybox"')357 if stk_utils.getObjectProperty(obj, "soccer_ball", "false") == "true":358 flags.append('soccer_ball="true"')359 uses_skeletal_animation = False360 # check if this object has an armature modifier361 for curr_mod in obj.modifiers:362 if curr_mod.type == 'ARMATURE':363 uses_skeletal_animation = True364 # check if this object has an armature parent (second way to do armature animations in blender)365 if obj.parent:366 if obj.parent.type == "ARMATURE":367 uses_skeletal_animation = True368 if uses_skeletal_animation:369 flags.append('skeletal-animation="true"')370 else:371 flags.append('skeletal-animation="false"')372 on_kart_collision = stk_utils.getObjectProperty(obj, "on_kart_collision", "")373 if len(on_kart_collision) > 0:374 flags.append("on-kart-collision=\"%s\""%on_kart_collision)375 custom_xml = stk_utils.getObjectProperty(obj, "custom_xml", "")376 if len(custom_xml) > 0:377 flags.append(custom_xml)378 if_condition = stk_utils.getObjectProperty(obj, "if", "")379 if len(if_condition) > 0:380 flags.append("if=\"%s\""%if_condition)381 lAnim = checkForAnimatedTextures(self, [obj])382 detail_level = 0383 if stk_utils.getObjectProperty(obj, "enable_geo_detail", "false") == 'true':384 detail_level = int(stk_utils.getObjectProperty(obj, "geo_detail_level", 0))385 if detail_level > 0:386 flags.append("geometry-level=\"%d\"" % detail_level)387 if parent and parent.type=="ARMATURE":388 f.write(" <object id=\"%s\" type=\"%s\" %s %s>\n"% (obj.name, objectType, stk_utils.getXYZHPRString(parent), ' '.join(flags)))389 else:390 f.write(" <object id=\"%s\" type=\"%s\" %s %s>\n"% (obj.name, objectType, stk_utils.getXYZHPRString(obj), ' '.join(flags)))391 if lAnim:392 writeAnimatedTextures(f, lAnim)393 writeIPO(self, f, ipo)394 f.write(" </object>\n")395 # --------------------------------------------------------------------------396 def writeLODModels(self, f, sPath, lLODModels):397 for props in lLODModels:398 obj = props['object']399 spm_name = self.exportLocalSPM(obj, sPath, props['filename'], props['modifiers'])400 skeletal_anim_str = ""401 uses_skeletal_animation = False402 # check if this object has an armature modifier403 for curr_mod in obj.modifiers:404 if curr_mod.type == 'ARMATURE':405 uses_skeletal_animation = True406 # check if this object has an armature parent (second way to do armature animations in blender)407 if obj.parent:408 if obj.parent.type == "ARMATURE":409 uses_skeletal_animation = True410 if uses_skeletal_animation:411 additional_prop_str = ' skeletal-animation="true"'412 else:413 additional_prop_str = ' skeletal-animation="false"'414 detail_level = 0415 if stk_utils.getObjectProperty(obj, "enable_geo_detail", "false") == 'true':416 detail_level = int(stk_utils.getObjectProperty(obj, "geo_detail_level", 0))417 if detail_level > 0:418 additional_prop_str += " geometry-level=\"%d\"" % detail_level419 f.write(" <static-object lod_distance=\"%i\" lod_group=\"%s\" model=\"%s\" %s interaction=\"%s\"%s/>\n" % (props['distance'], props['groupname'], spm_name, stk_utils.getXYZHPRString(obj), stk_utils.getObjectProperty(obj, "interaction", "static"), additional_prop_str) )420 # --------------------------------------------------------------------------421 # Write the objects that are part of the track (but not animated or422 # physical).423 def writeStaticObjects(self, f, sPath, lStaticObjects, lAnimTextures):424 for obj in lStaticObjects:425 lodstring = self.getModelDefinitionString(obj)426 # An object can set the 'name' property, then this name will427 # be used to name the exported object (instead of the python name428 # which might be a default name with a number). Additionally, names429 # are cached so it can be avoided to export two or more identical430 # objects.431 lAnim = checkForAnimatedTextures(self, [obj])432 name = stk_utils.getObjectProperty(obj, "name", obj.name)433 if len(name) == 0: name = obj.name434 type = stk_utils.getObjectProperty(obj, "type", "X")435 if type != "lod_instance":436 spm_name = self.exportLocalSPM(obj, sPath, name, True)437 kind = stk_utils.getObjectProperty(obj, "kind", "")438 attributes = []439 attributes.append(lodstring)440 if type != "lod_instance" and type != "single_lod":441 attributes.append("model=\"%s\""%spm_name)442 attributes.append(stk_utils.getXYZHPRString(obj))443 condition_if = stk_utils.getObjectProperty(obj, "if", "")444 if len(condition_if) > 0:445 attributes.append("if=\"%s\""%condition_if)446 challenge_val = stk_utils.getObjectProperty(obj, "challenge", "")447 if len(challenge_val) > 0:448 attributes.append("challenge=\"%s\""% challenge_val)449 detail_level = 0450 if stk_utils.getObjectProperty(obj, "enable_geo_detail", "false") == 'true':451 detail_level = int(stk_utils.getObjectProperty(obj, "geo_detail_level", 0))452 if detail_level > 0:453 attributes.append("geometry-level=\"%d\"" % detail_level)454 interaction = stk_utils.getObjectProperty(obj, "interaction", '??')455 if interaction == 'reset':456 attributes.append("reset=\"y\"")457 elif interaction == 'explode':458 attributes.append("explode=\"y\"")459 elif interaction == 'flatten':460 attributes.append("flatten=\"y\"")461 if interaction == 'physicsonly':462 attributes.append('interaction="physics-only"')463 if lAnim:464 f.write(" <static-object %s>\n" % ' '.join(attributes))465 writeAnimatedTextures(f, lAnim)466 f.write(" </static-object>\n")467 else:468 f.write(" <static-object %s/>\n" % ' '.join(attributes))469 writeAnimatedTextures(f, lAnimTextures)470 # --------------------------------------------------------------------------471 # Get LOD string for a given object (returns an empty string if object is not LOD)472 def getModelDefinitionString(self, obj):473 lodstring = ""474 type = stk_utils.getObjectProperty(obj, "type", "object")475 if type == "lod_model":476 pass477 #elif type == "object" and stk_utils.getObjectProperty(obj, "instancing", "false") == "true":478 # group = type = stk_utils.getObjectProperty(obj, "name", "")479 # if len(group) == 0:480 # self.log.report({'WARNING'}, "Instancing object " + obj.name + " has no name property")481 # lodstring = ' instancing="true" instancing_model="' + group + '"'482 elif type == "lod_instance":483 group = type = stk_utils.getObjectProperty(obj, "lod_name", "")484 if len(group) == 0:485 self.log.report({'WARNING'}, "LOD instance " + obj.name + " has no group property")486 lodstring = ' lod_instance="true" lod_group="' + group + '"'487 elif type == "single_lod":488 lodstring = ' lod_instance="true" lod_group="_single_lod_' + stk_utils.getObjectProperty(obj, "name", obj.name) + '"'489 return lodstring490 # --------------------------------------------------------------------------491 # Writes a non-static track object. The objects can be animated or492 # non-animated meshes, and physical or non-physical.493 # Type is either 'movable' or 'nophysics'.494 def writeObject(self, f, sPath, obj):495 name = stk_utils.getObjectProperty(obj, "name", obj.name)496 if len(name) == 0: name = obj.name497 type = stk_utils.getObjectProperty(obj, "type", "X")498 if obj.type != "CAMERA":499 if type == "lod_instance":500 spm_name = None501 else:502 spm_name = self.exportLocalSPM(obj, sPath, name, True)503 interact = stk_utils.getObjectProperty(obj, "interaction", "none")504 if obj.type=="CAMERA":505 ipo = obj.animation_data506 self.writeAnimationWithIPO(f, "", obj, ipo, objectType="cutscene_camera")507 # An object that can be moved by the player. This object508 # can not have an IPO, so no need to test this here.509 elif interact=="move":510 ipo = obj.animation_data511 if ipo and ipo.action:512 self.log.report({'WARNING'}, "Movable object %s has an ipo - ipo is ignored." \513 %obj.name)514 shape = stk_utils.getObjectProperty(obj, "shape", "")515 if not shape:516 self.log.report({'WARNING'}, "Movable object %s has no shape - box assumed!" \517 % obj.name)518 shape="box"519 mass = stk_utils.getObjectProperty(obj, "mass", 10)520 flags = []521 lodstring = self.getModelDefinitionString(obj)522 if len(lodstring) > 0:523 flags.append(lodstring)524 type = stk_utils.getObjectProperty(obj, "type", "?")525 if type != "lod_instance":526 flags.append('model="%s"' % spm_name)527 if stk_utils.getObjectProperty(obj, "forcedbloom", "false") == "true":528 flags.append('forcedbloom="true"')529 if stk_utils.getObjectProperty(obj, "shadowpass", "true") == "false":530 flags.append('shadow-pass="false"')531 if len(stk_utils.getObjectProperty(obj, "outline", "")) > 0:532 flags.append('glow="%s"'%stk_utils.getObjectProperty(obj, "outline", ""))533 if stk_utils.getObjectProperty(obj, "displacing", "false") == "true":534 flags.append('displacing="true"')535 #if stk_utils.getObjectProperty(obj, "skyboxobject", "false") == "true":536 # flags.append('renderpass="skybox"')537 if stk_utils.getObjectProperty(obj, "soccer_ball", "false") == "true":538 flags.append('soccer_ball="true"')539 on_kart_collision = stk_utils.getObjectProperty(obj, "on_kart_collision", "")540 if len(on_kart_collision) > 0:541 flags.append("on-kart-collision=\"%s\""%on_kart_collision)542 custom_xml = stk_utils.getObjectProperty(obj, "custom_xml", "")543 if len(custom_xml) > 0:544 flags.append(custom_xml)545 if_condition = stk_utils.getObjectProperty(obj, "if", "")546 if len(if_condition) > 0:547 flags.append("if=\"%s\""%if_condition)548 uses_skeletal_animation = False549 # check if this object has an armature modifier550 for curr_mod in obj.modifiers:551 if curr_mod.type == 'ARMATURE':552 uses_skeletal_animation = True553 # check if this object has an armature parent (second way to do armature animations in blender)554 if obj.parent:555 if obj.parent.type == "ARMATURE":556 uses_skeletal_animation = True557 if uses_skeletal_animation:558 flags.append('skeletal-animation="true"')559 else:560 flags.append('skeletal-animation="false"')561 detail_level = 0562 if stk_utils.getObjectProperty(obj, "enable_geo_detail", "false") == 'true':563 detail_level = int(stk_utils.getObjectProperty(obj, "geo_detail_level", 0))564 if detail_level > 0:565 flags.append("geometry-level=\"%d\"" % detail_level)566 f.write(' <object type="movable" id=\"%s\" %s\n'% (obj.name, stk_utils.getXYZHPRString(obj)))567 f.write(' shape="%s" mass="%s" %s/>\n' % (shape, mass, ' '.join(flags)))568 # Now the object either has an IPO, or is a 'ghost' object.569 # Either can have an IPO. Even if the objects don't move570 # they are saved as animations (with 0 IPOs).571 elif interact=="ghost" or interact=="none" or interact=="static" or interact=="reset" or interact=="explode" or interact=="flatten" or interact=="physicsonly":572 ipo = obj.animation_data573 # In objects with skeletal animations the actual armature (which574 # is a parent) contains the IPO. So check for this:575 if not ipo or not ipo.action or not ipo.action.fcurves or len(ipo.action.fcurves) == 0:576 parent = obj.parent577 if parent:578 ipo = parent.animation_data579 self.writeAnimationWithIPO(f, spm_name, obj, ipo)580 else:581 self.log.report({'WARNING'}, "Unknown interaction '%s' - ignored!"%interact)582 # --------------------------------------------------------------------------583 def writeEasterEggsFile(self, sPath, lEasterEggs):584 with open(sPath + "/easter_eggs.xml", "w", encoding="utf8", newline="\n") as f:585 f.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")586 f.write("<EasterEggHunt>\n")587 #print("lEasterEggs : ", len(lEasterEggs), lEasterEggs);588 f.write(" <easy>\n")589 for obj in lEasterEggs:590 #print(stk_utils.getObjectProperty(obj, "easteregg_easy", "false"))591 if stk_utils.getObjectProperty(obj, "easteregg_easy", "false") == "true":592 f.write(" <easter-egg %s />\n" % stk_utils.getXYZHString(obj))593 f.write(" </easy>\n")594 f.write(" <medium>\n")595 for obj in lEasterEggs:596 #print(stk_utils.getObjectProperty(obj, "easteregg_medium", "false"))597 if stk_utils.getObjectProperty(obj, "easteregg_medium", "false") == "true":598 f.write(" <easter-egg %s />\n" % stk_utils.getXYZHString(obj))599 f.write(" </medium>\n")600 f.write(" <hard>\n")601 for obj in lEasterEggs:602 #print(stk_utils.getObjectProperty(obj, "easteregg_hard", "false"))603 if stk_utils.getObjectProperty(obj, "easteregg_hard", "false") == "true":604 f.write(" <easter-egg %s />\n" % stk_utils.getXYZHString(obj))605 f.write(" </hard>\n")606 f.write("</EasterEggHunt>\n")607 # --------------------------------------------------------------------------608 # Writes the scene files, which includes all models, animations, and items609 def writeSceneFile(self, sPath, sTrackName, exporters, lTrack, lObjects, lSun):610 #start_time = bsys.time()611 print("Writing scene file --> \t")612 is_lib_node = (stk_utils.getSceneProperty(bpy.data.scenes[0], 'is_stk_node', 'false') == 'true')613 filename = "scene.xml"614 if is_lib_node:615 filename = "node.xml"616 with open(sPath + "/" + filename, "w", encoding="utf8", newline="\n") as f:617 f.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")618 f.write("<scene>\n")619 # Extract all static objects (which will be merged into one bullet object in stk):620 lStaticObjects = []621 # Include LOD models (i.e. the definition of a LOD group. Does not include LOD instances)622 lLODModels = {}623 #lInstancingModels = {}624 lOtherObjects = []625 for obj in lObjects:626 type = stk_utils.getObjectProperty(obj, "type", "??")627 interact = stk_utils.getObjectProperty(obj, "interaction", "static")628 #if type == "lod_instance" or type == "lod_model" or type == "single_lod":629 # interact = "static"630 # TODO: remove this fuzzy logic and let the artist clearly decide what is exported in the631 # track main model and what is exporter separately632 export_non_static = False633 if stk_utils.getObjectProperty(obj, "forcedbloom", "false") == "true":634 export_non_static = True635 elif stk_utils.getObjectProperty(obj, "shadowpass", "true") == "false":636 export_non_static = True637 elif len(stk_utils.getObjectProperty(obj, "outline", "")) > 0:638 export_non_static = True639 elif stk_utils.getObjectProperty(obj, "displacing", "false") == "true":640 export_non_static = True641 #elif stk_utils.getObjectProperty(obj, "skyboxobject", "false") == "true":642 # export_non_static = True643 elif stk_utils.getObjectProperty(obj, "soccer_ball", "false") == "true":644 export_non_static = True645 elif is_lib_node:646 export_non_static = True647 elif interact=="reset" or interact=="explode" or interact=="flatten":648 export_non_static = True649 elif len(stk_utils.getObjectProperty(obj, "on_kart_collision", "")) > 0:650 export_non_static = True651 elif len(stk_utils.getObjectProperty(obj, "if", "")):652 export_non_static = True653 #if type == "object" and stk_utils.getObjectProperty(obj, "instancing", "false") == "true":654 # if is_lib_node:655 # instancing_name = stk_utils.getObjectProperty(obj, 'name', '')656 # if len(instancing_name) == 0:657 # self.log.report({'WARNING'}, 'Object %s marked as instancing has no name' % obj.name)658 # continue659 # lInstancingModels[instancing_name] = obj660 # lOtherObjects.append(obj)661 # else:662 # self.log.report({'WARNING'}, 'Object %s marked as instancing. Instancing only works with library nodes.' % obj.name)663 #elif664 if type == 'lod_model':665 group_name = stk_utils.getObjectProperty(obj, 'lod_name', '')666 if len(group_name) == 0:667 self.log.report({'WARNING'}, 'Object %s marked as LOD but no LOD name specified' % obj.name)668 continue669 if group_name not in lLODModels:670 lLODModels[group_name] = []671 lod_model_name = stk_utils.getObjectProperty(obj, "name", obj.name)672 loddistance = stk_utils.getObjectProperty(obj, "lod_distance", 60.0)673 if len(lod_model_name) == 0: lod_model_name = obj.name674 lLODModels[group_name].append({'object': obj, 'groupname': group_name, 'distance': loddistance, 'filename': lod_model_name, 'modifiers': True})675 elif type == 'single_lod':676 lod_model_name = stk_utils.getObjectProperty(obj, "name", obj.name)677 if len(lod_model_name) == 0: lod_model_name = obj.name678 group_name = "_single_lod_" + lod_model_name679 if group_name not in lLODModels:680 lLODModels[group_name] = []681 if stk_utils.getObjectProperty(obj, "nomodifierautolod", "false") == "true":682 loddistance = stk_utils.getObjectProperty(obj, "nomodierlod_distance", 30.0)683 lLODModels[group_name].append({'object': obj, 'groupname': group_name, 'distance': loddistance, 'filename': lod_model_name, 'modifiers': True})684 loddistance = stk_utils.getObjectProperty(obj, "lod_distance", 60.0)685 lLODModels[group_name].append({'object': obj, 'groupname': group_name, 'distance': loddistance, 'filename': lod_model_name + "_mid", 'modifiers': False})686 else:687 loddistance = stk_utils.getObjectProperty(obj, "lod_distance", 60.0)688 lLODModels[group_name].append({'object': obj, 'groupname': group_name, 'distance': loddistance, 'filename': lod_model_name, 'modifiers': True})689 # this object is both a model and an instance, so also add it to the list of objects, where it will be exported as a LOD instance690 if export_non_static:691 lOtherObjects.append(obj)692 else:693 lStaticObjects.append(obj)694 elif not export_non_static and (interact=="static" or type == "lod_model" or interact=="physicsonly"):695 ipo = obj.animation_data696 if obj.parent is not None and obj.parent.type=="ARMATURE" and obj.parent.animation_data is not None:697 ipo = obj.parent.animation_data698 # If an static object has an IPO, it will be moved, and699 # can't be merged with the physics model of the track700 if (ipo and ipo.action):701 lOtherObjects.append(obj)702 else:703 lStaticObjects.append(obj)704 else:705 lOtherObjects.append(obj)706 lAnimTextures = checkForAnimatedTextures(self, lTrack)707 if len(lLODModels.keys()) > 0:708 f.write(' <lod>\n')709 for group_name in lLODModels.keys():710 lLODModels[group_name].sort(key = lambda a: a['distance'])711 f.write(' <group name="%s">\n' % group_name)712 self.writeLODModels(f, sPath, lLODModels[group_name])713 f.write(' </group>\n')714 f.write(' </lod>\n')715 #if len(lInstancingModels.keys()) > 0:716 # f.write(' <instancing>\n')717 # for instancing_name in lInstancingModels.keys():718 # f.write(' <group name="%s">\n' % instancing_name)719 # self.writeInstancingModel(f, sPath, instancing_name, lInstancingModels[instancing_name])720 # f.write(' </group>\n')721 # f.write(' </instancing>\n')722 if stk_utils.getSceneProperty(bpy.data.scenes[0], 'is_stk_node', 'false') != 'true':723 if lStaticObjects or lAnimTextures:724 f.write(" <track model=\"%s\" x=\"0\" y=\"0\" z=\"0\">\n"%sTrackName)725 self.writeStaticObjects(f, sPath, lStaticObjects, lAnimTextures)726 f.write(" </track>\n")727 else:728 f.write(" <track model=\"%s\" x=\"0\" y=\"0\" z=\"0\"/>\n"%sTrackName)729 for obj in lOtherObjects:730 self.writeObject(f, sPath, obj)731 # Subtitles732 subtitles = []733 end_time = bpy.data.scenes[0].frame_end734 for marker in reversed(bpy.data.scenes[0].timeline_markers):735 if marker.name.startswith("subtitle"):736 subtitle_text = bpy.data.scenes[0][marker.name]737 subtitles.insert(0, [marker.frame, end_time - 1, subtitle_text])738 end_time = marker.frame739 if len(subtitles) > 0:740 f.write(" <subtitles>\n")741 for subtitle in subtitles:742 f.write(" <subtitle from=\"%i\" to=\"%i\" text=\"%s\"/>\n" % (subtitle[0], subtitle[1], subtitle[2]))743 f.write(" </subtitles>\n")744 # Assemble all sky/fog related parameters745 # ---------------------------------------746 # We do not export sky, sun, etc if its a lib node. Those are objects not scenes.747 if not is_lib_node:748 if len(lSun) > 1:749 self.log.report({'WARNING'}, "Warning: more than one Sun defined, only the first will be used." )750 sSky=""751 scene = bpy.context.scene752 s = stk_utils.getSceneProperty(scene, "fog", 0)753 if s == "yes" or s == "true":754 sSky="%s fog=\"true\""%sSky755 s=stk_utils.getSceneProperty(scene, "fog_color", 0)756 if s: sSky="%s fog-color=\"%s\""%(sSky, s)757 s=float(stk_utils.getSceneProperty(scene, "fog_max", 0))758 if s: sSky="%s fog-max=\"%s\""%(sSky, s)759 s=float(stk_utils.getSceneProperty(scene, "fog_start", 0))760 if s: sSky="%s fog-start=\"%.2f\""%(sSky, s)761 s=float(stk_utils.getSceneProperty(scene, "fog_end", 0))762 if s: sSky="%s fog-end=\"%.2f\""%(sSky, s)763 # If there is a sun:764 if len(lSun) > 0:765 sun = lSun[0]766 xyz=sun.location767 sSky="%s xyz=\"%.2f %.2f %.2f\""%(sSky, float(xyz[0]), float(xyz[2]), float(xyz[1]))768 s=stk_utils.getObjectProperty(sun, "color", 0)769 if s: sSky="%s sun-color=\"%s\""%(sSky, s)770 s=stk_utils.getObjectProperty(sun, "specular", 0)771 if s: sSky="%s sun-specular=\"%s\""%(sSky, s)772 s=stk_utils.getObjectProperty(sun, "diffuse", 0)773 if s: sSky="%s sun-diffuse=\"%s\""%(sSky, s)774 s=stk_utils.getObjectProperty(sun, "ambient", 0)775 if s: sSky="%s ambient=\"%s\""%(sSky, s)776 if sSky:777 f.write(" <sun %s/>\n"%sSky)778 sky_color=stk_utils.getSceneProperty(scene, "sky_color", None)779 if sky_color:780 f.write(" <sky-color rgb=\"%s\"/>\n"%sky_color)781 weather = ""782 weather_type = stk_utils.getSceneProperty(scene, "weather_type", "none")783 if weather_type != "none":784 if weather_type[:4] != ".xml":785 weather_type = weather_type + ".xml"786 weather = " particles=\"" + weather_type + "\""787 lightning = stk_utils.getSceneProperty(scene, "weather_lightning", "false")788 if lightning == "true":789 weather = weather + " lightning=\"true\""790 weather_sound = stk_utils.getSceneProperty(scene, "weather_sound", "")791 if weather_sound != "":792 weather = weather + " sound=\"" + weather_sound + "\""793 if weather != "":794 f.write(" <weather%s/>\n"%weather)795 rad2deg = 180.0/3.1415926796 sky = stk_utils.getSceneProperty(scene, "sky_type", None)797 sphericalHarmonicsStr = ""798 if stk_utils.getSceneProperty(scene, "ambientmap", "false") == "true":799 sphericalHarmonicsTextures = []800 s = stk_utils.getSceneProperty(scene, "ambientmap_texture2", "")801 if len(s) > 0: sphericalHarmonicsTextures.append(s)802 s = stk_utils.getSceneProperty(scene, "ambientmap_texture3", "")803 if len(s) > 0: sphericalHarmonicsTextures.append(s)804 s = stk_utils.getSceneProperty(scene, "ambientmap_texture4", "")805 if len(s) > 0: sphericalHarmonicsTextures.append(s)806 s = stk_utils.getSceneProperty(scene, "ambientmap_texture5", "")807 if len(s) > 0: sphericalHarmonicsTextures.append(s)808 s = stk_utils.getSceneProperty(scene, "ambientmap_texture6", "")809 if len(s) > 0: sphericalHarmonicsTextures.append(s)810 s = stk_utils.getSceneProperty(scene, "ambientmap_texture1", "")811 if len(s) > 0: sphericalHarmonicsTextures.append(s)812 if len(sphericalHarmonicsTextures) == 6:813 sphericalHarmonicsStr = 'sh-texture="' + " ".join(sphericalHarmonicsTextures) + '"'814 else:815 self.log.report({'WARNING'}, 'Invalid ambient map textures')816 # Note that there is a limit to the length of id properties,817 # which can easily be exceeded by 6 sky textures for a full sky box.818 # Therefore also check for sky-texture1 and sky-texture2.819 texture = stk_utils.getSceneProperty(scene, "sky_texture", "")820 s = stk_utils.getSceneProperty(scene, "sky_texture1", "")821 if s: texture = "%s %s"%(texture, s)822 s = stk_utils.getSceneProperty(scene, "sky_texture2", "")823 if s: texture = "%s %s"%(texture, s)824 if sky and texture:825 if sky=="box":826 lTextures = [stk_utils.getSceneProperty(scene, "sky_texture2", ""),827 stk_utils.getSceneProperty(scene, "sky_texture3", ""),828 stk_utils.getSceneProperty(scene, "sky_texture4", ""),829 stk_utils.getSceneProperty(scene, "sky_texture5", ""),830 stk_utils.getSceneProperty(scene, "sky_texture6", ""),831 stk_utils.getSceneProperty(scene, "sky_texture1", "")]832 f.write(" <sky-box texture=\"%s\" %s/>\n" % (" ".join(lTextures), sphericalHarmonicsStr))833 camera_far = stk_utils.getSceneProperty(scene, "camera_far", "" )834 if camera_far:835 f.write(" <camera far=\"%s\"/>\n"%camera_far)836 for exporter in exporters:837 exporter.export(f)838 f.write("</scene>\n")839 #print bsys.time()-start_time,"seconds"840 def __init__(self, log, sFilePath, exportImages, exportDrivelines, exportScene, exportMaterials):841 self.dExportedObjects = {}842 self.log = log843 sBase = os.path.basename(sFilePath)844 sPath = os.path.dirname(sFilePath)845 stk_delete_old_files_on_export = False846 try:847 stk_delete_old_files_on_export = bpy.context.preferences.addons[os.path.basename(os.path.dirname(__file__))].preferences.stk_delete_old_files_on_export848 except:849 pass850 if stk_delete_old_files_on_export:851 os.chdir(sPath)852 old_model_files = [ f for f in os.listdir(sPath) if f.endswith(".spm") ]853 for f in old_model_files:854 print("Deleting ", f)855 os.remove(f)856 blendfile_dir = os.path.dirname(bpy.data.filepath)857 if exportImages:858 for i,curr in enumerate(bpy.data.images):859 try:860 if curr.filepath is None or len(curr.filepath) == 0:861 continue862 abs_texture_path = bpy.path.abspath(curr.filepath)863 print('abs_texture_path', abs_texture_path, blendfile_dir)864 if bpy.path.is_subdir(abs_texture_path, blendfile_dir):865 shutil.copy(abs_texture_path, sPath)866 except:867 traceback.print_exc(file=sys.stdout)868 self.log.report({'WARNING'}, 'Failed to copy texture ' + curr.filepath)869 drivelineExporter = stk_track_utils.DrivelineExporter(self.log)870 navmeshExporter = stk_track_utils.NavmeshExporter(self.log)871 exporters = [drivelineExporter, stk_track_utils.ParticleEmitterExporter(self.log), stk_track_utils.BlenderHairExporter(self.log), stk_track_utils.SoundEmitterExporter(self.log),872 stk_track_utils.ActionTriggerExporter(self.log), stk_track_utils.ItemsExporter(), stk_track_utils.BillboardExporter(self.log), stk_track_utils.LightsExporter(self.log), stk_track_utils.LightShaftExporter(),873 stk_track_utils.StartPositionFlagExporter(self.log), stk_track_utils.LibraryNodeExporter(self.log), navmeshExporter]874 # Collect the different kind of meshes this exporter handles875 # ----------------------------------------------------------876 lObj = bpy.context.scene.objects877 lTrack = [] # All main track objects878 lCameraCurves = [] # Camera curves (unused atm)879 lObjects = [] # All special objects880 lSun = []881 lEasterEggs = []882 for obj in lObj:883 # Try to get the supertuxkart type field. If it's not defined,884 # use the name of the objects as type.885 stktype = stk_utils.getObjectProperty(obj, "type", "").strip().upper()886 #print("Checking object",obj.name,"which has type",stktype)887 # Make it possible to ignore certain objects, e.g. if you keep a888 # selection of 'templates' (ready to go models) around to be889 # copied into the main track.890 # This also works with objects that have hide_render enabled.891 # Do not export linked objects if part of the STK object library;892 # linked objects will be used as templates to create instances from.893 if obj.hide_render or stktype == "IGNORE" or \894 (obj.name.startswith("stklib_") and obj.library is not None):895 continue896 if stktype=="EASTEREGG":897 lEasterEggs.append(obj)898 continue899 objectProcessed = False900 for exporter in exporters:901 if exporter.processObject(obj, stktype):902 objectProcessed = True903 break904 if objectProcessed:905 continue906 if obj.type=="LIGHT" and stktype == "SUN":907 lSun.append(obj)908 continue909 elif obj.type=="CAMERA" and stktype == 'CUTSCENE_CAMERA':910 lObjects.append(obj)911 continue912 elif obj.type!="MESH":913 #print "Non-mesh object '%s' (type: '%s') is ignored!"%(obj.name, stktype)914 continue915 if stktype=="OBJECT" or stktype=="SPECIAL_OBJECT" or stktype=="LOD_MODEL" or stktype=="LOD_INSTANCE" or stktype=="SINGLE_LOD":916 lObjects.append(obj)917 elif stktype=="CANNONEND":918 pass # cannon ends are handled with cannon start objects919 elif stktype=="NONE":920 lTrack.append(obj)921 else:922 s = stk_utils.getObjectProperty(obj, "type", None)923 if s:924 self.log.report({'WARNING'}, "object " + obj.name + " has type property '%s', which is not supported.\n"%s)925 lTrack.append(obj)926 is_arena = stk_utils.getSceneProperty(bpy.data.scenes[0], "arena", "false") == "true"927 is_soccer = stk_utils.getSceneProperty(bpy.data.scenes[0], "soccer", "false") == "true"928 is_cutscene = stk_utils.getSceneProperty(bpy.data.scenes[0], "cutscene", "false") == "true"929 # Now export the different parts: track file930 # ------------------------------------------931 if exportScene and stk_utils.getSceneProperty(bpy.data.scenes[0], 'is_stk_node', 'false') != 'true':932 self.writeTrackFile(sPath, sBase)933 # Quads and mapping files934 # -----------------------935 scene = bpy.context.scene936 is_arena = stk_utils.getSceneProperty(scene, "arena", "n")937 if not is_arena: is_arena="n"938 is_arena = not (is_arena[0]=="n" or is_arena[0]=="N" or \939 is_arena[0]=="f" or is_arena[0]=="F" )940 is_soccer = stk_utils.getSceneProperty(scene, "soccer", "n")941 if not is_soccer: is_soccer="n"942 is_soccer = not (is_soccer[0]=="n" or is_soccer[0]=="N" or \943 is_soccer[0]=="f" or is_soccer[0]=="F" )944 if exportDrivelines and not is_arena and not is_soccer and not is_cutscene:945 drivelineExporter.writeQuadAndGraph(sPath)946 if (is_arena or is_soccer):947 navmeshExporter.exportNavmesh(sPath)948 sTrackName = sBase+"_track.spm"949 stk_utils.unhideObjectsTransiently();950 stk_utils.selectObjectsInList(lTrack)951 if exportScene and stk_utils.getSceneProperty(bpy.data.scenes[0], 'is_stk_node', 'false') != 'true':952 bpy.ops.screen.spm_export(localsp=False, filepath=sPath+"/"+sTrackName, selection_type="selected", \953 export_tangent=stk_utils.getSceneProperty(scene, 'precalculate_tangents', 'false') == 'true')954 bpy.ops.object.select_all(action='DESELECT')955 stk_utils.hideTransientObjects();956 # scene file957 # ----------958 if exportScene:959 self.writeSceneFile(sPath, sTrackName, exporters, lTrack, lObjects, lSun)960 if len(lEasterEggs) > 0 and stk_utils.getSceneProperty(scene, 'is_stk_node', 'false') != 'true':961 self.writeEasterEggsFile(sPath, lEasterEggs)962 # materials file963 # ----------964 if 'stk_material_export' not in dir(bpy.ops.screen):965 self.log.report({'ERROR'}, "Cannot find the material exporter, make sure you installed it properly")966 return967 if exportMaterials:968 bpy.ops.screen.stk_material_export(filepath=sPath + "/materials.xml")969# ==============================================================================970def savescene_callback(self, sFilePath, exportImages, exportDrivelines, exportScene, exportMaterials):971 if 'spm_export' not in dir(bpy.ops.screen):972 self.report({'ERROR'}, "Cannot find the spm exporter, make sure you installed it properly")973 return974 # Export the actual track and any individual objects975 TrackExport(self, sFilePath, exportImages, exportDrivelines and stk_utils.getSceneProperty(bpy.data.scenes[0], 'is_stk_node', 'false') != 'true', exportScene, exportMaterials)976 now = datetime.datetime.now()977 self.report({'INFO'}, "Track export completed on " + now.strftime("%Y-%m-%d %H:%M"))978# ==== EXPORT OPERATOR ====979class STK_Track_Export_Operator(bpy.types.Operator):980 """Export current scene to a STK track or library node"""981 bl_idname = ("screen.stk_track_export")982 bl_label = ("Export STK Track")983 filepath: bpy.props.StringProperty(subtype="FILE_PATH")984 exportScene: bpy.props.BoolProperty(name="Export scene", default=True)985 exportDrivelines: bpy.props.BoolProperty(name="Export drivelines", default=True)986 exportMaterials: bpy.props.BoolProperty(name="Export materials", default=True)987 def invoke(self, context, event):988 isATrack = ('is_stk_track' in context.scene) and (context.scene['is_stk_track'] == 'true')989 isANode = ('is_stk_node' in context.scene) and (context.scene['is_stk_node'] == 'true')990 if not isATrack and not isANode:991 self.report({'ERROR'}, "Not a STK library node or a track!")992 return {'FINISHED'}993 # FIXME: in library nodes it's "name", in tracks it's "code"994 if isANode:995 if 'name' not in context.scene or len(context.scene['name']) == 0:996 self.report({'ERROR'}, "Please specify a name")997 return {'FINISHED'}998 code = context.scene['name']999 else:1000 if 'code' not in context.scene or len(context.scene['code']) == 0:1001 self.report({'ERROR'}, "Please specify a code name (folder name)")1002 return {'FINISHED'}1003 code = context.scene['code']1004 assets_path = ""1005 try:1006 assets_path = bpy.context.preferences.addons[os.path.basename(os.path.dirname(__file__))].preferences.stk_assets_path1007 except:1008 pass1009 if assets_path is None or len(assets_path) < 0:1010 self.report({'ERROR'}, "Please select the export path in the add-on preferences or quick exporter panel")1011 return {'FINISHED'}1012 if isANode:1013 folder = os.path.join(assets_path, 'library', code)1014 else:1015 if 'is_wip_track' in context.scene and context.scene['is_wip_track'] == 'true':1016 folder = os.path.join(assets_path, 'wip-tracks', code)1017 else:1018 folder = os.path.join(assets_path, 'tracks', code)1019 if not os.path.exists(folder):1020 os.makedirs(folder)1021 self.filepath = os.path.join(folder, code)1022 return self.execute(context)1023 def execute(self, context):1024 if bpy.context.mode != 'OBJECT':1025 # Return to object mode before exporting1026 bpy.ops.object.mode_set(mode='OBJECT')1027 isNotATrack = ('is_stk_track' not in context.scene) or (context.scene['is_stk_track'] != 'true')1028 isNotANode = ('is_stk_node' not in context.scene) or (context.scene['is_stk_node'] != 'true')1029 if self.filepath == "" or (isNotATrack and isNotANode):1030 return {'FINISHED'}1031 exportImages = context.preferences.addons[os.path.basename(os.path.dirname(__file__))].preferences.stk_export_images1032 savescene_callback(self, self.filepath, exportImages, self.exportDrivelines, self.exportScene, self.exportMaterials)1033 return {'FINISHED'}1034 @classmethod1035 def poll(self, context):1036 if ('is_stk_track' in context.scene and context.scene['is_stk_track'] == 'true') or \1037 ('is_stk_node' in context.scene and context.scene['is_stk_node'] == 'true'):1038 return True1039 else:...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run pyatom automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful