123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 |
- // Copyright (C) 2009-2012 Gaz Davidson
- // This file is part of the "Irrlicht Engine".
- // For conditions of distribution and use, see copyright notice in irrlicht.h
- #include "CIrrDeviceConsole.h"
- #ifdef _IRR_COMPILE_WITH_CONSOLE_DEVICE_
- #include "os.h"
- #include "IGUISkin.h"
- #include "IGUIEnvironment.h"
- // to close the device on terminate signal
- irr::CIrrDeviceConsole *DeviceToClose;
- #ifdef _IRR_WINDOWS_NT_CONSOLE_
- // Callback for Windows
- BOOL WINAPI ConsoleHandler(DWORD CEvent)
- {
- switch(CEvent)
- {
- case CTRL_C_EVENT:
- irr::os::Printer::log("Closing console device", "CTRL+C");
- break;
- case CTRL_BREAK_EVENT:
- irr::os::Printer::log("Closing console device", "CTRL+Break");
- break;
- case CTRL_CLOSE_EVENT:
- irr::os::Printer::log("Closing console device", "User closed console");
- break;
- case CTRL_LOGOFF_EVENT:
- irr::os::Printer::log("Closing console device", "User is logging off");
- break;
- case CTRL_SHUTDOWN_EVENT:
- irr::os::Printer::log("Closing console device", "Computer shutting down");
- break;
- }
- DeviceToClose->closeDevice();
- return TRUE;
- }
- #elif defined(_IRR_POSIX_API_)
- // sigterm handler
- #include <signal.h>
- void sighandler(int sig)
- {
- irr::core::stringc code = "Signal ";
- code += sig;
- code += " received";
- irr::os::Printer::log("Closing console device", code.c_str());
- DeviceToClose->closeDevice();
- }
- #endif
- namespace irr
- {
- const c8 ASCIIArtChars[] = " .,'~:;!+>=icopjtJY56SB8XDQKHNWM"; //MWNHKQDX8BS65YJtjpoci=+>!;:~',. ";
- const u16 ASCIIArtCharsCount = 32;
- //const c8 ASCIIArtChars[] = " \xb0\xb1\xf9\xb2\xdb";
- //const u16 ASCIIArtCharsCount = 5;
- //! constructor
- CIrrDeviceConsole::CIrrDeviceConsole(const SIrrlichtCreationParameters& params)
- : CIrrDeviceStub(params), IsWindowFocused(true), ConsoleFont(0), OutFile(stdout)
- {
- DeviceToClose = this;
- #ifdef _IRR_WINDOWS_NT_CONSOLE_
- MouseButtonStates = 0;
- WindowsSTDIn = GetStdHandle(STD_INPUT_HANDLE);
- WindowsSTDOut = GetStdHandle(STD_OUTPUT_HANDLE);
- PCOORD Dimensions = 0;
- if (CreationParams.Fullscreen)
- {
- // Some mingw versions lack this define, so avoid it in case it does not exist
- #if (_WIN32_WINNT >= 0x0501) && defined(CONSOLE_FULLSCREEN_MODE)
- if (SetConsoleDisplayMode(WindowsSTDOut, CONSOLE_FULLSCREEN_MODE, Dimensions))
- {
- CreationParams.WindowSize.Width = Dimensions->X;
- CreationParams.WindowSize.Width = Dimensions->Y;
- }
- #endif
- }
- else
- {
- COORD ConsoleSize;
- ConsoleSize.X = CreationParams.WindowSize.Width;
- ConsoleSize.X = CreationParams.WindowSize.Height;
- SetConsoleScreenBufferSize(WindowsSTDOut, ConsoleSize);
- }
- // catch windows close/break signals
- SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE);
- #elif defined(_IRR_POSIX_API_)
- // catch other signals
- signal(SIGABRT, &sighandler);
- signal(SIGTERM, &sighandler);
- signal(SIGINT, &sighandler);
- // set output stream
- if (params.WindowId)
- OutFile = (FILE*)(params.WindowId);
- #endif
- #ifdef _IRR_VT100_CONSOLE_
- // reset terminal
- fprintf(OutFile, "%cc", 27);
- // disable line wrapping
- fprintf(OutFile, "%c[7l", 27);
- #endif
- switch (params.DriverType)
- {
- case video::EDT_SOFTWARE:
- #ifdef _IRR_COMPILE_WITH_SOFTWARE_
- VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);
- #else
- os::Printer::log("Software driver was not compiled in.", ELL_ERROR);
- #endif
- break;
- case video::EDT_BURNINGSVIDEO:
- #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
- VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);
- #else
- os::Printer::log("Burning's Video driver was not compiled in.", ELL_ERROR);
- #endif
- break;
- case video::EDT_DIRECT3D8:
- case video::EDT_DIRECT3D9:
- case video::EDT_OPENGL:
- os::Printer::log("The console device cannot use hardware drivers yet.", ELL_ERROR);
- break;
- case video::EDT_NULL:
- VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
- break;
- default:
- break;
- }
- // set up output buffer
- for (u32 y=0; y<CreationParams.WindowSize.Height; ++y)
- {
- core::stringc str;
- str.reserve(CreationParams.WindowSize.Width);
- for (u32 x=0; x<CreationParams.WindowSize.Width; ++x)
- str += " ";
- OutputBuffer.push_back(str);
- }
- #ifdef _IRR_WINDOWS_NT_CONSOLE_
- CursorControl = new CCursorControl(CreationParams.WindowSize);
- #endif
- if (VideoDriver)
- {
- createGUIAndScene();
- #ifdef _IRR_USE_CONSOLE_FONT_
- if (GUIEnvironment)
- {
- ConsoleFont = new gui::CGUIConsoleFont(this);
- gui::IGUISkin *skin = GUIEnvironment->getSkin();
- if (skin)
- {
- for (u32 i=0; i < gui::EGDF_COUNT; ++i)
- skin->setFont(ConsoleFont, gui::EGUI_DEFAULT_FONT(i));
- }
- }
- #endif
- }
- }
- //! destructor
- CIrrDeviceConsole::~CIrrDeviceConsole()
- {
- // GUI and scene are dropped in the stub
- if (CursorControl)
- {
- CursorControl->drop();
- CursorControl = 0;
- }
- if (ConsoleFont)
- {
- ConsoleFont->drop();
- ConsoleFont = 0;
- }
- #ifdef _IRR_VT100_CONSOLE_
- // reset terminal
- fprintf(OutFile, "%cc", 27);
- #endif
- }
- //! runs the device. Returns false if device wants to be deleted
- bool CIrrDeviceConsole::run()
- {
- // increment timer
- os::Timer::tick();
- // process Windows console input
- #ifdef _IRR_WINDOWS_NT_CONSOLE_
- INPUT_RECORD in;
- DWORD oldMode;
- DWORD count, waste;
- // get old input mode
- GetConsoleMode(WindowsSTDIn, &oldMode);
- SetConsoleMode(WindowsSTDIn, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
- GetNumberOfConsoleInputEvents(WindowsSTDIn, &count);
- // read keyboard and mouse input
- while (count)
- {
- ReadConsoleInput(WindowsSTDIn, &in, 1, &waste );
- switch(in.EventType)
- {
- case KEY_EVENT:
- {
- SEvent e;
- e.EventType = EET_KEY_INPUT_EVENT;
- e.KeyInput.PressedDown = (in.Event.KeyEvent.bKeyDown == TRUE);
- e.KeyInput.Control = (in.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0;
- e.KeyInput.Shift = (in.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) != 0;
- e.KeyInput.Key = EKEY_CODE(in.Event.KeyEvent.wVirtualKeyCode);
- e.KeyInput.Char = in.Event.KeyEvent.uChar.UnicodeChar;
- postEventFromUser(e);
- break;
- }
- case MOUSE_EVENT:
- {
- SEvent e;
- e.EventType = EET_MOUSE_INPUT_EVENT;
- e.MouseInput.X = in.Event.MouseEvent.dwMousePosition.X;
- e.MouseInput.Y = in.Event.MouseEvent.dwMousePosition.Y;
- e.MouseInput.Wheel = 0.f;
- e.MouseInput.ButtonStates =
- ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) ? EMBSM_LEFT : 0 ) |
- ( (in.Event.MouseEvent.dwButtonState & RIGHTMOST_BUTTON_PRESSED) ? EMBSM_RIGHT : 0 ) |
- ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) ? EMBSM_MIDDLE : 0 ) |
- ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_3RD_BUTTON_PRESSED) ? EMBSM_EXTRA1 : 0 ) |
- ( (in.Event.MouseEvent.dwButtonState & FROM_LEFT_4TH_BUTTON_PRESSED) ? EMBSM_EXTRA2 : 0 );
- if (in.Event.MouseEvent.dwEventFlags & MOUSE_MOVED)
- {
- CursorControl->setPosition(core::position2di(e.MouseInput.X, e.MouseInput.Y));
- // create mouse moved event
- e.MouseInput.Event = EMIE_MOUSE_MOVED;
- postEventFromUser(e);
- }
- if (in.Event.MouseEvent.dwEventFlags & MOUSE_WHEELED)
- {
- e.MouseInput.Event = EMIE_MOUSE_WHEEL;
- e.MouseInput.Wheel = (in.Event.MouseEvent.dwButtonState & 0xFF000000) ? -1.0f : 1.0f;
- postEventFromUser(e);
- }
- if ( (MouseButtonStates & EMBSM_LEFT) != (e.MouseInput.ButtonStates & EMBSM_LEFT) )
- {
- e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_LEFT) ? EMIE_LMOUSE_PRESSED_DOWN : EMIE_LMOUSE_LEFT_UP;
- postEventFromUser(e);
- }
- if ( (MouseButtonStates & EMBSM_RIGHT) != (e.MouseInput.ButtonStates & EMBSM_RIGHT) )
- {
- e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_RIGHT) ? EMIE_RMOUSE_PRESSED_DOWN : EMIE_RMOUSE_LEFT_UP;
- postEventFromUser(e);
- }
- if ( (MouseButtonStates & EMBSM_MIDDLE) != (e.MouseInput.ButtonStates & EMBSM_MIDDLE) )
- {
- e.MouseInput.Event = (e.MouseInput.ButtonStates & EMBSM_MIDDLE) ? EMIE_MMOUSE_PRESSED_DOWN : EMIE_MMOUSE_LEFT_UP;
- postEventFromUser(e);
- }
- // save current button states
- MouseButtonStates = e.MouseInput.ButtonStates;
- break;
- }
- case WINDOW_BUFFER_SIZE_EVENT:
- VideoDriver->OnResize(
- core::dimension2d<u32>(in.Event.WindowBufferSizeEvent.dwSize.X,
- in.Event.WindowBufferSizeEvent.dwSize.Y));
- break;
- case FOCUS_EVENT:
- IsWindowFocused = (in.Event.FocusEvent.bSetFocus == TRUE);
- break;
- default:
- break;
- }
- GetNumberOfConsoleInputEvents(WindowsSTDIn, &count);
- }
- // set input mode
- SetConsoleMode(WindowsSTDIn, oldMode);
- #else
- // todo: keyboard input from terminal in raw mode
- #endif
- return !Close;
- }
- //! Cause the device to temporarily pause execution and let other processes to run
- // This should bring down processor usage without major performance loss for Irrlicht
- void CIrrDeviceConsole::yield()
- {
- #ifdef _IRR_WINDOWS_API_
- Sleep(1);
- #else
- struct timespec ts = {0,0};
- nanosleep(&ts, NULL);
- #endif
- }
- //! Pause execution and let other processes to run for a specified amount of time.
- void CIrrDeviceConsole::sleep(u32 timeMs, bool pauseTimer)
- {
- const bool wasStopped = Timer ? Timer->isStopped() : true;
- #ifdef _IRR_WINDOWS_API_
- Sleep(timeMs);
- #else
- struct timespec ts;
- ts.tv_sec = (time_t) (timeMs / 1000);
- ts.tv_nsec = (long) (timeMs % 1000) * 1000000;
- if (pauseTimer && !wasStopped)
- Timer->stop();
- nanosleep(&ts, NULL);
- #endif
- if (pauseTimer && !wasStopped)
- Timer->start();
- }
- //! sets the caption of the window
- void CIrrDeviceConsole::setWindowCaption(const wchar_t* text)
- {
- #ifdef _IRR_WINDOWS_NT_CONSOLE_
- SetConsoleTitleW(text);
- #endif
- }
- //! returns if window is active. if not, nothing need to be drawn
- bool CIrrDeviceConsole::isWindowActive() const
- {
- // there is no window, but we always assume it is active
- return true;
- }
- //! returns if window has focus
- bool CIrrDeviceConsole::isWindowFocused() const
- {
- return IsWindowFocused;
- }
- //! returns if window is minimized
- bool CIrrDeviceConsole::isWindowMinimized() const
- {
- return false;
- }
- //! presents a surface in the client area
- bool CIrrDeviceConsole::present(video::IImage* surface, void* windowId, core::rect<s32>* src)
- {
- if (surface)
- {
- for (u32 y=0; y < surface->getDimension().Height; ++y)
- {
- for (u32 x=0; x< surface->getDimension().Width; ++x)
- {
- // get average pixel
- u32 avg = surface->getPixel(x,y).getAverage() * (ASCIIArtCharsCount-1);
- avg /= 255;
- OutputBuffer[y] [x] = ASCIIArtChars[avg];
- }
- }
- }
- #ifdef _IRR_USE_CONSOLE_FONT_
- for (u32 i=0; i< Text.size(); ++i)
- {
- s32 y = Text[i].Pos.Y;
- if ( y < (s32)OutputBuffer.size() && y > 0)
- for (u32 c=0; c < Text[i].Text.size() && c + Text[i].Pos.X < OutputBuffer[y].size(); ++c)
- //if (Text[i].Text[c] != ' ')
- OutputBuffer[y] [c+Text[i].Pos.X] = Text[i].Text[c];
- }
- Text.clear();
- #endif
- // draw output
- for (u32 y=0; y<OutputBuffer.size(); ++y)
- {
- setTextCursorPos(0,y);
- fprintf(OutFile, "%s", OutputBuffer[y].c_str());
- }
- return surface != 0;
- }
- //! notifies the device that it should close itself
- void CIrrDeviceConsole::closeDevice()
- {
- // return false next time we run()
- Close = true;
- }
- //! Sets if the window should be resizable in windowed mode.
- void CIrrDeviceConsole::setResizable(bool resize)
- {
- // do nothing
- }
- //! Minimize the window.
- void CIrrDeviceConsole::minimizeWindow()
- {
- // do nothing
- }
- //! Maximize window
- void CIrrDeviceConsole::maximizeWindow()
- {
- // do nothing
- }
- //! Restore original window size
- void CIrrDeviceConsole::restoreWindow()
- {
- // do nothing
- }
- void CIrrDeviceConsole::setTextCursorPos(s16 x, s16 y)
- {
- #ifdef _IRR_WINDOWS_NT_CONSOLE_
- // move WinNT cursor
- COORD Position;
- Position.X = x;
- Position.Y = y;
- SetConsoleCursorPosition(WindowsSTDOut, Position);
- #elif defined(_IRR_VT100_CONSOLE_)
- // send escape code
- fprintf(OutFile, "%c[%d;%dH", 27, y, x);
- #else
- // not implemented
- #endif
- }
- void CIrrDeviceConsole::addPostPresentText(s16 X, s16 Y, const wchar_t *text)
- {
- SPostPresentText p;
- p.Text = text;
- p.Pos.X = X;
- p.Pos.Y = Y;
- Text.push_back(p);
- }
- } // end namespace irr
- #endif // _IRR_COMPILE_WITH_CONSOLE_DEVICE_
|