HollowBond/Public/ecma/Geometries/Game/RailingGeometryGame.ecma.js

92 lines
4.0 KiB
JavaScript

"use strict";
const RailingGeometryGame = (function(){
const RailingGeometryGame = function(hollow_bond){
const cache = {};
// Genera un prisma cuadrangular (box) dentro de los buffers de la geometría
const append_box = (buffers, min_x, max_x, min_y, max_y, min_z, max_z) => {
const { positions, normals, uvs, indices } = buffers;
let offset = positions.length / 3;
const add_quad = (p1, p2, p3, p4, n) => {
positions.push(...p1, ...p2, ...p3, ...p4);
normals.push(...n, ...n, ...n, ...n);
uvs.push(0, 0, 1, 0, 1, 1, 0, 1);
indices.push(offset, offset + 2, offset + 1, offset, offset + 3, offset + 2);
offset += 4;
};
// Top (+Y) y Bottom (-Y)
add_quad([min_x, max_y, max_z], [max_x, max_y, max_z], [max_x, max_y, min_z], [min_x, max_y, min_z], [0, 1, 0]);
add_quad([min_x, min_y, min_z], [max_x, min_y, min_z], [max_x, min_y, max_z], [min_x, min_y, max_z], [0, -1, 0]);
// North (-Z) y South (+Z)
add_quad([max_x, min_y, min_z], [min_x, min_y, min_z], [min_x, max_y, min_z], [max_x, max_y, min_z], [0, 0, -1]);
add_quad([min_x, min_y, max_z], [max_x, min_y, max_z], [max_x, max_y, max_z], [min_x, max_y, max_z], [0, 0, 1]);
// West (-X) y East (+X)
add_quad([min_x, min_y, min_z], [min_x, min_y, max_z], [min_x, max_y, max_z], [min_x, max_y, min_z], [-1, 0, 0]);
add_quad([max_x, min_y, max_z], [max_x, min_y, min_z], [max_x, max_y, min_z], [max_x, max_y, max_z], [1, 0, 0]);
};
this.get_for_segment = segment => {
const is_x = (segment.side === "north" || segment.side === "south");
const length = is_x ? Math.abs(segment.xt - segment.xf) : Math.abs(segment.zt - segment.zf);
const height = segment.height || 1.0;
const th = segment.thickness || 0.08;
const h_th = th * 0.5;
const key = `rail_${is_x ? "x" : "z"}_${length.toFixed(2)}`;
if(cache[key]){
return cache[key];
}
const buffers = { positions: [], normals: [], uvs: [], indices: [] };
const half_len = length * 0.5;
// 1. Pasamanos superior (1.0m) y Travesaño medio (0.5m)
if(is_x){
append_box(buffers, -half_len, half_len, height - 0.05, height, -h_th, h_th);
append_box(buffers, -half_len, half_len, height * 0.5 - 0.02, height * 0.5 + 0.02, -h_th * 0.7, h_th * 0.7);
} else {
append_box(buffers, -h_th, h_th, height - 0.05, height, -half_len, half_len);
append_box(buffers, -h_th * 0.7, h_th * 0.7, height * 0.5 - 0.02, height * 0.5 + 0.02, -half_len, half_len);
}
// 2. Postes verticales (en los extremos y espaciados cada ~1.0m)
const post_count = Math.max(2, Math.round(length / 1.0) + 1);
for(let i = 0; i < post_count; i++){
const t = i / (post_count - 1);
const pos = (t - 0.5) * length;
if(is_x){
append_box(buffers, pos - h_th, pos + h_th, 0, height, -h_th, h_th);
} else {
append_box(buffers, -h_th, h_th, 0, height, pos - h_th, pos + h_th);
}
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", new THREE.Float32BufferAttribute(buffers.positions, 3));
geometry.setAttribute("normal", new THREE.Float32BufferAttribute(buffers.normals, 3));
geometry.setAttribute("uv", new THREE.Float32BufferAttribute(buffers.uvs, 2));
geometry.setIndex(buffers.indices);
cache[key] = geometry;
return geometry;
};
this.reset = () => {
for(const k in cache){
cache[k].dispose();
delete cache[k];
}
};
};
return RailingGeometryGame;
})();