Skip to content

Commit

Permalink
resolved #722: export cs/cop *.part
Browse files Browse the repository at this point in the history
  • Loading branch information
PavelBlend committed Dec 16, 2023
1 parent 5a084ca commit 4f18c3e
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 26 deletions.
47 changes: 34 additions & 13 deletions io_scene_xray/formats/le/write.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@
from ... import utils


def get_obj_count(bpy_objs):
obj_count = 0

for obj in bpy_objs:
if obj.xray.isroot:
obj_count += 1

return obj_count


def write_level_tag(chunked_writer):
owner = utils.obj.get_current_user()

Expand All @@ -20,10 +30,7 @@ def write_level_tag(chunked_writer):


def write_objects_count(chunked_writer, bpy_objs):
obj_count = 0
for obj in bpy_objs:
if obj.xray.isroot:
obj_count += 1
obj_count = get_obj_count(bpy_objs)

packed_writer = rw.write.PackedWriter()

Expand Down Expand Up @@ -78,7 +85,11 @@ def write_flags(body_chunked_writer):
body_chunked_writer.put(fmt.ObjectChunks.FLAGS, packed_reader)


def write_transform(loc, rot, scl, body_chunked_writer):
def get_transform(bpy_obj):
loc = bpy_obj.location
rot = bpy_obj.rotation_euler
scl = bpy_obj.scale

location = (loc[0], loc[2], loc[1])

rotation_matrix = rot.to_matrix()
Expand All @@ -87,7 +98,10 @@ def write_transform(loc, rot, scl, body_chunked_writer):

scale = (scl[0], scl[2], scl[1])

# write
return location, rotation, scale


def write_transform(location, rotation, scale, body_chunked_writer):
packed_reader = rw.write.PackedWriter()

packed_reader.putf('<3f', *location)
Expand All @@ -97,7 +111,13 @@ def write_transform(loc, rot, scl, body_chunked_writer):
body_chunked_writer.put(fmt.ObjectChunks.TRANSFORM, packed_reader)


def write_object_body(chunked_writer, bpy_obj):
def export_transform(bpy_obj, body_chunked_writer):
location, rotation, scale = get_transform(bpy_obj)

write_transform(location, rotation, scale, body_chunked_writer)


def get_obj_name(bpy_obj):
exp_path = utils.ie.get_export_path(bpy_obj)
object_name = exp_path + bpy_obj.name

Expand All @@ -110,6 +130,12 @@ def write_object_body(chunked_writer, bpy_obj):
if object_name.endswith('.object'):
object_name = object_name[0 : -len('.object')]

return object_name


def write_object_body(chunked_writer, bpy_obj):
object_name = get_obj_name(bpy_obj)

body_chunked_writer = rw.write.ChunkedWriter()

# flags
Expand All @@ -119,12 +145,7 @@ def write_object_body(chunked_writer, bpy_obj):
write_name(object_name, body_chunked_writer)

# transform
write_transform(
bpy_obj.location,
bpy_obj.rotation_euler,
bpy_obj.scale,
body_chunked_writer
)
export_transform(bpy_obj, body_chunked_writer)

# version
packed_reader = rw.write.PackedWriter()
Expand Down
158 changes: 149 additions & 9 deletions io_scene_xray/formats/part/exp.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# standart modules
import os
import time

# addon modules
from .. import le
Expand All @@ -9,7 +10,137 @@
from ... import utils


def write_guid(file_path, chunked_writer):
def _write_object(obj, lines, obj_index, errors):
loc, rot, scl = le.write.get_transform(obj)
object_name = le.write.get_obj_name(obj)

if ' ' in object_name:
errors.append([obj.name, object_name])
return

lines.append('[object_{}]'.format(obj_index))
lines.append(' clsid = {}'.format(le.fmt.ClassID.OBJECT))
lines.append(' co_flags = 3')
lines.append(' flags = 0')
lines.append(' name = {}'.format(object_name))
lines.append(' position = {0:.6f}, {0:.6f}, {0:.6f}'.format(*loc))
lines.append(' reference_name = {}'.format(object_name))
lines.append(' rotation = {0:.6f}, {0:.6f}, {0:.6f}'.format(*rot))
lines.append(' scale = {0:.6f}, {0:.6f}, {0:.6f}'.format(*scl))
lines.append(' version = {}'.format(le.fmt.OBJECT_VER_COP))
lines.append('')


def _write_objects(lines, objs):
obj_index = 0
errors = []

for obj in objs:
if obj.xray.isroot:
_write_object(obj, lines, obj_index, errors)
obj_index += 1

if errors:
if len(errors) == 1:
obj_name, obj_path = errors[0]
raise log.AppError(
text.error.part_no_space,
log.props(object=obj_name, object_path=obj_path)
)
else:
obj_names = list(map(lambda i: i[0], errors))
obj_paths = list(map(lambda i: i[1], errors))
raise log.AppError(
text.error.part_no_space,
log.props(
objects_count=len(obj_names),
objects=obj_names,
objects_paths=obj_paths
)
)


def _write_modif(lines):
owner = utils.obj.get_current_user()
create_time = int(time.time())

lines.append('[modif]')
lines.append(' name = {}'.format(owner))
lines.append(' time = {}'.format(create_time))
lines.append('')


def _write_main(lines, objs):
obj_count = le.write.get_obj_count(objs)

lines.append('[main]')
lines.append(' flags = 0')
lines.append(' objects_count = {}'.format(obj_count))
lines.append(' version = 0')
lines.append('')


def _write_guid_cop(file_path, lines):
if os.path.exists(file_path):
part_ltx = rw.ltx.LtxParser()

try:
part_ltx.from_file(file_path)
except:
raise log.AppError(
text.error.part_no_txt,
log.props(file=file_path)
)

guid_data = part_ltx.sections.get('guid', None)

if guid_data is None:
raise log.AppError(
text.error.part_no_guid,
log.props(file=file_path)
)

guid_g0 = guid_data.params.get('guid_g0', None)
guid_g1 = guid_data.params.get('guid_g1', None)

if guid_g0 is None or guid_g1 is None:
raise log.AppError(
text.error.part_no_guid,
log.props(file=file_path)
)

lines.append('[guid]')
lines.append(' guid_g0 = {}'.format(guid_g0))
lines.append(' guid_g1 = {}'.format(guid_g1))
lines.append('')

else:
raise log.AppError(text.error.part_no_file)


def _write_append_random(lines):
lines.append('[appendrandom]')
lines.append(' AppendRandomMaxRotation = 0.000000, 0.000000, 0.000000')
lines.append(' AppendRandomMaxScale = 1.000000, 1.000000, 1.000000')
lines.append(' AppendRandomMinRotation = 0.000000, 0.000000, 0.000000')
lines.append(' AppendRandomMinScale = 1.000000, 1.000000, 1.000000')
lines.append(' AppendRandomObjects_size = 0')
lines.append('')


def _export_sccop_part(file_path, objs):
lines = []

_write_append_random(lines)
_write_guid_cop(file_path, lines)
_write_main(lines, objs)
_write_modif(lines)
_write_objects(lines, objs)

return '\n'.join(lines)


def _write_guid_soc(file_path, chunked_writer):
packed_writer = rw.write.PackedWriter()

if os.path.exists(file_path):
Expand All @@ -34,17 +165,26 @@ def write_guid(file_path, chunked_writer):
chunked_writer.put(le.fmt.ToolsChunks.GUID, packed_writer)


def _export(file_path, objs, chunked_writer):
write_guid(file_path, chunked_writer)
def _export_soc_part(file_path, objs, chunked_writer):
_write_guid_soc(file_path, chunked_writer)
le.write.write_objects(chunked_writer, objs, part=True)


@log.with_context(name='export-part')
@utils.stats.timer
def export_file(objs, file_path):
utils.stats.status('Export File', file_path)
log.update(file_path=file_path)
def export_file(ctx, objs):
utils.stats.status('Export File', ctx.filepath)
log.update(file_path=ctx.filepath)

# shadow of chernobyl
if ctx.fmt_ver == 'soc':
writer = rw.write.ChunkedWriter()
_export_soc_part(ctx.filepath, objs, writer)
rw.utils.save_file(ctx.filepath, writer)

# clear sky / call of pripyat
else:
file_data = _export_sccop_part(ctx.filepath, objs)

writer = rw.write.ChunkedWriter()
_export(file_path, objs, writer)
rw.utils.save_file(file_path, writer)
with open(ctx.filepath, 'w', encoding='cp1251') as file:
file.write(file_data)
30 changes: 29 additions & 1 deletion io_scene_xray/formats/part/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from . import imp
from . import exp
from .. import ie
from .. import contexts
from .. import obj
from ... import utils
from ... import text
Expand All @@ -19,6 +20,12 @@ class ImportPartContext(obj.imp.ctx.ImportObjectContext):
pass


class ExportPartContext(contexts.ExportContext):
def __init__(self):
super().__init__()
self.fmt_ver = None


filename_ext = '.part'
op_text = 'Scene Objects'

Expand Down Expand Up @@ -101,22 +108,39 @@ class XRAY_OT_export_part(
ext = filename_ext
filename_ext = filename_ext

# file browser properties
filter_glob = bpy.props.StringProperty(
default='*'+filename_ext,
options={'HIDDEN'}
)

# export properties
fmt_ver = ie.PropSDKVersion()

# system properties
processed = bpy.props.BoolProperty(default=False, options={'HIDDEN'})

def draw(self, context): # pragma: no cover
layout = self.layout

utils.draw.draw_fmt_ver_prop(layout, self, 'fmt_ver')

@log.execute_with_logger
@utils.stats.execute_with_stats
@utils.ie.set_initial_state
def execute(self, context):
utils.stats.update('Export *.part')

exp_ctx = ExportPartContext()

exp_ctx.filepath = self.filepath
exp_ctx.operator = self
exp_ctx.fmt_ver = self.fmt_ver

objs = context.selected_objects

try:
exp.export_file(objs, self.filepath)
exp.export_file(exp_ctx, objs)

except log.AppError as err:
log.err(err)
Expand All @@ -131,6 +155,10 @@ def invoke(self, context, event): # pragma: no cover
self.report({'ERROR'}, text.get_text(text.error.no_selected_obj))
return {'CANCELLED'}

pref = utils.version.get_preferences()

self.fmt_ver = utils.ie.get_sdk_ver(pref.part_exp_sdk_ver)

return super().invoke(context, event)


Expand Down
3 changes: 3 additions & 0 deletions io_scene_xray/prefs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ class XRAY_addon_preferences(bpy.types.AddonPreferences):
part_sdk_version = formats.ie.PropSDKVersion()
part_mesh_split_by_mat = formats.ie.PropObjectMeshSplitByMaterials()

# part export props
part_exp_sdk_ver = formats.ie.PropSDKVersion()

# group import props
group_sdk_ver = formats.ie.PropSDKVersion()
group_split_by_mat = formats.ie.PropObjectMeshSplitByMaterials()
Expand Down
1 change: 1 addition & 0 deletions io_scene_xray/prefs/props.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
'scene_selection_mesh_split_by_mat',
'part_sdk_version',
'part_mesh_split_by_mat',
'part_exp_sdk_ver',
'keymaps_collection',
'keymaps_collection_index',
'enable_object_import',
Expand Down
Loading

0 comments on commit 4f18c3e

Please sign in to comment.