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

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;
})();