GlassExample(void)
	 : make_plane(Vec3f(2.0f, 0.0f, 0.0f), Vec3f(0.0f, 0.0f, -2.0f))
	 , plane_instr(make_plane.Instructions())
	 , plane_indices(make_plane.Indices())
	 , make_shape()
	 , shape_instr(make_shape.Instructions())
	 , shape_indices(make_shape.Indices())
	 , plane_vs(ObjectDesc("Plane vertex"))
	 , shape_vs(ObjectDesc("Shape vertex"))
	 , plane_fs(ObjectDesc("Plane fragment"))
	 , shape_fs(ObjectDesc("Shape fragment"))
	 , plane_proj_matrix(plane_prog)
	 , plane_camera_matrix(plane_prog)
	 , plane_model_matrix(plane_prog)
	 , shape_proj_matrix(shape_prog)
	 , shape_camera_matrix(shape_prog)
	 , shape_model_matrix(shape_prog)
	 , shape_clip_plane(shape_prog)
	 , shape_clip_direction(shape_prog)
	 , width(512)
	 , height(512)
	 , tex_side(512)
	{
		plane_vs.Source(
			"#version 140\n"
			"uniform vec3 LightPosition;"
			"uniform mat4 ProjectionMatrix, CameraMatrix, ModelMatrix;"
			"in vec4 Position;"
			"in vec2 TexCoord;"
			"out vec3 vertLightDir;"
			"out vec2 vertTexCoord;"
			"void main(void)"
			"{"
			"	gl_Position = "
			"		ModelMatrix* "
			"		Position;"
			"	vertLightDir = normalize("
			"		LightPosition - gl_Position.xyz"
			"	);"
			"	gl_Position = "
			"		ProjectionMatrix *"
			"		CameraMatrix *"
			"		gl_Position;"
			"	vertTexCoord = TexCoord;"
			"}"
		);
		plane_vs.Compile();

		plane_fs.Source(
			"#version 140\n"
			"uniform vec3 Normal;"
			"in vec3 vertLightDir;"
			"in vec2 vertTexCoord;"
			"out vec4 fragColor;"
			"void main(void)"
			"{"
			"	float checker = ("
			"		int(vertTexCoord.x*18) % 2+"
			"		int(vertTexCoord.y*18) % 2"
			"	) % 2;"
			"	vec3 color = mix("
			"		vec3(0.2, 0.4, 0.9),"
			"		vec3(0.2, 0.2, 0.7),"
			"		checker"
			"	);"
			"	float d = dot("
			"		Normal, "
			"		vertLightDir"
			"	);"
			"	float intensity = 0.5 + pow(1.4*d, 2.0);"
			"	fragColor = vec4(color*intensity, 1.0);"
			"}"
		);
		plane_fs.Compile();

		plane_prog.AttachShader(plane_vs);
		plane_prog.AttachShader(plane_fs);
		plane_prog.Link();
		plane_prog.Use();
		plane_proj_matrix.BindTo("ProjectionMatrix");
		plane_camera_matrix.BindTo("CameraMatrix");
		plane_model_matrix.BindTo("ModelMatrix");

		Vec3f lightPos(3.0f, 3.0f, 3.0f);
		Uniform<Vec3f>(plane_prog, "LightPosition").Set(lightPos);
		Uniform<Vec3f>(plane_prog, "Normal").Set(make_plane.Normal());

		gl.Bind(plane);

		gl.Bind(Buffer::Target::Array, plane_verts);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_plane.Positions(data);
			Buffer::Data(Buffer::Target::Array, data);
			VertexArrayAttrib attr(plane_prog, "Position");
			attr.Setup<GLfloat>(n_per_vertex);
			attr.Enable();
		}

		gl.Bind(Buffer::Target::Array, plane_texcoords);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_plane.TexCoordinates(data);
			Buffer::Data(Buffer::Target::Array, data);
			VertexArrayAttrib attr(plane_prog, "TexCoord");
			attr.Setup<GLfloat>(n_per_vertex);
			attr.Enable();
		}

		shape_vs.Source(
			"#version 140\n"
			"uniform vec3 LightPosition;"
			"uniform mat4 ProjectionMatrix, ModelMatrix, CameraMatrix;"
			"uniform vec4 ClipPlane;"
			"uniform float ClipDirection;"
			"in vec4 Position;"
			"in vec3 Normal;"
			"out vec3 vertNormal;"
			"out vec3 vertLightDir;"
			"out vec3 vertLightRefl;"
			"out vec3 vertViewDir;"
			"out vec2 vertTexCoord;"
			"void main(void)"
			"{"
			"	gl_Position = "
			"		ModelMatrix *"
			"		Position;"
			"	gl_ClipDistance[0] = "
			"		ClipDirection* "
			"		dot(ClipPlane, gl_Position);"
			"	vertLightDir = LightPosition - gl_Position.xyz;"
			"	vertNormal = mat3(ModelMatrix)*Normal;"
			"	vertLightRefl = reflect("
			"		-normalize(vertLightDir),"
			"		normalize(vertNormal)"
			"	);"
			"	vertViewDir = (vec4(0.0, 0.0, 1.0, 1.0)*CameraMatrix).xyz;"
			"	gl_Position = ProjectionMatrix * CameraMatrix * gl_Position;"
			"	vec3 TexOffs = mat3(CameraMatrix)*vertNormal*0.05;"
			"	vertTexCoord = "
			"		vec2(0.5, 0.5) +"
			"		(gl_Position.xy/gl_Position.w)*0.5 +"
			"		(TexOffs.z<0.0 ? TexOffs.xy : -TexOffs.xy);"
			"}"
		);
		shape_vs.Compile();

		shape_fs.Source(
			"#version 140\n"
			"uniform sampler2D RefractTex;"
			"in vec3 vertNormal;"
			"in vec3 vertLightDir;"
			"in vec3 vertLightRefl;"
			"in vec3 vertViewDir;"
			"in vec2 vertTexCoord;"
			"out vec4 fragColor;"

			"float adj_lt(float i)"
			"{"
			"	return i > 0.0 ? i : -0.7*i;"
			"}"

			"void main(void)"
			"{"
			"	float l = length(vertLightDir);"
			"	float d = dot("
			"		normalize(vertNormal), "
			"		normalize(vertLightDir)"
			"	) / l;"
			"	float s = dot("
			"		normalize(vertLightRefl),"
			"		normalize(vertViewDir)"
			"	);"
			"	vec3 lt = vec3(1.0, 1.0, 1.0);"
			"	vec3 tex = texture(RefractTex, vertTexCoord).rgb;"
			"	fragColor = vec4("
			"		tex * 0.5 + "
			"		(lt + tex) * 1.5 * adj_lt(d) + "
			"		lt * pow(adj_lt(s), 64), "
			"		1.0"
			"	);"
			"}"
		);
		shape_fs.Compile();

		shape_prog.AttachShader(shape_vs);
		shape_prog.AttachShader(shape_fs);
		shape_prog.Link();
		shape_prog.Use();
		shape_proj_matrix.BindTo("ProjectionMatrix");
		shape_camera_matrix.BindTo("CameraMatrix");
		shape_model_matrix.BindTo("ModelMatrix");
		shape_clip_plane.BindTo("ClipPlane");
		shape_clip_direction.BindTo("ClipDirection");

		Uniform<Vec3f>(shape_prog, "LightPosition").Set(lightPos);

		gl.Bind(shape);

		gl.Bind(Buffer::Target::Array, shape_verts);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_shape.Positions(data);
			Buffer::Data(Buffer::Target::Array, data);
			VertexArrayAttrib attr(shape_prog, "Position");
			attr.Setup<GLfloat>(n_per_vertex);
			attr.Enable();
		}

		gl.Bind(Buffer::Target::Array, shape_normals);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_shape.Normals(data);
			Buffer::Data(Buffer::Target::Array, data);
			VertexArrayAttrib attr(shape_prog, "Normal");
			attr.Setup<GLfloat>(n_per_vertex);
			attr.Enable();
		}
		//
		Texture::Active(0);
		UniformSampler(shape_prog, "RefractTex").Set(0);
		{
			gl.Bound(Texture::Target::_2D, refract_tex)
				.MinFilter(TextureMinFilter::Linear)
				.MagFilter(TextureMagFilter::Linear)
				.WrapS(TextureWrap::MirroredRepeat)
				.WrapT(TextureWrap::MirroredRepeat)
				.Image2D(
					0,
					PixelDataInternalFormat::RGB,
					tex_side, tex_side,
					0,
					PixelDataFormat::RGB,
					PixelDataType::UnsignedByte,
					nullptr
				);
		}
		//
		gl.ClearColor(0.8f, 0.8f, 0.7f, 0.0f);
		gl.ClearDepth(1.0f);
		gl.Enable(Capability::DepthTest);
	}
	CubeExample(void)
	 : cube_instr(make_cube.Instructions())
	 , cube_indices(make_cube.Indices())
	 , projection_matrix(prog)
	 , camera_matrix(prog)
	{
		// Set the vertex shader source and compile it
		VertexShader vs;
		vs.Source(
			"#version 150\n"
			"uniform mat4 ProjectionMatrix, CameraMatrix;"
			"layout (std140) uniform ModelBlock {"
			"	mat4 ModelMatrices[36];"
			"};"
			"in vec4 Position;"
			"out vec3 vertColor;"
			"void main(void)"
			"{"
			"	mat4 ModelMatrix = ModelMatrices[gl_InstanceID];"
			"	gl_Position = "
			"		ProjectionMatrix *"
			"		CameraMatrix *"
			"		ModelMatrix *"
			"		Position;"
			"	vertColor = abs(normalize((ModelMatrix*Position).yxz));"
			"}"
		).Compile();

		// set the fragment shader source and compile it
		FragmentShader fs;
		fs.Source(
			"#version 150\n"
			"in vec3 vertColor;"
			"out vec4 fragColor;"
			"void main(void)"
			"{"
			"	fragColor = vec4(vertColor, 1.0);"
			"}"
		).Compile();

		// attach the shaders to the program
		prog.AttachShader(vs);
		prog.AttachShader(fs);
		// link and use it
		prog.Link().Use();

		projection_matrix.BindTo("ProjectionMatrix");
		camera_matrix.BindTo("CameraMatrix");

		// bind the VAO for the cube
		cube.Bind();

		// bind the VBO for the cube vertices
		verts.Bind(Buffer::Target::Array);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_cube.Positions(data);
			// upload the data
			Buffer::Data(Buffer::Target::Array, data);
			// setup the vertex attribs array for the vertices
			(prog|"Position").Setup<GLfloat>(n_per_vertex).Enable();
		}

		// make the matrices
		{
			// 36 x 4x4 matrices
			std::vector<GLfloat> matrix_data(36*16);
			auto p = matrix_data.begin(), e = matrix_data.end();

			Angle<GLfloat> angle, astep = Angle<GLfloat>::Degrees(10);
			while(p != e)
			{
				GLfloat cx = Cos(angle);
				GLfloat sx = Sin(angle);
				auto matrix = Transposed(Mat4f(
					Vec4f( cx, 0.0, -sx, 0.0),
					Vec4f(0.0, 1.0, 0.0, 0.0),
					Vec4f( sx, 0.0,  cx, 0.0),
					Vec4f(0.0, 0.0, 0.0, 1.0)
				) * Mat4f(
					Vec4f(1.0, 0.0, 0.0,12.0),
					Vec4f(0.0, 1.0, 0.0, 0.0),
					Vec4f(0.0, 0.0, 1.0, 0.0),
					Vec4f(0.0, 0.0, 0.0, 1.0)
				));
				p = std::copy(
					Data(matrix),
					Data(matrix)+Size(matrix),
					p
				);
				angle += astep;
			}

			UniformBlock model_block(prog, "ModelBlock");
			model_block.Binding(0);

			block_buf.Bind(Buffer::Target::Uniform);
			Buffer::Data(
				Buffer::Target::Uniform,
				matrix_data,
				BufferUsage::DynamicDraw
			);
			block_buf.BindBaseUniform(0);
		}

		//
		gl.ClearColor(0.9f, 0.9f, 0.9f, 0.0f);
		gl.ClearDepth(1.0f);
		gl.Enable(Capability::DepthTest);
	}
Exemple #3
0
	TessellationExample(void)
	 : shape_instr(make_shape.Instructions())
	 , shape_indices(make_shape.Indices())
	 , tess_level(prog)
	 , viewport_dimensions(prog)
	 , projection_matrix(prog)
	 , camera_matrix(prog)
	 , model_matrix(prog)
	{
		vs.Source(
			"#version 330\n"

			"in vec4 Position;"

			"void main(void)"
			"{"
			"	gl_Position = Position;"
			"}"
		);
		vs.Compile();

		gs.Source(
			"#version 330\n"
			"layout (triangles) in;"
			"layout (triangle_strip, max_vertices = 48) out;"

			"const vec3 LightPosition = vec3(12.0, 10.0, 7.0);"

			"uniform mat4 ProjectionMatrix, CameraMatrix, ModelMatrix;"
			"uniform vec2 ViewportDimensions;"
			"uniform int TessLevel;"

			"noperspective out vec3 geomDist;"
			"flat out vec3 geomNormal;"
			"out vec3 geomColor;"
			"out vec3 geomLightDir;"

			"void make_triangle(vec4 p0, vec4 p1, vec4 p2)"
			"{"
			"	vec3 n0 = (ModelMatrix*vec4(p0.xyz, 0)).xyz;"
			"	vec3 n1 = (ModelMatrix*vec4(p1.xyz, 0)).xyz;"
			"	vec3 n2 = (ModelMatrix*vec4(p2.xyz, 0)).xyz;"

			"	vec4 m0 = ModelMatrix*p0;"
			"	vec4 m1 = ModelMatrix*p1;"
			"	vec4 m2 = ModelMatrix*p2;"

			"	vec4 c0 = ProjectionMatrix*CameraMatrix*m0;"
			"	vec4 c1 = ProjectionMatrix*CameraMatrix*m1;"
			"	vec4 c2 = ProjectionMatrix*CameraMatrix*m2;"

			"	vec2 s0 = ViewportDimensions * c0.xy/c0.w;"
			"	vec2 s1 = ViewportDimensions * c1.xy/c1.w;"
			"	vec2 s2 = ViewportDimensions * c2.xy/c2.w;"

			"	vec2 v0 = s2 - s1;"
			"	vec2 v1 = s0 - s2;"
			"	vec2 v2 = s1 - s0;"

			"	float d0 = abs(v1.x*v2.y-v1.y*v2.x)/length(v0);"
			"	float d1 = abs(v2.x*v0.y-v2.y*v0.x)/length(v1);"
			"	float d2 = abs(v0.x*v1.y-v0.y*v1.x)/length(v2);"

			"	geomNormal = normalize(n0+n1+n2);"

			"	gl_Position = c0;"
			"	geomColor = normalize(abs(vec3(1, 1, 1) - n0));"
			"	geomLightDir = LightPosition - m0.xyz;"
			"	geomDist = vec3(d0, 0.0, 0.0);"
			"	EmitVertex();"

			"	gl_Position = c1;"
			"	geomColor = normalize(abs(vec3(1, 1, 1) - n1));"
			"	geomLightDir = LightPosition - m1.xyz;"
			"	geomDist = vec3(0.0, d1, 0.0);"
			"	EmitVertex();"

			"	gl_Position = c2;"
			"	geomColor = normalize(abs(vec3(1, 1, 1) - n2));"
			"	geomLightDir = LightPosition - m2.xyz;"
			"	geomDist = vec3(0.0, 0.0, d2);"
			"	EmitVertex();"

			"	EndPrimitive();"
			"}"

			"void do_tess_1(vec4 p_0, vec4 p_1, vec4 p_2, int l)"
			"{"
			"	if(l == 1) make_triangle(p_0, p_1, p_2);"
			"	else"
			"	{"
			"		vec4 p01 = vec4(normalize(p_0.xyz+p_1.xyz), 1.0);"
			"		vec4 p12 = vec4(normalize(p_1.xyz+p_2.xyz), 1.0);"
			"		vec4 p20 = vec4(normalize(p_2.xyz+p_0.xyz), 1.0);"
			"		make_triangle(p_0, p01, p20);"
			"		make_triangle(p01, p_1, p12);"
			"		make_triangle(p20, p12, p_2);"
			"		make_triangle(p01, p12, p20);"
			"	}"
			"}"

			"void do_tess_0(vec4 p_0, vec4 p_1, vec4 p_2, int l)"
			"{"
			"	if(l == 0) make_triangle(p_0, p_1, p_2);"
			"	else"
			"	{"
			"		vec4 p01 = vec4(normalize(p_0.xyz+p_1.xyz), 1.0);"
			"		vec4 p12 = vec4(normalize(p_1.xyz+p_2.xyz), 1.0);"
			"		vec4 p20 = vec4(normalize(p_2.xyz+p_0.xyz), 1.0);"
			"		do_tess_1(p_0, p01, p20, l);"
			"		do_tess_1(p01, p_1, p12, l);"
			"		do_tess_1(p20, p12, p_2, l);"
			"		do_tess_1(p01, p12, p20, l);"
			"	}"
			"}"

			"void main(void)"
			"{"
			"	do_tess_0("
			"		gl_in[0].gl_Position,"
			"		gl_in[1].gl_Position,"
			"		gl_in[2].gl_Position,"
			"		TessLevel"
			"	);"
			"}"
		);
		gs.Compile();

		fs.Source(
			"#version 330\n"

			"noperspective in vec3 geomDist;"
			"flat in vec3 geomNormal;"
			"in vec3 geomColor;"
			"in vec3 geomLightDir;"

			"out vec3 fragColor;"

			"void main(void)"
			"{"
			"	float MinDist = min(min(geomDist.x,geomDist.y),geomDist.z);"
			"	float EdgeAlpha = exp2(-pow(MinDist, 2.0));"

			"	const float Ambient = 0.7;"
			"	float Diffuse = max(dot("
			"		normalize(geomNormal),"
			"		normalize(geomLightDir)"
			"	)+0.1, 0.0)*1.4;"

			"	vec3 FaceColor = geomColor * (Diffuse + Ambient);"
			"	const vec3 EdgeColor = vec3(0.0, 0.0, 0.0);"

			"	fragColor = mix(FaceColor, EdgeColor, EdgeAlpha);"
			"}"
		);
		fs.Compile();

		prog.AttachShader(vs);
		prog.AttachShader(gs);
		prog.AttachShader(fs);
		prog.Link();
		prog.Use();

		tess_level.BindTo("TessLevel");
		viewport_dimensions.BindTo("ViewportDimensions");
		projection_matrix.BindTo("ProjectionMatrix");
		camera_matrix.BindTo("CameraMatrix");
		model_matrix.BindTo("ModelMatrix");

		shape.Bind();

		verts.Bind(Buffer::Target::Array);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_shape.Positions(data);
			Buffer::Data(Buffer::Target::Array, data);
			VertexArrayAttrib attr(prog, "Position");
			attr.Setup<GLfloat>(n_per_vertex);
			attr.Enable();

			indices.Bind(Buffer::Target::ElementArray);
			Buffer::Data(Buffer::Target::ElementArray, shape_indices);
			shape_indices.clear();
		}

		//
		gl.ClearColor(0.7f, 0.7f, 0.7f, 0.0f);
		gl.ClearDepth(1.0f);
		gl.Enable(Capability::DepthTest);

		prog.Use();
	}
    ShadowExample()
      : make_torus(1.0, 0.7, 72, 48)
      , torus_indices(make_torus.Indices())
      , torus_instr(make_torus.Instructions())
      , object_projection_matrix(object_prog)
      , object_camera_matrix(object_prog)
      , object_model_matrix(object_prog)
      , shadow_projection_matrix(shadow_prog)
      , shadow_camera_matrix(shadow_prog)
      , shadow_model_matrix(shadow_prog)
      , object_color(object_prog)
      , object_light_mult(object_prog) {
        vs_object.Source(
          "#version 140\n"
          "in vec4 Position;"
          "in vec3 Normal;"
          "uniform mat4 ProjectionMatrix, CameraMatrix, ModelMatrix;"
          "uniform vec3 LightPos;"
          "out vec3 vertNormal;"
          "out vec3 vertLight;"
          "void main()"
          "{"
          "	gl_Position = ModelMatrix * Position;"
          "	vertNormal = mat3(ModelMatrix)*Normal;"
          "	vertLight = LightPos - gl_Position.xyz;"
          "	gl_Position = ProjectionMatrix * CameraMatrix * gl_Position;"
          "}");
        vs_object.Compile();

        fs_object.Source(
          "#version 140\n"
          "in vec3 vertNormal;"
          "in vec3 vertLight;"
          "uniform vec3 Color;"
          "uniform float LightMult;"
          "out vec4 fragColor;"
          "void main()"
          "{"
          "	float l = sqrt(length(vertLight));"
          "	float d = l > 0.0 ?"
          "		dot("
          "			vertNormal,"
          "			normalize(vertLight)"
          "		) / l : 0.0;"
          "	float i = 0.3 + max(d, 0.0) * LightMult;"
          "	fragColor = vec4(Color*i, 1.0);"
          "}");
        fs_object.Compile();

        object_prog.AttachShader(vs_object);
        object_prog.AttachShader(fs_object);
        object_prog.Link().Use();

        object_projection_matrix.BindTo("ProjectionMatrix");
        object_camera_matrix.BindTo("CameraMatrix");
        object_model_matrix.BindTo("ModelMatrix");
        object_color.BindTo("Color");
        object_light_mult.BindTo("LightMult");

        vs_shadow.Source(
          "#version 150\n"
          "in vec4 Position;"
          "in vec3 Normal;"
          "uniform mat4 ModelMatrix;"
          "uniform vec3 LightPos;"
          "out float ld;"
          "void main()"
          "{"
          "	gl_Position = ModelMatrix * Position;"
          "	vec3 geomNormal = mat3(ModelMatrix)*Normal;"
          "	vec3 lightDir = LightPos - gl_Position.xyz;"
          "	ld = dot(geomNormal, normalize(lightDir));"
          "}");
        vs_shadow.Compile();

        gs_shadow.Source(
          "#version 150\n"
          "layout(triangles) in;"
          "layout(triangle_strip, max_vertices = 12) out;"

          "in float ld[];"

          "uniform mat4 CameraMatrix, ProjectionMatrix;"
          "uniform vec3 LightPos;"

          "void main()"
          "{"
          "	for(int v=0; v!=3; ++v)"
          "	{"
          "		int a = v, b = (v+1)%3, c = (v+2)%3;"
          "		vec4 pa = gl_in[a].gl_Position;"
          "		vec4 pb = gl_in[b].gl_Position;"
          "		vec4 pc = gl_in[c].gl_Position;"
          "		vec4 px, py;"
          "		if(ld[a] == 0.0 && ld[b] == 0.0)"
          "		{"
          "			px = pa;"
          "			py = pb;"
          "		}"
          "		else if(ld[a] > 0.0 && ld[b] < 0.0)"
          "		{"
          "			float x = ld[a]/(ld[a]-ld[b]);"
          "			float y;"
          "			px = mix(pa, pb, x);"
          "			if(ld[c] < 0.0)"
          "			{"
          "				y = ld[a]/(ld[a]-ld[c]);"
          "				py = mix(pa, pc, y);"
          "			}"
          "			else"
          "			{"
          "				y = ld[c]/(ld[c]-ld[b]);"
          "				py = mix(pc, pb, y);"
          "			}"
          "		}"
          "		else continue;"
          "		vec3 vx = px.xyz - LightPos;"
          "		vec3 vy = py.xyz - LightPos;"
          "		vec4 sx = vec4(px.xyz + vx*10.0, 1.0);"
          "		vec4 sy = vec4(py.xyz + vy*10.0, 1.0);"
          "		vec4 cpx = CameraMatrix * px;"
          "		vec4 cpy = CameraMatrix * py;"
          "		vec4 csx = CameraMatrix * sx;"
          "		vec4 csy = CameraMatrix * sy;"
          "		gl_Position = ProjectionMatrix * cpy;"
          "		EmitVertex();"
          "		gl_Position = ProjectionMatrix * cpx;"
          "		EmitVertex();"
          "		gl_Position = ProjectionMatrix * csy;"
          "		EmitVertex();"
          "		gl_Position = ProjectionMatrix * csx;"
          "		EmitVertex();"
          "		EndPrimitive();"
          "		break;"
          "	}"
          "}");
        gs_shadow.Compile();

        fs_shadow.Source(
          "#version 150\n"
          "out vec4 fragColor;"
          "void main()"
          "{"
          "	fragColor = vec4(0.0, 0.0, 0.0, 1.0);"
          "}");
        fs_shadow.Compile();

        shadow_prog.AttachShader(vs_shadow);
        shadow_prog.AttachShader(gs_shadow);
        shadow_prog.AttachShader(fs_shadow);
        shadow_prog.Link().Use();

        shadow_projection_matrix.BindTo("ProjectionMatrix");
        shadow_camera_matrix.BindTo("CameraMatrix");
        shadow_model_matrix.BindTo("ModelMatrix");

        // bind the VAO for the torus
        torus.Bind();

        // bind the VBO for the torus vertices
        torus_verts.Bind(Buffer::Target::Array);
        {
            std::vector<GLfloat> data;
            GLuint n_per_vertex = make_torus.Positions(data);
            Buffer::Data(Buffer::Target::Array, data);

            VertexArrayAttrib attr(VertexArrayAttrib::GetCommonLocation(
              MakeGroup(object_prog, shadow_prog), "Position"));
            attr.Setup<GLfloat>(n_per_vertex);
            attr.Enable();
        }

        // bind the VBO for the torus normals
        torus_normals.Bind(Buffer::Target::Array);
        {
            std::vector<GLfloat> data;
            GLuint n_per_vertex = make_torus.Normals(data);
            Buffer::Data(Buffer::Target::Array, data);

            object_prog.Use();
            VertexArrayAttrib attr(object_prog, "Normal");
            attr.Setup<GLfloat>(n_per_vertex);
            attr.Enable();
        }
        // bind the VAO for the plane
        plane.Bind();

        // bind the VBO for the plane vertices
        plane_verts.Bind(Buffer::Target::Array);
        {
            GLfloat data[4 * 3] = {-9.0f,
                                   0.0f,
                                   -9.0f,
                                   -9.0f,
                                   0.0f,
                                   9.0f,
                                   9.0f,
                                   0.0f,
                                   -9.0f,
                                   9.0f,
                                   0.0f,
                                   9.0f};
            Buffer::Data(Buffer::Target::Array, 4 * 3, data);
            object_prog.Use();
            VertexArrayAttrib attr(object_prog, "Position");
            attr.Setup<GLfloat>(3);
            attr.Enable();
        }

        // bind the VBO for the torus normals
        plane_normals.Bind(Buffer::Target::Array);
        {
            GLfloat data[4 * 3] = {-0.1f,
                                   1.0f,
                                   0.1f,
                                   -0.1f,
                                   1.0f,
                                   -0.1f,
                                   0.1f,
                                   1.0f,
                                   0.1f,
                                   0.1f,
                                   1.0f,
                                   -0.1f};
            Buffer::Data(Buffer::Target::Array, 4 * 3, data);
            object_prog.Use();
            VertexArrayAttrib attr(object_prog, "Normal");
            attr.Setup<GLfloat>(3);
            attr.Enable();
        }

        Vec3f lightPos(2.0f, 9.0f, 3.0f);

        ProgramUniform<Vec3f>(object_prog, "LightPos").Set(lightPos);
        ProgramUniform<Vec3f>(shadow_prog, "LightPos").Set(lightPos);

        gl.ClearColor(0.2f, 0.2f, 0.2f, 0.0f);
        gl.ClearDepth(1.0f);
        gl.ClearStencil(0);

        gl.Enable(Capability::DepthTest);
        gl.Enable(Capability::CullFace);
        gl.FrontFace(make_torus.FaceWinding());
    }
	CubeExample(void)
	 : cube_instr(make_cube.Instructions())
	 , cube_indices(make_cube.Indices())
	 , projection_matrix(prog)
	 , camera_matrix(prog)
	{
		// Set the vertex shader source and compile it
		vs.Source(
			"#version 150\n"
			"in vec4 Position;"
			"void main(void)"
			"{"
			"	gl_Position = Position;"
			"}"
		).Compile();

		// Set the geometry shader source and compile it
		gs.Source(
			"#version 150\n"
			"layout(triangles) in;"
			"layout(triangle_strip, max_vertices = 108) out;"
			"uniform mat4 ProjectionMatrix, CameraMatrix;"
			"out vec3 vertColor;"
			"void main(void)"
			"{"
			"	for(int c=0; c!=36; ++c)"
			"	{"
			"		float angle = c * 10 * 2 * 3.14159 / 360.0;"
			"		float cx = cos(angle);"
			"		float sx = sin(angle);"
			"		mat4 ModelMatrix = mat4("
			"			 cx, 0.0,  sx, 0.0,"
			"			0.0, 1.0, 0.0, 0.0,"
			"			-sx, 0.0,  cx, 0.0,"
			"			0.0, 0.0, 0.0, 1.0 "
			"		) * mat4("
			"			 1.0, 0.0, 0.0, 0.0,"
			"			 0.0, 1.0, 0.0, 0.0,"
			"			 0.0, 0.0, 1.0, 0.0,"
			"			12.0, 0.0, 0.0, 1.0 "
			"		);"
			"		for(int v=0; v!=gl_in.length(); ++v)"
			"		{"
			"			vec4 vert = gl_in[v].gl_Position;"
			"			gl_Position = "
			"				ProjectionMatrix *"
			"				CameraMatrix *"
			"				ModelMatrix *"
			"				vert;"
			"			vertColor = abs(normalize(ModelMatrix*vert)).xzy;"
			"			EmitVertex();"
			"		}"
			"		EndPrimitive();"
			"	}"
			"}"
		).Compile();

		// set the fragment shader source and compile it
		fs.Source(
			"#version 150\n"
			"in vec3 vertColor;"
			"out vec4 fragColor;"
			"void main(void)"
			"{"
			"	fragColor = vec4(vertColor, 1.0);"
			"}"
		).Compile();

		// attach the shaders to the program
		prog << vs << gs << fs;
		// link and use it
		prog.Link().Use();

		projection_matrix.BindTo("ProjectionMatrix");
		camera_matrix.BindTo("CameraMatrix");

		// bind the VAO for the cube
		cube.Bind();

		// bind the VBO for the cube vertices
		verts.Bind(Buffer::Target::Array);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_cube.Positions(data);
			// upload the data
			Buffer::Data(Buffer::Target::Array, data);
			// setup the vertex attribs array for the vertices
			VertexArrayAttrib attr(prog, "Position");
			attr.Setup<GLfloat>(n_per_vertex).Enable();
		}

		gl.ClearColor(0.9f, 0.9f, 0.9f, 0.0f);
		gl.ClearDepth(1.0f);
		gl.Enable(Capability::DepthTest);
	}