Example(GLuint width, GLuint height)
	 : log_sink(
		[](const oglplus::ARB_debug_output::CallbackData& data) -> void
		{
			std::cout << "[" << data.id << "] '" <<
				data.message << "'" << std::endl;
			std::cout << "  [source]   '" <<
				oglplus::EnumValueName(data.source)  << "'" <<
				std::endl;
			std::cout << "  [type]     '" <<
				oglplus::EnumValueName(data.type)  << "'" <<
				std::endl;
			std::cout << "  [severity] '" <<
				oglplus::EnumValueName(data.severity)  << "'" <<
				std::endl;
		}
	)
	{
		using namespace oglplus;

		dbg.Control(
			DebugOutputARBSource::DontCare,
			DebugOutputARBType::DontCare,
			DebugOutputARBSeverity::Low,
			true
		);

		gl.ClearColor(1.0f, 1.0f, 1.0f, 0.0f);
		gl.Viewport(width, height);

		glc.MatrixMode(CompatibilityMatrixMode::Projection);
		glc.LoadIdentity();
		glc.MatrixMode(CompatibilityMatrixMode::Modelview);
		glc.LoadIdentity();
	}
예제 #2
0
	DSATextureExample(int /*argc*/, const char** /*argv*/)
	 : gl()
	 , prog(make_prog())
	 , projection_matrix(prog, "ProjectionMatrix")
	 , camera_matrix(prog, "CameraMatrix")
	 , model_matrix(prog, "ModelMatrix")
	 , textured_cube(
		oglplus::List("Position")("Normal")("TexCoord").Get(),
		oglplus::shapes::Cube(),
		prog
	)
	{
		using namespace oglplus;

		checker.target = Texture::Target::_2D;
		checker.Image2D(images::CheckerRedBlack(256, 256, 8, 8));
		checker.GenerateMipmap();
		checker.MinFilter(TextureMinFilter::LinearMipmapLinear);
		checker.MagFilter(TextureMagFilter::Linear);
		checker.Anisotropy(2.0);
		checker.WrapS(TextureWrap::Repeat);
		checker.WrapT(TextureWrap::Repeat);
		checker.Bind();
		(prog/"Checker") = 0;
		(prog/"LightPos") = Vec3f(10.0f, 20.0f, 30.0f);

		gl.ClearColor(0.3f, 0.3f, 0.3f, 0.0f);
		gl.ClearDepth(1.0f);
		gl.Enable(Capability::DepthTest);
		gl.Enable(Capability::CullFace);
	}
예제 #3
0
//------------------------------------------------------------------------------
void Example::RenderFrame(double /*time*/)
{
	bool dragging = mouse_left_down || mouse_middle_down;

	if(dragging && (frame_no % 2))
	{
		gl.Scissor(
			mouse_x-screen_width/(view_divs*2),
			mouse_y-screen_height/(view_divs*2),
			screen_width/view_divs,
			screen_height/view_divs
		);
	}
	else
	{
		unsigned this_tile = view_tile_index[view_tile];
		gl.Scissor(
			(this_tile % view_divs)*screen_width/view_divs,
			(this_tile / view_divs)*screen_height/view_divs,
			screen_width/view_divs+1,
			screen_height/view_divs+1
		);

		if(++view_tile >= (dragging?view_divs:view_divs*view_divs))
		{
			view_tile = 0;
		}
	}

	screen.Draw();
	++frame_no;
}
	void Render(void)
	{
		using namespace oglplus;

		double t = FrameTime();

		gl.Clear().ColorBuffer().DepthBuffer();
		//
		auto camera = CamMatrixf::Orbiting(
			camera_target,
			camera_distance,
			-FullCircles(t / 17.0),
			Degrees(SineWave(t / 41.0) * 85)
		);
		camera_matrix.Set(camera);
		camera_position.Set(camera.Position());

		light_position.Set(
			CamMatrixf::Orbiting(
				camera_target,
				camera_distance*2.0,
				FullCircles(t / 37.0),
				Degrees(SineWave(t / 31.0) * 85)
			).Position()
		);

		face_normals.Set(int(t*0.25) % 2);

		gl.DrawElements(
			PrimitiveType::TriangleFan,
			element_count,
			DataType::UnsignedInt
		);
	}
예제 #5
0
  void drawScene() {
    gl.ClearColor(0.2, 0.2, 0.2, 1.0);
    gl.Clear().ColorBuffer().DepthBuffer();
    gl.Viewport(0, 0, 640, 480);

    // draw GUI
    System::getSingleton().renderAllGUIContexts();
  }
예제 #6
0
	void Render(void)
	{
		gl.Clear().ColorBuffer();

		gl.DrawArrays(
			oglplus::PrimitiveType::Triangles,
			0, 3
		);
	}
예제 #7
0
void FullscreenQuad::DrawElements() const
{
    static oglplus::Context gl;
    fsQuadVertexArray.Bind();
    gl.DrawElements(
        oglplus::PrimitiveType::Triangles, 6,
        oglplus::DataType::UnsignedInt
    );
}
예제 #8
0
    void Render() {
        using namespace oglplus;

        gl.Clear().ColorBuffer().StencilBuffer();

        glc.Color(0.2, 0.2, 1.0);

        text_path.StencilFillInstanced(
          glyph_indices,
          PathNVFillMode::CountUp,
          0xFF,
          PathNVTransformType::TranslateX,
          glyph_spacings);
        text_path.CoverFillInstanced(
          glyph_indices,
          PathNVFillCoverMode::BoundingBoxOfBoundingBoxes,
          PathNVTransformType::TranslateX,
          glyph_spacings);

        glc.Color(0.0, 0.0, 0.0);

        text_path.StencilStrokeInstanced(
          glyph_indices,
          1,
          ~0,
          PathNVTransformType::TranslateX,
          glyph_spacings);
        text_path.CoverStrokeInstanced(
          glyph_indices,
          PathNVStrokeCoverMode::ConvexHull,
          PathNVTransformType::TranslateX,
          glyph_spacings);
    }
    void Render() {
        using namespace oglplus;

        gl.Clear().ColorBuffer().DoIt();

        GLfloat t = GLfloat(FrameTime());

        rndr.Use();

        text_stream.str(std::string());
        text_stream << "Time: " << std::fixed << std::setw(5)
                    << std::setprecision(3) << t << " [s]";
        if(time_str != text_stream.str()) {
            time_str = text_stream.str();
            time_layout.Set(time_str);
        }

        rndr.SetCamera(CamMatrixf::Orbiting(
          Vec3f(),
          GLfloat(9.0 + SineWave(t / 7.0) * 3.0),
          -FullCircles(t / 17.0),
          Degrees(SineWave(t / 21.0) * 35)));

        rndr.SetLayoutTransform(ModelMatrixf::Translation(-3.0f, 0.7f, 1.1f));
        rndr.Render(oglp_layout);

        rndr.SetLayoutTransform(ModelMatrixf::Translation(-6.0f, -0.7f, 0.0f));
        rndr.Render(desc_layout);

        rndr.SetLayoutTransform(
          ModelMatrixf::Translation(-4.0f, -2.0f, -0.5f) *
          ModelMatrixf::Scale(0.7f, 0.7f, 0.5f));
        rndr.Render(time_layout);
    }
    void Reshape() {
        using namespace oglplus;

        gl.Viewport(Width(), Height());

        rndr.SetProjection(
          CamMatrixf::PerspectiveX(Degrees(60), Width() / Height(), 1, 60));
    }
예제 #11
0
	STBTruetypeExample(int argc, const char** argv)
	 : gl()
	 , tr(oglplus::text::STBTrueTypeRendering(0, 1, 2))
	 , font(tr.LoadFont((argc>1)?argv[1]:"FreeSans"))
	 , oglp_layout(tr.MakeLayout(font, "OGLplus"))
	 , desc_layout(tr.MakeLayout(font, u8"a C++ wrapper for OpenGL©"))
	 , time_layout(tr.MakeLayout(font, 25))
	 , rndr(tr.GetRenderer(
			oglplus::FragmentShader(
				oglplus::ObjectDesc("Pixel color"),
				oglplus::StrCRef(
				"#version 330\n"
				"vec4 PixelColor("
				"	vec4 TexelColor,"
				"	vec3 GlyphPosition,"
				"	float GlyphXOffset,"
				"	vec2 GlyphExtent,"
				"	vec2 GlyphCoord,"
				"	float LayoutWidth"
				")"
				"{"
				"	float g = GlyphXOffset / LayoutWidth;"
				"	float b = GlyphCoord.y;"
				"	vec3 Color = mix("
				"		vec3(1.0, 0.2, 0.2+0.8*b), "
				"		vec3(0.2, 1.0, 0.2+0.8*b), "
				"		g"
				"	);"
				"	return vec4(Color, TexelColor.r);"
				"}")
			)
		)
	)
	{
		using namespace oglplus;

		rndr.Use();

		gl.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		gl.Enable(Capability::Blend);
		gl.BlendFunc(
			BlendFunction::SrcAlpha,
			BlendFunction::DstAlpha
		);
	}
예제 #12
0
	void Render(void)
	{
		gl.Clear().ColorBuffer().DepthBuffer();
		//
		oglplus::Uniform<GLfloat>(prog, "Time") = FrameTime();

		// draw 36 instances of the cube
		// the vertex shader will take care of their placement
		cube_instr.Draw(cube_indices, 36);
	}
예제 #13
0
//------------------------------------------------------------------------------
void Example::Resize(int width, int height)
{
	if((width > 0) && (height > 0))
	{
		screen_width = width;
		screen_height = height;
		view_aspect = float(width)/float(height);
	}
	gl.Viewport(0, 0, width, height);
}
예제 #14
0
	PangoCairoTextExample(int argc, const char** argv)
	 : gl()
	 , tr(0)
	 , font(tr.LoadFont((argc>2)?argv[2]:"Sans 38"))
	 , layout(tr.MakeLayout(font, 48))
	 , rndr(tr.GetRenderer(
			oglplus::FragmentShader(
				oglplus::ObjectDesc("Pixel color"),
				"#version 330\n"
				"uniform vec3 Color;"
				"uniform float Opacity;"
				"vec4 PixelColor("
				"	vec4 TexelColor,"
				"	vec3 GlyphPosition,"
				"	float GlyphXOffset,"
				"	vec2 GlyphExtent,"
				"	vec2 GlyphCoord,"
				"	float LayoutWidth"
				")"
				"{"
				"	return vec4(Color, TexelColor.r*Opacity);"
				"}"
			)
		)
	), rndr_color(rndr.GetUniform<oglplus::Vec3f>("Color"))
	 , rndr_opacity(rndr.GetUniform<GLfloat>("Opacity"))
	 , prev_interval(-1)
	 , current_line(0)
	{
		using namespace oglplus;

		rndr.Use();

		gl.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		gl.Enable(Capability::Blend);
		gl.BlendFunc(
			BlendFunction::SrcAlpha,
			BlendFunction::DstAlpha
		);

		rndr.SetAlignment(text::Alignment::Center);
	}
예제 #15
0
	void Display(void)
	{
		using namespace oglplus;

		gl.BlitFramebuffer(
			0, 0, width, height,
			0, height, width, 0,
			BufferSelectBit::ColorBuffer,
			BlitFilter::Nearest
		);
	}
예제 #16
0
	void Reshape(void)
	{
		using namespace oglplus;

		gl.Viewport(Width(), Height());

		projection_matrix.Set(
			CamMatrixf::PerspectiveX(
				Degrees(60),
				Aspect(),
				1, 50
			)
		);
	}
	void Reshape(void)
	{
		using namespace oglplus;

		gl.Viewport(Width(), Height());

		Uniform<Mat4f>(prog, "ProjectionMatrix").Set(
			CamMatrixf::PerspectiveX(
				Degrees(60),
				Aspect(),
				1, 70
			)
		);
	}
예제 #18
0
	void Reshape(void)
	{
		gl.Viewport(Width(), Height());

		auto camera = glm::perspective(
			53.0f,
			GLfloat(Aspect()),
			1.0f, 100.0f
		) * glm::lookAt(
			glm::vec3(21.0f, 7.0f, 0.0f),
			glm::vec3( 0.0f, 0.0f, 0.0f),
			glm::vec3( 0.0f, 1.0f, 0.0f)
		);
		oglplus::Uniform<oglplus::Mat4f>(prog, "CameraMatrix").Set(camera);
	}
예제 #19
0
	PathExample(int, const char**)
	{
		using namespace oglplus;

		PathNVCommand commands[] = {
			PathNVCommand::MoveTo,
			PathNVCommand::LineTo,
			PathNVCommand::LineTo,
			PathNVCommand::LineTo,
			PathNVCommand::LineTo,
			PathNVCommand::Close
		};

		GLfloat coords[] = {
			 0.00, 0.85,
			 0.65,-0.80,
			-0.85, 0.30,
			 0.85, 0.30,
			-0.65,-0.80
		};

		path.Commands(
			sizeof(commands)/sizeof(commands[0]),
			commands,
			sizeof(coords)/sizeof(coords[0]),
			coords
		);

		path.StrokeWidth(0.01);
		path.JoinStyle(PathNVJoinStyle::Round);

		GLfloat dash_array[] = {0.05, 0.02};

		path.DashArray(
			sizeof(dash_array)/sizeof(dash_array[0]),
			dash_array
		);

		glc.MatrixMode(CompatibilityMatrixMode::Projection);
		glc.LoadIdentity();
		glc.MatrixMode(CompatibilityMatrixMode::Modelview);
		glc.LoadIdentity();

		gl.ClearColor(1.0f, 1.0f, 1.0f, 0.0f);
		gl.ClearStencil(0);
		gl.StencilMask(~0);
		gl.StencilFunc(CompareFunction::NotEqual, 0, 0x1F);
		gl.StencilOp(
			StencilOperation::Keep,
			StencilOperation::Keep,
			StencilOperation::Zero
		);

		gl.Enable(Capability::StencilTest);
	}
예제 #20
0
	void Render(void)
	{
		using namespace oglplus;

		gl.Clear().ColorBuffer().StencilBuffer();

		glc.Color(0.2, 0.2, 1.0);

		path.StencilFill(PathNVFillMode::CountUp, 0x1F);
		path.CoverFill(PathNVFillCoverMode::BoundingBox);

		glc.Color(0.1, 0.1, 0.1);

		path.StencilStroke(1, ~0);
		path.CoverStroke(PathNVStrokeCoverMode::ConvexHull);
	}
	void Display(void)
	{
		using namespace oglplus;

		gl.Clear().ColorBuffer();

		glc.Begin(CompatibilityPrimitiveType::Triangles);
			glc.Color(1.0, 0.0, 0.0);
			glc.Vertex(0.0f, 0.0f);

			glc.Color(0.0, 1.0, 0.0);
			glc.Vertex(1.0f, 0.0f);

			glc.Color(0.0, 0.0, 1.0);
			glc.Vertex(0.0f, 1.0f);
		glc.End();
	}
예제 #22
0
	void Render(void)
	{
		using namespace oglplus;

		gl.Clear().ColorBuffer().StencilBuffer();

		auto h = Height();
		int l = font_height / 2, i = 1;
		RenderText(l, h - font_height*i++, "NV_path_rendering");

		{
			std::stringstream s;
			s << "Frame no.: " << FrameNumber();
			RenderText(l, h - font_height*i++, s.str());
		}
		{
			std::stringstream s;
			s << std::fixed << std::setprecision(2);
			s << "Time: " << FrameTime() << " [s]";
			RenderText(l, h - font_height*i++, s.str());
		}
		{
			std::stringstream s;
			s << std::fixed << std::setprecision(2);
			s << "Average FPS: " << (FrameTime()>0.0 ? AverageFPS() : 0.0);
			RenderText(l, h - font_height*i++, s.str());
		}
		{
			std::stringstream s;
			s << std::fixed << std::setprecision(2);
			s << "Current FPS: " << (FrameDuration()>0.0 ? CurrentFPS() : 0.0);
			RenderText(l, h - font_height*i++, s.str());
		}
		{
			std::stringstream s;
			s << "Viewport: " << Width() << " x " << Height();
			RenderText(l, h - font_height*i++, s.str());
		}
		{
			std::stringstream s;
			s << std::fixed << std::setprecision(3);
			s << "Aspect ratio: " << Aspect();
			RenderText(l, h - font_height*i++, s.str());
		}
	}
예제 #23
0
	void Render(void)
	{
		using namespace oglplus;

		gl.Clear().ColorBuffer().DepthBuffer();

		camera_matrix.Set(
			CamMatrixf::Orbiting(
				Vec3f(),
				9.5 - SineWave(FrameTime() / 6.0) * 7.0,
				FullCircles(FrameTime() / 9.0),
				Degrees(SineWave(FrameTime() / 30.0) * 90)
			)
		);

		model_matrix.Set(ModelMatrixf::RotationX(FullCircles(FrameTime() * 0.1)));

		textured_cube.Draw();
	}
예제 #24
0
	void Reshape(void)
	{
		using namespace oglplus;

		gl.Viewport(Width(), Height());

		dsa.ProjectionMatrix()
			.LoadIdentity()
			.Ortho(0, Width(), 0, Height(), -1, 1);

		GLfloat font_min_max[2];
		text_glyphs.GetMetricRange(
			PathNVMetricQuery::FontYMinBounds|
			PathNVMetricQuery::FontYMaxBounds,
			1, 0,
			font_min_max
		);
		font_y_min = font_min_max[0];
		font_y_max = font_min_max[1];
		font_height = font_y_max - font_y_min;
	}
예제 #25
0
	void Render(void)
	{
		using namespace oglplus;

		GLfloat t = GLfloat(FrameTime());
		GLfloat i = t*0.3f;
		int interval = int(i);
		GLfloat f = i - GLfloat(interval);
		if(prev_interval < interval)
		{
			LoadNext();
			prev_interval = interval;
		}

		gl.Clear().ColorBuffer().DoIt();

		rndr_opacity.Set(SineWave(f*0.5f));

		rndr.SetLayoutTransform(ModelMatrixf::TranslationZ(-20.0f+16.0f*f));
		rndr.Render(layout);
	}
예제 #26
0
	TriangleExample(void)
	 : gl()
	 , prog(make_prog())
	{
		triangle.Bind();
		GLfloat triangle_pos[9] = {
			-1.0f,-1.0f, 0.0f,
			 1.0f,-1.0f, 0.0f,
			-1.0f, 1.0f, 0.0f
		};

		positions.Bind(oglplus::Buffer::Target::Array);

		oglplus::Buffer::Data(
			oglplus::Buffer::Target::Array,
			triangle_pos
		);

		oglplus::VertexAttribArray(prog, "Position")
			.Setup<GLfloat>(3)
			.Enable();

		gl.ClearColor(1.0, 0.0, 1.0, 0.0);
	}
예제 #27
0
	TextExample(int /*argc*/, const char** /*argv*/)
	 : text_glyphs(128)
	{
		using namespace oglplus;

		GLfloat font_scale = 48;

		text_glyphs.GlyphRange(
			PathNVFontTarget::Standard,
			"Sans",
			PathNVFontStyle::Bold,
			0, 128,
			PathNVMissingGlyph::Use,
			~0,
			font_scale
		);

		GLfloat color_gen_coeffs[9] = {
			-0.6f, 0.0f, 0.8f,
			 0.0f, 0.0f, 0.0f,
			 0.5f, 0.0f, 0.5f
		};
		npr.ColorGen(
			PathNVColor::Primary,
			PathNVGenMode::ObjectBoundingBox,
			PathNVColorFormat::RGB,
			color_gen_coeffs
		);

		gl.ClearColor(1.0f, 1.0f, 1.0f, 0.0f);
		gl.ClearStencil(0);
		gl.StencilMask(~0);
		gl.StencilFunc(CompareFunction::NotEqual, 0, 0xFF);
		gl.StencilOp(
			StencilOperation::Keep,
			StencilOperation::Keep,
			StencilOperation::Zero
		);

		gl.Enable(Capability::StencilTest);
	}
	BitmapGlyphExample(int argc, const char** argv)
	 : gl()
	 , tr(0, 1, 2)
	 , font(tr.LoadFont((argc>1)?argv[1]:"Sans"))
	 , oglp_layout(tr.MakeLayout(font, "OGLplus"))
#if !OGLPLUS_NO_UNICODE_LITERALS
	 , desc_layout(tr.MakeLayout(font, u8"a C++ wrapper for OpenGL©"))
#else
	 , desc_layout(tr.MakeLayout(font, "a C++ wrapper for OpenGL(c)"))
#endif
	 , time_layout(tr.MakeLayout(font, 25))
	 , rndr(tr.GetRenderer(
			oglplus::GeometryShader(
				oglplus::ObjectDesc("Layout transform"),
				"#version 150\n"
				"uniform mat4  ProjectionMatrix,CameraMatrix,LayoutMatrix;"
				"mat4 Matrix = ProjectionMatrix*CameraMatrix*LayoutMatrix;"

				"vec4 TransformLayout(vec3 GlyphPosition)"
				"{"
				"	return Matrix * vec4(GlyphPosition, 1.0);"
				"}"
			),
			oglplus::GeometryShader(
				oglplus::ObjectDesc("Glyph transform"),
				"#version 150\n"
				"uniform float Time;"

				"vec3 TransformGlyph("
				"	vec4 LogicalMetrics,"
				"	vec4 InkMetrics,"
				"	vec2 Pos,"
				"	float XOffs,"
				"	float LayoutWidth,"
				"	int Idx"
				")"
				"{"
				"	float a = Idx*0.7+Time*2.4;"
				"	return vec3("
				"		Pos.x+XOffs,"
				"		Pos.y+sin(a)*0.1,"
				"		cos(a)*0.05"
				"	);"
				"}"
			),
			oglplus::FragmentShader(
				oglplus::ObjectDesc("Pixel color"),
				"#version 150\n"
				"vec4 PixelColor("
				"	vec4 TexelColor,"
				"	vec3 GlyphPosition,"
				"	float GlyphXOffset,"
				"	vec2 GlyphExtent,"
				"	vec2 GlyphCoord,"
				"	float LayoutWidth"
				")"
				"{"
				"	float g = GlyphXOffset / LayoutWidth - GlyphCoord.x;"
				"	vec3 Color = mix("
				"		vec3(1.0, 0.2+0.8*g, 0.2), "
				"		vec3(0.2, 0.2+0.8*g, 1.0), "
				"		(GlyphPosition.z+0.1)/0.2"
				"	);"
				"	return vec4(Color, TexelColor.r);"
				"}"
			)
		)
	), rndr_projection_matrix(rndr.GetUniform<oglplus::Mat4f>("ProjectionMatrix"))
	 , rndr_camera_matrix(rndr.GetUniform<oglplus::Mat4f>("CameraMatrix"))
	 , rndr_layout_matrix(rndr.GetUniform<oglplus::Mat4f>("LayoutMatrix"))
	 , rndr_time(rndr.GetUniform<GLfloat>("Time"))
	{
		using namespace oglplus;

		rndr.Use();

		gl.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		gl.Enable(Capability::Blend);
		gl.BlendFunc(
			BlendFunction::SrcAlpha,
			BlendFunction::DstAlpha
		);
	}
예제 #29
0
	GLMBoxesExample(int, const char**)
	 : cube_instr(make_cube.Instructions())
	 , cube_indices(make_cube.Indices())
	{
		// Set the vertex shader source
		vs.Source(
			"#version 330\n"
			"uniform mat4 CameraMatrix, ScaleMatrix;"
			"uniform vec3 LightPos;"
			"uniform float Time;"
			"in vec4 Position;"
			"in vec3 Normal;"
			"out vec3 vertColor;"
			"void main(void)"
			"{"
			"	float angle = gl_InstanceID * 10 * 2 * 3.14159 / 360.0;"
			"	float ct = cos(angle+Time);"
			"	float st = sin(angle+Time);"
			"	mat4 ModelMatrix = mat4("
			"		 ct, 0.0,  st, 0.0,"
			"		0.0, 1.0, 0.0, 0.0,"
			"		-st, 0.0,  ct, 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 "
			"	) * mat4("
			"		 ct, -st, 0.0, 0.0,"
			"		 st,  ct, 0.0, 0.0,"
			"		0.0, 0.0, 1.0, 0.0,"
			"		0.0, 0.0, 0.0, 1.0 "
			"	);"
			"	gl_Position = "
			"		ModelMatrix *"
			"		ScaleMatrix *"
			"		Position;"

			"	vec3 vertLightDir = normalize(LightPos - gl_Position.xyz);"
			"	vec3 vertNormal = normalize(("
			"		ModelMatrix *"
			"		vec4(Normal, 0.0)"
			"	).xyz);"

			"	gl_Position = CameraMatrix * gl_Position;"

			"	vertColor = abs(normalize("
			"		Normal -"
			"		vec3(1.0, 1.0, 1.0) +"
			"		Position.xyz*0.2"
			"	)) * (0.6 + 0.5*max(dot(vertNormal, vertLightDir), 0.0));"
			"}"
		);
		// compile it
		vs.Compile();

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

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

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

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

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

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

		oglplus::Uniform<oglplus::Vec3f>(prog, "LightPos").Set(
			glm::vec3(7.0, 3.0, -1.0)
		);

		oglplus::Uniform<oglplus::Mat4f>(prog, "ScaleMatrix").Set(
			glm::scale(glm::mat4(1.0), glm::vec3(1.0, 0.3, 1.7))
		);
	}
	BlenderMeshExample(int argc, const char* argv[])
	 : prog()
	 , camera_matrix(prog, "CameraMatrix")
	 , light_position(prog, "LightPosition")
	 , camera_position(prog, "CameraPosition")
	 , face_normals(prog, "FaceNormals")
	 , element_count(0)
	{
		using namespace oglplus;

		VertexShader vs;
		vs.Source(
			"#version 330\n"
			"uniform mat4 CameraMatrix, ProjectionMatrix;"
			"uniform vec3 LightPosition, CameraPosition;"

			"mat4 Matrix = ProjectionMatrix * CameraMatrix;"

			"in vec3 Position;"
			"in vec3 Normal;"

			"out vec3 vertNormal;"
			"out vec3 vertLightDir;"
			"out vec3 vertViewDir;"

			"void main(void)"
			"{"
			"	vertNormal = Normal;"
			"	vertLightDir = LightPosition - Position;"
			"	vertViewDir = CameraPosition - Position;"
			"	gl_Position = Matrix * vec4(Position, 1.0);"
			"}"
		);
		vs.Compile();
		prog.AttachShader(vs);

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

			"uniform bool FaceNormals;"

			"in vec3 vertNormal[3];"
			"in vec3 vertLightDir[3];"
			"in vec3 vertViewDir[3];"

			"out vec3 geomNormal;"
			"out vec3 geomLightDir;"
			"out vec3 geomViewDir;"

			"void main(void)"
			"{"
			"	vec3 fn;"
			"	if(FaceNormals)"
			"	{"
			"		vec3 p0 = gl_in[0].gl_Position.xyz;"
			"		vec3 p1 = gl_in[1].gl_Position.xyz;"
			"		vec3 p2 = gl_in[2].gl_Position.xyz;"
			"		fn = normalize(cross(p1-p0, p2-p0));"
			"	}"

			"	for(int v=0; v!=3; ++v)"
			"	{"
			"		gl_Position = gl_in[v].gl_Position;"
			"		if(FaceNormals) geomNormal = fn;"
			"		else geomNormal = vertNormal[v];"
			"		geomLightDir = vertLightDir[v];"
			"		geomViewDir = vertViewDir[v];"
			"		EmitVertex();"
			"	}"
			"	EndPrimitive();"
			"}"
		);
		gs.Compile();
		prog.AttachShader(gs);

		FragmentShader fs;
		fs.Source(
			"#version 330\n"

			"in vec3 geomNormal;"
			"in vec3 geomLightDir;"
			"in vec3 geomViewDir;"

			"out vec3 fragColor;"

			"void main(void)"
			"{"
			"	vec3 LightColor = vec3(1.0, 1.0, 1.0);"
			"	vec3 MatColor = vec3(0.5, 0.5, 0.5);"

			"	vec3 LightRefl = reflect(-geomLightDir, geomNormal);"

			"	float Ambient = 0.3;"
			"	float Diffuse = max(dot("
			"		normalize(geomNormal),"
			"		normalize(geomLightDir)"
			"	), 0.0);"

			"	float Contour = pow((1.0 - max(dot("
			"		normalize(geomNormal),"
			"		normalize(geomViewDir)"
			"	)-0.1, 0.0))*1.05, 4.0);"

			"	float Specular = pow(clamp(dot("
			"		normalize(geomViewDir),"
			"		normalize(LightRefl)"
			"	)+0.005, 0.0, 0.98), 64.0);"

			"	fragColor = MatColor * LightColor * (Contour + Diffuse + Ambient)+"
			"			LightColor * Specular;"
			"}"
		);
		fs.Compile();
		prog.AttachShader(fs);

		prog.Link();
		prog.Use();

		gl.PrimitiveRestartIndex(0);
		// vectors with vertex position and normals
		// the values at index 0 is unused
		// 0 is used as primitive restart index
		std::vector<GLfloat> pos_data(3, 0.0);
		std::vector<GLfloat> nml_data(3, 0.0);
		// index offset starting at 1
		GLuint index_offset = 1;
		// vectors with vertex indices
		std::vector<GLuint> idx_data(1, 0);

		// open an input stream
		std::ifstream input(argc>1? argv[1]: "./test.blend");
		// check if we succeeded
		if(!input.good())
			throw std::runtime_error("Error opening file for reading");
		// parse the input stream
		imports::BlendFile blend_file(input);
		// get the file's global block
		auto glob_block = blend_file.StructuredGlobalBlock();

		// get the default scene
		auto scene_data = blend_file[glob_block.curscene];
		//
		// get the pointer to the first object in the scene
		auto object_link_ptr = scene_data.Field<void*>("base.first").Get();
		// and go through the whole list of objects
		while(object_link_ptr)
		{
			// for each list element open the linked list block
			auto object_link_data = blend_file[object_link_ptr];
			// get the pointer to its object
			auto object_ptr = object_link_data.Field<void*>("object").Get();
			// open the object block (if any)
			if(object_ptr) try
			{
				auto object_data = blend_file[object_ptr];
				// get the data pointer
				auto object_data_ptr = object_data.Field<void*>("data").Get();
				// open the data block (if any)
				if(object_data_ptr)
				{
					auto object_data_data = blend_file[object_data_ptr];
					// if it is a mesh
					if(object_data_data.StructureName() == "Mesh")
					{
						// get the object matrix field
						auto object_obmat_field = object_data.Field<float>("obmat");
						// make a transformation matrix
						Mat4f obmat(
							object_obmat_field.Get(0, 0),
							object_obmat_field.Get(0, 4),
							object_obmat_field.Get(0, 8),
							object_obmat_field.Get(0,12),

							object_obmat_field.Get(0, 1),
							object_obmat_field.Get(0, 5),
							object_obmat_field.Get(0, 9),
							object_obmat_field.Get(0,13),

							object_obmat_field.Get(0, 2),
							object_obmat_field.Get(0, 6),
							object_obmat_field.Get(0,10),
							object_obmat_field.Get(0,14),

							object_obmat_field.Get(0, 3),
							object_obmat_field.Get(0, 7),
							object_obmat_field.Get(0,11),
							object_obmat_field.Get(0,15)
						);
						// the number of vertices
						std::size_t n_verts = 0;
						// get the vertex block pointer
						auto vertex_ptr = object_data_data.Field<void*>("mvert").Get();
						// open the vertex block (if any)
						if(vertex_ptr)
						{
							auto vertex_data = blend_file[vertex_ptr];
							// get the number of vertices in the block
							n_verts = vertex_data.BlockElementCount();
							// get the vertex coordinate and normal fields
							auto vertex_co_field = vertex_data.Field<float>("co");
							auto vertex_no_field = vertex_data.Field<short>("no");
							// make two vectors of position and normal data
							std::vector<GLfloat> ps(3 * n_verts);
							std::vector<GLfloat> ns(3 * n_verts);
							for(std::size_t v=0; v!=n_verts; ++v)
							{
								// (transpose y and z axes)
								// get the positional coordinates
								Vec4f position(
									vertex_co_field.Get(v, 0),
									vertex_co_field.Get(v, 1),
									vertex_co_field.Get(v, 2),
									1.0f
								);
								Vec4f newpos = obmat * position;
								ps[3*v+0] = newpos.x();
								ps[3*v+1] = newpos.z();
								ps[3*v+2] =-newpos.y();
								// get the normals
								Vec4f normal(
									vertex_no_field.Get(v, 0),
									vertex_no_field.Get(v, 1),
									vertex_no_field.Get(v, 2),
									0.0f
								);
								Vec4f newnorm = obmat * normal;
								ns[3*v+0] = newnorm.x();
								ns[3*v+1] = newnorm.z();
								ns[3*v+2] =-newnorm.y();
							}
							// append the values
							pos_data.insert(pos_data.end(), ps.begin(), ps.end());
							nml_data.insert(nml_data.end(), ns.begin(), ns.end());
						}

						// get the face block pointer
						auto face_ptr = object_data_data.Field<void*>("mface").Get();
						// open the face block (if any)
						if(face_ptr)
						{
							auto face_data = blend_file[face_ptr];
							// get the number of faces in the block
							std::size_t n_faces = face_data.BlockElementCount();
							// get the vertex index fields of the face
							auto face_v1_field = face_data.Field<int>("v1");
							auto face_v2_field = face_data.Field<int>("v2");
							auto face_v3_field = face_data.Field<int>("v3");
							auto face_v4_field = face_data.Field<int>("v4");
							// make a vector of index data
							std::vector<GLuint> is(5 * n_faces);
							for(std::size_t f=0; f!=n_faces; ++f)
							{
								// get face vertex indices
								int v1 = face_v1_field.Get(f);
								int v2 = face_v2_field.Get(f);
								int v3 = face_v3_field.Get(f);
								int v4 = face_v4_field.Get(f);

								is[5*f+0] = v1+index_offset;
								is[5*f+1] = v2+index_offset;
								is[5*f+2] = v3+index_offset;
								is[5*f+3] = v4?v4+index_offset:0;
								is[5*f+4] = 0; // primitive restart index
							}
							// append the values
							idx_data.insert(idx_data.end(), is.begin(), is.end());
						}

						// get the poly block pointer
						auto poly_ptr = object_data_data.TryGet<void*>("mpoly", nullptr);
						// and the loop block pointer
						auto loop_ptr = object_data_data.TryGet<void*>("mloop", nullptr);
						// open the poly and loop blocks (if we have both)
						if(poly_ptr && loop_ptr)
						{
							auto poly_data = blend_file[poly_ptr];
							auto loop_data = blend_file[loop_ptr];
							// get the number of polys in the block
							std::size_t n_polys = poly_data.BlockElementCount();
							// get the fields of poly and loop
							auto poly_loopstart_field = poly_data.Field<int>("loopstart");
							auto poly_totloop_field = poly_data.Field<int>("totloop");
							auto loop_v_field = loop_data.Field<int>("v");

							// make a vector of index data
							std::vector<GLuint> is;
							for(std::size_t f=0; f!=n_polys; ++f)
							{
								int ls = poly_loopstart_field.Get(f);
								int tl = poly_totloop_field.Get(f);

								for(int l=0; l!=tl; ++l)
								{
									int v = loop_v_field.Get(ls+l);
									is.push_back(v+index_offset);
								}
								is.push_back(0); // primitive restart index
							}
							// append the values
							idx_data.insert(idx_data.end(), is.begin(), is.end());
						}
						index_offset += n_verts;
					}
				}
			}
			catch(...)
			{ }
			// and get the pointer to the nex block
			object_link_ptr = object_link_data.Field<void*>("next").Get();
		}

		meshes.Bind();

		positions.Bind(Buffer::Target::Array);
		{
			Buffer::Data(Buffer::Target::Array, pos_data);
			VertexAttribArray attr(prog, "Position");
			attr.Setup<GLfloat>(3);
			attr.Enable();
		}

		normals.Bind(Buffer::Target::Array);
		{
			Buffer::Data(Buffer::Target::Array, nml_data);
			VertexAttribArray attr(prog, "Normal");
			attr.Setup<GLfloat>(3);
			attr.Enable();
		}

		indices.Bind(Buffer::Target::ElementArray);
		Buffer::Data(Buffer::Target::ElementArray, idx_data);

		element_count = idx_data.size();

		// find the extremes of the mesh(es)
		GLfloat min_x = pos_data[3], max_x = pos_data[3];
		GLfloat min_y = pos_data[4], max_y = pos_data[4];
		GLfloat min_z = pos_data[5], max_z = pos_data[5];
		for(std::size_t v=1, vn=pos_data.size()/3; v!=vn; ++v)
		{
			GLfloat x = pos_data[v*3+0];
			GLfloat y = pos_data[v*3+1];
			GLfloat z = pos_data[v*3+2];

			if(min_x > x) min_x = x;
			if(min_y > y) min_y = y;
			if(min_z > z) min_z = z;
			if(max_x < x) max_x = x;
			if(max_y < y) max_y = y;
			if(max_z < z) max_z = z;
		}

		// position the camera target
		camera_target = Vec3f(
			(min_x + max_x) * 0.5,
			(min_y + max_y) * 0.5,
			(min_z + max_z) * 0.5
		);
		// and calculate a good value for camera distance
		camera_distance = 1.1*Distance(camera_target, Vec3f(min_x, min_y, min_z))+1.0;


		gl.ClearColor(0.17f, 0.22f, 0.17f, 0.0f);
		gl.ClearDepth(1.0f);
		gl.Enable(Capability::DepthTest);
		gl.Enable(Capability::PrimitiveRestart);

	}