Package fife :: Package extensions :: Package serializers :: Module xmlmap
[hide private]
[frames] | no frames]

Source Code for Module fife.extensions.serializers.xmlmap

  1  # -*- coding: utf-8 -*- 
  2  # #################################################################### 
  3  #  Copyright (C) 2005-2019 by the FIFE team 
  4  #  http://www.fifengine.net 
  5  #  This file is part of FIFE. 
  6  # 
  7  #  FIFE is free software; you can redistribute it and/or 
  8  #  modify it under the terms of the GNU Lesser General Public 
  9  #  License as published by the Free Software Foundation; either 
 10  #  version 2.1 of the License, or (at your option) any later version. 
 11  # 
 12  #  This library is distributed in the hope that it will be useful, 
 13  #  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 14  #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 15  #  Lesser General Public License for more details. 
 16  # 
 17  #  You should have received a copy of the GNU Lesser General Public 
 18  #  License along with this library; if not, write to the 
 19  #  Free Software Foundation, Inc., 
 20  #  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
 21  # #################################################################### 
 22   
 23  """ main xml parser class for xml map loading """ 
 24  from __future__ import print_function 
 25   
 26  from builtins import str 
 27  from builtins import object 
 28  import time 
 29   
 30  from fife import fife 
 31   
 32  from fife.extensions.serializers import ET 
 33  from fife.extensions.serializers import SerializerError, InvalidFormat 
 34  from fife.extensions.serializers import NameClash, NotFound, WrongFileType 
 35   
 36  from fife.extensions.serializers.xmlobject import XMLObjectLoader 
 37  from fife.extensions.serializers.xmlanimation import loadXMLAnimation 
 38  from fife.extensions.serializers.xml_loader_tools import loadImportFile, loadImportDir 
 39  from fife.extensions.serializers.xml_loader_tools import loadImportDirRec 
 40  from fife.extensions.serializers.xml_loader_tools import root_subfile, reverse_root_subfile 
 41   
 42   
 43  FORMAT = '1.0' 
 44   
45 -class XMLMapLoader(object):
46 """ The B{XMLMapLoader} parses the xml map using several section. 47 Each section fires a callback (if given) which can e. g. be 48 used to show a progress bar. 49 50 The callback sends two values, a string and a float (which shows 51 the overall process): callback(string, float) 52 """
53 - def __init__(self, engine, callback, debug, extensions):
54 """ 55 @type engine: object 56 @param engine: a pointer to fife.engine 57 @type callback: function 58 @param callback: a callback with two arguments, optional 59 @type debug: bool 60 @param debug: flag to activate / deactivate print statements 61 @type extensions: dict 62 @param extensions: information package which extension should be activated (lights, sounds) 63 """ 64 # self.thisown = 0 65 66 self.callback = callback 67 self.debug = debug 68 69 self.engine = engine 70 self.vfs = self.engine.getVFS() 71 self.model = self.engine.getModel() 72 self.image_manager = self.engine.getImageManager() 73 self.anim_pool = None 74 75 self.obj_loader = XMLObjectLoader(engine) 76 77 self.map = None 78 self.source = None 79 self.time_to_load = 0 80 81 self.nspace = None 82 83 self.msg = {} 84 self.msg['map'] = 'created map' 85 self.msg['imports'] = 'loaded imports' 86 self.msg['layer'] = 'loaded layer: %s' 87 self.msg['camera'] = 'loaded camera: %s' 88 89 if 'sound' not in extensions: 90 extensions['sound'] = False 91 if 'lights' not in extensions: 92 extensions['lights'] = False 93 94 self.light_data = {} 95 self.extensions = extensions
96
97 - def _err(self, msg):
98 raise SyntaxError(''.join(['File: ', self.source, ' . ', msg]))
99
100 - def loadResource(self, location):
101 """ overwrite of B{fife.ResourceLoader} 102 103 @type location: object 104 @param location: path to a map file as a fife.ResourceLocation 105 @return FIFE map object 106 @rtype object 107 """ 108 start_time = time.time() 109 self.source = location 110 f = self.vfs.open(self.source) 111 f.thisown = 1 112 tree = ET.parse(f) 113 root = tree.getroot() 114 115 map = self.parse_map(root) 116 self.time_to_load = time.time() - start_time 117 return map
118
119 - def parse_map(self, mapelt):
120 """ start parsing the xml structure and 121 call submethods for turning found tags 122 into FIFE objects and create the map 123 124 @type mapelt: object 125 @param mapelt: ElementTree root 126 @return FIFE map object 127 @rtype object 128 """ 129 if not mapelt: 130 self._err('No <map> element found at top level of map file definition.') 131 _id, format = mapelt.get('id'), mapelt.get('format') 132 133 if not format == FORMAT: self._err(''.join(['This file has format ', format, ' but this loader has format ', FORMAT])) 134 if not _id: self._err('Map declared without an identifier.') 135 136 map = None 137 try: 138 self.map = self.model.createMap(str(_id)) 139 self.map.setFilename(self.source) 140 except fife.Exception as e: # NameClash appears as general fife.Exception; any ideas? 141 print(e.getMessage()) 142 print(''.join(['File: ', self.source, '. The map ', str(_id), ' already exists! Ignoring map definition.'])) 143 return map 144 145 # xml-specific directory imports. This is used by xml savers. 146 self.map.importDirs = [] 147 148 if self.callback is not None: 149 self.callback(self.msg['map'], float(0.25) ) 150 151 self.parse_imports(mapelt, self.map) 152 self.parse_layers(mapelt, self.map) 153 self.parse_cameras(mapelt, self.map) 154 155 # create light nodes 156 if self.light_data: 157 self.create_light_nodes(self.map) 158 159 return self.map
160
161 - def parse_imports(self, mapelt, map):
162 """ load all objects defined as import into memory 163 164 @type mapelt: object 165 @param mapelt: ElementTree root 166 @return FIFE map object 167 @rtype object 168 """ 169 parsedImports = {} 170 171 if self.callback: 172 tmplist = mapelt.findall('import') 173 i = float(0) 174 175 for item in mapelt.findall('import'): 176 _file = item.get('file') 177 if _file: 178 _file = reverse_root_subfile(self.source, _file) 179 _dir = item.get('dir') 180 if _dir: 181 _dir = reverse_root_subfile(self.source, _dir) 182 183 # Don't parse duplicate imports 184 if (_dir,_file) in parsedImports: 185 if self.debug: print("Duplicate import:" ,(_dir, _file)) 186 continue 187 parsedImports[(_dir,_file)] = 1 188 189 if _file and _dir: 190 loadImportFile(self.obj_loader, '/'.join(_dir, _file), self.engine, self.debug) 191 elif _file: 192 loadImportFile(self.obj_loader, _file, self.engine, self.debug) 193 elif _dir: 194 loadImportDirRec(self.obj_loader, _dir, self.engine, self.debug) 195 map.importDirs.append(_dir) 196 else: 197 if self.debug: print('Empty import statement?') 198 199 if self.callback: 200 i += 1 201 self.callback(self.msg['imports'], float( i / float(len(tmplist)) * 0.25 + 0.25 ) )
202
203 - def parse_layers(self, mapelt, map):
204 """ create all layers and their instances 205 206 @type mapelt: object 207 @param mapelt: ElementTree root 208 @type map: object 209 @param map: FIFE map object 210 """ 211 if self.callback is not None: 212 tmplist = mapelt.findall('layer') 213 i = float(0) 214 215 for layer in mapelt.findall('layer'): 216 _id = layer.get('id') 217 grid_type = layer.get('grid_type') 218 219 if not _id: self._err('<layer> declared with no id attribute.') 220 if not grid_type: self._err(''.join(['Layer ', str(_id), ' has no grid_type attribute.'])) 221 222 x_scale = layer.get('x_scale') 223 y_scale = layer.get('y_scale') 224 rotation = layer.get('rotation') 225 x_offset = layer.get('x_offset') 226 y_offset = layer.get('y_offset') 227 z_offset = layer.get('z_offset') 228 pathing = layer.get('pathing') 229 transparency = layer.get('transparency') 230 231 layer_type = layer.get('layer_type') 232 layer_type_id = layer.get('layer_type_id') 233 234 if not x_scale: x_scale = 1.0 235 if not y_scale: y_scale = 1.0 236 if not rotation: rotation = 0.0 237 if not x_offset: x_offset = 0.0 238 if not y_offset: y_offset = 0.0 239 if not z_offset: z_offset = 0.0 240 if not pathing: pathing = "cell_edges_only" 241 if not transparency: 242 transparency = 0 243 else: 244 transparency = int(transparency) 245 246 cellgrid = self.model.getCellGrid(grid_type) 247 if not cellgrid: self._err('<layer> declared with invalid cellgrid type. (%s)' % grid_type) 248 249 cellgrid.setRotation(float(rotation)) 250 cellgrid.setXScale(float(x_scale)) 251 cellgrid.setYScale(float(y_scale)) 252 cellgrid.setXShift(float(x_offset)) 253 cellgrid.setYShift(float(y_offset)) 254 cellgrid.setZShift(float(z_offset)) 255 256 layer_obj = None 257 try: 258 layer_obj = map.createLayer(str(_id), cellgrid) 259 except fife.Exception as e: 260 print(e.getMessage()) 261 print('The layer ' + str(_id) + ' already exists! Ignoring this layer.') 262 263 continue 264 265 strgy = fife.CELL_EDGES_ONLY 266 if pathing == "cell_edges_and_diagonals": 267 strgy = fife.CELL_EDGES_AND_DIAGONALS 268 269 layer_obj.setPathingStrategy(strgy) 270 layer_obj.setLayerTransparency(transparency) 271 272 if layer_type: 273 if layer_type == 'walkable': 274 layer_obj.setWalkable(True) 275 elif layer_type == 'interact' and layer_type_id: 276 layer_obj.setInteract(True, layer_type_id) 277 278 self.parse_instances(layer, layer_obj) 279 280 if self.extensions['lights']: 281 self.parse_lights(layer, layer_obj) 282 if self.extensions['sound']: 283 self.parse_sounds(layer, layer_obj) 284 285 if self.callback is not None: 286 i += 1 287 self.callback(self.msg['layer'] % str(_id), float( i / float(len(tmplist)) * 0.25 + 0.5 ) ) 288 289 290 layers = map.getLayers() 291 for l in layers: 292 if l.isInteract(): 293 walk_layer = map.getLayer(l.getWalkableId()) 294 if walk_layer: 295 walk_layer.addInteractLayer(l); 296 297 for l in layers: 298 if l.isWalkable(): 299 l.createCellCache() 300 301 # cleanup 302 if self.callback is not None: 303 del tmplist 304 del i
305
306 - def parse_lights(self, layerelt, layer):
307 """ create light nodes 308 309 @type layerelt: object 310 @param layerelt: ElementTree layer branch 311 @type layer: object 312 @param layer: FIFE layer object 313 """ 314 _LIGHT_DEFAULT_BLENDING_SRC = -1 315 _LIGHT_DEFAULT_BLENDING_DST = -1 316 _LIGHT_DEFAULT_SUBDIVISIONS = 32 317 _LIGHT_DEFAULT_CAM_ID = 'default' 318 _LIGHT_DEFAULT_INTENSITY = 128 319 _LIGHT_DEFAULT_RADIUS = 10.0 320 321 print("Processing lights ... ") 322 lightelt = layerelt.find('lights') 323 if not lightelt: 324 print("\tno lights found on layer %s" % layer.getId()) 325 return 326 327 lights = [] 328 for attr in ('l', 'light', 'lgt'): 329 lights.extend(lightelt.findall(attr)) 330 331 for light in lights: 332 group = light.get('group') 333 if not group: 334 print("Light has no group. Omitting...") 335 continue 336 337 blending_src = light.get('src') 338 if not blending_src: 339 blending_src = _LIGHT_DEFAULT_BLENDING_SRC 340 blending_dst = light.get('dst') 341 if not blending_dst: 342 blending_dst = _LIGHT_DEFAULT_BLENDING_DST 343 344 _x = light.get('x') 345 if not _x: _x = 0 346 _y = light.get('y') 347 if not _y: _y = 0 348 _z = light.get('y') 349 if not _z: _z = 0 350 351 node = {} 352 node['blending_src'] = int(blending_src) 353 node['blending_dst'] = int(blending_dst) 354 node['layer'] = layer.getId() 355 node['position'] = int(_x), int(_y), int(_z) 356 357 # where is the light? *sing* 358 instance_id = light.get('instance') 359 node['instance'] = None 360 if instance_id and layer.getInstance(instance_id): 361 node['instance'] = instance_id 362 363 type = light.get('type') 364 if type: 365 s_ref = light.get('s_ref') 366 if not s_ref: s_ref = -1 367 node['s_ref'] = int(s_ref) 368 a_ref = light.get('a_ref') 369 if not a_ref: a_ref = 0.0 370 node['a_ref'] = float(a_ref) 371 372 if type == 'image': 373 image = light.get('image') 374 if not image: 375 print("Light has no image. Omitting...") 376 continue 377 node['type'] = 'image' 378 image = reverse_root_subfile(self.source, image) 379 img = self.image_manager.create(image) 380 node['image'] = img 381 elif type == 'animation': 382 animation = light.get('animation') 383 if not animation: 384 print("Light has no animation. Omitting...") 385 continue 386 node['type'] = 'animation' 387 animation = reverse_root_subfile(self.source, animation) 388 anim = loadXMLAnimation(self.engine, animation) 389 node['animation'] = anim 390 elif type == 'simple': 391 node['type'] = type 392 radius = light.get('radius') 393 if not radius: radius = _LIGHT_DEFAULT_RADIUS 394 node['radius'] = float(radius) 395 396 subdivisions = light.get('subdivisions') 397 if not subdivisions: 398 subdivisions = _LIGHT_DEFAULT_SUBDIVISIONS 399 node['subdivisions'] = int(subdivisions) 400 401 intensity = light.get('intensity') 402 if not intensity: 403 intensity = _LIGHT_DEFAULT_INTENSITY 404 node['intensity'] = int(intensity) 405 406 xstretch = light.get('xstretch') 407 if not xstretch: xstretch = 1.0 408 ystretch = light.get('ystretch') 409 if not ystretch: ystretch = 1.0 410 node['stretch'] = float(xstretch), float(ystretch) 411 412 color = light.get('color') 413 if not color: color = '%d,%d,%d' % (255, 255, 255) 414 node['color'] = ([int(c) for c in color.split(',')]) 415 416 else: 417 continue 418 419 cam_id = light.get('camera_id') 420 if not cam_id: cam_id = _LIGHT_DEFAULT_CAM_ID 421 422 if not cam_id in self.light_data: 423 self.light_data[cam_id] = {} 424 if group not in self.light_data[cam_id]: 425 self.light_data[cam_id][group] = [] 426 427 self.light_data[cam_id][group].append(node) 428 429 for camera, groups in self.light_data.items(): 430 print("Lights for camera %s" % camera) 431 for group, lights in groups.items(): 432 print(group, lights)
433
434 - def parse_sounds(self, layerelt, layer):
435 """ create sound emitter 436 437 FIXME: 438 - FIFE has a hard limit of sound emitters 439 how should we load emitters here? 440 - my first thought: collect a list of sound 441 files & data for emitter creation, 442 then let the client decide what to do with it 443 444 @type layerelt: object 445 @param layerelt: ElementTree layer branch 446 @type layer: object 447 @param layer: FIFE layer object 448 """ 449 # to be continued 450 pass
451
452 - def parse_instances(self, layerelt, layer):
453 """ create all layers and their instances 454 455 @type layerelt: object 456 @param layerelt: ElementTree layer branch 457 @type layer: object 458 @param layer: FIFE layer object 459 """ 460 instelt = layerelt.find('instances') 461 462 instances = [] 463 for attr in ('i', 'inst', 'instance'): 464 instances.extend(instelt.findall(attr)) 465 466 for instance in instances: 467 _id = instance.get('id') 468 if not _id: 469 _id = '' 470 471 objectID = '' 472 for attr in ('o', 'object', 'obj'): 473 objectID = instance.get(attr) 474 if objectID: break 475 if not objectID: self._err('<instance> %s does not specify an object attribute.' % str(objectID)) 476 objectID = str(objectID) 477 478 nspace = '' 479 for attr in ('namespace', 'ns'): 480 nspace = instance.get(attr) 481 if nspace: break 482 # try to reuse the previous namespace 483 if not nspace and self.nspace: 484 nspace = self.nspace 485 if not nspace and not self.nspace: self._err('<instance> %s does not specify an object namespace, and no default is available.' % str(objectID)) 486 nspace = str(nspace) 487 self.nspace = nspace 488 489 # check if there is an object for this instance available, if not -> skip this one 490 object = self.model.getObject(objectID, nspace) 491 if not object: 492 print("Object with id=%s, ns=%s could not be found. Omitting..." % (objectID, nspace)) 493 continue 494 495 x = instance.get('x') 496 if x: self.x = x = float(x) 497 else: x = self.x 498 499 y = instance.get('y') 500 if y: self.y = y = float(y) 501 else: y = self.y 502 503 z = instance.get('z') 504 if z: z = float(z) 505 else: z = 0.0 506 507 inst = layer.createInstance(object, fife.ExactModelCoordinate(x,y,z), _id) 508 509 rotation = 0 510 for attr in ('r', 'rotation'): 511 rotation = instance.get(attr) 512 if rotation: break 513 if not rotation: 514 angles = object.get2dGfxVisual().getStaticImageAngles() 515 if angles: 516 rotation = angles[0] 517 else: 518 rotation = 0 519 else: 520 rotation = int(rotation) 521 inst.setRotation(rotation) 522 523 over_block = instance.get('override_blocking') 524 if over_block is not None: 525 inst.setOverrideBlocking(bool(over_block)) 526 blocking = instance.get('blocking') 527 if blocking is not None: 528 inst.setBlocking(bool(int(blocking))) 529 530 fife.InstanceVisual.create(inst) 531 532 stackpos = instance.get('stackpos') 533 if stackpos: 534 inst.get2dGfxVisual().setStackPosition(int(stackpos)) 535 536 if (object.getAction('default')): 537 target = fife.Location(layer) 538 inst.actRepeat('default', target)
539
540 - def parse_cameras(self, mapelt, map):
541 """ create all cameras and activate them 542 543 FIXME: 544 - should the cameras really be enabled here? 545 IMO that's part of the setup within a client 546 (we just _load_ things here) 547 548 @type mapelt: object 549 @param mapelt: ElementTree root 550 @type map: object 551 @param map: FIFE map object 552 """ 553 if self.callback: 554 tmplist = mapelt.findall('camera') 555 i = float(0) 556 557 for camera in mapelt.findall('camera'): 558 _id = camera.get('id') 559 zoom = camera.get('zoom') 560 tilt = camera.get('tilt') 561 rotation = camera.get('rotation') 562 ref_cell_width = camera.get('ref_cell_width') 563 ref_cell_height = camera.get('ref_cell_height') 564 viewport = camera.get('viewport') 565 light_color = camera.get('light_color') 566 567 if not zoom: zoom = 1 568 if not tilt: tilt = 0 569 if not rotation: rotation = 0 570 571 if not _id: self._err('Camera declared without an id.') 572 if not (ref_cell_width and ref_cell_height): self._err(''.join(['Camera ', str(_id), ' declared without reference cell dimensions.'])) 573 574 try: 575 if viewport: 576 cam = map.addCamera(str(_id), fife.Rect(*[int(c) for c in viewport.split(',')])) 577 578 else: 579 screen = self.engine.getRenderBackend() 580 cam = map.addCamera(str(_id), fife.Rect(0,0,screen.getScreenWidth(),screen.getScreenHeight())) 581 582 renderer = fife.InstanceRenderer.getInstance(cam) 583 renderer.activateAllLayers(map) 584 585 except fife.Exception as e: 586 print(e.getMessage()) 587 588 if light_color: cam.setLightingColor(*[float(c) for c in light_color.split(',')]) 589 cam.setCellImageDimensions(int(ref_cell_width), int(ref_cell_height)) 590 cam.setRotation(float(rotation)) 591 cam.setTilt(float(tilt)) 592 cam.setZoom(float(zoom)) 593 594 renderer = fife.InstanceRenderer.getInstance(cam) 595 renderer.activateAllLayers(map) 596 597 if self.callback: 598 i += 1 599 self.callback(self.msg['camera'] % str(_id), float( i / len(tmplist) * 0.25 + 0.75 ) )
600
601 - def create_light_nodes(self, map):
602 """ loop through all preloaded lights and create them 603 according to their data 604 605 @type map: object 606 @param map: FIFE map object 607 """ 608 cameras = [i.getId() for i in map.getCameras()] 609 renderers = {} 610 default_cam = map.getCameras()[0].getId() 611 612 def add_simple_light(group, renderer, node, data): 613 """ add a node as simple light to the renderer 614 615 @type group: string 616 @param group: name of the light group 617 @type renderer: object 618 @param renderer: fife.LightRenderer instance 619 @type node: object 620 @param node: fife.RendererNode instance 621 @type data: dict 622 @param data: all data for the light type creation 623 """ 624 if not node: return 625 if not group: return 626 renderer.addSimpleLight( 627 group, 628 node, 629 data['intensity'], 630 data['radius'], 631 data['subdivisions'], 632 data['stretch'][0], 633 data['stretch'][1], 634 data['color'][0], 635 data['color'][1], 636 data['color'][2], 637 data['blending_src'], 638 data['blending_dst'], 639 ) 640 if data['s_ref'] != -1: 641 add_stencil_test(group, renderer, data)
642 def add_animated_lightmap(group, renderer, node, data): 643 """ add a node as animated lightmap to the renderer 644 645 @type group: string 646 @param group: name of the light group 647 @type renderer: object 648 @param renderer: fife.LightRenderer instance 649 @type node: object 650 @param node: fife.RendererNode instance 651 @type data: dict 652 @param data: all data for the light type creation 653 """ 654 if not node: return 655 if not group: return 656 renderer.addAnimation( 657 group, 658 node, 659 data['animation'], 660 data['blending_src'], 661 data['blending_dst'], 662 ) 663 if data['s_ref'] != -1: 664 add_stencil_test(group, renderer, data)
665 def add_lightmap(group, renderer, node, data): 666 """ add a node as lightmap to the renderer 667 668 @type group: string 669 @param group: name of the light group 670 @type renderer: object 671 @param renderer: fife.LightRenderer instance 672 @type node: object 673 @param node: fife.RendererNode instance 674 @type data: dict 675 @param data: all data for the light type creation 676 """ 677 if not node: return 678 if not group: return 679 renderer.addImage( 680 group, 681 node, 682 data['image'], 683 data['blending_src'], 684 data['blending_dst'], 685 ) 686 if data['s_ref'] != -1: 687 add_stencil_test(group, renderer, data) 688 def add_stencil_test(group, renderer, data): 689 """ add a stencil test to a group 690 691 @type group: string 692 @param group: name of the light group 693 @type renderer: object 694 @param renderer: fife.LightRenderer instance 695 @type data: dict 696 @param data: all data for the light type creation 697 """ 698 if not group: return 699 renderer.addStencilTest( 700 group, 701 data['s_ref'], 702 data['a_ref'], 703 ) 704 705 def create_node(instance=None, point=None, layer=None): 706 """ creates a node of one of these types: 707 708 - attached to an instance 709 - attached to an instance with offset 710 - attached to a point 711 712 FIXME: 713 - add location node 714 715 @type: instance: object 716 @param instance: fife instance object 717 @type point: tuple 718 @param point: x,y,z tuple 719 @type layer: object 720 @param layer: fife layer object 721 """ 722 node = None 723 if not layer: return node 724 725 # node at layer coordinates 726 if point and not instance: 727 point = fife.Point(point[0], point[1]) 728 node = fife.RendererNode(point); 729 # node with offset 730 if instance and point: 731 node = fife.RendererNode(instance, layer, fife.Point(point[0], point[1])) 732 # node attached to instance 733 if instance and not point: 734 node = fife.RendererNode(instance, layer) 735 736 if node: 737 node.thisown = 0 738 739 return node 740 741 def dump_data(): 742 """ dump all loaded data """ 743 for camera, groups in self.light_data.items(): 744 print("Lights for camera %s" % camera) 745 for group, lights in groups.items(): 746 print(group, lights) 747 748 # fetch all renderer instances for available cameras 749 for _id in cameras: 750 camera = map.getCamera(_id) 751 renderers[_id] = fife.LightRenderer.getInstance(camera) 752 753 # parse data and create the lights 754 for camera, groups in self.light_data.items(): 755 for group, lights in groups.items(): 756 for light in lights: 757 instance = None 758 layer = map.getLayer(light['layer']) 759 if light['instance']: 760 instance = layer.getInstance(light['instance']) 761 position = light['position'] 762 node = create_node(instance, position, layer) 763 764 # some guards 765 if not node: continue 766 767 if camera == 'default': 768 renderer = renderers[default_cam] 769 else: 770 renderer = renderers[camera] 771 772 if light['type'] == 'simple': 773 add_simple_light(group, renderer, node, light) 774 elif light['type'] == 'image': 775 add_lightmap(group, renderer, node, light) 776 elif light['type'] == 'animation': 777 add_animated_lightmap(group, renderer, node, light) 778 779 # dump_data() 780