1 /**
2 Copyright: Copyright (c) 2015-2017 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 
7 module voxelman.graphics.plugin;
8 
9 import voxelman.log;
10 import derelict.opengl3.gl3;
11 import voxelman.container.buffer;
12 import voxelman.math;
13 
14 import pluginlib;
15 import anchovy.iwindow;
16 import anchovy.irenderer;
17 import anchovy.shaderprogram;
18 import anchovy.glerrors;
19 import voxelman.core.config;
20 import voxelman.core.events;
21 import voxelman.eventdispatcher.plugin;
22 import voxelman.gui.plugin;
23 import voxelman.config.configmanager;
24 import voxelman.utils.fpscamera;
25 public import voxelman.graphics;
26 
27 import voxelman.graphics.shaders;
28 
29 final class GraphicsPlugin : IPlugin
30 {
31 private:
32 	uint vao;
33 	uint vbo;
34 	EventDispatcherPlugin evDispatcher;
35 	Matrix4f ortho_projection;
36 
37 public:
38 	FpsCamera camera;
39 	Batch debugBatch;
40 	Buffer!ColoredVertex transparentBuffer;
41 	Batch2d overlayBatch;
42 
43 	SolidShader3d solidShader3d;
44 	TransparentShader3d transparentShader3d;
45 	SolidShader2d solidShader2d;
46 
47 	IRenderer renderer;
48 	IWindow window;
49 
50 	ConfigOption cameraSensivity;
51 	ConfigOption cameraFov;
52 
53 	mixin IdAndSemverFrom!"voxelman.graphics.plugininfo";
54 
55 	override void registerResources(IResourceManagerRegistry resmanRegistry)
56 	{
57 		auto config = resmanRegistry.getResourceManager!ConfigManager;
58 		cameraSensivity = config.registerOption!double("camera_sensivity", 0.4);
59 		cameraFov = config.registerOption!double("camera_fov", 60.0);
60 	}
61 
62 	override void preInit()
63 	{
64 		camera.move(vec3(0, 0, 0));
65 		camera.sensivity = cameraSensivity.get!float;
66 		camera.fov = cameraFov.get!float;
67 	}
68 
69 	override void init(IPluginManager pluginman)
70 	{
71 		evDispatcher = pluginman.getPlugin!EventDispatcherPlugin;
72 		auto gui = pluginman.getPlugin!GuiPlugin;
73 
74 		evDispatcher.subscribeToEvent(&onWindowResizedEvent);
75 		evDispatcher.subscribeToEvent(&draw);
76 
77 		renderer = gui.renderer;
78 		window = gui.window;
79 
80 		glGenVertexArrays(1, &vao);
81 		glGenBuffers( 1, &vbo);
82 
83 		// Setup shaders
84 		solidShader3d.compile(renderer);
85 		transparentShader3d.compile(renderer);
86 		solidShader2d.compile(renderer);
87 
88 		ortho_projection.arrayof =
89 		[
90 			 2f/1, 0f,   0f, 0f,
91 			 0f,  -2f/1, 0f, 0f,
92 			 0f,   0f,  -1f, 0f,
93 			-1f,   1f,   0f, 1f,
94 		];
95 	}
96 
97 	override void postInit()
98 	{
99 		renderer.setClearColor(165,211,238);
100 		camera.aspect = cast(float)renderer.framebufferSize.x/renderer.framebufferSize.y;
101 		updateOrtoMatrix();
102 	}
103 
104 	private void onWindowResizedEvent(ref WindowResizedEvent event)
105 	{
106 		camera.aspect = cast(float)event.newSize.x/event.newSize.y;
107 		updateOrtoMatrix();
108 	}
109 
110 	void resetCamera()
111 	{
112 		camera.position = vec3(0,0,0);
113 		camera.target = vec3(0,0,1);
114 		camera.heading = vec2(0, 0);
115 		camera.update();
116 	}
117 
118 	private void draw(ref RenderEvent event)
119 	{
120 		checkgl!glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
121 		renderer.depthTest(true);
122 
123 		draw(debugBatch);
124 		debugBatch.reset();
125 
126 		evDispatcher.postEvent(RenderSolid3dEvent(renderer));
127 
128 		renderer.depthTest(false);
129 		renderer.alphaBlending(true);
130 
131 		evDispatcher.postEvent(RenderTransparent3dEvent(renderer));
132 
133 		transparentShader3d.bind;
134 		transparentShader3d.setMVP(Matrix4f.identity, camera.cameraMatrix, camera.perspective);
135 		transparentShader3d.setTransparency(0.3f);
136 
137 		drawBuffer(transparentBuffer.data, GL_TRIANGLES);
138 		transparentShader3d.unbind;
139 		transparentBuffer.clear();
140 
141 		evDispatcher.postEvent(Render2Event(renderer));
142 
143 		draw(overlayBatch);
144 		overlayBatch.reset();
145 
146 		evDispatcher.postEvent(Render3Event(renderer));
147 
148 		renderer.alphaBlending(false);
149 		renderer.flush();
150 	}
151 
152 	void draw(Batch batch)
153 	{
154 		solidShader3d.bind;
155 		solidShader3d.setMVP(Matrix4f.identity, camera.cameraMatrix, camera.perspective);
156 
157 		drawBuffer(batch.triBuffer.data, GL_TRIANGLES);
158 		drawBuffer(batch.lineBuffer.data, GL_LINES);
159 		drawBuffer(batch.pointBuffer.data, GL_POINTS);
160 
161 		solidShader3d.unbind;
162 	}
163 
164 	void draw(Batch2d batch)
165 	{
166 		solidShader2d.bind;
167 		solidShader2d.setProjection(ortho_projection);
168 
169 		drawBuffer(batch.triBuffer.data, GL_TRIANGLES);
170 		drawBuffer(batch.lineBuffer.data, GL_LINES);
171 		drawBuffer(batch.pointBuffer.data, GL_POINTS);
172 
173 		solidShader2d.unbind;
174 	}
175 
176 	void drawBuffer3d(VertexType)(VertexType[] buffer, uint mode)
177 	{
178 		if (buffer.length == 0) return;
179 		solidShader3d.bind;
180 		solidShader3d.setMVP(Matrix4f.identity, camera.cameraMatrix, camera.perspective);
181 
182 		drawBuffer(buffer, mode);
183 
184 		solidShader3d.unbind;
185 	}
186 
187 private:
188 
189 	void updateOrtoMatrix()
190 	{
191 		renderer.setViewport(ivec2(0, 0), renderer.framebufferSize);
192 		ortho_projection.a11 =  2f/renderer.framebufferSize.x;
193 		ortho_projection.a22 = -2f/renderer.framebufferSize.y;
194 	}
195 
196 	void drawBuffer(VertexType)(VertexType[] buffer, uint mode)
197 	{
198 		if (buffer.length == 0) return;
199 		checkgl!glBindVertexArray(vao);
200 		checkgl!glBindBuffer(GL_ARRAY_BUFFER, vbo);
201 		checkgl!glBufferData(GL_ARRAY_BUFFER, buffer.length*VertexType.sizeof, buffer.ptr, GL_DYNAMIC_DRAW);
202 		VertexType.setAttributes();
203 		checkgl!glBindBuffer(GL_ARRAY_BUFFER, 0);
204 		checkgl!glDrawArrays(mode, 0, cast(uint)(buffer.length));
205 		checkgl!glBindVertexArray(0);
206 	}
207 }