import type { ASTNode , ASTOpts } from "@thi.ng/gp" ; import { AST } from "@thi.ng/gp/ast" ; import { ConsoleLogger } from "@thi.ng/logger/console" ; import type { IRandom } from "@thi.ng/random" ; import { SYSTEM } from "@thi.ng/random/system" ; import type { Term , Vec3Sym , Vec3Term } from "@thi.ng/shader-ast" ; import { constantFolding } from "@thi.ng/shader-ast-optimize/contant-folding" ; import { clamp11 } from "@thi.ng/shader-ast-stdlib/math/clamp" ; import { snoise3 , snoiseVec3 } from "@thi.ng/shader-ast-stdlib/noise/simplex3" ; import { fragUV } from "@thi.ng/shader-ast-stdlib/screen/uv" ; import { assign } from "@thi.ng/shader-ast/ast/assign" ; import { ret } from "@thi.ng/shader-ast/ast/function" ; import { vec3 , vec4 } from "@thi.ng/shader-ast/ast/lit" ; import { add , div , mul , neg , sub } from "@thi.ng/shader-ast/ast/ops" ; import { $ } from "@thi.ng/shader-ast/ast/swizzle" ; import { sym } from "@thi.ng/shader-ast/ast/sym" ; import { abs , acos , asin , cos , distance , exp , fract , inversesqrt , length , log , mix , mod , normalize , pow , sin , sqrt , tan , } from "@thi.ng/shader-ast/builtin/math" ; import { type , MainImageFn , shaderToy , type , ShaderToyUniforms , } from "@thi.ng/webgl-shadertoy" ; import { glCanvas } from "@thi.ng/webgl/canvas" ; import { setLogger } from "@thi.ng/webgl/logger" ; setLogger ( new ConsoleLogger ( "webgl" ) ) ; const MAX_DEPTH = 11 ; const NORM_SCALE = 1 ; const OP1 = [ abs , exp , neg , normalize , sin , cos , snoiseVec3 , tan , fract , ( x ) => vec3 ( snoise3 ( x ) ) , ( x ) => sub ( 1 , clamp11 ( x ) ) , ( x ) => vec3 ( length ( x ) ) , ( x ) => log ( abs ( x ) ) , ( x ) => inversesqrt ( abs ( x ) ) , ( x ) => sqrt ( abs ( x ) ) , ( x ) => asin ( clamp11 ( x ) ) , ( x ) => acos ( clamp11 ( x ) ) , ( x ) => $ ( x , "zyx" ) , ( x ) => $ ( x , "yzx" ) , ( x ) => $ ( x , "yxz" ) , ( x ) => $ ( x , "xxx" ) , ( x ) => $ ( x , "yyy" ) , ( x ) => $ ( x , "zzz" ) , ] ; const OP2 = [ add , sub , mul , div , mod , pow , ( x , y ) => vec3 ( distance ( x , y ) ) , ] ; const OP3 = [ mix ] ; const UV = sym ( vec3 ( ) ) ; const randomFn = ( ops ) => ( rnd ) => ops [ rnd . int ( ) % ops . length ] ; const AST_OPTS = { terminal : ( rnd ) => rnd . float ( ) < 0.5 ? UV : vec3 ( rnd . norm ( NORM_SCALE ) , rnd . norm ( NORM_SCALE ) , rnd . norm ( NORM_SCALE ) ) , ops : [ { fn : randomFn ( OP1 ) , arity : 1 , prob : 0.4 } , { fn : randomFn ( OP2 ) , arity : 2 , prob : 0.4 } , { fn : randomFn ( OP3 ) , arity : 3 , prob : 0.1 } , ] , maxDepth : MAX_DEPTH , probMutate : 0.01 , } ; const transpile = ( node ) : Term < any > => node . type === "op" ? node . op . apply ( null , node . args . map ( transpile ) ) : node . value ; const shaderFunction = ( ast ) : MainImageFn < ShaderToyUniforms > => ( gl , unis ) => { return [ UV , assign ( UV , vec3 ( fragUV ( gl . gl_FragCoord , unis . resolution ) , mul ( 1 , fract ( unis . time ) ) ) ) , ret ( vec4 ( abs ( constantFolding ( transpile ( ast ) ) ) , 1 ) ) , ] ; } ; const ast = new AST ( AST_OPTS ) ; let currTree = ast . randomAST ( ) ; const canvas = glCanvas ( { width : 640 , height : 640 , parent : document . body , version : 1 , } ) ; const toy = shaderToy ( { canvas : canvas . canvas , gl : canvas . gl , main : shaderFunction ( currTree ) , } ) ; toy . start ( ) ; const update = ( ) => { console . clear ( ) ; currTree = SYSTEM . float ( ) < 0.9 ? ast . mutate ( currTree , SYSTEM . minmax ( 1 , 4 ) ) : ast . crossoverSingle ( currTree , ast . randomAST ( ) ) [ 0 ] ; toy . recompile ( shaderFunction ( currTree ) , { prec : 4 } ) ; } ; setInterval ( update , 500 ) ;