]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CIrrDeviceConsole.cpp
Stop dlopening libGL(ESv2).so
[irrlicht.git] / source / Irrlicht / CIrrDeviceConsole.cpp
1 // Copyright (C) 2009-2012 Gaz Davidson\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "CIrrDeviceConsole.h"\r
6 \r
7 #ifdef _IRR_COMPILE_WITH_CONSOLE_DEVICE_\r
8 \r
9 #include "os.h"\r
10 #include "IGUISkin.h"\r
11 #include "IGUIEnvironment.h"\r
12 \r
13 // to close the device on terminate signal\r
14 irr::CIrrDeviceConsole *DeviceToClose;\r
15 \r
16 #ifdef _IRR_WINDOWS_NT_CONSOLE_\r
17 // Callback for Windows\r
18 BOOL WINAPI ConsoleHandler(DWORD CEvent)\r
19 {\r
20     switch(CEvent)\r
21     {\r
22     case CTRL_C_EVENT:\r
23                 irr::os::Printer::log("Closing console device", "CTRL+C");\r
24                 break;\r
25         case CTRL_BREAK_EVENT:\r
26                 irr::os::Printer::log("Closing console device", "CTRL+Break");\r
27                 break;\r
28     case CTRL_CLOSE_EVENT:\r
29                 irr::os::Printer::log("Closing console device", "User closed console");\r
30                 break;\r
31     case CTRL_LOGOFF_EVENT:\r
32                 irr::os::Printer::log("Closing console device", "User is logging off");\r
33                 break;\r
34     case CTRL_SHUTDOWN_EVENT:\r
35                 irr::os::Printer::log("Closing console device", "Computer shutting down");\r
36                 break;\r
37     }\r
38         DeviceToClose->closeDevice();\r
39     return TRUE;\r
40 }\r
41 #elif defined(_IRR_POSIX_API_)\r
42 // sigterm handler\r
43 #include <signal.h>\r
44 \r
45 void sighandler(int sig)\r
46 {\r
47         irr::core::stringc code = "Signal ";\r
48         code += sig;\r
49         code += " received";\r
50         irr::os::Printer::log("Closing console device", code.c_str());\r
51 \r
52         DeviceToClose->closeDevice();\r
53 }\r
54 #endif\r
55 \r
56 namespace irr\r
57 {\r
58 \r
59 const c8 ASCIIArtChars[] = " .,'~:;!+>=icopjtJY56SB8XDQKHNWM"; //MWNHKQDX8BS65YJtjpoci=+>!;:~',. ";\r
60 const u16 ASCIIArtCharsCount = 32;\r
61 \r
62 //const c8 ASCIIArtChars[] = " \xb0\xb1\xf9\xb2\xdb";\r
63 //const u16 ASCIIArtCharsCount = 5;\r
64 \r
65 //! constructor\r
66 CIrrDeviceConsole::CIrrDeviceConsole(const SIrrlichtCreationParameters& params)\r
67   : CIrrDeviceStub(params), IsWindowFocused(true), ConsoleFont(0), OutFile(stdout)\r
68 {\r
69         DeviceToClose = this;\r
70 \r
71 #ifdef _IRR_WINDOWS_NT_CONSOLE_\r
72         MouseButtonStates = 0;\r
73 \r
74         WindowsSTDIn  = GetStdHandle(STD_INPUT_HANDLE);\r
75         WindowsSTDOut = GetStdHandle(STD_OUTPUT_HANDLE);\r
76 \r
77         if (CreationParams.Fullscreen)\r
78         {\r
79                 PCOORD dimensions = 0;\r
80                 if (SetConsoleDisplayMode(WindowsSTDOut, CONSOLE_FULLSCREEN_MODE, dimensions))\r
81                 {\r
82                         CreationParams.WindowSize.Width = dimensions->X;\r
83                         CreationParams.WindowSize.Width = dimensions->Y;\r
84                 }\r
85         }\r
86         else\r
87         {\r
88                 COORD ConsoleSize;\r
89                 ConsoleSize.X = CreationParams.WindowSize.Width;\r
90                 ConsoleSize.X = CreationParams.WindowSize.Height;\r
91                 SetConsoleScreenBufferSize(WindowsSTDOut, ConsoleSize);\r
92         }\r
93 \r
94         // catch windows close/break signals\r
95         SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE);\r
96 \r
97 #elif defined(_IRR_POSIX_API_)\r
98         // catch other signals\r
99         signal(SIGABRT, &sighandler);\r
100         signal(SIGTERM, &sighandler);\r
101         signal(SIGINT,  &sighandler);\r
102 \r
103         // set output stream\r
104         if (params.WindowId)\r
105                 OutFile = (FILE*)(params.WindowId);\r
106 #endif\r
107 \r
108 #ifdef _IRR_VT100_CONSOLE_\r
109         // reset terminal\r
110         fprintf(OutFile, "%cc", 27);\r
111         // disable line wrapping\r
112         fprintf(OutFile, "%c[7l", 27);\r
113 #endif\r
114 \r
115         switch (params.DriverType)\r
116         {\r
117         case video::EDT_SOFTWARE:\r
118                 #ifdef _IRR_COMPILE_WITH_SOFTWARE_\r
119                 VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);\r
120                 #else\r
121                 os::Printer::log("Software driver was not compiled in.", ELL_ERROR);\r
122                 #endif\r
123                 break;\r
124 \r
125         case video::EDT_BURNINGSVIDEO:\r
126                 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_\r
127                 VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);\r
128                 #else\r
129                 os::Printer::log("Burning's Video driver was not compiled in.", ELL_ERROR);\r
130                 #endif\r
131                 break;\r
132 \r
133         case video::EDT_DIRECT3D9:\r
134         case video::EDT_OPENGL:\r
135                 os::Printer::log("The console device cannot use hardware drivers yet.", ELL_ERROR);\r
136                 break;\r
137         case video::EDT_NULL:\r
138                 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);\r
139                 break;\r
140         default:\r
141                 os::Printer::log("Unsupported device.", ELL_ERROR);\r
142                 break;\r
143         }\r
144 \r
145         // set up output buffer\r
146         for (u32 y=0; y<CreationParams.WindowSize.Height; ++y)\r
147         {\r
148                 core::stringc str;\r
149                 str.reserve(CreationParams.WindowSize.Width);\r
150                 for (u32 x=0; x<CreationParams.WindowSize.Width; ++x)\r
151                         str += " ";\r
152                 OutputBuffer.push_back(str);\r
153         }\r
154 \r
155 \r
156 #ifdef _IRR_WINDOWS_NT_CONSOLE_\r
157         CursorControl = new CCursorControl(CreationParams.WindowSize);\r
158 #endif\r
159 \r
160         if (VideoDriver)\r
161         {\r
162                 createGUIAndScene();\r
163 #ifdef _IRR_USE_CONSOLE_FONT_\r
164                 if (GUIEnvironment)\r
165                 {\r
166                         ConsoleFont = new gui::CGUIConsoleFont(this);\r
167                         gui::IGUISkin *skin = GUIEnvironment->getSkin();\r
168                         if (skin)\r
169                         {\r
170                                 for (u32 i=0; i < gui::EGDF_COUNT; ++i)\r
171                                         skin->setFont(ConsoleFont, gui::EGUI_DEFAULT_FONT(i));\r
172                         }\r
173                 }\r
174 #endif\r
175         }\r
176 }\r
177 \r
178 //! destructor\r
179 CIrrDeviceConsole::~CIrrDeviceConsole()\r
180 {\r
181         // GUI and scene are dropped in the stub\r
182         if (CursorControl)\r
183         {\r
184                 CursorControl->drop();\r
185                 CursorControl = 0;\r
186         }\r
187         if (ConsoleFont)\r
188         {\r
189                 ConsoleFont->drop();\r
190                 ConsoleFont = 0;\r
191         }\r
192 #ifdef _IRR_VT100_CONSOLE_\r
193         // reset terminal\r
194         fprintf(OutFile, "%cc", 27);\r
195 #endif\r
196 }\r
197 \r
198 //! runs the device. Returns false if device wants to be deleted\r
199 bool CIrrDeviceConsole::run()\r
200 {\r
201         // increment timer\r
202         os::Timer::tick();\r
203 \r
204         // process Windows console input\r
205 #ifdef _IRR_WINDOWS_NT_CONSOLE_\r
206 \r
207         INPUT_RECORD in;\r
208         DWORD        oldMode;\r
209         DWORD        count, waste;\r
210 \r
211         // get old input mode\r
212         GetConsoleMode(WindowsSTDIn, &oldMode);\r
213         SetConsoleMode(WindowsSTDIn, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);\r
214 \r
215         GetNumberOfConsoleInputEvents(WindowsSTDIn, &count);\r
216 \r
217         // read keyboard and mouse input\r
218         while (count)\r
219         {\r
220                 ReadConsoleInput(WindowsSTDIn, &in, 1, &waste );\r
221                 switch(in.EventType)\r
222                 {\r
223                 case KEY_EVENT:\r
224                 {\r
225                         SEvent e;\r
226                         e.EventType            = EET_KEY_INPUT_EVENT;\r
227                         e.KeyInput.PressedDown = (in.Event.KeyEvent.bKeyDown == TRUE);\r
228                         e.KeyInput.Control     = (in.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0;\r
229                         e.KeyInput.Shift       = (in.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) != 0;\r
230                         e.KeyInput.Key         = EKEY_CODE(in.Event.KeyEvent.wVirtualKeyCode);\r
231                         e.KeyInput.Char        = in.Event.KeyEvent.uChar.UnicodeChar;\r
232                         postEventFromUser(e);\r
233                         break;\r
234                 }\r
235                 case MOUSE_EVENT:\r
236                 {\r
237                         SEvent e;\r
238                         e.EventType        = EET_MOUSE_INPUT_EVENT;\r
239                         e.MouseInput.X     = in.Event.MouseEvent.dwMousePosition.X;\r
240                         e.MouseInput.Y     = in.Event.MouseEvent.dwMousePosition.Y;\r
241                         e.MouseInput.Wheel = 0.f;\r
242                         e.MouseInput.ButtonStates =\r
243                                 ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) ? EMBSM_LEFT   : 0 ) |\r
244                                 ( (in.Event.MouseEvent.dwButtonState & RIGHTMOST_BUTTON_PRESSED)     ? EMBSM_RIGHT  : 0 ) |\r
245                                 ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) ? EMBSM_MIDDLE : 0 ) |\r
246                                 ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_3RD_BUTTON_PRESSED) ? EMBSM_EXTRA1 : 0 ) |\r
247                                 ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_4TH_BUTTON_PRESSED) ? EMBSM_EXTRA2 : 0 );\r
248 \r
249                         if (in.Event.MouseEvent.dwEventFlags & MOUSE_MOVED)\r
250                         {\r
251                                 CursorControl->setPosition(core::position2di(e.MouseInput.X, e.MouseInput.Y));\r
252 \r
253                                 // create mouse moved event\r
254                                 e.MouseInput.Event = EMIE_MOUSE_MOVED;\r
255                                 postEventFromUser(e);\r
256                         }\r
257 \r
258                         if (in.Event.MouseEvent.dwEventFlags & MOUSE_WHEELED)\r
259                         {\r
260                                 e.MouseInput.Event = EMIE_MOUSE_WHEEL;\r
261                                 e.MouseInput.Wheel = (in.Event.MouseEvent.dwButtonState & 0xFF000000) ? -1.0f : 1.0f;\r
262                                 postEventFromUser(e);\r
263                         }\r
264 \r
265                         if ( (MouseButtonStates & EMBSM_LEFT) != (e.MouseInput.ButtonStates & EMBSM_LEFT) )\r
266                         {\r
267                                 e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_LEFT) ? EMIE_LMOUSE_PRESSED_DOWN : EMIE_LMOUSE_LEFT_UP;\r
268                                 postEventFromUser(e);\r
269                         }\r
270 \r
271                         if ( (MouseButtonStates & EMBSM_RIGHT) != (e.MouseInput.ButtonStates & EMBSM_RIGHT) )\r
272                         {\r
273                                 e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_RIGHT) ? EMIE_RMOUSE_PRESSED_DOWN : EMIE_RMOUSE_LEFT_UP;\r
274                                 postEventFromUser(e);\r
275                         }\r
276 \r
277                         if ( (MouseButtonStates & EMBSM_MIDDLE) != (e.MouseInput.ButtonStates & EMBSM_MIDDLE) )\r
278                         {\r
279                                 e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_MIDDLE) ? EMIE_MMOUSE_PRESSED_DOWN : EMIE_MMOUSE_LEFT_UP;\r
280                                 postEventFromUser(e);\r
281                         }\r
282 \r
283                         // save current button states\r
284                         MouseButtonStates = e.MouseInput.ButtonStates;\r
285 \r
286                         break;\r
287                 }\r
288                 case WINDOW_BUFFER_SIZE_EVENT:\r
289                         VideoDriver->OnResize(\r
290                                 core::dimension2d<u32>(in.Event.WindowBufferSizeEvent.dwSize.X,\r
291                                                        in.Event.WindowBufferSizeEvent.dwSize.Y));\r
292                         break;\r
293                 case FOCUS_EVENT:\r
294                         IsWindowFocused = (in.Event.FocusEvent.bSetFocus == TRUE);\r
295                         break;\r
296                 default:\r
297                         break;\r
298                 }\r
299                 GetNumberOfConsoleInputEvents(WindowsSTDIn, &count);\r
300         }\r
301 \r
302         // set input mode\r
303         SetConsoleMode(WindowsSTDIn, oldMode);\r
304 #else\r
305         // todo: keyboard input from terminal in raw mode\r
306 #endif\r
307 \r
308         return !Close;\r
309 }\r
310 \r
311 //! Cause the device to temporarily pause execution and let other processes to run\r
312 // This should bring down processor usage without major performance loss for Irrlicht\r
313 void CIrrDeviceConsole::yield()\r
314 {\r
315 #ifdef _IRR_WINDOWS_API_\r
316         Sleep(1);\r
317 #else\r
318         struct timespec ts = {0,0};\r
319         nanosleep(&ts, NULL);\r
320 #endif\r
321 }\r
322 \r
323 //! Pause execution and let other processes to run for a specified amount of time.\r
324 void CIrrDeviceConsole::sleep(u32 timeMs, bool pauseTimer)\r
325 {\r
326         const bool wasStopped = Timer ? Timer->isStopped() : true;\r
327 \r
328 #ifdef _IRR_WINDOWS_API_\r
329         Sleep(timeMs);\r
330 #else\r
331         struct timespec ts;\r
332         ts.tv_sec = (time_t) (timeMs / 1000);\r
333         ts.tv_nsec = (long) (timeMs % 1000) * 1000000;\r
334 \r
335         if (pauseTimer && !wasStopped)\r
336                 Timer->stop();\r
337 \r
338         nanosleep(&ts, NULL);\r
339 #endif\r
340 \r
341         if (pauseTimer && !wasStopped)\r
342                 Timer->start();\r
343 }\r
344 \r
345 //! sets the caption of the window\r
346 void CIrrDeviceConsole::setWindowCaption(const wchar_t* text)\r
347 {\r
348 #ifdef _IRR_WINDOWS_NT_CONSOLE_\r
349         SetConsoleTitleW(text);\r
350 #endif\r
351 }\r
352 \r
353 //! returns if window is active. if not, nothing need to be drawn\r
354 bool CIrrDeviceConsole::isWindowActive() const\r
355 {\r
356         // there is no window, but we always assume it is active\r
357         return true;\r
358 }\r
359 \r
360 //! returns if window has focus\r
361 bool CIrrDeviceConsole::isWindowFocused() const\r
362 {\r
363         return IsWindowFocused;\r
364 }\r
365 \r
366 //! returns if window is minimized\r
367 bool CIrrDeviceConsole::isWindowMinimized() const\r
368 {\r
369         return false;\r
370 }\r
371 \r
372 //! presents a surface in the client area\r
373 bool CIrrDeviceConsole::present(video::IImage* surface, void* windowId, core::rect<s32>* src)\r
374 {\r
375 \r
376         if (surface)\r
377         {\r
378                 for (u32 y=0; y < surface->getDimension().Height; ++y)\r
379                 {\r
380                         for (u32 x=0; x< surface->getDimension().Width; ++x)\r
381                         {\r
382                                 // get average pixel\r
383                                 u32 avg = surface->getPixel(x,y).getAverage() * (ASCIIArtCharsCount-1);\r
384                                 avg /= 255;\r
385                                 OutputBuffer[y] [x] = ASCIIArtChars[avg];\r
386                         }\r
387                 }\r
388         }\r
389 #ifdef _IRR_USE_CONSOLE_FONT_\r
390         for (u32 i=0; i< Text.size(); ++i)\r
391         {\r
392                 s32 y = Text[i].Pos.Y;\r
393 \r
394                 if ( y < (s32)OutputBuffer.size() && y > 0)\r
395                         for (u32 c=0; c < Text[i].Text.size() && c + Text[i].Pos.X < OutputBuffer[y].size(); ++c)\r
396                                 //if (Text[i].Text[c] != ' ')\r
397                                 OutputBuffer[y] [c+Text[i].Pos.X] = Text[i].Text[c];\r
398         }\r
399         Text.clear();\r
400 #endif\r
401 \r
402         // draw output\r
403         for (u32 y=0; y<OutputBuffer.size(); ++y)\r
404         {\r
405                 setTextCursorPos(0,y);\r
406                 fprintf(OutFile, "%s", OutputBuffer[y].c_str());\r
407         }\r
408         return surface != 0;\r
409 }\r
410 \r
411 //! notifies the device that it should close itself\r
412 void CIrrDeviceConsole::closeDevice()\r
413 {\r
414         // return false next time we run()\r
415         Close = true;\r
416 }\r
417 \r
418 \r
419 //! Sets if the window should be resizable in windowed mode.\r
420 void CIrrDeviceConsole::setResizable(bool resize)\r
421 {\r
422         // do nothing\r
423 }\r
424 \r
425 \r
426 //! Minimize the window.\r
427 void CIrrDeviceConsole::minimizeWindow()\r
428 {\r
429         // do nothing\r
430 }\r
431 \r
432 \r
433 //! Maximize window\r
434 void CIrrDeviceConsole::maximizeWindow()\r
435 {\r
436         // do nothing\r
437 }\r
438 \r
439 \r
440 //! Restore original window size\r
441 void CIrrDeviceConsole::restoreWindow()\r
442 {\r
443         // do nothing\r
444 }\r
445 \r
446 \r
447 void CIrrDeviceConsole::setTextCursorPos(s16 x, s16 y)\r
448 {\r
449 #ifdef _IRR_WINDOWS_NT_CONSOLE_\r
450         // move WinNT cursor\r
451         COORD Position;\r
452     Position.X = x;\r
453     Position.Y = y;\r
454     SetConsoleCursorPosition(WindowsSTDOut, Position);\r
455 #elif defined(_IRR_VT100_CONSOLE_)\r
456         // send escape code\r
457         fprintf(OutFile, "%c[%d;%dH", 27, y, x);\r
458 #else\r
459         // not implemented\r
460 #endif\r
461 }\r
462 \r
463 void CIrrDeviceConsole::addPostPresentText(s16 X, s16 Y, const wchar_t *text)\r
464 {\r
465         SPostPresentText p;\r
466         p.Text = text;\r
467         p.Pos.X = X;\r
468         p.Pos.Y = Y;\r
469         Text.push_back(p);\r
470 }\r
471 \r
472 } // end namespace irr\r
473 \r
474 #endif // _IRR_COMPILE_WITH_CONSOLE_DEVICE_\r