Skip to content

Commit

Permalink
Merge 'issue/266/more-strict-export' branch into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
PavelBlend committed Aug 19, 2019
2 parents f801cb7 + f34e68e commit 61a9f45
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 69 deletions.
11 changes: 5 additions & 6 deletions io_scene_xray/anm/exp.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import io
import bpy

from ..xray_io import ChunkedWriter, PackedWriter
from .fmt import Chunks
from ..xray_envelope import export_envelope, EPSILON
from ..utils import smooth_euler, AppError
from ..utils import smooth_euler, save_file


def _export(bpy_obj, chunked_writer):
Expand Down Expand Up @@ -73,7 +73,6 @@ def _export_action_data(pkw, xray, fcurves):


def export_file(bpy_obj, fpath):
with io.open(fpath, 'wb') as file:
writer = ChunkedWriter()
_export(bpy_obj, writer)
file.write(writer.data)
writer = ChunkedWriter()
_export(bpy_obj, writer)
save_file(fpath, writer)
2 changes: 1 addition & 1 deletion io_scene_xray/anm/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from bpy_extras import io_utils

from .. import plugin_prefs, registry
from ..utils import execute_with_logger, FilenameExtHelper, AppError, set_cursor_state
from ..utils import execute_with_logger, FilenameExtHelper, set_cursor_state
from ..version_utils import assign_props, IS_28


Expand Down
10 changes: 4 additions & 6 deletions io_scene_xray/details/exp.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import io

from .. import xray_io
from ..utils import save_file
from . import write, convert


Expand All @@ -24,7 +23,6 @@ def _export(bpy_obj, chunked_writer, context):


def export_file(bpy_obj, fpath, context):
with io.open(fpath, 'wb') as file:
chunked_writer = xray_io.ChunkedWriter()
_export(bpy_obj, chunked_writer, context)
file.write(chunked_writer.data)
chunked_writer = xray_io.ChunkedWriter()
_export(bpy_obj, chunked_writer, context)
save_file(fpath, chunked_writer)
9 changes: 3 additions & 6 deletions io_scene_xray/details/model/exp.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import io

import bpy
import bmesh
import mathutils
Expand Down Expand Up @@ -88,7 +86,6 @@ def export(bpy_obj, packed_writer, context, mode='DM'):


def export_file(bpy_obj, fpath, context):
with io.open(fpath, 'wb') as file:
packed_writer = xray_io.PackedWriter()
export(bpy_obj, packed_writer, context)
file.write(packed_writer.data)
packed_writer = xray_io.PackedWriter()
export(bpy_obj, packed_writer, context)
utils.save_file(fpath, packed_writer)
11 changes: 4 additions & 7 deletions io_scene_xray/obj/exp/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import io

from ... import xray_io
from ... import xray_io, utils
from .. import fmt
from . import main

Expand All @@ -27,7 +25,6 @@ def _export(bpy_obj, chunked_writer, context):


def export_file(bpy_obj, fpath, context):
with io.open(fpath, 'wb') as file:
writer = xray_io.ChunkedWriter()
_export(bpy_obj, writer, context)
file.write(writer.data)
writer = xray_io.ChunkedWriter()
_export(bpy_obj, writer, context)
utils.save_file(fpath, writer)
33 changes: 33 additions & 0 deletions io_scene_xray/obj/exp/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,46 @@ def export_flags(chunked_writer, xray):
)


def validate_vertex_weights(bpy_obj, arm_obj):
exportable_bones_names = [
bone.name for bone in arm_obj.data.bones if bone.xray.exportable
]
exportable_groups_indices = [
group.index for group in bpy_obj.vertex_groups if group.name in exportable_bones_names
]
has_ungrouped_vertices = None
ungrouped_vertices_count = 0
for vertex in bpy_obj.data.vertices:
if not len(vertex.groups):
has_ungrouped_vertices = True
ungrouped_vertices_count += 1
else:
exportable_groups_count = 0
for vertex_group in vertex.groups:
if vertex_group.group in exportable_groups_indices:
exportable_groups_count += 1
if not exportable_groups_count:
has_ungrouped_vertices = True
ungrouped_vertices_count += 1
if has_ungrouped_vertices:
raise utils.AppError('Mesh "{0}" has {1} vertices that are not tied to any exportable bones'.format(
bpy_obj.data.name, ungrouped_vertices_count
))


def export_meshes(chunked_writer, bpy_obj, context):
mesh_writers = []
armatures = set()
materials = set()
meshes = set()
uv_maps_names = {}
bpy_root = bpy_obj

def scan_r(bpy_obj):
if utils.is_helper_object(bpy_obj):
return
if bpy_obj.type == 'MESH':
meshes.add(bpy_obj)
mesh_writer = xray_io.ChunkedWriter()
used_material_names = mesh.export_mesh(
bpy_obj,
Expand Down Expand Up @@ -81,6 +110,10 @@ def scan_r(bpy_obj):
'Skeletal object "{}" has more than one mesh'.format(bpy_obj.name)
)

if len(armatures) == 1:
for mesh_obj in meshes:
validate_vertex_weights(mesh_obj, list(armatures)[0])

bone_writers = []
root_bones = []
armatures = list(armatures)
Expand Down
8 changes: 4 additions & 4 deletions io_scene_xray/obj/exp/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,13 @@ def export_vertices(cw, bm):
cw.put(fmt.Chunks.Mesh.VERTS, writer)


def export_faces(cw, bm):
def export_faces(cw, bm, bpy_obj):
uvs = []
vtx = []
fcs = []
uv_layer = bm.loops.layers.uv.active
if not uv_layer:
raise utils.AppError('UV-map is required, but not found')
raise utils.AppError('UV-map is required, but not found on the "{0}" object'.format(bpy_obj.name))

writer = xray_io.PackedWriter()
writer.putf('I', len(bm.faces))
Expand Down Expand Up @@ -162,7 +162,7 @@ def export_mesh(bpy_obj, bpy_root, cw, context):

export_vertices(cw, bm)

uvs, vtx, fcs = export_faces(cw, bm)
uvs, vtx, fcs = export_faces(cw, bm, bpy_obj)

if bpy_root.type == 'ARMATURE':
bones_names = []
Expand Down Expand Up @@ -222,7 +222,7 @@ def export_mesh(bpy_obj, bpy_root, cw, context):
used_material_names.add(material_name)

if not sfaces:
raise utils.AppError('mesh has no material')
raise utils.AppError('mesh "{0}" has no material'.format(bpy_obj.data.name))
writer.putf('H', len(used_material_names))
for name, fidxs in sfaces.items():
if name in used_material_names:
Expand Down
11 changes: 4 additions & 7 deletions io_scene_xray/ogf/exp.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import io

from bmesh.ops import triangulate
import bpy
import mathutils
Expand All @@ -9,7 +7,7 @@
from ..utils import is_exportable_bone, find_bone_exportable_parent, AppError, \
fix_ensure_lookup_table, convert_object_to_space_bmesh, \
calculate_mesh_bbox, gen_texture_name
from ..utils import is_helper_object
from ..utils import is_helper_object, save_file
from ..xray_motions import MATRIX_BONE_INVERTED
from ..version_utils import multiply, IS_28

Expand Down Expand Up @@ -335,7 +333,6 @@ def scan_r(bpy_obj):


def export_file(bpy_obj, fpath, context):
with io.open(fpath, 'wb') as file:
cwriter = ChunkedWriter()
_export(bpy_obj, cwriter, context)
file.write(cwriter.data)
cwriter = ChunkedWriter()
_export(bpy_obj, cwriter, context)
save_file(fpath, cwriter)
10 changes: 4 additions & 6 deletions io_scene_xray/scene/exp.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import io
import string

from .. import xray_io
from .. import xray_io, utils
from . import fmt


Expand Down Expand Up @@ -113,7 +112,6 @@ def _export(bpy_objs, chunked_writer):


def export_file(bpy_objs, filepath):
with io.open(filepath, 'wb') as file:
writer = xray_io.ChunkedWriter()
_export(bpy_objs, writer)
file.write(writer.data)
writer = xray_io.ChunkedWriter()
_export(bpy_objs, writer)
utils.save_file(filepath, writer)
23 changes: 11 additions & 12 deletions io_scene_xray/skl/exp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from ..xray_io import ChunkedWriter, PackedWriter
from ..xray_motions import export_motion, export_motions
from ..utils import save_file


class ExportContext:
Expand All @@ -17,18 +18,16 @@ def _export_skl(chunked_writer, context):


def export_skl_file(fpath, context):
with open(fpath, 'wb') as file:
writer = ChunkedWriter()
_export_skl(writer, context)
file.write(writer.data)
writer = ChunkedWriter()
_export_skl(writer, context)
save_file(fpath, writer)


def export_skls_file(fpath, context):
with open(fpath, 'wb') as file:
writer = PackedWriter()
actions = []
for motion in bpy.context.object.xray.motions_collection:
action = bpy.data.actions[motion.name]
actions.append(action)
export_motions(writer, actions, context.armature)
file.write(writer.data)
writer = PackedWriter()
actions = []
for motion in bpy.context.object.xray.motions_collection:
action = bpy.data.actions[motion.name]
actions.append(action)
export_motions(writer, actions, context.armature)
save_file(fpath, writer)
29 changes: 21 additions & 8 deletions io_scene_xray/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def logger(name, report):
with log.using_logger(lgr):
yield
except AppError as err:
lgr.warn(str(err), err.ctx)
lgr.err(str(err), err.ctx)
raise err
finally:
lgr.flush(name)
Expand All @@ -67,26 +67,34 @@ def __init__(self, report):
self._report = report
self._full = list()

def warn(self, message, ctx=None):
def message_format(self, message):
message = str(message)
message = message.strip()
message = message[0].upper() + message[1:]
self._full.append((message, ctx))
return message

def warn(self, message, ctx=None):
message = self.message_format(message)
self._full.append((message, ctx, 'WARNING'))

def err(self, message, ctx=None):
message = self.message_format(message)
self._full.append((message, ctx, 'ERROR'))

def flush(self, logname='log'):
uniq = dict()
for msg, _ in self._full:
uniq[msg] = uniq.get(msg, 0) + 1
for msg, _, typ in self._full:
uniq[msg] = uniq.get(msg, (0, typ))[0] + 1, typ
if not uniq:
return

lines = ['Digest:']
for msg, cnt in uniq.items():
for msg, (cnt, typ) in uniq.items():
line = msg
if cnt > 1:
line = ('[%dx] ' % cnt) + line
lines.append(' ' + line)
self._report({'WARNING'}, line)
self._report({typ}, line)

lines.extend(['', 'Full log:'])
processed_groups = dict()
Expand Down Expand Up @@ -125,7 +133,7 @@ def ensure_group_processed(group):

last_message = None
last_message_count = 0
for msg, ctx in self._full:
for msg, ctx, typ in self._full:
data = dict()
group = ctx
while group and group.lightweight:
Expand Down Expand Up @@ -495,3 +503,8 @@ def wrap(*args, **kwargs):
log.debug('time', func=name, time=(time() - start))
return wrap
return decorator


def save_file(file_path, writer):
with open(file_path, 'wb') as file:
file.write(writer.data)
2 changes: 2 additions & 0 deletions tests/cases/test_armature.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ def test_import_sg_maya(self):
obj_me = utils.create_object(bmesh, True)
obj_me.parent = obj
obj_me.xray.isroot = False
group = obj_me.vertex_groups.new(name='exp')
group.add(range(len(obj_me.data.vertices)), 1, 'REPLACE')

# Act
bpy.ops.export_object.xray_objects(
Expand Down
2 changes: 2 additions & 0 deletions tests/cases/test_io_motions.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ def _prepare_animation():
(-1, -1, 0), (+1, -1, 0), (+1, +1, 0), (-1, +1, 0),
), ((0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 4, 1)), True)
obj_me = utils.create_object(bmesh, True)
group = obj_me.vertex_groups.new(name='bone')
group.add(range(len(obj_me.data.vertices)), 1, 'REPLACE')
obj_me.parent = obj
obj_me.xray.isroot = False

Expand Down
16 changes: 10 additions & 6 deletions tests/cases/test_object_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ def test_empty_bone_groups(self):
obj_me = utils.create_object(bmesh, True)
obj_me.parent = obj
obj_me.xray.isroot = False
vertex_group = obj_me.vertex_groups.new(name='b-exportable0')
vertex_group.add(range(len(obj_me.data.vertices)), 1.0, 'REPLACE')

# Act
bpy.ops.export_object.xray_objects(
Expand Down Expand Up @@ -195,7 +197,7 @@ def test_export_no_uvmap(self):

# Assert
self.assertReportsContains(
'WARNING',
'ERROR',
re.compile('UV-map is required, but not found')
)

Expand All @@ -209,9 +211,10 @@ def test_export_no_material(self):
)

# Assert
mesh_name = bpy.data.objects['tobj1'].data.name
self.assertReportsContains(
'WARNING',
re.compile('Mesh has no material')
'ERROR',
re.compile('Mesh "{0}" has no material'.format(mesh_name))
)

def _create_objects(self, create_uv=True, create_material=True):
Expand Down Expand Up @@ -244,9 +247,10 @@ def _create_armature(target):

target.modifiers.new(name='Armature', type='ARMATURE').object = obj
target.parent = obj
grp = target.vertex_groups.new()
grp.add(range(3), 1, 'REPLACE')
grp = target.vertex_groups.new(name='tbone')
vertices_count = len(target.data.vertices)
grp.add(range(vertices_count), 1, 'REPLACE')
grp = target.vertex_groups.new(name=io_scene_xray.utils.BAD_VTX_GROUP_NAME)
grp.add([3], 1, 'REPLACE')
grp.add([vertices_count], 1, 'REPLACE')

return obj

0 comments on commit 61a9f45

Please sign in to comment.