Setting the file. One moment.
Surface · Code Slice Hero · heygen-com/hyperframes · Skills Docs
ContentsBack to the top of the page surface.js
JavaScript · 253 lines · 8 KB
;
7 canvas.height = 1080 ;
8 canvas.style.cssText = "display:block;width:1920px;height:1080px" ;
9 stage. appendChild (canvas);
10 const gl = canvas. getContext ( "webgl2" , {
11 alpha: false ,
12 antialias: true ,
13 preserveDrawingBuffer: true ,
14 });
15 if ( ! gl) throw new Error ( "Code Slice Hero requires WebGL 2 for its full tile surface." );
16 const vertex = `#version 300 es
17 precision highp float;
18 layout(location=0) in vec3 aPosition;
19 layout(location=1) in vec2 aUV;
20 layout(location=2) in float aFace;
21 layout(location=3) in vec4 aCell;
22 layout(location=4) in vec4 aMotion;
23 layout(location=5) in vec4 aAngles;
24 layout(location=6) in vec2 aSurface;
25 out vec2 vUV;
26 out vec2 vAtlasUV;
27 flat out float vFace;
28 flat out float vFormation;
29 flat out float vShade;
30 flat out float vInk;
31 void main() {
32 vec3 p = vec3(aPosition.xy * aCell.zw, aPosition.z * 3.0 * aAngles.w) * aMotion.w;
33 // CSS transform order is translate * Rx * Ry * Rz * scale.
34 vec3 c = cos(aAngles.xyz), s = sin(aAngles.xyz);
35 p.xy = vec2(c.z*p.x-s.z*p.y, s.z*p.x+c.z*p.y);
36 p.xz = vec2(c.y*p.x+s.y*p.z, -s.y*p.x+c.y*p.z);
37 p.yz = vec2(c.x*p.y-s.x*p.z, s.x*p.y+c.x*p.z);
38 p += vec3(aCell.xy, 0.0) + aMotion.xyz;
39 float w = 1.0 - p.z / 1712.661;
40 gl_Position = vec4((p.x-960.0)/960.0, -(p.y-540.0)/540.0,
41 1.00020002*w - 0.00116788, w);
42 vUV = aUV;
43 vAtlasUV = (aCell.xy + (aUV-0.5)*aCell.zw) / vec2(1920.0,1080.0);
44 vFace = aFace; vFormation = aAngles.w; vShade = aSurface.x; vInk = aSurface.y;
45 }` ;
46 const fragment = `#version 300 es
47 precision highp float;
48 uniform sampler2D uFront;
49 uniform sampler2D uBack;
50 in vec2 vUV;
51 in vec2 vAtlasUV;
52 flat in float vFace;
53 flat in float vFormation;
54 flat in float vShade;
55 flat in float vInk;
56 out vec4 color;
57 void main() {
58 if (vFace > 1.5) {
59 if (vInk < 0.5 || vFormation < 0.003) discard;
60 float shade = vFace == 4.0 ? 0.910 : vFace == 5.0 ? 0.651 : 0.741;
61 color = vec4(vec3(shade),1.0); return;
62 }
63 float radius = 0.06*vFormation;
64 vec2 q = abs(vUV-0.5) - (0.5-radius);
65 float distance = length(max(q,0.0)) + min(max(q.x,q.y),0.0) - radius;
66 // At zero radius adjacent faces use their exact shared pixel boundary.
67 float alpha = radius > 0.00001 ? 1.0-smoothstep(-fwidth(distance),0.0,distance) : 1.0;
68 if (alpha < 0.01) discard;
69 vec3 ink = vInk < 0.5 ? vec3(1.0) :
70 (vFace < 0.5 ? texture(uFront,vAtlasUV).rgb : texture(uBack,vAtlasUV).rgb);
71 color = vec4(ink*vShade,alpha);
72 }` ;
73 const shaders = [];
74 function compile ( kind , source ) {
75 const shader = gl. createShader (kind);
76 gl. shaderSource (shader, source);
77 gl. compileShader (shader);
78 if ( ! gl. getShaderParameter (shader, gl. COMPILE_STATUS ))
79 throw new Error (gl. getShaderInfoLog (shader));
80 shaders. push (shader);
81 return shader;
82 }
83 const program = gl. createProgram ();
84 gl. attachShader (program, compile (gl. VERTEX_SHADER , vertex));
85 gl. attachShader (program, compile (gl. FRAGMENT_SHADER , fragment));
86 gl. linkProgram (program);
87 if ( ! gl. getProgramParameter (program, gl. LINK_STATUS ))
88 throw new Error (gl. getProgramInfoLog (program));
89 gl. useProgram (program);
90 const vertices = [];
91 function quad ( corners , face ) {
92 const uv = [
93 [ 0 , 0 ],
94 [ 1 , 0 ],
95 [ 1 , 1 ],
96 [ 0 , 1 ],
97 ];
98 for ( const i of [ 0 , 1 , 2 , 0 , 2 , 3 ]) vertices. push ( ... corners[i], ... uv[i], face);
99 }
100 quad (
101 [
102 [ - 0.5 , - 0.5 , 0.5 ],
103 [ 0.5 , - 0.5 , 0.5 ],
104 [ 0.5 , 0.5 , 0.5 ],
105 [ - 0.5 , 0.5 , 0.5 ],
106 ],
107 0 ,
108 );
109 // Rear UVs are reversed in local X, just like a CSS rotateY(180deg) face.
110 quad (
111 [
112 [ 0.5 , - 0.5 , - 0.5 ],
113 [ - 0.5 , - 0.5 , - 0.5 ],
114 [ - 0.5 , 0.5 , - 0.5 ],
115 [ 0.5 , 0.5 , - 0.5 ],
116 ],
117 1 ,
118 );
119 quad (
120 [
121 [ - 0.5 , - 0.5 , - 0.5 ],
122 [ - 0.5 , - 0.5 , 0.5 ],
123 [ - 0.5 , 0.5 , 0.5 ],
124 [ - 0.5 , 0.5 , - 0.5 ],
125 ],
126 2 ,
127 );
128 quad (
129 [
130 [ 0.5 , - 0.5 , 0.5 ],
131 [ 0.5 , - 0.5 , - 0.5 ],
132 [ 0.5 , 0.5 , - 0.5 ],
133 [ 0.5 , 0.5 , 0.5 ],
134 ],
135 3 ,
136 );
137 quad (
138 [
139 [ - 0.5 , - 0.5 , - 0.5 ],
140 [ 0.5 , - 0.5 , - 0.5 ],
141 [ 0.5 , - 0.5 , 0.5 ],
142 [ - 0.5 , - 0.5 , 0.5 ],
143 ],
144 4 ,
145 );
146 quad (
147 [
148 [ - 0.5 , 0.5 , 0.5 ],
149 [ 0.5 , 0.5 , 0.5 ],
150 [ 0.5 , 0.5 , - 0.5 ],
151 [ - 0.5 , 0.5 , - 0.5 ],
152 ],
153 5 ,
154 );
155 const vao = gl. createVertexArray ();
156 gl. bindVertexArray (vao);
157 const geometry = gl. createBuffer ();
158 gl. bindBuffer (gl. ARRAY_BUFFER , geometry);
159 gl. bufferData (gl. ARRAY_BUFFER , new Float32Array (vertices), gl. STATIC_DRAW );
160 for ( const [ location , size , offset ] of [
161 [ 0 , 3 , 0 ],
162 [ 1 , 2 , 12 ],
163 [ 2 , 1 , 20 ],
164 ]) {
165 gl. enableVertexAttribArray (location);
166 gl. vertexAttribPointer (location, size, gl. FLOAT , false , 24 , offset);
167 }
168 const data = new Float32Array (tiles. length * 14 ),
169 instances = gl. createBuffer ();
170 tiles. forEach (( tile , i ) => {
171 data. set ([tile.cx, tile.cy, tile.width, tile.height], i * 14 );
172 data[i * 14 + 13 ] = tile.active ? 1 : 0 ;
173 });
174 gl. bindBuffer (gl. ARRAY_BUFFER , instances);
175 gl. bufferData (gl. ARRAY_BUFFER , data.byteLength, gl. DYNAMIC_DRAW );
176 for ( const [ location , size , offset ] of [
177 [ 3 , 4 , 0 ],
178 [ 4 , 4 , 16 ],
179 [ 5 , 4 , 32 ],
180 [ 6 , 2 , 48 ],
181 ]) {
182 gl. enableVertexAttribArray (location);
183 gl. vertexAttribPointer (location, size, gl. FLOAT , false , 56 , offset);
184 gl. vertexAttribDivisor (location, 1 );
185 }
186 const textures = [front, back]. map (( source , i ) => {
187 const texture = gl. createTexture ();
188 gl. activeTexture (gl. TEXTURE0 + i);
189 gl. bindTexture (gl. TEXTURE_2D , texture);
190 gl. texParameteri (gl. TEXTURE_2D , gl. TEXTURE_MIN_FILTER , gl. LINEAR );
191 gl. texParameteri (gl. TEXTURE_2D , gl. TEXTURE_MAG_FILTER , gl. LINEAR );
192 gl. texParameteri (gl. TEXTURE_2D , gl. TEXTURE_WRAP_S , gl. CLAMP_TO_EDGE );
193 gl. texParameteri (gl. TEXTURE_2D , gl. TEXTURE_WRAP_T , gl. CLAMP_TO_EDGE );
194 gl. texImage2D (gl. TEXTURE_2D , 0 , gl. RGBA , gl. RGBA , gl. UNSIGNED_BYTE , source);
195 gl. uniform1i (gl. getUniformLocation (program, i === 0 ? "uFront" : "uBack" ), i);
196 return texture;
197 });
198 gl. enable (gl. DEPTH_TEST );
199 gl. enable (gl. CULL_FACE );
200 gl. frontFace (gl. CW );
201 gl. enable (gl. BLEND );
202 gl. blendFunc (gl. SRC_ALPHA , gl. ONE_MINUS_SRC_ALPHA );
203 const rgb = options.behindColor. match ( / [0-9a-f] {2} / gi ). map (( part ) => parseInt (part, 16 ) / 255 );
204 const shadows = window. CodeSliceShadows (
205 gl,
206 tiles,
207 data,
208 options.shadowStrength,
209 options.shadowSoftness,
210 );
211 gl. clearColor ( ... rgb, 1 );
212 gl. viewport ( 0 , 0 , 1920 , 1080 );
213 return {
214 data,
215 shadowStats: shadows.stats,
216 set ( index , p ) {
217 const offset = index * 14 + 4 ;
218 data. set (
219 [
220 p.x,
221 p.y,
222 p.z,
223 p.scale,
224 (p.rx * Math. PI ) / 180 ,
225 (p.ry * Math. PI ) / 180 ,
226 (p.rz * Math. PI ) / 180 ,
227 p.formation,
228 p.shade,
229 ],
230 offset,
231 );
232 },
233 draw () {
234 gl. useProgram (program);
235 gl. bindVertexArray (vao);
236 gl. bindBuffer (gl. ARRAY_BUFFER , instances);
237 gl. bufferSubData (gl. ARRAY_BUFFER , 0 , data);
238 gl. clear (gl. COLOR_BUFFER_BIT | gl. DEPTH_BUFFER_BIT );
239 gl. drawArraysInstanced (gl. TRIANGLES , 0 , 36 , tiles. length );
240 return 1 + shadows. draw ();
241 },
242 dispose () {
243 shadows. dispose ();
244 textures. forEach (( t ) => gl. deleteTexture (t));
245 shaders. forEach (( s ) => gl. deleteShader (s));
246 gl. deleteBuffer (instances);
247 gl. deleteBuffer (geometry);
248 gl. deleteVertexArray (vao);
249 gl. deleteProgram (program);
250 canvas. remove ();
251 },
252 };
253 };