1/*
2 src/example4.cpp -- C++ version of an example application that shows
3 how to use the OpenGL widget. For a Python implementation, see
4 '../python/example4.py'.
5
6 NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>.
7 The widget drawing code is based on the NanoVG demo application
8 by Mikko Mononen.
9
10 All rights reserved. Use of this source code is governed by a
11 BSD-style license that can be found in the LICENSE.txt file.
12*/
13
14#include <nanogui/opengl.h>
15#include <nanogui/glutil.h>
16#include <nanogui/screen.h>
17#include <nanogui/window.h>
18#include <nanogui/layout.h>
19#include <nanogui/label.h>
20#include <nanogui/checkbox.h>
21#include <nanogui/button.h>
22#include <nanogui/toolbutton.h>
23#include <nanogui/popupbutton.h>
24#include <nanogui/combobox.h>
25#include <nanogui/progressbar.h>
26#include <nanogui/entypo.h>
27#include <nanogui/messagedialog.h>
28#include <nanogui/textbox.h>
29#include <nanogui/slider.h>
30#include <nanogui/imagepanel.h>
31#include <nanogui/imageview.h>
32#include <nanogui/vscrollpanel.h>
33#include <nanogui/colorwheel.h>
34#include <nanogui/graph.h>
35#include <nanogui/tabwidget.h>
36#include <nanogui/glcanvas.h>
37#include <iostream>
38#include <string>
39
40// Includes for the GLTexture class.
41#include <cstdint>
42#include <memory>
43#include <utility>
44
45#if defined(__GNUC__)
46# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
47#endif
48#if defined(_WIN32)
49# pragma warning(push)
50# pragma warning(disable: 4457 4456 4005 4312)
51#endif
52
53#if defined(_WIN32)
54# pragma warning(pop)
55#endif
56#if defined(_WIN32)
57# if defined(APIENTRY)
58# undef APIENTRY
59# endif
60# include <windows.h>
61#endif
62
63using std::cout;
64using std::cerr;
65using std::endl;
66using std::string;
67using std::vector;
68using std::pair;
69using std::to_string;
70
71
72class MyGLCanvas : public nanogui::GLCanvas {
73public:
74 MyGLCanvas(Widget *parent) : nanogui::GLCanvas(parent), mRotation(nanogui::Vector3f(0.25f, 0.5f, 0.33f)) {
75 using namespace nanogui;
76
77 mShader.init(
78 /* An identifying name */
79 "a_simple_shader",
80
81 /* Vertex shader */
82 "#version 330\n"
83 "uniform mat4 modelViewProj;\n"
84 "in vec3 position;\n"
85 "in vec3 color;\n"
86 "out vec4 frag_color;\n"
87 "void main() {\n"
88 " frag_color = 3.0 * modelViewProj * vec4(color, 1.0);\n"
89 " gl_Position = modelViewProj * vec4(position, 1.0);\n"
90 "}",
91
92 /* Fragment shader */
93 "#version 330\n"
94 "out vec4 color;\n"
95 "in vec4 frag_color;\n"
96 "void main() {\n"
97 " color = frag_color;\n"
98 "}"
99 );
100
101 MatrixXu indices(3, 12); /* Draw a cube */
102 indices.col( 0) << 0, 1, 3;
103 indices.col( 1) << 3, 2, 1;
104 indices.col( 2) << 3, 2, 6;
105 indices.col( 3) << 6, 7, 3;
106 indices.col( 4) << 7, 6, 5;
107 indices.col( 5) << 5, 4, 7;
108 indices.col( 6) << 4, 5, 1;
109 indices.col( 7) << 1, 0, 4;
110 indices.col( 8) << 4, 0, 3;
111 indices.col( 9) << 3, 7, 4;
112 indices.col(10) << 5, 6, 2;
113 indices.col(11) << 2, 1, 5;
114
115 MatrixXf positions(3, 8);
116 positions.col(0) << -1, 1, 1;
117 positions.col(1) << -1, 1, -1;
118 positions.col(2) << 1, 1, -1;
119 positions.col(3) << 1, 1, 1;
120 positions.col(4) << -1, -1, 1;
121 positions.col(5) << -1, -1, -1;
122 positions.col(6) << 1, -1, -1;
123 positions.col(7) << 1, -1, 1;
124
125 MatrixXf colors(3, 12);
126 colors.col( 0) << 1, 0, 0;
127 colors.col( 1) << 0, 1, 0;
128 colors.col( 2) << 1, 1, 0;
129 colors.col( 3) << 0, 0, 1;
130 colors.col( 4) << 1, 0, 1;
131 colors.col( 5) << 0, 1, 1;
132 colors.col( 6) << 1, 1, 1;
133 colors.col( 7) << 0.5, 0.5, 0.5;
134 colors.col( 8) << 1, 0, 0.5;
135 colors.col( 9) << 1, 0.5, 0;
136 colors.col(10) << 0.5, 1, 0;
137 colors.col(11) << 0.5, 1, 0.5;
138
139 mShader.bind();
140 mShader.uploadIndices(indices);
141
142 mShader.uploadAttrib("position", positions);
143 mShader.uploadAttrib("color", colors);
144 }
145
146 ~MyGLCanvas() {
147 mShader.free();
148 }
149
150 void setRotation(nanogui::Vector3f vRotation) {
151 mRotation = vRotation;
152 }
153
154 virtual void drawGL() override {
155 using namespace nanogui;
156
157 mShader.bind();
158
159 Matrix4f mvp;
160 mvp.setIdentity();
161 float fTime = (float)glfwGetTime();
162 mvp.topLeftCorner<3,3>() = Eigen::Matrix3f(Eigen::AngleAxisf(mRotation[0]*fTime, Vector3f::UnitX()) *
163 Eigen::AngleAxisf(mRotation[1]*fTime, Vector3f::UnitY()) *
164 Eigen::AngleAxisf(mRotation[2]*fTime, Vector3f::UnitZ())) * 0.25f;
165
166 mShader.setUniform("modelViewProj", mvp);
167
168 glEnable(GL_DEPTH_TEST);
169 /* Draw 12 triangles starting at index 0 */
170 mShader.drawIndexed(GL_TRIANGLES, 0, 12);
171 glDisable(GL_DEPTH_TEST);
172 }
173
174private:
175 nanogui::GLShader mShader;
176 Eigen::Vector3f mRotation;
177};
178
179
180class ExampleApplication : public nanogui::Screen {
181public:
182 ExampleApplication() : nanogui::Screen(Eigen::Vector2i(800, 600), "NanoGUI Test", false) {
183 using namespace nanogui;
184
185 Window *window = new Window(this, "GLCanvas Demo");
186 window->setPosition(Vector2i(15, 15));
187 window->setLayout(new GroupLayout());
188
189 mCanvas = new MyGLCanvas(window);
190 mCanvas->setBackgroundColor({100, 100, 100, 255});
191 mCanvas->setSize({400, 400});
192
193 Widget *tools = new Widget(window);
194 tools->setLayout(new BoxLayout(Orientation::Horizontal,
195 Alignment::Middle, 0, 5));
196
197 Button *b0 = new Button(tools, "Random Color");
198 b0->setCallback([this]() { mCanvas->setBackgroundColor(Vector4i(rand() % 256, rand() % 256, rand() % 256, 255)); });
199
200 Button *b1 = new Button(tools, "Random Rotation");
201 b1->setCallback([this]() { mCanvas->setRotation(nanogui::Vector3f((rand() % 100) / 100.0f, (rand() % 100) / 100.0f, (rand() % 100) / 100.0f)); });
202
203 performLayout();
204 }
205
206 virtual bool keyboardEvent(int key, int scancode, int action, int modifiers) {
207 if (Screen::keyboardEvent(key, scancode, action, modifiers))
208 return true;
209 if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
210 setVisible(false);
211 return true;
212 }
213 return false;
214 }
215
216 virtual void draw(NVGcontext *ctx) {
217 /* Draw the user interface */
218 Screen::draw(ctx);
219 }
220private:
221 MyGLCanvas *mCanvas;
222};
223
224int main(int /* argc */, char ** /* argv */) {
225 try {
226 nanogui::init();
227
228 /* scoped variables */ {
229 nanogui::ref<ExampleApplication> app = new ExampleApplication();
230 app->drawAll();
231 app->setVisible(true);
232 nanogui::mainloop();
233 }
234
235 nanogui::shutdown();
236 } catch (const std::runtime_error &e) {
237 std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what());
238 #if defined(_WIN32)
239 MessageBoxA(nullptr, error_msg.c_str(), NULL, MB_ICONERROR | MB_OK);
240 #else
241 std::cerr << error_msg << endl;
242 #endif
243 return -1;
244 }
245
246 return 0;
247}
248