mirror of
https://github.com/FMS-Cat/condition.git
synced 2025-08-13 17:24:00 +02:00
feature: SufferTexts
This commit is contained in:
144
src/entities/SufferTexts.ts
Normal file
144
src/entities/SufferTexts.ts
Normal 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 };
|
||||
}
|
||||
}
|
11
src/globals/tinyCharTexture.ts
Normal file
11
src/globals/tinyCharTexture.ts
Normal 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
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
4
src/png.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
declare module '*.png' {
|
||||
const uri: string;
|
||||
export default uri;
|
||||
}
|
11
src/scene.ts
11
src/scene.ts
@@ -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', () => {
|
||||
|
24
src/shaders/suffer-texts-compute.frag
Normal file
24
src/shaders/suffer-texts-compute.frag
Normal 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
|
||||
}
|
40
src/shaders/suffer-texts-render.frag
Normal file
40
src/shaders/suffer-texts-render.frag
Normal 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
|
||||
}
|
66
src/shaders/suffer-texts-render.vert
Normal file
66
src/shaders/suffer-texts-render.vert
Normal 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
18
src/sufferList.ts
Normal 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',
|
||||
];
|
@@ -53,7 +53,7 @@ module.exports = ( env, argv ) => {
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.opus$/,
|
||||
test: /\.(opus|png)$/,
|
||||
type: 'asset/inline',
|
||||
},
|
||||
{
|
||||
|
Reference in New Issue
Block a user