| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 | import {	AnimationMixer,	Box3,	Mesh,	MeshLambertMaterial,	Object3D,	TextureLoader,	UVMapping,	sRGBEncoding} from '../../../build/three.module.js';import { MD2Loader } from '../loaders/MD2Loader.js';class MD2Character {	constructor() {		this.scale = 1;		this.animationFPS = 6;		this.root = new Object3D();		this.meshBody = null;		this.meshWeapon = null;		this.skinsBody = [];		this.skinsWeapon = [];		this.weapons = [];		this.activeAnimation = null;		this.mixer = null;		this.onLoadComplete = function () {};		this.loadCounter = 0;	}	loadParts( config ) {		const scope = this;		function createPart( geometry, skinMap ) {			const materialWireframe = new MeshLambertMaterial( { color: 0xffaa00, wireframe: true } );			const materialTexture = new MeshLambertMaterial( { color: 0xffffff, wireframe: false, map: skinMap } );			//			const mesh = new Mesh( geometry, materialTexture );			mesh.rotation.y = - Math.PI / 2;			mesh.castShadow = true;			mesh.receiveShadow = true;			//			mesh.materialTexture = materialTexture;			mesh.materialWireframe = materialWireframe;			return mesh;		}		function loadTextures( baseUrl, textureUrls ) {			const textureLoader = new TextureLoader();			const textures = [];			for ( let i = 0; i < textureUrls.length; i ++ ) {				textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );				textures[ i ].mapping = UVMapping;				textures[ i ].name = textureUrls[ i ];				textures[ i ].encoding = sRGBEncoding;			}			return textures;		}		function checkLoadingComplete() {			scope.loadCounter -= 1;			if ( scope.loadCounter === 0 ) scope.onLoadComplete();		}		this.loadCounter = config.weapons.length * 2 + config.skins.length + 1;		const weaponsTextures = [];		for ( let i = 0; i < config.weapons.length; i ++ ) weaponsTextures[ i ] = config.weapons[ i ][ 1 ];		// SKINS		this.skinsBody = loadTextures( config.baseUrl + 'skins/', config.skins );		this.skinsWeapon = loadTextures( config.baseUrl + 'skins/', weaponsTextures );		// BODY		const loader = new MD2Loader();		loader.load( config.baseUrl + config.body, function ( geo ) {			const boundingBox = new Box3();			boundingBox.setFromBufferAttribute( geo.attributes.position );			scope.root.position.y = - scope.scale * boundingBox.min.y;			const mesh = createPart( geo, scope.skinsBody[ 0 ] );			mesh.scale.set( scope.scale, scope.scale, scope.scale );			scope.root.add( mesh );			scope.meshBody = mesh;			scope.meshBody.clipOffset = 0;			scope.activeAnimationClipName = mesh.geometry.animations[ 0 ].name;			scope.mixer = new AnimationMixer( mesh );			checkLoadingComplete();		} );		// WEAPONS		const generateCallback = function ( index, name ) {			return function ( geo ) {				const mesh = createPart( geo, scope.skinsWeapon[ index ] );				mesh.scale.set( scope.scale, scope.scale, scope.scale );				mesh.visible = false;				mesh.name = name;				scope.root.add( mesh );				scope.weapons[ index ] = mesh;				scope.meshWeapon = mesh;				checkLoadingComplete();			};		};		for ( let i = 0; i < config.weapons.length; i ++ ) {			loader.load( config.baseUrl + config.weapons[ i ][ 0 ], generateCallback( i, config.weapons[ i ][ 0 ] ) );		}	}	setPlaybackRate( rate ) {		if ( rate !== 0 ) {			this.mixer.timeScale = 1 / rate;		} else {			this.mixer.timeScale = 0;		}	}	setWireframe( wireframeEnabled ) {		if ( wireframeEnabled ) {			if ( this.meshBody ) this.meshBody.material = this.meshBody.materialWireframe;			if ( this.meshWeapon ) this.meshWeapon.material = this.meshWeapon.materialWireframe;		} else {			if ( this.meshBody ) this.meshBody.material = this.meshBody.materialTexture;			if ( this.meshWeapon ) this.meshWeapon.material = this.meshWeapon.materialTexture;		}	}	setSkin( index ) {		if ( this.meshBody && this.meshBody.material.wireframe === false ) {			this.meshBody.material.map = this.skinsBody[ index ];		}	}	setWeapon( index ) {		for ( let i = 0; i < this.weapons.length; i ++ ) this.weapons[ i ].visible = false;		const activeWeapon = this.weapons[ index ];		if ( activeWeapon ) {			activeWeapon.visible = true;			this.meshWeapon = activeWeapon;			this.syncWeaponAnimation();		}	}	setAnimation( clipName ) {		if ( this.meshBody ) {			if ( this.meshBody.activeAction ) {				this.meshBody.activeAction.stop();				this.meshBody.activeAction = null;			}			const action = this.mixer.clipAction( clipName, this.meshBody );			if ( action ) {				this.meshBody.activeAction = action.play();			}		}		this.activeClipName = clipName;		this.syncWeaponAnimation();	}	syncWeaponAnimation() {		const clipName = this.activeClipName;		if ( this.meshWeapon ) {			if ( this.meshWeapon.activeAction ) {				this.meshWeapon.activeAction.stop();				this.meshWeapon.activeAction = null;			}			const action = this.mixer.clipAction( clipName, this.meshWeapon );			if ( action ) {				this.meshWeapon.activeAction = action.syncWith( this.meshBody.activeAction ).play();			}		}	}	update( delta ) {		if ( this.mixer ) this.mixer.update( delta );	}}export { MD2Character };
 |