mirror of
https://github.com/MapMakersAndProgrammers/io_scene_a3d.git
synced 2025-10-25 17:39:10 -07:00
Initial, broken, support for legacy maps
This commit is contained in:
@@ -274,7 +274,7 @@ class Prop:
|
||||
self.position = (0.0, 0.0, 0.0)
|
||||
|
||||
# Optional
|
||||
self.groupName = ""
|
||||
self.groupName = None
|
||||
self.rotation = (0.0, 0.0, 0.0)
|
||||
self.scale = (1.0, 1.0, 1.0)
|
||||
|
||||
|
||||
@@ -26,48 +26,122 @@ import bpy
|
||||
from bpy_extras.image_utils import load_image
|
||||
from bpy_extras.node_shader_utils import PrincipledBSDFWrapper
|
||||
import bmesh
|
||||
from mathutils import Matrix
|
||||
|
||||
from .A3D import A3D
|
||||
from .A3DBlenderImporter import A3DBlenderImporter
|
||||
from .BlenderMaterialUtils import addImageTextureToMaterial
|
||||
|
||||
class PropLibrary:
|
||||
propCache = {}
|
||||
class Prop:
|
||||
def __init__(self):
|
||||
self.objects = []
|
||||
self.mainObject = None
|
||||
|
||||
def loadModel(self, modelPath):
|
||||
fileExtension = modelPath.split(".")[-1]
|
||||
if fileExtension == "a3d":
|
||||
modelData = A3D()
|
||||
with open(modelPath, "rb") as file: modelData.read(file)
|
||||
|
||||
# Import the model
|
||||
modelImporter = A3DBlenderImporter(modelData, None, reset_empty_transform=False, try_import_textures=False)
|
||||
self.objects = modelImporter.importData()
|
||||
elif fileExtension == "3ds":
|
||||
bpy.ops.import_scene.max3ds(filepath=modelPath, use_apply_transform=False)
|
||||
for ob in bpy.context.selectable_objects:
|
||||
# The imported objects are added to the active collection, remove them
|
||||
bpy.context.collection.objects.unlink(ob)
|
||||
|
||||
# Correct the origin XXX: this does not work for all cases, investigate more
|
||||
ob.animation_data_clear()
|
||||
x, y, z = -ob.location.x, -ob.location.y, -ob.location.z
|
||||
objectOrigin = Matrix.Translation((x, y, z))
|
||||
ob.data.transform(objectOrigin)
|
||||
ob.location = (0.0, 0.0, 0.0)
|
||||
|
||||
self.objects.append(ob)
|
||||
else:
|
||||
raise RuntimeError(f"Unknown model file extension: {fileExtension}")
|
||||
|
||||
# Identify the main parent object
|
||||
for ob in self.objects:
|
||||
if ob.parent == None: self.mainObject = ob
|
||||
if self.mainObject == None:
|
||||
raise RuntimeError(f"Unable to find the parent object for: {modelPath}")
|
||||
|
||||
def loadSprite(self, propInfo):
|
||||
spriteInfo = propInfo["sprite"]
|
||||
|
||||
# Create a plane we can use for the sprite
|
||||
me = bpy.data.meshes.new(propInfo["name"])
|
||||
|
||||
bm = bmesh.new()
|
||||
bmesh.ops.create_grid(bm, x_segments=1, y_segments=1, size=spriteInfo["scale"]*100)
|
||||
bm.to_mesh(me)
|
||||
bm.free()
|
||||
|
||||
ob = bpy.data.objects.new(me.name, me)
|
||||
|
||||
# Assign data
|
||||
ob.scale = (spriteInfo["width"], 1.0, spriteInfo["height"]) #XXX: this should involve spriteInfo["scale"] probably?
|
||||
spriteOrigin = Matrix.Translation((0.0, spriteInfo["originY"], 0.0))
|
||||
me.transform(spriteOrigin)
|
||||
|
||||
# Finalise
|
||||
self.objects.append(ob)
|
||||
self.mainObject = ob
|
||||
|
||||
class PropLibrary:
|
||||
propGroups = {}
|
||||
def __init__(self, directory):
|
||||
self.directory = directory
|
||||
|
||||
# Load library json
|
||||
self.libraryInfo = {}
|
||||
with open(f"{self.directory}/library.json", "r") as file: # XXX: Get platform agnostic way of doing this
|
||||
self.libraryInfo = load(file)
|
||||
|
||||
print(f"Loaded prop library: {self.libraryInfo["name"]}")
|
||||
|
||||
def getProp(self, name, groupName):
|
||||
# XXX: Handle group names, this code can only load from the remaster libs
|
||||
# Check if the prop is cached
|
||||
if not name in self.propCache:
|
||||
# Get the prop's info
|
||||
propGroupInfo = self.libraryInfo["groups"][0]
|
||||
propInfo = {}
|
||||
for propInfo in propGroupInfo["props"]:
|
||||
if propInfo["name"] == name: break
|
||||
|
||||
# Load the prop
|
||||
modelFilePath = f"{self.directory}/{propInfo['mesh']['file']}" # XXX: Get platform agnostic way of doing this
|
||||
modelData = A3D()
|
||||
with open(modelFilePath, "rb") as file:
|
||||
modelData.read(file)
|
||||
|
||||
# Import into blender
|
||||
modelImporter = A3DBlenderImporter(modelData, self.directory, try_import_textures=False)
|
||||
ob, = modelImporter.importData()
|
||||
|
||||
self.propCache[name] = ob
|
||||
# Load library info
|
||||
with open(f"{self.directory}/library.json", "r") as file: self.libraryInfo = load(file)
|
||||
print(f"Loaded prop library: " + self.libraryInfo["name"])
|
||||
|
||||
def getProp(self, propName, groupName):
|
||||
# Create the prop group if it's not already loaded
|
||||
if not groupName in self.propGroups:
|
||||
self.propGroups[groupName] = {}
|
||||
|
||||
return self.propCache[name]
|
||||
|
||||
# Load the prop if it's not already loaded
|
||||
if not propName in self.propGroups[groupName]:
|
||||
# Find the prop group
|
||||
groupInfo = None
|
||||
for group in self.libraryInfo["groups"]:
|
||||
if group["name"] == groupName:
|
||||
groupInfo = group
|
||||
break
|
||||
if groupInfo == None:
|
||||
raise RuntimeError(f"Unable to find prop group with name {groupName} in " + self.libraryInfo["name"])
|
||||
|
||||
# Find the prop
|
||||
propInfo = None
|
||||
for prop in groupInfo["props"]:
|
||||
if prop["name"] == propName:
|
||||
propInfo = prop
|
||||
break
|
||||
if propInfo == None:
|
||||
raise RuntimeError(f"Unable to find prop with name {propName} in {groupName} from " + self.libraryInfo["name"])
|
||||
|
||||
# Create the prop
|
||||
prop = Prop()
|
||||
meshInfo = propInfo["mesh"]
|
||||
spriteInfo = propInfo["sprite"]
|
||||
if meshInfo != None:
|
||||
modelPath = f"{self.directory}/" + meshInfo["file"]
|
||||
prop.loadModel(modelPath)
|
||||
elif spriteInfo != None:
|
||||
prop.loadSprite(propInfo)
|
||||
else:
|
||||
#XXX: Uhhhhhh, empty prop?
|
||||
pass
|
||||
self.propGroups[groupName][propName] = prop
|
||||
|
||||
return self.propGroups[groupName][propName]
|
||||
|
||||
def getTexture(self, textureName):
|
||||
im = load_image(textureName, self.directory)
|
||||
return im
|
||||
@@ -149,14 +223,22 @@ class BattleMapBlenderImporter:
|
||||
|
||||
return self.libraryCache[libraryName]
|
||||
|
||||
def tryLoadTexture(self, textureName, libraryName):
|
||||
if libraryName == None:
|
||||
libraryName = "Remaster"
|
||||
|
||||
propLibrary = self.getPropLibrary(libraryName)
|
||||
texture = propLibrary.getTexture(f"{textureName}.webp")
|
||||
return texture
|
||||
|
||||
'''
|
||||
Blender data builders
|
||||
'''
|
||||
def getBlenderProp(self, propData):
|
||||
# Load prop
|
||||
propLibrary = self.getPropLibrary(propData.libraryName)
|
||||
propOB = propLibrary.getProp(propData.name, propData.groupName)
|
||||
propOB = propOB.copy() # We want to use a copy of the prop object
|
||||
prop = propLibrary.getProp(propData.name, propData.groupName)
|
||||
propOB = prop.mainObject.copy() # We want to use a copy of the prop object
|
||||
|
||||
# Assign data
|
||||
propOB.name = f"{propData.name}_{propData.ID}"
|
||||
@@ -167,7 +249,8 @@ class BattleMapBlenderImporter:
|
||||
|
||||
# Material
|
||||
ma = self.materials[propData.materialID]
|
||||
propOB.data.materials[0] = ma
|
||||
if len(propOB.data.materials) != 0:
|
||||
propOB.data.materials[0] = ma
|
||||
|
||||
return propOB
|
||||
|
||||
@@ -264,15 +347,14 @@ class BattleMapBlenderImporter:
|
||||
ma = bpy.data.materials.new(f"{materialData.ID}_{materialData.name}")
|
||||
|
||||
# Shader specific logic
|
||||
if materialData.shader == "TankiOnline/SingleTextureShader":
|
||||
if materialData.shader == "TankiOnline/SingleTextureShader" or materialData.shader == "TankiOnline/SingleTextureShaderWinter":
|
||||
bsdf = PrincipledBSDFWrapper(ma, is_readonly=False, use_nodes=True)
|
||||
bsdf.roughness_set(1.0)
|
||||
bsdf.ior_set(1.0)
|
||||
|
||||
# Try load texture
|
||||
textureParameter = materialData.textureParameters[0]
|
||||
propLibrary = self.getPropLibrary("Remaster")
|
||||
texture = propLibrary.getTexture(f"{textureParameter.textureName}.webp")
|
||||
texture = self.tryLoadTexture(textureParameter.textureName, textureParameter.libraryName)
|
||||
|
||||
addImageTextureToMaterial(texture, ma.node_tree)
|
||||
elif materialData.shader == "TankiOnline/SpriteShader":
|
||||
@@ -282,8 +364,7 @@ class BattleMapBlenderImporter:
|
||||
|
||||
# Try load texture
|
||||
textureParameter = materialData.textureParameters[0]
|
||||
propLibrary = self.getPropLibrary("Remaster")
|
||||
texture = propLibrary.getTexture(f"{textureParameter.textureName}.webp")
|
||||
texture = self.tryLoadTexture(textureParameter.textureName, textureParameter.libraryName)
|
||||
|
||||
addImageTextureToMaterial(texture, ma.node_tree, linkAlpha=True)
|
||||
elif materialData.shader == "TankiOnline/Terrain":
|
||||
@@ -292,5 +373,7 @@ class BattleMapBlenderImporter:
|
||||
bsdf.roughness_set(1.0)
|
||||
bsdf.ior_set(1.0)
|
||||
bsdf.base_color_set((0.0, 0.0, 0.0))
|
||||
else:
|
||||
pass # Unknown shader
|
||||
|
||||
return ma
|
||||
Reference in New Issue
Block a user