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 	~this()
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 	~this()
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 		DerelictFI.load();
178 		DerelictFT.load();
179 
180 		FreeImage_SetOutputMessage(&FreeImageErrorHandler);
181 		shaders = new IdArray!(ShaderProgram);
182 
183 		primShader = new ShaderProgram(primVertFill2d, primFragFill2d);
184 		if (!primShader.compile)
185 			throw new Exception(primShader.errorLog);
186 		
187 		primTexShader = new ShaderProgram(primVertTex2d, primFragTex2d);
188 		if (!primTexShader.compile)
189 			throw new Exception("textured primitive shader failed compilation\n"~primTexShader.errorLog);
190 
191 		rectVao = new Vao;
192 		texRectVao = new Vao;
193 		rectVbo = new Vbo(GL_STREAM_DRAW);
194 		texRectVbo = new Vbo(GL_STREAM_DRAW);
195 
196 		rectVao.bind;
197 			rectVbo.bind;
198 				glEnableVertexAttribArray(0);
199 				glVertexAttribPointer(0, 2, GL_SHORT, GL_FALSE, 2*short.sizeof, null);
200 			rectVbo.unbind;
201 		rectVao.unbind;
202 		texRectVao.bind;
203 			texRectVbo.bind;
204 				glEnableVertexAttribArray(0);
205 				glEnableVertexAttribArray(1);
206 				glVertexAttribPointer(0, 2, GL_SHORT, GL_FALSE, 4*short.sizeof, null);
207 				glVertexAttribPointer(1, 2, GL_SHORT, GL_FALSE, 4*short.sizeof, cast(void*)(2*short.sizeof));
208 			texRectVbo.unbind;
209 		texRectVao.unbind;
210 	}
211 	
212 	void drawText(string text, uint x, uint y, uint font)
213 	{
214 		
215 	}
216 
217 	override uint createShaderProgram(string vertexSource, string fragmentSource)
218 	{
219 		ShaderProgram newProgram = new ShaderProgram(vertexSource, fragmentSource);
220 		if (!newProgram.compile)
221 			writeln(newProgram.errorLog);
222 		return shaders.add(newProgram);
223 	}
224 
225 	override uint registerShaderProgram(ShaderProgram program)
226 	{
227 		return shaders.add(program);
228 	}
229 
230 	override Texture createTexture(string filename)
231 	in
232 	{
233 		assert(textures !is null);
234 	}
235 	body
236 	{
237 		Texture tex = new Texture(filename, TextureTarget.target2d, TextureFormat.rgba);
238 		return tex;
239 	}
240 
241 	override void bindTexture(Texture texture, uint textureUnit = 0)
242 	in
243 	{
244 		assert(texture !is null);
245 	}
246 	body
247 	{
248 		texture.validateBind(textureUnit);
249 	}
250 	
251 	override void bindShaderProgram(uint programName)
252 	{
253 		ShaderProgram program = shaders[programName];
254 		assert(program !is null);
255 		bindShaderProgram(program);
256 	}
257 
258 	override void bindShaderProgram(ref ShaderProgram program)
259 	{
260 		//if (currentShaderProgram == program) return;
261 		program.bind;
262 		_currentShaderProgram = program;
263 	}
264 	
265 	void setProgram(in uint program)
266 	{
267 		
268 	}
269 
270 	override void setClearColor(in Color color)
271 	{
272 		with(color)
273 		{
274 			glClearColor(cast(float)r/255, cast(float)g/255, cast(float)b/255, cast(float)a/255);
275 		}
276 	}
277 
278 	override void setColor(in Color newColor)
279 	{
280 		Color4f c4f = Color4f(newColor);
281 		if (c4f != curColor)
282 		{
283 			curColor = c4f;
284 		}
285 	}
286 
287 	override void setColor(in Color4f newColor)
288 	{
289 		curColor = newColor;
290 	}
291 
292 	override void enableAlphaBlending()
293 	{
294 		glEnable(GL_BLEND);
295 		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
296 	}
297 
298 	override void disableAlphaBlending()
299 	{
300 		glDisable(GL_BLEND);
301 	}
302 
303 	override void drawRect(Rect rect)
304 	{
305 		bindShaderProgram(primShader);
306 		primShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2);
307 		primShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a);
308 		rectVao.bind;
309 		rectVbo.data = cast(short[])[rect.x, rect.y + rect.height, rect.x, rect.y,
310 					rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height];
311 		glDrawArrays(GL_LINE_LOOP, 0, 4);
312 		rectVao.unbind;
313 	}
314 
315 	override void fillRect(Rect rect)
316 	{
317 		bindShaderProgram(primShader);
318 		primShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2);
319 		primShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a);
320 		rectVao.bind;
321 		rectVbo.data = cast(short[])[rect.x, rect.y + rect.height, rect.x, rect.y,
322 					rect.x + rect.width, rect.y, rect.x, rect.y + rect.height,
323 					rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height];
324 		glDrawArrays(GL_TRIANGLES, 0, 6);
325 		rectVao.unbind;
326 	}
327 
328 	/+++++
329 	 + Draws textured rectangle to the current target
330 	 + target - position and size on the screen.
331 	 + source - position and size of rectangle in texture
332 	 +++++/
333 	override void drawTexRect(Rect target, Rect source, Texture texture)
334 	in
335 	{
336 		assert(texture !is null);
337 	}
338 	body
339 	{
340 		if (texture.size == uvec2(0, 0)) return;
341 
342 		bindShaderProgram(primTexShader);
343 		primTexShader.setUniform2!float("gHalfTarget", window.size.x/2, window.size.y/2);
344 		primTexShader.setUniform2!float("gPosition", target.x, target.y);
345 		primTexShader.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a);
346 
347 		texture.validateBind();
348 		texRectVao.bind;
349 		int ty2 = source.y + source.height;
350 		int tx2 = source.x + source.width;
351 		int y2 = target.y + target.height;
352 		int x2 = target.x + target.width;
353 		texRectVbo.data = cast(short[])[0, target.height, source.x, ty2,
354 		                             0, 0, source.x, source.y,
355 		                             target.width, 0, tx2, source.y,
356 		                             0, target.height, source.x, ty2,
357 		                             target.width, 0, tx2, source.y,
358 									 target.width, target.height, tx2, ty2];
359 		glDrawArrays(GL_TRIANGLES, 0, 6);
360 		texRectVao.unbind;
361 		texture.unbind;
362 	}
363 
364 	override void drawTexRectArray(TexRectArray array, ivec2 position, Texture texture, ShaderProgram customProgram = null)
365 	in
366 	{
367 		assert(texture !is null);
368 	}
369 	body
370 	{
371 		ShaderProgram program = customProgram;
372 		if (customProgram is null) program = primTexShader;
373 		drawTexRectArrayImpl(array, position, texture, program);
374 	}
375 
376 	private void drawTexRectArrayImpl(TexRectArray array, ivec2 position, Texture texture, ShaderProgram program)
377 	in
378 	{
379 		assert(texture !is null);
380 	}
381 	body
382 	{
383 		bindShaderProgram(program);
384 		program.setUniform2!float("gHalfTarget", cast(float)window.size.x / 2, cast(float)window.size.y / 2);
385 		program.setUniform2!float("gPosition", position.x, position.y);
386 		program.setUniform4!float("gColor", curColor.r, curColor.g, curColor.b, curColor.a);
387 		
388 		texture.validateBind();
389 		array.bind;
390 		glDrawArrays(GL_TRIANGLES, 0, array.vertieces.length);
391 		array.unbind;
392 		texture.unbind;
393 	}
394 
395 	override uvec2 windowSize()
396 	{
397 		return window.size();
398 	}
399 	
400 	override void flush()
401 	{
402 		window.swapBuffers;
403 	}
404 	
405 private:
406 
407 	ShaderProgram _currentShaderProgram;
408 	ShaderProgram primShader;
409 	ShaderProgram primTexShader;
410 
411 	IdArray!(ShaderProgram) shaders;
412 
413 	IWindow	window;
414 
415 	Vbo rectVbo;
416 	Vbo texRectVbo;
417 	Vao rectVao;
418 	Vao texRectVao;
419 
420 	Color4f curColor;
421 	uint primColorLoc, primTargetSizeLoc;
422 }
423 
424 extern(C)
425 {
426 	nothrow void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const( char)*message) 
427 	{
428 		try
429 		{
430 			writeln("\n*** ");
431 			if(fif != FIF_UNKNOWN) {
432 				writefln("%s Format\n", FreeImage_GetFormatFromFIF(fif));
433 			}
434 			writeln(ZToString(message));
435 			writeln(" ***\n");
436 		}
437 		catch(Exception e)
438 		{
439 			//writeln(e.msg);
440 		}
441 	}
442 }
443