SdlBFApp.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. #include "SdlBFApp.h"
  2. #include "GLRenderDevice.h"
  3. #include "platform/PlatformHelper.h"
  4. #include <SDL2/SDL.h>
  5. USING_NS_BF;
  6. ///
  7. #pragma comment(lib, "imm32.lib")
  8. #pragma comment(lib, "version.lib")
  9. SDL_Window* (SDLCALL* bf_SDL_CreateWindow)(const char* title, int x, int y, int w, int h, Uint32 flags);
  10. int (SDLCALL* bf_SDL_GL_SetAttribute)(SDL_GLattr attr, int value);
  11. Uint32 (SDLCALL* bf_SDL_GetWindowID)(SDL_Window* window);
  12. void (SDLCALL* bf_SDL_DestroyWindow)(SDL_Window* window);
  13. int (SDLCALL* bf_SDL_Init)(Uint32 flags);
  14. void (SDLCALL* bf_SDL_GetWindowPosition)(SDL_Window* window,int* x, int* y);
  15. char* (SDLCALL* bf_SDL_GetClipboardText)(void);
  16. int (SDLCALL* bf_SDL_SetClipboardText)(const char* text);
  17. void* (SDLCALL* bf_SDL_GL_GetProcAddress)(const char* proc);
  18. void (SDLCALL* bf_SDL_GetWindowSize)(SDL_Window* window, int* w, int* h);
  19. void (SDLCALL* bf_SDL_GL_SwapWindow)(SDL_Window* window);
  20. void (SDLCALL* bf_SDL_free)(void* mem);
  21. void (SDLCALL* bf_SDL_SetWindowPosition)(SDL_Window* window, int x, int y);
  22. int (SDLCALL* bf_SDL_PollEvent)(SDL_Event* event);
  23. const char* (SDLCALL* bf_SDL_GetError)(void);
  24. SDL_GLContext (SDLCALL* bf_SDL_GL_CreateContext)(SDL_Window* window);
  25. void (SDLCALL* bf_SDL_Quit)(void);
  26. static HMODULE gSDLModule;
  27. static HMODULE GetSDLModule(const StringImpl& installDir)
  28. {
  29. if (gSDLModule == NULL)
  30. {
  31. String loadPath = installDir + "SDL2.dll";
  32. gSDLModule = ::LoadLibraryA(loadPath.c_str());
  33. if (gSDLModule == NULL)
  34. {
  35. #ifdef BF_PLATFORM_WINDOWS
  36. ::MessageBoxA(NULL, "Failed to load SDL2.dll", "FATAL ERROR", MB_OK | MB_ICONERROR);
  37. ::ExitProcess(1);
  38. #endif
  39. BF_FATAL("Failed to load SDL2.dll");
  40. }
  41. }
  42. return gSDLModule;
  43. }
  44. template <typename T>
  45. static void BFGetSDLProc(T& proc, const char* name, const StringImpl& installDir)
  46. {
  47. proc = (T)::GetProcAddress(GetSDLModule(installDir), name);
  48. }
  49. #define BF_GET_SDLPROC(name) BFGetSDLProc(bf_##name, #name, mInstallDir)
  50. SdlBFWindow::SdlBFWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags)
  51. {
  52. int sdlWindowFlags = 0;
  53. if (windowFlags & BFWINDOW_RESIZABLE)
  54. sdlWindowFlags |= SDL_WINDOW_RESIZABLE;
  55. sdlWindowFlags |= SDL_WINDOW_OPENGL;
  56. if (windowFlags & BFWINDOW_FULLSCREEN)
  57. sdlWindowFlags |= SDL_WINDOW_FULLSCREEN;
  58. #ifdef BF_PLATFORM_FULLSCREEN
  59. sdlWindowFlags |= SDL_WINDOW_FULLSCREEN;
  60. #endif
  61. mSDLWindow = bf_SDL_CreateWindow(title.c_str(), x, y, width, height, sdlWindowFlags);
  62. #ifndef BF_PLATFORM_OPENGL_ES2
  63. bf_SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
  64. bf_SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
  65. bf_SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
  66. #endif
  67. if (!bf_SDL_GL_CreateContext(mSDLWindow))
  68. {
  69. String str = StrFormat(
  70. #ifdef BF_PLATFORM_OPENGL_ES2
  71. "Unable to create SDL OpenGLES context: %s"
  72. #else
  73. "Unable to create SDL OpenGL context: %s"
  74. #endif
  75. , bf_SDL_GetError());
  76. BF_FATAL(str.c_str());
  77. bf_SDL_Quit();
  78. exit(2);
  79. }
  80. #ifndef BF_PLATFORM_OPENGL_ES2
  81. glEnable(GL_DEBUG_OUTPUT);
  82. glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
  83. #endif
  84. glEnable(GL_BLEND);
  85. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  86. #ifndef BF_PLATFORM_OPENGL_ES2
  87. //glEnableClientState(GL_INDEX_ARRAY);
  88. #endif
  89. mIsMouseInside = false;
  90. mRenderWindow = new GLRenderWindow((GLRenderDevice*)gBFApp->mRenderDevice, mSDLWindow);
  91. mRenderWindow->mWindow = this;
  92. gBFApp->mRenderDevice->AddRenderWindow(mRenderWindow);
  93. if (parent != NULL)
  94. parent->mChildren.push_back(this);
  95. }
  96. SdlBFWindow::~SdlBFWindow()
  97. {
  98. if (mSDLWindow != NULL)
  99. TryClose();
  100. }
  101. bool SdlBFWindow::TryClose()
  102. {
  103. SdlBFApp* app = (SdlBFApp*)gBFApp;
  104. app->mSdlWindowMap.Remove(bf_SDL_GetWindowID(mSDLWindow));
  105. bf_SDL_DestroyWindow(mSDLWindow);
  106. mSDLWindow = NULL;
  107. return true;
  108. }
  109. static int SDLConvertScanCode(int scanCode)
  110. {
  111. if ((scanCode >= SDL_SCANCODE_A) && (scanCode <= SDL_SCANCODE_Z))
  112. return (scanCode - SDL_SCANCODE_A) + 'A';
  113. if ((scanCode >= SDL_SCANCODE_1) && (scanCode <= SDL_SCANCODE_9))
  114. return (scanCode - SDL_SCANCODE_1) + '1';
  115. switch (scanCode)
  116. {
  117. case SDL_SCANCODE_9: return '0';
  118. case SDL_SCANCODE_CANCEL: return 0x03;
  119. case SDL_SCANCODE_AC_BACK: return 0x08;
  120. case SDL_SCANCODE_TAB: return 0x09;
  121. case SDL_SCANCODE_CLEAR: return 0x0C;
  122. case SDL_SCANCODE_RETURN: return 0x0D;
  123. case SDL_SCANCODE_LSHIFT: return 0x10;
  124. case SDL_SCANCODE_RSHIFT: return 0x10;
  125. case SDL_SCANCODE_LCTRL: return 0x11;
  126. case SDL_SCANCODE_RCTRL: return 0x11;
  127. case SDL_SCANCODE_MENU: return 0x12;
  128. case SDL_SCANCODE_PAUSE: return 0x13;
  129. case SDL_SCANCODE_LANG1: return 0x15;
  130. case SDL_SCANCODE_LANG2: return 0x15;
  131. case SDL_SCANCODE_LANG3: return 0x17;
  132. case SDL_SCANCODE_LANG4: return 0x18;
  133. case SDL_SCANCODE_LANG5: return 0x19;
  134. case SDL_SCANCODE_LANG6: return 0x19;
  135. case SDL_SCANCODE_ESCAPE: return 0x1B;
  136. case SDL_SCANCODE_SPACE: return 0x20;
  137. case SDL_SCANCODE_PAGEUP: return 0x21;
  138. case SDL_SCANCODE_PAGEDOWN: return 0x22;
  139. case SDL_SCANCODE_END: return 0x23;
  140. case SDL_SCANCODE_HOME: return 0x24;
  141. case SDL_SCANCODE_LEFT: return 0x25;
  142. case SDL_SCANCODE_UP: return 0x26;
  143. case SDL_SCANCODE_RIGHT: return 0x27;
  144. case SDL_SCANCODE_DOWN: return 0x28;
  145. case SDL_SCANCODE_SELECT: return 0x29;
  146. case SDL_SCANCODE_PRINTSCREEN: return 0x2A;
  147. case SDL_SCANCODE_EXECUTE: return 0x2B;
  148. case SDL_SCANCODE_INSERT: return 0x2D;
  149. case SDL_SCANCODE_DELETE: return 0x2E;
  150. case SDL_SCANCODE_HELP: return 0x2F;
  151. case SDL_SCANCODE_LGUI: return 0x5B;
  152. case SDL_SCANCODE_RGUI: return 0x5C;
  153. case SDL_SCANCODE_KP_0: return 0x60;
  154. case SDL_SCANCODE_KP_1: return 0x61;
  155. case SDL_SCANCODE_KP_2: return 0x62;
  156. case SDL_SCANCODE_KP_3: return 0x63;
  157. case SDL_SCANCODE_KP_4: return 0x64;
  158. case SDL_SCANCODE_KP_5: return 0x65;
  159. case SDL_SCANCODE_KP_6: return 0x66;
  160. case SDL_SCANCODE_KP_7: return 0x67;
  161. case SDL_SCANCODE_KP_8: return 0x68;
  162. case SDL_SCANCODE_KP_9: return 0x69;
  163. case SDL_SCANCODE_KP_MULTIPLY: return 0x6A;
  164. case SDL_SCANCODE_KP_PLUS: return 0x6B;
  165. case SDL_SCANCODE_SEPARATOR: return 0x6C;
  166. case SDL_SCANCODE_KP_MINUS: return 0x6D;
  167. case SDL_SCANCODE_KP_PERIOD: return 0x6E;
  168. case SDL_SCANCODE_KP_DIVIDE: return 0x6F;
  169. case SDL_SCANCODE_F1: return 0x70;
  170. case SDL_SCANCODE_F2: return 0x71;
  171. case SDL_SCANCODE_F3: return 0x72;
  172. case SDL_SCANCODE_F4: return 0x73;
  173. case SDL_SCANCODE_F5: return 0x74;
  174. case SDL_SCANCODE_F6: return 0x75;
  175. case SDL_SCANCODE_F7: return 0x76;
  176. case SDL_SCANCODE_F8: return 0x77;
  177. case SDL_SCANCODE_F9: return 0x78;
  178. case SDL_SCANCODE_F10: return 0x79;
  179. case SDL_SCANCODE_F11: return 0x7A;
  180. case SDL_SCANCODE_F12: return 0x7B;
  181. case SDL_SCANCODE_NUMLOCKCLEAR: return 0x90;
  182. case SDL_SCANCODE_SCROLLLOCK: return 0x91;
  183. case SDL_SCANCODE_GRAVE: return 0xC0;
  184. //case SDL_SCANCODE_COMMAND: return 0xF0;
  185. }
  186. return 0;
  187. }
  188. #ifdef _WIN32
  189. extern HINSTANCE gDLLInstance;
  190. #endif
  191. SdlBFApp::SdlBFApp()
  192. {
  193. mRunning = false;
  194. mRenderDevice = NULL;
  195. Beefy::String exePath;
  196. BfpGetStrHelper(exePath, [](char* outStr, int* inOutStrSize, BfpResult* result)
  197. {
  198. BfpSystem_GetExecutablePath(outStr, inOutStrSize, (BfpSystemResult*)result);
  199. });
  200. mInstallDir = GetFileDir(exePath) + "/";
  201. int lastSlash = std::max((int)mInstallDir.LastIndexOf('\\'), (int)mInstallDir.LastIndexOf('/'));
  202. if (lastSlash != -1)
  203. mInstallDir = mInstallDir.Substring(0, lastSlash);
  204. //TODO: We're not properly using DataDir vs InstallDir
  205. #if (!defined BFSYSLIB_DYNAMIC) && (defined BF_RESOURCES_REL_DIR)
  206. mInstallDir += "/" + Beefy::UTF8Decode(BF_RESOURCES_REL_DIR);
  207. #endif
  208. mInstallDir += "/";
  209. if (bf_SDL_CreateWindow == NULL)
  210. {
  211. BF_GET_SDLPROC(SDL_CreateWindow);
  212. BF_GET_SDLPROC(SDL_GL_SetAttribute);
  213. BF_GET_SDLPROC(SDL_GetWindowID);
  214. BF_GET_SDLPROC(SDL_DestroyWindow);
  215. BF_GET_SDLPROC(SDL_Init);
  216. BF_GET_SDLPROC(SDL_GetWindowPosition);
  217. BF_GET_SDLPROC(SDL_GetClipboardText);
  218. BF_GET_SDLPROC(SDL_SetClipboardText);
  219. BF_GET_SDLPROC(SDL_GL_GetProcAddress);
  220. BF_GET_SDLPROC(SDL_GetWindowSize);
  221. BF_GET_SDLPROC(SDL_GL_SwapWindow);
  222. BF_GET_SDLPROC(SDL_free);
  223. BF_GET_SDLPROC(SDL_SetWindowPosition);
  224. BF_GET_SDLPROC(SDL_PollEvent);
  225. BF_GET_SDLPROC(SDL_GetError);
  226. BF_GET_SDLPROC(SDL_GL_CreateContext);
  227. BF_GET_SDLPROC(SDL_Quit);
  228. }
  229. mDataDir = mInstallDir;
  230. if (bf_SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0)
  231. BF_FATAL(StrFormat("Unable to initialize SDL: %s", bf_SDL_GetError()).c_str());
  232. }
  233. SdlBFApp::~SdlBFApp()
  234. {
  235. }
  236. SdlBFWindow* SdlBFApp::GetSdlWindowFromId(uint32 id)
  237. {
  238. SdlBFWindow* window = NULL;
  239. mSdlWindowMap.TryGetValue(id, &window);
  240. return window;
  241. }
  242. void SdlBFApp::Init()
  243. {
  244. mRunning = true;
  245. mInMsgProc = false;
  246. mRenderDevice = new GLRenderDevice();
  247. mRenderDevice->Init(this);
  248. }
  249. void SdlBFApp::Run()
  250. {
  251. while (mRunning)
  252. {
  253. SDL_Event sdlEvent;
  254. while (true)
  255. {
  256. {
  257. //Beefy::DebugTimeGuard suspendTimeGuard(30, "BFApp::Run1");
  258. if (!bf_SDL_PollEvent(&sdlEvent))
  259. break;
  260. }
  261. //Beefy::DebugTimeGuard suspendTimeGuard(30, "BFApp::Run2");
  262. switch (sdlEvent.type)
  263. {
  264. case SDL_QUIT:
  265. //gBFApp->RemoveWindow(sdlEvent.window);
  266. Shutdown();
  267. break;
  268. case SDL_MOUSEBUTTONUP:
  269. {
  270. SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.button.windowID);
  271. if (sdlBFWindow != NULL)
  272. sdlBFWindow->mMouseUpFunc(sdlBFWindow, sdlEvent.button.x, sdlEvent.button.y, sdlEvent.button.button);
  273. }
  274. break;
  275. case SDL_MOUSEBUTTONDOWN:
  276. {
  277. SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.button.windowID);
  278. if (sdlBFWindow != NULL)
  279. sdlBFWindow->mMouseDownFunc(sdlBFWindow, sdlEvent.button.x, sdlEvent.button.y, sdlEvent.button.button, 1);
  280. }
  281. break;
  282. case SDL_MOUSEMOTION:
  283. {
  284. SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.button.windowID);
  285. if (sdlBFWindow != NULL)
  286. sdlBFWindow->mMouseMoveFunc(sdlBFWindow, sdlEvent.button.x, sdlEvent.button.y);
  287. }
  288. break;
  289. case SDL_KEYDOWN:
  290. {
  291. SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.key.windowID);
  292. if (sdlBFWindow != NULL)
  293. {
  294. sdlBFWindow->mKeyDownFunc(sdlBFWindow, SDLConvertScanCode(sdlEvent.key.keysym.scancode), sdlEvent.key.repeat);
  295. }
  296. }
  297. break;
  298. case SDL_TEXTINPUT:
  299. {
  300. SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.key.windowID);
  301. if (sdlBFWindow != NULL)
  302. {
  303. sdlBFWindow->mKeyCharFunc(sdlBFWindow, *(wchar_t*)sdlEvent.text.text);
  304. }
  305. }
  306. break;
  307. case SDL_KEYUP:
  308. {
  309. SdlBFWindow* sdlBFWindow = GetSdlWindowFromId(sdlEvent.key.windowID);
  310. if (sdlBFWindow != NULL)
  311. sdlBFWindow->mKeyUpFunc(sdlBFWindow, SDLConvertScanCode(sdlEvent.key.keysym.scancode));
  312. }
  313. break;
  314. }
  315. }
  316. Process();
  317. }
  318. }
  319. extern int gPixelsDrawn;
  320. int gFrameCount = 0;
  321. int gBFDrawBatchCount = 0;
  322. void SdlBFApp::Draw()
  323. {
  324. //Beefy::DebugTimeGuard suspendTimeGuard(30, "SdlBFApp::Draw");
  325. glDisable(GL_SCISSOR_TEST);
  326. glDisable(GL_CULL_FACE);
  327. glDisable(GL_DEPTH_TEST);
  328. glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
  329. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  330. gPixelsDrawn = 0;
  331. gBFDrawBatchCount = 0;
  332. mRenderDevice->FrameStart();
  333. BFApp::Draw();
  334. mRenderDevice->FrameEnd();
  335. gFrameCount++;
  336. //if (gFrameCount % 60 == 0)
  337. //OutputDebugStrF("Pixels: %d Batches: %d\n", gPixelsDrawn / 1000, gBFDrawBatchCount);
  338. }
  339. BFWindow* SdlBFApp::CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags)
  340. {
  341. SdlBFWindow* aWindow = new SdlBFWindow(parent, title, x, y, width, height, windowFlags);
  342. mSdlWindowMap[bf_SDL_GetWindowID(aWindow->mSDLWindow)] = aWindow;
  343. mWindowList.push_back(aWindow);
  344. return aWindow;
  345. }
  346. void SdlBFWindow::GetPosition(int* x, int* y, int* width, int* height, int* clientX, int* clientY, int* clientWidth, int* clientHeight)
  347. {
  348. bf_SDL_GetWindowPosition(mSDLWindow, x, y);
  349. bf_SDL_GetWindowSize(mSDLWindow, width, height);
  350. *clientWidth = *width;
  351. *clientHeight = *height;
  352. }
  353. void SdlBFApp::PhysSetCursor()
  354. {
  355. }
  356. void SdlBFWindow::SetClientPosition(int x, int y)
  357. {
  358. bf_SDL_SetWindowPosition(mSDLWindow, x, y);
  359. if (mMovedFunc != NULL)
  360. mMovedFunc(this);
  361. }
  362. void SdlBFWindow::SetAlpha(float alpha, uint32 destAlphaSrcMask, bool isMouseVisible)
  363. {
  364. // Not supported
  365. }
  366. uint32 SdlBFApp::GetClipboardFormat(const StringImpl& format)
  367. {
  368. return /*CF_TEXT*/1;
  369. }
  370. void* SdlBFApp::GetClipboardData(const StringImpl& format, int* size)
  371. {
  372. return bf_SDL_GetClipboardText();
  373. }
  374. void SdlBFApp::ReleaseClipboardData(void* ptr)
  375. {
  376. bf_SDL_free(ptr);
  377. }
  378. void SdlBFApp::SetClipboardData(const StringImpl& format, const void* ptr, int size, bool resetClipboard)
  379. {
  380. bf_SDL_SetClipboardText((const char*)ptr);
  381. }
  382. BFMenu* SdlBFWindow::AddMenuItem(BFMenu* parent, int insertIdx, const char* text, const char* hotKey, BFSysBitmap* bitmap, bool enabled, int checkState, bool radioCheck)
  383. {
  384. return NULL;
  385. }
  386. void SdlBFWindow::RemoveMenuItem(BFMenu* item)
  387. {
  388. }
  389. BFSysBitmap* SdlBFApp::LoadSysBitmap(const wchar_t* fileName)
  390. {
  391. return NULL;
  392. }
  393. void SdlBFWindow::ModalsRemoved()
  394. {
  395. //::EnableWindow(mHWnd, TRUE);
  396. //::SetFocus(mHWnd);
  397. }
  398. DrawLayer* SdlBFApp::CreateDrawLayer(BFWindow* window)
  399. {
  400. GLDrawLayer* drawLayer = new GLDrawLayer();
  401. if (window != NULL)
  402. {
  403. drawLayer->mRenderWindow = window->mRenderWindow;
  404. window->mRenderWindow->mDrawLayerList.push_back(drawLayer);
  405. }
  406. drawLayer->mRenderDevice = mRenderDevice;
  407. return drawLayer;
  408. }
  409. void SdlBFApp::GetDesktopResolution(int& width, int& height)
  410. {
  411. width = 1024;
  412. height = 768;
  413. }
  414. void SdlBFApp::GetWorkspaceRect(int& x, int& y, int& width, int& height)
  415. {
  416. x = 0;
  417. y = 0;
  418. width = 1024;
  419. height = 768;
  420. }