mirror of
https://github.com/FMS-Cat/condition.git
synced 2025-08-14 09:43:58 +02:00
help
This commit is contained in:
305
src/Music.ts
305
src/Music.ts
@@ -1,305 +0,0 @@
|
|||||||
import { Channel } from '@fms-cat/automaton';
|
|
||||||
import { GLCat, GLCatBuffer, GLCatProgram, GLCatTexture, GLCatTransformFeedback } from '@fms-cat/glcat-ts';
|
|
||||||
import { MUSIC_AUTOMATON_TEXTURE_HEIGHT, MUSIC_BPM, MUSIC_BUFFER_LENGTH } from './config';
|
|
||||||
import { Pool } from './utils/Pool';
|
|
||||||
import { automaton } from './globals/automaton';
|
|
||||||
import { gl, glCat } from './globals/canvas';
|
|
||||||
import { injectCodeToShader } from './utils/injectCodeToShader';
|
|
||||||
import { randomTextureStatic } from './globals/randomTexture';
|
|
||||||
import musicVert from './shaders/music.vert';
|
|
||||||
import samplesOpus from './samples.opus';
|
|
||||||
import type { AutomatonWithGUI } from '@fms-cat/automaton-with-gui';
|
|
||||||
|
|
||||||
const discardFrag = '#version 300 es\nvoid main(){discard;}';
|
|
||||||
|
|
||||||
export class Music {
|
|
||||||
public isPlaying: boolean;
|
|
||||||
public time: number;
|
|
||||||
public deltaTime: number;
|
|
||||||
public audio: AudioContext;
|
|
||||||
|
|
||||||
private __program: GLCatProgram;
|
|
||||||
private __bufferOff: GLCatBuffer;
|
|
||||||
private __bufferTransformFeedbacks: [
|
|
||||||
GLCatBuffer,
|
|
||||||
GLCatBuffer
|
|
||||||
];
|
|
||||||
private __transformFeedback: GLCatTransformFeedback;
|
|
||||||
private __prevAudioTime: number;
|
|
||||||
private __bufferPool: Pool<AudioBuffer>;
|
|
||||||
private __prevBufferSource: AudioBufferSourceNode | null = null;
|
|
||||||
private __samples?: GLCatTexture;
|
|
||||||
private __automatonChannelList: Channel[];
|
|
||||||
private __automatonDefineString: string;
|
|
||||||
private __arrayAutomaton: Float32Array;
|
|
||||||
private __textureAutomaton: GLCatTexture;
|
|
||||||
|
|
||||||
public constructor( glCat: GLCat, audio: AudioContext ) {
|
|
||||||
this.audio = audio;
|
|
||||||
|
|
||||||
// == yoinked from wavenerd-deck ===============================================================
|
|
||||||
const bufferOffArray = new Array( MUSIC_BUFFER_LENGTH )
|
|
||||||
.fill( 0 )
|
|
||||||
.map( ( _, i ) => i );
|
|
||||||
this.__bufferOff = glCat.createBuffer();
|
|
||||||
this.__bufferOff.setVertexbuffer( new Float32Array( bufferOffArray ) );
|
|
||||||
|
|
||||||
this.__bufferTransformFeedbacks = [
|
|
||||||
glCat.createBuffer(),
|
|
||||||
glCat.createBuffer(),
|
|
||||||
];
|
|
||||||
this.__transformFeedback = glCat.createTransformFeedback();
|
|
||||||
|
|
||||||
this.__bufferTransformFeedbacks[ 0 ].setVertexbuffer(
|
|
||||||
MUSIC_BUFFER_LENGTH * 4,
|
|
||||||
gl.STREAM_READ
|
|
||||||
);
|
|
||||||
|
|
||||||
this.__bufferTransformFeedbacks[ 1 ].setVertexbuffer(
|
|
||||||
MUSIC_BUFFER_LENGTH * 4,
|
|
||||||
gl.STREAM_READ
|
|
||||||
);
|
|
||||||
|
|
||||||
this.__transformFeedback.bindBuffer( 0, this.__bufferTransformFeedbacks[ 0 ] );
|
|
||||||
this.__transformFeedback.bindBuffer( 1, this.__bufferTransformFeedbacks[ 1 ] );
|
|
||||||
|
|
||||||
// == automaton? ===============================================================================
|
|
||||||
this.__automatonChannelList = [];
|
|
||||||
this.__automatonDefineString = '';
|
|
||||||
|
|
||||||
this.__updateAutomatonChannelList();
|
|
||||||
|
|
||||||
this.__arrayAutomaton = new Float32Array(
|
|
||||||
MUSIC_BUFFER_LENGTH * MUSIC_AUTOMATON_TEXTURE_HEIGHT
|
|
||||||
);
|
|
||||||
|
|
||||||
this.__textureAutomaton = glCat.createTexture();
|
|
||||||
this.__textureAutomaton.textureFilter( gl.NEAREST );
|
|
||||||
|
|
||||||
// == program ==================================================================================
|
|
||||||
this.__program = glCat.lazyProgram(
|
|
||||||
injectCodeToShader( musicVert, this.__automatonDefineString ),
|
|
||||||
discardFrag,
|
|
||||||
{ transformFeedbackVaryings: [ 'outL', 'outR' ] },
|
|
||||||
);
|
|
||||||
|
|
||||||
// == audio ====================================================================================
|
|
||||||
this.__prevAudioTime = 0;
|
|
||||||
|
|
||||||
this.__bufferPool = new Pool( [
|
|
||||||
audio.createBuffer( 2, MUSIC_BUFFER_LENGTH, audio.sampleRate ),
|
|
||||||
audio.createBuffer( 2, MUSIC_BUFFER_LENGTH, audio.sampleRate ),
|
|
||||||
] );
|
|
||||||
|
|
||||||
this.__loadSamples();
|
|
||||||
|
|
||||||
// == I think these are gonna be required ======================================================
|
|
||||||
this.isPlaying = false;
|
|
||||||
this.time = 0.0;
|
|
||||||
this.deltaTime = 0.0;
|
|
||||||
|
|
||||||
// == hot hot hot hot hot ======================================================================
|
|
||||||
if ( process.env.DEV && module.hot ) {
|
|
||||||
const recompileShader = async (): Promise<void> => {
|
|
||||||
const program = await glCat.lazyProgramAsync(
|
|
||||||
injectCodeToShader( musicVert, this.__automatonDefineString ),
|
|
||||||
discardFrag,
|
|
||||||
{ transformFeedbackVaryings: [ 'outL', 'outR' ] },
|
|
||||||
).catch( ( error: any ) => {
|
|
||||||
console.error( error );
|
|
||||||
return null;
|
|
||||||
} );
|
|
||||||
|
|
||||||
if ( program ) {
|
|
||||||
this.__program.dispose( true );
|
|
||||||
this.__program = program;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.hot.accept(
|
|
||||||
[ './shaders/music.vert' ],
|
|
||||||
() => {
|
|
||||||
recompileShader();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
module.hot.accept(
|
|
||||||
[ './automaton.json' ],
|
|
||||||
() => {
|
|
||||||
this.__updateAutomatonChannelList();
|
|
||||||
recompileShader();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
( automaton as AutomatonWithGUI ).on( 'createChannel', ( { name } ) => {
|
|
||||||
if ( name.startsWith( 'Music/' ) ) {
|
|
||||||
this.__updateAutomatonChannelList();
|
|
||||||
recompileShader();
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
( automaton as AutomatonWithGUI ).on( 'removeChannel', ( { name } ) => {
|
|
||||||
if ( name.startsWith( 'Music/' ) ) {
|
|
||||||
this.__updateAutomatonChannelList();
|
|
||||||
recompileShader();
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public update(): void {
|
|
||||||
const { audio, isPlaying } = this;
|
|
||||||
|
|
||||||
const genTime = audio.currentTime;
|
|
||||||
|
|
||||||
if ( isPlaying ) {
|
|
||||||
this.deltaTime = genTime - this.__prevAudioTime;
|
|
||||||
this.time += this.deltaTime;
|
|
||||||
|
|
||||||
const buffer = this.__bufferPool.next();
|
|
||||||
|
|
||||||
if ( this.__program ) {
|
|
||||||
this.__updateAutomatonTexture();
|
|
||||||
this.__prepareBuffer( buffer );
|
|
||||||
}
|
|
||||||
|
|
||||||
const bufferSource = audio.createBufferSource();
|
|
||||||
bufferSource.buffer = buffer;
|
|
||||||
bufferSource.connect( audio.destination );
|
|
||||||
|
|
||||||
this.__prevBufferSource?.stop( audio.currentTime );
|
|
||||||
bufferSource.start( audio.currentTime, audio.currentTime - genTime );
|
|
||||||
this.__prevBufferSource = bufferSource;
|
|
||||||
} else {
|
|
||||||
this.deltaTime = 0.0;
|
|
||||||
|
|
||||||
this.__prevBufferSource?.stop( audio.currentTime );
|
|
||||||
this.__prevBufferSource = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.__prevAudioTime = genTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async __loadSamples(): Promise<void> {
|
|
||||||
const inputBuffer = await fetch( samplesOpus ).then( ( res ) => res.arrayBuffer() );
|
|
||||||
const audioBuffer = await this.audio.decodeAudioData( inputBuffer );
|
|
||||||
|
|
||||||
const buffer = new Float32Array( 96000 );
|
|
||||||
|
|
||||||
const data = audioBuffer.getChannelData( 0 );
|
|
||||||
for ( let i = 0; i < audioBuffer.length; i ++ ) {
|
|
||||||
buffer[ i ] = data[ i ];
|
|
||||||
}
|
|
||||||
|
|
||||||
const texture = glCat.createTexture()!;
|
|
||||||
texture.setTextureFromArray(
|
|
||||||
6000,
|
|
||||||
16,
|
|
||||||
buffer,
|
|
||||||
{
|
|
||||||
internalformat: gl.R32F,
|
|
||||||
format: gl.RED,
|
|
||||||
type: gl.FLOAT,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
texture.textureFilter( gl.LINEAR );
|
|
||||||
|
|
||||||
this.__samples = texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
private __updateAutomatonChannelList(): void {
|
|
||||||
this.__automatonChannelList = [];
|
|
||||||
this.__automatonDefineString = '';
|
|
||||||
|
|
||||||
for ( const [ channelName, channel ] of automaton.mapNameToChannel.entries() ) {
|
|
||||||
if ( channelName.startsWith( 'Music/' ) ) {
|
|
||||||
const key = channelName.substring( 6 );
|
|
||||||
const index = this.__automatonChannelList.length;
|
|
||||||
const y = ( index + 0.5 ) / MUSIC_AUTOMATON_TEXTURE_HEIGHT;
|
|
||||||
this.__automatonDefineString += `const float AUTO_${key}=${y};`;
|
|
||||||
this.__automatonChannelList.push( channel );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private __updateAutomatonTexture(): void {
|
|
||||||
for ( const [ iChannel, channel ] of this.__automatonChannelList.entries() ) {
|
|
||||||
for ( let iSample = 0; iSample < MUSIC_BUFFER_LENGTH; iSample ++ ) {
|
|
||||||
const t = this.time + iSample / this.audio.sampleRate;
|
|
||||||
this.__arrayAutomaton[ MUSIC_BUFFER_LENGTH * iChannel + iSample ] = channel.getValue( t );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.__textureAutomaton.setTextureFromArray(
|
|
||||||
MUSIC_BUFFER_LENGTH,
|
|
||||||
MUSIC_AUTOMATON_TEXTURE_HEIGHT,
|
|
||||||
this.__arrayAutomaton,
|
|
||||||
{
|
|
||||||
internalformat: gl.R32F,
|
|
||||||
format: gl.RED,
|
|
||||||
type: gl.FLOAT,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private __prepareBuffer( buffer: AudioBuffer ): void {
|
|
||||||
const { time } = this;
|
|
||||||
const program = this.__program;
|
|
||||||
|
|
||||||
const beatLength = 60.0 / MUSIC_BPM;
|
|
||||||
const barLength = 240.0 / MUSIC_BPM;
|
|
||||||
const sixteenBarLength = 3840.0 / MUSIC_BPM;
|
|
||||||
|
|
||||||
program.attribute( 'off', this.__bufferOff, 1 );
|
|
||||||
program.uniform( 'bpm', '1f', MUSIC_BPM );
|
|
||||||
program.uniform( 'bufferLength', '1f', MUSIC_BUFFER_LENGTH );
|
|
||||||
program.uniform( '_deltaSample', '1f', 1.0 / this.audio.sampleRate );
|
|
||||||
program.uniform(
|
|
||||||
'timeLength',
|
|
||||||
'4f',
|
|
||||||
beatLength,
|
|
||||||
barLength,
|
|
||||||
sixteenBarLength,
|
|
||||||
1E16
|
|
||||||
);
|
|
||||||
program.uniform(
|
|
||||||
'_timeHead',
|
|
||||||
'4f',
|
|
||||||
time % beatLength,
|
|
||||||
time % barLength,
|
|
||||||
time % sixteenBarLength,
|
|
||||||
time,
|
|
||||||
);
|
|
||||||
|
|
||||||
program.uniformTexture( 'samplerRandom', randomTextureStatic.texture );
|
|
||||||
program.uniformTexture( 'samplerAutomaton', this.__textureAutomaton );
|
|
||||||
|
|
||||||
if ( this.__samples ) {
|
|
||||||
program.uniformTexture( 'samplerSamples', this.__samples );
|
|
||||||
}
|
|
||||||
|
|
||||||
glCat.useProgram( program, () => {
|
|
||||||
glCat.bindTransformFeedback( this.__transformFeedback, () => {
|
|
||||||
gl.enable( gl.RASTERIZER_DISCARD );
|
|
||||||
gl.beginTransformFeedback( gl.POINTS );
|
|
||||||
gl.drawArrays( gl.POINTS, 0, MUSIC_BUFFER_LENGTH );
|
|
||||||
gl.endTransformFeedback();
|
|
||||||
gl.disable( gl.RASTERIZER_DISCARD );
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
|
|
||||||
gl.flush();
|
|
||||||
|
|
||||||
[ 0, 1 ].map( ( i ) => {
|
|
||||||
glCat.bindVertexBuffer( this.__bufferTransformFeedbacks[ i ], () => {
|
|
||||||
gl.getBufferSubData(
|
|
||||||
gl.ARRAY_BUFFER,
|
|
||||||
0,
|
|
||||||
buffer.getChannelData( i ),
|
|
||||||
0,
|
|
||||||
MUSIC_BUFFER_LENGTH
|
|
||||||
);
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
@@ -6,5 +6,7 @@ export const
|
|||||||
RESOLUTION = [ 1280, 720 ],
|
RESOLUTION = [ 1280, 720 ],
|
||||||
MUSIC_BPM = 180,
|
MUSIC_BPM = 180,
|
||||||
START_POSITION = 36,
|
START_POSITION = 36,
|
||||||
MUSIC_BUFFER_LENGTH = 4096,
|
MUSIC_LENGTH = 213,
|
||||||
MUSIC_AUTOMATON_TEXTURE_HEIGHT = 16;
|
MUSIC_AUTOMATON_TEXTURE_HEIGHT = 16,
|
||||||
|
IBLLUT_ITER = 400,
|
||||||
|
IBLLUT_SIZE = 256;
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { BufferRenderTarget } from '../heck/BufferRenderTarget';
|
import { BufferRenderTarget } from '../heck/BufferRenderTarget';
|
||||||
import { Entity } from '../heck/Entity';
|
import { Entity } from '../heck/Entity';
|
||||||
import { GLCatTexture } from '@fms-cat/glcat-ts';
|
import { GLCatTexture } from '@fms-cat/glcat-ts';
|
||||||
|
import { IBLLUT_ITER, IBLLUT_SIZE } from '../config';
|
||||||
import { Lambda } from '../heck/components/Lambda';
|
import { Lambda } from '../heck/components/Lambda';
|
||||||
import { Material } from '../heck/Material';
|
import { Material } from '../heck/Material';
|
||||||
import { Quad } from '../heck/components/Quad';
|
import { Quad } from '../heck/components/Quad';
|
||||||
@@ -11,8 +12,6 @@ import { vdc } from '../utils/vdc';
|
|||||||
import iblLutFrag from '../shaders/ibl-lut.frag';
|
import iblLutFrag from '../shaders/ibl-lut.frag';
|
||||||
import quadVert from '../shaders/quad.vert';
|
import quadVert from '../shaders/quad.vert';
|
||||||
|
|
||||||
const IBL_SIZE = 256;
|
|
||||||
|
|
||||||
export class IBLLUT {
|
export class IBLLUT {
|
||||||
public entity: Entity;
|
public entity: Entity;
|
||||||
|
|
||||||
@@ -29,13 +28,13 @@ export class IBLLUT {
|
|||||||
// -- swap -------------------------------------------------------------------------------------
|
// -- swap -------------------------------------------------------------------------------------
|
||||||
this.swap = new Swap(
|
this.swap = new Swap(
|
||||||
new BufferRenderTarget( {
|
new BufferRenderTarget( {
|
||||||
width: IBL_SIZE,
|
width: IBLLUT_SIZE,
|
||||||
height: IBL_SIZE,
|
height: IBLLUT_SIZE,
|
||||||
name: process.env.DEV && 'IBLLUT/swap0',
|
name: process.env.DEV && 'IBLLUT/swap0',
|
||||||
} ),
|
} ),
|
||||||
new BufferRenderTarget( {
|
new BufferRenderTarget( {
|
||||||
width: IBL_SIZE,
|
width: IBLLUT_SIZE,
|
||||||
height: IBL_SIZE,
|
height: IBLLUT_SIZE,
|
||||||
name: process.env.DEV && 'IBLLUT/swap1',
|
name: process.env.DEV && 'IBLLUT/swap1',
|
||||||
} ),
|
} ),
|
||||||
);
|
);
|
||||||
@@ -64,7 +63,7 @@ export class IBLLUT {
|
|||||||
samples ++;
|
samples ++;
|
||||||
this.swap.swap();
|
this.swap.swap();
|
||||||
|
|
||||||
if ( samples > 1024 ) {
|
if ( samples > IBLLUT_ITER ) {
|
||||||
this.entity.active = false;
|
this.entity.active = false;
|
||||||
} else {
|
} else {
|
||||||
material.addUniform( 'samples', '1f', samples );
|
material.addUniform( 'samples', '1f', samples );
|
||||||
|
@@ -63,12 +63,6 @@ export class LightEntity extends Entity {
|
|||||||
this.camera.clear = [ 1.0, 1.0, 1.0, 1.0 ];
|
this.camera.clear = [ 1.0, 1.0, 1.0, 1.0 ];
|
||||||
this.components.push( this.camera );
|
this.components.push( this.camera );
|
||||||
|
|
||||||
this.shadowMap = new BufferRenderTarget( {
|
|
||||||
width: options.shadowMapWidth ?? 1024,
|
|
||||||
height: options.shadowMapHeight ?? 1024,
|
|
||||||
name: process.env.DEV && `${ options.namePrefix }/shadowMap`,
|
|
||||||
} );
|
|
||||||
|
|
||||||
swap.swap();
|
swap.swap();
|
||||||
|
|
||||||
// -- blur -------------------------------------------------------------------------------------
|
// -- blur -------------------------------------------------------------------------------------
|
||||||
@@ -82,12 +76,15 @@ export class LightEntity extends Entity {
|
|||||||
material.addUniformTexture( 'sampler0', swap.i.texture );
|
material.addUniformTexture( 'sampler0', swap.i.texture );
|
||||||
|
|
||||||
this.components.push( new Quad( {
|
this.components.push( new Quad( {
|
||||||
target: i === 0 ? swap.o : this.shadowMap,
|
target: swap.o,
|
||||||
material,
|
material,
|
||||||
name: process.env.DEV && `${ options.namePrefix }/quadShadowBlur${ i }`,
|
name: process.env.DEV && `${ options.namePrefix }/quadShadowBlur${ i }`,
|
||||||
} ) );
|
} ) );
|
||||||
|
|
||||||
swap.swap();
|
swap.swap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- this is the shadow map -------------------------------------------------------------------
|
||||||
|
this.shadowMap = swap.i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
import { Automaton } from '@fms-cat/automaton';
|
import { Automaton } from '@fms-cat/automaton';
|
||||||
import { AutomatonWithGUI } from '@fms-cat/automaton-with-gui';
|
import { AutomatonWithGUI } from '@fms-cat/automaton-with-gui';
|
||||||
|
import { Music } from '../music/Music';
|
||||||
import { fxDefinitions } from '../automaton-fxs/fxDefinitions';
|
import { fxDefinitions } from '../automaton-fxs/fxDefinitions';
|
||||||
import { getDivAutomaton } from './dom';
|
import { getDivAutomaton } from './dom';
|
||||||
import automatonData from '../automaton.json';
|
import automatonData from '../automaton.json';
|
||||||
import type { Music } from '../Music';
|
|
||||||
|
|
||||||
export const automaton = ( () => {
|
export const automaton = ( () => {
|
||||||
if ( process.env.DEV ) {
|
if ( process.env.DEV ) {
|
||||||
@@ -13,7 +13,7 @@ export const automaton = ( () => {
|
|||||||
automatonData,
|
automatonData,
|
||||||
{
|
{
|
||||||
gui: getDivAutomaton(),
|
gui: getDivAutomaton(),
|
||||||
isPlaying: true,
|
isPlaying: false,
|
||||||
fxDefinitions,
|
fxDefinitions,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
import { Music } from '../Music';
|
import { Music } from '../music/Music';
|
||||||
|
import { MusicOffline } from '../music/MusicOffline';
|
||||||
|
import { MusicRealtime } from '../music/MusicRealtime';
|
||||||
import { automatonSetupMusic } from './automaton';
|
import { automatonSetupMusic } from './automaton';
|
||||||
import { glCat } from './canvas';
|
|
||||||
|
|
||||||
export const audio = new AudioContext();
|
export const audio = new AudioContext();
|
||||||
export const music = new Music( glCat, audio );
|
// export const music: Music = new MusicRealtime();
|
||||||
|
export const music: Music = new MusicOffline();
|
||||||
automatonSetupMusic( music );
|
automatonSetupMusic( music );
|
||||||
|
35
src/main.ts
35
src/main.ts
@@ -23,26 +23,12 @@ if ( process.env.DEV ) {
|
|||||||
canvas.style.margin = 'auto';
|
canvas.style.margin = 'auto';
|
||||||
canvas.style.maxWidth = '100%';
|
canvas.style.maxWidth = '100%';
|
||||||
canvas.style.maxHeight = '100%';
|
canvas.style.maxHeight = '100%';
|
||||||
|
|
||||||
music.isPlaying = true;
|
|
||||||
music.time = START_POSITION;
|
|
||||||
} else {
|
} else {
|
||||||
canvas.style.position = 'fixed';
|
canvas.style.position = 'fixed';
|
||||||
canvas.style.left = '0';
|
canvas.style.left = '0';
|
||||||
canvas.style.top = '0';
|
canvas.style.top = '0';
|
||||||
document.body.style.width = canvas.style.width = '100%';
|
document.body.style.width = canvas.style.width = '100%';
|
||||||
document.body.style.height = canvas.style.height = '100%';
|
document.body.style.height = canvas.style.height = '100%';
|
||||||
|
|
||||||
const button = document.createElement( 'a' );
|
|
||||||
document.body.appendChild( button );
|
|
||||||
button.innerHTML = 'click me!';
|
|
||||||
|
|
||||||
button.onclick = () => {
|
|
||||||
document.body.appendChild( canvas );
|
|
||||||
music.isPlaying = true;
|
|
||||||
music.time = START_POSITION;
|
|
||||||
document.body.requestFullscreen();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- keyboards ------------------------------------------------------------------------------------
|
// -- keyboards ------------------------------------------------------------------------------------
|
||||||
@@ -85,3 +71,24 @@ if ( process.env.DEV ) {
|
|||||||
console.info( Component.nameMap );
|
console.info( Component.nameMap );
|
||||||
console.info( BufferRenderTarget.nameMap );
|
console.info( BufferRenderTarget.nameMap );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- let's gooooo ---------------------------------------------------------------------------------
|
||||||
|
async function load(): Promise<void> {
|
||||||
|
await music.prepare();
|
||||||
|
|
||||||
|
if ( process.env.DEV ) {
|
||||||
|
music.time = START_POSITION;
|
||||||
|
( automaton as AutomatonWithGUI ).play();
|
||||||
|
} else {
|
||||||
|
const button = document.createElement( 'a' );
|
||||||
|
document.body.appendChild( button );
|
||||||
|
button.innerHTML = 'click me!';
|
||||||
|
|
||||||
|
button.onclick = () => {
|
||||||
|
document.body.appendChild( canvas );
|
||||||
|
music.isPlaying = true;
|
||||||
|
document.body.requestFullscreen();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
load();
|
||||||
|
99
src/music/AutomatonManager.ts
Normal file
99
src/music/AutomatonManager.ts
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import { Channel } from '@fms-cat/automaton';
|
||||||
|
import { GLCatTexture } from '@fms-cat/glcat-ts';
|
||||||
|
import { MUSIC_AUTOMATON_TEXTURE_HEIGHT } from '../config';
|
||||||
|
import { Music } from './Music';
|
||||||
|
import { audio } from '../globals/music';
|
||||||
|
import { automaton } from '../globals/automaton';
|
||||||
|
import { gl, glCat } from '../globals/canvas';
|
||||||
|
import type { AutomatonWithGUI } from '@fms-cat/automaton-with-gui';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject automaton params into music...
|
||||||
|
*/
|
||||||
|
export class AutomatonManager {
|
||||||
|
public texture: GLCatTexture;
|
||||||
|
public defineString: string;
|
||||||
|
private __music: Music;
|
||||||
|
private __ChannelList: Channel[];
|
||||||
|
private __array: Float32Array;
|
||||||
|
|
||||||
|
public constructor( music: Music ) {
|
||||||
|
this.__music = music;
|
||||||
|
|
||||||
|
this.defineString = '';
|
||||||
|
this.__ChannelList = [];
|
||||||
|
|
||||||
|
this.__updateAutomatonChannelList();
|
||||||
|
|
||||||
|
this.__array = new Float32Array(
|
||||||
|
music.bufferLength * MUSIC_AUTOMATON_TEXTURE_HEIGHT
|
||||||
|
);
|
||||||
|
|
||||||
|
this.texture = glCat.createTexture();
|
||||||
|
this.texture.textureFilter( gl.NEAREST );
|
||||||
|
|
||||||
|
// == hot hot hot hot hot ======================================================================
|
||||||
|
if ( process.env.DEV ) {
|
||||||
|
if ( module.hot ) {
|
||||||
|
module.hot.accept(
|
||||||
|
[ '../automaton.json' ],
|
||||||
|
() => {
|
||||||
|
this.__updateAutomatonChannelList();
|
||||||
|
music.recompile?.();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
( automaton as AutomatonWithGUI ).on( 'createChannel', ( { name } ) => {
|
||||||
|
if ( name.startsWith( 'Music/' ) ) {
|
||||||
|
this.__updateAutomatonChannelList();
|
||||||
|
music.recompile?.();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
( automaton as AutomatonWithGUI ).on( 'removeChannel', ( { name } ) => {
|
||||||
|
if ( name.startsWith( 'Music/' ) ) {
|
||||||
|
this.__updateAutomatonChannelList();
|
||||||
|
music.recompile?.();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public update( time: number ): void {
|
||||||
|
const bufferLength = this.__music.bufferLength;
|
||||||
|
|
||||||
|
for ( const [ iChannel, channel ] of this.__ChannelList.entries() ) {
|
||||||
|
for ( let iSample = 0; iSample < bufferLength; iSample ++ ) {
|
||||||
|
const t = time + iSample / audio.sampleRate;
|
||||||
|
this.__array[ bufferLength * iChannel + iSample ] = channel.getValue( t );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.texture.setTextureFromArray(
|
||||||
|
bufferLength,
|
||||||
|
MUSIC_AUTOMATON_TEXTURE_HEIGHT,
|
||||||
|
this.__array,
|
||||||
|
{
|
||||||
|
internalformat: gl.R32F,
|
||||||
|
format: gl.RED,
|
||||||
|
type: gl.FLOAT,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private __updateAutomatonChannelList(): void {
|
||||||
|
this.__ChannelList = [];
|
||||||
|
this.defineString = '';
|
||||||
|
|
||||||
|
for ( const [ channelName, channel ] of automaton.mapNameToChannel.entries() ) {
|
||||||
|
if ( channelName.startsWith( 'Music/' ) ) {
|
||||||
|
const key = channelName.substring( 6 );
|
||||||
|
const index = this.__ChannelList.length;
|
||||||
|
const y = ( index + 0.5 ) / MUSIC_AUTOMATON_TEXTURE_HEIGHT;
|
||||||
|
this.defineString += `const float AUTO_${key}=${y};`;
|
||||||
|
this.__ChannelList.push( channel );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
178
src/music/Music.ts
Normal file
178
src/music/Music.ts
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
import { AutomatonManager } from './AutomatonManager';
|
||||||
|
import { GLCatBuffer, GLCatProgram, GLCatTransformFeedback } from '@fms-cat/glcat-ts';
|
||||||
|
import { MUSIC_BPM } from '../config';
|
||||||
|
import { SamplesManager } from './SamplesManager';
|
||||||
|
import { audio } from '../globals/music';
|
||||||
|
import { gl, glCat } from '../globals/canvas';
|
||||||
|
import { injectCodeToShader } from '../utils/injectCodeToShader';
|
||||||
|
import { randomTextureStatic } from '../globals/randomTexture';
|
||||||
|
import musicVert from './music.vert';
|
||||||
|
|
||||||
|
const discardFrag = '#version 300 es\nvoid main(){discard;}';
|
||||||
|
|
||||||
|
export abstract class Music {
|
||||||
|
public isPlaying: boolean;
|
||||||
|
public time: number;
|
||||||
|
public deltaTime: number;
|
||||||
|
public readonly bufferLength: number;
|
||||||
|
|
||||||
|
protected __program: GLCatProgram;
|
||||||
|
protected __samplesManager: SamplesManager;
|
||||||
|
protected __automatonManager: AutomatonManager;
|
||||||
|
|
||||||
|
private __bufferOff: GLCatBuffer;
|
||||||
|
private __bufferTransformFeedbacks: [
|
||||||
|
GLCatBuffer,
|
||||||
|
GLCatBuffer,
|
||||||
|
];
|
||||||
|
private __transformFeedback: GLCatTransformFeedback;
|
||||||
|
private __prevAudioTime: number;
|
||||||
|
|
||||||
|
public constructor( bufferLength: number ) {
|
||||||
|
this.isPlaying = false;
|
||||||
|
this.time = 0.0;
|
||||||
|
this.deltaTime = 0.0;
|
||||||
|
this.__prevAudioTime = 0.0;
|
||||||
|
this.bufferLength = bufferLength;
|
||||||
|
|
||||||
|
// == spicy boys ===============================================================================
|
||||||
|
this.__samplesManager = new SamplesManager( this );
|
||||||
|
this.__automatonManager = new AutomatonManager( this );
|
||||||
|
|
||||||
|
// == gl =======================================================================================
|
||||||
|
const bufferOffArray = new Array( bufferLength )
|
||||||
|
.fill( 0 )
|
||||||
|
.map( ( _, i ) => i );
|
||||||
|
this.__bufferOff = glCat.createBuffer();
|
||||||
|
this.__bufferOff.setVertexbuffer( new Float32Array( bufferOffArray ) );
|
||||||
|
|
||||||
|
this.__bufferTransformFeedbacks = [
|
||||||
|
glCat.createBuffer(),
|
||||||
|
glCat.createBuffer(),
|
||||||
|
];
|
||||||
|
this.__transformFeedback = glCat.createTransformFeedback();
|
||||||
|
|
||||||
|
this.__bufferTransformFeedbacks[ 0 ].setVertexbuffer(
|
||||||
|
bufferLength * 4,
|
||||||
|
gl.STREAM_READ
|
||||||
|
);
|
||||||
|
|
||||||
|
this.__bufferTransformFeedbacks[ 1 ].setVertexbuffer(
|
||||||
|
bufferLength * 4,
|
||||||
|
gl.STREAM_READ
|
||||||
|
);
|
||||||
|
|
||||||
|
this.__transformFeedback.bindBuffer( 0, this.__bufferTransformFeedbacks[ 0 ] );
|
||||||
|
this.__transformFeedback.bindBuffer( 1, this.__bufferTransformFeedbacks[ 1 ] );
|
||||||
|
|
||||||
|
this.__program = glCat.lazyProgram(
|
||||||
|
injectCodeToShader( musicVert, this.__automatonManager.defineString ),
|
||||||
|
discardFrag,
|
||||||
|
{ transformFeedbackVaryings: [ 'outL', 'outR' ] },
|
||||||
|
);
|
||||||
|
|
||||||
|
// == hot hot hot hot hot ======================================================================
|
||||||
|
if ( process.env.DEV && module.hot ) {
|
||||||
|
module.hot.accept(
|
||||||
|
[ './music.vert' ],
|
||||||
|
() => {
|
||||||
|
this.recompile();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async prepare(): Promise<void> {
|
||||||
|
await this.__samplesManager.loadSamples();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async recompile(): Promise<void> {
|
||||||
|
if ( process.env.DEV ) {
|
||||||
|
const program = await glCat.lazyProgramAsync(
|
||||||
|
injectCodeToShader( musicVert, this.__automatonManager.defineString ),
|
||||||
|
discardFrag,
|
||||||
|
{ transformFeedbackVaryings: [ 'outL', 'outR' ] },
|
||||||
|
).catch( ( error: any ) => {
|
||||||
|
console.error( error );
|
||||||
|
return null;
|
||||||
|
} );
|
||||||
|
|
||||||
|
if ( program ) {
|
||||||
|
this.__program.dispose( true );
|
||||||
|
this.__program = program;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public update(): void {
|
||||||
|
const now = audio.currentTime;
|
||||||
|
|
||||||
|
if ( this.isPlaying ) {
|
||||||
|
this.deltaTime = now - this.__prevAudioTime;
|
||||||
|
this.time += this.deltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__updateImpl();
|
||||||
|
|
||||||
|
this.__prevAudioTime = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract __updateImpl(): void;
|
||||||
|
|
||||||
|
protected __render( time: number, callback: ( channel: number ) => void ): void {
|
||||||
|
this.__automatonManager.update( time );
|
||||||
|
|
||||||
|
const program = this.__program;
|
||||||
|
|
||||||
|
const beatLength = 60.0 / MUSIC_BPM;
|
||||||
|
const barLength = 240.0 / MUSIC_BPM;
|
||||||
|
const sixteenBarLength = 3840.0 / MUSIC_BPM;
|
||||||
|
|
||||||
|
program.attribute( 'off', this.__bufferOff, 1 );
|
||||||
|
program.uniform( 'bpm', '1f', MUSIC_BPM );
|
||||||
|
program.uniform( 'bufferLength', '1f', this.bufferLength );
|
||||||
|
program.uniform( '_deltaSample', '1f', 1.0 / audio.sampleRate );
|
||||||
|
program.uniform(
|
||||||
|
'timeLength',
|
||||||
|
'4f',
|
||||||
|
beatLength,
|
||||||
|
barLength,
|
||||||
|
sixteenBarLength,
|
||||||
|
1E16
|
||||||
|
);
|
||||||
|
program.uniform(
|
||||||
|
'_timeHead',
|
||||||
|
'4f',
|
||||||
|
time % beatLength,
|
||||||
|
time % barLength,
|
||||||
|
time % sixteenBarLength,
|
||||||
|
time,
|
||||||
|
);
|
||||||
|
|
||||||
|
program.uniformTexture( 'samplerRandom', randomTextureStatic.texture );
|
||||||
|
program.uniformTexture( 'samplerAutomaton', this.__automatonManager.texture );
|
||||||
|
|
||||||
|
if ( this.__samplesManager.texture ) {
|
||||||
|
program.uniformTexture( 'samplerSamples', this.__samplesManager.texture );
|
||||||
|
}
|
||||||
|
|
||||||
|
glCat.useProgram( program, () => {
|
||||||
|
glCat.bindTransformFeedback( this.__transformFeedback, () => {
|
||||||
|
gl.enable( gl.RASTERIZER_DISCARD );
|
||||||
|
gl.beginTransformFeedback( gl.POINTS );
|
||||||
|
gl.drawArrays( gl.POINTS, 0, this.bufferLength );
|
||||||
|
gl.endTransformFeedback();
|
||||||
|
gl.disable( gl.RASTERIZER_DISCARD );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
gl.finish(); // fenceよくわからん
|
||||||
|
|
||||||
|
[ 0, 1 ].map( ( i ) => {
|
||||||
|
glCat.bindVertexBuffer(
|
||||||
|
this.__bufferTransformFeedbacks[ i ],
|
||||||
|
() => callback( i ),
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
67
src/music/MusicOffline.ts
Normal file
67
src/music/MusicOffline.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { MUSIC_LENGTH } from '../config';
|
||||||
|
import { Music } from './Music';
|
||||||
|
import { audio } from '../globals/music';
|
||||||
|
import { gl } from '../globals/canvas';
|
||||||
|
|
||||||
|
const BUFFER_LENGTH = 16384;
|
||||||
|
|
||||||
|
export class MusicOffline extends Music {
|
||||||
|
private __buffer: AudioBuffer;
|
||||||
|
private __currentBufferSource?: AudioBufferSourceNode | null;
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
super( BUFFER_LENGTH );
|
||||||
|
|
||||||
|
this.__buffer = audio.createBuffer(
|
||||||
|
2,
|
||||||
|
MUSIC_LENGTH * audio.sampleRate,
|
||||||
|
audio.sampleRate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async prepare(): Promise<void> {
|
||||||
|
await super.prepare();
|
||||||
|
|
||||||
|
let head = 0;
|
||||||
|
|
||||||
|
return new Promise( ( resolve ) => {
|
||||||
|
const render = (): void => {
|
||||||
|
const remain = ( MUSIC_LENGTH * audio.sampleRate ) - head;
|
||||||
|
if ( remain <= 0 ) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__render( head / audio.sampleRate, ( i ) => {
|
||||||
|
gl.getBufferSubData(
|
||||||
|
gl.ARRAY_BUFFER,
|
||||||
|
0,
|
||||||
|
this.__buffer.getChannelData( i ),
|
||||||
|
head,
|
||||||
|
Math.min( remain, BUFFER_LENGTH )
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
|
||||||
|
head += BUFFER_LENGTH;
|
||||||
|
|
||||||
|
setTimeout( render, 1 );
|
||||||
|
};
|
||||||
|
render();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
public __updateImpl(): void {
|
||||||
|
if ( this.isPlaying && this.__currentBufferSource == null ) {
|
||||||
|
this.__currentBufferSource = audio.createBufferSource();
|
||||||
|
this.__currentBufferSource.buffer = this.__buffer;
|
||||||
|
this.__currentBufferSource.connect( audio.destination );
|
||||||
|
|
||||||
|
this.__currentBufferSource.start( audio.currentTime, this.time );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !this.isPlaying && this.__currentBufferSource != null ) {
|
||||||
|
this.__currentBufferSource.stop( audio.currentTime );
|
||||||
|
this.__currentBufferSource = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
src/music/MusicRealtime.ts
Normal file
55
src/music/MusicRealtime.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { Music } from './Music';
|
||||||
|
import { Pool } from '../utils/Pool';
|
||||||
|
import { audio } from '../globals/music';
|
||||||
|
import { gl } from '../globals/canvas';
|
||||||
|
|
||||||
|
const BUFFER_LENGTH = 4096;
|
||||||
|
|
||||||
|
export class MusicRealtime extends Music {
|
||||||
|
private __bufferPool: Pool<AudioBuffer>;
|
||||||
|
private __prevBufferSource: AudioBufferSourceNode | null = null;
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
super( BUFFER_LENGTH );
|
||||||
|
|
||||||
|
this.__bufferPool = new Pool( [
|
||||||
|
audio.createBuffer( 2, BUFFER_LENGTH, audio.sampleRate ),
|
||||||
|
audio.createBuffer( 2, BUFFER_LENGTH, audio.sampleRate ),
|
||||||
|
] );
|
||||||
|
|
||||||
|
// casually calling async function
|
||||||
|
this.__samplesManager.loadSamples();
|
||||||
|
}
|
||||||
|
|
||||||
|
public __updateImpl(): void {
|
||||||
|
if ( this.isPlaying ) {
|
||||||
|
const buffer = this.__bufferPool.next();
|
||||||
|
const genTime = audio.currentTime;
|
||||||
|
|
||||||
|
if ( this.__program ) {
|
||||||
|
this.__render( this.time, ( i ) => {
|
||||||
|
gl.getBufferSubData(
|
||||||
|
gl.ARRAY_BUFFER,
|
||||||
|
0,
|
||||||
|
buffer.getChannelData( i ),
|
||||||
|
0,
|
||||||
|
BUFFER_LENGTH
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
const bufferSource = audio.createBufferSource();
|
||||||
|
bufferSource.buffer = buffer;
|
||||||
|
bufferSource.connect( audio.destination );
|
||||||
|
|
||||||
|
this.__prevBufferSource?.stop( audio.currentTime );
|
||||||
|
bufferSource.start( audio.currentTime, audio.currentTime - genTime );
|
||||||
|
this.__prevBufferSource = bufferSource;
|
||||||
|
} else {
|
||||||
|
this.deltaTime = 0.0;
|
||||||
|
|
||||||
|
this.__prevBufferSource?.stop( audio.currentTime );
|
||||||
|
this.__prevBufferSource = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
src/music/SamplesManager.ts
Normal file
62
src/music/SamplesManager.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import { GLCatTexture } from '@fms-cat/glcat-ts';
|
||||||
|
import { Music } from './Music';
|
||||||
|
import { audio } from '../globals/music';
|
||||||
|
import { gl, glCat } from '../globals/canvas';
|
||||||
|
import samplesOpus from './samples.opus';
|
||||||
|
|
||||||
|
export class SamplesManager {
|
||||||
|
public __music: Music;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* it can be undefined since it's loaded asynchronously
|
||||||
|
*/
|
||||||
|
public texture?: GLCatTexture;
|
||||||
|
|
||||||
|
public constructor( music: Music ) {
|
||||||
|
this.__music = music;
|
||||||
|
|
||||||
|
// == hot hot hot hot hot ======================================================================
|
||||||
|
if ( process.env.DEV ) {
|
||||||
|
if ( module.hot ) {
|
||||||
|
module.hot.accept(
|
||||||
|
[ './samples.opus' ],
|
||||||
|
async () => {
|
||||||
|
await this.loadSamples();
|
||||||
|
music.recompile?.();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async loadSamples(): Promise<void> {
|
||||||
|
const inputBuffer = await fetch( samplesOpus ).then( ( res ) => res.arrayBuffer() );
|
||||||
|
const audioBuffer = await audio.decodeAudioData( inputBuffer );
|
||||||
|
|
||||||
|
const buffer = new Float32Array( 96000 );
|
||||||
|
|
||||||
|
const data = audioBuffer.getChannelData( 0 );
|
||||||
|
for ( let i = 0; i < audioBuffer.length; i ++ ) {
|
||||||
|
buffer[ i ] = data[ i ];
|
||||||
|
}
|
||||||
|
|
||||||
|
const texture = glCat.createTexture()!;
|
||||||
|
texture.setTextureFromArray(
|
||||||
|
6000,
|
||||||
|
16,
|
||||||
|
buffer,
|
||||||
|
{
|
||||||
|
internalformat: gl.R32F,
|
||||||
|
format: gl.RED,
|
||||||
|
type: gl.FLOAT,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
texture.textureFilter( gl.LINEAR );
|
||||||
|
|
||||||
|
if ( process.env.DEV && this.texture != null ) {
|
||||||
|
this.texture.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.texture = texture;
|
||||||
|
}
|
||||||
|
}
|
12
src/scene.ts
12
src/scene.ts
@@ -14,6 +14,7 @@ import { FlashyTerrain } from './entities/FlashyTerrain';
|
|||||||
import { FlickyParticles } from './entities/FlickyParticles';
|
import { FlickyParticles } from './entities/FlickyParticles';
|
||||||
import { Glitch } from './entities/Glitch';
|
import { Glitch } from './entities/Glitch';
|
||||||
import { IBLLUT } from './entities/IBLLUT';
|
import { IBLLUT } from './entities/IBLLUT';
|
||||||
|
import { IFSPistons } from './entities/IFSPistons';
|
||||||
import { Lambda } from './heck/components/Lambda';
|
import { Lambda } from './heck/components/Lambda';
|
||||||
import { LightEntity } from './entities/LightEntity';
|
import { LightEntity } from './entities/LightEntity';
|
||||||
import { PixelSorter } from './entities/PixelSorter';
|
import { PixelSorter } from './entities/PixelSorter';
|
||||||
@@ -162,6 +163,13 @@ if ( process.env.DEV && module.hot ) {
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const replacerIFSPistons = new EntityReplacer( () => new IFSPistons(), 'IFSPistons' );
|
||||||
|
if ( process.env.DEV && module.hot ) {
|
||||||
|
module.hot.accept( './entities/IFSPistons', () => {
|
||||||
|
replacerIFSPistons.replace();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
// -- things that is not an "object" ---------------------------------------------------------------
|
// -- things that is not an "object" ---------------------------------------------------------------
|
||||||
const swapOptions = {
|
const swapOptions = {
|
||||||
width: canvasRenderTarget.width,
|
width: canvasRenderTarget.width,
|
||||||
@@ -187,7 +195,7 @@ const replacerLightFirst = new EntityReplacer( () => {
|
|||||||
shadowMapFar: 20.0,
|
shadowMapFar: 20.0,
|
||||||
namePrefix: process.env.DEV && 'lightFirst',
|
namePrefix: process.env.DEV && 'lightFirst',
|
||||||
} );
|
} );
|
||||||
light.color = [ 1.0, 1.0, 1.0 ];
|
light.color = [ 40.0, 40.0, 40.0 ];
|
||||||
light.transform.lookAt( new Vector3( [ -1.0, 2.0, 8.0 ] ) );
|
light.transform.lookAt( new Vector3( [ -1.0, 2.0, 8.0 ] ) );
|
||||||
return light;
|
return light;
|
||||||
}, 'LightFirst' );
|
}, 'LightFirst' );
|
||||||
@@ -201,7 +209,7 @@ const replacerLightPink = new EntityReplacer( () => {
|
|||||||
shadowMapFar: 20.0,
|
shadowMapFar: 20.0,
|
||||||
namePrefix: process.env.DEV && 'lightPink',
|
namePrefix: process.env.DEV && 'lightPink',
|
||||||
} );
|
} );
|
||||||
light.color = [ 60.0, 1.0, 5.0 ];
|
light.color = [ 120.0, 2.0, 10.0 ];
|
||||||
light.transform.lookAt( new Vector3( [ -1.0, 4.0, 4.0 ] ) );
|
light.transform.lookAt( new Vector3( [ -1.0, 4.0, 4.0 ] ) );
|
||||||
return light;
|
return light;
|
||||||
}, 'LightPink' );
|
}, 'LightPink' );
|
||||||
|
Reference in New Issue
Block a user