feature: SufferTexts

This commit is contained in:
FMS-Cat
2021-03-23 20:01:13 +09:00
parent 633a0db7ea
commit 90751c2b75
10 changed files with 319 additions and 1 deletions

144
src/entities/SufferTexts.ts Normal file
View File

@@ -0,0 +1,144 @@
import { Entity } from '../heck/Entity';
import { GPUParticles } from './GPUParticles';
import { Geometry } from '../heck/Geometry';
import { InstancedGeometry } from '../heck/InstancedGeometry';
import { Material, MaterialMap } from '../heck/Material';
import quadVert from '../shaders/quad.vert';
import sufferTextsComputeFrag from '../shaders/suffer-texts-compute.frag';
import sufferTextsRenderFrag from '../shaders/suffer-texts-render.frag';
import sufferTextsRenderVert from '../shaders/suffer-texts-render.vert';
import { TRIANGLE_STRIP_QUAD } from '@fms-cat/experimental';
import { gl, glCat } from '../globals/canvas';
import { randomTextureStatic } from '../globals/randomTexture';
import { tinyCharTexture } from '../globals/tinyCharTexture';
import { Lambda } from '../heck/components/Lambda';
import { auto } from '../globals/automaton';
import { sufferList } from '../sufferList';
const PARTICLES = 256;
export class SufferTexts {
public get entity(): Entity {
return this.gpuParticles.entity;
}
public gpuParticles: GPUParticles;
public queue: number[][];
public particleIndex: number;
public constructor() {
this.gpuParticles = new GPUParticles( {
materialCompute: this.__createMaterialCompute(),
geometryRender: this.__createGeometryRender(),
materialsRender: this.__createMaterialsRender(),
computeWidth: PARTICLES,
computeHeight: 1,
computeNumBuffers: 1,
namePrefix: process.env.DEV && 'SufferTexts',
} );
this.queue = [];
this.particleIndex = 0;
auto( 'sufferText/push', ( { value } ) => {
const suffer = sufferList[ Math.floor( value ) ].split( '\n' );
suffer.forEach( ( line, iLine ) => {
const chars = [ ...line ];
this.queue.push( ...chars.map( ( char, iChar ) => [
iChar - 0.5 * ( chars.length - 1 ),
iLine - 0.5 * ( suffer.length - 1 ),
char.charCodeAt( 0 ),
] ) );
} );
} );
this.entity.components.push( new Lambda( {
onUpdate: () => {
const val = this.queue.shift();
if ( val != null ) {
const x = ( this.particleIndex + 0.5 ) / PARTICLES;
this.gpuParticles.materialCompute.addUniform( 'logInit', '4f', ...val, x );
this.particleIndex = ( this.particleIndex + 1 ) % PARTICLES;
} else {
this.gpuParticles.materialCompute.addUniform( 'logInit', '4f', 0.0, 0.0, 0.0, 0.0 );
}
},
} ) );
}
private __createMaterialCompute(): Material {
const material = new Material( quadVert, sufferTextsComputeFrag );
if ( process.env.DEV ) {
if ( module.hot ) {
module.hot.accept( '../shaders/suffer-texts-compute.frag', () => {
material.replaceShader( quadVert, sufferTextsComputeFrag );
} );
}
}
return material;
}
private __createGeometryRender(): Geometry {
const geometry = new InstancedGeometry();
const bufferP = glCat.createBuffer();
bufferP.setVertexbuffer( new Float32Array( TRIANGLE_STRIP_QUAD ) );
geometry.addAttribute( 'position', {
buffer: bufferP,
size: 2,
type: gl.FLOAT,
} );
const bufferComputeUV = glCat.createBuffer();
bufferComputeUV.setVertexbuffer( ( () => {
const ret = new Float32Array( PARTICLES );
for ( let ix = 0; ix < PARTICLES; ix ++ ) {
const s = ( ix + 0.5 ) / PARTICLES;
ret[ ix ] = s;
}
return ret;
} )() );
geometry.addAttribute( 'computeX', {
buffer: bufferComputeUV,
size: 1,
divisor: 1,
type: gl.FLOAT
} );
geometry.count = 4;
geometry.mode = gl.TRIANGLE_STRIP;
geometry.primcount = PARTICLES;
return geometry;
}
private __createMaterialsRender(): MaterialMap<'deferred'> {
const deferred = new Material(
sufferTextsRenderVert,
sufferTextsRenderFrag,
{ defines: { 'DEFERRED': 'true' } },
);
deferred.addUniformTexture( 'samplerRandomStatic', randomTextureStatic.texture );
deferred.addUniformTexture( 'samplerTinyChar', tinyCharTexture );
if ( process.env.DEV ) {
if ( module.hot ) {
module.hot.accept(
[
'../shaders/suffer-texts-render.vert',
'../shaders/suffer-texts-render.frag',
],
() => {
deferred.replaceShader( sufferTextsRenderVert, sufferTextsRenderFrag );
}
);
}
}
return { deferred };
}
}

View File

@@ -0,0 +1,11 @@
import { gl, glCat } from './canvas';
import char5x5Png from '../images/char5x5.png';
export const tinyCharTexture = glCat.createTexture();
const image = new Image();
image.onload = () => {
tinyCharTexture.setTexture( image );
tinyCharTexture.textureFilter( gl.NEAREST );
};
image.src = char5x5Png;

BIN
src/images/char5x5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 B

4
src/png.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
declare module '*.png' {
const uri: string;
export default uri;
}

View File

@@ -14,6 +14,7 @@ import { Raymarcher } from './entities/Raymarcher';
import { Rings } from './entities/Rings';
import { RTInspector } from './entities/RTInspector';
import { SphereParticles } from './entities/SphereParticles';
import { SufferTexts } from './entities/SufferTexts';
import { Trails } from './entities/Trails';
import { auto, automaton } from './globals/automaton';
import { music } from './globals/music';
@@ -133,6 +134,16 @@ if ( process.env.DEV && module.hot ) {
} );
}
const replacerSufferTexts = new EntityReplacer(
() => new SufferTexts(),
'SufferTexts',
);
if ( process.env.DEV && module.hot ) {
module.hot.accept( './entities/SufferTexts', () => {
replacerSufferTexts.replace();
} );
}
const replacerRaymarcher = new EntityReplacer( () => new Raymarcher(), 'Raymarcher' );
if ( process.env.DEV && module.hot ) {
module.hot.accept( './entities/Raymarcher', () => {

View File

@@ -0,0 +1,24 @@
#version 300 es
precision highp float;
out vec4 fragCompute0;
uniform float time;
uniform float deltaTime;
uniform vec2 resolution;
uniform vec4 logInit;
uniform sampler2D samplerCompute0;
void main() {
vec2 uv = gl_FragCoord.xy / resolution;
fragCompute0 = texture( samplerCompute0, uv );
if ( logInit.w == uv.x ) {
fragCompute0 = logInit;
fragCompute0.w = 0.0; // life
}
fragCompute0.w += deltaTime; // life
}

View File

@@ -0,0 +1,40 @@
#version 300 es
precision highp float;
const int MTL_UNLIT = 1;
// == varings / uniforms ===========================================================================
in float vLife;
in float vMode;
in vec2 vUv;
in vec2 vSize;
in vec3 vNormal;
in vec4 vPosition;
in vec4 vDice;
uniform float time;
uniform sampler2D samplerRandomStatic;
uniform sampler2D samplerTinyChar;
#ifdef DEFERRED
layout (location = 0) out vec4 fragPosition;
layout (location = 1) out vec4 fragNormal;
layout (location = 2) out vec4 fragColor;
layout (location = 3) out vec4 fragWTF;
#endif
// == main procedure ===============================================================================
void main() {
if ( vLife > 1.0 ) { discard; }
float tex = texture( samplerTinyChar, vUv ).x;
if ( tex < 0.5 ) { discard; }
#ifdef DEFERRED
fragPosition = vPosition;
fragNormal = vec4( vNormal, 1.0 );
fragColor = vec4( 1.0 );
fragWTF = vec4( vec3( 0.0 ), MTL_UNLIT );
#endif
}

View File

@@ -0,0 +1,66 @@
#version 300 es
#define fs(i) (fract(sin((i)*114.514)*1919.810))
#define saturate(i) clamp(i,0.,1.)
#define lofi(i,m) (floor((i)/(m))*(m))
#define lofir(i,m) (floor((i+0.5)/(m))*(m))
// -------------------------------------------------------------------------------------------------
in float computeX;
in vec2 position;
out float vLife;
out vec2 vUv;
out vec2 vSize;
out vec3 vNormal;
out vec4 vPosition;
uniform vec2 resolution;
uniform vec2 resolutionCompute;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 normalMatrix;
uniform sampler2D samplerCompute0;
uniform sampler2D samplerRandomStatic;
// == utils ========================================================================================
vec2 yflip( vec2 uv ) {
return vec2( 0.0, 1.0 ) + vec2( 1.0, -1.0 ) * uv;
}
// == main procedure ===============================================================================
void main() {
vec2 computeUV = vec2( computeX, 0.5 );
vec4 tex0 = texture( samplerCompute0, computeUV );
// == assign varying variables ===================================================================
vLife = tex0.w;
float char = tex0.z;
char += 64.0 * ( min( vLife, 0.3 ) + max( vLife, 0.7 ) - 1.0 );
vUv = yflip( 0.5 + 0.499 * position );
vUv = ( vUv + floor( mod( vec2( char / vec2( 1.0, 16.0 ) ), 16.0 ) ) ) / 16.0;
vNormal = normalize( ( normalMatrix * vec4( 0.0, 0.0, 1.0, 1.0 ) ).xyz );
// == compute size ===============================================================================
float scale = 0.0625;
vPosition = vec4( scale * 1.2 * tex0.xy, 0.0, 1.0 );
vPosition.y = -vPosition.y;
vec2 shape = position * scale * 0.5;
vPosition.xy += shape;
// == send the vertex position ===================================================================
vPosition = vPosition;
vec4 outPos = vPosition;
outPos.x *= resolution.y / resolution.x;
gl_Position = outPos;
vPosition.w = outPos.z / outPos.w;
}

18
src/sufferList.ts Normal file
View File

@@ -0,0 +1,18 @@
export const sufferList = [
'#DEFINE DISGRACE 1',
'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?',
'SVG.GETPOINTATLENGTH IS CHEATING',
'COPY\'N\'PASTE ENGINEER',
'ENGLISH SUCKS',
'60FPS OR DIE',
'END MY SUFFER',
];

View File

@@ -53,7 +53,7 @@ module.exports = ( env, argv ) => {
],
},
{
test: /\.opus$/,
test: /\.(opus|png)$/,
type: 'asset/inline',
},
{