3232from .A3DBlenderImporter import A3DBlenderImporter
3333from .BlenderMaterialUtils import addImageTextureToMaterial , decodeIntColorToTuple
3434
35- class Prop :
36- def __init__ (self ):
37- self .objects = []
38- self .mainObject = None
39-
40- def loadModel (self , modelPath ):
41- fileExtension = modelPath .split ("." )[- 1 ]
42- if fileExtension == "a3d" :
43- modelData = A3D ()
44- with open (modelPath , "rb" ) as file : modelData .read (file )
45-
46- # Import the model
47- modelImporter = A3DBlenderImporter (modelData , None , reset_empty_transform = False , try_import_textures = False )
48- self .objects = modelImporter .importData ()
49- elif fileExtension == "3ds" :
50- bpy .ops .import_scene .max3ds (filepath = modelPath , use_apply_transform = False )
51- for ob in bpy .context .selectable_objects :
52- # The imported objects are added to the active collection, remove them
53- bpy .context .collection .objects .unlink (ob )
54-
55- # Correct the origin XXX: this does not work for all cases, investigate more
56- ob .animation_data_clear ()
57- x , y , z = - ob .location .x , - ob .location .y , - ob .location .z
58- objectOrigin = Matrix .Translation ((x , y , z ))
59- ob .data .transform (objectOrigin )
60- ob .location = (0.0 , 0.0 , 0.0 )
61-
62- self .objects .append (ob )
63- else :
64- raise RuntimeError (f"Unknown model file extension: { fileExtension } " )
65-
66- # Identify the main parent object
67- for ob in self .objects :
68- if ob .parent == None : self .mainObject = ob
69- if self .mainObject == None :
70- raise RuntimeError (f"Unable to find the parent object for: { modelPath } " )
71-
72- def loadSprite (self , propInfo ):
73- spriteInfo = propInfo ["sprite" ]
74-
75- # Create a plane we can use for the sprite
76- me = bpy .data .meshes .new (propInfo ["name" ])
77-
78- # bm = bmesh.new()
79- # bmesh.ops.create_grid(bm, x_segments=1, y_segments=1, size=spriteInfo["scale"]*100)
80- # bm.to_mesh(me)
81- # bm.free()
82-
83- ob = bpy .data .objects .new (me .name , me )
84-
85- # Assign data
86- ob .scale = (spriteInfo ["width" ], 1.0 , spriteInfo ["height" ]) #XXX: this should involve spriteInfo["scale"] probably?
87- spriteOrigin = Matrix .Translation ((0.0 , spriteInfo ["originY" ], 0.0 ))
88- me .transform (spriteOrigin )
89-
90- # Finalise
91- self .objects .append (ob )
92- self .mainObject = ob
93-
94- class PropLibrary :
95- propGroups = {}
96- def __init__ (self , directory ):
97- self .directory = directory
98- self .libraryInfo = {}
99-
100- # Load library info
101- with open (f"{ self .directory } /library.json" , "r" ) as file : self .libraryInfo = load (file )
102- print (f"Loaded prop library: " + self .libraryInfo ["name" ])
103-
104- def getProp (self , propName , groupName ):
105- # Create the prop group if it's not already loaded
106- if not groupName in self .propGroups :
107- self .propGroups [groupName ] = {}
108-
109- # Load the prop if it's not already loaded
110- if not propName in self .propGroups [groupName ]:
111- # Find the prop group
112- groupInfo = None
113- for group in self .libraryInfo ["groups" ]:
114- if group ["name" ] == groupName :
115- groupInfo = group
116- break
117- if groupInfo == None :
118- raise RuntimeError (f"Unable to find prop group with name { groupName } in " + self .libraryInfo ["name" ])
119-
120- # Find the prop
121- propInfo = None
122- for prop in groupInfo ["props" ]:
123- if prop ["name" ] == propName :
124- propInfo = prop
125- break
126- if propInfo == None :
127- raise RuntimeError (f"Unable to find prop with name { propName } in { groupName } from " + self .libraryInfo ["name" ])
128-
129- # Create the prop
130- prop = Prop ()
131- meshInfo = propInfo ["mesh" ]
132- spriteInfo = propInfo ["sprite" ]
133- if meshInfo != None :
134- modelPath = f"{ self .directory } /" + meshInfo ["file" ]
135- prop .loadModel (modelPath )
136- elif spriteInfo != None :
137- prop .loadSprite (propInfo )
138- else :
139- #XXX: Uhhhhhh, empty prop?
140- pass
141- self .propGroups [groupName ][propName ] = prop
142-
143- return self .propGroups [groupName ][propName ]
144-
145- def getTexture (self , textureName ):
146- im = load_image (textureName , self .directory )
147- return im
148-
14935class BattleMapBlenderImporter :
15036 # Allows subsequent map loads to be faster
15137 libraryCache = {}
@@ -170,12 +56,16 @@ def importData(self):
17056 ma = self .createBlenderMaterial (materialData )
17157 self .materials [materialData .ID ] = ma
17258
59+ # Static geometry
17360 propObjects = []
17461 if self .import_static_geom :
17562 # Load props
17663 for propData in self .mapData .staticGeometry :
17764 ob = self .getBlenderProp (propData )
17865 propObjects .append (ob )
66+ print (f"Loaded { len (propObjects )} prop objects" )
67+
68+ # Collision geometry
17969 collisionObjects = []
18070 if self .import_collision_geom :
18171 # Load collision meshes
@@ -189,21 +79,25 @@ def importData(self):
18979 collisionObjects += collisionTriangleObjects
19080 collisionObjects += collisionPlaneObjects
19181 collisionObjects += collisionBoxObjects
82+ print (f"Loaded { len (collisionObjects )} collision objects" )
83+
84+ # Spawn points
19285 spawnPointObjects = []
19386 if self .import_spawn_points :
19487 # Create spawn points
19588 for spawnPointData in self .mapData .spawnPoints :
19689 ob = self .createBlenderSpawnPoint (spawnPointData )
19790 spawnPointObjects .append (ob )
91+ print (f"Loaded { len (spawnPointObjects )} spawn points" )
19892
19993 # Create container object to store all our objects
20094 objects = propObjects + collisionObjects + spawnPointObjects
20195 mapOB = bpy .data .objects .new ("BattleMap" , None )
202- mapOB .empty_display_size = 100
96+ mapOB .empty_display_size = 100 # Alternativa use a x100 scale
20397 mapOB .scale = (self .map_scale_factor , self .map_scale_factor , self .map_scale_factor )
20498 objects .append (mapOB )
20599
206- # Create empty objects to house each type of object
100+ # Create empty objects to group each type of object
207101 if self .import_static_geom :
208102 groupOB = bpy .data .objects .new ("StaticGeometry" , None )
209103 groupOB .parent = mapOB
@@ -223,6 +117,7 @@ def importData(self):
223117 for ob in spawnPointObjects :
224118 ob .parent = groupOB
225119
120+ # Lighting data
226121 if self .import_lightmapdata :
227122 # Create a sun light object
228123 li = bpy .data .lights .new ("DirectionalLight" , "SUN" )
@@ -252,14 +147,15 @@ def getPropLibrary(self, libraryName):
252147 # First check if we've already loaded the required prop library
253148 if not libraryName in self .libraryCache :
254149 # Load the proplib
255- libraryPath = f"{ self .propLibrarySourcePath } /{ libraryName } " # XXX: Get platform agnostic way of doing this
150+ libraryPath = f"{ self .propLibrarySourcePath } /{ libraryName } "
256151 library = PropLibrary (libraryPath )
257152 self .libraryCache [libraryName ] = library
258153
259154 return self .libraryCache [libraryName ]
260155
261156 def tryLoadTexture (self , textureName , libraryName ):
262157 if libraryName == None :
158+ # For some reason Remaster proplib is alwaus marked as None? This is not true for the ny2024 remaster prop lib though
263159 libraryName = "Remaster"
264160
265161 propLibrary = self .getPropLibrary (libraryName )
@@ -302,6 +198,7 @@ def getBlenderProp(self, propData):
302198 # Material
303199 ma = self .materials [propData .materialID ]
304200 if len (propOB .data .materials ) != 0 :
201+ # Create a duplicate mesh object if it needs a different material, XXX: could probably cache these to reuse datablocks
305202 if propOB .data .materials [0 ] != ma :
306203 propOB .data = propOB .data .copy ()
307204 propOB .data .materials [0 ] = ma
@@ -430,4 +327,118 @@ def createBlenderMaterial(self, materialData):
430327 else :
431328 pass # Unknown shader
432329
433- return ma
330+ return ma
331+
332+ class PropLibrary :
333+ propGroups = {}
334+ def __init__ (self , directory ):
335+ self .directory = directory
336+ self .libraryInfo = {}
337+
338+ # Load library info
339+ with open (f"{ self .directory } /library.json" , "r" ) as file : self .libraryInfo = load (file )
340+ print (f"Loaded prop library: " + self .libraryInfo ["name" ])
341+
342+ def getProp (self , propName , groupName ):
343+ # Create the prop group if it's not already loaded
344+ if not groupName in self .propGroups :
345+ self .propGroups [groupName ] = {}
346+
347+ # Load the prop if it's not already loaded
348+ if not propName in self .propGroups [groupName ]:
349+ # Find the prop group
350+ groupInfo = None
351+ for group in self .libraryInfo ["groups" ]:
352+ if group ["name" ] == groupName :
353+ groupInfo = group
354+ break
355+ if groupInfo == None :
356+ raise RuntimeError (f"Unable to find prop group with name { groupName } in " + self .libraryInfo ["name" ])
357+
358+ # Find the prop
359+ propInfo = None
360+ for prop in groupInfo ["props" ]:
361+ if prop ["name" ] == propName :
362+ propInfo = prop
363+ break
364+ if propInfo == None :
365+ raise RuntimeError (f"Unable to find prop with name { propName } in { groupName } from " + self .libraryInfo ["name" ])
366+
367+ # Create the prop
368+ prop = Prop ()
369+ meshInfo = propInfo ["mesh" ]
370+ spriteInfo = propInfo ["sprite" ]
371+ if meshInfo != None :
372+ modelPath = f"{ self .directory } /" + meshInfo ["file" ]
373+ prop .loadModel (modelPath )
374+ elif spriteInfo != None :
375+ prop .loadSprite (propInfo )
376+ else :
377+ #XXX: Uhhhhhh, empty prop?
378+ pass
379+ self .propGroups [groupName ][propName ] = prop
380+
381+ return self .propGroups [groupName ][propName ]
382+
383+ def getTexture (self , textureName ):
384+ im = load_image (textureName , self .directory )
385+ return im
386+
387+ class Prop :
388+ def __init__ (self ):
389+ self .objects = []
390+ self .mainObject = None
391+
392+ def loadModel (self , modelPath ):
393+ fileExtension = modelPath .split ("." )[- 1 ]
394+ if fileExtension == "a3d" :
395+ modelData = A3D ()
396+ with open (modelPath , "rb" ) as file : modelData .read (file )
397+
398+ # Import the model
399+ modelImporter = A3DBlenderImporter (modelData , None , reset_empty_transform = False , try_import_textures = False )
400+ self .objects = modelImporter .importData ()
401+ elif fileExtension == "3ds" :
402+ bpy .ops .import_scene .max3ds (filepath = modelPath , use_apply_transform = False )
403+ for ob in bpy .context .selectable_objects :
404+ # The imported objects are added to the active collection, remove them
405+ bpy .context .collection .objects .unlink (ob )
406+
407+ # Correct the origin XXX: this does not work for all cases, investigate more
408+ ob .animation_data_clear ()
409+ x , y , z = - ob .location .x , - ob .location .y , - ob .location .z
410+ objectOrigin = Matrix .Translation ((x , y , z ))
411+ ob .data .transform (objectOrigin )
412+ ob .location = (0.0 , 0.0 , 0.0 )
413+
414+ self .objects .append (ob )
415+ else :
416+ raise RuntimeError (f"Unknown model file extension: { fileExtension } " )
417+
418+ # Identify the main parent object
419+ for ob in self .objects :
420+ if ob .parent == None : self .mainObject = ob
421+ if self .mainObject == None :
422+ raise RuntimeError (f"Unable to find the parent object for: { modelPath } " )
423+
424+ def loadSprite (self , propInfo ):
425+ spriteInfo = propInfo ["sprite" ]
426+
427+ # Create a plane we can use for the sprite
428+ me = bpy .data .meshes .new (propInfo ["name" ])
429+
430+ # bm = bmesh.new()
431+ # bmesh.ops.create_grid(bm, x_segments=1, y_segments=1, size=spriteInfo["scale"]*100)
432+ # bm.to_mesh(me)
433+ # bm.free()
434+
435+ ob = bpy .data .objects .new (me .name , me )
436+
437+ # Assign data
438+ ob .scale = (spriteInfo ["width" ], 1.0 , spriteInfo ["height" ]) #XXX: this should involve spriteInfo["scale"] probably?
439+ spriteOrigin = Matrix .Translation ((0.0 , spriteInfo ["originY" ], 0.0 ))
440+ me .transform (spriteOrigin )
441+
442+ # Finalise
443+ self .objects .append (ob )
444+ self .mainObject = ob
0 commit comments