Optimized scene format
This commit is contained in:
parent
a19f26300c
commit
a759210355
|
@ -517,36 +517,39 @@ class ConvexBreaker {
|
|||
addFlatNormal(f.normal, f.c);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
var paa = new kha.arrays.Float32Array(pa.length);
|
||||
for (i in 0...pa.length) paa.set(i, pa[i]);
|
||||
var naa = new kha.arrays.Float32Array(na.length);
|
||||
for (i in 0...na.length) naa.set(i, na[i]);
|
||||
var inda = new kha.arrays.Uint32Array(ind.length);
|
||||
for (i in 0...ind.length) inda.set(i, ind[i]);
|
||||
|
||||
var pos:TVertexArray = {
|
||||
attrib: "position",
|
||||
size: 3,
|
||||
values: pa
|
||||
values: paa
|
||||
};
|
||||
|
||||
var nor:TVertexArray = {
|
||||
attrib: "normal",
|
||||
size: 3,
|
||||
values: na
|
||||
values: naa
|
||||
};
|
||||
|
||||
var indices:TIndexArray = {
|
||||
material: 0,
|
||||
size: 3,
|
||||
values: ind
|
||||
values: inda
|
||||
};
|
||||
|
||||
var rawmesh:TMesh = {
|
||||
primitive: "triangles",
|
||||
var rawmesh:TMeshData = {
|
||||
name: "TempMesh" + (meshIndex++),
|
||||
vertex_arrays: [pos, nor],
|
||||
index_arrays: [indices]
|
||||
};
|
||||
|
||||
var rawmeshData:TMeshData = {
|
||||
name: "TempMesh" + (meshIndex++),
|
||||
mesh: rawmesh
|
||||
};
|
||||
|
||||
var md = MeshData.newSync(rawmeshData);
|
||||
var md = MeshData.newSync(rawmesh);
|
||||
md.geom.calculateAABB();
|
||||
return md;
|
||||
}
|
||||
|
|
|
@ -29,164 +29,164 @@ class PathTracer extends Trait {
|
|||
|
||||
function getColorFromNode(object:MeshObject):Array<Float> {
|
||||
// Hard code for now
|
||||
for (c in object.materials[0].contexts[0].raw.bind_constants) {
|
||||
if (c.name == "baseCol") {
|
||||
return c.vec4;
|
||||
}
|
||||
}
|
||||
// for (c in object.materials[0].contexts[0].raw.bind_constants) {
|
||||
// if (c.name == "baseCol") {
|
||||
// return c.vec4;
|
||||
// }
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
||||
Data.getMaterial('pt_material', '', function(b:MaterialData) {
|
||||
// Data.getMaterial('pt_material', '', function(b:MaterialData) {
|
||||
|
||||
context = b.getContext('pt_trace_pass');
|
||||
// context = b.getContext('pt_trace_pass');
|
||||
|
||||
context.raw.bind_constants.push(
|
||||
{
|
||||
name: "glossiness",
|
||||
float: 0.6
|
||||
}
|
||||
);
|
||||
// context.raw.bind_constants.push(
|
||||
// {
|
||||
// name: "glossiness",
|
||||
// float: 0.6
|
||||
// }
|
||||
// );
|
||||
|
||||
context.raw.bind_constants.push(
|
||||
{
|
||||
name: "ray00",
|
||||
vec3: [0.0, 0.0, 0.0]
|
||||
}
|
||||
);
|
||||
ray00Location = context.raw.bind_constants.length - 1;
|
||||
// context.raw.bind_constants.push(
|
||||
// {
|
||||
// name: "ray00",
|
||||
// vec3: [0.0, 0.0, 0.0]
|
||||
// }
|
||||
// );
|
||||
// ray00Location = context.raw.bind_constants.length - 1;
|
||||
|
||||
context.raw.bind_constants.push(
|
||||
{
|
||||
name: "ray01",
|
||||
vec3: [0.0, 0.0, 0.0]
|
||||
}
|
||||
);
|
||||
ray01Location = context.raw.bind_constants.length - 1;
|
||||
// context.raw.bind_constants.push(
|
||||
// {
|
||||
// name: "ray01",
|
||||
// vec3: [0.0, 0.0, 0.0]
|
||||
// }
|
||||
// );
|
||||
// ray01Location = context.raw.bind_constants.length - 1;
|
||||
|
||||
context.raw.bind_constants.push(
|
||||
{
|
||||
name: "ray10",
|
||||
vec3: [0.0, 0.0, 0.0]
|
||||
}
|
||||
);
|
||||
ray10Location = context.raw.bind_constants.length - 1;
|
||||
// context.raw.bind_constants.push(
|
||||
// {
|
||||
// name: "ray10",
|
||||
// vec3: [0.0, 0.0, 0.0]
|
||||
// }
|
||||
// );
|
||||
// ray10Location = context.raw.bind_constants.length - 1;
|
||||
|
||||
context.raw.bind_constants.push(
|
||||
{
|
||||
name: "ray11",
|
||||
vec3: [0.0, 0.0, 0.0]
|
||||
}
|
||||
);
|
||||
ray11Location = context.raw.bind_constants.length - 1;
|
||||
// context.raw.bind_constants.push(
|
||||
// {
|
||||
// name: "ray11",
|
||||
// vec3: [0.0, 0.0, 0.0]
|
||||
// }
|
||||
// );
|
||||
// ray11Location = context.raw.bind_constants.length - 1;
|
||||
|
||||
objectLocations = [];
|
||||
transformMap = new Map();
|
||||
var sphereNum = 0;
|
||||
var cubeNum = 0;
|
||||
for (n in iron.Scene.active.meshes) {
|
||||
if (n.name.split(".")[0] == "Sphere") {
|
||||
context.raw.bind_constants.push(
|
||||
{
|
||||
name: "sphereCenter" + sphereNum,
|
||||
vec3: [0.0, 0.0, 0.0]
|
||||
}
|
||||
);
|
||||
var loc = context.raw.bind_constants.length - 1;
|
||||
objectLocations.push(loc);
|
||||
transformMap.set(loc, n.transform);
|
||||
// objectLocations = [];
|
||||
// transformMap = new Map();
|
||||
// var sphereNum = 0;
|
||||
// var cubeNum = 0;
|
||||
// for (n in iron.Scene.active.meshes) {
|
||||
// if (n.name.split(".")[0] == "Sphere") {
|
||||
// context.raw.bind_constants.push(
|
||||
// {
|
||||
// name: "sphereCenter" + sphereNum,
|
||||
// vec3: [0.0, 0.0, 0.0]
|
||||
// }
|
||||
// );
|
||||
// var loc = context.raw.bind_constants.length - 1;
|
||||
// objectLocations.push(loc);
|
||||
// transformMap.set(loc, n.transform);
|
||||
|
||||
context.raw.bind_constants.push(
|
||||
{
|
||||
name: "sphereRadius" + sphereNum,
|
||||
float: n.transform.size.x / 2 - 0.02
|
||||
}
|
||||
);
|
||||
// context.raw.bind_constants.push(
|
||||
// {
|
||||
// name: "sphereRadius" + sphereNum,
|
||||
// float: n.transform.size.x / 2 - 0.02
|
||||
// }
|
||||
// );
|
||||
|
||||
var col = getColorFromNode(n);
|
||||
context.raw.bind_constants.push(
|
||||
{
|
||||
name: "sphereColor" + sphereNum,
|
||||
vec3: [col[0], col[1], col[2]]
|
||||
}
|
||||
);
|
||||
// var col = getColorFromNode(n);
|
||||
// context.raw.bind_constants.push(
|
||||
// {
|
||||
// name: "sphereColor" + sphereNum,
|
||||
// vec3: [col[0], col[1], col[2]]
|
||||
// }
|
||||
// );
|
||||
|
||||
sphereNum++;
|
||||
}
|
||||
else if (n.name.split(".")[0] == "Cube") {
|
||||
context.raw.bind_constants.push(
|
||||
{
|
||||
name: "cubeCenter" + cubeNum,
|
||||
vec3: [0.0, 0.0, 0.0]
|
||||
}
|
||||
);
|
||||
var loc = context.raw.bind_constants.length - 1;
|
||||
objectLocations.push(loc);
|
||||
transformMap.set(loc, n.transform);
|
||||
// sphereNum++;
|
||||
// }
|
||||
// else if (n.name.split(".")[0] == "Cube") {
|
||||
// context.raw.bind_constants.push(
|
||||
// {
|
||||
// name: "cubeCenter" + cubeNum,
|
||||
// vec3: [0.0, 0.0, 0.0]
|
||||
// }
|
||||
// );
|
||||
// var loc = context.raw.bind_constants.length - 1;
|
||||
// objectLocations.push(loc);
|
||||
// transformMap.set(loc, n.transform);
|
||||
|
||||
context.raw.bind_constants.push(
|
||||
{
|
||||
name: "cubeSize" + cubeNum,
|
||||
vec3: [n.transform.size.x / 2, n.transform.size.y / 2, n.transform.size.z / 2]
|
||||
}
|
||||
);
|
||||
// context.raw.bind_constants.push(
|
||||
// {
|
||||
// name: "cubeSize" + cubeNum,
|
||||
// vec3: [n.transform.size.x / 2, n.transform.size.y / 2, n.transform.size.z / 2]
|
||||
// }
|
||||
// );
|
||||
|
||||
var col = getColorFromNode(n);
|
||||
context.raw.bind_constants.push(
|
||||
{
|
||||
name: "cubeColor" + cubeNum,
|
||||
vec3: [col[0], col[1], col[2]]
|
||||
}
|
||||
);
|
||||
// var col = getColorFromNode(n);
|
||||
// context.raw.bind_constants.push(
|
||||
// {
|
||||
// name: "cubeColor" + cubeNum,
|
||||
// vec3: [col[0], col[1], col[2]]
|
||||
// }
|
||||
// );
|
||||
|
||||
cubeNum++;
|
||||
}
|
||||
}
|
||||
// cubeNum++;
|
||||
// }
|
||||
// }
|
||||
|
||||
notifyOnUpdate(update);
|
||||
});
|
||||
// notifyOnUpdate(update);
|
||||
// });
|
||||
}
|
||||
|
||||
function update() {
|
||||
var camera = iron.Scene.active.camera;
|
||||
var eye = camera.transform.loc;
|
||||
// var camera = iron.Scene.active.camera;
|
||||
// var eye = camera.transform.loc;
|
||||
|
||||
// var jitter = Mat4.identity();
|
||||
// jitter.initTranslate(Math.random() * 2 - 1, Math.random() * 2 - 1, 0);
|
||||
// jitter.multiplyScalar(1 / iron.App.w);
|
||||
// jitter.multiplyScalar(1 / 400);
|
||||
var mvp = Mat4.identity();
|
||||
mvp.multmat2(camera.V);
|
||||
mvp.multmat2(camera.P);
|
||||
var inverse = Mat4.identity();
|
||||
// jitter.multmat2(mvp);
|
||||
// inverse.getInverse(mvp);
|
||||
var matrix = inverse;
|
||||
// // var jitter = Mat4.identity();
|
||||
// // jitter.initTranslate(Math.random() * 2 - 1, Math.random() * 2 - 1, 0);
|
||||
// // jitter.multiplyScalar(1 / iron.App.w);
|
||||
// // jitter.multiplyScalar(1 / 400);
|
||||
// var mvp = Mat4.identity();
|
||||
// mvp.multmat2(camera.V);
|
||||
// mvp.multmat2(camera.P);
|
||||
// var inverse = Mat4.identity();
|
||||
// // jitter.multmat2(mvp);
|
||||
// // inverse.getInverse(mvp);
|
||||
// var matrix = inverse;
|
||||
|
||||
// Set uniforms
|
||||
// // Set uniforms
|
||||
|
||||
var v = getEyeRay(matrix, -1, -1, eye);
|
||||
context.raw.bind_constants[ray00Location].vec3 = [v.x, v.y, v.z];
|
||||
// var v = getEyeRay(matrix, -1, -1, eye);
|
||||
// context.raw.bind_constants[ray00Location].vec3 = [v.x, v.y, v.z];
|
||||
|
||||
var v = getEyeRay(matrix, -1, 1, eye);
|
||||
context.raw.bind_constants[ray01Location].vec3 = [v.x, v.y, v.z];
|
||||
// var v = getEyeRay(matrix, -1, 1, eye);
|
||||
// context.raw.bind_constants[ray01Location].vec3 = [v.x, v.y, v.z];
|
||||
|
||||
var v = getEyeRay(matrix, 1, -1, eye);
|
||||
context.raw.bind_constants[ray10Location].vec3 = [v.x, v.y, v.z];
|
||||
// var v = getEyeRay(matrix, 1, -1, eye);
|
||||
// context.raw.bind_constants[ray10Location].vec3 = [v.x, v.y, v.z];
|
||||
|
||||
var v = getEyeRay(matrix, 1, 1, eye);
|
||||
context.raw.bind_constants[ray11Location].vec3 = [v.x, v.y, v.z];
|
||||
// var v = getEyeRay(matrix, 1, 1, eye);
|
||||
// context.raw.bind_constants[ray11Location].vec3 = [v.x, v.y, v.z];
|
||||
|
||||
for (loc in objectLocations) {
|
||||
var t:Transform = transformMap.get(loc);
|
||||
t.buildMatrix();
|
||||
var c = context.raw.bind_constants[loc];
|
||||
c.vec3[0] = t.absx();
|
||||
c.vec3[1] = t.absy();
|
||||
c.vec3[2] = t.absz();
|
||||
}
|
||||
// for (loc in objectLocations) {
|
||||
// var t:Transform = transformMap.get(loc);
|
||||
// t.buildMatrix();
|
||||
// var c = context.raw.bind_constants[loc];
|
||||
// c.vec3[0] = t.absx();
|
||||
// c.vec3[1] = t.absy();
|
||||
// c.vec3[2] = t.absz();
|
||||
// }
|
||||
}
|
||||
|
||||
function getEyeRay(matrix:Mat4, x:Float, y:Float, eye:Vec4):Vec4 {
|
||||
|
|
|
@ -76,7 +76,7 @@ class PhysicsWorld extends Trait {
|
|||
dispatcher = BtCollisionDispatcher.create(collisionConfiguration);
|
||||
var solver = BtSequentialImpulseConstraintSolver.create();
|
||||
|
||||
var gravity = iron.Scene.active.raw.gravity == null ? [0, 0, -9.81] : iron.Scene.active.raw.gravity;
|
||||
var gravity = iron.Scene.active.raw.gravity == null ? gravityArray() : iron.Scene.active.raw.gravity;
|
||||
|
||||
#if arm_physics_soft
|
||||
var softSolver = BtDefaultSoftBodySolver.create();
|
||||
|
@ -97,6 +97,14 @@ class PhysicsWorld extends Trait {
|
|||
});
|
||||
}
|
||||
|
||||
function gravityArray():kha.arrays.Float32Array {
|
||||
var ar = new kha.arrays.Float32Array(3);
|
||||
ar[0] = 0.0;
|
||||
ar[1] = 0.0;
|
||||
ar[2] = -9.81;
|
||||
return ar;
|
||||
}
|
||||
|
||||
public function addRigidBody(body:RigidBody) {
|
||||
world.addRigidBody(body.body);
|
||||
rbMap.set(body.id, body);
|
||||
|
|
|
@ -15,7 +15,6 @@ import bpy
|
|||
import math
|
||||
from mathutils import *
|
||||
import time
|
||||
import ast
|
||||
import subprocess
|
||||
import arm.utils
|
||||
import arm.write_probes as write_probes
|
||||
|
@ -142,7 +141,7 @@ class ArmoryExporter:
|
|||
def write_vector3d(self, vector):
|
||||
return [vector[0], vector[1], vector[2]]
|
||||
|
||||
def write_vertex_array2d(self, vertexArray, attrib):
|
||||
def write_va2d(self, vertexArray, attrib):
|
||||
va = []
|
||||
count = len(vertexArray)
|
||||
k = 0
|
||||
|
@ -166,7 +165,7 @@ class ArmoryExporter:
|
|||
|
||||
return va
|
||||
|
||||
def write_vertex_array3d(self, vertex_array, attrib):
|
||||
def write_va3d(self, vertex_array, attrib):
|
||||
va = []
|
||||
count = len(vertex_array)
|
||||
k = 0
|
||||
|
@ -431,8 +430,8 @@ class ArmoryExporter:
|
|||
|
||||
face_index += 1
|
||||
|
||||
colorCount = len(mesh.tessface_vertex_colors)
|
||||
if colorCount > 0:
|
||||
color_count = len(mesh.tessface_vertex_colors)
|
||||
if color_count > 0:
|
||||
colorFace = mesh.tessface_vertex_colors[0].data
|
||||
vertex_index = 0
|
||||
face_index = 0
|
||||
|
@ -526,7 +525,7 @@ class ArmoryExporter:
|
|||
bucketCount = 1
|
||||
|
||||
hashTable = [[] for i in range(bucketCount)]
|
||||
unifiedVertexArray = []
|
||||
unifiedVA = []
|
||||
|
||||
for i in range(len(export_vertex_array)):
|
||||
ev = export_vertex_array[i]
|
||||
|
@ -539,13 +538,13 @@ class ArmoryExporter:
|
|||
break
|
||||
|
||||
if index < 0:
|
||||
indexTable.append(len(unifiedVertexArray))
|
||||
unifiedVertexArray.append(ev)
|
||||
indexTable.append(len(unifiedVA))
|
||||
unifiedVA.append(ev)
|
||||
hashTable[bucket].append(i)
|
||||
else:
|
||||
indexTable.append(indexTable[index])
|
||||
|
||||
return unifiedVertexArray
|
||||
return unifiedVA
|
||||
|
||||
def export_bone(self, armature, bone, scene, o, action):
|
||||
bobjectRef = self.bobjectArray.get(bone)
|
||||
|
@ -1407,11 +1406,11 @@ class ArmoryExporter:
|
|||
if subbobject.parent_type != "BONE":
|
||||
self.export_object(subbobject, scene, None, o)
|
||||
|
||||
def export_skin_quality(self, bobject, armature, export_vertex_array, om):
|
||||
def export_skin_quality(self, bobject, armature, export_vertex_array, o):
|
||||
# This function exports all skinning data, which includes the skeleton
|
||||
# and per-vertex bone influence data
|
||||
oskin = {}
|
||||
om['skin'] = oskin
|
||||
o['skin'] = oskin
|
||||
|
||||
# Write the skin bind pose transform
|
||||
otrans = {}
|
||||
|
@ -1501,9 +1500,9 @@ class ArmoryExporter:
|
|||
# Write the bone weight array. The number of entries is the sum of the bone counts for all vertices.
|
||||
oskin['bone_weight_array'] = bone_weight_array
|
||||
|
||||
# def export_skin_fast(self, bobject, armature, vert_list, om):
|
||||
# def export_skin_fast(self, bobject, armature, vert_list, o):
|
||||
# oskin = {}
|
||||
# om['skin'] = oskin
|
||||
# o['skin'] = oskin
|
||||
|
||||
# otrans = {}
|
||||
# oskin['transform'] = otrans
|
||||
|
@ -1606,73 +1605,88 @@ class ArmoryExporter:
|
|||
else:
|
||||
self.output['mesh_datas'].append(o)
|
||||
|
||||
def export_mesh_fast(self, exportMesh, bobject, fp, o, om):
|
||||
def make_va(self, attrib, size, values):
|
||||
va = {}
|
||||
va['attrib'] = attrib
|
||||
va['size'] = size
|
||||
va['values'] = values
|
||||
return va
|
||||
|
||||
def export_mesh_fast(self, exportMesh, bobject, fp, o):
|
||||
# Much faster export but produces slightly less efficient data
|
||||
exportMesh.calc_normals_split()
|
||||
exportMesh.calc_tessface()
|
||||
vert_list = { Vertex(exportMesh, loop) : 0 for loop in exportMesh.loops}.keys()
|
||||
num_verts = len(vert_list)
|
||||
num_uv_layers = len(exportMesh.uv_layers)
|
||||
has_tex = self.get_export_uvs(exportMesh) == True and num_uv_layers > 0
|
||||
has_tex1 = has_tex == True and num_uv_layers > 1
|
||||
num_colors = len(exportMesh.vertex_colors)
|
||||
has_col = self.get_export_vcols(exportMesh) == True and num_colors > 0
|
||||
has_tang = self.has_tangents(exportMesh)
|
||||
|
||||
vdata = [0] * num_verts * 3
|
||||
ndata = [0] * num_verts * 3
|
||||
if num_uv_layers > 0:
|
||||
if has_tex:
|
||||
t0data = [0] * num_verts * 2
|
||||
if num_uv_layers > 1:
|
||||
if has_tex1:
|
||||
t1data = [0] * num_verts * 2
|
||||
if num_colors > 0:
|
||||
if has_col:
|
||||
cdata = [0] * num_verts * 3
|
||||
|
||||
|
||||
# va_stride = 3 + 3 # pos + nor
|
||||
# va_name = 'pos_nor'
|
||||
# if has_tex:
|
||||
# va_stride += 2
|
||||
# va_name += '_tex'
|
||||
# if has_tex1:
|
||||
# va_stride += 2
|
||||
# va_name += '_tex1'
|
||||
# if has_col > 0:
|
||||
# va_stride += 3
|
||||
# va_name += '_col'
|
||||
# if has_tang:
|
||||
# va_stride += 3
|
||||
# va_name += '_tang'
|
||||
# vdata = [0] * num_verts * va_stride
|
||||
|
||||
# Make arrays
|
||||
for i, vtx in enumerate(vert_list):
|
||||
vtx.index = i
|
||||
|
||||
co = vtx.co
|
||||
normal = vtx.normal
|
||||
for j in range(3):
|
||||
vdata[(i * 3) + j] = co[j]
|
||||
ndata[(i * 3) + j] = normal[j]
|
||||
if num_uv_layers > 0:
|
||||
if has_tex:
|
||||
t0data[i * 2] = vtx.uvs[0].x
|
||||
t0data[i * 2 + 1] = 1.0 - vtx.uvs[0].y # Reverse TCY
|
||||
if num_uv_layers > 1:
|
||||
if has_tex1:
|
||||
t1data[i * 2] = vtx.uvs[1].x
|
||||
t1data[i * 2 + 1] = 1.0 - vtx.uvs[1].y
|
||||
if num_colors > 0:
|
||||
if has_col > 0:
|
||||
cdata[i * 3] = vtx.col[0]
|
||||
cdata[i * 3 + 1] = vtx.col[1]
|
||||
cdata[i * 3 + 2] = vtx.col[2]
|
||||
|
||||
# Output
|
||||
om['vertex_arrays'] = []
|
||||
pa = {}
|
||||
pa['attrib'] = "position"
|
||||
pa['size'] = 3
|
||||
pa['values'] = vdata
|
||||
om['vertex_arrays'].append(pa)
|
||||
na = {}
|
||||
na['attrib'] = "normal"
|
||||
na['size'] = 3
|
||||
na['values'] = ndata
|
||||
om['vertex_arrays'].append(na)
|
||||
o['vertex_arrays'] = []
|
||||
pa = self.make_va('pos', 3, vdata)
|
||||
o['vertex_arrays'].append(pa)
|
||||
na = self.make_va('nor', 3, ndata)
|
||||
o['vertex_arrays'].append(na)
|
||||
|
||||
if self.get_export_uvs(exportMesh) == True and num_uv_layers > 0:
|
||||
ta = {}
|
||||
ta['attrib'] = "texcoord"
|
||||
ta['size'] = 2
|
||||
ta['values'] = t0data
|
||||
om['vertex_arrays'].append(ta)
|
||||
if num_uv_layers > 1:
|
||||
ta1 = {}
|
||||
ta1['attrib'] = "texcoord1"
|
||||
ta1['size'] = 2
|
||||
ta1['values'] = t1data
|
||||
om['vertex_arrays'].append(ta1)
|
||||
if has_tex:
|
||||
ta = self.make_va('tex', 2, t0data)
|
||||
o['vertex_arrays'].append(ta)
|
||||
if has_tex1:
|
||||
ta1 = self.make_va('tex1', 2, t1data)
|
||||
o['vertex_arrays'].append(ta1)
|
||||
|
||||
if self.get_export_vcols(exportMesh) == True and num_colors > 0:
|
||||
ca = {}
|
||||
ca['attrib'] = "color"
|
||||
ca['size'] = 3
|
||||
ca['values'] = cdata
|
||||
om['vertex_arrays'].append(ca)
|
||||
if has_col:
|
||||
ca = self.make_va('col', 3, cdata)
|
||||
o['vertex_arrays'].append(ca)
|
||||
|
||||
# Indices
|
||||
prims = {ma.name if ma else '': [] for ma in exportMesh.materials}
|
||||
|
@ -1696,7 +1710,7 @@ class ArmoryExporter:
|
|||
prim += (indices[-1], indices[i], indices[i + 1])
|
||||
|
||||
# Write indices
|
||||
om['index_arrays'] = []
|
||||
o['index_arrays'] = []
|
||||
for mat, prim in prims.items():
|
||||
idata = [0] * len(prim)
|
||||
for i, v in enumerate(prim):
|
||||
|
@ -1712,18 +1726,19 @@ class ArmoryExporter:
|
|||
(exportMesh.materials[i] == None and mat == ''): # Default material for empty slots
|
||||
ia['material'] = i
|
||||
break
|
||||
om['index_arrays'].append(ia)
|
||||
o['index_arrays'].append(ia)
|
||||
|
||||
# Make tangents
|
||||
if self.get_export_uvs(exportMesh) == True and self.get_export_tangents(exportMesh) == True and num_uv_layers > 0:
|
||||
tanga = {}
|
||||
tanga['attrib'] = "tangent"
|
||||
tanga['size'] = 3
|
||||
tanga['values'] = self.calc_tangents(pa['values'], na['values'], ta['values'], om['index_arrays'][0]['values'])
|
||||
om['vertex_arrays'].append(tanga)
|
||||
if has_tang:
|
||||
tanga_vals = self.calc_tangents(pa['values'], na['values'], ta['values'], o['index_arrays'][0]['values'])
|
||||
tanga = self.make_va('tang', 3, tanga_vals)
|
||||
o['vertex_arrays'].append(tanga)
|
||||
|
||||
return vert_list
|
||||
|
||||
def has_tangents(self, exportMesh):
|
||||
return self.get_export_uvs(exportMesh) == True and self.get_export_tangents(exportMesh) == True and len(exportMesh.uv_layers) > 0
|
||||
|
||||
def do_export_mesh(self, objectRef, scene):
|
||||
# This function exports a single mesh object
|
||||
bobject = objectRef[1]["objectTable"][0]
|
||||
|
@ -1794,19 +1809,10 @@ class ArmoryExporter:
|
|||
shapeKeys.key_blocks[0].value = 1.0
|
||||
mesh.update()
|
||||
|
||||
om = {}
|
||||
# Triangles is default
|
||||
# om['primitive'] = "triangles"
|
||||
|
||||
armature = bobject.find_armature()
|
||||
apply_modifiers = not armature
|
||||
|
||||
# Apply all modifiers to create a new mesh with tessfaces
|
||||
# We don't apply modifiers for a skinned mesh because we need the vertex positions
|
||||
# before they are deformed by the armature modifier in order to export the proper
|
||||
# bind pose. This does mean that modifiers preceding the armature modifier are ignored,
|
||||
# but the Blender API does not provide a reasonable way to retrieve the mesh at an
|
||||
# arbitrary stage in the modifier stack.
|
||||
exportMesh = bobject.to_mesh(scene, apply_modifiers, "RENDER", True, False)
|
||||
|
||||
if exportMesh == None:
|
||||
|
@ -1818,19 +1824,28 @@ class ArmoryExporter:
|
|||
|
||||
# Process meshes
|
||||
if ArmoryExporter.option_optimize_mesh:
|
||||
unifiedVertexArray = self.export_mesh_quality(exportMesh, bobject, fp, o, om)
|
||||
vert_list = self.export_mesh_quality(exportMesh, bobject, fp, o)
|
||||
if armature:
|
||||
self.export_skin_quality(bobject, armature, unifiedVertexArray, om)
|
||||
self.export_skin_quality(bobject, armature, vert_list, o)
|
||||
else:
|
||||
vert_list = self.export_mesh_fast(exportMesh, bobject, fp, o, om)
|
||||
vert_list = self.export_mesh_fast(exportMesh, bobject, fp, o)
|
||||
if armature:
|
||||
self.export_skin_quality(bobject, armature, vert_list, om)
|
||||
# self.export_skin_fast(bobject, armature, vert_list, om)
|
||||
self.export_skin_quality(bobject, armature, vert_list, o)
|
||||
# self.export_skin_fast(bobject, armature, vert_list, o)
|
||||
|
||||
# Save aabb
|
||||
for va in om['vertex_arrays']:
|
||||
if va['attrib'] == 'position':
|
||||
for va in o['vertex_arrays']:
|
||||
if va['attrib'].startswith('pos'):
|
||||
positions = va['values']
|
||||
stride = 0
|
||||
ar = va['attrib'].split('_')
|
||||
for a in ar:
|
||||
if a == 'pos' or a == 'nor' or a == 'col' or a == 'tang':
|
||||
stride += 3
|
||||
elif a == 'tex' or a == 'tex1':
|
||||
stride += 2
|
||||
elif a == 'bone' or a == 'weight':
|
||||
stride += 4
|
||||
aabb_min = [-0.01, -0.01, -0.01]
|
||||
aabb_max = [0.01, 0.01, 0.01]
|
||||
i = 0
|
||||
|
@ -1847,7 +1862,7 @@ class ArmoryExporter:
|
|||
aabb_min[1] = positions[i + 1];
|
||||
if positions[i + 2] < aabb_min[2]:
|
||||
aabb_min[2] = positions[i + 2];
|
||||
i += 3;
|
||||
i += stride;
|
||||
if hasattr(bobject.data, 'mesh_aabb'):
|
||||
bobject.data.mesh_aabb = [abs(aabb_min[0]) + abs(aabb_max[0]), abs(aabb_min[1]) + abs(aabb_max[1]), abs(aabb_min[2]) + abs(aabb_max[2])]
|
||||
break
|
||||
|
@ -1864,63 +1879,46 @@ class ArmoryExporter:
|
|||
|
||||
# Save offset data for instanced rendering
|
||||
if is_instanced == True:
|
||||
om['instance_offsets'] = instance_offsets
|
||||
o['instance_offsets'] = instance_offsets
|
||||
|
||||
# Export usage
|
||||
if bobject.data.dynamic_usage:
|
||||
om['dynamic_usage'] = bobject.data.dynamic_usage
|
||||
o['dynamic_usage'] = bobject.data.dynamic_usage
|
||||
|
||||
o['mesh'] = om
|
||||
self.write_mesh(bobject, fp, o)
|
||||
|
||||
def export_mesh_quality(self, exportMesh, bobject, fp, o, om):
|
||||
def export_mesh_quality(self, exportMesh, bobject, fp, o):
|
||||
# Triangulate mesh and remap vertices to eliminate duplicates
|
||||
material_table = []
|
||||
export_vertex_array = ArmoryExporter.deindex_mesh(exportMesh, material_table)
|
||||
triangleCount = len(material_table)
|
||||
|
||||
indexTable = []
|
||||
unifiedVertexArray = ArmoryExporter.unify_vertices(export_vertex_array, indexTable)
|
||||
unifiedVA = ArmoryExporter.unify_vertices(export_vertex_array, indexTable)
|
||||
|
||||
# Write the position array
|
||||
om['vertex_arrays'] = []
|
||||
pa = {}
|
||||
pa['attrib'] = "position"
|
||||
pa['size'] = 3
|
||||
pa['values'] = self.write_vertex_array3d(unifiedVertexArray, "position")
|
||||
om['vertex_arrays'].append(pa)
|
||||
o['vertex_arrays'] = []
|
||||
pa = self.make_va('pos', 3, self.write_va3d(unifiedVA, "position"))
|
||||
o['vertex_arrays'].append(pa)
|
||||
|
||||
# Write the normal array
|
||||
na = {}
|
||||
na['attrib'] = "normal"
|
||||
na['size'] = 3
|
||||
na['values'] = self.write_vertex_array3d(unifiedVertexArray, "normal")
|
||||
om['vertex_arrays'].append(na)
|
||||
na = self.make_va('nor', 3, self.write_va3d(unifiedVA, "normal"))
|
||||
o['vertex_arrays'].append(na)
|
||||
|
||||
# Write the color array if it exists
|
||||
colorCount = len(exportMesh.tessface_vertex_colors)
|
||||
if self.get_export_vcols(exportMesh) == True and colorCount > 0:
|
||||
ca = {}
|
||||
ca['attrib'] = "color"
|
||||
ca['size'] = 3
|
||||
ca['values'] = self.write_vertex_array3d(unifiedVertexArray, "color")
|
||||
om['vertex_arrays'].append(ca)
|
||||
color_count = len(exportMesh.tessface_vertex_colors)
|
||||
if self.get_export_vcols(exportMesh) == True and color_count > 0:
|
||||
ca = self.make_va('col', 3, self.write_va3d(unifiedVA, "color"))
|
||||
o['vertex_arrays'].append(ca)
|
||||
|
||||
# Write the texcoord arrays
|
||||
texcoordCount = len(exportMesh.tessface_uv_textures)
|
||||
if self.get_export_uvs(exportMesh) == True and texcoordCount > 0:
|
||||
ta = {}
|
||||
ta['attrib'] = "texcoord"
|
||||
ta['size'] = 2
|
||||
ta['values'] = self.write_vertex_array2d(unifiedVertexArray, "texcoord0")
|
||||
om['vertex_arrays'].append(ta)
|
||||
|
||||
ta = self.make_va('tex', 2, self.write_va2d(unifiedVA, "texcoord0"))
|
||||
o['vertex_arrays'].append(ta)
|
||||
if texcoordCount > 1:
|
||||
ta2 = {}
|
||||
ta2['attrib'] = "texcoord1"
|
||||
ta2['size'] = 2
|
||||
ta2['values'] = self.write_vertex_array2d(unifiedVertexArray, "texcoord1")
|
||||
om['vertex_arrays'].append(ta2)
|
||||
ta2 = self.make_va('tex1', 2, self.write_va2d(unifiedVA, "texcoord1"))
|
||||
o['vertex_arrays'].append(ta2)
|
||||
|
||||
# If there are multiple morph targets, export them here
|
||||
# if shapeKeys:
|
||||
|
@ -1942,7 +1940,7 @@ class ArmoryExporter:
|
|||
|
||||
# self.IndentWrite(B"float[3]\t\t// ")
|
||||
# self.IndentWrite(B"{\n", 0, True)
|
||||
# self.WriteMorphPositionArray3D(unifiedVertexArray, morphMesh.vertices)
|
||||
# self.WriteMorphPositionArray3D(unifiedVA, morphMesh.vertices)
|
||||
# self.IndentWrite(B"}\n")
|
||||
|
||||
# self.indentLevel -= 1
|
||||
|
@ -1958,7 +1956,7 @@ class ArmoryExporter:
|
|||
|
||||
# self.IndentWrite(B"float[3]\t\t// ")
|
||||
# self.IndentWrite(B"{\n", 0, True)
|
||||
# self.WriteMorphNormalArray3D(unifiedVertexArray, morphMesh.vertices, morphMesh.tessfaces)
|
||||
# self.WriteMorphNormalArray3D(unifiedVA, morphMesh.vertices, morphMesh.tessfaces)
|
||||
# self.IndentWrite(B"}\n")
|
||||
|
||||
# self.indentLevel -= 1
|
||||
|
@ -1967,7 +1965,7 @@ class ArmoryExporter:
|
|||
# bpy.data.meshes.remove(morphMesh)
|
||||
|
||||
# Write the index arrays
|
||||
om['index_arrays'] = []
|
||||
o['index_arrays'] = []
|
||||
|
||||
maxMaterialIndex = 0
|
||||
for i in range(len(material_table)):
|
||||
|
@ -1981,7 +1979,7 @@ class ArmoryExporter:
|
|||
ia['size'] = 3
|
||||
ia['values'] = self.write_triangle_array(triangleCount, indexTable)
|
||||
ia['material'] = 0
|
||||
om['index_arrays'].append(ia)
|
||||
o['index_arrays'].append(ia)
|
||||
else:
|
||||
# If there are multiple material indexes, then write a separate index array for each one.
|
||||
materialTriangleCount = [0 for i in range(maxMaterialIndex + 1)]
|
||||
|
@ -2002,19 +2000,17 @@ class ArmoryExporter:
|
|||
ia['size'] = 3
|
||||
ia['values'] = self.write_triangle_array(materialTriangleCount[m], materialIndexTable)
|
||||
ia['material'] = m
|
||||
om['index_arrays'].append(ia)
|
||||
o['index_arrays'].append(ia)
|
||||
|
||||
# Export tangents
|
||||
if self.get_export_tangents(exportMesh) == True and len(exportMesh.uv_textures) > 0:
|
||||
tanga = {}
|
||||
tanga['attrib'] = "tangent"
|
||||
tanga['size'] = 3
|
||||
tanga['values'] = self.calc_tangents(pa['values'], na['values'], ta['values'], om['index_arrays'][0]['values'])
|
||||
om['vertex_arrays'].append(tanga)
|
||||
if self.has_tangents(exportMesh):
|
||||
tanga_vals = self.calc_tangents(pa['values'], na['values'], ta['values'], o['index_arrays'][0]['values'])
|
||||
tanga = make_va('tang', 3, tanga_vals)
|
||||
o['vertex_arrays'].append(tanga)
|
||||
|
||||
# Delete the new mesh that we made earlier
|
||||
bpy.data.meshes.remove(exportMesh)
|
||||
return unifiedVertexArray
|
||||
return unifiedVA
|
||||
|
||||
def export_lamp(self, objectRef):
|
||||
# This function exports a single lamp object
|
||||
|
@ -2572,7 +2568,7 @@ class ArmoryExporter:
|
|||
if n.instanced_children == True:
|
||||
is_instanced = True
|
||||
# Save offset data
|
||||
instance_offsets = [0, 0, 0] # Include parent
|
||||
instance_offsets = [0.0, 0.0, 0.0] # Include parent
|
||||
for sn in n.children:
|
||||
# Child hidden
|
||||
if sn.game_export == False or (sn.hide_render and ArmoryExporter.option_export_hide_render == False):
|
||||
|
@ -2785,7 +2781,7 @@ class ArmoryExporter:
|
|||
if len(t.my_paramstraitlist) > 0:
|
||||
x['parameters'] = []
|
||||
for pt in t.my_paramstraitlist: # Append parameters
|
||||
x['parameters'].append(ast.literal_eval(pt.name))
|
||||
x['parameters'].append(pt.name)
|
||||
o['traits'].append(x)
|
||||
|
||||
# Rigid body trait
|
||||
|
@ -2814,14 +2810,14 @@ class ArmoryExporter:
|
|||
x = {}
|
||||
x['type'] = 'Script'
|
||||
x['class_name'] = 'armory.trait.internal.RigidBody'
|
||||
x['parameters'] = [body_mass, shape, rb.friction, rb.restitution]
|
||||
x['parameters'] = [str(body_mass), str(shape), str(rb.friction), str(rb.restitution)]
|
||||
if rb.use_margin:
|
||||
x['parameters'].append(rb.collision_margin)
|
||||
x['parameters'].append(str(rb.collision_margin))
|
||||
else:
|
||||
x['parameters'].append(0.0)
|
||||
x['parameters'].append(rb.linear_damping)
|
||||
x['parameters'].append(rb.angular_damping)
|
||||
x['parameters'].append(rb.type == 'PASSIVE')
|
||||
x['parameters'].append('0.0')
|
||||
x['parameters'].append(str(rb.linear_damping))
|
||||
x['parameters'].append(str(rb.angular_damping))
|
||||
x['parameters'].append(str(rb.type == 'PASSIVE').lower())
|
||||
o['traits'].append(x)
|
||||
|
||||
# Soft bodies modifier
|
||||
|
@ -2846,7 +2842,7 @@ class ArmoryExporter:
|
|||
bend = soft_mod.settings.bending_stiffness
|
||||
elif soft_type == 1:
|
||||
bend = (soft_mod.settings.bend + 1.0) * 10
|
||||
cloth_trait['parameters'] = [soft_type, bend, soft_mod.settings.mass, bobject.soft_body_margin]
|
||||
cloth_trait['parameters'] = [str(soft_type), str(bend), str(soft_mod.settings.mass), str(bobject.soft_body_margin)]
|
||||
o['traits'].append(cloth_trait)
|
||||
if soft_type == 0 and soft_mod.settings.use_pin_cloth:
|
||||
self.add_hook_trait(o, bobject, '', soft_mod.settings.vertex_group_mass)
|
||||
|
@ -2883,7 +2879,7 @@ class ArmoryExporter:
|
|||
navigation_trait = {}
|
||||
navigation_trait['type'] = 'Script'
|
||||
navigation_trait['class_name'] = 'armory.trait.WalkNavigation'
|
||||
navigation_trait['parameters'] = [arm.utils.get_ease_viewport_camera()]
|
||||
navigation_trait['parameters'] = [str(arm.utils.get_ease_viewport_camera()).lower()]
|
||||
o['traits'].append(navigation_trait)
|
||||
|
||||
# Map objects to materials, can be used in later stages
|
||||
|
@ -2930,7 +2926,7 @@ class ArmoryExporter:
|
|||
verts.append(v.co.x)
|
||||
verts.append(v.co.y)
|
||||
verts.append(v.co.z)
|
||||
hook_trait['parameters'] = [target_name, verts]
|
||||
hook_trait['parameters'] = [target_name, str(verts)]
|
||||
o['traits'].append(hook_trait)
|
||||
|
||||
def post_export_world(self, world, o):
|
||||
|
|
150
blender/arm/lib/armpack.py
Executable file
150
blender/arm/lib/armpack.py
Executable file
|
@ -0,0 +1,150 @@
|
|||
# Msgpack parser with typed arrays
|
||||
# Based on u-msgpack-python v2.4.1 - v at sergeev.io
|
||||
# https://github.com/vsergeev/u-msgpack-python
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
import struct
|
||||
import io
|
||||
|
||||
def _pack_integer(obj, fp):
|
||||
if obj < 0:
|
||||
if obj >= -32:
|
||||
fp.write(struct.pack("b", obj))
|
||||
elif obj >= -2**(8 - 1):
|
||||
fp.write(b"\xd0" + struct.pack("b", obj))
|
||||
elif obj >= -2**(16 - 1):
|
||||
fp.write(b"\xd1" + struct.pack(">h", obj))
|
||||
elif obj >= -2**(32 - 1):
|
||||
fp.write(b"\xd2" + struct.pack(">i", obj))
|
||||
elif obj >= -2**(64 - 1):
|
||||
fp.write(b"\xd3" + struct.pack(">q", obj))
|
||||
else:
|
||||
raise Exception("huge signed int")
|
||||
else:
|
||||
if obj <= 127:
|
||||
fp.write(struct.pack("B", obj))
|
||||
elif obj <= 2**8 - 1:
|
||||
fp.write(b"\xcc" + struct.pack("B", obj))
|
||||
elif obj <= 2**16 - 1:
|
||||
fp.write(b"\xcd" + struct.pack(">H", obj))
|
||||
elif obj <= 2**32 - 1:
|
||||
fp.write(b"\xce" + struct.pack(">I", obj))
|
||||
elif obj <= 2**64 - 1:
|
||||
fp.write(b"\xcf" + struct.pack(">Q", obj))
|
||||
else:
|
||||
raise Exception("huge unsigned int")
|
||||
|
||||
def _pack_nil(obj, fp):
|
||||
fp.write(b"\xc0")
|
||||
|
||||
def _pack_boolean(obj, fp):
|
||||
fp.write(b"\xc3" if obj else b"\xc2")
|
||||
|
||||
def _pack_float(obj, fp):
|
||||
# NOTE: forced 32-bit floats for Armory
|
||||
# fp.write(b"\xcb" + struct.pack(">d", obj)) # Double
|
||||
fp.write(b"\xca" + struct.pack(">f", obj))
|
||||
|
||||
def _pack_string(obj, fp):
|
||||
obj = obj.encode('utf-8')
|
||||
if len(obj) <= 31:
|
||||
fp.write(struct.pack("B", 0xa0 | len(obj)) + obj)
|
||||
elif len(obj) <= 2**8 - 1:
|
||||
fp.write(b"\xd9" + struct.pack("B", len(obj)) + obj)
|
||||
elif len(obj) <= 2**16 - 1:
|
||||
fp.write(b"\xda" + struct.pack(">H", len(obj)) + obj)
|
||||
elif len(obj) <= 2**32 - 1:
|
||||
fp.write(b"\xdb" + struct.pack(">I", len(obj)) + obj)
|
||||
else:
|
||||
raise Exception("huge string")
|
||||
|
||||
def _pack_binary(obj, fp):
|
||||
if len(obj) <= 2**8 - 1:
|
||||
fp.write(b"\xc4" + struct.pack("B", len(obj)) + obj)
|
||||
elif len(obj) <= 2**16 - 1:
|
||||
fp.write(b"\xc5" + struct.pack(">H", len(obj)) + obj)
|
||||
elif len(obj) <= 2**32 - 1:
|
||||
fp.write(b"\xc6" + struct.pack(">I", len(obj)) + obj)
|
||||
else:
|
||||
raise Exception("huge binary string")
|
||||
|
||||
def _pack_array(obj, fp):
|
||||
if len(obj) <= 15:
|
||||
fp.write(struct.pack("B", 0x90 | len(obj)))
|
||||
elif len(obj) <= 2**16 - 1:
|
||||
fp.write(b"\xdc" + struct.pack(">H", len(obj)))
|
||||
elif len(obj) <= 2**32 - 1:
|
||||
fp.write(b"\xdd" + struct.pack(">I", len(obj)))
|
||||
else:
|
||||
raise Exception("huge array")
|
||||
|
||||
# Float32
|
||||
if len(obj) > 0 and isinstance(obj[0], float):
|
||||
fp.write(b"\xca")
|
||||
for e in obj:
|
||||
fp.write(struct.pack(">f", e))
|
||||
# Int32
|
||||
elif len(obj) > 0 and isinstance(obj[0], int):
|
||||
fp.write(b"\xd2")
|
||||
for e in obj:
|
||||
fp.write(struct.pack(">i", e))
|
||||
# Regular
|
||||
else:
|
||||
for e in obj:
|
||||
pack(e, fp)
|
||||
|
||||
def _pack_map(obj, fp):
|
||||
if len(obj) <= 15:
|
||||
fp.write(struct.pack("B", 0x80 | len(obj)))
|
||||
elif len(obj) <= 2**16 - 1:
|
||||
fp.write(b"\xde" + struct.pack(">H", len(obj)))
|
||||
elif len(obj) <= 2**32 - 1:
|
||||
fp.write(b"\xdf" + struct.pack(">I", len(obj)))
|
||||
else:
|
||||
raise Exception("huge array")
|
||||
|
||||
for k, v in obj.items():
|
||||
pack(k, fp)
|
||||
pack(v, fp)
|
||||
|
||||
def pack(obj, fp):
|
||||
if obj is None:
|
||||
_pack_nil(obj, fp)
|
||||
elif isinstance(obj, bool):
|
||||
_pack_boolean(obj, fp)
|
||||
elif isinstance(obj, int):
|
||||
_pack_integer(obj, fp)
|
||||
elif isinstance(obj, float):
|
||||
_pack_float(obj, fp)
|
||||
elif isinstance(obj, str):
|
||||
_pack_string(obj, fp)
|
||||
elif isinstance(obj, bytes):
|
||||
_pack_binary(obj, fp)
|
||||
elif isinstance(obj, list) or isinstance(obj, tuple):
|
||||
_pack_array(obj, fp)
|
||||
elif isinstance(obj, dict):
|
||||
_pack_map(obj, fp)
|
||||
else:
|
||||
raise Exception("unsupported type: %s" % str(type(obj)))
|
||||
|
||||
def packb(obj):
|
||||
fp = io.BytesIO()
|
||||
pack(obj, fp)
|
||||
return fp.getvalue()
|
|
@ -1,881 +0,0 @@
|
|||
# u-msgpack-python v2.1 - vsergeev at gmail
|
||||
# https://github.com/vsergeev/u-msgpack-python
|
||||
#
|
||||
# u-msgpack-python is a lightweight MessagePack serializer and deserializer
|
||||
# module, compatible with both Python 2 and 3, as well CPython and PyPy
|
||||
# implementations of Python. u-msgpack-python is fully compliant with the
|
||||
# latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In
|
||||
# particular, it supports the new binary, UTF-8 string, and application ext
|
||||
# types.
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2013-2014 Ivan A. Sergeev
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
"""
|
||||
u-msgpack-python v2.1 - vsergeev at gmail
|
||||
https://github.com/vsergeev/u-msgpack-python
|
||||
|
||||
u-msgpack-python is a lightweight MessagePack serializer and deserializer
|
||||
module, compatible with both Python 2 and 3, as well CPython and PyPy
|
||||
implementations of Python. u-msgpack-python is fully compliant with the
|
||||
latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In
|
||||
particular, it supports the new binary, UTF-8 string, and application ext
|
||||
types.
|
||||
|
||||
License: MIT
|
||||
"""
|
||||
|
||||
__version__ = "2.1"
|
||||
"Module version string"
|
||||
|
||||
version = (2,1)
|
||||
"Module version tuple"
|
||||
|
||||
import struct
|
||||
import collections
|
||||
import sys
|
||||
import io
|
||||
|
||||
################################################################################
|
||||
### Ext Class
|
||||
################################################################################
|
||||
|
||||
# Extension type for application-defined types and data
|
||||
class Ext:
|
||||
"""
|
||||
The Ext class facilitates creating a serializable extension object to store
|
||||
an application-defined type and data byte array.
|
||||
"""
|
||||
|
||||
def __init__(self, type, data):
|
||||
"""
|
||||
Construct a new Ext object.
|
||||
|
||||
Args:
|
||||
type: application-defined type integer from 0 to 127
|
||||
data: application-defined data byte array
|
||||
|
||||
Raises:
|
||||
TypeError:
|
||||
Specified ext type is outside of 0 to 127 range.
|
||||
|
||||
Example:
|
||||
>>> foo = umsgpack.Ext(0x05, b"\x01\x02\x03")
|
||||
>>> umsgpack.packb({u"special stuff": foo, u"awesome": True})
|
||||
'\x82\xa7awesome\xc3\xadspecial stuff\xc7\x03\x05\x01\x02\x03'
|
||||
>>> bar = umsgpack.unpackb(_)
|
||||
>>> print(bar["special stuff"])
|
||||
Ext Object (Type: 0x05, Data: 01 02 03)
|
||||
>>>
|
||||
"""
|
||||
# Application ext type should be 0 <= type <= 127
|
||||
if not isinstance(type, int) or not (type >= 0 and type <= 127):
|
||||
raise TypeError("ext type out of range")
|
||||
# Check data is type bytes
|
||||
elif sys.version_info[0] == 3 and not isinstance(data, bytes):
|
||||
raise TypeError("ext data is not type \'bytes\'")
|
||||
elif sys.version_info[0] == 2 and not isinstance(data, str):
|
||||
raise TypeError("ext data is not type \'str\'")
|
||||
self.type = type
|
||||
self.data = data
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
Compare this Ext object with another for equality.
|
||||
"""
|
||||
return (isinstance(other, self.__class__) and
|
||||
self.type == other.type and
|
||||
self.data == other.data)
|
||||
|
||||
def __ne__(self, other):
|
||||
"""
|
||||
Compare this Ext object with another for inequality.
|
||||
"""
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
String representation of this Ext object.
|
||||
"""
|
||||
s = "Ext Object (Type: 0x%02x, Data: " % self.type
|
||||
for i in range(min(len(self.data), 8)):
|
||||
if i > 0:
|
||||
s += " "
|
||||
if isinstance(self.data[i], int):
|
||||
s += "%02x" % (self.data[i])
|
||||
else:
|
||||
s += "%02x" % ord(self.data[i])
|
||||
if len(self.data) > 8:
|
||||
s += " ..."
|
||||
s += ")"
|
||||
return s
|
||||
|
||||
################################################################################
|
||||
### Exceptions
|
||||
################################################################################
|
||||
|
||||
# Base Exception classes
|
||||
class PackException(Exception):
|
||||
"Base class for exceptions encountered during packing."
|
||||
pass
|
||||
class UnpackException(Exception):
|
||||
"Base class for exceptions encountered during unpacking."
|
||||
pass
|
||||
|
||||
# Packing error
|
||||
class UnsupportedTypeException(PackException):
|
||||
"Object type not supported for packing."
|
||||
pass
|
||||
|
||||
# Unpacking error
|
||||
class InsufficientDataException(UnpackException):
|
||||
"Insufficient data to unpack the encoded object."
|
||||
pass
|
||||
class InvalidStringException(UnpackException):
|
||||
"Invalid UTF-8 string encountered during unpacking."
|
||||
pass
|
||||
class ReservedCodeException(UnpackException):
|
||||
"Reserved code encountered during unpacking."
|
||||
pass
|
||||
class UnhashableKeyException(UnpackException):
|
||||
"""
|
||||
Unhashable key encountered during map unpacking.
|
||||
The serialized map cannot be deserialized into a Python dictionary.
|
||||
"""
|
||||
pass
|
||||
class DuplicateKeyException(UnpackException):
|
||||
"Duplicate key encountered during map unpacking."
|
||||
pass
|
||||
|
||||
# Backwards compatibility
|
||||
KeyNotPrimitiveException = UnhashableKeyException
|
||||
KeyDuplicateException = DuplicateKeyException
|
||||
|
||||
################################################################################
|
||||
### Exported Functions and Globals
|
||||
################################################################################
|
||||
|
||||
# Exported functions and variables, set up in __init()
|
||||
pack = None
|
||||
packb = None
|
||||
unpack = None
|
||||
unpackb = None
|
||||
dump = None
|
||||
dumps = None
|
||||
load = None
|
||||
loads = None
|
||||
|
||||
compatibility = False
|
||||
"""
|
||||
Compatibility mode boolean.
|
||||
|
||||
When compatibility mode is enabled, u-msgpack-python will serialize both
|
||||
unicode strings and bytes into the old "raw" msgpack type, and deserialize the
|
||||
"raw" msgpack type into bytes. This provides backwards compatibility with the
|
||||
old MessagePack specification.
|
||||
|
||||
Example:
|
||||
>>> umsgpack.compatibility = True
|
||||
>>>
|
||||
>>> umsgpack.packb([u"some string", b"some bytes"])
|
||||
b'\x92\xabsome string\xaasome bytes'
|
||||
>>> umsgpack.unpackb(_)
|
||||
[b'some string', b'some bytes']
|
||||
>>>
|
||||
"""
|
||||
|
||||
################################################################################
|
||||
### Packing
|
||||
################################################################################
|
||||
|
||||
# You may notice struct.pack("B", obj) instead of the simpler chr(obj) in the
|
||||
# code below. This is to allow for seamless Python 2 and 3 compatibility, as
|
||||
# chr(obj) has a str return type instead of bytes in Python 3, and
|
||||
# struct.pack(...) has the right return type in both versions.
|
||||
|
||||
def _pack_integer(obj, fp):
|
||||
if obj < 0:
|
||||
if obj >= -32:
|
||||
fp.write(struct.pack("b", obj))
|
||||
elif obj >= -2**(8-1):
|
||||
fp.write(b"\xd0" + struct.pack("b", obj))
|
||||
elif obj >= -2**(16-1):
|
||||
fp.write(b"\xd1" + struct.pack(">h", obj))
|
||||
elif obj >= -2**(32-1):
|
||||
fp.write(b"\xd2" + struct.pack(">i", obj))
|
||||
elif obj >= -2**(64-1):
|
||||
fp.write(b"\xd3" + struct.pack(">q", obj))
|
||||
else:
|
||||
raise UnsupportedTypeException("huge signed int")
|
||||
else:
|
||||
if obj <= 127:
|
||||
fp.write(struct.pack("B", obj))
|
||||
elif obj <= 2**8-1:
|
||||
fp.write(b"\xcc" + struct.pack("B", obj))
|
||||
elif obj <= 2**16-1:
|
||||
fp.write(b"\xcd" + struct.pack(">H", obj))
|
||||
elif obj <= 2**32-1:
|
||||
fp.write(b"\xce" + struct.pack(">I", obj))
|
||||
elif obj <= 2**64-1:
|
||||
fp.write(b"\xcf" + struct.pack(">Q", obj))
|
||||
else:
|
||||
raise UnsupportedTypeException("huge unsigned int")
|
||||
|
||||
def _pack_nil(obj, fp):
|
||||
fp.write(b"\xc0")
|
||||
|
||||
def _pack_boolean(obj, fp):
|
||||
fp.write(b"\xc3" if obj else b"\xc2")
|
||||
|
||||
def _pack_float(obj, fp):
|
||||
if _float_size == 64:
|
||||
fp.write(b"\xcb" + struct.pack(">d", obj))
|
||||
else:
|
||||
fp.write(b"\xca" + struct.pack(">f", obj))
|
||||
|
||||
def _pack_string(obj, fp):
|
||||
obj = obj.encode('utf-8')
|
||||
if len(obj) <= 31:
|
||||
fp.write(struct.pack("B", 0xa0 | len(obj)) + obj)
|
||||
elif len(obj) <= 2**8-1:
|
||||
fp.write(b"\xd9" + struct.pack("B", len(obj)) + obj)
|
||||
elif len(obj) <= 2**16-1:
|
||||
fp.write(b"\xda" + struct.pack(">H", len(obj)) + obj)
|
||||
elif len(obj) <= 2**32-1:
|
||||
fp.write(b"\xdb" + struct.pack(">I", len(obj)) + obj)
|
||||
else:
|
||||
raise UnsupportedTypeException("huge string")
|
||||
|
||||
def _pack_binary(obj, fp):
|
||||
if len(obj) <= 2**8-1:
|
||||
fp.write(b"\xc4" + struct.pack("B", len(obj)) + obj)
|
||||
elif len(obj) <= 2**16-1:
|
||||
fp.write(b"\xc5" + struct.pack(">H", len(obj)) + obj)
|
||||
elif len(obj) <= 2**32-1:
|
||||
fp.write(b"\xc6" + struct.pack(">I", len(obj)) + obj)
|
||||
else:
|
||||
raise UnsupportedTypeException("huge binary string")
|
||||
|
||||
def _pack_oldspec_raw(obj, fp):
|
||||
if len(obj) <= 31:
|
||||
fp.write(struct.pack("B", 0xa0 | len(obj)) + obj)
|
||||
elif len(obj) <= 2**16-1:
|
||||
fp.write(b"\xda" + struct.pack(">H", len(obj)) + obj)
|
||||
elif len(obj) <= 2**32-1:
|
||||
fp.write(b"\xdb" + struct.pack(">I", len(obj)) + obj)
|
||||
else:
|
||||
raise UnsupportedTypeException("huge raw string")
|
||||
|
||||
def _pack_ext(obj, fp):
|
||||
if len(obj.data) == 1:
|
||||
fp.write(b"\xd4" + struct.pack("B", obj.type & 0xff) + obj.data)
|
||||
elif len(obj.data) == 2:
|
||||
fp.write(b"\xd5" + struct.pack("B", obj.type & 0xff) + obj.data)
|
||||
elif len(obj.data) == 4:
|
||||
fp.write(b"\xd6" + struct.pack("B", obj.type & 0xff) + obj.data)
|
||||
elif len(obj.data) == 8:
|
||||
fp.write(b"\xd7" + struct.pack("B", obj.type & 0xff) + obj.data)
|
||||
elif len(obj.data) == 16:
|
||||
fp.write(b"\xd8" + struct.pack("B", obj.type & 0xff) + obj.data)
|
||||
elif len(obj.data) <= 2**8-1:
|
||||
fp.write(b"\xc7" + struct.pack("BB", len(obj.data), obj.type & 0xff) + obj.data)
|
||||
elif len(obj.data) <= 2**16-1:
|
||||
fp.write(b"\xc8" + struct.pack(">HB", len(obj.data), obj.type & 0xff) + obj.data)
|
||||
elif len(obj.data) <= 2**32-1:
|
||||
fp.write(b"\xc9" + struct.pack(">IB", len(obj.data), obj.type & 0xff) + obj.data)
|
||||
else:
|
||||
raise UnsupportedTypeException("huge ext data")
|
||||
|
||||
def _pack_array(obj, fp):
|
||||
if len(obj) <= 15:
|
||||
fp.write(struct.pack("B", 0x90 | len(obj)))
|
||||
elif len(obj) <= 2**16-1:
|
||||
fp.write(b"\xdc" + struct.pack(">H", len(obj)))
|
||||
elif len(obj) <= 2**32-1:
|
||||
fp.write(b"\xdd" + struct.pack(">I", len(obj)))
|
||||
else:
|
||||
raise UnsupportedTypeException("huge array")
|
||||
|
||||
for e in obj:
|
||||
pack(e, fp)
|
||||
|
||||
def _pack_map(obj, fp):
|
||||
if len(obj) <= 15:
|
||||
fp.write(struct.pack("B", 0x80 | len(obj)))
|
||||
elif len(obj) <= 2**16-1:
|
||||
fp.write(b"\xde" + struct.pack(">H", len(obj)))
|
||||
elif len(obj) <= 2**32-1:
|
||||
fp.write(b"\xdf" + struct.pack(">I", len(obj)))
|
||||
else:
|
||||
raise UnsupportedTypeException("huge array")
|
||||
|
||||
for k,v in obj.items():
|
||||
pack(k, fp)
|
||||
pack(v, fp)
|
||||
|
||||
########################################
|
||||
|
||||
# Pack for Python 2, with 'unicode' type, 'str' type, and 'long' type
|
||||
def _pack2(obj, fp):
|
||||
"""
|
||||
Serialize a Python object into MessagePack bytes.
|
||||
|
||||
Args:
|
||||
obj: a Python object
|
||||
fp: a .write()-supporting file-like object
|
||||
|
||||
Returns:
|
||||
None.
|
||||
|
||||
Raises:
|
||||
UnsupportedType(PackException):
|
||||
Object type not supported for packing.
|
||||
|
||||
Example:
|
||||
>>> f = open('test.bin', 'wb')
|
||||
>>> umsgpack.pack({u"compact": True, u"schema": 0}, f)
|
||||
>>>
|
||||
"""
|
||||
|
||||
global compatibility
|
||||
|
||||
if obj is None:
|
||||
_pack_nil(obj, fp)
|
||||
elif isinstance(obj, bool):
|
||||
_pack_boolean(obj, fp)
|
||||
elif isinstance(obj, int) or isinstance(obj, long):
|
||||
_pack_integer(obj, fp)
|
||||
elif isinstance(obj, float):
|
||||
_pack_float(obj, fp)
|
||||
elif compatibility and isinstance(obj, unicode):
|
||||
_pack_oldspec_raw(bytes(obj), fp)
|
||||
elif compatibility and isinstance(obj, bytes):
|
||||
_pack_oldspec_raw(obj, fp)
|
||||
elif isinstance(obj, unicode):
|
||||
_pack_string(obj, fp)
|
||||
elif isinstance(obj, str):
|
||||
_pack_binary(obj, fp)
|
||||
elif isinstance(obj, list) or isinstance(obj, tuple):
|
||||
_pack_array(obj, fp)
|
||||
elif isinstance(obj, dict):
|
||||
_pack_map(obj, fp)
|
||||
elif isinstance(obj, Ext):
|
||||
_pack_ext(obj, fp)
|
||||
else:
|
||||
raise UnsupportedTypeException("unsupported type: %s" % str(type(obj)))
|
||||
|
||||
# Pack for Python 3, with unicode 'str' type, 'bytes' type, and no 'long' type
|
||||
def _pack3(obj, fp):
|
||||
"""
|
||||
Serialize a Python object into MessagePack bytes.
|
||||
|
||||
Args:
|
||||
obj: a Python object
|
||||
fp: a .write()-supporting file-like object
|
||||
|
||||
Returns:
|
||||
None.
|
||||
|
||||
Raises:
|
||||
UnsupportedType(PackException):
|
||||
Object type not supported for packing.
|
||||
|
||||
Example:
|
||||
>>> f = open('test.bin', 'wb')
|
||||
>>> umsgpack.pack({u"compact": True, u"schema": 0}, f)
|
||||
>>>
|
||||
"""
|
||||
global compatibility
|
||||
|
||||
if obj is None:
|
||||
_pack_nil(obj, fp)
|
||||
elif isinstance(obj, bool):
|
||||
_pack_boolean(obj, fp)
|
||||
elif isinstance(obj, int):
|
||||
_pack_integer(obj, fp)
|
||||
elif isinstance(obj, float):
|
||||
_pack_float(obj, fp)
|
||||
elif compatibility and isinstance(obj, str):
|
||||
_pack_oldspec_raw(obj.encode('utf-8'), fp)
|
||||
elif compatibility and isinstance(obj, bytes):
|
||||
_pack_oldspec_raw(obj, fp)
|
||||
elif isinstance(obj, str):
|
||||
_pack_string(obj, fp)
|
||||
elif isinstance(obj, bytes):
|
||||
_pack_binary(obj, fp)
|
||||
elif isinstance(obj, list) or isinstance(obj, tuple):
|
||||
_pack_array(obj, fp)
|
||||
elif isinstance(obj, dict):
|
||||
_pack_map(obj, fp)
|
||||
elif isinstance(obj, Ext):
|
||||
_pack_ext(obj, fp)
|
||||
else:
|
||||
raise UnsupportedTypeException("unsupported type: %s" % str(type(obj)))
|
||||
|
||||
def _packb2(obj):
|
||||
"""
|
||||
Serialize a Python object into MessagePack bytes.
|
||||
|
||||
Args:
|
||||
obj: a Python object
|
||||
|
||||
Returns:
|
||||
A 'str' containing serialized MessagePack bytes.
|
||||
|
||||
Raises:
|
||||
UnsupportedType(PackException):
|
||||
Object type not supported for packing.
|
||||
|
||||
Example:
|
||||
>>> umsgpack.packb({u"compact": True, u"schema": 0})
|
||||
'\x82\xa7compact\xc3\xa6schema\x00'
|
||||
>>>
|
||||
"""
|
||||
fp = io.BytesIO()
|
||||
_pack2(obj, fp)
|
||||
return fp.getvalue()
|
||||
|
||||
def _packb3(obj):
|
||||
"""
|
||||
Serialize a Python object into MessagePack bytes.
|
||||
|
||||
Args:
|
||||
obj: a Python object
|
||||
|
||||
Returns:
|
||||
A 'bytes' containing serialized MessagePack bytes.
|
||||
|
||||
Raises:
|
||||
UnsupportedType(PackException):
|
||||
Object type not supported for packing.
|
||||
|
||||
Example:
|
||||
>>> umsgpack.packb({u"compact": True, u"schema": 0})
|
||||
b'\x82\xa7compact\xc3\xa6schema\x00'
|
||||
>>>
|
||||
"""
|
||||
fp = io.BytesIO()
|
||||
_pack3(obj, fp)
|
||||
return fp.getvalue()
|
||||
|
||||
################################################################################
|
||||
### Unpacking
|
||||
################################################################################
|
||||
|
||||
def _read_except(fp, n):
|
||||
data = fp.read(n)
|
||||
if len(data) < n:
|
||||
raise InsufficientDataException()
|
||||
return data
|
||||
|
||||
def _unpack_integer(code, fp):
|
||||
if (ord(code) & 0xe0) == 0xe0:
|
||||
return struct.unpack("b", code)[0]
|
||||
elif code == b'\xd0':
|
||||
return struct.unpack("b", _read_except(fp, 1))[0]
|
||||
elif code == b'\xd1':
|
||||
return struct.unpack(">h", _read_except(fp, 2))[0]
|
||||
elif code == b'\xd2':
|
||||
return struct.unpack(">i", _read_except(fp, 4))[0]
|
||||
elif code == b'\xd3':
|
||||
return struct.unpack(">q", _read_except(fp, 8))[0]
|
||||
elif (ord(code) & 0x80) == 0x00:
|
||||
return struct.unpack("B", code)[0]
|
||||
elif code == b'\xcc':
|
||||
return struct.unpack("B", _read_except(fp, 1))[0]
|
||||
elif code == b'\xcd':
|
||||
return struct.unpack(">H", _read_except(fp, 2))[0]
|
||||
elif code == b'\xce':
|
||||
return struct.unpack(">I", _read_except(fp, 4))[0]
|
||||
elif code == b'\xcf':
|
||||
return struct.unpack(">Q", _read_except(fp, 8))[0]
|
||||
raise Exception("logic error, not int: 0x%02x" % ord(code))
|
||||
|
||||
def _unpack_reserved(code, fp):
|
||||
if code == b'\xc1':
|
||||
raise ReservedCodeException("encountered reserved code: 0x%02x" % ord(code))
|
||||
raise Exception("logic error, not reserved code: 0x%02x" % ord(code))
|
||||
|
||||
def _unpack_nil(code, fp):
|
||||
if code == b'\xc0':
|
||||
return None
|
||||
raise Exception("logic error, not nil: 0x%02x" % ord(code))
|
||||
|
||||
def _unpack_boolean(code, fp):
|
||||
if code == b'\xc2':
|
||||
return False
|
||||
elif code == b'\xc3':
|
||||
return True
|
||||
raise Exception("logic error, not boolean: 0x%02x" % ord(code))
|
||||
|
||||
def _unpack_float(code, fp):
|
||||
if code == b'\xca':
|
||||
return struct.unpack(">f", _read_except(fp, 4))[0]
|
||||
elif code == b'\xcb':
|
||||
return struct.unpack(">d", _read_except(fp, 8))[0]
|
||||
raise Exception("logic error, not float: 0x%02x" % ord(code))
|
||||
|
||||
def _unpack_string(code, fp):
|
||||
if (ord(code) & 0xe0) == 0xa0:
|
||||
length = ord(code) & ~0xe0
|
||||
elif code == b'\xd9':
|
||||
length = struct.unpack("B", _read_except(fp, 1))[0]
|
||||
elif code == b'\xda':
|
||||
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
||||
elif code == b'\xdb':
|
||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||
else:
|
||||
raise Exception("logic error, not string: 0x%02x" % ord(code))
|
||||
|
||||
# Always return raw bytes in compatibility mode
|
||||
global compatibility
|
||||
if compatibility:
|
||||
return _read_except(fp, length)
|
||||
|
||||
try:
|
||||
return bytes.decode(_read_except(fp, length), 'utf-8')
|
||||
except UnicodeDecodeError:
|
||||
raise InvalidStringException("unpacked string is not utf-8")
|
||||
|
||||
def _unpack_binary(code, fp):
|
||||
if code == b'\xc4':
|
||||
length = struct.unpack("B", _read_except(fp, 1))[0]
|
||||
elif code == b'\xc5':
|
||||
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
||||
elif code == b'\xc6':
|
||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||
else:
|
||||
raise Exception("logic error, not binary: 0x%02x" % ord(code))
|
||||
|
||||
return _read_except(fp, length)
|
||||
|
||||
def _unpack_ext(code, fp):
|
||||
if code == b'\xd4':
|
||||
length = 1
|
||||
elif code == b'\xd5':
|
||||
length = 2
|
||||
elif code == b'\xd6':
|
||||
length = 4
|
||||
elif code == b'\xd7':
|
||||
length = 8
|
||||
elif code == b'\xd8':
|
||||
length = 16
|
||||
elif code == b'\xc7':
|
||||
length = struct.unpack("B", _read_except(fp, 1))[0]
|
||||
elif code == b'\xc8':
|
||||
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
||||
elif code == b'\xc9':
|
||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||
else:
|
||||
raise Exception("logic error, not ext: 0x%02x" % ord(code))
|
||||
|
||||
return Ext(ord(_read_except(fp, 1)), _read_except(fp, length))
|
||||
|
||||
def _unpack_array(code, fp):
|
||||
if (ord(code) & 0xf0) == 0x90:
|
||||
length = (ord(code) & ~0xf0)
|
||||
elif code == b'\xdc':
|
||||
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
||||
elif code == b'\xdd':
|
||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||
else:
|
||||
raise Exception("logic error, not array: 0x%02x" % ord(code))
|
||||
|
||||
return [_unpack(fp) for i in xrange(length)]
|
||||
|
||||
def _deep_list_to_tuple(obj):
|
||||
if isinstance(obj, list):
|
||||
return tuple([_deep_list_to_tuple(e) for e in obj])
|
||||
return obj
|
||||
|
||||
def _unpack_map(code, fp):
|
||||
if (ord(code) & 0xf0) == 0x80:
|
||||
length = (ord(code) & ~0xf0)
|
||||
elif code == b'\xde':
|
||||
length = struct.unpack(">H", _read_except(fp, 2))[0]
|
||||
elif code == b'\xdf':
|
||||
length = struct.unpack(">I", _read_except(fp, 4))[0]
|
||||
else:
|
||||
raise Exception("logic error, not map: 0x%02x" % ord(code))
|
||||
|
||||
d = {}
|
||||
for i in xrange(length):
|
||||
# Unpack key
|
||||
k = _unpack(fp)
|
||||
|
||||
if isinstance(k, list):
|
||||
# Attempt to convert list into a hashable tuple
|
||||
k = _deep_list_to_tuple(k)
|
||||
elif not isinstance(k, collections.Hashable):
|
||||
raise UnhashableKeyException("encountered unhashable key: %s, %s" % (str(k), str(type(k))))
|
||||
elif k in d:
|
||||
raise DuplicateKeyException("encountered duplicate key: %s, %s" % (str(k), str(type(k))))
|
||||
|
||||
# Unpack value
|
||||
v = _unpack(fp)
|
||||
|
||||
try:
|
||||
d[k] = v
|
||||
except TypeError:
|
||||
raise UnhashableKeyException("encountered unhashable key: %s" % str(k))
|
||||
return d
|
||||
|
||||
def _unpack(fp):
|
||||
code = _read_except(fp, 1)
|
||||
return _unpack_dispatch_table[code](code, fp)
|
||||
|
||||
########################################
|
||||
|
||||
def _unpack2(fp):
|
||||
"""
|
||||
Deserialize MessagePack bytes into a Python object.
|
||||
|
||||
Args:
|
||||
fp: a .read()-supporting file-like object
|
||||
|
||||
Returns:
|
||||
A Python object.
|
||||
|
||||
Raises:
|
||||
InsufficientDataException(UnpackException):
|
||||
Insufficient data to unpack the encoded object.
|
||||
InvalidStringException(UnpackException):
|
||||
Invalid UTF-8 string encountered during unpacking.
|
||||
ReservedCodeException(UnpackException):
|
||||
Reserved code encountered during unpacking.
|
||||
UnhashableKeyException(UnpackException):
|
||||
Unhashable key encountered during map unpacking.
|
||||
The serialized map cannot be deserialized into a Python dictionary.
|
||||
DuplicateKeyException(UnpackException):
|
||||
Duplicate key encountered during map unpacking.
|
||||
|
||||
Example:
|
||||
>>> f = open('test.bin', 'rb')
|
||||
>>> umsgpack.unpackb(f)
|
||||
{u'compact': True, u'schema': 0}
|
||||
>>>
|
||||
"""
|
||||
return _unpack(fp)
|
||||
|
||||
def _unpack3(fp):
|
||||
"""
|
||||
Deserialize MessagePack bytes into a Python object.
|
||||
|
||||
Args:
|
||||
fp: a .read()-supporting file-like object
|
||||
|
||||
Returns:
|
||||
A Python object.
|
||||
|
||||
Raises:
|
||||
InsufficientDataException(UnpackException):
|
||||
Insufficient data to unpack the encoded object.
|
||||
InvalidStringException(UnpackException):
|
||||
Invalid UTF-8 string encountered during unpacking.
|
||||
ReservedCodeException(UnpackException):
|
||||
Reserved code encountered during unpacking.
|
||||
UnhashableKeyException(UnpackException):
|
||||
Unhashable key encountered during map unpacking.
|
||||
The serialized map cannot be deserialized into a Python dictionary.
|
||||
DuplicateKeyException(UnpackException):
|
||||
Duplicate key encountered during map unpacking.
|
||||
|
||||
Example:
|
||||
>>> f = open('test.bin', 'rb')
|
||||
>>> umsgpack.unpackb(f)
|
||||
{'compact': True, 'schema': 0}
|
||||
>>>
|
||||
"""
|
||||
return _unpack(fp)
|
||||
|
||||
# For Python 2, expects a str object
|
||||
def _unpackb2(s):
|
||||
"""
|
||||
Deserialize MessagePack bytes into a Python object.
|
||||
|
||||
Args:
|
||||
s: a 'str' containing serialized MessagePack bytes
|
||||
|
||||
Returns:
|
||||
A Python object.
|
||||
|
||||
Raises:
|
||||
TypeError:
|
||||
Packed data is not type 'str'.
|
||||
InsufficientDataException(UnpackException):
|
||||
Insufficient data to unpack the encoded object.
|
||||
InvalidStringException(UnpackException):
|
||||
Invalid UTF-8 string encountered during unpacking.
|
||||
ReservedCodeException(UnpackException):
|
||||
Reserved code encountered during unpacking.
|
||||
UnhashableKeyException(UnpackException):
|
||||
Unhashable key encountered during map unpacking.
|
||||
The serialized map cannot be deserialized into a Python dictionary.
|
||||
DuplicateKeyException(UnpackException):
|
||||
Duplicate key encountered during map unpacking.
|
||||
|
||||
Example:
|
||||
>>> umsgpack.unpackb(b'\x82\xa7compact\xc3\xa6schema\x00')
|
||||
{u'compact': True, u'schema': 0}
|
||||
>>>
|
||||
"""
|
||||
if not isinstance(s, str):
|
||||
raise TypeError("packed data is not type 'str'")
|
||||
return _unpack(io.BytesIO(s))
|
||||
|
||||
# For Python 3, expects a bytes object
|
||||
def _unpackb3(s):
|
||||
"""
|
||||
Deserialize MessagePack bytes into a Python object.
|
||||
|
||||
Args:
|
||||
s: a 'bytes' containing serialized MessagePack bytes
|
||||
|
||||
Returns:
|
||||
A Python object.
|
||||
|
||||
Raises:
|
||||
TypeError:
|
||||
Packed data is not type 'bytes'.
|
||||
InsufficientDataException(UnpackException):
|
||||
Insufficient data to unpack the encoded object.
|
||||
InvalidStringException(UnpackException):
|
||||
Invalid UTF-8 string encountered during unpacking.
|
||||
ReservedCodeException(UnpackException):
|
||||
Reserved code encountered during unpacking.
|
||||
UnhashableKeyException(UnpackException):
|
||||
Unhashable key encountered during map unpacking.
|
||||
The serialized map cannot be deserialized into a Python dictionary.
|
||||
DuplicateKeyException(UnpackException):
|
||||
Duplicate key encountered during map unpacking.
|
||||
|
||||
Example:
|
||||
>>> umsgpack.unpackb(b'\x82\xa7compact\xc3\xa6schema\x00')
|
||||
{'compact': True, 'schema': 0}
|
||||
>>>
|
||||
"""
|
||||
if not isinstance(s, bytes):
|
||||
raise TypeError("packed data is not type 'bytes'")
|
||||
return _unpack(io.BytesIO(s))
|
||||
|
||||
################################################################################
|
||||
### Module Initialization
|
||||
################################################################################
|
||||
|
||||
def __init():
|
||||
global pack
|
||||
global packb
|
||||
global unpack
|
||||
global unpackb
|
||||
global dump
|
||||
global dumps
|
||||
global load
|
||||
global loads
|
||||
global compatibility
|
||||
global _float_size
|
||||
global _unpack_dispatch_table
|
||||
global xrange
|
||||
|
||||
# Compatibility mode for handling strings/bytes with the old specification
|
||||
compatibility = False
|
||||
|
||||
# Auto-detect system float precision
|
||||
if sys.float_info.mant_dig == 53:
|
||||
_float_size = 64
|
||||
else:
|
||||
_float_size = 32
|
||||
|
||||
# Map packb and unpackb to the appropriate version
|
||||
if sys.version_info[0] == 3:
|
||||
pack = _pack3
|
||||
packb = _packb3
|
||||
dump = _pack3
|
||||
dumps = _packb3
|
||||
unpack = _unpack3
|
||||
unpackb = _unpackb3
|
||||
load = _unpack3
|
||||
loads = _unpackb3
|
||||
xrange = range
|
||||
else:
|
||||
pack = _pack2
|
||||
packb = _packb2
|
||||
dump = _pack2
|
||||
dumps = _packb2
|
||||
unpack = _unpack2
|
||||
unpackb = _unpackb2
|
||||
load = _unpack2
|
||||
loads = _unpackb2
|
||||
|
||||
# Build a dispatch table for fast lookup of unpacking function
|
||||
|
||||
_unpack_dispatch_table = {}
|
||||
# Fix uint
|
||||
for code in range(0, 0x7f+1):
|
||||
_unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer
|
||||
# Fix map
|
||||
for code in range(0x80, 0x8f+1):
|
||||
_unpack_dispatch_table[struct.pack("B", code)] = _unpack_map
|
||||
# Fix array
|
||||
for code in range(0x90, 0x9f+1):
|
||||
_unpack_dispatch_table[struct.pack("B", code)] = _unpack_array
|
||||
# Fix str
|
||||
for code in range(0xa0, 0xbf+1):
|
||||
_unpack_dispatch_table[struct.pack("B", code)] = _unpack_string
|
||||
# Nil
|
||||
_unpack_dispatch_table[b'\xc0'] = _unpack_nil
|
||||
# Reserved
|
||||
_unpack_dispatch_table[b'\xc1'] = _unpack_reserved
|
||||
# Boolean
|
||||
_unpack_dispatch_table[b'\xc2'] = _unpack_boolean
|
||||
_unpack_dispatch_table[b'\xc3'] = _unpack_boolean
|
||||
# Bin
|
||||
for code in range(0xc4, 0xc6+1):
|
||||
_unpack_dispatch_table[struct.pack("B", code)] = _unpack_binary
|
||||
# Ext
|
||||
for code in range(0xc7, 0xc9+1):
|
||||
_unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext
|
||||
# Float
|
||||
_unpack_dispatch_table[b'\xca'] = _unpack_float
|
||||
_unpack_dispatch_table[b'\xcb'] = _unpack_float
|
||||
# Uint
|
||||
for code in range(0xcc, 0xcf+1):
|
||||
_unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer
|
||||
# Int
|
||||
for code in range(0xd0, 0xd3+1):
|
||||
_unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer
|
||||
# Fixext
|
||||
for code in range(0xd4, 0xd8+1):
|
||||
_unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext
|
||||
# String
|
||||
for code in range(0xd9, 0xdb+1):
|
||||
_unpack_dispatch_table[struct.pack("B", code)] = _unpack_string
|
||||
# Array
|
||||
_unpack_dispatch_table[b'\xdc'] = _unpack_array
|
||||
_unpack_dispatch_table[b'\xdd'] = _unpack_array
|
||||
# Map
|
||||
_unpack_dispatch_table[b'\xde'] = _unpack_map
|
||||
_unpack_dispatch_table[b'\xdf'] = _unpack_map
|
||||
# Negative fixint
|
||||
for code in range(0xe0, 0xff+1):
|
||||
_unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer
|
||||
|
||||
__init()
|
|
@ -73,7 +73,7 @@ def make_set_target(stage, node_group, node, currentNode=None, target_index=1, v
|
|||
|
||||
# First param is viewport scale
|
||||
if len(stage['params']) == 0:
|
||||
stage['params'].append(viewport_scale)
|
||||
stage['params'].append(str(viewport_scale))
|
||||
|
||||
currentNode = nodes.find_node_by_link(node_group, currentNode, currentNode.inputs[target_index])
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ def init_properties():
|
|||
bpy.types.World.arm_minimize = BoolProperty(name="Minimize Data", description="Export scene data in binary", default=True, update=assets.invalidate_compiled_data)
|
||||
bpy.types.World.arm_optimize_mesh = BoolProperty(name="Optimize Meshes", description="Export more efficient geometry indices, can prolong build times", default=False, update=assets.invalidate_mesh_data)
|
||||
bpy.types.World.arm_sampled_animation = BoolProperty(name="Sampled Animation", description="Export object animation as raw matrices", default=False, update=assets.invalidate_compiled_data)
|
||||
bpy.types.World.arm_deinterleaved_buffers = BoolProperty(name="Deinterleaved Buffers", description="Use deinterleaved vertex buffers", default=False)
|
||||
bpy.types.World.arm_deinterleaved_buffers = BoolProperty(name="Deinterleaved Buffers", description="Use deinterleaved vertex buffers", default=True)
|
||||
bpy.types.World.arm_export_tangents = BoolProperty(name="Export Tangents", description="Precompute tangents for normal mapping, otherwise computed in shader", default=True, update=assets.invalidate_compiled_data)
|
||||
bpy.types.World.arm_batch_meshes = BoolProperty(name="Batch Meshes", description="Group meshes by materials to speed up rendering", default=False)
|
||||
bpy.types.World.arm_batch_materials = BoolProperty(name="Batch Materials", description="Marge similar materials into single pipeline state", default=False, update=assets.invalidate_shader_cache)
|
||||
|
|
|
@ -5,19 +5,19 @@ import glob
|
|||
import platform
|
||||
import zipfile
|
||||
import re
|
||||
import arm.lib.umsgpack
|
||||
import arm.lib.armpack
|
||||
|
||||
def write_arm(filepath, output):
|
||||
if filepath.endswith('.zip'):
|
||||
with zipfile.ZipFile(filepath, 'w', zipfile.ZIP_DEFLATED) as zip_file:
|
||||
if bpy.data.worlds['Arm'].arm_minimize:
|
||||
zip_file.writestr('data.arm', arm.lib.umsgpack.dumps(output))
|
||||
zip_file.writestr('data.arm', arm.lib.armpack.packb(output))
|
||||
else:
|
||||
zip_file.writestr('data.arm', json.dumps(output, sort_keys=True, indent=4))
|
||||
else:
|
||||
if bpy.data.worlds['Arm'].arm_minimize:
|
||||
with open(filepath, 'wb') as f:
|
||||
f.write(arm.lib.umsgpack.dumps(output))
|
||||
f.write(arm.lib.armpack.packb(output))
|
||||
else:
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(json.dumps(output, sort_keys=True, indent=4))
|
||||
|
|
Loading…
Reference in a new issue