size: mangler hell

This commit is contained in:
FMS-Cat
2021-03-27 01:40:50 +09:00
parent 871a569f2a
commit bdf5d8ca01
29 changed files with 289 additions and 389 deletions

View File

@@ -2,9 +2,24 @@
## Build
- You will need [`shader_minifier.exe`](https://github.com/laurentlb/Shader_Minifier) in your PATH
- You will need these stuff in your PATH:
- [`shader_minifier.exe`](https://github.com/laurentlb/Shader_Minifier)
- [`jsexe.exe`](https://www.pouet.net/)
```sh
yarn
yarn build
```
## Minification
[terser's](https://terser.org/docs/api-reference.html) mangler is spicy
you'll die instantly if you access to object properties using a string identifier
see `webpack.config.js` and `src/automaton-fxs/fxDefinitions.ts` for the funny jokes
jsexe is good
note that it cannot parse nowadays ecmascript though
shader minifier is way too spicy so I made a [separate document](./shader-minifier-tips.md)
libopus is cheating

View File

@@ -5,7 +5,10 @@
"license": "MIT",
"scripts": {
"dev": "webpack-cli serve --mode development",
"build": "webpack --mode production && ruby pnginator.rb ./dist/bundle.js ./dist/out.png.html"
"build": "yarn build-js && yarn build-png",
"build-js": "webpack --mode production",
"build-png": "jsexe -cn -po ./dist/bundle.js ./dist/out.png.html",
"h": "start http://localhost:8081/out.png.html && http-server ./dist"
},
"devDependencies": {
"@fms-cat/automaton": "^4.1.0",

View File

@@ -1,106 +0,0 @@
#!/usr/bin/env ruby -w
# pnginator.rb: pack a .js file into a PNG image with an HTML payload;
# when saved with an .html extension and opened in a browser, the HTML extracts and executes
# the javascript.
# Usage: ruby pnginator.rb input.js output.png.html
# By Gasman <http://matt.west.co.tt/>
# from an original idea by Daeken: http://daeken.com/superpacking-js-demos
MAX_WIDTH = 4096
USE_PNGOUT = true
require 'zlib'
require 'tempfile'
input_filename, output_filename = ARGV
f = File.open(input_filename, 'rb')
js = f.read
f.close
if js.length < MAX_WIDTH
# js fits onto one pixel line
js += "\x00"
scanlines = [js]
width = js.length
height = 1
# Daeken's single-pixel-row bootstrap (requires js string to be reversed)
# (edit by Gasman: change eval to (1,eval) to force global evaluation and avoid massive slowdown)
# html = "<canvas id=q><img onload=for(p=q.width=#{width},(c=q.getContext('2d')).drawImage(this,0,e='');p;)e+=String.fromCharCode(c.getImageData(--p,0,1,1).data[0]);(1,eval)(e) src=#>"
# p01's single-pixel-row bootstrap (requires an 0x00 end marker on the js string)
# (edit by Gasman: move drawImage out of getImageData params (it returns undef, which is invalid) and change eval to (1,eval) to force global evaluation)
html = "<canvas id=c><img onload=with(c.getContext('2d'))for(p=e='';drawImage(this,p--,0),t=getImageData(0,0,1,1).data[0];)e+=String.fromCharCode(t);(1,eval)(e) src=#>"
else
js = "\x00" + js
width = MAX_WIDTH
# split js into scanlines of 'width' pixels; pad the last one with whitespace
scanlines = js.scan(/.{1,#{width}}/m).collect{|line| line.ljust(width, "\x00")}
height = scanlines.length
# p01's multiple-pixel-row bootstrap (requires a dummy first byte on the js string)
# (edit by Gasman: set explicit canvas width to support widths above 300; move drawImage out of getImageData params; change eval to (1,eval) to force global evaluation)
html = "<canvas id=c><img onload=for(w=c.width=#{width},a=c.getContext('2d'),a.drawImage(this,p=0,0),e='',d=a.getImageData(0,0,w,#{height}).data;t=d[p+=4];)e+=String.fromCharCode(t);(1,eval)(e) src=#>"
end
# prepend each scanline with 0x00 to indicate 'no filtering', then concat into one string
image_data = scanlines.collect{|line| "\x00" + line}.join
idat_chunk = Zlib::Deflate.deflate(image_data, 9) # 9 = maximum compression
def png_chunk(signature, data)
[data.length, signature, data, Zlib::crc32(signature + data)].pack("NA4A*N")
end
if USE_PNGOUT
# Create a valid (no format hacks) .png file to pass to pngout
f = Tempfile.open(['pnginator', '.png'])
begin
f.write("\x89PNG\x0d\x0a\x1a\x0a") # PNG file header
f.write(png_chunk("IHDR", [width, height, 8, 0, 0, 0, 0].pack("NNccccc")))
f.write(png_chunk("IDAT", idat_chunk))
f.write(png_chunk("IEND", ''))
f.close
system("pngout", f.path, "-c0", "-y")
# read file back and extract the IDAT chunk
f.open
f.read(8)
while !f.eof?
length, signature = f.read(8).unpack("NA4")
data = f.read(length)
crc = f.read(4)
if signature == "IDAT"
idat_chunk = data
break
end
end
ensure
f.close
f.unlink
end
end
File.open(output_filename, 'wb') do |f|
f.write("\x89PNG\x0d\x0a\x1a\x0a") # PNG file header
f.write(png_chunk("IHDR", [width, height, 8, 0, 0, 0, 0].pack("NNccccc")))
# a custom chunk containing the HTML payload; stated chunk length is 4 less than the actual length,
# leaving the final 4 bytes to take the place of the checksum
f.write([html.length - 4, "jawh", html].pack("NA4A*"))
# can safely omit the checksum of the IDAT chunk
# f.write([idat_chunk.length, "IDAT", idat_chunk, Zlib::crc32("IDAT" + idat_chunk)].pack("NA4A*N"))
f.write([idat_chunk.length, "IDAT", idat_chunk].pack("NA4A*"))
# can safely omit the IEND chunk
# f.write([0, "IEND", "", Zlib::crc32("IEND")].pack("NA4A*N"))
end

View File

@@ -1,3 +0,0 @@
export { sine, hermitePatch } from '@fms-cat/automaton-fxs';
export { repeat } from './repeat';
export { transpose } from './transpose';

View File

@@ -0,0 +1,14 @@
import { sine } from './sine';
import { repeat } from './repeat';
import { hermitePatch } from './hermitePatch';
import { transpose } from './transpose';
// quotes! prevent fx names from being mangled
const fxDefinitions = {
'sine': sine,
'repeat': repeat,
'hermitePatch': hermitePatch,
'transpose': transpose,
};
export { fxDefinitions };

View File

@@ -0,0 +1,34 @@
import type { FxDefinition } from '@fms-cat/automaton';
export const hermitePatch: FxDefinition = {
func( context ) {
if ( context.init ) {
const dt = context.deltaTime;
const v0 = context.getValue( context.t0 );
const dv0 = v0 - context.getValue( context.t0 - dt );
const v1 = context.getValue( context.t1 );
const dv1 = v1 - context.getValue( context.t1 - dt );
context.state.p0 = v0;
context.state.m0 = dv0 / dt * context.length;
context.state.p1 = v1;
context.state.m1 = dv1 / dt * context.length;
}
const { p0, m0, p1, m1 } = context.state;
const t = context.progress;
return (
( ( 2.0 * t - 3.0 ) * t * t + 1.0 ) * p0 +
( ( ( t - 2.0 ) * t + 1.0 ) * t ) * m0 +
( ( -2.0 * t + 3.0 ) * t * t ) * p1 +
( ( t - 1.0 ) * t * t ) * m1
);
}
};
if ( process.env.DEV ) {
hermitePatch.name = 'Hermite Patch';
hermitePatch.description = 'Patch a curve using hermite spline.';
}

View File

@@ -1,11 +1,6 @@
import type { FxDefinition } from '@fms-cat/automaton';
export const repeat: FxDefinition = {
name: 'Repeat',
description: 'Repeat a section of the curve.',
params: {
interval: { name: 'Interval', type: 'float', default: 1.0, min: 0.0 },
},
func( context ) {
if ( context.index === context.i1 ) {
context.setShouldNotInterpolate( true );
@@ -20,3 +15,11 @@ export const repeat: FxDefinition = {
return context.getValue( context.t0 + context.elapsed % context.params.interval );
}
};
if ( process.env.DEV ) {
repeat.name = 'Repeat';
repeat.description = 'Repeat a section of the curve.';
repeat.params = {
interval: { name: 'Interval', type: 'float', default: 1.0, min: 0.0 },
};
}

21
src/automaton-fxs/sine.ts Normal file
View File

@@ -0,0 +1,21 @@
import type { FxDefinition } from '@fms-cat/automaton';
const TAU = Math.PI * 2.0;
export const sine: FxDefinition = {
func( context ) {
const v = context.value;
const p = context.elapsed * context.params.freq + context.params.offset;
return v + context.params.amp * Math.sin( p * TAU );
}
};
if ( process.env.DEV ) {
sine.name = 'Sinewave';
sine.description = 'Overlay a sinewave to the curve.';
sine.params = {
amp: { name: 'Amp', type: 'float', default: 0.1 },
freq: { name: 'Frequency', type: 'float', default: 5.0 },
offset: { name: 'Offset', type: 'float', default: 0.0, min: 0.0, max: 1.0 }
};
}

View File

@@ -1,9 +1,6 @@
import type { FxDefinition } from '@fms-cat/automaton';
export const transpose: FxDefinition = {
params: {
note: { name: 'Note', type: 'float', default: 0.0 }
},
func( context ) {
if ( context.init ) {
context.state.v0 = context.value;
@@ -17,3 +14,11 @@ export const transpose: FxDefinition = {
return v0 + ( context.value - v0 ) * Math.pow( 2.0, context.params.note / 12.0 );
}
};
if ( process.env.DEV ) {
transpose.name = 'Transpose';
transpose.description = 'I probably don\'t need it...';
transpose.params = {
note: { name: 'Note', type: 'float', default: 0.0 },
};
}

File diff suppressed because one or more lines are too long

View File

@@ -5,5 +5,6 @@ export const
AO_RESOLUTION_RATIO = 1.0,
RESOLUTION = [ 1280, 720 ],
MUSIC_BPM = 180,
START_POSITION = 36,
MUSIC_BUFFER_LENGTH = 4096,
MUSIC_AUTOMATON_TEXTURE_HEIGHT = 16;

View File

@@ -97,9 +97,7 @@ export class CameraEntity extends Entity {
quadVert,
shadingFrag,
{
defines: {
IS_FIRST_LIGHT: iLight === 0 ? 'true' : undefined
},
defines: iLight === 0 ? [ 'IS_FIRST_LIGHT' ] : [],
initOptions: { geometry: quadGeometry, target: dummyRenderTarget },
},
);

View File

@@ -102,32 +102,34 @@ export class Condition extends Entity {
geometry.primcount = 12 * 16;
// -- create materials -------------------------------------------------------------------------
const materials = {
forward: new Material(
const forward = new Material(
conditionVert,
conditionFrag,
{
defines: { 'FORWARD': 'true' },
defines: [ 'FORWARD 1' ],
initOptions: { geometry, target: dummyRenderTarget },
},
),
deferred: new Material(
);
const deferred = new Material(
conditionVert,
conditionFrag,
{
defines: { 'DEFERRED': 'true' },
defines: [ 'DEFERRED 1' ],
initOptions: { geometry, target: dummyRenderTargetFourDrawBuffers },
},
),
shadow: new Material(
);
const depth = new Material(
conditionVert,
conditionFrag,
{
defines: { 'SHADOW': 'true' },
defines: [ 'SHADOW 1' ],
initOptions: { geometry, target: dummyRenderTarget },
},
),
};
);
const materials = { forward, deferred, depth };
objectValuesMap( materials, ( material ) => {
material.addUniformTexture( 'samplerSvg', texture );
@@ -149,9 +151,9 @@ export class Condition extends Entity {
'../shaders/condition.frag',
],
() => {
materials.forward.replaceShader( conditionVert, conditionFrag );
materials.deferred.replaceShader( conditionVert, conditionFrag );
materials.shadow.replaceShader( conditionVert, conditionFrag );
forward.replaceShader( conditionVert, conditionFrag );
deferred.replaceShader( conditionVert, conditionFrag );
depth.replaceShader( conditionVert, conditionFrag );
},
);
}

View File

@@ -1,132 +0,0 @@
import { Mesh } from '../heck/components/Mesh';
import { Entity } from '../heck/Entity';
import { Geometry } from '../heck/Geometry';
import { Material } from '../heck/Material';
import svgVert from '../shaders/svg.vert';
import conditionCharFrag from '../shaders/condition-char.frag';
import { gl, glCat } from '../globals/canvas';
import { Vector3 } from '@fms-cat/experimental';
import { GLCatTexture } from '@fms-cat/glcat-ts';
import { auto } from '../globals/automaton';
import { dummyRenderTargetFourDrawBuffers, dummyRenderTarget } from '../globals/dummyRenderTarget';
const POINTS_MAX = 256;
interface SVGTestOptions {
table: GLCatTexture;
pos: number;
i: number;
}
export class ConditionChar extends Entity {
public constructor( { table, pos, i }: SVGTestOptions ) {
super();
this.transform.position = this.transform.position.add( new Vector3( [ 2 * pos, 0, 0 ] ) );
// -- create buffers ---------------------------------------------------------------------------
const arrayPos = [];
const arrayInd = [];
for ( let i = 0; i < POINTS_MAX; i ++ ) {
const x = i / POINTS_MAX;
arrayPos.push( x, 0, x, 1, x, 2 );
for ( let j = 0; j < 3; j ++ ) {
const j1 = ( j + 1 ) % 3;
arrayInd.push(
i * 3 + j,
i * 3 + 3 + j,
i * 3 + 3 + j1,
i * 3 + j,
i * 3 + 3 + j1,
i * 3 + j1,
);
}
}
arrayPos.push( 1, 0, 1, 1, 1, 2 );
const bufferPos = glCat.createBuffer();
bufferPos.setVertexbuffer( new Float32Array( arrayPos ) );
const bufferInd = glCat.createBuffer();
bufferInd.setIndexbuffer( new Uint16Array( arrayInd ) );
// -- create geometry --------------------------------------------------------------------------
const geometry = new Geometry();
geometry.vao.bindVertexbuffer( bufferPos, 0, 2 );
geometry.vao.bindIndexbuffer( bufferInd );
geometry.count = 18 * POINTS_MAX;
geometry.mode = gl.TRIANGLES;
geometry.indexType = gl.UNSIGNED_SHORT;
// -- create materials -------------------------------------------------------------------------
const materials = {
forward: new Material(
svgVert,
conditionCharFrag,
{
defines: { 'FORWARD': 'true' },
initOptions: { geometry, target: dummyRenderTarget },
},
),
deferred: new Material(
svgVert,
conditionCharFrag,
{
defines: { 'DEFERRED': 'true' },
initOptions: { geometry, target: dummyRenderTargetFourDrawBuffers },
},
),
shadow: new Material(
svgVert,
conditionCharFrag,
{
defines: { 'SHADOW': 'true' },
initOptions: { geometry, target: dummyRenderTarget },
},
),
};
if ( process.env.DEV ) {
if ( module.hot ) {
module.hot.accept(
[
'../shaders/svg.vert',
'../shaders/condition-char.frag',
],
() => {
materials.forward.replaceShader( svgVert, conditionCharFrag );
materials.deferred.replaceShader( svgVert, conditionCharFrag );
materials.shadow.replaceShader( svgVert, conditionCharFrag );
},
);
}
}
// -- create meshes ----------------------------------------------------------------------------
const mesh = new Mesh( {
geometry,
materials,
name: process.env.DEV && `ConditionChar/mesh${ i }`,
} );
this.components.push( mesh );
// -- material uniforms ------------------------------------------------------------------------
for ( const material of Object.values( materials ) ) {
material.addUniform( 'svgi', '1f', i );
material.addUniformTexture( 'samplerSvg', table );
auto( 'Condition/phaseOffset', ( { value } ) => {
material.addUniform( 'phaseOffset', '1f', value );
} );
auto( 'Condition/phaseWidth', ( { value } ) => {
material.addUniform( 'phaseWidth', '1f', value );
} );
}
}
}

View File

@@ -54,21 +54,22 @@ export class Cube extends Entity {
geometry.primcount = PRIMCOUNT;
// -- materials --------------------------------------------------------------------------------
const materials = {
deferred: new Material(
const deferred = new Material(
cubeVert,
cubeFrag,
{
defines: { 'DEFERRED': 'true' },
defines: [ 'DEFERRED 1' ],
initOptions: { geometry: quadGeometry, target: dummyRenderTargetFourDrawBuffers },
},
),
shadow: new Material(
);
const depth = new Material(
cubeVert,
depthFrag,
{ initOptions: { geometry: quadGeometry, target: dummyRenderTarget } },
),
};
);
const materials = { deferred, depth };
if ( process.env.DEV ) {
if ( module.hot ) {
@@ -78,8 +79,8 @@ export class Cube extends Entity {
'../shaders/cube.frag',
],
() => {
materials.deferred.replaceShader( cubeVert, cubeFrag );
materials.shadow.replaceShader( cubeVert, depthFrag );
deferred.replaceShader( cubeVert, cubeFrag );
depth.replaceShader( cubeVert, depthFrag );
},
);
}

View File

@@ -11,6 +11,7 @@ import { gl, glCat } from '../globals/canvas';
import { randomTexture, randomTextureStatic } from '../globals/randomTexture';
import { quadGeometry } from '../globals/quadGeometry';
import { dummyRenderTargetFourDrawBuffers, dummyRenderTarget } from '../globals/dummyRenderTarget';
import { objectValuesMap } from '../utils/objectEntriesMap';
const PARTICLES_SQRT = 8;
const PARTICLES = PARTICLES_SQRT * PARTICLES_SQRT;
@@ -72,7 +73,7 @@ export class FlickyParticles extends Entity {
flickyParticleRenderVert,
flickyParticleRenderFrag,
{
defines: { 'FORWARD': 'true' },
defines: [ 'FORWARD 1' ],
initOptions: { geometry: geometryRender, target: dummyRenderTarget },
},
);
@@ -81,7 +82,7 @@ export class FlickyParticles extends Entity {
flickyParticleRenderVert,
flickyParticleRenderFrag,
{
defines: { 'DEFERRED': 'true' },
defines: [ 'DEFERRED 1' ],
initOptions: { geometry: geometryRender, target: dummyRenderTargetFourDrawBuffers },
},
);
@@ -90,16 +91,16 @@ export class FlickyParticles extends Entity {
flickyParticleRenderVert,
flickyParticleRenderFrag,
{
defines: { 'SHADOW': 'true' },
defines: [ 'SHADOW 1' ],
initOptions: { geometry: geometryRender, target: dummyRenderTarget },
},
);
const materialsRender = { forward, deferred, shadow };
for ( const material of Object.values( materialsRender ) ) {
objectValuesMap( materialsRender, ( material ) => {
material.addUniformTexture( 'samplerRandomStatic', randomTextureStatic.texture );
}
} );
if ( process.env.DEV ) {
if ( module.hot ) {

View File

@@ -7,6 +7,7 @@ import { Mesh } from '../heck/components/Mesh';
import { Quad } from '../heck/components/Quad';
import { Swap } from '@fms-cat/experimental';
import { gl } from '../globals/canvas';
import { objectValuesMap } from '../utils/objectEntriesMap';
export interface GPUParticlesOptions {
materialCompute: Material;
@@ -62,14 +63,14 @@ export class GPUParticles extends Entity {
name: process.env.DEV && `${ namePrefix }/meshRender`,
} );
for ( const material of Object.values( materialsRender ) ) {
objectValuesMap( materialsRender, ( material ) => {
material?.addUniform(
'resolutionCompute',
'2f',
computeWidth,
computeHeight
);
}
} );
// -- swapper ----------------------------------------------------------------------------------
this.components.push( new Lambda( {
@@ -84,12 +85,12 @@ export class GPUParticles extends Entity {
swapCompute.i.getTexture( attachment )
);
for ( const material of Object.values( materialsRender ) ) {
objectValuesMap( materialsRender, ( material ) => {
material?.addUniformTexture(
`samplerCompute${ i }`,
swapCompute.o.getTexture( attachment )
);
}
} );
}
quadCompute.target = swapCompute.o;

View File

@@ -58,7 +58,7 @@ export class LightEntity extends Entity {
renderTarget: swap.o,
scene: this.root,
name: process.env.DEV && `${ options.namePrefix }/shadowMapCamera`,
materialTag: 'shadow',
materialTag: 'depth',
} );
this.camera.clear = [ 1.0, 1.0, 1.0, 1.0 ];
this.components.push( this.camera );

View File

@@ -10,6 +10,7 @@ import { randomTexture, randomTextureStatic } from '../globals/randomTexture';
import { auto } from '../globals/automaton';
import { dummyRenderTargetFourDrawBuffers, dummyRenderTarget } from '../globals/dummyRenderTarget';
import { genOctahedron } from '../geometries/genOctahedron';
import { objectValuesMap } from '../utils/objectEntriesMap';
export class Raymarcher extends Entity {
public constructor() {
@@ -31,45 +32,46 @@ export class Raymarcher extends Entity {
geometry.indexType = octahedron.indexType;
// -- materials --------------------------------------------------------------------------------
const materials = {
deferred: new Material(
const deferred = new Material(
raymarchObjectVert,
raymarcherFrag,
{
defines: { 'DEFERRED': 'true' },
defines: [ 'DEFERRED 1' ],
initOptions: { geometry, target: dummyRenderTargetFourDrawBuffers },
},
),
shadow: new Material(
);
const depth = new Material(
raymarchObjectVert,
raymarcherFrag,
{
defines: { 'SHADOW': 'true' },
defines: [ 'SHADOW 1' ],
initOptions: { geometry, target: dummyRenderTarget }
},
),
};
);
const materials = { deferred, depth };
if ( process.env.DEV ) {
if ( module.hot ) {
module.hot.accept( '../shaders/raymarcher.frag', () => {
materials.deferred.replaceShader( raymarchObjectVert, raymarcherFrag );
materials.shadow.replaceShader( raymarchObjectVert, raymarcherFrag );
deferred.replaceShader( raymarchObjectVert, raymarcherFrag );
depth.replaceShader( raymarchObjectVert, raymarcherFrag );
} );
}
}
for ( const material of Object.values( materials ) ) {
objectValuesMap( materials, ( material ) => {
material.addUniform( 'range', '4f', -1.0, -1.0, 1.0, 1.0 );
material.addUniformTexture( 'samplerRandom', randomTexture.texture );
material.addUniformTexture( 'samplerRandomStatic', randomTextureStatic.texture );
}
} );
// -- updater ----------------------------------------------------------------------------------
this.components.push( new Lambda( {
onDraw: ( event ) => {
for ( const material of Object.values( materials ) ) {
objectValuesMap( materials, ( material ) => {
material.addUniform(
'cameraNearFar',
'2f',
@@ -90,15 +92,15 @@ export class Raymarcher extends Entity {
material.addUniform( 'deformAmp', '1f', auto( 'Music/NEURO_WUB_AMP' ) );
material.addUniform( 'deformFreq', '1f', auto( 'Music/NEURO_WUB_FREQ' ) + auto( 'Music/NEURO_DETUNE' ) );
material.addUniform( 'deformTime', '1f', auto( 'Music/NEURO_TIME' ) );
}
} );
},
name: process.env.DEV && 'Raymarcher/updater',
} ) );
// -- mesh -------------------------------------------------------------------------------------
const mesh = new Mesh( {
geometry: geometry,
materials: materials,
geometry,
materials,
name: process.env.DEV && 'Raymarcher/mesh',
} );
mesh.cull = MeshCull.None;

View File

@@ -47,28 +47,34 @@ export class Rings extends Entity {
geometry.primcount = PRIMCOUNT;
// -- materials --------------------------------------------------------------------------------
const materials = {
forward: new Material(
const forward = new Material(
ringsVert,
ringsFrag,
{
defines: { 'FORWARD': 'true' },
defines: [ 'FORWARD 1' ],
initOptions: { geometry, target: dummyRenderTarget },
},
),
deferred: new Material(
);
const deferred = new Material(
ringsVert,
ringsFrag,
{
defines: { 'DEFERRED': 'true' },
defines: [ 'DEFERRED 1' ],
initOptions: { geometry, target: dummyRenderTarget },
},
),
shadow: new Material(
);
const depth = new Material(
ringsVert,
depthFrag,
{ initOptions: { geometry, target: dummyRenderTarget } },
),
);
const materials = {
forward,
deferred,
depth,
}
if ( process.env.DEV ) {
@@ -79,9 +85,9 @@ export class Rings extends Entity {
'../shaders/rings.frag',
],
() => {
materials.forward.replaceShader( ringsVert, ringsFrag );
materials.deferred.replaceShader( ringsVert, ringsFrag );
materials.shadow.replaceShader( ringsVert, depthFrag );
forward.replaceShader( ringsVert, ringsFrag );
deferred.replaceShader( ringsVert, ringsFrag );
depth.replaceShader( ringsVert, depthFrag );
},
);
}
@@ -89,8 +95,8 @@ export class Rings extends Entity {
// -- mesh -------------------------------------------------------------------------------------
const mesh = new Mesh( {
geometry: geometry,
materials: materials,
geometry,
materials,
name: process.env.DEV && 'Rings/mesh',
} );
this.components.push( mesh );

View File

@@ -75,21 +75,21 @@ export class SphereParticles extends Entity {
sphereParticleRenderVert,
sphereParticleRenderFrag,
{
defines: { 'DEFERRED': 'true' },
defines: [ 'DEFERRED 1' ],
initOptions: { geometry: geometryRender, target: dummyRenderTargetFourDrawBuffers },
},
);
const shadow = new Material(
const depth = new Material(
sphereParticleRenderVert,
depthFrag,
{ initOptions: { geometry: geometryRender, target: dummyRenderTarget } },
);
const materialsRender = { deferred, shadow };
const materialsRender = { deferred, depth };
deferred.addUniformTexture( 'samplerRandomStatic', randomTextureStatic.texture );
shadow.addUniformTexture( 'samplerRandomStatic', randomTextureStatic.texture );
depth.addUniformTexture( 'samplerRandomStatic', randomTextureStatic.texture );
if ( process.env.DEV ) {
if ( module.hot ) {
@@ -100,7 +100,7 @@ export class SphereParticles extends Entity {
],
() => {
deferred.replaceShader( sphereParticleRenderVert, sphereParticleRenderFrag );
shadow.replaceShader( sphereParticleRenderVert, depthFrag );
depth.replaceShader( sphereParticleRenderVert, depthFrag );
}
);
}

View File

@@ -68,7 +68,7 @@ export class SufferTexts extends Entity {
sufferTextsRenderVert,
sufferTextsRenderFrag,
{
defines: { 'DEFERRED': 'true' },
defines: [ 'DEFERRED 1' ],
initOptions: { geometry: geometryRender, target: dummyRenderTargetFourDrawBuffers },
},
);

View File

@@ -108,20 +108,20 @@ export class Trails extends Entity {
trailsRenderVert,
trailsRenderFrag,
{
defines: { 'DEFERRED': 'true' },
defines: [ 'DEFERRED 1' ],
initOptions: { geometry: geometryRender, target: dummyRenderTargetFourDrawBuffers },
},
);
const shadow = new Material(
const depth = new Material(
trailsRenderVert,
depthFrag,
{ initOptions: { geometry: geometryRender, target: dummyRenderTarget } },
);
const materialsRender = { deferred, shadow };
const materialsRender = { deferred, depth };
deferred.addUniformTexture( 'samplerRandomStatic', randomTextureStatic.texture );
shadow.addUniformTexture( 'samplerRandomStatic', randomTextureStatic.texture );
depth.addUniformTexture( 'samplerRandomStatic', randomTextureStatic.texture );
if ( process.env.DEV ) {
if ( module.hot ) {
@@ -132,7 +132,7 @@ export class Trails extends Entity {
],
() => {
deferred.replaceShader( trailsRenderVert, trailsRenderFrag );
shadow.replaceShader( trailsRenderVert, depthFrag );
depth.replaceShader( trailsRenderVert, depthFrag );
}
);
}

View File

@@ -1,9 +1,9 @@
import { Automaton } from '@fms-cat/automaton';
import { AutomatonWithGUI } from '@fms-cat/automaton-with-gui';
import automatonData from '../automaton.json';
import * as automatonFxs from '../automaton-fxs/automatonFxs';
import { music } from './music';
import { getDivAutomaton } from './dom';
import { fxDefinitions } from '../automaton-fxs/fxDefinitions';
export const automaton = ( () => {
if ( process.env.DEV ) {
@@ -14,8 +14,8 @@ export const automaton = ( () => {
{
gui: getDivAutomaton(),
isPlaying: true,
fxDefinitions: automatonFxs,
}
fxDefinitions,
},
);
automatonWithGUI.on( 'play', () => { music.isPlaying = true; } );
@@ -38,8 +38,8 @@ export const automaton = ( () => {
return new Automaton(
automatonData,
{
fxDefinitions: automatonFxs
}
fxDefinitions,
},
);
}
} )();

View File

@@ -8,7 +8,7 @@ import { SHADERPOOL } from './ShaderPool';
export type MaterialTag =
| 'deferred'
| 'forward'
| 'shadow';
| 'depth';
export type MaterialMap<T extends MaterialTag = MaterialTag> = { [ tag in T ]: Material };
@@ -20,9 +20,7 @@ export interface MaterialInitOptions {
export class Material {
protected __linkOptions: GLCatProgramLinkOptions;
protected __defines: {
[ name: string ]: ( string | undefined );
};
protected __defines: string[];
protected __uniforms: {
[ name: string ]: {
@@ -84,7 +82,7 @@ export class Material {
vert: string,
frag: string,
{ defines, blend, linkOptions, initOptions }: {
defines?: { [ key: string ]: ( string | undefined ) },
defines?: string[],
blend?: [ GLenum, GLenum ],
linkOptions?: GLCatProgramLinkOptions,
initOptions?: MaterialInitOptions,
@@ -93,7 +91,7 @@ export class Material {
this.__vert = vert;
this.__frag = frag;
this.__linkOptions = linkOptions ?? {};
this.__defines = defines ?? {};
this.__defines = defines ?? [];
this.blend = blend ?? [ gl.ONE, gl.ZERO ];
if ( initOptions ) {
@@ -153,12 +151,12 @@ export class Material {
vert: string,
frag: string,
options?: {
defines?: { [ key: string ]: ( string | undefined ) },
defines?: string[],
linkOptions?: GLCatProgramLinkOptions,
},
): Promise<void> {
if ( options?.defines ) {
this.__defines = { ...options.defines };
this.__defines = [ ...options.defines ];
}
const program = await SHADERPOOL.getProgramAsync(
@@ -194,9 +192,9 @@ export class Material {
protected __withDefines( code: string ): string {
let inject = '';
Object.entries( this.__defines ).map( ( [ key, value ] ) => {
this.__defines.map( ( value ) => {
if ( value != null ) {
inject += `#define ${key} ${value}\n`;
inject += `#define ${value}\n`;
}
} );

View File

@@ -4,6 +4,7 @@ import { Component } from './heck/components/Component';
import { music } from './globals/music';
import { getCheckboxActive, getDivCanvasContainer } from './globals/dom';
import { dog } from './scene';
import { START_POSITION } from './config';
// == dom ==========================================================================================
document.body.style.margin = '0';
@@ -20,6 +21,9 @@ if ( process.env.DEV ) {
canvas.style.margin = 'auto';
canvas.style.maxWidth = '100%';
canvas.style.maxHeight = '100%';
music.isPlaying = true;
music.time = START_POSITION;
} else {
canvas.style.position = 'fixed';
canvas.style.left = '0';
@@ -34,6 +38,7 @@ if ( process.env.DEV ) {
button.onclick = () => {
document.body.appendChild( canvas );
music.isPlaying = true;
music.time = START_POSITION;
document.body.requestFullscreen();
};
}
@@ -70,8 +75,3 @@ if ( process.env.DEV ) {
console.info( Component.nameMap );
console.info( BufferRenderTarget.nameMap );
}
// == music ========================================================================================
if ( process.env.DEV ) {
music.isPlaying = true;
}

View File

@@ -1,18 +1,18 @@
export const sufferList = [
'#DEFINE DISGRACE 1',
'WELCOME TO THE MANGLER HELL',
'CTRL + ALT + DESPAIR',
'PUBIC CONSTRUCTOR()',
'LIBOPUS IS CHEATING',
'PUBLIC GET FUCKED()',
'\'RETRUN\': UNDECLARED IDENTIFIER',
'NOTICE ME, GARBAGE COLLECTOR',
'WEBGL HATES YOU',
'#DEFINE COMPROMISE 1',
'GL.DISABLE(GL.TIMEZONE)',
'WHERE IS MY SLEEPING SCHEDULE?',
'GL.DISABLE(GL.TIMEZONE)',
'SVG.GETPOINTATLENGTH IS CHEATING',
'COPY\'N\'PASTE ENGINEER',
'ENGLISH SUCKS',
'60FPS OR DIE',
'<PLACEHOLDER>',
'END MY SUFFER',
];

View File

@@ -0,0 +1,6 @@
export function iterateOverMap<TKey, TValue, TReturn>(
map: Map<TKey, TValue>,
func: ( value: TValue, key: TKey ) => TReturn,
): TReturn[] {
return Array.from( map.entries() ).map( ( [ key, value ] ) => func( value, key ) );
}

View File

@@ -1,11 +1,40 @@
/* eslint-env node */
/* eslint-disable @typescript-eslint/no-var-requires */
const TerserPlugin = require( 'terser-webpack-plugin' );
const HtmlWebpackPlugin = require( 'html-webpack-plugin' );
const packageJson = require( './package.json' );
const path = require( 'path' );
const webpack = require( 'webpack' );
/**
* @type TerserPlugin.TerserPluginOptions[ 'terserOptions' ]
*/
const terserOptions = {
compress: {
arguments: true,
booleans_as_integers: true,
drop_console: true,
keep_fargs: false,
passes: 1,
unsafe_arrows: true,
unsafe_math: true,
},
mangle: {
properties: {
regex: /.+/,
reserved: [
// material tags
'forward',
'deferred',
'depth',
]
},
},
module: true,
toplevel: true,
};
module.exports = ( env, argv ) => {
const VERSION = packageJson.version;
const DEV = argv.mode === 'development';
@@ -67,6 +96,7 @@ module.exports = ( env, argv ) => {
},
optimization: {
minimize: !DEV,
minimizer: [ new TerserPlugin( { terserOptions } ) ],
moduleIds: DEV ? 'named' : undefined,
usedExports: !DEV,
},