1 module evael.graphics.GraphicsDevice;
2 
3 debug 
4 {
5 	import std.stdio;
6 	import std.format;
7 } 
8 
9 public import evael.graphics.GL;
10 public import derelict.nanovg.nanovg;
11 
12 import evael.graphics.GL;
13 import evael.graphics.shaders.Shader;
14 import evael.graphics.shaders.BasicShader;
15 import evael.graphics.shaders.BasicLightShader;
16 import evael.graphics.Drawable;
17 import evael.graphics.Vertex;
18 import evael.graphics.Texture;
19 import evael.graphics.FrameBuffer;
20 import evael.graphics.Font;
21 import evael.graphics.lights;
22 import evael.graphics.shapes;
23 import evael.graphics.Environment;
24 
25 import evael.system.AssetLoader;
26 
27 import evael.utils.Singleton;
28 import evael.utils.Math;
29 import evael.utils.Size;
30 import evael.utils.Color;
31 
32 import dnogc.DynamicArray;
33 
34 /**
35  * GraphicsDevice
36  */
37 class GraphicsDevice
38 {
39 	mixin Singleton!();
40 
41 	/// Asset loader
42 	private AssetLoader m_assetLoader;
43 
44 	/// Nanovg context
45 	private NVGcontext* m_nvg;
46 
47 	private Size!int m_viewportSize;
48     
49     /// Game resolution
50     private Size!int m_resolution;
51     
52 	/// Matrixes
53 	private mat4 m_viewMatrix, m_projectionMatrix;
54 	private mat4 m_2DprojectionMatrix;
55 
56 	/// Current enabled shader
57 	private Shader m_currentShader;
58 
59 	private Shader m_2dShader;
60 
61 	/// Vertices display mode
62 	private PolygonMode m_polygonMode;
63 
64 	/// Projection type
65 	private ProjectionType m_projectionType;
66 
67     /// List of VAOs
68     private DynamicArray!uint m_vaos;
69     
70 	/// List of generated buffers
71 	private DynamicArray!uint m_buffers;	
72 
73 	private DynamicArray!FrameBuffer m_frameBuffers;
74 
75 	/// Default font
76 	private Font m_defaultFont;
77 
78 	/// Environment
79 	private Environment m_environment;
80 
81 	private Circle m_circle;
82 
83 	/// Shapes vao (lines, circles)
84 	private uint m_shapesVAO;
85 	private uint m_shapesVBO;
86 
87 	/**
88 	 * GraphicsDevice constructor.
89 	 */
90 	private this()
91 	{
92 		this.m_nvg = nvgCreateGL3(NVGcreateFlags.NVG_STENCIL_STROKES | NVGcreateFlags.NVG_DEBUG);
93 
94 		this.m_assetLoader = AssetLoader.getInstance();
95 
96 		this.m_polygonMode = PolygonMode.Fill;
97 		this.resolution = Size!int(1024, 768);
98 
99 		this.initializeOpenGL();
100 		this.initialize2DProjection(this.m_viewportSize);
101 		this.initializePerspectiveProjection(60.0f);
102 
103 		this.m_environment = new Environment(this);
104 
105 		this.m_circle = new Circle(this, 16, 1);
106 		this.m_circle.shader = this.m_assetLoader.load!(BasicLightShader)("colored_primitive");
107 		this.m_circle.initialize();
108 
109 		this.m_shapesVAO = this.generateVAO();
110 		this.m_shapesVBO = this.createVertexBuffer(VertexPositionColor!3.sizeof * 2, null);
111 		this.setVertexBuffer!(VertexPositionColor!3)(this.m_shapesVBO);		
112 
113 		this.bindVAO(0);
114 	}
115 
116 	/**
117 	 * GraphicsDevice destructor.
118 	 */
119 	public void dispose()
120 	{
121 		foreach(id; this.m_buffers)
122 		{
123 			gl.DeleteBuffers(1, &id);
124 		}
125 
126 		foreach(fb; this.m_frameBuffers)
127 		{
128             fb.dispose();
129 		}
130 
131         foreach(vao; this.m_vaos)
132         {
133             gl.DeleteVertexArrays(1, &vao);
134         }
135         
136 		this.m_buffers.dispose();
137 		this.m_frameBuffers.dispose();
138 		this.m_vaos.dispose();
139 
140 		nvgDeleteGL3(this.m_nvg);
141 	}
142 
143 	/**
144 	 * Initializes Opengl.
145 	 */
146 	@nogc
147 	private void initializeOpenGL() const nothrow
148 	{
149    	 	gl.ClearDepth(1.0f);
150 
151    		gl.Enable(GL_BLEND);
152         gl.Enable(GL_DEPTH_TEST);
153 		gl.Enable(GL_MULTISAMPLE); 
154             
155 		gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
156 	}
157 
158 	/**
159 	 * Initializes a perspective projection.
160 	 * Params:
161 	 *		fov:
162 	 * 		nearPlane:
163 	 * 		farPlane:	
164 	 */
165 	public void initializePerspectiveProjection(in float fov, in float nearPlane = 0.1f, in float farPlane = 2000.0f)
166 	{
167 		this.m_projectionType = ProjectionType.Perspective;
168 		this.m_projectionMatrix = perspectiveMatrix(cast(float)fov, this.m_viewportSize.width / this.m_viewportSize.height, nearPlane, farPlane);
169 	}
170 	
171 	/**
172 	 * Initializes an orthographic projection.
173 	 * Params:
174 	 */
175 	public void initializeOrthographicProjection(
176 		in float left, in float right, in float bottom, in float top, in float near = -2000.0f, in float far = 2000.0f
177 	)
178 	{
179 		this.m_projectionType = ProjectionType.Orthographic;
180 		this.m_projectionMatrix = orthoMatrix(
181 			cast(float)left, cast(float)right, cast(float)bottom, cast(float)top,
182 			cast(float)near, cast(float)far
183 		);
184 	}
185 
186 	/**
187 	 * Begin drawing.
188 	 * Params:
189 	 *		color : clear color
190 	 */
191 	@nogc
192 	public void beginScene(in Color color = Color.Black) const nothrow
193 	{
194 		gl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
195 
196 		auto colorf = color.asFloat();
197 		gl.ClearColor(colorf[0], colorf[1], colorf[2], 1.0f); 
198 	}
199 
200 
201 	/**
202 	 * Renders a circle.
203 	 */
204 	public void drawCircle()(in float deltaTime, in auto ref vec3 position, in uint radius)
205 	{
206 		this.m_circle.position = position;
207 		this.m_circle.scale = radius;
208 		this.m_circle.draw(deltaTime);
209 	}
210 
211 	/**
212 	 * Renders a line.
213 	 */
214 	public void drawLine()(in auto ref vec3 a, in auto ref vec3 b) 
215 	{
216 		this.bindTexture(0);
217 		auto shader = this.m_assetLoader.load!(BasicLightShader)("colored_primitive");
218 
219 		this.enableShader(shader);
220 
221 		auto vertices =
222 		[
223 			VertexPositionColor!3(a, Color.Red),
224 			VertexPositionColor!3(b, Color.Red),			
225 		];
226 
227 		this.sendVertexBufferData(this.m_shapesVBO, 0, VertexPositionColor!3.sizeof * vertices.length, vertices.ptr);
228 
229 		this.setMatrix(shader.modelMatrix, mat4.identity.arrayof.ptr);
230 		this.setMatrix(shader.viewMatrix, this.m_viewMatrix.arrayof.ptr);
231 		this.setProjectionMatrix();
232 
233 		this.bindVAO(this.m_shapesVAO);
234 
235 		this.drawPrimitives!(PrimitiveType.Lines)(1);
236 
237 		this.bindVAO(0);
238 
239 		this.disableShader();
240 	}
241 
242 	/**
243 	 * Renders primitives.
244 	 * Params: http://www.opengl.org/sdk/docs/man/html/glDrawArrays.xhtml
245 	 */
246 	@nogc
247 	public void drawPrimitives(PrimitiveType type)(in int count, in int first = 0) const nothrow
248 	{
249 		static if(type == PrimitiveType.Triangle) 
250 		{
251 			gl.DrawArrays(type, first, count * 3);
252 		}
253 		else if(type == PrimitiveType.Lines)
254 		{
255 			gl.DrawArrays(type, first, count * 2);
256 		}
257 		else gl.DrawArrays(type, first, count);
258 	}
259 
260 	/**
261 	 * Renders indexed primitives.
262 	 * Params: https://www.opengl.org/sdk/docs/man/html/glDrawElements.xhtml
263 	 */
264 	@nogc
265 	public void drawIndexedPrimitives(PrimitiveType type)(in int count, in void* offset) const nothrow
266 	{
267 		static if(type == PrimitiveType.Triangle)
268 		{ 
269 			gl.DrawElements(type, count * 3, GL_UNSIGNED_INT, offset);
270 		}
271 		else gl.DrawElements(type, count, GL_UNSIGNED_INT, offset);
272 	}
273 	
274 	@nogc
275 	public void drawIndexedPrimitives(PrimitiveType type)(in int count, in int offset = 0) const nothrow
276 	{
277 		this.drawIndexedPrimitives!(type)(count, cast(void*)offset);
278 	}
279 
280     /**
281      * Generates a vertex array object.
282      */
283 	@nogc
284     public uint generateVAO() nothrow
285     {
286         uint id;
287         gl.GenVertexArrays(1, &id); 
288         gl.BindVertexArray(id);
289         
290         this.m_vaos ~= id;
291         
292         return id;
293     }
294     
295 	/**
296 	 * Generates a buffer object.
297 	 * Params:
298 	 *		type : buffer object type
299 	 */
300 	@nogc
301     public uint generateBuffer(BufferType type) nothrow
302 	{
303 		uint id;
304 		gl.GenBuffers(1, &id);
305 		gl.BindBuffer(type, id);
306 
307 		this.m_buffers ~= id;
308 
309 		return id;
310 	}
311     
312 	/**
313 	 * Generates multiple vertex buffer objects.
314 	 * Params:
315 	 *		type : buffer object type
316 	 *		count : count
317 	 * Todo: nogc
318 	 */
319 	/*@nogc*/ 
320     public uint[] generateBuffers(BufferType type, in int count) nothrow
321 	{
322 		uint[] ids = new uint[count];
323 		gl.GenBuffers(count, ids.ptr);
324 
325 		foreach (id; ids)
326 		{
327 			this.m_buffers ~= id;
328 		}
329 
330 		return ids;
331 	}
332     
333 	/**
334 	 * Generates a buffer object and send data.
335 	 * Params:
336 	 *		type : buffer object type
337 	 *		size : buffer object size
338 	 *		data : data to send
339 	 *		usage : usage type
340 	 */
341 	@nogc
342 	public uint createBuffer(BufferType type, in int size, in void* data, BufferUsage usage = BufferUsage.StaticDraw) nothrow
343 	{
344 		immutable uint id = this.generateBuffer(type);
345 
346 		gl.BufferData(type, size, data, usage);
347 
348 		return id;
349 	}
350 
351 	/**
352 	 * Creates a frame buffet object.
353 	 * Params:
354 	 *		width : 
355 	 *		height : 
356 	 */
357 	public T createFrameBuffer(T)(in int width, in int height) nothrow
358 	{
359 		auto frameBuffer = new T(this, width, height);
360 
361 		this.m_frameBuffers ~= frameBuffer;
362 
363 		gl.BindFramebuffer(GL_FRAMEBUFFER, 0);  
364 
365 		return frameBuffer;
366 	}
367 
368 	/**
369 	 * Creates a vertex buffer object.
370 	 * Params:
371 	 *		size : buffer object size
372 	 *		data : data to send
373 	 *		usage : usage type
374 	 */
375 	@nogc
376 	public uint createVertexBuffer(in int size, in void* data, BufferUsage usage = BufferUsage.StaticDraw) nothrow
377 	{
378 		return this.createBuffer(BufferType.VertexBuffer, size, data, usage);
379 	}
380 	
381 	/**
382 	 * Creates an index buffer object.
383 	 * Params:
384 	 *		size : buffer object size
385 	 *		data : data to send
386 	 */
387 	@nogc
388 	public uint createIndexBuffer(in int size, in void* data) nothrow
389 	{
390 		return this.createBuffer(BufferType.IndexBuffer, size, data);
391 	}
392 
393 	/**
394 	 * Deletes a buffer object.
395 	 * Params:
396 	 *		id : buffer id
397 	 */
398 	public void deleteBuffer(in uint id)
399 	{
400 		gl.DeleteBuffers(1, &id);
401 
402 		foreach (i, bufferId; this.m_buffers)
403 		{
404 			if(bufferId == id)
405 			{
406 				this.m_buffers.remove(i);
407 				break;
408 			}
409 		}
410 	}
411 
412 	/**
413 	 * Allocates and sends data to a vertex buffer object.
414 	 * Params:
415 	 *		vbo : vertex buffer object
416 	 *		data : data to send
417 	 */
418 	@nogc
419 	public uint allocVertexBufferData(in uint id, in int size, in void* data, BufferUsage usage = BufferUsage.StaticDraw) const nothrow
420 	{
421 		this.bindVertexBuffer(id);
422 		gl.BufferData(BufferType.VertexBuffer, size, data, usage);
423 
424 		return size;
425 	}
426 
427 
428 	/**
429 	 * Sends data to vertex buffer object.
430 	 * Params:
431 	 *		 vbo : vertex buffer object
432 	 *		 data : data to send
433 	 */
434 	@nogc
435 	public uint sendVertexBufferData(in uint id, in uint offset, in uint size, in void* data) const nothrow
436 	{
437 		this.bindVertexBuffer(id);
438 		gl.BufferSubData(BufferType.VertexBuffer, offset, size, data);
439 
440 		return offset + size;
441 	}
442 
443 	/**
444 	 * Binds a vertex buffer object for the next drawing operation.
445 	 * Params:
446 	 *		vbo : vertex buffer object to bind
447 	 */
448 	@nogc
449 	public void setVertexBuffer(T, int line = __LINE__, string file = __FILE__)(in uint id) const nothrow
450 	{
451 		this.bindVertexBuffer(id);
452 
453 		enum size = mixin(T.stringof ~ ".sizeof");
454 		
455 		T* nullStruct = null;
456 
457 		foreach (i, member; __traits(allMembers, T))
458 		{
459 			static if (member == "opAssign")
460 			{
461 				continue;
462 			}
463 			else
464 			{
465 				enum UDAs = __traits(getAttributes, mixin(T.stringof ~ "." ~ member));
466 
467 				static assert(UDAs.length > 0, "You need to specify UDA for member " ~ T.stringof ~ "." ~ member);
468 
469 				enum shaderAttribute = UDAs[0];
470 
471 				static if(is(typeof(shaderAttribute) : ShaderAttribute))
472 				{
473 					void* offset = i == 0 ? null : mixin("&nullStruct." ~ member);
474 					
475 					gl.EnableVertexAttribArray(shaderAttribute.layoutIndex);
476 					gl.VertexAttribPointer(
477 						shaderAttribute.layoutIndex, 
478 						shaderAttribute.size, 
479 						shaderAttribute.type, 
480 						shaderAttribute.normalized, 
481 						size, offset
482 					);
483 
484 					version(GLDebug) 
485 					{
486 						pragma(msg, "%s:%d : gl.VertexAttribPointer(%d, %d, %d, %d, %d, %d);".format(file, line, shaderAttribute.layoutIndex,
487 							shaderAttribute.size, 
488 							shaderAttribute.type, 
489 							shaderAttribute.normalized, 
490 							size, 0
491 						));
492 					}
493 				}
494 				else 
495 				{
496 					static assert(false, "UDA defined member " ~ T.stringof ~ "." ~ member ~ " but is not of the good type.");
497 				}
498 			}
499 		}
500 	}
501 
502 	/**
503 	 * Binds a vertex array object.
504 	 * Params:
505 	 *		id : id
506 	 */
507 	@nogc
508 	public void bindVAO(in uint id) const nothrow
509 	{
510 		gl.BindVertexArray(id);
511 	}
512 
513 	/**
514 	 * Binds a vertex buffer object.
515 	 * Params:
516 	 *		id : id
517 	 */
518 	@nogc
519 	public void bindVertexBuffer(in uint id)  const nothrow
520 	{
521 		gl.BindBuffer(BufferType.VertexBuffer, id);
522 	}
523 
524 	/**
525 	 * Binds an index array object.
526 	 * Params:
527 	 *		id : id
528 	 */
529 	@nogc
530 	public void bindIndexBuffer(in uint id) const nothrow 
531 	{
532 		gl.BindBuffer(BufferType.IndexBuffer, id);
533 	}
534 
535 	/**
536 	 * Binds a frame buffer.
537 	 * Params:
538 	 *		id : id
539 	 */
540 	@nogc
541 	public void bindFrameBuffer(in uint id) const nothrow
542 	{
543 		gl.BindFramebuffer(GL_FRAMEBUFFER, id);
544 	}
545 
546 	/**
547 	 * Binds a vertex array object.
548 	 * Params:
549 	 *		id : id
550 	 */
551 	@nogc
552 	public void bindFrameBuffer(FrameBuffer frameBuffer) const nothrow
553 	{
554 		gl.BindFramebuffer(GL_FRAMEBUFFER, frameBuffer.id);
555 	}
556 
557 	/**
558 	 * Enables a shader for the next drawing operation.
559 	 * Params:
560 	 *		shader : shader to enable
561 	 */
562 	@nogc
563 	public void enableShader(Shader shader) nothrow
564 	{
565         gl.UseProgram(shader.programID);
566 		this.m_currentShader = shader;
567 	}
568 
569 	/**
570 	 * Disables last used shader.
571 	 */
572 	@nogc
573 	public void disableShader() const nothrow
574 	{
575         gl.UseProgram(0);
576 	}
577 	
578 	/**
579 	 * Sets environment for the next render (lights, fog...).
580 	 */
581 	@nogc
582 	public void setEnvironment() nothrow
583 	{
584 		this.m_environment.set();
585 	}
586 
587 	/**
588 	 * Binds a texture.
589 	 * Params:
590 	 *		texture : texture to bind
591 	 *		target : texture type
592 	 */
593 	@nogc
594 	public void bindTexture(Texture texture, TextureTarget target = TextureTarget.Texture2D) const nothrow
595 	{
596 		assert(texture !is null);
597 		gl.BindTexture(target, texture.id);
598 	}
599 
600 	/**
601 	 * Binds a texture.
602 	 * Params:
603 	 *		textureId : texture to bind
604 	 *		target : texture type
605 	 */
606 	@nogc
607 	public void bindTexture(in uint textureId, TextureTarget target = TextureTarget.Texture2D) const nothrow
608 	{
609 		gl.BindTexture(target, textureId);
610 	}
611 
612 	/**
613 	 * Unbinds last used texture.
614 	 * Params:
615 	 *		 target : texture type
616 	 */
617 	@nogc
618 	public void clearTexture(TextureTarget target = TextureTarget.Texture2D) const nothrow
619 	{
620 		gl.BindTexture(target, 0);
621 	}
622 
623 	/**
624 	 * Enables GL capability.
625 	 */
626 	@nogc
627 	public void enable(in uint target) const nothrow
628 	{
629 		gl.Enable(target);
630 	}
631 
632 	/**
633 	 * Disables GL capability.
634 	 */
635 	@nogc
636 	public void disable(in uint target) const nothrow
637 	{
638 		gl.Disable(target);
639 	}
640 
641 	/**
642 	 * Switch display mode of vertices.
643 	 */
644 	@nogc
645 	public void switchPolygonMode() nothrow
646 	{
647 		final switch(this.m_polygonMode)
648 		{
649 			case PolygonMode.Fill:
650 				this.m_polygonMode = PolygonMode.Line;
651 				break;
652 			case PolygonMode.Line:
653 				this.m_polygonMode = PolygonMode.Point;
654 				break;
655 			case PolygonMode.Point:
656 				this.m_polygonMode = PolygonMode.Fill;
657 				break;
658 		}
659 
660 		gl.PolygonMode(GL_FRONT_AND_BACK, this.m_polygonMode);
661 	}
662 	
663 	/**
664 	 * Converts screen coordinates to world coordinates.
665 	 * Params:
666 	 * 		mousePosition : mouse position
667 	 */
668 	@nogc
669 	public vec3 getWorldCoordinates(in ref vec2 mousePosition) nothrow
670 	{
671 		immutable mouseY = this.m_resolution.height - mousePosition.y; 
672 
673 		float z;
674 		gl.ReadPixels(cast(int)mousePosition.x, cast(int)mouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
675 		mat4 A = this.m_projectionMatrix * this.viewMatrix;
676 		A.invert();
677 		vec4 i;
678 
679 		/* Map x and y from window coordinates */
680 		i.x = mousePosition.x;
681 		i.y = mouseY;
682 		i.z = z;
683 		i.w = 1.0f;
684 
685 		i.x = i.x / this.m_viewportSize.width;
686 		i.y = i.y / this.m_viewportSize.height;
687 
688 		/* Map to range -1 to 1 */
689 		i.x = i.x * 2 - 1;
690 		i.y = i.y * 2 - 1;
691 		i.z = i.z * 2 - 1;
692 
693 		vec4 o = i * A;
694 
695 		o.x = o.x / o.w;
696 		o.y = o.y / o.w;
697 		o.z = o.z / o.w;
698 
699 		return vec3(o.x, o.y, o.z);
700 	}
701 
702 	/**
703 	 * Converts world coordinates to screen coordinates.
704 	 * Params:
705 	 * 		mousePosition : mouse position
706 	 * Credits: http://stackoverflow.com/questions/7748357/converting-3d-position-to-2d-screen-position
707 	 */
708 	@nogc
709 	public vec2 getScreenCoordinates(in ref vec3 position) nothrow
710 	{
711 		auto pos = position * this.m_viewMatrix;
712 		pos = pos * this.m_projectionMatrix;
713 		
714       	pos.x = this.m_viewportSize.width * (pos.x + 1.0) / 2.0;
715         pos.y = this.m_viewportSize.height * (1.0 - ( (pos.y + 1.0) / 2.0) );
716 
717 		return vec2(pos.x, pos.y);
718 	}
719 										  
720 	/**
721 	 * Renders text using default font.
722 	 * Params :
723 	 *		text : text to draw
724 	 *		x :
725 	 *		y : 
726 	 */
727 	public void drawText()(in wstring text, in float x, in float y, in auto ref color = Color.Black) 
728 	{
729 		this.m_defaultFont.draw(text, x , y, color, 20);
730 	}
731 
732 	/**
733 	 * Sends values to current shader.
734 	 * Params:
735 			 T : gl uniform name
736 			 U : values types
737 			 data : values
738 	 */
739 	public void setUniform(string T, U)(in int uniformLocation, in U* data, in size_t count, bool normalized = false) const
740 	{
741 		mixin("gl.Uniform" ~ T ~ "(uniformLocation, count, normalized, data);");
742 	}
743 
744 	public void setUniform(string T, U)(in int uniformLocation, in U* data, in size_t count = 1) const
745 	{
746 		mixin("gl.Uniform" ~ T ~ "(uniformLocation, count, data);");
747 	}
748 
749 	public void setUniform(string T, U)(in int uniformLocation, in U data) const
750 	{
751 		mixin("gl.Uniform" ~ T ~ "(uniformLocation, data);");
752 	}
753 
754 	@nogc
755     public void setMatrix(U)(in int location, in U* data, in size_t count = 1, in bool transposed = false) const nothrow
756     {
757 		gl.UniformMatrix4fv(location, count, transposed, data);
758     }
759 	
760 	/**
761 	 * Sets default projection matrix.
762 	 */
763 	@nogc
764 	public void setProjectionMatrix() nothrow
765 	{
766 		assert(this.m_currentShader !is null, "Trying to set projection matrix on null shader.");
767 		this.setMatrix(this.m_currentShader.projectionMatrix, this.m_projectionMatrix.arrayof.ptr, 1, false);
768 	}
769 
770 	/**
771 	 * Sets viewport.
772 	 * Params:
773 	 *		width : viewport width
774 	 *		height : viewport height
775 	 */
776 	@nogc
777 	public void setViewport(in int width, in int height) const nothrow
778 	{
779 		gl.Viewport(0, 0, width, height);
780 	}
781     
782 	/**
783 	 * Sets viewport.
784 	 * Params:
785 	 *		size : viewport size
786 	 */
787 	@nogc
788 	public void setViewport(in ref Size!int size) const nothrow
789 	{
790 		gl.Viewport(0, 0, size.width, size.height);
791 	}
792 
793 	/**
794 	 * Sets viewport.
795 	 * Params:
796 	 *		position : viewport position
797 	 *		size : viewport size
798 	 */
799 	@nogc
800 	public void setViewport(V)(in ref V position, in ref Size!int size) const nothrow
801 		if(is(V : vec2) || is(V : ivec2))
802 	{
803 		gl.Viewport(position.x, position.y, size.width, size.height);
804 	}
805 
806 	/**
807 	 * Resets viewport to its initial size.
808 	 */
809 	@nogc
810 	public void resetViewport() const nothrow
811 	{
812 		this.setViewport(this.m_viewportSize);
813 	}
814 
815 	@nogc
816 	public void initialize2DProjection(T)(in ref T viewportSize) nothrow
817 	{
818 		this.m_2DprojectionMatrix = orthoMatrix(
819 			cast(float)0, cast(float)viewportSize.width, cast(float)0, cast(float)viewportSize.height, cast(float)-5,cast(float) 5
820 		);
821 	}
822 
823 	@nogc
824 	public void initialize2DProjection(V, S)(in ref V position, in ref S viewportSize) nothrow
825 		if(is(V : vec2) || is(V : ivec2) && is(S : Size!int) || is(S : Size!float))
826 	{
827 		this.m_2DprojectionMatrix = orthoMatrix(position.x, viewportSize.width, position.y, viewportSize.height, -5, 5);
828 	}
829 
830 	/**
831 	 * Resets 2d projection (GUI) to the default value.
832 	 */
833 	@nogc
834 	public void reset2DProjection() nothrow
835 	{
836 		this.initialize2DProjection(this.m_viewportSize);
837 	}
838 
839 	/**
840 	 * Properties
841 	 */
842 	@nogc
843 	@property nothrow
844 	{
845 		public NVGcontext* nvgContext()
846 		{
847 			return this.m_nvg;
848 		}
849 		
850 		public mat4 viewMatrix() const
851 		{
852 			return this.m_viewMatrix;
853 		}
854 
855 		public void viewMatrix(mat4 value)
856 		{
857 			this.m_viewMatrix = value;
858 		}
859 	
860 		public mat4 projectionMatrix() const
861 		{
862 			return this.m_projectionMatrix;
863 		}
864 
865 		public mat4 GUIprojectionMatrix() const
866 		{ 
867 			return this.m_2DprojectionMatrix;
868 		}
869 
870 		public void projectionType(ProjectionType value)
871 		{
872 			this.m_projectionType = value;
873 		}
874 
875 		public ref const(Size!int) viewportSize() const
876 		{
877 			return this.m_viewportSize;
878 		}
879 
880 
881 		public Font defaultFont()
882 		{
883 			return this.m_defaultFont;
884 		}
885 
886 		public void defaultFont(Font value)
887 		{
888 			this.m_defaultFont = value;
889 		}
890 
891     	public ref const(Size!int) resolution() const
892 		{
893 			return this.m_resolution;
894 		}
895 		
896 		public void resolution(in Size!int value)
897 		{
898 			this.m_resolution = value;
899 			this.m_viewportSize = value;
900 
901 			this.setViewport(value);
902 		}
903 
904 		public Environment environment()
905 		{
906 			return this.m_environment;
907 		}
908 
909 		public Shader currentShader()
910 		{
911 			return this.m_currentShader;
912 		}
913 	}
914 
915 }