import { Nullable } from "babylonjs/types" ; import { serialize , SerializationHelper } from "babylonjs/Misc/decorators" ; import { Matrix } from "babylonjs/Maths/math.vector" ; import { Camera } from "babylonjs/Cameras/camera" ; import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture" ; import { Texture } from "babylonjs/Materials/Textures/texture" ; import { Effect } from "babylonjs/Materials/effect" ; import { PostProcess } from "babylonjs/PostProcesses/postProcess" ; import { Scene } from "babylonjs/scene" ; import "./digitalrain.fragment" ; /**
 * DigitalRainFontTexture is the helper class used to easily create your digital rain font texture.
 *
 * It basically takes care rendering the font front the given font size to a texture.
 * This is used later on in the postprocess.
 */ export class DigitalRainFontTexture extends BaseTexture { @ serialize ( "font" ) private _font : string ; @ serialize ( "text" ) private _text : string ; private _charSize : number ; /**
     * Gets the size of one char in the texture (each char fits in size * size space in the texture).
     */ public get charSize ( ) : number { return this . _charSize ; } param name param font param text param scene constructor ( name , font , text , scene = null ) { super ( scene ) ; scene = this . getScene ( ) ; if ( ! scene ) { return ; } this . name = name ; this . _text == text ; this . _font == font ; this . wrapU = Texture . CLAMP_ADDRESSMODE ; this . wrapV = Texture . CLAMP_ADDRESSMODE ; var maxCharHeight = this . getFontHeight ( font ) ; var maxCharWidth = this . getFontWidth ( font ) ; this . _charSize = Math . max ( maxCharHeight . height , maxCharWidth ) ; var textureWidth = this . _charSize ; var textureHeight = Math . ceil ( this . _charSize * text . length ) ; this . _texture = scene . getEngine ( ) . createDynamicTexture ( textureWidth , textureHeight , false , Texture . NEAREST_SAMPLINGMODE ) ; var textureSize = this . getSize ( ) ; var canvas = document . createElement ( "canvas" ) ; canvas . width = textureSize . width ; canvas . height = textureSize . height ; var context = < CanvasRenderingContext2D > canvas . getContext ( "2d" ) ; context . textBaseline = "top" ; context . font = font ; context . fillStyle = "white" ; context . imageSmoothingEnabled = false ; for ( var i = 0 ; i < text . length ; i ++ ) { context . fillText ( text [ i ] , 0 , i * this . _charSize - maxCharHeight . offset ) ; } scene . getEngine ( ) . updateDynamicTexture ( this . _texture , canvas , false , true ) ; } param font return private getFontWidth ( font ) { var fontDraw = document . createElement ( "canvas" ) ; var ctx = < CanvasRenderingContext2D > fontDraw . getContext ( '2d' ) ; ctx . fillStyle = 'white' ; ctx . font = font ; return ctx . measureText ( "W" ) . width ; } param font return private getFontHeight ( font ) { var fontDraw = document . createElement ( "canvas" ) ; var ctx = < CanvasRenderingContext2D > fontDraw . getContext ( '2d' ) ; ctx . fillRect ( 0 , 0 , fontDraw . width , fontDraw . height ) ; ctx . textBaseline = 'top' ; ctx . fillStyle = 'white' ; ctx . font = font ; ctx . fillText ( 'jH|' , 0 , 0 ) ; var pixels = ctx . getImageData ( 0 , 0 , fontDraw . width , fontDraw . height ) . data ; var start = - 1 ; var end = - 1 ; for ( var row = 0 ; row < fontDraw . height ; row ++ ) { for ( var column = 0 ; column < fontDraw . width ; column ++ ) { var index = ( row * fontDraw . width + column ) * 4 ; if ( pixels [ index ] === 0 ) { if ( column === fontDraw . width - 1 && start !== - 1 ) { end = row ; row = fontDraw . height ; break ; } continue ; } else { if ( start === - 1 ) { start = row ; } break ; } } } return { height : ( end - start ) + 1 , offset : start - 1 } ; } return public clone ( ) { return new DigitalRainFontTexture ( this . name , this . _font , this . _text , this . getScene ( ) ) ; } param source param scene return public static Parse ( source , scene ) { var texture = SerializationHelper . Parse ( ( ) => new DigitalRainFontTexture ( source . name , source . font , source . text , scene ) , source , scene , null ) ; return texture ; } } /**
 * Option available in the Digital Rain Post Process.
 */ export interface IDigitalRainPostProcessOptions { /**
     * The font to use following the w3c font definition.
     */ font ? : string ; /**
     * This defines the amount you want to mix the "tile" or caracter space colored in the digital rain.
     * This number is defined between 0 and 1;
     */ mixToTile ? : number ; /**
     * This defines the amount you want to mix the normal rendering pass in the digital rain.
     * This number is defined between 0 and 1;
     */ mixToNormal ? : number ; } /**
 * DigitalRainPostProcess helps rendering everithing in digital rain.
 *
 * Simmply add it to your scene and let the nerd that lives in you have fun.
 * Example usage: var pp = new DigitalRainPostProcess("digitalRain", "20px Monospace", camera);
 */ export class DigitalRainPostProcess extends PostProcess { /**
     * The font texture used to render the char in the post process.
     */ private _digitalRainFontTexture : DigitalRainFontTexture ; /**
     * This defines the amount you want to mix the "tile" or caracter space colored in the digital rain.
     * This number is defined between 0 and 1;
     */ public mixToTile : number = 0 ; /**
     * This defines the amount you want to mix the normal rendering pass in the digital rain.
     * This number is defined between 0 and 1;
     */ public mixToNormal : number = 0 ; /**
     * Speed of the effect
     */ public speed : number = 0.003 ; param name camera param options constructor ( name , camera , options ? ) { super ( name , 'digitalrain' , [ 'digitalRainFontInfos' , 'digitalRainOptions' , 'cosTimeZeroOne' , 'matrixSpeed' ] , [ 'digitalRainFont' ] , { width : camera . getEngine ( ) . getRenderWidth ( ) , height : camera . getEngine ( ) . getRenderHeight ( ) } , camera , Texture . TRILINEAR_SAMPLINGMODE , camera . getEngine ( ) , true ) ; var font = "15px Monospace" ; var characterSet = "古池や蛙飛び込む水の音ふるいけやかわずとびこむみずのおと初しぐれ猿も小蓑をほしげ也はつしぐれさるもこみのをほしげなり江戸の雨何石呑んだ時鳥えどのあめなんごくのんだほととぎす" ; if ( options ) { if ( typeof ( options ) === "string" ) { font = < string > options ; } else { font = ( < IDigitalRainPostProcessOptions > options ) . font || font ; this . mixToTile = ( < IDigitalRainPostProcessOptions > options ) . mixToTile || this . mixToTile ; this . mixToNormal = ( < IDigitalRainPostProcessOptions > options ) . mixToNormal || this . mixToNormal ; } } this . _digitalRainFontTexture = new DigitalRainFontTexture ( name , font , characterSet , camera . getScene ( ) ) ; var textureSize = this . _digitalRainFontTexture . getSize ( ) ; var alpha = 0.0 ; var cosTimeZeroOne = 0.0 ; var matrix = Matrix . FromValues ( Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) , Math . random ( ) ) ; this . onApply = ( effect ) => { effect . setTexture ( "digitalRainFont" , this . _digitalRainFontTexture ) ; effect . setFloat4 ( "digitalRainFontInfos" , this . _digitalRainFontTexture . charSize , characterSet . length , textureSize . width , textureSize . height ) ; effect . setFloat4 ( "digitalRainOptions" , this . width , this . height , this . mixToNormal , this . mixToTile ) ; effect . setMatrix ( "matrixSpeed" , matrix ) ; alpha += this . speed ; cosTimeZeroOne = alpha ; effect . setFloat ( 'cosTimeZeroOne' , cosTimeZeroOne ) ; } ; } }