1 /*
2 * Copyright (c) 2011-2021, The DART development contributors
3 * All rights reserved.
4 *
5 * The list of contributors can be found at:
6 * https://github.com/dartsim/dart/blob/master/LICENSE
7 *
8 * This file is provided under the following "BSD-style" License:
9 * Redistribution and use in source and binary forms, with or
10 * without modification, are permitted provided that the following
11 * conditions are met:
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include "dart/gui/glut/Window.hpp"
34
35 #include "dart/external/lodepng/lodepng.h"
36
37 #ifdef _WIN32
38 # include <direct.h>
39 # include <sys/stat.h>
40 # include <sys/types.h>
41 #else
42 # include <dirent.h>
43 # include <sys/stat.h>
44 # include <sys/types.h>
45 #endif
46 #include <cstdio>
47 #include <iostream>
48 #include <vector>
49
50 #include "dart/common/Console.hpp"
51 #include "dart/gui/GLFuncs.hpp"
52 #include "dart/gui/OpenGLRenderInterface.hpp"
53 #include "dart/gui/glut/LoadGlut.hpp"
54
55 namespace dart {
56 namespace gui {
57 namespace glut {
58
59 std::vector<Window*> Window::mWindows;
60 std::vector<int> Window::mWinIDs;
61
Window()62 Window::Window()
63 {
64 mWinWidth = 0;
65 mWinHeight = 0;
66 mMouseX = 0;
67 mMouseY = 0;
68 mDisplayTimeout = 1000.0 / 30.0;
69 mMouseDown = false;
70 mMouseDrag = false;
71 mCapture = false;
72 mBackground[0] = 0.3;
73 mBackground[1] = 0.3;
74 mBackground[2] = 0.3;
75 mBackground[3] = 1.0;
76 mRI = nullptr;
77 }
78
~Window()79 Window::~Window()
80 {
81 delete mRI;
82 }
83
initWindow(int _w,int _h,const char * _name)84 void Window::initWindow(int _w, int _h, const char* _name)
85 {
86 mWindows.push_back(this);
87
88 mWinWidth = _w;
89 mWinHeight = _h;
90
91 glutInitDisplayMode(
92 GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE | GLUT_ACCUM);
93 glutInitWindowPosition(150, 100);
94 glutInitWindowSize(_w, _h);
95 mWinIDs.push_back(glutCreateWindow(_name));
96
97 glutDisplayFunc(refresh);
98 glutReshapeFunc(reshape);
99 glutKeyboardFunc(keyEvent);
100 glutSpecialFunc(specKeyEvent);
101 glutMouseFunc(mouseClick);
102 glutMotionFunc(mouseDrag);
103 glutPassiveMotionFunc(mouseMove);
104
105 delete mRI;
106 mRI = new gui::OpenGLRenderInterface();
107 mRI->initialize();
108 // glutTimerFunc(mDisplayTimeout, refreshTimer, 0);
109 // glutTimerFunc(mDisplayTimeout, runTimer, 0);
110
111 #ifndef _WIN32
112 glDisable(GL_MULTISAMPLE);
113 #endif
114 // TODO: Disabled use of GL_MULTISAMPLE for Windows. Please see #411 for the
115 // detail.
116
117 glutTimerFunc(mDisplayTimeout, refreshTimer, 0);
118 // Note: We book the timer id 0 for the main rendering purpose.
119 }
120
reshape(int _w,int _h)121 void Window::reshape(int _w, int _h)
122 {
123 current()->mScreenshotTemp = std::vector<unsigned char>(_w * _h * 4);
124 current()->mScreenshotTemp2 = std::vector<unsigned char>(_w * _h * 4);
125 current()->resize(_w, _h);
126 }
127
keyEvent(unsigned char _key,int _x,int _y)128 void Window::keyEvent(unsigned char _key, int _x, int _y)
129 {
130 current()->keyboard(_key, _x, _y);
131 }
132
specKeyEvent(int _key,int _x,int _y)133 void Window::specKeyEvent(int _key, int _x, int _y)
134 {
135 current()->specKey(_key, _x, _y);
136 }
137
mouseClick(int _button,int _state,int _x,int _y)138 void Window::mouseClick(int _button, int _state, int _x, int _y)
139 {
140 current()->click(_button, _state, _x, _y);
141 }
142
mouseDrag(int _x,int _y)143 void Window::mouseDrag(int _x, int _y)
144 {
145 current()->drag(_x, _y);
146 }
147
mouseMove(int _x,int _y)148 void Window::mouseMove(int _x, int _y)
149 {
150 current()->move(_x, _y);
151 }
152
refresh()153 void Window::refresh()
154 {
155 current()->render();
156 }
157
refreshTimer(int _val)158 void Window::refreshTimer(int _val)
159 {
160 current()->displayTimer(_val);
161 }
162
displayTimer(int _val)163 void Window::displayTimer(int _val)
164 {
165 glutPostRedisplay();
166 glutTimerFunc(mDisplayTimeout, refreshTimer, _val);
167 }
168
simTimer(int)169 void Window::simTimer(int /*_val*/)
170 {
171 }
172
runTimer(int _val)173 void Window::runTimer(int _val)
174 {
175 current()->simTimer(_val);
176 }
177
screenshot()178 bool Window::screenshot()
179 {
180 static int count = 0;
181 const char directory[8] = "frames";
182 const char fileBase[8] = "Capture";
183 char fileName[32];
184
185 // create frames directory if not exists
186 using Stat = struct stat;
187 Stat buff;
188
189 #ifdef _WIN32
190 # define __S_ISTYPE(mode, mask) (((mode)&_S_IFMT) == (mask))
191 # define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR)
192 if (stat(directory, &buff) != 0)
193 _mkdir(directory);
194 #else
195 if (stat(directory, &buff) != 0)
196 mkdir(directory, 0777);
197 #endif
198
199 if (!S_ISDIR(buff.st_mode))
200 {
201 dtwarn << "[Window::screenshot] 'frames' is not a directory, "
202 << "cannot write a screenshot\n";
203 return false;
204 }
205
206 // png
207 #ifdef _WIN32
208 _snprintf(
209 fileName,
210 sizeof(fileName),
211 "%s%s%s%.4d.png",
212 directory,
213 "\\",
214 fileBase,
215 count++);
216 #else
217 std::snprintf(
218 fileName,
219 sizeof(fileName),
220 "%s%s%s%.4d.png",
221 directory,
222 "/",
223 fileBase,
224 count++);
225 #endif
226 int tw = glutGet(GLUT_WINDOW_WIDTH);
227 int th = glutGet(GLUT_WINDOW_HEIGHT);
228
229 glReadPixels(0, 0, tw, th, GL_RGBA, GL_UNSIGNED_BYTE, &mScreenshotTemp[0]);
230
231 // reverse temp2 temp1
232 for (int row = 0; row < th; row++)
233 {
234 memcpy(
235 &mScreenshotTemp2[row * tw * 4],
236 &mScreenshotTemp[(th - row - 1) * tw * 4],
237 tw * 4);
238 }
239
240 unsigned result = lodepng::encode(fileName, mScreenshotTemp2, tw, th);
241
242 // if there's an error, display it
243 if (result)
244 {
245 std::cout << "lodepng error " << result << ": "
246 << lodepng_error_text(result) << std::endl;
247 return false;
248 }
249 else
250 {
251 std::cout << "wrote screenshot " << fileName << "\n";
252 return true;
253 }
254 }
255
current()256 inline Window* Window::current()
257 {
258 int id = glutGetWindow();
259 for (unsigned int i = 0; i < mWinIDs.size(); i++)
260 {
261 if (mWinIDs.at(i) == id)
262 {
263 return mWindows.at(i);
264 }
265 }
266 std::cout << "An unknown error occurred!" << std::endl;
267 exit(0);
268 }
269
keyboard(unsigned char,int,int)270 void Window::keyboard(unsigned char /*_key*/, int /*_x*/, int /*_y*/)
271 {
272 // TODO(JS): Is 2d point information necessary for keyboard event?
273 }
274
specKey(int,int,int)275 void Window::specKey(int /*_key*/, int /*_x*/, int /*_y*/)
276 {
277 }
278
click(int,int,int,int)279 void Window::click(int /*_button*/, int /*_state*/, int /*_x*/, int /*_y*/)
280 {
281 }
282
drag(int,int)283 void Window::drag(int /*_x*/, int /*_y*/)
284 {
285 }
286
move(int,int)287 void Window::move(int /*_x*/, int /*_y*/)
288 {
289 }
290
291 } // namespace glut
292 } // namespace gui
293 } // namespace dart
294