bug(import_bsi): Fix incorrect BSIZ parsing
This commit is contained in:
parent
64a15a0274
commit
f032838230
1 changed files with 139 additions and 119 deletions
|
@ -15,13 +15,16 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import sys
|
||||
import zlib
|
||||
import json
|
||||
import bpy
|
||||
import math
|
||||
import traceback
|
||||
|
||||
from mathutils import Vector, Matrix
|
||||
from bpy_extras.io_utils import unpack_list
|
||||
from bitsquid import sjson
|
||||
|
||||
|
||||
def parse_sjson(file_path, skip_editor_data=True):
|
||||
|
@ -32,12 +35,11 @@ def parse_sjson(file_path, skip_editor_data=True):
|
|||
Taken from `bsi_import` in the Vermintide 2 SDK, but slightly
|
||||
modified to fix some issues and improve readability.
|
||||
"""
|
||||
return_dict = {}
|
||||
try:
|
||||
|
||||
with open(file_path, 'rb') as f:
|
||||
data = f.read()
|
||||
|
||||
if data[:4] == 'bsiz':
|
||||
if data[:4] == b'bsiz':
|
||||
data = zlib.decompress(data[8:])
|
||||
|
||||
data = data.decode("utf-8")
|
||||
|
@ -162,10 +164,7 @@ def parse_sjson(file_path, skip_editor_data=True):
|
|||
file_lines[-1] = file_lines[-1][:-2] + '\n'
|
||||
|
||||
file_lines.append('}\n')
|
||||
return_dict = json.loads(''.join(file_lines))
|
||||
except ValueError:
|
||||
print(file_path.replace('\\', '/') + ': SJSON file contains a syntax error')
|
||||
return return_dict
|
||||
return json.loads(''.join(file_lines))
|
||||
|
||||
|
||||
def find(arr, f):
|
||||
|
@ -180,14 +179,15 @@ def find(arr, f):
|
|||
|
||||
def create_mesh(self, context, name, node_data, geo_data):
|
||||
"""
|
||||
Create a Blender object from a BSI node definition
|
||||
Create a Blender mesh object from a BSI node definition
|
||||
and additional data from the file.
|
||||
"""
|
||||
|
||||
# A list of vectors that represent vertex locations.
|
||||
# A list of 3-dimensional vectors. Each vector encodes a vertex position.
|
||||
vertices = []
|
||||
# A list of vectors, where each vector contains three indices into `vertices`.
|
||||
# Those three indices define the vertices that make up the face.
|
||||
# A list of vectors, where each vector contains three indices into
|
||||
# `vertices`. Those three indices define the vertices that make up
|
||||
# the face.
|
||||
faces = []
|
||||
uv_name = "UVMap"
|
||||
uvs = []
|
||||
|
@ -204,11 +204,11 @@ def create_mesh(self, context, name, node_data, geo_data):
|
|||
# stride would only be possible for objects that can be built
|
||||
# entirely from quads, which is very uncommon.
|
||||
if stride != 3:
|
||||
raise RuntimeError("stride != 3 cannot be handled")
|
||||
raise NotImplementedError("stride != 3 cannot be handled")
|
||||
|
||||
# Get vertex positions.
|
||||
# Iterate over data in sets of three values that represent
|
||||
# `x`, `y` and `z`.
|
||||
# Iterate over data in sets of three values. Each set
|
||||
# represents `x`, `y` and `z`.
|
||||
for j in range(0, len(stream_data), 3):
|
||||
vertices.append(Vector((
|
||||
stream_data[j],
|
||||
|
@ -224,6 +224,9 @@ def create_mesh(self, context, name, node_data, geo_data):
|
|||
index_stream[j + 1],
|
||||
index_stream[j + 2],
|
||||
)))
|
||||
|
||||
print(vertices)
|
||||
print(faces)
|
||||
elif channel["name"] == 'NORMAL':
|
||||
# Blender is able to create normals from the face definition
|
||||
# (i.e. the order in which the faces vertices were defined)
|
||||
|
@ -464,10 +467,12 @@ def import_geometry(self, context, name, node_data, global_data):
|
|||
obj = bpy.data.objects.new(mesh.name, mesh)
|
||||
obj.matrix_world = Matrix()
|
||||
|
||||
# Check of a local offset
|
||||
if "local" in node_data:
|
||||
mat = matrix_from_list(node_data["local"])
|
||||
obj.matrix_local = mat
|
||||
|
||||
# Recurse into child nodes and parent them to the current object
|
||||
if "children" in node_data:
|
||||
for child_name, child_data in node_data["children"].items():
|
||||
if child_data["parent"] != name:
|
||||
|
@ -517,6 +522,9 @@ def import_node(self, context, name, node_data, global_data):
|
|||
if has_geometry:
|
||||
return import_geometry(self, context, name, node_data, global_data)
|
||||
else:
|
||||
# Only the root node should be left now.
|
||||
# It needs slightly different treatment compared to a regular geometry
|
||||
# node
|
||||
if name != "root_point":
|
||||
self.report({'WARNING'}, "Unknown kind of node: '{}'. Falling back to Empty.".format(name))
|
||||
|
||||
|
@ -550,7 +558,19 @@ def import_node(self, context, name, node_data, global_data):
|
|||
|
||||
|
||||
def load(self, context, filepath, *, relpath=None):
|
||||
global_data = parse_sjson(filepath)
|
||||
try:
|
||||
with open(filepath, 'rb') as f:
|
||||
data = f.read()
|
||||
|
||||
if data[:4] == b'bsiz':
|
||||
data = zlib.decompress(data[8:])
|
||||
|
||||
data = data.decode("utf-8")
|
||||
global_data = sjson.loads(data)
|
||||
except Exception:
|
||||
self.report({'ERROR'}, "Failed to parse SJSON: {}".format(filepath))
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
return {'CANCELLED'}
|
||||
|
||||
# Nothing to do if there are no nodes
|
||||
if "nodes" not in global_data:
|
||||
|
|
Loading…
Add table
Reference in a new issue