Нет описания
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

olcPixelGameEngine.cpp 47KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652
  1. #include "olcPixelGameEngine.h"
  2. #ifdef _WIN32
  3. static wglSwapInterval_t *wglSwapInterval;
  4. #else
  5. static glSwapInterval_t *glSwapIntervalEXT;
  6. #endif
  7. namespace olc
  8. {
  9. Pixel::Pixel()
  10. {
  11. r = 0; g = 0; b = 0; a = 255;
  12. }
  13. Pixel::Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
  14. {
  15. r = red; g = green; b = blue; a = alpha;
  16. }
  17. Pixel::Pixel(uint32_t p)
  18. {
  19. n = p;
  20. }
  21. Pixel Pixel::CreateFromHSV(uint8_t h, uint8_t s, uint8_t v, uint8_t alpha) {
  22. Pixel rgb;
  23. rgb.a = alpha;
  24. uint8_t region, remainder, p, q, t;
  25. if (s == 0)
  26. {
  27. rgb.r = v;
  28. rgb.g = v;
  29. rgb.b = v;
  30. return rgb;
  31. }
  32. region = h / 43;
  33. remainder = (h - (region * 43)) * 6;
  34. p = (v * (255 - s)) >> 8;
  35. q = (v * (255 - ((s * remainder) >> 8))) >> 8;
  36. t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
  37. switch (region)
  38. {
  39. case 0:
  40. rgb.r = v; rgb.g = t; rgb.b = p;
  41. break;
  42. case 1:
  43. rgb.r = q; rgb.g = v; rgb.b = p;
  44. break;
  45. case 2:
  46. rgb.r = p; rgb.g = v; rgb.b = t;
  47. break;
  48. case 3:
  49. rgb.r = p; rgb.g = q; rgb.b = v;
  50. break;
  51. case 4:
  52. rgb.r = t; rgb.g = p; rgb.b = v;
  53. break;
  54. default:
  55. rgb.r = v; rgb.g = p; rgb.b = q;
  56. break;
  57. }
  58. return rgb;
  59. }
  60. //==========================================================
  61. std::wstring ConvertS2W(std::string s)
  62. {
  63. #ifdef _WIN32
  64. int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0);
  65. wchar_t* buffer = new wchar_t[count];
  66. MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count);
  67. std::wstring w(buffer);
  68. delete[] buffer;
  69. return w;
  70. #else
  71. return L"SVN FTW!";
  72. #endif
  73. }
  74. Sprite::Sprite()
  75. {
  76. pColData = nullptr;
  77. width = 0;
  78. height = 0;
  79. }
  80. Sprite::Sprite(std::string sImageFile)
  81. {
  82. LoadFromFile(sImageFile);
  83. }
  84. Sprite::Sprite(std::string sImageFile, olc::ResourcePack *pack)
  85. {
  86. LoadFromPGESprFile(sImageFile, pack);
  87. }
  88. Sprite::Sprite(int32_t w, int32_t h)
  89. {
  90. if(pColData) delete[] pColData;
  91. width = w; height = h;
  92. pColData = new Pixel[width * height];
  93. for (int32_t i = 0; i < width*height; i++)
  94. pColData[i] = Pixel();
  95. }
  96. Sprite::~Sprite()
  97. {
  98. if (pColData) delete pColData;
  99. }
  100. olc::rcode Sprite::LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack)
  101. {
  102. if (pColData) delete[] pColData;
  103. auto ReadData = [&](std::istream &is)
  104. {
  105. is.read((char*)&width, sizeof(int32_t));
  106. is.read((char*)&height, sizeof(int32_t));
  107. pColData = new Pixel[width * height];
  108. is.read((char*)pColData, width * height * sizeof(uint32_t));
  109. };
  110. // These are essentially Memory Surfaces represented by olc::Sprite
  111. // which load very fast, but are completely uncompressed
  112. if (pack == nullptr)
  113. {
  114. std::ifstream ifs;
  115. ifs.open(sImageFile, std::ifstream::binary);
  116. if (ifs.is_open())
  117. {
  118. ReadData(ifs);
  119. return olc::OK;
  120. }
  121. else
  122. return olc::FAIL;
  123. }
  124. else
  125. {
  126. auto streamBuffer = pack->GetStreamBuffer(sImageFile);
  127. std::istream is(&streamBuffer);
  128. ReadData(is);
  129. }
  130. return olc::FAIL;
  131. }
  132. olc::rcode Sprite::SaveToPGESprFile(std::string sImageFile)
  133. {
  134. if (pColData == nullptr) return olc::FAIL;
  135. std::ofstream ofs;
  136. ofs.open(sImageFile, std::ifstream::binary);
  137. if (ofs.is_open())
  138. {
  139. ofs.write((char*)&width, sizeof(int32_t));
  140. ofs.write((char*)&height, sizeof(int32_t));
  141. ofs.write((char*)pColData, width*height*sizeof(uint32_t));
  142. ofs.close();
  143. return olc::OK;
  144. }
  145. return olc::FAIL;
  146. }
  147. olc::rcode Sprite::LoadFromFile(std::string sImageFile, olc::ResourcePack *pack)
  148. {
  149. #ifdef _WIN32
  150. // Use GDI+
  151. std::wstring wsImageFile;
  152. #ifdef __MINGW32__
  153. wchar_t *buffer = new wchar_t[sImageFile.length() + 1];
  154. mbstowcs(buffer, sImageFile.c_str(), sImageFile.length());
  155. buffer[sImageFile.length()] = L'\0';
  156. wsImageFile = buffer;
  157. delete [] buffer;
  158. #else
  159. wsImageFile = ConvertS2W(sImageFile);
  160. #endif
  161. Gdiplus::Bitmap *bmp = Gdiplus::Bitmap::FromFile(wsImageFile.c_str());
  162. if (bmp == nullptr)
  163. return olc::NO_FILE;
  164. width = bmp->GetWidth();
  165. height = bmp->GetHeight();
  166. pColData = new Pixel[width * height];
  167. for(int x=0; x<width; x++)
  168. for (int y = 0; y < height; y++)
  169. {
  170. Gdiplus::Color c;
  171. bmp->GetPixel(x, y, &c);
  172. SetPixel(x, y, Pixel(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha()));
  173. }
  174. delete bmp;
  175. return olc::OK;
  176. #else
  177. ////////////////////////////////////////////////////////////////////////////
  178. // Use libpng, Thanks to Guillaume Cottenceau
  179. // https://gist.github.com/niw/5963798
  180. png_structp png;
  181. png_infop info;
  182. FILE *f = fopen(sImageFile.c_str(), "rb");
  183. if (!f) return olc::NO_FILE;
  184. png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  185. if (!png) goto fail_load;
  186. info = png_create_info_struct(png);
  187. if (!info) goto fail_load;
  188. if (setjmp(png_jmpbuf(png))) goto fail_load;
  189. png_init_io(png, f);
  190. png_read_info(png, info);
  191. png_byte color_type;
  192. png_byte bit_depth;
  193. png_bytep *row_pointers;
  194. width = png_get_image_width(png, info);
  195. height = png_get_image_height(png, info);
  196. color_type = png_get_color_type(png, info);
  197. bit_depth = png_get_bit_depth(png, info);
  198. #ifdef _DEBUG
  199. std::cout << "Loading PNG: " << sImageFile << "\n";
  200. std::cout << "W:" << width << " H:" << height << " D:" << (int)bit_depth << "\n";
  201. #endif
  202. if (bit_depth == 16) png_set_strip_16(png);
  203. if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
  204. if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png);
  205. if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png);
  206. if (color_type == PNG_COLOR_TYPE_RGB ||
  207. color_type == PNG_COLOR_TYPE_GRAY ||
  208. color_type == PNG_COLOR_TYPE_PALETTE)
  209. png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
  210. if (color_type == PNG_COLOR_TYPE_GRAY ||
  211. color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  212. png_set_gray_to_rgb(png);
  213. png_read_update_info(png, info);
  214. row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
  215. for (int y = 0; y < height; y++) {
  216. row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info));
  217. }
  218. png_read_image(png, row_pointers);
  219. ////////////////////////////////////////////////////////////////////////////
  220. // Create sprite array
  221. pColData = new Pixel[width * height];
  222. // Iterate through image rows, converting into sprite format
  223. for (int y = 0; y < height; y++)
  224. {
  225. png_bytep row = row_pointers[y];
  226. for (int x = 0; x < width; x++)
  227. {
  228. png_bytep px = &(row[x * 4]);
  229. SetPixel(x, y, Pixel(px[0], px[1], px[2], px[3]));
  230. }
  231. }
  232. fclose(f);
  233. return olc::OK;
  234. fail_load:
  235. width = 0;
  236. height = 0;
  237. fclose(f);
  238. pColData = nullptr;
  239. return olc::FAIL;
  240. #endif
  241. }
  242. void Sprite::SetSampleMode(olc::Sprite::Mode mode)
  243. {
  244. modeSample = mode;
  245. }
  246. Pixel Sprite::GetPixel(int32_t x, int32_t y)
  247. {
  248. if (modeSample == olc::Sprite::Mode::NORMAL)
  249. {
  250. if (x >= 0 && x < width && y >= 0 && y < height)
  251. return pColData[y*width + x];
  252. else
  253. return Pixel(0, 0, 0, 0);
  254. }
  255. else
  256. {
  257. return pColData[abs(y%height)*width + abs(x%width)];
  258. }
  259. }
  260. bool Sprite::SetPixel(int32_t x, int32_t y, Pixel p)
  261. {
  262. #ifdef OLC_DBG_OVERDRAW
  263. nOverdrawCount++;
  264. #endif
  265. if (x >= 0 && x < width && y >= 0 && y < height)
  266. {
  267. pColData[y*width + x] = p;
  268. return true;
  269. }
  270. else
  271. return false;
  272. }
  273. Pixel Sprite::Sample(float x, float y)
  274. {
  275. int32_t sx = std::min((int32_t)((x * (float)width)), width - 1);
  276. int32_t sy = std::min((int32_t)((y * (float)height)), height - 1);
  277. return GetPixel(sx, sy);
  278. }
  279. Pixel Sprite::SampleBL(float u, float v)
  280. {
  281. u = u * width - 0.5f;
  282. v = v * height - 0.5f;
  283. int x = (int)floor(u); // cast to int rounds toward zero, not downward
  284. int y = (int)floor(v); // Thanks @joshinils
  285. float u_ratio = u - x;
  286. float v_ratio = v - y;
  287. float u_opposite = 1 - u_ratio;
  288. float v_opposite = 1 - v_ratio;
  289. olc::Pixel p1 = GetPixel(std::max(x, 0), std::max(y, 0));
  290. olc::Pixel p2 = GetPixel(std::min(x + 1, (int)width - 1), std::max(y, 0));
  291. olc::Pixel p3 = GetPixel(std::max(x, 0), std::min(y + 1, (int)height - 1));
  292. olc::Pixel p4 = GetPixel(std::min(x + 1, (int)width - 1), std::min(y + 1, (int)height - 1));
  293. return olc::Pixel(
  294. (uint8_t)((p1.r * u_opposite + p2.r * u_ratio) * v_opposite + (p3.r * u_opposite + p4.r * u_ratio) * v_ratio),
  295. (uint8_t)((p1.g * u_opposite + p2.g * u_ratio) * v_opposite + (p3.g * u_opposite + p4.g * u_ratio) * v_ratio),
  296. (uint8_t)((p1.b * u_opposite + p2.b * u_ratio) * v_opposite + (p3.b * u_opposite + p4.b * u_ratio) * v_ratio));
  297. }
  298. Pixel* Sprite::GetData() { return pColData; }
  299. //==========================================================
  300. PixelGameEngine::PixelGameEngine()
  301. {
  302. sAppName = "Undefined";
  303. olc::PGEX::pge = this;
  304. }
  305. olc::rcode PixelGameEngine::Construct(uint32_t screen_w, uint32_t screen_h, uint32_t pixel_w, uint32_t pixel_h, bool full_screen)
  306. {
  307. nScreenWidth = screen_w;
  308. nScreenHeight = screen_h;
  309. nPixelWidth = pixel_w;
  310. nPixelHeight = pixel_h;
  311. bFullScreen = full_screen;
  312. fPixelX = 2.0f / (float)(nScreenWidth);
  313. fPixelY = 2.0f / (float)(nScreenHeight);
  314. if (nPixelWidth == 0 || nPixelHeight == 0 || nScreenWidth == 0 || nScreenHeight == 0)
  315. return olc::FAIL;
  316. #ifdef _WIN32
  317. #ifdef UNICODE
  318. #ifndef __MINGW32__
  319. wsAppName = ConvertS2W(sAppName);
  320. #endif
  321. #endif
  322. #endif
  323. // Load the default font sheet
  324. olc_ConstructFontSheet();
  325. // Create a sprite that represents the primary drawing target
  326. pDefaultDrawTarget = new Sprite(nScreenWidth, nScreenHeight);
  327. SetDrawTarget(nullptr);
  328. return olc::OK;
  329. }
  330. olc::rcode PixelGameEngine::ConstructAuto(uint32_t screen_w, uint32_t screen_h, bool fullscreen)
  331. {
  332. uint32_t pixelSize = olc_GetMaximumPixelSize(screen_w, screen_h);
  333. return Construct(screen_w, screen_h, pixelSize, pixelSize, fullscreen);
  334. }
  335. olc::rcode PixelGameEngine::Start()
  336. {
  337. // Construct the window
  338. if (!olc_WindowCreate())
  339. return olc::FAIL;
  340. // Load libraries required for PNG file interaction
  341. //#ifdef _WIN32
  342. // // Windows use GDI+
  343. // Gdiplus::GdiplusStartupInput startupInput;
  344. // ULONG_PTR token;
  345. // Gdiplus::GdiplusStartup(&token, &startupInput, NULL);
  346. //#else
  347. // // Linux use libpng
  348. //
  349. //#endif
  350. // Start the thread
  351. bAtomActive = true;
  352. std::thread t = std::thread(&PixelGameEngine::EngineThread, this);
  353. #ifdef _WIN32
  354. // Handle Windows Message Loop
  355. MSG msg;
  356. while (GetMessage(&msg, NULL, 0, 0) > 0)
  357. {
  358. TranslateMessage(&msg);
  359. DispatchMessage(&msg);
  360. }
  361. #endif
  362. // Wait for thread to be exited
  363. t.join();
  364. return olc::OK;
  365. }
  366. void PixelGameEngine::SetDrawTarget(Sprite *target)
  367. {
  368. if (target)
  369. pDrawTarget = target;
  370. else
  371. pDrawTarget = pDefaultDrawTarget;
  372. }
  373. Sprite* PixelGameEngine::GetDrawTarget()
  374. {
  375. return pDrawTarget;
  376. }
  377. int32_t PixelGameEngine::GetDrawTargetWidth()
  378. {
  379. if (pDrawTarget)
  380. return pDrawTarget->width;
  381. else
  382. return 0;
  383. }
  384. int32_t PixelGameEngine::GetDrawTargetHeight()
  385. {
  386. if (pDrawTarget)
  387. return pDrawTarget->height;
  388. else
  389. return 0;
  390. }
  391. bool PixelGameEngine::IsFocused()
  392. {
  393. return bHasInputFocus;
  394. }
  395. HWButton PixelGameEngine::GetKey(Key k)
  396. {
  397. return pKeyboardState[k];
  398. }
  399. HWButton PixelGameEngine::GetMouse(uint32_t b)
  400. {
  401. return pMouseState[b];
  402. }
  403. int32_t PixelGameEngine::GetMouseX()
  404. {
  405. return nMousePosX;
  406. }
  407. int32_t PixelGameEngine::GetMouseY()
  408. {
  409. return nMousePosY;
  410. }
  411. int32_t PixelGameEngine::GetMouseWheel()
  412. {
  413. return nMouseWheelDelta;
  414. }
  415. int32_t PixelGameEngine::ScreenWidth()
  416. {
  417. return nScreenWidth;
  418. }
  419. int32_t PixelGameEngine::ScreenHeight()
  420. {
  421. return nScreenHeight;
  422. }
  423. bool PixelGameEngine::Draw(int32_t x, int32_t y, Pixel p)
  424. {
  425. if (!pDrawTarget) return false;
  426. if (nPixelMode == Pixel::NORMAL)
  427. {
  428. return pDrawTarget->SetPixel(x, y, p);
  429. }
  430. if (nPixelMode == Pixel::MASK)
  431. {
  432. if(p.a == 255)
  433. return pDrawTarget->SetPixel(x, y, p);
  434. }
  435. if (nPixelMode == Pixel::ALPHA)
  436. {
  437. Pixel d = pDrawTarget->GetPixel(x, y);
  438. float a = (float)(p.a / 255.0f) * fBlendFactor;
  439. float c = 1.0f - a;
  440. float r = a * (float)p.r + c * (float)d.r;
  441. float g = a * (float)p.g + c * (float)d.g;
  442. float b = a * (float)p.b + c * (float)d.b;
  443. return pDrawTarget->SetPixel(x, y, Pixel((uint8_t)r, (uint8_t)g, (uint8_t)b));
  444. }
  445. if (nPixelMode == Pixel::CUSTOM)
  446. {
  447. return pDrawTarget->SetPixel(x, y, funcPixelMode(x, y, p, pDrawTarget->GetPixel(x, y)));
  448. }
  449. return false;
  450. }
  451. void PixelGameEngine::SetSubPixelOffset(float ox, float oy)
  452. {
  453. fSubPixelOffsetX = ox * fPixelX;
  454. fSubPixelOffsetY = oy * fPixelY;
  455. }
  456. void PixelGameEngine::DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p, uint32_t pattern)
  457. {
  458. int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i;
  459. dx = x2 - x1; dy = y2 - y1;
  460. auto rol = [&](void)
  461. {
  462. pattern = (pattern << 1) | (pattern >> 31);
  463. return pattern & 1;
  464. };
  465. // straight lines idea by gurkanctn
  466. if (dx == 0) // Line is vertical
  467. {
  468. if (y2 < y1) std::swap(y1, y2);
  469. for (y = y1; y <= y2; y++)
  470. if (rol()) Draw(x1, y, p);
  471. return;
  472. }
  473. if (dy == 0) // Line is horizontal
  474. {
  475. if (x2 < x1) std::swap(x1, x2);
  476. for (x = x1; x <= x2; x++)
  477. if (rol()) Draw(x, y1, p);
  478. return;
  479. }
  480. // Line is Funk-aye
  481. dx1 = abs(dx); dy1 = abs(dy);
  482. px = 2 * dy1 - dx1; py = 2 * dx1 - dy1;
  483. if (dy1 <= dx1)
  484. {
  485. if (dx >= 0)
  486. {
  487. x = x1; y = y1; xe = x2;
  488. }
  489. else
  490. {
  491. x = x2; y = y2; xe = x1;
  492. }
  493. if (rol()) Draw(x, y, p);
  494. for (i = 0; x<xe; i++)
  495. {
  496. x = x + 1;
  497. if (px<0)
  498. px = px + 2 * dy1;
  499. else
  500. {
  501. if ((dx<0 && dy<0) || (dx>0 && dy>0)) y = y + 1; else y = y - 1;
  502. px = px + 2 * (dy1 - dx1);
  503. }
  504. if (rol()) Draw(x, y, p);
  505. }
  506. }
  507. else
  508. {
  509. if (dy >= 0)
  510. {
  511. x = x1; y = y1; ye = y2;
  512. }
  513. else
  514. {
  515. x = x2; y = y2; ye = y1;
  516. }
  517. if (rol()) Draw(x, y, p);
  518. for (i = 0; y<ye; i++)
  519. {
  520. y = y + 1;
  521. if (py <= 0)
  522. py = py + 2 * dx1;
  523. else
  524. {
  525. if ((dx<0 && dy<0) || (dx>0 && dy>0)) x = x + 1; else x = x - 1;
  526. py = py + 2 * (dx1 - dy1);
  527. }
  528. if (rol()) Draw(x, y, p);
  529. }
  530. }
  531. }
  532. void PixelGameEngine::DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p, uint8_t mask)
  533. {
  534. int x0 = 0;
  535. int y0 = radius;
  536. int d = 3 - 2 * radius;
  537. if (!radius) return;
  538. while (y0 >= x0) // only formulate 1/8 of circle
  539. {
  540. if (mask & 0x01) Draw(x + x0, y - y0, p);
  541. if (mask & 0x02) Draw(x + y0, y - x0, p);
  542. if (mask & 0x04) Draw(x + y0, y + x0, p);
  543. if (mask & 0x08) Draw(x + x0, y + y0, p);
  544. if (mask & 0x10) Draw(x - x0, y + y0, p);
  545. if (mask & 0x20) Draw(x - y0, y + x0, p);
  546. if (mask & 0x40) Draw(x - y0, y - x0, p);
  547. if (mask & 0x80) Draw(x - x0, y - y0, p);
  548. if (d < 0) d += 4 * x0++ + 6;
  549. else d += 4 * (x0++ - y0--) + 10;
  550. }
  551. }
  552. void PixelGameEngine::FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p)
  553. {
  554. // Taken from wikipedia
  555. int x0 = 0;
  556. int y0 = radius;
  557. int d = 3 - 2 * radius;
  558. if (!radius) return;
  559. auto drawline = [&](int sx, int ex, int ny)
  560. {
  561. for (int i = sx; i <= ex; i++)
  562. Draw(i, ny, p);
  563. };
  564. while (y0 >= x0)
  565. {
  566. // Modified to draw scan-lines instead of edges
  567. drawline(x - x0, x + x0, y - y0);
  568. drawline(x - y0, x + y0, y - x0);
  569. drawline(x - x0, x + x0, y + y0);
  570. drawline(x - y0, x + y0, y + x0);
  571. if (d < 0) d += 4 * x0++ + 6;
  572. else d += 4 * (x0++ - y0--) + 10;
  573. }
  574. }
  575. void PixelGameEngine::DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p)
  576. {
  577. DrawLine(x, y, x+w, y, p);
  578. DrawLine(x+w, y, x+w, y+h, p);
  579. DrawLine(x+w, y+h, x, y+h, p);
  580. DrawLine(x, y+h, x, y, p);
  581. }
  582. void PixelGameEngine::Clear(Pixel p)
  583. {
  584. int pixels = GetDrawTargetWidth() * GetDrawTargetHeight();
  585. Pixel* m = GetDrawTarget()->GetData();
  586. for (int i = 0; i < pixels; i++)
  587. m[i] = p;
  588. #ifdef OLC_DBG_OVERDRAW
  589. olc::Sprite::nOverdrawCount += pixels;
  590. #endif
  591. }
  592. void PixelGameEngine::FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p)
  593. {
  594. int32_t x2 = x + w;
  595. int32_t y2 = y + h;
  596. if (x < 0) x = 0;
  597. if (x >= (int32_t)nScreenWidth) x = (int32_t)nScreenWidth;
  598. if (y < 0) y = 0;
  599. if (y >= (int32_t)nScreenHeight) y = (int32_t)nScreenHeight;
  600. if (x2 < 0) x2 = 0;
  601. if (x2 >= (int32_t)nScreenWidth) x2 = (int32_t)nScreenWidth;
  602. if (y2 < 0) y2 = 0;
  603. if (y2 >= (int32_t)nScreenHeight) y2 = (int32_t)nScreenHeight;
  604. for (int i = x; i < x2; i++)
  605. for (int j = y; j < y2; j++)
  606. Draw(i, j, p);
  607. }
  608. void PixelGameEngine::DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p)
  609. {
  610. DrawLine(x1, y1, x2, y2, p);
  611. DrawLine(x2, y2, x3, y3, p);
  612. DrawLine(x3, y3, x1, y1, p);
  613. }
  614. // https://www.avrfreaks.net/sites/default/files/triangles.c
  615. void PixelGameEngine::FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p)
  616. {
  617. auto SWAP = [](int &x, int &y) { int t = x; x = y; y = t; };
  618. auto drawline = [&](int sx, int ex, int ny) { for (int i = sx; i <= ex; i++) Draw(i, ny, p); };
  619. int t1x, t2x, y, minx, maxx, t1xp, t2xp;
  620. bool changed1 = false;
  621. bool changed2 = false;
  622. int signx1, signx2, dx1, dy1, dx2, dy2;
  623. int e1, e2;
  624. // Sort vertices
  625. if (y1>y2) { SWAP(y1, y2); SWAP(x1, x2); }
  626. if (y1>y3) { SWAP(y1, y3); SWAP(x1, x3); }
  627. if (y2>y3) { SWAP(y2, y3); SWAP(x2, x3); }
  628. t1x = t2x = x1; y = y1; // Starting points
  629. dx1 = (int)(x2 - x1); if (dx1<0) { dx1 = -dx1; signx1 = -1; }
  630. else signx1 = 1;
  631. dy1 = (int)(y2 - y1);
  632. dx2 = (int)(x3 - x1); if (dx2<0) { dx2 = -dx2; signx2 = -1; }
  633. else signx2 = 1;
  634. dy2 = (int)(y3 - y1);
  635. if (dy1 > dx1) { // swap values
  636. SWAP(dx1, dy1);
  637. changed1 = true;
  638. }
  639. if (dy2 > dx2) { // swap values
  640. SWAP(dy2, dx2);
  641. changed2 = true;
  642. }
  643. e2 = (int)(dx2 >> 1);
  644. // Flat top, just process the second half
  645. if (y1 == y2) goto next;
  646. e1 = (int)(dx1 >> 1);
  647. for (int i = 0; i < dx1;) {
  648. t1xp = 0; t2xp = 0;
  649. if (t1x<t2x) { minx = t1x; maxx = t2x; }
  650. else { minx = t2x; maxx = t1x; }
  651. // process first line until y value is about to change
  652. while (i<dx1) {
  653. i++;
  654. e1 += dy1;
  655. while (e1 >= dx1) {
  656. e1 -= dx1;
  657. if (changed1) t1xp = signx1;//t1x += signx1;
  658. else goto next1;
  659. }
  660. if (changed1) break;
  661. else t1x += signx1;
  662. }
  663. // Move line
  664. next1:
  665. // process second line until y value is about to change
  666. while (1) {
  667. e2 += dy2;
  668. while (e2 >= dx2) {
  669. e2 -= dx2;
  670. if (changed2) t2xp = signx2;//t2x += signx2;
  671. else goto next2;
  672. }
  673. if (changed2) break;
  674. else t2x += signx2;
  675. }
  676. next2:
  677. if (minx>t1x) minx = t1x; if (minx>t2x) minx = t2x;
  678. if (maxx<t1x) maxx = t1x; if (maxx<t2x) maxx = t2x;
  679. drawline(minx, maxx, y); // Draw line from min to max points found on the y
  680. // Now increase y
  681. if (!changed1) t1x += signx1;
  682. t1x += t1xp;
  683. if (!changed2) t2x += signx2;
  684. t2x += t2xp;
  685. y += 1;
  686. if (y == y2) break;
  687. }
  688. next:
  689. // Second half
  690. dx1 = (int)(x3 - x2); if (dx1<0) { dx1 = -dx1; signx1 = -1; }
  691. else signx1 = 1;
  692. dy1 = (int)(y3 - y2);
  693. t1x = x2;
  694. if (dy1 > dx1) { // swap values
  695. SWAP(dy1, dx1);
  696. changed1 = true;
  697. }
  698. else changed1 = false;
  699. e1 = (int)(dx1 >> 1);
  700. for (int i = 0; i <= dx1; i++) {
  701. t1xp = 0; t2xp = 0;
  702. if (t1x<t2x) { minx = t1x; maxx = t2x; }
  703. else { minx = t2x; maxx = t1x; }
  704. // process first line until y value is about to change
  705. while (i<dx1) {
  706. e1 += dy1;
  707. while (e1 >= dx1) {
  708. e1 -= dx1;
  709. if (changed1) { t1xp = signx1; break; }//t1x += signx1;
  710. else goto next3;
  711. }
  712. if (changed1) break;
  713. else t1x += signx1;
  714. if (i<dx1) i++;
  715. }
  716. next3:
  717. // process second line until y value is about to change
  718. while (t2x != x3) {
  719. e2 += dy2;
  720. while (e2 >= dx2) {
  721. e2 -= dx2;
  722. if (changed2) t2xp = signx2;
  723. else goto next4;
  724. }
  725. if (changed2) break;
  726. else t2x += signx2;
  727. }
  728. next4:
  729. if (minx>t1x) minx = t1x; if (minx>t2x) minx = t2x;
  730. if (maxx<t1x) maxx = t1x; if (maxx<t2x) maxx = t2x;
  731. drawline(minx, maxx, y);
  732. if (!changed1) t1x += signx1;
  733. t1x += t1xp;
  734. if (!changed2) t2x += signx2;
  735. t2x += t2xp;
  736. y += 1;
  737. if (y>y3) return;
  738. }
  739. }
  740. void PixelGameEngine::DrawSprite(int32_t x, int32_t y, Sprite *sprite, uint32_t scale)
  741. {
  742. if (sprite == nullptr)
  743. return;
  744. if (scale > 1)
  745. {
  746. for (int32_t i = 0; i < sprite->width; i++)
  747. for (int32_t j = 0; j < sprite->height; j++)
  748. for (uint32_t is = 0; is < scale; is++)
  749. for (uint32_t js = 0; js < scale; js++)
  750. Draw(x + (i*scale) + is, y + (j*scale) + js, sprite->GetPixel(i, j));
  751. }
  752. else
  753. {
  754. for (int32_t i = 0; i < sprite->width; i++)
  755. for (int32_t j = 0; j < sprite->height; j++)
  756. Draw(x + i, y + j, sprite->GetPixel(i, j));
  757. }
  758. }
  759. void PixelGameEngine::DrawPartialSprite(int32_t x, int32_t y, Sprite *sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale)
  760. {
  761. if (sprite == nullptr)
  762. return;
  763. if (scale > 1)
  764. {
  765. for (int32_t i = 0; i < w; i++)
  766. for (int32_t j = 0; j < h; j++)
  767. for (uint32_t is = 0; is < scale; is++)
  768. for (uint32_t js = 0; js < scale; js++)
  769. Draw(x + (i*scale) + is, y + (j*scale) + js, sprite->GetPixel(i + ox, j + oy));
  770. }
  771. else
  772. {
  773. for (int32_t i = 0; i < w; i++)
  774. for (int32_t j = 0; j < h; j++)
  775. Draw(x + i, y + j, sprite->GetPixel(i + ox, j + oy));
  776. }
  777. }
  778. void PixelGameEngine::DrawString(int32_t x, int32_t y, std::string sText, Pixel col, uint32_t scale)
  779. {
  780. int32_t sx = 0;
  781. int32_t sy = 0;
  782. Pixel::Mode m = nPixelMode;
  783. if(col.ALPHA != 255) SetPixelMode(Pixel::ALPHA);
  784. else SetPixelMode(Pixel::MASK);
  785. for (auto c : sText)
  786. {
  787. if (c == '\n')
  788. {
  789. sx = 0; sy += 8 * scale;
  790. }
  791. else
  792. {
  793. int32_t ox = (c - 32) % 16;
  794. int32_t oy = (c - 32) / 16;
  795. if (scale > 1)
  796. {
  797. for (uint32_t i = 0; i < 8; i++)
  798. for (uint32_t j = 0; j < 8; j++)
  799. if (fontSprite->GetPixel(i + ox * 8, j + oy * 8).r > 0)
  800. for (uint32_t is = 0; is < scale; is++)
  801. for (uint32_t js = 0; js < scale; js++)
  802. Draw(x + sx + (i*scale) + is, y + sy + (j*scale) + js, col);
  803. }
  804. else
  805. {
  806. for (uint32_t i = 0; i < 8; i++)
  807. for (uint32_t j = 0; j < 8; j++)
  808. if (fontSprite->GetPixel(i + ox * 8, j + oy * 8).r > 0)
  809. Draw(x + sx + i, y + sy + j, col);
  810. }
  811. sx += 8 * scale;
  812. }
  813. }
  814. SetPixelMode(m);
  815. }
  816. void PixelGameEngine::SetPixelMode(Pixel::Mode m)
  817. {
  818. nPixelMode = m;
  819. }
  820. Pixel::Mode PixelGameEngine::GetPixelMode()
  821. {
  822. return nPixelMode;
  823. }
  824. void PixelGameEngine::SetPixelMode(std::function<olc::Pixel(const int x, const int y, const olc::Pixel&, const olc::Pixel&)> pixelMode)
  825. {
  826. funcPixelMode = pixelMode;
  827. nPixelMode = Pixel::Mode::CUSTOM;
  828. }
  829. void PixelGameEngine::SetPixelBlend(float fBlend)
  830. {
  831. fBlendFactor = fBlend;
  832. if (fBlendFactor < 0.0f) fBlendFactor = 0.0f;
  833. if (fBlendFactor > 1.0f) fBlendFactor = 1.0f;
  834. }
  835. // User must override these functions as required. I have not made
  836. // them abstract because I do need a default behaviour to occur if
  837. // they are not overwritten
  838. bool PixelGameEngine::OnUserCreate()
  839. { return false; }
  840. bool PixelGameEngine::OnUserUpdate(float fElapsedTime)
  841. { return false; }
  842. bool PixelGameEngine::OnUserDestroy()
  843. { return true; }
  844. //////////////////////////////////////////////////////////////////
  845. void PixelGameEngine::olc_UpdateViewport()
  846. {
  847. int32_t ww = nScreenWidth * nPixelWidth;
  848. int32_t wh = nScreenHeight * nPixelHeight;
  849. float wasp = (float)ww / (float)wh;
  850. nViewW = (int32_t)nWindowWidth;
  851. nViewH = (int32_t)((float)nViewW / wasp);
  852. if (nViewH > nWindowHeight)
  853. {
  854. nViewH = nWindowHeight;
  855. nViewW = (int32_t)((float)nViewH * wasp);
  856. }
  857. nViewX = (nWindowWidth - nViewW) / 2;
  858. nViewY = (nWindowHeight - nViewH) / 2;
  859. }
  860. void PixelGameEngine::olc_UpdateWindowSize(int32_t x, int32_t y)
  861. {
  862. nWindowWidth = x;
  863. nWindowHeight = y;
  864. olc_UpdateViewport();
  865. }
  866. void PixelGameEngine::olc_UpdateMouseWheel(int32_t delta)
  867. {
  868. nMouseWheelDeltaCache += delta;
  869. }
  870. void PixelGameEngine::olc_UpdateMouse(int32_t x, int32_t y)
  871. {
  872. // Mouse coords come in screen space
  873. // But leave in pixel space
  874. //if (bFullScreen)
  875. {
  876. // Full Screen mode may have a weird viewport we must clamp to
  877. x -= nViewX;
  878. y -= nViewY;
  879. }
  880. nMousePosXcache = (int32_t)(((float)x / (float)(nWindowWidth - (nViewX * 2)) * (float)nScreenWidth));
  881. nMousePosYcache = (int32_t)(((float)y / (float)(nWindowHeight - (nViewY * 2)) * (float)nScreenHeight));
  882. if (nMousePosXcache >= (int32_t)nScreenWidth)
  883. nMousePosXcache = nScreenWidth - 1;
  884. if (nMousePosYcache >= (int32_t)nScreenHeight)
  885. nMousePosYcache = nScreenHeight - 1;
  886. if (nMousePosXcache < 0)
  887. nMousePosXcache = 0;
  888. if (nMousePosYcache < 0)
  889. nMousePosYcache = 0;
  890. }
  891. uint32_t PixelGameEngine::olc_GetMaximumPixelSize(uint32_t width, uint32_t height)
  892. {
  893. #ifdef _WIN32
  894. return 1; // TODO
  895. #else
  896. Display* d = XOpenDisplay(NULL);
  897. int defaultScreen = DefaultScreen(d);
  898. Screen *s = ScreenOfDisplay(d, defaultScreen);
  899. int minWidth = WidthOfScreen(s);
  900. int minHeight = HeightOfScreen(s);
  901. int screensCount = ScreenCount(d);
  902. for (int i=0; i < screensCount; i++) {
  903. s = ScreenOfDisplay(d, i);
  904. if (WidthOfScreen(s) < minWidth) {
  905. minWidth = WidthOfScreen(s);
  906. }
  907. if (HeightOfScreen(s) < minHeight) {
  908. minHeight = HeightOfScreen(s);
  909. }
  910. }
  911. uint32_t pixelWidth = minWidth / width;
  912. uint32_t pixelHeight = minHeight / height;
  913. return std::min(pixelWidth, pixelHeight);
  914. #endif
  915. }
  916. void PixelGameEngine::EngineThread()
  917. {
  918. // Start OpenGL, the context is owned by the game thread
  919. olc_OpenGLCreate();
  920. // Create Screen Texture - disable filtering
  921. glEnable(GL_TEXTURE_2D);
  922. glGenTextures(1, &glBuffer);
  923. glBindTexture(GL_TEXTURE_2D, glBuffer);
  924. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  925. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  926. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
  927. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nScreenWidth, nScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pDefaultDrawTarget->GetData());
  928. // Create user resources as part of this thread
  929. if (!OnUserCreate())
  930. bAtomActive = false;
  931. auto tp1 = std::chrono::system_clock::now();
  932. auto tp2 = std::chrono::system_clock::now();
  933. while (bAtomActive)
  934. {
  935. // Run as fast as possible
  936. while (bAtomActive)
  937. {
  938. // Handle Timing
  939. tp2 = std::chrono::system_clock::now();
  940. std::chrono::duration<float> elapsedTime = tp2 - tp1;
  941. tp1 = tp2;
  942. // Our time per frame coefficient
  943. float fElapsedTime = elapsedTime.count();
  944. #ifndef _WIN32
  945. // Handle Xlib Message Loop - we do this in the
  946. // same thread that OpenGL was created so we dont
  947. // need to worry too much about multithreading with X11
  948. XEvent xev;
  949. while (XPending(olc_Display))
  950. {
  951. XNextEvent(olc_Display, &xev);
  952. if (xev.type == Expose)
  953. {
  954. XWindowAttributes gwa;
  955. XGetWindowAttributes(olc_Display, olc_Window, &gwa);
  956. nWindowWidth = gwa.width;
  957. nWindowHeight = gwa.height;
  958. olc_UpdateViewport();
  959. glClear(GL_COLOR_BUFFER_BIT); // Thanks Benedani!
  960. }
  961. else if (xev.type == ConfigureNotify)
  962. {
  963. XConfigureEvent xce = xev.xconfigure;
  964. nWindowWidth = xce.width;
  965. nWindowHeight = xce.height;
  966. }
  967. else if (xev.type == KeyPress)
  968. {
  969. KeySym sym = XLookupKeysym(&xev.xkey, 0);
  970. pKeyNewState[mapKeys[sym]] = true;
  971. XKeyEvent *e = (XKeyEvent *)&xev; // Because DragonEye loves numpads
  972. XLookupString(e, NULL, 0, &sym, NULL);
  973. pKeyNewState[mapKeys[sym]] = true;
  974. }
  975. else if (xev.type == KeyRelease)
  976. {
  977. KeySym sym = XLookupKeysym(&xev.xkey, 0);
  978. pKeyNewState[mapKeys[sym]] = false;
  979. XKeyEvent *e = (XKeyEvent *)&xev;
  980. XLookupString(e, NULL, 0, &sym, NULL);
  981. pKeyNewState[mapKeys[sym]] = false;
  982. }
  983. else if (xev.type == ButtonPress)
  984. {
  985. switch (xev.xbutton.button)
  986. {
  987. case 1: pMouseNewState[0] = true; break;
  988. case 2: pMouseNewState[2] = true; break;
  989. case 3: pMouseNewState[1] = true; break;
  990. case 4: olc_UpdateMouseWheel(120); break;
  991. case 5: olc_UpdateMouseWheel(-120); break;
  992. default: break;
  993. }
  994. }
  995. else if (xev.type == ButtonRelease)
  996. {
  997. switch (xev.xbutton.button)
  998. {
  999. case 1: pMouseNewState[0] = false; break;
  1000. case 2: pMouseNewState[2] = false; break;
  1001. case 3: pMouseNewState[1] = false; break;
  1002. default: break;
  1003. }
  1004. }
  1005. else if (xev.type == MotionNotify)
  1006. {
  1007. olc_UpdateMouse(xev.xmotion.x, xev.xmotion.y);
  1008. }
  1009. else if (xev.type == FocusIn)
  1010. {
  1011. bHasInputFocus = true;
  1012. }
  1013. else if (xev.type == FocusOut)
  1014. {
  1015. bHasInputFocus = false;
  1016. }
  1017. else if (xev.type == ClientMessage)
  1018. {
  1019. bAtomActive = false;
  1020. }
  1021. }
  1022. #endif
  1023. // Handle User Input - Keyboard
  1024. for (int i = 0; i < 256; i++)
  1025. {
  1026. pKeyboardState[i].bPressed = false;
  1027. pKeyboardState[i].bReleased = false;
  1028. if (pKeyNewState[i] != pKeyOldState[i])
  1029. {
  1030. if (pKeyNewState[i])
  1031. {
  1032. pKeyboardState[i].bPressed = !pKeyboardState[i].bHeld;
  1033. pKeyboardState[i].bHeld = true;
  1034. }
  1035. else
  1036. {
  1037. pKeyboardState[i].bReleased = true;
  1038. pKeyboardState[i].bHeld = false;
  1039. }
  1040. }
  1041. pKeyOldState[i] = pKeyNewState[i];
  1042. }
  1043. // Handle User Input - Mouse
  1044. for (int i = 0; i < 5; i++)
  1045. {
  1046. pMouseState[i].bPressed = false;
  1047. pMouseState[i].bReleased = false;
  1048. if (pMouseNewState[i] != pMouseOldState[i])
  1049. {
  1050. if (pMouseNewState[i])
  1051. {
  1052. pMouseState[i].bPressed = !pMouseState[i].bHeld;
  1053. pMouseState[i].bHeld = true;
  1054. }
  1055. else
  1056. {
  1057. pMouseState[i].bReleased = true;
  1058. pMouseState[i].bHeld = false;
  1059. }
  1060. }
  1061. pMouseOldState[i] = pMouseNewState[i];
  1062. }
  1063. // Cache mouse coordinates so they remain
  1064. // consistent during frame
  1065. nMousePosX = nMousePosXcache;
  1066. nMousePosY = nMousePosYcache;
  1067. nMouseWheelDelta = nMouseWheelDeltaCache;
  1068. nMouseWheelDeltaCache = 0;
  1069. #ifdef OLC_DBG_OVERDRAW
  1070. olc::Sprite::nOverdrawCount = 0;
  1071. #endif
  1072. // Handle Frame Update
  1073. if (!OnUserUpdate(fElapsedTime))
  1074. bAtomActive = false;
  1075. // Display Graphics
  1076. glViewport(nViewX, nViewY, nViewW, nViewH);
  1077. // TODO: This is a bit slow (especially in debug, but 100x faster in release mode???)
  1078. // Copy pixel array into texture
  1079. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, nScreenWidth, nScreenHeight, GL_RGBA, GL_UNSIGNED_BYTE, pDefaultDrawTarget->GetData());
  1080. // Display texture on screen
  1081. glBegin(GL_QUADS);
  1082. glTexCoord2f(0.0, 1.0); glVertex3f(-1.0f + (fSubPixelOffsetX), -1.0f + (fSubPixelOffsetY), 0.0f);
  1083. glTexCoord2f(0.0, 0.0); glVertex3f(-1.0f + (fSubPixelOffsetX), 1.0f + (fSubPixelOffsetY), 0.0f);
  1084. glTexCoord2f(1.0, 0.0); glVertex3f( 1.0f + (fSubPixelOffsetX), 1.0f + (fSubPixelOffsetY), 0.0f);
  1085. glTexCoord2f(1.0, 1.0); glVertex3f( 1.0f + (fSubPixelOffsetX), -1.0f + (fSubPixelOffsetY), 0.0f);
  1086. glEnd();
  1087. // Present Graphics to screen
  1088. #ifdef _WIN32
  1089. SwapBuffers(glDeviceContext);
  1090. #else
  1091. glXSwapBuffers(olc_Display, olc_Window);
  1092. #endif
  1093. // Update Title Bar
  1094. fFrameTimer += fElapsedTime;
  1095. nFrameCount++;
  1096. if (fFrameTimer >= 1.0f)
  1097. {
  1098. fFrameTimer -= 1.0f;
  1099. std::string sTitle = "OneLoneCoder.com - Pixel Game Engine - " + sAppName + " - FPS: " + std::to_string(nFrameCount);
  1100. #ifdef _WIN32
  1101. #ifdef UNICODE
  1102. SetWindowText(olc_hWnd, ConvertS2W(sTitle).c_str());
  1103. #else
  1104. SetWindowText(olc_hWnd, sTitle.c_str());
  1105. #endif
  1106. #else
  1107. XStoreName(olc_Display, olc_Window, sTitle.c_str());
  1108. #endif
  1109. nFrameCount = 0;
  1110. }
  1111. }
  1112. // Allow the user to free resources if they have overrided the destroy function
  1113. if (OnUserDestroy())
  1114. {
  1115. // User has permitted destroy, so exit and clean up
  1116. }
  1117. else
  1118. {
  1119. // User denied destroy for some reason, so continue running
  1120. bAtomActive = true;
  1121. }
  1122. }
  1123. #ifdef _WIN32
  1124. wglDeleteContext(glRenderContext);
  1125. PostMessage(olc_hWnd, WM_DESTROY, 0, 0);
  1126. #else
  1127. glXMakeCurrent(olc_Display, None, NULL);
  1128. glXDestroyContext(olc_Display, glDeviceContext);
  1129. XDestroyWindow(olc_Display, olc_Window);
  1130. XCloseDisplay(olc_Display);
  1131. #endif
  1132. }
  1133. #ifdef _WIN32
  1134. // Thanks @MaGetzUb for this, which allows sprites to be defined
  1135. // at construction, by initialising the GDI subsystem
  1136. static class GDIPlusStartup
  1137. {
  1138. public:
  1139. GDIPlusStartup()
  1140. {
  1141. Gdiplus::GdiplusStartupInput startupInput;
  1142. ULONG_PTR token;
  1143. Gdiplus::GdiplusStartup(&token, &startupInput, NULL);
  1144. };
  1145. } gdistartup;
  1146. #endif
  1147. void PixelGameEngine::olc_ConstructFontSheet()
  1148. {
  1149. std::string data;
  1150. data += "?Q`0001oOch0o01o@F40o0<AGD4090LAGD<090@A7ch0?00O7Q`0600>00000000";
  1151. data += "O000000nOT0063Qo4d8>?7a14Gno94AA4gno94AaOT0>o3`oO400o7QN00000400";
  1152. data += "Of80001oOg<7O7moBGT7O7lABET024@aBEd714AiOdl717a_=TH013Q>00000000";
  1153. data += "720D000V?V5oB3Q_HdUoE7a9@DdDE4A9@DmoE4A;Hg]oM4Aj8S4D84@`00000000";
  1154. data += "OaPT1000Oa`^13P1@AI[?g`1@A=[OdAoHgljA4Ao?WlBA7l1710007l100000000";
  1155. data += "ObM6000oOfMV?3QoBDD`O7a0BDDH@5A0BDD<@5A0BGeVO5ao@CQR?5Po00000000";
  1156. data += "Oc``000?Ogij70PO2D]??0Ph2DUM@7i`2DTg@7lh2GUj?0TO0C1870T?00000000";
  1157. data += "70<4001o?P<7?1QoHg43O;`h@GT0@:@LB@d0>:@hN@L0@?aoN@<0O7ao0000?000";
  1158. data += "OcH0001SOglLA7mg24TnK7ln24US>0PL24U140PnOgl0>7QgOcH0K71S0000A000";
  1159. data += "00H00000@Dm1S007@DUSg00?OdTnH7YhOfTL<7Yh@Cl0700?@Ah0300700000000";
  1160. data += "<008001QL00ZA41a@6HnI<1i@FHLM81M@@0LG81?O`0nC?Y7?`0ZA7Y300080000";
  1161. data += "O`082000Oh0827mo6>Hn?Wmo?6HnMb11MP08@C11H`08@FP0@@0004@000000000";
  1162. data += "00P00001Oab00003OcKP0006@6=PMgl<@440MglH@000000`@000001P00000000";
  1163. data += "Ob@8@@00Ob@8@Ga13R@8Mga172@8?PAo3R@827QoOb@820@0O`0007`0000007P0";
  1164. data += "O`000P08Od400g`<3V=P0G`673IP0`@3>1`00P@6O`P00g`<O`000GP800000000";
  1165. data += "?P9PL020O`<`N3R0@E4HC7b0@ET<ATB0@@l6C4B0O`H3N7b0?P01L3R000000020";
  1166. fontSprite = new olc::Sprite(128, 48);
  1167. int px = 0, py = 0;
  1168. for (int b = 0; b < 1024; b += 4)
  1169. {
  1170. uint32_t sym1 = (uint32_t)data[b + 0] - 48;
  1171. uint32_t sym2 = (uint32_t)data[b + 1] - 48;
  1172. uint32_t sym3 = (uint32_t)data[b + 2] - 48;
  1173. uint32_t sym4 = (uint32_t)data[b + 3] - 48;
  1174. uint32_t r = sym1 << 18 | sym2 << 12 | sym3 << 6 | sym4;
  1175. for (int i = 0; i < 24; i++)
  1176. {
  1177. int k = r & (1 << i) ? 255 : 0;
  1178. fontSprite->SetPixel(px, py, olc::Pixel(k, k, k, k));
  1179. if (++py == 48) { px++; py = 0; }
  1180. }
  1181. }
  1182. }
  1183. #ifdef _WIN32
  1184. HWND PixelGameEngine::olc_WindowCreate()
  1185. {
  1186. WNDCLASS wc;
  1187. wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  1188. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  1189. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  1190. wc.hInstance = GetModuleHandle(nullptr);
  1191. wc.lpfnWndProc = olc_WindowEvent;
  1192. wc.cbClsExtra = 0;
  1193. wc.cbWndExtra = 0;
  1194. wc.lpszMenuName = nullptr;
  1195. wc.hbrBackground = nullptr;
  1196. #ifdef UNICODE
  1197. wc.lpszClassName = L"OLC_PIXEL_GAME_ENGINE";
  1198. #else
  1199. wc.lpszClassName = "OLC_PIXEL_GAME_ENGINE";
  1200. #endif
  1201. RegisterClass(&wc);
  1202. nWindowWidth = (LONG)nScreenWidth * (LONG)nPixelWidth;
  1203. nWindowHeight = (LONG)nScreenHeight * (LONG)nPixelHeight;
  1204. // Define window furniture
  1205. DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
  1206. DWORD dwStyle = WS_CAPTION | WS_SYSMENU | WS_VISIBLE; // | WS_THICKFRAME;
  1207. int nCosmeticOffset = 30;
  1208. nViewW = nWindowWidth;
  1209. nViewH = nWindowHeight;
  1210. // Handle Fullscreen
  1211. if (bFullScreen)
  1212. {
  1213. dwExStyle = 0;
  1214. dwStyle = WS_VISIBLE | WS_POPUP;
  1215. nCosmeticOffset = 0;
  1216. HMONITOR hmon = MonitorFromWindow(olc_hWnd, MONITOR_DEFAULTTONEAREST);
  1217. MONITORINFO mi = { sizeof(mi) };
  1218. if (!GetMonitorInfo(hmon, &mi)) return NULL;
  1219. nWindowWidth = mi.rcMonitor.right;
  1220. nWindowHeight = mi.rcMonitor.bottom;
  1221. }
  1222. olc_UpdateViewport();
  1223. // Keep client size as requested
  1224. RECT rWndRect = { 0, 0, nWindowWidth, nWindowHeight };
  1225. AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle);
  1226. int width = rWndRect.right - rWndRect.left;
  1227. int height = rWndRect.bottom - rWndRect.top;
  1228. #ifdef UNICODE
  1229. olc_hWnd = CreateWindowEx(dwExStyle, L"OLC_PIXEL_GAME_ENGINE", L"", dwStyle,
  1230. nCosmeticOffset, nCosmeticOffset, width, height, NULL, NULL, GetModuleHandle(nullptr), this);
  1231. #else
  1232. olc_hWnd = CreateWindowEx(dwExStyle, "OLC_PIXEL_GAME_ENGINE", "", dwStyle,
  1233. nCosmeticOffset, nCosmeticOffset, width, height, NULL, NULL, GetModuleHandle(nullptr), this);
  1234. #endif
  1235. // Create Keyboard Mapping
  1236. mapKeys[0x00] = Key::NONE;
  1237. mapKeys[0x41] = Key::A; mapKeys[0x42] = Key::B; mapKeys[0x43] = Key::C; mapKeys[0x44] = Key::D; mapKeys[0x45] = Key::E;
  1238. mapKeys[0x46] = Key::F; mapKeys[0x47] = Key::G; mapKeys[0x48] = Key::H; mapKeys[0x49] = Key::I; mapKeys[0x4A] = Key::J;
  1239. mapKeys[0x4B] = Key::K; mapKeys[0x4C] = Key::L; mapKeys[0x4D] = Key::M; mapKeys[0x4E] = Key::N; mapKeys[0x4F] = Key::O;
  1240. mapKeys[0x50] = Key::P; mapKeys[0x51] = Key::Q; mapKeys[0x52] = Key::R; mapKeys[0x53] = Key::S; mapKeys[0x54] = Key::T;
  1241. mapKeys[0x55] = Key::U; mapKeys[0x56] = Key::V; mapKeys[0x57] = Key::W; mapKeys[0x58] = Key::X; mapKeys[0x59] = Key::Y;
  1242. mapKeys[0x5A] = Key::Z;
  1243. mapKeys[VK_F1] = Key::F1; mapKeys[VK_F2] = Key::F2; mapKeys[VK_F3] = Key::F3; mapKeys[VK_F4] = Key::F4;
  1244. mapKeys[VK_F5] = Key::F5; mapKeys[VK_F6] = Key::F6; mapKeys[VK_F7] = Key::F7; mapKeys[VK_F8] = Key::F8;
  1245. mapKeys[VK_F9] = Key::F9; mapKeys[VK_F10] = Key::F10; mapKeys[VK_F11] = Key::F11; mapKeys[VK_F12] = Key::F12;
  1246. mapKeys[VK_DOWN] = Key::DOWN; mapKeys[VK_LEFT] = Key::LEFT; mapKeys[VK_RIGHT] = Key::RIGHT; mapKeys[VK_UP] = Key::UP;
  1247. mapKeys[VK_RETURN] = Key::ENTER; //mapKeys[VK_RETURN] = Key::RETURN;
  1248. mapKeys[VK_BACK] = Key::BACK; mapKeys[VK_ESCAPE] = Key::ESCAPE; mapKeys[VK_RETURN] = Key::ENTER; mapKeys[VK_PAUSE] = Key::PAUSE;
  1249. mapKeys[VK_SCROLL] = Key::SCROLL; mapKeys[VK_TAB] = Key::TAB; mapKeys[VK_DELETE] = Key::DEL; mapKeys[VK_HOME] = Key::HOME;
  1250. mapKeys[VK_END] = Key::END; mapKeys[VK_PRIOR] = Key::PGUP; mapKeys[VK_NEXT] = Key::PGDN; mapKeys[VK_INSERT] = Key::INS;
  1251. mapKeys[VK_SHIFT] = Key::SHIFT; mapKeys[VK_CONTROL] = Key::CTRL;
  1252. mapKeys[VK_SPACE] = Key::SPACE;
  1253. mapKeys[0x30] = Key::K0; mapKeys[0x31] = Key::K1; mapKeys[0x32] = Key::K2; mapKeys[0x33] = Key::K3; mapKeys[0x34] = Key::K4;
  1254. mapKeys[0x35] = Key::K5; mapKeys[0x36] = Key::K6; mapKeys[0x37] = Key::K7; mapKeys[0x38] = Key::K8; mapKeys[0x39] = Key::K9;
  1255. mapKeys[VK_NUMPAD0] = Key::NP0; mapKeys[VK_NUMPAD1] = Key::NP1; mapKeys[VK_NUMPAD2] = Key::NP2; mapKeys[VK_NUMPAD3] = Key::NP3; mapKeys[VK_NUMPAD4] = Key::NP4;
  1256. mapKeys[VK_NUMPAD5] = Key::NP5; mapKeys[VK_NUMPAD6] = Key::NP6; mapKeys[VK_NUMPAD7] = Key::NP7; mapKeys[VK_NUMPAD8] = Key::NP8; mapKeys[VK_NUMPAD9] = Key::NP9;
  1257. mapKeys[VK_MULTIPLY] = Key::NP_MUL; mapKeys[VK_ADD] = Key::NP_ADD; mapKeys[VK_DIVIDE] = Key::NP_DIV; mapKeys[VK_SUBTRACT] = Key::NP_SUB; mapKeys[VK_DECIMAL] = Key::NP_DECIMAL;
  1258. return olc_hWnd;
  1259. }
  1260. bool PixelGameEngine::olc_OpenGLCreate()
  1261. {
  1262. // Create Device Context
  1263. glDeviceContext = GetDC(olc_hWnd);
  1264. PIXELFORMATDESCRIPTOR pfd =
  1265. {
  1266. sizeof(PIXELFORMATDESCRIPTOR), 1,
  1267. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
  1268. PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1269. PFD_MAIN_PLANE, 0, 0, 0, 0
  1270. };
  1271. int pf = 0;
  1272. if (!(pf = ChoosePixelFormat(glDeviceContext, &pfd))) return false;
  1273. SetPixelFormat(glDeviceContext, pf, &pfd);
  1274. if (!(glRenderContext = wglCreateContext(glDeviceContext))) return false;
  1275. wglMakeCurrent(glDeviceContext, glRenderContext);
  1276. glViewport(nViewX, nViewY, nViewW, nViewH);
  1277. // Remove Frame cap
  1278. wglSwapInterval = (wglSwapInterval_t*)wglGetProcAddress("wglSwapIntervalEXT");
  1279. if (wglSwapInterval) wglSwapInterval(0);
  1280. return true;
  1281. }
  1282. // Windows Event Handler
  1283. LRESULT CALLBACK PixelGameEngine::olc_WindowEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1284. {
  1285. static PixelGameEngine *sge;
  1286. switch (uMsg)
  1287. {
  1288. case WM_CREATE: sge = (PixelGameEngine*)((LPCREATESTRUCT)lParam)->lpCreateParams; return 0;
  1289. case WM_MOUSEMOVE:
  1290. {
  1291. uint16_t x = lParam & 0xFFFF; // Thanks @ForAbby (Discord)
  1292. uint16_t y = (lParam >> 16) & 0xFFFF;
  1293. int16_t ix = *(int16_t*)&x;
  1294. int16_t iy = *(int16_t*)&y;
  1295. sge->olc_UpdateMouse(ix, iy);
  1296. return 0;
  1297. }
  1298. case WM_SIZE:
  1299. {
  1300. sge->olc_UpdateWindowSize(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF);
  1301. return 0;
  1302. }
  1303. case WM_MOUSEWHEEL:
  1304. {
  1305. sge->olc_UpdateMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
  1306. return 0;
  1307. }
  1308. case WM_MOUSELEAVE: sge->bHasMouseFocus = false; return 0;
  1309. case WM_SETFOCUS: sge->bHasInputFocus = true; return 0;
  1310. case WM_KILLFOCUS: sge->bHasInputFocus = false; return 0;
  1311. case WM_KEYDOWN: sge->pKeyNewState[mapKeys[wParam]] = true; return 0;
  1312. case WM_KEYUP: sge->pKeyNewState[mapKeys[wParam]] = false; return 0;
  1313. case WM_LBUTTONDOWN:sge->pMouseNewState[0] = true; return 0;
  1314. case WM_LBUTTONUP: sge->pMouseNewState[0] = false; return 0;
  1315. case WM_RBUTTONDOWN:sge->pMouseNewState[1] = true; return 0;
  1316. case WM_RBUTTONUP: sge->pMouseNewState[1] = false; return 0;
  1317. case WM_MBUTTONDOWN:sge->pMouseNewState[2] = true; return 0;
  1318. case WM_MBUTTONUP: sge->pMouseNewState[2] = false; return 0;
  1319. case WM_CLOSE: bAtomActive = false; return 0;
  1320. case WM_DESTROY: PostQuitMessage(0); return 0;
  1321. }
  1322. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  1323. }
  1324. #else
  1325. // Do the Linux stuff!
  1326. Display* PixelGameEngine::olc_WindowCreate()
  1327. {
  1328. XInitThreads();
  1329. // Grab the deafult display and window
  1330. olc_Display = XOpenDisplay(NULL);
  1331. olc_WindowRoot = DefaultRootWindow(olc_Display);
  1332. // Based on the display capabilities, configure the appearance of the window
  1333. GLint olc_GLAttribs[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
  1334. olc_VisualInfo = glXChooseVisual(olc_Display, 0, olc_GLAttribs);
  1335. olc_ColourMap = XCreateColormap(olc_Display, olc_WindowRoot, olc_VisualInfo->visual, AllocNone);
  1336. olc_SetWindowAttribs.colormap = olc_ColourMap;
  1337. // Register which events we are interested in receiving
  1338. olc_SetWindowAttribs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | StructureNotifyMask;
  1339. // Create the window
  1340. olc_Window = XCreateWindow(olc_Display, olc_WindowRoot, 30, 30, nScreenWidth * nPixelWidth, nScreenHeight * nPixelHeight, 0, olc_VisualInfo->depth, InputOutput, olc_VisualInfo->visual, CWColormap | CWEventMask, &olc_SetWindowAttribs);
  1341. Atom wmDelete = XInternAtom(olc_Display, "WM_DELETE_WINDOW", true);
  1342. XSetWMProtocols(olc_Display, olc_Window, &wmDelete, 1);
  1343. XMapWindow(olc_Display, olc_Window);
  1344. XStoreName(olc_Display, olc_Window, "OneLoneCoder.com - Pixel Game Engine");
  1345. if (bFullScreen) // Thanks DragonEye, again :D
  1346. {
  1347. Atom wm_state;
  1348. Atom fullscreen;
  1349. wm_state = XInternAtom(olc_Display, "_NET_WM_STATE", False);
  1350. fullscreen = XInternAtom(olc_Display, "_NET_WM_STATE_FULLSCREEN", False);
  1351. XEvent xev{ 0 };
  1352. xev.type = ClientMessage;
  1353. xev.xclient.window = olc_Window;
  1354. xev.xclient.message_type = wm_state;
  1355. xev.xclient.format = 32;
  1356. xev.xclient.data.l[0] = (bFullScreen ? 1 : 0); // the action (0: off, 1: on, 2: toggle)
  1357. xev.xclient.data.l[1] = fullscreen; // first property to alter
  1358. xev.xclient.data.l[2] = 0; // second property to alter
  1359. xev.xclient.data.l[3] = 0; // source indication
  1360. XMapWindow(olc_Display, olc_Window);
  1361. XSendEvent(olc_Display, DefaultRootWindow(olc_Display), False,
  1362. SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  1363. XFlush(olc_Display);
  1364. XWindowAttributes gwa;
  1365. XGetWindowAttributes(olc_Display, olc_Window, &gwa);
  1366. nWindowWidth = gwa.width;
  1367. nWindowHeight = gwa.height;
  1368. olc_UpdateViewport();
  1369. } else {
  1370. olc_SizeHints.flags = PMaxSize | PMinSize;
  1371. olc_SizeHints.max_width = nScreenWidth * nPixelWidth;
  1372. olc_SizeHints.max_height = nScreenHeight * nPixelHeight;
  1373. olc_SizeHints.min_width = nScreenWidth * nPixelWidth;
  1374. olc_SizeHints.min_height = nScreenHeight * nPixelHeight;
  1375. XSetWMNormalHints(olc_Display, olc_Window, &olc_SizeHints);
  1376. }
  1377. // Create Keyboard Mapping
  1378. mapKeys[0x00] = Key::NONE;
  1379. mapKeys[0x61] = Key::A; mapKeys[0x62] = Key::B; mapKeys[0x63] = Key::C; mapKeys[0x64] = Key::D; mapKeys[0x65] = Key::E;
  1380. mapKeys[0x66] = Key::F; mapKeys[0x67] = Key::G; mapKeys[0x68] = Key::H; mapKeys[0x69] = Key::I; mapKeys[0x6A] = Key::J;
  1381. mapKeys[0x6B] = Key::K; mapKeys[0x6C] = Key::L; mapKeys[0x6D] = Key::M; mapKeys[0x6E] = Key::N; mapKeys[0x6F] = Key::O;
  1382. mapKeys[0x70] = Key::P; mapKeys[0x71] = Key::Q; mapKeys[0x72] = Key::R; mapKeys[0x73] = Key::S; mapKeys[0x74] = Key::T;
  1383. mapKeys[0x75] = Key::U; mapKeys[0x76] = Key::V; mapKeys[0x77] = Key::W; mapKeys[0x78] = Key::X; mapKeys[0x79] = Key::Y;
  1384. mapKeys[0x7A] = Key::Z;
  1385. mapKeys[XK_F1] = Key::F1; mapKeys[XK_F2] = Key::F2; mapKeys[XK_F3] = Key::F3; mapKeys[XK_F4] = Key::F4;
  1386. mapKeys[XK_F5] = Key::F5; mapKeys[XK_F6] = Key::F6; mapKeys[XK_F7] = Key::F7; mapKeys[XK_F8] = Key::F8;
  1387. mapKeys[XK_F9] = Key::F9; mapKeys[XK_F10] = Key::F10; mapKeys[XK_F11] = Key::F11; mapKeys[XK_F12] = Key::F12;
  1388. mapKeys[XK_Down] = Key::DOWN; mapKeys[XK_Left] = Key::LEFT; mapKeys[XK_Right] = Key::RIGHT; mapKeys[XK_Up] = Key::UP;
  1389. mapKeys[XK_KP_Enter] = Key::ENTER; mapKeys[XK_Return] = Key::ENTER;
  1390. mapKeys[XK_BackSpace] = Key::BACK; mapKeys[XK_Escape] = Key::ESCAPE; mapKeys[XK_Linefeed] = Key::ENTER; mapKeys[XK_Pause] = Key::PAUSE;
  1391. mapKeys[XK_Scroll_Lock] = Key::SCROLL; mapKeys[XK_Tab] = Key::TAB; mapKeys[XK_Delete] = Key::DEL; mapKeys[XK_Home] = Key::HOME;
  1392. mapKeys[XK_End] = Key::END; mapKeys[XK_Page_Up] = Key::PGUP; mapKeys[XK_Page_Down] = Key::PGDN; mapKeys[XK_Insert] = Key::INS;
  1393. mapKeys[XK_Shift_L] = Key::SHIFT; mapKeys[XK_Shift_R] = Key::SHIFT; mapKeys[XK_Control_L] = Key::CTRL; mapKeys[XK_Control_R] = Key::CTRL;
  1394. mapKeys[XK_space] = Key::SPACE;
  1395. mapKeys[XK_0] = Key::K0; mapKeys[XK_1] = Key::K1; mapKeys[XK_2] = Key::K2; mapKeys[XK_3] = Key::K3; mapKeys[XK_4] = Key::K4;
  1396. mapKeys[XK_5] = Key::K5; mapKeys[XK_6] = Key::K6; mapKeys[XK_7] = Key::K7; mapKeys[XK_8] = Key::K8; mapKeys[XK_9] = Key::K9;
  1397. mapKeys[XK_KP_0] = Key::NP0; mapKeys[XK_KP_1] = Key::NP1; mapKeys[XK_KP_2] = Key::NP2; mapKeys[XK_KP_3] = Key::NP3; mapKeys[XK_KP_4] = Key::NP4;
  1398. mapKeys[XK_KP_5] = Key::NP5; mapKeys[XK_KP_6] = Key::NP6; mapKeys[XK_KP_7] = Key::NP7; mapKeys[XK_KP_8] = Key::NP8; mapKeys[XK_KP_9] = Key::NP9;
  1399. mapKeys[XK_KP_Multiply] = Key::NP_MUL; mapKeys[XK_KP_Add] = Key::NP_ADD; mapKeys[XK_KP_Divide] = Key::NP_DIV; mapKeys[XK_KP_Subtract] = Key::NP_SUB; mapKeys[XK_KP_Decimal] = Key::NP_DECIMAL;
  1400. return olc_Display;
  1401. }
  1402. bool PixelGameEngine::olc_OpenGLCreate()
  1403. {
  1404. glDeviceContext = glXCreateContext(olc_Display, olc_VisualInfo, nullptr, GL_TRUE);
  1405. glXMakeCurrent(olc_Display, olc_Window, glDeviceContext);
  1406. XWindowAttributes gwa;
  1407. XGetWindowAttributes(olc_Display, olc_Window, &gwa);
  1408. glViewport(0, 0, gwa.width, gwa.height);
  1409. glSwapIntervalEXT = nullptr;
  1410. glSwapIntervalEXT = (glSwapInterval_t*)glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT");
  1411. if (glSwapIntervalEXT)
  1412. glSwapIntervalEXT(olc_Display, olc_Window, 0);
  1413. else
  1414. {
  1415. printf("NOTE: Could not disable VSYNC, glXSwapIntervalEXT() was not found!\n");
  1416. printf(" Don't worry though, things will still work, it's just the\n");
  1417. printf(" frame rate will be capped to your monitors refresh rate - javidx9\n");
  1418. }
  1419. return true;
  1420. }
  1421. #endif
  1422. // Need a couple of statics as these are singleton instances
  1423. // read from multiple locations
  1424. std::atomic<bool> PixelGameEngine::bAtomActive{ false };
  1425. std::map<uint16_t, uint8_t> PixelGameEngine::mapKeys;
  1426. olc::PixelGameEngine* olc::PGEX::pge = nullptr;
  1427. #ifdef OLC_DBG_OVERDRAW
  1428. int olc::Sprite::nOverdrawCount = 0;
  1429. #endif
  1430. //=============================================================
  1431. }