mirror of
https://github.com/MapMakersAndProgrammers/io_scene_a3d.git
synced 2025-10-26 01:49:13 -07:00
Initial blender importing
This commit is contained in:
@@ -203,7 +203,7 @@ class A3D:
|
|||||||
# Read and assign transform ids
|
# Read and assign transform ids
|
||||||
for transformI in range(transformCount):
|
for transformI in range(transformCount):
|
||||||
transformID, = unpackStream("<I", stream)
|
transformID, = unpackStream("<I", stream)
|
||||||
self.transforms[transformID] = transforms[transformI]
|
self.transforms[transformI] = transforms[transformI] #XXX: The IDs seem to be incorrect and instead map to index?
|
||||||
|
|
||||||
# Padding
|
# Padding
|
||||||
padding = calculatePadding(length)
|
padding = calculatePadding(length)
|
||||||
|
|||||||
@@ -135,7 +135,8 @@ class A3DSubmesh:
|
|||||||
self.indexCount = 0
|
self.indexCount = 0
|
||||||
|
|
||||||
def read2(self, stream):
|
def read2(self, stream):
|
||||||
self.indexCount, = unpackStream("<I", stream)*3
|
self.indexCount, = unpackStream("<I", stream) # This is just the face count so multiply it by 3
|
||||||
|
self.indexCount *= 3
|
||||||
self.indices = list(unpackStream(f"<{self.indexCount}H", stream))
|
self.indices = list(unpackStream(f"<{self.indexCount}H", stream))
|
||||||
self.smoothingGroups = list(unpackStream(f"<{self.indexCount//3}I", stream))
|
self.smoothingGroups = list(unpackStream(f"<{self.indexCount//3}I", stream))
|
||||||
self.materialID, = unpackStream("<H", stream)
|
self.materialID, = unpackStream("<H", stream)
|
||||||
@@ -195,7 +196,7 @@ class A3DObject:
|
|||||||
|
|
||||||
# Read material IDs
|
# Read material IDs
|
||||||
for _ in range(self.materialCount):
|
for _ in range(self.materialCount):
|
||||||
materialID, = unpackStream("<I", stream)
|
materialID, = unpackStream("<i", stream)
|
||||||
self.materialIDs.append(materialID)
|
self.materialIDs.append(materialID)
|
||||||
|
|
||||||
print(f"[A3DObject name: {self.name} meshID: {self.meshID} transformID: {self.transformID} materialIDs: {len(self.materialIDs)}]")
|
print(f"[A3DObject name: {self.name} meshID: {self.meshID} transformID: {self.transformID} materialIDs: {len(self.materialIDs)}]")
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
import bmesh
|
||||||
|
import bpy
|
||||||
|
from bpy.types import Operator
|
||||||
|
from bpy.props import StringProperty, BoolProperty
|
||||||
|
from bpy_extras.io_utils import ImportHelper
|
||||||
|
from bpy_extras.node_shader_utils import PrincipledBSDFWrapper
|
||||||
|
|
||||||
|
from .A3D import A3D
|
||||||
|
from .A3DObjects import (
|
||||||
|
A3D_VERTEXTYPE_COORDINATE,
|
||||||
|
A3D_VERTEXTYPE_UV1,
|
||||||
|
A3D_VERTEXTYPE_NORMAL1,
|
||||||
|
A3D_VERTEXTYPE_UV2,
|
||||||
|
A3D_VERTEXTYPE_COLOR,
|
||||||
|
A3D_VERTEXTYPE_NORMAL2
|
||||||
|
)
|
||||||
|
|
||||||
|
'''
|
||||||
|
Operators
|
||||||
|
'''
|
||||||
|
class ImportA3D(Operator, ImportHelper):
|
||||||
|
bl_idname = "import_scene.alternativa"
|
||||||
|
bl_label = "Import A3D"
|
||||||
|
bl_description = "Import an A3D model"
|
||||||
|
|
||||||
|
filter_glob: StringProperty(default="*.a3d", options={'HIDDEN'})
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
return ImportHelper.invoke(self, context, event)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
filepath = self.filepath
|
||||||
|
|
||||||
|
# Read the file
|
||||||
|
print(f"Reading A3D data from {filepath}")
|
||||||
|
modelData = A3D()
|
||||||
|
with open(filepath, "rb") as file:
|
||||||
|
modelData.read(file)
|
||||||
|
|
||||||
|
# Import data into blender
|
||||||
|
print("Importing mesh data into blender")
|
||||||
|
# Create materials
|
||||||
|
materials = []
|
||||||
|
for material in modelData.materials:
|
||||||
|
ma = bpy.data.materials.new(material.name)
|
||||||
|
maWrapper = PrincipledBSDFWrapper(ma, is_readonly=False, use_nodes=True)
|
||||||
|
maWrapper.base_color = material.color
|
||||||
|
maWrapper.roughness = 1.0
|
||||||
|
|
||||||
|
materials.append(ma)
|
||||||
|
# Build meshes
|
||||||
|
meshes = []
|
||||||
|
for mesh in modelData.meshes:
|
||||||
|
me = bpy.data.meshes.new(mesh.name)
|
||||||
|
|
||||||
|
# Gather all vertex data
|
||||||
|
coordinates = []
|
||||||
|
uv1 = []
|
||||||
|
normal1 = []
|
||||||
|
uv2 = []
|
||||||
|
colors = []
|
||||||
|
normal2 = []
|
||||||
|
for vertexBuffer in mesh.vertexBuffers:
|
||||||
|
if vertexBuffer.bufferType == A3D_VERTEXTYPE_COORDINATE:
|
||||||
|
coordinates += vertexBuffer.data
|
||||||
|
elif vertexBuffer.bufferType == A3D_VERTEXTYPE_UV1:
|
||||||
|
uv1 += vertexBuffer.data
|
||||||
|
elif vertexBuffer.bufferType == A3D_VERTEXTYPE_NORMAL1:
|
||||||
|
normal1 += vertexBuffer.data
|
||||||
|
elif vertexBuffer.bufferType == A3D_VERTEXTYPE_UV2:
|
||||||
|
uv2 += vertexBuffer.data
|
||||||
|
elif vertexBuffer.bufferType == A3D_VERTEXTYPE_COLOR:
|
||||||
|
colors += vertexBuffer.data
|
||||||
|
elif vertexBuffer.bufferType == A3D_VERTEXTYPE_NORMAL2:
|
||||||
|
normal2 += vertexBuffer.data
|
||||||
|
|
||||||
|
# Add blender vertices
|
||||||
|
blenderVertexIndices = []
|
||||||
|
blenderVertices = []
|
||||||
|
blenderUV1s = []
|
||||||
|
blenderUV2s = []
|
||||||
|
for submesh in mesh.submeshes:
|
||||||
|
polygonCount = len(submesh.indices) // 3
|
||||||
|
me.vertices.add(polygonCount*3)
|
||||||
|
me.loops.add(polygonCount*3)
|
||||||
|
me.polygons.add(polygonCount)
|
||||||
|
|
||||||
|
for indexI in range(submesh.indexCount):
|
||||||
|
index = submesh.indices[indexI]
|
||||||
|
blenderVertexIndices.append(indexI)
|
||||||
|
blenderVertices += list(coordinates[index])
|
||||||
|
blenderUV1s.append(uv1[index])
|
||||||
|
#blenderUV2s += uv2[index]
|
||||||
|
me.vertices.foreach_set("co", blenderVertices)
|
||||||
|
me.polygons.foreach_set("loop_start", range(0, len(blenderVertices)//3, 3))
|
||||||
|
me.loops.foreach_set("vertex_index", blenderVertexIndices)
|
||||||
|
|
||||||
|
# UVs
|
||||||
|
if len(uv1) != 0:
|
||||||
|
uvData = me.uv_layers.new(name="UV1").data
|
||||||
|
for polygonI, po in enumerate(me.polygons):
|
||||||
|
indexI = polygonI * 3
|
||||||
|
uvData[po.loop_start].uv = blenderUV1s[blenderVertexIndices[indexI]]
|
||||||
|
uvData[po.loop_start+1].uv = blenderUV1s[blenderVertexIndices[indexI+1]]
|
||||||
|
uvData[po.loop_start+2].uv = blenderUV1s[blenderVertexIndices[indexI+2]]
|
||||||
|
|
||||||
|
# Apply materials (version 2)
|
||||||
|
faceIndexBase = 0
|
||||||
|
for submeshI, submesh in enumerate(mesh.submeshes):
|
||||||
|
if submesh.materialID == None:
|
||||||
|
continue
|
||||||
|
me.materials.append(materials[submesh.materialID])
|
||||||
|
for faceI in range(submesh.indexCount//3):
|
||||||
|
me.polygons[faceI+faceIndexBase].material_index = submeshI
|
||||||
|
faceIndexBase += submesh.indexCount//3
|
||||||
|
|
||||||
|
# Finalise
|
||||||
|
me.validate()
|
||||||
|
me.update()
|
||||||
|
meshes.append(me)
|
||||||
|
# Create objects
|
||||||
|
for objec in modelData.objects:
|
||||||
|
me = meshes[objec.meshID]
|
||||||
|
mesh = modelData.meshes[objec.meshID]
|
||||||
|
transform = modelData.transforms[objec.transformID]
|
||||||
|
|
||||||
|
# Select a name for the blender object
|
||||||
|
name = ""
|
||||||
|
if objec.name != "":
|
||||||
|
name = objec.name
|
||||||
|
elif mesh.name != "":
|
||||||
|
name = mesh.name
|
||||||
|
else:
|
||||||
|
name = transform.name
|
||||||
|
|
||||||
|
# Create the object
|
||||||
|
ob = bpy.data.objects.new(name, me)
|
||||||
|
bpy.context.collection.objects.link(ob)
|
||||||
|
|
||||||
|
# Set transform
|
||||||
|
ob.location = transform.position
|
||||||
|
ob.scale = transform.scale
|
||||||
|
ob.rotation_mode = "QUATERNION"
|
||||||
|
x, y, z, w = transform.rotation
|
||||||
|
ob.rotation_quaternion = (w, x, y, z)
|
||||||
|
|
||||||
|
# Apply materials (version 3)
|
||||||
|
for materialID in objec.materialIDs:
|
||||||
|
print(materialID)
|
||||||
|
if materialID == -1:
|
||||||
|
continue
|
||||||
|
me.materials.append(materials[materialID])
|
||||||
|
# Set the default material to the first one we added
|
||||||
|
for polygon in me.polygons:
|
||||||
|
polygon.material_index = 0
|
||||||
|
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
'''
|
||||||
|
Menu
|
||||||
|
'''
|
||||||
|
def menu_func_import_a3d(self, context):
|
||||||
|
self.layout.operator(ImportA3D.bl_idname, text="Alternativa3D HTML5 (.a3d)")
|
||||||
|
|
||||||
|
'''
|
||||||
|
Registration
|
||||||
|
'''
|
||||||
|
classes = [
|
||||||
|
ImportA3D
|
||||||
|
]
|
||||||
|
|
||||||
|
def register():
|
||||||
|
for c in classes:
|
||||||
|
bpy.utils.register_class(c)
|
||||||
|
bpy.types.TOPBAR_MT_file_import.append(menu_func_import_a3d)
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
for c in classes:
|
||||||
|
bpy.utils.unregister_class(c)
|
||||||
|
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import_a3d)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
register()
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
from sys import argv
|
|
||||||
from .A3D import A3D
|
|
||||||
|
|
||||||
with open(argv[1], "rb") as f:
|
|
||||||
model = A3D()
|
|
||||||
model.read(f)
|
|
||||||
Reference in New Issue
Block a user