diff --git a/demos/html5/MAKE.bat b/demos/html5/MAKE.bat index 27510fe..ed720c9 100644 --- a/demos/html5/MAKE.bat +++ b/demos/html5/MAKE.bat @@ -49,7 +49,7 @@ if not exist "emsdk" ( if "%EMSDK%"=="" call emsdk\emsdk_env.bat --system rem cook art -..\..\tools\cook.exe --cook-jobs=1 --cook-ini=..\..\tools\cook.ini +..\..\tools\cook.exe --cook-jobs=1 --cook-ini=..\..\tools\cook_web.ini rem host webserver, compile and launch rem start python -m http.server --bind 127.0.0.1 8000 diff --git a/demos/html5/art/fonts/Carlito-BoldItalic.license b/demos/html5/art/fonts/Carlito-BoldItalic.license new file mode 100644 index 0000000..e999b31 --- /dev/null +++ b/demos/html5/art/fonts/Carlito-BoldItalic.license @@ -0,0 +1,95 @@ +Copyright (c) 2010-2013 by tyPoland Lukasz Dziedzic with Reserved Font Name "Carlito". + +This Font Software is licensed under the SIL Open Font License, +Version 1.1 as shown below. + +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 + +PREAMBLE The goals of the Open Font License (OFL) are to stimulate +worldwide development of collaborative font projects, to support the font +creation efforts of academic and linguistic communities, and to provide +a free and open framework in which fonts may be shared and improved in +partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. +The fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply to +any document created using the fonts or their derivatives. + + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. +This may include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components +as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting ? in part or in whole ? +any of the components of the Original Version, by changing formats or +by porting the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical writer +or other person who contributed to the Font Software. + + +PERMISSION & CONDITIONS + +Permission is hereby granted, free of charge, to any person obtaining a +copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components,in + Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, + redistributed and/or sold with any software, provided that each copy + contains the above copyright notice and this license. These can be + included either as stand-alone text files, human-readable headers or + in the appropriate machine-readable metadata fields within text or + binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font + Name(s) unless explicit written permission is granted by the + corresponding Copyright Holder. This restriction only applies to the + primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font + Software shall not be used to promote, endorse or advertise any + Modified Version, except to acknowledge the contribution(s) of the + Copyright Holder(s) and the Author(s) or with their explicit written + permission. + +5) The Font Software, modified or unmodified, in part or in whole, must + be distributed entirely under this license, and must not be distributed + under any other license. The requirement for fonts to remain under + this license does not apply to any document created using the Font + Software. + + + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + + + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER +DEALINGS IN THE FONT SOFTWARE. + diff --git a/demos/html5/art/fonts/Carlito-BoldItalic.ttf b/demos/html5/art/fonts/Carlito-BoldItalic.ttf new file mode 100644 index 0000000..0eaa04e Binary files /dev/null and b/demos/html5/art/fonts/Carlito-BoldItalic.ttf differ diff --git a/demos/html5/art/fonts/Carlito-Regular.license b/demos/html5/art/fonts/Carlito-Regular.license new file mode 100644 index 0000000..e999b31 --- /dev/null +++ b/demos/html5/art/fonts/Carlito-Regular.license @@ -0,0 +1,95 @@ +Copyright (c) 2010-2013 by tyPoland Lukasz Dziedzic with Reserved Font Name "Carlito". + +This Font Software is licensed under the SIL Open Font License, +Version 1.1 as shown below. + +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 + +PREAMBLE The goals of the Open Font License (OFL) are to stimulate +worldwide development of collaborative font projects, to support the font +creation efforts of academic and linguistic communities, and to provide +a free and open framework in which fonts may be shared and improved in +partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. +The fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply to +any document created using the fonts or their derivatives. + + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. +This may include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components +as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting ? in part or in whole ? +any of the components of the Original Version, by changing formats or +by porting the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical writer +or other person who contributed to the Font Software. + + +PERMISSION & CONDITIONS + +Permission is hereby granted, free of charge, to any person obtaining a +copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components,in + Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, + redistributed and/or sold with any software, provided that each copy + contains the above copyright notice and this license. These can be + included either as stand-alone text files, human-readable headers or + in the appropriate machine-readable metadata fields within text or + binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font + Name(s) unless explicit written permission is granted by the + corresponding Copyright Holder. This restriction only applies to the + primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font + Software shall not be used to promote, endorse or advertise any + Modified Version, except to acknowledge the contribution(s) of the + Copyright Holder(s) and the Author(s) or with their explicit written + permission. + +5) The Font Software, modified or unmodified, in part or in whole, must + be distributed entirely under this license, and must not be distributed + under any other license. The requirement for fonts to remain under + this license does not apply to any document created using the Font + Software. + + + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + + + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER +DEALINGS IN THE FONT SOFTWARE. + diff --git a/demos/html5/art/fonts/Carlito-Regular.ttf b/demos/html5/art/fonts/Carlito-Regular.ttf new file mode 100644 index 0000000..6b7e0e3 Binary files /dev/null and b/demos/html5/art/fonts/Carlito-Regular.ttf differ diff --git a/demos/html5/art/fonts/Inconsolata-Regular.license b/demos/html5/art/fonts/Inconsolata-Regular.license new file mode 100644 index 0000000..65f04ca --- /dev/null +++ b/demos/html5/art/fonts/Inconsolata-Regular.license @@ -0,0 +1,93 @@ +Copyright 2006 The Inconsolata Project Authors + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/demos/html5/art/fonts/Inconsolata-Regular.ttf b/demos/html5/art/fonts/Inconsolata-Regular.ttf new file mode 100644 index 0000000..fc981ce Binary files /dev/null and b/demos/html5/art/fonts/Inconsolata-Regular.ttf differ diff --git a/demos/html5/art/fonts/MaterialIconsSharp-Regular.license b/demos/html5/art/fonts/MaterialIconsSharp-Regular.license new file mode 100644 index 0000000..cd5d86e --- /dev/null +++ b/demos/html5/art/fonts/MaterialIconsSharp-Regular.license @@ -0,0 +1,2 @@ +License +We have made these icons available for you to incorporate into your products under the Apache License Version 2.0. Feel free to remix and re-share these icons and documentation in your products. We'd love attribution in your app's about screen, but it's diff --git a/demos/html5/art/fonts/MaterialIconsSharp-Regular.otf b/demos/html5/art/fonts/MaterialIconsSharp-Regular.otf new file mode 100644 index 0000000..f06982a Binary files /dev/null and b/demos/html5/art/fonts/MaterialIconsSharp-Regular.otf differ diff --git a/demos/html5/art/fx/fxAberration.fs b/demos/html5/art/fx/fxAberration.fs new file mode 100644 index 0000000..c1e60c2 --- /dev/null +++ b/demos/html5/art/fx/fxAberration.fs @@ -0,0 +1,12 @@ +uniform float intensity = 0.003f; +uniform float angle = 0.0f; + +void main() { + vec2 uv = TEXCOORD.st; + vec2 offset = intensity * vec2( cos(angle), sin(angle) ); + vec4 color = texture( iChannel0, uv); + color.r = texture( iChannel0, uv + offset ).x; + color.b = texture( iChannel0, uv - offset ).z; + + FRAGCOLOR = color; +} diff --git a/demos/html5/art/fx/fxBloom.fs b/demos/html5/art/fx/fxBloom.fs new file mode 100644 index 0000000..7fd83f7 --- /dev/null +++ b/demos/html5/art/fx/fxBloom.fs @@ -0,0 +1,7 @@ +uniform float intensity = 2.0; + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 src = texture(iChannel0, uv); + fragColor = vec4( clamp(src * intensity, 0.0, 1.0).rgb, src.a ); +} diff --git a/demos/html5/art/fx/fxBlur.fs b/demos/html5/art/fx/fxBlur.fs new file mode 100644 index 0000000..f836971 --- /dev/null +++ b/demos/html5/art/fx/fxBlur.fs @@ -0,0 +1,16 @@ +// [ref] https://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ + +uniform float intensity = 4; +uniform vec2 direction = vec2(1.0, 0.0); + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 base = texture(iChannel0, uv), color = vec4(0.0); + vec2 offset = (direction * vec2(intensity)) / iResolution; + color += base * 0.30; + color += texture(iChannel0, uv + offset) * 0.35; + color += texture(iChannel0, uv - offset) * 0.35; + + fragColor = vec4( color.rgb, base.a ); +} diff --git a/demos/html5/art/fx/fxCRT.fs b/demos/html5/art/fx/fxCRT.fs new file mode 100644 index 0000000..91ffcc6 --- /dev/null +++ b/demos/html5/art/fx/fxCRT.fs @@ -0,0 +1,169 @@ +// +// PUBLIC DOMAIN CRT STYLED SCAN-LINE SHADER +// +// by Timothy Lottes +// +// This is more along the style of a really good CGA arcade monitor. +// With RGB inputs instead of NTSC. +// The shadow mask example has the mask rotated 90 degrees for less chromatic aberration. +// +// Left it unoptimized to show the theory behind the algorithm. +// +// It is an example what I personally would want as a display option for pixel art games. +// Please take and use, change, or whatever. +// + +out vec4 color; + +// Emulated input resolution. +#if 0 + // Fix resolution to set amount. + vec2 res=vec2(320.0/1.0,160.0/1.0); +#else + // Optimize for resize. + vec2 res=iResolution.xy/6.0; +#endif + +// Hardness of scanline. +// -8.0 = soft +// -16.0 = medium +uniform float hardScan=-8.0; + +// Hardness of pixels in scanline. +// -2.0 = soft +// -4.0 = hard +uniform float hardPix=-3.0; + +// Display warp. +// 0.0 = none +// 1.0/8.0 = extreme +vec2 warp=vec2(1.0/32.0,1.0/24.0); + +// Amount of shadow mask. +float maskDark=0.5; +float maskLight=1.5; + +//------------------------------------------------------------------------ + +// sRGB to Linear. +// Assuing using sRGB typed textures this should not be needed. +float ToLinear1(float c){return(c<=0.04045)?c/12.92:pow((c+0.055)/1.055,2.4);} +vec3 ToLinear(vec3 c){return vec3(ToLinear1(c.r),ToLinear1(c.g),ToLinear1(c.b));} + +// Linear to sRGB. +// Assuing using sRGB typed textures this should not be needed. +float ToSrgb1(float c){return(c<0.0031308?c*12.92:1.055*pow(c,0.41666)-0.055);} +vec3 ToSrgb(vec3 c){return vec3(ToSrgb1(c.r),ToSrgb1(c.g),ToSrgb1(c.b));} + +// Nearest emulated sample given floating point position and texel offset. +// Also zero's off screen. +vec3 Fetch(vec2 pos,vec2 off){ + pos=floor(pos*res+off)/res; + if(max(abs(pos.x-0.5),abs(pos.y-0.5))>0.5)return vec3(0.0,0.0,0.0); + return ToLinear(texture2D(iChannel0,pos.xy,-16.0).rgb);} + +// Distance in emulated pixels to nearest texel. +vec2 Dist(vec2 pos){pos=pos*res;return -((pos-floor(pos))-vec2(0.5));} + +// 1D Gaussian. +float Gaus(float pos,float scale){return exp2(scale*pos*pos);} + +// 3-tap Gaussian filter along horz line. +vec3 Horz3(vec2 pos,float off){ + vec3 b=Fetch(pos,vec2(-1.0,off)); + vec3 c=Fetch(pos,vec2( 0.0,off)); + vec3 d=Fetch(pos,vec2( 1.0,off)); + float dst=Dist(pos).x; + // Convert distance to weight. + float scale=hardPix; + float wb=Gaus(dst-1.0,scale); + float wc=Gaus(dst+0.0,scale); + float wd=Gaus(dst+1.0,scale); + // Return filtered sample. + return (b*wb+c*wc+d*wd)/(wb+wc+wd);} + +// 5-tap Gaussian filter along horz line. +vec3 Horz5(vec2 pos,float off){ + vec3 a=Fetch(pos,vec2(-2.0,off)); + vec3 b=Fetch(pos,vec2(-1.0,off)); + vec3 c=Fetch(pos,vec2( 0.0,off)); + vec3 d=Fetch(pos,vec2( 1.0,off)); + vec3 e=Fetch(pos,vec2( 2.0,off)); + float dst=Dist(pos).x; + // Convert distance to weight. + float scale=hardPix; + float wa=Gaus(dst-2.0,scale); + float wb=Gaus(dst-1.0,scale); + float wc=Gaus(dst+0.0,scale); + float wd=Gaus(dst+1.0,scale); + float we=Gaus(dst+2.0,scale); + // Return filtered sample. + return (a*wa+b*wb+c*wc+d*wd+e*we)/(wa+wb+wc+wd+we);} + +// Return scanline weight. +float Scan(vec2 pos,float off){ + float dst=Dist(pos).y; + return Gaus(dst+off,hardScan);} + +// Allow nearest three lines to effect pixel. +vec3 Tri(vec2 pos){ + vec3 a=Horz3(pos,-1.0); + vec3 b=Horz5(pos, 0.0); + vec3 c=Horz3(pos, 1.0); + float wa=Scan(pos,-1.0); + float wb=Scan(pos, 0.0); + float wc=Scan(pos, 1.0); + return a*wa+b*wb+c*wc;} + +// Distortion of scanlines, and end of screen alpha. +vec2 Warp(vec2 pos){ + pos=pos*2.0-1.0; + pos*=vec2(1.0+(pos.y*pos.y)*warp.x,1.0+(pos.x*pos.x)*warp.y); + return pos*0.5+0.5;} + +// Shadow mask. +vec3 Mask(vec2 pos){ + pos.x+=pos.y*3.0; + vec3 mask=vec3(maskDark,maskDark,maskDark); + pos.x=fract(pos.x/6.0); + if(pos.x<0.333)mask.r=maskLight; + else if(pos.x<0.666)mask.g=maskLight; + else mask.b=maskLight; + return mask;} + +// Draw dividing bars. +float Bar(float pos,float bar){pos-=bar;return pos*pos<4.0?0.0:1.0;} + +// Entry. +void main() { +#if 0 + // Unmodified. + if(gl_FragCoord.x 1.025f || xy.y > 1.025f) return vec4(0, 0, 0, 0); + // Bazel + if(xy.x < -0.015f || xy.y < -0.015f) return vec4(0.03f, 0.03f, 0.03f, 0.0f); + if(xy.x > 1.015f || xy.y > 1.015f) return vec4(0.03f, 0.03f, 0.03f, 0.0f); + // Screen Border + if(xy.x < 0.001f || xy.y < 0.001f) return vec4(0.0f, 0.0f, 0.0f, 0.0f); + if(xy.x > 0.999f || xy.y > 0.999f) return vec4(0.0f, 0.0f, 0.0f, 0.0f); + #endif + + vec4 color = texture(iChannel0, xy); + + #if DEBUG + if(xy.x < 0.5f) return color; + #endif + + #if ENABLE_REFRESHLINE + float timeOver = fmod(iTime / 5, 1); + float refreshLineColorTint = timeOver - xy.y; + if(xy.y > timeOver && xy.y - 0.03f < timeOver ) color.rgb += (refreshLineColorTint * 2.0f); + #endif + + #if ENABLE_SCANLINES + // scanlines are always every 1px + if(fmod(floor(uv.y * iResolution.y), 2) != 0) color *= scanlineTint; + #endif + + #if ENABLE_TINT + float grayscale = (color.r + color.g + color.b) / 3.f; + color = vec4(grayscale, grayscale, grayscale, 0); + color *= tint; + #endif + + #if ENABLE_GRAIN + vec3 m = vec3(tex, fmod(iTime, 5) / 5) + 1.; + float state = permute(permute(m.x) + m.y) + m.z; + + float p = 0.95 * rand(state) + 0.025; + float q = p - 0.5; + float r2 = q * q; + + float grain = q * (a2 + (a1 * r2 + a0) / (r2 * r2 + b1 * r2 + b0)); + color.rgb += GRAIN_INTENSITY * grain; + #endif + + return color; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 src = texture(iChannel0, uv); + + fragColor = vec4(CRT(uv).rgb, src.a); +} diff --git a/demos/html5/art/fx/fxColorblind.fs b/demos/html5/art/fx/fxColorblind.fs new file mode 100644 index 0000000..61a71ea --- /dev/null +++ b/demos/html5/art/fx/fxColorblind.fs @@ -0,0 +1,29 @@ +// [ref] https://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html + +uniform int colorblind_mode = 2; // [0..4] +uniform mat3 colorblind_matrices[5] = mat3[5]( + mat3(1.000,0.000,0.000, 0.000,1.000,0.000, 0.000,0.000,1.000), // 0 no colorblind + mat3(0.299,0.587,0.114, 0.299,0.587,0.114, 0.299,0.587,0.114), // 1 achromatopsia (luma) + mat3( // protanomaly (no red cone) + 0.152286, 1.052583,-0.204868, + 0.114503, 0.786281, 0.099216, + -0.003882,-0.048116, 1.051998 + ), + mat3( // deuteranomaly (no green cone) + 0.367322, 0.860646, -0.227968, + 0.280085, 0.672501, 0.047413, + -0.011820, 0.042940, 0.968881 + ), + mat3( // tritanomaly (no blue cone) + 1.255528,-0.076749,-0.178779, + -0.078411, 0.930809, 0.147602, + 0.004733, 0.691367, 0.303900 + ) +); + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 src = texture(iChannel0, uv); + fragColor = vec4( src.rgb * colorblind_matrices[colorblind_mode], src.a ); +} diff --git a/demos/html5/art/fx/fxContrast.fs b/demos/html5/art/fx/fxContrast.fs new file mode 100644 index 0000000..61f29ce --- /dev/null +++ b/demos/html5/art/fx/fxContrast.fs @@ -0,0 +1,15 @@ +uniform float contrast = 1.5; // > 1 to saturate, < 1 to bleach-to-gray +uniform float brightness = 0; + +void main() { + vec4 pixelColor = texture(iChannel0, TEXCOORD.st); + pixelColor.rgb /= pixelColor.a; + + pixelColor.rgb = ((pixelColor.rgb - 0.5f) * max(contrast, 0)) + 0.5f; + + pixelColor.rgb += brightness; + + pixelColor.rgb *= pixelColor.a; + + FRAGCOLOR = pixelColor; +} diff --git a/demos/html5/art/fx/fxDissolve.fs b/demos/html5/art/fx/fxDissolve.fs new file mode 100644 index 0000000..62d53d5 --- /dev/null +++ b/demos/html5/art/fx/fxDissolve.fs @@ -0,0 +1,16 @@ +uniform float intensity = 0.004; + +highp float rand(vec2 co) { + highp float a = 12.9898; + highp float b = 78.233; + highp float c = 43758.5453; + highp float dt= dot(co.xy ,vec2(a,b)); + highp float sn= mod(dt,3.14); + return fract(sin(sn) * c); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 fetch = texture(iChannel0, uv + intensity * rand(uv)); + fragColor = fetch; +} diff --git a/demos/html5/art/fx/fxDithering.fs b/demos/html5/art/fx/fxDithering.fs new file mode 100644 index 0000000..1a87ca0 --- /dev/null +++ b/demos/html5/art/fx/fxDithering.fs @@ -0,0 +1,47 @@ +// https://en.wikipedia.org/wiki/Ordered_dithering + +#define BAYER 4 + +#if BAYER == 2 + +const float threshold[4] = float[4]( + 1/4.,2/4., + 3/4.,1/4. +); + +#elif BAYER == 4 + +const float threshold[16] = float[16]( + 1/16., 9/16., 3/16., 11/16., + 13/16., 5/16., 15/16., 7/16., + 4/16., 12/16., 2/16., 10/16., + 16/16., 8/16., 14/16., 6/16. +); + +#else // 8 + +const float threshold[64] = float[64]( + 1/64.,33/64., 9/64.,41/64., 3/64.,35/64.,11/64.,43/64., + 49/64.,17/64.,57/64.,25/64.,51/64.,19/64.,59/64.,27/64., + 13/64.,45/64., 5/64.,37/64.,15/64.,47/64., 7/64.,39/64., + 61/64.,29/64.,53/64.,21/64.,63/64.,31/64.,55/64.,23/64., + 4/64.,36/64.,12/64.,42/64., 2/64.,34/64.,10/64.,42/64., + 52/64.,20/64.,60/64.,28/64.,50/64.,18/64.,58/64.,26/64., + 16/64.,48/64., 8/64.,40/64.,14/64.,46/64., 6/64.,38/64., + 64/64.,32/64.,56/64.,24/64.,62/64.,30/64.,54/64.,22/64. +); + +#endif + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord/iResolution.xy; + vec4 src = texture(iChannel0, uv); + + int x = int(fragCoord.x) % BAYER; + int y = int(fragCoord.y) % BAYER; + + float luma = dot(vec3(0.2126, 0.7152, 0.0722), src.rgb); + luma = step(threshold[BAYER*x+y], luma); // find closest + + fragColor = vec4(vec3(luma), src.a); +} diff --git a/demos/html5/art/fx/fxEditorOutline.fs b/demos/html5/art/fx/fxEditorOutline.fs new file mode 100644 index 0000000..c3e6302 --- /dev/null +++ b/demos/html5/art/fx/fxEditorOutline.fs @@ -0,0 +1,19 @@ +uniform int thickness = 2; +uniform vec4 border_color = vec4(1,1,0,1); + +void main() { + vec4 texel = texture(iChannel0, uv); + float outline = 0.0; + if( texel.a == 0.0 ) { + for( int x = -thickness; x <= thickness; x++ ) { + for( int y = -thickness;y <= thickness; y++ ) { + float sample = texture(iChannel0, uv+vec2(float(x)/iWidth, float(y)/iHeight)).a; + if( sample > 0.0 ) { + outline = 1.0; + } + } + } + } + + FRAGCOLOR = vec4(border_color.rgb, outline * border_color.a); // mix(texel, border_color, outline * border_color.a); +} \ No newline at end of file diff --git a/demos/html5/art/fx/fxFXAA.fs b/demos/html5/art/fx/fxFXAA.fs new file mode 100644 index 0000000..c034695 --- /dev/null +++ b/demos/html5/art/fx/fxFXAA.fs @@ -0,0 +1,67 @@ +// FXAA fragment shader by Timothy Lottes (public domain) +// http://timothylottes.blogspot.com/ + +uniform sampler2D tex; + +float FXAA_SUBPIX_SHIFT = 1.0/4.0; + +// posPos: Output of FxaaVertexShader interpolated across screen. +// tex: Input texture. +// rcpFrame: const vec2(1.0/frameWidth, 1.0/frameHeight). +vec3 FxaaPixelShader(vec4 posPos, sampler2D tex, vec2 rcpFrame) { + #define FXAA_REDUCE_MIN (1.0/128.0) + #define FXAA_REDUCE_MUL (1.0/8.0) + #define FXAA_SPAN_MAX 8.0 + + vec3 rgbNW = texture2DLod(tex, posPos.zw, 0.0).xyz; + vec3 rgbNE = texture2DLod(tex, posPos.zw + vec2(1.0,0.0)*rcpFrame.xy, 0.0).xyz; + vec3 rgbSW = texture2DLod(tex, posPos.zw + vec2(0.0,1.0)*rcpFrame.xy, 0.0).xyz; + vec3 rgbSE = texture2DLod(tex, posPos.zw + vec2(1.0,1.0)*rcpFrame.xy, 0.0).xyz; + vec3 rgbM = texture2DLod(tex, posPos.xy,0.0).xyz; + + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max( + (lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL), + FXAA_REDUCE_MIN); + float rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * rcpFrame.xy; + + vec3 rgbA = (1.0/2.0) * ( + texture2DLod(tex, posPos.xy + dir * (1.0/3.0 - 0.5),0.0).xyz + + texture2DLod(tex, posPos.xy + dir * (2.0/3.0 - 0.5),0.0).xyz); + vec3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * ( + texture2DLod(tex, posPos.xy + dir * (0.0/3.0 - 0.5),0.0).xyz + + texture2DLod(tex, posPos.xy + dir * (3.0/3.0 - 0.5),0.0).xyz); + float lumaB = dot(rgbB, luma); + if((lumaB < lumaMin) || (lumaB > lumaMax)) return rgbA; + return rgbB; +} + +vec4 FXAA(sampler2D tex, vec2 uv) { + vec2 rcpFrame = vec2(1.0/iWidth, 1.0/iHeight); + vec4 posPos = vec4(texcoord.st,texcoord.st -(rcpFrame * (0.5 + FXAA_SUBPIX_SHIFT))); + vec4 c = vec4(0.0); + c.rgb = FxaaPixelShader(posPos, tex, rcpFrame); + // c.rgb = texture2D(tex, posPos.xy).rgb - c.rgb; // debug + c.a = texture2D(tex, posPos.xy).a; + return c; +} + +void main() { + FRAGCOLOR = FXAA(iChannel0, texcoord.st); +} diff --git a/demos/html5/art/fx/fxFXAA3.fs b/demos/html5/art/fx/fxFXAA3.fs new file mode 100644 index 0000000..fabceb1 --- /dev/null +++ b/demos/html5/art/fx/fxFXAA3.fs @@ -0,0 +1,610 @@ +/***************************************** + * FXAA 3.11 Implementation - effendiian + * ------------------------------------- + * FXAA implementation based off of the + * work by Timothy Lottes in the Nvidia white paper: + * https://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf + * + * Also used these resources: + * - https://catlikecoding.com/unity/tutorials/advanced-rendering/fxaa/ + * - https://blog.codinghorror.com/fast-approximate-anti-aliasing-fxaa/ + *****************************************/ + +// Turn off FXAA. +// #define FXAA 0 + +// Turn on FXAA. +#define FXAA 1 + +// Turn on split screen between no-FXAA and FXAA. +// #define FXAA 2 + +/* +/ FXAA setting, defined via preprocessor variables +*/ +#ifndef FXAA_PRESET + #define FXAA_PRESET 5 + #define FXAA_DEBUG_SKIPPED 0 + #define FXAA_DEBUG_PASSTHROUGH 0 + #define FXAA_DEBUG_HORZVERT 0 + #define FXAA_DEBUG_PAIR 0 + #define FXAA_DEBUG_NEGPOS 0 + #define FXAA_DEBUG_OFFSET 0 + #define FXAA_DEBUG_HIGHLIGHT 0 + #define FXAA_LUMINANCE 1 +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_PRESET == 0) + #define FXAA_EDGE_THRESHOLD (1.0/4.0) + #define FXAA_EDGE_THRESHOLD_MIN (1.0/12.0) + #define FXAA_SEARCH_STEPS 2 + #define FXAA_SEARCH_ACCELERATION 4 + #define FXAA_SEARCH_THRESHOLD (1.0/4.0) + #define FXAA_SUBPIX 1 + #define FXAA_SUBPIX_FASTER 1 + #define FXAA_SUBPIX_CAP (2.0/3.0) + #define FXAA_SUBPIX_TRIM (1.0/4.0) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_PRESET == 1) + #define FXAA_EDGE_THRESHOLD (1.0/8.0) + #define FXAA_EDGE_THRESHOLD_MIN (1.0/16.0) + #define FXAA_SEARCH_STEPS 4 + #define FXAA_SEARCH_ACCELERATION 3 + #define FXAA_SEARCH_THRESHOLD (1.0/4.0) + #define FXAA_SUBPIX 1 + #define FXAA_SUBPIX_FASTER 0 + #define FXAA_SUBPIX_CAP (3.0/4.0) + #define FXAA_SUBPIX_TRIM (1.0/4.0) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_PRESET == 2) + #define FXAA_EDGE_THRESHOLD (1.0/8.0) + #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0) + #define FXAA_SEARCH_STEPS 8 + #define FXAA_SEARCH_ACCELERATION 2 + #define FXAA_SEARCH_THRESHOLD (1.0/4.0) + #define FXAA_SUBPIX 1 + #define FXAA_SUBPIX_FASTER 0 + #define FXAA_SUBPIX_CAP (3.0/4.0) + #define FXAA_SUBPIX_TRIM (1.0/4.0) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_PRESET == 3) + #define FXAA_EDGE_THRESHOLD (1.0/8.0) + #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0) + #define FXAA_SEARCH_STEPS 16 + #define FXAA_SEARCH_ACCELERATION 1 + #define FXAA_SEARCH_THRESHOLD (1.0/4.0) + #define FXAA_SUBPIX 1 + #define FXAA_SUBPIX_FASTER 0 + #define FXAA_SUBPIX_CAP (3.0/4.0) + #define FXAA_SUBPIX_TRIM (1.0/4.0) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_PRESET == 4) + #define FXAA_EDGE_THRESHOLD (1.0/8.0) + #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0) + #define FXAA_SEARCH_STEPS 24 + #define FXAA_SEARCH_ACCELERATION 1 + #define FXAA_SEARCH_THRESHOLD (1.0/4.0) + #define FXAA_SUBPIX 1 + #define FXAA_SUBPIX_FASTER 0 + #define FXAA_SUBPIX_CAP (3.0/4.0) + #define FXAA_SUBPIX_TRIM (1.0/4.0) +#endif +/*--------------------------------------------------------------------------*/ +#if (FXAA_PRESET == 5) + #define FXAA_EDGE_THRESHOLD (1.0/8.0) + #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0) + #define FXAA_SEARCH_STEPS 32 + #define FXAA_SEARCH_ACCELERATION 1 + #define FXAA_SEARCH_THRESHOLD (1.0/4.0) + #define FXAA_SUBPIX 1 + #define FXAA_SUBPIX_FASTER 0 + #define FXAA_SUBPIX_CAP (3.0/4.0) + #define FXAA_SUBPIX_TRIM (1.0/4.0) +#endif +/*--------------------------------------------------------------------------*/ +#define FXAA_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_SUBPIX_TRIM)) + +// -------------------------------------- +// Helper functions. +// -------------------------------------- + +// --------------------- +// Conversion functions. + +// ToVec2 +vec2 ToVec2( float value ) { return vec2(value, value); } + +// ToVec3 +vec3 ToVec3( float value ) { return vec3(value, value, value); } +vec3 ToVec3( vec2 vector, float z ) { return vec3(vector.x, vector.y, z); } +vec3 ToVec3( vec2 vector ) { return ToVec3(vector, 0.0); } + +// ToVec4 +vec4 ToVec4( vec2 vector, float z, float w ) { return vec4(vector.x, vector.y, z, w); } +vec4 ToVec4( vec2 vector, float z ) { return ToVec4(vector, z, 0.0); } +vec4 ToVec4( vec2 vector ) { return ToVec4(vector, 0.0); } +vec4 ToVec4( vec3 vector, float w ) { return vec4(vector.x, vector.y, vector.z, w); } +vec4 ToVec4( vec3 vector ) { return ToVec4(vector, 0.0); } +vec4 ToVec4( float value, float w ) { return vec4(value, value, value, w); } +vec4 ToVec4( float value ) { return ToVec4(value, 0.0); } + +// --------------------- +// Texture sampler functions. + +// Return sampled image from a point + offset texel space. +vec4 TextureOffset( sampler2D tex, + vec2 uv, + vec2 offset ) { + + // Return color from the specified location. + return texture(tex, uv + offset); + +} + +// --------------------- +// Grayscale functions. + +// Return grayscaled image based off of the selected color channel. +vec3 Grayscale( vec3 color, int index ) { + int selectedChannel = clamp(index, 0, 2); // [0]r, [1]g, [2]b. + return ToVec3(color[selectedChannel]); +} + +// Return grayscaled image based off of the selected color channel. +vec4 Grayscale( vec4 color, int index ) { + int selectedChannel = clamp(index, 0, 3); // [0]r, [1]g, [2]b, [3]a. + return ToVec4(color[selectedChannel]); +} + +// Default to green color channel when no index is supplied. +vec3 Grayscale( vec3 color ) { return Grayscale(color, 1); } +vec4 Grayscale( vec4 color ) { return Grayscale(color, 1); } + +// --------------------- +// Luminance functions. + +// Map RGB to Luminance linearly. +float LinearRGBLuminance( vec3 color ) { + + // Weights for relative luma from here: https://en.wikipedia.org/wiki/Luma_(video) + vec3 weight = vec3(0.2126729, 0.7151522, 0.0721750); + + // Get the dot product: + // - color.r * weight.r + color.g * weight.g + color.b * weight*b. + return dot(color, weight); +} + +// Luminance based off of the original specification. +float FXAALuminance( vec3 color ) { + + #if FXAA_LUMINANCE == 0 + + return LinearRGBLuminance( color ); + + #else + + return color.g * (0.587/0.299) + color.r; + + #endif +} + +// --------------------- +// Vertical/Horizontal Edge Test functions. + +float FXAAVerticalEdge( float lumaO, + float lumaN, + float lumaE, + float lumaS, + float lumaW, + float lumaNW, + float lumaNE, + float lumaSW, + float lumaSE ) { + + // Slices to calculate. + float top = (0.25 * lumaNW) + (-0.5 * lumaN) + (0.25 * lumaNE); + float middle = (0.50 * lumaW ) + (-1.0 * lumaO) + (0.50 * lumaE ); + float bottom = (0.25 * lumaSW) + (-0.5 * lumaS) + (0.25 * lumaSE); + + // Return value. + return abs(top) + abs(middle) + abs(bottom); +} + +float FXAAHorizontalEdge( float lumaO, + float lumaN, + float lumaE, + float lumaS, + float lumaW, + float lumaNW, + float lumaNE, + float lumaSW, + float lumaSE ) { + + // Slices to calculate. + float top = (0.25 * lumaNW) + (-0.5 * lumaW) + (0.25 * lumaSW); + float middle = (0.50 * lumaN ) + (-1.0 * lumaO) + (0.50 * lumaS ); + float bottom = (0.25 * lumaNE) + (-0.5 * lumaE) + (0.25 * lumaSE); + + // Return value. + return abs(top) + abs(middle) + abs(bottom); +} + +// ------------------------ +// FXAA specific functions. +// ------------------------ + +// Entry point for the FXAA process. +vec3 applyFXAA(sampler2D textureSource, + vec2 textureDimensions, + vec2 pixelPosition, + vec2 screenResolution) { + + // Normalized pixel coordinates (from 0 to 1). + vec2 uv = pixelPosition / screenResolution; + + // Calculate distance between pixels in texture space. + vec2 texel = vec2(1.0, 1.0) / textureDimensions; + + // Caculate the luminance. + // float luma = FXAALuminance(rgbO.xyz); + // float luma = LinearRGBLuminance(clamp(rgbO.xyz, 0.0, 1.0)); + + //------------------------- + // 1. LOCAL CONTRAST CHECK + + // Sample textures from cardinal directions. + vec3 rgbN = TextureOffset(textureSource, uv, vec2(0, -texel.y)).rgb; // NORTH + vec3 rgbW = TextureOffset(textureSource, uv, vec2(-texel.x, 0)).rgb; // WEST + vec3 rgbO = TextureOffset(textureSource, uv, vec2(0, 0)).rgb; // ORIGIN + vec3 rgbE = TextureOffset(textureSource, uv, vec2(texel.x, 0)).rgb; // EAST + vec3 rgbS = TextureOffset(textureSource, uv, vec2(0, texel.y)).rgb; // SOUTH + + #if FXAA == 0 + return rgbO; // Skip FXAA if it is off. + #endif + + // Calculate the luminance for each sampled value. + float lumaN = FXAALuminance(rgbN); + float lumaW = FXAALuminance(rgbW); + float lumaO = FXAALuminance(rgbO); + float lumaE = FXAALuminance(rgbE); + float lumaS = FXAALuminance(rgbS); + + // Calculate the minimum luma range. + float minLuma = min( lumaO, min( min( lumaN, lumaW ), min( lumaS, lumaE ) ) ); + float maxLuma = max( lumaO, max( max( lumaN, lumaW ), max( lumaS, lumaE ) ) ); + float localContrast = maxLuma - minLuma; + + // Check for early exit. + if(localContrast < max( FXAA_EDGE_THRESHOLD_MIN, maxLuma * FXAA_EDGE_THRESHOLD )) { + + #if FXAA_DEBUG_SKIPPED + + return vec3(0); + + #else + + return rgbO; + + #endif + } + + //------------------------- + // 2. SUB-PIXEL ALIASING TEST + + // Calculate the pixel contrast ratio. + // - Sub-pixel aliasing is detected by taking the ratio of the + // pixel contrast over the local contrast. This ratio nears 1.0 + // in the presence of single pixel dots and otherwise falls off + // towards 0.0 as more pixels contribute to an edge. This ratio + // is transformed into the amount of lowpass filter to blend in + // at the end of the algorithm. + + #if FXAA_SUBPIX > 0 + + // Calculate sum of local samples for the lowpass. + vec3 rgbL = (rgbN + rgbW + rgbO + rgbE + rgbS); + + #if FXAA_SUBPIX_FASTER + + // Average the lowpass now since this skips the addition of the diagonal neighbors (NW, NE, SW, SE). + rgbL *= (1.0/5.0); + + #endif + + // Calculate the lowpass luma. + // - Lowpass luma is calculated as the average between the luma of neigboring pixels. + float lumaL = (lumaN + lumaW + lumaS + lumaE) * 0.25; + + // Calculate the pixel contrast. + // - Pixel contrast is the abs() difference between origin pixel luma and lowpass luma of neighbors. + float pixelContrast = abs(lumaL - lumaO); + + // Remember: + // - pixel contrast is the origin - lowpass(neighbors). + // - local contrast is the min(origin + neighbors) - max(origin + neighbors) < threshold. + + // Calculate the ratio between the pixelContrast and localContrast. + float contrastRatio = pixelContrast / localContrast; + float lowpassBlend = 0.0; // Default is zero. Will be changed depending on subpixel level. + + #if FXAA_SUBPIX == 1 + + // Normal subpixel aliasing. Set based on FXAA algorithm for subpixel aliasing. + lowpassBlend = max( 0.0, contrastRatio - FXAA_SUBPIX_TRIM ) * FXAA_SUBPIX_TRIM_SCALE; + lowpassBlend = min( FXAA_SUBPIX_CAP, lowpassBlend ); + + #elif FXAA_SUBPIX == 2 + + // Full force subpixel aliasing. Set blend to ratio. + lowpassBlend = contrastRatio; + + #endif + + #endif + + // Show selected pixels if debug mode is active. + #if FXAA_DEBUG_PASSTHROUGH + + #if FXAA_SUBPIX > 0 + + return vec3(localContrast, lowpassBlend, 0.0); + + #else + + return vec3(localContrast, 0.0, 0.0); + + #endif + + #endif + + //------------------------- + // 3. VERTICAL & HORIZONTAL EDGE TEST + + // Sample the additional diagonal neighbors. + vec3 rgbNW = TextureOffset(textureSource, uv, vec2(-texel.x, -texel.y)).rgb; // NORTH-WEST + vec3 rgbNE = TextureOffset(textureSource, uv, vec2(texel.x, -texel.y)).rgb; // NORTH-EAST + vec3 rgbSW = TextureOffset(textureSource, uv, vec2(-texel.x, texel.y)).rgb; // SOUTH-WEST + vec3 rgbSE = TextureOffset(textureSource, uv, vec2(texel.x, texel.y)).rgb; // SOUTH-EAST + + // Average additional neighbors when sub-pix aliasing is on and it isn't in 'fast' mode. + #if FXAA_SUBPIX > 0 + #if FXAA_SUBPIX_FASTER == 0 + // Add missing neighbors and average them. + rgbL += (rgbNW + rgbNE + rgbSW + rgbSE); + rgbL *= (1.0/9.0); + #endif + #endif + + // Calculate luma for additional neighbors. + float lumaNW = FXAALuminance(rgbNW); + float lumaNE = FXAALuminance(rgbNE); + float lumaSW = FXAALuminance(rgbSW); + float lumaSE = FXAALuminance(rgbSE); + + // Calculate the vertical and horizontal edges. (Uses algorithm from FXAA white paper). + float edgeVert = FXAAVerticalEdge(lumaO, lumaN, lumaE, lumaS, lumaW, lumaNW, lumaNE, lumaSW, lumaSE); + float edgeHori = FXAAHorizontalEdge(lumaO, lumaN, lumaE, lumaS, lumaW, lumaNW, lumaNE, lumaSW, lumaSE); + + // Check if edge is horizontal. + bool isHorizontal = edgeHori >= edgeVert; + + #if FXAA_DEBUG_HORZVERT + if(isHorizontal) + { + return vec3(1.0, 0.75, 0.0); + } + else + { + return vec3(0.10, 0.10, 1.0); + } + #endif + + //------------------------- + // 4. FIND HIGHEST CONTRAST PAIR 90deg TO EDGE + + // Contain the appropriate sign for the top left. + float edgeSign = isHorizontal ? -texel.y : -texel.x; // Note, if isHorizontal == true, -texel.y is applied (not -texel.x). + + // Calculate the gradients. The luma used changes based on the horizontal edge status. + float gradientNeg = isHorizontal ? abs(lumaN - lumaO) : abs(lumaW - lumaO); + float gradientPos = isHorizontal ? abs(lumaS - lumaO) : abs(lumaE - lumaO); + + // Calculate the luma based on its direction. + // It is an average of the origin and the luma in the respective direction. + float lumaNeg = isHorizontal ? ((lumaN + lumaO) * 0.5) : ((lumaW + lumaO) * 0.5); + float lumaPos = isHorizontal ? ((lumaS + lumaO) * 0.5) : ((lumaE + lumaO) * 0.5); + + // Select the highest gradient pair. + bool isNegative = (gradientNeg >= gradientPos); + float gradientHighest = isNegative ? gradientNeg : gradientPos; // Assign higher pair. + float lumaHighest = isNegative ? lumaNeg : lumaPos; + + // If gradient pair in the negative direction is higher, flip the edge sign. + if(isNegative) { edgeSign *= -1.0; } + + #if FXAA_DEBUG_PAIR + return isHorizontal ? vec3(0.0, gradientHighest, lumaHighest) : vec3(0.0, lumaHighest, gradientHighest); + #endif + + //------------------------- + // 5. END-OF-EDGE SEARCH + + // Select starting point. + vec2 pointN = vec2(0.0, 0.0); + pointN.x = uv.x + (isHorizontal ? 0.0 : edgeSign * 0.5); + pointN.y = uv.y + (isHorizontal ? edgeSign * 0.5 : 0.0); + + // Assign search limiting values. + gradientHighest *= FXAA_SEARCH_THRESHOLD; + + // Prepare variables for search. + vec2 pointP = pointN; // Start at the same point. + vec2 pointOffset = isHorizontal ? vec2(texel.x, 0.0) : vec2(0.0, texel.y); + float lumaNegEnd = lumaNeg; + float lumaPosEnd = lumaPos; + bool searchNeg = false; + bool searchPos = false; + + // Apply values based on FXAA flags. + if(FXAA_SEARCH_ACCELERATION == 1) { + + pointN += pointOffset * vec2(-1.0); + pointP += pointOffset * vec2(1.0); + // pointOffset *= vec2(1.0); + + } else if(FXAA_SEARCH_ACCELERATION == 2) { + + pointN += pointOffset * vec2(-1.5); + pointP += pointOffset * vec2(1.5); + pointOffset *= vec2(2.0); + + } else if(FXAA_SEARCH_ACCELERATION == 3) { + + pointN += pointOffset * vec2(-2.0); + pointP += pointOffset * vec2(2.0); + pointOffset *= vec2(3.0); + + } else if(FXAA_SEARCH_ACCELERATION == 4) { + + pointN += pointOffset * vec2(-2.5); + pointP += pointOffset * vec2(2.5); + pointOffset *= vec2(4.0); + + } + + // Perform the end-of-edge search. + for(int i = 0; i < FXAA_SEARCH_STEPS; i++) + { + if(FXAA_SEARCH_ACCELERATION == 1) { + if(!searchNeg) { lumaNegEnd = FXAALuminance(texture(textureSource, pointN).rgb); } + if(!searchPos) { lumaPosEnd = FXAALuminance(texture(textureSource, pointP).rgb); } + } + else + { + if(!searchNeg) { lumaNegEnd = FXAALuminance(textureGrad(textureSource, pointN, pointOffset, pointOffset).rgb); } + if(!searchPos) { lumaPosEnd = FXAALuminance(textureGrad(textureSource, pointP, pointOffset, pointOffset).rgb); } + } + + // Search for significant change in luma compared to current highest pair. +#if 0 // original + searchNeg = searchNeg || (abs(lumaNegEnd - lumaNeg) >= gradientNeg); + searchPos = searchPos || (abs(lumaPosEnd - lumaPos) >= gradientPos); +#else // iradicator's fix + searchNeg = searchNeg || (abs(lumaNegEnd - lumaHighest) >= gradientHighest); + searchPos = searchPos || (abs(lumaPosEnd - lumaHighest) >= gradientHighest); +#endif + + // Display debug information regarding edges. + #if FXAA_DEBUG_NEGPOS + + if(searchNeg) { + return vec3(abs(lumaNegEnd - gradientNeg), 0.0, 0.0); + } else if(searchPos) { + return vec3(0.0, 0.0, abs(lumaPosEnd - gradientPos)); + } + + #endif + + // Determine if search is over early. + if(searchNeg && searchPos) { break; } + + // If still searching, increment offset. + if(!searchNeg) { pointN -= pointOffset; } + if(!searchPos) { pointP += pointOffset; } + } + + //------------------------- + // 6. SUB-PIXEL SHIFT + + // Determine if sub-pixel center falls on positive or negative side. + float distanceNeg = isHorizontal ? uv.x - pointN.x : uv.y - pointN.y; + float distancePos = isHorizontal ? pointP.x - uv.x : pointP.y - uv.y; + bool isCloserToNegative = distanceNeg < distancePos; + + // Assign respective luma. + float lumaEnd = isCloserToNegative ? lumaNegEnd : lumaPosEnd; + + // Check if pixel is in area that receives no filtering. + if( ((lumaO - lumaNeg) < 0.0) == ((lumaEnd - lumaNeg) < 0.0) ) { + edgeSign = 0.0; + } + + // Compute sub-pixel offset and filter span. + float filterSpanLength = (distancePos + distanceNeg); + float filterDistance = isCloserToNegative ? distanceNeg : distancePos; + float subpixelOffset = ( 0.5 + ( filterDistance * (-1.0 / filterSpanLength) ) ) * edgeSign; + + #if FXAA_DEBUG_OFFSET + + if(subpixelOffset < 0.0) { + return isHorizontal ? vec3(1.0, 0.0, 0.0) : vec3(1.0, 0.7, 0.1); // neg-horizontal (red) : neg-vertical (gold) + } + + if(subpixelOffset > 0.0) { + return isHorizontal ? vec3(0.0, 0.0, 1.0) : vec3(0.1, 0.3, 1.0); // pos-horizontal (blue) : pos-vertical (skyblue) + } + + #endif + + // Resample using the subpixel offset. + vec3 rgbOffset = textureLod(textureSource, vec2( uv.x + (isHorizontal ? 0.0 : subpixelOffset), uv.y + (isHorizontal ? subpixelOffset : 0.0)), 0.0).rgb; + + // return vec3((lumaN + lumaS + lumaE + lumaW + lumaNW + lumaNE + lumaSW + lumaSE) * (1.0/9.0)); + + #if FXAA_DEBUG_HIGHLIGHT + + return isHorizontal ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0); + + #endif + + // Return the FXAA effect. + #if FXAA_SUBPIX == 0 + + return vec3(rgbOffset); + + #else + + return mix(rgbOffset, rgbL, lowpassBlend); + + #endif +} + +// ------------------------ +// Main function. +// ------------------------ + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + + #if (FXAA == 2) + + vec2 uv = fragCoord/iResolution.xy; // Normalized pixel coordinates (from 0 to 1) + vec3 resultFXAA = vec3(1.0); + + float speed = 0.45; + vec2 extents = vec2(0.1, 0.8); + float divisor = ( ((sin(iTime * speed) * 0.5) + 0.5) * extents.y ) + extents.x; + float increment = 0.005; + + float divNeg = divisor - increment; + float divPos = divisor + increment; + + if(uv.x >= divNeg && uv.x <= divPos) { resultFXAA = vec3(0.1); } + if(uv.x < divNeg) { resultFXAA = mix(texture(iChannel0, vec2(uv.x, uv.y)).xyz, vec3(0.9, 0.9, 0.9), 0.1); } + if(uv.x > divPos) { resultFXAA = applyFXAA(iChannel0, iChannelResolution[0].xy, fragCoord, iResolution.xy); } + + #else + + // Calculuate the FXAA value for the whole screen. + vec3 resultFXAA = applyFXAA(iChannel0, iChannelResolution[0].xy, fragCoord, iResolution.xy); + + #endif + + // Return the sampled pixel. + fragColor = ToVec4(resultFXAA, 1.0); +} \ No newline at end of file diff --git a/demos/html5/art/fx/fxGrain.fs b/demos/html5/art/fx/fxGrain.fs new file mode 100644 index 0000000..105b0d3 --- /dev/null +++ b/demos/html5/art/fx/fxGrain.fs @@ -0,0 +1,14 @@ +uniform float intensity = 16.0; + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 color = texture(iChannel0, uv), outcolor; + + float x = (uv.x + 4.0 ) * (uv.y + 4.0 ) * (iTime * 10.0); + vec4 grain = vec4(mod((mod(x, 13.0) + 1.0) * (mod(x, 123.0) + 1.0), 0.01)-0.005) * intensity; + + outcolor = color + grain; // method 1 + // outcolor = color * (1.0 - grain); // method 2 + + FRAGCOLOR = vec4(outcolor.rgb, color.a); +} diff --git a/demos/html5/art/fx/fxHSV.fs b/demos/html5/art/fx/fxHSV.fs new file mode 100644 index 0000000..db98dfc --- /dev/null +++ b/demos/html5/art/fx/fxHSV.fs @@ -0,0 +1,25 @@ +uniform float h = 1.0; // tint shift +uniform float s = 0.5; // saturate: >1, decolorize: <1 +uniform float v = 1.0; // white: >1, gray: <1 + +vec3 hsv2rgb(vec3 c) { + return mix(vec3(1.),clamp((abs(fract(c.r+vec3(3.,2.,1.)/3.)*6.-3.)-1.),0.,1.),c.g)*c.b; +} + +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +void main() { + vec2 uv = TEXCOORD.st; + vec4 src = texture2D( iChannel0, uv ); + + vec3 c = rgb2hsv(src.rgb); + + FRAGCOLOR = vec4( hsv2rgb(c * vec3(h,s,v)), src.a ); +} diff --git a/demos/html5/art/fx/fxLetterbox.fs b/demos/html5/art/fx/fxLetterbox.fs new file mode 100644 index 0000000..85fff18 --- /dev/null +++ b/demos/html5/art/fx/fxLetterbox.fs @@ -0,0 +1,11 @@ +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + // letterbox + if( abs(2.*fragCoord.y-iResolution.y) > iResolution.x * 0.42 ) { + fragColor = vec4( 0., 0., 0., 1. ); + return; + } + + vec2 uv = fragCoord.xy / iResolution.xy; + fragColor = texture(iChannel0, uv); +} diff --git a/demos/html5/art/fx/fxOutline.fs b/demos/html5/art/fx/fxOutline.fs new file mode 100644 index 0000000..9f2c8f7 --- /dev/null +++ b/demos/html5/art/fx/fxOutline.fs @@ -0,0 +1,19 @@ +uniform int thickness = 2; +uniform vec4 border_color = vec4(1,1,0,1); + +void main() { + vec4 texel = texture(iChannel0, uv); + float outline = 0.0; + if( texel.a == 0.0 ) { + for( int x = -thickness; x <= thickness; x++ ) { + for( int y = -thickness;y <= thickness; y++ ) { + float sample = texture(iChannel0, uv+vec2(float(x)/iWidth, float(y)/iHeight)).a; + if( sample > 0.0 ) { + outline = 1.0; + } + } + } + } + + FRAGCOLOR = mix(texel, border_color, outline * border_color.a); +} \ No newline at end of file diff --git a/demos/html5/art/fx/fxPixelate.fs b/demos/html5/art/fx/fxPixelate.fs new file mode 100644 index 0000000..751eeec --- /dev/null +++ b/demos/html5/art/fx/fxPixelate.fs @@ -0,0 +1,8 @@ +uniform float xCellSize = 2.5; +uniform float yCellSize = 2.5; + +void main() { + float xPixels = iWidth/xCellSize, yPixels = iHeight/yCellSize; + vec2 uv = vec2(floor(texcoord.s * xPixels) / xPixels, floor(texcoord.t * yPixels) / yPixels); + FRAGCOLOR = texture(iChannel0, uv); +} diff --git a/demos/html5/art/fx/fxQuantize.fs b/demos/html5/art/fx/fxQuantize.fs new file mode 100644 index 0000000..716ea58 --- /dev/null +++ b/demos/html5/art/fx/fxQuantize.fs @@ -0,0 +1,7 @@ +uniform float factor = 3.0; // [1(max)..255(min)] + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 src = texture(iChannel0, uv); + fragColor = vec4(floor(src.rgb * factor + 0.5) / factor, src.a); +} diff --git a/demos/html5/art/fx/fxSSAO.fs b/demos/html5/art/fx/fxSSAO.fs new file mode 100644 index 0000000..b5a0470 --- /dev/null +++ b/demos/html5/art/fx/fxSSAO.fs @@ -0,0 +1,132 @@ +// based on code by arkano22. See: http://www.gamedev.net/forums/topic/550699-ssao-no-halo-artifacts/ +// - rlyeh, public domain + +uniform vec2 camerarange = vec2(1.0, 1024.0); + +// uniform sampler2D som; // Depth texture (iChannel1) + +#if 0 + +uniform sampler2D rand; // Random texture (iChannel2) + +vec2 getRandom(vec2 uv) { + vec3 random = texture2D(rand, uv.st); + return random*2.0-vec3(1.0); +} + +#else + +#define MOD3 vec3(.1031,.11369,.13787) + +float hash12(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * MOD3); + p3 += dot(p3, p3.yzx + 19.19); + return fract((p3.x + p3.y) * p3.z); +} + +vec2 hash22(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * MOD3); + p3 += dot(p3, p3.yzx+19.19); + return fract(vec2((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y)); +} + +vec3 getPosition(vec2 uv) { + float fl = textureLod(iChannel0, vec2(0.), 0.).x; + float d = textureLod(iChannel0, uv, 0.).w; + + vec2 p = uv*2.-1.; + mat3 ca = mat3(1.,0.,0.,0.,1.,0.,0.,0.,-1./1.5); + vec3 rd = normalize( ca * vec3(p,fl) ); + + vec3 pos = rd * d; + return pos; +} + +vec2 getRandom(vec2 uv) { + return normalize(hash22(uv*126.1231) * 2. - 1.); +} + +#endif + + +float pw = 1.0/iResolution.x*0.5; +float ph = 1.0/iResolution.y*0.5; + +float readDepth(in vec2 coord) { + if (coord.x<0||coord.y<0) return 1.0; + float nearZ = camerarange.x; + float farZ =camerarange.y; + float posZ = texture(iChannel1, coord).x; + return (2.0 * nearZ) / (nearZ + farZ - posZ * (farZ - nearZ)); +} + +float compareDepths(in float depth1, in float depth2,inout int far) { + float diff = (depth1 - depth2)*100; //depth difference (0-100) + float gdisplace = 0.2; //gauss bell center + float garea = 2.0; //gauss bell width 2 + //reduce left bell width to avoid self-shadowing + if (diff 0.0 && coordh < 1.0 && coordh > 0.0){ + vec2 coord = vec2(coordw , coordh); + vec2 coord2 = vec2(coordw2, coordh2); + int far = 0; + temp = compareDepths(depth, readDepth(coord),far); + //DEPTH EXTRAPOLATION: + if (far > 0){ + temp2 = compareDepths(readDepth(coord2),depth,far); + temp += (1.0-temp)*temp2; + } + } + return temp; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + //randomization texture: + vec2 uv = fragCoord.xy / iResolution.xy; + vec2 random = getRandom( uv + vec2(iTime) ); + + //initialize stuff: + float depth = readDepth(uv); + float ao = 0.0; + for(int i=0; i<4;++i) { + //calculate color bleeding and ao: + ao+=calcAO(depth, uv, pw, ph); + ao+=calcAO(depth, uv, pw, -ph); + ao+=calcAO(depth, uv, -pw, ph); + ao+=calcAO(depth, uv, -pw, -ph); + ao+=calcAO(depth, uv, pw*1.2, 0); + ao+=calcAO(depth, uv, -pw*1.2, 0); + ao+=calcAO(depth, uv, 0, ph*1.2); + ao+=calcAO(depth, uv, 0, -ph*1.2); + + //sample jittering: + pw += random.x*0.0007; + ph += random.y*0.0007; + + //increase sampling area: + pw *= 1.7; + ph *= 1.7; + } + + //final values, some adjusting: + vec4 texel = texture(iChannel0, uv); + float finalAO = 1.0-(ao/32.0); finalAO = 0.5+finalAO*0.5; + fragColor = vec4(texel.rgb * vec3(finalAO), texel.a); + //fragColor = vec4(vec3(finalAO), texel.a); // << debug +} diff --git a/demos/html5/art/fx/fxScanlines.fs b/demos/html5/art/fx/fxScanlines.fs new file mode 100644 index 0000000..a7443b0 --- /dev/null +++ b/demos/html5/art/fx/fxScanlines.fs @@ -0,0 +1,14 @@ +uniform float hardness = 0.1; +uniform float flickering = 0.01; + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 src = texture( iChannel0, vec2(uv.x,uv.y) ); + vec3 color = src.rgb; + + color *= (1.0 - hardness)+hardness*sin(10.0*iTime+uv.y*1000.0); + color *= (1.0 - flickering)+flickering*sin(100.0*iTime); + + fragColor = vec4(color, src.a); +} diff --git a/demos/html5/art/fx/fxScreenSpaceDither.fs b/demos/html5/art/fx/fxScreenSpaceDither.fs new file mode 100644 index 0000000..461a1c1 --- /dev/null +++ b/demos/html5/art/fx/fxScreenSpaceDither.fs @@ -0,0 +1,22 @@ +// https://www.shadertoy.com/view/4dcSRX +// https://www.shadertoy.com/view/MslGR8 +// https://www.shadertoy.com/view/Md3XRf * + +// note: valve edition from http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf +// note: input in pixels (ie not normalized uv) + +uniform float intensity = 250.0; // [2..255] + +vec3 ScreenSpaceDither2(vec2 vScreenPos, float colorDepth) { + // lestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR + vec3 vDither = vec3(dot(vec2(131.0, 312.0), vScreenPos.xy + iTime)); + vDither.rgb = fract(vDither.rgb / vec3(103.0, 71.0, 97.0)) - vec3(0.5, 0.5, 0.5); + return (vDither.rgb / colorDepth) * 0.375; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 color = texture(iChannel0, uv); + fragColor = color + vec4(ScreenSpaceDither2(gl_FragCoord.xy,255.0 - intensity), 0); +} diff --git a/demos/html5/art/fx/fxSepia.fs b/demos/html5/art/fx/fxSepia.fs new file mode 100644 index 0000000..fe80b6f --- /dev/null +++ b/demos/html5/art/fx/fxSepia.fs @@ -0,0 +1,14 @@ +uniform float intensity = 1.0; + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + vec4 src = texture(iChannel0, uv); + + vec3 color = vec3( + dot(src.rgb, vec3(0.393 * intensity, 0.769 * intensity, 0.189 * intensity)), + dot(src.rgb, vec3(0.349 * intensity, 0.686 * intensity, 0.168 * intensity)), + dot(src.rgb, vec3(0.272 * intensity, 0.534 * intensity, 0.131 * intensity)) + ); + + fragColor = vec4(color, src.a); +} diff --git a/demos/html5/art/fx/fxSharpen.fs b/demos/html5/art/fx/fxSharpen.fs new file mode 100644 index 0000000..ce6d926 --- /dev/null +++ b/demos/html5/art/fx/fxSharpen.fs @@ -0,0 +1,17 @@ +uniform float intensity = 1.0; + +void mainImage( out vec4 fragColor, in vec2 fragCoord ){ + vec2 uv = fragCoord / iResolution.xy; + vec4 src = texture(iChannel0, uv); + vec3 kernel = src.rgb * 9. + + -1. * texture(iChannel0, uv + vec2(-1,-1) / iResolution.xy).rgb + -1. * texture(iChannel0, uv + vec2( 0,-1) / iResolution.xy).rgb + -1. * texture(iChannel0, uv + vec2( 1,-1) / iResolution.xy).rgb + -1. * texture(iChannel0, uv + vec2(-1, 0) / iResolution.xy).rgb + -1. * texture(iChannel0, uv + vec2( 1, 0) / iResolution.xy).rgb + -1. * texture(iChannel0, uv + vec2(-1, 1) / iResolution.xy).rgb + -1. * texture(iChannel0, uv + vec2( 0, 1) / iResolution.xy).rgb + -1. * texture(iChannel0, uv + vec2( 1, 1) / iResolution.xy).rgb; + vec3 outcolor = mix(src.rgb, kernel, intensity); + fragColor = vec4(outcolor, src.a); +} diff --git a/demos/html5/art/fx/fxTonemapACES.fs b/demos/html5/art/fx/fxTonemapACES.fs new file mode 100644 index 0000000..7eaeb42 --- /dev/null +++ b/demos/html5/art/fx/fxTonemapACES.fs @@ -0,0 +1,17 @@ +// https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ +vec3 acesFilm(const vec3 x) { + const float a = 2.51; + const float b = 0.03; + const float c = 2.43; + const float d = 0.59; + const float e = 0.14; + return clamp((x * (a * x + b)) / (x * (c * x + d ) + e), 0.0, 1.0); +} + +out vec4 color; + +void main(void) { + vec2 uv = TEXCOORD.st; + vec4 src = texture2D(iChannel0, uv); + color = vec4( acesFilm(src.xyz), src.a); +} diff --git a/demos/html5/art/fx/fxTonemapExposure.fs b/demos/html5/art/fx/fxTonemapExposure.fs new file mode 100644 index 0000000..cd3381b --- /dev/null +++ b/demos/html5/art/fx/fxTonemapExposure.fs @@ -0,0 +1,13 @@ +// exposure tone mapping +// https://learnopengl.com/Advanced-Lighting/HDR + +uniform float exposure = 1.0; // [0.1 .. 5] + +out vec4 color; + +void main(void) { + vec2 uv = TEXCOORD.st; + vec4 HDR_color = texture2D(iChannel0, uv); // HDR_color, SRGB texture + vec3 mapped = vec3(1.0) - exp(-HDR_color.xyz * exposure); + color = vec4( mapped.xyz, HDR_color.a ); +} diff --git a/demos/html5/art/fx/fxTonemapFilmic.fs b/demos/html5/art/fx/fxTonemapFilmic.fs new file mode 100644 index 0000000..d51240a --- /dev/null +++ b/demos/html5/art/fx/fxTonemapFilmic.fs @@ -0,0 +1,37 @@ +// Src: http://www.slideshare.net/ozlael/hable-john-uncharted2-hdr-lighting +// Based on Filmic Tonemapping Operators http://filmicgames.com/archives/75 + +vec3 tonemapFilmic(vec3 linearColor) { + vec3 x = max(vec3(0.0), linearColor - 0.004); + return (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06); +} + +// Remember final color = CustomFilmic(Linear color) / CustomFilmic(Linear white point value) : No gamma baked in + +vec3 customFilmic(vec3 linearColor, float shoulderStr, float linearStr, float linearAngle, float toeStr, float toeNumer, float toeDenom) { + return ((linearColor * (shoulderStr * linearColor + linearAngle * linearStr) + toeStr * toeNumer) / (linearColor * (shoulderStr * linearColor + linearStr) + toeStr * toeDenom)) - toeNumer / toeDenom; +} + +// This function applies a "film-like" tonemap to supplied +// HDR pixel. Does not apply 2.2 Gamma correction. +// +// hdr: linear colour in HDR +// whitePoint: scene white point / exposure. must be > 0.0 +// +// src: https://twitter.com/jimhejl/status/841149752389558272 + +vec3 tonemapFilmic_hejl2015(vec3 hdr, float whitePoint) { + vec4 vh = vec4(hdr, whitePoint); + vec4 va = (1.425 * vh) + 0.05f; // evaluate filmic curve + vec4 vf = ((vh * va + 0.004f) / ((vh * (va + 0.55f) + 0.0491f))) - 0.0821f; + return vf.rgb / vf.www; +} + +out vec4 color; + +void main(void) { + vec2 uv = TEXCOORD.st; + vec4 src = texture2D(iChannel0, uv); + color = vec4( tonemapFilmic_hejl2015(src.xyz, 0.5), src.a); + // ccolor = vec4( tonemapFilmic(src.xyz), src.a); +} diff --git a/demos/html5/art/fx/fxTonemapIlford.fs b/demos/html5/art/fx/fxTonemapIlford.fs new file mode 100644 index 0000000..29a71ac --- /dev/null +++ b/demos/html5/art/fx/fxTonemapIlford.fs @@ -0,0 +1,45 @@ +#define lerp(a,b,c) mix(a,b,c) +#define saturate(c) clamp(c, 0.0, 1.0) + +// This function approximates the black and white film stock +// "Ilford FP4" pushed to 400 ISO. It is typical for noir style. This +// tonal transformation does not approximate gamma 2.2, so an explicit +// sRGB transform should be performed before display. +// +// vec3 hdr (IN): Color pixel in linear space +// vec2 uv (IN): Screen space UV for vignette +// +// returns Filmic remapped pixel in gamma 1.0 space +// src: pic.twitter.com/7ZSMM5RRMz +// + +vec3 PostFilmic_IlfordFp4Push(vec3 c, vec2 uv) { + // film curve coefficients + const vec3 cb = vec3( 0.0307479, 0.00030400, -0.04458630); + const vec3 de = vec3(-0.0095000, -0.00162400, -0.01736670); + const vec3 df = vec3( 0.1493590, 0.21412400, 1.85780000); + const vec3 ef = vec3(-0.0636051, -0.00758438, -0.00934798); + + c = c * c * 1.88; // quick approximation of skip bleach + + // remap color channels + vec3 ax = vec3(2.36691,5.14272,0.49020)*c; + vec3 pn = (c*(ax+cb)+de); + vec3 pd = (c*(ax+vec3(0.022,0.004,-0.10543))+df); + + // collapse color channels + float pr = dot(saturate(pn/pd),vec3(0.45,0.45,0.45)); + + // vignette + float pv = saturate(pow(1.0 - dot(uv-.5, uv-.5), -.758) + -.23); + float x = lerp(pr,pr*pr*pr,pv); // done + return vec3(x,x,x); +} + +out vec4 color; + +void main(void) { + vec2 uv = TEXCOORD.st; + vec4 src = texture2D(iChannel0, uv); + color = vec4( PostFilmic_IlfordFp4Push(src.xyz, uv), src.a); +} diff --git a/demos/html5/art/fx/fxTonemapReinhard.fs b/demos/html5/art/fx/fxTonemapReinhard.fs new file mode 100644 index 0000000..6e27035 --- /dev/null +++ b/demos/html5/art/fx/fxTonemapReinhard.fs @@ -0,0 +1,38 @@ +// https://www.shadertoy.com/view/lslGzl + +vec3 tonemapReinhard(const vec3 color) { +// color *= toneMappingExposure; + return color / (color + vec3(1.0)); +} + +vec3 simpleReinhardToneMapping(vec3 color) +{ + float exposure = 1.5; + color *= exposure/(1. + color / exposure); + return color; +} + +vec3 lumaBasedReinhardToneMapping(vec3 color) +{ + float luma = dot(color, vec3(0.2126, 0.7152, 0.0722)); + float toneMappedLuma = luma / (1. + luma); + color *= toneMappedLuma / luma; + return color; +} + +vec3 whitePreservingLumaBasedReinhardToneMapping(vec3 color) +{ + float white = 2.; + float luma = dot(color, vec3(0.2126, 0.7152, 0.0722)); + float toneMappedLuma = luma * (1. + luma / (white*white)) / (1. + luma); + color *= toneMappedLuma / luma; + return color; +} + +out vec4 color; + +void main(void) { + vec2 uv = TEXCOORD.st; + vec4 src = texture2D(iChannel0, uv); + color = vec4( whitePreservingLumaBasedReinhardToneMapping(src.xyz), src.a); +} diff --git a/demos/html5/art/fx/fxTonemapUncharted.fs b/demos/html5/art/fx/fxTonemapUncharted.fs new file mode 100644 index 0000000..157910d --- /dev/null +++ b/demos/html5/art/fx/fxTonemapUncharted.fs @@ -0,0 +1,27 @@ +// https://www.shadertoy.com/view/lslGzl + +vec3 uncharted2Tonemap(const vec3 x) { + const float A = 0.15; + const float B = 0.50; + const float C = 0.10; + const float D = 0.20; + const float E = 0.02; + const float F = 0.30; + return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; +} + +vec3 tonemapUncharted2(const vec3 color) { + const float W = 11.2; + const float exposureBias = 2.0; + vec3 curr = uncharted2Tonemap(exposureBias * color); + vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W)); + return curr * whiteScale; +} + +out vec4 color; + +void main(void) { + vec2 uv = TEXCOORD.st; + vec4 src = texture2D(iChannel0, uv); + color = vec4( tonemapUncharted2(src.xyz), src.a); +} diff --git a/demos/html5/art/fx/fxTonemapZZGamma.fs b/demos/html5/art/fx/fxTonemapZZGamma.fs new file mode 100644 index 0000000..b3545a8 --- /dev/null +++ b/demos/html5/art/fx/fxTonemapZZGamma.fs @@ -0,0 +1,8 @@ +uniform float gamma = 2.2; +out vec4 color; + +void main(void) { + vec2 uv = TEXCOORD.st; + vec4 src = texture2D(iChannel0, uv); + color = vec4( pow(src.xyz, vec3(1.0 / gamma)), src.a); // gamma correction +} diff --git a/demos/html5/art/fx/fxVCR.fs b/demos/html5/art/fx/fxVCR.fs new file mode 100644 index 0000000..2c7c1cc --- /dev/null +++ b/demos/html5/art/fx/fxVCR.fs @@ -0,0 +1,154 @@ +/** + * (c) 2021 FMS_Cat + * Original shader: https://www.shadertoy.com/view/MdffD7 + * I dumbass don't know what it says despite it's my own shader + */ +/* + * Copyright 2021 FMS_Cat + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#define half2 vec2 +#define half3 vec3 +#define half4 vec4 +#define saturate(c) clamp(c, 0.0, 1.0) + +//uniform float iTime; +uniform float iScale; +//uniform vec2 iResolution; +uniform vec4 iBackground; + +const float PI = 3.14159265f; + +const int SAMPLES = 6; + +const float COLOR_NOISE_AMP = 0.1f; +const vec3 YIQ_OFFSET = vec3( -0.1f, -0.1f, 0.0f ); +const vec3 YIQ_AMP = vec3( 1.2f, 1.1f, 1.5f ); + +bool validuv( vec2 uv ) +{ + return 0.0f < uv.x && uv.x < 1.0f && 0.0f < uv.y && uv.y < 1.0f; +} + +vec2 yflip( vec2 uv ) +{ + return vec2( uv.x, 1.0 - uv.y ); +} + +float fs( float s ) +{ + return fract( sin( s * 114.514f ) * 1919.810f ); +} + +float fs2( vec2 s ) +{ + return fs( s.x + fs( s.y ) ); +} + +mat2x2 rotate2D( float t ) +{ + return mat2x2( cos( t ), sin( t ), -sin( t ), cos( t ) ); +} + +vec3 rgb2yiq( vec3 rgb ) +{ + return mat3x3( 0.299f, 0.596f, 0.211f, 0.587f, -0.274f, -0.523f, 0.114f, -0.322f, 0.312f ) * rgb; +} + +vec3 yiq2rgb( vec3 yiq ) +{ + return mat3x3( 1.000f, 1.000f, 1.000f, 0.956f, -0.272f, -1.106f, 0.621f, -0.647f, 1.703f ) * yiq; +} + +float v2Random( vec2 v ) +{ + vec2 vf = fract( v * 256.0f ); + vec2 vi = floor( v * 256.0f ) / 256.0f; + vec2 d = vec2( 0.0f, 1.0f / 256.0f ); + + return mix( + mix( fs2( vi + d.xx ), fs2( vi + d.yx ), vf.x ), + mix( fs2( vi + d.xy ), fs2( vi + d.yy ), vf.x ), + vf.y + ); +} + +half3 vhsTex2D( vec2 uv ) { + if ( validuv( uv ) ) { + half3 yiq = half3( 0.0f, 0.0f, 0.0f ); + for ( int i = 0; i < SAMPLES; i ++ ) { + vec2 uvt = uv - vec2( float( i ), 0.0f ) / iResolution; + if ( validuv( uvt ) ) { + half4 tex = texture(iChannel0, uvt ); + yiq += ( + rgb2yiq( mix( iBackground.rgb, tex.rgb, tex.a ) ) * + vec2( float( i ), float( SAMPLES - 1 - i ) ).yxx / float( SAMPLES - 1 ) + ) / float( SAMPLES ) * 2.0f; + } + } + return yiq2rgb( yiq ); + } + return half3( 0.1f, 0.1f, 0.1f ); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec2 uvt = yflip( uv ); + vec3 col = vec3( 0.0f, 0.0f, 0.0f ); + + // tape wave + uvt.x += ( v2Random( vec2( uvt.y / 10.0f, iTime / 10.0f ) / 1.0f ) - 0.5f ) / iResolution.x * 1.0f; + uvt.x += ( v2Random( vec2( uvt.y, iTime * 10.0f ) ) - 0.5f ) / iResolution.x * 1.0f; + + // tape crease + float tcPhase = smoothstep( 0.9f, 0.96f, sin( uvt.y * 8.0f - ( iTime + 0.14f * v2Random( iTime * vec2( 0.67f, 0.59f ) ) ) * PI * 1.2f ) ); + float tcNoise = smoothstep( 0.3f, 1.0f, v2Random( vec2( uvt.y * 4.77f, iTime ) ) ); + float tc = tcPhase * tcNoise; + uvt.x = uvt.x - tc / iResolution.x * 8.0f; + + // switching noise + float snPhase = smoothstep( 6.0f / iResolution.y, 0.0f, uvt.y ); + uvt.y += snPhase * 0.3f; + uvt.x += snPhase * ( ( v2Random( vec2( uv.y * 100.0f, iTime * 10.0f ) ) - 0.5f ) / iResolution.x * 24.0f ); + + // fetch + half4 tex = texture(iChannel0, uv); + half3 color = vhsTex2D( yflip( uvt ) ); + color = pow( color, vec3(0.4545f) ); + + // crease noise + float cn = tcNoise * ( 0.3f + 0.7f * tcPhase ); + if ( 0.29f < cn ) { + vec2 uvtt = ( uvt + vec2( 1.0f, 0.0f ) * v2Random( vec2( uvt.y, iTime ) ) ) * vec2( 0.1f, 1.0f ); + float n0 = v2Random( uvtt ); + float n1 = v2Random( uvtt + vec2( 1.0f, 0.0f ) / iResolution.x ); + if ( n1 < n0 ) { + color = mix( color, vec3( 2.0f, 2.0f, 2.0f ), pow( n0, 10.0f ) ); + } + } + + // ac beat + color *= 1.0f + 0.1f * smoothstep( 0.4f, 0.6f, v2Random( vec2( 0.0f, 0.1f * ( uv.y + iTime * 0.2f ) ) / 10.0f ) ); + + // color noise + half2 noiseuv = uvt + vec2( fs( iTime ), fs( iTime / 0.7f ) ); + half3 noise = half3( + v2Random( noiseuv ), + v2Random( noiseuv + 0.7f ), + v2Random( noiseuv + 1.4f ) + ); + color = saturate( color ); + + // yiq + color = rgb2yiq( color ); + color += COLOR_NOISE_AMP * ( noise - 0.5f ); + color = YIQ_OFFSET + YIQ_AMP * color; + color = yiq2rgb( color ); + color = pow( color, vec3(2.2f) ); + + fragColor = half4( color, tex.a ); +} diff --git a/demos/html5/art/fx/fxVignette.fs b/demos/html5/art/fx/fxVignette.fs new file mode 100644 index 0000000..9d05359 --- /dev/null +++ b/demos/html5/art/fx/fxVignette.fs @@ -0,0 +1,12 @@ +uniform float vignette = 0.75; + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { + vec2 uv = fragCoord.xy / iResolution.xy; + + vec4 src = texture( iChannel0, uv ); + vec3 color = src.rgb; + + color *= (1.0 - vignette) + vignette * 16.0 * uv.x * uv.y * (1.0-uv.x) * (1.0-uv.y); + + fragColor = vec4(color, src.a); +} diff --git a/demos/html5/art/icons/logo.ai b/demos/html5/art/icons/logo.ai new file mode 100644 index 0000000..5d05690 --- /dev/null +++ b/demos/html5/art/icons/logo.ai @@ -0,0 +1,208 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + Adobe Illustrator CS6 (Macintosh) + 2015-12-25T23:34:04+01:00 + 2015-12-25T23:34:04+01:00 + 2015-12-25T23:34:04+01:00 + + + + 256 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FUo8w+b/LHl2D19b1O3sEIqqyuA7f6kYq7f7EYq8s8w/wDOU3k2yLR6LYXWrSDpK1LWE/Jn DyffHirzzWf+covP92WXTrey0yL9krG00o+bSMUP/AYqw7Ufzi/M/UCTP5kvEr1+ruLb/kwI8VSC 78z+ZLyv1vVry4rsfVuJXrvX9pj3xVL5Z5pmDSyNIwFAzksaeG+KuinmhYtFI0bEULISpp4bYqmF p5n8yWdPqmrXlvTYelcSpTev7LDviqf6d+cX5n6eQYPMl49On1hxc/8AJ8SYqzHRv+co/P8AaELq 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 + + + + + + 1 + False + False + + 500.000000 + 300.000000 + Pixels + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + + + Document + + + application/pdf + + + free_logo_2 + + + + + proof:pdf + uuid:3d80f318-a73b-8d4a-83a0-aa7625a338e9 + uuid:5b825168-1d11-5942-b0fd-1d4846b03e6f + + + Adobe PDF library 10.01 + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 7 0 obj <>/Resources<>/Properties<>>>/Thumb 11 0 R/TrimBox[0.0 0.0 500.0 300.0]/Type/Page>> endobj 8 0 obj <>stream +HTRj@ +t.X^@!4~iJ]HzW^fh4c{~Ec`+0)zx +]r`EQG} Ji. +(7t.RF1G=▧zPihLCB*= +W%6&Z)9WKؑRl=zpQC{ eW2#Ol];@$76q\Nm⸼{$HJ$'T,*̢@^XJ36wY?lin&UI{BmZ\p? 6t endstream endobj 11 0 obj <>stream +8;Z]`;$t)]#R92hH2k3qSZsnIqh+e]H5Q7QM-m\g:%]#*OYRp(Z*]RDoMEeOX7_)r +\&pDInORVnSTaUX#JRV/I-[qIhAd;+2948oNP#+U?5t]ZX4=S[[.nn[H6BEc=:JEm +*[d#j>:MhSBUMrtA endstream endobj 12 0 obj [/Indexed/DeviceRGB 255 13 0 R] endobj 13 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <> endobj 14 0 obj [/View/Design] endobj 15 0 obj <>>> endobj 10 0 obj <> endobj 9 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 16.0 %%AI8_CreatorVersion: 16.0.0 %%For: (Karim Amrani) () %%Title: (free_logo_2.fxg) %%CreationDate: 25/12/15 23:34 %%Canvassize: 16383 %%BoundingBox: 132 -264 358 -37 %%HiResBoundingBox: 132 -263.7998 357.9502 -37.8501 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 12.0 %AI12_BuildNumber: 682 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0 0 ([Registration]) %AI3_Cropmarks: 0 -300 500 0 %AI3_TemplateBox: 249.5 -149.5 249.5 -149.5 %AI3_TileBox: -153 -429.5 630 129.5 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 6 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI9_OpenToView: -306 222 1 1114 753 26 0 0 78 134 0 0 0 1 1 0 1 1 0 1 %AI5_OpenViewLayers: 7 %%PageOrigin:-150 -550 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 18 0 obj <>stream +%%BoundingBox: 132 -264 358 -37 %%HiResBoundingBox: 132 -263.7998 357.9502 -37.8501 %AI7_Thumbnail: 128 128 8 %%BeginData: 8090 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD35FFA8A87D7D52522752FD0527522752527D7DA87DA8A8FD64FF %A87D52522727F827F8272727F8FD0927F827F8FD04277D7DA8A8FD5CFF7D %7D2727F8FD1B27F827275252A8A8FD56FF7D522727F8FD2327F827277DA8 %FD50FFA852FD2D275252A8FD4CFF7D2727F8FD1527F827F827F8FD1527F8 %527DFD48FF7D52FD1727FD04527D52522752FD17277DFD44FF7D2727F8FD %0B27F8FD04277D7DA8A8FFA8FFA8FD07FFA8FFA8A87D7D52522727F827F8 %FD0B27F8277DFD40FFA852FD0F27527DA8A8FD19FFA87D5252FD0F27A8FD %3DFF5227F8FD0927F827277D7DFD21FFA8A85227F8FD0B27F87DA8FD39FF %A8FD0D27527DFD28FFA852FD0B27F8527DFD36FFA87DF8FD0927F82752A8 %FD2CFFA87D2727F8FD0727F82752FD34FFA852FD0B277DA8FD31FF52FD0C %27FD32FF7D27F8FD0727F82752A8FD34FFA87DFD0A27F8A8FD2FFF52FD0A %2752A8FD38FFA852FD0927F87DFD2DFF5227F8FD08277DFD3CFF7D27F8FD %0727F852FD2BFF52FD092752FD3FFFA852FD092752FD29FFFD0827F82752 %FD42FF7DF8FD0727F852A8FD26FFFD0A277DFD44FFA8FD092752A8FD24FF %FD0827F852A8FD46FFA8FD0827F852A8FD22FFFD0827F852FD23FFA87D7D %A8FD23FF52FD0727F852FD21FFFD0827F852FD22FFA852F827F82752FD23 %FF52FD0727F852FD1FFF52FD0727F87DFD23FF52FD062752FD23FF52FD07 %27F852FD1DFF52FD0727F852FD23FFA8F8FD0727A8FD23FF52FD0727F87D %FD1BFF7DFD08277DFD24FF52FD0727F8A8FD24FF52FD0827A8FD19FFA8FD %0727F87DFD24FFA8FD0A27FD25FF52FD0827A8FD18FF52FD072752FD25FF %7DFD0A277DFD25FF52FD0827FD17FF7DF8FD0527F852A8FD25FFFD0A27F8 %52FD26FFFD082752FD15FFA8FD0827A8FD25FF7DFD0C27FD27FFFD08277D %FD14FFFD08277DFD26FF52F8FD0B2752FD26FFA8F8FD0727A8FD12FF52FD %07277DFD26FFA8FD0E27A8FD26FF7DF8FD06277DFD11FF7DFD0827FD27FF %52FD0D27F87DFD27FF52F8FD0527F8A8FD10FF52FD0727FD27FFA8FD1027 %FD27FFA8FD0827FD0FFF7DF8FD0527F87DFD27FF7DF8FD0F277DFD27FF7D %FD07277DFD0EFFFD072752FD28FFFD112752FD28FFFD072752FD0DFF7DFD %0727A8FD27FF7DFD1127F8A8FD27FFA8F8FD0527F87DFD0CFF52FD062752 %FD28FF52FD122752FD28FF7DFD0727FD0BFF7DF8FD0627A8FD27FFA8F8FD %1327A8FD27FFA8FD07277DFD0AFFFD0627F87DFD28FF52FD14277DFD28FF %52FD062752FD09FF7DFD0727A8FD27FFA8FD1627FD28FFA8FD0627F8A8FD %08FF7DFD062752FD28FF7DFD16277DFD28FF7DFD062752FD08FFFD0727A8 %FD28FFFD1627F852FD28FFA8FD0727A8FD06FF7DFD0527F852FD28FF7DFD %1827A8FD28FF52FD06277DFD06FF52F8FD05277DFD27FFA852F8FD172752 %FD28FF7DF8FD0627FD06FFFD0727FD28FFA8FD1A27A8FD28FF52FD0627A8 %FD04FF7DFD0527F852FD28FFFD1A27F87DFD28FF52FD0527F87DFD04FF52 %F8FD05277DFD27FFA8FD1C27FD28FFA8F8FD052752FD04FFFD0727FD28FF %7DF8FD1B277DFD27FFA827F8272727F827A8FFFFA8FD062752FD28FFFD1D %2752FD28FF52FD0627A8FFFF7DF8FD05277DFD27FF7DFD1D27F8A8FD27FF %7DF8FD05277DFFFF52FD0627A8FD27FF52FD1E2752FD27FFA8FD0527F87D %FFFF52F8272727F827A8FD26FFA8F8FD1D27F827A8FD27FFFD0727FFFFFD %062752FD27FF52FD20277DFD27FF52FD052752FFA8FD0527F87DFD26FFA8 %FD2227FD27FF52FD0627A8A8FD06277DFD26FF7DF8FD21277DFD26FF7DFD %06277D7DFD0527F8A8FD26FFFD2227F852FD26FF7DFD0527F87D7DFD0627 %A8FD25FF7DFD2427A8FD25FFA8FD06275252FD0627A8FD24FFA852FD2427 %52FD25FFA8FD0527F85252FD052752FD25FFA8F8FD2527A8FD25FFFD0627 %52FD0727FD25FFFD2627F87DFD25FF27F8272727F85252FD052752FD24FF %A8FD2827FD25FFFD0E27FD24FF52F8FD27277DFD24FF52F8FD0B2752FD24 %FFFD292752FD24FF52FD0C2752FD23FF52FD2927F8A8FD23FF52F8FD0B27 %52FD23FF52F8FD292752FD23FF52FD0C2752FD23FFA852F8FD2927A8FD22 %FF52F8FD052752FD052752FD22FF52A8FFA852FD2727F87DFD22FFFD0E27 %FD21FFA827F87DA8FF7D27F8FD2627FD22FF52F8272727F85252FD052752 %FD21FF7DFD04277DFFFF7DFD26277DFD21FFFD072752FD0627FD21FFFD07 %27A8FFFF5227F8FD2127F852FD20FFA8FD0527F8527DFD0627A8FD1FFF7D %FD0727F852A8FFA852FD2227F8A8FD20FFFD06275252FD0627A8FD1EFFA8 %27F8FD0727F82752FFFF7D2727F8FD2027FD1FFF7DFD0527F87DA8FD0627 %7DFD1EFFA8F8FD0C27A8FFFF52FD2127A8FD1EFFA8FD06277D7DFD0527F8 %7DFD1EFFFD0E27F852A8FFA852F8FD1D27F87DFD1EFF7DFD0527F8A8A8FD %062752FD1DFFA8FD112752FFFFA8FD1F27FD1EFF7DF8FD0527A8A827F827 %2727F852FD1DFF52F8FD0F27F827277DFFFF7D27F8FD1B2752FD1DFFFD07 %27FFFF52FD0627FD1DFFFD1427F852A8FFFF7DFD1B2752FD1DFFFD062752 %FFFF52F8FD05277DFD1BFF52FD1527F82752A8FFA82727F8FD1727F8A8FD %1BFFA8FD062752FFFF7DFD0527F87DFD1AFFA852FD1927FFFFFF7D27F8FD %172752FD1BFF7DFD06277DFFFFA8FD0727FD1AFF7DF8FD1527F82752FD05 %FFA87DF8FD17277DFD1AFF52F8272727F827A8FFFFFF52FD052752FD1AFF %FD17277DA8FD09FF52FD16277DFD1AFFFD0727FD04FF52FD0527F8A8FD18 %FF7DFD1627A8FD0CFF7D52F8FD1427FD19FF7DFD0527F852FD04FFA8FD06 %2752FD18FF52FD1227F8527DFD10FF7DFD14277DFD18FF7DFD06277DFD04 %FFA8FD0727A8FD16FFA8F8FD0F27F827277DA8FD13FF5227F8FD0F27F827 %A8FD17FFFD0727A8FD05FF52FD0627A8FD16FF52FD112752FD17FFA852F8 %FD0F27F8A8FD16FF7DFD062752FD06FF7DF8FD052752FD15FFA8FD0F27F8 %527DFD1AFF7DFD1127FD16FF52F8FD05277DFD06FFA8FD0727A8FD14FF7D %FD0F277DFD1EFF52FD0F27A8FD15FFFD0727FD08FF52FD0527F852FD14FF %FD0C27F82752FD21FFA852F8FD0B27F852FD14FF52FD0527F852FD08FFA8 %FD0727FD13FF7DFD0B27F852A8FD24FFA8FD0D27FD13FFA8FD0727A8FD09 %FF52FD062752FD12FF52F8FD0727F82727A8FD28FF7D27F8FD092752FD12 %FF7DF8FD0627FD0AFF7DFD0727A8FD10FFA8FD0A277DFD2BFFA87DFD0A27 %A8FD11FFFD0627F8A8FD0BFFFD0627F852FD10FF52FD0727F852A8FD2EFF %A82727F8FD0527F87DFD10FF52FD0527F827A8FD0BFF7DFD0727A8FD0EFF %A852FD0727A8FD32FF7D52FD0727FD0FFFA8FD07277DFD0CFFA852FD0727 %FD0EFF7DF8272727F8277DFD35FFA87DFD06277DFD0EFF52F8FD0627FD0E %FF7DFD07277DFD0DFFFD05277DA8FD39FF52FD042752FD0DFF7DFD0627F8 %A8FD0FFFFD0827A8FD0BFF7D27F82752A8FD3CFF7D52F82727A8FD0BFFA8 %FD0627F852FD10FFA8FD072752FD0BFF52F8527DFD40FFA8272752FD0BFF %52FD0727A8FD11FF7DF8FD0527F87DFD09FFA8F87DFD44FF5227A8FD09FF %52FD072752FD12FFA852FD0727A8FD08FF7DA8FD46FFA8A8FD08FF7DFD08 %27FD14FF7DFD0827A8FD06FFA8FD51FFA827F8FD0527F87DFD15FF52FD08 %27FD58FF52FD07277DFD17FFFD082752FD56FF52F8FD0527F852FD19FFFD %082752FD54FF7DF8FD0727A8FD19FFA8F8FD072752FD52FF52F8FD0527F8 %277DFD1BFF7DF8FD072752FD50FF7DFD08277DFD1DFF52F8FD072752FD4E %FF52F8FD072752FD1FFF52F8FD072752FD4CFF7DFD082752FD20FFA852F8 %FD0827FD49FFA852F8FD0827FD23FF52FD0927FD47FFA852F8FD0827FD24 %FFA852F8FD0827A8FD44FF7D27F8FD0827FD26FFA852FD09277DFD42FF7D %FD0A27FD28FFA852F8FD0727F852A8FD3EFFA8FD0B27FD2BFF52F8FD0927 %7DFD3CFF7DFD0A2752FD2DFF7DF8FD0727F82727A8FD38FFA852F8FD0927 %52FD2FFFA8FD0B277DA8FD35FF52FD0B277DFD31FFA8FD0A27F82752FD31 %FFA87DFD0A27F827A8FD34FF52FD0C277DA8FD2DFF5227F8FD0A277DFD37 %FF7D27F8FD0927F82752A8A8FD27FF7D52F8FD0C27A8FD3AFF7DF8FD0B27 %F85252A8A8FD21FF7D7DFD0E2752FD3DFFA82727F8FD0927F827F827527D %7DFD19FFA8A87D522727F8FD0B27F8527DFD40FF7D52F8FD102752527D7D %A8A8FD0DFFA8A87D7D5252FD1127A8FD43FFA87DFD1027F827F8FD0627FD %05522752FD0427F827F8FD0F27F8277DFD48FF7D52FD3327A8FD4CFFA852 %27F8FD2927F82727527DFD50FFA8A852FD2827527DFD56FFA87D52522727 %F8FD1B27F82727527DFD5DFFA87D7D27522727F8FD0F27F8FD042752527D %A8FD64FFA8A87D7DFD0452FD0727522752527D7DA8A8FD34FFFF %%EndData endstream endobj 19 0 obj <>stream +%AI12_CompressedDatax}z:wB0ӑ# Z&^ǹc;. d˲,ɒ5o+D1 Jϧbދ~F i.Ÿ7!/1Q4QQN'y=·8{ c C`<Gx! +Bg4v?!+S\MyD>/^%@AoD+?}UYkeKMgX~>tsOxы~ 7 MFLL+ M3h8{_ N{`^43I¤/iFzȿ9wyQŅ4M# ] +gh&W@˘fL@ad%~4~l0Y!xaa?t4:?a4yq>썄?\SOHmnޠ1@'lWxv1 :e~&aUV-ѨO=3$O|2=A_yOq~1K~,x#hڄ^yldmpab\M/ lx Vvn |?x{Ⲡx_40t}h# +.uouPGn~l wa/D/ gvlZU\fdDg]8ߪCi6\8Ny&d]U[o*)xt7nz#EhN!/zʩ=5SI┺\\ +9/pI.Kl]m+݌ W#u3*b.i~þ!Sb7ۊ+!J%R,6ǦXj@ZK'jgu:) + w?spȼCg?\ӫt}݈Hl~NH}W O\&Q`i sN Ʈ]ђMoTmmY=ɔm* +ϑnkYb?3 #s~Sg=ec~vk Z|?  +RgIZ(xd*IWGөq:g86 \cI沬MS#4(ҟ~: CT.!roIJ@Q&0aC]pntRnj'0;M%6'OC/?r;k7]GÉ[l<R L@"n&hc^6I^i6ZN+Ȩφ1e9(/jzL[X̧^ Fj U]=H2U5Pˆ!] A6 *J j40M'`3 ?x.lFk( ] J@\j"twVȒaa<DÊ\pN?Bo:{:%45DzMzYqn6aY z ({P>QD`dB +8v5pS{Êg3Qif3c]s)I07|6ɑZgljNc#ѵO1طuYok`6k@{e씢$@(Z.jF8l@M1 ҤV;e/84Xx,RWIAD nFюQ a:G=cp=ڷ +'9l[jZJbek6&X ?5;Le>ͯ%5J>c_czQY*mz"on3*niϜ頴;ڪ 2c$85崾0h,?9MJObM,پ̡ ԋ@ph&bqNHˋ<}{h<džc(TnPźa>&Xd/63c:wlf5G/F-C}L~Eh3;v`=d-yvҀ`C%HCvUJ3cEՉl[斄v.So';1[m%t").ѭNg=H63n< `7J{jlDnx0TNq;dzw W41u)xy4t}j8l 9L!Ah^~(67m s@V1hJW0c\tSs0j +3ԖN& d0]f9dɼ APelWy v1tÓa<%Qxcp^)gC;Meh쀋˩ޢhhzEX4x+[z2t!JnH)c3kRmh30Y>4kPA/5`'aJ| _2b{3.J%.6@*<۞yOYFJۦIT9EuQ1os;;_mr苸NNlZNDNvS= S~q W018{u' '4X6 `*7Ht2 X(OOLU]G,%Pi9 UwAwupn慷 %@r@x%Otx/얗Jm]Ǽ .3@tAep<ćD/@:O!M?H0 + |%-zؽIt02 CG?7LٓR)'guXx';Dzݱcd9 d\:cfkӉyipamX](tvz;rDoc1D푧@-w4놖Mפ4䂒MzBZ `I[rw$IRa$>)- ""͛H(tQ=ݰu woެUMbm^S(Tn{E0A!ѷK[:SSD^V ] +vA{H{ٻ̚]'N\YRtI((VWS6 sP6b*}I{0ic1 ,P(w1˃",i.:\_0,ٲM%Ƌ3 j@ Y}ALm4* pLj( q&% =O͋\usȗ?#)>I|Dx/tEC# /E2?| ")_)t8tp$[CD:${QFH!=oϯOetKAML&۫$d^ӑBF^*P44cDA3! |FqT.kitY^F՝47RH且ÊTJlKFQ(i|i:?|3 +^ R8/i_ʷ0n_)ޘ{?ctMO[d,@z*f"rpU/mOL$i'IO LFO=%%]az7=7=us~1w'AsY?=1`,|3{ߡԸ3=&=m0۹JCR"d2_kiTKy~1o O;"Kl VbigcܹuNv ^ s׏f݊!`a-fT5v. >D"M 5c_MH.ewkR_ /xwhΰwvtK҄il*@^Gt❍"n# $^&5x"ہZ})@FnB}H^Oj$Xfu+QУO +A ܧ|iе 5vPZ 6z KvsI~?YW g#ڟge^B@7+3݃ . T |0b ++?eh9VQ#ٱl7םou%lU~eX*Ob*SGUqp`@@@('K3ҚD? +=Y1[2DG!r|M>>W.Ps@t ,t^LOI^uO~%̰1<$vnǙ=g|%s2HAy{}PމMW>cEwe^e=y 𞀛٨a0Z '*#sbَ(CNW U^ZU nU)>C;fCL3 -e?4ЌB3kךcOڑGeoF䱜-=BCšk;&]10Q&!`,>ɲ}c +Aa;qݱu~(l :?ONm河EDIr1_^EtȔ= Ne3@H1, gabϘR0ȫk+-L]b)I,MwVEQ%d35F}vk&Vqc~wړ]VX9A.AKt+>ά;is$إ-R<{VrtP\c|~3KhYBqCq&-}7F1 ?Q$RLl~яp72kǺn,KKco?ƍNޠtn+pRWohUʹC9DϺ'?oEgLNڍ@ Q,բwC')xpkӄQGH Ԥv->N4ߢƨ%w$)0Dwi%`CdOlO^&%n qǔ]̰g%N0KO!%le,h(pr8d᎜gwtǭ <4vYǽ!35]{@={ t0Jtj@¤@3[֞*}oMt>3_QU`vgI#S߳N@&L6vM +MxvnW[/uqܼQzq>_6 OӍ\Q`cgI4 + +/>*  /Z(hb} gUo,FF0kRC!`56љ1=Z6)wk03]+o7_C3>");9ǠI4`B&~Sq[dAh߯-ҕo'( &GD=A\I4kM k}x@1G842 +OާνzhOÇ*-y,&,lw$?q]G1. N]*3uh&&Ϟ)5vK^A.,d=bE`%f_{[45cPQ8!D(ƽRn E3mOy,703|^yzw[ wCߠijd6߿4mz7l{V9eMbb#2 .֎ B!;X8g8,q7 -$ 돺 m|Zw|ХA,(-a,AV2C 'fhф`uI@bG:N$S;OeE] ++Ar6^83:1Ij,cti JΝ y|o W'6y|2owZSbYv_heSb,#wy|&320~!E>3w=H[#^@1wK4:'*]n.g 鋝._FZyq2fgس00f ͏w܃08Q֫6$8%f`K'#6f1r׾#9 $߸SF\-Ŏ+P`Y4gžJs+c9VF=`taZC!gD#VǾN+^_D\t:uޱ30ە,gv#e\ydl#"6Ov.NȘ$pnu<2:$m+;0fÙ{ CKihPں0e9xUqc%7)jC*|N pvDms8PRvGΒbzOs1@-W,d=yu4 e>ڸhD0\FN&_SsT.Çጶ|uˇs73ñχP]'ӓM9|8h(U@>^bn(N7gm:Ź|8{[tSkM7Y78XrH-)b"0nkR "!7N (KOx+? v=,Bli\E<xўyV^J(Zª~ˏ][SCw+YCwIx*56s0t \Xk#˰E ɷiì[KW;݆o)ڠ&dƴ|dF&3R6򳁌THF*TgTe0{hS\1 ,KSsX^qm,ad#zR]&8HZ.MRI+p+ەRwm2NpH\;ݡfPg]( 'cZ45_-j2~,\;a +:̣ab6:Lb8±8Hyͦ.n6rm+Et>,zf; naQ' w|{/Ryoa;]! ?5a˒/zI1wFٌxU\ٕdfl;vxTc[}MʰK^ޢD6iz E3|)2RXT[CXG;;Q>R `aoFJ{KvdLH^ w%!m֘m=ϳ-"RVDވ]zcU\=f-TcL/GQ\tuETK 6T;߱sՕR{:V3kBcubyU31抜Xe׷^%9cHMU:J/\s׿N6}.;W1ٔ23s¹("Gs7b#4㳺KmT:#Dw@^FNϓ\N6Mge^PdY^rqMg6MgKf8dzl:ztV$nn˦sQL69:t9s'#fYn:3l:{̦\:Sѵ6#Il:.aʦʥf6iwBn, +r»l:\:5Vl:m(*%(r9VkdYin&NK]l:#'ul:y&MϐzbMgmWɱb6F M$grMg5 "R +;RNb%}:EUQD:bC,Yittrl1)(9&ӱsة țe]u9]ZYT]R-LJ cC4!ZDwh-#P-XnŜ5_LT)yhsPyckWX`{/ +/Pusrp ߺ,Zul$6:i"biLvIj]NpfzU`"lؕހ7ە=)2:*&m[Ű+_7qwOc+q-qv(0oTKXǮVS0XbפW%%t+dwwuzRK| 4$Q۞w{}wω/܋%mmvLS>RD :R:l~.·;{psaEu=-K.5/ܿ["#!S<){YjLM).[?k#5Å$KEdh^[-~*E, +SeQM;˽q +W1PU\grp7 +uCPz]ugmn(TohQW]O+ÂWwd[P5Z#Ȗ*mJu]Dg? φ9En}!,OE̙M]?իj#u7:>r]?CRU5n2ls6&WsW\]=Unju]׏N&cL]?Y_6=ōo*K\Ϝj]?so}51#e]?Rvf <Yz|zLU֫GkseQodx%'q~eTa@]?5ͺ,֯g4 7m,ɺH1s]JWuH2P귡}U?m+ Pz:ۊ ; +u9c U0ZuVaVGItC]P׏&r~􎚷aț/,E|h]Ea>qkf#i(㧙ɇ&Yҗt5Af=ۉx0X}B1|c'K=FרT@)0rLͪ{DžˑrQgKaG> ٫{$f&}\ana3+kw;P?27bmk;̨tnq~{Kt9~P=N#(f}-QWQv+jvɷʟecvLCSeư5$>}7Jz2H[ս~_T/9&v:R9S`^J]/-[)yc7 +Vpi ھSP<3\| 9 3,)ђSL3 2&r"q+_;s50J˰"-aR| ]n&*ty:N<&{|)@Uά\GKF\h v<$6#XL^z. R09M`, +dkş4+rO_HN0R7XLHn8Ol=Ze!V s{&l@[LWwaKuKZg&ڼ A~u~L9<;v?|@rCFkVY|P[k'HjxhgEV;.ܕ?qGn,Y/mRMZ +0 +U^?»89j'R*\}4 kE[fI>K+zR)iÕ{WVC_q@} F\ j+k)[:# +R=8 bB=,+\$W"-ԘF hx'qi6@#4 -v#oy%ffR{wRev%4`): Pyk6ObFm'Gff MD#Zؚbb,u=]=fdm^iRZ, Lq$.3_FΘ=&-ikr9cp&\>׋抾W/R&^ZwAT[gD|lh1li1k+_\u13&e<)^5O^Tp,>l'՘g >LD`T^^rQcn 'S0w{j`G֪H^gde)nK@&%µ=$k(}Z{6:^޴c^os)H4؍=v{QKܷ6iYPV+f+nj6> K {@_HI'p%H`|ك|z*N?!_Uc/bOy :/nw6; v@´%Va(ԛͳpKl *]@^jɻ +e\\`,Y\Q\ FpV\\r&[Gq.c4k1{׊xfyQ..x,ѝKыb*BdƜzחq8uVLPO_|+kjme[E|WIT3h}F:?V lny~ +ZVBHmM)E#F<]`Wv/c+y4̞_xzu0%hcs ®צ+[j+;y¼4ȼ +K'D +ya!Gw'X(B;{)Q6IWdmpr(ˍP|Ee%ON*:Arn4=<$:<?EvNQXWls +-E͉WNģiW=mѴ{yOy֙x4j_xg|kLᣇsV:OM fA1 b awhbgvW9br _+~ҫԁp/י $4>XH+Exwu?z.e1*|&FRxD3=O`]83փ'`"Bu5ʕ@(rE-AK՘uŕ0 "rL&!H +'^A(f#qr *+G1.SE"zuRT-}yIyɀ*۞$jŹ1glgfkU|cⱸ%%@KzWe̺ KZsX<ËRX!>pRG_(EC԰#2\#<h+`Vޑ#,q"Ş +e}-)= GNZ6lO)9s%LwĄI1~F~99IME +tГ)+IL(A,uJMl+Mo'zw4L޵{R=پ ?<0أ@}p)'~ Lo ?_ƵۀS 2zgRvݷ:,7X(U-[7g{r ;H^ +==Jc5[\(sGJ$z;gZۺosLW8qZ8PO)%}yegE֧r>I:+qE[\~(>Ȝ̕NY˽it)orC%wO'X|H:O'P<`)5.;{q$ȇ.6_Is6GϽB(n + 08.ЮP TP'Q;DׄҲ5.sU{G^eҍ<@t%:evR/c|G0Au\L={("]"*,H*nK=5ǹr9$EXJ1xoF[cӐr}K+uʨ-^k&~ jd #ou4pٟG$x`ʀɉPXr +rddVL_$ "k(]QdrW36/eRB9 BE>drIΛeb$Ws8F"˳t<Īӧd"<1]pC4rb)`,`? +&ΛERs`ɿ=?"~OY>*;,ԋե ӛOA9=} dD(Вi/5a8n͊I! +K_4~7JWk{]YآH 3 KM'+(7Yծ(ʅ {%W4 xP򱛧Q=n,f#&{Zck[ D mBpf2hxSVv_*x VaT/ 2]a _Q|{VH)赇n# !~нBT^!oWE{QxJQ1JG~{ d>,.z]%o9wC|&Ս) JJ{<=Kx΍82@ {YX{@qpԛӸ>*;{@ +U:2Hߤ]t&MnBD~fW7hWhxƢ+p,KcKcE+nfmf/ί[kO EV50/@I"IQ|toq>qgLrpUNC,:HC@;`Kޤ boq70/[x%LPm5&{ZJ_ݯNK^71#PLjps.W( |N`Bw+ ':U'Hq":#6UsCsD`' I3([A PdvT{(:bEP^gY7 ty,-WƀT1 +A:tz)vu7z1(bԳ}<B֊8jV B?ŊK/rԜ)a6|cHw2׺%zѝV\c#*`B0 J(PçQXpiLTq3F#;fq3FtVaq܌Qoq܌Q'`q܌x7o|vO8n߈l<Ƣ~;!ˈZHΐ|,?C3V~9l J &4D +.ٓ&xmR9?RG$ROHKTrȎяe͑]=v/QH.ðI9b]zRh7šL٥O}0\/[L˘>Q݊@z!A_խ'zG}OAv*>~ /|1 R94?a ,r6 jeC׉yy؛^ßӲ7v@}oQzvd^g\ +/ (L67~:O ?oɧ/~P,OߟvXo:& ? +YÙc % ag[OW&%`M`Jbl"m#m_/o/x/ϯf}RL,̥L:IyǞq\܆c16yl1I2 é_L,H$/I ?L"c{Rq)o /fj&E6e9Lg\cĉ9؇2Oڻ= ΍K1A9@ф“@hJS]1 MpL`'0 ~J(RpT:2Kǒ- g.Lh c2 gKedpdO= E)Tai%R`8NL76;.ч&WGHGRPz&w6 6Ǥ ]kG4W@^U=m endstream endobj 6 0 obj [5 0 R] endobj 20 0 obj <> endobj xref 0 21 0000000000 65535 f +0000000016 00000 n +0000000144 00000 n +0000021511 00000 n +0000000000 00000 f +0000023188 00000 n +0000052867 00000 n +0000021562 00000 n +0000021892 00000 n +0000023487 00000 n +0000023374 00000 n +0000022293 00000 n +0000022627 00000 n +0000022675 00000 n +0000023258 00000 n +0000023289 00000 n +0000023560 00000 n +0000023734 00000 n +0000024741 00000 n +0000033030 00000 n +0000052890 00000 n +trailer <]>> startxref 53080 %%EOF \ No newline at end of file diff --git a/demos/html5/art/icons/logo.ico b/demos/html5/art/icons/logo.ico new file mode 100644 index 0000000..3b122dc Binary files /dev/null and b/demos/html5/art/icons/logo.ico differ diff --git a/demos/html5/art/icons/logo.license b/demos/html5/art/icons/logo.license new file mode 100644 index 0000000..07f18c1 --- /dev/null +++ b/demos/html5/art/icons/logo.license @@ -0,0 +1,2 @@ +Free & Open Sourced Logos +At Fairpixels, we had unused logo designs piling up on our hard drives and decided to make them available to the world, for free. The logos below can be downloaded unlimited times and used by anyone. For personal & commercial projects. No attribution required. Perfect for mvp's and mockups. diff --git a/demos/html5/art/icons/logo.png b/demos/html5/art/icons/logo.png new file mode 100644 index 0000000..1d2f849 Binary files /dev/null and b/demos/html5/art/icons/logo.png differ diff --git a/demos/html5/art/icons/suru.license b/demos/html5/art/icons/suru.license new file mode 100644 index 0000000..282825b --- /dev/null +++ b/demos/html5/art/icons/suru.license @@ -0,0 +1,12 @@ +This work is licenced under the terms of either the GNU GPL v3 or +Creative Commons Attribution-Share Alike 4.0 United States License. + +To view a copy of the CC-BY-SA licence, visit +http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative +Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA. + +You should have received a copy of the GNU General Public License along with +this program; if not, see + +When attributing the artwork, using "Suru Icons" is enough. +Please link to http://snwh.org/ where available. diff --git a/demos/html5/art/icons/suru.png b/demos/html5/art/icons/suru.png new file mode 100644 index 0000000..413e59c Binary files /dev/null and b/demos/html5/art/icons/suru.png differ diff --git a/demos/html5/demo_collide.c b/demos/html5/demo_collide.c index f474fd9..56b9368 100644 --- a/demos/html5/demo_collide.c +++ b/demos/html5/demo_collide.c @@ -578,16 +578,16 @@ void game_loop(void *userdata) { //ddraw_flush(); //fx_end(); - if( ui_panel("Audio", 0) ) { - if( ui_button("test audio") ) { - // audio (both clips & streams) - static audio_t voice; voice = audio_clip("coin.wav"); // "pew.sfxr" - static audio_t stream; stream = audio_stream("wrath_of_the_djinn.xm"); // "larry.mid" - audio_play(voice, 0); - audio_play(stream, 0); - } - ui_panel_end(); - } + // if( ui_panel("Audio", 0) ) { + // if( ui_button("test audio") ) { + // // audio (both clips & streams) + // static audio_t voice; voice = audio_clip("coin.wav"); // "pew.sfxr" + // static audio_t stream; stream = audio_stream("wrath_of_the_djinn.xm"); // "larry.mid" + // audio_play(voice, 0); + // audio_play(stream, 0); + // } + // ui_panel_end(); + // } if( ui_panel("FX", 0) ) { for( int i = 0; i < 64; ++i ) { @@ -605,9 +605,7 @@ int main(void) { window_create(0.75f, WINDOW_MSAA4); window_title( "V4K - SPACE pauses simulation" ); - // for(const char **list = file_list("fx**.fs"); *list; list++) { - // //fx_load(*list); - // } + // fx_load("fx**.fs"); // camera that points to origin cam = camera(); diff --git a/engine/v4k.html b/engine/v4k.html index a5085f3..8c72a46 100644 --- a/engine/v4k.html +++ b/engine/v4k.html @@ -596,7 +596,7 @@ details > summary::-webkit-details-marker { |Version: | 2023.9 | |:--------------|:------------| |Branch: | main | -|Commit: | 74 | +|Commit: | 75 | # [V·4·K 2023.9 ](https://v4k.dev) @@ -604,6 +604,7 @@ details > summary::-webkit-details-marker { - V4K is a multimedia workbench for prototyping and planning ideas. - Internal use only. +- you can try out the [live demo](https://v4k.dev/demo/) - Original repo at [FWK](https://github.com/r-lyeh/FWK). Huge thanks for the amazing base provided!
diff --git a/tools/cook_web.ini b/tools/cook_web.ini new file mode 100644 index 0000000..59279bf --- /dev/null +++ b/tools/cook_web.ini @@ -0,0 +1,62 @@ +; this is where you specify and configure the FWK pipeline. +; tweak the pipeline and add new importers just by editing this file. +; there is no flow control in this script file: lines are parsed and evaluated, from top to bottom. + +; ------------------------------------------------------------------------------ +; let's create a symbol. symbols are uppercase words always. +; syntax: symbols are defined in KEY=value form, as seen below. + +TOOLS=./ ; folder where our pipeline tools are located +ART=../demos/html5/art ; comma-separated folder(s) that store all our asset files + +; lines starting with @windows, @linux or @osx will be processed only where OS matches. +; we are defining here some symbols differently for each platform. +; syntax: lines starting with @keyword. valid keywords are win/dows, lin/ux, and osx. + +@linux NUL=/dev/null +@osx NUL=/dev/null +@window NUL=NUL + +@linux .EXE=.linux +@osx .EXE=.osx +@windows .EXE=.exe + +; you can invoke shell commands directly with `command` at anytime. +; also, once a symbol is found, it is replaced by its value always. +; some predefined symbols: INPUT (input filename), OUTPUT (output filename), PRETTY (clean input filename), PROGRESS (cook progress). + +@windows `echo Cooking PROGRESS% PRETTY...` +@linux `echo "Cooking PROGRESS% PRETTY..."` +@osx `echo "Cooking PROGRESS% PRETTY..."` + +; ------------------------------------------------------------------------------ +; groups below are collection of files that we want to cook, and then package. +; by default, no assets are cooked unless explictly listed below. +; syntax: group=ext1,ext2[...] + +[cook] +font=ttf,ttc,otf +text=json,xml,csv,ini,cfg,doc,txt,md,c,h,inl,cpp,hpp,htm,html +shader=hlsl,fx,dxil,dxbc,glsl,vert,frag,geom,tese,tesc,comp,vs,fs,gs,ts,cs,spirv,spv,slang + +; ------------------------------------------------------------------------------ +; cook localization files + +;[cook excel] +;TOOLS/xlsx2ini.EXE INPUT OUTPUT -> ini + +; ------------------------------------------------------------------------------ +; assets that need to be compressed at end of whole pipeline process are specified here. +; by default, no assets are compressed unless explictly listed below. +; supported compressors: DEFLATE (default), LZMA, LZ4, ULZ, BALZ, BCM, CRUSH, LZW3, LZSS and PPP. +; syntax: compression quality[0..15]|optional_compressor on the left, and type names on the right. +; where: level [0:fastest compression .. 10 max level .. anything >=11 is expensive ... 15 is uber] +; +; valid examples: 0, 3, 4, 6|LZMA, 6|DEFLATE, 6|ULZ, 9|ULZ, 9|LZ4, 2|BALZ, 3|BCM, 1|CRUSH, ... +; +; hint: use plain `0` to exclude non-compressible files (jpg,png,...) +; hint: use plain `0` to exclude those usually large files that compress poorly (<1%) (like mpg) +; hint: use plain `0` to exclude those files we would like to directly stream within the final zipfile (flac,mp3,adpcm wav,...) + +[compress] +0|ULZ=font,text,shader diff --git a/tools/docs/docs.md b/tools/docs/docs.md index 0c63cee..86757c5 100644 --- a/tools/docs/docs.md +++ b/tools/docs/docs.md @@ -9,6 +9,7 @@ - V4K is a multimedia workbench for prototyping and planning ideas. - Internal use only. +- you can try out the [live demo](https://v4k.dev/demo/) - Original repo at [FWK](https://github.com/r-lyeh/FWK). Huge thanks for the amazing base provided!