void RenderBox (IMTLRenderCommandEncoder renderEncoder, GameView view, nuint offset, string name)
		{
			renderEncoder.PushDebugGroup (name);
			//  set context state
			renderEncoder.SetRenderPipelineState (pipelineState);
			renderEncoder.SetVertexBuffer (vertexBuffer, 0, 0);
			renderEncoder.SetVertexBuffer (dynamicConstantBuffer [constantDataBufferIndex], offset, 1);

			// tell the render context we want to draw our primitives
			renderEncoder.DrawPrimitives (MTLPrimitiveType.Triangle, 0, 36, 1);
			renderEncoder.PopDebugGroup ();
		}
		public void Render (GameView view)
		{
			inflightSemaphore.WaitOne ();

			PrepareToDraw ();

			IMTLCommandBuffer commandBuffer = commandQueue.CommandBuffer ();
			ICAMetalDrawable drawable = view.GetNextDrawable ();
			MTLRenderPassDescriptor renderPassDescriptor = view.GetRenderPassDescriptor (drawable);

			if (renderPassDescriptor == null)
				Console.WriteLine ("ERROR: Failed to get render pass descriptor from view!");

			IMTLRenderCommandEncoder renderEncoder = commandBuffer.CreateRenderCommandEncoder (renderPassDescriptor);
			renderEncoder.SetDepthStencilState (depthState);

			RenderBox (renderEncoder, view, 0, "Box1");
			RenderBox (renderEncoder, view, (nuint)Marshal.SizeOf<Uniforms> (), "Box2");
			renderEncoder.EndEncoding ();

			commandBuffer.AddCompletedHandler ((IMTLCommandBuffer buffer) => {
				drawable.Dispose ();
				inflightSemaphore.Release ();
			});

			commandBuffer.PresentDrawable (drawable);
			commandBuffer.Commit ();

			constantDataBufferIndex = (constantDataBufferIndex + 1) % max_inflight_buffers;
		}
		public void Configure (GameView view)
		{
			view.DepthPixelFormat = depthPixelFormat;
			view.StencilPixelFormat = stencilPixelFormat;
			view.SampleCount = sampleCount;

			dynamicConstantBuffer = new IMTLBuffer[max_inflight_buffers];

			// allocate one region of memory for the constant buffer
			for (int i = 0; i < max_inflight_buffers; i++) {
				dynamicConstantBuffer [i] = device.CreateBuffer (max_bytes_per_frame, MTLResourceOptions.CpuCacheModeDefault);
				dynamicConstantBuffer [i].Label = string.Format ("ConstantBuffer{0}", i);
			}

			// load the fragment program into the library
			IMTLFunction fragmentProgram = defaultLibrary.CreateFunction ("lighting_fragment");
			if (fragmentProgram == null)
				Console.WriteLine ("ERROR: Couldnt load fragment function from default library");

			// load the vertex program into the library
			IMTLFunction vertexProgram = defaultLibrary.CreateFunction ("lighting_vertex");
			if (vertexProgram == null)
				Console.WriteLine ("ERROR: Couldnt load vertex function from default library");

			// setup the vertex buffers
			vertexBuffer = device.CreateBuffer<float> (cubeVertexData, MTLResourceOptions.CpuCacheModeDefault);
			vertexBuffer.Label = "Vertices";

			//  create a reusable pipeline state
			var pipelineStateDescriptor = new MTLRenderPipelineDescriptor {
				Label = "MyPipeline",
				SampleCount = sampleCount,
				VertexFunction = vertexProgram,
				FragmentFunction = fragmentProgram,
				DepthAttachmentPixelFormat = depthPixelFormat
			};

			pipelineStateDescriptor.ColorAttachments [0].PixelFormat = MTLPixelFormat.BGRA8Unorm;

			NSError error;
			pipelineState = device.CreateRenderPipelineState (pipelineStateDescriptor, out error);

			var depthStateDesc = new MTLDepthStencilDescriptor {
				DepthCompareFunction = MTLCompareFunction.Less,
				DepthWriteEnabled = true
			};

			depthState = device.CreateDepthStencilState (depthStateDesc);
		}
		public void Reshape (GameView view)
		{
			var aspect = (float)(view.Bounds.Size.Width / view.Bounds.Size.Height);
			projectionMatrix = CreateMatrixFromPerspective (FOVY, aspect, 0.1f, 100.0f);
			viewMatrix = LookAt (eye, center, up);
		}