Skip to content

Instantly share code, notes, and snippets.

@Pupix
Last active February 27, 2018 14:04
Show Gist options
  • Save Pupix/cafcae7e755134e105521b02c6454a6f to your computer and use it in GitHub Desktop.
Save Pupix/cafcae7e755134e105521b02c6454a6f to your computer and use it in GitHub Desktop.
three.js League of Legends .skl loader
/**
* @author Pupix / https://github.com/pupix
*/
THREE.SKLLoader = function ( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
};
THREE.SKLLoader.prototype = {
constructor: THREE.SKLLoader,
load: function ( url, onLoad, onProgress, onError ) {
var self = this;
var loader = new THREE.XHRLoader(self.manager);
loader.setResponseType('arraybuffer');
loader.load(url, function (buffer) {
onLoad(self.parse(buffer));
}, onProgress, onError);
},
setCrossOrigin: function (value) {
this.crossOrigin = value;
},
parse: function (buffer) {
console.time('SKLLoader');
this.parser = new THREE.FileParser(buffer);
var skl = {
header: {},
bones: []
},
skeleton = []
skl.header.magic = this.parser.string(8);
skl.header.version = this.parser.int32();
if (skl.header.version < 0 || skl.header.version > 2) {
return console.error('SKL version unsupported.');
}
this['_parseV' + skl.header.version](skl);
this['_readV' + skl.header.version](skl, skeleton);
console.timeEnd('SKLLoader');
return {skeleton: skeleton, skl: skl};
},
_parseV0: function (skl) {
var parser = this.parser,
boneName,
bones,
i;
skl.unks = {};
skl.unks[parser.tell()] = parser.int16();
skl.boneCounter = parser.int16();
skl.boneIndicesCounter = parser.int32();
skl.offsets = {};
skl.offsets.bonesStart = parser.int32();
skl.offsets.animationStart = parser.int32();
skl.offsets.boneIndicesStart = parser.int32();
skl.offsets.boneIndicesEnd = parser.int32();
skl.offsets.halfwayBetweenBoneindicesAndStrings = parser.int32();
skl.offsets.boneNamesStart = parser.int32();
skl.offsets.padding = parser.string(20);
for (i = 0; i < skl.boneCounter; i += 1) {
skl.bones.push({
unk0: parser.int16(),
id: parser.int16(),
parent: parser.int16(),
unk1: parser.int16(),
hash: parser.int32(),
twoPointOne: parser.float(),
position: {
x: parser.float(),
y: parser.float(),
z: parser.float()
},
scale: {
x: parser.float(),
y: parser.float(),
z: parser.float()
},
quaternion: {
x: parser.float(),
y: parser.float(),
z: parser.float(),
w: parser.float()
},
ct: {
x: parser.float(),
y: parser.float(),
z: parser.float()
},
padding: parser.string(32)
});
}
skl.bonesExtra = [];
for (i = 0; i < skl.boneCounter; i += 1) {
skl.bonesExtra.push({
boneId: parser.int32(),
boneHash: parser.int32()
});
}
skl.boneIndices = parser.int16(skl.boneIndicesCounter);
parser.seek(skl.offsets.boneNamesStart);
for (i = 0, skl.boneNames = []; i < skl.boneCounter; i += 1) {
boneName = '';
do {
boneName += parser.string(4);
} while (boneName.indexOf('\u0000') === -1);
skl.boneNames.push(boneName);
}
return skl;
},
_parseV1: function (skl) {
var parser = this.parser,
i;
skl.header.designerId = parser.int32();
skl.boneCounter = parser.int32();
for (i = 0; i < skl.boneCounter; i += 1) {
skl.bones.push({
name: parser.string(32),
parent: parser.int32(),
scale: parser.float(),
matrix: parser.float(12)
});
}
return skl;
},
_parseV2: function (skl) {
this._parseV1(skl);
const parser = this.parser;
skl.boneIndicesCounter = parser.int32();
skl.boneIndices = parser.int32(skl.boneIndicesCounter);
},
_readV0: function (skl, skeleton) {
var bone,
i;
for (i = 0; i < skl.bones.length; i += 1) {
bone = new THREE.Bone();
bone.name = skl.bones[i].name || skl.boneNames[i];
bone.name = bone.name.slice(0, bone.name.indexOf('\u0000'));
bone.hash = skl.bones[i].hash || this._createBoneHash(bone.name);
bone.position.set(
skl.bones[i].position.x,
skl.bones[i].position.y,
skl.bones[i].position.z
);
bone.scale.set(
skl.bones[i].scale.x,
skl.bones[i].scale.y,
skl.bones[i].scale.z
);
bone.quaternion.set(
skl.bones[i].quaternion.x,
skl.bones[i].quaternion.y,
skl.bones[i].quaternion.z,
skl.bones[i].quaternion.w
);
if (skeleton[skl.bones[i].parent]) {
skeleton[skl.bones[i].parent].add(bone);
}
skeleton.push(bone);
}
},
_readV1: function (skl, skeleton) {
var bone,
matrix,
i;
for (i = 0; i < skl.bones.length; i += 1) {
bone = new THREE.Bone();
bone.name = skl.bones[i].name;
bone.name = bone.name.slice(0, bone.name.indexOf('\u0000'));
bone.hash = this._createBoneHash(bone.name);
matrix = new THREE.Matrix4();
matrix.set.apply(matrix, skl.bones[i].matrix.concat([0, 0, 0, 1]));
if (skeleton[skl.bones[i].parent]) {
bone.matrix.getInverse(skeleton[skl.bones[i].parent].matrixWorld);
bone.matrix.multiply(bone.matrixWorld);
skeleton[skl.bones[i].parent].add(bone);
}
skeleton.push(bone);
}
},
_readV2: function (skl, skeleton) {
this._readV1(skl, skeleton);
},
_createBoneHash: function (name) {
var hash = 0,
mask = 4026531840,
i;
for (i = 0; i < name.length; i += 1) {
hash = parseInt(name.charCodeAt(i) + (16 * (hash >>> 0)), 10) >>> 0;
if ((hash & mask) !== 0) {
hash ^= hash & mask ^ ((hash & mask) >>> 24);
}
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment