1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module gtk.GLArea;
26 
27 private import gdk.GLContext;
28 private import glib.ConstructionException;
29 private import glib.ErrorG;
30 private import gobject.ObjectG;
31 private import gobject.Signals;
32 private import gtk.Widget;
33 private import gtkc.gtk;
34 public  import gtkc.gtktypes;
35 private import std.algorithm;
36 
37 
38 /**
39  * #GtkGLArea is a widget that allows drawing with OpenGL.
40  * 
41  * #GtkGLArea sets up its own #GdkGLContext for the window it creates, and
42  * creates a custom GL framebuffer that the widget will do GL rendering onto.
43  * It also ensures that this framebuffer is the default GL rendering target
44  * when rendering.
45  * 
46  * In order to draw, you have to connect to the #GtkGLArea::render signal,
47  * or subclass #GtkGLArea and override the @GtkGLAreaClass.render() virtual
48  * function.
49  * 
50  * The #GtkGLArea widget ensures that the #GdkGLContext is associated with
51  * the widget's drawing area, and it is kept updated when the size and
52  * position of the drawing area changes.
53  * 
54  * ## Drawing with GtkGLArea ##
55  * 
56  * The simplest way to draw using OpenGL commands in a #GtkGLArea is to
57  * create a widget instance and connect to the #GtkGLArea::render signal:
58  * 
59  * |[<!-- language="C" -->
60  * // create a GtkGLArea instance
61  * GtkWidget *gl_area = gtk_gl_area_new ();
62  * 
63  * // connect to the "render" signal
64  * g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);
65  * ]|
66  * 
67  * The `render()` function will be called when the #GtkGLArea is ready
68  * for you to draw its content:
69  * 
70  * |[<!-- language="C" -->
71  * static gboolean
72  * render (GtkGLArea *area, GdkGLContext *context)
73  * {
74  * // inside this function it's safe to use GL; the given
75  * // #GdkGLContext has been made current to the drawable
76  * // surface used by the #GtkGLArea and the viewport has
77  * // already been set to be the size of the allocation
78  * 
79  * // we can start by clearing the buffer
80  * glClearColor (0, 0, 0, 0);
81  * glClear (GL_COLOR_BUFFER_BIT);
82  * 
83  * // draw your object
84  * draw_an_object ();
85  * 
86  * // we completed our drawing; the draw commands will be
87  * // flushed at the end of the signal emission chain, and
88  * // the buffers will be drawn on the window
89  * return TRUE;
90  * }
91  * ]|
92  * 
93  * If you need to initialize OpenGL state, e.g. buffer objects or
94  * shaders, you should use the #GtkWidget::realize signal; you
95  * can use the #GtkWidget::unrealize signal to clean up. Since the
96  * #GdkGLContext creation and initialization may fail, you will
97  * need to check for errors, using gtk_gl_area_get_error(). An example
98  * of how to safely initialize the GL state is:
99  * 
100  * |[<!-- language="C" -->
101  * static void
102  * on_realize (GtkGLarea *area)
103  * {
104  * // We need to make the context current if we want to
105  * // call GL API
106  * gtk_gl_area_make_current (area);
107  * 
108  * // If there were errors during the initialization or
109  * // when trying to make the context current, this
110  * // function will return a #GError for you to catch
111  * if (gtk_gl_area_get_error (area) != NULL)
112  * return;
113  * 
114  * // You can also use gtk_gl_area_set_error() in order
115  * // to show eventual initialization errors on the
116  * // GtkGLArea widget itself
117  * GError *internal_error = NULL;
118  * init_buffer_objects (&error);
119  * if (error != NULL)
120  * {
121  * gtk_gl_area_set_error (area, error);
122  * g_error_free (error);
123  * return;
124  * }
125  * 
126  * init_shaders (&error);
127  * if (error != NULL)
128  * {
129  * gtk_gl_area_set_error (area, error);
130  * g_error_free (error);
131  * return;
132  * }
133  * }
134  * ]|
135  * 
136  * If you need to change the options for creating the #GdkGLContext
137  * you should use the #GtkGLArea::create-context signal.
138  *
139  * Since: 3.16
140  */
141 public class GLArea : Widget
142 {
143 	/** the main Gtk struct */
144 	protected GtkGLArea* gtkGLArea;
145 
146 	/** Get the main Gtk struct */
147 	public GtkGLArea* getGLAreaStruct()
148 	{
149 		return gtkGLArea;
150 	}
151 
152 	/** the main Gtk struct as a void* */
153 	protected override void* getStruct()
154 	{
155 		return cast(void*)gtkGLArea;
156 	}
157 
158 	protected override void setStruct(GObject* obj)
159 	{
160 		gtkGLArea = cast(GtkGLArea*)obj;
161 		super.setStruct(obj);
162 	}
163 
164 	/**
165 	 * Sets our main struct and passes it to the parent class.
166 	 */
167 	public this (GtkGLArea* gtkGLArea, bool ownedRef = false)
168 	{
169 		this.gtkGLArea = gtkGLArea;
170 		super(cast(GtkWidget*)gtkGLArea, ownedRef);
171 	}
172 
173 
174 	/** */
175 	public static GType getType()
176 	{
177 		return gtk_gl_area_get_type();
178 	}
179 
180 	/**
181 	 * Creates a new #GtkGLArea widget.
182 	 *
183 	 * Returns: the newly created #GtkGLArea
184 	 *
185 	 * Since: 3.16
186 	 *
187 	 * Throws: ConstructionException GTK+ fails to create the object.
188 	 */
189 	public this()
190 	{
191 		auto p = gtk_gl_area_new();
192 		
193 		if(p is null)
194 		{
195 			throw new ConstructionException("null returned by new");
196 		}
197 		
198 		this(cast(GtkGLArea*) p, true);
199 	}
200 
201 	/**
202 	 * Ensures that the @area framebuffer object is made the current draw
203 	 * and read target, and that all the required buffers for the @area
204 	 * are created and bound to the frambuffer.
205 	 *
206 	 * This function is automatically called before emitting the
207 	 * #GtkGLArea::render signal, and doesn't normally need to be called
208 	 * by application code.
209 	 *
210 	 * Since: 3.16
211 	 */
212 	public void attachBuffers()
213 	{
214 		gtk_gl_area_attach_buffers(gtkGLArea);
215 	}
216 
217 	/**
218 	 * Returns whether the area is in auto render mode or not.
219 	 *
220 	 * Returns: %TRUE if the @area is auto rendering, %FALSE otherwise
221 	 *
222 	 * Since: 3.16
223 	 */
224 	public bool getAutoRender()
225 	{
226 		return gtk_gl_area_get_auto_render(gtkGLArea) != 0;
227 	}
228 
229 	/**
230 	 * Retrieves the #GdkGLContext used by @area.
231 	 *
232 	 * Returns: the #GdkGLContext
233 	 *
234 	 * Since: 3.16
235 	 */
236 	public GLContext getContext()
237 	{
238 		auto p = gtk_gl_area_get_context(gtkGLArea);
239 		
240 		if(p is null)
241 		{
242 			return null;
243 		}
244 		
245 		return ObjectG.getDObject!(GLContext)(cast(GdkGLContext*) p);
246 	}
247 
248 	/**
249 	 * Gets the current error set on the @area.
250 	 *
251 	 * Returns: the #GError or %NULL
252 	 *
253 	 * Since: 3.16
254 	 */
255 	public ErrorG getError()
256 	{
257 		auto p = gtk_gl_area_get_error(gtkGLArea);
258 		
259 		if(p is null)
260 		{
261 			return null;
262 		}
263 		
264 		return new ErrorG(cast(GError*) p);
265 	}
266 
267 	/**
268 	 * Returns whether the area has an alpha component.
269 	 *
270 	 * Returns: %TRUE if the @area has an alpha component, %FALSE otherwise
271 	 *
272 	 * Since: 3.16
273 	 */
274 	public bool getHasAlpha()
275 	{
276 		return gtk_gl_area_get_has_alpha(gtkGLArea) != 0;
277 	}
278 
279 	/**
280 	 * Returns whether the area has a depth buffer.
281 	 *
282 	 * Returns: %TRUE if the @area has a depth buffer, %FALSE otherwise
283 	 *
284 	 * Since: 3.16
285 	 */
286 	public bool getHasDepthBuffer()
287 	{
288 		return gtk_gl_area_get_has_depth_buffer(gtkGLArea) != 0;
289 	}
290 
291 	/**
292 	 * Returns whether the area has a stencil buffer.
293 	 *
294 	 * Returns: %TRUE if the @area has a stencil buffer, %FALSE otherwise
295 	 *
296 	 * Since: 3.16
297 	 */
298 	public bool getHasStencilBuffer()
299 	{
300 		return gtk_gl_area_get_has_stencil_buffer(gtkGLArea) != 0;
301 	}
302 
303 	/**
304 	 * Retrieves the required version of OpenGL set
305 	 * using gtk_gl_area_set_required_version().
306 	 *
307 	 * Params:
308 	 *     major = return location for the required major version
309 	 *     minor = return location for the required minor version
310 	 *
311 	 * Since: 3.16
312 	 */
313 	public void getRequiredVersion(out int major, out int minor)
314 	{
315 		gtk_gl_area_get_required_version(gtkGLArea, &major, &minor);
316 	}
317 
318 	/**
319 	 * Retrieves the value set by gtk_gl_area_set_use_es().
320 	 *
321 	 * Returns: %TRUE if the #GtkGLArea should create an OpenGL ES context
322 	 *     and %FALSE otherwise
323 	 *
324 	 * Since: 3.22
325 	 */
326 	public bool getUseEs()
327 	{
328 		return gtk_gl_area_get_use_es(gtkGLArea) != 0;
329 	}
330 
331 	/**
332 	 * Ensures that the #GdkGLContext used by @area is associated with
333 	 * the #GtkGLArea.
334 	 *
335 	 * This function is automatically called before emitting the
336 	 * #GtkGLArea::render signal, and doesn't normally need to be called
337 	 * by application code.
338 	 *
339 	 * Since: 3.16
340 	 */
341 	public void makeCurrent()
342 	{
343 		gtk_gl_area_make_current(gtkGLArea);
344 	}
345 
346 	/**
347 	 * Marks the currently rendered data (if any) as invalid, and queues
348 	 * a redraw of the widget, ensuring that the #GtkGLArea::render signal
349 	 * is emitted during the draw.
350 	 *
351 	 * This is only needed when the gtk_gl_area_set_auto_render() has
352 	 * been called with a %FALSE value. The default behaviour is to
353 	 * emit #GtkGLArea::render on each draw.
354 	 *
355 	 * Since: 3.16
356 	 */
357 	public void queueRender()
358 	{
359 		gtk_gl_area_queue_render(gtkGLArea);
360 	}
361 
362 	/**
363 	 * If @auto_render is %TRUE the #GtkGLArea::render signal will be
364 	 * emitted every time the widget draws. This is the default and is
365 	 * useful if drawing the widget is faster.
366 	 *
367 	 * If @auto_render is %FALSE the data from previous rendering is kept
368 	 * around and will be used for drawing the widget the next time,
369 	 * unless the window is resized. In order to force a rendering
370 	 * gtk_gl_area_queue_render() must be called. This mode is useful when
371 	 * the scene changes seldomly, but takes a long time to redraw.
372 	 *
373 	 * Params:
374 	 *     autoRender = a boolean
375 	 *
376 	 * Since: 3.16
377 	 */
378 	public void setAutoRender(bool autoRender)
379 	{
380 		gtk_gl_area_set_auto_render(gtkGLArea, autoRender);
381 	}
382 
383 	/**
384 	 * Sets an error on the area which will be shown instead of the
385 	 * GL rendering. This is useful in the #GtkGLArea::create-context
386 	 * signal if GL context creation fails.
387 	 *
388 	 * Params:
389 	 *     error = a new #GError, or %NULL to unset the error
390 	 *
391 	 * Since: 3.16
392 	 */
393 	public void setError(ErrorG error)
394 	{
395 		gtk_gl_area_set_error(gtkGLArea, (error is null) ? null : error.getErrorGStruct());
396 	}
397 
398 	/**
399 	 * If @has_alpha is %TRUE the buffer allocated by the widget will have
400 	 * an alpha channel component, and when rendering to the window the
401 	 * result will be composited over whatever is below the widget.
402 	 *
403 	 * If @has_alpha is %FALSE there will be no alpha channel, and the
404 	 * buffer will fully replace anything below the widget.
405 	 *
406 	 * Params:
407 	 *     hasAlpha = %TRUE to add an alpha component
408 	 *
409 	 * Since: 3.16
410 	 */
411 	public void setHasAlpha(bool hasAlpha)
412 	{
413 		gtk_gl_area_set_has_alpha(gtkGLArea, hasAlpha);
414 	}
415 
416 	/**
417 	 * If @has_depth_buffer is %TRUE the widget will allocate and
418 	 * enable a depth buffer for the target framebuffer. Otherwise
419 	 * there will be none.
420 	 *
421 	 * Params:
422 	 *     hasDepthBuffer = %TRUE to add a depth buffer
423 	 *
424 	 * Since: 3.16
425 	 */
426 	public void setHasDepthBuffer(bool hasDepthBuffer)
427 	{
428 		gtk_gl_area_set_has_depth_buffer(gtkGLArea, hasDepthBuffer);
429 	}
430 
431 	/**
432 	 * If @has_stencil_buffer is %TRUE the widget will allocate and
433 	 * enable a stencil buffer for the target framebuffer. Otherwise
434 	 * there will be none.
435 	 *
436 	 * Params:
437 	 *     hasStencilBuffer = %TRUE to add a stencil buffer
438 	 *
439 	 * Since: 3.16
440 	 */
441 	public void setHasStencilBuffer(bool hasStencilBuffer)
442 	{
443 		gtk_gl_area_set_has_stencil_buffer(gtkGLArea, hasStencilBuffer);
444 	}
445 
446 	/**
447 	 * Sets the required version of OpenGL to be used when creating the context
448 	 * for the widget.
449 	 *
450 	 * This function must be called before the area has been realized.
451 	 *
452 	 * Params:
453 	 *     major = the major version
454 	 *     minor = the minor version
455 	 *
456 	 * Since: 3.16
457 	 */
458 	public void setRequiredVersion(int major, int minor)
459 	{
460 		gtk_gl_area_set_required_version(gtkGLArea, major, minor);
461 	}
462 
463 	/**
464 	 * Sets whether the @area should create an OpenGL or an OpenGL ES context.
465 	 *
466 	 * You should check the capabilities of the #GdkGLContext before drawing
467 	 * with either API.
468 	 *
469 	 * Params:
470 	 *     useEs = whether to use OpenGL or OpenGL ES
471 	 *
472 	 * Since: 3.22
473 	 */
474 	public void setUseEs(bool useEs)
475 	{
476 		gtk_gl_area_set_use_es(gtkGLArea, useEs);
477 	}
478 
479 	protected class OnCreateContextDelegateWrapper
480 	{
481 		static OnCreateContextDelegateWrapper[] listeners;
482 		GLContext delegate(GLArea) dlg;
483 		gulong handlerId;
484 		
485 		this(GLContext delegate(GLArea) dlg)
486 		{
487 			this.dlg = dlg;
488 			this.listeners ~= this;
489 		}
490 		
491 		void remove(OnCreateContextDelegateWrapper source)
492 		{
493 			foreach(index, wrapper; listeners)
494 			{
495 				if (wrapper.handlerId == source.handlerId)
496 				{
497 					listeners[index] = null;
498 					listeners = std.algorithm.remove(listeners, index);
499 					break;
500 				}
501 			}
502 		}
503 	}
504 
505 	/**
506 	 * The ::create-context signal is emitted when the widget is being
507 	 * realized, and allows you to override how the GL context is
508 	 * created. This is useful when you want to reuse an existing GL
509 	 * context, or if you want to try creating different kinds of GL
510 	 * options.
511 	 *
512 	 * If context creation fails then the signal handler can use
513 	 * gtk_gl_area_set_error() to register a more detailed error
514 	 * of how the construction failed.
515 	 *
516 	 * Returns: a newly created #GdkGLContext;
517 	 *     the #GtkGLArea widget will take ownership of the returned value.
518 	 *
519 	 * Since: 3.16
520 	 */
521 	gulong addOnCreateContext(GLContext delegate(GLArea) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
522 	{
523 		auto wrapper = new OnCreateContextDelegateWrapper(dlg);
524 		wrapper.handlerId = Signals.connectData(
525 			this,
526 			"create-context",
527 			cast(GCallback)&callBackCreateContext,
528 			cast(void*)wrapper,
529 			cast(GClosureNotify)&callBackCreateContextDestroy,
530 			connectFlags);
531 		return wrapper.handlerId;
532 	}
533 	
534 	extern(C) static GdkGLContext* callBackCreateContext(GtkGLArea* glareaStruct, OnCreateContextDelegateWrapper wrapper)
535 	{
536 		auto r = wrapper.dlg(wrapper.outer);
537 		return r.getGLContextStruct();
538 	}
539 	
540 	extern(C) static void callBackCreateContextDestroy(OnCreateContextDelegateWrapper wrapper, GClosure* closure)
541 	{
542 		wrapper.remove(wrapper);
543 	}
544 
545 	protected class OnRenderDelegateWrapper
546 	{
547 		static OnRenderDelegateWrapper[] listeners;
548 		bool delegate(GLContext, GLArea) dlg;
549 		gulong handlerId;
550 		
551 		this(bool delegate(GLContext, GLArea) dlg)
552 		{
553 			this.dlg = dlg;
554 			this.listeners ~= this;
555 		}
556 		
557 		void remove(OnRenderDelegateWrapper source)
558 		{
559 			foreach(index, wrapper; listeners)
560 			{
561 				if (wrapper.handlerId == source.handlerId)
562 				{
563 					listeners[index] = null;
564 					listeners = std.algorithm.remove(listeners, index);
565 					break;
566 				}
567 			}
568 		}
569 	}
570 
571 	/**
572 	 * The ::render signal is emitted every time the contents
573 	 * of the #GtkGLArea should be redrawn.
574 	 *
575 	 * The @context is bound to the @area prior to emitting this function,
576 	 * and the buffers are painted to the window once the emission terminates.
577 	 *
578 	 * Params:
579 	 *     context = the #GdkGLContext used by @area
580 	 *
581 	 * Returns: %TRUE to stop other handlers from being invoked for the event.
582 	 *     %FALSE to propagate the event further.
583 	 *
584 	 * Since: 3.16
585 	 */
586 	gulong addOnRender(bool delegate(GLContext, GLArea) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
587 	{
588 		auto wrapper = new OnRenderDelegateWrapper(dlg);
589 		wrapper.handlerId = Signals.connectData(
590 			this,
591 			"render",
592 			cast(GCallback)&callBackRender,
593 			cast(void*)wrapper,
594 			cast(GClosureNotify)&callBackRenderDestroy,
595 			connectFlags);
596 		return wrapper.handlerId;
597 	}
598 	
599 	extern(C) static int callBackRender(GtkGLArea* glareaStruct, GdkGLContext* context, OnRenderDelegateWrapper wrapper)
600 	{
601 		return wrapper.dlg(ObjectG.getDObject!(GLContext)(context), wrapper.outer);
602 	}
603 	
604 	extern(C) static void callBackRenderDestroy(OnRenderDelegateWrapper wrapper, GClosure* closure)
605 	{
606 		wrapper.remove(wrapper);
607 	}
608 
609 	protected class OnResizeDelegateWrapper
610 	{
611 		static OnResizeDelegateWrapper[] listeners;
612 		void delegate(int, int, GLArea) dlg;
613 		gulong handlerId;
614 		
615 		this(void delegate(int, int, GLArea) dlg)
616 		{
617 			this.dlg = dlg;
618 			this.listeners ~= this;
619 		}
620 		
621 		void remove(OnResizeDelegateWrapper source)
622 		{
623 			foreach(index, wrapper; listeners)
624 			{
625 				if (wrapper.handlerId == source.handlerId)
626 				{
627 					listeners[index] = null;
628 					listeners = std.algorithm.remove(listeners, index);
629 					break;
630 				}
631 			}
632 		}
633 	}
634 
635 	/**
636 	 * The ::resize signal is emitted once when the widget is realized, and
637 	 * then each time the widget is changed while realized. This is useful
638 	 * in order to keep GL state up to date with the widget size, like for
639 	 * instance camera properties which may depend on the width/height ratio.
640 	 *
641 	 * The GL context for the area is guaranteed to be current when this signal
642 	 * is emitted.
643 	 *
644 	 * The default handler sets up the GL viewport.
645 	 *
646 	 * Params:
647 	 *     width = the width of the viewport
648 	 *     height = the height of the viewport
649 	 *
650 	 * Since: 3.16
651 	 */
652 	gulong addOnResize(void delegate(int, int, GLArea) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
653 	{
654 		auto wrapper = new OnResizeDelegateWrapper(dlg);
655 		wrapper.handlerId = Signals.connectData(
656 			this,
657 			"resize",
658 			cast(GCallback)&callBackResize,
659 			cast(void*)wrapper,
660 			cast(GClosureNotify)&callBackResizeDestroy,
661 			connectFlags);
662 		return wrapper.handlerId;
663 	}
664 	
665 	extern(C) static void callBackResize(GtkGLArea* glareaStruct, int width, int height, OnResizeDelegateWrapper wrapper)
666 	{
667 		wrapper.dlg(width, height, wrapper.outer);
668 	}
669 	
670 	extern(C) static void callBackResizeDestroy(OnResizeDelegateWrapper wrapper, GClosure* closure)
671 	{
672 		wrapper.remove(wrapper);
673 	}
674 }