1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047 |
- /**
- * @author takahiro / https://github.com/takahirox
- *
- * Dependencies
- * charset-encoder-js https://github.com/takahirox/charset-encoder-js
- *
- *
- * This loader loads and parses PMD/PMX and VMD binary files
- * then creates mesh for Three.js.
- *
- * PMD/PMX is a model data format and VMD is a motion data format
- * used in MMD(Miku Miku Dance).
- *
- * MMD is a 3D CG animation tool which is popular in Japan.
- *
- *
- * MMD official site
- * http://www.geocities.jp/higuchuu4/index_e.htm
- *
- * PMD, VMD format
- * http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
- *
- * PMX format
- * http://gulshan-i-raz.geo.jp/labs/2012/10/17/pmx-format1/
- *
- * Model data requirements
- * convert .tga files to .png files if exist. (Should I use THREE.TGALoader?)
- * resize the texture image files to power_of_2*power_of_2
- *
- *
- * TODO
- * separate model/vmd loaders.
- * multi vmd files support.
- * edge(outline) support.
- * culling support.
- * toon(cel) shadering support.
- * add-sphere-mapping support.
- * physics support.
- * camera motion in vmd support.
- * light motion in vmd support.
- * music support.
- * make own shader for the performance and functionarity.
- * SDEF support.
- * uv/material/bone morphing support.
- * tga file loading support.
- * supply skinning support.
- * shadow support.
- */
- THREE.MMDLoader = function ( showStatus, manager ) {
- THREE.Loader.call( this, showStatus );
- this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
- };
- THREE.MMDLoader.prototype = Object.create( THREE.Loader.prototype );
- THREE.MMDLoader.prototype.constructor = THREE.MMDLoader;
- THREE.MMDLoader.prototype.extractExtension = function ( url ) {
- var index = url.lastIndexOf( '.' );
- if ( index < 0 ) {
- return null;
- }
- return url.slice( index + 1 );
- };
- THREE.MMDLoader.prototype.load = function ( modelUrl, vmdUrl, callback, onProgress, onError ) {
- var texturePath = this.extractUrlBase( modelUrl );
- var modelExtension = this.extractExtension( modelUrl );
- this.loadModelFile( modelUrl, vmdUrl, texturePath, modelExtension, callback, onProgress, onError );
- };
- THREE.MMDLoader.prototype.loadFileAsBuffer = function ( url, onLoad, onProgress, onError ) {
- var loader = new THREE.XHRLoader( this.manager );
- loader.setCrossOrigin( this.crossOrigin );
- loader.setResponseType( 'arraybuffer' );
- loader.load( url, function ( buffer ) {
- onLoad( buffer );
- }, onProgress, onError );
- };
- THREE.MMDLoader.prototype.loadModelFile = function ( modelUrl, vmdUrl, texturePath, modelExtension, callback, onProgress, onError ) {
- var scope = this;
- this.loadFileAsBuffer( modelUrl, function ( buffer ) {
- scope.loadVmdFile( buffer, vmdUrl, texturePath, modelExtension, callback, onProgress, onError );
- }, onProgress, onError );
- };
- THREE.MMDLoader.prototype.loadVmdFile = function ( modelBuffer, vmdUrl, texturePath, modelExtension, callback, onProgress, onError ) {
- var scope = this;
- if ( ! vmdUrl ) {
- scope.parse( modelBuffer, null, texturePath, modelExtension, callback );
- return;
- }
- this.loadFileAsBuffer( vmdUrl, function ( buffer ) {
- scope.parse( modelBuffer, buffer, texturePath, modelExtension, callback );
- }, onProgress, onError );
- };
- THREE.MMDLoader.prototype.parse = function ( modelBuffer, vmdBuffer, texturePath, modelExtension, callback ) {
- var model = this.parseModel( modelBuffer, modelExtension );
- var vmd = vmdBuffer !== null ? this.parseVmd( vmdBuffer ) : null;
- var mesh = this.createMesh( model, vmd, texturePath );
- callback( mesh );
- };
- THREE.MMDLoader.prototype.parseModel = function ( buffer, modelExtension ) {
- // Should I judge from model data header?
- switch( modelExtension.toLowerCase() ) {
- case 'pmd':
- return this.parsePmd( buffer );
- case 'pmx':
- return this.parsePmx( buffer );
- default:
- throw 'extension ' + modelExtension + ' is not supported.';
- }
- };
- THREE.MMDLoader.prototype.parsePmd = function ( buffer ) {
- var scope = this;
- var pmd = {};
- var dv = new THREE.MMDLoader.DataView( buffer );
- pmd.metadata = {};
- pmd.metadata.format = 'pmd';
- var parseHeader = function () {
- var metadata = pmd.metadata;
- metadata.magic = dv.getChars( 3 );
- if ( metadata.magic !== 'Pmd' ) {
- throw 'PMD file magic is not Pmd, but ' + metadata.magic;
- }
- metadata.version = dv.getFloat32();
- metadata.modelName = dv.getSjisStringsAsUnicode( 20 );
- metadata.comment = dv.getSjisStringsAsUnicode( 256 );
- };
- var parseVertices = function () {
- var parseVertex = function () {
- var p = {};
- p.position = dv.getFloat32Array( 3 );
- p.normal = dv.getFloat32Array( 3 );
- p.uv = dv.getFloat32Array( 2 );
- p.skinIndices = dv.getUint16Array( 2 );
- p.skinWeights = [ dv.getUint8() / 100 ];
- p.skinWeights.push( 1.0 - p.skinWeights[ 0 ] );
- p.edgeFlag = dv.getUint8();
- return p;
- };
- var metadata = pmd.metadata;
- metadata.vertexCount = dv.getUint32();
- pmd.vertices = [];
- for ( var i = 0; i < metadata.vertexCount; i++ ) {
- pmd.vertices.push( parseVertex() );
- }
- };
- var parseFaces = function () {
- var parseFace = function () {
- var p = {};
- p.indices = dv.getUint16Array( 3 );
- return p;
- };
- var metadata = pmd.metadata;
- metadata.faceCount = dv.getUint32() / 3;
- pmd.faces = [];
- for ( var i = 0; i < metadata.faceCount; i++ ) {
- pmd.faces.push( parseFace() );
- }
- };
- var parseMaterials = function () {
- var parseMaterial = function () {
- var p = {};
- p.diffuse = dv.getFloat32Array( 4 );
- p.shiness = dv.getFloat32();
- p.specular = dv.getFloat32Array( 3 );
- p.emissive = dv.getFloat32Array( 3 );
- p.toonIndex = dv.getUint8();
- p.edgeFlag = dv.getUint8();
- p.faceCount = dv.getUint32() / 3;
- p.fileName = dv.getChars( 20 );
- return p;
- };
- var metadata = pmd.metadata;
- metadata.materialCount = dv.getUint32();
- pmd.materials = [];
- for ( var i = 0; i < metadata.materialCount; i++ ) {
- pmd.materials.push( parseMaterial() );
- }
- };
- var parseBones = function () {
- var parseBone = function () {
- var p = {};
- // Skinning animation doesn't work when bone name is Japanese Unicode in r73.
- // So using charcode strings as workaround and keep original strings in .originalName.
- p.originalName = dv.getSjisStringsAsUnicode( 20 );
- p.name = dv.toCharcodeStrings( p.originalName );
- p.parentIndex = dv.getUint16();
- p.tailIndex = dv.getUint16();
- p.type = dv.getUint8();
- p.ikIndex = dv.getUint16();
- p.position = dv.getFloat32Array( 3 );
- return p;
- };
- var metadata = pmd.metadata;
- metadata.boneCount = dv.getUint16();
- pmd.bones = [];
- for ( var i = 0; i < metadata.boneCount; i++ ) {
- pmd.bones.push( parseBone() );
- }
- };
- var parseIks = function () {
- var parseIk = function () {
- var p = {};
- p.target = dv.getUint16();
- p.effector = dv.getUint16();
- p.linkCount = dv.getUint8();
- p.iteration = dv.getUint16();
- p.maxAngle = dv.getFloat32();
- p.links = [];
- for ( var i = 0; i < p.linkCount; i++ ) {
- var link = {}
- link.index = dv.getUint16();
- p.links.push( link );
- }
- return p;
- };
- var metadata = pmd.metadata;
- metadata.ikCount = dv.getUint16();
- pmd.iks = [];
- for ( var i = 0; i < metadata.ikCount; i++ ) {
- pmd.iks.push( parseIk() );
- }
- };
- var parseMorphs = function () {
- var parseMorph = function () {
- var p = {};
- p.name = dv.getSjisStringsAsUnicode( 20 );
- p.elementCount = dv.getUint32();
- p.type = dv.getUint8();
- p.elements = [];
- for ( var i = 0; i < p.elementCount; i++ ) {
- p.elements.push( {
- index: dv.getUint32(),
- position: dv.getFloat32Array( 3 )
- } ) ;
- }
- return p;
- };
- var metadata = pmd.metadata;
- metadata.morphCount = dv.getUint16();
- pmd.morphs = [];
- for ( var i = 0; i < metadata.morphCount; i++ ) {
- pmd.morphs.push( parseMorph() );
- }
- };
- parseHeader();
- parseVertices();
- parseFaces();
- parseMaterials();
- parseBones();
- parseIks();
- parseMorphs();
- return pmd;
- };
- THREE.MMDLoader.prototype.parsePmx = function ( buffer ) {
- var scope = this;
- var pmx = {};
- var dv = new THREE.MMDLoader.DataView( buffer );
- pmx.metadata = {};
- pmx.metadata.format = 'pmx';
- var parseHeader = function () {
- var metadata = pmx.metadata;
- metadata.magic = dv.getChars( 4 );
- // Note: don't remove the last blank space.
- if ( metadata.magic !== 'PMX ' ) {
- throw 'PMX file magic is not PMX , but ' + metadata.magic;
- }
- metadata.version = dv.getFloat32();
- if ( metadata.version !== 2.0 && metadata.version !== 2.1 ) {
- throw 'PMX version ' + metadata.version + ' is not supported.';
- }
- metadata.headerSize = dv.getUint8();
- metadata.encoding = dv.getUint8();
- metadata.additionalUvNum = dv.getUint8();
- metadata.vertexIndexSize = dv.getUint8();
- metadata.textureIndexSize = dv.getUint8();
- metadata.materialIndexSize = dv.getUint8();
- metadata.boneIndexSize = dv.getUint8();
- metadata.morphIndexSize = dv.getUint8();
- metadata.rigidbodyIndexSize = dv.getUint8();
- metadata.modelName = dv.getTextBuffer();
- metadata.englishModelName = dv.getTextBuffer();
- metadata.comment = dv.getTextBuffer();
- metadata.englishComment = dv.getTextBuffer();
- };
- var parseVertices = function () {
- var parseVertex = function () {
- var p = {};
- p.position = dv.getFloat32Array( 3 );
- p.normal = dv.getFloat32Array( 3 );
- p.uv = dv.getFloat32Array( 2 );
- p.auvs = [];
- for ( var i = 0; i < pmx.metadata.additionalUvNum; i++ ) {
- p.auvs.push( dv.getFloat32Array( 4 ) );
- }
- p.type = dv.getUint8();
- var indexSize = metadata.vertexIndexSize;
- if ( p.type === 0 ) { // BDEF1
- p.skinIndices = dv.getNumberArray( indexSize, 1 );
- p.skinWeights = [ 1.0 ];
- } else if ( p.type === 1 ) { // BDEF2
- p.skinIndices = dv.getNumberArray( indexSize, 2 );
- p.skinWeights = dv.getFloat32Array( 1 );
- p.skinWeights.push( 1.0 - p.skinWeights[ 0 ] );
- } else if ( p.type === 2 ) { // BDEF4
- p.skinIndices = dv.getNumberArray( indexSize, 4 );
- p.skinWeights = dv.getFloat32Array( 4 );
- } else if ( p.type === 3 ) { // SDEF
- p.skinIndices = dv.getNumberArray( indexSize, 2 );
- p.skinWeights = dv.getFloat32Array( 1 );
- p.skinWeights.push( 1.0 - p.skinWeights[ 0 ] );
- p.skinC = dv.getFloat32Array( 3 );
- p.skinR0 = dv.getFloat32Array( 3 );
- p.skinR1 = dv.getFloat32Array( 3 );
- // SDEF is not supported yet and is handled as BDEF2 so far.
- // TODO: SDEF support
- p.type = 1;
- } else {
- throw 'unsupport bone type ' + p.type + ' exception.';
- }
- p.edgeRatio = dv.getFloat32();
- return p;
- };
- var metadata = pmx.metadata;
- metadata.vertexCount = dv.getUint32();
- pmx.vertices = [];
- for ( var i = 0; i < metadata.vertexCount; i++ ) {
- pmx.vertices.push( parseVertex() );
- }
- };
- var parseFaces = function () {
- var parseFace = function () {
- var p = {};
- p.indices = dv.getNumberArray( metadata.vertexIndexSize, 3 );
- return p;
- };
- var metadata = pmx.metadata;
- metadata.faceCount = dv.getUint32() / 3;
- pmx.faces = [];
- for ( var i = 0; i < metadata.faceCount; i++ ) {
- pmx.faces.push( parseFace() );
- }
- };
- var parseTextures = function () {
- var parseTexture = function () {
- return dv.getTextBuffer();
- };
- var metadata = pmx.metadata;
- metadata.textureCount = dv.getUint32();
- pmx.textures = [];
- for ( var i = 0; i < metadata.textureCount; i++ ) {
- pmx.textures.push( parseTexture() );
- }
- };
- var parseMaterials = function () {
- var parseMaterial = function () {
- var p = {};
- p.name = dv.getTextBuffer();
- p.englishName = dv.getTextBuffer();
- p.diffuse = dv.getFloat32Array( 4 );
- p.specular = dv.getFloat32Array( 3 );
- p.shiness = dv.getFloat32();
- p.emissive = dv.getFloat32Array( 3 );
- p.flag = dv.getUint8();
- p.edgeColor = dv.getFloat32Array( 4 );
- p.edgeSize = dv.getFloat32();
- p.textureIndex = dv.getNumber( pmx.metadata.textureIndexSize );
- p.envTextureIndex = dv.getNumber( pmx.metadata.textureIndexSize );
- p.envFlag = dv.getUint8();
- p.toonFlag = dv.getUint8();
- if ( p.toonFlag === 0 ) {
- p.toonTextureIndex = dv.getNumber( pmx.metadata.textureIndexSize );
- } else if ( p.toonFlag === 1 ) {
- p.toonTextureIndex = dv.getUint8();
- } else {
- throw 'unknown toon flag ' + p.toonFlag + ' exception.';
- }
- p.comment = dv.getTextBuffer();
- p.faceCount = dv.getUint32() / 3;
- return p;
- };
- var metadata = pmx.metadata;
- metadata.materialCount = dv.getUint32();
- pmx.materials = [];
- for ( var i = 0; i < metadata.materialCount; i++ ) {
- pmx.materials.push( parseMaterial() );
- }
- };
- var parseBones = function () {
- var parseBone = function () {
- var p = {};
- // Skinning animation doesn't work when bone name is Japanese Unicode in r73.
- // So using charcode strings as workaround and keep original strings in .originalName.
- p.originalName = dv.getTextBuffer();
- p.name = dv.toCharcodeStrings( p.originalName );
- p.englishName = dv.getTextBuffer();
- p.position = dv.getFloat32Array( 3 );
- p.parentIndex = dv.getNumber( pmx.metadata.boneIndexSize );
- p.transformationClass = dv.getUint32();
- p.flag = dv.getUint16();
- if ( p.flag & 0x1 ) {
- p.connectIndex = dv.getNumber( pmx.metadata.boneIndexSize );
- } else {
- p.offsetPosition = dv.getFloat32Array( 3 );
- }
- if ( p.flag & 0x100 || p.flag & 0x200 ) {
- p.supplyParentIndex = dv.getNumber( pmx.metadata.boneIndexSize );
- p.supplyRatio = dv.getFloat32();
- }
- if ( p.flag & 0x400 ) {
- p.fixAxis = dv.getFloat32Array( 3 );
- }
- if ( p.flag & 0x800 ) {
- p.localXVector = dv.getFloat32Array( 3 );
- p.localZVector = dv.getFloat32Array( 3 );
- }
- if ( p.flag & 0x2000 ) {
- p.key = dv.getUint32();
- }
- if ( p.flag & 0x20 ) {
- var ik = {};
- ik.effector = dv.getNumber( pmx.metadata.boneIndexSize );
- ik.target = null;
- ik.iteration = dv.getUint32();
- ik.maxAngle = dv.getFloat32();
- ik.linkCount = dv.getUint32();
- ik.links = [];
- for ( var i = 0; i < ik.linkCount; i++ ) {
- var link = {};
- link.index = dv.getNumber( pmx.metadata.boneIndexSize );
- link.angleLimitation = dv.getUint8();
- if ( link.angleLimitation === 1 ) {
- link.lowerLimitationAngle = dv.getFloat32Array( 3 );
- link.upperLimitationAngle = dv.getFloat32Array( 3 );
- }
- ik.links.push( link );
- }
- p.ik = ik;
- }
- return p;
- };
- var metadata = pmx.metadata;
- metadata.boneCount = dv.getUint32();
- pmx.bones = [];
- for ( var i = 0; i < metadata.boneCount; i++ ) {
- pmx.bones.push( parseBone() );
- }
- };
- var parseMorphs = function () {
- var parseMorph = function () {
- var p = {};
- p.name = dv.getTextBuffer();
- p.englishName = dv.getTextBuffer();
- p.panel = dv.getUint8();
- p.type = dv.getUint8();
- p.elementCount = dv.getUint32();
- p.elements = [];
- for ( var i = 0; i < p.elementCount; i++ ) {
- if ( p.type === 0 ) { // group morph
- var m = {};
- m.index = dv.getNumber( pmx.metadata.morphIndexSize );
- m.ratio = dv.getFloat32();
- p.elements.push( m );
- } else if ( p.type === 1 ) { // vertex morph
- var m = {};
- m.index = dv.getNumber( pmx.metadata.vertexIndexSize );
- m.position = dv.getFloat32Array( 3 );
- p.elements.push( m );
- } else if ( p.type === 2 ) { // bone morph
- var m = {};
- m.index = dv.getNumber( pmx.metadata.boneIndexSize );
- m.position = dv.getFloat32Array( 3 );
- m.rotation = dv.getFloat32Array( 4 );
- p.elements.push( m );
- } else if ( p.type === 3 ) { // uv morph
- var m = {};
- m.index = dv.getNumber( pmx.metadata.vertexIndexSize );
- m.uv = dv.getFloat32Array( 4 );
- p.elements.push( m );
- } else if ( p.type === 8 ) { // material morph
- var m = {};
- m.index = dv.getNumber( pmx.metadata.materialIndexSize );
- m.type = dv.getUint8();
- m.diffuse = dv.getFloat32Array( 4 );
- m.specular = dv.getFloat32Array( 3 );
- m.shiness = dv.getFloat32();
- m.emissive = dv.getFloat32Array( 3 );
- m.edgeColor = dv.getFloat32Array( 4 );
- m.edgeSize = dv.getFloat32();
- m.textureColor = dv.getFloat32Array( 4 );
- m.sphereTextureColor = dv.getFloat32Array( 4 );
- m.toonColor = dv.getFloat32Array( 4 );
- p.elements.push( m );
- }
- }
- return p;
- };
- var metadata = pmx.metadata;
- metadata.morphCount = dv.getUint32();
- pmx.morphs = [];
- for ( var i = 0; i < metadata.morphCount; i++ ) {
- pmx.morphs.push( parseMorph() );
- }
- };
- parseHeader();
- parseVertices();
- parseFaces();
- parseTextures();
- parseMaterials();
- parseBones();
- parseMorphs();
- // console.log( pmx ); // for console debug
- return pmx;
- };
- THREE.MMDLoader.prototype.parseVmd = function ( buffer ) {
- var scope = this;
- var vmd = {};
- var dv = new THREE.MMDLoader.DataView( buffer );
- vmd.metadata = {};
- var parseHeader = function () {
- var metadata = vmd.metadata;
- metadata.magic = dv.getChars( 30 );
- if ( metadata.magic !== 'Vocaloid Motion Data 0002' ) {
- throw 'VMD file magic is not Vocaloid Motion Data 0002, but ' + metadata.magic;
- }
- metadata.name = dv.getSjisStringsAsUnicode( 20 );
- };
- var parseMotions = function () {
- var parseMotion = function () {
- var p = {};
- // Skinning animation doesn't work when bone name is Japanese Unicode in r73.
- // So using charcode strings as workaround and keep original strings in .originalName.
- p.originalBoneName = dv.getSjisStringsAsUnicode( 15 );
- p.boneName = dv.toCharcodeStrings( p.originalBoneName );
- p.frameNum = dv.getUint32();
- p.position = dv.getFloat32Array( 3 );
- p.rotation = dv.getFloat32Array( 4 );
- p.interpolation = dv.getUint8Array( 64 );
- return p;
- };
- var metadata = vmd.metadata;
- metadata.motionCount = dv.getUint32();
- vmd.motions = [];
- for ( var i = 0; i < metadata.motionCount; i++ ) {
- vmd.motions.push( parseMotion() );
- }
- };
- var parseMorphs = function () {
- var parseMorph = function () {
- var p = {};
- p.morphName = dv.getSjisStringsAsUnicode( 15 );
- p.frameNum = dv.getUint32();
- p.weight = dv.getFloat32();
- return p;
- };
- var metadata = vmd.metadata;
- metadata.morphCount = dv.getUint32();
- vmd.morphs = [];
- for ( var i = 0; i < metadata.morphCount; i++ ) {
- vmd.morphs.push( parseMorph() );
- }
- };
- parseHeader();
- parseMotions();
- parseMorphs();
- return vmd;
- };
- // maybe better to create json and then use JSONLoader...
- THREE.MMDLoader.prototype.createMesh = function ( model, vmd, texturePath, onProgress, onError ) {
- var scope = this;
- var geometry = new THREE.Geometry();
- var material = new THREE.MeshFaceMaterial();
- var leftToRight = function() {
- var convertVector = function ( v ) {
- v[ 2 ] = -v[ 2 ];
- };
- var convertQuaternion = function ( q ) {
- q[ 0 ] = -q[ 0 ];
- q[ 1 ] = -q[ 1 ];
- };
- var convertIndexOrder = function ( p ) {
- var tmp = p[ 2 ];
- p[ 2 ] = p[ 0 ];
- p[ 0 ] = tmp;
- };
- for ( var i = 0; i < model.metadata.vertexCount; i++ ) {
- convertVector( model.vertices[ i ].position );
- convertVector( model.vertices[ i ].normal );
- }
- for ( var i = 0; i < model.metadata.faceCount; i++ ) {
- convertIndexOrder( model.faces[ i ].indices );
- }
- for ( var i = 0; i < model.metadata.boneCount; i++ ) {
- convertVector( model.bones[ i ].position );
- }
- // TODO: support other morph for PMX
- for ( var i = 0; i < model.metadata.morphCount; i++ ) {
- var m = model.morphs[ i ];
- if ( model.metadata.format === 'pmx' ) {
- if ( m.type === 1 ) {
- m = m.elements;
- } else {
- continue;
- }
- }
- for ( var j = 0; j < m.elementCount; j++ ) {
- convertVector( m.elements[ j ].position );
- }
- }
- if ( vmd === null ) {
- return;
- }
- for ( var i = 0; i < vmd.metadata.motionCount; i++ ) {
- convertVector( vmd.motions[ i ].position );
- convertQuaternion( vmd.motions[ i ].rotation );
- }
- };
- var initVartices = function () {
- for ( var i = 0; i < model.metadata.vertexCount; i++ ) {
- var v = model.vertices[ i ];
- geometry.vertices.push(
- new THREE.Vector3(
- v.position[ 0 ],
- v.position[ 1 ],
- v.position[ 2 ]
- )
- );
- geometry.skinIndices.push(
- new THREE.Vector4(
- v.skinIndices.length >= 1 ? v.skinIndices[ 0 ] : 0.0,
- v.skinIndices.length >= 2 ? v.skinIndices[ 1 ] : 0.0,
- v.skinIndices.length >= 3 ? v.skinIndices[ 2 ] : 0.0,
- v.skinIndices.length >= 4 ? v.skinIndices[ 3 ] : 0.0
- )
- );
- geometry.skinWeights.push(
- new THREE.Vector4(
- v.skinWeights.length >= 1 ? v.skinWeights[ 0 ] : 0.0,
- v.skinWeights.length >= 2 ? v.skinWeights[ 1 ] : 0.0,
- v.skinWeights.length >= 3 ? v.skinWeights[ 2 ] : 0.0,
- v.skinWeights.length >= 4 ? v.skinWeights[ 3 ] : 0.0
- )
- );
- }
- };
- var initFaces = function () {
- for ( var i = 0; i < model.metadata.faceCount; i++ ) {
- geometry.faces.push(
- new THREE.Face3(
- model.faces[ i ].indices[ 0 ],
- model.faces[ i ].indices[ 1 ],
- model.faces[ i ].indices[ 2 ]
- )
- );
- for ( var j = 0; j < 3; j++ ) {
- geometry.faces[ i ].vertexNormals[ j ] =
- new THREE.Vector3(
- model.vertices[ model.faces[ i ].indices[ j ] ].normal[ 0 ],
- model.vertices[ model.faces[ i ].indices[ j ] ].normal[ 1 ],
- model.vertices[ model.faces[ i ].indices[ j ] ].normal[ 2 ]
- );
- }
- }
- };
- var initBones = function () {
- var bones = [];
- for ( var i = 0; i < model.metadata.boneCount; i++ ) {
- var bone = {};
- var b = model.bones[ i ];
- bone.parent = b.parentIndex;
- if ( model.metadata.format === 'pmd' ) {
- bone.parent = ( b.parentIndex === 0xFFFF ) ? -1 : b.parentIndex;
- }
- bone.name = b.name;
- bone.pos = [ b.position[ 0 ], b.position[ 1 ], b.position[ 2 ] ];
- bone.rotq = [ 0, 0, 0, 1 ];
- bone.scl = [ 1, 1, 1 ];
- if ( bone.parent !== -1 ) {
- bone.pos[ 0 ] -= model.bones[ bone.parent ].position[ 0 ];
- bone.pos[ 1 ] -= model.bones[ bone.parent ].position[ 1 ];
- bone.pos[ 2 ] -= model.bones[ bone.parent ].position[ 2 ];
- }
- bones.push( bone );
- }
- geometry.bones = bones;
- };
- var initIKs = function () {
- var iks = [];
- // TODO: remove duplicated codes between PMD and PMX
- if ( model.metadata.format === 'pmd' ) {
- for ( var i = 0; i < model.metadata.ikCount; i++ ) {
- var ik = model.iks[i];
- var param = {};
- param.target = ik.target;
- param.effector = ik.effector;
- param.iteration = ik.iteration;
- param.maxAngle = ik.maxAngle * 4;
- param.links = [];
- for ( var j = 0; j < ik.links.length; j++ ) {
- var link = {};
- link.index = ik.links[ j ].index;
- // Checking with .originalName, not .name.
- // See parseBone() for the detail.
- if ( model.bones[ link.index ].originalName.indexOf( 'ひざ' ) >= 0 ) {
- link.limitation = new THREE.Vector3( 1.0, 0.0, 0.0 );
- }
- param.links.push( link );
- }
- iks.push( param );
- }
- } else {
- for ( var i = 0; i < model.metadata.boneCount; i++ ) {
- var b = model.bones[ i ];
- var ik = b.ik;
- if ( ik === undefined ) {
- continue;
- }
- var param = {};
- param.target = i;
- param.effector = ik.effector;
- param.iteration = ik.iteration;
- param.maxAngle = ik.maxAngle;
- param.links = [];
- for ( var j = 0; j < ik.links.length; j++ ) {
- var link = {};
- link.index = ik.links[ j ].index;
- if ( ik.links[ j ].angleLimitation === 1 ) {
- link.limitation = new THREE.Vector3( 1.0, 0.0, 0.0 );
- // TODO: use limitation angles
- // link.lowerLimitationAngle;
- // link.upperLimitationAngle;
- }
- param.links.push( link );
- }
- iks.push( param );
- }
- }
- geometry.iks = iks;
- };
- var initMorphs = function () {
- function updateVertex ( params, index, v, ratio ) {
- params.vertices[ index ].x += v.position[ 0 ] * ratio;
- params.vertices[ index ].y += v.position[ 1 ] * ratio;
- params.vertices[ index ].z += v.position[ 2 ] * ratio;
- };
- function updateVertices ( params, m, ratio ) {
- for ( var i = 0; i < m.elementCount; i++ ) {
- var v = m.elements[ i ];
- var index;
- if ( model.metadata.format === 'pmd' ) {
- index = model.morphs[ 0 ].elements[ v.index ].index;
- } else {
- index = v.index;
- }
- updateVertex( params, index, v, ratio );
- }
- };
- for ( var i = 0; i < model.metadata.morphCount; i++ ) {
- var m = model.morphs[ i ];
- var params = {};
- params.name = m.name;
- params.vertices = [];
- for ( var j = 0; j < model.metadata.vertexCount; j++ ) {
- params.vertices[ j ] = new THREE.Vector3( 0, 0, 0 );
- params.vertices[ j ].x = geometry.vertices[ j ].x;
- params.vertices[ j ].y = geometry.vertices[ j ].y;
- params.vertices[ j ].z = geometry.vertices[ j ].z;
- }
- if ( model.metadata.format === 'pmd' ) {
- if ( i !== 0 ) {
- updateVertices( params, m, 1.0 );
- }
- } else {
- if ( m.type === 0 ) {
- for ( var j = 0; j < m.elementCount; j++ ) {
- var m2 = model.morphs[ m.elements[ j ].index ];
- var ratio = m.elements[ j ].ratio;
- if ( m2.type === 1 ) {
- updateVertices( params, m2, ratio );
- }
- }
- } else if ( m.type === 1 ) {
- updateVertices( params, m, 1.0 );
- }
- }
- // TODO: skip if this's non-vertex morphing of PMX to reduce CPU/Memory use
- geometry.morphTargets.push( params );
- }
- };
- var initMaterials = function () {
- var offset = 0;
- var materialParams = [];
- for ( var i = 1; i < model.metadata.materialCount; i++ ) {
- geometry.faceVertexUvs.push( [] );
- }
- for ( var i = 0; i < model.metadata.materialCount; i++ ) {
- var m = model.materials[ i ];
- var params = {};
- for ( var j = 0; j < m.faceCount; j++ ) {
- geometry.faces[ offset ].materialIndex = i;
- var uvs = [];
- for ( var k = 0; k < 3; k++ ) {
- var v = model.vertices[ model.faces[ offset ].indices[ k ] ];
- uvs.push( new THREE.Vector2( v.uv[ 0 ], v.uv[ 1 ] ) );
- }
- geometry.faceVertexUvs[ 0 ].push( uvs );
- offset++;
- }
- params.shading = 'phong';
- params.colorDiffuse = [ m.diffuse[ 0 ], m.diffuse[ 1 ], m.diffuse[ 2 ] ];
- params.opacity = m.diffuse[ 3 ];
- params.colorSpecular = [ m.specular[ 0 ], m.specular[ 1 ], m.specular[ 2 ] ];
- params.specularCoef = m.shiness;
- // temporal workaround
- // TODO: implement correctly
- params.doubleSided = true;
- if ( model.metadata.format === 'pmd' ) {
- if ( m.fileName ) {
- var fileName = m.fileName;
- var fileNames = [];
- // temporal workaround, disable sphere mapping so far
- // TODO: sphere mapping support
- var index = fileName.lastIndexOf( '*' );
- if ( index >= 0 ) {
- fileNames.push( fileName.slice( 0, index ) );
- fileNames.push( fileName.slice( index + 1 ) );
- } else {
- fileNames.push( fileName );
- }
- for ( var j = 0; j < fileNames.length; j++ ) {
- var n = fileNames[ j ];
- // TODO: support spa
- if ( /* n.indexOf( '.spa' ) >= 0 || */ n.indexOf( '.sph' ) >= 0 ) {
- params.mapEnv = n;
- } else {
- // temporal workaround, use .png instead of .tga
- // TODO: tga file support
- params.mapDiffuse = n.replace( '.tga', '.png' );
- }
- }
- }
- } else {
- if ( m.textureIndex !== -1 ) {
- var n = model.textures[ m.textureIndex ];
- // temporal workaround, use .png instead of .tga
- // TODO: tga file support
- params.mapDiffuse = n.replace( '.tga', '.png' );
- }
- // TODO: support m.envFlag === 0, 2, 3
- if ( m.envTextureIndex !== -1 && m.envFlag === 1 ) {
- var n = model.textures[ m.envTextureIndex ];
- params.mapEnv = n;
- }
- }
- if ( params.mapDiffuse === undefined ) {
- params.colorEmissive = [ m.emissive[ 0 ], m.emissive[ 1 ], m.emissive[ 2 ] ];
- }
- materialParams.push( params );
- }
- var materials = scope.initMaterials( materialParams, texturePath );
- for ( var i = 0; i < materials.length; i++ ) {
- var m = materials[ i ];
- var p = materialParams[ i ];
- if ( m.map ) {
- m.map.flipY = false;
- }
- // this should be in THREE.Loader.createMaterial.
- // remove this if it supports.
- // TODO: make patch of THREE.Loader.createMaterial?
- if ( p.mapEnv !== undefined ) {
- var fullPath = texturePath + p.mapEnv;
- var loader = THREE.Loader.Handlers.get( fullPath );
- if ( loader === null ) {
- loader = new THREE.TextureLoader( this.manager );
- }
- var texture = loader.load( fullPath );
- // currently only support multiply-sphere-mapping
- // TODO: support add-sphere-mapping
- texture.mapping = THREE.SphericalReflectionMapping;
- m.envMap = texture;
- }
- m.skinning = true;
- m.morphTargets = true;
- material.materials.push( m );
- }
- };
- var initMotionAnimations = function () {
- var orderedMotions = [];
- var boneTable = {};
- for ( var i = 0; i < model.metadata.boneCount; i++ ) {
- var b = model.bones[ i ];
- boneTable[ b.name ] = i;
- orderedMotions[ i ] = [];
- }
- for ( var i = 0; i < vmd.motions.length; i++ ) {
- var m = vmd.motions[ i ];
- var num = boneTable[ m.boneName ];
- if ( num === undefined )
- continue;
- orderedMotions[ num ].push( m );
- }
- for ( var i = 0; i < orderedMotions.length; i++ ) {
- orderedMotions[ i ].sort( function ( a, b ) {
- return a.frameNum - b.frameNum;
- } ) ;
- }
- var animation = {
- name: 'Action',
- fps: 30,
- length: 0.0,
- hierarchy: []
- };
- for ( var i = 0; i < geometry.bones.length; i++ ) {
- animation.hierarchy.push(
- {
- parent: geometry.bones[ i ].parent,
- keys: []
- }
- );
- }
- var maxTime = 0.0;
- for ( var i = 0; i < orderedMotions.length; i++ ) {
- var array = orderedMotions[ i ];
- for ( var j = 0; j < array.length; j++ ) {
- var t = array[ j ].frameNum / 30;
- var p = array[ j ].position;
- var r = array[ j ].rotation;
- animation.hierarchy[ i ].keys.push(
- {
- time: t,
- pos: [ geometry.bones[ i ].pos[ 0 ] + p[ 0 ],
- geometry.bones[ i ].pos[ 1 ] + p[ 1 ],
- geometry.bones[ i ].pos[ 2 ] + p[ 2 ] ],
- rot: [ r[ 0 ], r[ 1 ], r[ 2 ], r[ 3 ] ],
- scl: [ 1, 1, 1 ]
- }
- );
- if ( t > maxTime )
- maxTime = t;
- }
- }
- // add 2 secs as afterglow
- maxTime += 2.0;
- animation.length = maxTime;
- for ( var i = 0; i < orderedMotions.length; i++ ) {
- var keys = animation.hierarchy[ i ].keys;
- if ( keys.length === 0 ) {
- keys.push( { time: 0.0,
- pos: [ geometry.bones[ i ].pos[ 0 ],
- geometry.bones[ i ].pos[ 1 ],
- geometry.bones[ i ].pos[ 2 ] ],
- rot: [ 0, 0, 0, 1 ],
- scl: [ 1, 1, 1 ]
- } );
- }
- var k = keys[ 0 ];
- if ( k.time !== 0.0 ) {
- keys.unshift( { time: 0.0,
- pos: [ k.pos[ 0 ], k.pos[ 1 ], k.pos[ 2 ] ],
- rot: [ k.rot[ 0 ], k.rot[ 1 ], k.rot[ 2 ], k.rot[ 3 ] ],
- scl: [ 1, 1, 1 ]
- } );
- }
- k = keys[ keys.length - 1 ];
- if ( k.time < maxTime ) {
- keys.push( { time: maxTime,
- pos: [ k.pos[ 0 ], k.pos[ 1 ], k.pos[ 2 ] ],
- rot: [ k.rot[ 0 ], k.rot[ 1 ], k.rot[ 2 ], k.rot[ 3 ] ],
- scl: [ 1, 1, 1 ]
- } );
- }
- }
- // geometry.animation = animation;
- geometry.animations = [];
- geometry.animations.push( THREE.AnimationClip.parseAnimation( animation, geometry.bones ) );
- };
- var initMorphAnimations = function () {
- var orderedMorphs = [];
- var morphTable = {}
- for ( var i = 0; i < model.metadata.morphCount; i++ ) {
- var m = model.morphs[ i ];
- morphTable[ m.name ] = i;
- orderedMorphs[ i ] = [];
- }
- for ( var i = 0; i < vmd.morphs.length; i++ ) {
- var m = vmd.morphs[ i ];
- var num = morphTable[ m.morphName ];
- if ( num === undefined )
- continue;
- orderedMorphs[ num ].push( m );
- }
- for ( var i = 0; i < orderedMorphs.length; i++ ) {
- orderedMorphs[ i ].sort( function ( a, b ) {
- return a.frameNum - b.frameNum;
- } ) ;
- }
- var morphAnimation = {
- fps: 30,
- length: 0.0,
- hierarchy: []
- };
- for ( var i = 0; i < model.metadata.morphCount; i++ ) {
- morphAnimation.hierarchy.push( { keys: [] } );
- }
- var maxTime = 0.0;
- for ( var i = 0; i < orderedMorphs.length; i++ ) {
- var array = orderedMorphs[ i ];
- for ( var j = 0; j < array.length; j++ ) {
- var t = array[ j ].frameNum / 30;
- var w = array[ j ].weight;
- morphAnimation.hierarchy[ i ].keys.push( { time: t, value: w } );
- if ( t > maxTime ) {
- maxTime = t;
- }
- }
- }
- // add 2 secs as afterglow
- maxTime += 2.0;
- // use animation's length if exists. animation is master.
- maxTime = ( geometry.animation !== undefined &&
- geometry.animation.length > 0.0 )
- ? geometry.animation.length : maxTime;
- morphAnimation.length = maxTime;
- for ( var i = 0; i < orderedMorphs.length; i++ ) {
- var keys = morphAnimation.hierarchy[ i ].keys;
- if ( keys.length === 0 ) {
- keys.push( { time: 0.0, value: 0.0 } );
- }
- var k = keys[ 0 ];
- if ( k.time !== 0.0 ) {
- keys.unshift( { time: 0.0, value: k.value } );
- }
- k = keys[ keys.length - 1 ];
- if ( k.time < maxTime ) {
- keys.push( { time: maxTime, value: k.value } );
- }
- }
- // geometry.morphAnimation = morphAnimation;
- var tracks = [];
- for ( var i = 1; i < orderedMorphs.length; i++ ) {
- var keys = morphAnimation.hierarchy[ i ].keys;
- var times = [];
- var values = [];
- for ( var j = 0; j < keys.length; j++ ) {
- var key = keys[ j ];
- times.push( key.time );
- values.push( key.value );
- }
- tracks.push( new THREE.NumberKeyframeTrack( '.morphTargetInfluences[' + i + ']', times, values ) );
- }
- geometry.morphAnimations = [];
- geometry.morphAnimations.push( new THREE.AnimationClip( 'morphAnimation', -1, tracks ) );
- };
- leftToRight();
- initVartices();
- initFaces();
- initBones();
- initIKs();
- initMorphs();
- initMaterials();
- if ( vmd !== null ) {
- initMotionAnimations();
- initMorphAnimations();
- }
- geometry.computeFaceNormals();
- geometry.verticesNeedUpdate = true;
- geometry.normalsNeedUpdate = true;
- geometry.uvsNeedUpdate = true;
- geometry.mmdFormat = model.metadata.format;
- var mesh = new THREE.SkinnedMesh( geometry, material );
- // console.log( mesh ); // for console debug
- return mesh;
- };
- THREE.MMDLoader.DataView = function ( buffer, littleEndian ) {
- this.dv = new DataView( buffer );
- this.offset = 0;
- this.littleEndian = ( littleEndian !== undefined ) ? littleEndian : true;
- this.encoder = new CharsetEncoder();
- };
- THREE.MMDLoader.DataView.prototype = {
- constructor: THREE.MMDLoader.DataView,
- getInt8: function () {
- var value = this.dv.getInt8( this.offset );
- this.offset += 1;
- return value;
- },
- getInt8Array: function ( size ) {
- var a = [];
- for ( var i = 0; i < size; i++ ) {
- a.push( this.getInt8() );
- }
- return a;
- },
- getUint8: function () {
- var value = this.dv.getUint8( this.offset );
- this.offset += 1;
- return value;
- },
- getUint8Array: function ( size ) {
- var a = [];
- for ( var i = 0; i < size; i++ ) {
- a.push( this.getUint8() );
- }
- return a;
- },
- getInt16: function () {
- var value = this.dv.getInt16( this.offset, this.littleEndian );
- this.offset += 2;
- return value;
- },
- getInt16Array: function ( size ) {
- var a = [];
- for ( var i = 0; i < size; i++ ) {
- a.push( this.getInt16() );
- }
- return a;
- },
- getUint16: function () {
- var value = this.dv.getUint16( this.offset, this.littleEndian );
- this.offset += 2;
- return value;
- },
- getUint16Array: function ( size ) {
- var a = [];
- for ( var i = 0; i < size; i++ ) {
- a.push( this.getUint16() );
- }
- return a;
- },
- getInt32: function () {
- var value = this.dv.getInt32( this.offset, this.littleEndian );
- this.offset += 4;
- return value;
- },
- getInt32Array: function ( size ) {
- var a = [];
- for ( var i = 0; i < size; i++ ) {
- a.push( this.getInt32() );
- }
- return a;
- },
- getUint32: function () {
- var value = this.dv.getUint32( this.offset, this.littleEndian );
- this.offset += 4;
- return value;
- },
- getUint32Array: function ( size ) {
- var a = [];
- for ( var i = 0; i < size; i++ ) {
- a.push( this.getUint32() );
- }
- return a;
- },
- getFloat32: function () {
- var value = this.dv.getFloat32( this.offset, this.littleEndian );
- this.offset += 4;
- return value;
- },
- getFloat32Array: function( size ) {
- var a = [];
- for ( var i = 0; i < size; i++ ) {
- a.push( this.getFloat32() );
- }
- return a;
- },
- getFloat64: function () {
- var value = this.dv.getFloat64( this.offset, this.littleEndian );
- this.offset += 8;
- return value;
- },
- getFloat64Array: function( size ) {
- var a = [];
- for ( var i = 0; i < size; i++ ) {
- a.push( this.getFloat64() );
- }
- return a;
- },
- getNumber: function ( type ) {
- switch ( type ) {
- case 1:
- return this.getInt8();
- case 2:
- return this.getInt16();
- case 4:
- return this.getInt32();
- default:
- throw 'unknown number type ' + type + ' exception.';
- }
- },
- getNumberArray: function ( type, size ) {
- var a = [];
- for ( var i = 0; i < size; i++ ) {
- a.push( this.getNumber( type ) );
- }
- return a;
- },
- getChars: function ( size ) {
- var str = '';
- while ( size > 0 ) {
- var value = this.getUint8();
- size--;
- if ( value === 0 ) {
- break;
- }
- str += String.fromCharCode( value );
- }
- while ( size > 0 ) {
- this.getUint8();
- size--;
- }
- return str;
- },
- getSjisStringsAsUnicode: function ( size ) {
- var a = [];
- while ( size > 0 ) {
- var value = this.getUint8();
- size--;
- if ( value === 0 ) {
- break;
- }
- a.push( value );
- }
- while ( size > 0 ) {
- this.getUint8();
- size--;
- }
- return this.encoder.s2u( new Uint8Array( a ) );
- },
- /*
- * Note: Sometimes to use Japanese Unicode characters runs into problems in Three.js.
- * In such a case, use this method to convert it to Unicode hex charcode strings,
- * like 'あいう' -> '0x30420x30440x3046'
- */
- toCharcodeStrings: function ( s ) {
- var str = '';
- for ( var i = 0; i < s.length; i++ ) {
- str += '0x' + ( '0000' + s[ i ].charCodeAt().toString( 16 ) ).substr( -4 );
- }
- return str;
- },
- getUnicodeStrings: function ( size ) {
- var str = '';
- while ( size > 0 ) {
- var value = this.getUint16();
- size -= 2;
- if ( value === 0 ) {
- break;
- }
- str += String.fromCharCode( value );
- }
- while ( size > 0 ) {
- this.getUint8();
- size--;
- }
- return str;
- },
- getTextBuffer: function () {
- var size = this.getUint32();
- return this.getUnicodeStrings( size );
- }
- };
|