1
0
Fork 0
2022-untitled-game/code/tools/blender/ajm_export/data.py

241 lines
7.8 KiB
Python

import bpy
import os
import numpy as np
from .types import *
@dataclass
class Scene:
transforms: list[Transform]
@classmethod
def collect_transforms(cls, parent, objs, out):
if len(objs) == 0:
return
for obj in objs:
if parent == "":
name = obj.name
else:
name = parent + "+" + obj.name
position = np.array([obj.location.x, obj.location.y, obj.location.z], dtype="float32")
rotation = np.array([obj.rotation_euler.x, obj.rotation_euler.y, obj.rotation_euler.z], dtype="float32")
scale = np.array([obj.scale.x, obj.scale.y, obj.scale.z], dtype="float32")
if obj.instance_type == "COLLECTION":
prefab = obj.instance_collection
# Collections flatten the hierarchy; unflatten it
components = {}
for o in prefab.objects:
components[o.name] = o
to_remove = []
for (k,v) in components.items():
for child in v.children:
if child.name in components:
to_remove.append(child.name)
for r in to_remove:
components.pop(r)
# Now we have the direct children of the prefab itself
children = []
for child in components:
child_name = name + "+" + child
children.append(child_name)
transform = Transform(name, position, rotation, scale, parent, children, Handle(0), [], obj)
out.append(transform)
cls.collect_transforms(name, components.values(), out)
else:
children = []
for child in obj.children:
child_name = name + "+" + child.name
children.append(child_name)
transform = Transform(name, position, rotation, scale, parent, children, Handle(0), [], obj)
out.append(transform)
cls.collect_transforms(name, obj.children, out)
def __init__(self):
# Load transforms in hierarchical order
transforms = [Transform()]
self.collect_transforms("Root", bpy.data.objects["Root"].children, transforms)
# Set up parent-child relationships
for transform in transforms:
if transform.parent_name != "":
for i, parent_transform in enumerate(transforms):
if transform.parent_name == parent_transform.name:
transform.parent = Handle(np.uint32(i))
break
if len(transform.children_names) > 0:
for child_name in transform.children_names:
for i, child_transform in enumerate(transforms):
if child_name == child_transform.name:
transform.children.append(Handle(np.uint32(i)))
break
self.transforms = transforms
@dataclass
class Data1:
cameras: list[Camera]
materials: list[Material]
meshes: list[Mesh]
renderables: list[Renderable]
box_colliders: list[BoxCollider]
point_lights: list[PointLight]
def __init__(self, scene):
materials = [Material()]
for material in bpy.data.materials:
if material.name == "Dots Stroke":
continue
materials.append(Material.load(material))
meshes = [Mesh()]
for mesh in bpy.data.meshes:
meshes.append(Mesh.load(mesh))
renderables = [Renderable()]
box_colliders = [BoxCollider()]
point_lights = [PointLight()]
cameras = [Camera()]
for (i,transform) in enumerate(scene.transforms):
if transform.name == "NULL":
continue;
obj = transform.obj
if obj.ajm_type.box_collider:
box_colliders.append(BoxCollider.load(obj, i))
if obj.ajm_type.camera:
cameras.append(Camera.load(obj, i))
if obj.ajm_type.point_light:
point_lights.append(PointLight.load(obj, i))
if obj.ajm_type.renderable:
renderables.append(Renderable.load(obj, meshes, materials, i))
self.cameras = cameras
self.materials = materials
self.meshes = meshes
self.transforms = scene.transforms
self.renderables = renderables
self.box_colliders = box_colliders
self.point_lights = point_lights
def serialize(self, path):
fp = open(path, "wb")
fp.write("AJM\0".encode('UTF-8'))
# Transforms
print("Transforms: " + str(len(self.transforms)-1))
transform_count = np.uint16(len(self.transforms))
fp.write(transform_count.tobytes())
for transform in self.transforms:
transform.serialize(fp)
# Meshes
print("Meshes: " + str(len(self.meshes)-1))
mesh_count = np.uint16(len(self.meshes))
fp.write(mesh_count.tobytes())
for mesh in self.meshes:
mesh.serialize(fp)
# Materials
print("Materials: " + str(len(self.materials)-1))
material_count = np.uint16(len(self.materials))
fp.write(material_count.tobytes())
for material in self.materials:
material.serialize(fp)
# Cameras
print("Cameras: " + str(len(self.cameras)-1))
camera_count = np.uint16(len(self.cameras))
fp.write(camera_count.tobytes())
for camera in self.cameras:
camera.serialize(fp)
# Renderables
print("Renderables: " + str(len(self.renderables)-1))
renderable_count = np.uint16(len(self.renderables))
fp.write(renderable_count.tobytes())
for renderable in self.renderables:
renderable.serialize(fp)
# Box Colliders
print("Box Colliders: " + str(len(self.box_colliders)-1))
box_collider_count = np.uint16(len(self.box_colliders))
fp.write(box_collider_count.tobytes())
for box_collider in self.box_colliders:
box_collider.serialize(fp)
# Point Lights
print("Point Lights: " + str(len(self.point_lights)-1))
point_light_count = np.uint16(len(self.point_lights))
fp.write(point_light_count.tobytes())
for point_light in self.point_lights:
point_light.serialize(fp)
fp.close()
@dataclass
class Data2:
sounds: list[Sound]
audio_sources: list[AudioSource]
def __init__(self, scene):
sounds = [Sound()]
audio_sources = [AudioSource()]
for (i,transform) in enumerate(scene.transforms):
if transform.name == "NULL":
continue;
obj = transform.obj
if obj.ajm_type.audio_source:
sound = Sound.load(obj.ajm_audio_source.file_path)
unique = True
for s in sounds:
if sound.path == s.path:
unique = False
if unique:
sounds.append(sound)
audio_sources.append(AudioSource.load(obj, sounds, i))
self.sounds = sounds
self.audio_sources = audio_sources
def serialize(self, path):
fp = open(path, "wb")
fp.write("AJM\0".encode('UTF-8'))
print("Sounds: " + str(len(self.sounds)-1))
sound_count = np.uint16(len(self.sounds))
fp.write(sound_count.tobytes())
for sound in self.sounds:
sound.serialize(fp)
print("Audio Sources: " + str(len(self.audio_sources)-1))
audio_source_count = np.uint16(len(self.audio_sources))
fp.write(audio_source_count.tobytes())
for audio_source in self.audio_sources:
audio_source.serialize(fp)
fp.close()