• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

GLSL minifier

Status
Not open for further replies.
Level 29
Joined
Jul 29, 2007
Messages
5,174
Not that anyone will care or use this, but I am presenting my home brewed GLSL code minifier.

I've used it on the shaders used by the 3D viewer and got 71% reduction.

Here's how the main M3 shader looks before, and after minification:
C:
uniform vec3 u_teamColor;

varying vec3 v_normal;
varying vec2 v_uv[4];
varying vec3 v_lightDir;
varying vec3 v_eyeVec;
varying vec3 v_halfVec;

struct LayerSettings {
  bool enabled;
  float op;
  float channels;
  float teamColorMode;
  vec3 multAddAlpha;
  bool useAlphaFactor;
  bool invert;
  bool multColor;
  bool addColor;
  bool clampResult;
  bool useConstantColor;
  vec4 constantColor;
  float uvSource;
  float uvCoordinate;
  float fresnelMode;
  float fresnelTransformMode;
  mat4 fresnelTransform;
  bool fresnelClamp;
  vec3 fresnelExponentBiasScale;
};

#define SPECULAR_RGB 0.0
#define SPECULAR_A_ONLY 1.0

#define FRESNELMODE_NONE 0.0
#define FRESNELMODE_STANDARD 1.0
#define FRESNELMODE_INVERTED 2.0

#define FRESNELTRANSFORM_NONE 0.0
#define FRESNELTRANSFORM_SIMPLE 1.0
#define FRESNELTRANSFORM_NORMALIZED 2.0

#define UVMAP_EXPLICITUV0 0.0
#define UVMAP_EXPLICITUV1 1.0
#define UVMAP_REFLECT_CUBICENVIO 2.0
#define UVMAP_REFLECT_SPHERICALENVIO 3.0
#define UVMAP_PLANARLOCALZ 4.0
#define UVMAP_PLANARWORLDZ 5.0
#define UVMAP_PARTICLE_FLIPBOOK 6.0
#define UVMAP_CUBICENVIO 7.0
#define UVMAP_SPHERICALENVIO 8.0
#define UVMAP_EXPLICITUV2 9.0
#define UVMAP_EXPLICITUV3 10.0
#define UVMAP_PLANARLOCALX 11.0
#define UVMAP_PLANARLOCALY 12.0
#define UVMAP_PLANARWORLDX 13.0
#define UVMAP_PLANARWORLDY 14.0
#define UVMAP_SCREENSPACE 15.0
#define UVMAP_TRIPLANAR_LOCAL 16.0
#define UVMAP_TRIPLANAR_WORLD 17.0
#define UVMAP_TRIPLANAR_WORLD_LOCAL_Z 18.0

#define CHANNELSELECT_RGB 0.0
#define CHANNELSELECT_RGBA 1.0
#define CHANNELSELECT_A 2.0
#define CHANNELSELECT_R 3.0
#define CHANNELSELECT_G 4.0
#define CHANNELSELECT_B 5.0

#define TEAMCOLOR_NONE 0.0
#define TEAMCOLOR_DIFFUSE 1.0
#define TEAMCOLOR_EMISSIVE 2.0

#define LAYEROP_MOD 0.0
#define LAYEROP_MOD2X 1.0
#define LAYEROP_ADD 2.0
#define LAYEROP_LERP 3.0
#define LAYEROP_TEAMCOLOR_EMISSIVE_ADD 4.0
#define LAYEROP_TEAMCOLOR_DIFFUSE_ADD 5.0
#define LAYEROP_ADD_NO_ALPHA 6.0
/*
float calculateFresnelTerm(vec3 normal, vec3 eyeToVertex, float exponent, mat4 fresnelTransform, float fresnelTransformMode, bool fresnelClamp) {
  vec3 fresnelDir = eyeToVertex;
  float result;
  
  if (fresnelTransformMode != FRESNELTRANSFORM_NONE) {
    fresnelDir = (fresnelTransform * vec4(fresnelDir, 1.0)).xyz;
    
    if (fresnelTransformMode == FRESNELTRANSFORM_NORMALIZED) {
      fresnelDir = normalize(fresnelDir);
    }
  }
  
  if (fresnelClamp) {
    result = 1.0 - clamp(-dot(normal, fresnelDir), 0.0, 1.0);
  } else {
    result = 1.0 - abs(dot(normal, fresnelDir));
  }
  
  result = max(result, 0.0000001);
  
  return pow(result, exponent);
}
*/
vec3 combineLayerColor(vec4 color, vec3 result, LayerSettings layerSettings) {
  if (layerSettings.op == LAYEROP_MOD) {
    result *= color.rgb;
  } else if (layerSettings.op == LAYEROP_MOD2X) {
    result *= color.rgb * 2.0;
  } else if (layerSettings.op == LAYEROP_ADD) {
    result += color.rgb * color.a;
  } else if (layerSettings.op == LAYEROP_ADD_NO_ALPHA) {
    result += color.rgb;
  } else if (layerSettings.op == LAYEROP_LERP) {
    result = mix(result, color.rgb, color.a);
  } else if (layerSettings.op == LAYEROP_TEAMCOLOR_EMISSIVE_ADD) {
    result += color.a * u_teamColor;
  } else if (layerSettings.op == LAYEROP_TEAMCOLOR_DIFFUSE_ADD) {
    result += color.a * u_teamColor;
  }
  
  return result;
}

vec4 chooseChannel(float channel, vec4 texel) {
  if (channel == CHANNELSELECT_R) {
    texel = texel.rrrr;
  } else if (channel == CHANNELSELECT_G) {
    texel = texel.gggg;
  } else if (channel == CHANNELSELECT_B) {
    texel = texel.bbbb;
  } else if (channel == CHANNELSELECT_A) {
    texel = texel.aaaa;
  } else if (channel == CHANNELSELECT_RGB) {
    texel.a = 1.0;
  }
  
  return texel;
}

vec2 getUV(LayerSettings layerSettings) {
  if (layerSettings.uvCoordinate == 1.0) {
    return v_uv[1];
  } else if (layerSettings.uvCoordinate == 2.0) {
    return v_uv[2];
  } else if (layerSettings.uvCoordinate == 3.0) {
    return v_uv[3];
  }
  
  return v_uv[0];
}

vec4 sampleLayer(sampler2D layer, LayerSettings layerSettings) {
  /*
  if (layerSettings.useConstantColor && false) {
    return layerSettings.constantColor;
  }
  */
  return texture2D(layer, getUV(layerSettings));
}

vec4 computeLayerColor(sampler2D layer, LayerSettings layerSettings) {
  vec4 texel = sampleLayer(layer, layerSettings);
  vec4 result = chooseChannel(layerSettings.channels, texel);
  /*
  if (layerSettings.useAlphaFactor && false) {
    result.a *= layerSettings.multAddAlpha.z;
  }
  */
  if (layerSettings.teamColorMode == TEAMCOLOR_DIFFUSE) {
    result = vec4(mix(u_teamColor, result.rgb, texel.a), 1);
  } else if (layerSettings.teamColorMode == TEAMCOLOR_EMISSIVE) {
    result = vec4(mix(u_teamColor, result.rgb, texel.a), 1);
  }
  
  if (layerSettings.invert) {
    result = vec4(1) - result;
  }
  /*
  if (layerSettings.multColor && false) {
    result *= layerSettings.multAddAlpha.x;
  }
  
  if (layerSettings.addColor && false) {
    result += layerSettings.multAddAlpha.y;
  }
  */
  if (layerSettings.clampResult) {
    result = clamp(result, 0.0, 1.0);
  }
  /*
  if (layerSettings.fresnelMode != FRESNELMODE_NONE) {
    float fresnelTerm = calculateFresnelTerm(v_normal, v_eyeVec, layerSettings.fresnelExponentBiasScale.x, layerSettings.fresnelTransform, layerSettings.fresnelTransformMode, layerSettings.fresnelClamp);
    
    if (layerSettings.fresnelMode == FRESNELMODE_INVERTED) {
      fresnelTerm = 1.0 - fresnelTerm;
    }
    
    fresnelTerm = clamp(fresnelTerm * layerSettings.fresnelExponentBiasScale.z + layerSettings.fresnelExponentBiasScale.y, 0.0, 1.0);
    
    result *= fresnelTerm;
  }
  */
  return result;
}

vec3 decodeNormal(sampler2D map) {
  vec4 texel = texture2D(map, v_uv[0]);
  vec3 normal;
  
  normal.xy = 2.0 * texel.wy - 1.0;
  normal.z = sqrt(max(0.0, 1.0 - dot(normal.xy, normal.xy)));
  
  return normal;
}

vec4 computeSpecular(sampler2D specularMap, LayerSettings layerSettings, float specularity, float specMult, vec3 normal) {
  vec4 color;
  
  if (layerSettings.enabled) {
    color = computeLayerColor(specularMap, layerSettings);
  } else {
    color = vec4(0);
  }
  
  float factor = pow(max(-dot(v_halfVec, normal), 0.0), specularity) * specMult;
  
  return color * factor;
}

uniform float u_specularity;
uniform float u_specMult;
uniform float u_emisMult;
uniform vec4 u_lightAmbient;

uniform LayerSettings u_diffuseLayerSettings;
uniform sampler2D u_diffuseMap;
uniform LayerSettings u_decalLayerSettings;
uniform sampler2D u_decalMap;
uniform LayerSettings u_specularLayerSettings;
uniform sampler2D u_specularMap;
uniform LayerSettings u_glossLayerSettings;
uniform sampler2D u_glossMap;
uniform LayerSettings u_emissiveLayerSettings;
uniform sampler2D u_emissiveMap;
uniform LayerSettings u_emissive2LayerSettings;
uniform sampler2D u_emissive2Map;
uniform LayerSettings u_evioLayerSettings;
uniform sampler2D u_evioMap;
uniform LayerSettings u_evioMaskLayerSettings;
uniform sampler2D u_evioMaskMap;
uniform LayerSettings u_alphaLayerSettings;
uniform sampler2D u_alphaMap;
uniform LayerSettings u_alphaMaskLayerSettings;
uniform sampler2D u_alphaMaskMap;
uniform LayerSettings u_normalLayerSettings;
uniform sampler2D u_normalMap;
uniform LayerSettings u_heightLayerSettings;
uniform sampler2D u_heightMap;
uniform LayerSettings u_lightMapLayerSettings;
uniform sampler2D u_lightMapMap;
uniform LayerSettings u_aoLayerSettings;
uniform sampler2D u_aoMap;

void main() {
  vec3 color;
  vec4 final = u_lightAmbient;
  vec3 normal;
  vec3 lightMapDiffuse;
  
  if (u_normalLayerSettings.enabled) {
    normal = decodeNormal(u_normalMap);
  } else {
    normal = v_normal;
  }

  float lambertFactor = max(dot(normal, v_lightDir), 0.0);
    
  if (lambertFactor > 0.0) {
    if (u_diffuseLayerSettings.enabled) {
      vec4 diffuseColor = computeLayerColor(u_diffuseMap, u_diffuseLayerSettings);
      
      color = combineLayerColor(diffuseColor, color, u_diffuseLayerSettings);
    }
    
    if (u_decalLayerSettings.enabled) {
      vec4 decalColor = computeLayerColor(u_decalMap, u_decalLayerSettings);
      
      color = combineLayerColor(decalColor, color, u_decalLayerSettings);
    }
    
    vec4 specularColor = computeSpecular(u_specularMap, u_specularLayerSettings, u_specularity, u_specMult, normal);
    
    if (u_lightMapLayerSettings.enabled) {
      vec4 lightMapColor = computeLayerColor(u_lightMapMap, u_lightMapLayerSettings) * 2.0;
      
      lightMapDiffuse = lightMapColor.rgb;
    }
    
    /*final.rgb = color * lightMapDiffuse + specularColor.rgb;*/
    final.rgb = (color + specularColor.rgb) * lambertFactor;
    
    bool addEmissive = false;
    vec3 emissiveColor;
    vec4 tempColor;
    
    if (u_emissiveLayerSettings.enabled) {
        tempColor = computeLayerColor(u_emissiveMap, u_emissiveLayerSettings);
      
        if (u_emissiveLayerSettings.op == LAYEROP_MOD || u_emissiveLayerSettings.op == LAYEROP_MOD2X || u_emissiveLayerSettings.op == LAYEROP_LERP) {
            final.rgb = combineLayerColor(tempColor, final.rgb, u_emissiveLayerSettings);
        } else {
            emissiveColor = combineLayerColor(tempColor, emissiveColor, u_emissiveLayerSettings);
            addEmissive = true;
        }
    }
    
    if (u_emissive2LayerSettings.enabled) {
        tempColor = computeLayerColor(u_emissive2Map, u_emissive2LayerSettings);
      
        if (!addEmissive && (u_emissive2LayerSettings.op == LAYEROP_MOD || u_emissive2LayerSettings.op == LAYEROP_MOD2X || u_emissive2LayerSettings.op == LAYEROP_LERP)) {
            final.rgb = combineLayerColor(tempColor, final.rgb, u_emissive2LayerSettings);
        } else {
            emissiveColor = combineLayerColor(tempColor, emissiveColor, u_emissive2LayerSettings);
            addEmissive = true;
        }
    }
    
    if (addEmissive) {
        final.rgb += emissiveColor * u_emisMult;
    }
  }
  
  gl_FragColor = final;
}

\n#define CY else\n#define DM return\n#define EN vec4\n#define FG sampler2D\nuniform vec3 X;varying vec3 BS,BT,BU,BV;varying vec2 BQ[4];struct K{bool a,f,g,h,i,j,k,r;float b,c,d,m,n,o,p;vec3 e,s;EN l;mat4 q;};vec3 D(EN a,vec3 c,K b){if(b.b==.0){c*=a.rgb;}CY if(b.b==1.){c*=a.rgb*2.;}CY if(b.b==2.){c+=a.rgb*a.a;}CY if(b.b==6.){c+=a.rgb;}CY if(b.b==3.){c=mix(c,a.rgb,a.a);}CY if(b.b==4.){c+=a.a*X;}CY if(b.b==5.){c+=a.a*X;}DM c;}EN E(float a,EN b){if(a==3.){b=b.rrrr;}CY if(a==4.){b=b.gggg;}CY if(a==5.){b=b.bbbb;}CY if(a==2.){b=b.aaaa;}CY if(a==.0){b.a=1.;}DM b;}vec2 F(K a){if(a.n==1.){DM BQ[1];}CY if(a.n==2.){DM BQ[2];}CY if(a.n==3.){DM BQ[3];}DM BQ[0];}EN G(FG a,K b){DM texture2D(a,F(b));}EN H(FG a,K b){EN d=G(a,b);EN c=E(b.c,d);if(b.d==1.){c=EN(mix(X,c.rgb,d.a),1);}CY if(b.d==2.){c=EN(mix(X,c.rgb,d.a),1);}if(b.g){c=EN(1)-c;}if(b.j){c=clamp(c,.0,1.);}DM c;}vec3 I(FG a){EN c=texture2D(a,BQ[0]);vec3 b;b.xy=2.*c.wy-1.;b.z=sqrt(max(.0,1.-dot(b.xy,b.xy)));DM b;}EN J(FG d,K a,float e,float c,vec3 b){EN f;if(a.a){f=H(d,a);}CY{f=EN(0);}float g=pow(max(-dot(BV,b),.0),e)*c;DM f*g;}\n#define BY uniform\nBY float Y,Z,AA;BY vec4 AB;BY K AC,AE,AG,AI,AK,AM,AO,AQ,AS,AU,AW,AY,BA,BC;BY sampler2D AD,AF,AH,AJ,AL,AN,AP,AR,AT,AV,AX,AZ,BB,BD;void main(){vec3 b;vec4 f=AB;vec3 j;vec3 i;if(AW.a){j=I(AX);}else{j=BS;}float g=max(dot(j,BT),.0);if(g>.0){if(AC.a){vec4 d=H(AD,AC);b=D(d,b,AC);}if(AE.a){vec4 c=H(AF,AE);b=D(c,b,AE);}vec4 k=J(AH,AG,Y,Z,j);if(BA.a){vec4 h=H(BB,BA)*2.;i=h.rgb;}f.rgb=(b+k.rgb)*g;bool a=false;vec3 e;vec4 l;if(AK.a){l=H(AL,AK);if(AK.b==.0||AK.b==1.||AK.b==3.){f.rgb=D(l,f.rgb,AK);}else{e=D(l,e,AK);a=true;}}if(AM.a){l=H(AN,AM);if(!a&&(AM.b==.0||AM.b==1.||AM.b==3.)){f.rgb=D(l,f.rgb,AM);}else{e=D(l,e,AM);a=true;}}if(a){f.rgb+=e*AA;}}gl_FragColor=f;}
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
seems it also declares float a; float b; float c; into float a, b, c; so that is a bit of size optimization

cant spot anything more

edit: also seems that frequently used keywords(else, return, vec4) are optimized with #define-s, but the output still has some else-es in it, so the CY is not used on the whole script
also seems that the defines got inlined
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
There's a list of features on the github page.
Not all else's are inlined because what I put here is actually two different files concatenated, and the #defines are on a per-file basis.

A big part of this minifier is that it synchronizes all the changes across multiple inputs, which is the only reason I made it instead of using one of the existing ones.
For the viewer, there is a large file of shared code. Another minifier would delete all of it because it supposedly isn't used, even though other files will end up using it. So all the files are checked, and only real dead code is removed. All new names come from a global pool of names, #defines are inlined across all files, and so on.
 
Status
Not open for further replies.
Top