whisper.cat/weboasis/arcade/chess/js/factory.js
2023-10-05 23:28:32 +11:00

420 lines
10 KiB
JavaScript

// ECMAScript 5 strict mode
/* jshint globalstrict: true*/
/* global THREE, $, document, window, console */
/* global LOADING_BAR_SCALE,ROWS,COLS,PIECE_SIZE, BOARD_SIZE, FLOOR_SIZE, WIREFRAME, DEBUG, Cell, WHITE, BLACK, FEEDBACK, SHADOW */
/* global createCell */
/*
* initPieceFactory and initCellFactory need to be called after
* all ressources are loaded (geometry and texture)
*
* they will create the createPiece and createCell function
* and keep some texture/material objects in a closure to avoid
* unnecessary cloning
*/
"use strict";
var geometries = {};
var textures = {};
function initPieceFactory () {
// common textures
var tiling = 4;
var colors = [];
for(var c = 0; c<2; c++) {
colors[c] = textures['texture/wood-'+c+'.jpg'].clone();
colors[c].tile(tiling);
}
var norm = textures['texture/wood_N.jpg'].clone();
norm.tile(tiling);
var spec = textures['texture/wood_S.jpg'].clone();
spec.tile(tiling);
function createPiece(name,color) {
var size = BOARD_SIZE/COLS * PIECE_SIZE;
// container for the piece and its reflexion
var piece = new THREE.Object3D();
// base material for all the piece (only lightmap changes)
var material = new THREE.MeshPhongMaterial({
color:0xffffff,
specular:0xaaaaaa,
shininess:60.0,
map:colors[color],
normalMap:norm,
specularMap:spec,
wireframe:WIREFRAME
});
material.normalScale.set(0.3,0.3);
// urls of geometry and lightmap
var urlJson = '3D/json/'+name+'.json';
var urlAO = 'texture/'+name+'-ao.jpg';
var geo = geometries[urlJson];
// no need to clone this texture
// since its pretty specific
var light = textures[urlAO];
light.format = THREE.LuminanceFormat;
material.lightMap = light;
var mesh = new THREE.Mesh(geo,material);
if (SHADOW) {
mesh.castShadow = true;
mesh.receiveShadow = true;
}
mesh.scale.set(size,size,size);
// we rotate pieces so they face each other (mostly relevant for knight)
mesh.rotation.y += (color == WHITE) ? -Math.PI/2 : Math.PI/2;
// we create the reflection
// it's a cloned with a negative scale on the Y axis
var reflexion = mesh.clone();
reflexion.scale.y *= -1;
reflexion.material = reflexion.material.clone();
reflexion.material.side = THREE.BackSide;
piece.add(mesh);
piece.add(reflexion);
piece.name = name;
piece.color = color;
return piece;
}
// make it global
window.createPiece = createPiece;
}
function initCellFactory() {
var materials = [];
var tiling = 2;
// common textures
var diff;
var norm = textures['texture/wood_N.jpg'].clone();
norm.tile(tiling);
var spec = textures['texture/wood_S.jpg'].clone();
spec.tile(tiling);
for(var c = 0; c<2; c++) {
diff = textures['texture/wood-'+c+'.jpg'].clone();
diff.tile(tiling);
//common material
materials[c] = new THREE.MeshPhongMaterial({
color:0xffffff,
specular:[0xAAAAAA,0x444444][c],
shininess:30.0,
wireframe:WIREFRAME,
transparent:true,
map:diff,
specularMap:spec,
normalMap:norm,
//blending: THREE.AdditiveBlending,
opacity:0.5
});
//materials[c].normalScale.set(0.5,0.5);
}
function createCell(size,color) {
// container for the cell and its reflexion
var geo = new THREE.PlaneGeometry(size,size);
// randomize uv offset to ad a bit of variety
var randU = Math.random();
var randV = Math.random();
var uvs = geo.faceVertexUvs[0][0];
for (var j = 0; j < uvs.length; j++) {
uvs[j].x += randU;
uvs[j].y += randV;
}
var cell = new THREE.Mesh(geo,materials[color]);
if (SHADOW) {
cell.receiveShadow = true;
}
// by default PlaneGeometry is vertical
cell.rotation.x = -Math.PI/2;
cell.color = color;
return cell;
}
// make it global
window.createCell = createCell;
}
function createChessBoard(size) {
// contains everything that makes the board
var lChessBoard = new THREE.Object3D();
var cellSize = size/COLS;
var square,cell;
for(var i=0; i< ROWS*COLS; i++) {
var col = i%COLS;
var row = Math.floor(i/COLS);
cell = new Cell(i);
square = createCell(cellSize,1-(i+row)%2);
square.position = cell.getWorldPosition();
square.name = cell.position;
lChessBoard.add(square);
}
// some fake inner environment color for reflexion
var innerBoard = new THREE.Mesh (
geometries['3D/json/innerBoard.json'],
new THREE.MeshBasicMaterial({
color:0x783e12
})
);
innerBoard.scale.set(size,size,size);
/// board borders
var tiling = 6;
var wood = textures['texture/wood-0.jpg'].clone();
var spec = textures['texture/wood_S.jpg'].clone();
var norm = textures['texture/wood_N.jpg'].clone();
wood.tile(tiling);
spec.tile(tiling);
norm.tile(tiling);
var geo = geometries['3D/json/board.json'];
geo.computeBoundingBox();
var board = new THREE.Mesh (
geo,
new THREE.MeshPhongMaterial({
color:0xffffff,
map:wood,
specular: 0xffffff,
specularMap: spec,
normalMap: norm,
shininess: 60,
normalScale: new THREE.Vector2(0.2,0.2)
})
);
var hCorrection = 0.62; // yeah I should just create a better geometry
board.scale.set(size,size*hCorrection,size);
lChessBoard.height = geo.boundingBox.min.y * board.scale.y;
if (SHADOW) {
board.receiveShadow = true;
board.castShadow = true;
}
lChessBoard.add(innerBoard);
lChessBoard.add(board);
lChessBoard.name = "chessboard";
return lChessBoard;
}
function createFloor(size,chessboardSize) {
// The floor is a fake plane with a hole in it to allow
// for the fake reflexion trick to work
// so we build it vertices by vertices
// material
var tiling = 30*size/1000;
var material = new THREE.MeshPhongMaterial({
color:0xffffff,
wireframe:WIREFRAME ,
specular:0xaaaaaa,
shininess:30
});
var diff = textures['texture/floor.jpg'];
var spec = textures['texture/floor_S.jpg'];
var norm = textures['texture/floor_N.jpg'];
var light = textures['texture/fakeShadow.jpg'];
diff.tile(tiling);
spec.tile(tiling);
norm.tile(tiling);
light.format = THREE.RGBFormat;
material.map = diff;
material.normalMap = norm;
material.normalScale.set(0.6,0.6);
material.specularMap = spec;
material.lightMap = light;
// geometry
var halfBoard = chessboardSize/2;
var halfSize = size/2;
var floorGeo = new THREE.Geometry();
// outter vertices
floorGeo.vertices.push(new THREE.Vector3(-halfSize,0,-halfSize));
floorGeo.vertices.push(new THREE.Vector3( halfSize,0,-halfSize));
floorGeo.vertices.push(new THREE.Vector3( halfSize,0, halfSize));
floorGeo.vertices.push(new THREE.Vector3(-halfSize,0, halfSize));
// hole vertices
floorGeo.vertices.push(new THREE.Vector3(-halfBoard,0,-halfBoard));
floorGeo.vertices.push(new THREE.Vector3( halfBoard,0,-halfBoard));
floorGeo.vertices.push(new THREE.Vector3( halfBoard,0, halfBoard));
floorGeo.vertices.push(new THREE.Vector3(-halfBoard,0, halfBoard));
floorGeo.faceVertexUvs[ 0 ] = [];
floorGeo.faceVertexUvs[ 1 ] = [];
/*
* vertices uvs-lightmap
* 0-----------1 80-----------80
* |\ /| |\ /|
* | \ / | | \ / |
* | \ / | | \ / |
* | 4---5 | | 0---0 |
* | | | | | | | |
* | 7---6 | | 0---0 |
* | / \ | | / \ |
* | / \ | | / \ |
* |/ \| |/ \|
* 3-----------2 80-----------80
*/
// all normals just points upward
var normal = new THREE.Vector3( 0, 1, 0 );
// list of vertex index for each face
var faces = [
[0,4,5,1],
[1,5,6,2],
[2,6,7,3],
[3,7,4,0]
];
faces.forEach( function(f) {
var uvs1 = [];
var uvs2 = [];
var lightU,lightV;
f.forEach(function(v,i) {
// we linearily transform positions
// from a -halfSize-halfSize space
// to a 0-1 space
uvs1.push(new THREE.Vector2(
(floorGeo.vertices[v].x+halfSize)/size,
(floorGeo.vertices[v].z+halfSize)/size
));
lightU = (v < 4) ? 80 : 0;
lightV = (i < 2) ? 0 : 1;
uvs2.push(new THREE.Vector2(lightU,lightV));
});
// we create a new face folowing the faces list
var face = new THREE.Face4(
f[0],f[1],f[2],f[3]
);
// and apply normals (without this, no proper lighting)
face.normal.copy( normal );
face.vertexNormals.push(
normal.clone(),
normal.clone(),
normal.clone(),
normal.clone()
);
// add the face to the geometry's faces list
floorGeo.faces.push(face);
// add uv coordinates to uv channels.
floorGeo.faceVertexUvs[ 0 ].push(uvs1); // for diffuse/normal
floorGeo.faceVertexUvs[ 1 ].push(uvs2); // for lightmap
});
// not sure it's needed but since it's in THREE.PlaneGeometry...
floorGeo.computeCentroids();
var floor = new THREE.Mesh(floorGeo,material);
if(SHADOW) {
floor.receiveShadow = true;
}
floor.name = "floor";
return floor;
}
// special highlighting materials
var validCellMaterial = null;
function createValidCellMaterial () {
validCellMaterial = [];
var tiling = 2;
// common textures
var diff;
var norm = textures['texture/wood_N.jpg'].clone();
norm.tile(tiling);
var spec = textures['texture/wood_S.jpg'].clone();
spec.tile(tiling);
for(var c = 0; c<2; c++) {
diff = textures['texture/wood-1.jpg'].clone();
diff.tile(tiling);
//common material
validCellMaterial[c] = new THREE.MeshPhongMaterial({
color:0x00ff00,
specular:0x999999,
shininess:60.0,
wireframe:WIREFRAME,
map:diff,
specularMap:spec,
normalMap:norm
});
//materials[c].normalScale.set(0.5,0.5);
}
}
var selectedMaterial = null;
function createSelectedMaterial() {
selectedMaterial = [];
var tiling = 4;
// common textures
var diff;
var norm = textures['texture/wood_N.jpg'].clone();
norm.tile(tiling);
var spec = textures['texture/wood_S.jpg'].clone();
spec.tile(tiling);
for(var c = 0; c<2; c++) {
diff = textures['texture/wood-1.jpg'].clone();
diff.tile(tiling);
//common material
selectedMaterial[c] = new THREE.MeshPhongMaterial({
color:0x00ff00,
emissive:0x009900,
specular:0x999999,
shininess:60.0,
wireframe:WIREFRAME,
transparent:false,
map:diff,
specularMap:spec,
normalMap:norm
//opacity:0.4
});
selectedMaterial[c].normalScale.set(0.3,0.3);
}
}