CIrrDeviceFB.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. // Copyright (C) 2002-2007 Nikolaus Gebhardt
  2. // Copyright (C) 2007-2012 Christian Stehno
  3. // This file is part of the "Irrlicht Engine".
  4. // For conditions of distribution and use, see copyright notice in irrlicht.h
  5. #include "CIrrDeviceFB.h"
  6. #ifdef _IRR_COMPILE_WITH_FB_DEVICE_
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <sys/ioctl.h>
  13. #include <fcntl.h>
  14. #include <sys/mman.h>
  15. #include <sys/utsname.h>
  16. #include <time.h>
  17. #include <errno.h>
  18. #include "IEventReceiver.h"
  19. #include "os.h"
  20. #include "CTimer.h"
  21. #include "irrString.h"
  22. #include "Keycodes.h"
  23. #include "COSOperator.h"
  24. #include "CColorConverter.h"
  25. #include "SIrrCreationParameters.h"
  26. #include <linux/input.h>
  27. namespace irr
  28. {
  29. //! constructor
  30. CIrrDeviceFB::CIrrDeviceFB(const SIrrlichtCreationParameters& params)
  31. : CIrrDeviceStub(params), Framebuffer(-1), EventDevice(-1), SoftwareImage(0),
  32. Pitch(0), FBColorFormat(video::ECF_A8R8G8B8), Close(false)
  33. {
  34. #ifdef _DEBUG
  35. setDebugName("CIrrDeviceFB");
  36. #endif
  37. // print version, distribution etc.
  38. // thx to LynxLuna for pointing me to the uname function
  39. core::stringc linuxversion;
  40. struct utsname FBInfo;
  41. uname(&FBInfo);
  42. linuxversion += FBInfo.sysname;
  43. linuxversion += " ";
  44. linuxversion += FBInfo.release;
  45. linuxversion += " ";
  46. linuxversion += FBInfo.version;
  47. linuxversion += " ";
  48. linuxversion += FBInfo.machine;
  49. Operator = new COSOperator(linuxversion);
  50. os::Printer::log(linuxversion.c_str(), ELL_INFORMATION);
  51. // create window
  52. if (params.DriverType != video::EDT_NULL)
  53. {
  54. // create the window, only if we do not use the null device
  55. if (!createWindow(params.WindowSize, params.Bits))
  56. return;
  57. }
  58. // create cursor control
  59. CursorControl = new CCursorControl(this, params.DriverType == video::EDT_NULL);
  60. // create driver
  61. createDriver();
  62. if (!VideoDriver)
  63. return;
  64. createGUIAndScene();
  65. }
  66. //! destructor
  67. CIrrDeviceFB::~CIrrDeviceFB()
  68. {
  69. if (SoftwareImage)
  70. munmap(SoftwareImage, CreationParams.WindowSize.Height*Pitch);
  71. // go back to previous format
  72. if (ioctl(Framebuffer, FBIOPUT_VSCREENINFO, &oldscreeninfo) <0)
  73. perror("Restoring old fb mode");
  74. if (KeyboardDevice != -1)
  75. if (ioctl(KeyboardDevice, KDSETMODE, &KeyboardMode) <0)
  76. perror("Restoring keyboard mode");
  77. if (EventDevice != -1)
  78. close(EventDevice);
  79. if (KeyboardDevice != -1)
  80. close(KeyboardDevice);
  81. if (Framebuffer != -1)
  82. close(Framebuffer);
  83. }
  84. bool CIrrDeviceFB::createWindow(const core::dimension2d<u32>& windowSize, u32 bits)
  85. {
  86. char buf[256];
  87. CreationParams.WindowSize.Width = windowSize.Width;
  88. CreationParams.WindowSize.Height = windowSize.Height;
  89. KeyboardDevice = open("/dev/tty", O_RDWR);
  90. if (KeyboardDevice == -1)
  91. perror("Open keyboard");
  92. if (ioctl(KeyboardDevice, KDGETMODE, &KeyboardMode) <0)
  93. perror("Read keyboard mode");
  94. if (ioctl(KeyboardDevice, KDSETMODE, KD_GRAPHICS) <0)
  95. perror("Set keyboard mode");
  96. Framebuffer=open("/dev/fb/0", O_RDWR);
  97. if (Framebuffer == -1)
  98. {
  99. Framebuffer=open("/dev/fb0", O_RDWR);
  100. if (Framebuffer == -1)
  101. {
  102. perror("Open framebuffer");
  103. return false;
  104. }
  105. }
  106. EventDevice = open("/dev/input/event0", O_RDONLY | O_NONBLOCK);
  107. if (EventDevice == -1)
  108. perror("Open event device");
  109. // make format settings
  110. ioctl(Framebuffer, FBIOGET_FSCREENINFO, &fbfixscreeninfo);
  111. ioctl(Framebuffer, FBIOGET_VSCREENINFO, &oldscreeninfo);
  112. snprintf(buf, 256, "Original resolution: %d x %d\nARGB%d%d%d%d\n",oldscreeninfo.xres,oldscreeninfo.yres,
  113. oldscreeninfo.transp.length,oldscreeninfo.red.length,oldscreeninfo.green.length,oldscreeninfo.blue.length);
  114. os::Printer::log(buf);
  115. memcpy(&fbscreeninfo, &oldscreeninfo, sizeof(struct fb_var_screeninfo));
  116. if (CreationParams.DriverType != video::EDT_NULL)
  117. {
  118. fbscreeninfo.xres = fbscreeninfo.xres_virtual = CreationParams.WindowSize.Width;
  119. fbscreeninfo.yres = fbscreeninfo.yres_virtual = CreationParams.WindowSize.Height;
  120. fbscreeninfo.bits_per_pixel = 16;
  121. fbscreeninfo.red.offset = 10;
  122. fbscreeninfo.red.length = 5;
  123. fbscreeninfo.green.offset = 5;
  124. fbscreeninfo.green.length = 5;
  125. fbscreeninfo.blue.offset = 0;
  126. fbscreeninfo.blue.length = 5;
  127. fbscreeninfo.transp.offset = 15;
  128. fbscreeninfo.transp.length = 1;
  129. ioctl(Framebuffer, FBIOPUT_VSCREENINFO, &fbscreeninfo);
  130. ioctl(Framebuffer, FBIOGET_VSCREENINFO, &fbscreeninfo);
  131. snprintf(buf, 256, "New resolution: %d x %d (%d x %d)\nARGB%d%d%d%d\n",fbscreeninfo.xres,fbscreeninfo.yres,fbscreeninfo.xres_virtual,fbscreeninfo.yres_virtual,
  132. fbscreeninfo.transp.length,fbscreeninfo.red.length,fbscreeninfo.green.length,fbscreeninfo.blue.length);
  133. os::Printer::log(buf);
  134. CreationParams.WindowSize.Width = fbscreeninfo.xres;
  135. CreationParams.WindowSize.Height = fbscreeninfo.yres;
  136. CreationParams.Bits = fbscreeninfo.bits_per_pixel;
  137. Pitch = fbfixscreeninfo.line_length;
  138. if (fbscreeninfo.bits_per_pixel == 16)
  139. {
  140. if (fbscreeninfo.transp.length == 0)
  141. FBColorFormat = video::ECF_R5G6B5;
  142. else
  143. FBColorFormat = video::ECF_A1R5G5B5;
  144. }
  145. else
  146. {
  147. if (fbscreeninfo.transp.length == 0)
  148. FBColorFormat = video::ECF_R8G8B8;
  149. else
  150. FBColorFormat = video::ECF_A8R8G8B8;
  151. }
  152. if (MAP_FAILED==(SoftwareImage=(u8*)mmap(0, CreationParams.WindowSize.Height*Pitch, PROT_READ|PROT_WRITE, MAP_SHARED, Framebuffer, 0)))
  153. {
  154. perror("mmap render target");
  155. return false;
  156. }
  157. }
  158. return true;
  159. }
  160. //! create the driver
  161. void CIrrDeviceFB::createDriver()
  162. {
  163. switch(CreationParams.DriverType)
  164. {
  165. case video::EDT_SOFTWARE:
  166. #ifdef _IRR_COMPILE_WITH_SOFTWARE_
  167. VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);
  168. #else
  169. os::Printer::log("No Software driver support compiled in.", ELL_WARNING);
  170. #endif
  171. break;
  172. case video::EDT_BURNINGSVIDEO:
  173. #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
  174. VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);
  175. #else
  176. os::Printer::log("Burning's video driver was not compiled in.", ELL_WARNING);
  177. #endif
  178. break;
  179. case video::EDT_OPENGL:
  180. case video::EDT_DIRECT3D8:
  181. case video::EDT_DIRECT3D9:
  182. os::Printer::log("This driver is not available in FB. Try Software renderer.",
  183. ELL_WARNING);
  184. break;
  185. default:
  186. VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
  187. break;
  188. }
  189. }
  190. //! runs the device. Returns false if device wants to be deleted
  191. bool CIrrDeviceFB::run()
  192. {
  193. os::Timer::tick();
  194. struct input_event ev;
  195. if (EventDevice>=0)
  196. {
  197. if ((read(EventDevice, &ev, sizeof(input_event)) < 0) &&
  198. errno != EAGAIN)
  199. perror("Read input event");
  200. if (ev.type == EV_KEY)
  201. {
  202. irr::SEvent irrevent;
  203. irrevent.EventType = irr::EET_KEY_INPUT_EVENT;
  204. irrevent.KeyInput.PressedDown = true;
  205. switch (ev.code)
  206. {
  207. case KEY_RIGHTCTRL:
  208. case KEY_LEFTCTRL:
  209. irrevent.KeyInput.Control = true;
  210. break;
  211. case KEY_RIGHTSHIFT:
  212. case KEY_LEFTSHIFT:
  213. irrevent.KeyInput.Shift = true;
  214. break;
  215. case KEY_ESC:
  216. irrevent.KeyInput.Key = (EKEY_CODE)0x1B;
  217. break;
  218. case KEY_SPACE:
  219. irrevent.KeyInput.Key = (EKEY_CODE)0x20;
  220. break;
  221. case KEY_UP:
  222. irrevent.KeyInput.Key = (EKEY_CODE)0x26;
  223. break;
  224. case KEY_LEFT:
  225. irrevent.KeyInput.Key = (EKEY_CODE)0x25;
  226. break;
  227. case KEY_RIGHT:
  228. irrevent.KeyInput.Key = (EKEY_CODE)0x27;
  229. break;
  230. case KEY_DOWN:
  231. irrevent.KeyInput.Key = (EKEY_CODE)0x28;
  232. break;
  233. default:
  234. irrevent.KeyInput.Key = (EKEY_CODE)0;
  235. break;
  236. }
  237. postEventFromUser(irrevent);
  238. }
  239. }
  240. return !Close;
  241. }
  242. //! Pause the current process for the minimum time allowed only to allow other processes to execute
  243. void CIrrDeviceFB::yield()
  244. {
  245. struct timespec ts = {0,0};
  246. nanosleep(&ts, NULL);
  247. }
  248. //! Pause execution and let other processes to run for a specified amount of time.
  249. void CIrrDeviceFB::sleep(u32 timeMs, bool pauseTimer=false)
  250. {
  251. bool wasStopped = Timer ? Timer->isStopped() : true;
  252. struct timespec ts;
  253. ts.tv_sec = (time_t) (timeMs / 1000);
  254. ts.tv_nsec = (long) (timeMs % 1000) * 1000000;
  255. if (pauseTimer && !wasStopped)
  256. Timer->stop();
  257. nanosleep(&ts, NULL);
  258. if (pauseTimer && !wasStopped)
  259. Timer->start();
  260. }
  261. //! presents a surface in the client area
  262. bool CIrrDeviceFB::present(video::IImage* image, void* windowId, core::rect<s32>* src )
  263. {
  264. // this is only necessary for software drivers.
  265. if (CreationParams.DriverType != video::EDT_SOFTWARE && CreationParams.DriverType != video::EDT_BURNINGSVIDEO)
  266. return false;
  267. if (!SoftwareImage)
  268. return false;
  269. u8* destData = SoftwareImage;
  270. u32 srcwidth = (u32)image->getDimension().Width;
  271. u32 srcheight = (u32)image->getDimension().Height;
  272. // clip images
  273. srcheight = core::min_(srcheight, CreationParams.WindowSize.Height);
  274. srcwidth = core::min_(srcwidth, CreationParams.WindowSize.Width);
  275. u8* srcdata = (u8*)image->lock();
  276. for (u32 y=0; y<srcheight; ++y)
  277. {
  278. video::CColorConverter::convert_viaFormat(srcdata, image->getColorFormat(), srcwidth, destData, FBColorFormat);
  279. srcdata+=image->getPitch();
  280. destData+=Pitch;
  281. }
  282. image->unlock();
  283. msync(SoftwareImage,CreationParams.WindowSize.Width*CreationParams.WindowSize.Height,MS_ASYNC);
  284. return true;
  285. }
  286. //! notifies the device that it should close itself
  287. void CIrrDeviceFB::closeDevice()
  288. {
  289. Close = true;
  290. }
  291. //! returns if window is active. if not, nothing need to be drawn
  292. bool CIrrDeviceFB::isWindowActive() const
  293. {
  294. return true;
  295. }
  296. //! returns if window has focus
  297. bool CIrrDeviceFB::isWindowFocused() const
  298. {
  299. return true;
  300. }
  301. //! returns if window is minimized
  302. bool CIrrDeviceFB::isWindowMinimized() const
  303. {
  304. return false;
  305. }
  306. //! sets the caption of the window
  307. void CIrrDeviceFB::setWindowCaption(const wchar_t* text)
  308. {
  309. }
  310. //! Sets if the window should be resizeable in windowed mode.
  311. void CIrrDeviceFB::setResizable(bool resize)
  312. {
  313. }
  314. //! Minimizes window
  315. void CIrrDeviceFB::minimizeWindow()
  316. {
  317. }
  318. //! Maximizes window
  319. void CIrrDeviceFB::maximizeWindow()
  320. {
  321. }
  322. //! Restores original window size
  323. void CIrrDeviceFB::restoreWindow()
  324. {
  325. }
  326. //! Returns the type of this device
  327. E_DEVICE_TYPE CIrrDeviceFB::getType() const
  328. {
  329. return EIDT_FRAMEBUFFER;
  330. }
  331. } // end namespace irr
  332. #endif // _IRR_USE_FB_DEVICE_