1 /*
2 Copyright (c) 2013 Andrey Penechko
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license the "Software" to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 module anchovy.graphics.renderers.ogl3renderer;
30 
31 import std.conv;
32 import std.stdio;
33 import std..string;
34 
35 import derelict.freeimage.freeimage;
36 import derelict.freetype.ft;
37 
38 import anchovy.utils..string;
39 
40 public import anchovy.core.types;
41 
42 //import anchovy.graphics.all;
43 import anchovy.graphics.shaderprogram;
44 import anchovy.graphics.texture;
45 
46 import anchovy.graphics.interfaces.irenderer;
47 import anchovy.core.interfaces.iwindow;
48 
49 
50 class Vbo
51 {
52 	this(uint bufferUsage, uint target = GL_ARRAY_BUFFER)
53 	{
54 		this.bufferUsage = bufferUsage;
55 		this.target = target;
56 		glGenBuffers(1, &handle);
57 	}
58 
59 	void close()
60 	{
61 		glDeleteBuffers(1, &handle);
62 	}
63 
64 	ref const(void[]) data(void[] newData) @property
65 	{
66 		_data = newData;
67 		glBindBuffer(target, handle);
68 		glBufferData(target, _data.length, _data.ptr, bufferUsage);
69 		glBindBuffer(target, 0);
70 		return _data;
71 	}
72 
73 	ref const(void[]) data() @property
74 	{
75 		return _data;
76 	}
77 
78 	void bind()
79 	{
80 		glBindBuffer(target, handle);
81 	}
82 
83 	void unbind()
84 	{
85 		glBindBuffer(target, 0);
86 	}
87 
88 	uint handle;
89 	uint bufferUsage;
90 	uint target;
91 	void[] _data;
92 }
93 
94 class Vao
95 {
96 	this()
97 	{
98 		glGenVertexArrays(1, &handle);
99 	}
100 	void close()
101 	{
102 		glDeleteVertexArrays(1, &handle);
103 	}
104 	void bind()
105 	{
106 		glBindVertexArray(handle);
107 	}
108 
109 	static void unbind()
110 	{
111 		glBindVertexArray(0);
112 	}
113 	uint handle;
114 }
115 
116 string primVertTex2d = `#version 330
117 layout (location = 0) in vec2 position;
118 layout (location = 1) in vec2 texCoord;
119 uniform sampler2D gSampler;
120 uniform vec2 gHalfTarget;
121 uniform vec2 gPosition;
122 out vec2 texCoord0;
123 
124 void main()
125 {
126 	gl_Position = vec4((position.x + gPosition.x) / gHalfTarget.x - 1,
127 					   1 - ((position.y + gPosition.y) / gHalfTarget.y),
128 					   0.0, 1.0);
129 	ivec2 texSize = textureSize(gSampler, 0);
130 	texCoord0 = vec2(texCoord.x/texSize.x, texCoord.y/texSize.y);
131 }
132 `;
133 
134 string primFragTex2d=`#version 330
135 in vec2 texCoord0;
136 out vec4 FragColor;
137 
138 uniform sampler2D gSampler;
139 uniform vec4 gColor = vec4(1, 1, 1, 1);
140 
141 void main()
142 {
143 	FragColor = texture2D(gSampler, texCoord0)*gColor;
144 }`;
145 
146 string primVertFill2d = `#version 330
147 in vec2 position;
148 
149 uniform vec2 gHalfTarget;
150 uniform vec4 gColor;
151 
152 smooth out vec4 theColor;
153 
154 void main()
155 {
156 	gl_Position = vec4(((position.x+0.5)/gHalfTarget.x)-1, 1-((position.y+0.5)/gHalfTarget.y), 0.0, 1.0);
157 	theColor = gColor;
158 }
159 `;
160 //in smooth vec4 theColor DOESN'T works use smooth in unstead
161 string primFragFill2d=`#version 330
162 smooth in vec4 theColor;
163 out vec4 fragColor;
164 
165 void main()
166 {
167 	fragColor = theColor;
168 }
169 `;
170 
171 class Ogl3Renderer : IRenderer
172 {
173 	this(IWindow window)
174 	{
175 		this.window = window;
176 
177 		FreeImage_SetOutputMessage(&FreeImageErrorHandler);
178 		shaders = new IdArray!(ShaderProgram);
179 
180 		primShader = new ShaderProgram(primVertFill2d, primFragFill2d);
181 		if (!primShader.compile)
182 			throw new Exception(primShader.errorLog);
183 		registerShaderProgram(primShader);
184 
185 		primTexShader = new ShaderProgram(primVertTex2d, primFragTex2d);
186 		if (!primTexShader.compile)
187 			throw new Exception("textured primitive shader failed compilation\n"~primTexShader.errorLog);
188 		registerShaderProgram(primTexShader);
189 
190 		rectVao = new Vao;
191 		texRectVao = new Vao;
192 		rectVbo = new Vbo(GL_STREAM_DRAW);
193 		texRectVbo = new Vbo(GL_STREAM_DRAW);
194 
195 		rectVao.bind;
196 			rectVbo.bind;
197 				glEnableVertexAttribArray(0);
198 				glVertexAttribPointer(0, 2, GL_SHORT, GL_FALSE, 2*short.sizeof, null);
199 			rectVbo.unbind;
200 		rectVao.unbind;
201 		texRectVao.bind;
202 			texRectVbo.bind;
203 				glEnableVertexAttribArray(0);
204 				glEnableVertexAttribArray(1);
205 				glVertexAttribPointer(0, 2, GL_SHORT, GL_FALSE, 4*short.sizeof, null);
206 				glVertexAttribPointer(1, 2, GL_SHORT, GL_FALSE, 4*short.sizeof, cast(void*)(2*short.sizeof));
207 			texRectVbo.unbind;
208 		texRectVao.unbind;
209 	}
210 
211 	override void close()
212 	{
213 		foreach(k; shaders.array.byKey)
214 		{
215 			shaders[k].close;
216 			shaders.remove(k);
217 		}
218 	}
219 
220 	void drawText(string text, uint x, uint y, uint font)
221 	{
222 
223 	}
224 
225 	override uint createShaderProgram(string vertexSource, string fragmentSource)
226 	{
227 		ShaderProgram newProgram = new ShaderProgram(vertexSource, fragmentSource);
228 		if (!newProgram.compile)
229 			writeln(newProgram.errorLog);
230 		return shaders.add(newProgram);
231 	}
232 
233 	override uint registerShaderProgram(ShaderProgram program)
234 	{
235 		return shaders.add(program);
236 	}
237 
238 	override Texture createTexture(string filename)
239 	in
240 	{
241 		assert(textures !is null);
242 	}
243 	body
244 	{
245 		Texture tex = new Texture(filename, TextureTarget.target2d, TextureFormat.rgba);
246 		return tex;
247 	}
248 
249 	override void bindTexture(Texture texture, uint textureUnit = 0)
250 	in
251 	{
252 		assert(texture !is null);
253 	}
254 	body
255 	{
256 		texture.validateBind(textureUnit);
257 	}
258 
259 	override void bindShaderProgram(uint programName)
260 	{
261 		ShaderProgram program = shaders[programName];
262 		assert(program !is null);
263 		bindShaderProgram(program);
264 	}
265 
266 	override void bindShaderProgram(ref ShaderProgram program)
267 	{
268 		//if (currentShaderProgram == program) return;
269 		program.bind;
270 		_currentShaderProgram = program;
271 	}
272 
273 	void setProgram(in uint program)
274 	{
275 
276 	}
277 
278 	override void setClearColor(in Color color)
279 	{
280 		with(color)
281 		{
282 			glClearColor(cast(float)r/255, cast(float)g/255, cast(float)b/255, cast(float)a/255);
283 		}
284 	}
285 
286 	override void setColor(in Color newColor)
287 	{
288 		Color4f c4f = Color4f(newColor);
289 		if (c4f != curColor)
290 		{
291 			curColor = c4f;
292 		}
293 	}
294 
295 	override void setColor(in Color4f newColor)
296 	{
297 		curColor = newColor;
298 	}
299 
300 	override void enableAlphaBlending()
301 	{
302 		glEnable(GL_BLEND);
303 		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
304 	}
305 
306 	override void disableAlphaBlending()
307 	{
308 		glDisable(GL_BLEND);
309 	}
310 
311 	override void drawRect(Rect rect)
312 	{
313 		bindShaderProgram(primShader);
314 		primShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2);
315 		primShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a);
316 		rectVao.bind;
317 		rectVbo.data = cast(short[])[rect.x, rect.y + rect.height, rect.x, rect.y,
318 					rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height];
319 		glDrawArrays(GL_LINE_LOOP, 0, 4);
320 		rectVao.unbind;
321 	}
322 
323 	override void fillRect(Rect rect)
324 	{
325 		bindShaderProgram(primShader);
326 		primShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2);
327 		primShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a);
328 		rectVao.bind;
329 		rectVbo.data = cast(short[])[rect.x, rect.y + rect.height, rect.x, rect.y,
330 					rect.x + rect.width, rect.y, rect.x, rect.y + rect.height,
331 					rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height];
332 		glDrawArrays(GL_TRIANGLES, 0, 6);
333 		rectVao.unbind;
334 	}
335 
336 	/+++++
337 	 + Draws textured rectangle to the current target
338 	 + target - position and size on the screen.
339 	 + source - position and size of rectangle in texture
340 	 +++++/
341 	override void drawTexRect(Rect target, Rect source, Texture texture)
342 	in
343 	{
344 		assert(texture !is null);
345 	}
346 	body
347 	{
348 		if (texture.size == uvec2(0, 0)) return;
349 
350 		bindShaderProgram(primTexShader);
351 		primTexShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2);
352 		primTexShader.setUniform2!float("gPosition", target.x, target.y);
353 		primTexShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a);
354 
355 		texture.validateBind();
356 		texRectVao.bind;
357 		int ty2 = source.y + source.height;
358 		int tx2 = source.x + source.width;
359 		int y2 = target.y + target.height;
360 		int x2 = target.x + target.width;
361 		texRectVbo.data = cast(short[])[0, target.height, source.x, ty2,
362 		                             0, 0, source.x, source.y,
363 		                             target.width, 0, tx2, source.y,
364 		                             0, target.height, source.x, ty2,
365 		                             target.width, 0, tx2, source.y,
366 									 target.width, target.height, tx2, ty2];
367 		glDrawArrays(GL_TRIANGLES, 0, 6);
368 		texRectVao.unbind;
369 		texture.unbind;
370 	}
371 
372 	override void drawTexRectArray(TexRectArray array, ivec2 position, Texture texture, ShaderProgram customProgram = null)
373 	in
374 	{
375 		assert(texture !is null);
376 	}
377 	body
378 	{
379 		ShaderProgram program = customProgram;
380 		if (customProgram is null) program = primTexShader;
381 		drawTexRectArrayImpl(array, position, texture, program);
382 	}
383 
384 	private void drawTexRectArrayImpl(TexRectArray array, ivec2 position, Texture texture, ShaderProgram program)
385 	in
386 	{
387 		assert(texture !is null);
388 	}
389 	body
390 	{
391 		bindShaderProgram(program);
392 		program.setUniform2!float("gHalfTarget", cast(float)window.size.x / 2, cast(float)window.size.y / 2);
393 		program.setUniform2!float("gPosition", position.x, position.y);
394 		program.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a);
395 
396 		texture.validateBind();
397 		array.bind;
398 		glDrawArrays(GL_TRIANGLES, 0, cast(uint)array.vertieces.length);
399 		array.unbind;
400 		texture.unbind;
401 	}
402 
403 	override uvec2 windowSize()
404 	{
405 		return window.size();
406 	}
407 
408 	override void flush()
409 	{
410 		window.swapBuffers;
411 	}
412 
413 private:
414 
415 	ShaderProgram _currentShaderProgram;
416 	ShaderProgram primShader;
417 	ShaderProgram primTexShader;
418 
419 	IdArray!(ShaderProgram) shaders;
420 
421 	IWindow	window;
422 
423 	Vbo rectVbo;
424 	Vbo texRectVbo;
425 	Vao rectVao;
426 	Vao texRectVao;
427 
428 	Color4f curColor;
429 	uint primColorLoc, primTargetSizeLoc;
430 }
431 
432 extern(C)
433 {
434 	nothrow void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const( char)*message)
435 	{
436 		try
437 		{
438 			writeln("\n*** ");
439 			if(fif != FIF_UNKNOWN) {
440 				writefln("%s Format\n", FreeImage_GetFormatFromFIF(fif));
441 			}
442 			writeln(ZToString(message));
443 			writeln(" ***\n");
444 		}
445 		catch(Exception e)
446 		{
447 			//writeln(e.msg);
448 		}
449 	}
450 }
451