mirror of
https://github.com/MapMakersAndProgrammers/io_scene_a3d.git
synced 2025-10-26 01:49:13 -07:00
Initial version 3 export support
This commit is contained in:
@@ -139,7 +139,19 @@ class A3D:
|
||||
stream.read(padding)
|
||||
|
||||
def writeRootBlock3(self, stream):
|
||||
raise RuntimeError("Version 3 files are not supported yet")
|
||||
buffer = BytesIO()
|
||||
|
||||
# Write data to the buffer
|
||||
print("Writing root block")
|
||||
self.writeMaterialBlock3(buffer)
|
||||
self.writeMeshBlock3(buffer)
|
||||
self.writeTransformBlock3(buffer)
|
||||
self.writeObjectBlock3(buffer)
|
||||
|
||||
# Write buffer to stream
|
||||
packStream("<2I", stream, A3D_ROOTBLOCK_SIGNATURE, buffer.tell())
|
||||
buffer.seek(0, 0)
|
||||
stream.write(buffer.read())
|
||||
|
||||
'''
|
||||
Material data blocks
|
||||
@@ -188,6 +200,24 @@ class A3D:
|
||||
padding = calculatePadding(length)
|
||||
stream.read(padding)
|
||||
|
||||
def writeMaterialBlock3(self, stream):
|
||||
buffer = BytesIO()
|
||||
|
||||
# Write data to the buffer
|
||||
print("Writing material block")
|
||||
packStream("<I", buffer, len(self.materials))
|
||||
for material in self.materials:
|
||||
material.write3(buffer)
|
||||
|
||||
# Write buffer to stream
|
||||
packStream("<2I", stream, A3D_MATERIALBLOCK_SIGNATURE, buffer.tell())
|
||||
buffer.seek(0, 0)
|
||||
stream.write(buffer.read())
|
||||
|
||||
# Padding
|
||||
paddingSize = calculatePadding(buffer.tell())
|
||||
stream.write(b"\x00" * paddingSize)
|
||||
|
||||
'''
|
||||
Mesh data blocks
|
||||
'''
|
||||
@@ -235,6 +265,24 @@ class A3D:
|
||||
padding = calculatePadding(length)
|
||||
stream.read(padding)
|
||||
|
||||
def writeMeshBlock3(self, stream):
|
||||
buffer = BytesIO()
|
||||
|
||||
# Write data to the buffer
|
||||
print("Writing mesh block")
|
||||
packStream("<I", buffer, len(self.meshes))
|
||||
for mesh in self.meshes:
|
||||
mesh.write3(buffer)
|
||||
|
||||
# Write buffer to stream
|
||||
packStream("<2I", stream, A3D_MESHBLOCK_SIGNATURE, buffer.tell())
|
||||
buffer.seek(0, 0)
|
||||
stream.write(buffer.read())
|
||||
|
||||
# Padding
|
||||
paddingSize = calculatePadding(buffer.tell())
|
||||
stream.write(b"\x00" * paddingSize)
|
||||
|
||||
'''
|
||||
Transform data blocks
|
||||
'''
|
||||
@@ -279,7 +327,6 @@ class A3D:
|
||||
|
||||
# Read data
|
||||
print(f"Reading transform block with {transformCount} transforms and length {length}")
|
||||
transforms = []
|
||||
for _ in range(transformCount):
|
||||
transform = A3DObjects.A3DTransform()
|
||||
transform.read3(stream)
|
||||
@@ -293,6 +340,26 @@ class A3D:
|
||||
padding = calculatePadding(length)
|
||||
stream.read(padding)
|
||||
|
||||
def writeTransformBlock3(self, stream):
|
||||
buffer = BytesIO()
|
||||
|
||||
# Write data to the buffer
|
||||
print("Writing transform block")
|
||||
packStream("<I", buffer, len(self.transforms))
|
||||
for transform in self.transforms:
|
||||
transform.write3(buffer)
|
||||
for parentID in self.transformParentIDs:
|
||||
packStream("<i", buffer, parentID)
|
||||
|
||||
# Write buffer to stream
|
||||
packStream("<2I", stream, A3D_TRANSFORMBLOCK_SIGNATURE, buffer.tell())
|
||||
buffer.seek(0, 0)
|
||||
stream.write(buffer.read())
|
||||
|
||||
# Padding
|
||||
paddingSize = calculatePadding(buffer.tell())
|
||||
stream.write(b"\x00" * paddingSize)
|
||||
|
||||
'''
|
||||
Object data blocks
|
||||
'''
|
||||
@@ -339,3 +406,21 @@ class A3D:
|
||||
# Padding
|
||||
padding = calculatePadding(length)
|
||||
stream.read(padding)
|
||||
|
||||
def writeObjectBlock3(self, stream):
|
||||
buffer = BytesIO()
|
||||
|
||||
# Write data to the buffer
|
||||
print("Writing object block")
|
||||
packStream("<I", buffer, len(self.objects))
|
||||
for objec in self.objects:
|
||||
objec.write3(buffer)
|
||||
|
||||
# Write buffer to stream
|
||||
packStream("<2I", stream, A3D_OBJECTBLOCK_SIGNATURE, buffer.tell())
|
||||
buffer.seek(0, 0)
|
||||
stream.write(buffer.read())
|
||||
|
||||
# Padding
|
||||
paddingSize = calculatePadding(buffer.tell())
|
||||
stream.write(b"\x00" * paddingSize)
|
||||
|
||||
@@ -31,9 +31,10 @@ from .A3DObjects import (
|
||||
)
|
||||
|
||||
class A3DBlenderExporter:
|
||||
def __init__(self, modelData, objects):
|
||||
def __init__(self, modelData, objects, version=2):
|
||||
self.modelData = modelData
|
||||
self.objects = objects
|
||||
self.version = version
|
||||
|
||||
def exportData(self):
|
||||
print("Exporting blender data to A3D")
|
||||
@@ -60,7 +61,7 @@ class A3DBlenderExporter:
|
||||
|
||||
materials[ma.name] = materialData
|
||||
# Create mesh
|
||||
mesh = self.buildA3DMesh(me)
|
||||
mesh = self.buildA3DMesh(me, ob)
|
||||
meshes.append(mesh)
|
||||
# Create transform
|
||||
transform = A3DObjects.A3DTransform()
|
||||
@@ -68,22 +69,34 @@ class A3DBlenderExporter:
|
||||
rotationW, rotationX, rotationY, rotationZ = ob.rotation_quaternion
|
||||
transform.rotation = (rotationX, rotationY, rotationZ, rotationW)
|
||||
transform.scale = ob.scale
|
||||
transform.name = ob.name
|
||||
transforms[ob.name] = transform
|
||||
# Create object
|
||||
objec = A3DObjects.A3DObject()
|
||||
objec.name = ob.name
|
||||
objec.meshID = len(meshes) - 1
|
||||
objec.transformID = len(transforms) - 1
|
||||
materialIDs = []
|
||||
for ma in me.materials:
|
||||
materialID = list(materials.keys()).index(ma.name)
|
||||
materialIDs.append(materialID)
|
||||
objec.materialCount = len(materialIDs)
|
||||
objec.materialIDs = materialIDs
|
||||
objects.append(objec)
|
||||
# Create parentIDs
|
||||
transformParentIDs = []
|
||||
for ob in self.objects:
|
||||
parentOB = ob.parent
|
||||
if (parentOB == None) or (parentOB.name not in transforms):
|
||||
transformParentIDs.append(0) #XXX: this is only for version 2
|
||||
if self.version < 3:
|
||||
transformParentIDs.append(0)
|
||||
else:
|
||||
transformParentIDs.append(-1)
|
||||
else:
|
||||
parentIndex = list(transforms.keys()).index(parentOB.name)
|
||||
transformParentIDs.append(parentIndex+1)
|
||||
if self.version < 3:
|
||||
parentIndex += 1 # Version 2 uses 0 to signify empty parent
|
||||
transformParentIDs.append(parentIndex)
|
||||
|
||||
self.modelData.materials = materials.values()
|
||||
self.modelData.meshes = meshes
|
||||
@@ -91,7 +104,7 @@ class A3DBlenderExporter:
|
||||
self.modelData.transformParentIDs = transformParentIDs
|
||||
self.modelData.objects = objects
|
||||
|
||||
def buildA3DMesh(self, me):
|
||||
def buildA3DMesh(self, me, ob):
|
||||
mesh = A3DObjects.A3DMesh()
|
||||
mesh.vertexCount = len(me.vertices)
|
||||
|
||||
@@ -137,4 +150,12 @@ class A3DBlenderExporter:
|
||||
mesh.submeshCount = len(submeshes)
|
||||
mesh.submeshes = submeshes
|
||||
|
||||
# Bound box data
|
||||
bounds = []
|
||||
for bound in ob.bound_box:
|
||||
x, y, z = bound
|
||||
bounds.append((x, y, z))
|
||||
mesh.bboxMax = max(bounds)
|
||||
mesh.bboxMin = min(bounds)
|
||||
|
||||
return mesh
|
||||
|
||||
@@ -20,7 +20,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
'''
|
||||
|
||||
from .IOTools import unpackStream, packStream, readNullTerminatedString, writeNullTerminatedString, readLengthPrefixedString, calculatePadding
|
||||
from .IOTools import unpackStream, packStream, readNullTerminatedString, writeNullTerminatedString, readLengthPrefixedString, writeLengthPrefixedString, calculatePadding
|
||||
|
||||
class A3DMaterial:
|
||||
def __init__(self):
|
||||
@@ -48,6 +48,12 @@ class A3DMaterial:
|
||||
|
||||
print(f"[A3DMaterial name: {self.name} color: {self.color} diffuse map: {self.diffuseMap}]")
|
||||
|
||||
def write3(self, stream):
|
||||
writeLengthPrefixedString(stream, self.name)
|
||||
colorR, colorG, colorB = self.color
|
||||
packStream("<3f", stream, colorR, colorG, colorB)
|
||||
writeLengthPrefixedString(stream, self.diffuseMap)
|
||||
|
||||
class A3DMesh:
|
||||
def __init__(self):
|
||||
self.name = ""
|
||||
@@ -110,6 +116,24 @@ class A3DMesh:
|
||||
|
||||
print(f"[A3DMesh name: {self.name} bbox max: {self.bboxMax} bbox min: {self.bboxMin} vertex buffers: {len(self.vertexBuffers)} submeshes: {len(self.submeshes)}]")
|
||||
|
||||
def write3(self, stream):
|
||||
writeLengthPrefixedString(stream, self.name)
|
||||
bboxMaxX, bboxMaxY, bboxMaxZ = self.bboxMax
|
||||
packStream("<3f", stream, bboxMaxX, bboxMaxY, bboxMaxZ)
|
||||
bboxMinX, bboxMinY, bboxMinZ = self.bboxMin
|
||||
packStream("<3f", stream, bboxMinX, bboxMinY, bboxMinZ)
|
||||
packStream("<f", stream, 0.0) # XXX: Unknown float value!
|
||||
|
||||
# Write vertex buffers
|
||||
packStream("<2I", stream, self.vertexCount, self.vertexBufferCount)
|
||||
for vertexBuffer in self.vertexBuffers:
|
||||
vertexBuffer.write2(stream)
|
||||
|
||||
# Write submeshes
|
||||
packStream("<I", stream, self.submeshCount)
|
||||
for submesh in self.submeshes:
|
||||
submesh.write3(stream)
|
||||
|
||||
A3D_VERTEXTYPE_COORDINATE = 1
|
||||
A3D_VERTEXTYPE_UV1 = 2
|
||||
A3D_VERTEXTYPE_NORMAL1 = 3
|
||||
@@ -179,11 +203,20 @@ class A3DSubmesh:
|
||||
self.indices = list(unpackStream(f"<{self.indexCount}H", stream))
|
||||
|
||||
# Padding
|
||||
padding = calculatePadding(self.indexCount*2) # Each index is 2 bytes
|
||||
stream.read(padding)
|
||||
paddingSize = calculatePadding(self.indexCount*2) # Each index is 2 bytes
|
||||
stream.read(paddingSize)
|
||||
|
||||
print(f"[A3DSubmesh indices: {len(self.indices)} smoothing groups: {len(self.smoothingGroups)} materialID: {self.materialID}]")
|
||||
|
||||
def write3(self, stream):
|
||||
packStream("<I", stream, self.indexCount)
|
||||
for index in self.indices:
|
||||
packStream("<H", stream, index)
|
||||
|
||||
# Padding
|
||||
paddingSize = calculatePadding(self.indexCount*2) # Each index is 2 bytes
|
||||
stream.write(b"\x00" * paddingSize)
|
||||
|
||||
class A3DTransform:
|
||||
def __init__(self):
|
||||
self.name = ""
|
||||
@@ -214,6 +247,15 @@ class A3DTransform:
|
||||
|
||||
print(f"[A3DTransform name: {self.name} position: {self.position} rotation: {self.rotation} scale: {self.scale}]")
|
||||
|
||||
def write3(self, stream):
|
||||
writeLengthPrefixedString(stream, self.name)
|
||||
positionX, positionY, positionZ = self.position
|
||||
packStream("<3f", stream, positionX, positionY, positionZ)
|
||||
rotationX, rotationY, rotationZ, rotationW = self.rotation
|
||||
packStream("<4f", stream, rotationX, rotationY, rotationZ, rotationW)
|
||||
scaleX, scaleY, scaleZ = self.scale
|
||||
packStream("<3f", stream, scaleX, scaleY, scaleZ)
|
||||
|
||||
class A3DObject:
|
||||
def __init__(self):
|
||||
self.name = ""
|
||||
@@ -242,3 +284,8 @@ class A3DObject:
|
||||
self.materialIDs.append(materialID)
|
||||
|
||||
print(f"[A3DObject name: {self.name} meshID: {self.meshID} transformID: {self.transformID} materialIDs: {len(self.materialIDs)}]")
|
||||
|
||||
def write3(self, stream):
|
||||
packStream("<3I", stream, self.meshID, self.transformID, self.materialCount)
|
||||
for materialID in self.materialIDs:
|
||||
packStream("<i", stream, materialID)
|
||||
|
||||
@@ -57,3 +57,12 @@ def readLengthPrefixedString(stream):
|
||||
stream.read(paddingSize)
|
||||
|
||||
return string.decode("utf8", errors="ignore")
|
||||
|
||||
def writeLengthPrefixedString(stream, string):
|
||||
string = string.encode("utf-8")
|
||||
|
||||
packStream("<I", stream, len(string))
|
||||
stream.write(string)
|
||||
|
||||
paddingSize = calculatePadding(len(string))
|
||||
stream.write(b"\x00" * paddingSize)
|
||||
Reference in New Issue
Block a user