Exemplo n.º 1
0
	void Render(double time)
	{
		gl.Clear().ColorBuffer().DepthBuffer();
		//
		auto camera = CamMatrixf::Orbiting(
			Vec3f(),
			4.5,
			Degrees(time * 35),
			Degrees(SineWave(time / 30.0) * 60)
		);

		auto model =
			ModelMatrixf::RotationY(FullCircles(time * 0.25)) *
			ModelMatrixf::RotationX(FullCircles(time * 0.33));

		camera_matrix.Set(camera);
		model_matrix.Set(model);
		transf_time.Set(time);

		face_pp.Bind();
		gl.PolygonMode(PolygonMode::Fill);
		torus_instr.Draw(torus_indices);

		frame_pp.Bind();
		gl.PolygonMode(PolygonMode::Line);
		torus_instr.Draw(torus_indices);
	}
Exemplo n.º 2
0
// static
ProgramPipeline *ProgramPipelineManager::AllocateNewObject(rx::GLImplFactory *factory,
                                                           GLuint handle)
{
    ProgramPipeline *pipeline = new ProgramPipeline(factory, handle);
    pipeline->addRef();
    return pipeline;
}
Exemplo n.º 3
0
	void RenderFrameShadowMap(
		const Vec3f& light_position,
		const Mat4f& torus_matrix,
		const Mat4f& light_proj_matrix
	)
	{
		frame_shadow_fbo.Bind(Framebuffer::Target::Draw);

		gl.Viewport(shadow_tex_side, shadow_tex_side);
		gl.ClearDepthBuffer(1.0f);
		gl.CullFace(Face::Back);

		transf_prog.camera_matrix.Set(light_proj_matrix);
		transf_prog.camera_position.Set(light_position);

		// Render the torus' frame
		transf_prog.model_matrix.Set(torus_matrix);

		shadow_pp.Bind();

		gl.Enable(Capability::PolygonOffsetFill);
		torus.Draw(
			[](GLuint phase) -> bool
			{
				return (phase <= 3);
			}
		);
		gl.Disable(Capability::PolygonOffsetFill);
	}
Exemplo n.º 4
0
	void RenderGlassShadowMap(
		const Vec3f& light_position,
		const Vec3f& torus_center,
		const Mat4f& torus_matrix,
		const Mat4f& light_proj_matrix
	)
	{
		glass_shadow_fbo.Bind(Framebuffer::Target::Draw);

		gl.Viewport(shadow_tex_side, shadow_tex_side);
		const GLfloat clear_color[4] = {1.0f, 1.0f, 1.0f, 0.0f};
		gl.ClearColorBuffer(0, clear_color);

		transf_prog.camera_matrix.Set(light_proj_matrix);
		transf_prog.camera_position.Set(light_position);
		transf_prog.light_proj_matrix.Set(light_proj_matrix);
		transf_prog.light_position.Set(light_position);

		// Render the torus' frame
		transf_prog.model_matrix.Set(torus_matrix);

		// setup the view clipping plane
		Planef clip_plane = Planef::FromPointAndNormal(
			torus_center,
			Normalized(light_position-torus_center)
		);
		transf_prog.clip_plane.Set(clip_plane.Equation());

		light_pp.Bind();

		light_prog.color = Vec3f(0.6f, 0.4f, 0.1f);

		gl.Disable(Capability::DepthTest);
		gl.Enable(Functionality::ClipDistance, 0);
		gl.Enable(Capability::Blend);

		for(int c=0; c!=2; ++c)
		{
			transf_prog.clip_direction.Set((c == 0)?1:-1);

			for(int p=3; p>=0; --p)
			{
				if(p % 2 == 0) gl.CullFace(Face::Front);
				else gl.CullFace(Face::Back);
				torus.Draw(
					[&p](GLuint phase) -> bool
					{
						if(p == 0 || p == 3)
						{
							return (phase == 4);
						}
						else return (phase > 4);
					}
				);
			}
		}
		gl.Disable(Capability::Blend);
		gl.Disable(Functionality::ClipDistance, 0);
		gl.Enable(Capability::DepthTest);
	}
Exemplo n.º 5
0
	TorusExample(void)
	 : make_torus(1.0, 0.5, 18, 36)
	 , torus_instr(make_torus.Instructions())
	 , torus_indices(make_torus.Indices())
	 , transf_prog(make_transf_prog())
	 , face_prog(make_face_prog())
	 , frame_prog(make_frame_prog())
	 , projection_matrix(transf_prog, "ProjectionMatrix")
	 , camera_matrix(transf_prog, "CameraMatrix")
	 , model_matrix(transf_prog, "ModelMatrix")
	 , transf_time(transf_prog, "Time")
	{
		transf_prog.Use();
		torus.Bind();
		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(transf_prog, "Position");
			attr.Setup<GLfloat>(n_per_vertex);
			attr.Enable();
		}

		normals.Bind(Buffer::Target::Array);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_torus.Normals(data);
			Buffer::Data(Buffer::Target::Array, data);

			VertexArrayAttrib attr(transf_prog, "Normal");
			attr.Setup<GLfloat>(n_per_vertex);
			attr.Enable();
		}

		texcoords.Bind(Buffer::Target::Array);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_torus.TexCoordinates(data);
			Buffer::Data(Buffer::Target::Array, data);

			VertexArrayAttrib attr(transf_prog, "TexCoord");
			attr.Setup<GLfloat>(n_per_vertex);
			attr.Enable();
		}

		face_pp.Bind();
		face_prog.Use();
		face_pp.UseStages(transf_prog).Vertex().Geometry();
		face_pp.UseStages(face_prog).Fragment();


		frame_pp.Bind();
		frame_prog.Use();
		frame_pp.UseStages(transf_prog).Vertex().Geometry();
		frame_pp.UseStages(frame_prog).Fragment();

		gl.Bind(NoProgramPipeline());
		gl.Use(NoProgram());

		gl.ClearColor(0.7f, 0.6f, 0.5f, 0.0f);
		gl.ClearDepth(1.0f);
		gl.Enable(Capability::DepthTest);
		gl.DepthFunc(CompareFn::Less);
		gl.FrontFace(make_torus.FaceWinding());
	}
Exemplo n.º 6
0
	void RenderImage(
		double time,
		const Vec3f& torus_center,
		const Mat4f& torus_matrix,
		const Mat4f& light_proj_matrix
	)
	{
		// this is going into the on-screen framebuffer
		DefaultFramebuffer().Bind(Framebuffer::Target::Draw);

		gl.ClearColor(0.6f, 0.6f, 0.5f, 0.0f);
		gl.Viewport(width, height);
		gl.Clear().ColorBuffer().DepthBuffer();
		gl.CullFace(Face::Back);
		//
		transf_prog.light_proj_matrix.Set(light_proj_matrix);

		Mat4f perspective = CamMatrixf::PerspectiveX(
			Degrees(60),
			float(width)/height,
			1, 60
		);

		// setup the camera
		Vec3f camera_target(0.0f, 0.8f, 0.0f);
		auto camera = CamMatrixf::Orbiting(
			camera_target,
			GLfloat(8.0 - SineWave(time / 15.0)*3.0),
			FullCircles(time / 24.0),
			Degrees(45 + SineWave(time / 20.0) * 40)
		);
		Vec3f camera_position = camera.Position();
		transf_prog.camera_matrix.Set(perspective*camera);
		transf_prog.camera_position.Set(camera_position);

		// setup the view clipping plane
		Planef clip_plane = Planef::FromPointAndNormal(
			torus_center,
			Normalized(camera_position-torus_center)
		);

		metal_pp.Bind();

		// Render the plane
		transf_prog.model_matrix = ModelMatrixf();
		transf_prog.texture_matrix.Set(Mat2f(Vec2f(9.0f,0.0f), Vec2f(0.0f,9.0f)));
		metal_prog.color_1 = Vec3f(1.0f, 0.9f, 0.8f);
		metal_prog.color_2 = Vec3f(0.9f, 0.8f, 0.6f);
		metal_prog.with_glass_shadow = 1;

		plane.Draw([](GLuint) -> bool {return true;});

		// Render the torus
		transf_prog.model_matrix.Set(torus_matrix);
		transf_prog.texture_matrix.Set(Mat2f(Vec2f(16.0f,0.0f), Vec2f(0.0f, 4.0f)));
		metal_prog.metal_tex.Set(0);
		metal_prog.color_1 = Vec3f(0.9f, 0.9f, 0.9f);
		metal_prog.color_2 = Vec3f(0.3f, 0.3f, 0.3f);
		metal_prog.with_glass_shadow = 0;

		// the metal-part
		torus.Draw(
			[](GLuint phase) -> bool
			{
				return (phase <= 3);
			}
		);

		// now the glass part
		glass_pp.Bind();

		glass_prog.color = Vec3f(0.6f, 0.4f, 0.1f);

		gl.Enable(Functionality::ClipDistance, 0);
		gl.Enable(Capability::Blend);
		transf_prog.clip_plane.Set(clip_plane.Equation());

		for(int c=0; c!=2; ++c)
		{
			transf_prog.clip_direction.Set((c == 0)?-1:1);

			for(int p=0; p!=4; ++p)
			{
				if(p % 2 == 0) gl.CullFace(Face::Front);
				else gl.CullFace(Face::Back);
				torus.Draw(
					[&p](GLuint phase) -> bool
					{
						if(p == 0 || p == 3)
							return (phase == 4);
						else return (phase > 4);
					}
				);
			}
		}
		gl.Disable(Capability::Blend);
		gl.Disable(Functionality::ClipDistance, 0);
	}
Exemplo n.º 7
0
	GlassAndMetalExample(void)
	 : transf_prog()
	 , metal_prog()
	 , plane(transf_prog, shapes::Plane(Vec3f(9, 0, 0), Vec3f(0, 0,-9)))
	 , torus(transf_prog, shapes::WickerTorus())
	 , shadow_tex_side(1024)
	{
		NoProgram().Use();

		shadow_pp.Bind();
		shadow_pp.UseStages(transf_prog).Vertex();
		shadow_pp.UseStages(shadow_prog).Fragment();

		light_pp.Bind();
		light_pp.UseStages(transf_prog).Vertex();
		light_pp.UseStages(light_prog).Fragment();

		glass_pp.Bind();
		glass_pp.UseStages(transf_prog).Vertex();
		glass_pp.UseStages(glass_prog).Fragment();

		metal_pp.Bind();
		metal_pp.UseStages(transf_prog).Vertex();
		metal_pp.UseStages(metal_prog).Fragment();

		Texture::Active(0);
		metal_prog.metal_tex.Set(0);
		gl.Bound(Texture::Target::_2D, metal_texture)
			.MinFilter(TextureMinFilter::LinearMipmapLinear)
			.MagFilter(TextureMagFilter::Linear)
			.WrapS(TextureWrap::Repeat)
			.WrapT(TextureWrap::Repeat)
			.Image2D(
				images::BrushedMetalUByte(
					512, 512,
					5120,
					-3, +3,
					32, 128
				)
			).GenerateMipmap();

		Texture::Active(1);
		metal_prog.frame_shadow_tex.Set(1);
		glass_prog.frame_shadow_tex.Set(1);

		gl.Bound(Texture::Target::_2D, frame_shadow_tex)
			.MinFilter(TextureMinFilter::Linear)
			.MagFilter(TextureMagFilter::Linear)
			.WrapS(TextureWrap::ClampToEdge)
			.WrapT(TextureWrap::ClampToEdge)
			.CompareMode(TextureCompareMode::CompareRefToTexture)
			.Image2D(
				0,
				PixelDataInternalFormat::DepthComponent32,
				shadow_tex_side, shadow_tex_side,
				0,
				PixelDataFormat::DepthComponent,
				PixelDataType::Float,
				nullptr
			);

		gl.Bound(Framebuffer::Target::Draw, frame_shadow_fbo)
			.AttachTexture(
				FramebufferAttachment::Depth,
				frame_shadow_tex,
				0
			);

		Texture::Active(2);
		metal_prog.glass_shadow_tex.Set(2);

		gl.Bound(Texture::Target::_2D, glass_shadow_tex)
			.MinFilter(TextureMinFilter::Linear)
			.MagFilter(TextureMagFilter::Linear)
			.WrapS(TextureWrap::ClampToEdge)
			.WrapT(TextureWrap::ClampToEdge)
			.Image2D(
				0,
				PixelDataInternalFormat::RGBA,
				shadow_tex_side, shadow_tex_side,
				0,
				PixelDataFormat::RGBA,
				PixelDataType::UnsignedByte,
				nullptr
			);

		gl.Bound(Framebuffer::Target::Draw, glass_shadow_fbo)
			.AttachTexture(
				FramebufferAttachment::Color,
				glass_shadow_tex,
				0
			);

		gl.ClearDepth(1.0f);
		gl.Enable(Capability::DepthTest);
		gl.Enable(Capability::CullFace);

		gl.BlendFunc(BlendFn::SrcAlpha, BlendFn::OneMinusSrcAlpha);

		gl.PolygonOffset(1.0, 1.0);

	}
Exemplo n.º 8
0
	void RenderImage(
		double time,
		const Mat4f& torus_matrix,
		const Mat4f& light_proj_matrix
	)
	{
		// this is going into the on-screen framebuffer
		DefaultFramebuffer().Bind(Framebuffer::Target::Draw);

		gl.ClearColor(1.0f, 0.9f, 0.8f, 0.0f);
		gl.Viewport(width, height);
		gl.Clear().ColorBuffer().DepthBuffer();
		gl.CullFace(Face::Back);
		//
		transf_prog.light_proj_matrix.Set(light_proj_matrix);

		Mat4f perspective = CamMatrixf::PerspectiveX(
			Degrees(60),
			float(width)/height,
			1, 60
		);

		// setup the camera
		Vec3f camera_target(0.0f, 0.8f, 0.0f);
		auto camera = CamMatrixf::Orbiting(
			camera_target,
			GLfloat(7.0 - SineWave(time / 14.0)*3.0),
			FullCircles(time / 26.0),
			Degrees(45 + SineWave(time / 17.0) * 40)
		);
		Vec3f camera_position = camera.Position();
		transf_prog.camera_matrix.Set(perspective*camera);
		transf_prog.camera_position.Set(camera_position);

		// render into the depth buffer
		shadow_pp.Bind();

		gl.Enable(Capability::PolygonOffsetFill);
		gl.ColorMask(false, false, false, false);

		transf_prog.model_matrix = ModelMatrixf();
		plane.Draw();

		transf_prog.model_matrix.Set(torus_matrix);
		torus.Draw();

		gl.ColorMask(true, true, true, true);
		gl.Disable(Capability::PolygonOffsetFill);

		gl.Enable(Capability::Blend);
		gl.Disable(Capability::Blend);

		// render into the color buffer
		sketch_pp.Bind();

		gl.Enable(Capability::Blend);

		transf_prog.model_matrix = ModelMatrixf();
		transf_prog.texture_matrix.Set(Mat2f(Vec2f(3.0, 0.0), Vec2f(0.0, 3.0)));
		plane.Draw();

		transf_prog.model_matrix.Set(torus_matrix);
		transf_prog.texture_matrix.Set(Mat2f(Vec2f(8.0, 0.0), Vec2f(0.0, 2.0)));
		torus.Draw([](GLuint phase) -> bool { return phase <  4; });
		transf_prog.texture_matrix.Set(Mat2f(Vec2f(0.0, 2.0), Vec2f(8.0, 0.0)));
		torus.Draw([](GLuint phase) -> bool { return phase >= 4; });

		// render the edges
		line_pp.Bind();

		transf_prog.model_matrix = ModelMatrixf();
		plane.DrawEdges();

		transf_prog.model_matrix.Set(torus_matrix);
		torus.DrawEdges();

		gl.Disable(Capability::Blend);
	}
Exemplo n.º 9
0
	SketchExample(void)
	 : transf_prog()
	 , sketch_prog()
	 , plane(
		transf_prog,
		shapes::Plane(
			Vec3f(0, 0, 0),
			Vec3f(9, 0, 0),
			Vec3f(0, 0,-9),
			9, 9
		)
	), torus(transf_prog, shapes::WickerTorus())
	 , sketch_tex_layers(8)
	 , shadow_tex_side(1024)
	{

		NoProgram().Use();

		shadow_pp.Bind();
		shadow_pp.UseStages(transf_prog).Vertex();
		shadow_pp.UseStages(shadow_prog).Fragment();

		sketch_pp.Bind();
		sketch_pp.UseStages(transf_prog).Vertex();
		sketch_pp.UseStages(sketch_prog).Fragment();

		line_pp.Bind();
		line_pp.UseStages(transf_prog).Vertex();
		line_pp.UseStages(line_prog).Geometry().Fragment();

		Texture::Active(0);
		sketch_prog.sketch_tex.Set(0);
		{
			auto bound_tex = gl.Bound(Texture::Target::_3D, sketch_texture);

			for(GLuint i=0; i<sketch_tex_layers; ++i)
			{
				auto image = images::BrushedMetalUByte(
					512, 512,
					64 + i*128,
					-(2+i*4), +(2+i*4),
					64, 256-i*4
				);
				if(i == 0)
				{
					bound_tex.Image3D(
						0,
						PixelDataInternalFormat::RGB,
						image.Width(),
						image.Height(),
						sketch_tex_layers,
						0,
						image.Format(),
						image.Type(),
						nullptr
					);
				}
				bound_tex.SubImage3D(
					0,
					0, 0, i,
					image.Width(),
					image.Height(),
					1,
					image.Format(),
					image.Type(),
					image.RawData()
				);
			}
			bound_tex.GenerateMipmap();
			bound_tex.MinFilter(TextureMinFilter::LinearMipmapLinear);
			bound_tex.MagFilter(TextureMagFilter::Linear);
			bound_tex.WrapS(TextureWrap::Repeat);
			bound_tex.WrapT(TextureWrap::Repeat);
			bound_tex.WrapR(TextureWrap::ClampToEdge);
		}

		Texture::Active(1);
		sketch_prog.shadow_tex.Set(1);

		gl.Bound(Texture::Target::_2D, shadow_tex)
			.MinFilter(TextureMinFilter::Linear)
			.MagFilter(TextureMagFilter::Linear)
			.WrapS(TextureWrap::ClampToEdge)
			.WrapT(TextureWrap::ClampToEdge)
			.CompareMode(TextureCompareMode::CompareRefToTexture)
			.Image2D(
				0,
				PixelDataInternalFormat::DepthComponent32,
				shadow_tex_side, shadow_tex_side,
				0,
				PixelDataFormat::DepthComponent,
				PixelDataType::Float,
				nullptr
			);

		gl.Bound(Framebuffer::Target::Draw, frame_shadow_fbo)
			.AttachTexture(
				FramebufferAttachment::Depth,
				shadow_tex,
				0
			);

		gl.ClearDepth(1.0f);
		gl.Enable(Capability::DepthTest);
		gl.Enable(Capability::CullFace);

		gl.DepthFunc(CompareFn::LEqual);
		gl.BlendFunc(BlendFn::SrcAlpha, BlendFn::OneMinusSrcAlpha);

		gl.PolygonOffset(1.0, 1.0);
		gl.LineWidth(1.5);

	}
Exemplo n.º 10
0
	TorusExample(void)
	 : make_torus(1.0, 0.5, 18, 36)
	 , torus_instr(make_torus.Instructions())
	 , torus_indices(make_torus.Indices())
	 , vs(ObjectDesc("Vertex"))
	 , gs(ObjectDesc("Geometry"))
	 , face_fs(ObjectDesc("Face fragment"))
	 , frame_fs(ObjectDesc("Frame fragment"))
	 , transf_prog(ObjectDesc("Transformation"))
	 , face_prog(ObjectDesc("Face"))
	 , frame_prog(ObjectDesc("Frame"))
	 , projection_matrix(transf_prog, "ProjectionMatrix")
	 , camera_matrix(transf_prog, "CameraMatrix")
	 , model_matrix(transf_prog, "ModelMatrix")
	 , transf_time(transf_prog, "Time")
	{
		vs.Source(
			"#version 330\n"
			"uniform mat4 ModelMatrix;"
			"in vec4 Position;"
			"in vec3 Normal;"
			"in vec2 TexCoord;"
			"out gl_PerVertex {"
			"	vec4 gl_Position;"
			"};"
			"out vec3 vertNormal;"
			"out vec2 vertTexCoord;"
			"void main(void)"
			"{"
			"	gl_Position = ModelMatrix * Position;"
			"	vertNormal = (ModelMatrix*vec4(Normal,0.0)).xyz;"
			"	vertTexCoord = TexCoord;"
			"}"
		);
		vs.Compile();

		gs.Source(
			"#version 330\n"
			"layout(triangles) in;"
			"layout(triangle_strip, max_vertices = 15) out;"
			"uniform mat4 CameraMatrix, ProjectionMatrix;"
			"uniform vec3 LightPos;"
			"uniform float Time;"
			"in gl_PerVertex {"
			"	vec4 gl_Position;"
			"} gl_in[];"
			"in vec3 vertNormal[];"
			"in vec2 vertTexCoord[];"
			"out gl_PerVertex {"
			"	vec4 gl_Position;"
			"};"
			"out vec3 geomNormal;"
			"out vec3 geomLight;"
			"out float geomGlow;"
			"flat out int geomTop;"
			"void main(void)"
			"{"
			"	vec3 FaceNormal = normalize("
			"		vertNormal[0]+"
			"		vertNormal[1]+"
			"		vertNormal[2] "
			"	);"
			"	vec2 FaceCoord = 0.33333 * ("
			"		vertTexCoord[0]+"
			"		vertTexCoord[1]+"
			"		vertTexCoord[2] "
			"	);"
			"	float Offs = (sin((FaceCoord.s + Time/10.0)* 3.14 * 2.0 * 10)*0.5 + 0.5)*0.4;"
			"	Offs *= cos(FaceCoord.t * 3.1415 * 2.0)*0.5 + 0.51;"

			"	vec3 pos[3], norm[3];"
			"	for(int i=0; i!=3; ++i)"
			"		pos[i] = gl_in[i].gl_Position.xyz;"
			"	for(int i=0; i!=3; ++i)"
			"		norm[i] = cross("
			"			FaceNormal, "
			"			normalize(pos[(i+1)%3] - pos[i])"
			"		);"
			"	vec3 pofs = FaceNormal * Offs;"

			"	geomTop = 0;"
			"	for(int i=0; i!=3; ++i)"
			"	{"
			"		geomNormal = norm[i];"
			"		for(int j=0; j!=2; ++j)"
			"		{"
			"			vec3 tpos = pos[(i+j)%3];"
			"			geomLight = LightPos-tpos;"
			"			geomGlow = 1.0;"
			"			gl_Position = "
			"				ProjectionMatrix *"
			"				CameraMatrix *"
			"				vec4(tpos, 1.0);"
			"			EmitVertex();"
			"			geomGlow = 0.7;"
			"			geomLight = LightPos-tpos+pofs;"
			"			gl_Position = "
			"				ProjectionMatrix *"
			"				CameraMatrix *"
			"				vec4(tpos + pofs, 1.0);"
			"			EmitVertex();"
			"		}"
			"		EndPrimitive();"
			"	}"

			"	geomGlow = 0.0;"
			"	geomTop = 1;"
			"	for(int i=0; i!=3; ++i)"
			"	{"
			"		geomLight = LightPos - (pos[i]+pofs);"
			"		geomNormal = vertNormal[i];"
			"		gl_Position = "
			"			ProjectionMatrix *"
			"			CameraMatrix *"
			"			vec4(pos[i] + pofs, 1.0);"
			"		EmitVertex();"
			"	}"
			"	EndPrimitive();"
			"}"
		);
		gs.Compile();

		transf_prog.AttachShader(vs);
		transf_prog.AttachShader(gs);
		transf_prog.MakeSeparable();
		transf_prog.Link();
		transf_prog.Use();

		ProgramUniform<Vec3f>(transf_prog, "LightPos").Set(4, 4, -8);

		torus.Bind();
		verts.Bind(Buffer::Target::Array);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_torus.Positions(data);
			Buffer::Data(Buffer::Target::Array, data);

			VertexAttribArray attr(transf_prog, "Position");
			attr.Setup(n_per_vertex, DataType::Float);
			attr.Enable();
		}

		normals.Bind(Buffer::Target::Array);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_torus.Normals(data);
			Buffer::Data(Buffer::Target::Array, data);

			VertexAttribArray attr(transf_prog, "Normal");
			attr.Setup(n_per_vertex, DataType::Float);
			attr.Enable();
		}

		texcoords.Bind(Buffer::Target::Array);
		{
			std::vector<GLfloat> data;
			GLuint n_per_vertex = make_torus.TexCoordinates(data);
			Buffer::Data(Buffer::Target::Array, data);

			VertexAttribArray attr(transf_prog, "TexCoord");
			attr.Setup(n_per_vertex, DataType::Float);
			attr.Enable();
		}

		face_fs.Source(
			"#version 330\n"
			"in vec3 geomNormal;"
			"in vec3 geomLight;"
			"in float geomGlow;"
			"flat in int geomTop;"
			"uniform vec3 TopColor, SideColor;"
			"const vec3 LightColor = vec3(1.0, 1.0, 1.0);"
			"out vec4 fragColor;"
			"void main(void)"
			"{"
			"	float d = max(dot("
			"		normalize(geomLight),"
			"		normalize(geomNormal)"
			"	), 0.0);"
			"	vec3 color;"
			"	if(geomTop != 0)"
			"	{"
			"		color = TopColor * d +"
			"			LightColor * pow(d, 8.0);"
			"	}"
			"	else"
			"	{"
			"		color = SideColor * geomGlow +"
			"			LightColor *"
			"			pow(d, 2.0) * 0.2;"
			"	}"
			"	fragColor = vec4(color, 1.0);"
			"}"
		);
		face_fs.Compile();

		face_prog.AttachShader(face_fs);
		face_prog.MakeSeparable();
		face_prog.Link();

		ProgramUniform<Vec3f>(face_prog, "TopColor").Set(0.2f, 0.2f, 0.2f);
		ProgramUniform<Vec3f>(face_prog, "SideColor").Set(0.9f, 0.9f, 0.2f);

		face_pp.Bind();
		face_prog.Use();
		face_pp.UseStages(transf_prog).Vertex().Geometry();
		face_pp.UseStages(face_prog).Fragment();


		frame_fs.Source(
			"#version 330\n"
			"out vec4 fragColor;"
			"void main(void)"
			"{"
			"	fragColor = vec4(0.2, 0.1, 0.0, 1.0);"
			"}"
		);
		frame_fs.Compile();

		frame_prog.AttachShader(frame_fs);
		frame_prog.MakeSeparable();
		frame_prog.Link();

		frame_pp.Bind();
		frame_prog.Use();
		frame_pp.UseStages(transf_prog).Vertex().Geometry();
		frame_pp.UseStages(frame_prog).Fragment();

		ProgramPipeline::Unbind();
		Program::UseNone();

		gl.ClearColor(0.7f, 0.6f, 0.5f, 0.0f);
		gl.ClearDepth(1.0f);
		gl.Enable(Capability::DepthTest);
		gl.DepthFunc(CompareFn::Less);
		gl.FrontFace(make_torus.FaceWinding());
	}