"use strict"; const FrameGeometryGame = (function(){ const FrameGeometryGame = function(hollow_bond){ const cache = {}; /** * Construye el túnel del marco con moldura 3D sin solapamiento de suelo con la sala. * * @param {number} pass_w - Ancho libre del vano * @param {number} height - Altura libre del vano * @param {number} wall_depth - Grosor del tabique entre salas (room_padding * 2) * @param {boolean} is_horiz - true si corre en X, false si corre en Z */ this.get = (pass_w, height, wall_depth, is_horiz) => { const key = `${pass_w}_${height}_${wall_depth}_${is_horiz}`; if(cache[key]){ return cache[key]; } const geometry = new THREE.BufferGeometry(); // Medias dimensiones del vano libre const hx = is_horiz ? pass_w / 2 : wall_depth / 2; const hz = is_horiz ? wall_depth / 2 : pass_w / 2; const hy = height / 2; // Dimensiones de la moldura/tapajuntas const casing_w = 0.06; // 6 cm de solape sobre la pared const casing_t = 0.02; // 2 cm de relieve hacia el interior de la sala const positions = []; const normals = []; const uvs = []; const indices = []; let index_offset = 0; const add_quad = (p1, p2, p3, p4, normal, uv_w, uv_h) => { positions.push(...p1, ...p2, ...p3, ...p4); normals.push(...normal, ...normal, ...normal, ...normal); uvs.push(0, 0, uv_w, 0, uv_w, uv_h, 0, uv_h); indices.push( index_offset, index_offset + 2, index_offset + 1, index_offset, index_offset + 3, index_offset + 2 ); index_offset += 4; }; if(is_horiz){ const total_z = hz + casing_t; // 1. UMBRAL / SUELO TRANSITABLE (+Y) // Se acota estrictamente a [-hz, hz] para que coincida justo con el final de la moqueta add_quad( [-hx, -hy, -hz], [ hx, -hy, -hz], [ hx, -hy, hz], [-hx, -hy, hz], [0, 1, 0], pass_w, wall_depth ); // 2. TECHO INTERIOR DEL VANO (-Y) // Aquí sí cubre hasta total_z para sellar la parte baja de la moldura superior add_quad( [-hx, hy, total_z], [ hx, hy, total_z], [ hx, hy, -total_z], [-hx, hy, -total_z], [0, -1, 0], pass_w, total_z * 2 ); // 3. JAMBAS INTERIORES LATERALES // Izquierda (+X) add_quad( [-hx, -hy, -total_z], [-hx, -hy, total_z], [-hx, hy, total_z], [-hx, hy, -total_z], [1, 0, 0], total_z * 2, height ); // Derecha (-X) add_quad( [ hx, -hy, total_z], [ hx, -hy, -total_z], [ hx, hy, -total_z], [ hx, hy, total_z], [-1, 0, 0], total_z * 2, height ); // 4. MOLDURAS EXTERIORES // Cara Sur (+Z) const z_s = total_z; add_quad([-hx - casing_w, -hy, z_s], [-hx, -hy, z_s], [-hx, hy + casing_w, z_s], [-hx - casing_w, hy + casing_w, z_s], [0, 0, 1], casing_w, height + casing_w); add_quad([ hx, -hy, z_s], [ hx + casing_w, -hy, z_s], [ hx + casing_w, hy + casing_w, z_s], [ hx, hy + casing_w, z_s], [0, 0, 1], casing_w, height + casing_w); add_quad([-hx, hy, z_s], [ hx, hy, z_s], [ hx, hy + casing_w, z_s], [-hx, hy + casing_w, z_s], [0, 0, 1], pass_w, casing_w); // Cantos de cierre contra la pared (Sur) add_quad([-hx - casing_w, -hy, hz], [-hx - casing_w, -hy, z_s], [-hx - casing_w, hy + casing_w, z_s], [-hx - casing_w, hy + casing_w, hz], [-1, 0, 0], casing_t, height + casing_w); add_quad([ hx + casing_w, -hy, z_s], [ hx + casing_w, -hy, hz], [ hx + casing_w, hy + casing_w, hz], [ hx + casing_w, hy + casing_w, z_s], [1, 0, 0], casing_t, height + casing_w); add_quad([-hx - casing_w, hy + casing_w, hz], [ hx + casing_w, hy + casing_w, hz], [ hx + casing_w, hy + casing_w, z_s], [-hx - casing_w, hy + casing_w, z_s], [0, 1, 0], pass_w + casing_w * 2, casing_t); // Cara Norte (-Z) const z_n = -total_z; add_quad([-hx, -hy, z_n], [-hx - casing_w, -hy, z_n], [-hx - casing_w, hy + casing_w, z_n], [-hx, hy + casing_w, z_n], [0, 0, -1], casing_w, height + casing_w); add_quad([ hx + casing_w, -hy, z_n], [ hx, -hy, z_n], [ hx, hy + casing_w, z_n], [ hx + casing_w, hy + casing_w, z_n], [0, 0, -1], casing_w, height + casing_w); add_quad([ hx, hy, z_n], [-hx, hy, z_n], [-hx, hy + casing_w, z_n], [ hx, hy + casing_w, z_n], [0, 0, -1], pass_w, casing_w); // Cantos de cierre contra la pared (Norte) add_quad([-hx - casing_w, -hy, z_n], [-hx - casing_w, -hy, -hz], [-hx - casing_w, hy + casing_w, -hz], [-hx - casing_w, hy + casing_w, z_n], [-1, 0, 0], casing_t, height + casing_w); add_quad([ hx + casing_w, -hy, -hz], [ hx + casing_w, -hy, z_n], [ hx + casing_w, hy + casing_w, z_n], [ hx + casing_w, hy + casing_w, -hz], [1, 0, 0], casing_t, height + casing_w); add_quad([-hx - casing_w, hy + casing_w, z_n], [ hx + casing_w, hy + casing_w, z_n], [ hx + casing_w, hy + casing_w, -hz], [-hx - casing_w, hy + casing_w, -hz], [0, 1, 0], pass_w + casing_w * 2, casing_t); } else { const total_x = hx + casing_t; // 1. UMBRAL / SUELO TRANSITABLE (+Y) // Se acota a [-hx, hx] para alinearse de forma exacta a la moqueta add_quad( [-hx, -hy, -hz], [ hx, -hy, -hz], [ hx, -hy, hz], [-hx, -hy, hz], [0, 1, 0], wall_depth, pass_w ); // 2. TECHO INTERIOR (-Y) add_quad( [-total_x, hy, hz], [ total_x, hy, hz], [ total_x, hy, -hz], [-total_x, hy, -hz], [0, -1, 0], total_x * 2, pass_w ); // 3. JAMBAS INTERIORES LATERALES // Izquierda (+Z) add_quad( [-total_x, -hy, -hz], [ total_x, -hy, -hz], [ total_x, hy, -hz], [-total_x, hy, -hz], [0, 0, 1], total_x * 2, height ); // Derecha (-Z) add_quad( [ total_x, -hy, hz], [-total_x, -hy, hz], [-total_x, hy, hz], [ total_x, hy, hz], [0, 0, -1], total_x * 2, height ); // 4. MOLDURAS EXTERIORES // Cara Este (+X) const x_e = total_x; add_quad([x_e, -hy, hz], [x_e, -hy, hz + casing_w], [x_e, hy + casing_w, hz + casing_w], [x_e, hy + casing_w, hz], [1, 0, 0], casing_w, height + casing_w); add_quad([x_e, -hy, -hz - casing_w], [x_e, -hy, -hz], [x_e, hy + casing_w, -hz], [x_e, hy + casing_w, -hz - casing_w], [1, 0, 0], casing_w, height + casing_w); add_quad([x_e, hy, -hz], [x_e, hy, hz], [x_e, hy + casing_w, hz], [x_e, hy + casing_w, -hz], [1, 0, 0], pass_w, casing_w); // Cantos Este add_quad([hx, -hy, -hz - casing_w], [x_e, -hy, -hz - casing_w], [x_e, hy + casing_w, -hz - casing_w], [hx, hy + casing_w, -hz - casing_w], [0, 0, -1], casing_t, height + casing_w); add_quad([x_e, -hy, hz + casing_w], [hx, -hy, hz + casing_w], [hx, hy + casing_w, hz + casing_w], [x_e, hy + casing_w, hz + casing_w], [0, 0, 1], casing_t, height + casing_w); add_quad([hx, hy + casing_w, -hz - casing_w], [x_e, hy + casing_w, -hz - casing_w], [x_e, hy + casing_w, hz + casing_w], [hx, hy + casing_w, hz + casing_w], [0, 1, 0], casing_t, pass_w + casing_w * 2); // Cara Oeste (-X) const x_w = -total_x; add_quad([x_w, -hy, hz + casing_w], [x_w, -hy, hz], [x_w, hy + casing_w, hz], [x_w, hy + casing_w, hz + casing_w], [-1, 0, 0], casing_w, height + casing_w); add_quad([x_w, -hy, -hz], [x_w, -hy, -hz - casing_w], [x_w, hy + casing_w, -hz - casing_w], [x_w, hy + casing_w, -hz], [-1, 0, 0], casing_w, height + casing_w); add_quad([x_w, hy, hz], [x_w, hy, -hz], [x_w, hy + casing_w, -hz], [x_w, hy + casing_w, hz], [-1, 0, 0], pass_w, casing_w); // Cantos Oeste add_quad([x_w, -hy, -hz - casing_w], [-hx, -hy, -hz - casing_w], [-hx, hy + casing_w, -hz - casing_w], [x_w, hy + casing_w, -hz - casing_w], [0, 0, -1], casing_t, height + casing_w); add_quad([-hx, -hy, hz + casing_w], [x_w, -hy, hz + casing_w], [x_w, hy + casing_w, hz + casing_w], [-hx, hy + casing_w, hz + casing_w], [0, 0, 1], casing_t, height + casing_w); add_quad([x_w, hy + casing_w, -hz - casing_w], [-hx, hy + casing_w, -hz - casing_w], [-hx, hy + casing_w, hz + casing_w], [x_w, hy + casing_w, hz + casing_w], [0, 1, 0], casing_t, pass_w + casing_w * 2); } geometry.setAttribute("position", new THREE.Float32BufferAttribute(positions, 3)); geometry.setAttribute("normal", new THREE.Float32BufferAttribute(normals, 3)); geometry.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2)); geometry.setIndex(indices); cache[key] = geometry; return geometry; }; this.reset = () => { for(const key in cache){ if(cache[key]){ cache[key].dispose(); delete cache[key]; } } }; }; return FrameGeometryGame; })();