c&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+.5,
-a.y));return a.clone()}THREE.Geometry.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;for(var k=this,n=0,p=a.length;nr&&(.2>d&&(b[0].x+=1),.2>a&&(b[1].x+=1),.2>q&&(b[2].x+=1));n=0;for(p=this.vertices.length;n
c.y?this.quaternion.set(1,0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}();
-THREE.ArrowHelper.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);this.line.scale.set(1,a,1);this.line.updateMatrix();this.cone.scale.set(c,b,c);this.cone.position.y=a;this.cone.updateMatrix()};THREE.ArrowHelper.prototype.setColor=function(a){this.line.material.color.set(a);this.cone.material.color.set(a)};
-THREE.BoxHelper=function(a){var b=new THREE.BufferGeometry;b.addAttribute("position",new THREE.BufferAttribute(new Float32Array(72),3));THREE.Line.call(this,b,new THREE.LineBasicMaterial({color:16776960}),THREE.LinePieces);void 0!==a&&this.update(a)};THREE.BoxHelper.prototype=Object.create(THREE.Line.prototype);
-THREE.BoxHelper.prototype.update=function(a){var b=a.geometry;null===b.boundingBox&&b.computeBoundingBox();var c=b.boundingBox.min,b=b.boundingBox.max,d=this.geometry.attributes.position.array;d[0]=b.x;d[1]=b.y;d[2]=b.z;d[3]=c.x;d[4]=b.y;d[5]=b.z;d[6]=c.x;d[7]=b.y;d[8]=b.z;d[9]=c.x;d[10]=c.y;d[11]=b.z;d[12]=c.x;d[13]=c.y;d[14]=b.z;d[15]=b.x;d[16]=c.y;d[17]=b.z;d[18]=b.x;d[19]=c.y;d[20]=b.z;d[21]=b.x;d[22]=b.y;d[23]=b.z;d[24]=b.x;d[25]=b.y;d[26]=c.z;d[27]=c.x;d[28]=b.y;d[29]=c.z;d[30]=c.x;d[31]=b.y;
-d[32]=c.z;d[33]=c.x;d[34]=c.y;d[35]=c.z;d[36]=c.x;d[37]=c.y;d[38]=c.z;d[39]=b.x;d[40]=c.y;d[41]=c.z;d[42]=b.x;d[43]=c.y;d[44]=c.z;d[45]=b.x;d[46]=b.y;d[47]=c.z;d[48]=b.x;d[49]=b.y;d[50]=b.z;d[51]=b.x;d[52]=b.y;d[53]=c.z;d[54]=c.x;d[55]=b.y;d[56]=b.z;d[57]=c.x;d[58]=b.y;d[59]=c.z;d[60]=c.x;d[61]=c.y;d[62]=b.z;d[63]=c.x;d[64]=c.y;d[65]=c.z;d[66]=b.x;d[67]=c.y;d[68]=b.z;d[69]=b.x;d[70]=c.y;d[71]=c.z;this.geometry.attributes.position.needsUpdate=!0;this.geometry.computeBoundingSphere();this.matrix=a.matrixWorld;
-this.matrixAutoUpdate=!1};THREE.BoundingBoxHelper=function(a,b){var c=void 0!==b?b:8947848;this.object=a;this.box=new THREE.Box3;THREE.Mesh.call(this,new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial({color:c,wireframe:!0}))};THREE.BoundingBoxHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.BoundingBoxHelper.prototype.update=function(){this.box.setFromObject(this.object);this.box.size(this.scale);this.box.center(this.position)};
-THREE.CameraHelper=function(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){d.vertices.push(new THREE.Vector3);d.colors.push(new THREE.Color(b));void 0===f[a]&&(f[a]=[]);f[a].push(d.vertices.length-1)}var d=new THREE.Geometry,e=new THREE.LineBasicMaterial({color:16777215,vertexColors:THREE.FaceColors}),f={};b("n1","n2",16755200);b("n2","n4",16755200);b("n4","n3",16755200);b("n3","n1",16755200);b("f1","f2",16755200);b("f2","f4",16755200);b("f4","f3",16755200);b("f3","f1",16755200);b("n1","f1",16755200);
-b("n2","f2",16755200);b("n3","f3",16755200);b("n4","f4",16755200);b("p","n1",16711680);b("p","n2",16711680);b("p","n3",16711680);b("p","n4",16711680);b("u1","u2",43775);b("u2","u3",43775);b("u3","u1",43775);b("c","t",16777215);b("p","c",3355443);b("cn1","cn2",3355443);b("cn3","cn4",3355443);b("cf1","cf2",3355443);b("cf3","cf4",3355443);THREE.Line.call(this,d,e,THREE.LinePieces);this.camera=a;this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap=f;this.update()};
-THREE.CameraHelper.prototype=Object.create(THREE.Line.prototype);
-THREE.CameraHelper.prototype.update=function(){var a,b,c=new THREE.Vector3,d=new THREE.Camera,e=function(e,g,h,k){c.set(g,h,k).unproject(d);e=b[e];if(void 0!==e)for(g=0,h=e.length;gt;t++){d[0]=r[g[t]];d[1]=r[g[(t+1)%3]];d.sort(f);var s=d.toString();void 0===e[s]?(e[s]={vert1:d[0],vert2:d[1],face1:q,face2:void 0},p++):e[s].face2=q}d=new Float32Array(6*p);f=0;for(s in e)if(g=e[s],void 0===g.face2||
-.9999>k[g.face1].normal.dot(k[g.face2].normal))p=n[g.vert1],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z,p=n[g.vert2],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3));THREE.Line.call(this,h,new THREE.LineBasicMaterial({color:c}),THREE.LinePieces);this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1};THREE.EdgesHelper.prototype=Object.create(THREE.Line.prototype);
-THREE.FaceNormalsHelper=function(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;a=void 0!==c?c:16776960;d=void 0!==d?d:1;b=new THREE.Geometry;c=0;for(var e=this.object.geometry.faces.length;cb;b++)a.faces[b].color=this.colors[4>b?0:1];b=new THREE.MeshBasicMaterial({vertexColors:THREE.FaceColors,wireframe:!0});this.lightSphere=new THREE.Mesh(a,b);this.add(this.lightSphere);
-this.update()};THREE.HemisphereLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose();this.lightSphere.material.dispose()};
-THREE.HemisphereLightHelper.prototype.update=function(){var a=new THREE.Vector3;return function(){this.colors[0].copy(this.light.color).multiplyScalar(this.light.intensity);this.colors[1].copy(this.light.groundColor).multiplyScalar(this.light.intensity);this.lightSphere.lookAt(a.setFromMatrixPosition(this.light.matrixWorld).negate());this.lightSphere.geometry.colorsNeedUpdate=!0}}();
-THREE.PointLightHelper=function(a,b){this.light=a;this.light.updateMatrixWorld();var c=new THREE.SphereGeometry(b,4,2),d=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);THREE.Mesh.call(this,c,d);this.matrix=this.light.matrixWorld;this.matrixAutoUpdate=!1};THREE.PointLightHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.PointLightHelper.prototype.dispose=function(){this.geometry.dispose();this.material.dispose()};
-THREE.PointLightHelper.prototype.update=function(){this.material.color.copy(this.light.color).multiplyScalar(this.light.intensity)};
-THREE.SkeletonHelper=function(a){this.bones=this.getBoneList(a);for(var b=new THREE.Geometry,c=0;cs;s++){d[0]=t[g[s]];d[1]=t[g[(s+1)%3]];d.sort(f);var u=d.toString();void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++)}d=new Float32Array(6*p);m=0;for(r=p;ms;s++)p=
-k[q[2*m+s]],g=6*m+3*s,d[g+0]=p.x,d[g+1]=p.y,d[g+2]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3))}else if(a.geometry instanceof THREE.BufferGeometry){if(void 0!==a.geometry.attributes.index){k=a.geometry.attributes.position.array;r=a.geometry.attributes.index.array;n=a.geometry.drawcalls;p=0;0===n.length&&(n=[{count:r.length,index:0,start:0}]);for(var q=new Uint32Array(2*r.length),t=0,v=n.length;ts;s++)d[0]=
-g+r[m+s],d[1]=g+r[m+(s+1)%3],d.sort(f),u=d.toString(),void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++);d=new Float32Array(6*p);m=0;for(r=p;ms;s++)g=6*m+3*s,p=3*q[2*m+s],d[g+0]=k[p],d[g+1]=k[p+1],d[g+2]=k[p+2]}else for(k=a.geometry.attributes.position.array,p=k.length/3,q=p/3,d=new Float32Array(6*p),m=0,r=q;ms;s++)g=18*m+6*s,q=9*m+3*s,d[g+0]=k[q],d[g+1]=k[q+1],d[g+2]=k[q+2],p=9*m+(s+1)%3*3,d[g+3]=k[p],d[g+4]=k[p+1],d[g+5]=k[p+2];h.addAttribute("position",new THREE.BufferAttribute(d,
-3))}THREE.Line.call(this,h,new THREE.LineBasicMaterial({color:c}),THREE.LinePieces);this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1};THREE.WireframeHelper.prototype=Object.create(THREE.Line.prototype);THREE.ImmediateRenderObject=function(){THREE.Object3D.call(this);this.render=function(a){}};THREE.ImmediateRenderObject.prototype=Object.create(THREE.Object3D.prototype);
-THREE.MorphBlendMesh=function(a,b){THREE.Mesh.call(this,a,b);this.animationsMap={};this.animationsList=[];var c=this.geometry.morphTargets.length;this.createAnimation("__default",0,c-1,c/1);this.setAnimationWeight("__default",1)};THREE.MorphBlendMesh.prototype=Object.create(THREE.Mesh.prototype);
-THREE.MorphBlendMesh.prototype.createAnimation=function(a,b,c,d){b={startFrame:b,endFrame:c,length:c-b+1,fps:d,duration:(c-b)/d,lastFrame:0,currentFrame:0,active:!1,time:0,direction:1,weight:1,directionBackwards:!1,mirroredLoop:!1};this.animationsMap[a]=b;this.animationsList.push(b)};
-THREE.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b=/([a-z]+)_?(\d+)/,c,d={},e=this.geometry,f=0,g=e.morphTargets.length;fh.end&&(h.end=f);c||(c=k)}}for(k in d)h=d[k],this.createAnimation(k,h.start,h.end,a);this.firstAnimation=c};
-THREE.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){if(a=this.animationsMap[a])a.direction=1,a.directionBackwards=!1};THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){if(a=this.animationsMap[a])a.direction=-1,a.directionBackwards=!0};THREE.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)};
-THREE.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)};THREE.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)};THREE.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)};THREE.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0;if(a=this.animationsMap[a])b=a.time;return b};
-THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("animation["+a+"] undefined")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1};
-THREE.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;bd.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var f=d.startFrame+THREE.Math.clamp(Math.floor(d.time/e),0,d.length-1),g=d.weight;
-f!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*g,this.morphTargetInfluences[f]=0,d.lastFrame=d.currentFrame,d.currentFrame=f);e=d.time%e/e;d.directionBackwards&&(e=1-e);this.morphTargetInfluences[d.currentFrame]=e*g;this.morphTargetInfluences[d.lastFrame]=(1-e)*g}}};
diff --git a/wipeout.js b/wipeout.js
index 7789dd5..5a0d1ce 100644
--- a/wipeout.js
+++ b/wipeout.js
@@ -491,63 +491,68 @@ Wipeout.prototype.readObject = function(buffer, offset) {
// ----------------------------------------------------------------------------
// Create a ThreeJS Model from a single PRM 3D Object
-Wipeout.prototype.createModelFromObject = function(object, spriteCollection) {
+Wipeout.prototype.createModelFromObject = function (object, spriteCollection) {
var model = new THREE.Object3D();
- var geometry = new THREE.Geometry();
- model.position.set(object.header.position.x, -object.header.position.y, -object.header.position.z);
+ const vertices = [];
+ const uvs = [];
+ const colors = [];
+ const materials = [];
- // Load vertices
- for( var i = 0; i < object.vertices.length; i++ ) {
- geometry.vertices.push( new THREE.Vector3(object.vertices[i].x, -object.vertices[i].y, -object.vertices[i].z) );
+ for (var i = 0; i < object.vertices.length; i++) {
+ vertices.push(object.vertices[i].x);
+ vertices.push(-object.vertices[i].y);
+ vertices.push(-object.vertices[i].z);
}
- var whiteColor = new THREE.Color(1,1,1);
+ model.position.set(object.header.position.x, -object.header.position.y, -object.header.position.z);
+
+ var whiteColor = new THREE.Color(1, 1, 1);
var nullVector = new THREE.Vector2(0, 0);
// Create faces
- for( var i = 0; i < object.polygons.length; i++ ) {
+ for (var i = 0; i < object.polygons.length; i++) {
var p = object.polygons[i];
-
+
// Sprite
- if(
- p.header.type === Wipeout.POLYGON_TYPE.SPRITE_BOTTOM_ANCHOR ||
- p.header.type === Wipeout.POLYGON_TYPE.SPRITE_TOP_ANCHOR
- ) {
- var v = geometry.vertices[p.index];
- var color = this.int32ToColor( p.color );
- var yOffset = p.header.type === Wipeout.POLYGON_TYPE.SPRITE_BOTTOM_ANCHOR
- ? p.height/2
- : -p.height/2;
+ if (p.header.type === Wipeout.POLYGON_TYPE.SPRITE_BOTTOM_ANCHOR || p.header.type === Wipeout.POLYGON_TYPE.SPRITE_TOP_ANCHOR) {
+ var vx = vertices[p.index * 3];
+ var vy = vertices[p.index * 3 + 1];
+ var vz = vertices[p.index * 3 + 2];
+
+ var color = this.int32ToColor(p.color);
+ var yOffset = p.header.type === Wipeout.POLYGON_TYPE.SPRITE_BOTTOM_ANCHOR
+ ? p.height / 2
+ : -p.height / 2;
// We can't use THREE.Sprite here, because they rotate to the camera on
// all axis. We just want rotation around the Y axis, so we do it manually.
- var spriteMaterial = new THREE.MeshBasicMaterial({map: this.sceneMaterial.materials[p.texture].map, color: color, alphaTest:0.5});
- var spriteMesh = new THREE.Mesh( new THREE.PlaneBufferGeometry(p.width, p.height), spriteMaterial );
+ var spriteMaterial = new THREE.MeshBasicMaterial({ map: this.sceneMaterial[p.texture].map, color: color, alphaTest: 0.5 });
+ var spriteMesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(p.width, p.height), spriteMaterial);
var sprite = new THREE.Object3D();
- sprite.position.set(v.x, v.y + yOffset, v.z);
- sprite.add( spriteMesh );
+ sprite.position.set(vx, vy + yOffset, vz);
+ sprite.add(spriteMesh);
model.add(sprite);
// We have to collect sprites separately, so we can go through all of them
// and rotate them to the camera before rendering the frame
- spriteCollection.push( sprite );
+ spriteCollection.push(sprite);
}
// Tris or Quad
- else if( p.indices ) {
- var materialIndex = this.sceneMaterial.flatMaterialIndex;
+ else if (p.indices) {
+ var materialIndex = this.sceneMaterial.length - 1;
var c = [whiteColor, whiteColor, whiteColor, whiteColor];
var uv = [nullVector, nullVector, nullVector, nullVector];
// Textured
- if( typeof(p.texture) !== 'undefined' ) {
+ if (typeof (p.texture) !== 'undefined') {
materialIndex = p.texture;
-
- var img = this.sceneMaterial.materials[materialIndex].map.image;
- for( var j = 0; j < p.uv.length; j++ ) {
- uv[j] = new THREE.Vector2(p.uv[j].u/img.width, 1-p.uv[j].v/img.height);
+
+ var img = this.sceneMaterial[materialIndex].map.image;
+ for (var j = 0; j < p.uv.length; j++) {
+ uv[j] = new THREE.Vector2(p.uv[j].u/img.width, 1 - p.uv[j].v/img.height);
}
}
@@ -558,21 +563,57 @@ Wipeout.prototype.createModelFromObject = function(object, spriteCollection) {
}
}
- geometry.faceVertexUvs[0].push([uv[2], uv[1], uv[0]]);
- geometry.faces.push( new THREE.Face3(p.indices[2], p.indices[1], p.indices[0], null, [c[2], c[1], c[0]], materialIndex) );
+ var indices = [];
+
+ indices.push(p.indices[2]);
+ indices.push(p.indices[1]);
+ indices.push(p.indices[0]);
+
+ uvs[p.indices[0] * 2] = uv[0].x;uvs[p.indices[0] * 2 + 1] = uv[0].y;
+ uvs[p.indices[1] * 2] = uv[1].x;uvs[p.indices[1] * 2 + 1] = uv[1].y;
+ uvs[p.indices[2] * 2] = uv[2].x;uvs[p.indices[2] * 2 + 1] = uv[2].y;
+
+ colors[p.indices[0] * 3] = c[0].r;colors[p.indices[0] * 3 + 1] = c[0].g;colors[p.indices[0] * 3 + 2] = c[0].b;
+ colors[p.indices[1] * 3] = c[1].r;colors[p.indices[1] * 3 + 1] = c[1].g;colors[p.indices[1] * 3 + 2] = c[1].b;
+ colors[p.indices[2] * 3] = c[2].r;colors[p.indices[2] * 3 + 1] = c[2].g;colors[p.indices[2] * 3 + 2] = c[2].b;
+
+ if (p.indices.length === 4) {
+ indices.push(p.indices[2]);
+ indices.push(p.indices[3]);
+ indices.push(p.indices[1]);
+
+ uvs[p.indices[3] * 2] = uv[3].x;
+ uvs[p.indices[3] * 2 + 1] = uv[3].y;
+
+ colors[p.indices[3] * 3] = c[3].r;
+ colors[p.indices[3] * 3 + 1] = c[3].g;
+ colors[p.indices[3] * 3 + 2] = c[3].b;
+ }
+
+ if (materials[materialIndex] === undefined) {
+ materials[materialIndex] = [];
+ }
- // Push extra UV and Face for Quads
- if( p.indices.length === 4 ) {
- geometry.faceVertexUvs[0].push([uv[2], uv[3], uv[1]]);
- geometry.faces.push( new THREE.Face3(p.indices[2], p.indices[3], p.indices[1], null, [c[2], c[3], c[1]], materialIndex) );
- }
+ indices.forEach((index) => materials[materialIndex].push(index));
}
}
- if( geometry.faces.length ) {
- var mesh = new THREE.Mesh(geometry, this.sceneMaterial);
+ var positionAttribute = new THREE.BufferAttribute(new Float32Array(vertices), 3);
+ var colorAttribute = new THREE.BufferAttribute(new Float32Array(colors),3);
+ var uvAtrribute = new THREE.BufferAttribute(new Float32Array(uvs),2);
+
+ //group rendering by material
+ materials.forEach((indices, materialIndex) => {
+ var geometry = new THREE.BufferGeometry();
+ geometry.setAttribute('position', positionAttribute);
+ geometry.setAttribute('color', colorAttribute);
+ geometry.setAttribute('uv', uvAtrribute);
+ geometry.setIndex(indices);
+
+ var mesh = new THREE.Mesh(geometry, this.sceneMaterial[materialIndex]);
model.add(mesh);
- }
+ });
+
return model;
};
@@ -789,12 +830,9 @@ Wipeout.prototype.createMeshFaceMaterial = function(images, vertexColors, side){
materials.push(material);
}
- materials.push(basicMaterial)-1;
-
- var faceMat = new THREE.MeshFaceMaterial(materials);
- faceMat.flatMaterialIndex = materials.length-1;
+ materials.push(basicMaterial);
- return faceMat;
+ return materials;
};
@@ -827,7 +865,7 @@ Wipeout.prototype.createScene = function(files, modify) {
// ----------------------------------------------------------------------------
// Add a track from TRV, TRF, CMP and TTF files to the scene
-Wipeout.prototype.createTrack = function(files) {
+Wipeout.prototype.createTrack = function (files) {
var rawImages = this.unpackImages(files.textures);
var images = rawImages.map(this.readImage.bind(this));
@@ -838,18 +876,18 @@ Wipeout.prototype.createTrack = function(files) {
// Extract the big (near) versions of these textures only. The near
// version is composed of 4x4 32px tiles.
var composedImages = [];
- for( var i = 0; i < textureIndex.length; i++ ) {
+ for (var i = 0; i < textureIndex.length; i++) {
var idx = textureIndex[i];
-
+
var composedImage = document.createElement('canvas');
composedImage.width = 128;
composedImage.height = 128;
var ctx = composedImage.getContext('2d');
- for( var x = 0; x < 4; x++ ) {
- for( var y = 0; y < 4; y++ ) {
+ for (var x = 0; x < 4; x++) {
+ for (var y = 0; y < 4; y++) {
var image = images[idx.near[y * 4 + x]];
- ctx.drawImage(image, x*32, y*32)
+ ctx.drawImage(image, x * 32, y * 32)
}
}
composedImages.push(composedImage);
@@ -859,70 +897,99 @@ Wipeout.prototype.createTrack = function(files) {
this.trackMaterial = this.createMeshFaceMaterial(composedImages, THREE.FaceColors, THREE.DoubleSide);
var model = new THREE.Object3D();
- var geometry = new THREE.Geometry();
+ const vertices = [];
+ var materials = [];
// Load vertices
var vertexCount = files.vertices.byteLength / Wipeout.TrackVertex.byteLength;
var rawVertices = Wipeout.TrackVertex.readStructs(files.vertices, 0, vertexCount);
- for( var i = 0; i < rawVertices.length; i++ ) {
- geometry.vertices.push( new THREE.Vector3(rawVertices[i].x, -rawVertices[i].y, -rawVertices[i].z) );
+ for (var i = 0; i < rawVertices.length; i++) {
+ vertices.push(new THREE.Vector3(rawVertices[i].x, -rawVertices[i].y, -rawVertices[i].z));
}
// Load Faces
var faceCount = files.faces.byteLength / Wipeout.TrackFace.byteLength;
var faces = Wipeout.TrackFace.readStructs(files.faces, 0, faceCount);
-
+
// Load track texture file (WO2097/WOXL only)
- if( files.trackTexture ) {
+ if (files.trackTexture) {
var trackTextureCount = files.trackTexture.byteLength / Wipeout.TrackTexture.byteLength;
var trackTextures = Wipeout.TrackTexture.readStructs(files.trackTexture, 0, trackTextureCount);
-
+
// Copy data from TEX to TRF structure
- for( var i = 0; i < faces.length; i++ ) {
+ for (var i = 0; i < faces.length; i++) {
var f = faces[i];
var t = trackTextures[i];
-
+
f.tile = t.tile;
f.flags = t.flags;
}
}
- for( var i = 0; i < faces.length; i++ ) {
+ for (var i = 0; i < faces.length; i++) {
var f = faces[i];
- var color = this.int32ToColor( f.color );
- var materialIndex = f.tile;
-
- if(f.flags & Wipeout.TrackFace.FLAGS.BOOST)
- {
- //render boost tile as bright blue
- color = new THREE.Color(0.25, 0.25, 2);
+ if (materials[f.tile] === undefined) {
+ materials[f.tile] = [];
}
-
- geometry.faces.push( new THREE.Face3(f.indices[0], f.indices[1], f.indices[2], null, color, materialIndex) );
- geometry.faces.push( new THREE.Face3(f.indices[2], f.indices[3], f.indices[0], null, color, materialIndex) );
-
- var flipx = (f.flags & Wipeout.TrackFace.FLAGS.FLIP) ? 1: 0;
- geometry.faceVertexUvs[0].push([
- new THREE.Vector2(1-flipx, 1),
- new THREE.Vector2(0+flipx, 1),
- new THREE.Vector2(0+flipx, 0)
- ]);
- geometry.faceVertexUvs[0].push([
- new THREE.Vector2(0+flipx, 0),
- new THREE.Vector2(1-flipx, 0),
- new THREE.Vector2(1-flipx, 1)
- ]);
+ materials[f.tile].push(f);
}
- var mesh = new THREE.Mesh(geometry, this.trackMaterial);
- model.add(mesh);
- this.scene.add( model );
+ materials.forEach((faces, index) => {
+ var faceVertices = [];
+ var faceColors = [];
+ var faceUVs = [];
+
+ var geometry = new THREE.BufferGeometry();
+
+ faces.forEach((f) => {
+ var c = this.int32ToColor(f.color);
+
+ if (f.flags & Wipeout.TrackFace.FLAGS.BOOST) {
+ //render boost tile as bright blue
+ c = new THREE.Color(0.25, 0.25, 2);
+ }
+
+ faceVertices.push(vertices[f.indices[0]].x); faceVertices.push(vertices[f.indices[0]].y); faceVertices.push(vertices[f.indices[0]].z);
+ faceVertices.push(vertices[f.indices[1]].x); faceVertices.push(vertices[f.indices[1]].y); faceVertices.push(vertices[f.indices[1]].z);
+ faceVertices.push(vertices[f.indices[2]].x); faceVertices.push(vertices[f.indices[2]].y); faceVertices.push(vertices[f.indices[2]].z);
+
+ faceVertices.push(vertices[f.indices[2]].x); faceVertices.push(vertices[f.indices[2]].y); faceVertices.push(vertices[f.indices[2]].z);
+ faceVertices.push(vertices[f.indices[3]].x); faceVertices.push(vertices[f.indices[3]].y); faceVertices.push(vertices[f.indices[3]].z);
+ faceVertices.push(vertices[f.indices[0]].x); faceVertices.push(vertices[f.indices[0]].y); faceVertices.push(vertices[f.indices[0]].z);
+
+ faceColors.push(c.r); faceColors.push(c.g); faceColors.push(c.b);
+ faceColors.push(c.r); faceColors.push(c.g); faceColors.push(c.b);
+ faceColors.push(c.r); faceColors.push(c.g); faceColors.push(c.b);
+
+ faceColors.push(c.r); faceColors.push(c.g); faceColors.push(c.b);
+ faceColors.push(c.r); faceColors.push(c.g); faceColors.push(c.b);
+ faceColors.push(c.r); faceColors.push(c.g); faceColors.push(c.b);
+
+ var flipx = (f.flags & Wipeout.TrackFace.FLAGS.FLIP) ? 1 : 0;
+
+ faceUVs.push(1 - flipx); faceUVs.push(1);
+ faceUVs.push(0 + flipx); faceUVs.push(1);
+ faceUVs.push(0 + flipx); faceUVs.push(0);
+
+ faceUVs.push(0 + flipx); faceUVs.push(0);
+ faceUVs.push(1 - flipx); faceUVs.push(0);
+ faceUVs.push(1 - flipx); faceUVs.push(1);
+ });
+
+ geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(faceVertices), 3));
+ geometry.setAttribute('color', new THREE.BufferAttribute(new Float32Array(faceColors), 3));
+ geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(faceUVs), 2));
+
+ var mesh = new THREE.Mesh(geometry, this.trackMaterial[index]);
+ model.add(mesh);
+ });
+ this.scene.add(model);
- this.createCameraSpline(files.sections, faces, geometry.vertices);
+ this.createCameraSpline(files.sections, faces, vertices);
};
@@ -983,7 +1050,7 @@ Wipeout.prototype.createCameraSpline = function(buffer, faces, vertices) {
// Increase arc length subdivisions to get constant camera speed during jumps.
// This prevent camera going too fast due imprecise length distance estimations.
- this.cameraSpline.__arcLengthDivisions = 20000;
+ this.cameraSpline.arcLengthDivisions = 20000;
// Draw the Camera Spline
// this.scene.add( new THREE.Mesh(