Forum

[FTEQW][REL]GLSL showreel - also mini tutorial

The home for dedicated threads to specific projects, be they mods, tools, or independent games.

Moderator: InsideQC Admins

[FTEQW][REL]GLSL showreel - also mini tutorial

Postby toneddu2000 » Tue Mar 28, 2017 3:12 pm

Hello guys! It was quite a lot that I had the idea to create some code that showed the muscles underneath GLSL's post processing and shader support in FTE, so.. here it is!
When I was creating the skeleton of the project I asked myself: "What if I create a project without neither models, maps, nor textures, just procedural models and GLSL shaders?"
The idea behind this GLSL showreel is double face: the project (that lives in this page, with no additional physical contents, except for sounds files) and a mini-tutorial that explains how GLSL shaders and postprocessing are possible with FTE engine. Yeah, I know, mini-tutorial part is a bit lame, but, for now, it's the maximum I can do. If you have any input to share, please post it below and I'll add it with your credits

This is the video showing the final project. It's not wonderful but I liked it for many reasons, first of all is that, for creating it, you'll need just the pieces of code I'll write in this topic: that's it, no 3d models, no textures, no maps! Crazy, isn't it? Well, let's see..

CSQC Warning: this mini-tutorial requires basic/mid knowledge of CSQC to understand it (otherwise you can just follow the steps and obtain the final project anyway, but that's half of the fun imo..)
a
License warning: GLSL showreel code is 100% written by me (Antonio Latronico) and placed under cc0 public domain license, so you can do basically what you want with it without any kind of restrictions, BUT (and this is very important) every GLSL file present in this mini-tutorial is not written by me (I downloaded from shadertoy and "just" adapted to FTEism GLSL syntax), so you MUST pay attention to every GLSL file license header to be sure to credit every single author to avoid license infringement (unfortunately, 70% of GLSL files are released under CC non commercial license, so, forget about using those files for commercial projects..ugh..)

Nomenclature warning: When I talk about a shader, I describe .shader files stored in scripts subfolder in game data folder, when I talk about a GLSL file I mean glsl files in glsl subfolder in game data folder

GLSL files external licenses:

Overcast Sky
author: CaliCoastReplay
https://www.shadertoy.com/view/Ml3Gzs

Warp Speed
author: David Hoskins 2013.
https://www.shadertoy.com/view/Msl3WH#

Synthetic aperture
author: FabriceNeyret2
https://www.shadertoy.com/view/ldlSzX#

Tileable Water Caustic
author: David Hoskins
https://www.shadertoy.com/view/MdlXz8

Post Processing effect: ASCII
author: mattdesl
https://www.npmjs.com/package/glsl-ascii-filter#float-asciifilter-vec3-color-vec2-uv-float-pixelsize

Post Processing effect: Black&White
author: lezard
https://blog.sovapps.com/play-with-shaders-black-and-white-part-1/

Post Processing effect: Bloom
author: mAlk
https://www.shadertoy.com/view/Ms2Xz3

Post Processing effect: Barrel Blur Chroma
author: hornet
https://www.shadertoy.com/view/XssGz8

Post Processing effect: Fast, Small-Radius GPU Median Filter
author: Morgan McGuire
http://graphics.cs.williams.edu/papers/MedianShaderX6/

Post Processing effect: GLSL depth of field (used as Motion Blur)
author: martins upitis
http://devlog-martinsh.blogspot.it/2011/10/glsl-depth-of-field-with-bokeh-v2.html
Last edited by toneddu2000 on Fri Mar 31, 2017 11:12 am, edited 2 times in total.
toneddu2000
 
Posts: 1318
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: [FTEQW][REL]GLSL showreel - also mini tutorial

Postby toneddu2000 » Fri Mar 31, 2017 11:06 am

Glsl Showreel code
Step-by-step reel creation:

  1. Grab from here latest version of FTEQW for your O.S. (I'd suggest debug version, for better debugging, but it's up to you)
  2. Create in main game folder a textfile named default.fmf and edit like this
    Code: Select all
    game gs
    name "GLSL Showreel"
    basegame data
    disablehomedir 1
  3. Create a data folder, inside create 2 subfolders: glsl and scripts
  4. In scripts folder create a text file named objects.shader (this will store shaders for objects in scene) and edit like this
    Code: Select all
    sky
    {
       program ton_daysky
       cull none
    }

    sea
    {
       program ton_sea
       cull none
    }

    portal
    {
       program ton_portal
       cull none
    }

    portal2
    {
       program ton_portal2
       cull none
    }

    portalframe
    {
       program ton_portalframe
       cull none
    }

    portalframe2
    {
       program ton_portalframe2
       cull none
    }

    horizon
    {
       program ton_flatcolor#AZURE
       cull none
    }

    cube
    {
       program ton_flatcolor#GREYDARK
       cull none
    }
  5. In scripts folder create a text file named pp.shader (this will store shaders for post-processing effects) and edit like this:
    Code: Select all
    ppcolor
    {
       program ton_pp_basic
       {
          map $rt:ppcolor
       }
       {
          map $sourcedepth
       }
       
    }

    ppdepth
    {
       program ton_pp_depth
       {
          map $rt:ppdepth
       }
       {
          map $sourcedepth
       }
    }

    ppbandw
    {
       program ton_pp_bandw
       {
          map $rt:ppbandw
       }
    }

    ppmblur
    {
       program ton_pp_motionblur
       {
          map $rt:ppmblur
       }
    }

    ppchrom
    {
       program ton_pp_chromaticaberration
       {
          map $rt:ppchrom
       }
    }

    ppascii
    {
       program ton_pp_ascii
       {
          map $rt:ppascii
       }
    }

    ppbloom
    {
       program ton_pp_bloom
       {
          map $rt:ppbloom
       }
    }

    ppmedian
    {
       program ton_pp_median
       {
          map $rt:ppmedian
       }
    }
  6. In glsl folder let's add all the glsl files that will be called by shaders. Let's start with the ones called by objects.shader. Remember to add to every glsl file a .glsl extension and remember to contact glsl file author before using it in your commercial project!

    ton_daysky.glsl
    Code: Select all
    !!ver 330
    !!cvarf glsl_time
    !!cvarf glsl_skysize
    !!permu FOG
    //   author: CaliCoastReplay
    //    https://www.shadertoy.com/view/Ml3Gzs
    //   Adapted from  :  https://www.shadertoy.com/view/Md3SzB
    #include "sys/fog.h"
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
      gl_Position = ftetransform();
      v_edge = v_texcoord.xy;
    }
    #endif

    #ifdef FRAGMENT_SHADER
    varying vec2 v_edge;
    uniform float cvar_glsl_time;//time set in a cvar!!
    uniform float cvar_glsl_skysize;

    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);
    }

    vec3 hsv2rgb(vec3 c)
    {
        vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
        vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
       
       return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
    }


    float hash21(vec2 p)
    {
       float h = dot(p,vec2(127.1,311.7));
       
        return  -1.+2.*fract(sin(h)*43758.5453123);
    }

    vec2 hash22(vec2 p)
    {
        p = p*mat2(127.1,311.7,269.5,183.3);
       p = -1.0 + 2.0 * fract(sin(p)*43758.5453123);
       
       return sin(p*6.283 + cvar_glsl_time/4.0);
    }

    float perlin_noise(vec2 p)
    {
       vec2 pi = floor(p);
       vec2 pf = p-pi;
       vec2 w = pf*pf*(3.-2.*pf);
       float f00 = dot(hash22(pi+vec2(.0,.0)),pf-vec2(.0,.0));
       float f01 = dot(hash22(pi+vec2(.0,1.)),pf-vec2(.0,1.));
       float f10 = dot(hash22(pi+vec2(1.0,0.)),pf-vec2(1.0,0.));
       float f11 = dot(hash22(pi+vec2(1.0,1.)),pf-vec2(1.0,1.));
       float xm1 = mix(f00,f10,w.x);
       float xm2 = mix(f01,f11,w.x);
       float ym = mix(xm1,xm2,w.y);
       
       return ym;
    }

    float noise(vec2 p)
    {
       p *= 4.;
       float a = 1., r = 0., s=0.;

       for (int i=0; i<9; i++) {
         r += a*perlin_noise(p); s+= a; p *= 2.00; a*=.57;
       }

       return r/s;///(.1*3.);
    }


    vec3 sphereProject(vec2 plane)
    {
       vec3 r;
       plane.x -= 0.55;
       plane.y -= 0.35;
       float denom = (1.0 + plane.x*plane.x + plane.y*plane.y);
       r.x = (2.0*plane.x)/denom;   
       r.y = (2.0*plane.y)/denom;
       r.z = (1.0 - plane.x*plane.x+plane.y*plane.y)/denom;

       return r*1.2;
    }

    void main( void )
    {
       vec2 uv = v_edge.xy / cvar_glsl_skysize * 0.6;
       
        //vec3 sphere = sphereProject(uv);
        //uv = sphere.xy/2.1;
        vec2 uv2 = uv + vec2(0.12253 + cvar_glsl_time/210.0,0.73483-cvar_glsl_time/90.3);
        vec2 uv3 = uv + vec2(0.34646 - cvar_glsl_time/150.3,0.46436 - cvar_glsl_time/180.4);
        vec2 uv4 = uv + vec2(0.98398 - cvar_glsl_time/34.5,0.11242 + cvar_glsl_time/100.7);
        float f = noise(uv)/1.0;
        f+= noise(uv3)/2.45;
        f+= noise(uv4)/0.7;
        f = f*0.35+0.55;
        vec3 lightColor = vec3(0.719,0.719,1.0);   
        vec3 color = vec3(lightColor*f);
        vec3 hsv = rgb2hsv(color);
        hsv.z += 0.5;
        float cloudCoverFactor = 0.01;
        hsv.z *= hsv.z * hsv.z * sqrt(hsv.z)* 2.01 * (cloudCoverFactor + 0.91);
        bool deblue = false;
       if (hsv.z > 2.75)
        {
            hsv.z =4.7 - hsv.z/2.11;
            hsv.z -= 0.559;
            deblue = true;
        }
        else{
            hsv.z -= 0.041;
        }
        hsv.y *= 2.2;
        hsv.z -= 0.01;
        color = hsv2rgb(hsv);
          if (deblue){
            color.z = color.y = color.x * .91;
            color.x -= 0.07;
        }
       gl_FragColor = vec4(color,1.0);
       #ifdef FOG
       gl_FragColor = fog4(gl_FragColor);
       #endif
    }
    #endif


    ton_flatcolor.glsl
    Code: Select all
    !!ver 330
    //author: Antonio "toneddu2000" Latronico
    //placed under cc0 public domain license
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
      gl_Position = ftetransform();
      v_edge = v_texcoord.xy;
    }
    #endif

    #ifdef FRAGMENT_SHADER
    void main() {
       gl_FragColor = vec4(vec3(0,0,1),1.0);
       #ifdef GREENLIGHT
          gl_FragColor = vec4(vec3(0.248,0.840,0.293),1.0);
       #endif
       #ifdef GREENDARK
          gl_FragColor = vec4(vec3(0.115,0.390,0.136),1.0);
       #endif
       #ifdef AZURE
          gl_FragColor = vec4(vec3(0.666,0.823,0.912),1.0);
       #endif
       #ifdef RED
          gl_FragColor = vec4(vec3(0.910,0.081,0.116),1.0);
       #endif
       #ifdef WHITE
          gl_FragColor = vec4(vec3(1,1,1),1.0);
       #endif
       #ifdef GREYDARK
          gl_FragColor = vec4(vec3(0.330,0.340,0.340),1.0);
       #endif
    }
    #endif


    ton_portal.glsl
    Code: Select all
    !!ver 330
    !!cvarf glsl_time
    !!permu FOG
    #include "sys/fog.h"
    //    'Warp Speed'
    //    author: David Hoskins 2013.
    //   https://www.shadertoy.com/view/Msl3WH#
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
       gl_Position = ftetransform();
       v_edge = v_texcoord.xy;
    }
    #endif

    #ifdef FRAGMENT_SHADER
    varying vec2 v_edge;
    uniform float cvar_glsl_time;
    #define TAU 6.28318530718
    #define MAX_ITER 5
    void main( void )
    {
       float time = (cvar_glsl_time+29.) * 60.0;
        float s = 0.0, v = 0.0;
       vec2 uv = (v_edge.xy) * 2.0 - 1.0;
       float t = time*0.005;
       uv.x = (uv.x) + sin(t) * 0.5;
       float si = sin(t + 2.17); // ...Squiffy rotation matrix!
       float co = cos(t);
       uv *= mat2(co, si, -si, co);
       vec3 col = vec3(0.0);
       vec3 init = vec3(0.25, 0.25 + sin(time * 0.001) * 0.4, floor(time) * 0.0008);
       for (int r = 0; r < 100; r++) {
          vec3 p = init + s * vec3(uv, 0.143);
          p.z = mod(p.z, 2.0);
          for (int i=0; i < 10; i++)   p = abs(p * 2.04) / dot(p, p) - 0.75;
          v += length(p * p) * smoothstep(0.0, 0.5, 0.9 - s) * .002;
          // Get a purple and cyan effect by biasing the RGB in different ways...
          col +=  vec3(v * 0.8, 1.1 - s * 0.5, .7 + v * 0.5) * v * 0.013;
          s += .01;
       }
       gl_FragColor = vec4(col, 1.0);
       #ifdef FOG
       gl_FragColor = fog4(gl_FragColor);
       #endif
    }
    #endif


    ton_portal2.glsl
    Code: Select all
    !!ver 330
    !!cvarf glsl_time
    !!permu FOG
    // author: FabriceNeyret2
    // https://www.shadertoy.com/view/ldlSzX#
    #include "sys/fog.h"
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
       gl_Position = ftetransform();
       v_edge = v_texcoord.xy;
    }
    #endif

    #ifdef FRAGMENT_SHADER
    varying vec2 v_edge;
    uniform float cvar_glsl_time;
    #define N 23       // number of sources

    int MODE = 5;      // source distrib
    float POW = 1.;      // fading with distance


    const float k = 2.*3.14159/.04,  // 2 Pi / wavelenght
               c = 0.1;          // wavespeed

    #define t cvar_glsl_time

    bool keyToggle(int ascii) {
       return (vec3(0,vec2((.5+float(ascii))/256.,0.75)).x > 0.);
    }

    float rnd(float i) {
       return mod(4000.*sin(23464.345*i+45.345),1.);
    }
    float srnd(float i) { return 2.*rnd(i)-1.; }

    void main(void)
    {
       vec2 uv = 2.*(v_edge.xy-vec2(.5,.5));

       // --- controls

       
       vec2 mouse = vec2(1.5*cos(.2345*t)-.7*sin(t),sin(.3214*t)+.5*cos(1.234*t))/1.5;

       bool DISPLAY = keyToggle(64+23);                 // waves vs energy
       bool RND = keyToggle(64+18);                  // even vs random source distrib
       MODE = ( (keyToggle(32)||keyToggle(64+19)) ? 1 : 3 ) + ( (RND) ?0:1);    // line or circle source
       POW = (keyToggle(64+16)) ? 0. : 1.;             // 1/r decrease or not
          
       // --- calc sources contribs
       
       float x = -.75, y=-.7,
            xt = x  +((keyToggle(64+20))?.03*t:0.);
       const float step = 1.54/float(N);
       
       float Phi[N],D2[N];
       for (int i=0; i<N; i++) {
          vec2 P;   // generates sources distribution
          if       (MODE==1) { P = vec2(x,-.9); x+= step;}
          else if (MODE==2) { P = vec2(x,-.9); x+= step*(1.+srnd(float(i))); }
          else if (MODE==3) { P = .99*vec2(sin(4.*xt),-cos(4.*xt)); xt+= step;}
          else if (MODE==4) { P = .99*vec2(sin(4.*xt),-cos(4.*xt)); xt+= step*(1.+.7*srnd(float(i)));}
          else if (MODE==5) { P = vec2(2.*x,y); x+= 1.4*sqrt(step);
                          if (x>.7) { x=-.7; y+=sqrt(1.4*step);} }
          // the key: wave's phase pixel to source calibrated by wave phase mouse to source
          float dm = length(mouse-P),   phim = dm, //   -c*t,
               d  = length(uv-P),   phi  = d -c*t;
          Phi[i] = k*(phi-phim);  // stores wave attributes
          D2[i] = pow(d,POW);

          if (d<0.01) { gl_FragColor = vec4(0.,0.,1.,0.); return; }
       }
       
       // --- combines waves or energy
       
       float v = 0.;
       if (DISPLAY)               // waves       
          for (int i=0; i<N; i++)
             v += cos(Phi[i])/D2[i];

          else {                  // energy . is int_t{ ( sum_i{waves(i,x,t)} )^2 }
    #if 1
             for (int i=0; i<N; i++) {
                for (int j=0; j<N; j++)
                   v += cos(Phi[j]-Phi[i]) / (D2[i]*D2[j]);         
                //   if (j<i) v += 2.*cos(Phi[j]-Phi[i]) / (D2[i]*D2[j]); // not faster !
                //v += 1./ (D2[i]*D2[i]);
             }
    #else
          for (int i=0; i<N; i++)
             v += 1./ (D2[i]*D2[i]);
          int i=0, j=N-1;
          for (int k=0; k<N*(N-1)/2; k++) {
             if (i>=j) { i=0; j--; }
             v += 2.*cos(Phi[j]-Phi[i]) / (D2[i]*D2[j]);
          }      
    #endif         
          v = sqrt(v/2.);
       }
       v = v*4.5/float(N);
       gl_FragColor = vec4(v,v/2.,v/4.,1.);
       #ifdef FOG
       gl_FragColor = fog4(gl_FragColor);
       #endif
    }
    #endif


    ton_portalframe.glsl
    Code: Select all
    !!ver 330
    !!cvarf glsl_time
    //   author: Antonio "toneddu2000" Latronico
    //   placed under cc0 public domain license
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
      gl_Position = ftetransform();
      v_edge = v_texcoord.xy;
    }
    #endif

    #ifdef FRAGMENT_SHADER
    varying vec2 v_edge;
    uniform float cvar_glsl_time;//time set in a cvar!!
    vec3 start = vec3(0.489,0.650,0.912);
    vec3 end = vec3(0.624,0.893,1.000);

    void main() {
       vec3 color = vec3(0.0);
        color = mix(start, end, abs(sin(cvar_glsl_time)));
       gl_FragColor = vec4(color,1.0);
    }
    #endif


    ton_portalframe2.glsl
    Code: Select all
    !!ver 330
    !!cvarf glsl_time
    //   author: Antonio "toneddu2000" Latronico
    //   placed under cc0 public domain license
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
      gl_Position = ftetransform();
      v_edge = v_texcoord.xy;
    }
    #endif

    #ifdef FRAGMENT_SHADER
    varying vec2 v_edge;
    uniform float cvar_glsl_time;//time set in a cvar!!
    vec3 start = vec3(0.912,0.161,0.003);
    vec3 end = vec3(1.000,0.697,0.139);

    void main() {
       vec3 color = vec3(0.0);
        color = mix(start, end, abs(sin(cvar_glsl_time)));
       gl_FragColor = vec4(color,1.0);
    }
    #endif


    ton_sea.glsl
    Code: Select all
    !!ver 330
    !!cvarf glsl_time
    !!cvarf glsl_seasize
    !!permu FOG
    //    author: David Hoskins.
    //   https://www.shadertoy.com/view/MdlXz8
    //    Water turbulence effect by joltz0r 2013-07-04, improved 2013-07-07
    #include "sys/fog.h"
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
      gl_Position = ftetransform();
      v_edge = v_texcoord.xy;
    }
    #endif

    #ifdef FRAGMENT_SHADER
    varying vec2 v_edge;
    uniform float cvar_glsl_time;
    uniform float cvar_glsl_seasize;
    #define TAU 6.28318530718
    #define MAX_ITER 5

    void main( void )
    {
       float time = cvar_glsl_time * .5+23.0;
       vec2 texres = vec2(cvar_glsl_seasize,cvar_glsl_seasize);
        // uv should be the 0-1 uv of texture...
       vec2 uv = v_edge.xy / texres.xy;
        vec2 p = mod(uv*TAU, TAU)-250.0;
       vec2 i = vec2(p);
       float c = 1.0;
       float inten = .005;
       for (int n = 0; n < MAX_ITER; n++) {
          float t = time * (1.0 - (3.5 / float(n+1)));
          i = p + vec2(cos(t - i.x) + sin(t + i.y), sin(t - i.y) + cos(t + i.x));
          c += 1.0/length(vec2(p.x / (sin(i.x+t)/inten),p.y / (cos(i.y+t)/inten)));
       }
       c /= float(MAX_ITER);
       c = 1.17-pow(c, 1.4);
       vec3 colour = vec3(pow(abs(c), 8.0));
        colour = clamp(colour + vec3(0.0, 0.35, 0.5), 0.0, 1.0);
       gl_FragColor = vec4(colour, 1.0);
       #ifdef FOG
       gl_FragColor = fog4(gl_FragColor);
       #endif
    }
    #endif
  7. Now let's create, in the same glsl folder, all the glsl files for post processing effects

    ton_pp_ascii.glsl
    Code: Select all
    !!ver 130
    //   author: mattdesl
    //   https://www.npmjs.com/package/glsl-ascii-filter#float-asciifilter-vec3-color-vec2-uv-float-pixelsize
    //   A simple ASCII post-processing effect in GLSL, original at https://www.shadertoy.com/view/lssGDj by @movAX13h.
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main ()
    {
       gl_Position = ftetransform();
       v_edge = v_texcoord.xy;
    }
    #endif
    #ifdef FRAGMENT_SHADER
    uniform sampler2D s_t0;
    uniform vec3  iResolution;
    varying vec2 v_edge;


    float character(float n, vec2 p) {
      p = floor(p*vec2(4.0, -4.0) + 2.5);
      if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y){
        if (int(mod(n/exp2(p.x + 5.0*p.y), 2.0)) == 1) return 1.0;
      }
      return 0.0;
    }

    float luma(vec3 color) {
      return dot(color, vec3(0.299, 0.587, 0.114));
    }

    float asciiFilter(vec3 color, vec2 uv, float pixelSize) {
      float threshold = luma(color);
      float n =  65536.0;                  // .
      if (threshold > 0.2) n = 65600.0;    // :
      if (threshold > 0.3) n = 332772.0;   // *
      if (threshold > 0.4) n = 15255086.0; // o
      if (threshold > 0.5) n = 23385164.0; // &
      if (threshold > 0.6) n = 15252014.0; // 8
      if (threshold > 0.7) n = 13199452.0; // @
      if (threshold > 0.8) n = 11512810.0; // #
      vec2 p = mod( uv / ( pixelSize * 0.2 ), 2.0) - vec2(1.0);
      return character(n, p);
    }

    float asciiFilter(vec3 color, vec2 uv) {
      return asciiFilter(color, uv, 1.0 / 25.0);
    }

    void main ()
    {


       vec4 color = texture2D(s_t0, v_edge.xy);

       //aspect-corrected screen UVs
       vec2 st = v_edge.xy;
       //st.x *= iResolution.x / iResolution.y;
       //st.x = iResolution.x * 2;
       //apply filter
       //gl_FragColor.rgb = color.rgb * asciiFilter(color.rgb, st);
       //gl_FragColor.a = color.a;
       vec4 zaz;
       zaz.rgb = color.rgb * asciiFilter(color.rgb, st);
       gl_FragColor = vec4(zaz.r, zaz.g, zaz.b, 1);
    }
    #endif


    ton_pp_bandw.glsl
    Code: Select all
    !!ver 130
    //   author: lezard //https://blog.sovapps.com/author/lezard/
    //   https://blog.sovapps.com/play-with-shaders-black-and-white-part-1/
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main ()
    {
       gl_Position = ftetransform();
       v_edge = v_texcoord.xy;
    }
    #endif
    #ifdef FRAGMENT_SHADER
    uniform sampler2D s_t0;
    varying vec2 v_edge;
    varying vec3 graycol;
    uniform vec4 tint = vec4(1,1,1,1);

    void main ()
    {

       gl_FragColor = texture2D(s_t0, v_edge.xy);
       vec4 normalColor = texture2D(s_t0, v_edge.xy);
        float gray = 0.299*normalColor.r + 0.587*normalColor.g + 0.114*normalColor.b;
        gl_FragColor = vec4(gray, gray, gray, normalColor.a);
    }
    #endif


    ton_pp_basic.glsl
    Code: Select all
    !!ver 330
    //   author: Antonio "toneddu2000" Latronico
    //   placed under cc0 public domain license
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
       gl_Position = ftetransform();
       v_edge = v_texcoord.xy;
    }
    #endif
    #ifdef FRAGMENT_SHADER
    varying vec2 v_edge;
    uniform sampler2D s_t0;
    void main(void)
    {
       vec3 img;
       img = vec3(texture2D(s_t0,v_edge.xy));
       gl_FragColor = vec4(vec3(img.r,img.g,img.b),1);
    }
    #endif


    ton_pp_bloom.glsl
    Code: Select all
    !!ver 330
    !!cvarf glsl_bloomthres
    !!cvarf glsl_bloomintensity
    //   author: mAlk
    //   https://www.shadertoy.com/view/Ms2Xz3
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
       gl_Position = ftetransform();
       v_edge = v_texcoord.xy;
    }
    #endif
    #ifdef FRAGMENT_SHADER
    varying vec2 v_edge;
    uniform sampler2D s_t0;
    uniform float cvar_glsl_bloomthres;
    uniform float cvar_glsl_bloomintensity;

    vec4 BlurColor (in vec2 Coord, in sampler2D Tex, in float MipBias)
    {
       vec2 res = vec2(0.5,0.5);
       vec2 TexelSize = MipBias/res.xy;
       
        vec4  Color = texture(Tex, Coord, MipBias);
        Color += texture(Tex, Coord + vec2(TexelSize.x,0.0), MipBias);       
        Color += texture(Tex, Coord + vec2(-TexelSize.x,0.0), MipBias);       
        Color += texture(Tex, Coord + vec2(0.0,TexelSize.y), MipBias);       
        Color += texture(Tex, Coord + vec2(0.0,-TexelSize.y), MipBias);       
        Color += texture(Tex, Coord + vec2(TexelSize.x,TexelSize.y), MipBias);       
        Color += texture(Tex, Coord + vec2(-TexelSize.x,TexelSize.y), MipBias);       
        Color += texture(Tex, Coord + vec2(TexelSize.x,-TexelSize.y), MipBias);       
        Color += texture(Tex, Coord + vec2(-TexelSize.x,-TexelSize.y), MipBias);   

        return Color/9.0;
    }

    void main() {
       float thres = cvar_glsl_bloomthres;
        float intens = cvar_glsl_bloomintensity;
        float blursize = 0.5;
        vec2 uv = (v_edge.xy);
        vec4 Color = texture(s_t0, uv);
        vec4 highlight = clamp(BlurColor(uv, s_t0, blursize)-thres,0.0,1.0)*1.0/(1.0-thres);
        gl_FragColor = 1.0-(1.0-Color)*(1.0-highlight*intens); //Screen Blend Mode   
    }
    #endif


    ton_pp_chromaticaberration.glsl
    Code: Select all
    !!ver 330
    //   author: hornet
    //   https://www.shadertoy.com/view/XssGz8
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
      gl_Position = ftetransform();
      //gl_TexCoord[0] = gl_MultiTexCoord0;
      v_edge = v_texcoord.xy;
    }
    #endif
    #ifdef FRAGMENT_SHADER
    varying vec2 v_edge;
    uniform sampler2D s_t0;
    float linterp( float t ) {
       return clamp( 1.0 - abs( 2.0*t - 1.0 ), 0.0, 1.0 );
    }

    float remap( float t, float a, float b ) {
       return clamp( (t - a) / (b - a), 0.0, 1.0 );
    }
    vec2 remap( vec2 t, vec2 a, vec2 b ) {
       return clamp( (t - a) / (b - a), 0.0, 1.0 );
    }

    vec3 spectrum_offset_rgb( float t ) {
       vec3 ret;
       float lo = step(t,0.5);
       float hi = 1.0-lo;
       float w = linterp( remap( t, 1.0/6.0, 5.0/6.0 ) );
       ret = vec3(lo,1.0,hi) * vec3(1.0-w, w, 1.0-w);

       return pow( ret, vec3(1.0/2.2) );
    }

    const float gamma = 2.2;
    vec3 lin2srgb( vec3 c )
    {
        return pow( c, vec3(gamma) );
    }
    vec3 srgb2lin( vec3 c )
    {
        return pow( c, vec3(1.0/gamma));
    }


    vec3 yCgCo2rgb(vec3 ycc)
    {
        float R = ycc.x - ycc.y + ycc.z;
       float G = ycc.x + ycc.y;
       float B = ycc.x - ycc.y - ycc.z;
        return vec3(R,G,B);
    }

    vec3 spectrum_offset_ycgco( float t )
    {
       //vec3 ygo = vec3( 1.0, 1.5*t, 0.0 ); //green-pink
        //vec3 ygo = vec3( 1.0, -1.5*t, 0.0 ); //green-purple
        vec3 ygo = vec3( 1.0, 0.0, -1.25*t ); //cyan-orange
        //vec3 ygo = vec3( 1.0, 0.0, 1.5*t ); //brownyello-blue
        return yCgCo2rgb( ygo );
    }

    vec3 yuv2rgb( vec3 yuv )
    {
        vec3 rgb;
        rgb.r = yuv.x + yuv.z * 1.13983;
        rgb.g = yuv.x + dot( vec2(-0.39465, -0.58060), yuv.yz );
        rgb.b = yuv.x + yuv.y * 2.03211;
        return rgb;
    }


    // ====

    //note: from https://www.shadertoy.com/view/XslGz8
    vec2 radialdistort(vec2 coord, vec2 amt)
    {
       vec2 cc = coord - 0.5;
       return coord + 2.0 * cc * amt;
    }

    // Given a vec2 in [-1,+1], generate a texture coord in [0,+1]
    vec2 barrelDistortion( vec2 p, vec2 amt )
    {
        p = 2.0 * p - 1.0;

        /*
        const float maxBarrelPower = 5.0;
       //note: http://glsl.heroku.com/e#3290.7 , copied from Little Grasshopper
        float theta  = atan(p.y, p.x);
        vec2 radius = vec2( length(p) );
        radius = pow(radius, 1.0 + maxBarrelPower * amt);
        p.x = radius.x * cos(theta);
        p.y = radius.y * sin(theta);

       /*/
        // much faster version
        //const float maxBarrelPower = 5.0;
        //float radius = length(p);
        const float maxBarrelPower = sqrt(5.0);
        float radius = dot(p,p); //faster but doesn't match above accurately
        p *= pow(vec2(radius), maxBarrelPower * amt);
       /* */

        return p * 0.5 + 0.5;
    }

    //note: from https://www.shadertoy.com/view/MlSXR3
    vec2 brownConradyDistortion(vec2 uv, float dist)
    {
        uv = uv * 2.0 - 1.0;
        // positive values of K1 give barrel distortion, negative give pincushion
        float barrelDistortion1 = 0.1 * dist; // K1 in text books
        float barrelDistortion2 = -0.025 * dist; // K2 in text books

        float r2 = dot(uv,uv);
        uv *= 1.0 + barrelDistortion1 * r2 + barrelDistortion2 * r2 * r2;
        //uv *= 1.0 + barrelDistortion1 * r2;
       
        // tangential distortion (due to off center lens elements)
        // is not modeled in this function, but if it was, the terms would go here
        return uv * 0.5 + 0.5;
    }

    vec2 distort( vec2 uv, float t, vec2 min_distort, vec2 max_distort )
    {
        vec2 dist = mix( min_distort, max_distort, t );
        //return radialdistort( uv, 2.0 * dist );
        //return barrelDistortion( uv, 1.75 * dist ); //distortion at center
        return brownConradyDistortion( uv, 75.0 * dist.x );
    }

    // ====

    vec3 spectrum_offset_yuv( float t )
    {
       //vec3 yuv = vec3( 1.0, 3.0*t, 0.0 ); //purple-green
        //vec3 yuv = vec3( 1.0, 0.0, 2.0*t ); //purple-green
        vec3 yuv = vec3( 1.0, 0.0, -1.0*t ); //cyan-orange
        //vec3 yuv = vec3( 1.0, -0.75*t, 0.0 ); //brownyello-blue
        return yuv2rgb( yuv );
    }

    vec3 spectrum_offset( float t )
    {
        return spectrum_offset_rgb( t );
        //return spectrum_offset_ycgco( t );
        //return spectrum_offset_yuv( t );
    }

    // ====

    float nrand( vec2 n )
    {
       return fract(sin(dot(n.xy, vec2(12.9898, 78.233)))* 43758.5453);
    }

    void main( )
    {   
       vec2 uv = v_edge.xy;
       
       //tweak these 2 const
        const float MAX_DIST_PX = 40.0;
       const float SIZE = 3;
       
        float max_distort_px = MAX_DIST_PX * (1.0-vec2(0.5,0.8).x/1920);
       vec2 max_distort = vec2(max_distort_px) / vec2(1920,1080);
        vec2 min_distort = SIZE * max_distort;

        //vec2 oversiz = vec2(1.0);
        vec2 oversiz = distort( vec2(1.0), 1.0, min_distort, max_distort );
        uv = remap( uv, 1.0-oversiz, oversiz );
       
        //debug oversiz
        //vec2 distuv = distort( uv, 1.0, max_distort );
        //if ( abs(distuv.x-0.5)>0.5 || abs(distuv.y-0.5)>0.5)
        //{
        //    fragColor = vec4( 1.0, 0.0, 0.0, 1.0 ); return;
        //}
       
       vec3 sumcol = vec3(0.0);
       vec3 sumw = vec3(0.0);
        float rnd = nrand( uv + fract(0.01) );
        const int num_iter = 16;
       for ( int i=0; i<num_iter;++i )
       {
          float t = (float(i)+rnd) / float(num_iter-1);
          vec3 w = spectrum_offset( t );
          sumw += w;
          sumcol += w * srgb2lin(texture2D( s_t0, distort(uv, t, min_distort, max_distort ) ).rgb);
       }
        sumcol.rgb /= sumw;
       
        vec3 outcol = lin2srgb(sumcol.rgb);
        outcol += rnd/255.0;
       
       gl_FragColor = vec4( outcol, 1.0);
    }
    #endif


    ton_pp_depth.glsl
    Code: Select all
    !!ver 330
    //   author: Antonio "toneddu2000" Latronico
    //   placed under cc0 public domain license
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
       gl_Position = ftetransform();
       v_edge = v_texcoord.xy;
    }
    #endif
    #ifdef FRAGMENT_SHADER
    varying vec2 v_edge;
    uniform sampler2D s_t0;
    void main(void)
    {
       vec3 img;
       img = vec3(texture2D(s_t0,v_edge.xy));
       gl_FragColor = vec4(img,1);
    }
    #endif


    ton_pp_median.glsl
    Code: Select all
    !!ver 330
    //   author: Morgan McGuire https://www.cs.williams.edu/~morgan/
    //   http://graphics.cs.williams.edu/papers/MedianShaderX6/
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
      gl_Position = ftetransform();
      //gl_TexCoord[0] = gl_MultiTexCoord0;
      v_edge = v_texcoord.xy;
    }
    #endif
    #ifdef FRAGMENT_SHADER
    uniform sampler2D s_t0;
    varying vec2 v_edge;

    #ifndef G3D
    // vec2(1/width, 1/height) of the texture
        uniform vec2 Tinvsize;
    #else
    #    define Tinvsize g3d_sampler2DInvSize(s_t0))
    #endif


    // Change these 2 defines to change precision,
    #define vec vec3
    #define toVec(x) x.rgb

    //#define vec vec4
    //#define toVec(x) x.rgba

    #define s2(a, b)            temp = a; a = min(a, b); b = max(temp, b);
    #define mn3(a, b, c)         s2(a, b); s2(a, c);
    #define mx3(a, b, c)         s2(b, c); s2(a, c);

    #define mnmx3(a, b, c)         mx3(a, b, c); s2(a, b);                                   // 3 exchanges
    #define mnmx4(a, b, c, d)      s2(a, b); s2(c, d); s2(a, c); s2(b, d);                   // 4 exchanges
    #define mnmx5(a, b, c, d, e)   s2(a, b); s2(c, d); mn3(a, c, e); mx3(b, d, e);           // 6 exchanges
    #define mnmx6(a, b, c, d, e, f) s2(a, d); s2(b, e); s2(c, f); mn3(a, b, c); mx3(d, e, f); // 7 exchanges

    void main() {

      vec v[9];
      //change noise1 to increase / decrease
      float noise1 = 0.003;

      // Add the pixels which make up our window to the pixel array.
      for(int dX = -1; dX <= 1; ++dX) {
        for(int dY = -1; dY <= 1; ++dY) {      
          vec2 offset = vec2(float(dX), float(dY));
             
          // If a pixel in the window is located at (x+dX, y+dY), put it at index (dX + R)(2R + 1) + (dY + R) of the
          // pixel array. This will fill the pixel array, with the top left pixel of the window at pixel[0] and the
          // bottom right pixel of the window at pixel[N-1].
          v[(dX + 1) * 3 + (dY + 1)] = toVec(texture2D(s_t0, v_edge.xy + offset * noise1));
        }
      }

      vec temp;

      // Starting with a subset of size 6, remove the min and max each time
      mnmx6(v[0], v[1], v[2], v[3], v[4], v[5]);
      mnmx5(v[1], v[2], v[3], v[4], v[6]);
      mnmx4(v[2], v[3], v[4], v[7]);
      mnmx3(v[3], v[4], v[8]);
      toVec(gl_FragColor) = v[4];
    }
    #endif


    ton_pp_motionblur.glsl
    Code: Select all
    !!ver 330
    !!cvarf glsl_mousex
    !!cvarf glsl_mousey
    !!cvarf glsl_velx
    !!cvarf glsl_vely
    //   author: martins upitis
    //   http://devlog-martinsh.blogspot.it/2011/10/glsl-depth-of-field-with-bokeh-v2.html
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    varying vec2 v_edge;
    void main(void)
    {
      gl_Position = ftetransform();
      //gl_TexCoord[0] = gl_MultiTexCoord0;
      v_edge = v_texcoord.xy;
    }
    #endif
    #ifdef FRAGMENT_SHADER
    varying vec2 v_edge;
    uniform sampler2D s_t0;
    uniform float cvar_glsl_mousex;//mouse x position in a cvar!!
    uniform float cvar_glsl_mousey;//mouse y position in a cvar!!
    uniform float cvar_glsl_velx;//player velocity x in a cvar!!
    uniform float cvar_glsl_vely;//player velocity y in a cvar!!

    uniform sampler2D bgl_RenderedTexture;
    uniform sampler2D bgl_DepthTexture;
    uniform float bgl_RenderedTextureWidth;
    uniform float bgl_RenderedTextureHeight;

    #define PI    3.14159265

    float width = 1920; //texture width
    float height = 1080; //texture height

    vec2 texel = vec2(1.0/width,1.0/height);

    uniform float focalDepth;  //focal point. comes from external script, but you may use autofocus option below

    //------------------------------------------
    //user variables

    int samples = 3; //samples on the first ring
    int rings = 5; //ring count
    bool autofocus = false; //use autofocus in shader?
    float range = 5.0; //focal range
    float maxblur = cvar_glsl_mousex/30; //clamp value of max blur
    float threshold = 0.4; //highlight threshold;
    float gain = 0.0; //highlight gain;
    float bias = 1; //bokeh edge bias
    float fringe = 1; //bokeh chromatic aberration/fringing
    bool noise = true; //use noise instead of pattern for sample dithering
    float namount = 0.001; //noise amount
    bool depthblur = true; //blur the depth buffer?
    float dbsize = 6.0; //depthblursize

    //------------------------------------------

    float bdepth(vec2 coords) //blurring depth
    {
       float d = 0.0;
       float kernel[9];
       vec2 offset[9];
       
       vec2 wh = vec2(texel.x, texel.y) * dbsize;
       
       offset[0] = vec2(-wh.x,-wh.y);
       offset[1] = vec2( 0.0, -wh.y);
       offset[2] = vec2( wh.x -wh.y);
       
       offset[3] = vec2( -wh.x, 0.0);
       offset[4] = vec2( 0.0,   0.0);
       offset[5] = vec2( wh.x,  0.0);
       
       offset[6] = vec2( -wh.x, wh.y);
       offset[7] = vec2( 0.0,   wh.y);
       offset[8] = vec2( wh.x,  wh.y);
       
       kernel[0] = 1.0/16.0;    kernel[1] = 2.0/16.0;   kernel[2] = 1.0/16.0;
       kernel[3] = 2.0/16.0;   kernel[4] = 4.0/16.0;   kernel[5] = 2.0/16.0;
       kernel[6] = 1.0/16.0;   kernel[7] = 2.0/16.0;   kernel[8] = 1.0/16.0;
       
       for( int i = 0; i < 9; i++ ){
          float tmp = texture2D(s_t0, coords + offset[i]).r;
          d += tmp * kernel[i];
       }
       
       return d;
    }


    vec3 color(vec2 coords,float blur) //processing the sample
    {
       vec3 col = vec3(0.0);
       
       col.r = texture2D(s_t0,coords + vec2(0.0,1.0)*texel*fringe*blur).r;
       col.g = texture2D(s_t0,coords + vec2(-0.866,-0.5)*texel*fringe*blur).g;
       col.b = texture2D(s_t0,coords + vec2(0.866,-0.5)*texel*fringe*blur).b;
       
       vec3 lumcoeff = vec3(0.299,0.587,0.114);
       float lum = dot(col.rgb, lumcoeff);
       float thresh = max((lum-threshold)*gain, 0.0);
       return col + mix(vec3(0.0),col,thresh*blur);
    }

    vec2 rand(in vec2 coord) //generating noise/pattern texture for dithering
    {
       float noiseX = ((fract(1.0-coord.s*(width/2.0))*0.25)+(fract(coord.t*(height/2.0))*0.75))*2.0-1.0;
       float noiseY = ((fract(1.0-coord.s*(width/2.0))*0.75)+(fract(coord.t*(height/2.0))*0.25))*2.0-1.0;
       
       if (noise){
           noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0;
           noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0;
       }
       return vec2(noiseX,noiseY);
    }

    void main()
    {
       
       float depth = texture2D(s_t0,v_edge.xy).x;
       float blur = 0.0;
       
       if (depthblur){
          depth = bdepth(v_edge.xy);
       }
       blur = clamp((abs(depth - focalDepth)/range)*100.0,-maxblur,maxblur);
       if (autofocus){
          float fDepth = texture2D(s_t0,vec2(0.5,0.5)).x;
          blur = clamp((abs(depth - fDepth)/range)*100.0,-maxblur,maxblur);
       }
       vec2 noise = rand(v_edge.xy)*namount*blur;
       float w = (1.0/width)*blur+noise.x;
       float h = (1.0/height)*blur+noise.y;
       vec3 col = texture2D(s_t0, v_edge.xy).rgb;
       float s = 1.0;
       int ringsamples;
       for (int i = 1; i <= rings; i += 1){   
          ringsamples = i * samples;
          for (int j = 0 ; j < ringsamples ; j += 1){     
             float step = PI*2.0 / float(ringsamples);
             float pw = (cos(float(j)*step)*float(i));
             float ph = (sin(float(j)*step)*float(i));
             col += color(v_edge.xy + vec2(pw*w,ph*h),blur)*mix(1.0,(float(i))/(float(rings)),bias);
             s += 1.0*mix(1.0,(float(i))/(float(rings)),bias);
          }
       }
       col /= s;
       gl_FragColor.rgb = col;
       gl_FragColor.a = 0;
    }
    #endif
  8. if you want sounds as showed in the video, just download these lame sounds I made just for this project and put them in a sounds subfolder in data folder. Don't worry: released under cc0 public domain license, so no license problem here
  9. now launch fteqw executable. Open console (shift+ESC key) and you should see "GLSL Showreel initialized" in the top. Type in the console
    Code: Select all
    pr_dumpplatform -o defs -Ffte -Tcs

    Close fteqw. Go to the autocreated src folder and rename defs.qc to defs.c. In the src folder add these source files (all released under cc0 public domain license, no problem here)

    progs.src
    Code: Select all
    #pragma    PROGS_DAT "../csprogs.dat"
    #define    CSQC
    #include   "defs.c"
    #include   "defscustom.c"
    #include   "fx.c"
    #include   "render.c"
    #include   "csqc.c"


    csqc.c
    Code: Select all
    //GLSL Showreel - created by Antonio "toneddu2000" Latronico and released under CC0 Public Domain license https://creativecommons.org/publicdomain/zero/1.0/
    void CSQC_Init(float apilevel, string enginename, float engineversion)
    {
       //create sun cvar
       registercvar("sun_intensity","0.2");
       registercvar("sun_height","1000");
       //create camera cvar
       registercvar("camera_speed","0.5");
       //create glsl cvars
       registercvar("glsl_time","0");
       registercvar("glsl_mousex","0");
       registercvar("glsl_mousey","0");
       registercvar("glsl_velx","0");
       registercvar("glsl_vely","0");
       registercvar("glsl_skysize","0.006");
       registercvar("glsl_seasize","0.0006");
       registercvar("glsl_seamove","1");
       registercvar("glsl_bloomthres","0.45");
       registercvar("glsl_bloomintensity","1.2");
       //camera
       camera = spawn();
       camera.movetype = MOVETYPE_FLY;
       setorigin(camera,CAMERA_START_ORIGIN);
       //glsl init
       fxName = "ppcolor";
       fxTitle = "None";
       //fog init
       localcmd("fog 0.12 0.95 0.95 1.2 0.65 1.5\n");
       //ui
       uiMenu = TRUE;
       uiMenuQuit = FALSE;
       uiColorAlpha = 1;
       uiFlashAlpha = 1;
       //sounds
       #ifdef USESOUNDS
       precache_sound(SOUND_SEA);
       precache_sound(SOUND_SEAWAVE);
       precache_sound(SOUND_PORTAL);
       precache_sound(SOUND_WIND);
       precache_sound(SOUND_SWITCH);
       sound(camera,CHAN_AUTO,SOUND_WIND,SOUND_VOL_WIND,0,0,SOUNDFLAG_FORCELOOP);
       sound(camera,CHAN_WEAPON,SOUND_SEA,SOUND_VOL_SEA,0,0,SOUNDFLAG_FORCELOOP);
       sound(camera,CHAN_ITEM,SOUND_SEAWAVE,SOUND_VOL_SEAWAVE,0,0,SOUNDFLAG_FORCELOOP);
       #endif
    }

    noref float CSQC_InputEvent(float evtype, float scanx, float chary, float devid)
    {
       switch(evtype){
          case IE_KEYUP:
             if (scanx == K_MOUSE1){
                fxPostprocessColor = !fxPostprocessColor;
                if(fxPostprocessColor == TRUE){
                   uiColorAlpha = 1;
                }
             }
             if (scanx == K_MOUSE2){
                fxPostprocessDepth = !fxPostprocessDepth;
             }
             if (scanx == K_MWHEELUP){
                #ifdef USESOUNDS
                if(fxPostprocessColor && !uiMenu){
                   sound(camera,CHAN_VOICE,SOUND_SWITCH,SOUND_VOL_SEA,0);
                }
                #endif
                uiColorAlpha = 0;
                FX_PlayLoop();
             }
             if (scanx == K_ESCAPE){
                uiMenuQuit = FALSE;
             }
             //letter N
             if (scanx == 110){
                uiMenu = TRUE;
                uiMenuQuit = FALSE;
             }
             //letter Q
             if (scanx == 113){
                uiMenu = TRUE;
                uiMenuQuit = TRUE;
             }
             //letter Y
             if (scanx == 121){
                if(uiMenuQuit){
                   localcmd("quit\n");
                }
             }
          break;
       }
       return FALSE;
    }

    void CSQC_Input_Frame()
    {
       local float spd = cvar("camera_speed");
       
       if(!uiMenu){
          makevectors(input_angles);
          camera.angles = input_angles;
          camera.velocity = v_forward;
          camera.velocity *= input_movevalues_x * spd;
          if(camera.origin_z < CAMERA_LIMIT_GROUND){
             camera.origin_z = CAMERA_LIMIT_GROUND+5;
          }
          if(camera.origin_z > CAMERA_LIMIT_SKY){
             camera.origin_z = CAMERA_LIMIT_SKY-5;
          }
          if(vlen(PORTAL1_ORG - camera.origin)<150){
             #ifdef USESOUNDS
             sound(camera,CHAN_VOICE,SOUND_PORTAL,SOUND_VOL_PORTAL,0);
             #endif
             uiFlashAlpha = 1;
             camera.origin = PORTAL2_ORG + [350,0,0];
          }
          if(vlen(PORTAL2_ORG - camera.origin)<150){
             #ifdef USESOUNDS
             sound(camera,CHAN_VOICE,SOUND_PORTAL,SOUND_VOL_PORTAL,0);
             #endif
             uiFlashAlpha = 1;
             camera.origin = PORTAL1_ORG + [-350,0,0];
          }
          
       }
       if(cvar("glsl_seamove")==TRUE){
          if(camera.velocity_x == 0 && camera.velocity_y == 0 && camera.velocity_z == 0){
             camera.origin_z += 0.1 * sin(time * 1);
          }
       }
    }

    float CSQC_ConsoleCommand(string strMessage)
    {
       tokenize(strMessage);
       switch(argv(0))
       {
          case "togglemenu":
             uiMenu = !uiMenu;
             return TRUE;
          break;
       }
       return FALSE;
    }

    void CSQC_UpdateView(float vwidth, float vheight, float notmenu)
    {   
       clearscene();
       //fx set vars
       FX_GlslGetUniformByCvars();
       //view properties
       setviewprop(VF_DRAWWORLD,FALSE);
       setviewprop(VF_SCREENPSIZE,[vwidth,vheight,0]);
       setviewprop(VF_SIZE,[vwidth,vheight,0]);
       setviewprop(VF_ORIGIN, camera.origin);
       setviewprop(VF_ANGLES, camera.angles);
       //fx init
       FX_GlslPostProcessInit();
       //add view entities
       addentities(MASK_ENGINE);
       //render 3d objects
       local vector seemov;
       if(cvar("glsl_seamove") == TRUE){
          seemov = [0,0,25*sin(time * 0.9)];
       }
       else{
          seemov = [0,0,0];
       }
       Render_Sky();
       Render_Sea();
       Render_PortalFrame(5,70,100,1,PORTAL1_ORG+[-58.8,0,0]+seemov,"portalframe");
       Render_Portal(64,PORTAL1_ORG+seemov,"portal");
       Render_PortalFrame(5,70,100,1,PORTAL2_ORG+[-69.1,0,0]+seemov,"portalframe2");
       Render_Portal(64,PORTAL2_ORG+seemov,"portal2");
       Render_Horizon();
       //render scene
       renderscene();
       //fx end
       FX_GlslPostProcessFlush();
       FX_GlslPostProcessStoreToTexture(vwidth,vheight);
       //ui
       local string uicolen = "Post process color enabled";
       local string uimenutit = "GLSL Showreel - Antonio Latronico";
       local string uimenutgl = "ESC key to toggle menu";
       local string uimenumouse = "Mouse1 for toggle GLSL color, Mouse2 for toggle GLSL depth";
       local string uiquit = "Q key to quit showreel";
       local string uiquitmsg = "Do you want to leave showreel?";
       local string uiquitconfirm = "Y or N";
       local vector uitextcolor = [0.4,0.4,0.4];
       local vector uitextsize = [3.5,3.5,0];
       local vector uimenutitlesize = [7.5,7.5,0];
       local vector uimenutextsize = [5,5,0];
       if(uiMenu){
          if(!uiMenuQuit){
             drawfill([0,0,0],[vwidth,vheight,0],[1,1,1],0.92);
             drawstring([vwidth-stringwidth(uimenutit,0)*2,40,0],uimenutit,uimenutitlesize,uitextcolor,0.8,0);
             drawstring([20,70,0],uimenutgl,uimenutextsize,uitextcolor,0.8,0);
             drawstring([20,100,0],uimenumouse,uimenutextsize,uitextcolor,0.8,0);
             drawstring([20,130,0],uiquit,uimenutextsize,uitextcolor,0.8,0);
          }
          else{
             drawfill([0,0,0],[vwidth,vheight,0],[1,1,1],1);
             drawstring([vwidth-(stringwidth(uiquitmsg,0)*2),70,0],uiquitmsg,uimenutextsize,uitextcolor,0.8,0);
             drawstring([vwidth/2,95,0],uiquitconfirm,uimenutextsize,uitextcolor,0.8,0);
          }
       }
       else{
          if(uiFlashAlpha > 0){
             uiFlashAlpha -= frametime * 1;
          }
          if(fxPostprocessColor){
             if(uiColorAlpha > 0){
                uiColorAlpha -= frametime * 1;
             }
             drawstring([vwidth/2-stringwidth(uicolen,0)/2,100,0],uicolen,[10,10,0],uitextcolor+[0,0.8,0],uiColorAlpha,0);
             drawstring([20,20,0], "Glsl used: ",uitextsize,uitextcolor,0.5,0);
             drawstring([65,20,0], fxTitle,uitextsize,uitextcolor+[0,0,1.5],0.9,0);
             drawstring([20,35,0], "Scroll mouse wheel up to loop post process effects",uitextsize,uitextcolor,0.5,0);
          }
          drawfill([1,1,1],[vwidth,vheight,0],[1,1,1],uiFlashAlpha);
       }
    }


    defscustom.c
    Code: Select all
    //GLSL Showreel - created by Antonio "toneddu2000" Latronico and released under CC0 Public Domain license https://creativecommons.org/publicdomain/zero/1.0/
    //camera
    entity      camera;
    vector      CAMERA_START_ORIGIN = [-400,0,165];
    float      CAMERA_LIMIT_GROUND = 55;
    float      CAMERA_LIMIT_SKY = 1200;
    //fx
    float      fxPostprocessDepth, fxPostprocessColor, fxGlslTimer, fxLoop;
    string      fxName, fxTitle;
    float      FX_TOTAL = 6;
    //ui
    float      uiMenu,uiMenuQuit,uiColorAlpha,uiFlashAlpha;
    //portal
    vector      PORTAL1_ORG = [0,0,150];
    vector       PORTAL2_ORG = [-2000,0,150];
    //sounds
    //#define    USESOUNDS
    #ifdef USESOUNDS
    string      SOUND_SEA = "sounds/water.wav";
    string      SOUND_SEAWAVE = "sounds/seawave.wav";
    string      SOUND_PORTAL = "sounds/portal.wav";
    string      SOUND_WIND = "sounds/wind_loop.wav";
    string      SOUND_SWITCH = "sounds/switch.wav";
    float      SOUND_VOL_SEA = 0.5;
    float      SOUND_VOL_SEAWAVE = 0.85;
    float      SOUND_VOL_WIND = 3.5;
    float      SOUND_VOL_PORTAL = 6;
    #endif


    fx.c
    Code: Select all
    //GLSL Showreel - created by Antonio "toneddu2000" Latronico and released under CC0 Public Domain license https://creativecommons.org/publicdomain/zero/1.0/

    void FX_PlayLoop()
    {
       fxLoop++;
       if(fxLoop > FX_TOTAL){
          fxLoop = 0;
       }
       //increase here for new effects
       switch(fxLoop){
          case 0:
             fxName = "ppcolor";
             fxTitle = "None";
          break;
          case 1:
             fxName = "ppbandw";
             fxTitle = "Black and white";
          break;
          case 2:
             fxName = "ppmblur";
             fxTitle = "Motion blur";
          break;
          case 3:
             fxName = "ppchrom";
             fxTitle = "Chromatic aberration";
          break;
          case 4:
             fxName = "ppascii";
             fxTitle = "Ascii code";
          break;
          case 5:
             fxName = "ppbloom";
             fxTitle = "Bloom";
          break;
          case 6:
             fxName = "ppmedian";
             fxTitle = "Median point";
          break;
          default:
             fxName = "";
          break;
       }
    }

    void FX_GlslPostProcessVarsInit()
    {
       fxPostprocessDepth = TRUE;
       fxPostprocessColor = TRUE;
    }

    void FX_GlslPostProcessInit()
    {
       local float sizex = cvar("vid_width");
       local float sizey = cvar("vid_height");
       local vector r = [sizex,sizey,0];
       
       //rt shaders to compile. Order matters! Latter will be seen!
       if(fxPostprocessDepth == TRUE){
          setproperty(VF_RT_DEPTH, "ppdepth", 4,r);
          setviewprop(VF_SIZE, r);
       }
       if(fxPostprocessColor == TRUE){
          setproperty(VF_RT_DESTCOLOUR, fxName, 1, r);
          setviewprop(VF_SIZE, r);
       }
    }

    void FX_GlslPostProcessFlush()
    {
       //flush fx or scene won't be rendered
       if(fxPostprocessDepth == TRUE){
          setproperty(VF_RT_DEPTH, "");
       }
       if(fxPostprocessColor == TRUE){
          setproperty(VF_RT_DESTCOLOUR, "");
       }
    }

    void FX_GlslPostProcessStoreToTexture(float screenwidth,float screenheight)
    {
       
       //store postprocess in shader which has $rt: keyword
       if(fxPostprocessColor == TRUE){
          drawpic([0,0,0],fxName,[screenwidth,screenheight,0],[1,1,1],1);
       }
       if(fxPostprocessDepth == TRUE){
          drawpic([0,0,0],"ppdepth",[screenwidth,screenheight,0],[1,1,1],1);
       }
    }

    void FX_GlslGetUniformByCvars()
    {
       //setting vars to cvars, which have uniform corrispective in glsl shader.
       //add time
       fxGlslTimer = time;
       localcmd(strcat("glsl_time ",ftos(fxGlslTimer),"\n"));
       //add mouse position (for motion blur stuff)
       local vector mpos = getmousepos();
       localcmd(strcat("glsl_mousex ",ftos(mpos_x),"\n"));
       localcmd(strcat("glsl_mousey ",ftos(mpos_y),"\n"));
       //add velocity
       localcmd(strcat("glsl_velx ",ftos(camera.velocity_x),"\n"));
       localcmd(strcat("glsl_vely ",ftos(camera.velocity_y),"\n"));
    }


    render.c
    Code: Select all
    //GLSL Showreel - created by Antonio "toneddu2000" Latronico and released under CC0 Public Domain license https://creativecommons.org/publicdomain/zero/1.0/

    void Render_Cube(float side,vector org)
    {      
       local string shd = "cube";
       
       //left_ok
       R_BeginPolygon(shd);
          R_PolygonVertex([-side,side,side]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([side,side,side]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([side,side,-side]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([-side,side,-side]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
       // top_ok
          R_PolygonVertex([side,-side,side]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([side,side,side]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([-side,side,side]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,side]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
       // back_ok
          R_PolygonVertex([side,side,-side]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([side,side,side]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([side,-side,side]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([side,-side,-side]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
       //   right_ok
          R_PolygonVertex([side,-side,side]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,side]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,-side]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([side,-side,-side]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
       // bottom_ok
          R_PolygonVertex([side,side,-side]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([side,-side,-side]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,-side]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([-side,side,-side]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
    }

    void Render_PortalFrame(float sd1,float sd2,float sd3,float size, vector org,string shd)
    {
       local float side1 = sd1 * size;
       local float side2 = sd2 * size;
       local float side3 = sd3 * size;
       
       R_BeginPolygon(shd);
          R_PolygonVertex([-side1, side2, -side3]+org,[-1, 0, 0],[1,1,1],1);
          R_PolygonVertex([-side1, -side2, -side3]+org,[-1, 0, 0],[1,1,1],1);
          R_PolygonVertex([-side1, -side2, side3]+org,[-1, 0, 0],[1,1,1],1);
       R_EndPolygon();
       
          R_PolygonVertex([-side1, -side2, side3]+org,[-1, 0, 0],[1,1,1],1);
          R_PolygonVertex([-side1, side2, side3]+org,[-1, 0, 0],[1,1,1],1);
          R_PolygonVertex([-side1, side2, -side3]+org,[-1, 0, 0],[1,1,1],1);
       R_EndPolygon();
       
          R_PolygonVertex([-side1, side2, side3]+org,[0, 1, 0],[1,1,1],1);
          R_PolygonVertex([side1, side2, side3]+org,[0, 1, 0],[1,1,1],1);
          R_PolygonVertex([side1, side2, -side3]+org,[0, 1, 0],[1,1,1],1);
       R_EndPolygon();
       
          R_PolygonVertex([side1, side2, -side3]+org,[0, 1, 0],[1,1,1],1);
          R_PolygonVertex([-side1, side2, -side3]+org,[0, 1, 0],[1,1,1],1);
          R_PolygonVertex([-side1, side2, side3]+org,[0, 1, 0],[1,1,1],1);
       R_EndPolygon();
       
          R_PolygonVertex([side1, side2, side3]+org,[1, 0, 0],[1,1,1],1);
          R_PolygonVertex([side1, -side2, side3]+org,[1, 0, 0],[1,1,1],1);
          R_PolygonVertex([side1, -side2, -side3]+org,[1, 0, 0],[1,1,1],1);
       R_EndPolygon();
       
          R_PolygonVertex([side1, -side2, -side3]+org,[1, 0, 0],[1,1,1],1);
          R_PolygonVertex([side1, side2, -side3]+org,[1, 0, 0],[1,1,1],1);
          R_PolygonVertex([side1, side2, side3]+org,[1, 0, 0],[1,1,1],1);
       R_EndPolygon();
       
          R_PolygonVertex([-side1, -side2, -side3]+org,[0, -1, 0],[1,1,1],1);
          R_PolygonVertex([side1, -side2, -side3]+org,[0, -1, 0],[1,1,1],1);
          R_PolygonVertex([side1, -side2, side3]+org,[0, -1, 0],[1,1,1],1);
       R_EndPolygon();
       
          R_PolygonVertex([side1, -side2, side3]+org,[0, -1, 0],[1,1,1],1);
          R_PolygonVertex([-side1, -side2, side3]+org,[0, -1, 0],[1,1,1],1);
          R_PolygonVertex([-side1, -side2, -side3]+org,[0, -1, 0],[1,1,1],1);
       R_EndPolygon();
       
          R_PolygonVertex([-side1, -side2, -side3]+org,[0, 0, -1],[1,1,1],1);
          R_PolygonVertex([-side1, side2, -side3]+org,[0, 0, -1],[1,1,1],1);
          R_PolygonVertex([side1, side2, -side3]+org,[0, 0, -1],[1,1,1],1);
       R_EndPolygon();
       
          R_PolygonVertex([side1, side2, -side3]+org,[0, 0, -1],[1,1,1],1);
          R_PolygonVertex([side1, -side2, -side3]+org,[0, 0, -1],[1,1,1],1);
          R_PolygonVertex([-side1, -side2, -side3]+org,[0, 0, -1],[1,1,1],1);
       R_EndPolygon();
       
          R_PolygonVertex([side1, -side2, side3]+org,[0, 0, 1],[1,1,1],1);
          R_PolygonVertex([side1, side2, side3]+org,[0, 0, 1],[1,1,1],1);
          R_PolygonVertex([-side1, side2, side3]+org,[0, 0, 1],[1,1,1],1);
       R_EndPolygon();
       
          R_PolygonVertex([-side1, side2, side3]+org,[0, 0, 1],[1,1,1],1);
          R_PolygonVertex([-side1, -side2, side3]+org,[0, 0, 1],[1,1,1],1);
          R_PolygonVertex([side1, -side2, side3]+org,[0, 0, 1],[1,1,1],1);
       R_EndPolygon();
    }

    void Render_Portal(float side, vector org,string shd)
    {      
       local float z = 1.47;
       R_BeginPolygon(shd);
       // left(is front)
          R_PolygonVertex([-side,-side,side*z]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([-side,side,side*z]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([-side,side,-side*z]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,-side*z]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
    }

    void Render_Sky()
    {      
       local string shd = "sky";
       local float side = 1048576*10;
       local float z = 10000;
       R_BeginPolygon(shd);
          R_PolygonVertex([side,-side,z],[0,1,0],[1,1,1],1);
          R_PolygonVertex([side,side,z],[1,1,0],[1,1,1],1);
          R_PolygonVertex([-side,side,z],[1,0,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,z],[0,0,0],[1,1,1],1);
       R_EndPolygon();
    }

    void Render_Horizon()
    {      
       local string shd = "horizon";
       local float side = 1048576*10;
       local float z = 10000;
       local vector org;
       makevectors(input_angles);
       org = camera.origin +(v_forward * 10000);
       // front
       R_BeginPolygon(shd);
          R_PolygonVertex([-side,side,side]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([side,side,side]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([side,side,-side]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([-side,side,-side]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
       // top

          R_PolygonVertex([side,-side,side]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([side,side,side]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([-side,side,side]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,side]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
       // right

          R_PolygonVertex([side,side,-side]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([side,side,side]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([side,-side,side]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([side,-side,-side]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
       // left

          R_PolygonVertex([-side,-side,side]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([-side,side,side]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([-side,side,-side]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,-side]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
       // bottom

          R_PolygonVertex([side,-side,side]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,side]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,-side]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([side,-side,-side]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
       // back

          R_PolygonVertex([side,side,-side]+org,[0,1,0],[1,1,1],1);
          R_PolygonVertex([side,-side,-side]+org,[1,1,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,-side]+org,[1,0,0],[1,1,1],1);
          R_PolygonVertex([-side,side,-side]+org,[0,0,0],[1,1,1],1);
       R_EndPolygon();
    }

    void Render_Sea()
    {      
       local string shd = "sea";
       local float side = 1048576;
       local float z = 15;
       // front
       R_BeginPolygon(shd);
          R_PolygonVertex([side,-side,z],[0,1,0],[1,1,1],1);
          R_PolygonVertex([side,side,z],[1,1,0],[1,1,1],1);
          R_PolygonVertex([-side,side,z],[1,0,0],[1,1,1],1);
          R_PolygonVertex([-side,-side,z],[0,0,0],[1,1,1],1);
       R_EndPolygon();
    }
  10. now create in data folder a default.cfg file and edit like this:
    Code: Select all
    //make sure csqc runs without a server
    set pr_csqc_formenus 1
    //resolution
    vid_fullscreen_standalone   1
    vid_width               1920
    vid_height               1080
    //input
    bind   a            +moveleft
    bind   d            +moveright
    bind   w            +forward
    bind   s            +back
    //graphics
    vid_multisample 4
    r_fxaa 8
    fov 120
  11. Ok it's time to compile. SOUNDS WARNING: if you want lame sounds enabled, just go to defscustom.c and uncomment #define USESOUNDS, remember to download my sounds file

    Open fteqw executable, open console and type
    Code: Select all
    compile

    If you copy everything correctly (and I didn't miss anything :confused: ), engine should print somthing like
    Code: Select all
    Compile finished. It took blablabla seconds.
    0 Warnings. Done.

    Now close fteqw and reopen it. It *should* be exactly like the one in the video! :biggrin:
Last edited by toneddu2000 on Sun Apr 02, 2017 10:13 am, edited 2 times in total.
toneddu2000
 
Posts: 1318
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: [FTEQW][REL]GLSL showreel - also mini tutorial

Postby toneddu2000 » Fri Mar 31, 2017 11:09 am

GLSL Mini tutorial
How GLSL files work:
For those who never heard of, GLSL stands for OpenGL shading Language and it's a C-syntax-like shader file that permits "to draw something on screen": that could be an entire 3d scene (take a look at some beautiful works at shadertoy), a 2d scene, a post-processing 2d effect or even a "living texture" put on top of a 3d mesh.
GLSL file is divided in two parts, vertex shader and fragment shader. Vertex shader manages vertex positions in space and time, fragment position is about pixels colors, alpha in space and time. In fragment you can also retrieve textures and edit them

There are many file types in GLSL: vec2,vec3,vec4,int,float, and other I didn't even tried (like matricies) but for now let's concentrate on these types.
A vec2 is like an array of 2 elements and it's declared like this vec2 foo = vec2(15.0,12.1); and its values can be retrieved singularly like this foo.x = 15.0 foo.y = 12.1 vec2 is usually used for 2d coords (that's why I used .x and .y but I could use .r and .g or .s and .t without any problem)
a vec3 is like vec2 but with 3 elements, it's often used for rgb colors. vec3 foo = vec3(1.0,0.1,0.1); -> foo.r = 1.0,and so on
a vec4 is like vec3 plus a 4th element that's usually used for opacity, so vec4 foo = vec4(1,0,0.0,0.0,0.5) it's an half transparent red

Variables qualifiers are explained a lot well here, so why bother re-explaining them again? In FTE, qualifiers are used like this:
  1. uniform is used by some actor that needs to talk to GLSL. An example: using cvars to control GLSL in CSQC. Using uniform it's the only way (at least that I know) to export from FTE csqc a var and import it in GSLS shader. A typical example is time. You set a cvar, apply time value to that cvar through localcmd, declare it in GLSL header and then use it (it will be explained in detail later)
  2. varying is used to share a var between vertex and fragment parts. An example is v_edge var (I used always this var name as Spike did in his GLSL files), which stores uv coordinates in vertex shader as long as it can be used in fragment shader (imagine to make a texture scroll in fragment shader: v_edge.x * time, for example)
  3. regular var types without qualifiers can be used as global scope (for global scope I mean through all the entire vertex shader and through all the entire fragment shader) and local scope

Main function (for both vertex and fragment shaders) is void main(void){} and their are COMPLETELY separated from each other. If you want that a var is shared by two blocks, you have to declare it in both vertex and fragment block. Textures example below will show you how
Inside vertex main block I usually just write
Inside fragment main block you have to write at least a GL_FragColor() func to draw anything. For example: GL_FragColor(1.0,0.0,0.0,1.0); it will draw a red solid color

To pass a CSQC var to GLSL file (game time for example), do like this.
  1. create a cvar (for example name it glsl_time)in your CSQC_Init via registercvar or put it in your default.cfg file (both methods are OK).
  2. declare it on top of GLSL file, just after version number (REMEMBER: version number MUST be first line in GLSL file or it will throw an error!)
    Code: Select all
    !!cvarf glsl_time
  3. Create an uniform float in fragment block that comprehends cvar name + "cvar_" prefix
    Code: Select all
    uniform float cvar_glsl_time;
  4. use it in your fragment block
    Code: Select all
    void main(void)
    {
       float time = cvar_glsl_time;
       v_edge.x = time * 0.1;//scroll texture horizontally
    }

In FTEQW textures are used by GLSL in this way
  1. In vertex block add a vec2 v_edge that stores UV texture coordinates and a system attribute vec2 v_texcoord (do NOT change its name!) that reads engine 3d model uv's
    Code: Select all
    attribute vec2 v_texcoord;
    varying vec2 v_edge;

    Then in main block make sure uv tex coords are applied to the "shared" v_edge vec2. Don't ask me about gl_Position, because I don't know how engine handles it. Ask Spike instead
    Code: Select all
    void main(void)
    {
       gl_Position = ftetransform();
       v_edge = v_texcoord.xy;
    }
  2. In GLSL fragment block define a sampler2D (which is a bidimensional texture in GLSL) and, of course another "copy" of v_edge as vertex copy of uv's
    Code: Select all
    varying vec2 v_edge;
    uniform sampler2D s_t0;

    In fragment main block
    Code: Select all
    void main(void)
    {
       vec4 img = texture2D( s_t0, v_edge);
       GL_FragColor = img;
    }
  3. In shader file you have to put a texture definition that links to s_t0 glsl texture. For example:
    Code: Select all
    exampleshader
    {
       program ton_myglslfile
       {
          diffusemap   textures/example_diff.tga
       }
    }
  4. If you want more than one textures(diffuse, specular, normal, etc.) and you want to manage them in GLSL, you have to make sure that order of textures in shader file must be the order of sampler2D in glsl file. For example:

    shader file
    Code: Select all
    exampleshader
    {
       program ton_myglslfile
       {
          diffusemap   textures/example_diff.tga
          specularmap   textures/example_spec.tga
          normalmap   textures/example_normal.tga
       }
    }


    glsl file - fragment block
    Code: Select all
    varying vec2 v_edge;
    uniform sampler2D s_t0;//diffuse
    uniform sampler2D s_t1;//specular
    uniform sampler2D s_t2;//normal

    Then, in fragment main block
    Code: Select all
    void main(void)
    {
       vec4 dif = texture2D( s_t0, v_edge);
       vec4 spec = texture2D( s_t1, v_edge);
       vec4 nor = texture2D( s_t2, v_edge);
       //now let's do all the complex code to manage them..
    }
toneddu2000
 
Posts: 1318
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: [FTEQW][REL]GLSL showreel - also mini tutorial

Postby Nahuel » Fri Mar 31, 2017 11:50 pm

thats GREAT documentation about GLSL and FTE :surprised:

Did you try something like sung light beams!! ??


Fte is so powerful, this helps a lot to all who want to get into this engine (I include myself)

I think I'm going to add some shader of these and test them with FREE-CS !!

I would really like to see some of those powerful shaders acting on counter strike 1.5 !!

I wonder what limitations there are in FTE for glsl !!! And if there is a distant possibility of doing something similar in DP (you know, csqc interacting with shaders) I still hope :razz:

Incredible, thank you very much.
hi, I am nahuel, I love quake and qc.
User avatar
Nahuel
 
Posts: 485
Joined: Wed Jan 12, 2011 8:42 pm
Location: mar del plata

Re: [FTEQW][REL]GLSL showreel - also mini tutorial

Postby toneddu2000 » Sat Apr 01, 2017 9:40 am

Glad you found it interesting, Nahuel! There are plenty of things to say about GLSL. I'll try to add more stuff

Nahuel wrote:Did you try something like sung light beams!! ??
Like god rays? No, I didn't try and, honestly, I dunno know where to start. The problem is that you should be able to create some sort of bloom only when glsl intercepts a "sun entity"(bloom effect in glsl showreel could do the job), but I don't know how to isolate only a specific region of pixels (maybe by color?) and then apply the effect

Nahuel wrote:Fte is so powerful, this helps a lot to all who want to get into this engine (I include myself)
Yeah, fte is awesome, it has an endless list of builtin functions to make practically every kind of game (well, car physics game excluded, maybe)

Nahuel wrote:I think I'm going to add some shader of these and test them with FREE-CS !!
Cool! Post your works on insideqc so we'll see them

Nahuel wrote:I wonder what limitations there are in FTE for glsl !!! And if there is a distant possibility of doing something similar in DP (you know, csqc interacting with shaders) I still hope :razz:
Regarding dp no idea, but about limitations, don't know if there are any, only thing I know is that creating post-processing effect that envolve depth buffer use (ambient occlusion, depth of field, etc.) are extremely difficult to achieve. Just to make an example: in GLSL Showreel if you press right mouse click you see depth buffer, but, as many techniques I tried, I NEVER accomplished to store it to re-use in the shader.
toneddu2000
 
Posts: 1318
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: [FTEQW][REL]GLSL showreel - also mini tutorial

Postby Julius » Sat Apr 01, 2017 3:57 pm

Really helpfull, thanks!

Maybe we should start a wiki on github or so where we can put all the nice documentation in one place? I wish Spike would finally use it or gitlab for the code and bugtracker as well... the current svn sourceforge repository is atrocious (not even talking about the outdated website ;) ).

By the way, do GLSL shaders work seamlessly with the Vulkan renderer as well?
Julius
 
Posts: 92
Joined: Sun Aug 29, 2010 4:32 pm

Re: [FTEQW][REL]GLSL showreel - also mini tutorial

Postby toneddu2000 » Sat Apr 01, 2017 9:21 pm

Julius wrote:Maybe we should start a wiki on github or so where we can put all the nice documentation in one place? I wish Spike would finally use it or gitlab for the code and bugtracker as well... the current svn sourceforge repository is atrocious (not even talking about the outdated website ;) ).
Probably a wiki would be great, but don't count on Spike: he HATES writing documentation, he prefers help devs on this forum so it's up to us to collect his answers and assemble them in a formal document. That's also why I created GLSL showreel. My intent is, everytime I learn something about the use of GLSL (in general and/or related to FTE), to update this topic as it can be shared with other users.

Julius wrote:By the way, do GLSL shaders work seamlessly with the Vulkan renderer as well?

As far as I understood (but not count on my words as I'm not an expert) you'll need a GLSL to SPIR-V compiler which compiles GLSL files in SPIR-V shaders, which are way more low-level than GLSL shaders, making things easier for driver manufacturers
toneddu2000
 
Posts: 1318
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: [FTEQW][REL]GLSL showreel - also mini tutorial

Postby Spike » Sat Apr 01, 2017 11:12 pm

depth: be aware that depth buffers are non-linear. the lpp_light.glsl fragment shader has some function to convert a depth value and texture coord back into a 3d worldspace coord. if you just try drawing the depth buffer as-is then yeah, you'll probably just get something really close to black.

regarding vulkan, the renderer I wrote does not contain its own glsl compiler thus it currently requires precompiled glsl, which means that all the ifdef stuff cannot work the same as with the gl renderer. instead it depends upon vulkan's specialisation constants for permutations and parms.
this sucks, of course so I really ougt to try and figure out some better solution some time.
nvidia drivers embed a glsl compiler but have no reflection stuff, iirc my implementation of it is also limited and can't handle permutations, and of course vendor specific so whatever.
but yeah, (optimised) spirv not having any reflection info means that fte depends upon metadata which requires specialised tools... specifically the 'makevulkanblob.c' program on fte's svn. it depends upon glslang's spirv compiler (which has various bugs with specialisation constants so I had to keep it using some old version of the vulkan sdk to avoid the worst of it). really the whole thing sucks.
so yeah, I don't really expect anyone to try writing any glsl/spir-v for fte's vulkan renderer.

toneddu2000, you might want to use s_diffuse/s_specular etc in your glsl instead of assuming that s_t0, s_t1 etc match them. doing so means that you can skip the extra {map foo} blocks in your .shader (although annoyingly you normally still need one, in order to specify the blend mode properly).


god rays: http://triptohell.info/moodles/junk/fte00016.jpg - just set r_sun_colour (and don't use a skybox)
Spike
 
Posts: 2883
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: [FTEQW][REL]GLSL showreel - also mini tutorial

Postby toneddu2000 » Sun Apr 02, 2017 10:06 am

Spike wrote:depth: be aware that depth buffers are non-linear. the lpp_light.glsl fragment shader has some function to convert a depth value and texture coord back into a 3d worldspace coord. if you just try drawing the depth buffer as-is then yeah, you'll probably just get something really close to black.
Wow,didn't know that. Is this the function?
Code: Select all
vec3 calcLightWorldPos(vec2 screenPos, float depth)
{
vec4 pos = m_invviewprojection * vec4(screenPos.xy, (depth*2.0)-1.0, 1.0);
return pos.xyz / pos.w;
}

Regarding depth..if you compile GLSL showreel and toggle depth on/off with right mouse click, you'll notice that depth image coords is not "aligned". For example, if you stare at the portal box, and switch depth on, you'll see that box is stretched and stands more on the right respect color pass, like if the image was zoomed...Do I miss something?
This is the depth GLSL file. Very very basic
Code: Select all
!!ver 330
//   author: Antonio "toneddu2000" Latronico
//   placed under cc0 public domain license
#ifdef VERTEX_SHADER
attribute vec2 v_texcoord;
varying vec2 v_edge;
void main(void)
{
   gl_Position = ftetransform();
   v_edge = v_texcoord.xy;
}
#endif
#ifdef FRAGMENT_SHADER
varying vec2 v_edge;
uniform sampler2D s_t0;
void main(void)
{
   vec3 img;
   img = vec3(texture2D(s_t0,v_edge.xy));
   gl_FragColor = vec4(img,1);
}
#endif


Could you consider creating a ssao GLSL post-processing file? That would help a lot final rendered image!

Spike wrote:toneddu2000, you might want to use s_diffuse/s_specular etc in your glsl instead of assuming that s_t0, s_t1 etc match them. doing so means that you can skip the extra {map foo} blocks in your .shader (although annoyingly you normally still need one, in order to specify the blend mode properly).

That's..awesome! Thanks a lot Spike! That helps a lot!
toneddu2000
 
Posts: 1318
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: [FTEQW][REL]GLSL showreel - also mini tutorial

Postby toneddu2000 » Sun Apr 02, 2017 4:01 pm

Another thing that probably I already asked you and it's a bit off-topic (but not too much) regarding GLSL: at what entity should I apply GLSL lpp_light?
This is what you told me about light prepass in fte
  1. add to wall this shader
    Code: Select all
    somewallshader
    {
       fte_program lpp_wall
       {
          map $sourcecolour
       }

       //this is drawn during the gbuffer pass to prepare it
       fte_bemode gbuffer
       {
          fte_program lpp_depthnorm
          {
             map $normalmap
          }
       }
    }
  2. particle script with embedded GLSL
    Code: Select all
    r_lightprepass 2

    r_part tr_rocket
    {
       shader "particles/myprelight"
       {
          glslprogram
          {
    varying vec4 tf;
    varying vec3 lpos;
    varying vec4 lightColour;
    #define lightradius (300.0)// * 0.25)
    #ifdef VERTEX_SHADER
    attribute vec2 v_texcoord;
    attribute vec4 v_colour;
    uniform mat4 m_view;
    void main(void)
    {
       vec3 fwd, right, up;
       right.x = m_view[0].x;
       right.y = m_view[1].x;
       right.z = m_view[2].x;
       up.x = m_view[0].y;
       up.y = m_view[1].y;
       up.z = m_view[2].y;
       fwd.x = m_view[0].z;
       fwd.y = m_view[1].z;
       fwd.z = m_view[2].z;
       lpos = v_position;
       lpos += 1.5*(v_texcoord.x-0.5) * right * lightradius;
       lpos += 1.5*(v_texcoord.y-0.5) * up * lightradius;
       lpos.z += 2.0;
       lightColour = v_colour;
       gl_Position = tf = m_modelviewprojection * vec4(v_position.xyz, 1.0);
    }
    #endif
    #ifdef FRAGMENT_SHADER
    uniform sampler2D s_t0;
    uniform mat4 m_invviewprojection;
    vec3 calcLightWorldPos(vec2 screenPos, float depth)
    {
       vec4 pos = m_invviewprojection * vec4(screenPos.xy, (depth*2.0)-1.0, 1.0);
       return pos.xyz / pos.w;
    }
    void main (void)
    {
       float lightAttenuation   = lightradius*0.5;
       float radiusFar         = lightradius*0.5;
       float radiusNear      = lightradius*0.25;
       vec2 fc;
       fc = tf.xy / tf.w;
       vec4 data = texture2D(s_t0, (1.0 + fc) / 2.0);
       float depth = data.a;
       vec3 norm = data.xyz;
       vec3 worldPos   = calcLightWorldPos(fc, depth);
       vec3 lightDir = lpos - worldPos;
       float zdiff = 1.0 - clamp(length(lightDir) / lightAttenuation, 0.0, 1.0);
       float atten = (radiusFar * zdiff) / (radiusFar - radiusNear);
       atten = pow(atten, 2.0);
       lightDir = normalize(lightDir);
       float nDotL = dot(norm, lightDir) * atten;
       float lightDiffuse = max(0.0, nDotL);
       gl_FragColor = vec4(lightDiffuse * (lightColour.rgb), lightColour.a);
       //gl_FragColor = vec4(lightColour);
       //gl_FragColor = vec4(lightDir, 1.0);
    }
    #endif
          }
          {
             map $sourcecolour
             blend gl_src_alpha gl_one
             nodepthtest
          }
          surfaceparm nodlight
          lpp_light
       }

       step 8
       scale 300
       alpha 10
       die 5
       rgbrand 255 255 255
       scalefactor 1
       gravity 200
       spawnmode box 500 100
       spawnvel 200
       friction 2
    //   clipbounce 0
    //   cliptype tr_rocket
       rotationstart 225
    }

    r_part +tr_rocket
    {
       texture "ball"
       step 8
       scale 4
       alpha 10
       die 5
       rgbrand 255 255 255
       scalefactor 1
       gravity 200
       spawnmode box 500 100
       spawnvel 200
       friction 2
       rotationstart 225
    }

    r_part te_explosion
    {
       shader "particles/myprelight"
       scale 300
       die 4
       rgb 128 255 128
       scalefactor 1
       rotationstart 225
       spawnvel 64
       gravity 200
       count 40[*][*]
    }
    r_part +te_explosion
    {
       texture "ball"
       scale 4
       die 4
       rgb 255 128 255
       scalefactor 1
       rotationstart 225
       spawnvel 64
       gravity 200
       count 40
    }
  3. Code: Select all
    r_lightprepass 1

    and then
    Code: Select all
    vid_reload

But, in case I don't want lpp_* particle but a lpp_ light. At what entity I apply lpp_light shader? I cannot apply a shader to a light entity: there's no light entity in csqc as far as I know: I use dynamiclight_add() to draw dynamic lights in CSQC, I never created a light entity that has its own properties. Or should I use .rtlights file to create lights? But, even if I create lights in this way, how can I apply GLSL files to them?

Adding ssao + deferred light would boost fte's renderer quality at its best! :biggrin:
toneddu2000
 
Posts: 1318
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: [FTEQW][REL]GLSL showreel - also mini tutorial

Postby Spike » Sun Apr 02, 2017 5:16 pm

regarding depth, remember to divide any projected texture coords by w before passing them to that function. read up on homogeneous coords some time for why this is needed.

deferred lights are basically just a sprite that covers the parts of the screen that the light should affect. These 'sprites' can either be provided via the engine from the .rtlights file/adddynamiclight builtin, or you can provide them as actual sprites yourself.
If your shader has the lpp_light directive inside it, then it will be 'drawn' after the regular gbuffer pass and before the lpp_wall stuff. its input texture will be the normalmap and depth values from the lpp_depthnorm shaders over the underlaying geometry, and its output is the raw lighting values. the lpp_wall shader is then given the output of those lighting 'sprites', and combines the lighting values with the diffuse textures.
its all single outputs right now, which means specular with deferred shading cannot really work right now. I'd like to come up with some nice configurable way to make the gbuffers extensible to allow for other effects, but I've not really gotten around to finalising anything in that regard (especially as I'd want it to apply to the vk+d3d11 renderers eventually too).
Spike
 
Posts: 2883
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: [FTEQW][REL]GLSL showreel - also mini tutorial

Postby toneddu2000 » Sun Apr 02, 2017 8:53 pm

Spike wrote:regarding depth, remember to divide any projected texture coords by w before passing them to that function. read up on homogeneous coords some time for why this is needed.

This is what I did, I premise that in Glsl Showreel I'm using
Code: Select all
setviewprop(VF_DRAWWORLD,FALSE);
,
so probably it's not the best scenario to test depth

in csqc, in CSQC_UpdateView() I call
Code: Select all
if(fxPostprocessDepth == TRUE){
      setproperty(VF_RT_DEPTH, "ppdepth", 4,r);
      setviewprop(VF_SIZE, r);
   }
   if(fxPostprocessColor == TRUE){
      setproperty(VF_RT_DESTCOLOUR, fxName, 1, r);
      setviewprop(VF_SIZE, r);
   }

then I switch on/off postprocess depth with right mouse click and on/off postprocess color with left mouse click, so I can see in realtime where I fail

This is what I tried for depth glsl file
Code: Select all
!!ver 130
!!cvarf glsl_depth
varying vec4 tf;
varying vec2 uvcoords;
#ifdef VERTEX_SHADER
attribute vec2 v_texcoord;
void main ()
{
   tf = ftetransform();
   gl_Position = tf;
   uvcoords = v_texcoord.xy;
}
#endif
#ifdef FRAGMENT_SHADER
uniform sampler2D s_t0;
uniform mat4 m_invviewprojection;
uniform float cvar_glsl_depth;

vec3 calcLightWorldPos(vec2 screenPos, float depth)
{
   vec4 pos = m_invviewprojection * vec4(screenPos.xy, (depth*2.0)-1.0, 1.0);
   return pos.xyz / pos.w;
}

void main ()
{
   vec2 fc;
   fc = tf.xy / tf.w;
   //invert y axis otherwise img will be upside-down
   fc.y = -fc.y;
   vec4 data = texture2D(s_t0, (1.0 + fc) / 2.0);
   float depth = data.a;
   vec3 norm = data.xyz;
   vec3 worldPos = calcLightWorldPos((1.0 + fc) / 2.0, depth);
   //normal img
   vec4 img = texture2D(s_t0,uvcoords);
   //test depth
   if(cvar_glsl_depth == 1){
      gl_FragColor = data;
   }
   else if(cvar_glsl_depth == 2){
      gl_FragColor = vec4(worldPos,depth);
   }
   else{
      gl_FragColor = img*depth;
   }
}
#endif

If I switch to depth mode and change cvar glsl_depth to 0(which was old technique) or 1, no changes at all
If I switch to 2, screen becomes yellow (obviously) and a red and blue line appear above and left. I guess calcLightWorldPos() returns some sort of coordinates (so, of course, it's not usable with gl_FragColor directly) but I guess it won't help me for test I'm trying to accomplish, also because I think it's related somehow to light position and, in my scene, there are no lights.

I'd just like to understand if depth var is storing some information. So I tried to combine with .rgb in gl_FragColor but is always white, even when I go close to objects, but depth post process shows different shades of gray when I'm standing near to portals, so, obviously, it's doing stuff..

Tried same code even in post-process color and no changes at all. So, my question is: is depth buffer visible (retrievable, computable, choose the term you prefer) in depth post processing pass, color post-processing pass or both? Because, right now depth post processing pass it's useful to me just to say that I implemented it, but, apart from that, I cannot understand how to use it.

Another thing I fixed. Myself said today:
toneddu2000 wrote:Regarding depth..if you compile GLSL showreel and toggle depth on/off with right mouse click, you'll notice that depth image coords is not "aligned". For example, if you stare at the portal box, and switch depth on, you'll see that box is stretched and stands more on the right respect color pass, like if the image was zoomed...Do I miss something?
Well, I was making a mistake. Toggling on post-process color makes the post-process depth pass (when enabled) to be aligned with color pass. Probably non-post-processed pass and post-processed pass use different system of coordinates or.. i dunno

Spike wrote:deferred lights are basically just a sprite that covers the parts of the screen that the light should affect. These 'sprites' can either be provided via the engine from the .rtlights file/adddynamiclight builtin, or you can provide them as actual sprites yourself.
If your shader has the lpp_light directive inside it, then it will be 'drawn' after the regular gbuffer pass and before the lpp_wall stuff. its input texture will be the normalmap and depth values from the lpp_depthnorm shaders over the underlaying geometry, and its output is the raw lighting values. the lpp_wall shader is then given the output of those lighting 'sprites', and combines the lighting values with the diffuse textures.
its all single outputs right now, which means specular with deferred shading cannot really work right now. I'd like to come up with some nice configurable way to make the gbuffers extensible to allow for other effects, but I've not really gotten around to finalising anything in that regard (especially as I'd want it to apply to the vk+d3d11 renderers eventually too).
Wow...it will take a week to make a test like this and be sure to try all the possibilities. Thanks Spike, I'll post all the tests here
toneddu2000
 
Posts: 1318
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy


Return to Project Showcase

Who is online

Users browsing this forum: No registered users and 2 guests