1 module nanogui.glcanvas;
2 /*
3     NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>.
4     The widget drawing code is based on the NanoVG demo application
5     by Mikko Mononen.
6 
7     All rights reserved. Use of this source code is governed by a
8     BSD-style license that can be found in the LICENSE.txt file.
9 */
10 /**
11  * \file nanogui/glcanvas.h
12  *
13  * \brief Canvas widget for rendering OpenGL content.  This widget was
14  *        contributed by Jan Winkler.
15  */
16 
17 import nanogui.widget;
18 // #include <nanogui/opengl.h>
19 // #include <nanogui/glutil.h>
20 
21 /**
22  * \class GLCanvas glcanvas.d
23  *
24  * \brief Canvas widget for rendering OpenGL content.  This widget was
25  *        contributed by Jan Winkler.
26  *
27  * Canvas widget that can be used to display arbitrary OpenGL content. This is
28  * useful to display and manipulate 3D objects as part of an interactive
29  * application. The implementation uses scissoring to ensure that rendered
30  * objects don't spill into neighboring widgets.
31  *
32  * \rst
33  * **Usage**
34  *     Override :func:`nanogui.GLCanvas.drawGL` in subclasses to provide
35  *     custom drawing code.
36  *
37  * \endrst
38  */
39 class GLCanvas : Widget
40 {
41 	import nanogui.common : Vector2f, Vector2i, Vector4i;	
42 public:
43     /**
44      * Creates a GLCanvas attached to the specified parent.
45      *
46      * \param parent
47      *     The Widget to attach this GLCanvas to.
48      */
49     this(Widget parent)
50 	{
51 		super(parent);
52 		mBackgroundColor = Vector4i(128, 128, 128, 255);
53 		mDrawBorder = true;
54 		mSize = Vector2i(250, 250);
55 	}
56 
57     /// Returns the background color.
58     final const(Color) backgroundColor() const { return mBackgroundColor; }
59 
60     /// Sets the background color.
61     final void backgroundColor(const Color backgroundColor) { mBackgroundColor = backgroundColor; }
62 
63     /// Set whether to draw the widget border or not.
64     final void drawBorder(const bool bDrawBorder) { mDrawBorder = bDrawBorder; }
65 
66     /// Return whether the widget border gets drawn or not.
67     bool drawBorder() const { return mDrawBorder; }
68 
69     /// Draw the canvas.
70     override void draw(ref NanoContext ctx)
71 	{
72 		Widget.draw(ctx);
73 
74 		if (mDrawBorder)
75 			drawWidgetBorder(ctx);
76 
77 		ctx.endFrame;
78 
79 		const screen = this.screen();
80 		assert(screen);
81 
82 		float pixelRatio = screen.pixelRatio;
83 		auto screenSize = cast(Vector2f) screen.size;
84 		Vector2i positionInScreen = absolutePosition;
85 
86 		auto size = cast(Vector2i)(cast(Vector2f)mSize * pixelRatio);
87 		auto imagePosition = cast(Vector2i)(Vector2f(positionInScreen[0],
88 			screenSize[1] - positionInScreen[1] -
89 			cast(float) mSize[1]) * pixelRatio);
90 
91 		import gfm.opengl;
92 		GLint[4] storedViewport;
93 		glGetIntegerv(GL_VIEWPORT, storedViewport.ptr);
94 
95 		glViewport(imagePosition[0], imagePosition[1], size[0] , size[1]);
96 
97 		glEnable(GL_SCISSOR_TEST);
98 		glScissor(imagePosition[0], imagePosition[1], size[0], size[1]);
99 		glClearColor(mBackgroundColor[0], mBackgroundColor[1],
100 					mBackgroundColor[2], mBackgroundColor[3]);
101 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
102 
103 		this.drawGL();
104 
105 		glDisable(GL_SCISSOR_TEST);
106 		glViewport(storedViewport[0], storedViewport[1],
107 				storedViewport[2], storedViewport[3]);
108 
109 		ctx.beginFrame(screen.size.x, screen.size.y);
110 	}
111 
112     /// Draw the GL scene. Override this method to draw the actual GL content.
113     void drawGL() {}
114 
115     // /// Save the state of this GLCanvas to the specified Serializer.
116     // virtual void save(Serializer &s) const override;
117 
118     // /// Set the state of this GLCanvas from the specified Serializer.
119     // virtual bool load(Serializer &s) override;
120 
121 protected:
122     /// Internal helper function for drawing the widget border
123     void drawWidgetBorder(NanoContext ctx) const
124 	{
125 		// import arsd.nanovega;
126 		ctx.beginPath;
127 		ctx.strokeWidth(1.0f);
128 		ctx.roundedRect(mPos.x - 0.5f, mPos.y - 0.5f,
129 					mSize.x + 1, mSize.y + 1, mTheme.mWindowCornerRadius);
130 		ctx.strokeColor(mTheme.mBorderLight);
131 		ctx.roundedRect(mPos.x - 1.0f, mPos.y - 1.0f,
132 					mSize.x + 2, mSize.y + 2, mTheme.mWindowCornerRadius);
133 		ctx.strokeColor(mTheme.mBorderDark);
134 		ctx.stroke;
135 	}
136 
137 protected:
138     /// The background color (what is used with ``glClearColor``).
139     Color mBackgroundColor;
140 
141     /// Whether to draw the widget border or not.
142     bool mDrawBorder;
143 
144 }