Last active
February 27, 2018 14:04
-
-
Save Pupix/cafcae7e755134e105521b02c6454a6f to your computer and use it in GitHub Desktop.
three.js League of Legends .skl loader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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