Quellcode durchsuchen

changing shaders preprocessing...

leonsal vor 8 Jahren
Ursprung
Commit
6d47c8aa75
37 geänderte Dateien mit 1639 neuen und 1126 gelöschten Zeilen
  1. 4 4
      gui/chart.go
  2. 1 1
      gui/panel.go
  3. 1 1
      material/basic.go
  4. 1 1
      material/phong.go
  5. 1 1
      material/standard.go
  6. 13 13
      renderer/renderer.go
  7. 0 19
      renderer/shader/chunkAttributes.go
  8. 0 50
      renderer/shader/chunkLights.go
  9. 0 36
      renderer/shader/chunkMaterial.go
  10. 0 123
      renderer/shader/chunkPhongModel.go
  11. 0 6
      renderer/shader/doc.go
  12. 0 50
      renderer/shader/shaderBasic.go
  13. 0 54
      renderer/shader/shaderLineDashed.go
  14. 0 111
      renderer/shader/shaderPhong.go
  15. 0 85
      renderer/shader/shaderPoint.go
  16. 0 74
      renderer/shader/shaderSprite.go
  17. 0 117
      renderer/shader/shaderStandard.go
  18. 0 113
      renderer/shader/shaderTiles.go
  19. 0 90
      renderer/shader/shaders.go
  20. 12 0
      renderer/shaders/basic_fragment.glsl
  21. 18 0
      renderer/shaders/basic_vertex.glsl
  22. 276 0
      renderer/shaders/g3nshaders/main.go
  23. 11 0
      renderer/shaders/include/attributes.glsl
  24. 28 0
      renderer/shaders/include/lights.glsl
  25. 27 0
      renderer/shaders/include/material.glsl
  26. 83 0
      renderer/shaders/include/phong_model.glsl
  27. 11 55
      renderer/shader/shaderPanel.go
  28. 24 0
      renderer/shaders/panel_vertex.glsl
  29. 53 0
      renderer/shaders/phong_fragment.glsl
  30. 42 0
      renderer/shaders/phong_vertex.glsl
  31. 114 0
      renderer/shaders/shaders.go
  32. 635 0
      renderer/shaders/sources.go
  33. 32 0
      renderer/shaders/sprite_fragment.glsl
  34. 33 0
      renderer/shaders/sprite_vertex.glsl
  35. 49 0
      renderer/shaders/standard_fragment.glsl
  36. 51 0
      renderer/shaders/standard_vertex.glsl
  37. 119 122
      renderer/shaman.go

+ 4 - 4
gui/chart.go

@@ -12,14 +12,14 @@ import (
 	"github.com/g3n/engine/graphic"
 	"github.com/g3n/engine/material"
 	"github.com/g3n/engine/math32"
-	"github.com/g3n/engine/renderer/shader"
+	"github.com/g3n/engine/renderer/shaders"
 	"math"
 )
 
 func init() {
-	shader.AddShader("shaderChartVertex", shaderChartVertex)
-	shader.AddShader("shaderChartFrag", shaderChartFrag)
-	shader.AddProgram("shaderChart", "shaderChartVertex", "shaderChartFrag")
+	shaders.AddShader("shaderChartVertex", shaderChartVertex)
+	shaders.AddShader("shaderChartFrag", shaderChartFrag)
+	shaders.AddProgram("shaderChart", "shaderChartVertex", "shaderChartFrag")
 }
 
 //

+ 1 - 1
gui/panel.go

@@ -128,7 +128,7 @@ func (p *Panel) Initialize(width, height float32) {
 
 	// Initialize material
 	p.mat = material.NewMaterial()
-	p.mat.SetShader("shaderPanel")
+	p.mat.SetShader("panel")
 	p.mat.SetShaderUnique(true)
 
 	// Initialize graphic

+ 1 - 1
material/basic.go

@@ -14,6 +14,6 @@ func NewBasic() *Basic {
 
 	mb := new(Basic)
 	mb.Material.Init()
-	mb.SetShader("shaderBasic")
+	mb.SetShader("basic")
 	return mb
 }

+ 1 - 1
material/phong.go

@@ -19,6 +19,6 @@ type Phong struct {
 func NewPhong(color *math32.Color) *Phong {
 
 	pm := new(Phong)
-	pm.Standard.Init("shaderPhong", color)
+	pm.Standard.Init("phong", color)
 	return pm
 }

+ 1 - 1
material/standard.go

@@ -33,7 +33,7 @@ const (
 func NewStandard(color *math32.Color) *Standard {
 
 	ms := new(Standard)
-	ms.Init("shaderStandard", color)
+	ms.Init("standard", color)
 	return ms
 }
 

+ 13 - 13
renderer/renderer.go

@@ -46,28 +46,28 @@ func (r *Renderer) AddDefaultShaders() error {
 	return r.shaman.AddDefaultShaders()
 }
 
-func (r *Renderer) AddChunk(name, source string) error {
+func (r *Renderer) AddChunk(name, source string) {
 
-	return r.shaman.AddChunk(name, source)
+	r.shaman.AddChunk(name, source)
 }
 
-func (r *Renderer) AddShader(name, source string) error {
+func (r *Renderer) AddShader(name, source string) {
 
-	return r.shaman.AddShader(name, source)
+	r.shaman.AddShader(name, source)
 }
 
-func (r *Renderer) AddProgram(name, vertex, frag string) error {
+func (r *Renderer) AddProgram(name, vertex, frag string, others ...string) {
 
-	return r.shaman.AddProgram(name, vertex, frag)
+	r.shaman.AddProgram(name, vertex, frag, others...)
 }
 
-// SetProgramShader sets the shader type and name for a previously specified program name.
-// Returns error if the specified program or shader name not found or
-// if an invalid shader type was specified.
-func (r *Renderer) SetProgramShader(pname string, stype int, sname string) error {
-
-	return r.shaman.SetProgramShader(pname, stype, sname)
-}
+//// SetProgramShader sets the shader type and name for a previously specified program name.
+//// Returns error if the specified program or shader name not found or
+//// if an invalid shader type was specified.
+//func (r *Renderer) SetProgramShader(pname string, stype int, sname string) error {
+//
+//	return r.shaman.SetProgramShader(pname, stype, sname)
+//}
 
 func (r *Renderer) Render(iscene core.INode, icam camera.ICamera) error {
 

+ 0 - 19
renderer/shader/chunkAttributes.go

@@ -1,19 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-func init() {
-	AddChunk("attributes", chunkAttributes)
-}
-
-const chunkAttributes = `
-// Vertex attributes
-layout(location = 0) in vec3  VertexPosition;
-layout(location = 1) in vec3  VertexNormal;
-layout(location = 2) in vec3  VertexColor;
-layout(location = 3) in vec2  VertexTexcoord;
-layout(location = 4) in float VertexDistance;
-layout(location = 5) in vec4  VertexTexoffsets;
-`

+ 0 - 50
renderer/shader/chunkLights.go

@@ -1,50 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-func init() {
-	AddChunk("lights", chunkLights)
-}
-
-const chunkLights = `
-{{if .AmbientLightsMax}}
-// Ambient lights uniforms
-uniform vec3 AmbientLightColor[{{.AmbientLightsMax}}];
-{{end}}
-
-{{if .DirLightsMax}}
-// Directional lights uniform array. Each directional light uses 2 elements
-uniform vec3  DirLight[2*{{.DirLightsMax}}];
-
-// Macros to access elements inside the DirectionalLight uniform array
-#define DirLightColor(a)		DirLight[2*a]
-#define DirLightPosition(a)		DirLight[2*a+1]
-{{end}}
-
-{{if .PointLightsMax}}
-// Point lights uniform array. Each point light uses 3 elements
-uniform vec3  PointLight[3*{{.PointLightsMax}}];
-
-// Macros to access elements inside the PointLight uniform array
-#define PointLightColor(a)			PointLight[3*a]
-#define PointLightPosition(a)		PointLight[3*a+1]
-#define PointLightLinearDecay(a)	PointLight[3*a+2].x
-#define PointLightQuadraticDecay(a)	PointLight[3*a+2].y
-{{end}}
-
-{{if .SpotLightsMax}}
-// Spot lights uniforms. Each spot light uses 5 elements
-uniform vec3  SpotLight[5*{{.SpotLightsMax}}];
-
-// Macros to access elements inside the PointLight uniform array
-#define SpotLightColor(a)			SpotLight[5*a]
-#define SpotLightPosition(a)		SpotLight[5*a+1]
-#define SpotLightDirection(a)		SpotLight[5*a+2]
-#define SpotLightAngularDecay(a)	SpotLight[5*a+3].x
-#define SpotLightCutoffAngle(a)		SpotLight[5*a+3].y
-#define SpotLightLinearDecay(a)		SpotLight[5*a+3].z
-#define SpotLightQuadraticDecay(a)	SpotLight[5*a+4].x
-{{end}}
-`

+ 0 - 36
renderer/shader/chunkMaterial.go

@@ -1,36 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-func init() {
-	AddChunk("material", chunkMaterial)
-}
-
-const chunkMaterial = `
-// Material uniforms
-uniform vec3	Material[6];
-
-// Macros to access elements inside the Material uniform array
-#define MatAmbientColor		Material[0]
-#define MatDiffuseColor		Material[1]
-#define MatSpecularColor	Material[2]
-#define MatEmissiveColor	Material[3]
-#define MatShininess		Material[4].x
-#define MatOpacity			Material[4].y
-#define MatPointSize		Material[4].z
-#define MatPointRotationZ	Material[5].x
-
-{{if .MatTexturesMax}}
-// Textures uniforms
-uniform sampler2D	MatTexture[{{.MatTexturesMax}}];
-uniform mat3		MatTexinfo[{{.MatTexturesMax}}];
-
-// Macros to access elements inside MatTexinfo uniform
-#define MatTexOffset(a)		MatTexinfo[a][0].xy
-#define MatTexRepeat(a)		MatTexinfo[a][1].xy
-#define MatTexFlipY(a)		bool(MatTexinfo[a][2].x)
-#define MatTexVisible(a)	bool(MatTexinfo[a][2].y)
-{{ end }}
-`

+ 0 - 123
renderer/shader/chunkPhongModel.go

@@ -1,123 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-func init() {
-	AddChunk("phong_model", chunkPhongModel)
-}
-
-const chunkPhongModel = `
-/***
- phong lighting model
- Parameters:
-    position:   input vertex position in camera coordinates
-    normal:     input vertex normal in camera coordinates
-    camDir:     input camera directions
-    matAmbient: input material ambient color
-    matDiffuse: input material diffuse color
-    ambdiff:    output ambient+diffuse color
-    spec:       output specular color
- Uniforms:
-    AmbientLightColor[]
-    DiffuseLightColor[]
-    DiffuseLightPosition[]
-    PointLightColor[]
-    PointLightPosition[];
-    PointLightLinearDecay[];
-    PointLightQuadraticDecay[];
-    MatSpecularColor
-    MatShininess
-*/
-void phongModel(vec4 position, vec3 normal, vec3 camDir, vec3 matAmbient, vec3 matDiffuse, out vec3 ambdiff, out vec3 spec) {
-
-    vec3 ambientTotal  = vec3(0.0);
-    vec3 diffuseTotal  = vec3(0.0);
-    vec3 specularTotal = vec3(0.0);
-
-    {{ range loop .AmbientLightsMax }}
-        ambientTotal += AmbientLightColor[{{.}}] * matAmbient;
-    {{ end }}
-
-    {{ range loop .DirLightsMax }}
-    {
-        // Diffuse reflection
-        // DirLightPosition is the direction of the current light
-        vec3 lightDirection = normalize(DirLightPosition({{.}}));
-        // Calculates the dot product between the light direction and this vertex normal.
-        float dotNormal = max(dot(lightDirection, normal), 0.0);
-        diffuseTotal += DirLightColor({{.}}) * matDiffuse * dotNormal;
-
-        // Specular reflection
-        // Calculates the light reflection vector 
-        vec3 ref = reflect(-lightDirection, normal);
-        if (dotNormal > 0.0) {
-            specularTotal += DirLightColor({{.}}) * MatSpecularColor * pow(max(dot(ref, camDir), 0.0), MatShininess);
-        }
-    }
-    {{ end }}
-
-    {{ range loop .PointLightsMax }}
-    {
-        // Calculates the direction and distance from the current vertex to this point light.
-        vec3 lightDirection = PointLightPosition({{.}}) - vec3(position);
-        float lightDistance = length(lightDirection);
-        // Normalizes the lightDirection
-        lightDirection = lightDirection / lightDistance;
-        // Calculates the attenuation due to the distance of the light
-        float attenuation = 1.0 / (1.0 + PointLightLinearDecay({{.}}) * lightDistance +
-            PointLightQuadraticDecay({{.}}) * lightDistance * lightDistance);
-
-        // Diffuse reflection
-        float dotNormal = max(dot(lightDirection, normal), 0.0);
-        diffuseTotal += PointLightColor({{.}}) * matDiffuse * dotNormal * attenuation;
-        
-        // Specular reflection
-        // Calculates the light reflection vector 
-        vec3 ref = reflect(-lightDirection, normal);
-        if (dotNormal > 0.0) {
-            specularTotal += PointLightColor({{.}}) * MatSpecularColor *
-                pow(max(dot(ref, camDir), 0.0), MatShininess) * attenuation;
-        }
-    }
-    {{ end }}
-
-    {{ range loop .SpotLightsMax }}
-    {
-        // Calculates the direction and distance from the current vertex to this spot light.
-        vec3 lightDirection = SpotLightPosition({{.}}) - vec3(position);
-        float lightDistance = length(lightDirection);
-        lightDirection = lightDirection / lightDistance;
-
-        // Calculates the attenuation due to the distance of the light
-        float attenuation = 1.0 / (1.0 + SpotLightLinearDecay({{.}}) * lightDistance +
-            SpotLightQuadraticDecay({{.}}) * lightDistance * lightDistance);
-
-        // Calculates the angle between the vertex direction and spot direction
-        // If this angle is greater than the cutoff the spotlight will not contribute
-        // to the final color.
-        float angle = acos(dot(-lightDirection, SpotLightDirection({{.}})));
-        float cutoff = radians(clamp(SpotLightCutoffAngle({{.}}), 0.0, 90.0));
-
-        if (angle < cutoff) {
-            float spotFactor = pow(dot(-lightDirection, SpotLightDirection({{.}})), SpotLightAngularDecay({{.}}));
-
-            // Diffuse reflection
-            float dotNormal = max(dot(lightDirection, normal), 0.0);
-            diffuseTotal += SpotLightColor({{.}}) * matDiffuse * dotNormal * attenuation * spotFactor;
-
-            // Specular reflection
-            vec3 ref = reflect(-lightDirection, normal);
-            if (dotNormal > 0.0) {
-                specularTotal += SpotLightColor({{.}}) * MatSpecularColor * pow(max(dot(ref, camDir), 0.0), MatShininess) * attenuation * spotFactor;
-            }
-        }
-    }
-    {{ end }}
-
-    // Sets output colors
-    ambdiff = ambientTotal + MatEmissiveColor + diffuseTotal;
-    spec = specularTotal;
-}
-`

+ 0 - 6
renderer/shader/doc.go

@@ -1,6 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package shader contains the several shaders used by the engine.
-package shader

+ 0 - 50
renderer/shader/shaderBasic.go

@@ -1,50 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-func init() {
-	AddShader("shaderBasicVertex", shaderBasicVertex)
-	AddShader("shaderBasicFrag", shaderBasicFrag)
-	AddProgram("shaderBasic", "shaderBasicVertex", "shaderBasicFrag")
-}
-
-//
-// Vertex Shader template
-//
-const shaderBasicVertex = `
-#version {{.Version}}
-
-{{template "attributes" .}}
-{{template "material" .}}
-
-// Model uniforms
-uniform mat4 MVP;
-
-
-// Final output color for fragment shader
-out vec3 Color;
-
-void main() {
-
-    Color = VertexColor;
-    gl_Position = MVP * vec4(VertexPosition, 1.0);
-}
-`
-
-//
-// Fragment Shader template
-//
-const shaderBasicFrag = `
-#version {{.Version}}
-
-in vec3 Color;
-out vec4 FragColor;
-
-void main() {
-
-    FragColor = vec4(Color, 1.0);
-}
-
-`

+ 0 - 54
renderer/shader/shaderLineDashed.go

@@ -1,54 +0,0 @@
-package shader
-
-
-const shaderLineDashedVertex = `
-#version {{.Version}}
-
-{{?attributes}}
-
-// Model uniforms
-uniform mat4 MVP;
-
-// Material uniforms
-uniform float Scale;
-
-// Outputs for fragment shader
-out vec3 Color;
-out float vLineDistance; 
-
-void main() {
-
-    vLineDistance = Scale * VertexDistance;
-    Color = VertexColor;
-    gl_Position = MVP * vec4(VertexPosition, 1.0);
-}
-`
-
-
-//
-// Fragment Shader template
-//
-const shaderLineDashedFrag = `
-#version {{.Version}}
-
-// Inputs from vertex shader
-in vec3 Color;
-in float vLineDistance;
-
-// Material uniforms
-uniform float DashSize;
-uniform float TotalSize;
-
-// Output
-out vec4 FragColor;
-
-void main() {
-
-    if (mod(vLineDistance, TotalSize) > DashSize) {
-        discard;
-    }
-
-    FragColor = vec4(Color, 1.0);
-}
-
-`

+ 0 - 111
renderer/shader/shaderPhong.go

@@ -1,111 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-func init() {
-	AddShader("shaderPhongVertex", shaderPhongVertex)
-	AddShader("shaderPhongFrag", shaderPhongFrag)
-	AddProgram("shaderPhong", "shaderPhongVertex", "shaderPhongFrag")
-}
-
-//
-// Vertex Shade template
-//
-var shaderPhongVertex = `
-#version {{.Version}}
-
-{{template "attributes" .}}
-
-// Model uniforms
-uniform mat4 ModelViewMatrix;
-uniform mat3 NormalMatrix;
-uniform mat4 MVP;
-
-{{template "material" .}}
-
-// Output variables for Fragment shader
-out vec4 Position;
-out vec3 Normal;
-out vec3 CamDir;
-out vec2 FragTexcoord;
-
-void main() {
-
-    // Transform this vertex position to camera coordinates.
-    Position = ModelViewMatrix * vec4(VertexPosition, 1.0);
-
-    // Transform this vertex normal to camera coordinates.
-    Normal = normalize(NormalMatrix * VertexNormal);
-
-    // Calculate the direction vector from the vertex to the camera
-    // The camera is at 0,0,0
-    CamDir = normalize(-Position.xyz);
-
-    // Flips texture coordinate Y if requested.
-    vec2 texcoord = VertexTexcoord;
-    {{ if .MatTexturesMax }}
-    if (MatTexFlipY(0)) {
-        texcoord.y = 1 - texcoord.y;
-    }
-    {{ end }}
-    FragTexcoord = texcoord;
-
-    gl_Position = MVP * vec4(VertexPosition, 1.0);
-}
-`
-
-//
-// Fragment Shader template
-//
-var shaderPhongFrag = `
-#version {{.Version}}
-
-// Inputs from vertex shader
-in vec4 Position;       // Vertex position in camera coordinates.
-in vec3 Normal;         // Vertex normal in camera coordinates.
-in vec3 CamDir;         // Direction from vertex to camera
-in vec2 FragTexcoord;
-
-{{template "lights" .}}
-{{template "material" .}}
-{{template "phong_model" .}}
-
-// Final fragment color
-out vec4 FragColor;
-
-void main() {
-
-    // Combine all texture colors
-    vec4 texCombined = vec4(1);
-    {{ range loop .MatTexturesMax }}
-    if (MatTexVisible({{.}})) {
-        vec4 texcolor = texture(MatTexture[{{.}}], FragTexcoord * MatTexRepeat({{.}}) + MatTexOffset({{.}}));
-        if ({{.}} == 0) {
-            texCombined = texcolor;
-        } else {
-            texCombined = mix(texCombined, texcolor, texcolor.a);
-        }
-    }
-    {{ end }}
-
-    // Combine material with texture colors
-    vec4 matDiffuse = vec4(MatDiffuseColor, MatOpacity) * texCombined;
-    vec4 matAmbient = vec4(MatAmbientColor, MatOpacity) * texCombined;
-
-    // Inverts the fragment normal if not FrontFacing
-    vec3 fragNormal = Normal;
-    if (!gl_FrontFacing) {
-        fragNormal = -fragNormal;
-    }
-
-    // Calculates the Ambient+Diffuse and Specular colors for this fragment using the Phong model.
-    vec3 Ambdiff, Spec;
-    phongModel(Position, fragNormal, CamDir, vec3(matAmbient), vec3(matDiffuse), Ambdiff, Spec);
-
-    // Final fragment color
-    FragColor = min(vec4(Ambdiff + Spec, matDiffuse.a), vec4(1.0));
-}
-
-`

+ 0 - 85
renderer/shader/shaderPoint.go

@@ -1,85 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-func init() {
-	AddShader("shaderPointVertex", shaderPointVertex)
-	AddShader("shaderPointFrag", shaderPointFrag)
-	AddProgram("shaderPoint", "shaderPointVertex", "shaderPointFrag")
-}
-
-//
-// Vertex Shader template
-//
-const shaderPointVertex = `
-#version {{.Version}}
-
-{{template "attributes" .}}
-
-// Model uniforms
-uniform mat4 MVP;
-
-// Material uniforms
-{{template "material" .}}
-
-// Outputs for fragment shader
-out vec3 Color;
-flat out mat2 Rotation;
-
-void main() {
-
-    // Rotation matrix for fragment shader
-    float rotSin = sin(MatPointRotationZ);
-    float rotCos = cos(MatPointRotationZ);
-    Rotation = mat2(rotCos, rotSin, - rotSin, rotCos);
-
-    // Sets the vertex position
-    vec4 pos = MVP * vec4(VertexPosition, 1.0);
-    gl_Position = pos;
-
-    // Sets the size of the rasterized point decreasing with distance
-    gl_PointSize = (1.0 - pos.z / pos.w) * MatPointSize;
-
-    // Outputs color
-    Color = MatEmissiveColor;
-}
-`
-
-//
-// Fragment Shader template
-//
-const shaderPointFrag = `
-#version {{.Version}}
-
-{{template "material" .}}
-
-// Inputs from vertex shader
-in vec3 Color;
-flat in mat2 Rotation;
-
-// Output
-out vec4 FragColor;
-
-void main() {
-
-    // Combine all texture colors and opacity
-    vec4 texCombined = vec4(1);
-    {{ range loop .MatTexturesMax }}
-    {
-        vec2 pt = gl_PointCoord - vec2(0.5);
-        vec4 texcolor = texture(MatTexture[{{.}}], (Rotation * pt + vec2(0.5)) * MatTexRepeat({{.}}) + MatTexOffset({{.}}));
-        if ({{.}} == 0) {
-            texCombined = texcolor;
-        } else {
-            texCombined = mix(texCombined, texcolor, texcolor.a);
-        }
-    }
-    {{ end }}
-
-    // Combine material color with texture
-    FragColor = min(vec4(Color, MatOpacity) * texCombined, vec4(1));
-}
-
-`

+ 0 - 74
renderer/shader/shaderSprite.go

@@ -1,74 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-const shaderSpriteVertex = `
-#version {{.Version}}
-
-{{template "attributes" .}}
-
-// Input uniforms
-uniform mat4 MVP;
-
-{{template "material" .}}
-
-// Outputs for fragment shader
-out vec3 Color;
-out vec2 FragTexcoord;
-
-void main() {
-
-    // Applies transformation to vertex position
-    gl_Position = MVP * vec4(VertexPosition, 1.0);
-
-    // Outputs color
-    Color = MatDiffuseColor;
-
-    // Flips texture coordinate Y if requested.
-    vec2 texcoord = VertexTexcoord;
-    {{if .MatTexturesMax}}
-    if (MatTexFlipY[0] > 0) {
-        texcoord.y = 1 - texcoord.y;
-    }
-    {{ end }}
-    FragTexcoord = texcoord;
-}
-`
-
-//
-// Fragment Shader template
-//
-const shaderSpriteFrag = `
-#version {{.Version}}
-
-{{template "material" .}}
-
-// Inputs from vertex shader
-in vec3 Color;
-in vec2 FragTexcoord;
-
-// Output
-out vec4 FragColor;
-
-void main() {
-
-    // Combine all texture colors and opacity
-    vec4 texCombined = vec4(1);
-    {{ range loop .MatTexturesMax }}
-    {
-        vec4 texcolor = texture(MatTexture[{{.}}], FragTexcoord * MatTexRepeat[{{.}}] + MatTexOffset[{{.}}]);
-        if ({{.}} == 0) {
-            texCombined = texcolor;
-        } else {
-            texCombined = mix(texCombined, texcolor, texcolor.a);
-        }
-    }
-    {{ end }}
-
-    // Combine material color with texture
-    FragColor = min(vec4(Color, MatOpacity) * texCombined, vec4(1));
-}
-
-`

+ 0 - 117
renderer/shader/shaderStandard.go

@@ -1,117 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-func init() {
-	AddShader("shaderStandardVertex", shaderStandardVertex)
-	AddShader("shaderStandardFrag", shaderStandardFrag)
-	AddProgram("shaderStandard", "shaderStandardVertex", "shaderStandardFrag")
-}
-
-//
-// Vertex Shader template
-//
-const shaderStandardVertex = `
-#version {{.Version}}
-
-{{template "attributes" .}}
-
-// Model uniforms
-uniform mat4 ModelViewMatrix;
-uniform mat3 NormalMatrix;
-uniform mat4 MVP;
-
-{{template "lights" .}}
-{{template "material" .}}
-{{template "phong_model" .}}
-
-
-// Outputs for the fragment shader.
-out vec3 ColorFrontAmbdiff;
-out vec3 ColorFrontSpec;
-out vec3 ColorBackAmbdiff;
-out vec3 ColorBackSpec;
-out vec2 FragTexcoord;
-
-void main() {
-
-    // Transform this vertex normal to camera coordinates.
-    vec3 normal = normalize(NormalMatrix * VertexNormal);
-
-    // Calculate this vertex position in camera coordinates
-    vec4 position = ModelViewMatrix * vec4(VertexPosition, 1.0);
-
-    // Calculate the direction vector from the vertex to the camera
-    // The camera is at 0,0,0
-    vec3 camDir = normalize(-position.xyz);
-
-    // Calculates the vertex Ambient+Diffuse and Specular colors using the Phong model
-    // for the front and back
-    phongModel(position,  normal, camDir, MatAmbientColor, MatDiffuseColor, ColorFrontAmbdiff, ColorFrontSpec);
-    phongModel(position, -normal, camDir, MatAmbientColor, MatDiffuseColor, ColorBackAmbdiff, ColorBackSpec);
-
-    vec2 texcoord = VertexTexcoord;
-    {{if .MatTexturesMax }}
-    // Flips texture coordinate Y if requested.
-    if (MatTexFlipY(0)) {
-        texcoord.y = 1 - texcoord.y;
-    }
-    {{ end }}
-    FragTexcoord = texcoord;
-
-    gl_Position = MVP * vec4(VertexPosition, 1.0);
-}
-`
-
-//
-// Fragment Shader template
-//
-const shaderStandardFrag = `
-#version {{.Version}}
-
-{{template "material" .}}
-
-// Inputs from Vertex shader
-in vec3 ColorFrontAmbdiff;
-in vec3 ColorFrontSpec;
-in vec3 ColorBackAmbdiff;
-in vec3 ColorBackSpec;
-in vec2 FragTexcoord;
-
-// Output
-out vec4 FragColor;
-
-
-void main() {
-
-    vec4 texCombined = vec4(1);
-
-    // Combine all texture colors and opacity
-    // Use Go templates to unroll the loop because non-const
-    // array indexes are not allowed until GLSL 4.00.
-    {{ range loop .MatTexturesMax }}
-    if (MatTexVisible({{.}})) {
-        vec4 texcolor = texture(MatTexture[{{.}}], FragTexcoord * MatTexRepeat({{.}}) + MatTexOffset({{.}}));
-        if ({{.}} == 0) {
-            texCombined = texcolor;
-        } else {
-            texCombined = mix(texCombined, texcolor, texcolor.a);
-        }
-    }
-    {{ end }}
-
-    vec4 colorAmbDiff;
-    vec4 colorSpec;
-    if (gl_FrontFacing) {
-        colorAmbDiff = vec4(ColorFrontAmbdiff, MatOpacity);
-        colorSpec = vec4(ColorFrontSpec, 0);
-    } else {
-        colorAmbDiff = vec4(ColorBackAmbdiff, MatOpacity);
-        colorSpec = vec4(ColorBackSpec, 0);
-    }
-    FragColor = min(colorAmbDiff * texCombined + colorSpec, vec4(1));
-}
-
-`

+ 0 - 113
renderer/shader/shaderTiles.go

@@ -1,113 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-const shaderTilesVertex = `
-#version {{.Version}}
-
-{{template "attributes" .}}
-
-// Model uniforms
-uniform mat4 ModelViewMatrix;
-uniform mat3 NormalMatrix;
-uniform mat4 MVP;
-
-// Templates
-{{template "uniLights" .}}
-{{template "uniMaterial" .}}
-{{template "funcPhongModel" .}}
-
-
-// Outputs for the fragment shader.
-out vec3 ColorFrontAmbdiff;
-out vec3 ColorFrontSpec;
-out vec3 ColorBackAmbdiff;
-out vec3 ColorBackSpec;
-out vec2 FragTexcoord;
-flat out vec4 TexOffsets;
-
-
-void main() {
-
-    // Transform this vertex normal to camera coordinates.
-    vec3 normal = normalize(NormalMatrix * VertexNormal);
-
-    // Calculate this vertex position in camera coordinates
-    vec4 position = ModelViewMatrix * vec4(VertexPosition, 1.0);
-
-    // Calculate the direction vector from the vertex to the camera
-    // The camera is at 0,0,0
-    vec3 camDir = normalize(-position.xyz);
-
-    // Calculates the vertex Ambient+Diffuse and Specular colors using the Phong model
-    // for the front and back
-    phongModel(position,  normal, camDir, MatAmbientColor, MatDiffuseColor, ColorFrontAmbdiff, ColorFrontSpec);
-    phongModel(position, -normal, camDir, MatAmbientColor, MatDiffuseColor, ColorBackAmbdiff, ColorBackSpec);
-
-    // Flips texture coordinate Y if requested.
-    vec2 texcoord = VertexTexcoord;
-    {{ if .MatTexturesMax }}
-    if (MatTexFlipY[0] > 0) {
-        texcoord.y = 1 - texcoord.y;
-    }
-    {{ end }}
-    FragTexcoord = texcoord;
-    TexOffsets = VertexTexoffsets;
-
-    gl_Position = MVP * vec4(VertexPosition, 1.0);
-}
-`
-
-//
-// Fragment Shader template
-//
-const shaderTilesFrag = `
-#version {{.Version}}
-
-{{template "uniMaterial" .}}
-
-// Inputs from Vertex shader
-in vec3 ColorFrontAmbdiff;
-in vec3 ColorFrontSpec;
-in vec3 ColorBackAmbdiff;
-in vec3 ColorBackSpec;
-in vec2 FragTexcoord;
-flat in vec4 TexOffsets;
-
-// Output
-out vec4 FragColor;
-
-
-void main() {
-
-    vec2 offset = vec2(TexOffsets.xy);
-    vec2 repeat = vec2(TexOffsets.zw);
-    vec4 texCombined = texture(MatTexture[0], FragTexcoord * repeat + offset);
-
-//    vec4 texCombined = vec4(1);
-//    {{ range loop .MatTexturesMax }}
-//    // Combine all texture colors and opacity
-//    {
-//        vec4 texcolor = texture(MatTexture[{{.}}], FragTexcoord * MatTexRepeat[{{.}}] + MatTexOffset[{{.}}]);
-//        if ({{.}} == 0) {
-//            texCombined = texcolor;
-//        } else {
-//            texCombined = mix(texCombined, texcolor, texcolor.a);
-//        }
-//    }
-//    {{ end }}
-
-    vec4 colorAmbDiff;
-    vec4 colorSpec;
-    if (gl_FrontFacing) {
-        colorAmbDiff = vec4(ColorFrontAmbdiff, MatOpacity);
-        colorSpec = vec4(ColorFrontSpec, 0);
-    } else {
-        colorAmbDiff = vec4(ColorBackAmbdiff, MatOpacity);
-        colorSpec = vec4(ColorBackSpec, 0);
-    }
-    FragColor = min(colorAmbDiff * texCombined + colorSpec, vec4(1));
-}
-`

+ 0 - 90
renderer/shader/shaders.go

@@ -1,90 +0,0 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-import (
-	"fmt"
-
-	"github.com/g3n/engine/gls"
-)
-
-// ProgramInfo contains information for a registered program name
-type ProgramInfo struct {
-	Vertex   string // Vertex shader name
-	Frag     string // Fragment shader name
-	Geometry string // Geometry shader name (maybe an empty string)
-}
-
-// Internal global maps of shader chunks, shader sources and programs
-var chunks = map[string]string{}
-var shaders = map[string]string{}
-var programs = map[string]ProgramInfo{}
-
-// Chunks returns a map with all registered shader chunks names
-// associated with its glsl source code.
-func Chunks() map[string]string {
-
-	return chunks
-}
-
-// Shaders returns a map with all registered shader names
-// associated with
-func Shaders() map[string]string {
-
-	return shaders
-}
-
-func Programs() map[string]ProgramInfo {
-
-	return programs
-}
-
-func AddChunk(name, source string) {
-
-	chunks[name] = source
-}
-
-func AddShader(name, source string) {
-
-	shaders[name] = source
-}
-
-// AddProgram adds a program name to the global program registry
-func AddProgram(name, vertexName, fragName string) {
-
-	programs[name] = ProgramInfo{vertexName, fragName, ""}
-}
-
-// SetProgramShader sets the shader type and name for a previously
-// specified program name.
-// It panics if the specified program or shader name not found or
-// if an invalid shader type was specified.
-func SetProgramShader(pname string, stype int, sname string) {
-
-	// Checks if program name is valid
-	pinfo, ok := programs[pname]
-	if !ok {
-		panic(fmt.Sprintf("Program name:%s not found", pname))
-	}
-
-	// Checks if shader name is valid
-	_, ok = shaders[sname]
-	if !ok {
-		panic(fmt.Sprintf("Shader name:%s not found", sname))
-	}
-
-	// Sets the program shader name for the specified type
-	switch stype {
-	case gls.VERTEX_SHADER:
-		pinfo.Vertex = sname
-	case gls.FRAGMENT_SHADER:
-		pinfo.Frag = sname
-	case gls.GEOMETRY_SHADER:
-		pinfo.Geometry = sname
-	default:
-		panic("Invalid shader type")
-	}
-	programs[pname] = pinfo
-}

+ 12 - 0
renderer/shaders/basic_fragment.glsl

@@ -0,0 +1,12 @@
+//
+// Fragment Shader template
+//
+
+in vec3 Color;
+out vec4 FragColor;
+
+void main() {
+
+    FragColor = vec4(Color, 1.0);
+}
+

+ 18 - 0
renderer/shaders/basic_vertex.glsl

@@ -0,0 +1,18 @@
+//
+// Vertex shader basic
+//
+#include <attributes>
+
+// Model uniforms
+uniform mat4 MVP;
+
+// Final output color for fragment shader
+out vec3 Color;
+
+void main() {
+
+    Color = VertexColor;
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
+}
+
+

+ 276 - 0
renderer/shaders/g3nshaders/main.go

@@ -0,0 +1,276 @@
+// Copyright 2016 The G3N Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/format"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"text/template"
+)
+
+const (
+	PROGNAME      = "g3nshaders"
+	VMAJOR        = 0
+	VMINOR        = 1
+	SHADEREXT     = ".glsl"
+	DIR_INCLUDE   = "include"
+	TYPE_VERTEX   = "vertex"
+	TYPE_FRAGMENT = "fragment"
+	TYPE_GEOMETRY = "geometry"
+)
+
+//
+// Go template to generate the output file with the shaders' sources and
+// maps describing the include and shader names and programs shaders.
+//
+const TEMPLATE = `// File generated by G3NSHADERS. Do not edit.
+// To regenerate this file install 'g3nshaders' and execute:
+// 'go generate' in this folder.
+package {{.Pkg}}
+
+{{range .Includes}}
+const include_{{.Name}}_source = ` + "`{{.Source}}`" + `
+{{end}}
+
+{{range .Shaders}}
+const {{.Name}}_source = ` + "`{{.Source}}`" + `
+{{end}}
+
+// Maps include name with its source code
+var includeMap = map[string]string {
+{{range .Includes}}
+	"{{- .Name}}": include_{{.Name}}_source, {{end}}
+}
+
+// Maps shader name with its source code
+var shaderMap = map[string]string {
+{{range .Shaders}}
+	"{{- .Name}}": {{.Name}}_source, {{end}}
+}
+
+// Maps program name with Proginfo struct with shaders names
+var programMap = map[string]ProgramInfo{
+{{ range $progName, $progInfo := .Programs }}
+	"{{$progName}}": { "{{$progInfo.Vertex}}","{{$progInfo.Fragment}}","{{$progInfo.Geometry}}" }, {{end}}
+}
+`
+
+// Command line options
+var (
+	oVersion = flag.Bool("version", false, "Show version and exits")
+	oInp     = flag.String("in", ".", "Input directory")
+	oOut     = flag.String("out", "sources.go", "Go output file")
+	oPackage = flag.String("pkg", "shaders", "Package name")
+	oVerbose = flag.Bool("v", false, "Show files being processed")
+)
+
+// Valid shader types
+var shaderTypes = map[string]bool{
+	TYPE_VERTEX:   true,
+	TYPE_FRAGMENT: true,
+	TYPE_GEOMETRY: true,
+}
+
+// fileInfo describes a shader or include file name and source code
+type fileInfo struct {
+	Name    string // shader or include name
+	Source  string // shader or include source code
+	Include bool   // true if include, false otherwise
+}
+
+// progInfo describes all the shader names of an specific program
+// If the program doesn't use the geometry shader it is set as an empty string
+type progInfo struct {
+	Vertex   string // vertex shader name
+	Fragment string // fragment shader name
+	Geometry string // geometry shader name
+}
+
+// templInfo contains all information needed for the template expansion
+type templInfo struct {
+	Pkg      string
+	Includes []fileInfo
+	Shaders  []fileInfo
+	Programs map[string]progInfo
+}
+
+var templData templInfo
+
+func main() {
+
+	// Parse command line parameters
+	flag.Usage = usage
+	flag.Parse()
+
+	// If requested, print version and exits
+	if *oVersion == true {
+		fmt.Fprintf(os.Stderr, "%s v%d.%d\n", PROGNAME, VMAJOR, VMINOR)
+		return
+	}
+
+	// Initialize template data
+	templData.Pkg = *oPackage
+	templData.Programs = make(map[string]progInfo)
+
+	// Process the current directory and its subdirectories recursively
+	// appending information into templData
+	processDir(*oInp, false)
+
+	// Generates output file from TEMPLATE
+	generate(*oOut)
+}
+
+// processDir processes recursively all shaders files in the specified directory
+func processDir(dir string, include bool) {
+
+	// Open directory
+	f, err := os.Open(dir)
+	if err != nil {
+		panic(err)
+	}
+	defer f.Close()
+
+	// Read all fileinfos
+	finfos, err := f.Readdir(0)
+	if err != nil {
+		panic(err)
+	}
+
+	// Process subdirectory recursively or process file
+	for _, fi := range finfos {
+		if fi.IsDir() {
+			dirInclude := include
+			if fi.Name() == DIR_INCLUDE {
+				dirInclude = true
+			}
+			processDir(filepath.Join(dir, fi.Name()), dirInclude)
+		} else {
+			processFile(filepath.Join(dir, fi.Name()), include)
+		}
+	}
+}
+
+// processFile process one file checking if it has the shaders extension,
+// otherwise it is ignored.
+// If the include flag is true the file is an include file otherwise it
+// it a shader
+func processFile(file string, include bool) {
+
+	// Ignore file if it has not the shader extension
+	fext := filepath.Ext(file)
+	if fext != SHADEREXT {
+		if *oVerbose {
+			fmt.Printf("Ignored file (not shader): %s\n", file)
+		}
+		return
+	}
+
+	// Get the file base name and its name with the extension
+	fbase := filepath.Base(file)
+	fname := fbase[:len(fbase)-len(fext)]
+
+	// If not in include directory, the file must be a shader program
+	// which name must have the format: <name>_<shader_type>
+	if !include {
+		parts := strings.Split(string(fname), "_")
+		if len(parts) < 2 {
+			fmt.Printf("Ignored file (INVALID NAME): %s\n", file)
+			return
+		}
+		stype := parts[len(parts)-1]
+		if !shaderTypes[stype] {
+			fmt.Printf("Ignored file (INVALID SHADER TYPE): %s\n", file)
+			return
+		}
+		sname := strings.Join(parts[:len(parts)-1], "_")
+		pinfo, ok := templData.Programs[sname]
+		if !ok {
+			templData.Programs[sname] = pinfo
+		}
+		switch stype {
+		case TYPE_VERTEX:
+			pinfo.Vertex = fname
+		case TYPE_FRAGMENT:
+			pinfo.Fragment = fname
+		case TYPE_GEOMETRY:
+			pinfo.Geometry = fname
+		}
+		templData.Programs[sname] = pinfo
+	}
+
+	// Reads all file data
+	f, err := os.Open(file)
+	if err != nil {
+		panic(err)
+	}
+	defer f.Close()
+	data, err := ioutil.ReadAll(f)
+	if err != nil {
+		panic(err)
+	}
+
+	// Appends entry in Includes or Shaders
+	if include {
+		templData.Includes = append(templData.Includes, fileInfo{
+			Name:   fname,
+			Source: string(data),
+		})
+	} else {
+		templData.Shaders = append(templData.Shaders, fileInfo{
+			Name:   fname,
+			Source: string(data),
+		})
+	}
+	if *oVerbose {
+		fmt.Printf("%s (%v bytes)\n", file, len(data))
+	}
+}
+
+// generate generates output go file with shaders sources from TEMPLATE
+func generate(file string) {
+
+	// Parses the template
+	tmpl := template.New("tmpl")
+	tmpl, err := tmpl.Parse(TEMPLATE)
+	if err != nil {
+		panic(err)
+	}
+
+	// Expands template to buffer
+	var buf bytes.Buffer
+	err = tmpl.Execute(&buf, &templData)
+	if err != nil {
+		panic(err)
+	}
+
+	// Formats buffer as Go source
+	p, err := format.Source(buf.Bytes())
+	if err != nil {
+		panic(err)
+	}
+
+	// Writes formatted source to output file
+	f, err := os.Create(file)
+	if err != nil {
+		panic(err)
+	}
+	f.Write(p)
+	f.Close()
+}
+
+// usage shows the application usage
+func usage() {
+
+	fmt.Fprintf(os.Stderr, "%s v%d.%d\n", PROGNAME, VMAJOR, VMINOR)
+	fmt.Fprintf(os.Stderr, "usage: %s [options]\n", strings.ToLower(PROGNAME))
+	flag.PrintDefaults()
+	os.Exit(2)
+}

+ 11 - 0
renderer/shaders/include/attributes.glsl

@@ -0,0 +1,11 @@
+//
+// Vertex attributes
+//
+layout(location = 0) in  vec3  VertexPosition;
+layout(location = 1) in  vec3  VertexNormal;
+layout(location = 2) in  vec3  VertexColor;
+layout(location = 3) in  vec2  VertexTexcoord;
+layout(location = 4) in  float VertexDistance;
+layout(location = 5) in  vec4  VertexTexoffsets;
+
+

+ 28 - 0
renderer/shaders/include/lights.glsl

@@ -0,0 +1,28 @@
+//
+// Lights uniforms
+//
+
+// Ambient lights uniforms
+#if AMB_LIGHTS>0
+uniform vec3 AmbientLightColor[AMB_LIGHTS];
+#endif
+
+// Directional lights uniform array. Each directional light uses 2 elements
+#if DIR_LIGHTS>0
+uniform vec3 DirLight[2*DIR_LIGHTS];
+// Macros to access elements inside the DirectionalLight uniform array
+#define DirLightColor(a)		DirLight[2*a]
+#define DirLightPosition(a)		DirLight[2*a+1]
+#endif
+
+// Point lights uniform array. Each point light uses 3 elements
+#if POINT_LIGHTS>0
+uniform vec3 PointLight[3*POINT_LIGHTS];
+// Macros to access elements inside the PointLight uniform array
+#define PointLightColor(a)			PointLight[3*a]
+#define PointLightPosition(a)		PointLight[3*a+1]
+#define PointLightLinearDecay(a)	PointLight[3*a+2].x
+#define PointLightQuadraticDecay(a)	PointLight[3*a+2].y
+#endif
+
+

+ 27 - 0
renderer/shaders/include/material.glsl

@@ -0,0 +1,27 @@
+//
+// Material properties uniform
+//
+uniform vec3 Material[5];
+// Macros to access elements inside the MatTexinfo array
+// Each texture uses 3 vec2 elements.
+#define MatAmbientColor		Material[0]
+#define MatDiffuseColor     Material[1]
+#define MatEmissiveColor    Material[2]
+#define MatSpecularColor    Material[3]
+#define MatShininess        Material[4].x
+#define MatOpacity          Material[4].y
+
+#if MAT_TEXTURES > 0
+    // Texture unit sampler array
+    uniform sampler2D MatTexture[MAT_TEXTURES];
+    // Texture parameters (3*vec2 per texture)
+    uniform vec2 MatTexinfo[3*MAT_TEXTURES];
+    // Macros to access elements inside the MatTexinfo array
+    // Each texture uses 3 vec2 elements.
+    #define MatTexOffset(a)		MatTexinfo[(3*a)]
+    #define MatTexRepeat(a)		MatTexinfo[(3*a)+1]
+    #define MatTexFlipY(a)		bool(MatTexinfo[(3*a)+2].x)
+    #define MatTexVisible(a)	bool(MatTexinfo[(3*a)+2].y)
+#endif
+
+

+ 83 - 0
renderer/shaders/include/phong_model.glsl

@@ -0,0 +1,83 @@
+/***
+ phong lighting model
+ Parameters:
+    position:   input vertex position in camera coordinates
+    normal:     input vertex normal in camera coordinates
+    camDir:     input camera directions
+    matAmbient: input material ambient color
+    matDiffuse: input material diffuse color
+    ambdiff:    output ambient+diffuse color
+    spec:       output specular color
+ Uniforms:
+    AmbientLightColor[]
+    DiffuseLightColor[]
+    DiffuseLightPosition[]
+    PointLightColor[]
+    PointLightPosition[]
+    PointLightLinearDecay[]
+    PointLightQuadraticDecay[]
+    MatSpecularColor
+    MatShininess
+*****/
+void phongModel(vec4 position, vec3 normal, vec3 camDir, vec3 matAmbient, vec3 matDiffuse, out vec3 ambdiff, out vec3 spec) {
+
+    vec3 ambientTotal  = vec3(0.0);
+    vec3 diffuseTotal  = vec3(0.0);
+    vec3 specularTotal = vec3(0.0);
+
+#if AMB_LIGHTS>0
+    // Ambient lights
+    for (int i = 0; i < AMB_LIGHTS; i++) {
+        ambientTotal += AmbientLightColor[i] * matAmbient;
+    }
+#endif
+
+#if DIR_LIGHTS>0
+    // Directional lights
+    for (int i = 0; i < DIR_LIGHTS; i++) {
+        // Diffuse reflection
+        // DirLightPosition is the direction of the current light
+        vec3 lightDirection = normalize(DirLightPosition(i));
+        // Calculates the dot product between the light direction and this vertex normal.
+        float dotNormal = max(dot(lightDirection, normal), 0.0);
+        diffuseTotal += DirLightColor(i) * matDiffuse * dotNormal;
+        // Specular reflection
+        // Calculates the light reflection vector
+        vec3 ref = reflect(-lightDirection, normal);
+        if (dotNormal > 0.0) {
+            specularTotal += DirLightColor(i) * MatSpecularColor * pow(max(dot(ref, camDir), 0.0), MatShininess);
+        }
+    }
+#endif
+
+#if POINT_LIGHTS>0
+    // Point lights
+    for (int i = 0; i < POINT_LIGHTS; i++) {
+        // Common calculations
+        // Calculates the direction and distance from the current vertex to this point light.
+        vec3 lightDirection = PointLightPosition(i) - vec3(position);
+        float lightDistance = length(lightDirection);
+        // Normalizes the lightDirection
+        lightDirection = lightDirection / lightDistance;
+        // Calculates the attenuation due to the distance of the light
+        float attenuation = 1.0 / (1.0 + PointLightLinearDecay(i) * lightDistance +
+            PointLightQuadraticDecay(i) * lightDistance * lightDistance);
+        // Diffuse reflection
+        float dotNormal = max(dot(lightDirection, normal), 0.0);
+        diffuseTotal += PointLightColor(i) * matDiffuse * dotNormal * attenuation;
+        // Specular reflection
+        // Calculates the light reflection vector
+        vec3 ref = reflect(-lightDirection, normal);
+        if (dotNormal > 0.0) {
+            specularTotal += PointLightColor(i) * MatSpecularColor *
+                pow(max(dot(ref, camDir), 0.0), MatShininess) * attenuation;
+        }
+    }
+#endif
+
+    // Sets output colors
+    ambdiff = ambientTotal + MatEmissiveColor + diffuseTotal;
+    spec = specularTotal;
+}
+
+

+ 11 - 55
renderer/shader/shaderPanel.go

@@ -1,59 +1,16 @@
-// Copyright 2016 The G3N Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package shader
-
-func init() {
-	AddShader("shaderPanelVertex", shaderPanelVertex)
-	AddShader("shaderPanelFrag", shaderPanelFrag)
-	AddProgram("shaderPanel", "shaderPanelVertex", "shaderPanelFrag")
-}
-
-//
-// Vertex Shader template
-//
-const shaderPanelVertex = `
-#version {{.Version}}
-
-// Vertex attributes
-{{template "attributes" .}}
-
-// Input uniforms
-uniform mat4 ModelMatrix;
-
-// Outputs for fragment shader
-out vec2 FragTexcoord;
-
-
-void main() {
-
-    // Always flip texture coordinates
-    vec2 texcoord = VertexTexcoord;
-    texcoord.y = 1 - texcoord.y;
-    FragTexcoord = texcoord;
-
-    // Set position
-    vec4 pos = vec4(VertexPosition.xyz, 1);
-    gl_Position = ModelMatrix * pos;
-}
-`
-
 //
 // Fragment Shader template
 //
-const shaderPanelFrag = `
-#version {{.Version}}
 
-// Textures uniforms
+// Texture uniforms
 uniform sampler2D	MatTexture[1];
-uniform mat3		MatTexinfo[1];
+uniform vec2		MatTexinfo[3];
 
-// Macros to access elements inside MatTexinfo uniform
-#define MatTexOffset(a)		MatTexinfo[a][0].xy
-#define MatTexRepeat(a)		MatTexinfo[a][1].xy
-#define MatTexFlipY(a)		bool(MatTexinfo[a][2].x)
-#define MatTexVisible(a)	bool(MatTexinfo[a][2].y)
+// Macros to access elements inside the MatTexinfo array
+#define MatTexOffset		MatTexinfo[0]
+#define MatTexRepeat		MatTexinfo[1]
+#define MatTexFlipY	    	bool(MatTexinfo[2].x) // not used
+#define MatTexVisible	    bool(MatTexinfo[2].y) // not used
 
 // Inputs from vertex shader
 in vec2 FragTexcoord;
@@ -122,11 +79,11 @@ void main() {
             vec2 offset = vec2(-Content[0], -Content[1]);
             vec2 factor = vec2(1/Content[2], 1/Content[3]);
             vec2 texcoord = (FragTexcoord + offset) * factor;
-            color = texture(MatTexture[0], texcoord * MatTexRepeat(0) + MatTexOffset(0));
+            vec4 texColor = texture(MatTexture[0], texcoord * MatTexRepeat + MatTexOffset);
+            // Mix content color with texture color ???
+            //color = mix(color, texColor, texColor.a);
+            color = texColor;
 		}
-        if (color.a == 0) {
-            discard;
-        }
         FragColor = color;
         return;
     }
@@ -147,4 +104,3 @@ void main() {
     FragColor = vec4(1,1,1,0);
 }
 
-`

+ 24 - 0
renderer/shaders/panel_vertex.glsl

@@ -0,0 +1,24 @@
+//
+// Vertex shader panel
+//
+#include <attributes>
+
+// Model uniforms
+uniform mat4 ModelMatrix;
+
+// Outputs for fragment shader
+out vec2 FragTexcoord;
+
+
+void main() {
+
+    // Always flip texture coordinates
+    vec2 texcoord = VertexTexcoord;
+    texcoord.y = 1 - texcoord.y;
+    FragTexcoord = texcoord;
+
+    // Set position
+    vec4 pos = vec4(VertexPosition.xyz, 1);
+    gl_Position = ModelMatrix * pos;
+}
+

+ 53 - 0
renderer/shaders/phong_fragment.glsl

@@ -0,0 +1,53 @@
+//
+// Fragment Shader template
+//
+
+// Inputs from vertex shader
+in vec4 Position;       // Vertex position in camera coordinates.
+in vec3 Normal;         // Vertex normal in camera coordinates.
+in vec3 CamDir;         // Direction from vertex to camera
+in vec2 FragTexcoord;
+
+#include <lights>
+#include <material>
+#include <phong_model>
+
+// Final fragment color
+out vec4 FragColor;
+
+void main() {
+
+    // Combine all texture colors
+    vec4 texCombined = vec4(1);
+    #if MAT_TEXTURES>0
+    for (int i = 0; i < MAT_TEXTURES; i++) {
+        if (MatTexVisible(i) == false) {
+            continue;
+        }
+        vec4 texcolor = texture(MatTexture[i], FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));
+        if (i == 0) {
+            texCombined = texcolor;
+        } else {
+            texCombined = mix(texCombined, texcolor, texcolor.a);
+        }
+    }
+    #endif
+
+    // Combine material with texture colors
+    vec4 matDiffuse = vec4(MatDiffuseColor, MatOpacity) * texCombined;
+    vec4 matAmbient = vec4(MatAmbientColor, MatOpacity) * texCombined;
+
+    // Inverts the fragment normal if not FrontFacing
+    vec3 fragNormal = Normal;
+    if (!gl_FrontFacing) {
+        fragNormal = -fragNormal;
+    }
+
+    // Calculates the Ambient+Diffuse and Specular colors for this fragment using the Phong model.
+    vec3 Ambdiff, Spec;
+    phongModel(Position, fragNormal, CamDir, vec3(matAmbient), vec3(matDiffuse), Ambdiff, Spec);
+
+    // Final fragment color
+    FragColor = min(vec4(Ambdiff + Spec, matDiffuse.a), vec4(1.0));
+}
+

+ 42 - 0
renderer/shaders/phong_vertex.glsl

@@ -0,0 +1,42 @@
+//
+// Vertex Shader
+//
+#include <attributes>
+
+// Model uniforms
+uniform mat4 ModelViewMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 MVP;
+
+#include <material>
+
+// Output variables for Fragment shader
+out vec4 Position;
+out vec3 Normal;
+out vec3 CamDir;
+out vec2 FragTexcoord;
+
+void main() {
+
+    // Transform this vertex position to camera coordinates.
+    Position = ModelViewMatrix * vec4(VertexPosition, 1.0);
+
+    // Transform this vertex normal to camera coordinates.
+    Normal = normalize(NormalMatrix * VertexNormal);
+
+    // Calculate the direction vector from the vertex to the camera
+    // The camera is at 0,0,0
+    CamDir = normalize(-Position.xyz);
+
+    // Flips texture coordinate Y if requested.
+    vec2 texcoord = VertexTexcoord;
+#if MAT_TEXTURES>0
+    if (MatTexFlipY(0)) {
+        texcoord.y = 1 - texcoord.y;
+    }
+#endif
+    FragTexcoord = texcoord;
+
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
+}
+

+ 114 - 0
renderer/shaders/shaders.go

@@ -0,0 +1,114 @@
+// Copyright 2016 The G3N Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package shader contains the several shaders used by the engine
+package shaders
+
+// Generates shaders sources from this directory and include directory *.glsl files
+//go:generate g3nshaders -in=. -out=sources.go -pkg=shaders
+
+// ProgramInfo contains information for a registered shader program
+type ProgramInfo struct {
+	Vertex   string // Vertex shader name
+	Fragment string // Fragment shader name
+	Geometry string // Geometry shader name (maybe an empty string)
+}
+
+// AddInclude adds a chunk of shader code to the default shaders registry
+// which can be included in a shader using the "#include <name>" directive
+func AddInclude(name string, source string) {
+
+	if len(name) == 0 || len(source) == 0 {
+		panic("Invalid include name and/or source")
+	}
+	includeMap[name] = source
+}
+
+// AddShaders add a shader to default shaders registry.
+// The specified name can be used when adding programs to the registry
+func AddShader(name string, source string) {
+
+	if len(name) == 0 || len(source) == 0 {
+		panic("Invalid shader name and/or source")
+	}
+	shaderMap[name] = source
+}
+
+// AddProgram adds a shader program to the default registry of programs.
+// Currently up to 3 shaders: vertex, fragment and geometry (optional) can be specified.
+func AddProgram(name string, vertex string, frag string, others ...string) {
+
+	if len(name) == 0 || len(vertex) == 0 || len(frag) == 0 {
+		panic("Program and/or shader name empty")
+	}
+	if shaderMap[vertex] == "" {
+		panic("Invalid vertex shader name")
+	}
+	if shaderMap[frag] == "" {
+		panic("Invalid vertex shader name")
+	}
+	var geom = ""
+	if len(others) > 0 {
+		geom = others[0]
+		if shaderMap[geom] == "" {
+			panic("Invalid geometry shader name")
+		}
+	}
+	programMap[name] = ProgramInfo{
+		Vertex:   vertex,
+		Fragment: frag,
+		Geometry: geom,
+	}
+}
+
+// Includes returns list with the names of all include chunks currently in the default shaders registry.
+func Includes() []string {
+
+	list := make([]string, 0)
+	for name, _ := range includeMap {
+		list = append(list, name)
+	}
+	return list
+}
+
+// GetInclude returns the source code of the specified shader include chunk.
+// If the name is not found an empty string is returned
+func IncludeSource(name string) string {
+
+	return includeMap[name]
+}
+
+// Shaders returns list with the names of all shaders currently in the default shaders registry.
+func Shaders() []string {
+
+	list := make([]string, 0)
+	for name, _ := range shaderMap {
+		list = append(list, name)
+	}
+	return list
+}
+
+// ShaderSource returns the source code of the specified shader in the default shaders registry.
+// If the name is not found an empty string is returned
+func ShaderSource(name string) string {
+
+	return shaderMap[name]
+}
+
+// Programs returns list with the names of all programs currently in the default shaders registry.
+func Programs() []string {
+
+	list := make([]string, 0)
+	for name, _ := range programMap {
+		list = append(list, name)
+	}
+	return list
+}
+
+// GetProgram returns ProgramInfo struct for the specified program name
+// in the default shaders registry
+func GetProgramInfo(name string) ProgramInfo {
+
+	return programMap[name]
+}

+ 635 - 0
renderer/shaders/sources.go

@@ -0,0 +1,635 @@
+// File generated by G3NSHADERS. Do not edit.
+// To regenerate this file install 'g3nshaders' and execute:
+// 'go generate' in this folder.
+package shaders
+
+const include_phong_model_source = `/***
+ phong lighting model
+ Parameters:
+    position:   input vertex position in camera coordinates
+    normal:     input vertex normal in camera coordinates
+    camDir:     input camera directions
+    matAmbient: input material ambient color
+    matDiffuse: input material diffuse color
+    ambdiff:    output ambient+diffuse color
+    spec:       output specular color
+ Uniforms:
+    AmbientLightColor[]
+    DiffuseLightColor[]
+    DiffuseLightPosition[]
+    PointLightColor[]
+    PointLightPosition[]
+    PointLightLinearDecay[]
+    PointLightQuadraticDecay[]
+    MatSpecularColor
+    MatShininess
+*****/
+void phongModel(vec4 position, vec3 normal, vec3 camDir, vec3 matAmbient, vec3 matDiffuse, out vec3 ambdiff, out vec3 spec) {
+
+    vec3 ambientTotal  = vec3(0.0);
+    vec3 diffuseTotal  = vec3(0.0);
+    vec3 specularTotal = vec3(0.0);
+
+#if AMB_LIGHTS>0
+    // Ambient lights
+    for (int i = 0; i < AMB_LIGHTS; i++) {
+        ambientTotal += AmbientLightColor[i] * matAmbient;
+    }
+#endif
+
+#if DIR_LIGHTS>0
+    // Directional lights
+    for (int i = 0; i < DIR_LIGHTS; i++) {
+        // Diffuse reflection
+        // DirLightPosition is the direction of the current light
+        vec3 lightDirection = normalize(DirLightPosition(i));
+        // Calculates the dot product between the light direction and this vertex normal.
+        float dotNormal = max(dot(lightDirection, normal), 0.0);
+        diffuseTotal += DirLightColor(i) * matDiffuse * dotNormal;
+        // Specular reflection
+        // Calculates the light reflection vector
+        vec3 ref = reflect(-lightDirection, normal);
+        if (dotNormal > 0.0) {
+            specularTotal += DirLightColor(i) * MatSpecularColor * pow(max(dot(ref, camDir), 0.0), MatShininess);
+        }
+    }
+#endif
+
+#if POINT_LIGHTS>0
+    // Point lights
+    for (int i = 0; i < POINT_LIGHTS; i++) {
+        // Common calculations
+        // Calculates the direction and distance from the current vertex to this point light.
+        vec3 lightDirection = PointLightPosition(i) - vec3(position);
+        float lightDistance = length(lightDirection);
+        // Normalizes the lightDirection
+        lightDirection = lightDirection / lightDistance;
+        // Calculates the attenuation due to the distance of the light
+        float attenuation = 1.0 / (1.0 + PointLightLinearDecay(i) * lightDistance +
+            PointLightQuadraticDecay(i) * lightDistance * lightDistance);
+        // Diffuse reflection
+        float dotNormal = max(dot(lightDirection, normal), 0.0);
+        diffuseTotal += PointLightColor(i) * matDiffuse * dotNormal * attenuation;
+        // Specular reflection
+        // Calculates the light reflection vector
+        vec3 ref = reflect(-lightDirection, normal);
+        if (dotNormal > 0.0) {
+            specularTotal += PointLightColor(i) * MatSpecularColor *
+                pow(max(dot(ref, camDir), 0.0), MatShininess) * attenuation;
+        }
+    }
+#endif
+
+    // Sets output colors
+    ambdiff = ambientTotal + MatEmissiveColor + diffuseTotal;
+    spec = specularTotal;
+}
+
+
+`
+
+const include_material_source = `//
+// Material properties uniform
+//
+uniform vec3 Material[5];
+// Macros to access elements inside the MatTexinfo array
+// Each texture uses 3 vec2 elements.
+#define MatAmbientColor		Material[0]
+#define MatDiffuseColor     Material[1]
+#define MatEmissiveColor    Material[2]
+#define MatSpecularColor    Material[3]
+#define MatShininess        Material[4].x
+#define MatOpacity          Material[4].y
+
+#if MAT_TEXTURES > 0
+    // Texture unit sampler array
+    uniform sampler2D MatTexture[MAT_TEXTURES];
+    // Texture parameters (3*vec2 per texture)
+    uniform vec2 MatTexinfo[3*MAT_TEXTURES];
+    // Macros to access elements inside the MatTexinfo array
+    // Each texture uses 3 vec2 elements.
+    #define MatTexOffset(a)		MatTexinfo[(3*a)]
+    #define MatTexRepeat(a)		MatTexinfo[(3*a)+1]
+    #define MatTexFlipY(a)		bool(MatTexinfo[(3*a)+2].x)
+    #define MatTexVisible(a)	bool(MatTexinfo[(3*a)+2].y)
+#endif
+
+
+`
+
+const include_lights_source = `//
+// Lights uniforms
+//
+
+// Ambient lights uniforms
+#if AMB_LIGHTS>0
+uniform vec3 AmbientLightColor[AMB_LIGHTS];
+#endif
+
+// Directional lights uniform array. Each directional light uses 2 elements
+#if DIR_LIGHTS>0
+uniform vec3 DirLight[2*DIR_LIGHTS];
+// Macros to access elements inside the DirectionalLight uniform array
+#define DirLightColor(a)		DirLight[2*a]
+#define DirLightPosition(a)		DirLight[2*a+1]
+#endif
+
+// Point lights uniform array. Each point light uses 3 elements
+#if POINT_LIGHTS>0
+uniform vec3 PointLight[3*POINT_LIGHTS];
+// Macros to access elements inside the PointLight uniform array
+#define PointLightColor(a)			PointLight[3*a]
+#define PointLightPosition(a)		PointLight[3*a+1]
+#define PointLightLinearDecay(a)	PointLight[3*a+2].x
+#define PointLightQuadraticDecay(a)	PointLight[3*a+2].y
+#endif
+
+
+`
+
+const include_attributes_source = `//
+// Vertex attributes
+//
+layout(location = 0) in  vec3  VertexPosition;
+layout(location = 1) in  vec3  VertexNormal;
+layout(location = 2) in  vec3  VertexColor;
+layout(location = 3) in  vec2  VertexTexcoord;
+layout(location = 4) in  float VertexDistance;
+layout(location = 5) in  vec4  VertexTexoffsets;
+
+
+`
+
+const basic_fragment_source = `//
+// Fragment Shader template
+//
+
+in vec3 Color;
+out vec4 FragColor;
+
+void main() {
+
+    FragColor = vec4(Color, 1.0);
+}
+
+`
+
+const standard_fragment_source = `//
+// Fragment Shader template
+//
+#include <material>
+
+// Inputs from Vertex shader
+in vec3 ColorFrontAmbdiff;
+in vec3 ColorFrontSpec;
+in vec3 ColorBackAmbdiff;
+in vec3 ColorBackSpec;
+in vec2 FragTexcoord;
+
+// Output
+out vec4 FragColor;
+
+
+void main() {
+
+    vec4 texCombined = vec4(1);
+    #if MAT_TEXTURES > 0
+    // Combine all texture colors and opacity
+    for (int i = 0; i < MAT_TEXTURES; i++) {
+        if (MatTexVisible(i) == false) {
+            continue;
+        }
+        vec4 texcolor = texture(MatTexture[i], FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));
+        if (i == 0) {
+            texCombined = texcolor;
+        } else {
+            texCombined = mix(texCombined, texcolor, texcolor.a);
+        }
+    }
+    #endif
+
+    vec4 colorAmbDiff;
+    vec4 colorSpec;
+    if (gl_FrontFacing) {
+        colorAmbDiff = vec4(ColorFrontAmbdiff, MatOpacity);
+        colorSpec = vec4(ColorFrontSpec, 0);
+    } else {
+        colorAmbDiff = vec4(ColorBackAmbdiff, MatOpacity);
+        colorSpec = vec4(ColorBackSpec, 0);
+    }
+    FragColor = min(colorAmbDiff * texCombined + colorSpec, vec4(1));
+}
+
+
+
+
+`
+
+const panel_vertex_source = `//
+// Vertex shader panel
+//
+#include <attributes>
+
+// Model uniforms
+uniform mat4 ModelMatrix;
+
+// Outputs for fragment shader
+out vec2 FragTexcoord;
+
+
+void main() {
+
+    // Always flip texture coordinates
+    vec2 texcoord = VertexTexcoord;
+    texcoord.y = 1 - texcoord.y;
+    FragTexcoord = texcoord;
+
+    // Set position
+    vec4 pos = vec4(VertexPosition.xyz, 1);
+    gl_Position = ModelMatrix * pos;
+}
+
+`
+
+const sprite_fragment_source = `//
+// Fragment shader for sprite
+//
+
+#include <material>
+
+// Inputs from vertex shader
+in vec3 Color;
+in vec2 FragTexcoord;
+
+// Output
+out vec4 FragColor;
+
+void main() {
+
+    // Combine all texture colors and opacity
+    vec4 texCombined = vec4(1);
+#if MAT_TEXTURES>0
+    for (int i = 0; i < {{.MatTexturesMax}}; i++) {
+        vec4 texcolor = texture(MatTexture[i], FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));
+        if (i == 0) {
+            texCombined = texcolor;
+        } else {
+            texCombined = mix(texCombined, texcolor, texcolor.a);
+        }
+    }
+#endif
+
+    // Combine material color with texture
+    FragColor = min(vec4(Color, MatOpacity) * texCombined, vec4(1));
+}
+
+`
+
+const phong_vertex_source = `//
+// Vertex Shader
+//
+#include <attributes>
+
+// Model uniforms
+uniform mat4 ModelViewMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 MVP;
+
+#include <material>
+
+// Output variables for Fragment shader
+out vec4 Position;
+out vec3 Normal;
+out vec3 CamDir;
+out vec2 FragTexcoord;
+
+void main() {
+
+    // Transform this vertex position to camera coordinates.
+    Position = ModelViewMatrix * vec4(VertexPosition, 1.0);
+
+    // Transform this vertex normal to camera coordinates.
+    Normal = normalize(NormalMatrix * VertexNormal);
+
+    // Calculate the direction vector from the vertex to the camera
+    // The camera is at 0,0,0
+    CamDir = normalize(-Position.xyz);
+
+    // Flips texture coordinate Y if requested.
+    vec2 texcoord = VertexTexcoord;
+#if MAT_TEXTURES>0
+    if (MatTexFlipY(0)) {
+        texcoord.y = 1 - texcoord.y;
+    }
+#endif
+    FragTexcoord = texcoord;
+
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
+}
+
+`
+
+const panel_fragment_source = `//
+// Fragment Shader template
+//
+
+// Texture uniforms
+uniform sampler2D	MatTexture[1];
+uniform vec2		MatTexinfo[3];
+
+// Macros to access elements inside the MatTexinfo array
+#define MatTexOffset		MatTexinfo[0]
+#define MatTexRepeat		MatTexinfo[1]
+#define MatTexFlipY	    	bool(MatTexinfo[2].x) // not used
+#define MatTexVisible	    bool(MatTexinfo[2].y) // not used
+
+// Inputs from vertex shader
+in vec2 FragTexcoord;
+
+// Input uniform
+uniform vec4 Panel[8];
+#define Bounds			Panel[0]		  // panel bounds in texture coordinates
+#define Border			Panel[1]		  // panel border in texture coordinates
+#define Padding			Panel[2]		  // panel padding in texture coordinates
+#define Content			Panel[3]		  // panel content area in texture coordinates
+#define BorderColor		Panel[4]		  // panel border color
+#define PaddingColor	Panel[5]		  // panel padding color
+#define ContentColor	Panel[6]		  // panel content color
+#define TextureValid	bool(Panel[7].x)  // texture valid flag
+
+// Output
+out vec4 FragColor;
+
+
+/***
+* Checks if current fragment texture coordinate is inside the
+* supplied rectangle in texture coordinates:
+* rect[0] - position x [0,1]
+* rect[1] - position y [0,1]
+* rect[2] - width [0,1]
+* rect[3] - height [0,1]
+*/
+bool checkRect(vec4 rect) {
+
+    if (FragTexcoord.x < rect[0]) {
+        return false;
+    }
+    if (FragTexcoord.x > rect[0] + rect[2]) {
+        return false;
+    }
+    if (FragTexcoord.y < rect[1]) {
+        return false;
+    }
+    if (FragTexcoord.y > rect[1] + rect[3]) {
+        return false;
+    }
+    return true;
+}
+
+
+void main() {
+
+    // Discard fragment outside of received bounds
+    // Bounds[0] - xmin
+    // Bounds[1] - ymin
+    // Bounds[2] - xmax
+    // Bounds[3] - ymax
+    if (FragTexcoord.x <= Bounds[0] || FragTexcoord.x >= Bounds[2]) {
+        discard;
+    }
+    if (FragTexcoord.y <= Bounds[1] || FragTexcoord.y >= Bounds[3]) {
+        discard;
+    }
+
+    // Check if fragment is inside content area
+    if (checkRect(Content)) {
+        // If no texture, the color will be the material color.
+        vec4 color = ContentColor;
+		if (TextureValid) {
+            // Adjust texture coordinates to fit texture inside the content area
+            vec2 offset = vec2(-Content[0], -Content[1]);
+            vec2 factor = vec2(1/Content[2], 1/Content[3]);
+            vec2 texcoord = (FragTexcoord + offset) * factor;
+            vec4 texColor = texture(MatTexture[0], texcoord * MatTexRepeat + MatTexOffset);
+            // Mix content color with texture color ???
+            //color = mix(color, texColor, texColor.a);
+            color = texColor;
+		}
+        FragColor = color;
+        return;
+    }
+
+    // Checks if fragment is inside paddings area
+    if (checkRect(Padding)) {
+        FragColor = PaddingColor;
+        return;
+    }
+
+    // Checks if fragment is inside borders area
+    if (checkRect(Border)) {
+        FragColor = BorderColor;
+        return;
+    }
+
+    // Fragment is in margins area (always transparent)
+    FragColor = vec4(1,1,1,0);
+}
+
+`
+
+const phong_fragment_source = `//
+// Fragment Shader template
+//
+
+// Inputs from vertex shader
+in vec4 Position;       // Vertex position in camera coordinates.
+in vec3 Normal;         // Vertex normal in camera coordinates.
+in vec3 CamDir;         // Direction from vertex to camera
+in vec2 FragTexcoord;
+
+#include <lights>
+#include <material>
+#include <phong_model>
+
+// Final fragment color
+out vec4 FragColor;
+
+void main() {
+
+    // Combine all texture colors
+    vec4 texCombined = vec4(1);
+    #if MAT_TEXTURES>0
+    for (int i = 0; i < MAT_TEXTURES; i++) {
+        if (MatTexVisible(i) == false) {
+            continue;
+        }
+        vec4 texcolor = texture(MatTexture[i], FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));
+        if (i == 0) {
+            texCombined = texcolor;
+        } else {
+            texCombined = mix(texCombined, texcolor, texcolor.a);
+        }
+    }
+    #endif
+
+    // Combine material with texture colors
+    vec4 matDiffuse = vec4(MatDiffuseColor, MatOpacity) * texCombined;
+    vec4 matAmbient = vec4(MatAmbientColor, MatOpacity) * texCombined;
+
+    // Inverts the fragment normal if not FrontFacing
+    vec3 fragNormal = Normal;
+    if (!gl_FrontFacing) {
+        fragNormal = -fragNormal;
+    }
+
+    // Calculates the Ambient+Diffuse and Specular colors for this fragment using the Phong model.
+    vec3 Ambdiff, Spec;
+    phongModel(Position, fragNormal, CamDir, vec3(matAmbient), vec3(matDiffuse), Ambdiff, Spec);
+
+    // Final fragment color
+    FragColor = min(vec4(Ambdiff + Spec, matDiffuse.a), vec4(1.0));
+}
+
+`
+
+const sprite_vertex_source = `//
+// Vertex shader for sprites
+//
+
+#include <attributes>
+
+// Input uniforms
+uniform mat4 MVP;
+
+#include <material>
+
+// Outputs for fragment shader
+out vec3 Color;
+out vec2 FragTexcoord;
+
+void main() {
+
+    // Applies transformation to vertex position
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
+
+    // Outputs color
+    Color = MatDiffuseColor;
+
+    // Flips texture coordinate Y if requested.
+    vec2 texcoord = VertexTexcoord;
+#if MAT_TEXTURES>0
+    if (MatTexFlipY[0]) {
+        texcoord.y = 1 - texcoord.y;
+    }
+#endif
+    FragTexcoord = texcoord;
+}
+
+`
+
+const standard_vertex_source = `//
+// Vertex shader standard
+//
+#include <attributes>
+
+// Model uniforms
+uniform mat4 ModelViewMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 MVP;
+
+#include <lights>
+#include <material>
+#include <phong_model>
+
+
+// Outputs for the fragment shader.
+out vec3 ColorFrontAmbdiff;
+out vec3 ColorFrontSpec;
+out vec3 ColorBackAmbdiff;
+out vec3 ColorBackSpec;
+out vec2 FragTexcoord;
+
+void main() {
+
+    // Transform this vertex normal to camera coordinates.
+    vec3 normal = normalize(NormalMatrix * VertexNormal);
+
+    // Calculate this vertex position in camera coordinates
+    vec4 position = ModelViewMatrix * vec4(VertexPosition, 1.0);
+
+    // Calculate the direction vector from the vertex to the camera
+    // The camera is at 0,0,0
+    vec3 camDir = normalize(-position.xyz);
+
+    // Calculates the vertex Ambient+Diffuse and Specular colors using the Phong model
+    // for the front and back
+    phongModel(position,  normal, camDir, MatAmbientColor, MatDiffuseColor, ColorFrontAmbdiff, ColorFrontSpec);
+    phongModel(position, -normal, camDir, MatAmbientColor, MatDiffuseColor, ColorBackAmbdiff, ColorBackSpec);
+
+    vec2 texcoord = VertexTexcoord;
+#if MAT_TEXTURES > 0
+    // Flips texture coordinate Y if requested.
+    if (MatTexFlipY(0)) {
+        texcoord.y = 1 - texcoord.y;
+    }
+#endif
+    FragTexcoord = texcoord;
+
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
+}
+
+`
+
+const basic_vertex_source = `//
+// Vertex shader basic
+//
+#include <attributes>
+
+// Model uniforms
+uniform mat4 MVP;
+
+// Final output color for fragment shader
+out vec3 Color;
+
+void main() {
+
+    Color = VertexColor;
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
+}
+
+
+`
+
+// Maps include name with its source code
+var includeMap = map[string]string{
+
+	"phong_model": include_phong_model_source,
+	"material":    include_material_source,
+	"lights":      include_lights_source,
+	"attributes":  include_attributes_source,
+}
+
+// Maps shader name with its source code
+var shaderMap = map[string]string{
+
+	"basic_fragment":    basic_fragment_source,
+	"standard_fragment": standard_fragment_source,
+	"panel_vertex":      panel_vertex_source,
+	"sprite_fragment":   sprite_fragment_source,
+	"phong_vertex":      phong_vertex_source,
+	"panel_fragment":    panel_fragment_source,
+	"phong_fragment":    phong_fragment_source,
+	"sprite_vertex":     sprite_vertex_source,
+	"standard_vertex":   standard_vertex_source,
+	"basic_vertex":      basic_vertex_source,
+}
+
+// Maps program name with Proginfo struct with shaders names
+var programMap = map[string]ProgramInfo{
+
+	"basic":    {"basic_vertex", "basic_fragment", ""},
+	"panel":    {"panel_vertex", "panel_fragment", ""},
+	"phong":    {"phong_vertex", "phong_fragment", ""},
+	"sprite":   {"sprite_vertex", "sprite_fragment", ""},
+	"standard": {"standard_vertex", "standard_fragment", ""},
+}

+ 32 - 0
renderer/shaders/sprite_fragment.glsl

@@ -0,0 +1,32 @@
+//
+// Fragment shader for sprite
+//
+
+#include <material>
+
+// Inputs from vertex shader
+in vec3 Color;
+in vec2 FragTexcoord;
+
+// Output
+out vec4 FragColor;
+
+void main() {
+
+    // Combine all texture colors and opacity
+    vec4 texCombined = vec4(1);
+#if MAT_TEXTURES>0
+    for (int i = 0; i < {{.MatTexturesMax}}; i++) {
+        vec4 texcolor = texture(MatTexture[i], FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));
+        if (i == 0) {
+            texCombined = texcolor;
+        } else {
+            texCombined = mix(texCombined, texcolor, texcolor.a);
+        }
+    }
+#endif
+
+    // Combine material color with texture
+    FragColor = min(vec4(Color, MatOpacity) * texCombined, vec4(1));
+}
+

+ 33 - 0
renderer/shaders/sprite_vertex.glsl

@@ -0,0 +1,33 @@
+//
+// Vertex shader for sprites
+//
+
+#include <attributes>
+
+// Input uniforms
+uniform mat4 MVP;
+
+#include <material>
+
+// Outputs for fragment shader
+out vec3 Color;
+out vec2 FragTexcoord;
+
+void main() {
+
+    // Applies transformation to vertex position
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
+
+    // Outputs color
+    Color = MatDiffuseColor;
+
+    // Flips texture coordinate Y if requested.
+    vec2 texcoord = VertexTexcoord;
+#if MAT_TEXTURES>0
+    if (MatTexFlipY[0]) {
+        texcoord.y = 1 - texcoord.y;
+    }
+#endif
+    FragTexcoord = texcoord;
+}
+

+ 49 - 0
renderer/shaders/standard_fragment.glsl

@@ -0,0 +1,49 @@
+//
+// Fragment Shader template
+//
+#include <material>
+
+// Inputs from Vertex shader
+in vec3 ColorFrontAmbdiff;
+in vec3 ColorFrontSpec;
+in vec3 ColorBackAmbdiff;
+in vec3 ColorBackSpec;
+in vec2 FragTexcoord;
+
+// Output
+out vec4 FragColor;
+
+
+void main() {
+
+    vec4 texCombined = vec4(1);
+    #if MAT_TEXTURES > 0
+    // Combine all texture colors and opacity
+    for (int i = 0; i < MAT_TEXTURES; i++) {
+        if (MatTexVisible(i) == false) {
+            continue;
+        }
+        vec4 texcolor = texture(MatTexture[i], FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));
+        if (i == 0) {
+            texCombined = texcolor;
+        } else {
+            texCombined = mix(texCombined, texcolor, texcolor.a);
+        }
+    }
+    #endif
+
+    vec4 colorAmbDiff;
+    vec4 colorSpec;
+    if (gl_FrontFacing) {
+        colorAmbDiff = vec4(ColorFrontAmbdiff, MatOpacity);
+        colorSpec = vec4(ColorFrontSpec, 0);
+    } else {
+        colorAmbDiff = vec4(ColorBackAmbdiff, MatOpacity);
+        colorSpec = vec4(ColorBackSpec, 0);
+    }
+    FragColor = min(colorAmbDiff * texCombined + colorSpec, vec4(1));
+}
+
+
+
+

+ 51 - 0
renderer/shaders/standard_vertex.glsl

@@ -0,0 +1,51 @@
+//
+// Vertex shader standard
+//
+#include <attributes>
+
+// Model uniforms
+uniform mat4 ModelViewMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 MVP;
+
+#include <lights>
+#include <material>
+#include <phong_model>
+
+
+// Outputs for the fragment shader.
+out vec3 ColorFrontAmbdiff;
+out vec3 ColorFrontSpec;
+out vec3 ColorBackAmbdiff;
+out vec3 ColorBackSpec;
+out vec2 FragTexcoord;
+
+void main() {
+
+    // Transform this vertex normal to camera coordinates.
+    vec3 normal = normalize(NormalMatrix * VertexNormal);
+
+    // Calculate this vertex position in camera coordinates
+    vec4 position = ModelViewMatrix * vec4(VertexPosition, 1.0);
+
+    // Calculate the direction vector from the vertex to the camera
+    // The camera is at 0,0,0
+    vec3 camDir = normalize(-position.xyz);
+
+    // Calculates the vertex Ambient+Diffuse and Specular colors using the Phong model
+    // for the front and back
+    phongModel(position,  normal, camDir, MatAmbientColor, MatDiffuseColor, ColorFrontAmbdiff, ColorFrontSpec);
+    phongModel(position, -normal, camDir, MatAmbientColor, MatDiffuseColor, ColorBackAmbdiff, ColorBackSpec);
+
+    vec2 texcoord = VertexTexcoord;
+#if MAT_TEXTURES > 0
+    // Flips texture coordinate Y if requested.
+    if (MatTexFlipY(0)) {
+        texcoord.y = 1 - texcoord.y;
+    }
+#endif
+    FragTexcoord = texcoord;
+
+    gl_Position = MVP * vec4(VertexPosition, 1.0);
+}
+

+ 119 - 122
renderer/shaman.go

@@ -5,15 +5,25 @@
 package renderer
 
 import (
-	"bytes"
 	"fmt"
-	"text/template"
+	"regexp"
+	"strconv"
+	"strings"
 
 	"github.com/g3n/engine/gls"
 	"github.com/g3n/engine/material"
-	"github.com/g3n/engine/renderer/shader"
+	"github.com/g3n/engine/renderer/shaders"
 )
 
+// Regular expression to parse #include <name> directive
+var rexInclude *regexp.Regexp
+
+func init() {
+
+	rexInclude = regexp.MustCompile(`#include\s+<(.*)>`)
+}
+
+// ShaderSpecs describes the specification of a compiled shader program
 type ShaderSpecs struct {
 	Name             string             // Shader name
 	Version          string             // GLSL version
@@ -33,11 +43,11 @@ type ProgSpecs struct {
 
 type Shaman struct {
 	gs       *gls.GLS
-	chunks   *template.Template            // template with all chunks
-	shaders  map[string]*template.Template // maps shader name to its template
-	proginfo map[string]shader.ProgramInfo // maps name of the program to ProgramInfo
-	programs []ProgSpecs                   // list of compiled programs with specs
-	specs    ShaderSpecs                   // Current shader specs
+	includes map[string]string              // include files sources
+	shadersm map[string]string              // maps shader name to its template
+	proginfo map[string]shaders.ProgramInfo // maps name of the program to ProgramInfo
+	programs []ProgSpecs                    // list of compiled programs with specs
+	specs    ShaderSpecs                    // Current shader specs
 }
 
 // NewShaman creates and returns a pointer to a new shader manager
@@ -52,116 +62,54 @@ func NewShaman(gs *gls.GLS) *Shaman {
 func (sm *Shaman) Init(gs *gls.GLS) {
 
 	sm.gs = gs
-	sm.chunks = template.New("_chunks_")
-	sm.shaders = make(map[string]*template.Template)
-	sm.proginfo = make(map[string]shader.ProgramInfo)
-
-	// Add "loop" function to chunks template
-	// "loop" is used inside the shader templates to unroll loops.
-	sm.chunks.Funcs(template.FuncMap{
-		"loop": func(n int) []int {
-			s := make([]int, n)
-			for i := range s {
-				s[i] = i
-			}
-			return s
-		},
-	})
+	sm.includes = make(map[string]string)
+	sm.shadersm = make(map[string]string)
+	sm.proginfo = make(map[string]shaders.ProgramInfo)
 }
 
-// AddDefaultShaders adds to the shader manager all default
-// shaders statically registered.
+// AddDefaultShaders adds to this shader manager all default
+// include chunks, shaders and programs statically registered.
 func (sm *Shaman) AddDefaultShaders() error {
 
-	for name, source := range shader.Chunks() {
-		err := sm.AddChunk(name, source)
-		if err != nil {
-			return err
-		}
+	for _, name := range shaders.Includes() {
+		sm.AddChunk(name, shaders.IncludeSource(name))
 	}
 
-	for name, source := range shader.Shaders() {
-		err := sm.AddShader(name, source)
-		if err != nil {
-			return err
-		}
+	for _, name := range shaders.Shaders() {
+		sm.AddShader(name, shaders.ShaderSource(name))
 	}
 
-	for name, pinfo := range shader.Programs() {
-		sm.proginfo[name] = pinfo
+	for _, name := range shaders.Programs() {
+		sm.proginfo[name] = shaders.GetProgramInfo(name)
 	}
 	return nil
 }
 
 // AddChunk adds a shader chunk with the specified name and source code
-func (sm *Shaman) AddChunk(name, source string) error {
+func (sm *Shaman) AddChunk(name, source string) {
 
-	tmpl := sm.chunks.New(name)
-	_, err := tmpl.Parse(source)
-	if err != nil {
-		return err
-	}
-	return nil
+	sm.includes[name] = source
 }
 
 // AddShader adds a shader program with the specified name and source code
-func (sm *Shaman) AddShader(name, source string) error {
+func (sm *Shaman) AddShader(name, source string) {
 
-	// Clone chunks template so any shader can use
-	// any of the chunks
-	tmpl, err := sm.chunks.Clone()
-	if err != nil {
-		return err
-	}
-	// Parses this shader template source
-	_, err = tmpl.Parse(source)
-	if err != nil {
-		return err
-	}
-
-	sm.shaders[name] = tmpl
-	return nil
+	sm.shadersm[name] = source
 }
 
 // AddProgram adds a program with the specified name and associated vertex
 // and fragment shaders names (previously registered)
-// To specify other types of shaders for a program use SetProgramShader()
-func (sm *Shaman) AddProgram(name, vertexName, fragName string) error {
+func (sm *Shaman) AddProgram(name, vertexName, fragName string, others ...string) {
 
-	sm.proginfo[name] = shader.ProgramInfo{Vertex: vertexName, Frag: fragName}
-	return nil
-}
-
-// SetProgramShader sets the shader type and name for a previously specified program name.
-// Returns error if the specified program or shader name not found or
-// if an invalid shader type was specified.
-func (sm *Shaman) SetProgramShader(pname string, stype int, sname string) error {
-
-	// Checks if program name is valid
-	pinfo, ok := sm.proginfo[pname]
-	if !ok {
-		return fmt.Errorf("Program name:%s not found", pname)
+	geomName := ""
+	if len(others) > 0 {
+		geomName = others[0]
 	}
-
-	// Checks if shader name is valid
-	_, ok = sm.shaders[sname]
-	if !ok {
-		return fmt.Errorf("Shader name:%s not found", sname)
-	}
-
-	// Sets the program shader name for the specified type
-	switch stype {
-	case gls.VERTEX_SHADER:
-		pinfo.Vertex = sname
-	case gls.FRAGMENT_SHADER:
-		pinfo.Frag = sname
-	case gls.GEOMETRY_SHADER:
-		pinfo.Geometry = sname
-	default:
-		return fmt.Errorf("Invalid shader type")
+	sm.proginfo[name] = shaders.ProgramInfo{
+		Vertex:   vertexName,
+		Fragment: fragName,
+		Geometry: geomName,
 	}
-	sm.proginfo[pname] = pinfo
-	return nil
 }
 
 // SetProgram set the shader program to satisfy the specified specs.
@@ -207,8 +155,7 @@ func (sm *Shaman) SetProgram(s *ShaderSpecs) (bool, error) {
 	}
 	log.Debug("Created new shader:%v", specs.Name)
 
-	// Save specs as current specs, adds new program to the list
-	// and actives program
+	// Save specs as current specs, adds new program to the list and activates the program
 	sm.specs = specs
 	sm.programs = append(sm.programs, ProgSpecs{prog, specs})
 	sm.gs.UseProgram(prog)
@@ -224,54 +171,60 @@ func (sm *Shaman) GenProgram(specs *ShaderSpecs) (*gls.Program, error) {
 		return nil, fmt.Errorf("Program:%s not found", specs.Name)
 	}
 
-	// Sets the GLSL version string
-	specs.Version = "330 core"
-
-	// Get vertex shader compiled template
-	vtempl, ok := sm.shaders[progInfo.Vertex]
+	// Sets the defines map
+	defines := map[string]string{}
+	defines["GLSL_VERSION"] = "330 core"
+	defines["AMB_LIGHTS"] = strconv.FormatUint(uint64(specs.AmbientLightsMax), 10)
+	defines["DIR_LIGHTS"] = strconv.FormatUint(uint64(specs.DirLightsMax), 10)
+	defines["POINT_LIGHTS"] = strconv.FormatUint(uint64(specs.PointLightsMax), 10)
+	defines["SPOT_LIGHTS"] = strconv.FormatUint(uint64(specs.SpotLightsMax), 10)
+	defines["MAT_TEXTURES"] = strconv.FormatUint(uint64(specs.MatTexturesMax), 10)
+
+	// Get vertex shader source
+	vertexSource, ok := sm.shadersm[progInfo.Vertex]
 	if !ok {
-		return nil, fmt.Errorf("Vertex shader:%s template not found", progInfo.Vertex)
+		return nil, fmt.Errorf("Vertex shader:%s not found", progInfo.Vertex)
 	}
-	// Generates vertex shader source from template
-	var sourceVertex bytes.Buffer
-	err := vtempl.Execute(&sourceVertex, specs)
-	if err != nil {
+	// Preprocess vertex shader source
+	vertexSource, err := sm.preprocess(vertexSource, defines)
+	if !ok {
 		return nil, err
 	}
+	fmt.Printf("vertexSource:%s\n", vertexSource)
 
-	// Get fragment shader compiled template
-	fragTempl, ok := sm.shaders[progInfo.Frag]
+	// Get fragment shader source
+	fragSource, ok := sm.shadersm[progInfo.Fragment]
 	if !ok {
-		return nil, fmt.Errorf("Fragment shader:%s template not found", progInfo.Frag)
+		return nil, fmt.Errorf("Fragment shader:%s not found", progInfo.Fragment)
 	}
-	// Generates fragment shader source from template
-	var sourceFrag bytes.Buffer
-	err = fragTempl.Execute(&sourceFrag, specs)
-	if err != nil {
+	// Preprocess fragment shader source
+	fragSource, err = sm.preprocess(fragSource, defines)
+	if !ok {
 		return nil, err
 	}
+	fmt.Printf("fragSource:%s\n", fragSource)
 
 	// Checks for optional geometry shader compiled template
-	var sourceGeom bytes.Buffer
+	var geomSource = ""
 	if progInfo.Geometry != "" {
-		// Get geometry shader compiled template
-		geomTempl, ok := sm.shaders[progInfo.Geometry]
+		// Get geometry shader source
+		geomSource, ok = sm.shadersm[progInfo.Geometry]
 		if !ok {
-			return nil, fmt.Errorf("Geometry shader:%s template not found", progInfo.Geometry)
+			return nil, fmt.Errorf("Geometry shader:%s not found", progInfo.Geometry)
 		}
-		// Generates geometry shader source from template
-		err = geomTempl.Execute(&sourceGeom, specs)
-		if err != nil {
+		// Preprocess geometry shader source
+		geomSource, err = sm.preprocess(geomSource, defines)
+		if !ok {
 			return nil, err
 		}
 	}
 
 	// Creates shader program
 	prog := sm.gs.NewProgram()
-	prog.AddShader(gls.VERTEX_SHADER, sourceVertex.String(), nil)
-	prog.AddShader(gls.FRAGMENT_SHADER, sourceFrag.String(), nil)
+	prog.AddShader(gls.VERTEX_SHADER, vertexSource, nil)
+	prog.AddShader(gls.FRAGMENT_SHADER, fragSource, nil)
 	if progInfo.Geometry != "" {
-		prog.AddShader(gls.GEOMETRY_SHADER, sourceGeom.String(), nil)
+		prog.AddShader(gls.GEOMETRY_SHADER, geomSource, nil)
 	}
 	err = prog.Build()
 	if err != nil {
@@ -280,6 +233,50 @@ func (sm *Shaman) GenProgram(specs *ShaderSpecs) (*gls.Program, error) {
 	return prog, nil
 }
 
+// preprocess preprocesses the specified source prefixing it with optional defines directives
+// contained in "defines" parameter and replaces '#include <name>' directives
+// by the respective source code of include chunk of the specified name.
+// The included "files" are also processed recursively.
+func (sm *Shaman) preprocess(source string, defines map[string]string) (string, error) {
+
+	// If defines map supplied, generates prefix with glsl version directive first,
+	// followed by "#define directives"
+	var prefix = ""
+	if defines != nil {
+		prefix = fmt.Sprintf("#version %s\n", defines["GLSL_VERSION"])
+		for name, value := range defines {
+			if name == "GLSL_VERSION" {
+				continue
+			}
+			prefix = prefix + fmt.Sprintf("#define %s %s\n", name, value)
+		}
+	}
+
+	// Find all string submatches for the "#include <name>" directive
+	matches := rexInclude.FindAllStringSubmatch(source, 100)
+	if len(matches) == 0 {
+		return prefix + source, nil
+	}
+
+	// For each directive found, replace the name by the respective include chunk source code
+	var newSource = source
+	for _, m := range matches {
+		// Get the source of the include chunk with the match <name>
+		incSource := sm.includes[m[1]]
+		if len(incSource) == 0 {
+			return "", fmt.Errorf("Include:[%s] not found", m[1])
+		}
+		// Preprocess the include chunk source code
+		incSource, err := sm.preprocess(incSource, nil)
+		if err != nil {
+			return "", err
+		}
+		// Replace all occurances of the include directive with its processed source code
+		newSource = strings.Replace(newSource, m[0], incSource, -1)
+	}
+	return prefix + newSource, nil
+}
+
 // Compare compares two shaders specifications structures
 func (ss *ShaderSpecs) Compare(other *ShaderSpecs) bool {