130 lines
6.3 KiB
JavaScript
130 lines
6.3 KiB
JavaScript
"use strict";
|
|
|
|
const ElevatorFrameGeometryGame = (function(){
|
|
|
|
const ElevatorFrameGeometryGame = function(hollow_bond){
|
|
|
|
const cache = {};
|
|
|
|
// Añade una caja completa (6 caras) para elementos aislados o interiores
|
|
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;
|
|
};
|
|
|
|
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]);
|
|
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]);
|
|
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]);
|
|
};
|
|
|
|
// Añade una moldura apoyada en pared SIN cara trasera (-Z) para evitar Z-fighting
|
|
const append_relief = (buffers, min_x, max_x, min_y, max_y, z_base, z_front) => {
|
|
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;
|
|
};
|
|
|
|
// Frontal (+Z) hacia la sala
|
|
add_quad([min_x, min_y, z_front], [max_x, min_y, z_front], [max_x, max_y, z_front], [min_x, max_y, z_front], [0, 0, 1]);
|
|
// Superior (+Y)
|
|
add_quad([min_x, max_y, z_front], [max_x, max_y, z_front], [max_x, max_y, z_base], [min_x, max_y, z_base], [0, 1, 0]);
|
|
// Inferior (-Y)
|
|
add_quad([min_x, min_y, z_base], [max_x, min_y, z_base], [max_x, min_y, z_front], [min_x, min_y, z_front], [0, -1, 0]);
|
|
// Lateral Izquierdo (-X)
|
|
add_quad([min_x, min_y, z_base], [min_x, min_y, z_front], [min_x, max_y, z_front], [min_x, max_y, z_base], [-1, 0, 0]);
|
|
// Lateral Derecho (+X)
|
|
add_quad([max_x, min_y, z_front], [max_x, min_y, z_base], [max_x, max_y, z_base], [max_x, max_y, z_front], [1, 0, 0]);
|
|
// NOTA: No generamos la cara -Z (trasera) porque apoya directamente sobre la pared.
|
|
};
|
|
|
|
this.get_for_elevator = model => {
|
|
const door_w = hollow_bond.elevator_door_width || 1.1;
|
|
const door_h = 2.10;
|
|
const key = `frame_clean_${door_w}_${door_h}`;
|
|
if(cache[key]) return cache[key];
|
|
|
|
const buffers = { positions: [], normals: [], uvs: [], indices: [] };
|
|
const hw = door_w * 0.5; // 0.55m
|
|
|
|
const wall_z = (hollow_bond.room_padding !== undefined) ? hollow_bond.room_padding : 0.0;
|
|
const trim_w = 0.12; // 12 cm de moldura
|
|
const header_h = 0.22; // 22 cm de dintel
|
|
const z_front = wall_z + 0.02; // Relieve limpio de 2 cm
|
|
|
|
// --- GRUPO 0: Acero cepillado del marco ---
|
|
const start_metal = buffers.indices.length;
|
|
|
|
// 1. Forro interior de las jambas (dentro del vano, sin pared de yeso)
|
|
append_box(buffers, -hw - 0.025, -hw, 0, door_h, -0.04, wall_z);
|
|
append_box(buffers, hw, hw + 0.025, 0, door_h, -0.04, wall_z);
|
|
append_box(buffers, -hw, hw, door_h, door_h + 0.025, -0.04, wall_z);
|
|
|
|
// 2. Tapajuntas sobre la pared (SIN penetración y SIN cara trasera)
|
|
// Moldura izquierda
|
|
append_relief(buffers, -hw - trim_w, -hw, 0, door_h + header_h, wall_z, z_front);
|
|
// Moldura derecha
|
|
append_relief(buffers, hw, hw + trim_w, 0, door_h + header_h, wall_z, z_front);
|
|
// Dintel superior
|
|
append_relief(buffers, -hw, hw, door_h, door_h + header_h, wall_z, z_front);
|
|
|
|
// 3. Umbral de suelo
|
|
append_box(buffers, -hw, hw, 0, 0.012, -0.04, z_front);
|
|
|
|
// 4. Placa base de la botonera exterior (en relieve, sin cara trasera)
|
|
const btn_x1 = hw + trim_w + 0.03;
|
|
const btn_x2 = btn_x1 + 0.12;
|
|
append_relief(buffers, btn_x1, btn_x2, 1.10, 1.38, wall_z, z_front);
|
|
|
|
const count_metal = buffers.indices.length - start_metal;
|
|
|
|
// --- GRUPO 1: Elementos luminosos ---
|
|
const start_light = buffers.indices.length;
|
|
|
|
// Display de piso
|
|
append_relief(buffers, -0.18, 0.18, door_h + 0.06, door_h + 0.16, z_front, z_front + 0.006);
|
|
|
|
// Botón de llamada iluminado
|
|
append_relief(buffers, btn_x1 + 0.035, btn_x2 - 0.035, 1.20, 1.28, z_front, z_front + 0.008);
|
|
|
|
const count_light = buffers.indices.length - start_light;
|
|
|
|
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);
|
|
|
|
geometry.addGroup(start_metal, count_metal, 0);
|
|
geometry.addGroup(start_light, count_light, 1);
|
|
|
|
cache[key] = geometry;
|
|
return geometry;
|
|
};
|
|
|
|
this.reset = () => {
|
|
for(const k in cache){
|
|
cache[k].dispose();
|
|
delete cache[k];
|
|
}
|
|
};
|
|
|
|
};
|
|
|
|
return ElevatorFrameGeometryGame;
|
|
})(); |