greetings and stuff

This commit is contained in:
FMS-Cat
2021-04-01 01:31:49 +09:00
parent ce78b8045e
commit 0603dab195
19 changed files with 576 additions and 29 deletions

File diff suppressed because one or more lines are too long

View File

@@ -3,7 +3,7 @@ export const
// RTINSPECTOR_MULTIPLE = true, // RTINSPECTOR_MULTIPLE = true,
RTINSPECTOR_CAPTURE_NAME: string | null = null, RTINSPECTOR_CAPTURE_NAME: string | null = null,
// RTINSPECTOR_CAPTURE_NAME: string | null = 'PixelSorter/index', // RTINSPECTOR_CAPTURE_NAME: string | null = 'PixelSorter/index',
// RTINSPECTOR_CAPTURE_NAME: string | null = 'Bloom/swap1', // RTINSPECTOR_CAPTURE_NAME: string | null = 'Greetings/intermediate0',
// RTINSPECTOR_CAPTURE_NAME: string | null = 'main/postSwap0', // RTINSPECTOR_CAPTURE_NAME: string | null = 'main/postSwap0',
// RTINSPECTOR_CAPTURE_NAME: string | null = 'DeferredCamera/cameraTarget', // RTINSPECTOR_CAPTURE_NAME: string | null = 'DeferredCamera/cameraTarget',
RTINSPECTOR_CAPTURE_INDEX = 0, RTINSPECTOR_CAPTURE_INDEX = 0,

View File

@@ -5,7 +5,7 @@ export const
AO_RESOLUTION_RATIO = 1.0, AO_RESOLUTION_RATIO = 1.0,
RESOLUTION = [ 1280, 720 ], RESOLUTION = [ 1280, 720 ],
MUSIC_BPM = 180, MUSIC_BPM = 180,
START_POSITION = 45, START_POSITION = 112,
MUSIC_LENGTH = 213, MUSIC_LENGTH = 213,
MUSIC_AUTOMATON_TEXTURE_HEIGHT = 16, MUSIC_AUTOMATON_TEXTURE_HEIGHT = 16,
IBLLUT_ITER = 400, IBLLUT_ITER = 400,

View File

@@ -4,12 +4,12 @@ import { Entity } from '../heck/Entity';
import { Material } from '../heck/Material'; import { Material } from '../heck/Material';
import { Quad } from '../heck/components/Quad'; import { Quad } from '../heck/components/Quad';
import { RenderTarget } from '../heck/RenderTarget'; import { RenderTarget } from '../heck/RenderTarget';
import { auto } from '../globals/automaton';
import { dummyRenderTarget } from '../globals/dummyRenderTarget'; import { dummyRenderTarget } from '../globals/dummyRenderTarget';
import { quadGeometry } from '../globals/quadGeometry'; import { quadGeometry } from '../globals/quadGeometry';
import { randomTexture } from '../globals/randomTexture'; import { randomTexture } from '../globals/randomTexture';
import dviFrag from '../shaders/dvi.frag'; import dviFrag from '../shaders/dvi.frag';
import quadVert from '../shaders/quad.vert'; import quadVert from '../shaders/quad.vert';
import { auto } from '../globals/automaton';
export interface DViOptions { export interface DViOptions {
input: BufferRenderTarget; input: BufferRenderTarget;

View File

@@ -15,7 +15,6 @@ import { randomTexture } from '../globals/randomTexture';
import aoFrag from '../shaders/ao.frag'; import aoFrag from '../shaders/ao.frag';
import quadVert from '../shaders/quad.vert'; import quadVert from '../shaders/quad.vert';
import shadingFrag from '../shaders/shading.frag'; import shadingFrag from '../shaders/shading.frag';
import { auto } from '../globals/automaton';
export interface DeferredCameraOptions { export interface DeferredCameraOptions {
scenes: Entity[]; scenes: Entity[];

319
src/entities/Greetings.ts Normal file
View File

@@ -0,0 +1,319 @@
import { BufferRenderTarget } from '../heck/BufferRenderTarget';
import { Entity } from '../heck/Entity';
import { GLCatTexture } from '@fms-cat/glcat-ts';
import { InstancedGeometry } from '../heck/InstancedGeometry';
import { Lambda } from '../heck/components/Lambda';
import { Material } from '../heck/Material';
import { Mesh } from '../heck/components/Mesh';
import { Quad } from '../heck/components/Quad';
import { SPRITE_SHEET_SIZE, createFontSpriteSheet } from '../utils/createFontSpriteSheet';
import { Swap, TRIANGLE_STRIP_QUAD } from '@fms-cat/experimental';
import { auto } from '../globals/automaton';
import { calcCharPos } from '../utils/calcCharPos';
import { dummyRenderTarget } from '../globals/dummyRenderTarget';
import { gl, glCat } from '../globals/canvas';
import { quadGeometry } from '../globals/quadGeometry';
import blurFrag from '../shaders/blur.frag';
import greetingsFrag from '../shaders/greetings.frag';
import greetingsPreBeatmaniaFrag from '../shaders/greetings-pre-beatmania.frag';
import greetingsPreLainFrag from '../shaders/greetings-pre-lain.frag';
import greetingsVert from '../shaders/greetings.vert';
import quadVert from '../shaders/quad.vert';
const INSTANCES = 256;
// -- preprocessor ---------------------------------------------------------------------------------
const materialBlurH = new Material(
quadVert,
blurFrag,
{ initOptions: { geometry: quadGeometry, target: dummyRenderTarget } },
);
const materialBlurV = new Material(
quadVert,
blurFrag,
{
defines: [ 'IS_VERTICAL 1' ],
initOptions: { geometry: quadGeometry, target: dummyRenderTarget }
},
);
const materialPreBeatmania = new Material(
quadVert,
greetingsPreBeatmaniaFrag,
{ initOptions: { geometry: quadGeometry, target: dummyRenderTarget } },
);
const materialPreLain = new Material(
quadVert,
greetingsPreLainFrag,
{ initOptions: { geometry: quadGeometry, target: dummyRenderTarget } },
);
/**
* Do not add me to its components!
* It's just for preprocessing
*/
const quadPreprocessor = new Quad( {
name: process.env.DEV && 'Greetings/quadPreprocessor',
} );
// -- spritesheets ---------------------------------------------------------------------------------
const styles = [
{
font: 'Bold 96px Courier New',
preprocessorMaterials: [ materialPreLain ],
},
{
font: '96px Arial',
spacing: 2.0,
},
{
font: 'Bold 96px Arial',
preprocessorMaterials: [
materialBlurH,
materialBlurV,
materialBlurH, // fuck you
materialBlurV, // fuck you (2)
materialPreBeatmania,
],
},
{
font: '96px Times New Roman',
scaleY: 1.2,
spacing: 1.9,
},
{
font: 'Bold 96px Courier New',
preprocessorMaterials: [ materialPreLain ],
},
{
font: 'Bold 96px Arial',
spacing: 1.5,
},
{
font: 'Bold 96px Arial',
preprocessorMaterials: [
materialBlurH,
materialBlurV,
materialBlurH, // fuck you
materialBlurV, // fuck you (2)
materialPreBeatmania,
],
},
{
font: '96px Times New Roman',
},
];
const swapIntermediate = new Swap(
new BufferRenderTarget( {
width: SPRITE_SHEET_SIZE,
height: SPRITE_SHEET_SIZE,
name: process.env.DEV && 'Greetings/intermediate0',
} ),
new BufferRenderTarget( {
width: SPRITE_SHEET_SIZE,
height: SPRITE_SHEET_SIZE,
name: process.env.DEV && 'Greetings/intermediate0',
} ),
);
const spritesheets = styles.map( ( style, iStyle ) => {
const textureSpriteSheet = createFontSpriteSheet( style );
let texture: GLCatTexture = textureSpriteSheet;
( style.preprocessorMaterials ?? [] ).map( ( material, i ) => {
material.addUniformTexture(
'sampler0',
i === 0 ? textureSpriteSheet : swapIntermediate.o.texture,
);
quadPreprocessor.material = material;
quadPreprocessor.target = swapIntermediate.i;
quadPreprocessor.drawImmediate();
swapIntermediate.swap();
texture = swapIntermediate.o.texture;
} );
const dest = new BufferRenderTarget( {
width: SPRITE_SHEET_SIZE,
height: SPRITE_SHEET_SIZE,
name: process.env.DEV && `Greetings/spriteSheet${ iStyle }`,
} );
materialBlurH.addUniformTexture( 'sampler0', texture );
quadPreprocessor.material = materialBlurH;
quadPreprocessor.target = dest;
quadPreprocessor.drawImmediate();
return dest.texture;
} );
// -- greetings! -----------------------------------------------------------------------------------
const charPosList = [
'0x4015',
'Alcatraz',
'Altair',
'Astronomena',
'CNCD',
'Cocoon',
'Conspiracy',
'Fairlight',
'Flopine',
'FRONTL1NE',
'holon',
'gam0022',
'jetlag',
'Jugem-T',
'kaneta',
'Limp Ninja',
'LJ',
'Logicoma',
'Mercury',
'nikq::cube',
'Ninjadev',
'NuSan',
'Poo-Brain',
'Prismbeings',
'Radium Software',
'rgba',
'Satori',
'sp4ghet',
'Still',
'Suricrasia Online',
'tdhooper',
'Ümlaüt Design',
'Virgill',
'Wrighter',
'yx',
].map( ( text, iGreeting ) => {
const style = styles[ iGreeting % styles.length ];
const spacing = style.spacing ?? 1.0;
const { totalWidth, chars } = calcCharPos( text, style.font );
return {
totalWidth: totalWidth * spacing,
scaleY: style.scaleY ?? 1.0,
chars: chars.map( ( { char, x } ) => ( {
char: char.charCodeAt( 0 ),
x: ( x - 0.5 * totalWidth ) / 96.0 * spacing * 1.4 // what the fuck is this magic number
} ) ),
};
} );
export class Greetings extends Entity {
public constructor() {
super();
// -- geometry ---------------------------------------------------------------------------------
const geometry = new InstancedGeometry();
const bufferP = glCat.createBuffer();
bufferP.setVertexbuffer( new Float32Array( TRIANGLE_STRIP_QUAD ) );
geometry.vao.bindVertexbuffer( bufferP, 0, 2 );
const arrayParams = new Float32Array( 4 * INSTANCES ); // char, posFromCenter, width, time
const arrayParams2 = new Float32Array( 4 * INSTANCES ); // totalWidth, scaleY
for ( let i = 0; i < INSTANCES; i ++ ) {
arrayParams[ 4 * i + 0 ] = 0;
arrayParams[ 4 * i + 1 ] = 0;
arrayParams[ 4 * i + 2 ] = 0;
arrayParams[ 4 * i + 3 ] = 0;
arrayParams2[ 4 * i + 0 ] = 0;
}
const bufferParams = glCat.createBuffer();
bufferParams.setVertexbuffer( arrayParams, gl.STREAM_DRAW );
geometry.vao.bindVertexbuffer( bufferParams, 1, 4, 1 );
const bufferParams2 = glCat.createBuffer();
bufferParams2.setVertexbuffer( arrayParams2, gl.STREAM_DRAW );
geometry.vao.bindVertexbuffer( bufferParams2, 2, 4, 1 );
geometry.count = 4;
geometry.mode = gl.TRIANGLE_STRIP;
geometry.primcount = INSTANCES;
// -- material render --------------------------------------------------------------------------
const forward = new Material(
greetingsVert,
greetingsFrag,
{
initOptions: { geometry: geometry, target: dummyRenderTarget },
blend: [ gl.ONE, gl.ONE ],
},
);
const materials = { forward };
forward.addUniformTextureArray( 'samplerSpriteSheets', spritesheets );
if ( process.env.DEV ) {
if ( module.hot ) {
module.hot.accept(
[
'../shaders/greetings.vert',
'../shaders/greetings.frag',
],
() => {
forward.replaceShader( greetingsVert, greetingsFrag );
}
);
}
}
// -- mesh -------------------------------------------------------------------------------------
const mesh = new Mesh( {
geometry,
materials,
name: process.env.DEV && 'Greetings/mesh',
} );
// -- buffer updater ---------------------------------------------------------------------------
let headInstance = 0;
let headGreetings = 0;
const lambda = new Lambda( {
onUpdate: ( { time, deltaTime } ) => {
if ( Math.floor( 6.0 * time ) === Math.floor( 6.0 * ( time - deltaTime ) ) ) {
return;
}
const { totalWidth, scaleY, chars } = charPosList[ headGreetings ];
chars.map( ( { char, x } ) => {
arrayParams[ 4 * headInstance + 0 ] = char;
arrayParams[ 4 * headInstance + 1 ] = x;
arrayParams[ 4 * headInstance + 2 ] = headGreetings;
arrayParams[ 4 * headInstance + 3 ] = time;
arrayParams2[ 4 * headInstance + 0 ] = totalWidth;
arrayParams2[ 4 * headInstance + 1 ] = scaleY;
headInstance = ( headInstance + 1 ) % INSTANCES;
} );
headGreetings = ( headGreetings + 1 ) % charPosList.length;
bufferParams.setVertexbuffer( arrayParams, gl.STREAM_DRAW );
bufferParams2.setVertexbuffer( arrayParams2, gl.STREAM_DRAW );
},
name: process.env.DEV && 'Greetings/spawner',
} );
// -- components -------------------------------------------------------------------------------
this.components.push(
lambda,
mesh,
);
// -- auto -------------------------------------------------------------------------------------
auto( 'Greetings/active', ( { uninit } ) => {
mesh.active = !uninit;
mesh.visible = !uninit;
} );
}
}

View File

@@ -65,5 +65,9 @@ export class Post extends Entity {
material.addUniform( 'colorGamma', '4f', ...preset.gamma ); material.addUniform( 'colorGamma', '4f', ...preset.gamma );
material.addUniform( 'colorGain', '4f', ...preset.gain ); material.addUniform( 'colorGain', '4f', ...preset.gain );
} ); } );
auto( 'Post/mixInvert', ( { value } ) => {
material.addUniform( 'mixInvert', '1f', value );
} );
} }
} }

View File

@@ -1,6 +1,7 @@
import { ChaosTorus } from '../automaton-fxs/ChaosTorus'; import { ChaosTorus } from '../automaton-fxs/ChaosTorus';
import { Crystal } from './Crystal'; import { Crystal } from './Crystal';
import { Entity } from '../heck/Entity'; import { Entity } from '../heck/Entity';
import { Greetings } from './Greetings';
import { Lambda } from '../heck/components/Lambda'; import { Lambda } from '../heck/components/Lambda';
import { Quaternion, Vector3, Xorshift } from '@fms-cat/experimental'; import { Quaternion, Vector3, Xorshift } from '@fms-cat/experimental';
import { Rings } from './Rings'; import { Rings } from './Rings';
@@ -12,10 +13,8 @@ export class SceneCrystals extends Entity {
// -- crystals --------------------------------------------------------------------------------- // -- crystals ---------------------------------------------------------------------------------
const crystal = new Crystal( { width: 0.4, height: 1.5, noiseOffset: 7.0 } ); const crystal = new Crystal( { width: 0.4, height: 1.5, noiseOffset: 7.0 } );
this.children.push( crystal );
const speen = new Entity(); const speen = new Entity();
this.children.push( speen );
const up = new Vector3( [ 0.0, 1.0, 0.0 ] ); const up = new Vector3( [ 0.0, 1.0, 0.0 ] );
this.components.push( new Lambda( { this.components.push( new Lambda( {
@@ -40,12 +39,12 @@ export class SceneCrystals extends Entity {
new Vector3( [ 0.0, 0.0, 1.0 ] ), new Vector3( [ 0.0, 0.0, 1.0 ] ),
0.1, 0.1,
) ); ) );
this.children.push( rings );
// -- chaos torus ------------------------------------------------------------------------------ // -- chaos torus ------------------------------------------------------------------------------
const rng = new Xorshift( 618954 ); const rng = new Xorshift( 618954 );
const chaosToruses = [ ...Array( 6 ).keys() ].map( () => { const chaosToruses = [ ...Array( 6 ).keys() ].map( () => {
const pivot = new Entity(); const pivot = new Entity();
pivot.visible = false;
pivot.transform.rotation = Quaternion.fromAxisAngle( pivot.transform.rotation = Quaternion.fromAxisAngle(
new Vector3( [ 1.0, 0.0, 0.0 ] ), new Vector3( [ 1.0, 0.0, 0.0 ] ),
rng.gen() * 6.0, rng.gen() * 6.0,
@@ -53,7 +52,6 @@ export class SceneCrystals extends Entity {
new Vector3( [ 0.0, 1.0, 0.0 ] ), new Vector3( [ 0.0, 1.0, 0.0 ] ),
rng.gen() * 6.0, rng.gen() * 6.0,
) ); ) );
this.children.push( pivot );
const chaosTorus = new ChaosTorus(); const chaosTorus = new ChaosTorus();
chaosTorus.transform.position = new Vector3( [ 2.5, 0.0, 0.0 ] ); chaosTorus.transform.position = new Vector3( [ 2.5, 0.0, 0.0 ] );
@@ -65,5 +63,17 @@ export class SceneCrystals extends Entity {
auto( 'SceneCrystals/ChaosTorus/active', ( { uninit } ) => { auto( 'SceneCrystals/ChaosTorus/active', ( { uninit } ) => {
chaosToruses.map( ( entity ) => ( entity.visible = !uninit ) ); chaosToruses.map( ( entity ) => ( entity.visible = !uninit ) );
} ); } );
// -- greetings --------------------------------------------------------------------------------
const greetings = new Greetings();
// -- children ---------------------------------------------------------------------------------
this.children.push(
crystal,
speen,
rings,
...chaosToruses,
greetings,
);
} }
} }

View File

@@ -5,7 +5,7 @@ import { Lambda } from '../heck/components/Lambda';
import { Material } from '../heck/Material'; import { Material } from '../heck/Material';
import { TRIANGLE_STRIP_QUAD } from '@fms-cat/experimental'; import { TRIANGLE_STRIP_QUAD } from '@fms-cat/experimental';
import { auto } from '../globals/automaton'; import { auto } from '../globals/automaton';
import { dummyRenderTarget, dummyRenderTargetFourDrawBuffers } from '../globals/dummyRenderTarget'; import { dummyRenderTarget } from '../globals/dummyRenderTarget';
import { gl, glCat } from '../globals/canvas'; import { gl, glCat } from '../globals/canvas';
import { quadGeometry } from '../globals/quadGeometry'; import { quadGeometry } from '../globals/quadGeometry';
import { randomTextureStatic } from '../globals/randomTexture'; import { randomTextureStatic } from '../globals/randomTexture';
@@ -86,7 +86,7 @@ export class SufferTexts extends Entity {
sufferTextsRenderVert, sufferTextsRenderVert,
sufferTextsRenderFrag, sufferTextsRenderFrag,
{ {
initOptions: { geometry: geometryRender, target: dummyRenderTargetFourDrawBuffers }, initOptions: { geometry: geometryRender, target: dummyRenderTarget },
}, },
); );

View File

@@ -5,8 +5,8 @@ import { gl, glCat } from '../../globals/canvas';
import { quadGeometry } from '../../globals/quadGeometry'; import { quadGeometry } from '../../globals/quadGeometry';
export interface QuadOptions extends ComponentOptions { export interface QuadOptions extends ComponentOptions {
material: Material; material?: Material;
target: RenderTarget; target?: RenderTarget;
range?: [ number, number, number, number ]; range?: [ number, number, number, number ];
clear?: Array<number | undefined> | false; clear?: Array<number | undefined> | false;
} }
@@ -15,8 +15,8 @@ export interface QuadOptions extends ComponentOptions {
* Renders a fullscreen quad. * Renders a fullscreen quad.
*/ */
export class Quad extends Component { export class Quad extends Component {
public material: Material; public material?: Material;
public target: RenderTarget; public target?: RenderTarget;
public range: [ number, number, number, number ] = [ -1.0, -1.0, 1.0, 1.0 ]; public range: [ number, number, number, number ] = [ -1.0, -1.0, 1.0, 1.0 ];
public clear: Array<number | undefined> | false = false; public clear: Array<number | undefined> | false = false;
@@ -31,11 +31,17 @@ export class Quad extends Component {
if ( options.clear !== undefined ) { this.clear = options.clear; } if ( options.clear !== undefined ) { this.clear = options.clear; }
} }
protected __updateImpl( event: ComponentUpdateEvent ): void { public drawImmediate( event?: Partial<ComponentUpdateEvent> ): void {
glCat.useProgram( this.material.program ); const { target, material } = this;
this.target.bind(); if ( target == null || material == null ) {
this.material.setBlendMode(); throw process.env.DEV && new Error( 'Quad: You must assign target and material before draw' );
}
glCat.useProgram( material.program );
target.bind();
material.setBlendMode();
gl.enable( gl.DEPTH_TEST ); gl.enable( gl.DEPTH_TEST );
gl.depthMask( true ); gl.depthMask( true );
@@ -44,16 +50,20 @@ export class Quad extends Component {
glCat.clear( ...this.clear ); glCat.clear( ...this.clear );
} }
this.material.setUniforms(); material.setUniforms();
const program = this.material.program; const program = material.program;
program.uniform( 'time', '1f', event.time ); program.uniform( 'time', '1f', event?.time ?? 0.0 );
program.uniform( 'deltaTime', '1f', event.deltaTime ); program.uniform( 'deltaTime', '1f', event?.deltaTime ?? 0.0 );
program.uniform( 'frameCount', '1f', event.frameCount ); program.uniform( 'frameCount', '1f', event?.frameCount ?? 0 );
program.uniform( 'resolution', '2f', this.target.width, this.target.height ); program.uniform( 'resolution', '2f', target.width, target.height );
program.uniform( 'range', '4f', ...this.range ); program.uniform( 'range', '4f', ...this.range );
quadGeometry.draw(); quadGeometry.draw();
} }
protected __updateImpl( event: ComponentUpdateEvent ): void {
this.drawImmediate( event );
}
} }

View File

@@ -43,7 +43,7 @@ void main() {
#ifdef DEFERRED #ifdef DEFERRED
fragPosition = vPosition; fragPosition = vPosition;
fragNormal = vec4( normalize( vNormal ), 1.0 ); fragNormal = vec4( normalize( vNormal ), 1.0 );
fragColor = vec4( vec3( 0.001 ), 1.0 ); fragColor = vec4( vec3( 1.0 ), 1.0 );
fragWTF = vec4( vec3( 0.99, 0.01, 0.0 ), MTL_PBR ); fragWTF = vec4( vec3( 0.99, 0.01, 0.0 ), MTL_PBR );
#endif #endif

View File

@@ -0,0 +1,13 @@
#version 300 es
precision highp float;
in vec2 vUv;
out vec4 fragColor;
uniform sampler2D sampler0;
void main() {
fragColor = step( 0.9, texture( sampler0, vUv ) );
}

View File

@@ -0,0 +1,18 @@
#version 300 es
precision highp float;
in vec2 vUv;
out vec4 fragColor;
uniform sampler2D sampler0;
#pragma glslify: cyclicNoise = require( ./modules/cyclicNoise );
void main() {
vec2 uv = vUv;
uv += 0.001 * sin( 20.0 * cyclicNoise( vec3( 4.0 * uv, 1.0 ) ).xy );
fragColor = texture( sampler0, uv );
}

View File

@@ -0,0 +1,41 @@
#version 300 es
precision highp float;
in float vTime;
in vec2 vUv;
in vec4 vCharParams;
out vec4 fragColor;
uniform sampler2D samplerSpriteSheets[ 8 ];
// this is BAD
vec4 fetchSpriteSheet( int iFont ) {
if ( iFont == 0 ) {
return texture( samplerSpriteSheets[ 0 ], vUv );
} else if ( iFont == 1 ) {
return texture( samplerSpriteSheets[ 1 ], vUv );
} else if ( iFont == 2 ) {
return texture( samplerSpriteSheets[ 2 ], vUv );
} else if ( iFont == 3 ) {
return texture( samplerSpriteSheets[ 3 ], vUv );
} else if ( iFont == 4 ) {
return texture( samplerSpriteSheets[ 4 ], vUv );
} else if ( iFont == 5 ) {
return texture( samplerSpriteSheets[ 5 ], vUv );
} else if ( iFont == 6 ) {
return texture( samplerSpriteSheets[ 6 ], vUv );
} else if ( iFont == 7 ) {
return texture( samplerSpriteSheets[ 7 ], vUv );
}
}
// gl.ONE, gl.ONE
void main() {
if ( vTime < 0.0 ) { discard; }
int font = int( vCharParams.z ) % 8;
fragColor = exp( -17.0 * vTime ) * fetchSpriteSheet( font ) * vec4( 3.0, 0.4, 7.0, 1.0 );
}

View File

@@ -0,0 +1,56 @@
#version 300 es
#define fs(i) (fract(sin((i)*114.514)*1919.810))
#define saturate(i) clamp(i,0.,1.)
// -------------------------------------------------------------------------------------------------
layout (location = 0) in vec2 position;
layout (location = 1) in vec4 charParams;
layout (location = 2) in vec4 charParams2;
out float vTime;
out vec2 vUv;
out vec4 vCharParams;
out vec4 vPosition;
uniform float time;
uniform vec2 resolution;
// == utils ========================================================================================
vec2 yflip( vec2 uv ) {
return vec2( 0.0, 1.0 ) + vec2( 1.0, -1.0 ) * uv;
}
// == main procedure ===============================================================================
void main() {
vCharParams = charParams;
float char = vCharParams.x;
vUv = yflip( 0.5 + 0.499 * position );
vUv = ( vUv + floor( mod( vec2( char / vec2( 1.0, 16.0 ) ), 16.0 ) ) ) / 16.0;
vTime = time - vCharParams.w;
// == compute size ===============================================================================
vPosition = vec4( 0.0, 0.0, 0.0, 1.0 );
vec2 shape = 0.5 * position;
shape.y *= charParams2.y;
vec2 offset = ( 0.6 - 0.2 * exp( -5.0 * vTime ) ) * vec2( vCharParams.y, 0.0 );
vPosition.xy += ( offset + shape ) * min( 500.0 / charParams2.x, 1.0 );
vPosition.xy += 1.0
* ( fs( vCharParams.z + vec2( 2.66, 1.79 ) ) * 2.0 - 1.0 )
* pow( fs( vCharParams.z + 7.8 ), 2.0 );
// == send the vertex position ===================================================================
vPosition = vPosition;
vec4 outPos = vPosition;
outPos.x *= resolution.y / resolution.x;
gl_Position = outPos;
vPosition.w = outPos.z / outPos.w;
}

View File

@@ -18,6 +18,7 @@ in vec2 vUv;
out vec4 fragColor; out vec4 fragColor;
uniform float time; uniform float time;
uniform float mixInvert;
uniform vec2 resolution; uniform vec2 resolution;
uniform vec4 colorLift; uniform vec4 colorLift;
uniform vec4 colorGamma; uniform vec4 colorGamma;
@@ -86,6 +87,7 @@ void main() {
vec3 col = tex.xyz; vec3 col = tex.xyz;
vec4 seed = texture( samplerRandom, uv ); vec4 seed = texture( samplerRandom, uv );
col = mix( col, 1.0 - 5.0 * col, mixInvert );
prng( seed ); prng( seed );
prng( seed ); prng( seed );
col = aces( max( 2.0 * col, 0.0 ) ) / aces( vec3( 11.2 ) ); col = aces( max( 2.0 * col, 0.0 ) ) / aces( vec3( 11.2 ) );

View File

@@ -288,9 +288,12 @@ void main() {
// color = 0.5 + 0.5 * isect.normal; // color = 0.5 + 0.5 * isect.normal;
// color = vec3( calcDepth( tex0.xyz ) ); // color = vec3( calcDepth( tex0.xyz ) );
// color = vec3( 0.5, 0.9, 0.6 ) * ( 1.0 - texture( samplerAo, isect.screenUv ).xyz ); // color = vec3( 0.5, 0.2, 0.9 ) * ( 1.0 - texture( samplerAo, isect.screenUv ).xyz );
// color = vec3( 0.5, 0.9, 0.6 ) * ( texture( samplerAo, isect.screenUv ).xyz ); // color = mix(
// xfdA = shadeGradient( isect ); // color,
// vec3( 0.96 ) * smoothstep( 0.9, 0.1, texture( samplerAo, isect.screenUv ).xyz ),
// 1.0
// );
fragColor = vec4( color, 1.0 ); fragColor = vec4( color, 1.0 );
// fragColor.xyz *= smoothstep( 1.0, 0.7, calcDepth( tex0.xyz ) ); // fragColor.xyz *= smoothstep( 1.0, 0.7, calcDepth( tex0.xyz ) );

30
src/utils/calcCharPos.ts Normal file
View File

@@ -0,0 +1,30 @@
const canvas = document.createElement( 'canvas' );
const context = canvas.getContext( '2d' )!;
export function calcCharPos(
text: string,
font: string,
): {
totalWidth: number;
chars: {
char: string;
x: number;
}[];
} {
let totalWidth = 0;
let currentText = '';
context.font = font;
const chars = text.split( '' ).map( ( char ) => {
const charWidth = context.measureText( char ).width;
currentText += char;
totalWidth = context.measureText( currentText ).width;
const x = totalWidth - 0.5 * charWidth;
return { x, char };
} );
return { totalWidth, chars };
}

View File

@@ -0,0 +1,42 @@
// yoinked from https://github.com/mapbox/tiny-sdf (BSD 2-Clause)
import { GLCatTexture } from '@fms-cat/glcat-ts';
import { glCat } from '../globals/canvas';
const SPRITE_SIZE = 128;
export const SPRITE_SHEET_SIZE = 16 * SPRITE_SIZE;
const CHARS = [ ...new Array( 256 ).keys() ].map( ( i ) => String.fromCharCode( i ) );
export function createFontSpriteSheet( { font, baseline }: {
font: string;
/**
* 0.8 is recommended
*/
baseline?: number;
} ): GLCatTexture {
const texture = glCat.createTexture();
const canvas = document.createElement( 'canvas' );
canvas.width = SPRITE_SHEET_SIZE;
canvas.height = SPRITE_SHEET_SIZE;
const context = canvas.getContext( '2d' )!;
context.textAlign = 'center';
context.fillStyle = '#fff';
context.font = font;
for ( let i = 0; i < 256; i ++ ) {
const char = CHARS[ i ];
const x = ( ( i % 16 ) + 0.5 ) * SPRITE_SIZE;
const y = ( Math.floor( i / 16 ) + ( baseline ?? 0.7 ) ) * SPRITE_SIZE;
context.fillText( char, x, y );
}
texture.setTexture( canvas );
return texture;
}