mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-07 23:01:06 +02:00
/assets was served uncompressed and without Cache-Control, so phones downloaded the full 11 MB bundle and revalidated it on every load. Text assets are now gzip-compressed once per file and kept in memory, and files with a content hash in their name are marked immutable. The pdf.js runtime data has no hash and is revalidated instead. ----- Load pages and languages when they are needed (#3175) Every page and all 15 languages were one 11 MB script. Pages are now separate files loaded on first open, and only English is bundled; the language in use loads before the first render. A tab left on an older build reloads once when a file is gone, after the server answers again, so a kiosk is never left on the browser's connection error page. The service worker serves hashed files from its cache and drops the previous build's files.
129 lines
27 KiB
JavaScript
129 lines
27 KiB
JavaScript
import{i as e}from"./chunk-aKtaBQYM.js";import{C as t,D as n,l as r,w as i}from"./client-BdOyoZJz.js";import{t as a}from"./createLucideIcon-Yo2YoYjm.js";import{t as o}from"./loader-circle-CB4leTZa.js";import{A as s,O as c,_ as l,a as u,i as d,l as f,m as p,p as m,r as h,t as g,w as _}from"./OrbitControls-Bbqf07B-.js";var v=a(`file-exclamation-point`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]),y=e(n(),1),b={travel:0,wall:1,sparseInfill:2,solidInfill:3,skirt:4,support:5,raft:6,gapFill:7,thinWall:8,bridge:9,ironing:10,primeTower:11},x={"outer wall":b.wall,"inner wall":b.wall,perimeter:b.wall,"external perimeter":b.wall,"overhang wall":b.bridge,"overhang perimeter":b.bridge,"sparse infill":b.sparseInfill,"internal infill":b.sparseInfill,"solid infill":b.solidInfill,"internal solid infill":b.solidInfill,"top surface":b.solidInfill,"top solid infill":b.solidInfill,"bottom surface":b.solidInfill,skirt:b.skirt,"skirt/brim":b.skirt,brim:b.skirt,support:b.support,"support material":b.support,"support interface":b.support,"support material interface":b.support,"support transition":b.support,raft:b.raft,"gap fill":b.gapFill,"gap infill":b.gapFill,"thin wall":b.thinWall,"floating vertical shell":b.solidInfill,"internal bridge":b.bridge,"bottom shell":b.solidInfill,bridge:b.bridge,"bridge infill":b.bridge,"internal bridge infill":b.bridge,ironing:b.ironing,"prime tower":b.primeTower,"wipe tower":b.primeTower,custom:b.wall},S=8,C=Math.PI*2,w=.02,T=256,E=15,D=class{data=new Float32Array(1024*S);count=0;widths=[];push(e,t,n,r,i,a,o,s,c){if((this.count+1)*S>this.data.length){let e=new Float32Array(this.data.length*2);e.set(this.data),this.data=e}let l=this.count*S;this.data[l]=e,this.data[l+1]=t,this.data[l+2]=n,this.data[l+3]=r,this.data[l+4]=i,this.data[l+5]=a,this.data[l+6]=o,this.data[l+7]=c,this.count+=1,this.widths.push(s)}get length(){return this.count}toFloat32Array(){return this.data.slice(0,this.count*S)}};function O(e){let t,n=0;for(let[r,i]of e)i>n&&(t=r,n=i);return t}function k(e,t){let n=e.indexOf(t);if(n<0)return;let r=Number.parseFloat(e.slice(n+1));return Number.isFinite(r)?r:void 0}function A(e){let t=[],n=0,r=0,i=0,a=0,o=!1,s=b.wall,c=0,l=new Map,u=0,d=0,f=new D,p=0,m=!1,h=null,g=!1,_=0,v=!1,y=1/0,S=1/0,A=1/0,j=-1/0,M=-1/0,N=-1/0,P=()=>{f.length!==0&&(t.push({z:p,paths:f.toFloat32Array(),widths:f.widths}),f=new D,g=!1,h!==null&&(p=h,h=null))},F=(e,t,a,o)=>{if(o){if(!m&&g&&a!==p&&P(),g||(p=a,h=null),g=!0,!v){v=!0,n=e,r=t,i=a;return}f.push(n,r,i,s,e,t,a,c,_),u+=1,e<y&&(y=e),t<S&&(S=t),a<A&&(A=a),e>j&&(j=e),t>M&&(M=t),a>N&&(N=a)}else v&&(f.push(n,r,i,b.travel,e,t,a,0,_),d+=1);n=e,r=t,i=a,v=!0};for(let t of e.split(`
|
|
`)){let e=t.trim();if(e.length===0)continue;if(e.charCodeAt(0)===59){let t=e.slice(1).trimStart(),n=t.indexOf(`:`),r=(n>=0?t.slice(0,n):t).trim().toUpperCase(),i=n>=0?t.slice(n+1).trim():``;if(r===`FEATURE`||r===`TYPE`)s=x[i.toLowerCase()]??b.wall;else if(r===`LINE_WIDTH`||r===`WIDTH`){let e=Number.parseFloat(i);Number.isFinite(e)&&e>0&&(c=e,l.set(e,(l.get(e)??0)+1))}else if(r===`CHANGE_LAYER`||r===`LAYER_CHANGE`)m=!0,P();else if(r===`Z_HEIGHT`||r===`Z`){let e=Number.parseFloat(i);Number.isFinite(e)&&(h=e)}continue}if(e.startsWith(`M83`)){o=!0;continue}if(e.startsWith(`M82`)){o=!1;continue}if(e.startsWith(`G92`)){let t=k(e,`E`);t!==void 0&&(a=t);continue}if(e.charCodeAt(0)===84){let t=Number.parseInt(e.slice(1),10);Number.isFinite(t)&&t>=0&&t<=E&&(_=t);continue}let u=e.startsWith(`G2 `)||e.startsWith(`G3 `)||e.startsWith(`G2`)||e.startsWith(`G3`),d=e.startsWith(`G1`)||e.startsWith(`G0`);if(!d&&!u||u&&!/^G[23](\s|$)/.test(e)||d&&!/^G[01](\s|$)/.test(e))continue;let f=k(e,`X`)??n,p=k(e,`Y`)??r,g=k(e,`Z`)??i,v=k(e,`E`),y=0;v!==void 0&&(y=o?v:v-a,a=v);let S=y>0;if(u){let t=k(e,`I`)??0,a=k(e,`J`)??0,o=n+t,s=r+a,c=Math.hypot(t,a);if(c>0){let t=Math.atan2(r-s,n-o),a=Math.atan2(p-s,f-o),l=e.charCodeAt(1)===50,u=a-t;if(l){for(;u>=0;)u-=C;for(;u<-C;)u+=C}else{for(;u<=0;)u+=C;for(;u>C;)u-=C}if(f===n&&p===r){let t=Math.max(1,Math.round(k(e,`P`)??1));u=(l?-C:C)*t}let d=2*Math.acos(Math.max(-1,Math.min(1,1-w/c))),m=Math.max(1,Math.min(T,Math.ceil(Math.abs(u)/Math.max(d,.001))));for(let e=1;e<=m;e+=1){let n=e/m,r=t+u*n;F(o+c*Math.cos(r),s+c*Math.sin(r),i+(g-i)*n,S)}continue}}(f!==n||p!==r||g!==i)&&F(f,p,g,S)}return P(),{layers:t,segmentCount:u,travelCount:d,defaultWidth:O(l)??.42,bounds:u>0?{min:[y,S,A],max:[j,M,N]}:null}}function j(e){return e.map(e=>{let t=e.paths.slice();for(let e=0;e<t.length;e+=S)t[e+3]!==b.travel&&(t[e+3]=Math.min(t[e+7]+1,E));return{...e,paths:t}})}function M(e,t){if(t.size===0)return e;let n=[];for(let r of e){let e=new D;for(let n=0;n<r.paths.length;n+=S){let i=r.paths[n+3];t.has(i)||e.push(r.paths[n],r.paths[n+1],r.paths[n+2],i,r.paths[n+4],r.paths[n+5],r.paths[n+6],r.widths[n/S]??0,r.paths[n+7])}n.push({...r,paths:e.toFloat32Array(),widths:e.widths})}return n}var N=[0,1,2,0,2,3,0,3,4,0,4,5,0,5,6,0,6,1,5,4,7,5,7,6],P={0:[.42,.45,.5],1:[.85,.51,.17],2:[.21,.45,.76],3:[.35,.75,.85],4:[.16,.68,.4],5:[.66,.42,.85],6:[.55,.45,.35],7:[.95,.85,.25],8:[.9,.35,.65],9:[.9,.25,.25],10:[.6,.82,.55],11:[.3,.72,.7]};function F(e){let t=Math.round(e[0]*255),n=Math.round(e[1]*255),r=Math.round(e[2]*255);return t<<16|n<<8|r}function I(e,t){let n=e.length,r=t>0?t:.42,i=Array(n);for(let t=0;t<n;t++){let n=e[t].z;i[t]=Math.max(.02,t===0?n:n-e[t-1].z)}let a=[],o=[],s=[],c=[],l=[],u=[],d=[],f=[],p=[],m=[],h=new Float64Array(16),g=[],_=[],v=-1,y=0,b=0,x=0,S=-1,C=0,w=1e-4,T=(e,t,n,r,i,p)=>(a.push(e),o.push(t),s.push(n),u.push(r),c.push(i),l.push(p),d.push(C),f.push(!1),a.length-1);for(let t=0;t<n;t++){let n=e[t].paths,a=e[t].widths,o=i[t];if(C=t,n)for(let e=0;e<n.length;e+=8){let i=n[e+3],s=n[e],c=n[e+1],l=n[e+2],u=n[e+4],d=n[e+5],C=n[e+6];if(i===0){g.push(s,c,l,u,d,C),_.push(t);continue}let E=a&&a[e/8]>0?a[e/8]:r;i<16&&(h[i]+=Math.hypot(u-s,d-c));let D;v>=0&&S===i&&Math.abs(y-s)<w&&Math.abs(b-c)<w&&Math.abs(x-l)<w?(D=v,T(u,d,C,i,o,E)):(D=T(s,c,l,i,o,E),T(u,d,C,i,o,E)),f[D]=!0,v=D+1,y=u,b=d,x=C,S=i,p.push(D),m.push(t)}}let E=a.length,D=p.length,O=new Float32Array(E*4),k=new Float32Array(E*4),A=0,j=!1,M=1/0,N=1/0,I=1/0,L=-1/0,R=-1/0,z=-1/0;for(let e=0;e<E;e++){let t=c[e],n=a[e],r=o[e],i=s[e]-.5*t;O[e*4]=n,O[e*4+1]=r,O[e*4+2]=i;let d=e>0&&f[e-1],p=f[e],m=0;if(d||p){let t=d?a[e]-a[e-1]:0,n=d?o[e]-o[e-1]:0,r=d?s[e]-s[e-1]:0,i=p?a[e+1]-a[e]:0,c=p?o[e+1]-o[e]:0,l=p?s[e+1]-s[e]:0;m=Math.atan2(t*c-n*i,t*i+n*c+r*l)}k[e*4]=t,k[e*4+1]=l[e],k[e*4+2]=m,k[e*4+3]=F(P[u[e]]||P[1]),(!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(i)||!Number.isFinite(m))&&(j=!0),A=Math.max(A,Math.abs(n),Math.abs(r),Math.abs(i)),n<M&&(M=n),n>L&&(L=n),r<N&&(N=r),r>R&&(R=r),i<I&&(I=i),i>z&&(z=i)}let B=new Uint32Array(D*4);for(let e=0;e<D;e++)B[e*4]=p[e],B[e*4+1]=m[e];let V={vType:new Uint8Array(E),vWidth:new Float32Array(E),vHeight:new Float32Array(E),vLayer:new Int32Array(E)};for(let e=0;e<E;e++)V.vType[e]=u[e],V.vWidth[e]=l[e],V.vHeight[e]=c[e],V.vLayer[e]=d[e];let H=new Int32Array(n+1);{let e=0;for(let t=0;t<n;t++){for(;e<D&&m[e]===t;)e++;H[t+1]=e}}let U=_.length,W=new Float32Array(U*6);for(let e=0;e<W.length;e++)W[e]=g[e];for(let e=0;e<W.length;e+=3){let t=W[e],n=W[e+1],r=W[e+2];t<M&&(M=t),t>L&&(L=t),n<N&&(N=n),n>R&&(R=n),r<I&&(I=r),r>z&&(z=r)}let G=new Int32Array(n+1);{let e=0;for(let t=0;t<n;t++){for(;e<U&&_[e]===t;)e++;G[t+1]=e}}let ee=E+U>0?{min:[M,N,I],max:[L,R,z]}:null;return{position:O,hwa:k,segIndex:B,nV:E,nSeg:D,layerSegPrefix:H,travelPos:W,travelPrefix:G,nTrav:U,layerCount:n,maxAbs:A,hasNaN:j,meta:V,typeLengths:h,bbox:ee}}var L=[[11,44,122],[19,89,133],[28,136,145],[4,214,15],[170,242,0],[252,249,3],[245,206,10],[227,136,32],[209,104,48],[194,82,60],[148,38,22]].map(e=>[e[0]/255,e[1]/255,e[2]/255]);function R(e,t,n,r){let i=r.length;if(!(n>t))return r[0];let a=(n-t)/(i-1),o=(e-t)/a,s=Math.max(0,Math.min(i-1,Math.floor(o))),c=Math.max(0,Math.min(i-1,s+1)),l=o-s,u=r[s],d=r[c];return[u[0]+(d[0]-u[0])*l,u[1]+(d[1]-u[1])*l,u[2]+(d[2]-u[2])*l]}var z=[{key:`feature`,label:`Feature type`,cont:!1,unit:``},{key:`speed`,label:`Speed`,cont:!0,unit:`mm/s`},{key:`height`,label:`Layer Height`,cont:!0,unit:`mm`},{key:`width`,label:`Line Width`,cont:!0,unit:`mm`},{key:`fan`,label:`Fan Speed`,cont:!0,unit:`%`},{key:`temp`,label:`Temperature`,cont:!0,unit:`°C`}];function B(e,t,n,r){let i=t.vType[n],a=t.vLayer[n],o=a===0;switch(e){case`height`:return t.vHeight[n];case`width`:return t.vWidth[n];case`speed`:return o?r.firstLayerSpeed:r.speedByType[i]??r.speedByType[1];case`fan`:return a<r.closeFanLayers?0:i===9?100:r.fanNormal;case`temp`:return o?r.tempFirst:r.tempNormal;default:return 0}}function V(e,t,n){let{meta:r,nV:i}=e,a=new Float32Array(i*4),o=z.find(e=>e.key===t)||z[0];if(!o.cont){for(let e=0;e<i;e++)a[e*4]=F(P[r.vType[e]]||P[1]);return{color:a,min:0,max:0,viewType:t,label:o.label,unit:o.unit,cont:!1}}let s=1/0,c=-1/0,l=new Float32Array(i);for(let e=0;e<i;e++){let i=B(t,r,e,n);l[e]=i,i<s&&(s=i),i>c&&(c=i)}Number.isFinite(s)||(s=0,c=1);for(let e=0;e<i;e++){let t=R(l[e],s,c,L);a[e*4]=F(t)}return{color:a,min:s,max:c,viewType:t,label:o.label,unit:o.unit,cont:!0}}var H=`
|
|
precision highp float;
|
|
precision highp int;
|
|
precision highp sampler2D;
|
|
precision highp usampler2D;
|
|
#define POINTY_CAPS
|
|
#define FIX_TWISTING
|
|
const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);
|
|
const float light_top_diffuse = 0.6 * 0.8;
|
|
const float light_top_specular = 0.6 * 0.125;
|
|
const float light_top_shininess = 20.0;
|
|
const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);
|
|
const float light_front_diffuse = 0.6 * 0.3;
|
|
const float ambient = 0.3;
|
|
const float emission = 0.15;
|
|
const vec3 UP = vec3(0, 0, 1);
|
|
uniform mat4 view_matrix;
|
|
uniform mat4 projection_matrix;
|
|
uniform vec3 camera_position;
|
|
uniform sampler2D position_tex;
|
|
uniform sampler2D height_width_angle_tex;
|
|
uniform int layer_lo; // 25단계: 이중 슬라이더 하한(레이어). 범위 밖 세그먼트는 셰이더가 O(1) 클립.
|
|
uniform int layer_hi; // 상한은 instanceCount 로 컷(레이어 순 정렬).
|
|
in float vertex_id_float;
|
|
in uint seg_id_a_u; // 인스턴스 어트리뷰트(구 segment_index_tex.r) — 어트리뷰트 fetch 가 texelFetch 보다 쌈
|
|
in uint seg_layer_u; // 인스턴스 어트리뷰트(구 segment_index_tex.g)
|
|
out vec3 color;
|
|
vec3 decode_color(float col) {
|
|
int c = int(round(col));
|
|
int r = (c >> 16) & 0xFF;
|
|
int g = (c >> 8) & 0xFF;
|
|
int b = (c >> 0) & 0xFF;
|
|
float f = 1.0 / 255.0;
|
|
return f * vec3(r, g, b);
|
|
}
|
|
float lighting(vec3 eye_position, vec3 eye_normal) {
|
|
float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);
|
|
float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);
|
|
float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);
|
|
return ambient + top_diffuse + front_diffuse + top_specular + emission;
|
|
}
|
|
ivec2 tex_coord(sampler2D sampler, int id) {
|
|
ivec2 tex_size = textureSize(sampler, 0);
|
|
return (tex_size.y == 1) ? ivec2(id, 0) : ivec2(id % tex_size.x, id / tex_size.x);
|
|
}
|
|
void main() {
|
|
int vertex_id = int(vertex_id_float);
|
|
int seg_layer = int(seg_layer_u);
|
|
if (seg_layer < layer_lo || seg_layer > layer_hi) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); return; } // 범위 밖 → 클립
|
|
int id_a = int(seg_id_a_u);
|
|
int id_b = id_a + 1;
|
|
vec3 pos_a = texelFetch(position_tex, tex_coord(position_tex, id_a), 0).xyz;
|
|
vec3 pos_b = texelFetch(position_tex, tex_coord(position_tex, id_b), 0).xyz;
|
|
vec3 line = pos_b - pos_a;
|
|
float line_len = length(line);
|
|
vec3 line_dir;
|
|
if (line_len < 1e-4)
|
|
line_dir = vec3(1.0, 0.0, 0.0);
|
|
else
|
|
line_dir = line / line_len;
|
|
vec3 line_right_dir;
|
|
if (abs(dot(line_dir, UP)) > 0.9) {
|
|
line_right_dir = normalize(cross(vec3(1, 0, 0), line_dir));
|
|
}
|
|
else
|
|
line_right_dir = normalize(cross(line_dir, UP));
|
|
vec3 line_up_dir = normalize(cross(line_right_dir, line_dir));
|
|
const vec2 horizontal_vertical_view_signs_array[16] = vec2[](
|
|
vec2(1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, 0.0), vec2(0.0, -1.0),
|
|
vec2(0.0, -1.0), vec2(1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, 0.0),
|
|
vec2(0.0, 1.0), vec2(-1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 0.0),
|
|
vec2(1.0, 0.0), vec2(0.0, 1.0), vec2(-1.0, 0.0), vec2(0.0, 0.0)
|
|
);
|
|
int id = vertex_id < 4 ? id_a : id_b;
|
|
vec3 endpoint_pos = vertex_id < 4 ? pos_a : pos_b;
|
|
vec4 hwa_color = texelFetch(height_width_angle_tex, tex_coord(height_width_angle_tex, id), 0); // .xyz=h/w/angle, .w=packed color
|
|
vec3 height_width_angle = hwa_color.xyz;
|
|
#ifdef FIX_TWISTING
|
|
int closer_id = (dot(camera_position - pos_a, camera_position - pos_a) < dot(camera_position - pos_b, camera_position - pos_b)) ? id_a : id_b;
|
|
vec3 closer_pos = (closer_id == id_a) ? pos_a : pos_b;
|
|
vec3 camera_view_dir = normalize(closer_pos - camera_position);
|
|
vec3 closer_height_width_angle = texelFetch(height_width_angle_tex, tex_coord(height_width_angle_tex, closer_id), 0).xyz;
|
|
vec3 diagonal_dir_border = normalize(closer_height_width_angle.x * line_up_dir + closer_height_width_angle.y * line_right_dir);
|
|
#else
|
|
vec3 camera_view_dir = normalize(endpoint_pos - camera_position);
|
|
vec3 diagonal_dir_border = normalize(height_width_angle.x * line_up_dir + height_width_angle.y * line_right_dir);
|
|
#endif
|
|
bool is_vertical_view = abs(dot(camera_view_dir, line_up_dir)) / abs(dot(diagonal_dir_border, line_up_dir)) >
|
|
abs(dot(camera_view_dir, line_right_dir)) / abs(dot(diagonal_dir_border, line_right_dir));
|
|
vec2 signs = horizontal_vertical_view_signs_array[vertex_id + 8 * int(is_vertical_view)];
|
|
#ifndef POINTY_CAPS
|
|
if (vertex_id == 2 || vertex_id == 7) signs = -horizontal_vertical_view_signs_array[(vertex_id - 2) + 8 * int(is_vertical_view)];
|
|
#endif
|
|
float view_right_sign = sign(dot(-camera_view_dir, line_right_dir));
|
|
float view_top_sign = sign(dot(-camera_view_dir, line_up_dir));
|
|
float half_height = 0.5 * height_width_angle.x;
|
|
float half_width = 0.5 * height_width_angle.y;
|
|
vec3 horizontal_dir = half_width * line_right_dir;
|
|
vec3 vertical_dir = half_height * line_up_dir;
|
|
float horizontal_sign = signs.x * view_right_sign;
|
|
float vertical_sign = signs.y * view_top_sign;
|
|
vec3 pos = endpoint_pos + horizontal_sign * horizontal_dir + vertical_sign * vertical_dir;
|
|
if (vertex_id == 2 || vertex_id == 7) {
|
|
float line_dir_sign = (vertex_id == 2) ? -1.0 : 1.0;
|
|
if (height_width_angle.z == 0.0) {
|
|
#ifdef POINTY_CAPS
|
|
pos += line_dir_sign * line_dir * half_width;
|
|
#endif
|
|
}
|
|
else {
|
|
pos += line_dir_sign * line_dir * half_width * sin(abs(height_width_angle.z) * 0.5);
|
|
pos += sign(height_width_angle.z) * horizontal_dir * cos(abs(height_width_angle.z) * 0.5);
|
|
}
|
|
}
|
|
vec3 eye_position = (view_matrix * vec4(pos, 1.0)).xyz;
|
|
vec3 eye_normal = (view_matrix * vec4(normalize(pos - endpoint_pos), 0.0)).xyz;
|
|
vec3 color_base = decode_color(hwa_color.w);
|
|
color = color_base * lighting(eye_position, eye_normal);
|
|
gl_Position = projection_matrix * vec4(eye_position, 1.0);
|
|
}
|
|
`,U=`
|
|
precision highp float;
|
|
in vec3 color;
|
|
out vec4 fragment_color;
|
|
void main() {
|
|
fragment_color = vec4(color, 1.0);
|
|
}
|
|
`;function W(e,t){let n=(t,n)=>{let r=Math.min(2048,Math.max(1,n)),i=Math.max(1,Math.ceil(n/r)),a=new Float32Array(r*i*4);a.set(t.subarray(0,Math.min(t.length,r*i*4)));let o=new e.DataTexture(a,r,i,e.RGBAFormat,e.FloatType);return o.minFilter=o.magFilter=e.NearestFilter,o.generateMipmaps=!1,o.needsUpdate=!0,o},r=n(t.position,t.nV),i=n(t.hwa,t.nV),a=new e.InstancedBufferGeometry;a.setIndex(N),a.setAttribute(`position`,new e.BufferAttribute(new Float32Array(24),3)),a.setAttribute(`vertex_id_float`,new e.BufferAttribute(new Float32Array([0,1,2,3,4,5,6,7]),1));let o=new e.InstancedInterleavedBuffer(t.segIndex,4);a.setAttribute(`seg_id_a_u`,new e.InterleavedBufferAttribute(o,1,0)),a.setAttribute(`seg_layer_u`,new e.InterleavedBufferAttribute(o,1,1)),a.instanceCount=0;let s=new e.RawShaderMaterial({glslVersion:e.GLSL3,uniforms:{view_matrix:{value:new e.Matrix4},projection_matrix:{value:new e.Matrix4},camera_position:{value:new e.Vector3},position_tex:{value:r},height_width_angle_tex:{value:i},layer_lo:{value:0},layer_hi:{value:t.layerCount}},vertexShader:H,fragmentShader:U,side:e.DoubleSide}),c=new e.Mesh(a,s),l=null;if(t.bbox){let{min:n,max:r}=t.bbox,i=new e.Vector3((n[0]+r[0])/2,(n[1]+r[1])/2,(n[2]+r[2])/2),a=Math.hypot(r[0]-n[0],r[1]-n[1],r[2]-n[2])/2+2;l=new e.Sphere(i,a)}c.frustumCulled=!!l,l&&(a.boundingSphere=l);let u=new e.Matrix4,d=new e.Vector3;c.onBeforeRender=(e,t,n)=>{s.uniforms.projection_matrix.value.copy(n.projectionMatrix),s.uniforms.view_matrix.value.multiplyMatrices(n.matrixWorldInverse,c.matrixWorld),u.copy(c.matrixWorld).invert(),n.getWorldPosition(d).applyMatrix4(u),s.uniforms.camera_position.value.copy(d)};let f=new e.BufferGeometry;f.setAttribute(`position`,new e.BufferAttribute(t.travelPos,3)),f.setDrawRange(0,0);let p=new e.LineSegments(f,new e.LineBasicMaterial({color:7041658}));p.frustumCulled=!!l,p.visible=!1,l&&(f.boundingSphere=l);let m=!1,h=0,g=t.layerCount-1,_=()=>{let e=t.travelPrefix[h],n=t.travelPrefix[g+1];f.setDrawRange(m?e*2:0,m?(n-e)*2:0)},v=(e,n)=>{let r=t.layerCount;h=Math.max(0,Math.min(r-1,e|0)),g=Math.max(h,Math.min(r-1,n|0)),s.uniforms.layer_lo.value=h,s.uniforms.layer_hi.value=g,a.instanceCount=t.layerSegPrefix[g+1],_()};return{mesh:c,travLines:p,setVisibleLayers:e=>v(0,(e|0)-1),setLayerRange:v,setTravelVisible:e=>{m=!!e,p.visible=m,_()},setColors:e=>{let t=i.image.data,n=Math.min(e.length,t.length)/4;for(let r=0;r<n;r++)t[r*4+3]=e[r*4];i.needsUpdate=!0},dispose:()=>{a.dispose(),s.dispose(),r.dispose(),i.dispose(),f.dispose(),p.material.dispose()},nSeg:t.nSeg,layerCount:t.layerCount}}var G=t(),ee=[`filament`,`feature`,`height`,`width`],te=[{type:b.wall,key:`gcodeViewer.feature.wall`,fallback:`Walls`},{type:b.sparseInfill,key:`gcodeViewer.feature.sparseInfill`,fallback:`Sparse infill`},{type:b.solidInfill,key:`gcodeViewer.feature.solidInfill`,fallback:`Solid infill`},{type:b.bridge,key:`gcodeViewer.feature.bridge`,fallback:`Bridge / overhang`},{type:b.support,key:`gcodeViewer.feature.support`,fallback:`Support`},{type:b.skirt,key:`gcodeViewer.feature.skirt`,fallback:`Skirt / brim`},{type:b.gapFill,key:`gcodeViewer.feature.gapFill`,fallback:`Gap fill`},{type:b.ironing,key:`gcodeViewer.feature.ironing`,fallback:`Ironing`},{type:b.primeTower,key:`gcodeViewer.feature.primeTower`,fallback:`Prime tower`}];function ne(e){let t=e.replace(`#`,``),n=t.length===3?t.split(``).map(e=>e+e).join(``):t,r=Number.parseInt(n.slice(0,6),16);return Number.isFinite(r)?r:44610}var re=e=>e?`rgb(${e.map(e=>Math.round(e*255)).join(`,`)})`:`transparent`;function ie(){let e=L;return e.map((t,n)=>`${re(t)} ${(n/(e.length-1)*100).toFixed(0)}%`).join(`, `)}function ae(e){return Number.isFinite(e)?Math.abs(e)<10?e.toFixed(2):e.toFixed(0):`-`}function oe({gcodeUrl:e,buildVolume:t={x:256,y:256,z:256},filamentColors:n,className:a=``}){let{t:b}=i(),x=(0,y.useRef)(null),[S,C]=(0,y.useState)(!0),[w,T]=(0,y.useState)(null),[E,D]=(0,y.useState)(!1),[O,k]=(0,y.useState)(null),N=(n?.length??0)>0,[F,L]=(0,y.useState)(N?`filament`:`feature`),R=(0,y.useRef)(!1);(0,y.useEffect)(()=>{N&&!R.current&&L(`filament`)},[N]);let[z,B]=(0,y.useState)([0,0]),[H,U]=(0,y.useState)(new Set),[oe,se]=(0,y.useState)(new Set),K=F===`filament`,q=K?oe:H,ce=[...q].sort((e,t)=>e-t).join(`,`),le=e=>{let t=t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n};K?se(t):U(t)},[J,ue]=(0,y.useState)(!1),Y=(0,y.useRef)(null),X=(0,y.useRef)(null),de=(0,y.useRef)(null),Z=(0,y.useRef)(null),fe=(0,y.useRef)(null),[pe,me]=(0,y.useState)(0),he=(0,y.useRef)(J),ge=(0,y.useRef)(z);he.current=J,ge.current=z;let _e=(0,y.useRef)(!1),Q=(0,y.useMemo)(()=>({x:t.x,y:t.y,z:t.z}),[`${t.x}x${t.y}x${t.z}`]);(0,y.useEffect)(()=>{let t=!1;C(!0),T(null),D(!1),k(null);let n={},i=r();return i&&(n.Authorization=`Bearer ${i}`),fetch(e,{headers:n}).then(async e=>{if(!e.ok){if(e.status===404){let t=await e.json().catch(()=>({}));if(typeof t.detail==`string`&&t.detail.includes(`sliced`))throw D(!0),Error(`not_sliced`)}throw Error(`Failed to load G-code`)}return e.text()}).then(e=>{if(t)return;_e.current=!1;let n=A(e);k(n),B([0,Math.max(0,n.layers.length-1)]),C(!1)}).catch(e=>{t||(e.message!==`not_sliced`&&T(e.message),C(!1))}),()=>{t=!0}},[e]),(0,y.useEffect)(()=>{let e=x.current;if(!e)return;let t=e.clientWidth||1,n=e.clientHeight||1,r=new c;r.background=new f(1710618),Y.current=r;let i=new _(45,t/n,.1,1e4);X.current=i;let a=new h({antialias:!0});a.setSize(t,n),a.setPixelRatio(Math.min(window.devicePixelRatio,2)),a.domElement.style.display=`block`,a.domElement.style.position=`absolute`,a.domElement.style.inset=`0`,e.appendChild(a.domElement);let o=new g(i,a.domElement);o.enableDamping=!0,o.dampingFactor=.05,de.current=o;let s=new m(Math.max(Q.x,Q.y),Math.ceil(Math.max(Q.x,Q.y)/16),4473924,3355443);s.position.set(Q.x/2,0,-Q.y/2),r.add(s);let l=0,u=()=>{l=requestAnimationFrame(u),o.update(),a.render(r,i)};u();let d=()=>{let t=e.clientWidth||1,n=e.clientHeight||1;i.aspect=t/n,i.updateProjectionMatrix(),a.setSize(t,n)},p=new ResizeObserver(d);return p.observe(e),window.addEventListener(`resize`,d),()=>{window.removeEventListener(`resize`,d),p.disconnect(),cancelAnimationFrame(l),o.dispose(),s.geometry.dispose(),s.material.dispose(),a.dispose(),e.removeChild(a.domElement),Y.current=null,X.current=null,de.current=null}},[Q]),(0,y.useEffect)(()=>{let e=Y.current,t=X.current,n=de.current;if(!e||!t||!n||!O||O.layers.length===0)return;let r=I(M(K?j(O.layers):O.layers,q),O.defaultWidth),i=W(d,r);fe.current=r,Z.current=i;let a=new p;if(a.rotation.x=-Math.PI/2,a.add(i.mesh),a.add(i.travLines),e.add(a),i.setTravelVisible(he.current),i.setLayerRange(ge.current[0],ge.current[1]),me(e=>e+1),!_e.current){_e.current=!0;let e=O.bounds,r=e?new u(new s(e.min[0],e.min[2],-e.max[1]),new s(e.max[0],e.max[2],-e.min[1])):new u(new s(0,0,0),new s(Q.x,1,-Q.y)),i=r.getCenter(new s),a=Math.max(r.getSize(new s).length()/2,.001),o=l.degToRad(t.fov),c=2*Math.atan(Math.tan(o/2)*t.aspect),d=1.15*Math.max(a/Math.sin(o/2),a/Math.sin(c/2));t.position.copy(i).addScaledVector(new s(.7,.5,.7).normalize(),d),t.near=Math.max(d/1e3,.01),t.far=d+a*4,t.updateProjectionMatrix(),n.target.copy(i),n.update()}return()=>{e.remove(a),i.dispose(),Z.current=null,fe.current=null}},[O,K,Q,ce]),(0,y.useEffect)(()=>{Z.current?.setLayerRange(z[0],z[1])},[z]),(0,y.useEffect)(()=>{Z.current?.setTravelVisible(J)},[J]);let $=(0,y.useMemo)(()=>{let e=fe.current;if(!e||!O)return null;if(K){let t=new Float32Array(e.nV*4);for(let r=0;r<e.nV;r+=1){let i=Math.max(0,e.meta.vType[r]-1),a=n?.[i]??n?.[0]??`#00ae42`;t[r*4]=ne(a)}return{color:t,min:0,max:0,unit:``,cont:!1}}return V(e,F,{})},[F,O,K,n,pe]);(0,y.useEffect)(()=>{$&&Z.current?.setColors($.color)},[$]);let ve=O?.layers.length??0;return E?(0,G.jsxs)(`div`,{className:`flex flex-col items-center justify-center gap-2 text-bambu-gray ${a}`,children:[(0,G.jsx)(v,{className:`w-8 h-8`}),b(`gcodeViewer.notSliced`,`This file has not been sliced yet.`)]}):w?(0,G.jsxs)(`div`,{className:`flex flex-col items-center justify-center gap-2 text-bambu-gray ${a}`,children:[(0,G.jsx)(v,{className:`w-8 h-8`}),b(`gcodeViewer.loadFailed`,`Could not load the G-code for this file.`)]}):(0,G.jsxs)(`div`,{className:`relative ${a}`,children:[(0,G.jsx)(`div`,{ref:x,className:`absolute inset-0`}),S&&(0,G.jsxs)(`div`,{className:`absolute inset-0 flex items-center justify-center gap-2 bg-bambu-dark/60 text-sm text-bambu-gray`,children:[(0,G.jsx)(o,{className:`w-4 h-4 animate-spin`}),b(`gcodeViewer.loading`,`Reading toolpath...`)]}),!S&&ve>0&&(0,G.jsxs)(G.Fragment,{children:[(0,G.jsxs)(`div`,{className:`absolute left-3 top-3 flex flex-col gap-2 rounded border border-bambu-dark-tertiary bg-bambu-dark/85 p-2`,children:[(0,G.jsx)(`div`,{className:`flex overflow-hidden rounded border border-bambu-dark-tertiary`,children:ee.filter(e=>e!==`filament`||N).map(e=>(0,G.jsx)(`button`,{type:`button`,onClick:()=>{R.current=!0,L(e)},className:`px-2 py-1 text-xs transition-colors ${F===e?`bg-bambu-green text-white`:`text-bambu-gray hover:text-white`}`,children:b(`gcodeViewer.view.${e}`,e)},e))}),(0,G.jsxs)(`label`,{className:`flex cursor-pointer items-center gap-2 text-xs text-bambu-gray`,children:[(0,G.jsx)(`input`,{type:`checkbox`,checked:J,onChange:e=>ue(e.target.checked),className:`cursor-pointer`}),b(`gcodeViewer.showTravel`,`Travel moves`)]}),K?(0,G.jsx)(`ul`,{className:`flex flex-col gap-0.5`,children:(n??[]).map((e,t)=>{let n=t+1,r=q.has(n);return(0,G.jsx)(`li`,{children:(0,G.jsxs)(`button`,{type:`button`,onClick:()=>le(n),"aria-pressed":!r,className:`flex w-full items-center gap-1.5 text-left text-[0.7rem] transition-opacity hover:text-white ${r?`text-bambu-gray/40`:`text-bambu-gray`}`,children:[(0,G.jsx)(`span`,{className:`inline-block h-2.5 w-2.5 shrink-0 rounded-sm border border-white/20 ${r?`opacity-25`:``}`,style:{backgroundColor:e},"aria-hidden":!0}),(0,G.jsx)(`span`,{className:r?`line-through`:``,children:b(`gcodeViewer.filamentSlot`,`Filament {{n}}`,{n:t+1})})]})},t)})}):F===`feature`?(0,G.jsx)(`ul`,{className:`flex flex-col gap-0.5`,children:te.map(e=>{let t=q.has(e.type);return(0,G.jsx)(`li`,{children:(0,G.jsxs)(`button`,{type:`button`,onClick:()=>le(e.type),"aria-pressed":!t,className:`flex w-full items-center gap-1.5 text-left text-[0.7rem] transition-opacity hover:text-white ${t?`text-bambu-gray/40`:`text-bambu-gray`}`,children:[(0,G.jsx)(`span`,{className:`inline-block h-2.5 w-2.5 shrink-0 rounded-sm ${t?`opacity-25`:``}`,style:{backgroundColor:re(P[e.type])},"aria-hidden":!0}),(0,G.jsx)(`span`,{className:t?`line-through`:``,children:b(e.key,e.fallback)})]})},e.type)})}):$&&(0,G.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,G.jsx)(`div`,{className:`h-2.5 w-full rounded-sm border border-white/10`,style:{background:`linear-gradient(to right, ${ie()})`},"aria-hidden":!0}),(0,G.jsxs)(`div`,{className:`flex items-center justify-between text-[0.7rem] tabular-nums text-bambu-gray`,children:[(0,G.jsx)(`span`,{children:ae($.min)}),(0,G.jsx)(`span`,{className:`text-bambu-gray/70`,children:$.unit}),(0,G.jsx)(`span`,{children:ae($.max)})]})]})]}),(0,G.jsxs)(`div`,{className:`absolute right-3 top-3 flex flex-col items-center gap-1 rounded border border-bambu-dark-tertiary bg-bambu-dark/85 p-2`,children:[(0,G.jsx)(`span`,{className:`text-[0.65rem] tabular-nums text-bambu-gray`,children:z[1]+1}),(0,G.jsx)(`input`,{type:`range`,min:0,max:Math.max(0,ve-1),value:z[1],onChange:e=>{let t=Number(e.target.value);B(([e])=>[Math.min(e,t),t])},"aria-label":b(`gcodeViewer.topLayer`,`Top layer`),className:`h-40 w-4 cursor-pointer`,style:{writingMode:`vertical-lr`,direction:`rtl`}}),(0,G.jsx)(`input`,{type:`range`,min:0,max:Math.max(0,ve-1),value:z[0],onChange:e=>{let t=Number(e.target.value);B(([,e])=>[t,Math.max(t,e)])},"aria-label":b(`gcodeViewer.bottomLayer`,`Bottom layer`),className:`h-40 w-4 cursor-pointer`,style:{writingMode:`vertical-lr`,direction:`rtl`}}),(0,G.jsx)(`span`,{className:`text-[0.65rem] tabular-nums text-bambu-gray`,children:z[0]+1})]})]})]})}export{oe as t}; |