12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652 |
- #include "olcPixelGameEngine.h"
-
- #ifdef _WIN32
- static wglSwapInterval_t *wglSwapInterval;
- #else
- static glSwapInterval_t *glSwapIntervalEXT;
- #endif
-
- namespace olc
- {
- Pixel::Pixel()
- {
- r = 0; g = 0; b = 0; a = 255;
- }
-
- Pixel::Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
- {
- r = red; g = green; b = blue; a = alpha;
- }
-
- Pixel::Pixel(uint32_t p)
- {
- n = p;
- }
-
- Pixel Pixel::CreateFromHSV(uint8_t h, uint8_t s, uint8_t v, uint8_t alpha) {
- Pixel rgb;
- rgb.a = alpha;
- uint8_t region, remainder, p, q, t;
-
- if (s == 0)
- {
- rgb.r = v;
- rgb.g = v;
- rgb.b = v;
- return rgb;
- }
-
- region = h / 43;
- remainder = (h - (region * 43)) * 6;
-
- p = (v * (255 - s)) >> 8;
- q = (v * (255 - ((s * remainder) >> 8))) >> 8;
- t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
-
- switch (region)
- {
- case 0:
- rgb.r = v; rgb.g = t; rgb.b = p;
- break;
- case 1:
- rgb.r = q; rgb.g = v; rgb.b = p;
- break;
- case 2:
- rgb.r = p; rgb.g = v; rgb.b = t;
- break;
- case 3:
- rgb.r = p; rgb.g = q; rgb.b = v;
- break;
- case 4:
- rgb.r = t; rgb.g = p; rgb.b = v;
- break;
- default:
- rgb.r = v; rgb.g = p; rgb.b = q;
- break;
- }
-
- return rgb;
- }
-
- //==========================================================
-
- std::wstring ConvertS2W(std::string s)
- {
- #ifdef _WIN32
- int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0);
- wchar_t* buffer = new wchar_t[count];
- MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count);
- std::wstring w(buffer);
- delete[] buffer;
- return w;
- #else
- return L"SVN FTW!";
- #endif
- }
-
- Sprite::Sprite()
- {
- pColData = nullptr;
- width = 0;
- height = 0;
- }
-
- Sprite::Sprite(std::string sImageFile)
- {
- LoadFromFile(sImageFile);
- }
-
- Sprite::Sprite(std::string sImageFile, olc::ResourcePack *pack)
- {
- LoadFromPGESprFile(sImageFile, pack);
- }
-
- Sprite::Sprite(int32_t w, int32_t h)
- {
- if(pColData) delete[] pColData;
- width = w; height = h;
- pColData = new Pixel[width * height];
- for (int32_t i = 0; i < width*height; i++)
- pColData[i] = Pixel();
- }
-
- Sprite::~Sprite()
- {
- if (pColData) delete pColData;
- }
-
- olc::rcode Sprite::LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack)
- {
- if (pColData) delete[] pColData;
-
- auto ReadData = [&](std::istream &is)
- {
- is.read((char*)&width, sizeof(int32_t));
- is.read((char*)&height, sizeof(int32_t));
- pColData = new Pixel[width * height];
- is.read((char*)pColData, width * height * sizeof(uint32_t));
- };
-
- // These are essentially Memory Surfaces represented by olc::Sprite
- // which load very fast, but are completely uncompressed
- if (pack == nullptr)
- {
- std::ifstream ifs;
- ifs.open(sImageFile, std::ifstream::binary);
- if (ifs.is_open())
- {
- ReadData(ifs);
- return olc::OK;
- }
- else
- return olc::FAIL;
- }
- else
- {
- auto streamBuffer = pack->GetStreamBuffer(sImageFile);
- std::istream is(&streamBuffer);
- ReadData(is);
- }
-
-
- return olc::FAIL;
- }
-
- olc::rcode Sprite::SaveToPGESprFile(std::string sImageFile)
- {
- if (pColData == nullptr) return olc::FAIL;
-
- std::ofstream ofs;
- ofs.open(sImageFile, std::ifstream::binary);
- if (ofs.is_open())
- {
- ofs.write((char*)&width, sizeof(int32_t));
- ofs.write((char*)&height, sizeof(int32_t));
- ofs.write((char*)pColData, width*height*sizeof(uint32_t));
- ofs.close();
- return olc::OK;
- }
-
- return olc::FAIL;
- }
-
- olc::rcode Sprite::LoadFromFile(std::string sImageFile, olc::ResourcePack *pack)
- {
- #ifdef _WIN32
- // Use GDI+
- std::wstring wsImageFile;
- #ifdef __MINGW32__
- wchar_t *buffer = new wchar_t[sImageFile.length() + 1];
- mbstowcs(buffer, sImageFile.c_str(), sImageFile.length());
- buffer[sImageFile.length()] = L'\0';
- wsImageFile = buffer;
- delete [] buffer;
- #else
- wsImageFile = ConvertS2W(sImageFile);
- #endif
- Gdiplus::Bitmap *bmp = Gdiplus::Bitmap::FromFile(wsImageFile.c_str());
- if (bmp == nullptr)
- return olc::NO_FILE;
-
- width = bmp->GetWidth();
- height = bmp->GetHeight();
- pColData = new Pixel[width * height];
-
- for(int x=0; x<width; x++)
- for (int y = 0; y < height; y++)
- {
- Gdiplus::Color c;
- bmp->GetPixel(x, y, &c);
- SetPixel(x, y, Pixel(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha()));
- }
- delete bmp;
- return olc::OK;
- #else
- ////////////////////////////////////////////////////////////////////////////
- // Use libpng, Thanks to Guillaume Cottenceau
- // https://gist.github.com/niw/5963798
- png_structp png;
- png_infop info;
-
- FILE *f = fopen(sImageFile.c_str(), "rb");
- if (!f) return olc::NO_FILE;
-
- png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (!png) goto fail_load;
-
- info = png_create_info_struct(png);
- if (!info) goto fail_load;
-
- if (setjmp(png_jmpbuf(png))) goto fail_load;
-
- png_init_io(png, f);
- png_read_info(png, info);
-
- png_byte color_type;
- png_byte bit_depth;
- png_bytep *row_pointers;
- width = png_get_image_width(png, info);
- height = png_get_image_height(png, info);
- color_type = png_get_color_type(png, info);
- bit_depth = png_get_bit_depth(png, info);
-
- #ifdef _DEBUG
- std::cout << "Loading PNG: " << sImageFile << "\n";
- std::cout << "W:" << width << " H:" << height << " D:" << (int)bit_depth << "\n";
- #endif
-
- if (bit_depth == 16) png_set_strip_16(png);
- if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
- if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png);
- if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png);
- if (color_type == PNG_COLOR_TYPE_RGB ||
- color_type == PNG_COLOR_TYPE_GRAY ||
- color_type == PNG_COLOR_TYPE_PALETTE)
- png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
- if (color_type == PNG_COLOR_TYPE_GRAY ||
- color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
- png_set_gray_to_rgb(png);
-
- png_read_update_info(png, info);
- row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
- for (int y = 0; y < height; y++) {
- row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info));
- }
- png_read_image(png, row_pointers);
- ////////////////////////////////////////////////////////////////////////////
-
- // Create sprite array
- pColData = new Pixel[width * height];
-
- // Iterate through image rows, converting into sprite format
- for (int y = 0; y < height; y++)
- {
- png_bytep row = row_pointers[y];
- for (int x = 0; x < width; x++)
- {
- png_bytep px = &(row[x * 4]);
- SetPixel(x, y, Pixel(px[0], px[1], px[2], px[3]));
- }
- }
-
- fclose(f);
- return olc::OK;
-
- fail_load:
- width = 0;
- height = 0;
- fclose(f);
- pColData = nullptr;
- return olc::FAIL;
- #endif
- }
-
- void Sprite::SetSampleMode(olc::Sprite::Mode mode)
- {
- modeSample = mode;
- }
-
-
- Pixel Sprite::GetPixel(int32_t x, int32_t y)
- {
- if (modeSample == olc::Sprite::Mode::NORMAL)
- {
- if (x >= 0 && x < width && y >= 0 && y < height)
- return pColData[y*width + x];
- else
- return Pixel(0, 0, 0, 0);
- }
- else
- {
- return pColData[abs(y%height)*width + abs(x%width)];
- }
- }
-
- bool Sprite::SetPixel(int32_t x, int32_t y, Pixel p)
- {
-
- #ifdef OLC_DBG_OVERDRAW
- nOverdrawCount++;
- #endif
-
- if (x >= 0 && x < width && y >= 0 && y < height)
- {
- pColData[y*width + x] = p;
- return true;
- }
- else
- return false;
- }
-
- Pixel Sprite::Sample(float x, float y)
- {
- int32_t sx = std::min((int32_t)((x * (float)width)), width - 1);
- int32_t sy = std::min((int32_t)((y * (float)height)), height - 1);
- return GetPixel(sx, sy);
- }
-
- Pixel Sprite::SampleBL(float u, float v)
- {
- u = u * width - 0.5f;
- v = v * height - 0.5f;
- int x = (int)floor(u); // cast to int rounds toward zero, not downward
- int y = (int)floor(v); // Thanks @joshinils
- float u_ratio = u - x;
- float v_ratio = v - y;
- float u_opposite = 1 - u_ratio;
- float v_opposite = 1 - v_ratio;
-
- olc::Pixel p1 = GetPixel(std::max(x, 0), std::max(y, 0));
- olc::Pixel p2 = GetPixel(std::min(x + 1, (int)width - 1), std::max(y, 0));
- olc::Pixel p3 = GetPixel(std::max(x, 0), std::min(y + 1, (int)height - 1));
- olc::Pixel p4 = GetPixel(std::min(x + 1, (int)width - 1), std::min(y + 1, (int)height - 1));
-
- return olc::Pixel(
- (uint8_t)((p1.r * u_opposite + p2.r * u_ratio) * v_opposite + (p3.r * u_opposite + p4.r * u_ratio) * v_ratio),
- (uint8_t)((p1.g * u_opposite + p2.g * u_ratio) * v_opposite + (p3.g * u_opposite + p4.g * u_ratio) * v_ratio),
- (uint8_t)((p1.b * u_opposite + p2.b * u_ratio) * v_opposite + (p3.b * u_opposite + p4.b * u_ratio) * v_ratio));
- }
-
- Pixel* Sprite::GetData() { return pColData; }
-
- //==========================================================
-
- PixelGameEngine::PixelGameEngine()
- {
- sAppName = "Undefined";
- olc::PGEX::pge = this;
- }
-
- olc::rcode PixelGameEngine::Construct(uint32_t screen_w, uint32_t screen_h, uint32_t pixel_w, uint32_t pixel_h, bool full_screen)
- {
- nScreenWidth = screen_w;
- nScreenHeight = screen_h;
- nPixelWidth = pixel_w;
- nPixelHeight = pixel_h;
- bFullScreen = full_screen;
-
- fPixelX = 2.0f / (float)(nScreenWidth);
- fPixelY = 2.0f / (float)(nScreenHeight);
-
- if (nPixelWidth == 0 || nPixelHeight == 0 || nScreenWidth == 0 || nScreenHeight == 0)
- return olc::FAIL;
-
- #ifdef _WIN32
- #ifdef UNICODE
- #ifndef __MINGW32__
- wsAppName = ConvertS2W(sAppName);
- #endif
- #endif
- #endif
- // Load the default font sheet
- olc_ConstructFontSheet();
-
- // Create a sprite that represents the primary drawing target
- pDefaultDrawTarget = new Sprite(nScreenWidth, nScreenHeight);
- SetDrawTarget(nullptr);
- return olc::OK;
- }
-
- olc::rcode PixelGameEngine::ConstructAuto(uint32_t screen_w, uint32_t screen_h, bool fullscreen)
- {
- uint32_t pixelSize = olc_GetMaximumPixelSize(screen_w, screen_h);
- return Construct(screen_w, screen_h, pixelSize, pixelSize, fullscreen);
- }
-
- olc::rcode PixelGameEngine::Start()
- {
- // Construct the window
- if (!olc_WindowCreate())
- return olc::FAIL;
-
- // Load libraries required for PNG file interaction
- //#ifdef _WIN32
- // // Windows use GDI+
- // Gdiplus::GdiplusStartupInput startupInput;
- // ULONG_PTR token;
- // Gdiplus::GdiplusStartup(&token, &startupInput, NULL);
- //#else
- // // Linux use libpng
- //
- //#endif
- // Start the thread
- bAtomActive = true;
- std::thread t = std::thread(&PixelGameEngine::EngineThread, this);
-
- #ifdef _WIN32
- // Handle Windows Message Loop
- MSG msg;
- while (GetMessage(&msg, NULL, 0, 0) > 0)
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- #endif
-
- // Wait for thread to be exited
- t.join();
- return olc::OK;
- }
-
- void PixelGameEngine::SetDrawTarget(Sprite *target)
- {
- if (target)
- pDrawTarget = target;
- else
- pDrawTarget = pDefaultDrawTarget;
- }
-
- Sprite* PixelGameEngine::GetDrawTarget()
- {
- return pDrawTarget;
- }
-
- int32_t PixelGameEngine::GetDrawTargetWidth()
- {
- if (pDrawTarget)
- return pDrawTarget->width;
- else
- return 0;
- }
-
- int32_t PixelGameEngine::GetDrawTargetHeight()
- {
- if (pDrawTarget)
- return pDrawTarget->height;
- else
- return 0;
- }
-
- bool PixelGameEngine::IsFocused()
- {
- return bHasInputFocus;
- }
-
- HWButton PixelGameEngine::GetKey(Key k)
- {
- return pKeyboardState[k];
- }
-
- HWButton PixelGameEngine::GetMouse(uint32_t b)
- {
- return pMouseState[b];
- }
-
- int32_t PixelGameEngine::GetMouseX()
- {
- return nMousePosX;
- }
-
- int32_t PixelGameEngine::GetMouseY()
- {
- return nMousePosY;
- }
-
- int32_t PixelGameEngine::GetMouseWheel()
- {
- return nMouseWheelDelta;
- }
-
- int32_t PixelGameEngine::ScreenWidth()
- {
- return nScreenWidth;
- }
-
- int32_t PixelGameEngine::ScreenHeight()
- {
- return nScreenHeight;
- }
-
- bool PixelGameEngine::Draw(int32_t x, int32_t y, Pixel p)
- {
- if (!pDrawTarget) return false;
-
-
- if (nPixelMode == Pixel::NORMAL)
- {
- return pDrawTarget->SetPixel(x, y, p);
- }
-
- if (nPixelMode == Pixel::MASK)
- {
- if(p.a == 255)
- return pDrawTarget->SetPixel(x, y, p);
- }
-
- if (nPixelMode == Pixel::ALPHA)
- {
- Pixel d = pDrawTarget->GetPixel(x, y);
- float a = (float)(p.a / 255.0f) * fBlendFactor;
- float c = 1.0f - a;
- float r = a * (float)p.r + c * (float)d.r;
- float g = a * (float)p.g + c * (float)d.g;
- float b = a * (float)p.b + c * (float)d.b;
- return pDrawTarget->SetPixel(x, y, Pixel((uint8_t)r, (uint8_t)g, (uint8_t)b));
- }
-
- if (nPixelMode == Pixel::CUSTOM)
- {
- return pDrawTarget->SetPixel(x, y, funcPixelMode(x, y, p, pDrawTarget->GetPixel(x, y)));
- }
-
- return false;
- }
-
- void PixelGameEngine::SetSubPixelOffset(float ox, float oy)
- {
- fSubPixelOffsetX = ox * fPixelX;
- fSubPixelOffsetY = oy * fPixelY;
- }
-
- void PixelGameEngine::DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p, uint32_t pattern)
- {
- int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i;
- dx = x2 - x1; dy = y2 - y1;
-
- auto rol = [&](void)
- {
- pattern = (pattern << 1) | (pattern >> 31);
- return pattern & 1;
- };
-
- // straight lines idea by gurkanctn
- if (dx == 0) // Line is vertical
- {
- if (y2 < y1) std::swap(y1, y2);
- for (y = y1; y <= y2; y++)
- if (rol()) Draw(x1, y, p);
- return;
- }
-
- if (dy == 0) // Line is horizontal
- {
- if (x2 < x1) std::swap(x1, x2);
- for (x = x1; x <= x2; x++)
- if (rol()) Draw(x, y1, p);
- return;
- }
-
- // Line is Funk-aye
- dx1 = abs(dx); dy1 = abs(dy);
- px = 2 * dy1 - dx1; py = 2 * dx1 - dy1;
- if (dy1 <= dx1)
- {
- if (dx >= 0)
- {
- x = x1; y = y1; xe = x2;
- }
- else
- {
- x = x2; y = y2; xe = x1;
- }
-
- if (rol()) Draw(x, y, p);
-
- for (i = 0; x<xe; i++)
- {
- x = x + 1;
- if (px<0)
- px = px + 2 * dy1;
- else
- {
- if ((dx<0 && dy<0) || (dx>0 && dy>0)) y = y + 1; else y = y - 1;
- px = px + 2 * (dy1 - dx1);
- }
- if (rol()) Draw(x, y, p);
- }
- }
- else
- {
- if (dy >= 0)
- {
- x = x1; y = y1; ye = y2;
- }
- else
- {
- x = x2; y = y2; ye = y1;
- }
-
- if (rol()) Draw(x, y, p);
-
- for (i = 0; y<ye; i++)
- {
- y = y + 1;
- if (py <= 0)
- py = py + 2 * dx1;
- else
- {
- if ((dx<0 && dy<0) || (dx>0 && dy>0)) x = x + 1; else x = x - 1;
- py = py + 2 * (dx1 - dy1);
- }
- if (rol()) Draw(x, y, p);
- }
- }
- }
-
- void PixelGameEngine::DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p, uint8_t mask)
- {
- int x0 = 0;
- int y0 = radius;
- int d = 3 - 2 * radius;
- if (!radius) return;
-
- while (y0 >= x0) // only formulate 1/8 of circle
- {
- if (mask & 0x01) Draw(x + x0, y - y0, p);
- if (mask & 0x02) Draw(x + y0, y - x0, p);
- if (mask & 0x04) Draw(x + y0, y + x0, p);
- if (mask & 0x08) Draw(x + x0, y + y0, p);
- if (mask & 0x10) Draw(x - x0, y + y0, p);
- if (mask & 0x20) Draw(x - y0, y + x0, p);
- if (mask & 0x40) Draw(x - y0, y - x0, p);
- if (mask & 0x80) Draw(x - x0, y - y0, p);
- if (d < 0) d += 4 * x0++ + 6;
- else d += 4 * (x0++ - y0--) + 10;
- }
- }
-
- void PixelGameEngine::FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p)
- {
- // Taken from wikipedia
- int x0 = 0;
- int y0 = radius;
- int d = 3 - 2 * radius;
- if (!radius) return;
-
- auto drawline = [&](int sx, int ex, int ny)
- {
- for (int i = sx; i <= ex; i++)
- Draw(i, ny, p);
- };
-
- while (y0 >= x0)
- {
- // Modified to draw scan-lines instead of edges
- drawline(x - x0, x + x0, y - y0);
- drawline(x - y0, x + y0, y - x0);
- drawline(x - x0, x + x0, y + y0);
- drawline(x - y0, x + y0, y + x0);
- if (d < 0) d += 4 * x0++ + 6;
- else d += 4 * (x0++ - y0--) + 10;
- }
- }
-
- void PixelGameEngine::DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p)
- {
- DrawLine(x, y, x+w, y, p);
- DrawLine(x+w, y, x+w, y+h, p);
- DrawLine(x+w, y+h, x, y+h, p);
- DrawLine(x, y+h, x, y, p);
- }
-
- void PixelGameEngine::Clear(Pixel p)
- {
- int pixels = GetDrawTargetWidth() * GetDrawTargetHeight();
- Pixel* m = GetDrawTarget()->GetData();
- for (int i = 0; i < pixels; i++)
- m[i] = p;
- #ifdef OLC_DBG_OVERDRAW
- olc::Sprite::nOverdrawCount += pixels;
- #endif
- }
-
- void PixelGameEngine::FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p)
- {
- int32_t x2 = x + w;
- int32_t y2 = y + h;
-
- if (x < 0) x = 0;
- if (x >= (int32_t)nScreenWidth) x = (int32_t)nScreenWidth;
- if (y < 0) y = 0;
- if (y >= (int32_t)nScreenHeight) y = (int32_t)nScreenHeight;
-
- if (x2 < 0) x2 = 0;
- if (x2 >= (int32_t)nScreenWidth) x2 = (int32_t)nScreenWidth;
- if (y2 < 0) y2 = 0;
- if (y2 >= (int32_t)nScreenHeight) y2 = (int32_t)nScreenHeight;
-
- for (int i = x; i < x2; i++)
- for (int j = y; j < y2; j++)
- Draw(i, j, p);
- }
-
- void PixelGameEngine::DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p)
- {
- DrawLine(x1, y1, x2, y2, p);
- DrawLine(x2, y2, x3, y3, p);
- DrawLine(x3, y3, x1, y1, p);
- }
-
- // https://www.avrfreaks.net/sites/default/files/triangles.c
- void PixelGameEngine::FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p)
- {
- auto SWAP = [](int &x, int &y) { int t = x; x = y; y = t; };
- auto drawline = [&](int sx, int ex, int ny) { for (int i = sx; i <= ex; i++) Draw(i, ny, p); };
-
- int t1x, t2x, y, minx, maxx, t1xp, t2xp;
- bool changed1 = false;
- bool changed2 = false;
- int signx1, signx2, dx1, dy1, dx2, dy2;
- int e1, e2;
- // Sort vertices
- if (y1>y2) { SWAP(y1, y2); SWAP(x1, x2); }
- if (y1>y3) { SWAP(y1, y3); SWAP(x1, x3); }
- if (y2>y3) { SWAP(y2, y3); SWAP(x2, x3); }
-
- t1x = t2x = x1; y = y1; // Starting points
- dx1 = (int)(x2 - x1); if (dx1<0) { dx1 = -dx1; signx1 = -1; }
- else signx1 = 1;
- dy1 = (int)(y2 - y1);
-
- dx2 = (int)(x3 - x1); if (dx2<0) { dx2 = -dx2; signx2 = -1; }
- else signx2 = 1;
- dy2 = (int)(y3 - y1);
-
- if (dy1 > dx1) { // swap values
- SWAP(dx1, dy1);
- changed1 = true;
- }
- if (dy2 > dx2) { // swap values
- SWAP(dy2, dx2);
- changed2 = true;
- }
-
- e2 = (int)(dx2 >> 1);
- // Flat top, just process the second half
- if (y1 == y2) goto next;
- e1 = (int)(dx1 >> 1);
-
- for (int i = 0; i < dx1;) {
- t1xp = 0; t2xp = 0;
- if (t1x<t2x) { minx = t1x; maxx = t2x; }
- else { minx = t2x; maxx = t1x; }
- // process first line until y value is about to change
- while (i<dx1) {
- i++;
- e1 += dy1;
- while (e1 >= dx1) {
- e1 -= dx1;
- if (changed1) t1xp = signx1;//t1x += signx1;
- else goto next1;
- }
- if (changed1) break;
- else t1x += signx1;
- }
- // Move line
- next1:
- // process second line until y value is about to change
- while (1) {
- e2 += dy2;
- while (e2 >= dx2) {
- e2 -= dx2;
- if (changed2) t2xp = signx2;//t2x += signx2;
- else goto next2;
- }
- if (changed2) break;
- else t2x += signx2;
- }
- next2:
- if (minx>t1x) minx = t1x; if (minx>t2x) minx = t2x;
- if (maxx<t1x) maxx = t1x; if (maxx<t2x) maxx = t2x;
- drawline(minx, maxx, y); // Draw line from min to max points found on the y
- // Now increase y
- if (!changed1) t1x += signx1;
- t1x += t1xp;
- if (!changed2) t2x += signx2;
- t2x += t2xp;
- y += 1;
- if (y == y2) break;
-
- }
- next:
- // Second half
- dx1 = (int)(x3 - x2); if (dx1<0) { dx1 = -dx1; signx1 = -1; }
- else signx1 = 1;
- dy1 = (int)(y3 - y2);
- t1x = x2;
-
- if (dy1 > dx1) { // swap values
- SWAP(dy1, dx1);
- changed1 = true;
- }
- else changed1 = false;
-
- e1 = (int)(dx1 >> 1);
-
- for (int i = 0; i <= dx1; i++) {
- t1xp = 0; t2xp = 0;
- if (t1x<t2x) { minx = t1x; maxx = t2x; }
- else { minx = t2x; maxx = t1x; }
- // process first line until y value is about to change
- while (i<dx1) {
- e1 += dy1;
- while (e1 >= dx1) {
- e1 -= dx1;
- if (changed1) { t1xp = signx1; break; }//t1x += signx1;
- else goto next3;
- }
- if (changed1) break;
- else t1x += signx1;
- if (i<dx1) i++;
- }
- next3:
- // process second line until y value is about to change
- while (t2x != x3) {
- e2 += dy2;
- while (e2 >= dx2) {
- e2 -= dx2;
- if (changed2) t2xp = signx2;
- else goto next4;
- }
- if (changed2) break;
- else t2x += signx2;
- }
- next4:
-
- if (minx>t1x) minx = t1x; if (minx>t2x) minx = t2x;
- if (maxx<t1x) maxx = t1x; if (maxx<t2x) maxx = t2x;
- drawline(minx, maxx, y);
- if (!changed1) t1x += signx1;
- t1x += t1xp;
- if (!changed2) t2x += signx2;
- t2x += t2xp;
- y += 1;
- if (y>y3) return;
- }
- }
-
- void PixelGameEngine::DrawSprite(int32_t x, int32_t y, Sprite *sprite, uint32_t scale)
- {
- if (sprite == nullptr)
- return;
-
- if (scale > 1)
- {
- for (int32_t i = 0; i < sprite->width; i++)
- for (int32_t j = 0; j < sprite->height; j++)
- for (uint32_t is = 0; is < scale; is++)
- for (uint32_t js = 0; js < scale; js++)
- Draw(x + (i*scale) + is, y + (j*scale) + js, sprite->GetPixel(i, j));
- }
- else
- {
- for (int32_t i = 0; i < sprite->width; i++)
- for (int32_t j = 0; j < sprite->height; j++)
- Draw(x + i, y + j, sprite->GetPixel(i, j));
- }
- }
-
- 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)
- {
- if (sprite == nullptr)
- return;
-
- if (scale > 1)
- {
- for (int32_t i = 0; i < w; i++)
- for (int32_t j = 0; j < h; j++)
- for (uint32_t is = 0; is < scale; is++)
- for (uint32_t js = 0; js < scale; js++)
- Draw(x + (i*scale) + is, y + (j*scale) + js, sprite->GetPixel(i + ox, j + oy));
- }
- else
- {
- for (int32_t i = 0; i < w; i++)
- for (int32_t j = 0; j < h; j++)
- Draw(x + i, y + j, sprite->GetPixel(i + ox, j + oy));
- }
- }
-
- void PixelGameEngine::DrawString(int32_t x, int32_t y, std::string sText, Pixel col, uint32_t scale)
- {
- int32_t sx = 0;
- int32_t sy = 0;
- Pixel::Mode m = nPixelMode;
- if(col.ALPHA != 255) SetPixelMode(Pixel::ALPHA);
- else SetPixelMode(Pixel::MASK);
- for (auto c : sText)
- {
- if (c == '\n')
- {
- sx = 0; sy += 8 * scale;
- }
- else
- {
- int32_t ox = (c - 32) % 16;
- int32_t oy = (c - 32) / 16;
-
- if (scale > 1)
- {
- for (uint32_t i = 0; i < 8; i++)
- for (uint32_t j = 0; j < 8; j++)
- if (fontSprite->GetPixel(i + ox * 8, j + oy * 8).r > 0)
- for (uint32_t is = 0; is < scale; is++)
- for (uint32_t js = 0; js < scale; js++)
- Draw(x + sx + (i*scale) + is, y + sy + (j*scale) + js, col);
- }
- else
- {
- for (uint32_t i = 0; i < 8; i++)
- for (uint32_t j = 0; j < 8; j++)
- if (fontSprite->GetPixel(i + ox * 8, j + oy * 8).r > 0)
- Draw(x + sx + i, y + sy + j, col);
- }
- sx += 8 * scale;
- }
- }
- SetPixelMode(m);
- }
-
- void PixelGameEngine::SetPixelMode(Pixel::Mode m)
- {
- nPixelMode = m;
- }
-
- Pixel::Mode PixelGameEngine::GetPixelMode()
- {
- return nPixelMode;
- }
-
- void PixelGameEngine::SetPixelMode(std::function<olc::Pixel(const int x, const int y, const olc::Pixel&, const olc::Pixel&)> pixelMode)
- {
- funcPixelMode = pixelMode;
- nPixelMode = Pixel::Mode::CUSTOM;
- }
-
- void PixelGameEngine::SetPixelBlend(float fBlend)
- {
- fBlendFactor = fBlend;
- if (fBlendFactor < 0.0f) fBlendFactor = 0.0f;
- if (fBlendFactor > 1.0f) fBlendFactor = 1.0f;
- }
-
- // User must override these functions as required. I have not made
- // them abstract because I do need a default behaviour to occur if
- // they are not overwritten
- bool PixelGameEngine::OnUserCreate()
- { return false; }
- bool PixelGameEngine::OnUserUpdate(float fElapsedTime)
- { return false; }
- bool PixelGameEngine::OnUserDestroy()
- { return true; }
- //////////////////////////////////////////////////////////////////
-
- void PixelGameEngine::olc_UpdateViewport()
- {
- int32_t ww = nScreenWidth * nPixelWidth;
- int32_t wh = nScreenHeight * nPixelHeight;
- float wasp = (float)ww / (float)wh;
-
- nViewW = (int32_t)nWindowWidth;
- nViewH = (int32_t)((float)nViewW / wasp);
-
- if (nViewH > nWindowHeight)
- {
- nViewH = nWindowHeight;
- nViewW = (int32_t)((float)nViewH * wasp);
- }
-
- nViewX = (nWindowWidth - nViewW) / 2;
- nViewY = (nWindowHeight - nViewH) / 2;
- }
-
- void PixelGameEngine::olc_UpdateWindowSize(int32_t x, int32_t y)
- {
- nWindowWidth = x;
- nWindowHeight = y;
- olc_UpdateViewport();
-
- }
-
- void PixelGameEngine::olc_UpdateMouseWheel(int32_t delta)
- {
- nMouseWheelDeltaCache += delta;
- }
-
- void PixelGameEngine::olc_UpdateMouse(int32_t x, int32_t y)
- {
- // Mouse coords come in screen space
- // But leave in pixel space
-
- //if (bFullScreen)
- {
- // Full Screen mode may have a weird viewport we must clamp to
- x -= nViewX;
- y -= nViewY;
- }
-
- nMousePosXcache = (int32_t)(((float)x / (float)(nWindowWidth - (nViewX * 2)) * (float)nScreenWidth));
- nMousePosYcache = (int32_t)(((float)y / (float)(nWindowHeight - (nViewY * 2)) * (float)nScreenHeight));
-
- if (nMousePosXcache >= (int32_t)nScreenWidth)
- nMousePosXcache = nScreenWidth - 1;
- if (nMousePosYcache >= (int32_t)nScreenHeight)
- nMousePosYcache = nScreenHeight - 1;
-
- if (nMousePosXcache < 0)
- nMousePosXcache = 0;
- if (nMousePosYcache < 0)
- nMousePosYcache = 0;
- }
-
- uint32_t PixelGameEngine::olc_GetMaximumPixelSize(uint32_t width, uint32_t height)
- {
- #ifdef _WIN32
- return 1; // TODO
- #else
- Display* d = XOpenDisplay(NULL);
- int defaultScreen = DefaultScreen(d);
- Screen *s = ScreenOfDisplay(d, defaultScreen);
- int minWidth = WidthOfScreen(s);
- int minHeight = HeightOfScreen(s);
- int screensCount = ScreenCount(d);
- for (int i=0; i < screensCount; i++) {
- s = ScreenOfDisplay(d, i);
- if (WidthOfScreen(s) < minWidth) {
- minWidth = WidthOfScreen(s);
- }
- if (HeightOfScreen(s) < minHeight) {
- minHeight = HeightOfScreen(s);
- }
- }
-
- uint32_t pixelWidth = minWidth / width;
- uint32_t pixelHeight = minHeight / height;
-
- return std::min(pixelWidth, pixelHeight);
- #endif
- }
-
- void PixelGameEngine::EngineThread()
- {
- // Start OpenGL, the context is owned by the game thread
- olc_OpenGLCreate();
-
- // Create Screen Texture - disable filtering
- glEnable(GL_TEXTURE_2D);
- glGenTextures(1, &glBuffer);
- glBindTexture(GL_TEXTURE_2D, glBuffer);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nScreenWidth, nScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pDefaultDrawTarget->GetData());
-
-
- // Create user resources as part of this thread
- if (!OnUserCreate())
- bAtomActive = false;
-
- auto tp1 = std::chrono::system_clock::now();
- auto tp2 = std::chrono::system_clock::now();
-
- while (bAtomActive)
- {
- // Run as fast as possible
- while (bAtomActive)
- {
- // Handle Timing
- tp2 = std::chrono::system_clock::now();
- std::chrono::duration<float> elapsedTime = tp2 - tp1;
- tp1 = tp2;
-
- // Our time per frame coefficient
- float fElapsedTime = elapsedTime.count();
-
- #ifndef _WIN32
- // Handle Xlib Message Loop - we do this in the
- // same thread that OpenGL was created so we dont
- // need to worry too much about multithreading with X11
- XEvent xev;
- while (XPending(olc_Display))
- {
- XNextEvent(olc_Display, &xev);
- if (xev.type == Expose)
- {
- XWindowAttributes gwa;
- XGetWindowAttributes(olc_Display, olc_Window, &gwa);
- nWindowWidth = gwa.width;
- nWindowHeight = gwa.height;
- olc_UpdateViewport();
- glClear(GL_COLOR_BUFFER_BIT); // Thanks Benedani!
- }
- else if (xev.type == ConfigureNotify)
- {
- XConfigureEvent xce = xev.xconfigure;
- nWindowWidth = xce.width;
- nWindowHeight = xce.height;
- }
- else if (xev.type == KeyPress)
- {
- KeySym sym = XLookupKeysym(&xev.xkey, 0);
- pKeyNewState[mapKeys[sym]] = true;
- XKeyEvent *e = (XKeyEvent *)&xev; // Because DragonEye loves numpads
- XLookupString(e, NULL, 0, &sym, NULL);
- pKeyNewState[mapKeys[sym]] = true;
- }
- else if (xev.type == KeyRelease)
- {
- KeySym sym = XLookupKeysym(&xev.xkey, 0);
- pKeyNewState[mapKeys[sym]] = false;
- XKeyEvent *e = (XKeyEvent *)&xev;
- XLookupString(e, NULL, 0, &sym, NULL);
- pKeyNewState[mapKeys[sym]] = false;
- }
- else if (xev.type == ButtonPress)
- {
- switch (xev.xbutton.button)
- {
- case 1: pMouseNewState[0] = true; break;
- case 2: pMouseNewState[2] = true; break;
- case 3: pMouseNewState[1] = true; break;
- case 4: olc_UpdateMouseWheel(120); break;
- case 5: olc_UpdateMouseWheel(-120); break;
- default: break;
- }
- }
- else if (xev.type == ButtonRelease)
- {
- switch (xev.xbutton.button)
- {
- case 1: pMouseNewState[0] = false; break;
- case 2: pMouseNewState[2] = false; break;
- case 3: pMouseNewState[1] = false; break;
- default: break;
- }
- }
- else if (xev.type == MotionNotify)
- {
- olc_UpdateMouse(xev.xmotion.x, xev.xmotion.y);
- }
- else if (xev.type == FocusIn)
- {
- bHasInputFocus = true;
- }
- else if (xev.type == FocusOut)
- {
- bHasInputFocus = false;
- }
- else if (xev.type == ClientMessage)
- {
- bAtomActive = false;
- }
- }
- #endif
-
- // Handle User Input - Keyboard
- for (int i = 0; i < 256; i++)
- {
- pKeyboardState[i].bPressed = false;
- pKeyboardState[i].bReleased = false;
-
- if (pKeyNewState[i] != pKeyOldState[i])
- {
- if (pKeyNewState[i])
- {
- pKeyboardState[i].bPressed = !pKeyboardState[i].bHeld;
- pKeyboardState[i].bHeld = true;
- }
- else
- {
- pKeyboardState[i].bReleased = true;
- pKeyboardState[i].bHeld = false;
- }
- }
-
- pKeyOldState[i] = pKeyNewState[i];
- }
-
- // Handle User Input - Mouse
- for (int i = 0; i < 5; i++)
- {
- pMouseState[i].bPressed = false;
- pMouseState[i].bReleased = false;
-
- if (pMouseNewState[i] != pMouseOldState[i])
- {
- if (pMouseNewState[i])
- {
- pMouseState[i].bPressed = !pMouseState[i].bHeld;
- pMouseState[i].bHeld = true;
- }
- else
- {
- pMouseState[i].bReleased = true;
- pMouseState[i].bHeld = false;
- }
- }
-
- pMouseOldState[i] = pMouseNewState[i];
- }
-
- // Cache mouse coordinates so they remain
- // consistent during frame
- nMousePosX = nMousePosXcache;
- nMousePosY = nMousePosYcache;
-
- nMouseWheelDelta = nMouseWheelDeltaCache;
- nMouseWheelDeltaCache = 0;
-
- #ifdef OLC_DBG_OVERDRAW
- olc::Sprite::nOverdrawCount = 0;
- #endif
-
- // Handle Frame Update
- if (!OnUserUpdate(fElapsedTime))
- bAtomActive = false;
-
- // Display Graphics
- glViewport(nViewX, nViewY, nViewW, nViewH);
-
- // TODO: This is a bit slow (especially in debug, but 100x faster in release mode???)
- // Copy pixel array into texture
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, nScreenWidth, nScreenHeight, GL_RGBA, GL_UNSIGNED_BYTE, pDefaultDrawTarget->GetData());
-
- // Display texture on screen
- glBegin(GL_QUADS);
- glTexCoord2f(0.0, 1.0); glVertex3f(-1.0f + (fSubPixelOffsetX), -1.0f + (fSubPixelOffsetY), 0.0f);
- glTexCoord2f(0.0, 0.0); glVertex3f(-1.0f + (fSubPixelOffsetX), 1.0f + (fSubPixelOffsetY), 0.0f);
- glTexCoord2f(1.0, 0.0); glVertex3f( 1.0f + (fSubPixelOffsetX), 1.0f + (fSubPixelOffsetY), 0.0f);
- glTexCoord2f(1.0, 1.0); glVertex3f( 1.0f + (fSubPixelOffsetX), -1.0f + (fSubPixelOffsetY), 0.0f);
- glEnd();
-
- // Present Graphics to screen
- #ifdef _WIN32
- SwapBuffers(glDeviceContext);
- #else
- glXSwapBuffers(olc_Display, olc_Window);
- #endif
-
- // Update Title Bar
- fFrameTimer += fElapsedTime;
- nFrameCount++;
- if (fFrameTimer >= 1.0f)
- {
- fFrameTimer -= 1.0f;
-
- std::string sTitle = "OneLoneCoder.com - Pixel Game Engine - " + sAppName + " - FPS: " + std::to_string(nFrameCount);
- #ifdef _WIN32
- #ifdef UNICODE
- SetWindowText(olc_hWnd, ConvertS2W(sTitle).c_str());
- #else
- SetWindowText(olc_hWnd, sTitle.c_str());
- #endif
- #else
- XStoreName(olc_Display, olc_Window, sTitle.c_str());
- #endif
- nFrameCount = 0;
- }
- }
-
- // Allow the user to free resources if they have overrided the destroy function
- if (OnUserDestroy())
- {
- // User has permitted destroy, so exit and clean up
- }
- else
- {
- // User denied destroy for some reason, so continue running
- bAtomActive = true;
- }
- }
-
- #ifdef _WIN32
- wglDeleteContext(glRenderContext);
- PostMessage(olc_hWnd, WM_DESTROY, 0, 0);
- #else
- glXMakeCurrent(olc_Display, None, NULL);
- glXDestroyContext(olc_Display, glDeviceContext);
- XDestroyWindow(olc_Display, olc_Window);
- XCloseDisplay(olc_Display);
- #endif
-
- }
-
- #ifdef _WIN32
- // Thanks @MaGetzUb for this, which allows sprites to be defined
- // at construction, by initialising the GDI subsystem
- static class GDIPlusStartup
- {
- public:
- GDIPlusStartup()
- {
- Gdiplus::GdiplusStartupInput startupInput;
- ULONG_PTR token;
- Gdiplus::GdiplusStartup(&token, &startupInput, NULL);
- };
- } gdistartup;
- #endif
-
-
- void PixelGameEngine::olc_ConstructFontSheet()
- {
- std::string data;
- data += "?Q`0001oOch0o01o@F40o0<AGD4090LAGD<090@A7ch0?00O7Q`0600>00000000";
- data += "O000000nOT0063Qo4d8>?7a14Gno94AA4gno94AaOT0>o3`oO400o7QN00000400";
- data += "Of80001oOg<7O7moBGT7O7lABET024@aBEd714AiOdl717a_=TH013Q>00000000";
- data += "720D000V?V5oB3Q_HdUoE7a9@DdDE4A9@DmoE4A;Hg]oM4Aj8S4D84@`00000000";
- data += "OaPT1000Oa`^13P1@AI[?g`1@A=[OdAoHgljA4Ao?WlBA7l1710007l100000000";
- data += "ObM6000oOfMV?3QoBDD`O7a0BDDH@5A0BDD<@5A0BGeVO5ao@CQR?5Po00000000";
- data += "Oc``000?Ogij70PO2D]??0Ph2DUM@7i`2DTg@7lh2GUj?0TO0C1870T?00000000";
- data += "70<4001o?P<7?1QoHg43O;`h@GT0@:@LB@d0>:@hN@L0@?aoN@<0O7ao0000?000";
- data += "OcH0001SOglLA7mg24TnK7ln24US>0PL24U140PnOgl0>7QgOcH0K71S0000A000";
- data += "00H00000@Dm1S007@DUSg00?OdTnH7YhOfTL<7Yh@Cl0700?@Ah0300700000000";
- data += "<008001QL00ZA41a@6HnI<1i@FHLM81M@@0LG81?O`0nC?Y7?`0ZA7Y300080000";
- data += "O`082000Oh0827mo6>Hn?Wmo?6HnMb11MP08@C11H`08@FP0@@0004@000000000";
- data += "00P00001Oab00003OcKP0006@6=PMgl<@440MglH@000000`@000001P00000000";
- data += "Ob@8@@00Ob@8@Ga13R@8Mga172@8?PAo3R@827QoOb@820@0O`0007`0000007P0";
- data += "O`000P08Od400g`<3V=P0G`673IP0`@3>1`00P@6O`P00g`<O`000GP800000000";
- data += "?P9PL020O`<`N3R0@E4HC7b0@ET<ATB0@@l6C4B0O`H3N7b0?P01L3R000000020";
-
- fontSprite = new olc::Sprite(128, 48);
- int px = 0, py = 0;
- for (int b = 0; b < 1024; b += 4)
- {
- uint32_t sym1 = (uint32_t)data[b + 0] - 48;
- uint32_t sym2 = (uint32_t)data[b + 1] - 48;
- uint32_t sym3 = (uint32_t)data[b + 2] - 48;
- uint32_t sym4 = (uint32_t)data[b + 3] - 48;
- uint32_t r = sym1 << 18 | sym2 << 12 | sym3 << 6 | sym4;
-
- for (int i = 0; i < 24; i++)
- {
- int k = r & (1 << i) ? 255 : 0;
- fontSprite->SetPixel(px, py, olc::Pixel(k, k, k, k));
- if (++py == 48) { px++; py = 0; }
- }
- }
- }
-
- #ifdef _WIN32
- HWND PixelGameEngine::olc_WindowCreate()
- {
- WNDCLASS wc;
- wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
- wc.hInstance = GetModuleHandle(nullptr);
- wc.lpfnWndProc = olc_WindowEvent;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.lpszMenuName = nullptr;
- wc.hbrBackground = nullptr;
- #ifdef UNICODE
- wc.lpszClassName = L"OLC_PIXEL_GAME_ENGINE";
- #else
- wc.lpszClassName = "OLC_PIXEL_GAME_ENGINE";
- #endif
-
- RegisterClass(&wc);
-
- nWindowWidth = (LONG)nScreenWidth * (LONG)nPixelWidth;
- nWindowHeight = (LONG)nScreenHeight * (LONG)nPixelHeight;
-
- // Define window furniture
- DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
- DWORD dwStyle = WS_CAPTION | WS_SYSMENU | WS_VISIBLE; // | WS_THICKFRAME;
-
- int nCosmeticOffset = 30;
- nViewW = nWindowWidth;
- nViewH = nWindowHeight;
-
- // Handle Fullscreen
- if (bFullScreen)
- {
- dwExStyle = 0;
- dwStyle = WS_VISIBLE | WS_POPUP;
- nCosmeticOffset = 0;
- HMONITOR hmon = MonitorFromWindow(olc_hWnd, MONITOR_DEFAULTTONEAREST);
- MONITORINFO mi = { sizeof(mi) };
- if (!GetMonitorInfo(hmon, &mi)) return NULL;
- nWindowWidth = mi.rcMonitor.right;
- nWindowHeight = mi.rcMonitor.bottom;
-
-
- }
-
- olc_UpdateViewport();
-
- // Keep client size as requested
- RECT rWndRect = { 0, 0, nWindowWidth, nWindowHeight };
- AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle);
- int width = rWndRect.right - rWndRect.left;
- int height = rWndRect.bottom - rWndRect.top;
-
- #ifdef UNICODE
- olc_hWnd = CreateWindowEx(dwExStyle, L"OLC_PIXEL_GAME_ENGINE", L"", dwStyle,
- nCosmeticOffset, nCosmeticOffset, width, height, NULL, NULL, GetModuleHandle(nullptr), this);
- #else
- olc_hWnd = CreateWindowEx(dwExStyle, "OLC_PIXEL_GAME_ENGINE", "", dwStyle,
- nCosmeticOffset, nCosmeticOffset, width, height, NULL, NULL, GetModuleHandle(nullptr), this);
- #endif
-
- // Create Keyboard Mapping
- mapKeys[0x00] = Key::NONE;
- mapKeys[0x41] = Key::A; mapKeys[0x42] = Key::B; mapKeys[0x43] = Key::C; mapKeys[0x44] = Key::D; mapKeys[0x45] = Key::E;
- mapKeys[0x46] = Key::F; mapKeys[0x47] = Key::G; mapKeys[0x48] = Key::H; mapKeys[0x49] = Key::I; mapKeys[0x4A] = Key::J;
- mapKeys[0x4B] = Key::K; mapKeys[0x4C] = Key::L; mapKeys[0x4D] = Key::M; mapKeys[0x4E] = Key::N; mapKeys[0x4F] = Key::O;
- mapKeys[0x50] = Key::P; mapKeys[0x51] = Key::Q; mapKeys[0x52] = Key::R; mapKeys[0x53] = Key::S; mapKeys[0x54] = Key::T;
- mapKeys[0x55] = Key::U; mapKeys[0x56] = Key::V; mapKeys[0x57] = Key::W; mapKeys[0x58] = Key::X; mapKeys[0x59] = Key::Y;
- mapKeys[0x5A] = Key::Z;
-
- mapKeys[VK_F1] = Key::F1; mapKeys[VK_F2] = Key::F2; mapKeys[VK_F3] = Key::F3; mapKeys[VK_F4] = Key::F4;
- mapKeys[VK_F5] = Key::F5; mapKeys[VK_F6] = Key::F6; mapKeys[VK_F7] = Key::F7; mapKeys[VK_F8] = Key::F8;
- mapKeys[VK_F9] = Key::F9; mapKeys[VK_F10] = Key::F10; mapKeys[VK_F11] = Key::F11; mapKeys[VK_F12] = Key::F12;
-
- mapKeys[VK_DOWN] = Key::DOWN; mapKeys[VK_LEFT] = Key::LEFT; mapKeys[VK_RIGHT] = Key::RIGHT; mapKeys[VK_UP] = Key::UP;
- mapKeys[VK_RETURN] = Key::ENTER; //mapKeys[VK_RETURN] = Key::RETURN;
-
- mapKeys[VK_BACK] = Key::BACK; mapKeys[VK_ESCAPE] = Key::ESCAPE; mapKeys[VK_RETURN] = Key::ENTER; mapKeys[VK_PAUSE] = Key::PAUSE;
- mapKeys[VK_SCROLL] = Key::SCROLL; mapKeys[VK_TAB] = Key::TAB; mapKeys[VK_DELETE] = Key::DEL; mapKeys[VK_HOME] = Key::HOME;
- mapKeys[VK_END] = Key::END; mapKeys[VK_PRIOR] = Key::PGUP; mapKeys[VK_NEXT] = Key::PGDN; mapKeys[VK_INSERT] = Key::INS;
- mapKeys[VK_SHIFT] = Key::SHIFT; mapKeys[VK_CONTROL] = Key::CTRL;
- mapKeys[VK_SPACE] = Key::SPACE;
-
- mapKeys[0x30] = Key::K0; mapKeys[0x31] = Key::K1; mapKeys[0x32] = Key::K2; mapKeys[0x33] = Key::K3; mapKeys[0x34] = Key::K4;
- mapKeys[0x35] = Key::K5; mapKeys[0x36] = Key::K6; mapKeys[0x37] = Key::K7; mapKeys[0x38] = Key::K8; mapKeys[0x39] = Key::K9;
-
- 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;
- 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;
- 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;
-
- return olc_hWnd;
- }
-
- bool PixelGameEngine::olc_OpenGLCreate()
- {
- // Create Device Context
- glDeviceContext = GetDC(olc_hWnd);
- PIXELFORMATDESCRIPTOR pfd =
- {
- sizeof(PIXELFORMATDESCRIPTOR), 1,
- PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
- PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- PFD_MAIN_PLANE, 0, 0, 0, 0
- };
-
- int pf = 0;
- if (!(pf = ChoosePixelFormat(glDeviceContext, &pfd))) return false;
- SetPixelFormat(glDeviceContext, pf, &pfd);
-
- if (!(glRenderContext = wglCreateContext(glDeviceContext))) return false;
- wglMakeCurrent(glDeviceContext, glRenderContext);
-
- glViewport(nViewX, nViewY, nViewW, nViewH);
-
- // Remove Frame cap
- wglSwapInterval = (wglSwapInterval_t*)wglGetProcAddress("wglSwapIntervalEXT");
- if (wglSwapInterval) wglSwapInterval(0);
- return true;
- }
-
- // Windows Event Handler
- LRESULT CALLBACK PixelGameEngine::olc_WindowEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- static PixelGameEngine *sge;
- switch (uMsg)
- {
- case WM_CREATE: sge = (PixelGameEngine*)((LPCREATESTRUCT)lParam)->lpCreateParams; return 0;
- case WM_MOUSEMOVE:
- {
- uint16_t x = lParam & 0xFFFF; // Thanks @ForAbby (Discord)
- uint16_t y = (lParam >> 16) & 0xFFFF;
- int16_t ix = *(int16_t*)&x;
- int16_t iy = *(int16_t*)&y;
- sge->olc_UpdateMouse(ix, iy);
- return 0;
- }
- case WM_SIZE:
- {
- sge->olc_UpdateWindowSize(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF);
- return 0;
- }
- case WM_MOUSEWHEEL:
- {
- sge->olc_UpdateMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
- return 0;
- }
- case WM_MOUSELEAVE: sge->bHasMouseFocus = false; return 0;
- case WM_SETFOCUS: sge->bHasInputFocus = true; return 0;
- case WM_KILLFOCUS: sge->bHasInputFocus = false; return 0;
- case WM_KEYDOWN: sge->pKeyNewState[mapKeys[wParam]] = true; return 0;
- case WM_KEYUP: sge->pKeyNewState[mapKeys[wParam]] = false; return 0;
- case WM_LBUTTONDOWN:sge->pMouseNewState[0] = true; return 0;
- case WM_LBUTTONUP: sge->pMouseNewState[0] = false; return 0;
- case WM_RBUTTONDOWN:sge->pMouseNewState[1] = true; return 0;
- case WM_RBUTTONUP: sge->pMouseNewState[1] = false; return 0;
- case WM_MBUTTONDOWN:sge->pMouseNewState[2] = true; return 0;
- case WM_MBUTTONUP: sge->pMouseNewState[2] = false; return 0;
- case WM_CLOSE: bAtomActive = false; return 0;
- case WM_DESTROY: PostQuitMessage(0); return 0;
- }
- return DefWindowProc(hWnd, uMsg, wParam, lParam);
- }
- #else
- // Do the Linux stuff!
- Display* PixelGameEngine::olc_WindowCreate()
- {
- XInitThreads();
-
- // Grab the deafult display and window
- olc_Display = XOpenDisplay(NULL);
- olc_WindowRoot = DefaultRootWindow(olc_Display);
-
- // Based on the display capabilities, configure the appearance of the window
- GLint olc_GLAttribs[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
- olc_VisualInfo = glXChooseVisual(olc_Display, 0, olc_GLAttribs);
- olc_ColourMap = XCreateColormap(olc_Display, olc_WindowRoot, olc_VisualInfo->visual, AllocNone);
- olc_SetWindowAttribs.colormap = olc_ColourMap;
-
- // Register which events we are interested in receiving
- olc_SetWindowAttribs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | StructureNotifyMask;
-
- // Create the window
- 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);
-
- Atom wmDelete = XInternAtom(olc_Display, "WM_DELETE_WINDOW", true);
- XSetWMProtocols(olc_Display, olc_Window, &wmDelete, 1);
-
- XMapWindow(olc_Display, olc_Window);
- XStoreName(olc_Display, olc_Window, "OneLoneCoder.com - Pixel Game Engine");
-
- if (bFullScreen) // Thanks DragonEye, again :D
- {
- Atom wm_state;
- Atom fullscreen;
- wm_state = XInternAtom(olc_Display, "_NET_WM_STATE", False);
- fullscreen = XInternAtom(olc_Display, "_NET_WM_STATE_FULLSCREEN", False);
- XEvent xev{ 0 };
- xev.type = ClientMessage;
- xev.xclient.window = olc_Window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = (bFullScreen ? 1 : 0); // the action (0: off, 1: on, 2: toggle)
- xev.xclient.data.l[1] = fullscreen; // first property to alter
- xev.xclient.data.l[2] = 0; // second property to alter
- xev.xclient.data.l[3] = 0; // source indication
- XMapWindow(olc_Display, olc_Window);
- XSendEvent(olc_Display, DefaultRootWindow(olc_Display), False,
- SubstructureRedirectMask | SubstructureNotifyMask, &xev);
- XFlush(olc_Display);
- XWindowAttributes gwa;
- XGetWindowAttributes(olc_Display, olc_Window, &gwa);
- nWindowWidth = gwa.width;
- nWindowHeight = gwa.height;
- olc_UpdateViewport();
- } else {
- olc_SizeHints.flags = PMaxSize | PMinSize;
- olc_SizeHints.max_width = nScreenWidth * nPixelWidth;
- olc_SizeHints.max_height = nScreenHeight * nPixelHeight;
- olc_SizeHints.min_width = nScreenWidth * nPixelWidth;
- olc_SizeHints.min_height = nScreenHeight * nPixelHeight;
-
- XSetWMNormalHints(olc_Display, olc_Window, &olc_SizeHints);
- }
-
- // Create Keyboard Mapping
- mapKeys[0x00] = Key::NONE;
- mapKeys[0x61] = Key::A; mapKeys[0x62] = Key::B; mapKeys[0x63] = Key::C; mapKeys[0x64] = Key::D; mapKeys[0x65] = Key::E;
- mapKeys[0x66] = Key::F; mapKeys[0x67] = Key::G; mapKeys[0x68] = Key::H; mapKeys[0x69] = Key::I; mapKeys[0x6A] = Key::J;
- mapKeys[0x6B] = Key::K; mapKeys[0x6C] = Key::L; mapKeys[0x6D] = Key::M; mapKeys[0x6E] = Key::N; mapKeys[0x6F] = Key::O;
- mapKeys[0x70] = Key::P; mapKeys[0x71] = Key::Q; mapKeys[0x72] = Key::R; mapKeys[0x73] = Key::S; mapKeys[0x74] = Key::T;
- mapKeys[0x75] = Key::U; mapKeys[0x76] = Key::V; mapKeys[0x77] = Key::W; mapKeys[0x78] = Key::X; mapKeys[0x79] = Key::Y;
- mapKeys[0x7A] = Key::Z;
-
- mapKeys[XK_F1] = Key::F1; mapKeys[XK_F2] = Key::F2; mapKeys[XK_F3] = Key::F3; mapKeys[XK_F4] = Key::F4;
- mapKeys[XK_F5] = Key::F5; mapKeys[XK_F6] = Key::F6; mapKeys[XK_F7] = Key::F7; mapKeys[XK_F8] = Key::F8;
- mapKeys[XK_F9] = Key::F9; mapKeys[XK_F10] = Key::F10; mapKeys[XK_F11] = Key::F11; mapKeys[XK_F12] = Key::F12;
-
- mapKeys[XK_Down] = Key::DOWN; mapKeys[XK_Left] = Key::LEFT; mapKeys[XK_Right] = Key::RIGHT; mapKeys[XK_Up] = Key::UP;
- mapKeys[XK_KP_Enter] = Key::ENTER; mapKeys[XK_Return] = Key::ENTER;
-
- mapKeys[XK_BackSpace] = Key::BACK; mapKeys[XK_Escape] = Key::ESCAPE; mapKeys[XK_Linefeed] = Key::ENTER; mapKeys[XK_Pause] = Key::PAUSE;
- mapKeys[XK_Scroll_Lock] = Key::SCROLL; mapKeys[XK_Tab] = Key::TAB; mapKeys[XK_Delete] = Key::DEL; mapKeys[XK_Home] = Key::HOME;
- mapKeys[XK_End] = Key::END; mapKeys[XK_Page_Up] = Key::PGUP; mapKeys[XK_Page_Down] = Key::PGDN; mapKeys[XK_Insert] = Key::INS;
- mapKeys[XK_Shift_L] = Key::SHIFT; mapKeys[XK_Shift_R] = Key::SHIFT; mapKeys[XK_Control_L] = Key::CTRL; mapKeys[XK_Control_R] = Key::CTRL;
- mapKeys[XK_space] = Key::SPACE;
-
- 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;
- 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;
-
- 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;
- 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;
- 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;
-
- return olc_Display;
- }
-
- bool PixelGameEngine::olc_OpenGLCreate()
- {
- glDeviceContext = glXCreateContext(olc_Display, olc_VisualInfo, nullptr, GL_TRUE);
- glXMakeCurrent(olc_Display, olc_Window, glDeviceContext);
-
- XWindowAttributes gwa;
- XGetWindowAttributes(olc_Display, olc_Window, &gwa);
- glViewport(0, 0, gwa.width, gwa.height);
-
- glSwapIntervalEXT = nullptr;
- glSwapIntervalEXT = (glSwapInterval_t*)glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT");
- if (glSwapIntervalEXT)
- glSwapIntervalEXT(olc_Display, olc_Window, 0);
- else
- {
- printf("NOTE: Could not disable VSYNC, glXSwapIntervalEXT() was not found!\n");
- printf(" Don't worry though, things will still work, it's just the\n");
- printf(" frame rate will be capped to your monitors refresh rate - javidx9\n");
- }
-
- return true;
- }
-
- #endif
-
- // Need a couple of statics as these are singleton instances
- // read from multiple locations
- std::atomic<bool> PixelGameEngine::bAtomActive{ false };
- std::map<uint16_t, uint8_t> PixelGameEngine::mapKeys;
- olc::PixelGameEngine* olc::PGEX::pge = nullptr;
- #ifdef OLC_DBG_OVERDRAW
- int olc::Sprite::nOverdrawCount = 0;
- #endif
- //=============================================================
- }
|