olcPixelGameEngine v2.28
The official distribution of olcPixelGameEngine, a tool used in javidx9's YouTube videos and projects
Loading...
Searching...
No Matches
olcPixelGameEngine.h
Go to the documentation of this file.
1#pragma region license_and_help
2/*
3 olcPixelGameEngine.h
4
5 +-------------------------------------------------------------+
6 | OneLoneCoder Pixel Game Engine v2.28 |
7 | "What do you need? Pixels... Lots of Pixels..." - javidx9 |
8 +-------------------------------------------------------------+
9
10 What is this?
11 ~~~~~~~~~~~~~
12 olc::PixelGameEngine is a single file, cross platform graphics and userinput
13 framework used for games, visualisations, algorithm exploration and learning.
14 It was developed by YouTuber "javidx9" as an assistive tool for many of his
15 videos. The goal of this project is to provide high speed graphics with
16 minimal project setup complexity, to encourage new programmers, younger people,
17 and anyone else that wants to make fun things.
18
19 However, olc::PixelGameEngine is not a toy! It is a powerful and fast utility
20 capable of delivering high resolution, high speed, high quality applications
21 which behave the same way regardless of the operating system or platform.
22
23 This file provides the core utility set of the olc::PixelGameEngine, including
24 window creation, keyboard/mouse input, main game thread, timing, pixel drawing
25 routines, image/sprite loading and drawing routines, and a bunch of utility
26 types to make rapid development of games/visualisations possible.
27
28
29 License (OLC-3)
30 ~~~~~~~~~~~~~~~
31
32 Copyright 2018 - 2024 OneLoneCoder.com
33
34 Redistribution and use in source and binary forms, with or without modification,
35 are permitted provided that the following conditions are met:
36
37 1. Redistributions or derivations of source code must retain the above copyright
38 notice, this list of conditions and the following disclaimer.
39
40 2. Redistributions or derivative works in binary form must reproduce the above
41 copyright notice. This list of conditions and the following disclaimer must be
42 reproduced in the documentation and/or other materials provided with the distribution.
43
44 3. Neither the name of the copyright holder nor the names of its contributors may
45 be used to endorse or promote products derived from this software without specific
46 prior written permission.
47
48 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
49 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
51 SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
52 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
53 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
54 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
56 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 SUCH DAMAGE.
58
59 Links
60 ~~~~~
61 YouTube: https://www.youtube.com/javidx9
62 https://www.youtube.com/javidx9extra
63 Discord: https://discord.gg/WhwHUMV
64 Twitter: https://www.twitter.com/javidx9
65 Twitch: https://www.twitch.tv/javidx9
66 GitHub: https://www.github.com/onelonecoder
67 Homepage: https://www.onelonecoder.com
68 Patreon: https://www.patreon.com/javidx9
69 Community: https://community.onelonecoder.com
70
71
72
73 Compiling in Linux
74 ~~~~~~~~~~~~~~~~~~
75 You will need a modern C++ compiler, so update yours!
76 To compile use the command:
77
78 g++ -o YourProgName YourSource.cpp -lX11 -lGL -lpthread -lpng -lstdc++fs -std=c++17
79
80 On some Linux configurations, the frame rate is locked to the refresh
81 rate of the monitor. This engine tries to unlock it but may not be
82 able to, in which case try launching your program like this:
83
84 vblank_mode=0 ./YourProgName
85
86
87
88 Compiling in Code::Blocks on Windows
89 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
90 Well I wont judge you, but make sure your Code::Blocks installation
91 is really up to date - you may even consider updating your C++ toolchain
92 to use MinGW32-W64.
93
94 Guide for installing recent GCC for Windows:
95 https://www.msys2.org/
96 Guide for configuring code::blocks:
97 https://solarianprogrammer.com/2019/11/05/install-gcc-windows/
98 https://solarianprogrammer.com/2019/11/16/install-codeblocks-gcc-windows-build-c-cpp-fortran-programs/
99
100 Add these libraries to "Linker Options":
101 user32 gdi32 opengl32 gdiplus Shlwapi dwmapi stdc++fs
102
103 Set these compiler options: -std=c++17
104
105
106
107 Compiling on Mac - EXPERIMENTAL! PROBABLY HAS BUGS
108 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109 Yes yes, people use Macs for C++ programming! Who knew? Anyway, enough
110 arguing, thanks to Mumflr the PGE is now supported on Mac. Now I know nothing
111 about Mac, so if you need support, I suggest checking out the instructions
112 here: https://github.com/MumflrFumperdink/olcPGEMac
113
114 clang++ -arch x86_64 -std=c++17 -mmacosx-version-min=10.15 -Wall -framework OpenGL
115 -framework GLUT -framework Carbon -lpng YourSource.cpp -o YourProgName
116
117
118
119 Compiling with Emscripten (New & Experimental)
120 ~~~~~~~~~~~~~~~~~~~~~~~~~
121 Emscripten compiler will turn your awesome C++ PixelGameEngine project into WASM!
122 This means you can run your application in teh browser, great for distributing
123 and submission in to jams and things! It's a bit new at the moment.
124
125 em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 ./YourSource.cpp -o pge.html
126
127
128
129 Using stb_image.h
130 ~~~~~~~~~~~~~~~~~
131 The PGE will load png images by default (with help from libpng on non-windows systems).
132 However, the excellent "stb_image.h" can be used instead, supporting a variety of
133 image formats, and has no library dependence - something we like at OLC studios ;)
134 To use stb_image.h, make sure it's in your code base, and simply:
135
136 #define OLC_IMAGE_STB
137
138 Before including the olcPixelGameEngine.h header file. stb_image.h works on many systems
139 and can be downloaded here: https://github.com/nothings/stb/blob/master/stb_image.h
140
141
142
143 Multiple cpp file projects?
144 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
145 As a single header solution, the OLC_PGE_APPLICATION definition is used to
146 insert the engine implementation at a project location of your choosing.
147 The simplest way to setup multifile projects is to create a file called
148 "olcPixelGameEngine.cpp" which includes the following:
149
150 #define OLC_PGE_APPLICATION
151 #include "olcPixelGameEngine.h"
152
153 That's all it should include. You can also include PGEX includes and
154 defines in here too. With this in place, you dont need to
155 #define OLC_PGE_APPLICATION anywhere, and can simply include this
156 header file as an when you need to.
157
158
159
160 Ports
161 ~~~~~
162 olc::PixelGameEngine has been ported and tested with varying degrees of
163 success to: WinXP, Win7, Win8, Win10, Various Linux, Raspberry Pi,
164 Chromebook, Playstation Portable (PSP) and Nintendo Switch. If you are
165 interested in the details of these ports, come and visit the Discord!
166
167
168
169 Thanks
170 ~~~~~~
171 I'd like to extend thanks to Ian McKay, Bispoo, Eremiell, slavka, Kwizatz77, gurkanctn, Phantim,
172 IProgramInCPP, JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice,
173 dandistine, Ralakus, Gorbit99, raoul, joshinils, benedani, Moros1138, Alexio, SaladinAkara
174 & MagetzUb for advice, ideas and testing, and I'd like to extend my appreciation to the
175 250K YouTube followers, 80+ Patreons, 4.8K Twitch followers and 10K Discord server members
176 who give me the motivation to keep going with all this :D
177
178 Significant Contributors: @Moros1138, @SaladinAkara, @MaGetzUb, @slavka,
179 @Dragoneye, @Gorbit99, @dandistine & @Mumflr
180
181 Special thanks to those who bring gifts!
182 GnarGnarHead.......Domina
183 Gorbit99...........Bastion, Ori & The Blind Forest, Terraria, Spelunky 2, Skully
184 Marti Morta........Gris
185 Danicron...........Terraria
186 SaladinAkara.......Aseprite, Inside, Quern: Undying Thoughts, Outer Wilds
187 AlterEgo...........Final Fantasy XII - The Zodiac Age
188 SlicEnDicE.........Noita, Inside
189 TGD................Voucher Gift
190 Dragoneye..........Lucas Arts Adventure Game Pack
191 Anonymous Pirate...Return To Monkey Island
192
193 Special thanks to my Patreons too - I wont name you on here, but I've
194 certainly enjoyed my tea and flapjacks :D
195
196 - In Memory of SaladinAkara 25.06.2023 -
197
198 Author
199 ~~~~~~
200 David Barr, aka javidx9, (c) OneLoneCoder 2018, 2019, 2020, 2021, 2022, 2023, 2024
201*/
202#pragma endregion
203
204#pragma region version_history
205/*
206 2.01: Made renderer and platform static for multifile projects
207 2.02: Added Decal destructor, optimised Pixel constructor
208 2.03: Added FreeBSD flags, Added DrawStringDecal()
209 2.04: Windows Full-Screen bug fixed
210 2.05: +DrawPartialWarpedDecal() - draws a warped decal from a subset image
211 +DrawPartialRotatedDecal() - draws a rotated decal from a subset image
212 2.06: +GetTextSize() - returns area occupied by multiline string
213 +GetWindowSize() - returns actual window size
214 +GetElapsedTime() - returns last calculated fElapsedTime
215 +GetWindowMouse() - returns actual mouse location in window
216 +DrawExplicitDecal() - bow-chikka-bow-bow
217 +DrawPartialDecal(pos, size) - draws a partial decal to specified area
218 +FillRectDecal() - draws a flat shaded rectangle as a decal
219 +GradientFillRectDecal() - draws a rectangle, with unique colour corners
220 +Modified DrawCircle() & FillCircle() - Thanks IanM-Matrix1 (#PR121)
221 +Gone someway to appeasing pedants
222 2.07: +GetPixelSize() - returns user specified pixel size
223 +GetScreenPixelSize() - returns actual size in monitor pixels
224 +Pixel Cohesion Mode (flag in Construct()) - disallows arbitrary window scaling
225 +Working VSYNC in Windows windowed application - now much smoother
226 +Added string conversion for olc::vectors
227 +Added comparator operators for olc::vectors
228 +Added DestroyWindow() on windows platforms for serial PGE launches
229 +Added GetMousePos() to stop TarriestPython whinging
230 2.08: Fix SetScreenSize() aspect ratio pre-calculation
231 Fix DrawExplicitDecal() - stupid oversight with multiple decals
232 Disabled olc::Sprite copy constructor
233 +olc::Sprite Duplicate() - produces a new clone of the sprite
234 +olc::Sprite Duplicate(pos, size) - produces a new sprite from the region defined
235 +Unary operators for vectors
236 +More pedant mollification - Thanks TheLandfill
237 +ImageLoader modules - user selectable image handling core, gdi+, libpng, stb_image
238 +Mac Support via GLUT - thanks Mumflr!
239 2.09: Fix olc::Renderable Image load error - Thanks MaGetzUb & Zij-IT for finding and moaning about it
240 Fix file rejection in image loaders when using resource packs
241 Tidied Compiler defines per platform - Thanks slavka
242 +Pedant fixes, const correctness in parts
243 +DecalModes - Normal, Additive, Multiplicative blend modes
244 +Pixel Operators & Lerping
245 +Filtered Decals - If you hate pixels, then erase this file
246 +DrawStringProp(), GetTextSizeProp(), DrawStringPropDecal() - Draws non-monospaced font
247 2.10: Fix PixelLerp() - oops my bad, lerped the wrong way :P
248 Fix "Shader" support for strings - thanks Megarev for crying about it
249 Fix GetTextSizeProp() - Height was just plain wrong...
250 +vec2d operator overloads (element wise *=, /=)
251 +vec2d comparison operators... :| yup... hmmmm...
252 +vec2d ceil(), floor(), min(), max() functions - surprising how often I do it manually
253 +DrawExplicitDecal(... uint32_t elements) - complete control over convex polygons and lines
254 +DrawPolygonDecal() - to keep Bispoo happy, required significant rewrite of EVERYTHING, but hey ho
255 +Complete rewrite of decal renderer
256 +OpenGL 3.3 Renderer (also supports Raspberry Pi)
257 +PGEX Break-In Hooks - with a push from Dandistine
258 +Wireframe Decal Mode - For debug overlays
259 2.11: Made PGEX hooks optional - (provide true to super constructor)
260 2.12: Fix for MinGW compiler non-compliance :( - why is its sdk structure different?? why???
261 2.13: +GetFontSprite() - allows access to font data
262 2.14: Fix WIN32 Definition reshuffle
263 Fix DrawPartialDecal() - messed up dimension during renderer experiment, didnt remove junk code, thanks Alexio
264 Fix? Strange error regarding GDI+ Image Loader not knowing about COM, SDK change?
265 2.15: Big Reformat
266 +WASM Platform (via Emscripten) - Big Thanks to OLC Community - See Platform for details
267 +Sample Mode for Decals
268 +Made olc_ConfigureSystem() accessible
269 +Added OLC_----_CUSTOM_EX for externalised platforms, renderers and image loaders
270 =Refactored olc::Sprite pixel data store
271 -Deprecating LoadFromPGESprFile()
272 -Deprecating SaveToPGESprFile()
273 Fix Pixel -= operator (thanks Au Lit)
274 2.16: FIX Emscripten JS formatting in VS IDE (thanks Moros)
275 +"Headless" Mode
276 +DrawLineDecal()
277 +Mouse Button Constants
278 +Move Constructor for olc::Renderable
279 +Polar/Cartesian conversion for v2d_generic
280 +DrawRotatedStringDecal()/DrawRotatedStringPropDecal() (thanks Oso-Grande/Sopadeoso (PR #209))
281 =Using olc::Renderable for layer surface
282 +Major Mac and GLUT Update (thanks Mumflr)
283 2.17: +Clipping for DrawLine() functions
284 +Reintroduced sub-pixel decals
285 +Modified DrawPartialDecal() to quantise and correctly sample from tile atlasses
286 +olc::Sprite::GetPixel() - Clamp Mode
287 2.18: +Option to not "dirty" layers with SetDrawTarget() - Thanks TerasKasi!
288 =Detection for Mac M1, fix for scroll wheel interrogation - Thanks ruarq!
289 2.19: Textual Input(of)course Edition!
290 =Built in font is now olc::Renderable
291 +EnablePixelTransfer() - Gate if layer content transfers occur (speedup in decal only apps)
292 +TextEntryEnable() - Enables/Disables text entry mode
293 +TextEntryGetString() - Gets the current accumulated string in text entry mode
294 +TextEntryGetCursor() - Gets the current cursor position in text entry mode
295 +IsTextEntryEnabled() - Returns true if text entry mode is activated
296 +OnTextEntryComplete() - Override is called when user presses "ENTER" in text entry mode
297 +Potential for regional keyboard mappings - needs volunteers to do this
298 +ConsoleShow() - Opens built in command console
299 +ConsoleClear() - Clears built in command console output
300 +ConsoleOut() - Stream strings to command console output
301 +ConsoleCaptureStdOut() - Capture std::cout by redirecting to built-in console
302 +OnConsoleCommand() - Override is called when command is entered into built in console
303 2.20: +DrawRectDecal() - Keeps OneSketchyGuy quiet
304 +GetScreenSize()
305 +olc::Sprite::Size() - returns size of sprite in vector format
306 2.21: Emscripten Overhaul - Thanks Moros!
307 +DrawPolygonDecal() tint overload, can now tint a polygon accounting for vertex colours
308 +Multiplicative Pixel overload
309 +v2d_generic clamp()
310 +v2d_generic lerp()
311 +GetDroppedFiles() - returns files dropped onto engine window for that frame (MSW only)
312 +GetDroppedFilesPoint() - returns location of dropped files (MSW only)
313 +Exposed OpenGL33 Loader interface so the typedefs can be shared with PGEX & user
314 +Fix OGL33 DecalStructure types - wow, how did that one get missed?? lol
315 +FillTexturedTriangle() - Software rasterizes a textured, coloured, triangle
316 +FillTexturedPolygon() - Hijacks DecalStructure for configuration
317 +olc::vf2d arguments for Sprite::Sample() functions
318 2.22: = Fix typo on dragged file buffers for unicode builds
319 2.23: Fixed Emscripten host sizing errors - Thanks Moros
320 Fixed v2d_generic.clamp() function
321 2.24: Fix FillTexturedTriangle() to remove const-ref
322 2.25: +DrawPolygonDecal(pos, tex, w, col)
323 2.26: Window Manipulation Update! (MS Windows only right now... need volunteers!)
324 +1:1 "Real Window" mode which follows resizing - Construct(...)
325 +SetWindowSize() - Sets Position/Size of window
326 +ShowWindowFrame() - Enables/Disables window furniture
327 +olc_UpdateWindowPos() - Break in to set position of window
328 +adv_ManualRenderEnable() - [ADVANCED] To be PGE or not be PGE...
329 +adv_HardwareClip() - [ADVANCED] Specify target clip region
330 +adv_FlushLayer() - [ADVANCED] Force layer update to buffer
331 +adv_FlushLayerDecals() - [ADVANCED] Force layer's decal render to buffer
332 +FillTriangleDecal() - Draws a triangle decal
333 +GradientTriangleDecal() - Draws a triangle decal with unique vertex colours
334 2.27: Restructuring of connected files (post-jam clean up)
335 +Guarding olc::v_2d with less faff
336 +Updated olcUTIL_Geometry2D.h
337 +Updated olcUTIL_QuadTree.h
338 +Updated olcUTIL_Animate2D.h
339 +Updated olcUTIL_SplashScreen.h
340 +File Resolution for PGEtinker.com
341 2.28: Brought olc::v_2d inline with other sources
342
343 !! Apple Platforms will not see these updates immediately - Sorry, I dont have a mac to test... !!
344 !! Volunteers willing to help appreciated, though PRs are manually integrated with credit !!
345*/
346#pragma endregion
347
348#pragma region hello_world_example
349// O------------------------------------------------------------------------------O
350// | Example "Hello World" Program (main.cpp) |
351// O------------------------------------------------------------------------------O
352/*
353
354#define OLC_PGE_APPLICATION
355#include "olcPixelGameEngine.h"
356
357// Override base class with your custom functionality
358class Example : public olc::PixelGameEngine
359{
360public:
361 Example()
362 {
363 // Name your application
364 sAppName = "Example";
365 }
366
367public:
368 bool OnUserCreate() override
369 {
370 // Called once at the start, so create things here
371 return true;
372 }
373
374 bool OnUserUpdate(float fElapsedTime) override
375 {
376 // Called once per frame, draws random coloured pixels
377 for (int x = 0; x < ScreenWidth(); x++)
378 for (int y = 0; y < ScreenHeight(); y++)
379 Draw(x, y, olc::Pixel(rand() % 256, rand() % 256, rand() % 256));
380 return true;
381 }
382};
383
384int main()
385{
386 Example demo;
387 if (demo.Construct(256, 240, 4, 4))
388 demo.Start();
389 return 0;
390}
391
392*/
393#pragma endregion
394
395#ifndef OLC_PGE_DEF
396#define OLC_PGE_DEF
397
398#pragma region std_includes
399// O------------------------------------------------------------------------------O
400// | STANDARD INCLUDES |
401// O------------------------------------------------------------------------------O
402#include <cmath>
403#include <cstdint>
404#include <string>
405#include <iostream>
406#include <streambuf>
407#include <sstream>
408#include <chrono>
409#include <vector>
410#include <list>
411#include <thread>
412#include <atomic>
413#include <fstream>
414#include <map>
415#include <functional>
416#include <algorithm>
417#include <array>
418#include <cstring>
419#pragma endregion
420
421#define PGE_VER 228
422
423// O------------------------------------------------------------------------------O
424// | COMPILER CONFIGURATION ODDITIES |
425// O------------------------------------------------------------------------------O
426#pragma region compiler_config
427#define USE_EXPERIMENTAL_FS
428#if defined(_WIN32)
429 #if _MSC_VER >= 1920 && _MSVC_LANG >= 201703L
430 #undef USE_EXPERIMENTAL_FS
431 #endif
432#endif
433#if defined(__linux__) || defined(__MINGW32__) || defined(__EMSCRIPTEN__) || defined(__FreeBSD__) || defined(__APPLE__)
434 #if __cplusplus >= 201703L
435 #undef USE_EXPERIMENTAL_FS
436 #endif
437#endif
438
439#if !defined(OLC_KEYBOARD_UK)
440 #define OLC_KEYBOARD_UK
441#endif
442
443
444#if defined(USE_EXPERIMENTAL_FS) || defined(FORCE_EXPERIMENTAL_FS)
445 // C++14
446 #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
447 #include <experimental/filesystem>
448 namespace _gfs = std::experimental::filesystem::v1;
449#else
450 // C++17
451 #include <filesystem>
452 namespace _gfs = std::filesystem;
453#endif
454
455#if defined(UNICODE) || defined(_UNICODE)
456 #define olcT(s) L##s
457#else
458 #define olcT(s) s
459#endif
460
461#define UNUSED(x) (void)(x)
462
463// O------------------------------------------------------------------------------O
464// | PLATFORM SELECTION CODE, Thanks slavka! |
465// O------------------------------------------------------------------------------O
466
467#if defined(OLC_PGE_HEADLESS)
468 #define OLC_PLATFORM_HEADLESS
469 #define OLC_GFX_HEADLESS
470 #if !defined(OLC_IMAGE_STB) && !defined(OLC_IMAGE_GDI) && !defined(OLC_IMAGE_LIBPNG)
471 #define OLC_IMAGE_HEADLESS
472 #endif
473#endif
474
475// Platform
476#if !defined(OLC_PLATFORM_WINAPI) && !defined(OLC_PLATFORM_X11) && !defined(OLC_PLATFORM_GLUT) && !defined(OLC_PLATFORM_EMSCRIPTEN) && !defined(OLC_PLATFORM_HEADLESS)
477 #if !defined(OLC_PLATFORM_CUSTOM_EX)
478 #if defined(_WIN32)
479 #define OLC_PLATFORM_WINAPI
480 #endif
481 #if defined(__linux__) || defined(__FreeBSD__)
482 #define OLC_PLATFORM_X11
483 #endif
484 #if defined(__APPLE__)
485 #define GL_SILENCE_DEPRECATION
486 #define OLC_PLATFORM_GLUT
487 #endif
488 #if defined(__EMSCRIPTEN__)
489 #define OLC_PLATFORM_EMSCRIPTEN
490 #endif
491 #endif
492#endif
493
494// Start Situation
495#if defined(OLC_PLATFORM_GLUT) || defined(OLC_PLATFORM_EMSCRIPTEN)
496 #define PGE_USE_CUSTOM_START
497#endif
498
499
500
501// Renderer
502#if !defined(OLC_GFX_OPENGL10) && !defined(OLC_GFX_OPENGL33) && !defined(OLC_GFX_DIRECTX10) && !defined(OLC_GFX_HEADLESS)
503 #if !defined(OLC_GFX_CUSTOM_EX)
504 #if defined(OLC_PLATFORM_EMSCRIPTEN)
505 #define OLC_GFX_OPENGL33
506 #else
507 #define OLC_GFX_OPENGL10
508 #endif
509 #endif
510#endif
511
512// Image loader
513#if !defined(OLC_IMAGE_STB) && !defined(OLC_IMAGE_GDI) && !defined(OLC_IMAGE_LIBPNG) && !defined(OLC_IMAGE_HEADLESS)
514 #if !defined(OLC_IMAGE_CUSTOM_EX)
515 #if defined(_WIN32)
516 #define OLC_IMAGE_GDI
517 #endif
518 #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__EMSCRIPTEN__)
519 #define OLC_IMAGE_LIBPNG
520 #endif
521 #endif
522#endif
523
524// File resolver for runtime FS access of emscripten builds
525#if defined(__EMSCRIPTEN__)
526#include <emscripten.h>
527#define FILE_RESOLVE(url, file) emscripten_wget(url, file); emscripten_sleep(0)
528#else
529#define FILE_RESOLVE(url, file)
530#endif
531
532// O------------------------------------------------------------------------------O
533// | PLATFORM-SPECIFIC DEPENDENCIES |
534// O------------------------------------------------------------------------------O
535#if !defined(OLC_PGE_HEADLESS)
536#if defined(OLC_PLATFORM_WINAPI)
537 #define _WINSOCKAPI_ // Thanks Cornchipss
538 #if !defined(VC_EXTRALEAN)
539 #define VC_EXTRALEAN
540 #endif
541 #if !defined(NOMINMAX)
542 #define NOMINMAX
543 #endif
544
545 // In Code::Blocks
546 #if !defined(_WIN32_WINNT)
547 #ifdef HAVE_MSMF
548 #define _WIN32_WINNT 0x0600 // Windows Vista
549 #else
550 #define _WIN32_WINNT 0x0500 // Windows 2000
551 #endif
552 #endif
553
554 #include <windows.h>
555 #undef _WINSOCKAPI_
556#endif
557
558#if defined(OLC_PLATFORM_X11)
559 namespace X11
560 {
561 #include <X11/X.h>
562 #include <X11/Xlib.h>
563 }
564#endif
565
566#if defined(OLC_PLATFORM_GLUT)
567 #if defined(__linux__)
568 #include <GL/glut.h>
569 #include <GL/freeglut_ext.h>
570 #endif
571 #if defined(__APPLE__)
572 #include <GLUT/glut.h>
573 #include <objc/message.h>
574 #include <objc/NSObjCRuntime.h>
575 #endif
576#endif
577#endif
578
579#if defined(OLC_PGE_HEADLESS)
580#if defined max
581#undef max
582#endif
583#if defined min
584#undef min
585#endif
586#endif
587#pragma endregion
588
589
590
591#if !defined(OLC_VECTOR2D_DEFINED)
592 namespace olc
593 {
594 /*
595 A complete 2D geometric vector structure, with a variety
596 of useful utility functions and operator overloads
597 */
598 template<class T>
599 struct v_2d
600 {
601 static_assert(std::is_arithmetic<T>::value, "olc::v_2d<type> must be numeric");
602
603 // x-axis component
604 T x = 0;
605 // y-axis component
606 T y = 0;
607
608 // Default constructor
609 inline constexpr v_2d() = default;
610
611 // Specific constructor
612 inline constexpr v_2d(T _x, T _y) : x(_x), y(_y)
613 {}
614
615 // Copy constructor
616 inline constexpr v_2d(const v_2d& v) = default;
617
618 // Assignment operator
619 inline constexpr v_2d& operator=(const v_2d& v) = default;
620
621
622 // Returns rectangular area of vector
623 inline constexpr auto area() const
624 {
625 return x * y;
626 }
627
628 // Returns magnitude of vector
629 inline auto mag() const
630 {
631 return std::sqrt(x * x + y * y);
632 }
633
634 // Returns magnitude squared of vector (useful for fast comparisons)
635 inline constexpr T mag2() const
636 {
637 return x * x + y * y;
638 }
639
640 // Returns normalised version of vector
641 inline v_2d norm() const
642 {
643 auto r = 1 / mag();
644 return v_2d(x * r, y * r);
645 }
646
647 // Returns vector at 90 degrees to this one
648 inline constexpr v_2d perp() const
649 {
650 return v_2d(-y, x);
651 }
652
653 // Rounds both components down
654 inline constexpr v_2d floor() const
655 {
656 return v_2d(std::floor(x), std::floor(y));
657 }
658
659 // Rounds both components up
660 inline constexpr v_2d ceil() const
661 {
662 return v_2d(std::ceil(x), std::ceil(y));
663 }
664
665 // Returns 'element-wise' max of this and another vector
666 inline constexpr v_2d max(const v_2d& v) const
667 {
668 return v_2d(std::max(x, v.x), std::max(y, v.y));
669 }
670
671 // Returns 'element-wise' min of this and another vector
672 inline constexpr v_2d min(const v_2d& v) const
673 {
674 return v_2d(std::min(x, v.x), std::min(y, v.y));
675 }
676
677 // Calculates scalar dot product between this and another vector
678 inline constexpr auto dot(const v_2d& rhs) const
679 {
680 return this->x * rhs.x + this->y * rhs.y;
681 }
682
683 // Calculates 'scalar' cross product between this and another vector (useful for winding orders)
684 inline constexpr auto cross(const v_2d& rhs) const
685 {
686 return this->x * rhs.y - this->y * rhs.x;
687 }
688
689 // Treat this as polar coordinate (R, Theta), return cartesian equivalent (X, Y)
690 inline constexpr v_2d cart() const
691 {
692 return v_2d(std::cos(y) * x, std::sin(y) * x);
693 }
694
695 // Treat this as cartesian coordinate (X, Y), return polar equivalent (R, Theta)
696 inline constexpr v_2d polar() const
697 {
698 return v_2d(mag(), std::atan2(y, x));
699 }
700
701 // Clamp the components of this vector in between the 'element-wise' minimum and maximum of 2 other vectors
702 inline constexpr v_2d clamp(const v_2d& v1, const v_2d& v2) const
703 {
704 return this->max(v1).min(v2);
705 }
706
707 // Linearly interpolate between this vector, and another vector, given normalised parameter 't'
708 inline constexpr v_2d lerp(const v_2d& v1, const double t) const
709 {
710 return (*this) * (T(1.0 - t)) + (v1 * T(t));
711 }
712
713 // Compare if this vector is numerically equal to another
714 inline constexpr bool operator == (const v_2d& rhs) const
715 {
716 return (this->x == rhs.x && this->y == rhs.y);
717 }
718
719 // Compare if this vector is not numerically equal to another
720 inline constexpr bool operator != (const v_2d& rhs) const
721 {
722 return (this->x != rhs.x || this->y != rhs.y);
723 }
724
725 // Return this vector as a std::string, of the form "(x,y)"
726 inline std::string str() const
727 {
728 return std::string("(") + std::to_string(this->x) + "," + std::to_string(this->y) + ")";
729 }
730
731 // Assuming this vector is incident, given a normal, return the reflection
732 inline constexpr v_2d reflect(const v_2d& n) const
733 {
734 return (*this) - 2.0 * (this->dot(n) * n);
735 }
736
737 // Allow 'casting' from other v_2d types
738 template<class F>
739 inline constexpr operator v_2d<F>() const
740 {
741 return { static_cast<F>(this->x), static_cast<F>(this->y) };
742 }
743 };
744
745 // Multiplication operator overloads between vectors and scalars, and vectors and vectors
746 template<class TL, class TR>
747 inline constexpr auto operator * (const TL& lhs, const v_2d<TR>& rhs)
748 {
749 return v_2d(lhs * rhs.x, lhs * rhs.y);
750 }
751
752 template<class TL, class TR>
753 inline constexpr auto operator * (const v_2d<TL>& lhs, const TR& rhs)
754 {
755 return v_2d(lhs.x * rhs, lhs.y * rhs);
756 }
757
758 template<class TL, class TR>
759 inline constexpr auto operator * (const v_2d<TL>& lhs, const v_2d<TR>& rhs)
760 {
761 return v_2d(lhs.x * rhs.x, lhs.y * rhs.y);
762 }
763
764 template<class TL, class TR>
765 inline constexpr auto operator *= (v_2d<TL>& lhs, const TR& rhs)
766 {
767 lhs = lhs * rhs;
768 return lhs;
769 }
770
771 // Division operator overloads between vectors and scalars, and vectors and vectors
772 template<class TL, class TR>
773 inline constexpr auto operator / (const TL& lhs, const v_2d<TR>& rhs)
774 {
775 return v_2d(lhs / rhs.x, lhs / rhs.y);
776 }
777
778 template<class TL, class TR>
779 inline constexpr auto operator / (const v_2d<TL>& lhs, const TR& rhs)
780 {
781 return v_2d(lhs.x / rhs, lhs.y / rhs);
782 }
783
784 template<class TL, class TR>
785 inline constexpr auto operator / (const v_2d<TL>& lhs, const v_2d<TR>& rhs)
786 {
787 return v_2d(lhs.x / rhs.x, lhs.y / rhs.y);
788 }
789
790 template<class TL, class TR>
791 inline constexpr auto operator /= (v_2d<TL>& lhs, const TR& rhs)
792 {
793 lhs = lhs / rhs;
794 return lhs;
795 }
796
797 // Unary Addition operator (pointless but i like the platinum trophies)
798 template<class T>
799 inline constexpr auto operator + (const v_2d<T>& lhs)
800 {
801 return v_2d(+lhs.x, +lhs.y);
802 }
803
804 // Addition operator overloads between vectors and scalars, and vectors and vectors
805 template<class TL, class TR>
806 inline constexpr auto operator + (const TL& lhs, const v_2d<TR>& rhs)
807 {
808 return v_2d(lhs + rhs.x, lhs + rhs.y);
809 }
810
811 template<class TL, class TR>
812 inline constexpr auto operator + (const v_2d<TL>& lhs, const TR& rhs)
813 {
814 return v_2d(lhs.x + rhs, lhs.y + rhs);
815 }
816
817 template<class TL, class TR>
818 inline constexpr auto operator + (const v_2d<TL>& lhs, const v_2d<TR>& rhs)
819 {
820 return v_2d(lhs.x + rhs.x, lhs.y + rhs.y);
821 }
822
823 template<class TL, class TR>
824 inline constexpr auto operator += (v_2d<TL>& lhs, const TR& rhs)
825 {
826 lhs = lhs + rhs;
827 return lhs;
828 }
829
830 template<class TL, class TR>
831 inline constexpr auto operator += (v_2d<TL>& lhs, const v_2d<TR>& rhs)
832 {
833 lhs = lhs + rhs;
834 return lhs;
835 }
836
837 // Unary negation operator overoad for inverting a vector
838 template<class T>
839 inline constexpr auto operator - (const v_2d<T>& lhs)
840 {
841 return v_2d(-lhs.x, -lhs.y);
842 }
843
844 // Subtraction operator overloads between vectors and scalars, and vectors and vectors
845 template<class TL, class TR>
846 inline constexpr auto operator - (const TL& lhs, const v_2d<TR>& rhs)
847 {
848 return v_2d(lhs - rhs.x, lhs - rhs.y);
849 }
850
851 template<class TL, class TR>
852 inline constexpr auto operator - (const v_2d<TL>& lhs, const TR& rhs)
853 {
854 return v_2d(lhs.x - rhs, lhs.y - rhs);
855 }
856
857 template<class TL, class TR>
858 inline constexpr auto operator - (const v_2d<TL>& lhs, const v_2d<TR>& rhs)
859 {
860 return v_2d(lhs.x - rhs.x, lhs.y - rhs.y);
861 }
862
863 template<class TL, class TR>
864 inline constexpr auto operator -= (v_2d<TL>& lhs, const TR& rhs)
865 {
866 lhs = lhs - rhs;
867 return lhs;
868 }
869
870 // Greater/Less-Than Operator overloads - mathematically useless, but handy for "sorted" container storage
871 template<class TL, class TR>
872 inline constexpr bool operator < (const v_2d<TL>& lhs, const v_2d<TR>& rhs)
873 {
874 return (lhs.y < rhs.y) || (lhs.y == rhs.y && lhs.x < rhs.x);
875 }
876
877 template<class TL, class TR>
878 inline constexpr bool operator > (const v_2d<TL>& lhs, const v_2d<TR>& rhs)
879 {
880 return (lhs.y > rhs.y) || (lhs.y == rhs.y && lhs.x > rhs.x);
881 }
882
883 // Allow olc::v_2d to play nicely with std::cout
884 template<class T>
885 inline constexpr std::ostream& operator << (std::ostream& os, const v_2d<T>& rhs)
886 {
887 os << rhs.str();
888 return os;
889 }
890
891 // Convenient types ready-to-go
896 }
897#define OLC_VECTOR2D_DEFINED 1
898#endif
899
900
901
902// O------------------------------------------------------------------------------O
903// | olcPixelGameEngine INTERFACE DECLARATION |
904// O------------------------------------------------------------------------------O
905#pragma region pge_declaration
906namespace olc
907{
908 class PixelGameEngine;
909 class Sprite;
910
911 // Pixel Game Engine Advanced Configuration
912 constexpr uint8_t nMouseButtons = 5;
913 constexpr uint8_t nDefaultAlpha = 0xFF;
914 constexpr uint32_t nDefaultPixel = uint32_t(nDefaultAlpha << 24);
915 constexpr uint8_t nTabSizeInSpaces = 4;
916 constexpr size_t OLC_MAX_VERTS = 128;
917 enum rcode { FAIL = 0, OK = 1, NO_FILE = -1 };
918
919 // O------------------------------------------------------------------------------O
920 // | olc::Pixel - Represents a 32-Bit RGBA colour |
921 // O------------------------------------------------------------------------------O
922#if !defined(OLC_IGNORE_PIXEL)
923 struct Pixel
924 {
925 union
926 {
927 uint32_t n = nDefaultPixel;
928 struct { uint8_t r; uint8_t g; uint8_t b; uint8_t a; };
929 };
930
932
934 Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = nDefaultAlpha);
935 Pixel(uint32_t p);
936 Pixel& operator = (const Pixel& v) = default;
937 bool operator ==(const Pixel& p) const;
938 bool operator !=(const Pixel& p) const;
939 Pixel operator * (const float i) const;
940 Pixel operator / (const float i) const;
941 Pixel& operator *=(const float i);
942 Pixel& operator /=(const float i);
943 Pixel operator + (const Pixel& p) const;
944 Pixel operator - (const Pixel& p) const;
947 Pixel operator * (const Pixel& p) const;
949 Pixel inv() const;
950 };
951
952 Pixel PixelF(float red, float green, float blue, float alpha = 1.0f);
953 Pixel PixelLerp(const olc::Pixel& p1, const olc::Pixel& p2, float t);
954
955
956 // O------------------------------------------------------------------------------O
957 // | USEFUL CONSTANTS |
958 // O------------------------------------------------------------------------------O
959 static const Pixel
960 GREY(192, 192, 192), DARK_GREY(128, 128, 128), VERY_DARK_GREY(64, 64, 64),
961 RED(255, 0, 0), DARK_RED(128, 0, 0), VERY_DARK_RED(64, 0, 0),
962 YELLOW(255, 255, 0), DARK_YELLOW(128, 128, 0), VERY_DARK_YELLOW(64, 64, 0),
963 GREEN(0, 255, 0), DARK_GREEN(0, 128, 0), VERY_DARK_GREEN(0, 64, 0),
964 CYAN(0, 255, 255), DARK_CYAN(0, 128, 128), VERY_DARK_CYAN(0, 64, 64),
965 BLUE(0, 0, 255), DARK_BLUE(0, 0, 128), VERY_DARK_BLUE(0, 0, 64),
966 MAGENTA(255, 0, 255), DARK_MAGENTA(128, 0, 128), VERY_DARK_MAGENTA(64, 0, 64),
967 WHITE(255, 255, 255), BLACK(0, 0, 0), BLANK(0, 0, 0, 0);
968#endif
969 // Thanks to scripticuk and others for updating the key maps
970 // NOTE: The GLUT platform will need updating, open to contributions ;)
986
987 namespace Mouse
988 {
989 static constexpr int32_t LEFT = 0;
990 static constexpr int32_t RIGHT = 1;
991 static constexpr int32_t MIDDLE = 2;
992 };
993
994 // O------------------------------------------------------------------------------O
995 // | olc::HWButton - Represents the state of a hardware button (mouse/key/joy) |
996 // O------------------------------------------------------------------------------O
997 struct HWButton
998 {
999 bool bPressed = false; // Set once during the frame the event occurs
1000 bool bReleased = false; // Set once during the frame the event occurs
1001 bool bHeld = false; // Set true for all frames between pressed and released events
1002 };
1003
1004
1005 // O------------------------------------------------------------------------------O
1006 // | olc::ResourcePack - A virtual scrambled filesystem to pack your assets into |
1007 // O------------------------------------------------------------------------------O
1008 struct ResourceBuffer : public std::streambuf
1009 {
1010 ResourceBuffer(std::ifstream& ifs, uint32_t offset, uint32_t size);
1011 std::vector<char> vMemory;
1012 };
1013
1014 class ResourcePack : public std::streambuf
1015 {
1016 public:
1019 bool AddFile(const std::string& sFile);
1020 bool LoadPack(const std::string& sFile, const std::string& sKey);
1021 bool SavePack(const std::string& sFile, const std::string& sKey);
1022 ResourceBuffer GetFileBuffer(const std::string& sFile);
1023 bool Loaded();
1024 private:
1025 struct sResourceFile { uint32_t nSize; uint32_t nOffset; };
1026 std::map<std::string, sResourceFile> mapFiles;
1027 std::ifstream baseFile;
1028 std::vector<char> scramble(const std::vector<char>& data, const std::string& key);
1029 std::string makeposix(const std::string& path);
1030 };
1031
1032
1034 {
1035 public:
1036 ImageLoader() = default;
1037 virtual ~ImageLoader() = default;
1038 virtual olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) = 0;
1039 virtual olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) = 0;
1040 };
1041
1042
1043 // O------------------------------------------------------------------------------O
1044 // | olc::Sprite - An image represented by a 2D array of olc::Pixel |
1045 // O------------------------------------------------------------------------------O
1047 {
1048 public:
1050 Sprite(const std::string& sImageFile, olc::ResourcePack* pack = nullptr);
1051 Sprite(int32_t w, int32_t h);
1052 Sprite(const olc::Sprite&) = delete;
1054
1055 public:
1056 olc::rcode LoadFromFile(const std::string& sImageFile, olc::ResourcePack* pack = nullptr);
1057
1058 public:
1059 int32_t width = 0;
1060 int32_t height = 0;
1062 enum Flip { NONE = 0, HORIZ = 1, VERT = 2 };
1063
1064 public:
1066 Pixel GetPixel(int32_t x, int32_t y) const;
1067 bool SetPixel(int32_t x, int32_t y, Pixel p);
1068 Pixel GetPixel(const olc::vi2d& a) const;
1069 bool SetPixel(const olc::vi2d& a, Pixel p);
1070 Pixel Sample(float x, float y) const;
1071 Pixel Sample(const olc::vf2d& uv) const;
1072 Pixel SampleBL(float u, float v) const;
1073 Pixel SampleBL(const olc::vf2d& uv) const;
1076 olc::Sprite* Duplicate(const olc::vi2d& vPos, const olc::vi2d& vSize);
1078 void SetSize(int32_t w, int32_t h);
1079 std::vector<olc::Pixel> pColData;
1081
1082 static std::unique_ptr<olc::ImageLoader> loader;
1083 };
1084
1085 // O------------------------------------------------------------------------------O
1086 // | olc::Decal - A GPU resident storage of an olc::Sprite |
1087 // O------------------------------------------------------------------------------O
1088 class Decal
1089 {
1090 public:
1091 Decal(olc::Sprite* spr, bool filter = false, bool clamp = true);
1092 Decal(const uint32_t nExistingTextureResource, olc::Sprite* spr);
1093 virtual ~Decal();
1094 void Update();
1096
1097 public: // But dont touch
1098 int32_t id = -1;
1100 olc::vf2d vUVScale = { 1.0f, 1.0f };
1101 };
1102
1103 enum class DecalMode
1104 {
1105 NORMAL,
1106 ADDITIVE,
1108 STENCIL,
1109 ILLUMINATE,
1110 WIREFRAME,
1111 };
1112
1114 {
1115 LINE,
1116 FAN,
1117 STRIP,
1118 LIST
1119 };
1120
1121 // O------------------------------------------------------------------------------O
1122 // | olc::Renderable - Convenience class to keep a sprite and decal together |
1123 // O------------------------------------------------------------------------------O
1125 {
1126 public:
1127 Renderable() = default;
1128 Renderable(Renderable&& r) = default;
1130 Renderable(const Renderable&) = delete;
1131 olc::rcode Load(const std::string& sFile, ResourcePack* pack = nullptr, bool filter = false, bool clamp = true);
1132 void Create(uint32_t width, uint32_t height, bool filter = false, bool clamp = true);
1135
1136
1137 private:
1138 std::unique_ptr<olc::Sprite> pSprite = nullptr;
1139 std::unique_ptr<olc::Decal> pDecal = nullptr;
1140 };
1141
1142
1143 // O------------------------------------------------------------------------------O
1144 // | Auxilliary components internal to engine |
1145 // O------------------------------------------------------------------------------O
1146
1148 {
1149 olc::Decal* decal = nullptr;
1150 std::vector<olc::vf2d> pos;
1151 std::vector<olc::vf2d> uv;
1152 std::vector<float> w;
1153 std::vector<float> z;
1154 std::vector<olc::Pixel> tint;
1157 uint32_t points = 0;
1158 bool depth = false;
1159 };
1160
1162 {
1163 olc::vf2d vOffset = { 0, 0 };
1164 olc::vf2d vScale = { 1, 1 };
1165 bool bShow = false;
1166 bool bUpdate = false;
1168 uint32_t nResID = 0;
1169 std::vector<DecalInstance> vecDecalInstance;
1171 std::function<void()> funcHook = nullptr;
1172 };
1173
1175 {
1176 public:
1177 virtual ~Renderer() = default;
1178 virtual void PrepareDevice() = 0;
1179 virtual olc::rcode CreateDevice(std::vector<void*> params, bool bFullScreen, bool bVSYNC) = 0;
1181 virtual void DisplayFrame() = 0;
1182 virtual void PrepareDrawing() = 0;
1183 virtual void SetDecalMode(const olc::DecalMode& mode) = 0;
1184 virtual void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) = 0;
1185 virtual void DrawDecal(const olc::DecalInstance& decal) = 0;
1186 virtual uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered = false, const bool clamp = true) = 0;
1187 virtual void UpdateTexture(uint32_t id, olc::Sprite* spr) = 0;
1188 virtual void ReadTexture(uint32_t id, olc::Sprite* spr) = 0;
1189 virtual uint32_t DeleteTexture(const uint32_t id) = 0;
1190 virtual void ApplyTexture(uint32_t id) = 0;
1191 virtual void UpdateViewport(const olc::vi2d& pos, const olc::vi2d& size) = 0;
1192 virtual void ClearBuffer(olc::Pixel p, bool bDepth) = 0;
1194 };
1195
1197 {
1198 public:
1199 virtual ~Platform() = default;
1204 virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) = 0;
1205 virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) = 0;
1206 virtual olc::rcode SetWindowTitle(const std::string& s) = 0;
1207 virtual olc::rcode ShowWindowFrame(const bool bShowFrame = true) = 0;
1208 virtual olc::rcode SetWindowSize(const olc::vi2d& vWindowPos, const olc::vi2d& vWindowSize) = 0;
1212 };
1213
1214 class PGEX;
1215
1216 // The Static Twins (plus one)
1217 static std::unique_ptr<Renderer> renderer;
1218 static std::unique_ptr<Platform> platform;
1219 static std::map<size_t, uint8_t> mapKeys;
1220
1221 // O------------------------------------------------------------------------------O
1222 // | olc::PixelGameEngine - The main BASE class for your application |
1223 // O------------------------------------------------------------------------------O
1225 {
1226 public:
1229 public:
1230 olc::rcode Construct(int32_t screen_w, int32_t screen_h, int32_t pixel_w, int32_t pixel_h,
1231 bool full_screen = false, bool vsync = false, bool cohesion = false, bool realwindow = false);
1233
1234 public: // User Override Interfaces
1235 // Called once on application startup, use to load your resources
1236 virtual bool OnUserCreate();
1237 // Called every frame, and provides you with a time per frame value
1238 virtual bool OnUserUpdate(float fElapsedTime);
1239 // Called once on application termination, so you can be one clean coder
1240 virtual bool OnUserDestroy();
1241
1242 // Called when a text entry is confirmed with "enter" key
1243 virtual void OnTextEntryComplete(const std::string& sText);
1244 // Called when a console command is executed
1245 virtual bool OnConsoleCommand(const std::string& sCommand);
1246
1247
1248 public: // Hardware Interfaces
1249 // Returns true if window is currently in focus
1250 bool IsFocused() const;
1251 // Get the state of a specific keyboard button
1253 // Get the state of a specific mouse button
1254 HWButton GetMouse(uint32_t b) const;
1255 // Get Mouse X coordinate in "pixel" space
1256 int32_t GetMouseX() const;
1257 // Get Mouse Y coordinate in "pixel" space
1258 int32_t GetMouseY() const;
1259 // Get Mouse Wheel Delta
1260 int32_t GetMouseWheel() const;
1261 // Get the mouse in window space
1263 // Gets the mouse as a vector to keep Tarriest happy
1264 const olc::vi2d& GetMousePos() const;
1265
1266 static const std::map<size_t, uint8_t>& GetKeyMap() { return mapKeys; }
1267
1268 // Muck about with the GUI
1269 olc::rcode SetWindowSize(const olc::vi2d& vPos, const olc::vi2d& vSize);
1270 olc::rcode ShowWindowFrame(const bool bShowFrame);
1271
1272 public: // Utility
1273 // Returns the width of the screen in "pixels"
1274 int32_t ScreenWidth() const;
1275 // Returns the height of the screen in "pixels"
1276 int32_t ScreenHeight() const;
1277 // Returns the width of the currently selected drawing target in "pixels"
1278 int32_t GetDrawTargetWidth() const;
1279 // Returns the height of the currently selected drawing target in "pixels"
1280 int32_t GetDrawTargetHeight() const;
1281 // Returns the currently active draw target
1283 // Resize the primary screen sprite
1284 void SetScreenSize(int w, int h);
1285 // Specify which Sprite should be the target of drawing functions, use nullptr
1286 // to specify the primary screen
1287 void SetDrawTarget(Sprite* target);
1288 // Gets the current Frames Per Second
1289 uint32_t GetFPS() const;
1290 // Gets last update of elapsed time
1291 float GetElapsedTime() const;
1292 // Gets Actual Window size
1293 const olc::vi2d& GetWindowSize() const;
1294 // Gets Actual Window position
1295 const olc::vi2d& GetWindowPos() const;
1296 // Gets pixel scale
1297 const olc::vi2d& GetPixelSize() const;
1298 // Gets actual pixel scale
1300 // Gets "screen" size
1301 const olc::vi2d& GetScreenSize() const;
1302 // Gets any files dropped this frame
1303 const std::vector<std::string>& GetDroppedFiles() const;
1305
1306 public: // CONFIGURATION ROUTINES
1307 // Layer targeting functions
1308 void SetDrawTarget(uint8_t layer, bool bDirty = true);
1309 void EnableLayer(uint8_t layer, bool b);
1310 void SetLayerOffset(uint8_t layer, const olc::vf2d& offset);
1311 void SetLayerOffset(uint8_t layer, float x, float y);
1312 void SetLayerScale(uint8_t layer, const olc::vf2d& scale);
1313 void SetLayerScale(uint8_t layer, float x, float y);
1314 void SetLayerTint(uint8_t layer, const olc::Pixel& tint);
1315 void SetLayerCustomRenderFunction(uint8_t layer, std::function<void()> f);
1316
1317 std::vector<LayerDesc>& GetLayers();
1318 uint32_t CreateLayer();
1319
1320 // Change the pixel mode for different optimisations
1321 // olc::Pixel::NORMAL = No transparency
1322 // olc::Pixel::MASK = Transparent if alpha is < 255
1323 // olc::Pixel::ALPHA = Full transparency
1326 // Use a custom blend function
1327 void SetPixelMode(std::function<olc::Pixel(const int x, const int y, const olc::Pixel& pSource, const olc::Pixel& pDest)> pixelMode);
1328 // Change the blend factor from between 0.0f to 1.0f;
1329 void SetPixelBlend(float fBlend);
1330
1331 // [ADVANCED] For those that really want to dick about with PGE :P
1332 // Note: Normal use of olc::PGE does not require you use these functions
1333 void adv_ManualRenderEnable(const bool bEnable);
1334 void adv_HardwareClip(const bool bScale, const olc::vi2d& viewPos, const olc::vi2d& viewSize, const bool bClear = false);
1335 void adv_FlushLayer(const size_t nLayerID);
1336 void adv_FlushLayerDecals(const size_t nLayerID);
1337
1338 public: // DRAWING ROUTINES
1339 // Draws a single Pixel
1340 virtual bool Draw(int32_t x, int32_t y, Pixel p = olc::WHITE);
1341 bool Draw(const olc::vi2d& pos, Pixel p = olc::WHITE);
1342 // Draws a line from (x1,y1) to (x2,y2)
1343 void DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p = olc::WHITE, uint32_t pattern = 0xFFFFFFFF);
1344 void DrawLine(const olc::vi2d& pos1, const olc::vi2d& pos2, Pixel p = olc::WHITE, uint32_t pattern = 0xFFFFFFFF);
1345 // Draws a circle located at (x,y) with radius
1346 void DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p = olc::WHITE, uint8_t mask = 0xFF);
1347 void DrawCircle(const olc::vi2d& pos, int32_t radius, Pixel p = olc::WHITE, uint8_t mask = 0xFF);
1348 // Fills a circle located at (x,y) with radius
1349 void FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p = olc::WHITE);
1350 void FillCircle(const olc::vi2d& pos, int32_t radius, Pixel p = olc::WHITE);
1351 // Draws a rectangle at (x,y) to (x+w,y+h)
1352 void DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p = olc::WHITE);
1353 void DrawRect(const olc::vi2d& pos, const olc::vi2d& size, Pixel p = olc::WHITE);
1354 // Fills a rectangle at (x,y) to (x+w,y+h)
1355 void FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p = olc::WHITE);
1356 void FillRect(const olc::vi2d& pos, const olc::vi2d& size, Pixel p = olc::WHITE);
1357 // Draws a triangle between points (x1,y1), (x2,y2) and (x3,y3)
1358 void DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p = olc::WHITE);
1359 void DrawTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p = olc::WHITE);
1360 // Flat fills a triangle between points (x1,y1), (x2,y2) and (x3,y3)
1361 void FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p = olc::WHITE);
1362 void FillTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p = olc::WHITE);
1363 // Fill a textured and coloured triangle
1364 void FillTexturedTriangle(std::vector<olc::vf2d> vPoints, std::vector<olc::vf2d> vTex, std::vector<olc::Pixel> vColour, olc::Sprite* sprTex);
1365 void FillTexturedPolygon(const std::vector<olc::vf2d>& vPoints, const std::vector<olc::vf2d>& vTex, const std::vector<olc::Pixel>& vColour, olc::Sprite* sprTex, olc::DecalStructure structure = olc::DecalStructure::LIST);
1366 // Draws an entire sprite at location (x,y)
1367 void DrawSprite(int32_t x, int32_t y, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE);
1368 void DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE);
1369 // Draws an area of a sprite at location (x,y), where the
1370 // selected area is (ox,oy) to (ox+w,oy+h)
1371 void DrawPartialSprite(int32_t x, int32_t y, Sprite* sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE);
1372 void DrawPartialSprite(const olc::vi2d& pos, Sprite* sprite, const olc::vi2d& sourcepos, const olc::vi2d& size, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE);
1373 // Draws a single line of text - traditional monospaced
1374 void DrawString(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
1375 void DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
1376 olc::vi2d GetTextSize(const std::string& s);
1377 // Draws a single line of text - non-monospaced
1378 void DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
1379 void DrawStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
1380 olc::vi2d GetTextSizeProp(const std::string& s);
1381
1382 // Decal Quad functions
1383 void SetDecalMode(const olc::DecalMode& mode);
1385 // Draws a whole decal, with optional scale and tinting
1386 void DrawDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE);
1387 // Draws a region of a decal, with optional scale and tinting
1388 void DrawPartialDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE);
1389 void DrawPartialDecal(const olc::vf2d& pos, const olc::vf2d& size, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE);
1390 // Draws fully user controlled 4 vertices, pos(pixels), uv(pixels), colours
1391 void DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col, uint32_t elements = 4);
1392 // Draws a decal with 4 arbitrary points, warping the texture to look "correct"
1393 void DrawWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::Pixel& tint = olc::WHITE);
1394 void DrawWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::Pixel& tint = olc::WHITE);
1395 void DrawWarpedDecal(olc::Decal* decal, const std::array<olc::vf2d, 4>& pos, const olc::Pixel& tint = olc::WHITE);
1396 // As above, but you can specify a region of a decal source sprite
1397 void DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE);
1398 void DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE);
1399 void DrawPartialWarpedDecal(olc::Decal* decal, const std::array<olc::vf2d, 4>& pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE);
1400 // Draws a decal rotated to specified angle, wit point of rotation offset
1401 void DrawRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE);
1402 void DrawPartialRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f, 1.0f }, const olc::Pixel& tint = olc::WHITE);
1403 // Draws a multiline string as a decal, with tiniting and scaling
1404 void DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f });
1405 void DrawStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f });
1406 // Draws a single shaded filled rectangle as a decal
1407 void DrawRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::WHITE);
1408 void FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::WHITE);
1409 // Draws a corner shaded rectangle as a decal
1410 void GradientFillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel colTL, const olc::Pixel colBL, const olc::Pixel colBR, const olc::Pixel colTR);
1411 // Draws a single shaded filled triangle as a decal
1412 void FillTriangleDecal(const olc::vf2d& p0, const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col = olc::WHITE);
1413 // Draws a corner shaded triangle as a decal
1414 void GradientTriangleDecal(const olc::vf2d& p0, const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c0, const olc::Pixel c1, const olc::Pixel c2);
1415 // Draws an arbitrary convex textured polygon using GPU
1416 void DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<olc::vf2d>& uv, const olc::Pixel tint = olc::WHITE);
1417 void DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<float>& depth, const std::vector<olc::vf2d>& uv, const olc::Pixel tint = olc::WHITE);
1418 void DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<olc::vf2d>& uv, const std::vector<olc::Pixel>& tint);
1419 void DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<olc::vf2d>& uv, const std::vector<olc::Pixel>& colours, const olc::Pixel tint);
1420 void DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<float>& depth, const std::vector<olc::vf2d>& uv, const std::vector<olc::Pixel>& colours, const olc::Pixel tint);
1421
1422 // Draws a line in Decal Space
1423 void DrawLineDecal(const olc::vf2d& pos1, const olc::vf2d& pos2, Pixel p = olc::WHITE);
1424 void DrawRotatedStringDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f });
1425 void DrawRotatedStringPropDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f });
1426 // Clears entire draw target to Pixel
1427 void Clear(Pixel p);
1428 // Clears the rendering back buffer
1429 void ClearBuffer(Pixel p, bool bDepth = true);
1430 // Returns the font image
1432
1433 // Clip a line segment to visible area
1435
1436 // Dont allow PGE to mark layers as dirty, so pixel graphics don't update
1437 void EnablePixelTransfer(const bool bEnable = true);
1438
1439 // Command Console Routines
1440 void ConsoleShow(const olc::Key &keyExit, bool bSuspendTime = true);
1441 bool IsConsoleShowing() const;
1443 std::stringstream& ConsoleOut();
1444 void ConsoleCaptureStdOut(const bool bCapture);
1445
1446 // Text Entry Routines
1447 void TextEntryEnable(const bool bEnable, const std::string& sText = "");
1448 std::string TextEntryGetString() const;
1449 int32_t TextEntryGetCursor() const;
1451
1452
1453
1454 private:
1455 void UpdateTextEntry();
1456 void UpdateConsole();
1457
1458 public:
1459
1460 // Experimental Lightweight 3D Routines ================
1461#ifdef OLC_ENABLE_EXPERIMENTAL
1462 // Set Manual View Matrix
1463 void LW3D_View(const std::array<float, 16>& m);
1464 // Set Manual World Matrix
1465 void LW3D_World(const std::array<float, 16>& m);
1466 // Set Manual Projection Matrix
1467 void LW3D_Projection(const std::array<float, 16>& m);
1468
1469 // Draws a vector of vertices, interprted as individual triangles
1470 void LW3D_DrawTriangles(olc::Decal* decal, const std::vector<std::array<float,3>>& pos, const std::vector<olc::vf2d>& tex, const std::vector<olc::Pixel>& col);
1471 void LW3D_DrawWarpedDecal(olc::Decal* decal, const std::vector<std::array<float, 3>>& pos, const olc::Pixel& tint);
1472
1473 void LW3D_ModelTranslate(const float x, const float y, const float z);
1474
1475 // Camera convenience functions
1476 void LW3D_SetCameraAtTarget(const float fEyeX, const float fEyeY, const float fEyeZ,
1477 const float fTargetX, const float fTargetY, const float fTargetZ,
1478 const float fUpX = 0.0f, const float fUpY = 1.0f, const float fUpZ = 0.0f);
1479 void LW3D_SetCameraAlongDirection(const float fEyeX, const float fEyeY, const float fEyeZ,
1480 const float fDirX, const float fDirY, const float fDirZ,
1481 const float fUpX = 0.0f, const float fUpY = 1.0f, const float fUpZ = 0.0f);
1482
1483 // 3D Rendering Flags
1484 void LW3D_EnableDepthTest(const bool bEnableDepth);
1485 void LW3D_EnableBackfaceCulling(const bool bEnableCull);
1486#endif
1487 public: // Branding
1488 std::string sAppName;
1489
1490 private: // Inner mysterious workings
1491 olc::Sprite* pDrawTarget = nullptr;
1492 Pixel::Mode nPixelMode = Pixel::NORMAL;
1493 float fBlendFactor = 1.0f;
1494 olc::vi2d vScreenSize = { 256, 240 };
1495 olc::vf2d vInvScreenSize = { 1.0f / 256.0f, 1.0f / 240.0f };
1496 olc::vi2d vPixelSize = { 4, 4 };
1497 olc::vi2d vScreenPixelSize = { 4, 4 };
1498 olc::vi2d vMousePos = { 0, 0 };
1499 int32_t nMouseWheelDelta = 0;
1500 olc::vi2d vMousePosCache = { 0, 0 };
1501 olc::vi2d vMouseWindowPos = { 0, 0 };
1502 int32_t nMouseWheelDeltaCache = 0;
1503 olc::vi2d vWindowPos = { 0, 0 };
1504 olc::vi2d vWindowSize = { 0, 0 };
1505 olc::vi2d vViewPos = { 0, 0 };
1506 olc::vi2d vViewSize = { 0,0 };
1507 bool bFullScreen = false;
1508 olc::vf2d vPixel = { 1.0f, 1.0f };
1509 bool bHasInputFocus = false;
1510 bool bHasMouseFocus = false;
1511 bool bEnableVSYNC = false;
1512 bool bRealWindowMode = false;
1513 bool bResizeRequested = false;
1514 olc::vi2d vResizeRequested = { 0, 0 };
1515 float fFrameTimer = 1.0f;
1516 float fLastElapsed = 0.0f;
1517 int nFrameCount = 0;
1518 bool bSuspendTextureTransfer = false;
1519 Renderable fontRenderable;
1520 std::vector<LayerDesc> vLayers;
1521 uint8_t nTargetLayer = 0;
1522 uint32_t nLastFPS = 0;
1523 bool bManualRenderEnable = false;
1524 bool bPixelCohesion = false;
1525 DecalMode nDecalMode = DecalMode::NORMAL;
1526 DecalStructure nDecalStructure = DecalStructure::FAN;
1527 std::function<olc::Pixel(const int x, const int y, const olc::Pixel&, const olc::Pixel&)> funcPixelMode;
1528 std::chrono::time_point<std::chrono::system_clock> m_tp1, m_tp2;
1529 std::vector<olc::vi2d> vFontSpacing;
1530 std::vector<std::string> vDroppedFiles;
1531 std::vector<std::string> vDroppedFilesCache;
1532 olc::vi2d vDroppedFilesPoint;
1533 olc::vi2d vDroppedFilesPointCache;
1534
1535 // Command Console Specific
1536 bool bConsoleShow = false;
1537 bool bConsoleSuspendTime = false;
1538 olc::Key keyConsoleExit = olc::Key::F1;
1539 std::stringstream ssConsoleOutput;
1540 std::streambuf* sbufOldCout = nullptr;
1541 olc::vi2d vConsoleSize;
1542 olc::vi2d vConsoleCursor = { 0,0 };
1543 olc::vf2d vConsoleCharacterScale = { 1.0f, 2.0f };
1544 std::vector<std::string> sConsoleLines;
1545 std::list<std::string> sCommandHistory;
1546 std::list<std::string>::iterator sCommandHistoryIt;
1547
1548 // Text Entry Specific
1549 bool bTextEntryEnable = false;
1550 std::string sTextEntryString = "";
1551 int32_t nTextEntryCursor = 0;
1552 std::vector<std::tuple<olc::Key, std::string, std::string>> vKeyboardMap;
1553
1554
1555
1556 // State of keyboard
1557 bool pKeyNewState[256] = { 0 };
1558 bool pKeyOldState[256] = { 0 };
1559 HWButton pKeyboardState[256] = { 0 };
1560
1561 // State of mouse
1562 bool pMouseNewState[nMouseButtons] = { 0 };
1563 bool pMouseOldState[nMouseButtons] = { 0 };
1564 HWButton pMouseState[nMouseButtons] = { 0 };
1565
1566 // The main engine thread
1567 void EngineThread();
1568
1569
1570 // If anything sets this flag to false, the engine
1571 // "should" shut down gracefully
1572 static std::atomic<bool> bAtomActive;
1573
1574 public:
1575 // "Break In" Functions
1576 void olc_UpdateMouse(int32_t x, int32_t y);
1577 void olc_UpdateMouseWheel(int32_t delta);
1578 void olc_UpdateWindowPos(int32_t x, int32_t y);
1579 void olc_UpdateWindowSize(int32_t x, int32_t y);
1584 void olc_UpdateMouseState(int32_t button, bool state);
1585 void olc_UpdateKeyState(int32_t key, bool state);
1586 void olc_UpdateMouseFocus(bool state);
1587 void olc_UpdateKeyFocus(bool state);
1589 void olc_DropFiles(int32_t x, int32_t y, const std::vector<std::string>& vFiles);
1592
1593 // At the very end of this file, chooses which
1594 // components to compile
1595 virtual void olc_ConfigureSystem();
1596
1597 // NOTE: Items Here are to be deprecated, I have left them in for now
1598 // in case you are using them, but they will be removed.
1599 // olc::vf2d vSubPixelOffset = { 0.0f, 0.0f };
1600
1601 public: // PGEX Stuff
1602 friend class PGEX;
1604
1605 private:
1606 std::vector<olc::PGEX*> vExtensions;
1607 };
1608
1609
1610
1611 // O------------------------------------------------------------------------------O
1612 // | PGE EXTENSION BASE CLASS - Permits access to PGE functions from extension |
1613 // O------------------------------------------------------------------------------O
1614 class PGEX
1615 {
1617 public:
1618 PGEX(bool bHook = false);
1619
1620 protected:
1621 virtual void OnBeforeUserCreate();
1622 virtual void OnAfterUserCreate();
1623 virtual bool OnBeforeUserUpdate(float &fElapsedTime);
1624 virtual void OnAfterUserUpdate(float fElapsedTime);
1625
1626 protected:
1628 };
1629}
1630
1631#pragma endregion
1632
1633
1634#pragma region opengl33_iface
1635// In order to facilitate more advanced graphics features, some PGEX
1636// will rely on shaders. Instead of having each PGEX responsible for
1637// managing this, for convenience, this interface exists.
1638
1639#if defined(OLC_GFX_OPENGL33)
1640
1641 #if defined(OLC_PLATFORM_WINAPI)
1642 #include <gl/GL.h>
1643 #define CALLSTYLE __stdcall
1644 #endif
1645
1646 #if defined(__linux__) || defined(__FreeBSD__)
1647 #include <GL/gl.h>
1648 #endif
1649
1650 #if defined(OLC_PLATFORM_X11)
1651 namespace X11 {
1652 #include <GL/glx.h>
1653 }
1654 #define CALLSTYLE
1655 #endif
1656
1657 #if defined(__APPLE__)
1658 #define GL_SILENCE_DEPRECATION
1659 #include <OpenGL/OpenGL.h>
1660 #include <OpenGL/gl.h>
1661 #include <OpenGL/glu.h>
1662 #endif
1663
1664 #if defined(OLC_PLATFORM_EMSCRIPTEN)
1665 #include <EGL/egl.h>
1666 #include <GLES2/gl2.h>
1667 #define GL_GLEXT_PROTOTYPES
1668 #include <GLES2/gl2ext.h>
1669 #include <emscripten/emscripten.h>
1670 #define CALLSTYLE
1671 #define GL_CLAMP GL_CLAMP_TO_EDGE
1672 #endif
1673
1674namespace olc
1675{
1676 typedef char GLchar;
1677 typedef ptrdiff_t GLsizeiptr;
1678
1679 typedef GLuint CALLSTYLE locCreateShader_t(GLenum type);
1680 typedef GLuint CALLSTYLE locCreateProgram_t(void);
1681 typedef void CALLSTYLE locDeleteShader_t(GLuint shader);
1682 typedef void CALLSTYLE locCompileShader_t(GLuint shader);
1683 typedef void CALLSTYLE locLinkProgram_t(GLuint program);
1684 typedef void CALLSTYLE locDeleteProgram_t(GLuint program);
1685 typedef void CALLSTYLE locAttachShader_t(GLuint program, GLuint shader);
1686 typedef void CALLSTYLE locBindBuffer_t(GLenum target, GLuint buffer);
1687 typedef void CALLSTYLE locBufferData_t(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
1688 typedef void CALLSTYLE locGenBuffers_t(GLsizei n, GLuint* buffers);
1689 typedef void CALLSTYLE locVertexAttribPointer_t(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
1690 typedef void CALLSTYLE locEnableVertexAttribArray_t(GLuint index);
1691 typedef void CALLSTYLE locUseProgram_t(GLuint program);
1692 typedef void CALLSTYLE locBindVertexArray_t(GLuint array);
1693 typedef void CALLSTYLE locGenVertexArrays_t(GLsizei n, GLuint* arrays);
1694 typedef void CALLSTYLE locGetShaderInfoLog_t(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
1695 typedef GLint CALLSTYLE locGetUniformLocation_t(GLuint program, const GLchar* name);
1696 typedef void CALLSTYLE locUniform1f_t(GLint location, GLfloat v0);
1697 typedef void CALLSTYLE locUniform1i_t(GLint location, GLint v0);
1698 typedef void CALLSTYLE locUniform2fv_t(GLint location, GLsizei count, const GLfloat* value);
1699 typedef void CALLSTYLE locActiveTexture_t(GLenum texture);
1700 typedef void CALLSTYLE locGenFrameBuffers_t(GLsizei n, GLuint* ids);
1701 typedef void CALLSTYLE locBindFrameBuffer_t(GLenum target, GLuint fb);
1702 typedef GLenum CALLSTYLE locCheckFrameBufferStatus_t(GLenum target);
1703 typedef void CALLSTYLE locDeleteFrameBuffers_t(GLsizei n, const GLuint* fbs);
1704 typedef void CALLSTYLE locFrameBufferTexture2D_t(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
1705 typedef void CALLSTYLE locDrawBuffers_t(GLsizei n, const GLenum* bufs);
1706 typedef void CALLSTYLE locBlendFuncSeparate_t(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
1707
1708#if defined(OLC_PLATFORM_WINAPI)
1709 typedef void __stdcall locSwapInterval_t(GLsizei n);
1710#endif
1711
1712#if defined(OLC_PLATFORM_X11)
1713 typedef int(locSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval);
1714#endif
1715
1716#if defined(OLC_PLATFORM_EMSCRIPTEN)
1717 typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
1718 typedef EGLBoolean(locSwapInterval_t)(EGLDisplay display, EGLint interval);
1719#else
1720 typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar** string, const GLint* length);
1721#endif
1722
1723} // olc namespace
1724#endif // OpenGL33 Definitions
1725#pragma endregion
1726
1727
1728#endif // OLC_PGE_DEF
1729
1730
1731// O------------------------------------------------------------------------------O
1732// | START OF OLC_PGE_APPLICATION |
1733// O------------------------------------------------------------------------------O
1734#ifdef OLC_PGE_APPLICATION
1735#undef OLC_PGE_APPLICATION
1736
1737// O------------------------------------------------------------------------------O
1738// | olcPixelGameEngine INTERFACE IMPLEMENTATION (CORE) |
1739// | Note: The core implementation is platform independent |
1740// O------------------------------------------------------------------------------O
1741#pragma region pge_implementation
1742namespace olc
1743{
1744 // O------------------------------------------------------------------------------O
1745 // | olc::Pixel IMPLEMENTATION |
1746 // O------------------------------------------------------------------------------O
1747#if !defined(OLC_IGNORE_PIXEL)
1748 Pixel::Pixel()
1749 { r = 0; g = 0; b = 0; a = nDefaultAlpha; }
1750
1751 Pixel::Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
1752 { n = red | (green << 8) | (blue << 16) | (alpha << 24); } // Thanks jarekpelczar
1753
1754 Pixel::Pixel(uint32_t p)
1755 { n = p; }
1756
1757 bool Pixel::operator==(const Pixel& p) const
1758 { return n == p.n; }
1759
1760 bool Pixel::operator!=(const Pixel& p) const
1761 { return n != p.n; }
1762
1763 Pixel Pixel::operator * (const float i) const
1764 {
1765 float fR = std::min(255.0f, std::max(0.0f, float(r) * i));
1766 float fG = std::min(255.0f, std::max(0.0f, float(g) * i));
1767 float fB = std::min(255.0f, std::max(0.0f, float(b) * i));
1768 return Pixel(uint8_t(fR), uint8_t(fG), uint8_t(fB), a);
1769 }
1770
1771 Pixel Pixel::operator / (const float i) const
1772 {
1773 float fR = std::min(255.0f, std::max(0.0f, float(r) / i));
1774 float fG = std::min(255.0f, std::max(0.0f, float(g) / i));
1775 float fB = std::min(255.0f, std::max(0.0f, float(b) / i));
1776 return Pixel(uint8_t(fR), uint8_t(fG), uint8_t(fB), a);
1777 }
1778
1779 Pixel& Pixel::operator *=(const float i)
1780 {
1781 this->r = uint8_t(std::min(255.0f, std::max(0.0f, float(r) * i)));
1782 this->g = uint8_t(std::min(255.0f, std::max(0.0f, float(g) * i)));
1783 this->b = uint8_t(std::min(255.0f, std::max(0.0f, float(b) * i)));
1784 return *this;
1785 }
1786
1787 Pixel& Pixel::operator /=(const float i)
1788 {
1789 this->r = uint8_t(std::min(255.0f, std::max(0.0f, float(r) / i)));
1790 this->g = uint8_t(std::min(255.0f, std::max(0.0f, float(g) / i)));
1791 this->b = uint8_t(std::min(255.0f, std::max(0.0f, float(b) / i)));
1792 return *this;
1793 }
1794
1795 Pixel Pixel::operator + (const Pixel& p) const
1796 {
1797 uint8_t nR = uint8_t(std::min(255, std::max(0, int(r) + int(p.r))));
1798 uint8_t nG = uint8_t(std::min(255, std::max(0, int(g) + int(p.g))));
1799 uint8_t nB = uint8_t(std::min(255, std::max(0, int(b) + int(p.b))));
1800 return Pixel(nR, nG, nB, a);
1801 }
1802
1803 Pixel Pixel::operator - (const Pixel& p) const
1804 {
1805 uint8_t nR = uint8_t(std::min(255, std::max(0, int(r) - int(p.r))));
1806 uint8_t nG = uint8_t(std::min(255, std::max(0, int(g) - int(p.g))));
1807 uint8_t nB = uint8_t(std::min(255, std::max(0, int(b) - int(p.b))));
1808 return Pixel(nR, nG, nB, a);
1809 }
1810
1811 Pixel& Pixel::operator += (const Pixel& p)
1812 {
1813 this->r = uint8_t(std::min(255, std::max(0, int(r) + int(p.r))));
1814 this->g = uint8_t(std::min(255, std::max(0, int(g) + int(p.g))));
1815 this->b = uint8_t(std::min(255, std::max(0, int(b) + int(p.b))));
1816 return *this;
1817 }
1818
1819 Pixel& Pixel::operator -= (const Pixel& p) // Thanks Au Lit
1820 {
1821 this->r = uint8_t(std::min(255, std::max(0, int(r) - int(p.r))));
1822 this->g = uint8_t(std::min(255, std::max(0, int(g) - int(p.g))));
1823 this->b = uint8_t(std::min(255, std::max(0, int(b) - int(p.b))));
1824 return *this;
1825 }
1826
1827 Pixel Pixel::operator * (const Pixel& p) const
1828 {
1829 uint8_t nR = uint8_t(std::min(255.0f, std::max(0.0f, float(r) * float(p.r) / 255.0f)));
1830 uint8_t nG = uint8_t(std::min(255.0f, std::max(0.0f, float(g) * float(p.g) / 255.0f)));
1831 uint8_t nB = uint8_t(std::min(255.0f, std::max(0.0f, float(b) * float(p.b) / 255.0f)));
1832 uint8_t nA = uint8_t(std::min(255.0f, std::max(0.0f, float(a) * float(p.a) / 255.0f)));
1833 return Pixel(nR, nG, nB, nA);
1834 }
1835
1836 Pixel& Pixel::operator *=(const Pixel& p)
1837 {
1838 this->r = uint8_t(std::min(255.0f, std::max(0.0f, float(r) * float(p.r) / 255.0f)));
1839 this->g = uint8_t(std::min(255.0f, std::max(0.0f, float(g) * float(p.g) / 255.0f)));
1840 this->b = uint8_t(std::min(255.0f, std::max(0.0f, float(b) * float(p.b) / 255.0f)));
1841 this->a = uint8_t(std::min(255.0f, std::max(0.0f, float(a) * float(p.a) / 255.0f)));
1842 return *this;
1843 }
1844
1845 Pixel Pixel::inv() const
1846 {
1847 uint8_t nR = uint8_t(std::min(255, std::max(0, 255 - int(r))));
1848 uint8_t nG = uint8_t(std::min(255, std::max(0, 255 - int(g))));
1849 uint8_t nB = uint8_t(std::min(255, std::max(0, 255 - int(b))));
1850 return Pixel(nR, nG, nB, a);
1851 }
1852
1853 Pixel PixelF(float red, float green, float blue, float alpha)
1854 { return Pixel(uint8_t(red * 255.0f), uint8_t(green * 255.0f), uint8_t(blue * 255.0f), uint8_t(alpha * 255.0f)); }
1855
1856 Pixel PixelLerp(const olc::Pixel& p1, const olc::Pixel& p2, float t)
1857 { return (p2 * t) + p1 * (1.0f - t); }
1858#endif
1859 // O------------------------------------------------------------------------------O
1860 // | olc::Sprite IMPLEMENTATION |
1861 // O------------------------------------------------------------------------------O
1863 { width = 0; height = 0; }
1864
1865 Sprite::Sprite(const std::string& sImageFile, olc::ResourcePack* pack)
1866 { LoadFromFile(sImageFile, pack); }
1867
1868 Sprite::Sprite(int32_t w, int32_t h)
1869 {
1870 SetSize(w, h);
1871 }
1872
1873 void Sprite::SetSize(int32_t w, int32_t h)
1874 {
1875 width = w; height = h;
1877 }
1878
1880 { pColData.clear(); }
1881
1883 { modeSample = mode; }
1884
1885 Pixel Sprite::GetPixel(const olc::vi2d& a) const
1886 { return GetPixel(a.x, a.y); }
1887
1888 bool Sprite::SetPixel(const olc::vi2d& a, Pixel p)
1889 { return SetPixel(a.x, a.y, p); }
1890
1891 Pixel Sprite::GetPixel(int32_t x, int32_t y) const
1892 {
1894 {
1895 if (x >= 0 && x < width && y >= 0 && y < height)
1896 return pColData[y * width + x];
1897 else
1898 return Pixel(0, 0, 0, 0);
1899 }
1900 else
1901 {
1903 return pColData[abs(y % height) * width + abs(x % width)];
1904 else
1905 return pColData[std::max(0, std::min(y, height-1)) * width + std::max(0, std::min(x, width-1))];
1906 }
1907 }
1908
1909 bool Sprite::SetPixel(int32_t x, int32_t y, Pixel p)
1910 {
1911 if (x >= 0 && x < width && y >= 0 && y < height)
1912 {
1913 pColData[y * width + x] = p;
1914 return true;
1915 }
1916 else
1917 return false;
1918 }
1919
1920 Pixel Sprite::Sample(float x, float y) const
1921 {
1922 int32_t sx = std::min((int32_t)((x * (float)width)), width - 1);
1923 int32_t sy = std::min((int32_t)((y * (float)height)), height - 1);
1924 return GetPixel(sx, sy);
1925 }
1926
1927 Pixel Sprite::Sample(const olc::vf2d& uv) const
1928 {
1929 return Sample(uv.x, uv.y);
1930 }
1931
1932 Pixel Sprite::SampleBL(float u, float v) const
1933 {
1934 u = u * width - 0.5f;
1935 v = v * height - 0.5f;
1936 int x = (int)floor(u); // cast to int rounds toward zero, not downward
1937 int y = (int)floor(v); // Thanks @joshinils
1938 float u_ratio = u - x;
1939 float v_ratio = v - y;
1940 float u_opposite = 1 - u_ratio;
1941 float v_opposite = 1 - v_ratio;
1942
1943 olc::Pixel p1 = GetPixel(std::max(x, 0), std::max(y, 0));
1944 olc::Pixel p2 = GetPixel(std::min(x + 1, (int)width - 1), std::max(y, 0));
1945 olc::Pixel p3 = GetPixel(std::max(x, 0), std::min(y + 1, (int)height - 1));
1946 olc::Pixel p4 = GetPixel(std::min(x + 1, (int)width - 1), std::min(y + 1, (int)height - 1));
1947
1948 return olc::Pixel(
1949 (uint8_t)((p1.r * u_opposite + p2.r * u_ratio) * v_opposite + (p3.r * u_opposite + p4.r * u_ratio) * v_ratio),
1950 (uint8_t)((p1.g * u_opposite + p2.g * u_ratio) * v_opposite + (p3.g * u_opposite + p4.g * u_ratio) * v_ratio),
1951 (uint8_t)((p1.b * u_opposite + p2.b * u_ratio) * v_opposite + (p3.b * u_opposite + p4.b * u_ratio) * v_ratio));
1952 }
1953
1954 Pixel Sprite::SampleBL(const olc::vf2d& uv) const
1955 {
1956 return SampleBL(uv.x, uv.y);
1957 }
1958
1959 Pixel* Sprite::GetData()
1960 { return pColData.data(); }
1961
1962
1963 olc::rcode Sprite::LoadFromFile(const std::string& sImageFile, olc::ResourcePack* pack)
1964 {
1965 UNUSED(pack);
1966 return loader->LoadImageResource(this, sImageFile, pack);
1967 }
1968
1970 {
1971 olc::Sprite* spr = new olc::Sprite(width, height);
1972 std::memcpy(spr->GetData(), GetData(), width * height * sizeof(olc::Pixel));
1973 spr->modeSample = modeSample;
1974 return spr;
1975 }
1976
1977 olc::Sprite* Sprite::Duplicate(const olc::vi2d& vPos, const olc::vi2d& vSize)
1978 {
1979 olc::Sprite* spr = new olc::Sprite(vSize.x, vSize.y);
1980 for (int y = 0; y < vSize.y; y++)
1981 for (int x = 0; x < vSize.x; x++)
1982 spr->SetPixel(x, y, GetPixel(vPos.x + x, vPos.y + y));
1983 return spr;
1984 }
1985
1987 {
1988 return { width, height };
1989 }
1990
1991 // O------------------------------------------------------------------------------O
1992 // | olc::Decal IMPLEMENTATION |
1993 // O------------------------------------------------------------------------------O
1994 Decal::Decal(olc::Sprite* spr, bool filter, bool clamp)
1995 {
1996 id = -1;
1997 if (spr == nullptr) return;
1998 sprite = spr;
1999 id = renderer->CreateTexture(sprite->width, sprite->height, filter, clamp);
2000 Update();
2001 }
2002
2003 Decal::Decal(const uint32_t nExistingTextureResource, olc::Sprite* spr)
2004 {
2005 if (spr == nullptr) return;
2006 id = nExistingTextureResource;
2007 }
2008
2009 void Decal::Update()
2010 {
2011 if (sprite == nullptr) return;
2012 vUVScale = { 1.0f / float(sprite->width), 1.0f / float(sprite->height) };
2013 renderer->ApplyTexture(id);
2014 renderer->UpdateTexture(id, sprite);
2015 }
2016
2017 void Decal::UpdateSprite()
2018 {
2019 if (sprite == nullptr) return;
2020 renderer->ApplyTexture(id);
2021 renderer->ReadTexture(id, sprite);
2022 }
2023
2025 {
2026 if (id != -1)
2027 {
2028 renderer->DeleteTexture(id);
2029 id = -1;
2030 }
2031 }
2032
2033 void Renderable::Create(uint32_t width, uint32_t height, bool filter, bool clamp)
2034 {
2035 pSprite = std::make_unique<olc::Sprite>(width, height);
2036 pDecal = std::make_unique<olc::Decal>(pSprite.get(), filter, clamp);
2037 }
2038
2039 olc::rcode Renderable::Load(const std::string& sFile, ResourcePack* pack, bool filter, bool clamp)
2040 {
2041 pSprite = std::make_unique<olc::Sprite>();
2042 if (pSprite->LoadFromFile(sFile, pack) == olc::rcode::OK)
2043 {
2044 pDecal = std::make_unique<olc::Decal>(pSprite.get(), filter, clamp);
2045 return olc::rcode::OK;
2046 }
2047 else
2048 {
2049 pSprite.release();
2050 pSprite = nullptr;
2051 return olc::rcode::NO_FILE;
2052 }
2053 }
2054
2056 { return pDecal.get(); }
2057
2059 { return pSprite.get(); }
2060
2061 // O------------------------------------------------------------------------------O
2062 // | olc::ResourcePack IMPLEMENTATION |
2063 // O------------------------------------------------------------------------------O
2064
2065
2066 //=============================================================
2067 // Resource Packs - Allows you to store files in one large
2068 // scrambled file - Thanks MaGetzUb for debugging a null char in std::stringstream bug
2069 ResourceBuffer::ResourceBuffer(std::ifstream& ifs, uint32_t offset, uint32_t size)
2070 {
2071 vMemory.resize(size);
2072 ifs.seekg(offset); ifs.read(vMemory.data(), vMemory.size());
2073 setg(vMemory.data(), vMemory.data(), vMemory.data() + size);
2074 }
2075
2077 ResourcePack::~ResourcePack() { baseFile.close(); }
2078
2079 bool ResourcePack::AddFile(const std::string& sFile)
2080 {
2081 const std::string file = makeposix(sFile);
2082
2083 if (_gfs::exists(file))
2084 {
2085 sResourceFile e;
2086 e.nSize = (uint32_t)_gfs::file_size(file);
2087 e.nOffset = 0; // Unknown at this stage
2088 mapFiles[file] = e;
2089 return true;
2090 }
2091 return false;
2092 }
2093
2094 bool ResourcePack::LoadPack(const std::string& sFile, const std::string& sKey)
2095 {
2096 // Open the resource file
2097 baseFile.open(sFile, std::ifstream::binary);
2098 if (!baseFile.is_open()) return false;
2099
2100 // 1) Read Scrambled index
2101 uint32_t nIndexSize = 0;
2102 baseFile.read((char*)&nIndexSize, sizeof(uint32_t));
2103
2104 std::vector<char> buffer(nIndexSize);
2105 for (uint32_t j = 0; j < nIndexSize; j++)
2106 buffer[j] = baseFile.get();
2107
2108 std::vector<char> decoded = scramble(buffer, sKey);
2109 size_t pos = 0;
2110 auto read = [&decoded, &pos](char* dst, size_t size) {
2111 memcpy((void*)dst, (const void*)(decoded.data() + pos), size);
2112 pos += size;
2113 };
2114
2115 auto get = [&read]() -> int { char c; read(&c, 1); return c; };
2116
2117 // 2) Read Map
2118 uint32_t nMapEntries = 0;
2119 read((char*)&nMapEntries, sizeof(uint32_t));
2120 for (uint32_t i = 0; i < nMapEntries; i++)
2121 {
2122 uint32_t nFilePathSize = 0;
2123 read((char*)&nFilePathSize, sizeof(uint32_t));
2124
2125 std::string sFileName(nFilePathSize, ' ');
2126 for (uint32_t j = 0; j < nFilePathSize; j++)
2127 sFileName[j] = get();
2128
2129 sResourceFile e;
2130 read((char*)&e.nSize, sizeof(uint32_t));
2131 read((char*)&e.nOffset, sizeof(uint32_t));
2132 mapFiles[sFileName] = e;
2133 }
2134
2135 // Don't close base file! we will provide a stream
2136 // pointer when the file is requested
2137 return true;
2138 }
2139
2140 bool ResourcePack::SavePack(const std::string& sFile, const std::string& sKey)
2141 {
2142 // Create/Overwrite the resource file
2143 std::ofstream ofs(sFile, std::ofstream::binary);
2144 if (!ofs.is_open()) return false;
2145
2146 // Iterate through map
2147 uint32_t nIndexSize = 0; // Unknown for now
2148 ofs.write((char*)&nIndexSize, sizeof(uint32_t));
2149 uint32_t nMapSize = uint32_t(mapFiles.size());
2150 ofs.write((char*)&nMapSize, sizeof(uint32_t));
2151 for (auto& e : mapFiles)
2152 {
2153 // Write the path of the file
2154 size_t nPathSize = e.first.size();
2155 ofs.write((char*)&nPathSize, sizeof(uint32_t));
2156 ofs.write(e.first.c_str(), nPathSize);
2157
2158 // Write the file entry properties
2159 ofs.write((char*)&e.second.nSize, sizeof(uint32_t));
2160 ofs.write((char*)&e.second.nOffset, sizeof(uint32_t));
2161 }
2162
2163 // 2) Write the individual Data
2164 std::streampos offset = ofs.tellp();
2165 nIndexSize = (uint32_t)offset;
2166 for (auto& e : mapFiles)
2167 {
2168 // Store beginning of file offset within resource pack file
2169 e.second.nOffset = (uint32_t)offset;
2170
2171 // Load the file to be added
2172 std::vector<uint8_t> vBuffer(e.second.nSize);
2173 std::ifstream i(e.first, std::ifstream::binary);
2174 i.read((char*)vBuffer.data(), e.second.nSize);
2175 i.close();
2176
2177 // Write the loaded file into resource pack file
2178 ofs.write((char*)vBuffer.data(), e.second.nSize);
2179 offset += e.second.nSize;
2180 }
2181
2182 // 3) Scramble Index
2183 std::vector<char> stream;
2184 auto write = [&stream](const char* data, size_t size) {
2185 size_t sizeNow = stream.size();
2186 stream.resize(sizeNow + size);
2187 memcpy(stream.data() + sizeNow, data, size);
2188 };
2189
2190 // Iterate through map
2191 write((char*)&nMapSize, sizeof(uint32_t));
2192 for (auto& e : mapFiles)
2193 {
2194 // Write the path of the file
2195 size_t nPathSize = e.first.size();
2196 write((char*)&nPathSize, sizeof(uint32_t));
2197 write(e.first.c_str(), nPathSize);
2198
2199 // Write the file entry properties
2200 write((char*)&e.second.nSize, sizeof(uint32_t));
2201 write((char*)&e.second.nOffset, sizeof(uint32_t));
2202 }
2203 std::vector<char> sIndexString = scramble(stream, sKey);
2204 uint32_t nIndexStringLen = uint32_t(sIndexString.size());
2205 // 4) Rewrite Map (it has been updated with offsets now)
2206 // at start of file
2207 ofs.seekp(0, std::ios::beg);
2208 ofs.write((char*)&nIndexStringLen, sizeof(uint32_t));
2209 ofs.write(sIndexString.data(), nIndexStringLen);
2210 ofs.close();
2211 return true;
2212 }
2213
2214 ResourceBuffer ResourcePack::GetFileBuffer(const std::string& sFile)
2215 { return ResourceBuffer(baseFile, mapFiles[sFile].nOffset, mapFiles[sFile].nSize); }
2216
2218 { return baseFile.is_open(); }
2219
2220 std::vector<char> ResourcePack::scramble(const std::vector<char>& data, const std::string& key)
2221 {
2222 if (key.empty()) return data;
2223 std::vector<char> o;
2224 size_t c = 0;
2225 for (auto s : data) o.push_back(s ^ key[(c++) % key.size()]);
2226 return o;
2227 };
2228
2229 std::string ResourcePack::makeposix(const std::string& path)
2230 {
2231 std::string o;
2232 for (auto s : path) o += std::string(1, s == '\\' ? '/' : s);
2233 return o;
2234 };
2235
2236 // O------------------------------------------------------------------------------O
2237 // | olc::PixelGameEngine IMPLEMENTATION |
2238 // O------------------------------------------------------------------------------O
2240 {
2241 sAppName = "Undefined";
2242 olc::PGEX::pge = this;
2243
2244 // Bring in relevant Platform & Rendering systems depending
2245 // on compiler parameters
2247 }
2248
2250 {}
2251
2252
2253 olc::rcode PixelGameEngine::Construct(int32_t screen_w, int32_t screen_h, int32_t pixel_w, int32_t pixel_h, bool full_screen, bool vsync, bool cohesion, bool realwindow)
2254 {
2255 bPixelCohesion = cohesion;
2256 bRealWindowMode = realwindow;
2257 vScreenSize = { screen_w, screen_h };
2258 vInvScreenSize = { 1.0f / float(screen_w), 1.0f / float(screen_h) };
2259 vPixelSize = { pixel_w, pixel_h };
2260 vWindowSize = vScreenSize * vPixelSize;
2261 bFullScreen = full_screen;
2262 bEnableVSYNC = vsync;
2263 vPixel = 2.0f / vScreenSize;
2264
2265 if (vPixelSize.x <= 0 || vPixelSize.y <= 0 || vScreenSize.x <= 0 || vScreenSize.y <= 0)
2266 return olc::FAIL;
2267 return olc::OK;
2268 }
2269
2270
2271 void PixelGameEngine::SetScreenSize(int w, int h)
2272 {
2273 vScreenSize = { w, h };
2274 vInvScreenSize = { 1.0f / float(w), 1.0f / float(h) };
2275 for (auto& layer : vLayers)
2276 {
2277 layer.pDrawTarget.Create(vScreenSize.x, vScreenSize.y);
2278 layer.bUpdate = true;
2279 }
2280 SetDrawTarget(nullptr);
2281 if (!bRealWindowMode)
2282 {
2283 // Flush backbuffer
2284 renderer->ClearBuffer(olc::BLACK, true);
2285 renderer->DisplayFrame();
2286 renderer->ClearBuffer(olc::BLACK, true);
2287 }
2288 renderer->UpdateViewport(vViewPos, vViewSize);
2289 }
2290
2291#if !defined(PGE_USE_CUSTOM_START)
2293 {
2294 if (platform->ApplicationStartUp() != olc::OK) return olc::FAIL;
2295
2296 // Construct the window
2297 if (platform->CreateWindowPane({ 30,30 }, vWindowSize, bFullScreen) != olc::OK) return olc::FAIL;
2298 olc_UpdateWindowSize(vWindowSize.x, vWindowSize.y);
2299
2300 // Start the thread
2301 bAtomActive = true;
2302 std::thread t = std::thread(&PixelGameEngine::EngineThread, this);
2303
2304 // Some implementations may form an event loop here
2305 platform->StartSystemEventLoop();
2306
2307 // Wait for thread to be exited
2308 t.join();
2309
2310 if (platform->ApplicationCleanUp() != olc::OK) return olc::FAIL;
2311
2312 return olc::OK;
2313 }
2314#endif
2315
2316 void PixelGameEngine::SetDrawTarget(Sprite* target)
2317 {
2318 if (target)
2319 {
2320 pDrawTarget = target;
2321 }
2322 else
2323 {
2324 nTargetLayer = 0;
2325 if(!vLayers.empty())
2326 pDrawTarget = vLayers[0].pDrawTarget.Sprite();
2327 }
2328 }
2329
2330 void PixelGameEngine::SetDrawTarget(uint8_t layer, bool bDirty)
2331 {
2332 if (layer < vLayers.size())
2333 {
2334 pDrawTarget = vLayers[layer].pDrawTarget.Sprite();
2335 vLayers[layer].bUpdate = bDirty;
2336 nTargetLayer = layer;
2337 }
2338 }
2339
2340 void PixelGameEngine::EnableLayer(uint8_t layer, bool b)
2341 { if (layer < vLayers.size()) vLayers[layer].bShow = b; }
2342
2343 void PixelGameEngine::SetLayerOffset(uint8_t layer, const olc::vf2d& offset)
2344 { SetLayerOffset(layer, offset.x, offset.y); }
2345
2346 void PixelGameEngine::SetLayerOffset(uint8_t layer, float x, float y)
2347 { if (layer < vLayers.size()) vLayers[layer].vOffset = { x, y }; }
2348
2349 void PixelGameEngine::SetLayerScale(uint8_t layer, const olc::vf2d& scale)
2350 { SetLayerScale(layer, scale.x, scale.y); }
2351
2352 void PixelGameEngine::SetLayerScale(uint8_t layer, float x, float y)
2353 { if (layer < vLayers.size()) vLayers[layer].vScale = { x, y }; }
2354
2355 void PixelGameEngine::SetLayerTint(uint8_t layer, const olc::Pixel& tint)
2356 { if (layer < vLayers.size()) vLayers[layer].tint = tint; }
2357
2358 void PixelGameEngine::SetLayerCustomRenderFunction(uint8_t layer, std::function<void()> f)
2359 { if (layer < vLayers.size()) vLayers[layer].funcHook = f; }
2360
2361 std::vector<LayerDesc>& PixelGameEngine::GetLayers()
2362 { return vLayers; }
2363
2365 {
2366 LayerDesc ld;
2367 ld.pDrawTarget.Create(vScreenSize.x, vScreenSize.y);
2368 vLayers.push_back(std::move(ld));
2369 return uint32_t(vLayers.size()) - 1;
2370 }
2371
2372 Sprite* PixelGameEngine::GetDrawTarget() const
2373 { return pDrawTarget; }
2374
2376 {
2377 if (pDrawTarget)
2378 return pDrawTarget->width;
2379 else
2380 return 0;
2381 }
2382
2384 {
2385 if (pDrawTarget)
2386 return pDrawTarget->height;
2387 else
2388 return 0;
2389 }
2390
2391 uint32_t PixelGameEngine::GetFPS() const
2392 { return nLastFPS; }
2393
2394 bool PixelGameEngine::IsFocused() const
2395 { return bHasInputFocus; }
2396
2397 HWButton PixelGameEngine::GetKey(Key k) const
2398 { return pKeyboardState[k]; }
2399
2400 HWButton PixelGameEngine::GetMouse(uint32_t b) const
2401 { return pMouseState[b]; }
2402
2403 int32_t PixelGameEngine::GetMouseX() const
2404 { return vMousePos.x; }
2405
2406 int32_t PixelGameEngine::GetMouseY() const
2407 { return vMousePos.y; }
2408
2410 { return vMousePos; }
2411
2412 int32_t PixelGameEngine::GetMouseWheel() const
2413 { return nMouseWheelDelta; }
2414
2415 int32_t PixelGameEngine::ScreenWidth() const
2416 { return vScreenSize.x; }
2417
2418 int32_t PixelGameEngine::ScreenHeight() const
2419 { return vScreenSize.y; }
2420
2422 { return fLastElapsed; }
2423
2425 { return vWindowSize; }
2426
2428 { return vWindowPos; }
2429
2431 { return vPixelSize; }
2432
2434 { return vScreenPixelSize; }
2435
2437 { return vScreenSize; }
2438
2440 { return vMouseWindowPos; }
2441
2442 bool PixelGameEngine::Draw(const olc::vi2d& pos, Pixel p)
2443 { return Draw(pos.x, pos.y, p); }
2444
2445 // This is it, the critical function that plots a pixel
2446 bool PixelGameEngine::Draw(int32_t x, int32_t y, Pixel p)
2447 {
2448 if (!pDrawTarget) return false;
2449
2450 if (nPixelMode == Pixel::NORMAL)
2451 {
2452 return pDrawTarget->SetPixel(x, y, p);
2453 }
2454
2455 if (nPixelMode == Pixel::MASK)
2456 {
2457 if (p.a == 255)
2458 return pDrawTarget->SetPixel(x, y, p);
2459 }
2460
2461 if (nPixelMode == Pixel::ALPHA)
2462 {
2463 Pixel d = pDrawTarget->GetPixel(x, y);
2464 float a = (float)(p.a / 255.0f) * fBlendFactor;
2465 float c = 1.0f - a;
2466 float r = a * (float)p.r + c * (float)d.r;
2467 float g = a * (float)p.g + c * (float)d.g;
2468 float b = a * (float)p.b + c * (float)d.b;
2469 return pDrawTarget->SetPixel(x, y, Pixel((uint8_t)r, (uint8_t)g, (uint8_t)b/*, (uint8_t)(p.a * fBlendFactor)*/));
2470 }
2471
2472 if (nPixelMode == Pixel::CUSTOM)
2473 {
2474 return pDrawTarget->SetPixel(x, y, funcPixelMode(x, y, p, pDrawTarget->GetPixel(x, y)));
2475 }
2476
2477 return false;
2478 }
2479
2480
2481 void PixelGameEngine::DrawLine(const olc::vi2d& pos1, const olc::vi2d& pos2, Pixel p, uint32_t pattern)
2482 { DrawLine(pos1.x, pos1.y, pos2.x, pos2.y, p, pattern); }
2483
2484 void PixelGameEngine::DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p, uint32_t pattern)
2485 {
2486 int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i;
2487 dx = x2 - x1; dy = y2 - y1;
2488
2489 auto rol = [&](void) { pattern = (pattern << 1) | (pattern >> 31); return pattern & 1; };
2490
2491 olc::vi2d p1(x1, y1), p2(x2, y2);
2492 if (!ClipLineToScreen(p1, p2))
2493 return;
2494 x1 = p1.x; y1 = p1.y;
2495 x2 = p2.x; y2 = p2.y;
2496
2497 // straight lines idea by gurkanctn
2498 if (dx == 0) // Line is vertical
2499 {
2500 if (y2 < y1) std::swap(y1, y2);
2501 for (y = y1; y <= y2; y++) if (rol()) Draw(x1, y, p);
2502 return;
2503 }
2504
2505 if (dy == 0) // Line is horizontal
2506 {
2507 if (x2 < x1) std::swap(x1, x2);
2508 for (x = x1; x <= x2; x++) if (rol()) Draw(x, y1, p);
2509 return;
2510 }
2511
2512 // Line is Funk-aye
2513 dx1 = abs(dx); dy1 = abs(dy);
2514 px = 2 * dy1 - dx1; py = 2 * dx1 - dy1;
2515 if (dy1 <= dx1)
2516 {
2517 if (dx >= 0)
2518 {
2519 x = x1; y = y1; xe = x2;
2520 }
2521 else
2522 {
2523 x = x2; y = y2; xe = x1;
2524 }
2525
2526 if (rol()) Draw(x, y, p);
2527
2528 for (i = 0; x < xe; i++)
2529 {
2530 x = x + 1;
2531 if (px < 0)
2532 px = px + 2 * dy1;
2533 else
2534 {
2535 if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) y = y + 1; else y = y - 1;
2536 px = px + 2 * (dy1 - dx1);
2537 }
2538 if (rol()) Draw(x, y, p);
2539 }
2540 }
2541 else
2542 {
2543 if (dy >= 0)
2544 {
2545 x = x1; y = y1; ye = y2;
2546 }
2547 else
2548 {
2549 x = x2; y = y2; ye = y1;
2550 }
2551
2552 if (rol()) Draw(x, y, p);
2553
2554 for (i = 0; y < ye; i++)
2555 {
2556 y = y + 1;
2557 if (py <= 0)
2558 py = py + 2 * dx1;
2559 else
2560 {
2561 if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) x = x + 1; else x = x - 1;
2562 py = py + 2 * (dx1 - dy1);
2563 }
2564 if (rol()) Draw(x, y, p);
2565 }
2566 }
2567 }
2568
2569 void PixelGameEngine::DrawCircle(const olc::vi2d& pos, int32_t radius, Pixel p, uint8_t mask)
2570 { DrawCircle(pos.x, pos.y, radius, p, mask); }
2571
2572 void PixelGameEngine::DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p, uint8_t mask)
2573 { // Thanks to IanM-Matrix1 #PR121
2574 if (radius < 0 || x < -radius || y < -radius || x - GetDrawTargetWidth() > radius || y - GetDrawTargetHeight() > radius)
2575 return;
2576
2577 if (radius > 0)
2578 {
2579 int x0 = 0;
2580 int y0 = radius;
2581 int d = 3 - 2 * radius;
2582
2583 while (y0 >= x0) // only formulate 1/8 of circle
2584 {
2585 // Draw even octants
2586 if (mask & 0x01) Draw(x + x0, y - y0, p);// Q6 - upper right right
2587 if (mask & 0x04) Draw(x + y0, y + x0, p);// Q4 - lower lower right
2588 if (mask & 0x10) Draw(x - x0, y + y0, p);// Q2 - lower left left
2589 if (mask & 0x40) Draw(x - y0, y - x0, p);// Q0 - upper upper left
2590 if (x0 != 0 && x0 != y0)
2591 {
2592 if (mask & 0x02) Draw(x + y0, y - x0, p);// Q7 - upper upper right
2593 if (mask & 0x08) Draw(x + x0, y + y0, p);// Q5 - lower right right
2594 if (mask & 0x20) Draw(x - y0, y + x0, p);// Q3 - lower lower left
2595 if (mask & 0x80) Draw(x - x0, y - y0, p);// Q1 - upper left left
2596 }
2597
2598 if (d < 0)
2599 d += 4 * x0++ + 6;
2600 else
2601 d += 4 * (x0++ - y0--) + 10;
2602 }
2603 }
2604 else
2605 Draw(x, y, p);
2606 }
2607
2608 void PixelGameEngine::FillCircle(const olc::vi2d& pos, int32_t radius, Pixel p)
2609 { FillCircle(pos.x, pos.y, radius, p); }
2610
2611 void PixelGameEngine::FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p)
2612 { // Thanks to IanM-Matrix1 #PR121
2613 if (radius < 0 || x < -radius || y < -radius || x - GetDrawTargetWidth() > radius || y - GetDrawTargetHeight() > radius)
2614 return;
2615
2616 if (radius > 0)
2617 {
2618 int x0 = 0;
2619 int y0 = radius;
2620 int d = 3 - 2 * radius;
2621
2622 auto drawline = [&](int sx, int ex, int y)
2623 {
2624 for (int x = sx; x <= ex; x++)
2625 Draw(x, y, p);
2626 };
2627
2628 while (y0 >= x0)
2629 {
2630 drawline(x - y0, x + y0, y - x0);
2631 if (x0 > 0) drawline(x - y0, x + y0, y + x0);
2632
2633 if (d < 0)
2634 d += 4 * x0++ + 6;
2635 else
2636 {
2637 if (x0 != y0)
2638 {
2639 drawline(x - x0, x + x0, y - y0);
2640 drawline(x - x0, x + x0, y + y0);
2641 }
2642 d += 4 * (x0++ - y0--) + 10;
2643 }
2644 }
2645 }
2646 else
2647 Draw(x, y, p);
2648 }
2649
2650 void PixelGameEngine::DrawRect(const olc::vi2d& pos, const olc::vi2d& size, Pixel p)
2651 { DrawRect(pos.x, pos.y, size.x, size.y, p); }
2652
2653 void PixelGameEngine::DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p)
2654 {
2655 DrawLine(x, y, x + w, y, p);
2656 DrawLine(x + w, y, x + w, y + h, p);
2657 DrawLine(x + w, y + h, x, y + h, p);
2658 DrawLine(x, y + h, x, y, p);
2659 }
2660
2661 void PixelGameEngine::Clear(Pixel p)
2662 {
2663 int pixels = GetDrawTargetWidth() * GetDrawTargetHeight();
2664 Pixel* m = GetDrawTarget()->GetData();
2665 for (int i = 0; i < pixels; i++) m[i] = p;
2666 }
2667
2668 void PixelGameEngine::ClearBuffer(Pixel p, bool bDepth)
2669 { renderer->ClearBuffer(p, bDepth); }
2670
2672 { return fontRenderable.Sprite(); }
2673
2675 {
2676 // https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
2677 static constexpr int SEG_I = 0b0000, SEG_L = 0b0001, SEG_R = 0b0010, SEG_B = 0b0100, SEG_T = 0b1000;
2678 auto Segment = [&vScreenSize = vScreenSize](const olc::vi2d& v)
2679 {
2680 int i = SEG_I;
2681 if (v.x < 0) i |= SEG_L; else if (v.x > vScreenSize.x) i |= SEG_R;
2682 if (v.y < 0) i |= SEG_B; else if (v.y > vScreenSize.y) i |= SEG_T;
2683 return i;
2684 };
2685
2686 int s1 = Segment(in_p1), s2 = Segment(in_p2);
2687
2688 while (true)
2689 {
2690 if (!(s1 | s2)) return true;
2691 else if (s1 & s2) return false;
2692 else
2693 {
2694 int s3 = s2 > s1 ? s2 : s1;
2695 olc::vi2d n;
2696 if (s3 & SEG_T) { n.x = in_p1.x + (in_p2.x - in_p1.x) * (vScreenSize.y - in_p1.y) / (in_p2.y - in_p1.y); n.y = vScreenSize.y; }
2697 else if (s3 & SEG_B) { n.x = in_p1.x + (in_p2.x - in_p1.x) * (0 - in_p1.y) / (in_p2.y - in_p1.y); n.y = 0; }
2698 else if (s3 & SEG_R) { n.x = vScreenSize.x; n.y = in_p1.y + (in_p2.y - in_p1.y) * (vScreenSize.x - in_p1.x) / (in_p2.x - in_p1.x); }
2699 else if (s3 & SEG_L) { n.x = 0; n.y = in_p1.y + (in_p2.y - in_p1.y) * (0 - in_p1.x) / (in_p2.x - in_p1.x); }
2700 if (s3 == s1) { in_p1 = n; s1 = Segment(in_p1); }
2701 else { in_p2 = n; s2 = Segment(in_p2); }
2702 }
2703 }
2704 return true;
2705 }
2706
2707 void PixelGameEngine::EnablePixelTransfer(const bool bEnable)
2708 {
2709 bSuspendTextureTransfer = !bEnable;
2710 }
2711
2712
2713 void PixelGameEngine::FillRect(const olc::vi2d& pos, const olc::vi2d& size, Pixel p)
2714 { FillRect(pos.x, pos.y, size.x, size.y, p); }
2715
2716 void PixelGameEngine::FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p)
2717 {
2718 int32_t x2 = x + w;
2719 int32_t y2 = y + h;
2720
2721 if (x < 0) x = 0;
2722 if (x >= (int32_t)GetDrawTargetWidth()) x = (int32_t)GetDrawTargetWidth();
2723 if (y < 0) y = 0;
2724 if (y >= (int32_t)GetDrawTargetHeight()) y = (int32_t)GetDrawTargetHeight();
2725
2726 if (x2 < 0) x2 = 0;
2727 if (x2 >= (int32_t)GetDrawTargetWidth()) x2 = (int32_t)GetDrawTargetWidth();
2728 if (y2 < 0) y2 = 0;
2729 if (y2 >= (int32_t)GetDrawTargetHeight()) y2 = (int32_t)GetDrawTargetHeight();
2730
2731 for (int i = x; i < x2; i++)
2732 for (int j = y; j < y2; j++)
2733 Draw(i, j, p);
2734 }
2735
2736 void PixelGameEngine::DrawTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p)
2737 { DrawTriangle(pos1.x, pos1.y, pos2.x, pos2.y, pos3.x, pos3.y, p); }
2738
2739 void PixelGameEngine::DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p)
2740 {
2741 DrawLine(x1, y1, x2, y2, p);
2742 DrawLine(x2, y2, x3, y3, p);
2743 DrawLine(x3, y3, x1, y1, p);
2744 }
2745
2746 void PixelGameEngine::FillTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p)
2747 { FillTriangle(pos1.x, pos1.y, pos2.x, pos2.y, pos3.x, pos3.y, p); }
2748
2749 // https://www.avrfreaks.net/sites/default/files/triangles.c
2750 void PixelGameEngine::FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p)
2751 {
2752 auto drawline = [&](int sx, int ex, int ny) { for (int i = sx; i <= ex; i++) Draw(i, ny, p); };
2753
2754 int t1x, t2x, y, minx, maxx, t1xp, t2xp;
2755 bool changed1 = false;
2756 bool changed2 = false;
2757 int signx1, signx2, dx1, dy1, dx2, dy2;
2758 int e1, e2;
2759 // Sort vertices
2760 if (y1 > y2) { std::swap(y1, y2); std::swap(x1, x2); }
2761 if (y1 > y3) { std::swap(y1, y3); std::swap(x1, x3); }
2762 if (y2 > y3) { std::swap(y2, y3); std::swap(x2, x3); }
2763
2764 t1x = t2x = x1; y = y1; // Starting points
2765 dx1 = (int)(x2 - x1);
2766 if (dx1 < 0) { dx1 = -dx1; signx1 = -1; }
2767 else signx1 = 1;
2768 dy1 = (int)(y2 - y1);
2769
2770 dx2 = (int)(x3 - x1);
2771 if (dx2 < 0) { dx2 = -dx2; signx2 = -1; }
2772 else signx2 = 1;
2773 dy2 = (int)(y3 - y1);
2774
2775 if (dy1 > dx1) { std::swap(dx1, dy1); changed1 = true; }
2776 if (dy2 > dx2) { std::swap(dy2, dx2); changed2 = true; }
2777
2778 e2 = (int)(dx2 >> 1);
2779 // Flat top, just process the second half
2780 if (y1 == y2) goto next;
2781 e1 = (int)(dx1 >> 1);
2782
2783 for (int i = 0; i < dx1;) {
2784 t1xp = 0; t2xp = 0;
2785 if (t1x < t2x) { minx = t1x; maxx = t2x; }
2786 else { minx = t2x; maxx = t1x; }
2787 // process first line until y value is about to change
2788 while (i < dx1) {
2789 i++;
2790 e1 += dy1;
2791 while (e1 >= dx1) {
2792 e1 -= dx1;
2793 if (changed1) t1xp = signx1;//t1x += signx1;
2794 else goto next1;
2795 }
2796 if (changed1) break;
2797 else t1x += signx1;
2798 }
2799 // Move line
2800 next1:
2801 // process second line until y value is about to change
2802 while (1) {
2803 e2 += dy2;
2804 while (e2 >= dx2) {
2805 e2 -= dx2;
2806 if (changed2) t2xp = signx2;//t2x += signx2;
2807 else goto next2;
2808 }
2809 if (changed2) break;
2810 else t2x += signx2;
2811 }
2812 next2:
2813 if (minx > t1x) minx = t1x;
2814 if (minx > t2x) minx = t2x;
2815 if (maxx < t1x) maxx = t1x;
2816 if (maxx < t2x) maxx = t2x;
2817 drawline(minx, maxx, y); // Draw line from min to max points found on the y
2818 // Now increase y
2819 if (!changed1) t1x += signx1;
2820 t1x += t1xp;
2821 if (!changed2) t2x += signx2;
2822 t2x += t2xp;
2823 y += 1;
2824 if (y == y2) break;
2825 }
2826 next:
2827 // Second half
2828 dx1 = (int)(x3 - x2); if (dx1 < 0) { dx1 = -dx1; signx1 = -1; }
2829 else signx1 = 1;
2830 dy1 = (int)(y3 - y2);
2831 t1x = x2;
2832
2833 if (dy1 > dx1) { // swap values
2834 std::swap(dy1, dx1);
2835 changed1 = true;
2836 }
2837 else changed1 = false;
2838
2839 e1 = (int)(dx1 >> 1);
2840
2841 for (int i = 0; i <= dx1; i++) {
2842 t1xp = 0; t2xp = 0;
2843 if (t1x < t2x) { minx = t1x; maxx = t2x; }
2844 else { minx = t2x; maxx = t1x; }
2845 // process first line until y value is about to change
2846 while (i < dx1) {
2847 e1 += dy1;
2848 while (e1 >= dx1) {
2849 e1 -= dx1;
2850 if (changed1) { t1xp = signx1; break; }//t1x += signx1;
2851 else goto next3;
2852 }
2853 if (changed1) break;
2854 else t1x += signx1;
2855 if (i < dx1) i++;
2856 }
2857 next3:
2858 // process second line until y value is about to change
2859 while (t2x != x3) {
2860 e2 += dy2;
2861 while (e2 >= dx2) {
2862 e2 -= dx2;
2863 if (changed2) t2xp = signx2;
2864 else goto next4;
2865 }
2866 if (changed2) break;
2867 else t2x += signx2;
2868 }
2869 next4:
2870
2871 if (minx > t1x) minx = t1x;
2872 if (minx > t2x) minx = t2x;
2873 if (maxx < t1x) maxx = t1x;
2874 if (maxx < t2x) maxx = t2x;
2875 drawline(minx, maxx, y);
2876 if (!changed1) t1x += signx1;
2877 t1x += t1xp;
2878 if (!changed2) t2x += signx2;
2879 t2x += t2xp;
2880 y += 1;
2881 if (y > y3) return;
2882 }
2883 }
2884
2885 void PixelGameEngine::FillTexturedTriangle(std::vector<olc::vf2d> vPoints, std::vector<olc::vf2d> vTex, std::vector<olc::Pixel> vColour, olc::Sprite* sprTex)
2886 {
2887 olc::vi2d p1 = vPoints[0];
2888 olc::vi2d p2 = vPoints[1];
2889 olc::vi2d p3 = vPoints[2];
2890
2891 if (p2.y < p1.y){std::swap(p1.y, p2.y); std::swap(p1.x, p2.x); std::swap(vTex[0].x, vTex[1].x); std::swap(vTex[0].y, vTex[1].y); std::swap(vColour[0], vColour[1]);}
2892 if (p3.y < p1.y){std::swap(p1.y, p3.y); std::swap(p1.x, p3.x); std::swap(vTex[0].x, vTex[2].x); std::swap(vTex[0].y, vTex[2].y); std::swap(vColour[0], vColour[2]);}
2893 if (p3.y < p2.y){std::swap(p2.y, p3.y); std::swap(p2.x, p3.x); std::swap(vTex[1].x, vTex[2].x); std::swap(vTex[1].y, vTex[2].y); std::swap(vColour[1], vColour[2]);}
2894
2895 olc::vi2d dPos1 = p2 - p1;
2896 olc::vf2d dTex1 = vTex[1] - vTex[0];
2897 int dcr1 = vColour[1].r - vColour[0].r;
2898 int dcg1 = vColour[1].g - vColour[0].g;
2899 int dcb1 = vColour[1].b - vColour[0].b;
2900 int dca1 = vColour[1].a - vColour[0].a;
2901
2902 olc::vi2d dPos2 = p3 - p1;
2903 olc::vf2d dTex2 = vTex[2] - vTex[0];
2904 int dcr2 = vColour[2].r - vColour[0].r;
2905 int dcg2 = vColour[2].g - vColour[0].g;
2906 int dcb2 = vColour[2].b - vColour[0].b;
2907 int dca2 = vColour[2].a - vColour[0].a;
2908
2909 float dax_step = 0, dbx_step = 0, dcr1_step = 0, dcr2_step = 0, dcg1_step = 0, dcg2_step = 0, dcb1_step = 0, dcb2_step = 0, dca1_step = 0, dca2_step = 0;
2910 olc::vf2d vTex1Step, vTex2Step;
2911
2912 if (dPos1.y)
2913 {
2914 dax_step = dPos1.x / (float)abs(dPos1.y);
2915 vTex1Step = dTex1 / (float)abs(dPos1.y);
2916 dcr1_step = dcr1 / (float)abs(dPos1.y);
2917 dcg1_step = dcg1 / (float)abs(dPos1.y);
2918 dcb1_step = dcb1 / (float)abs(dPos1.y);
2919 dca1_step = dca1 / (float)abs(dPos1.y);
2920 }
2921
2922 if (dPos2.y)
2923 {
2924 dbx_step = dPos2.x / (float)abs(dPos2.y);
2925 vTex2Step = dTex2 / (float)abs(dPos2.y);
2926 dcr2_step = dcr2 / (float)abs(dPos2.y);
2927 dcg2_step = dcg2 / (float)abs(dPos2.y);
2928 dcb2_step = dcb2 / (float)abs(dPos2.y);
2929 dca2_step = dca2 / (float)abs(dPos2.y);
2930 }
2931
2932 olc::vi2d vStart;
2933 olc::vi2d vEnd;
2934 int vStartIdx;
2935
2936 for (int pass = 0; pass < 2; pass++)
2937 {
2938 if (pass == 0)
2939 {
2940 vStart = p1; vEnd = p2; vStartIdx = 0;
2941 }
2942 else
2943 {
2944 dPos1 = p3 - p2;
2945 dTex1 = vTex[2] - vTex[1];
2946 dcr1 = vColour[2].r - vColour[1].r;
2947 dcg1 = vColour[2].g - vColour[1].g;
2948 dcb1 = vColour[2].b - vColour[1].b;
2949 dca1 = vColour[2].a - vColour[1].a;
2950 dcr1_step = 0; dcg1_step = 0; dcb1_step = 0; dca1_step = 0;
2951
2952 if (dPos2.y) dbx_step = dPos2.x / (float)abs(dPos2.y);
2953 if (dPos1.y)
2954 {
2955 dax_step = dPos1.x / (float)abs(dPos1.y);
2956 vTex1Step = dTex1 / (float)abs(dPos1.y);
2957 dcr1_step = dcr1 / (float)abs(dPos1.y);
2958 dcg1_step = dcg1 / (float)abs(dPos1.y);
2959 dcb1_step = dcb1 / (float)abs(dPos1.y);
2960 dca1_step = dca1 / (float)abs(dPos1.y);
2961 }
2962
2963 vStart = p2; vEnd = p3; vStartIdx = 1;
2964 }
2965
2966 if (dPos1.y)
2967 {
2968 for (int i = vStart.y; i <= vEnd.y; i++)
2969 {
2970 int ax = int(vStart.x + (float)(i - vStart.y) * dax_step);
2971 int bx = int(p1.x + (float)(i - p1.y) * dbx_step);
2972
2973 olc::vf2d tex_s(vTex[vStartIdx].x + (float)(i - vStart.y) * vTex1Step.x, vTex[vStartIdx].y + (float)(i - vStart.y) * vTex1Step.y);
2974 olc::vf2d tex_e(vTex[0].x + (float)(i - p1.y) * vTex2Step.x, vTex[0].y + (float)(i - p1.y) * vTex2Step.y);
2975
2976 olc::Pixel col_s(vColour[vStartIdx].r + uint8_t((float)(i - vStart.y) * dcr1_step), vColour[vStartIdx].g + uint8_t((float)(i - vStart.y) * dcg1_step),
2977 vColour[vStartIdx].b + uint8_t((float)(i - vStart.y) * dcb1_step), vColour[vStartIdx].a + uint8_t((float)(i - vStart.y) * dca1_step));
2978
2979 olc::Pixel col_e(vColour[0].r + uint8_t((float)(i - p1.y) * dcr2_step), vColour[0].g + uint8_t((float)(i - p1.y) * dcg2_step),
2980 vColour[0].b + uint8_t((float)(i - p1.y) * dcb2_step), vColour[0].a + uint8_t((float)(i - p1.y) * dca2_step));
2981
2982 if (ax > bx) { std::swap(ax, bx); std::swap(tex_s, tex_e); std::swap(col_s, col_e); }
2983
2984 float tstep = 1.0f / ((float)(bx - ax));
2985 float t = 0.0f;
2986
2987 for (int j = ax; j < bx; j++)
2988 {
2989 olc::Pixel pixel = PixelLerp(col_s, col_e, t);
2990 if (sprTex != nullptr) pixel *= sprTex->Sample(tex_s.lerp(tex_e, t));
2991 Draw(j, i, pixel);
2992 t += tstep;
2993 }
2994 }
2995 }
2996 }
2997 }
2998
2999 void PixelGameEngine::FillTexturedPolygon(const std::vector<olc::vf2d>& vPoints, const std::vector<olc::vf2d>& vTex, const std::vector<olc::Pixel>& vColour, olc::Sprite* sprTex, olc::DecalStructure structure)
3000 {
3001 if (structure == olc::DecalStructure::LINE)
3002 {
3003 return; // Meaningless, so do nothing
3004 }
3005
3006 if (vPoints.size() < 3 || vTex.size() < 3 || vColour.size() < 3)
3007 return;
3008
3009 if (structure == olc::DecalStructure::LIST)
3010 {
3011 for (size_t tri = 0; tri < vPoints.size() / 3; tri++)
3012 {
3013 std::vector<olc::vf2d> vP = { vPoints[tri * 3 + 0], vPoints[tri * 3 + 1], vPoints[tri * 3 + 2] };
3014 std::vector<olc::vf2d> vT = { vTex[tri * 3 + 0], vTex[tri * 3 + 1], vTex[tri * 3 + 2] };
3015 std::vector<olc::Pixel> vC = { vColour[tri * 3 + 0], vColour[tri * 3 + 1], vColour[tri * 3 + 2] };
3016 FillTexturedTriangle(vP, vT, vC, sprTex);
3017 }
3018 return;
3019 }
3020
3021 if (structure == olc::DecalStructure::STRIP)
3022 {
3023 for (size_t tri = 2; tri < vPoints.size(); tri++)
3024 {
3025 std::vector<olc::vf2d> vP = { vPoints[tri - 2], vPoints[tri-1], vPoints[tri] };
3026 std::vector<olc::vf2d> vT = { vTex[tri - 2], vTex[tri - 1], vTex[tri] };
3027 std::vector<olc::Pixel> vC = { vColour[tri - 2], vColour[tri - 1], vColour[tri] };
3028 FillTexturedTriangle(vP, vT, vC, sprTex);
3029 }
3030 return;
3031 }
3032
3033 if (structure == olc::DecalStructure::FAN)
3034 {
3035 for (size_t tri = 2; tri < vPoints.size(); tri++)
3036 {
3037 std::vector<olc::vf2d> vP = { vPoints[0], vPoints[tri - 1], vPoints[tri] };
3038 std::vector<olc::vf2d> vT = { vTex[0], vTex[tri - 1], vTex[tri] };
3039 std::vector<olc::Pixel> vC = { vColour[0], vColour[tri - 1], vColour[tri] };
3040 FillTexturedTriangle(vP, vT, vC, sprTex);
3041 }
3042 return;
3043 }
3044 }
3045
3046
3047 void PixelGameEngine::DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale, uint8_t flip)
3048 { DrawSprite(pos.x, pos.y, sprite, scale, flip); }
3049
3050 void PixelGameEngine::DrawSprite(int32_t x, int32_t y, Sprite* sprite, uint32_t scale, uint8_t flip)
3051 {
3052 if (sprite == nullptr)
3053 return;
3054
3055 int32_t fxs = 0, fxm = 1, fx = 0;
3056 int32_t fys = 0, fym = 1, fy = 0;
3057 if (flip & olc::Sprite::Flip::HORIZ) { fxs = sprite->width - 1; fxm = -1; }
3058 if (flip & olc::Sprite::Flip::VERT) { fys = sprite->height - 1; fym = -1; }
3059
3060 if (scale > 1)
3061 {
3062 fx = fxs;
3063 for (int32_t i = 0; i < sprite->width; i++, fx += fxm)
3064 {
3065 fy = fys;
3066 for (int32_t j = 0; j < sprite->height; j++, fy += fym)
3067 for (uint32_t is = 0; is < scale; is++)
3068 for (uint32_t js = 0; js < scale; js++)
3069 Draw(x + (i * scale) + is, y + (j * scale) + js, sprite->GetPixel(fx, fy));
3070 }
3071 }
3072 else
3073 {
3074 fx = fxs;
3075 for (int32_t i = 0; i < sprite->width; i++, fx += fxm)
3076 {
3077 fy = fys;
3078 for (int32_t j = 0; j < sprite->height; j++, fy += fym)
3079 Draw(x + i, y + j, sprite->GetPixel(fx, fy));
3080 }
3081 }
3082 }
3083
3084 void PixelGameEngine::DrawPartialSprite(const olc::vi2d& pos, Sprite* sprite, const olc::vi2d& sourcepos, const olc::vi2d& size, uint32_t scale, uint8_t flip)
3085 { DrawPartialSprite(pos.x, pos.y, sprite, sourcepos.x, sourcepos.y, size.x, size.y, scale, flip); }
3086
3087 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, uint8_t flip)
3088 {
3089 if (sprite == nullptr)
3090 return;
3091
3092 int32_t fxs = 0, fxm = 1, fx = 0;
3093 int32_t fys = 0, fym = 1, fy = 0;
3094 if (flip & olc::Sprite::Flip::HORIZ) { fxs = w - 1; fxm = -1; }
3095 if (flip & olc::Sprite::Flip::VERT) { fys = h - 1; fym = -1; }
3096
3097 if (scale > 1)
3098 {
3099 fx = fxs;
3100 for (int32_t i = 0; i < w; i++, fx += fxm)
3101 {
3102 fy = fys;
3103 for (int32_t j = 0; j < h; j++, fy += fym)
3104 for (uint32_t is = 0; is < scale; is++)
3105 for (uint32_t js = 0; js < scale; js++)
3106 Draw(x + (i * scale) + is, y + (j * scale) + js, sprite->GetPixel(fx + ox, fy + oy));
3107 }
3108 }
3109 else
3110 {
3111 fx = fxs;
3112 for (int32_t i = 0; i < w; i++, fx += fxm)
3113 {
3114 fy = fys;
3115 for (int32_t j = 0; j < h; j++, fy += fym)
3116 Draw(x + i, y + j, sprite->GetPixel(fx + ox, fy + oy));
3117 }
3118 }
3119 }
3120
3122 { nDecalMode = mode; }
3123
3125 { nDecalStructure = structure; }
3126
3127 void PixelGameEngine::DrawPartialDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale, const olc::Pixel& tint)
3128 {
3129 olc::vf2d vScreenSpacePos =
3130 {
3131 (pos.x * vInvScreenSize.x) * 2.0f - 1.0f,
3132 -((pos.y * vInvScreenSize.y) * 2.0f - 1.0f)
3133 };
3134
3135
3136 olc::vf2d vScreenSpaceDim =
3137 {
3138 ((pos.x + source_size.x * scale.x) * vInvScreenSize.x) * 2.0f - 1.0f,
3139 -(((pos.y + source_size.y * scale.y) * vInvScreenSize.y) * 2.0f - 1.0f)
3140 };
3141
3142 olc::vf2d vWindow = olc::vf2d(vViewSize);
3143 olc::vf2d vQuantisedPos = ((vScreenSpacePos * vWindow) + olc::vf2d(0.5f, 0.5f)).floor() / vWindow;
3144 olc::vf2d vQuantisedDim = ((vScreenSpaceDim * vWindow) + olc::vf2d(0.5f, -0.5f)).ceil() / vWindow;
3145
3146 DecalInstance di;
3147 di.points = 4;
3148 di.decal = decal;
3149 di.tint = { tint, tint, tint, tint };
3150 di.pos = { { vQuantisedPos.x, vQuantisedPos.y }, { vQuantisedPos.x, vQuantisedDim.y }, { vQuantisedDim.x, vQuantisedDim.y }, { vQuantisedDim.x, vQuantisedPos.y } };
3151 olc::vf2d uvtl = (source_pos + olc::vf2d(0.0001f, 0.0001f)) * decal->vUVScale;
3152 olc::vf2d uvbr = (source_pos + source_size - olc::vf2d(0.0001f, 0.0001f)) * decal->vUVScale;
3153 di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } };
3154 di.w = { 1,1,1,1 };
3155 di.mode = nDecalMode;
3156 di.structure = nDecalStructure;
3157 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3158 }
3159
3160 void PixelGameEngine::DrawPartialDecal(const olc::vf2d& pos, const olc::vf2d& size, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint)
3161 {
3162 olc::vf2d vScreenSpacePos =
3163 {
3164 (pos.x * vInvScreenSize.x) * 2.0f - 1.0f,
3165 ((pos.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f
3166 };
3167
3168 olc::vf2d vScreenSpaceDim =
3169 {
3170 vScreenSpacePos.x + (2.0f * size.x * vInvScreenSize.x),
3171 vScreenSpacePos.y - (2.0f * size.y * vInvScreenSize.y)
3172 };
3173
3174 DecalInstance di;
3175 di.points = 4;
3176 di.decal = decal;
3177 di.tint = { tint, tint, tint, tint };
3178 di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } };
3179 olc::vf2d uvtl = (source_pos) * decal->vUVScale;
3180 olc::vf2d uvbr = uvtl + ((source_size) * decal->vUVScale);
3181 di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } };
3182 di.w = { 1,1,1,1 };
3183 di.mode = nDecalMode;
3184 di.structure = nDecalStructure;
3185 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3186 }
3187
3188
3189 void PixelGameEngine::DrawDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& scale, const olc::Pixel& tint)
3190 {
3191 olc::vf2d vScreenSpacePos =
3192 {
3193 (pos.x * vInvScreenSize.x) * 2.0f - 1.0f,
3194 ((pos.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f
3195 };
3196
3197 olc::vf2d vScreenSpaceDim =
3198 {
3199 vScreenSpacePos.x + (2.0f * (float(decal->sprite->width) * vInvScreenSize.x)) * scale.x,
3200 vScreenSpacePos.y - (2.0f * (float(decal->sprite->height) * vInvScreenSize.y)) * scale.y
3201 };
3202
3203 DecalInstance di;
3204 di.decal = decal;
3205 di.points = 4;
3206 di.tint = { tint, tint, tint, tint };
3207 di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } };
3208 di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} };
3209 di.w = { 1, 1, 1, 1 };
3210 di.mode = nDecalMode;
3211 di.structure = nDecalStructure;
3212 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3213 }
3214
3215 void PixelGameEngine::DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col, uint32_t elements)
3216 {
3217 DecalInstance di;
3218 di.decal = decal;
3219 di.pos.resize(elements);
3220 di.uv.resize(elements);
3221 di.w.resize(elements);
3222 di.tint.resize(elements);
3223 di.points = elements;
3224 for (uint32_t i = 0; i < elements; i++)
3225 {
3226 di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f };
3227 di.uv[i] = uv[i];
3228 di.tint[i] = col[i];
3229 di.w[i] = 1.0f;
3230 }
3231 di.mode = nDecalMode;
3232 di.structure = nDecalStructure;
3233 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3234 }
3235
3236 void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<olc::vf2d>& uv, const olc::Pixel tint)
3237 {
3238 DecalInstance di;
3239 di.decal = decal;
3240 di.points = uint32_t(pos.size());
3241 di.pos.resize(di.points);
3242 di.uv.resize(di.points);
3243 di.w.resize(di.points);
3244 di.tint.resize(di.points);
3245 for (uint32_t i = 0; i < di.points; i++)
3246 {
3247 di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f };
3248 di.uv[i] = uv[i];
3249 di.tint[i] = tint;
3250 di.w[i] = 1.0f;
3251 }
3252 di.mode = nDecalMode;
3253 di.structure = nDecalStructure;
3254 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3255 }
3256
3257 void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<olc::vf2d>& uv, const std::vector<olc::Pixel> &tint)
3258 {
3259 DecalInstance di;
3260 di.decal = decal;
3261 di.points = uint32_t(pos.size());
3262 di.pos.resize(di.points);
3263 di.uv.resize(di.points);
3264 di.w.resize(di.points);
3265 di.tint.resize(di.points);
3266 for (uint32_t i = 0; i < di.points; i++)
3267 {
3268 di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f };
3269 di.uv[i] = uv[i];
3270 di.tint[i] = tint[i];
3271 di.w[i] = 1.0f;
3272 }
3273 di.mode = nDecalMode;
3274 di.structure = nDecalStructure;
3275 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3276 }
3277
3278 void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<olc::vf2d>& uv, const std::vector<olc::Pixel>& colours, const olc::Pixel tint)
3279 {
3280 std::vector<olc::Pixel> newColours(colours.size(), olc::WHITE);
3281 std::transform(colours.begin(), colours.end(), newColours.begin(),
3282 [&tint](const olc::Pixel pin) { return pin * tint; });
3283 DrawPolygonDecal(decal, pos, uv, newColours);
3284 }
3285
3286
3287 void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<float>& depth, const std::vector<olc::vf2d>& uv, const olc::Pixel tint)
3288 {
3289 DecalInstance di;
3290 di.decal = decal;
3291 di.points = uint32_t(pos.size());
3292 di.pos.resize(di.points);
3293 di.uv.resize(di.points);
3294 di.w.resize(di.points);
3295 di.tint.resize(di.points);
3296 for (uint32_t i = 0; i < di.points; i++)
3297 {
3298 di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f };
3299 di.uv[i] = uv[i];
3300 di.tint[i] = tint;
3301 di.w[i] = depth[i];
3302 }
3303 di.mode = nDecalMode;
3304 di.structure = nDecalStructure;
3305 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3306 }
3307
3308 void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const std::vector<olc::vf2d>& pos, const std::vector<float>& depth, const std::vector<olc::vf2d>& uv, const std::vector<olc::Pixel>& colours, const olc::Pixel tint)
3309 {
3310 DecalInstance di;
3311 di.decal = decal;
3312 di.points = uint32_t(pos.size());
3313 di.pos.resize(di.points);
3314 di.uv.resize(di.points);
3315 di.w.resize(di.points);
3316 di.tint.resize(di.points);
3317 for (uint32_t i = 0; i < di.points; i++)
3318 {
3319 di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f };
3320 di.uv[i] = uv[i];
3321 di.tint[i] = colours[i] * tint;
3322 di.w[i] = depth[i];
3323 }
3324 di.mode = nDecalMode;
3325 di.structure = nDecalStructure;
3326 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3327 }
3328
3329#ifdef OLC_ENABLE_EXPERIMENTAL
3330 // Lightweight 3D
3331 void PixelGameEngine::LW3D_DrawTriangles(olc::Decal* decal, const std::vector<std::array<float, 3>>& pos, const std::vector<olc::vf2d>& tex, const std::vector<olc::Pixel>& col)
3332 {
3333 DecalInstance di;
3334 di.decal = decal;
3335 di.points = uint32_t(pos.size());
3336 di.pos.resize(di.points);
3337 di.uv.resize(di.points);
3338 di.w.resize(di.points);
3339 di.z.resize(di.points);
3340 di.tint.resize(di.points);
3341 for (uint32_t i = 0; i < di.points; i++)
3342 {
3343 di.pos[i] = { pos[i][0], pos[i][1] };
3344 di.w[i] = pos[i][2];
3345 di.z[i] = pos[i][2];
3346 di.uv[i] = tex[i];
3347 di.tint[i] = col[i];
3348 }
3349 di.mode = nDecalMode;
3350 di.structure = DecalStructure::LIST;
3351 di.depth = true;
3352 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3353 }
3354
3355 void PixelGameEngine::LW3D_DrawWarpedDecal(olc::Decal* decal, const std::vector<std::array<float, 3>>& pos, const olc::Pixel& tint)
3356 {
3357 // Thanks Nathan Reed, a brilliant article explaining whats going on here
3358 // http://www.reedbeta.com/blog/quadrilateral-interpolation-part-1/
3359 DecalInstance di;
3360 di.points = 4;
3361 di.decal = decal;
3362 di.tint = { tint, tint, tint, tint };
3363 di.w = { 1, 1, 1, 1 };
3364 di.z = { 1, 1, 1, 1 };
3365 di.pos.resize(4);
3366 di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} };
3367 olc::vf2d center;
3368 float rd = ((pos[2][0] - pos[0][0]) * (pos[3][1] - pos[1][1]) - (pos[3][0] - pos[1][0]) * (pos[2][1] - pos[0][1]));
3369 if (rd != 0)
3370 {
3371 rd = 1.0f / rd;
3372 float rn = ((pos[3][0] - pos[1][0]) * (pos[0][1] - pos[1][1]) - (pos[3][1] - pos[1][1]) * (pos[0][0] - pos[1][0])) * rd;
3373 float sn = ((pos[2][0] - pos[0][0]) * (pos[0][1] - pos[1][1]) - (pos[2][1] - pos[0][1]) * (pos[0][0] - pos[1][0])) * rd;
3374 if (!(rn < 0.f || rn > 1.f || sn < 0.f || sn > 1.f))
3375 {
3376 center.x = pos[0][0] + rn * (pos[2][0] - pos[0][0]);
3377 center.y = pos[0][1] + rn * (pos[2][1] - pos[0][1]);
3378 }
3379 float d[4];
3380 for (int i = 0; i < 4; i++)
3381 d[i] = std::sqrt((pos[i][0] - center.x) * (pos[i][0] - center.x) + (pos[i][1] - center.y) * (pos[i][1] - center.y));
3382
3383 for (int i = 0; i < 4; i++)
3384 {
3385 float q = d[i] == 0.0f ? 1.0f : (d[i] + d[(i + 2) & 3]) / d[(i + 2) & 3];
3386 di.uv[i] *= q;
3387 di.w[i] *= q;
3388 di.z[i] = pos[i][2];
3389 di.pos[i] = { (pos[i][0] * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i][1] * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f };
3390 }
3391 di.mode = nDecalMode;
3392 di.structure = nDecalStructure;
3393 di.depth = true;
3394 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3395 }
3396 }
3397#endif
3398
3399 void PixelGameEngine::DrawLineDecal(const olc::vf2d& pos1, const olc::vf2d& pos2, Pixel p)
3400 {
3401 auto m = nDecalMode;
3402 nDecalMode = olc::DecalMode::WIREFRAME;
3403 DrawPolygonDecal(nullptr, { pos1, pos2 }, { {0, 0}, {0,0} }, p);
3404 nDecalMode = m;
3405
3406 /*DecalInstance di;
3407 di.decal = nullptr;
3408 di.points = uint32_t(2);
3409 di.pos.resize(di.points);
3410 di.uv.resize(di.points);
3411 di.w.resize(di.points);
3412 di.tint.resize(di.points);
3413 di.pos[0] = { (pos1.x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos1.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f };
3414 di.uv[0] = { 0.0f, 0.0f };
3415 di.tint[0] = p;
3416 di.w[0] = 1.0f;
3417 di.pos[1] = { (pos2.x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos2.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f };
3418 di.uv[1] = { 0.0f, 0.0f };
3419 di.tint[1] = p;
3420 di.w[1] = 1.0f;
3421 di.mode = olc::DecalMode::WIREFRAME;
3422 di.structure = nDecalStructure;
3423 vLayers[nTargetLayer].vecDecalInstance.push_back(di);*/
3424 }
3425
3426 void PixelGameEngine::DrawRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col)
3427 {
3428 auto m = nDecalMode;
3430 olc::vf2d vNewSize = size;// (size - olc::vf2d(0.375f, 0.375f)).ceil();
3431 std::array<olc::vf2d, 4> points = { { {pos}, {pos.x, pos.y + vNewSize.y}, {pos + vNewSize}, {pos.x + vNewSize.x, pos.y} } };
3432 std::array<olc::vf2d, 4> uvs = { {{0,0},{0,0},{0,0},{0,0}} };
3433 std::array<olc::Pixel, 4> cols = { {col, col, col, col} };
3434 DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data(), 4);
3435 SetDecalMode(m);
3436
3437 }
3438
3439 void PixelGameEngine::FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col)
3440 {
3441 olc::vf2d vNewSize = size;// (size - olc::vf2d(0.375f, 0.375f)).ceil();
3442 std::array<olc::vf2d, 4> points = { { {pos}, {pos.x, pos.y + vNewSize.y}, {pos + vNewSize}, {pos.x + vNewSize.x, pos.y} } };
3443 std::array<olc::vf2d, 4> uvs = { {{0,0},{0,0},{0,0},{0,0}} };
3444 std::array<olc::Pixel, 4> cols = { {col, col, col, col} };
3445 DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data(), 4);
3446 }
3447
3448 void PixelGameEngine::GradientFillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel colTL, const olc::Pixel colBL, const olc::Pixel colBR, const olc::Pixel colTR)
3449 {
3450 std::array<olc::vf2d, 4> points = { { {pos}, {pos.x, pos.y + size.y}, {pos + size}, {pos.x + size.x, pos.y} } };
3451 std::array<olc::vf2d, 4> uvs = { {{0,0},{0,0},{0,0},{0,0}} };
3452 std::array<olc::Pixel, 4> cols = { {colTL, colBL, colBR, colTR} };
3453 DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data(), 4);
3454 }
3455
3456 void PixelGameEngine::FillTriangleDecal(const olc::vf2d& p0, const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel col)
3457 {
3458 std::array<olc::vf2d, 4> points = { { p0, p1, p2 } };
3459 std::array<olc::vf2d, 4> uvs = { {{0,0},{0,0},{0,0}} };
3460 std::array<olc::Pixel, 4> cols = { {col, col, col} };
3461 DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data(), 3);
3462 }
3463
3464 void PixelGameEngine::GradientTriangleDecal(const olc::vf2d& p0, const olc::vf2d& p1, const olc::vf2d& p2, const olc::Pixel c0, const olc::Pixel c1, const olc::Pixel c2)
3465 {
3466 std::array<olc::vf2d, 4> points = { { p0, p1, p2 } };
3467 std::array<olc::vf2d, 4> uvs = { {{0,0},{0,0},{0,0}} };
3468 std::array<olc::Pixel, 4> cols = { {c0, c1, c2} };
3469 DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data(), 3);
3470 }
3471
3472 void PixelGameEngine::DrawRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& scale, const olc::Pixel& tint)
3473 {
3474 DecalInstance di;
3475 di.decal = decal;
3476 di.pos.resize(4);
3477 di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} };
3478 di.w = { 1, 1, 1, 1 };
3479 di.tint = { tint, tint, tint, tint };
3480 di.points = 4;
3481 di.pos[0] = (olc::vf2d(0.0f, 0.0f) - center) * scale;
3482 di.pos[1] = (olc::vf2d(0.0f, float(decal->sprite->height)) - center) * scale;
3483 di.pos[2] = (olc::vf2d(float(decal->sprite->width), float(decal->sprite->height)) - center) * scale;
3484 di.pos[3] = (olc::vf2d(float(decal->sprite->width), 0.0f) - center) * scale;
3485 float c = cos(fAngle), s = sin(fAngle);
3486 for (int i = 0; i < 4; i++)
3487 {
3488 di.pos[i] = pos + olc::vf2d(di.pos[i].x * c - di.pos[i].y * s, di.pos[i].x * s + di.pos[i].y * c);
3489 di.pos[i] = di.pos[i] * vInvScreenSize * 2.0f - olc::vf2d(1.0f, 1.0f);
3490 di.pos[i].y *= -1.0f;
3491 di.w[i] = 1;
3492 }
3493 di.mode = nDecalMode;
3494 di.structure = nDecalStructure;
3495 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3496 }
3497
3498
3499 void PixelGameEngine::DrawPartialRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale, const olc::Pixel& tint)
3500 {
3501 DecalInstance di;
3502 di.decal = decal;
3503 di.points = 4;
3504 di.tint = { tint, tint, tint, tint };
3505 di.w = { 1, 1, 1, 1 };
3506 di.pos.resize(4);
3507 di.pos[0] = (olc::vf2d(0.0f, 0.0f) - center) * scale;
3508 di.pos[1] = (olc::vf2d(0.0f, source_size.y) - center) * scale;
3509 di.pos[2] = (olc::vf2d(source_size.x, source_size.y) - center) * scale;
3510 di.pos[3] = (olc::vf2d(source_size.x, 0.0f) - center) * scale;
3511 float c = cos(fAngle), s = sin(fAngle);
3512 for (int i = 0; i < 4; i++)
3513 {
3514 di.pos[i] = pos + olc::vf2d(di.pos[i].x * c - di.pos[i].y * s, di.pos[i].x * s + di.pos[i].y * c);
3515 di.pos[i] = di.pos[i] * vInvScreenSize * 2.0f - olc::vf2d(1.0f, 1.0f);
3516 di.pos[i].y *= -1.0f;
3517 }
3518
3519 olc::vf2d uvtl = source_pos * decal->vUVScale;
3520 olc::vf2d uvbr = uvtl + (source_size * decal->vUVScale);
3521 di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } };
3522 di.mode = nDecalMode;
3523 di.structure = nDecalStructure;
3524 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3525 }
3526
3527 void PixelGameEngine::DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint)
3528 {
3529 DecalInstance di;
3530 di.points = 4;
3531 di.decal = decal;
3532 di.tint = { tint, tint, tint, tint };
3533 di.w = { 1, 1, 1, 1 };
3534 di.pos.resize(4);
3535 di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} };
3536 olc::vf2d center;
3537 float rd = ((pos[2].x - pos[0].x) * (pos[3].y - pos[1].y) - (pos[3].x - pos[1].x) * (pos[2].y - pos[0].y));
3538 if (rd != 0)
3539 {
3540 olc::vf2d uvtl = source_pos * decal->vUVScale;
3541 olc::vf2d uvbr = uvtl + (source_size * decal->vUVScale);
3542 di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } };
3543
3544 rd = 1.0f / rd;
3545 float rn = ((pos[3].x - pos[1].x) * (pos[0].y - pos[1].y) - (pos[3].y - pos[1].y) * (pos[0].x - pos[1].x)) * rd;
3546 float sn = ((pos[2].x - pos[0].x) * (pos[0].y - pos[1].y) - (pos[2].y - pos[0].y) * (pos[0].x - pos[1].x)) * rd;
3547 if (!(rn < 0.f || rn > 1.f || sn < 0.f || sn > 1.f)) center = pos[0] + rn * (pos[2] - pos[0]);
3548 float d[4]; for (int i = 0; i < 4; i++) d[i] = (pos[i] - center).mag();
3549 for (int i = 0; i < 4; i++)
3550 {
3551 float q = d[i] == 0.0f ? 1.0f : (d[i] + d[(i + 2) & 3]) / d[(i + 2) & 3];
3552 di.uv[i] *= q; di.w[i] *= q;
3553 di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f };
3554 }
3555 di.mode = nDecalMode;
3556 di.structure = nDecalStructure;
3557 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3558 }
3559 }
3560
3561 void PixelGameEngine::DrawWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::Pixel& tint)
3562 {
3563 // Thanks Nathan Reed, a brilliant article explaining whats going on here
3564 // http://www.reedbeta.com/blog/quadrilateral-interpolation-part-1/
3565 DecalInstance di;
3566 di.points = 4;
3567 di.decal = decal;
3568 di.tint = { tint, tint, tint, tint };
3569 di.w = { 1, 1, 1, 1 };
3570 di.pos.resize(4);
3571 di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} };
3572 olc::vf2d center;
3573 float rd = ((pos[2].x - pos[0].x) * (pos[3].y - pos[1].y) - (pos[3].x - pos[1].x) * (pos[2].y - pos[0].y));
3574 if (rd != 0)
3575 {
3576 rd = 1.0f / rd;
3577 float rn = ((pos[3].x - pos[1].x) * (pos[0].y - pos[1].y) - (pos[3].y - pos[1].y) * (pos[0].x - pos[1].x)) * rd;
3578 float sn = ((pos[2].x - pos[0].x) * (pos[0].y - pos[1].y) - (pos[2].y - pos[0].y) * (pos[0].x - pos[1].x)) * rd;
3579 if (!(rn < 0.f || rn > 1.f || sn < 0.f || sn > 1.f)) center = pos[0] + rn * (pos[2] - pos[0]);
3580 float d[4]; for (int i = 0; i < 4; i++) d[i] = (pos[i] - center).mag();
3581 for (int i = 0; i < 4; i++)
3582 {
3583 float q = d[i] == 0.0f ? 1.0f : (d[i] + d[(i + 2) & 3]) / d[(i + 2) & 3];
3584 di.uv[i] *= q; di.w[i] *= q;
3585 di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f };
3586 }
3587 di.mode = nDecalMode;
3588 di.structure = nDecalStructure;
3589 vLayers[nTargetLayer].vecDecalInstance.push_back(di);
3590 }
3591 }
3592
3593 void PixelGameEngine::DrawWarpedDecal(olc::Decal* decal, const std::array<olc::vf2d, 4>& pos, const olc::Pixel& tint)
3594 { DrawWarpedDecal(decal, pos.data(), tint); }
3595
3596 void PixelGameEngine::DrawWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::Pixel& tint)
3597 { DrawWarpedDecal(decal, &pos[0], tint); }
3598
3599 void PixelGameEngine::DrawPartialWarpedDecal(olc::Decal* decal, const std::array<olc::vf2d, 4>& pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint)
3600 { DrawPartialWarpedDecal(decal, pos.data(), source_pos, source_size, tint); }
3601
3602 void PixelGameEngine::DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint)
3603 { DrawPartialWarpedDecal(decal, &pos[0], source_pos, source_size, tint); }
3604
3605 void PixelGameEngine::DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale)
3606 {
3607 olc::vf2d spos = { 0.0f, 0.0f };
3608 for (auto c : sText)
3609 {
3610 if (c == '\n')
3611 {
3612 spos.x = 0; spos.y += 8.0f * scale.y;
3613 }
3614 else if (c == '\t')
3615 {
3616 spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x;
3617 }
3618 else
3619 {
3620 int32_t ox = (c - 32) % 16;
3621 int32_t oy = (c - 32) / 16;
3622 DrawPartialDecal(pos + spos, fontRenderable.Decal(), {float(ox) * 8.0f, float(oy) * 8.0f}, {8.0f, 8.0f}, scale, col);
3623 spos.x += 8.0f * scale.x;
3624 }
3625 }
3626 }
3627
3628 void PixelGameEngine::DrawStringPropDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale)
3629 {
3630 olc::vf2d spos = { 0.0f, 0.0f };
3631 for (auto c : sText)
3632 {
3633 if (c == '\n')
3634 {
3635 spos.x = 0; spos.y += 8.0f * scale.y;
3636 }
3637 else if (c == '\t')
3638 {
3639 spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x;
3640 }
3641 else
3642 {
3643 int32_t ox = (c - 32) % 16;
3644 int32_t oy = (c - 32) / 16;
3645 DrawPartialDecal(pos + spos, fontRenderable.Decal(), { float(ox) * 8.0f + float(vFontSpacing[c - 32].x), float(oy) * 8.0f }, { float(vFontSpacing[c - 32].y), 8.0f }, scale, col);
3646 spos.x += float(vFontSpacing[c - 32].y) * scale.x;
3647 }
3648 }
3649 }
3650 // Thanks Oso-Grande/Sopadeoso For these awesom and stupidly clever Text Rotation routines... duh XD
3651 void PixelGameEngine::DrawRotatedStringDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center, const Pixel col, const olc::vf2d& scale)
3652 {
3653 olc::vf2d spos = center;
3654 for (auto c : sText)
3655 {
3656 if (c == '\n')
3657 {
3658 spos.x = center.x; spos.y -= 8.0f;
3659 }
3660 else if (c == '\t')
3661 {
3662 spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x;
3663 }
3664 else
3665 {
3666 int32_t ox = (c - 32) % 16;
3667 int32_t oy = (c - 32) / 16;
3668 DrawPartialRotatedDecal(pos, fontRenderable.Decal(), fAngle, spos, { float(ox) * 8.0f, float(oy) * 8.0f }, { 8.0f, 8.0f }, scale, col);
3669 spos.x -= 8.0f;
3670 }
3671 }
3672 }
3673
3674 void PixelGameEngine::DrawRotatedStringPropDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center, const Pixel col, const olc::vf2d& scale)
3675 {
3676 olc::vf2d spos = center;
3677 for (auto c : sText)
3678 {
3679 if (c == '\n')
3680 {
3681 spos.x = center.x; spos.y -= 8.0f;
3682 }
3683 else if (c == '\t')
3684 {
3685 spos.x += 8.0f * float(nTabSizeInSpaces) * scale.x;
3686 }
3687 else
3688 {
3689 int32_t ox = (c - 32) % 16;
3690 int32_t oy = (c - 32) / 16;
3691 DrawPartialRotatedDecal(pos, fontRenderable.Decal(), fAngle, spos, { float(ox) * 8.0f + float(vFontSpacing[c - 32].x), float(oy) * 8.0f }, { float(vFontSpacing[c - 32].y), 8.0f }, scale, col);
3692 spos.x -= float(vFontSpacing[c - 32].y);
3693 }
3694 }
3695 }
3696
3697 olc::vi2d PixelGameEngine::GetTextSize(const std::string& s)
3698 {
3699 olc::vi2d size = { 0,1 };
3700 olc::vi2d pos = { 0,1 };
3701 for (auto c : s)
3702 {
3703 if (c == '\n') { pos.y++; pos.x = 0; }
3704 else if (c == '\t') { pos.x += nTabSizeInSpaces; }
3705 else pos.x++;
3706 size.x = std::max(size.x, pos.x);
3707 size.y = std::max(size.y, pos.y);
3708 }
3709 return size * 8;
3710 }
3711
3712 void PixelGameEngine::DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col, uint32_t scale)
3713 { DrawString(pos.x, pos.y, sText, col, scale); }
3714
3715 void PixelGameEngine::DrawString(int32_t x, int32_t y, const std::string& sText, Pixel col, uint32_t scale)
3716 {
3717 int32_t sx = 0;
3718 int32_t sy = 0;
3719 Pixel::Mode m = nPixelMode;
3720 // Thanks @tucna, spotted bug with col.ALPHA :P
3721 if (m != Pixel::CUSTOM) // Thanks @Megarev, required for "shaders"
3722 {
3723 if (col.a != 255) SetPixelMode(Pixel::ALPHA);
3725 }
3726 for (auto c : sText)
3727 {
3728 if (c == '\n')
3729 {
3730 sx = 0; sy += 8 * scale;
3731 }
3732 else if (c == '\t')
3733 {
3734 sx += 8 * nTabSizeInSpaces * scale;
3735 }
3736 else
3737 {
3738 int32_t ox = (c - 32) % 16;
3739 int32_t oy = (c - 32) / 16;
3740
3741 if (scale > 1)
3742 {
3743 for (uint32_t i = 0; i < 8; i++)
3744 for (uint32_t j = 0; j < 8; j++)
3745 if (fontRenderable.Sprite()->GetPixel(i + ox * 8, j + oy * 8).r > 0)
3746 for (uint32_t is = 0; is < scale; is++)
3747 for (uint32_t js = 0; js < scale; js++)
3748 Draw(x + sx + (i * scale) + is, y + sy + (j * scale) + js, col);
3749 }
3750 else
3751 {
3752 for (uint32_t i = 0; i < 8; i++)
3753 for (uint32_t j = 0; j < 8; j++)
3754 if (fontRenderable.Sprite()->GetPixel(i + ox * 8, j + oy * 8).r > 0)
3755 Draw(x + sx + i, y + sy + j, col);
3756 }
3757 sx += 8 * scale;
3758 }
3759 }
3760 SetPixelMode(m);
3761 }
3762
3763 olc::vi2d PixelGameEngine::GetTextSizeProp(const std::string& s)
3764 {
3765 olc::vi2d size = { 0,1 };
3766 olc::vi2d pos = { 0,1 };
3767 for (auto c : s)
3768 {
3769 if (c == '\n') { pos.y += 1; pos.x = 0; }
3770 else if (c == '\t') { pos.x += nTabSizeInSpaces * 8; }
3771 else pos.x += vFontSpacing[c - 32].y;
3772 size.x = std::max(size.x, pos.x);
3773 size.y = std::max(size.y, pos.y);
3774 }
3775
3776 size.y *= 8;
3777 return size;
3778 }
3779
3780 void PixelGameEngine::DrawStringProp(const olc::vi2d& pos, const std::string& sText, Pixel col, uint32_t scale)
3781 { DrawStringProp(pos.x, pos.y, sText, col, scale); }
3782
3783 void PixelGameEngine::DrawStringProp(int32_t x, int32_t y, const std::string& sText, Pixel col, uint32_t scale)
3784 {
3785 int32_t sx = 0;
3786 int32_t sy = 0;
3787 Pixel::Mode m = nPixelMode;
3788
3789 if (m != Pixel::CUSTOM)
3790 {
3791 if (col.a != 255) SetPixelMode(Pixel::ALPHA);
3793 }
3794 for (auto c : sText)
3795 {
3796 if (c == '\n')
3797 {
3798 sx = 0; sy += 8 * scale;
3799 }
3800 else if (c == '\t')
3801 {
3802 sx += 8 * nTabSizeInSpaces * scale;
3803 }
3804 else
3805 {
3806 int32_t ox = (c - 32) % 16;
3807 int32_t oy = (c - 32) / 16;
3808
3809 if (scale > 1)
3810 {
3811 for (int32_t i = 0; i < vFontSpacing[c - 32].y; i++)
3812 for (int32_t j = 0; j < 8; j++)
3813 if (fontRenderable.Sprite()->GetPixel(i + ox * 8 + vFontSpacing[c - 32].x, j + oy * 8).r > 0)
3814 for (int32_t is = 0; is < int(scale); is++)
3815 for (int32_t js = 0; js < int(scale); js++)
3816 Draw(x + sx + (i * scale) + is, y + sy + (j * scale) + js, col);
3817 }
3818 else
3819 {
3820 for (int32_t i = 0; i < vFontSpacing[c - 32].y; i++)
3821 for (int32_t j = 0; j < 8; j++)
3822 if (fontRenderable.Sprite()->GetPixel(i + ox * 8 + vFontSpacing[c - 32].x, j + oy * 8).r > 0)
3823 Draw(x + sx + i, y + sy + j, col);
3824 }
3825 sx += vFontSpacing[c - 32].y * scale;
3826 }
3827 }
3828 SetPixelMode(m);
3829 }
3830
3832 { nPixelMode = m; }
3833
3835 { return nPixelMode; }
3836
3837 void PixelGameEngine::SetPixelMode(std::function<olc::Pixel(const int x, const int y, const olc::Pixel&, const olc::Pixel&)> pixelMode)
3838 {
3839 funcPixelMode = pixelMode;
3840 nPixelMode = Pixel::Mode::CUSTOM;
3841 }
3842
3843 void PixelGameEngine::SetPixelBlend(float fBlend)
3844 {
3845 fBlendFactor = fBlend;
3846 if (fBlendFactor < 0.0f) fBlendFactor = 0.0f;
3847 if (fBlendFactor > 1.0f) fBlendFactor = 1.0f;
3848 }
3849
3850 std::stringstream& PixelGameEngine::ConsoleOut()
3851 { return ssConsoleOutput; }
3852
3854 { return bConsoleShow; }
3855
3856 void PixelGameEngine::ConsoleShow(const olc::Key& keyExit, bool bSuspendTime)
3857 {
3858 if (bConsoleShow)
3859 return;
3860
3861 bConsoleShow = true;
3862 bConsoleSuspendTime = bSuspendTime;
3863 TextEntryEnable(true);
3864 keyConsoleExit = keyExit;
3865 pKeyboardState[keyConsoleExit].bHeld = false;
3866 pKeyboardState[keyConsoleExit].bPressed = false;
3867 pKeyboardState[keyConsoleExit].bReleased = true;
3868 }
3869
3871 { sConsoleLines.clear(); }
3872
3873 void PixelGameEngine::ConsoleCaptureStdOut(const bool bCapture)
3874 {
3875 if(bCapture)
3876 sbufOldCout = std::cout.rdbuf(ssConsoleOutput.rdbuf());
3877 else
3878 std::cout.rdbuf(sbufOldCout);
3879 }
3880
3881 void PixelGameEngine::UpdateConsole()
3882 {
3883 if (GetKey(keyConsoleExit).bPressed)
3884 {
3885 TextEntryEnable(false);
3886 bConsoleSuspendTime = false;
3887 bConsoleShow = false;
3888 return;
3889 }
3890
3891 // Keep Console sizes based in real screen dimensions
3892 vConsoleCharacterScale = olc::vf2d(1.0f, 2.0f) / (olc::vf2d(vViewSize) * vInvScreenSize);
3893 vConsoleSize = (vViewSize / olc::vi2d(8, 16)) - olc::vi2d(2, 4);
3894
3895 // If console has changed size, simply reset it
3896 if (vConsoleSize.y != sConsoleLines.size())
3897 {
3898 vConsoleCursor = { 0,0 };
3899 sConsoleLines.clear();
3900 sConsoleLines.resize(vConsoleSize.y);
3901 }
3902
3903 auto TypeCharacter = [&](const char c)
3904 {
3905 if (c >= 32 && c < 127)
3906 {
3907 sConsoleLines[vConsoleCursor.y].append(1, c);
3908 vConsoleCursor.x++;
3909 }
3910
3911 if( c == '\n' || vConsoleCursor.x >= vConsoleSize.x)
3912 {
3913 vConsoleCursor.y++; vConsoleCursor.x = 0;
3914 }
3915
3916 if (vConsoleCursor.y >= vConsoleSize.y)
3917 {
3918 vConsoleCursor.y = vConsoleSize.y - 1;
3919 for (int i = 1; i < vConsoleSize.y; i++)
3920 sConsoleLines[i - 1] = sConsoleLines[i];
3921 sConsoleLines[vConsoleCursor.y].clear();
3922 }
3923 };
3924
3925 // Empty out "std::cout", parsing as we go
3926 while (ssConsoleOutput.rdbuf()->sgetc() != -1)
3927 {
3928 char c = ssConsoleOutput.rdbuf()->sbumpc();
3929 TypeCharacter(c);
3930 }
3931
3932 // Draw Shadow
3933 GradientFillRectDecal({ 0,0 }, olc::vf2d(vScreenSize), olc::PixelF(0, 0, 0.5f, 0.5f), olc::PixelF(0, 0, 0.25f, 0.5f), olc::PixelF(0, 0, 0.25f, 0.5f), olc::PixelF(0, 0, 0.25f, 0.5f));
3934
3935 // Draw the console buffer
3937 for (int32_t nLine = 0; nLine < vConsoleSize.y; nLine++)
3938 DrawStringDecal(olc::vf2d( 1, 1 + float(nLine) ) * vConsoleCharacterScale * 8.0f, sConsoleLines[nLine], olc::WHITE, vConsoleCharacterScale);
3939
3940 // Draw Input State
3941 FillRectDecal(olc::vf2d(1 + float((TextEntryGetCursor() + 1)), 1 + float((vConsoleSize.y - 1))) * vConsoleCharacterScale * 8.0f, olc::vf2d(8, 8) * vConsoleCharacterScale, olc::DARK_CYAN);
3942 DrawStringDecal(olc::vf2d(1, 1 + float((vConsoleSize.y - 1))) * vConsoleCharacterScale * 8.0f, std::string(">") + TextEntryGetString(), olc::YELLOW, vConsoleCharacterScale);
3943 }
3944
3945
3946 const std::vector<std::string>& PixelGameEngine::GetDroppedFiles() const
3947 { return vDroppedFiles; }
3948
3950 { return vDroppedFilesPoint; }
3951
3952
3953 void PixelGameEngine::TextEntryEnable(const bool bEnable, const std::string& sText)
3954 {
3955 if (bEnable)
3956 {
3957 nTextEntryCursor = int32_t(sText.size());
3958 sTextEntryString = sText;
3959 bTextEntryEnable = true;
3960 }
3961 else
3962 {
3963 bTextEntryEnable = false;
3964 }
3965 }
3966
3967 std::string PixelGameEngine::TextEntryGetString() const
3968 { return sTextEntryString; }
3969
3971 { return nTextEntryCursor; }
3972
3974 { return bTextEntryEnable; }
3975
3976
3977 void PixelGameEngine::UpdateTextEntry()
3978 {
3979 // Check for typed characters
3980 for (const auto& key : vKeyboardMap)
3981 if (GetKey(std::get<0>(key)).bPressed)
3982 {
3983 sTextEntryString.insert(nTextEntryCursor, GetKey(olc::Key::SHIFT).bHeld ? std::get<2>(key) : std::get<1>(key));
3984 nTextEntryCursor++;
3985 }
3986
3987 // Check for command characters
3988 if (GetKey(olc::Key::LEFT).bPressed)
3989 nTextEntryCursor = std::max(0, nTextEntryCursor - 1);
3990 if (GetKey(olc::Key::RIGHT).bPressed)
3991 nTextEntryCursor = std::min(int32_t(sTextEntryString.size()), nTextEntryCursor + 1);
3992 if (GetKey(olc::Key::BACK).bPressed && nTextEntryCursor > 0)
3993 {
3994 sTextEntryString.erase(nTextEntryCursor-1, 1);
3995 nTextEntryCursor = std::max(0, nTextEntryCursor - 1);
3996 }
3997 if (GetKey(olc::Key::DEL).bPressed && size_t(nTextEntryCursor) < sTextEntryString.size())
3998 sTextEntryString.erase(nTextEntryCursor, 1);
3999
4000 if (GetKey(olc::Key::UP).bPressed)
4001 {
4002 if (!sCommandHistory.empty())
4003 {
4004 if (sCommandHistoryIt != sCommandHistory.begin())
4005 sCommandHistoryIt--;
4006
4007 nTextEntryCursor = int32_t(sCommandHistoryIt->size());
4008 sTextEntryString = *sCommandHistoryIt;
4009 }
4010 }
4011
4012 if (GetKey(olc::Key::DOWN).bPressed)
4013 {
4014 if (!sCommandHistory.empty())
4015 {
4016 if (sCommandHistoryIt != sCommandHistory.end())
4017 {
4018 sCommandHistoryIt++;
4019 if (sCommandHistoryIt != sCommandHistory.end())
4020 {
4021 nTextEntryCursor = int32_t(sCommandHistoryIt->size());
4022 sTextEntryString = *sCommandHistoryIt;
4023 }
4024 else
4025 {
4026 nTextEntryCursor = 0;
4027 sTextEntryString = "";
4028 }
4029 }
4030 }
4031 }
4032
4033 if (GetKey(olc::Key::ENTER).bPressed)
4034 {
4035 if (bConsoleShow)
4036 {
4037 std::cout << ">" + sTextEntryString + "\n";
4038 if (OnConsoleCommand(sTextEntryString))
4039 {
4040 sCommandHistory.push_back(sTextEntryString);
4041 sCommandHistoryIt = sCommandHistory.end();
4042 }
4043 sTextEntryString.clear();
4044 nTextEntryCursor = 0;
4045 }
4046 else
4047 {
4048 OnTextEntryComplete(sTextEntryString);
4049 TextEntryEnable(false);
4050 }
4051 }
4052 }
4053
4054 // User must override these functions as required. I have not made
4055 // them abstract because I do need a default behaviour to occur if
4056 // they are not overwritten
4057
4059 { return false; }
4060
4061 bool PixelGameEngine::OnUserUpdate(float fElapsedTime)
4062 { UNUSED(fElapsedTime); return false; }
4063
4065 { return true; }
4066
4067 void PixelGameEngine::OnTextEntryComplete(const std::string& sText) { UNUSED(sText); }
4068 bool PixelGameEngine::OnConsoleCommand(const std::string& sCommand) { UNUSED(sCommand); return false; }
4069
4070
4072 {
4073 if (platform)
4074 return platform->SetWindowSize(vPos, vSize);
4075 else
4076 return olc::FAIL;
4077 }
4078
4079 olc::rcode PixelGameEngine::ShowWindowFrame(const bool bShowFrame)
4080 {
4081 if (platform)
4082 return platform->ShowWindowFrame(bShowFrame);
4083 else
4084 return olc::FAIL;
4085 }
4086
4087
4088 // Externalised API
4090 {
4091 if (bRealWindowMode)
4092 {
4093 vPixelSize = { 1,1 };
4094 vViewSize = vScreenSize;
4095 vViewPos = { 0,0 };
4096 return;
4097 }
4098
4099 int32_t ww = vScreenSize.x * vPixelSize.x;
4100 int32_t wh = vScreenSize.y * vPixelSize.y;
4101 float wasp = (float)ww / (float)wh;
4102
4103 if (bPixelCohesion)
4104 {
4105 vScreenPixelSize = (vWindowSize / vScreenSize);
4106 vViewSize = (vWindowSize / vScreenSize) * vScreenSize;
4107 }
4108 else
4109 {
4110 vViewSize.x = (int32_t)vWindowSize.x;
4111 vViewSize.y = (int32_t)((float)vViewSize.x / wasp);
4112
4113 if (vViewSize.y > vWindowSize.y)
4114 {
4115 vViewSize.y = vWindowSize.y;
4116 vViewSize.x = (int32_t)((float)vViewSize.y * wasp);
4117 }
4118 }
4119
4120 vViewPos = (vWindowSize - vViewSize) / 2;
4121 }
4122
4123 void PixelGameEngine::olc_UpdateWindowPos(int32_t x, int32_t y)
4124 {
4125 vWindowPos = { x, y };
4127 }
4128
4129 void PixelGameEngine::olc_UpdateWindowSize(int32_t x, int32_t y)
4130 {
4131 vWindowSize = { x, y };
4132
4133 if (bRealWindowMode)
4134 {
4135 vResizeRequested = vWindowSize;
4136 bResizeRequested = true;
4137 }
4138
4140 }
4141
4142 void PixelGameEngine::olc_UpdateMouseWheel(int32_t delta)
4143 { nMouseWheelDeltaCache += delta; }
4144
4145 void PixelGameEngine::olc_UpdateMouse(int32_t x, int32_t y)
4146 {
4147 // Mouse coords come in screen space
4148 // But leave in pixel space
4149 bHasMouseFocus = true;
4150 vMouseWindowPos = { x, y };
4151 // Full Screen mode may have a weird viewport we must clamp to
4152 x -= vViewPos.x;
4153 y -= vViewPos.y;
4154 vMousePosCache.x = (int32_t)(((float)x / (float)(vWindowSize.x - (vViewPos.x * 2)) * (float)vScreenSize.x));
4155 vMousePosCache.y = (int32_t)(((float)y / (float)(vWindowSize.y - (vViewPos.y * 2)) * (float)vScreenSize.y));
4156 if (vMousePosCache.x >= (int32_t)vScreenSize.x) vMousePosCache.x = vScreenSize.x - 1;
4157 if (vMousePosCache.y >= (int32_t)vScreenSize.y) vMousePosCache.y = vScreenSize.y - 1;
4158 if (vMousePosCache.x < 0) vMousePosCache.x = 0;
4159 if (vMousePosCache.y < 0) vMousePosCache.y = 0;
4160 }
4161
4162 void PixelGameEngine::olc_UpdateMouseState(int32_t button, bool state)
4163 { pMouseNewState[button] = state; }
4164
4165 void PixelGameEngine::olc_UpdateKeyState(int32_t key, bool state)
4166 { pKeyNewState[key] = state; }
4167
4169 { bHasMouseFocus = state; }
4170
4172 { bHasInputFocus = state; }
4173
4174 void PixelGameEngine::olc_DropFiles(int32_t x, int32_t y, const std::vector<std::string>& vFiles)
4175 {
4176 x -= vViewPos.x;
4177 y -= vViewPos.y;
4178 vDroppedFilesPointCache.x = (int32_t)(((float)x / (float)(vWindowSize.x - (vViewPos.x * 2)) * (float)vScreenSize.x));
4179 vDroppedFilesPointCache.y = (int32_t)(((float)y / (float)(vWindowSize.y - (vViewPos.y * 2)) * (float)vScreenSize.y));
4180 if (vDroppedFilesPointCache.x >= (int32_t)vScreenSize.x) vDroppedFilesPointCache.x = vScreenSize.x - 1;
4181 if (vDroppedFilesPointCache.y >= (int32_t)vScreenSize.y) vDroppedFilesPointCache.y = vScreenSize.y - 1;
4182 if (vDroppedFilesPointCache.x < 0) vDroppedFilesPointCache.x = 0;
4183 if (vDroppedFilesPointCache.y < 0) vDroppedFilesPointCache.y = 0;
4184 vDroppedFilesCache = vFiles;
4185 }
4186
4188 { bAtomActive = true; }
4189
4191 { return bAtomActive; }
4192
4194 { bAtomActive = false; }
4195
4196 void PixelGameEngine::EngineThread()
4197 {
4198 // Allow platform to do stuff here if needed, since its now in the
4199 // context of this thread
4200 if (platform->ThreadStartUp() == olc::FAIL) return;
4201
4202 // Do engine context specific initialisation
4204
4205 // Create user resources as part of this thread
4206 for (auto& ext : vExtensions) ext->OnBeforeUserCreate();
4207 if (!OnUserCreate()) bAtomActive = false;
4208 for (auto& ext : vExtensions) ext->OnAfterUserCreate();
4209
4210 while (bAtomActive)
4211 {
4212 // Run as fast as possible
4213 while (bAtomActive) { olc_CoreUpdate(); }
4214
4215 // Allow the user to free resources if they have overrided the destroy function
4216 if (!OnUserDestroy())
4217 {
4218 // User denied destroy for some reason, so continue running
4219 bAtomActive = true;
4220 }
4221 }
4222
4223 platform->ThreadCleanUp();
4224 }
4225
4227 {
4228 // Start OpenGL, the context is owned by the game thread
4229 if (platform->CreateGraphics(bFullScreen, bEnableVSYNC, vViewPos, vViewSize) == olc::FAIL) return;
4230
4231 // Construct default font sheet
4233
4234 // Create Primary Layer "0"
4235 CreateLayer();
4236 vLayers[0].bUpdate = true;
4237 vLayers[0].bShow = true;
4238 SetDrawTarget(nullptr);
4239
4240 m_tp1 = std::chrono::system_clock::now();
4241 m_tp2 = std::chrono::system_clock::now();
4242 }
4243
4244
4245 void PixelGameEngine::adv_ManualRenderEnable(const bool bEnable)
4246 {
4247 bManualRenderEnable = bEnable;
4248 }
4249
4250 void PixelGameEngine::adv_HardwareClip(const bool bClipAndScale, const olc::vi2d & viewPos, const olc::vi2d & viewSize, const bool bClear)
4251 {
4252 olc::vf2d vNewSize = olc::vf2d(viewSize) / olc::vf2d(vScreenSize);
4253 olc::vf2d vNewPos = olc::vf2d(viewPos) / olc::vf2d(vScreenSize);
4254 renderer->UpdateViewport(vViewPos + vNewPos * vViewSize, vNewSize * vViewSize);
4255
4256 if (bClear)
4257 renderer->ClearBuffer(olc::BLACK, true);
4258
4260 renderer->PrepareDrawing();
4261
4262 if(!bClipAndScale)
4263 vInvScreenSize = 1.0f / olc::vf2d(viewSize);
4264 else
4265 vInvScreenSize = 1.0f / olc::vf2d(vScreenSize);
4266 }
4267
4268 void PixelGameEngine::adv_FlushLayer(const size_t nLayerID)
4269 {
4270 auto& layer = vLayers[nLayerID];
4271
4272 if (layer.bShow)
4273 {
4274 if (layer.funcHook == nullptr)
4275 {
4276 renderer->ApplyTexture(layer.pDrawTarget.Decal()->id);
4277 if (!bSuspendTextureTransfer)
4278 {
4279 layer.pDrawTarget.Decal()->Update();
4280 layer.bUpdate = false;
4281 }
4282
4283 // Can't use this as it assumes full screen coords
4284 // renderer->DrawLayerQuad(layer.vOffset, layer.vScale, layer.tint);
4285 // Instead, render a textured decal
4286
4287 olc::vf2d vScreenSpacePos =
4288 {
4289 (layer.vOffset.x * vInvScreenSize.x) * 2.0f - 1.0f,
4290 ((layer.vOffset.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f
4291 };
4292
4293 olc::vf2d vScreenSpaceDim =
4294 {
4295 vScreenSpacePos.x + (2.0f * (float(layer.pDrawTarget.Sprite()->width) * vInvScreenSize.x)) * layer.vScale.x,
4296 vScreenSpacePos.y - (2.0f * (float(layer.pDrawTarget.Sprite()->height) * vInvScreenSize.y)) * layer.vScale.y
4297 };
4298
4299 DecalInstance di;
4300 di.decal = layer.pDrawTarget.Decal();
4301 di.points = 4;
4302 di.tint = { olc::WHITE, olc::WHITE, olc::WHITE, olc::WHITE };
4303 di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } };
4304 di.uv = { { 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f} };
4305 di.w = { 1, 1, 1, 1 };
4306 di.mode = DecalMode::NORMAL;
4307 di.structure = DecalStructure::FAN;
4308 renderer->DrawDecal(di);
4309 }
4310 else
4311 {
4312 // Mwa ha ha.... Have Fun!!!
4313 layer.funcHook();
4314 }
4315 }
4316 }
4317
4318 void PixelGameEngine::adv_FlushLayerDecals(const size_t nLayerID)
4319 {
4320 // Display Decals in order for this layer
4321 auto& layer = vLayers[nLayerID];
4322 for (auto& decal : layer.vecDecalInstance)
4323 renderer->DrawDecal(decal);
4324 layer.vecDecalInstance.clear();
4325 }
4326
4327
4328
4330 {
4331 // Handle Timing
4332 m_tp2 = std::chrono::system_clock::now();
4333 std::chrono::duration<float> elapsedTime = m_tp2 - m_tp1;
4334 m_tp1 = m_tp2;
4335
4336 // Our time per frame coefficient
4337 float fElapsedTime = elapsedTime.count();
4338 fLastElapsed = fElapsedTime;
4339
4340 if (bConsoleSuspendTime)
4341 fElapsedTime = 0.0f;
4342
4343 // Some platforms will need to check for events
4344 platform->HandleSystemEvent();
4345
4346 // Compare hardware input states from previous frame
4347 auto ScanHardware = [&](HWButton* pKeys, bool* pStateOld, bool* pStateNew, uint32_t nKeyCount)
4348 {
4349 for (uint32_t i = 0; i < nKeyCount; i++)
4350 {
4351 pKeys[i].bPressed = false;
4352 pKeys[i].bReleased = false;
4353 if (pStateNew[i] != pStateOld[i])
4354 {
4355 if (pStateNew[i])
4356 {
4357 pKeys[i].bPressed = !pKeys[i].bHeld;
4358 pKeys[i].bHeld = true;
4359 }
4360 else
4361 {
4362 pKeys[i].bReleased = true;
4363 pKeys[i].bHeld = false;
4364 }
4365 }
4366 pStateOld[i] = pStateNew[i];
4367 }
4368 };
4369
4370 ScanHardware(pKeyboardState, pKeyOldState, pKeyNewState, 256);
4371 ScanHardware(pMouseState, pMouseOldState, pMouseNewState, nMouseButtons);
4372
4373 // Cache mouse coordinates so they remain consistent during frame
4374 vMousePos = vMousePosCache;
4375 nMouseWheelDelta = nMouseWheelDeltaCache;
4376 nMouseWheelDeltaCache = 0;
4377
4378 vDroppedFiles = vDroppedFilesCache;
4379 vDroppedFilesPoint = vDroppedFilesPointCache;
4380 vDroppedFilesCache.clear();
4381
4382 if (bTextEntryEnable)
4383 {
4384 UpdateTextEntry();
4385 }
4386
4387 // Handle Frame Update
4388 bool bExtensionBlockFrame = false;
4389 for (auto& ext : vExtensions) bExtensionBlockFrame |= ext->OnBeforeUserUpdate(fElapsedTime);
4390 if (!bExtensionBlockFrame)
4391 {
4392 if (!OnUserUpdate(fElapsedTime)) bAtomActive = false;
4393
4394 }
4395 for (auto& ext : vExtensions) ext->OnAfterUserUpdate(fElapsedTime);
4396
4397
4398
4399 if (bRealWindowMode)
4400 {
4401 vPixelSize = { 1,1 };
4402 vViewSize = vScreenSize;
4403 vViewPos = { 0,0 };
4404 }
4405
4406 if (!bManualRenderEnable)
4407 {
4408 if (bConsoleShow)
4409 {
4410 SetDrawTarget((uint8_t)0);
4411 UpdateConsole();
4412 }
4413
4414 // Display Frame
4415 renderer->UpdateViewport(vViewPos, vViewSize);
4416 renderer->ClearBuffer(olc::BLACK, true);
4417
4418 // Layer 0 must always exist
4419 vLayers[0].bUpdate = true;
4420 vLayers[0].bShow = true;
4422 renderer->PrepareDrawing();
4423
4424 for (auto layer = vLayers.rbegin(); layer != vLayers.rend(); ++layer)
4425 {
4426 if (layer->bShow)
4427 {
4428 if (layer->funcHook == nullptr)
4429 {
4430 renderer->ApplyTexture(layer->pDrawTarget.Decal()->id);
4431 if (!bSuspendTextureTransfer && layer->bUpdate)
4432 {
4433 layer->pDrawTarget.Decal()->Update();
4434 layer->bUpdate = false;
4435 }
4436
4437 renderer->DrawLayerQuad(layer->vOffset, layer->vScale, layer->tint);
4438
4439 // Display Decals in order for this layer
4440 for (auto& decal : layer->vecDecalInstance)
4441 renderer->DrawDecal(decal);
4442 layer->vecDecalInstance.clear();
4443 }
4444 else
4445 {
4446 // Mwa ha ha.... Have Fun!!!
4447 layer->funcHook();
4448 }
4449 }
4450 }
4451 }
4452
4453 // Present Graphics to screen
4454 renderer->DisplayFrame();
4455
4456 if (bResizeRequested)
4457 {
4458 bResizeRequested = false;
4459 SetScreenSize(vWindowSize.x, vWindowSize.y);
4460 renderer->UpdateViewport({ 0,0 }, vWindowSize);
4461 }
4462
4463 // Update Title Bar
4464 fFrameTimer += fElapsedTime;
4465 nFrameCount++;
4466 if (fFrameTimer >= 1.0f)
4467 {
4468 nLastFPS = nFrameCount;
4469 fFrameTimer -= 1.0f;
4470 std::string sTitle = "OneLoneCoder.com - Pixel Game Engine - " + sAppName + " - FPS: " + std::to_string(nFrameCount);
4471 platform->SetWindowTitle(sTitle);
4472 nFrameCount = 0;
4473 }
4474 }
4475
4477 {
4478 std::string data;
4479 data += "?Q`0001oOch0o01o@F40o0<AGD4090LAGD<090@A7ch0?00O7Q`0600>00000000";
4480 data += "O000000nOT0063Qo4d8>?7a14Gno94AA4gno94AaOT0>o3`oO400o7QN00000400";
4481 data += "Of80001oOg<7O7moBGT7O7lABET024@aBEd714AiOdl717a_=TH013Q>00000000";
4482 data += "720D000V?V5oB3Q_HdUoE7a9@DdDE4A9@DmoE4A;Hg]oM4Aj8S4D84@`00000000";
4483 data += "OaPT1000Oa`^13P1@AI[?g`1@A=[OdAoHgljA4Ao?WlBA7l1710007l100000000";
4484 data += "ObM6000oOfMV?3QoBDD`O7a0BDDH@5A0BDD<@5A0BGeVO5ao@CQR?5Po00000000";
4485 data += "Oc``000?Ogij70PO2D]??0Ph2DUM@7i`2DTg@7lh2GUj?0TO0C1870T?00000000";
4486 data += "70<4001o?P<7?1QoHg43O;`h@GT0@:@LB@d0>:@hN@L0@?aoN@<0O7ao0000?000";
4487 data += "OcH0001SOglLA7mg24TnK7ln24US>0PL24U140PnOgl0>7QgOcH0K71S0000A000";
4488 data += "00H00000@Dm1S007@DUSg00?OdTnH7YhOfTL<7Yh@Cl0700?@Ah0300700000000";
4489 data += "<008001QL00ZA41a@6HnI<1i@FHLM81M@@0LG81?O`0nC?Y7?`0ZA7Y300080000";
4490 data += "O`082000Oh0827mo6>Hn?Wmo?6HnMb11MP08@C11H`08@FP0@@0004@000000000";
4491 data += "00P00001Oab00003OcKP0006@6=PMgl<@440MglH@000000`@000001P00000000";
4492 data += "Ob@8@@00Ob@8@Ga13R@8Mga172@8?PAo3R@827QoOb@820@0O`0007`0000007P0";
4493 data += "O`000P08Od400g`<3V=P0G`673IP0`@3>1`00P@6O`P00g`<O`000GP800000000";
4494 data += "?P9PL020O`<`N3R0@E4HC7b0@ET<ATB0@@l6C4B0O`H3N7b0?P01L3R000000020";
4495
4496 fontRenderable.Create(128, 48);
4497
4498 int px = 0, py = 0;
4499 for (size_t b = 0; b < 1024; b += 4)
4500 {
4501 uint32_t sym1 = (uint32_t)data[b + 0] - 48;
4502 uint32_t sym2 = (uint32_t)data[b + 1] - 48;
4503 uint32_t sym3 = (uint32_t)data[b + 2] - 48;
4504 uint32_t sym4 = (uint32_t)data[b + 3] - 48;
4505 uint32_t r = sym1 << 18 | sym2 << 12 | sym3 << 6 | sym4;
4506
4507 for (int i = 0; i < 24; i++)
4508 {
4509 int k = r & (1 << i) ? 255 : 0;
4510 fontRenderable.Sprite()->SetPixel(px, py, olc::Pixel(k, k, k, k));
4511 if (++py == 48) { px++; py = 0; }
4512 }
4513 }
4514
4515 fontRenderable.Decal()->Update();
4516
4517 constexpr std::array<uint8_t, 96> vSpacing = { {
4518 0x03,0x25,0x16,0x08,0x07,0x08,0x08,0x04,0x15,0x15,0x08,0x07,0x15,0x07,0x24,0x08,
4519 0x08,0x17,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x24,0x15,0x06,0x07,0x16,0x17,
4520 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x17,0x08,0x08,0x17,0x08,0x08,0x08,
4521 0x08,0x08,0x08,0x08,0x17,0x08,0x08,0x08,0x08,0x17,0x08,0x15,0x08,0x15,0x08,0x08,
4522 0x24,0x18,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x33,0x17,0x17,0x33,0x18,0x17,0x17,
4523 0x17,0x17,0x17,0x17,0x07,0x17,0x17,0x18,0x18,0x17,0x17,0x07,0x33,0x07,0x08,0x00, } };
4524
4525 for (auto c : vSpacing) vFontSpacing.push_back({ c >> 4, c & 15 });
4526
4527 // UK Standard Layout
4528#ifdef OLC_KEYBOARD_UK
4529 vKeyboardMap =
4530 {
4531 {olc::Key::A, "a", "A"}, {olc::Key::B, "b", "B"}, {olc::Key::C, "c", "C"}, {olc::Key::D, "d", "D"}, {olc::Key::E, "e", "E"},
4532 {olc::Key::F, "f", "F"}, {olc::Key::G, "g", "G"}, {olc::Key::H, "h", "H"}, {olc::Key::I, "i", "I"}, {olc::Key::J, "j", "J"},
4533 {olc::Key::K, "k", "K"}, {olc::Key::L, "l", "L"}, {olc::Key::M, "m", "M"}, {olc::Key::N, "n", "N"}, {olc::Key::O, "o", "O"},
4534 {olc::Key::P, "p", "P"}, {olc::Key::Q, "q", "Q"}, {olc::Key::R, "r", "R"}, {olc::Key::S, "s", "S"}, {olc::Key::T, "t", "T"},
4535 {olc::Key::U, "u", "U"}, {olc::Key::V, "v", "V"}, {olc::Key::W, "w", "W"}, {olc::Key::X, "x", "X"}, {olc::Key::Y, "y", "Y"},
4536 {olc::Key::Z, "z", "Z"},
4537
4538 {olc::Key::K0, "0", ")"}, {olc::Key::K1, "1", "!"}, {olc::Key::K2, "2", "\""}, {olc::Key::K3, "3", "#"}, {olc::Key::K4, "4", "$"},
4539 {olc::Key::K5, "5", "%"}, {olc::Key::K6, "6", "^"}, {olc::Key::K7, "7", "&"}, {olc::Key::K8, "8", "*"}, {olc::Key::K9, "9", "("},
4540
4541 {olc::Key::NP0, "0", "0"}, {olc::Key::NP1, "1", "1"}, {olc::Key::NP2, "2", "2"}, {olc::Key::NP3, "3", "3"}, {olc::Key::NP4, "4", "4"},
4542 {olc::Key::NP5, "5", "5"}, {olc::Key::NP6, "6", "6"}, {olc::Key::NP7, "7", "7"}, {olc::Key::NP8, "8", "8"}, {olc::Key::NP9, "9", "9"},
4543 {olc::Key::NP_MUL, "*", "*"}, {olc::Key::NP_DIV, "/", "/"}, {olc::Key::NP_ADD, "+", "+"}, {olc::Key::NP_SUB, "-", "-"}, {olc::Key::NP_DECIMAL, ".", "."},
4544
4545 {olc::Key::PERIOD, ".", ">"}, {olc::Key::EQUALS, "=", "+"}, {olc::Key::COMMA, ",", "<"}, {olc::Key::MINUS, "-", "_"}, {olc::Key::SPACE, " ", " "},
4546
4547 {olc::Key::OEM_1, ";", ":"}, {olc::Key::OEM_2, "/", "?"}, {olc::Key::OEM_3, "\'", "@"}, {olc::Key::OEM_4, "[", "{"},
4548 {olc::Key::OEM_5, "\\", "|"}, {olc::Key::OEM_6, "]", "}"}, {olc::Key::OEM_7, "#", "~"},
4549
4550 // {olc::Key::TAB, "\t", "\t"}
4551 };
4552#endif
4553 }
4554
4556 {
4557 if (std::find(vExtensions.begin(), vExtensions.end(), pgex) == vExtensions.end())
4558 vExtensions.push_back(pgex);
4559 }
4560
4561
4562 PGEX::PGEX(bool bHook) { if(bHook) pge->pgex_Register(this); }
4563 void PGEX::OnBeforeUserCreate() {}
4564 void PGEX::OnAfterUserCreate() {}
4565 bool PGEX::OnBeforeUserUpdate(float& fElapsedTime) { return false; }
4566 void PGEX::OnAfterUserUpdate(float fElapsedTime) {}
4567
4568 // Need a couple of statics as these are singleton instances
4569 // read from multiple locations
4570 std::atomic<bool> PixelGameEngine::bAtomActive{ false };
4574 std::unique_ptr<ImageLoader> olc::Sprite::loader = nullptr;
4575};
4576#pragma endregion
4577
4578
4579#pragma region platform_headless
4580namespace olc
4581{
4582#if defined(OLC_GFX_HEADLESS)
4583 class Renderer_Headless : public olc::Renderer
4584 {
4585 public:
4586 virtual void PrepareDevice() {};
4587 virtual olc::rcode CreateDevice(std::vector<void*> params, bool bFullScreen, bool bVSYNC) { return olc::rcode::OK; }
4588 virtual olc::rcode DestroyDevice() { return olc::rcode::OK; }
4589 virtual void DisplayFrame() {}
4590 virtual void PrepareDrawing() {}
4591 virtual void SetDecalMode(const olc::DecalMode& mode) {}
4592 virtual void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) {}
4593 virtual void DrawDecal(const olc::DecalInstance& decal) {}
4594 virtual uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered = false, const bool clamp = true) {return 1;};
4595 virtual void UpdateTexture(uint32_t id, olc::Sprite* spr) {}
4596 virtual void ReadTexture(uint32_t id, olc::Sprite* spr) {}
4597 virtual uint32_t DeleteTexture(const uint32_t id) {return 1;}
4598 virtual void ApplyTexture(uint32_t id) {}
4599 virtual void UpdateViewport(const olc::vi2d& pos, const olc::vi2d& size) {}
4600 virtual void ClearBuffer(olc::Pixel p, bool bDepth) {}
4601 };
4602#endif
4603#if defined(OLC_PLATFORM_HEADLESS)
4604 class Platform_Headless : public olc::Platform
4605 {
4606 public:
4607 virtual olc::rcode SetWindowSize(const olc::vi2d& vPos, const olc::vi2d& vSize) override
4608 { return olc::rcode::OK; }
4609
4610 virtual olc::rcode ShowWindowFrame(const bool bShowFrame = true) override
4611 { return olc::rcode::OK; }
4612
4613 virtual olc::rcode ApplicationStartUp() { return olc::rcode::OK; }
4614 virtual olc::rcode ApplicationCleanUp() { return olc::rcode::OK; }
4615 virtual olc::rcode ThreadStartUp() { return olc::rcode::OK; }
4616 virtual olc::rcode ThreadCleanUp() { return olc::rcode::OK; }
4617 virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) { return olc::rcode::OK; }
4618 virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) { return olc::rcode::OK; }
4619 virtual olc::rcode SetWindowTitle(const std::string& s) { return olc::rcode::OK; }
4620 virtual olc::rcode StartSystemEventLoop() { return olc::rcode::OK; }
4621 virtual olc::rcode HandleSystemEvent() { return olc::rcode::OK; }
4622 };
4623#endif
4624}
4625#pragma endregion
4626
4627// O------------------------------------------------------------------------------O
4628// | olcPixelGameEngine Renderers - the draw-y bits |
4629// O------------------------------------------------------------------------------O
4630
4631#pragma region image_stb
4632// O------------------------------------------------------------------------------O
4633// | START IMAGE LOADER: stb_image.h, all systems, very fast |
4634// O------------------------------------------------------------------------------O
4635// Thanks to Sean Barrett - https://github.com/nothings/stb/blob/master/stb_image.h
4636// MIT License - Copyright(c) 2017 Sean Barrett
4637
4638// Note you need to download the above file into your project folder, and
4639// #define OLC_IMAGE_STB
4640// #define OLC_PGE_APPLICATION
4641// #include "olcPixelGameEngine.h"
4642
4643#if defined(OLC_IMAGE_STB)
4644#define STB_IMAGE_IMPLEMENTATION
4645#include "stb_image.h"
4646namespace olc
4647{
4648 class ImageLoader_STB : public olc::ImageLoader
4649 {
4650 public:
4651 ImageLoader_STB() : ImageLoader()
4652 {}
4653
4654 olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override
4655 {
4656 UNUSED(pack);
4657 // clear out existing sprite
4658 spr->pColData.clear();
4659 // Open file
4660 stbi_uc* bytes = nullptr;
4661 int w = 0, h = 0, cmp = 0;
4662 if (pack != nullptr)
4663 {
4664 ResourceBuffer rb = pack->GetFileBuffer(sImageFile);
4665 bytes = stbi_load_from_memory((unsigned char*)rb.vMemory.data(), rb.vMemory.size(), &w, &h, &cmp, 4);
4666 }
4667 else
4668 {
4669 // Check file exists
4670 if (!_gfs::exists(sImageFile)) return olc::rcode::NO_FILE;
4671 bytes = stbi_load(sImageFile.c_str(), &w, &h, &cmp, 4);
4672 }
4673
4674 if (!bytes) return olc::rcode::FAIL;
4675 spr->width = w; spr->height = h;
4676 spr->pColData.resize(spr->width * spr->height);
4677 std::memcpy(spr->pColData.data(), bytes, spr->width * spr->height * 4);
4678 delete[] bytes;
4679 return olc::rcode::OK;
4680 }
4681
4682 olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) override
4683 {
4684 return olc::rcode::OK;
4685 }
4686 };
4687}
4688#endif
4689// O------------------------------------------------------------------------------O
4690// | START IMAGE LOADER: stb_image.h |
4691// O------------------------------------------------------------------------------O
4692#pragma endregion
4693
4694
4695
4696#if !defined(OLC_PGE_HEADLESS)
4697
4698#pragma region renderer_ogl10
4699// O------------------------------------------------------------------------------O
4700// | START RENDERER: OpenGL 1.0 (the original, the best...) |
4701// O------------------------------------------------------------------------------O
4702#if defined(OLC_GFX_OPENGL10)
4703
4704#if defined(OLC_PLATFORM_WINAPI)
4705 #include <dwmapi.h>
4706 #include <GL/gl.h>
4707 #if !defined(__MINGW32__)
4708 #pragma comment(lib, "Dwmapi.lib")
4709 #endif
4710 typedef BOOL(WINAPI wglSwapInterval_t) (int interval);
4711 static wglSwapInterval_t* wglSwapInterval = nullptr;
4712 typedef HDC glDeviceContext_t;
4713 typedef HGLRC glRenderContext_t;
4714#endif
4715
4716#if defined(__linux__) || defined(__FreeBSD__)
4717 #include <GL/gl.h>
4718#endif
4719
4720#if defined(OLC_PLATFORM_X11)
4721 namespace X11
4722 {
4723 #include <GL/glx.h>
4724 }
4725 typedef int(glSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval);
4726 static glSwapInterval_t* glSwapIntervalEXT;
4727 typedef X11::GLXContext glDeviceContext_t;
4728 typedef X11::GLXContext glRenderContext_t;
4729#endif
4730
4731#if defined(__APPLE__)
4732 #define GL_SILENCE_DEPRECATION
4733 #include <OpenGL/OpenGL.h>
4734 #include <OpenGL/gl.h>
4735 #include <OpenGL/glu.h>
4736#endif
4737
4738namespace olc
4739{
4740 class Renderer_OGL10 : public olc::Renderer
4741 {
4742 private:
4743#if defined(OLC_PLATFORM_GLUT)
4744 bool mFullScreen = false;
4745#else
4746 glDeviceContext_t glDeviceContext = 0;
4747 glRenderContext_t glRenderContext = 0;
4748#endif
4749
4750 bool bSync = false;
4751 olc::DecalMode nDecalMode = olc::DecalMode(-1); // Thanks Gusgo & Bispoo
4752 olc::DecalStructure nDecalStructure = olc::DecalStructure(-1);
4753#if defined(OLC_PLATFORM_X11)
4754 X11::Display* olc_Display = nullptr;
4755 X11::Window* olc_Window = nullptr;
4756 X11::XVisualInfo* olc_VisualInfo = nullptr;
4757#endif
4758
4759 public:
4760 void PrepareDevice() override
4761 {
4762#if defined(OLC_PLATFORM_GLUT)
4763 //glutInit has to be called with main() arguments, make fake ones
4764 int argc = 0;
4765 char* argv[1] = { (char*)"" };
4766 glutInit(&argc, argv);
4767 glutInitWindowPosition(0, 0);
4768 glutInitWindowSize(512, 512);
4769 glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);
4770 // Creates the window and the OpenGL context for it
4771 glutCreateWindow("OneLoneCoder.com - Pixel Game Engine");
4772 glEnable(GL_TEXTURE_2D); // Turn on texturing
4773 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4774#endif
4775 }
4776
4777 olc::rcode CreateDevice(std::vector<void*> params, bool bFullScreen, bool bVSYNC) override
4778 {
4779#if defined(OLC_PLATFORM_WINAPI)
4780 // Create Device Context
4781 glDeviceContext = GetDC((HWND)(params[0]));
4782 PIXELFORMATDESCRIPTOR pfd =
4783 {
4784 sizeof(PIXELFORMATDESCRIPTOR), 1,
4785 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
4786 PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4787 PFD_MAIN_PLANE, 0, 0, 0, 0
4788 };
4789
4790 int pf = 0;
4791 if (!(pf = ChoosePixelFormat(glDeviceContext, &pfd))) return olc::FAIL;
4792 SetPixelFormat(glDeviceContext, pf, &pfd);
4793
4794 if (!(glRenderContext = wglCreateContext(glDeviceContext))) return olc::FAIL;
4795 wglMakeCurrent(glDeviceContext, glRenderContext);
4796
4797 // Remove Frame cap
4798 wglSwapInterval = (wglSwapInterval_t*)wglGetProcAddress("wglSwapIntervalEXT");
4799 if (wglSwapInterval && !bVSYNC) wglSwapInterval(0);
4800 bSync = bVSYNC;
4801#endif
4802
4803#if defined(OLC_PLATFORM_X11)
4804 using namespace X11;
4805 // Linux has tighter coupling between OpenGL and X11, so we store
4806 // various "platform" handles in the renderer
4807 olc_Display = (X11::Display*)(params[0]);
4808 olc_Window = (X11::Window*)(params[1]);
4809 olc_VisualInfo = (X11::XVisualInfo*)(params[2]);
4810
4811 glDeviceContext = glXCreateContext(olc_Display, olc_VisualInfo, nullptr, GL_TRUE);
4812 glXMakeCurrent(olc_Display, *olc_Window, glDeviceContext);
4813
4814 XWindowAttributes gwa;
4815 XGetWindowAttributes(olc_Display, *olc_Window, &gwa);
4816 glViewport(0, 0, gwa.width, gwa.height);
4817
4818 glSwapIntervalEXT = nullptr;
4819 glSwapIntervalEXT = (glSwapInterval_t*)glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT");
4820
4821 if (glSwapIntervalEXT == nullptr && !bVSYNC)
4822 {
4823 printf("NOTE: Could not disable VSYNC, glXSwapIntervalEXT() was not found!\n");
4824 printf(" Don't worry though, things will still work, it's just the\n");
4825 printf(" frame rate will be capped to your monitors refresh rate - javidx9\n");
4826 }
4827
4828 if (glSwapIntervalEXT != nullptr && !bVSYNC)
4829 glSwapIntervalEXT(olc_Display, *olc_Window, 0);
4830#endif
4831
4832#if defined(OLC_PLATFORM_GLUT)
4833 mFullScreen = bFullScreen;
4834 if (!bVSYNC)
4835 {
4836#if defined(__APPLE__)
4837 GLint sync = 0;
4838 CGLContextObj ctx = CGLGetCurrentContext();
4839 if (ctx) CGLSetParameter(ctx, kCGLCPSwapInterval, &sync);
4840#endif
4841 }
4842#else
4843 glEnable(GL_TEXTURE_2D); // Turn on texturing
4844 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
4845#endif
4846 return olc::rcode::OK;
4847 }
4848
4849 olc::rcode DestroyDevice() override
4850 {
4851#if defined(OLC_PLATFORM_WINAPI)
4852 wglDeleteContext(glRenderContext);
4853#endif
4854
4855#if defined(OLC_PLATFORM_X11)
4856 glXMakeCurrent(olc_Display, None, NULL);
4857 glXDestroyContext(olc_Display, glDeviceContext);
4858#endif
4859
4860#if defined(OLC_PLATFORM_GLUT)
4861 glutDestroyWindow(glutGetWindow());
4862#endif
4863 return olc::rcode::OK;
4864 }
4865
4866 void DisplayFrame() override
4867 {
4868#if defined(OLC_PLATFORM_WINAPI)
4869 SwapBuffers(glDeviceContext);
4870 if (bSync) DwmFlush(); // Woooohooooooo!!!! SMOOOOOOOTH!
4871#endif
4872
4873#if defined(OLC_PLATFORM_X11)
4874 X11::glXSwapBuffers(olc_Display, *olc_Window);
4875#endif
4876
4877#if defined(OLC_PLATFORM_GLUT)
4878 glutSwapBuffers();
4879#endif
4880 }
4881
4882 void PrepareDrawing() override
4883 {
4884
4885 //ClearBuffer(olc::GREEN, true);
4886 glEnable(GL_BLEND);
4887 nDecalMode = DecalMode::NORMAL;
4888 nDecalStructure = DecalStructure::FAN;
4889 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4890 }
4891
4892 void SetDecalMode(const olc::DecalMode& mode)
4893 {
4894 if (mode != nDecalMode)
4895 {
4896 switch (mode)
4897 {
4899 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4900 break;
4902 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
4903 break;
4905 glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
4906 break;
4908 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
4909 break;
4911 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
4912 break;
4914 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4915 break;
4916 }
4917
4918 nDecalMode = mode;
4919 }
4920 }
4921
4922 void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) override
4923 {
4924 glBegin(GL_QUADS);
4925 glColor4ub(tint.r, tint.g, tint.b, tint.a);
4926 glTexCoord2f(0.0f * scale.x + offset.x, 1.0f * scale.y + offset.y);
4927 glVertex3f(-1.0f /*+ vSubPixelOffset.x*/, -1.0f /*+ vSubPixelOffset.y*/, 0.0f);
4928 glTexCoord2f(0.0f * scale.x + offset.x, 0.0f * scale.y + offset.y);
4929 glVertex3f(-1.0f /*+ vSubPixelOffset.x*/, 1.0f /*+ vSubPixelOffset.y*/, 0.0f);
4930 glTexCoord2f(1.0f * scale.x + offset.x, 0.0f * scale.y + offset.y);
4931 glVertex3f(1.0f /*+ vSubPixelOffset.x*/, 1.0f /*+ vSubPixelOffset.y*/, 0.0f);
4932 glTexCoord2f(1.0f * scale.x + offset.x, 1.0f * scale.y + offset.y);
4933 glVertex3f(1.0f /*+ vSubPixelOffset.x*/, -1.0f /*+ vSubPixelOffset.y*/, 0.0f);
4934 glEnd();
4935 }
4936
4937 void DrawDecal(const olc::DecalInstance& decal) override
4938 {
4939 SetDecalMode(decal.mode);
4940
4941 if (decal.decal == nullptr)
4942 glBindTexture(GL_TEXTURE_2D, 0);
4943 else
4944 glBindTexture(GL_TEXTURE_2D, decal.decal->id);
4945
4946 if (decal.depth)
4947 {
4948 glEnable(GL_DEPTH_TEST);
4949 }
4950
4951 if (nDecalMode == DecalMode::WIREFRAME)
4952 glBegin(GL_LINE_LOOP);
4953 else
4954 {
4956 glBegin(GL_TRIANGLE_FAN);
4957 else if(decal.structure == olc::DecalStructure::STRIP)
4958 glBegin(GL_TRIANGLE_STRIP);
4959 else if(decal.structure == olc::DecalStructure::LIST)
4960 glBegin(GL_TRIANGLES);
4961 }
4962
4963 if (decal.depth)
4964 {
4965
4966 // Render as 3D Spatial Entity
4967 for (uint32_t n = 0; n < decal.points; n++)
4968 {
4969 glColor4ub(decal.tint[n].r, decal.tint[n].g, decal.tint[n].b, decal.tint[n].a);
4970 glTexCoord4f(decal.uv[n].x, decal.uv[n].y, 0.0f, decal.w[n]);
4971 glVertex3f(decal.pos[n].x, decal.pos[n].y, decal.z[n]);
4972 }
4973 }
4974 else
4975 {
4976 // Render as 2D Spatial entity
4977 for (uint32_t n = 0; n < decal.points; n++)
4978 {
4979 glColor4ub(decal.tint[n].r, decal.tint[n].g, decal.tint[n].b, decal.tint[n].a);
4980 glTexCoord4f(decal.uv[n].x, decal.uv[n].y, 0.0f, decal.w[n]);
4981 glVertex2f(decal.pos[n].x, decal.pos[n].y);
4982 }
4983 }
4984
4985 glEnd();
4986
4987 if (decal.depth)
4988 {
4989 glDisable(GL_DEPTH_TEST);
4990 }
4991
4992 }
4993
4994 uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered, const bool clamp) override
4995 {
4996 UNUSED(width);
4997 UNUSED(height);
4998 uint32_t id = 0;
4999 glGenTextures(1, &id);
5000 glBindTexture(GL_TEXTURE_2D, id);
5001 if (filtered)
5002 {
5003 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5004 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5005 }
5006 else
5007 {
5008 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5009 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5010 }
5011
5012 if (clamp)
5013 {
5014 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
5015 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
5016 }
5017 else
5018 {
5019 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
5020 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
5021 }
5022
5023 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
5024 return id;
5025 }
5026
5027 uint32_t DeleteTexture(const uint32_t id) override
5028 {
5029 glDeleteTextures(1, &id);
5030 return id;
5031 }
5032
5033 void UpdateTexture(uint32_t id, olc::Sprite* spr) override
5034 {
5035 UNUSED(id);
5036 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, spr->width, spr->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData());
5037 }
5038
5039 void ReadTexture(uint32_t id, olc::Sprite* spr) override
5040 {
5041 glReadPixels(0, 0, spr->width, spr->height, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData());
5042 }
5043
5044 void ApplyTexture(uint32_t id) override
5045 {
5046 glBindTexture(GL_TEXTURE_2D, id);
5047 }
5048
5049 void ClearBuffer(olc::Pixel p, bool bDepth) override
5050 {
5051 glClearColor(float(p.r) / 255.0f, float(p.g) / 255.0f, float(p.b) / 255.0f, float(p.a) / 255.0f);
5052 glClear(GL_COLOR_BUFFER_BIT);
5053 if (bDepth) glClear(GL_DEPTH_BUFFER_BIT);
5054 }
5055
5056 void UpdateViewport(const olc::vi2d& pos, const olc::vi2d& size) override
5057 {
5058 glViewport(pos.x, pos.y, size.x, size.y);
5059 }
5060 };
5061}
5062#endif
5063// O------------------------------------------------------------------------------O
5064// | END RENDERER: OpenGL 1.0 (the original, the best...) |
5065// O------------------------------------------------------------------------------O
5066#pragma endregion
5067
5068#pragma region renderer_ogl33
5069// O------------------------------------------------------------------------------O
5070// | START RENDERER: OpenGL 3.3 (3.0 es) (sh-sh-sh-shaders....) |
5071// O------------------------------------------------------------------------------O
5072#if defined(OLC_GFX_OPENGL33)
5073
5074#if defined(OLC_PLATFORM_WINAPI)
5075 #include <dwmapi.h>
5076 //#include <gl/GL.h>
5077 #if !defined(__MINGW32__)
5078 #pragma comment(lib, "Dwmapi.lib")
5079 #endif
5080 //typedef void __stdcall locSwapInterval_t(GLsizei n);
5081 typedef HDC glDeviceContext_t;
5082 typedef HGLRC glRenderContext_t;
5083 //#define CALLSTYLE __stdcall
5084 #define OGL_LOAD(t, n) (t*)wglGetProcAddress(#n)
5085#endif
5086//
5087//#if defined(__linux__) || defined(__FreeBSD__)
5088// #include <GL/gl.h>
5089//#endif
5090
5091#if defined(OLC_PLATFORM_X11)
5092 /*namespace X11
5093 {
5094 #include <GL/glx.h>
5095 }
5096 typedef int(locSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval);*/
5097 typedef X11::GLXContext glDeviceContext_t;
5098 typedef X11::GLXContext glRenderContext_t;
5099 //#define CALLSTYLE
5100 #define OGL_LOAD(t, n) (t*)glXGetProcAddress((unsigned char*)#n);
5101#endif
5102
5103//#if defined(__APPLE__)
5104// #define GL_SILENCE_DEPRECATION
5105// #include <OpenGL/OpenGL.h>
5106// #include <OpenGL/gl.h>
5107// #include <OpenGL/glu.h>
5108//#endif
5109
5110#if defined(OLC_PLATFORM_EMSCRIPTEN)
5111 #include <EGL/egl.h>
5112 #include <GLES2/gl2.h>
5113 #define GL_GLEXT_PROTOTYPES
5114 #include <GLES2/gl2ext.h>
5115 #include <emscripten/emscripten.h>
5116 #define CALLSTYLE
5117 typedef EGLBoolean(locSwapInterval_t)(EGLDisplay display, EGLint interval);
5118 #define GL_CLAMP GL_CLAMP_TO_EDGE
5119 #define OGL_LOAD(t, n) n;
5120#endif
5121
5122namespace olc
5123{
5124// typedef char GLchar;
5125// typedef ptrdiff_t GLsizeiptr;
5126// typedef GLuint CALLSTYLE locCreateShader_t(GLenum type);
5127// typedef GLuint CALLSTYLE locCreateProgram_t(void);
5128// typedef void CALLSTYLE locDeleteShader_t(GLuint shader);
5129//#if defined(OLC_PLATFORM_EMSCRIPTEN)
5130// typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
5131//#else
5132// typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar** string, const GLint* length);
5133//#endif
5134// typedef void CALLSTYLE locCompileShader_t(GLuint shader);
5135// typedef void CALLSTYLE locLinkProgram_t(GLuint program);
5136// typedef void CALLSTYLE locDeleteProgram_t(GLuint program);
5137// typedef void CALLSTYLE locAttachShader_t(GLuint program, GLuint shader);
5138// typedef void CALLSTYLE locBindBuffer_t(GLenum target, GLuint buffer);
5139// typedef void CALLSTYLE locBufferData_t(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
5140// typedef void CALLSTYLE locGenBuffers_t(GLsizei n, GLuint* buffers);
5141// typedef void CALLSTYLE locVertexAttribPointer_t(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
5142// typedef void CALLSTYLE locEnableVertexAttribArray_t(GLuint index);
5143// typedef void CALLSTYLE locUseProgram_t(GLuint program);
5144// typedef void CALLSTYLE locBindVertexArray_t(GLuint array);
5145// typedef void CALLSTYLE locGenVertexArrays_t(GLsizei n, GLuint* arrays);
5146// typedef void CALLSTYLE locGetShaderInfoLog_t(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
5147// typedef GLint CALLSTYLE locGetUniformLocation_t(GLuint program, const GLchar* name);
5148// typedef void CALLSTYLE locUniform1f_t(GLint location, GLfloat v0);
5149// typedef void CALLSTYLE locUniform1i_t(GLint location, GLint v0);
5150// typedef void CALLSTYLE locUniform2fv_t(GLint location, GLsizei count, const GLfloat* value);
5151// typedef void CALLSTYLE locActiveTexture_t(GLenum texture);
5152// typedef void CALLSTYLE locGenFrameBuffers_t(GLsizei n, GLuint* ids);
5153// typedef void CALLSTYLE locBindFrameBuffer_t(GLenum target, GLuint fb);
5154// typedef GLenum CALLSTYLE locCheckFrameBufferStatus_t(GLenum target);
5155// typedef void CALLSTYLE locDeleteFrameBuffers_t(GLsizei n, const GLuint* fbs);
5156// typedef void CALLSTYLE locFrameBufferTexture2D_t(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
5157// typedef void CALLSTYLE locDrawBuffers_t(GLsizei n, const GLenum* bufs);
5158// typedef void CALLSTYLE locBlendFuncSeparate_t(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
5159
5160
5161
5162 class Renderer_OGL33 : public olc::Renderer
5163 {
5164 private:
5165#if defined(OLC_PLATFORM_EMSCRIPTEN)
5166 EGLDisplay olc_Display;
5167 EGLConfig olc_Config;
5168 EGLContext olc_Context;
5169 EGLSurface olc_Surface;
5170#endif
5171
5172#if defined(OLC_PLATFORM_GLUT)
5173 bool mFullScreen = false;
5174#else
5175 #if !defined(OLC_PLATFORM_EMSCRIPTEN)
5176 glDeviceContext_t glDeviceContext = 0;
5177 glRenderContext_t glRenderContext = 0;
5178 #endif
5179#endif
5180 bool bSync = false;
5181 olc::DecalMode nDecalMode = olc::DecalMode(-1); // Thanks Gusgo & Bispoo
5182#if defined(OLC_PLATFORM_X11)
5183 X11::Display* olc_Display = nullptr;
5184 X11::Window* olc_Window = nullptr;
5185 X11::XVisualInfo* olc_VisualInfo = nullptr;
5186#endif
5187
5188 private:
5189 locCreateShader_t* locCreateShader = nullptr;
5190 locShaderSource_t* locShaderSource = nullptr;
5191 locCompileShader_t* locCompileShader = nullptr;
5192 locDeleteShader_t* locDeleteShader = nullptr;
5193 locCreateProgram_t* locCreateProgram = nullptr;
5194 locDeleteProgram_t* locDeleteProgram = nullptr;
5195 locLinkProgram_t* locLinkProgram = nullptr;
5196 locAttachShader_t* locAttachShader = nullptr;
5197 locBindBuffer_t* locBindBuffer = nullptr;
5198 locBufferData_t* locBufferData = nullptr;
5199 locGenBuffers_t* locGenBuffers = nullptr;
5200 locVertexAttribPointer_t* locVertexAttribPointer = nullptr;
5201 locEnableVertexAttribArray_t* locEnableVertexAttribArray = nullptr;
5202 locUseProgram_t* locUseProgram = nullptr;
5203 locBindVertexArray_t* locBindVertexArray = nullptr;
5204 locGenVertexArrays_t* locGenVertexArrays = nullptr;
5205 locSwapInterval_t* locSwapInterval = nullptr;
5206 locGetShaderInfoLog_t* locGetShaderInfoLog = nullptr;
5207
5208 uint32_t m_nFS = 0;
5209 uint32_t m_nVS = 0;
5210 uint32_t m_nQuadShader = 0;
5211 uint32_t m_vbQuad = 0;
5212 uint32_t m_vaQuad = 0;
5213
5214 struct locVertex
5215 {
5216 float pos[3];
5217 olc::vf2d tex;
5218 olc::Pixel col;
5219 };
5220
5221 locVertex pVertexMem[OLC_MAX_VERTS];
5222
5223 olc::Renderable rendBlankQuad;
5224
5225 public:
5226 void PrepareDevice() override
5227 {
5228#if defined(OLC_PLATFORM_GLUT)
5229 //glutInit has to be called with main() arguments, make fake ones
5230 int argc = 0;
5231 char* argv[1] = { (char*)"" };
5232 glutInit(&argc, argv);
5233 glutInitWindowPosition(0, 0);
5234 glutInitWindowSize(512, 512);
5235 glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);
5236 // Creates the window and the OpenGL context for it
5237 glutCreateWindow("OneLoneCoder.com - Pixel Game Engine");
5238 glEnable(GL_TEXTURE_2D); // Turn on texturing
5239 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
5240#endif
5241 }
5242
5243 olc::rcode CreateDevice(std::vector<void*> params, bool bFullScreen, bool bVSYNC) override
5244 {
5245 // Create OpenGL Context
5246#if defined(OLC_PLATFORM_WINAPI)
5247 // Create Device Context
5248 glDeviceContext = GetDC((HWND)(params[0]));
5249 PIXELFORMATDESCRIPTOR pfd =
5250 {
5251 sizeof(PIXELFORMATDESCRIPTOR), 1,
5252 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
5253 PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5254 PFD_MAIN_PLANE, 0, 0, 0, 0
5255 };
5256
5257 int pf = 0;
5258 if (!(pf = ChoosePixelFormat(glDeviceContext, &pfd))) return olc::FAIL;
5259 SetPixelFormat(glDeviceContext, pf, &pfd);
5260
5261 if (!(glRenderContext = wglCreateContext(glDeviceContext))) return olc::FAIL;
5262 wglMakeCurrent(glDeviceContext, glRenderContext);
5263
5264 // Set Vertical Sync
5265 locSwapInterval = OGL_LOAD(locSwapInterval_t, wglSwapIntervalEXT);
5266 if (locSwapInterval && !bVSYNC) locSwapInterval(0);
5267 bSync = bVSYNC;
5268#endif
5269
5270#if defined(OLC_PLATFORM_X11)
5271 using namespace X11;
5272 // Linux has tighter coupling between OpenGL and X11, so we store
5273 // various "platform" handles in the renderer
5274 olc_Display = (X11::Display*)(params[0]);
5275 olc_Window = (X11::Window*)(params[1]);
5276 olc_VisualInfo = (X11::XVisualInfo*)(params[2]);
5277
5278 glDeviceContext = glXCreateContext(olc_Display, olc_VisualInfo, nullptr, GL_TRUE);
5279 glXMakeCurrent(olc_Display, *olc_Window, glDeviceContext);
5280
5281 XWindowAttributes gwa;
5282 XGetWindowAttributes(olc_Display, *olc_Window, &gwa);
5283 glViewport(0, 0, gwa.width, gwa.height);
5284
5285 locSwapInterval = OGL_LOAD(locSwapInterval_t, glXSwapIntervalEXT);
5286
5287 if (locSwapInterval == nullptr && !bVSYNC)
5288 {
5289 printf("NOTE: Could not disable VSYNC, glXSwapIntervalEXT() was not found!\n");
5290 printf(" Don't worry though, things will still work, it's just the\n");
5291 printf(" frame rate will be capped to your monitors refresh rate - javidx9\n");
5292 }
5293
5294 if (locSwapInterval != nullptr && !bVSYNC)
5295 locSwapInterval(olc_Display, *olc_Window, 0);
5296#endif
5297
5298#if defined(OLC_PLATFORM_EMSCRIPTEN)
5299 EGLint const attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE };
5300 EGLint const context_config[] = { EGL_CONTEXT_CLIENT_VERSION , 2, EGL_NONE };
5301 EGLint num_config;
5302
5303 olc_Display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
5304 eglInitialize(olc_Display, nullptr, nullptr);
5305 eglChooseConfig(olc_Display, attribute_list, &olc_Config, 1, &num_config);
5306
5307 /* create an EGL rendering context */
5308 olc_Context = eglCreateContext(olc_Display, olc_Config, EGL_NO_CONTEXT, context_config);
5309 olc_Surface = eglCreateWindowSurface(olc_Display, olc_Config, NULL, nullptr);
5310 eglMakeCurrent(olc_Display, olc_Surface, olc_Surface, olc_Context);
5311 //eglSwapInterval is currently a NOP, plement anyways in case it becomes supported
5312 locSwapInterval = &eglSwapInterval;
5313 locSwapInterval(olc_Display, bVSYNC ? 1 : 0);
5314#endif
5315
5316#if defined(OLC_PLATFORM_GLUT)
5317 mFullScreen = bFullScreen;
5318 if (!bVSYNC)
5319 {
5320#if defined(__APPLE__)
5321 GLint sync = 0;
5322 CGLContextObj ctx = CGLGetCurrentContext();
5323 if (ctx) CGLSetParameter(ctx, kCGLCPSwapInterval, &sync);
5324#endif
5325 }
5326#else
5327 #if !defined(OLC_PLATFORM_EMSCRIPTEN)
5328 glEnable(GL_TEXTURE_2D); // Turn on texturing
5329 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
5330 #endif
5331#endif
5332 // Load External OpenGL Functions
5333 locCreateShader = OGL_LOAD(locCreateShader_t, glCreateShader);
5334 locCompileShader = OGL_LOAD(locCompileShader_t, glCompileShader);
5335 locShaderSource = OGL_LOAD(locShaderSource_t, glShaderSource);
5336 locDeleteShader = OGL_LOAD(locDeleteShader_t, glDeleteShader);
5337 locCreateProgram = OGL_LOAD(locCreateProgram_t, glCreateProgram);
5338 locDeleteProgram = OGL_LOAD(locDeleteProgram_t, glDeleteProgram);
5339 locLinkProgram = OGL_LOAD(locLinkProgram_t, glLinkProgram);
5340 locAttachShader = OGL_LOAD(locAttachShader_t, glAttachShader);
5341 locBindBuffer = OGL_LOAD(locBindBuffer_t, glBindBuffer);
5342 locBufferData = OGL_LOAD(locBufferData_t, glBufferData);
5343 locGenBuffers = OGL_LOAD(locGenBuffers_t, glGenBuffers);
5344 locVertexAttribPointer = OGL_LOAD(locVertexAttribPointer_t, glVertexAttribPointer);
5345 locEnableVertexAttribArray = OGL_LOAD(locEnableVertexAttribArray_t, glEnableVertexAttribArray);
5346 locUseProgram = OGL_LOAD(locUseProgram_t, glUseProgram);
5347 locGetShaderInfoLog = OGL_LOAD(locGetShaderInfoLog_t, glGetShaderInfoLog);
5348#if !defined(OLC_PLATFORM_EMSCRIPTEN)
5349 locBindVertexArray = OGL_LOAD(locBindVertexArray_t, glBindVertexArray);
5350 locGenVertexArrays = OGL_LOAD(locGenVertexArrays_t, glGenVertexArrays);
5351#else
5352 locBindVertexArray = glBindVertexArrayOES;
5353 locGenVertexArrays = glGenVertexArraysOES;
5354#endif
5355
5356 // Load & Compile Quad Shader - assumes no errors
5357 m_nFS = locCreateShader(0x8B30);
5358 const GLchar* strFS =
5359#if defined(__arm__) || defined(OLC_PLATFORM_EMSCRIPTEN)
5360 "#version 300 es\n"
5361 "precision mediump float;"
5362#else
5363 "#version 330 core\n"
5364#endif
5365 "out vec4 pixel;\n""in vec2 oTex;\n"
5366 "in vec4 oCol;\n""uniform sampler2D sprTex;\n""void main(){pixel = texture(sprTex, oTex) * oCol;}";
5367 locShaderSource(m_nFS, 1, &strFS, NULL);
5368 locCompileShader(m_nFS);
5369
5370 m_nVS = locCreateShader(0x8B31);
5371 const GLchar* strVS =
5372#if defined(__arm__) || defined(OLC_PLATFORM_EMSCRIPTEN)
5373 "#version 300 es\n"
5374 "precision mediump float;"
5375#else
5376 "#version 330 core\n"
5377#endif
5378 "layout(location = 0) in vec3 aPos;\n""layout(location = 1) in vec2 aTex;\n"
5379 "layout(location = 2) in vec4 aCol;\n""out vec2 oTex;\n""out vec4 oCol;\n"
5380 "void main(){ float p = 1.0 / aPos.z; gl_Position = p * vec4(aPos.x, aPos.y, 0.0, 1.0); oTex = p * aTex; oCol = aCol;}";
5381 locShaderSource(m_nVS, 1, &strVS, NULL);
5382 locCompileShader(m_nVS);
5383
5384 m_nQuadShader = locCreateProgram();
5385 locAttachShader(m_nQuadShader, m_nFS);
5386 locAttachShader(m_nQuadShader, m_nVS);
5387 locLinkProgram(m_nQuadShader);
5388
5389 // Create Quad
5390 locGenBuffers(1, &m_vbQuad);
5391 locGenVertexArrays(1, &m_vaQuad);
5392 locBindVertexArray(m_vaQuad);
5393 locBindBuffer(0x8892, m_vbQuad);
5394
5395 locVertex verts[OLC_MAX_VERTS];
5396 locBufferData(0x8892, sizeof(locVertex) * OLC_MAX_VERTS, verts, 0x88E0);
5397 locVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(locVertex), 0); locEnableVertexAttribArray(0);
5398 locVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(locVertex), (void*)(3 * sizeof(float))); locEnableVertexAttribArray(1);
5399 locVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(locVertex), (void*)(5 * sizeof(float))); locEnableVertexAttribArray(2);
5400 locBindBuffer(0x8892, 0);
5401 locBindVertexArray(0);
5402
5403 // Create blank texture for spriteless decals
5404 rendBlankQuad.Create(1, 1);
5405 rendBlankQuad.Sprite()->GetData()[0] = olc::WHITE;
5406 rendBlankQuad.Decal()->Update();
5407 return olc::rcode::OK;
5408 }
5409
5410 olc::rcode DestroyDevice() override
5411 {
5412#if defined(OLC_PLATFORM_WINAPI)
5413 wglDeleteContext(glRenderContext);
5414#endif
5415
5416#if defined(OLC_PLATFORM_X11)
5417 glXMakeCurrent(olc_Display, None, NULL);
5418 glXDestroyContext(olc_Display, glDeviceContext);
5419#endif
5420
5421#if defined(OLC_PLATFORM_GLUT)
5422 glutDestroyWindow(glutGetWindow());
5423#endif
5424
5425#if defined(OLC_PLATFORM_EMSCRIPTEN)
5426 eglMakeCurrent(olc_Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
5427 eglDestroyContext(olc_Display, olc_Context);
5428 eglDestroySurface(olc_Display, olc_Surface);
5429 eglTerminate(olc_Display);
5430 olc_Display = EGL_NO_DISPLAY;
5431 olc_Surface = EGL_NO_SURFACE;
5432 olc_Context = EGL_NO_CONTEXT;
5433#endif
5434 return olc::rcode::OK;
5435 }
5436
5437 void DisplayFrame() override
5438 {
5439#if defined(OLC_PLATFORM_WINAPI)
5440 SwapBuffers(glDeviceContext);
5441 if (bSync) DwmFlush(); // Woooohooooooo!!!! SMOOOOOOOTH!
5442#endif
5443
5444#if defined(OLC_PLATFORM_X11)
5445 X11::glXSwapBuffers(olc_Display, *olc_Window);
5446#endif
5447
5448#if defined(OLC_PLATFORM_GLUT)
5449 glutSwapBuffers();
5450#endif
5451
5452#if defined(OLC_PLATFORM_EMSCRIPTEN)
5453 eglSwapBuffers(olc_Display, olc_Surface);
5454#endif
5455 }
5456
5457 void PrepareDrawing() override
5458 {
5459 glEnable(GL_BLEND);
5460 nDecalMode = DecalMode::NORMAL;
5461 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5462 locUseProgram(m_nQuadShader);
5463 locBindVertexArray(m_vaQuad);
5464
5465#if defined(OLC_PLATFORM_EMSCRIPTEN)
5466 locVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(locVertex), 0); locEnableVertexAttribArray(0);
5467 locVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(locVertex), (void*)(3 * sizeof(float))); locEnableVertexAttribArray(1);
5468 locVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(locVertex), (void*)(5 * sizeof(float))); locEnableVertexAttribArray(2);
5469#endif
5470 }
5471
5472 void SetDecalMode(const olc::DecalMode& mode) override
5473 {
5474 if (mode != nDecalMode)
5475 {
5476 switch (mode)
5477 {
5478 case olc::DecalMode::NORMAL: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break;
5479 case olc::DecalMode::ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); break;
5480 case olc::DecalMode::MULTIPLICATIVE: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break;
5481 case olc::DecalMode::STENCIL: glBlendFunc(GL_ZERO, GL_SRC_ALPHA); break;
5482 case olc::DecalMode::ILLUMINATE: glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); break;
5483 case olc::DecalMode::WIREFRAME: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break;
5484 }
5485
5486 nDecalMode = mode;
5487 }
5488 }
5489
5490 void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) override
5491 {
5492 locBindBuffer(0x8892, m_vbQuad);
5493 locVertex verts[4] = {
5494 {{-1.0f, -1.0f, 1.0}, {0.0f * scale.x + offset.x, 1.0f * scale.y + offset.y}, tint},
5495 {{+1.0f, -1.0f, 1.0}, {1.0f * scale.x + offset.x, 1.0f * scale.y + offset.y}, tint},
5496 {{-1.0f, +1.0f, 1.0}, {0.0f * scale.x + offset.x, 0.0f * scale.y + offset.y}, tint},
5497 {{+1.0f, +1.0f, 1.0}, {1.0f * scale.x + offset.x, 0.0f * scale.y + offset.y}, tint},
5498 };
5499
5500 locBufferData(0x8892, sizeof(locVertex) * 4, verts, 0x88E0);
5501 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
5502 }
5503
5504 void DrawDecal(const olc::DecalInstance& decal) override
5505 {
5506 SetDecalMode(decal.mode);
5507 if (decal.decal == nullptr)
5508 glBindTexture(GL_TEXTURE_2D, rendBlankQuad.Decal()->id);
5509 else
5510 glBindTexture(GL_TEXTURE_2D, decal.decal->id);
5511
5512 locBindBuffer(0x8892, m_vbQuad);
5513
5514 for (uint32_t i = 0; i < decal.points; i++)
5515 pVertexMem[i] = { { decal.pos[i].x, decal.pos[i].y, decal.w[i] }, { decal.uv[i].x, decal.uv[i].y }, decal.tint[i] };
5516
5517 locBufferData(0x8892, sizeof(locVertex) * decal.points, pVertexMem, 0x88E0);
5518
5519 if (nDecalMode == DecalMode::WIREFRAME)
5520 glDrawArrays(GL_LINE_LOOP, 0, decal.points);
5521 else
5522 {
5524 glDrawArrays(GL_TRIANGLE_FAN, 0, decal.points);
5525 else if (decal.structure == olc::DecalStructure::STRIP)
5526 glDrawArrays(GL_TRIANGLE_STRIP, 0, decal.points);
5527 else if (decal.structure == olc::DecalStructure::LIST)
5528 glDrawArrays(GL_TRIANGLES, 0, decal.points);
5529 }
5530 }
5531
5532 uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered, const bool clamp) override
5533 {
5534 UNUSED(width);
5535 UNUSED(height);
5536 uint32_t id = 0;
5537 glGenTextures(1, &id);
5538 glBindTexture(GL_TEXTURE_2D, id);
5539
5540 if (filtered)
5541 {
5542 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5543 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5544 }
5545 else
5546 {
5547 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5548 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5549 }
5550
5551 if (clamp)
5552 {
5553 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
5554 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
5555 }
5556 else
5557 {
5558 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
5559 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
5560 }
5561#if !defined(OLC_PLATFORM_EMSCRIPTEN)
5562 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
5563#endif
5564 return id;
5565 }
5566
5567 uint32_t DeleteTexture(const uint32_t id) override
5568 {
5569 glDeleteTextures(1, &id);
5570 return id;
5571 }
5572
5573 void UpdateTexture(uint32_t id, olc::Sprite* spr) override
5574 {
5575 UNUSED(id);
5576 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, spr->width, spr->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData());
5577 }
5578
5579 void ReadTexture(uint32_t id, olc::Sprite* spr) override
5580 {
5581 glReadPixels(0, 0, spr->width, spr->height, GL_RGBA, GL_UNSIGNED_BYTE, spr->GetData());
5582 }
5583
5584 void ApplyTexture(uint32_t id) override
5585 {
5586 glBindTexture(GL_TEXTURE_2D, id);
5587 }
5588
5589 void ClearBuffer(olc::Pixel p, bool bDepth) override
5590 {
5591 glClearColor(float(p.r) / 255.0f, float(p.g) / 255.0f, float(p.b) / 255.0f, float(p.a) / 255.0f);
5592 glClear(GL_COLOR_BUFFER_BIT);
5593 if (bDepth) glClear(GL_DEPTH_BUFFER_BIT);
5594 }
5595
5596 void UpdateViewport(const olc::vi2d& pos, const olc::vi2d& size) override
5597 {
5598 glViewport(pos.x, pos.y, size.x, size.y);
5599 }
5600 };
5601}
5602#endif
5603// O------------------------------------------------------------------------------O
5604// | END RENDERER: OpenGL 3.3 (3.0 es) (sh-sh-sh-shaders....) |
5605// O------------------------------------------------------------------------------O
5606#pragma endregion
5607
5608// O------------------------------------------------------------------------------O
5609// | olcPixelGameEngine Image loaders |
5610// O------------------------------------------------------------------------------O
5611
5612#pragma region image_gdi
5613// O------------------------------------------------------------------------------O
5614// | START IMAGE LOADER: GDI+, Windows Only, always exists, a little slow |
5615// O------------------------------------------------------------------------------O
5616#if defined(OLC_IMAGE_GDI)
5617
5618#define min(a, b) ((a < b) ? a : b)
5619#define max(a, b) ((a > b) ? a : b)
5620#include <objidl.h>
5621#include <gdiplus.h>
5622#if defined(__MINGW32__) // Thanks Gusgo & Dandistine, but c'mon mingw!! wtf?!
5623 #include <gdiplus/gdiplusinit.h>
5624#else
5625 #include <gdiplusinit.h>
5626#endif
5627#include <shlwapi.h>
5628#undef min
5629#undef max
5630
5631#if !defined(__MINGW32__)
5632 #pragma comment(lib, "gdiplus.lib")
5633 #pragma comment(lib, "Shlwapi.lib")
5634#endif
5635
5636namespace olc
5637{
5638 // Thanks @MaGetzUb for this, which allows sprites to be defined
5639 // at construction, by initialising the GDI subsystem
5640 static class GDIPlusStartup
5641 {
5642 public:
5643 GDIPlusStartup()
5644 {
5645 Gdiplus::GdiplusStartupInput startupInput;
5646 GdiplusStartup(&token, &startupInput, NULL);
5647 }
5648
5649 ULONG_PTR token;
5650
5651 ~GDIPlusStartup()
5652 {
5653 // Well, MarcusTU thought this was important :D
5654 Gdiplus::GdiplusShutdown(token);
5655 }
5656 } gdistartup;
5657
5658 class ImageLoader_GDIPlus : public olc::ImageLoader
5659 {
5660 private:
5661 std::wstring ConvertS2W(std::string s)
5662 {
5663#ifdef __MINGW32__
5664 wchar_t* buffer = new wchar_t[s.length() + 1];
5665 mbstowcs(buffer, s.c_str(), s.length());
5666 buffer[s.length()] = L'\0';
5667#else
5668 int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0);
5669 wchar_t* buffer = new wchar_t[count];
5670 MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count);
5671#endif
5672 std::wstring w(buffer);
5673 delete[] buffer;
5674 return w;
5675 }
5676
5677 public:
5678 ImageLoader_GDIPlus() : ImageLoader()
5679 {}
5680
5681 olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override
5682 {
5683 // clear out existing sprite
5684 spr->pColData.clear();
5685
5686 // Open file
5687 UNUSED(pack);
5688 Gdiplus::Bitmap* bmp = nullptr;
5689 if (pack != nullptr)
5690 {
5691 // Load sprite from input stream
5692 ResourceBuffer rb = pack->GetFileBuffer(sImageFile);
5693 bmp = Gdiplus::Bitmap::FromStream(SHCreateMemStream((BYTE*)rb.vMemory.data(), UINT(rb.vMemory.size())));
5694 }
5695 else
5696 {
5697 // Check file exists
5698 if (!_gfs::exists(sImageFile)) return olc::rcode::NO_FILE;
5699
5700 // Load sprite from file
5701 bmp = Gdiplus::Bitmap::FromFile(ConvertS2W(sImageFile).c_str());
5702 }
5703
5704 if (bmp->GetLastStatus() != Gdiplus::Ok) return olc::rcode::FAIL;
5705 spr->width = bmp->GetWidth();
5706 spr->height = bmp->GetHeight();
5707
5708 spr->pColData.resize(spr->width * spr->height);
5709
5710 for (int y = 0; y < spr->height; y++)
5711 for (int x = 0; x < spr->width; x++)
5712 {
5713 Gdiplus::Color c;
5714 bmp->GetPixel(x, y, &c);
5715 spr->SetPixel(x, y, olc::Pixel(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha()));
5716 }
5717 delete bmp;
5718 return olc::rcode::OK;
5719 }
5720
5721 olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) override
5722 {
5723 return olc::rcode::OK;
5724 }
5725 };
5726}
5727#endif
5728// O------------------------------------------------------------------------------O
5729// | END IMAGE LOADER: GDI+ |
5730// O------------------------------------------------------------------------------O
5731#pragma endregion
5732
5733#pragma region image_libpng
5734// O------------------------------------------------------------------------------O
5735// | START IMAGE LOADER: libpng, default on linux, requires -lpng (libpng-dev) |
5736// O------------------------------------------------------------------------------O
5737#if defined(OLC_IMAGE_LIBPNG)
5738#include <png.h>
5739namespace olc
5740{
5741 void pngReadStream(png_structp pngPtr, png_bytep data, png_size_t length)
5742 {
5743 png_voidp a = png_get_io_ptr(pngPtr);
5744 ((std::istream*)a)->read((char*)data, length);
5745 }
5746
5747 class ImageLoader_LibPNG : public olc::ImageLoader
5748 {
5749 public:
5750 ImageLoader_LibPNG() : ImageLoader()
5751 {}
5752
5753 olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override
5754 {
5755 UNUSED(pack);
5756
5757 // clear out existing sprite
5758 spr->pColData.clear();
5759
5761 // Use libpng, Thanks to Guillaume Cottenceau
5762 // https://gist.github.com/niw/5963798
5763 // Also reading png from streams
5764 // http://www.piko3d.net/tutorials/libpng-tutorial-loading-png-files-from-streams/
5765 png_structp png;
5766 png_infop info;
5767
5768 auto loadPNG = [&]()
5769 {
5770 png_read_info(png, info);
5771 png_byte color_type;
5772 png_byte bit_depth;
5773 png_bytep* row_pointers;
5774 spr->width = png_get_image_width(png, info);
5775 spr->height = png_get_image_height(png, info);
5776 color_type = png_get_color_type(png, info);
5777 bit_depth = png_get_bit_depth(png, info);
5778 if (bit_depth == 16) png_set_strip_16(png);
5779 if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
5780 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png);
5781 if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png);
5782 if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)
5783 png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
5784 if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
5785 png_set_gray_to_rgb(png);
5786 png_read_update_info(png, info);
5787 row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * spr->height);
5788 for (int y = 0; y < spr->height; y++) {
5789 row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info));
5790 }
5791 png_read_image(png, row_pointers);
5793 // Create sprite array
5794 spr->pColData.resize(spr->width * spr->height);
5795 // Iterate through image rows, converting into sprite format
5796 for (int y = 0; y < spr->height; y++)
5797 {
5798 png_bytep row = row_pointers[y];
5799 for (int x = 0; x < spr->width; x++)
5800 {
5801 png_bytep px = &(row[x * 4]);
5802 spr->SetPixel(x, y, Pixel(px[0], px[1], px[2], px[3]));
5803 }
5804 }
5805
5806 for (int y = 0; y < spr->height; y++) // Thanks maksym33
5807 free(row_pointers[y]);
5808 free(row_pointers);
5809 png_destroy_read_struct(&png, &info, nullptr);
5810 };
5811
5812 png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
5813 if (!png) goto fail_load;
5814
5815 info = png_create_info_struct(png);
5816 if (!info) goto fail_load;
5817
5818 if (setjmp(png_jmpbuf(png))) goto fail_load;
5819
5820 if (pack == nullptr)
5821 {
5822 FILE* f = fopen(sImageFile.c_str(), "rb");
5823 if (!f) return olc::rcode::NO_FILE;
5824 png_init_io(png, f);
5825 loadPNG();
5826 fclose(f);
5827 }
5828 else
5829 {
5830 ResourceBuffer rb = pack->GetFileBuffer(sImageFile);
5831 std::istream is(&rb);
5832 png_set_read_fn(png, (png_voidp)&is, pngReadStream);
5833 loadPNG();
5834 }
5835
5836 return olc::rcode::OK;
5837
5838 fail_load:
5839 spr->width = 0;
5840 spr->height = 0;
5841 spr->pColData.clear();
5842 return olc::rcode::FAIL;
5843 }
5844
5845 olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) override
5846 {
5847 return olc::rcode::OK;
5848 }
5849 };
5850}
5851#endif
5852// O------------------------------------------------------------------------------O
5853// | END IMAGE LOADER: |
5854// O------------------------------------------------------------------------------O
5855#pragma endregion
5856
5857
5858// O------------------------------------------------------------------------------O
5859// | olcPixelGameEngine Platforms |
5860// O------------------------------------------------------------------------------O
5861
5862#pragma region platform_windows
5863// O------------------------------------------------------------------------------O
5864// | START PLATFORM: MICROSOFT WINDOWS XP, VISTA, 7, 8, 10 |
5865// O------------------------------------------------------------------------------O
5866#if defined(OLC_PLATFORM_WINAPI)
5867
5868#if defined(_WIN32) && !defined(__MINGW32__)
5869 #pragma comment(lib, "user32.lib") // Visual Studio Only
5870 #pragma comment(lib, "gdi32.lib") // For other Windows Compilers please add
5871 #pragma comment(lib, "opengl32.lib") // these libs to your linker input
5872#endif
5873
5874namespace olc
5875{
5876 class Platform_Windows : public olc::Platform
5877 {
5878 private:
5879 HWND olc_hWnd = nullptr;
5880 std::wstring wsAppName;
5881 inline static olc::vi2d vWinPos;
5882 inline static olc::vi2d vWinSize;
5883
5884 std::wstring ConvertS2W(std::string s)
5885 {
5886#ifdef __MINGW32__
5887 wchar_t* buffer = new wchar_t[s.length() + 1];
5888 mbstowcs(buffer, s.c_str(), s.length());
5889 buffer[s.length()] = L'\0';
5890#else
5891 int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0);
5892 wchar_t* buffer = new wchar_t[count];
5893 MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count);
5894#endif
5895 std::wstring w(buffer);
5896 delete[] buffer;
5897 return w;
5898 }
5899
5900
5901
5902 public:
5903 virtual olc::rcode ApplicationStartUp() override { return olc::rcode::OK; }
5904 virtual olc::rcode ApplicationCleanUp() override { return olc::rcode::OK; }
5905 virtual olc::rcode ThreadStartUp() override { return olc::rcode::OK; }
5906
5907 virtual olc::rcode ThreadCleanUp() override
5908 {
5909 renderer->DestroyDevice();
5910 PostMessage(olc_hWnd, WM_DESTROY, 0, 0);
5911 return olc::OK;
5912 }
5913
5914 virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) override
5915 {
5916 if (renderer->CreateDevice({ olc_hWnd }, bFullScreen, bEnableVSYNC) == olc::rcode::OK)
5917 {
5918 renderer->UpdateViewport(vViewPos, vViewSize);
5919 return olc::rcode::OK;
5920 }
5921 else
5922 return olc::rcode::FAIL;
5923 }
5924
5925 virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) override
5926 {
5927 WNDCLASS wc;
5928 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
5929 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
5930 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
5931 wc.hInstance = GetModuleHandle(nullptr);
5932 wc.lpfnWndProc = olc_WindowEvent;
5933 wc.cbClsExtra = 0;
5934 wc.cbWndExtra = 0;
5935 wc.lpszMenuName = nullptr;
5936 wc.hbrBackground = nullptr;
5937 wc.lpszClassName = olcT("OLC_PIXEL_GAME_ENGINE");
5938 RegisterClass(&wc);
5939
5940 vWinPos = vWindowPos;
5941 vWinSize = vWindowSize;
5942
5943 // Define window furniture
5944 DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
5945 DWORD dwStyle = WS_CAPTION | WS_SYSMENU | WS_VISIBLE | WS_THICKFRAME;
5946
5947 olc::vi2d vTopLeft = vWindowPos;
5948
5949 // Handle Fullscreen
5950 if (bFullScreen)
5951 {
5952 dwExStyle = 0;
5953 dwStyle = WS_VISIBLE | WS_POPUP;
5954 HMONITOR hmon = MonitorFromWindow(olc_hWnd, MONITOR_DEFAULTTONEAREST);
5955 MONITORINFO mi = { sizeof(mi) };
5956 if (!GetMonitorInfo(hmon, &mi)) return olc::rcode::FAIL;
5957 vWindowSize = { mi.rcMonitor.right, mi.rcMonitor.bottom };
5958 vTopLeft.x = 0;
5959 vTopLeft.y = 0;
5960 }
5961
5962 // Keep client size as requested
5963 RECT rWndRect = { 0, 0, vWindowSize.x, vWindowSize.y };
5964 AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle);
5965 int width = rWndRect.right - rWndRect.left;
5966 int height = rWndRect.bottom - rWndRect.top;
5967
5968 olc_hWnd = CreateWindowEx(dwExStyle, olcT("OLC_PIXEL_GAME_ENGINE"), olcT(""), dwStyle,
5969 vTopLeft.x, vTopLeft.y, width, height, NULL, NULL, GetModuleHandle(nullptr), this);
5970
5971 DragAcceptFiles(olc_hWnd, true);
5972
5973 // Create Keyboard Mapping
5974 mapKeys[0x00] = Key::NONE;
5975 mapKeys[0x41] = Key::A; mapKeys[0x42] = Key::B; mapKeys[0x43] = Key::C; mapKeys[0x44] = Key::D; mapKeys[0x45] = Key::E;
5976 mapKeys[0x46] = Key::F; mapKeys[0x47] = Key::G; mapKeys[0x48] = Key::H; mapKeys[0x49] = Key::I; mapKeys[0x4A] = Key::J;
5977 mapKeys[0x4B] = Key::K; mapKeys[0x4C] = Key::L; mapKeys[0x4D] = Key::M; mapKeys[0x4E] = Key::N; mapKeys[0x4F] = Key::O;
5978 mapKeys[0x50] = Key::P; mapKeys[0x51] = Key::Q; mapKeys[0x52] = Key::R; mapKeys[0x53] = Key::S; mapKeys[0x54] = Key::T;
5979 mapKeys[0x55] = Key::U; mapKeys[0x56] = Key::V; mapKeys[0x57] = Key::W; mapKeys[0x58] = Key::X; mapKeys[0x59] = Key::Y;
5980 mapKeys[0x5A] = Key::Z;
5981
5982 mapKeys[VK_F1] = Key::F1; mapKeys[VK_F2] = Key::F2; mapKeys[VK_F3] = Key::F3; mapKeys[VK_F4] = Key::F4;
5983 mapKeys[VK_F5] = Key::F5; mapKeys[VK_F6] = Key::F6; mapKeys[VK_F7] = Key::F7; mapKeys[VK_F8] = Key::F8;
5984 mapKeys[VK_F9] = Key::F9; mapKeys[VK_F10] = Key::F10; mapKeys[VK_F11] = Key::F11; mapKeys[VK_F12] = Key::F12;
5985
5986 mapKeys[VK_DOWN] = Key::DOWN; mapKeys[VK_LEFT] = Key::LEFT; mapKeys[VK_RIGHT] = Key::RIGHT; mapKeys[VK_UP] = Key::UP;
5987 //mapKeys[VK_RETURN] = Key::ENTER;// mapKeys[VK_RETURN] = Key::RETURN;
5988
5989 mapKeys[VK_BACK] = Key::BACK; mapKeys[VK_ESCAPE] = Key::ESCAPE; mapKeys[VK_RETURN] = Key::ENTER; mapKeys[VK_PAUSE] = Key::PAUSE;
5990 mapKeys[VK_SCROLL] = Key::SCROLL; mapKeys[VK_TAB] = Key::TAB; mapKeys[VK_DELETE] = Key::DEL; mapKeys[VK_HOME] = Key::HOME;
5991 mapKeys[VK_END] = Key::END; mapKeys[VK_PRIOR] = Key::PGUP; mapKeys[VK_NEXT] = Key::PGDN; mapKeys[VK_INSERT] = Key::INS;
5992 mapKeys[VK_SHIFT] = Key::SHIFT; mapKeys[VK_CONTROL] = Key::CTRL;
5993 mapKeys[VK_SPACE] = Key::SPACE;
5994
5995 mapKeys[0x30] = Key::K0; mapKeys[0x31] = Key::K1; mapKeys[0x32] = Key::K2; mapKeys[0x33] = Key::K3; mapKeys[0x34] = Key::K4;
5996 mapKeys[0x35] = Key::K5; mapKeys[0x36] = Key::K6; mapKeys[0x37] = Key::K7; mapKeys[0x38] = Key::K8; mapKeys[0x39] = Key::K9;
5997
5998 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;
5999 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;
6000 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;
6001
6002 // Thanks scripticuk
6003 mapKeys[VK_OEM_1] = Key::OEM_1; // On US and UK keyboards this is the ';:' key
6004 mapKeys[VK_OEM_2] = Key::OEM_2; // On US and UK keyboards this is the '/?' key
6005 mapKeys[VK_OEM_3] = Key::OEM_3; // On US keyboard this is the '~' key
6006 mapKeys[VK_OEM_4] = Key::OEM_4; // On US and UK keyboards this is the '[{' key
6007 mapKeys[VK_OEM_5] = Key::OEM_5; // On US keyboard this is '\|' key.
6008 mapKeys[VK_OEM_6] = Key::OEM_6; // On US and UK keyboards this is the ']}' key
6009 mapKeys[VK_OEM_7] = Key::OEM_7; // On US keyboard this is the single/double quote key. On UK, this is the single quote/@ symbol key
6010 mapKeys[VK_OEM_8] = Key::OEM_8; // miscellaneous characters. Varies by keyboard
6011 mapKeys[VK_OEM_PLUS] = Key::EQUALS; // the '+' key on any keyboard
6012 mapKeys[VK_OEM_COMMA] = Key::COMMA; // the comma key on any keyboard
6013 mapKeys[VK_OEM_MINUS] = Key::MINUS; // the minus key on any keyboard
6014 mapKeys[VK_OEM_PERIOD] = Key::PERIOD; // the period key on any keyboard
6015 mapKeys[VK_CAPITAL] = Key::CAPS_LOCK;
6016 return olc::OK;
6017 }
6018
6019 virtual olc::rcode SetWindowTitle(const std::string& s) override
6020 {
6021#ifdef UNICODE
6022 SetWindowText(olc_hWnd, ConvertS2W(s).c_str());
6023#else
6024 SetWindowText(olc_hWnd, s.c_str());
6025#endif
6026 return olc::OK;
6027 }
6028
6029 olc::rcode ShowWindowFrame(const bool bShowFrame)
6030 {
6031 // Oooooooof... yeah....
6032 DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
6033 DWORD dwStyle = WS_CAPTION | WS_SYSMENU | WS_VISIBLE | WS_THICKFRAME;
6034
6035 RECT rWndRect, rWndRectNow;
6036 GetWindowRect(olc_hWnd, &rWndRectNow);
6037
6038 if (!bShowFrame)
6039 {
6040 LONG_PTR lp = GetWindowLongPtr(olc_hWnd, GWL_STYLE);
6041 SetWindowLongPtr(olc_hWnd, GWL_STYLE, lp & ~(WS_CAPTION | WS_SYSMENU | WS_POPUPWINDOW | WS_THICKFRAME));
6042 lp = GetWindowLongPtr(olc_hWnd, GWL_EXSTYLE);
6043 SetWindowLongPtr(olc_hWnd, GWL_EXSTYLE, lp & ~(WS_EX_WINDOWEDGE));
6044 dwExStyle = WS_EX_APPWINDOW;
6045 dwStyle = 0;
6046 }
6047 else
6048 {
6049 LONG_PTR lp = GetWindowLongPtr(olc_hWnd, GWL_STYLE);
6050 SetWindowLongPtr(olc_hWnd, GWL_STYLE, lp | (WS_CAPTION | WS_SYSMENU | WS_POPUPWINDOW|WS_THICKFRAME));
6051 lp = GetWindowLongPtr(olc_hWnd, GWL_EXSTYLE);
6052 SetWindowLongPtr(olc_hWnd, GWL_EXSTYLE, lp | (WS_EX_WINDOWEDGE));
6053 }
6054
6055
6056 rWndRectNow.right = rWndRectNow.left + vWinSize.x;
6057 rWndRectNow.bottom = rWndRectNow.top + vWinSize.y;
6058 rWndRect = rWndRectNow;
6059 AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle);
6060 int width = rWndRect.right - rWndRect.left;
6061 int height = rWndRect.bottom - rWndRect.top;
6062 vWinPos = { rWndRect.left, rWndRect.top };
6063 vWinSize = { width, height };
6064 SetWindowPos(olc_hWnd, NULL, rWndRectNow.left, rWndRectNow.top, width, height, SWP_SHOWWINDOW);
6065
6066
6067 return olc::OK;
6068 }
6069
6070 olc::rcode SetWindowSize(const olc::vi2d& vWindowPos, const olc::vi2d& vWindowSize)
6071 {
6072 vWinPos = vWindowPos;
6073 vWinSize = vWindowSize;
6074 RECT rWndRect;
6075 rWndRect.left = vWinPos.x;
6076 rWndRect.top = vWinPos.y;
6077 rWndRect.right = rWndRect.left + vWinSize.x;
6078 rWndRect.bottom = rWndRect.top + vWinSize.y;
6079 rWndRect = rWndRect;
6080 DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
6081 DWORD dwStyle = WS_CAPTION | WS_SYSMENU | WS_VISIBLE | WS_THICKFRAME;
6082 AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle);
6083 int width = rWndRect.right - rWndRect.left;
6084 int height = rWndRect.bottom - rWndRect.top;
6085 vWinPos = { rWndRect.left, rWndRect.top };
6086 vWinSize = { width, height };
6087 SetWindowPos(olc_hWnd, NULL, vWinPos.x, vWinPos.y, width, height, SWP_SHOWWINDOW);
6088 return olc::OK;
6089 }
6090
6091 virtual olc::rcode StartSystemEventLoop() override
6092 {
6093 MSG msg;
6094 while (GetMessage(&msg, NULL, 0, 0) > 0)
6095 {
6096 TranslateMessage(&msg);
6097 DispatchMessage(&msg);
6098 }
6099 return olc::OK;
6100 }
6101
6102 virtual olc::rcode HandleSystemEvent() override { return olc::rcode::FAIL; }
6103
6104 // Windows Event Handler - this is statically connected to the windows event system
6105 static LRESULT CALLBACK olc_WindowEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
6106 {
6107 switch (uMsg)
6108 {
6109 case WM_MOUSEMOVE:
6110 {
6111 // Thanks @ForAbby (Discord)
6112 uint16_t x = lParam & 0xFFFF; uint16_t y = (lParam >> 16) & 0xFFFF;
6113 int16_t ix = *(int16_t*)&x; int16_t iy = *(int16_t*)&y;
6114 ptrPGE->olc_UpdateMouse(ix, iy);
6115 return 0;
6116 }
6117 case WM_MOVE: vWinPos = olc::vi2d(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); ptrPGE->olc_UpdateWindowPos(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); return 0;
6118 case WM_SIZE: vWinSize = olc::vi2d(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); ptrPGE->olc_UpdateWindowSize(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); return 0;
6119 case WM_MOUSEWHEEL: ptrPGE->olc_UpdateMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam)); return 0;
6120 case WM_MOUSELEAVE: ptrPGE->olc_UpdateMouseFocus(false); return 0;
6121 case WM_SETFOCUS: ptrPGE->olc_UpdateKeyFocus(true); return 0;
6122 case WM_KILLFOCUS: ptrPGE->olc_UpdateKeyFocus(false); return 0;
6123 case WM_KEYDOWN: ptrPGE->olc_UpdateKeyState(mapKeys[wParam], true); return 0;
6124 case WM_KEYUP: ptrPGE->olc_UpdateKeyState(mapKeys[wParam], false); return 0;
6125 case WM_SYSKEYDOWN: ptrPGE->olc_UpdateKeyState(mapKeys[wParam], true); return 0;
6126 case WM_SYSKEYUP: ptrPGE->olc_UpdateKeyState(mapKeys[wParam], false); return 0;
6127 case WM_LBUTTONDOWN:ptrPGE->olc_UpdateMouseState(0, true); return 0;
6128 case WM_LBUTTONUP: ptrPGE->olc_UpdateMouseState(0, false); return 0;
6129 case WM_RBUTTONDOWN:ptrPGE->olc_UpdateMouseState(1, true); return 0;
6130 case WM_RBUTTONUP: ptrPGE->olc_UpdateMouseState(1, false); return 0;
6131 case WM_MBUTTONDOWN:ptrPGE->olc_UpdateMouseState(2, true); return 0;
6132 case WM_MBUTTONUP: ptrPGE->olc_UpdateMouseState(2, false); return 0;
6133 case WM_DROPFILES:
6134 {
6135 // This is all eww...
6136 HDROP drop = (HDROP)wParam;
6137
6138 uint32_t nFiles = DragQueryFile(drop, 0xFFFFFFFF, nullptr, 0);
6139 std::vector<std::string> vFiles;
6140 for (uint32_t i = 0; i < nFiles; i++)
6141 {
6142 TCHAR dfbuffer[256]{};
6143 uint32_t len = DragQueryFile(drop, i, nullptr, 0);
6144 DragQueryFile(drop, i, dfbuffer, 256);
6145#ifdef UNICODE
6146 #ifdef __MINGW32__
6147 char* buffer = new char[len + 1];
6148 wcstombs(buffer, dfbuffer, len);
6149 buffer[len] = '\0';
6150 #else
6151 int count = WideCharToMultiByte(CP_UTF8, 0, dfbuffer, -1, NULL, 0, NULL, NULL);
6152 char* buffer = new char[count];
6153 WideCharToMultiByte(CP_UTF8, 0, dfbuffer, -1, buffer, count, NULL, NULL);
6154 #endif
6155 vFiles.push_back(std::string(buffer));
6156 delete[] buffer;
6157#else
6158 vFiles.push_back(std::string(dfbuffer));
6159#endif
6160 }
6161
6162 // Even more eww...
6163 POINT p; DragQueryPoint(drop, &p);
6164 ptrPGE->olc_DropFiles(p.x, p.y, vFiles);
6165 DragFinish(drop);
6166 return 0;
6167 }
6168 break;
6169
6170
6171 case WM_CLOSE: ptrPGE->olc_Terminate(); return 0;
6172 case WM_DESTROY: PostQuitMessage(0); DestroyWindow(hWnd); return 0;
6173 }
6174 return DefWindowProc(hWnd, uMsg, wParam, lParam);
6175 }
6176 };
6177}
6178#endif
6179// O------------------------------------------------------------------------------O
6180// | END PLATFORM: MICROSOFT WINDOWS XP, VISTA, 7, 8, 10 |
6181// O------------------------------------------------------------------------------O
6182#pragma endregion
6183
6184#pragma region platform_linux
6185// O------------------------------------------------------------------------------O
6186// | START PLATFORM: LINUX |
6187// O------------------------------------------------------------------------------O
6188#if defined(OLC_PLATFORM_X11)
6189namespace olc
6190{
6191 class Platform_Linux : public olc::Platform
6192 {
6193 private:
6194 X11::Display* olc_Display = nullptr;
6195 X11::Window olc_WindowRoot;
6196 X11::Window olc_Window;
6197 X11::XVisualInfo* olc_VisualInfo;
6198 X11::Colormap olc_ColourMap;
6199 X11::XSetWindowAttributes olc_SetWindowAttribs;
6200
6201 public:
6202 virtual olc::rcode ApplicationStartUp() override
6203 {
6204 return olc::rcode::OK;
6205 }
6206
6207 virtual olc::rcode ApplicationCleanUp() override
6208 {
6209 XDestroyWindow(olc_Display, olc_Window);
6210 return olc::rcode::OK;
6211 }
6212
6213 virtual olc::rcode ThreadStartUp() override
6214 {
6215 return olc::rcode::OK;
6216 }
6217
6218 virtual olc::rcode ThreadCleanUp() override
6219 {
6220 renderer->DestroyDevice();
6221 return olc::OK;
6222 }
6223
6224 virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) override
6225 {
6226 if (renderer->CreateDevice({ olc_Display, &olc_Window, olc_VisualInfo }, bFullScreen, bEnableVSYNC) == olc::rcode::OK)
6227 {
6228 renderer->UpdateViewport(vViewPos, vViewSize);
6229 return olc::rcode::OK;
6230 }
6231 else
6232 return olc::rcode::FAIL;
6233 }
6234
6235 virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) override
6236 {
6237 using namespace X11;
6238 XInitThreads();
6239
6240 // Grab the deafult display and window
6241 olc_Display = XOpenDisplay(NULL);
6242 olc_WindowRoot = DefaultRootWindow(olc_Display);
6243
6244 // Based on the display capabilities, configure the appearance of the window
6245 GLint olc_GLAttribs[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
6246 olc_VisualInfo = glXChooseVisual(olc_Display, 0, olc_GLAttribs);
6247 olc_ColourMap = XCreateColormap(olc_Display, olc_WindowRoot, olc_VisualInfo->visual, AllocNone);
6248 olc_SetWindowAttribs.colormap = olc_ColourMap;
6249
6250 // Register which events we are interested in receiving
6251 olc_SetWindowAttribs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
6252 ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | StructureNotifyMask;
6253
6254 // Create the window
6255 olc_Window = XCreateWindow(olc_Display, olc_WindowRoot, vWindowPos.x, vWindowPos.y,
6256 vWindowSize.x, vWindowSize.y,
6257 0, olc_VisualInfo->depth, InputOutput, olc_VisualInfo->visual,
6258 CWColormap | CWEventMask, &olc_SetWindowAttribs);
6259
6260 Atom wmDelete = XInternAtom(olc_Display, "WM_DELETE_WINDOW", true);
6261 XSetWMProtocols(olc_Display, olc_Window, &wmDelete, 1);
6262
6263 XMapWindow(olc_Display, olc_Window);
6264 XStoreName(olc_Display, olc_Window, "OneLoneCoder.com - Pixel Game Engine");
6265
6266 if (bFullScreen) // Thanks DragonEye, again :D
6267 {
6268 Atom wm_state;
6269 Atom fullscreen;
6270 wm_state = XInternAtom(olc_Display, "_NET_WM_STATE", False);
6271 fullscreen = XInternAtom(olc_Display, "_NET_WM_STATE_FULLSCREEN", False);
6272 XEvent xev{ 0 };
6273 xev.type = ClientMessage;
6274 xev.xclient.window = olc_Window;
6275 xev.xclient.message_type = wm_state;
6276 xev.xclient.format = 32;
6277 xev.xclient.data.l[0] = (bFullScreen ? 1 : 0); // the action (0: off, 1: on, 2: toggle)
6278 xev.xclient.data.l[1] = fullscreen; // first property to alter
6279 xev.xclient.data.l[2] = 0; // second property to alter
6280 xev.xclient.data.l[3] = 0; // source indication
6281 XMapWindow(olc_Display, olc_Window);
6282 XSendEvent(olc_Display, DefaultRootWindow(olc_Display), False,
6283 SubstructureRedirectMask | SubstructureNotifyMask, &xev);
6284 XFlush(olc_Display);
6285 XWindowAttributes gwa;
6286 XGetWindowAttributes(olc_Display, olc_Window, &gwa);
6287 vWindowSize.x = gwa.width;
6288 vWindowSize.y = gwa.height;
6289 }
6290
6291 // Create Keyboard Mapping
6292 mapKeys[0x00] = Key::NONE;
6293 mapKeys[0x61] = Key::A; mapKeys[0x62] = Key::B; mapKeys[0x63] = Key::C; mapKeys[0x64] = Key::D; mapKeys[0x65] = Key::E;
6294 mapKeys[0x66] = Key::F; mapKeys[0x67] = Key::G; mapKeys[0x68] = Key::H; mapKeys[0x69] = Key::I; mapKeys[0x6A] = Key::J;
6295 mapKeys[0x6B] = Key::K; mapKeys[0x6C] = Key::L; mapKeys[0x6D] = Key::M; mapKeys[0x6E] = Key::N; mapKeys[0x6F] = Key::O;
6296 mapKeys[0x70] = Key::P; mapKeys[0x71] = Key::Q; mapKeys[0x72] = Key::R; mapKeys[0x73] = Key::S; mapKeys[0x74] = Key::T;
6297 mapKeys[0x75] = Key::U; mapKeys[0x76] = Key::V; mapKeys[0x77] = Key::W; mapKeys[0x78] = Key::X; mapKeys[0x79] = Key::Y;
6298 mapKeys[0x7A] = Key::Z;
6299
6300 mapKeys[XK_F1] = Key::F1; mapKeys[XK_F2] = Key::F2; mapKeys[XK_F3] = Key::F3; mapKeys[XK_F4] = Key::F4;
6301 mapKeys[XK_F5] = Key::F5; mapKeys[XK_F6] = Key::F6; mapKeys[XK_F7] = Key::F7; mapKeys[XK_F8] = Key::F8;
6302 mapKeys[XK_F9] = Key::F9; mapKeys[XK_F10] = Key::F10; mapKeys[XK_F11] = Key::F11; mapKeys[XK_F12] = Key::F12;
6303
6304 mapKeys[XK_Down] = Key::DOWN; mapKeys[XK_Left] = Key::LEFT; mapKeys[XK_Right] = Key::RIGHT; mapKeys[XK_Up] = Key::UP;
6305 mapKeys[XK_KP_Enter] = Key::ENTER; mapKeys[XK_Return] = Key::ENTER;
6306
6307 mapKeys[XK_BackSpace] = Key::BACK; mapKeys[XK_Escape] = Key::ESCAPE; mapKeys[XK_Linefeed] = Key::ENTER; mapKeys[XK_Pause] = Key::PAUSE;
6308 mapKeys[XK_Scroll_Lock] = Key::SCROLL; mapKeys[XK_Tab] = Key::TAB; mapKeys[XK_Delete] = Key::DEL; mapKeys[XK_Home] = Key::HOME;
6309 mapKeys[XK_End] = Key::END; mapKeys[XK_Page_Up] = Key::PGUP; mapKeys[XK_Page_Down] = Key::PGDN; mapKeys[XK_Insert] = Key::INS;
6310 mapKeys[XK_Shift_L] = Key::SHIFT; mapKeys[XK_Shift_R] = Key::SHIFT; mapKeys[XK_Control_L] = Key::CTRL; mapKeys[XK_Control_R] = Key::CTRL;
6311 mapKeys[XK_space] = Key::SPACE; mapKeys[XK_period] = Key::PERIOD;
6312
6313 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;
6314 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;
6315
6316 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;
6317 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;
6318 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;
6319
6320 // These keys vary depending on the keyboard. I've included comments for US and UK keyboard layouts
6321 mapKeys[XK_semicolon] = Key::OEM_1; // On US and UK keyboards this is the ';:' key
6322 mapKeys[XK_slash] = Key::OEM_2; // On US and UK keyboards this is the '/?' key
6323 mapKeys[XK_asciitilde] = Key::OEM_3; // On US keyboard this is the '~' key
6324 mapKeys[XK_bracketleft] = Key::OEM_4; // On US and UK keyboards this is the '[{' key
6325 mapKeys[XK_backslash] = Key::OEM_5; // On US keyboard this is '\|' key.
6326 mapKeys[XK_bracketright] = Key::OEM_6; // On US and UK keyboards this is the ']}' key
6327 mapKeys[XK_apostrophe] = Key::OEM_7; // On US keyboard this is the single/double quote key. On UK, this is the single quote/@ symbol key
6328 mapKeys[XK_numbersign] = Key::OEM_8; // miscellaneous characters. Varies by keyboard. I believe this to be the '#~' key on UK keyboards
6329 mapKeys[XK_equal] = Key::EQUALS; // the '+' key on any keyboard
6330 mapKeys[XK_comma] = Key::COMMA; // the comma key on any keyboard
6331 mapKeys[XK_minus] = Key::MINUS; // the minus key on any keyboard
6332
6333 mapKeys[XK_Caps_Lock] = Key::CAPS_LOCK;
6334
6335 return olc::OK;
6336 }
6337
6338 virtual olc::rcode SetWindowTitle(const std::string& s) override
6339 {
6340 X11::XStoreName(olc_Display, olc_Window, s.c_str());
6341 return olc::OK;
6342 }
6343
6344 virtual olc::rcode SetWindowSize(const olc::vi2d& vPos, const olc::vi2d& vSize) override
6345 {
6346 return olc::rcode::OK;
6347 }
6348
6349 virtual olc::rcode ShowWindowFrame(const bool bShowFrame = true) override
6350 {
6351 return olc::rcode::OK;
6352 }
6353
6354
6355 virtual olc::rcode StartSystemEventLoop() override
6356 {
6357 return olc::OK;
6358 }
6359
6360 virtual olc::rcode HandleSystemEvent() override
6361 {
6362 using namespace X11;
6363 // Handle Xlib Message Loop - we do this in the
6364 // same thread that OpenGL was created so we dont
6365 // need to worry too much about multithreading with X11
6366 XEvent xev;
6367 while (XPending(olc_Display))
6368 {
6369 XNextEvent(olc_Display, &xev);
6370 if (xev.type == Expose)
6371 {
6372 XWindowAttributes gwa;
6373 XGetWindowAttributes(olc_Display, olc_Window, &gwa);
6374 ptrPGE->olc_UpdateWindowSize(gwa.width, gwa.height);
6375 }
6376 else if (xev.type == ConfigureNotify)
6377 {
6378 XConfigureEvent xce = xev.xconfigure;
6379 ptrPGE->olc_UpdateWindowSize(xce.width, xce.height);
6380 }
6381 else if (xev.type == KeyPress)
6382 {
6383 KeySym sym = XLookupKeysym(&xev.xkey, 0);
6384 ptrPGE->olc_UpdateKeyState(mapKeys[sym], true);
6385 XKeyEvent* e = (XKeyEvent*)&xev; // Because DragonEye loves numpads
6386 XLookupString(e, NULL, 0, &sym, NULL);
6387 ptrPGE->olc_UpdateKeyState(mapKeys[sym], true);
6388 }
6389 else if (xev.type == KeyRelease)
6390 {
6391 KeySym sym = XLookupKeysym(&xev.xkey, 0);
6392 ptrPGE->olc_UpdateKeyState(mapKeys[sym], false);
6393 XKeyEvent* e = (XKeyEvent*)&xev;
6394 XLookupString(e, NULL, 0, &sym, NULL);
6395 ptrPGE->olc_UpdateKeyState(mapKeys[sym], false);
6396 }
6397 else if (xev.type == ButtonPress)
6398 {
6399 switch (xev.xbutton.button)
6400 {
6401 case 1: ptrPGE->olc_UpdateMouseState(0, true); break;
6402 case 2: ptrPGE->olc_UpdateMouseState(2, true); break;
6403 case 3: ptrPGE->olc_UpdateMouseState(1, true); break;
6404 case 4: ptrPGE->olc_UpdateMouseWheel(120); break;
6405 case 5: ptrPGE->olc_UpdateMouseWheel(-120); break;
6406 default: break;
6407 }
6408 }
6409 else if (xev.type == ButtonRelease)
6410 {
6411 switch (xev.xbutton.button)
6412 {
6413 case 1: ptrPGE->olc_UpdateMouseState(0, false); break;
6414 case 2: ptrPGE->olc_UpdateMouseState(2, false); break;
6415 case 3: ptrPGE->olc_UpdateMouseState(1, false); break;
6416 default: break;
6417 }
6418 }
6419 else if (xev.type == MotionNotify)
6420 {
6421 ptrPGE->olc_UpdateMouse(xev.xmotion.x, xev.xmotion.y);
6422 }
6423 else if (xev.type == FocusIn)
6424 {
6425 ptrPGE->olc_UpdateKeyFocus(true);
6426 }
6427 else if (xev.type == FocusOut)
6428 {
6429 ptrPGE->olc_UpdateKeyFocus(false);
6430 }
6431 else if (xev.type == ClientMessage)
6432 {
6433 ptrPGE->olc_Terminate();
6434 }
6435 }
6436 return olc::OK;
6437 }
6438 };
6439}
6440#endif
6441// O------------------------------------------------------------------------------O
6442// | END PLATFORM: LINUX |
6443// O------------------------------------------------------------------------------O
6444#pragma endregion
6445
6446#pragma region platform_glut
6447// O------------------------------------------------------------------------------O
6448// | START PLATFORM: GLUT (used to make it simple for Apple) |
6449// O------------------------------------------------------------------------------O
6450//
6451// VERY IMPORTANT!!! The Apple port was originally created by @Mumflr (discord)
6452// and the repo for the development of this project can be found here:
6453// https://github.com/MumflrFumperdink/olcPGEMac which contains maccy goodness
6454// and support on how to setup your build environment.
6455//
6456// "MASSIVE MASSIVE THANKS TO MUMFLR" - Javidx9
6457#if defined(OLC_PLATFORM_GLUT)
6458namespace olc {
6459
6460 class Platform_GLUT : public olc::Platform
6461 {
6462 public:
6463 static std::atomic<bool>* bActiveRef;
6464
6465 virtual olc::rcode SetWindowSize(const olc::vi2d& vPos, const olc::vi2d& vSize) override
6466 {
6467 return olc::rcode::OK;
6468 }
6469
6470 virtual olc::rcode ShowWindowFrame(const bool bShowFrame = true) override
6471 {
6472 return olc::rcode::OK;
6473 }
6474
6475
6476 virtual olc::rcode ApplicationStartUp() override {
6477 return olc::rcode::OK;
6478 }
6479
6480 virtual olc::rcode ApplicationCleanUp() override
6481 {
6482 return olc::rcode::OK;
6483 }
6484
6485 virtual olc::rcode ThreadStartUp() override
6486 {
6487 return olc::rcode::OK;
6488 }
6489
6490 virtual olc::rcode ThreadCleanUp() override
6491 {
6492 renderer->DestroyDevice();
6493 return olc::OK;
6494 }
6495
6496 virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) override
6497 {
6498 if (renderer->CreateDevice({}, bFullScreen, bEnableVSYNC) == olc::rcode::OK)
6499 {
6500 renderer->UpdateViewport(vViewPos, vViewSize);
6501 return olc::rcode::OK;
6502 }
6503 else
6504 return olc::rcode::FAIL;
6505 }
6506
6507 static void ExitMainLoop() {
6508 if (!ptrPGE->OnUserDestroy()) {
6509 *bActiveRef = true;
6510 return;
6511 }
6512 platform->ThreadCleanUp();
6513 platform->ApplicationCleanUp();
6514 exit(0);
6515 }
6516
6517#if defined(__APPLE__)
6518 static void scrollWheelUpdate(id selff, SEL _sel, id theEvent) {
6519 static const SEL deltaYSel = sel_registerName("deltaY");
6520
6521#if defined(__aarch64__) // Thanks ruarq!
6522 double deltaY = ((double (*)(id, SEL))objc_msgSend)(theEvent, deltaYSel);
6523#else
6524 double deltaY = ((double (*)(id, SEL))objc_msgSend_fpret)(theEvent, deltaYSel);
6525#endif
6526
6527 for (int i = 0; i < abs(deltaY); i++) {
6528 if (deltaY > 0) {
6529 ptrPGE->olc_UpdateMouseWheel(-1);
6530 }
6531 else if (deltaY < 0) {
6532 ptrPGE->olc_UpdateMouseWheel(1);
6533 }
6534 }
6535 }
6536#endif
6537 static void ThreadFunct() {
6538#if defined(__APPLE__)
6539 static bool hasEnabledCocoa = false;
6540 if (!hasEnabledCocoa) {
6541 // Objective-C Wizardry
6542 Class NSApplicationClass = objc_getClass("NSApplication");
6543
6544 // NSApp = [NSApplication sharedApplication]
6545 SEL sharedApplicationSel = sel_registerName("sharedApplication");
6546 id NSApp = ((id(*)(Class, SEL))objc_msgSend)(NSApplicationClass, sharedApplicationSel);
6547 // window = [NSApp mainWindow]
6548 SEL mainWindowSel = sel_registerName("mainWindow");
6549 id window = ((id(*)(id, SEL))objc_msgSend)(NSApp, mainWindowSel);
6550
6551 // [window setStyleMask: NSWindowStyleMaskClosable | ~NSWindowStyleMaskResizable]
6552 SEL setStyleMaskSel = sel_registerName("setStyleMask:");
6553 ((void (*)(id, SEL, NSUInteger))objc_msgSend)(window, setStyleMaskSel, 7);
6554
6555 hasEnabledCocoa = true;
6556 }
6557#endif
6558 if (!*bActiveRef) {
6559 ExitMainLoop();
6560 return;
6561 }
6562 glutPostRedisplay();
6563 }
6564
6565 static void DrawFunct() {
6566 ptrPGE->olc_CoreUpdate();
6567 }
6568
6569 virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) override
6570 {
6571#if defined(__APPLE__)
6572 Class GLUTViewClass = objc_getClass("GLUTView");
6573
6574 SEL scrollWheelSel = sel_registerName("scrollWheel:");
6575 bool resultAddMethod = class_addMethod(GLUTViewClass, scrollWheelSel, (IMP)scrollWheelUpdate, "v@:@");
6576 assert(resultAddMethod);
6577#endif
6578
6579 renderer->PrepareDevice();
6580
6581 if (bFullScreen)
6582 {
6583 vWindowSize.x = glutGet(GLUT_SCREEN_WIDTH);
6584 vWindowSize.y = glutGet(GLUT_SCREEN_HEIGHT);
6585 glutFullScreen();
6586 }
6587 else
6588 {
6589 if (vWindowSize.x > glutGet(GLUT_SCREEN_WIDTH) || vWindowSize.y > glutGet(GLUT_SCREEN_HEIGHT))
6590 {
6591 perror("ERROR: The specified window dimensions do not fit on your screen\n");
6592 return olc::FAIL;
6593 }
6594 glutReshapeWindow(vWindowSize.x, vWindowSize.y - 1);
6595 }
6596
6597 // Create Keyboard Mapping
6598 mapKeys[0x00] = Key::NONE;
6599 mapKeys['A'] = Key::A; mapKeys['B'] = Key::B; mapKeys['C'] = Key::C; mapKeys['D'] = Key::D; mapKeys['E'] = Key::E;
6600 mapKeys['F'] = Key::F; mapKeys['G'] = Key::G; mapKeys['H'] = Key::H; mapKeys['I'] = Key::I; mapKeys['J'] = Key::J;
6601 mapKeys['K'] = Key::K; mapKeys['L'] = Key::L; mapKeys['M'] = Key::M; mapKeys['N'] = Key::N; mapKeys['O'] = Key::O;
6602 mapKeys['P'] = Key::P; mapKeys['Q'] = Key::Q; mapKeys['R'] = Key::R; mapKeys['S'] = Key::S; mapKeys['T'] = Key::T;
6603 mapKeys['U'] = Key::U; mapKeys['V'] = Key::V; mapKeys['W'] = Key::W; mapKeys['X'] = Key::X; mapKeys['Y'] = Key::Y;
6604 mapKeys['Z'] = Key::Z;
6605
6606 mapKeys[GLUT_KEY_F1] = Key::F1; mapKeys[GLUT_KEY_F2] = Key::F2; mapKeys[GLUT_KEY_F3] = Key::F3; mapKeys[GLUT_KEY_F4] = Key::F4;
6607 mapKeys[GLUT_KEY_F5] = Key::F5; mapKeys[GLUT_KEY_F6] = Key::F6; mapKeys[GLUT_KEY_F7] = Key::F7; mapKeys[GLUT_KEY_F8] = Key::F8;
6608 mapKeys[GLUT_KEY_F9] = Key::F9; mapKeys[GLUT_KEY_F10] = Key::F10; mapKeys[GLUT_KEY_F11] = Key::F11; mapKeys[GLUT_KEY_F12] = Key::F12;
6609
6610 mapKeys[GLUT_KEY_DOWN] = Key::DOWN; mapKeys[GLUT_KEY_LEFT] = Key::LEFT; mapKeys[GLUT_KEY_RIGHT] = Key::RIGHT; mapKeys[GLUT_KEY_UP] = Key::UP;
6611 mapKeys[13] = Key::ENTER;
6612
6613 mapKeys[127] = Key::BACK; mapKeys[27] = Key::ESCAPE;
6614 mapKeys[9] = Key::TAB; mapKeys[GLUT_KEY_HOME] = Key::HOME;
6615 mapKeys[GLUT_KEY_END] = Key::END; mapKeys[GLUT_KEY_PAGE_UP] = Key::PGUP; mapKeys[GLUT_KEY_PAGE_DOWN] = Key::PGDN; mapKeys[GLUT_KEY_INSERT] = Key::INS;
6616 mapKeys[32] = Key::SPACE; mapKeys[46] = Key::PERIOD;
6617
6618 mapKeys[48] = Key::K0; mapKeys[49] = Key::K1; mapKeys[50] = Key::K2; mapKeys[51] = Key::K3; mapKeys[52] = Key::K4;
6619 mapKeys[53] = Key::K5; mapKeys[54] = Key::K6; mapKeys[55] = Key::K7; mapKeys[56] = Key::K8; mapKeys[57] = Key::K9;
6620
6621 // NOTE: MISSING KEYS :O
6622
6623 glutKeyboardFunc([](unsigned char key, int x, int y) -> void {
6624 switch (glutGetModifiers()) {
6625 case 0: //This is when there are no modifiers
6626 if ('a' <= key && key <= 'z') key -= 32;
6627 break;
6628 case GLUT_ACTIVE_SHIFT:
6629 ptrPGE->olc_UpdateKeyState(Key::SHIFT, true);
6630 break;
6631 case GLUT_ACTIVE_CTRL:
6632 if ('a' <= key && key <= 'z') key -= 32;
6633 ptrPGE->olc_UpdateKeyState(Key::CTRL, true);
6634 break;
6635 case GLUT_ACTIVE_ALT:
6636 if ('a' <= key && key <= 'z') key -= 32;
6637 break;
6638 }
6639
6640 if (mapKeys[key])
6641 ptrPGE->olc_UpdateKeyState(mapKeys[key], true);
6642 });
6643
6644 glutKeyboardUpFunc([](unsigned char key, int x, int y) -> void {
6645 switch (glutGetModifiers()) {
6646 case 0: //This is when there are no modifiers
6647 if ('a' <= key && key <= 'z') key -= 32;
6648 break;
6649 case GLUT_ACTIVE_SHIFT:
6650 ptrPGE->olc_UpdateKeyState(Key::SHIFT, false);
6651 break;
6652 case GLUT_ACTIVE_CTRL:
6653 if ('a' <= key && key <= 'z') key -= 32;
6654 ptrPGE->olc_UpdateKeyState(Key::CTRL, false);
6655 break;
6656 case GLUT_ACTIVE_ALT:
6657 if ('a' <= key && key <= 'z') key -= 32;
6658 //No ALT in PGE
6659 break;
6660 }
6661
6662 if (mapKeys[key])
6663 ptrPGE->olc_UpdateKeyState(mapKeys[key], false);
6664 });
6665
6666 //Special keys
6667 glutSpecialFunc([](int key, int x, int y) -> void {
6668 if (mapKeys[key])
6669 ptrPGE->olc_UpdateKeyState(mapKeys[key], true);
6670 });
6671
6672 glutSpecialUpFunc([](int key, int x, int y) -> void {
6673 if (mapKeys[key])
6674 ptrPGE->olc_UpdateKeyState(mapKeys[key], false);
6675 });
6676
6677 glutMouseFunc([](int button, int state, int x, int y) -> void {
6678 switch (button) {
6679 case GLUT_LEFT_BUTTON:
6680 if (state == GLUT_UP) ptrPGE->olc_UpdateMouseState(0, false);
6681 else if (state == GLUT_DOWN) ptrPGE->olc_UpdateMouseState(0, true);
6682 break;
6683 case GLUT_MIDDLE_BUTTON:
6684 if (state == GLUT_UP) ptrPGE->olc_UpdateMouseState(2, false);
6685 else if (state == GLUT_DOWN) ptrPGE->olc_UpdateMouseState(2, true);
6686 break;
6687 case GLUT_RIGHT_BUTTON:
6688 if (state == GLUT_UP) ptrPGE->olc_UpdateMouseState(1, false);
6689 else if (state == GLUT_DOWN) ptrPGE->olc_UpdateMouseState(1, true);
6690 break;
6691 }
6692 });
6693
6694 auto mouseMoveCall = [](int x, int y) -> void {
6695 ptrPGE->olc_UpdateMouse(x, y);
6696 };
6697
6698 glutMotionFunc(mouseMoveCall);
6699 glutPassiveMotionFunc(mouseMoveCall);
6700
6701 glutEntryFunc([](int state) -> void {
6702 if (state == GLUT_ENTERED) ptrPGE->olc_UpdateKeyFocus(true);
6703 else if (state == GLUT_LEFT) ptrPGE->olc_UpdateKeyFocus(false);
6704 });
6705
6706 glutDisplayFunc(DrawFunct);
6707 glutIdleFunc(ThreadFunct);
6708
6709 return olc::OK;
6710 }
6711
6712 virtual olc::rcode SetWindowTitle(const std::string& s) override
6713 {
6714 glutSetWindowTitle(s.c_str());
6715 return olc::OK;
6716 }
6717
6718 virtual olc::rcode StartSystemEventLoop() override {
6719 glutMainLoop();
6720 return olc::OK;
6721 }
6722
6723 virtual olc::rcode HandleSystemEvent() override
6724 {
6725 return olc::OK;
6726 }
6727 };
6728
6729 std::atomic<bool>* Platform_GLUT::bActiveRef{ nullptr };
6730
6731 //Custom Start
6733 {
6734 if (platform->ApplicationStartUp() != olc::OK) return olc::FAIL;
6735
6736 // Construct the window
6737 if (platform->CreateWindowPane({ 30,30 }, vWindowSize, bFullScreen) != olc::OK) return olc::FAIL;
6738 olc_UpdateWindowSize(vWindowSize.x, vWindowSize.y);
6739
6740 if (platform->ThreadStartUp() == olc::FAIL) return olc::FAIL;
6742 if (!OnUserCreate()) return olc::FAIL;
6743 Platform_GLUT::bActiveRef = &bAtomActive;
6744 glutWMCloseFunc(Platform_GLUT::ExitMainLoop);
6745 bAtomActive = true;
6746 platform->StartSystemEventLoop();
6747
6748 //This code will not even be run but why not
6749 if (platform->ApplicationCleanUp() != olc::OK) return olc::FAIL;
6750
6751 return olc::OK;
6752 }
6753}
6754
6755#endif
6756// O------------------------------------------------------------------------------O
6757// | END PLATFORM: GLUT |
6758// O------------------------------------------------------------------------------O
6759#pragma endregion
6760
6761
6762
6763
6764
6765#pragma region platform_emscripten
6766// O------------------------------------------------------------------------------O
6767// | START PLATFORM: Emscripten - Totally Game Changing... |
6768// O------------------------------------------------------------------------------O
6769
6770//
6771// Firstly a big mega thank you to members of the OLC Community for sorting this
6772// out. Making a browser compatible version has been a priority for quite some
6773// time, but I lacked the expertise to do it. This awesome feature is possible
6774// because a group of former strangers got together and formed friendships over
6775// their shared passion for code. If anything demonstrates how powerful helping
6776// each other can be, it's this. - Javidx9
6777
6778// Emscripten Platform: MaGetzUb, Moros1138, Slavka, Dandistine, Gorbit99, Bispoo
6779// also: Ishidex, Gusgo99, SlicEnDicE, Alexio
6780
6781
6782#if defined(OLC_PLATFORM_EMSCRIPTEN)
6783
6784#include <emscripten/html5.h>
6785#include <emscripten/key_codes.h>
6786
6787extern "C"
6788{
6789 EMSCRIPTEN_KEEPALIVE inline int olc_OnPageUnload()
6790 { olc::platform->ApplicationCleanUp(); return 0; }
6791}
6792
6793namespace olc
6794{
6795 class Platform_Emscripten : public olc::Platform
6796 {
6797 public:
6798
6799 virtual olc::rcode SetWindowSize(const olc::vi2d& vPos, const olc::vi2d& vSize) override
6800 { return olc::rcode::OK; }
6801
6802 virtual olc::rcode ShowWindowFrame(const bool bShowFrame = true) override
6803 { return olc::rcode::OK; }
6804
6805 virtual olc::rcode ApplicationStartUp() override
6806 { return olc::rcode::OK; }
6807
6808 virtual olc::rcode ApplicationCleanUp() override
6809 { ThreadCleanUp(); return olc::rcode::OK; }
6810
6811 virtual olc::rcode ThreadStartUp() override
6812 { return olc::rcode::OK; }
6813
6814 virtual olc::rcode ThreadCleanUp() override
6815 { renderer->DestroyDevice(); return olc::OK; }
6816
6817 virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) override
6818 {
6819 if (renderer->CreateDevice({}, bFullScreen, bEnableVSYNC) == olc::rcode::OK)
6820 {
6821 renderer->UpdateViewport(vViewPos, vViewSize);
6822 return olc::rcode::OK;
6823 }
6824 else
6825 return olc::rcode::FAIL;
6826 }
6827
6828 virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) override
6829 {
6830 emscripten_set_canvas_element_size("#canvas", vWindowSize.x, vWindowSize.y);
6831
6832 mapKeys[DOM_PK_UNKNOWN] = Key::NONE;
6833 mapKeys[DOM_PK_A] = Key::A; mapKeys[DOM_PK_B] = Key::B; mapKeys[DOM_PK_C] = Key::C; mapKeys[DOM_PK_D] = Key::D;
6834 mapKeys[DOM_PK_E] = Key::E; mapKeys[DOM_PK_F] = Key::F; mapKeys[DOM_PK_G] = Key::G; mapKeys[DOM_PK_H] = Key::H;
6835 mapKeys[DOM_PK_I] = Key::I; mapKeys[DOM_PK_J] = Key::J; mapKeys[DOM_PK_K] = Key::K; mapKeys[DOM_PK_L] = Key::L;
6836 mapKeys[DOM_PK_M] = Key::M; mapKeys[DOM_PK_N] = Key::N; mapKeys[DOM_PK_O] = Key::O; mapKeys[DOM_PK_P] = Key::P;
6837 mapKeys[DOM_PK_Q] = Key::Q; mapKeys[DOM_PK_R] = Key::R; mapKeys[DOM_PK_S] = Key::S; mapKeys[DOM_PK_T] = Key::T;
6838 mapKeys[DOM_PK_U] = Key::U; mapKeys[DOM_PK_V] = Key::V; mapKeys[DOM_PK_W] = Key::W; mapKeys[DOM_PK_X] = Key::X;
6839 mapKeys[DOM_PK_Y] = Key::Y; mapKeys[DOM_PK_Z] = Key::Z;
6840 mapKeys[DOM_PK_0] = Key::K0; mapKeys[DOM_PK_1] = Key::K1; mapKeys[DOM_PK_2] = Key::K2;
6841 mapKeys[DOM_PK_3] = Key::K3; mapKeys[DOM_PK_4] = Key::K4; mapKeys[DOM_PK_5] = Key::K5;
6842 mapKeys[DOM_PK_6] = Key::K6; mapKeys[DOM_PK_7] = Key::K7; mapKeys[DOM_PK_8] = Key::K8;
6843 mapKeys[DOM_PK_9] = Key::K9;
6844 mapKeys[DOM_PK_F1] = Key::F1; mapKeys[DOM_PK_F2] = Key::F2; mapKeys[DOM_PK_F3] = Key::F3; mapKeys[DOM_PK_F4] = Key::F4;
6845 mapKeys[DOM_PK_F5] = Key::F5; mapKeys[DOM_PK_F6] = Key::F6; mapKeys[DOM_PK_F7] = Key::F7; mapKeys[DOM_PK_F8] = Key::F8;
6846 mapKeys[DOM_PK_F9] = Key::F9; mapKeys[DOM_PK_F10] = Key::F10; mapKeys[DOM_PK_F11] = Key::F11; mapKeys[DOM_PK_F12] = Key::F12;
6847 mapKeys[DOM_PK_ARROW_UP] = Key::UP; mapKeys[DOM_PK_ARROW_DOWN] = Key::DOWN;
6848 mapKeys[DOM_PK_ARROW_LEFT] = Key::LEFT; mapKeys[DOM_PK_ARROW_RIGHT] = Key::RIGHT;
6849 mapKeys[DOM_PK_SPACE] = Key::SPACE; mapKeys[DOM_PK_TAB] = Key::TAB;
6850 mapKeys[DOM_PK_SHIFT_LEFT] = Key::SHIFT; mapKeys[DOM_PK_SHIFT_RIGHT] = Key::SHIFT;
6851 mapKeys[DOM_PK_CONTROL_LEFT] = Key::CTRL; mapKeys[DOM_PK_CONTROL_RIGHT] = Key::CTRL;
6852 mapKeys[DOM_PK_INSERT] = Key::INS; mapKeys[DOM_PK_DELETE] = Key::DEL; mapKeys[DOM_PK_HOME] = Key::HOME;
6853 mapKeys[DOM_PK_END] = Key::END; mapKeys[DOM_PK_PAGE_UP] = Key::PGUP; mapKeys[DOM_PK_PAGE_DOWN] = Key::PGDN;
6854 mapKeys[DOM_PK_BACKSPACE] = Key::BACK; mapKeys[DOM_PK_ESCAPE] = Key::ESCAPE;
6855 mapKeys[DOM_PK_ENTER] = Key::ENTER; mapKeys[DOM_PK_NUMPAD_EQUAL] = Key::EQUALS;
6856 mapKeys[DOM_PK_NUMPAD_ENTER] = Key::ENTER; mapKeys[DOM_PK_PAUSE] = Key::PAUSE;
6857 mapKeys[DOM_PK_SCROLL_LOCK] = Key::SCROLL;
6858 mapKeys[DOM_PK_NUMPAD_0] = Key::NP0; mapKeys[DOM_PK_NUMPAD_1] = Key::NP1; mapKeys[DOM_PK_NUMPAD_2] = Key::NP2;
6859 mapKeys[DOM_PK_NUMPAD_3] = Key::NP3; mapKeys[DOM_PK_NUMPAD_4] = Key::NP4; mapKeys[DOM_PK_NUMPAD_5] = Key::NP5;
6860 mapKeys[DOM_PK_NUMPAD_6] = Key::NP6; mapKeys[DOM_PK_NUMPAD_7] = Key::NP7; mapKeys[DOM_PK_NUMPAD_8] = Key::NP8;
6861 mapKeys[DOM_PK_NUMPAD_9] = Key::NP9;
6862 mapKeys[DOM_PK_NUMPAD_MULTIPLY] = Key::NP_MUL; mapKeys[DOM_PK_NUMPAD_DIVIDE] = Key::NP_DIV;
6863 mapKeys[DOM_PK_NUMPAD_ADD] = Key::NP_ADD; mapKeys[DOM_PK_NUMPAD_SUBTRACT] = Key::NP_SUB;
6864 mapKeys[DOM_PK_NUMPAD_DECIMAL] = Key::NP_DECIMAL;
6865 mapKeys[DOM_PK_PERIOD] = Key::PERIOD; mapKeys[DOM_PK_EQUAL] = Key::EQUALS;
6866 mapKeys[DOM_PK_COMMA] = Key::COMMA; mapKeys[DOM_PK_MINUS] = Key::MINUS;
6867 mapKeys[DOM_PK_CAPS_LOCK] = Key::CAPS_LOCK;
6868 mapKeys[DOM_PK_SEMICOLON] = Key::OEM_1; mapKeys[DOM_PK_SLASH] = Key::OEM_2; mapKeys[DOM_PK_BACKQUOTE] = Key::OEM_3;
6869 mapKeys[DOM_PK_BRACKET_LEFT] = Key::OEM_4; mapKeys[DOM_PK_BACKSLASH] = Key::OEM_5; mapKeys[DOM_PK_BRACKET_RIGHT] = Key::OEM_6;
6870 mapKeys[DOM_PK_QUOTE] = Key::OEM_7; mapKeys[DOM_PK_BACKSLASH] = Key::OEM_8;
6871
6872 // Keyboard Callbacks
6873 emscripten_set_keydown_callback("#canvas", 0, 1, keyboard_callback);
6874 emscripten_set_keyup_callback("#canvas", 0, 1, keyboard_callback);
6875
6876 // Mouse Callbacks
6877 emscripten_set_wheel_callback("#canvas", 0, 1, wheel_callback);
6878 emscripten_set_mousedown_callback("#canvas", 0, 1, mouse_callback);
6879 emscripten_set_mouseup_callback("#canvas", 0, 1, mouse_callback);
6880 emscripten_set_mousemove_callback("#canvas", 0, 1, mouse_callback);
6881
6882 // Touch Callbacks
6883 emscripten_set_touchstart_callback("#canvas", 0, 1, touch_callback);
6884 emscripten_set_touchmove_callback("#canvas", 0, 1, touch_callback);
6885 emscripten_set_touchend_callback("#canvas", 0, 1, touch_callback);
6886
6887 // Canvas Focus Callbacks
6888 emscripten_set_blur_callback("#canvas", 0, 1, focus_callback);
6889 emscripten_set_focus_callback("#canvas", 0, 1, focus_callback);
6890
6891#pragma warning disable format
6892 EM_ASM( window.onunload = Module._olc_OnPageUnload; );
6893
6894 // IMPORTANT! - Sorry About This...
6895 //
6896 // In order to handle certain browser based events, such as resizing and
6897 // going to full screen, we have to effectively inject code into the container
6898 // running the PGE. Yes, I vomited about 11 times too when the others were
6899 // convincing me this is the future. Well, this isnt the future, and if it
6900 // were to be, I want no part of what must be a miserable distopian free
6901 // for all of anarchic code injection to get rudimentary events like "Resize()".
6902 //
6903 // Wake up people! Of course theres a spoon. There has to be to keep feeding
6904 // the giant web baby.
6905
6906
6907 EM_ASM({
6908
6909 // olc_ApsectRatio
6910 //
6911 // Used by olc_ResizeHandler to calculate the viewport from the
6912 // dimensions of the canvas container's element.
6913 Module.olc_AspectRatio = $0 / $1;
6914
6915 // HACK ALERT!
6916 //
6917 // Here we assume any html shell that uses 3 or more instance of the class "emscripten"
6918 // is using one of the default or minimal emscripten page layouts
6919 Module.olc_AssumeDefaultShells = (document.querySelectorAll('.emscripten').length >= 3) ? true : false;
6920
6921 // olc_ResizeHandler
6922 //
6923 // Used by olc_Init, and is called when a resize observer and fullscreenchange event is triggered.
6924 var olc_ResizeHandler = function()
6925 {
6926 // are we in fullscreen mode?
6927 let isFullscreen = (document.fullscreenElement != null);
6928
6929 // get the width of the containing element
6930 let width = (isFullscreen) ? window.innerWidth : Module.canvas.parentNode.clientWidth;
6931 let height = (isFullscreen) ? window.innerHeight : Module.canvas.parentNode.clientHeight;
6932
6933 // calculate the expected viewport size
6934 let viewWidth = width;
6935 let viewHeight = width / Module.olc_AspectRatio;
6936
6937 // if we're taller than the containing element, recalculate based on height
6938 if(viewHeight > height)
6939 {
6940 viewWidth = height * Module.olc_AspectRatio;
6941 viewHeight = height;
6942 }
6943
6944 // ensure resulting viewport is in integer space
6945 viewWidth = parseInt(viewWidth);
6946 viewHeight = parseInt(viewHeight);
6947
6948 setTimeout(function()
6949 {
6950 // if default shells, apply default styles
6951 if(Module.olc_AssumeDefaultShells)
6952 Module.canvas.parentNode.setAttribute('style', 'width: 100%; height: 70vh; margin-left: auto; margin-right: auto;');
6953
6954 // apply viewport dimensions to teh canvas
6955 Module.canvas.setAttribute('width', viewWidth);
6956 Module.canvas.setAttribute('height', viewHeight);
6957 Module.canvas.setAttribute('style', `width: ${viewWidth}px; height: ${viewHeight}px;`);
6958
6959 // update the PGE window size
6960 Module._olc_PGE_UpdateWindowSize(viewWidth, viewHeight);
6961
6962 // force focus on our PGE canvas
6963 Module.canvas.focus();
6964 }, 200);
6965 };
6966
6967
6968 // olc_Init
6969 //
6970 // set up resize observer and fullscreenchange event handler
6971 var olc_Init = function()
6972 {
6973 if(Module.olc_AspectRatio === undefined)
6974 {
6975 setTimeout(function() { Module.olc_Init(); }, 50);
6976 return;
6977 }
6978
6979 let resizeObserver = new ResizeObserver(function(entries)
6980 {
6981 Module.olc_ResizeHandler();
6982 }).observe(Module.canvas.parentNode);
6983
6984 let mutationObserver = new MutationObserver(function(mutationsList, observer)
6985 {
6986 setTimeout(function() { Module.olc_ResizeHandler(); }, 200);
6987 }).observe(Module.canvas.parentNode, { attributes: false, childList: true, subtree: false });
6988
6989 window.addEventListener('fullscreenchange', function(e)
6990 {
6991 setTimeout(function() { Module.olc_ResizeHandler();}, 200);
6992 });
6993 };
6994
6995 // set up hooks
6996 Module.olc_ResizeHandler = (Module.olc_ResizeHandler != undefined) ? Module.olc_ResizeHandler : olc_ResizeHandler;
6997 Module.olc_Init = (Module.olc_Init != undefined) ? Module.olc_Init : olc_Init;
6998
6999 // run everything!
7000 Module.olc_Init();
7001
7002 }, vWindowSize.x, vWindowSize.y); // Fullscreen and Resize Observers
7003#pragma warning restore format
7004 return olc::rcode::OK;
7005 }
7006
7007 // Interface PGE's UpdateWindowSize, for use in Javascript
7008 void UpdateWindowSize(int width, int height)
7009 {
7010 ptrPGE->olc_UpdateWindowSize(width, height);
7011 }
7012
7013 //TY Gorbit
7014 static EM_BOOL focus_callback(int eventType, const EmscriptenFocusEvent* focusEvent, void* userData)
7015 {
7016 if (eventType == EMSCRIPTEN_EVENT_BLUR)
7017 {
7018 ptrPGE->olc_UpdateKeyFocus(false);
7019 ptrPGE->olc_UpdateMouseFocus(false);
7020 }
7021 else if (eventType == EMSCRIPTEN_EVENT_FOCUS)
7022 {
7023 ptrPGE->olc_UpdateKeyFocus(true);
7024 ptrPGE->olc_UpdateMouseFocus(true);
7025 }
7026
7027 return 0;
7028 }
7029
7030 //TY Moros
7031 static EM_BOOL keyboard_callback(int eventType, const EmscriptenKeyboardEvent* e, void* userData)
7032 {
7033 if (eventType == EMSCRIPTEN_EVENT_KEYDOWN)
7034 ptrPGE->olc_UpdateKeyState(mapKeys[emscripten_compute_dom_pk_code(e->code)], true);
7035
7036 // THANK GOD!! for this compute function. And thanks Dandistine for pointing it out!
7037 if (eventType == EMSCRIPTEN_EVENT_KEYUP)
7038 ptrPGE->olc_UpdateKeyState(mapKeys[emscripten_compute_dom_pk_code(e->code)], false);
7039
7040 //Consume keyboard events so that keys like F1 and F5 don't do weird things
7041 return EM_TRUE;
7042 }
7043
7044 //TY Moros
7045 static EM_BOOL wheel_callback(int eventType, const EmscriptenWheelEvent* e, void* userData)
7046 {
7047 if (eventType == EMSCRIPTEN_EVENT_WHEEL)
7048 ptrPGE->olc_UpdateMouseWheel(-1 * e->deltaY);
7049
7050 return EM_TRUE;
7051 }
7052
7053 //TY Bispoo
7054 static EM_BOOL touch_callback(int eventType, const EmscriptenTouchEvent* e, void* userData)
7055 {
7056 // Move
7057 if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE)
7058 {
7059 ptrPGE->olc_UpdateMouse(e->touches->targetX, e->touches->targetY);
7060 }
7061
7062 // Start
7063 if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART)
7064 {
7065 ptrPGE->olc_UpdateMouse(e->touches->targetX, e->touches->targetY);
7066 ptrPGE->olc_UpdateMouseState(0, true);
7067 }
7068
7069 // End
7070 if (eventType == EMSCRIPTEN_EVENT_TOUCHEND)
7071 {
7072 ptrPGE->olc_UpdateMouseState(0, false);
7073 }
7074
7075 return EM_TRUE;
7076 }
7077
7078 //TY Moros
7079 static EM_BOOL mouse_callback(int eventType, const EmscriptenMouseEvent* e, void* userData)
7080 {
7081 //Mouse Movement
7082 if (eventType == EMSCRIPTEN_EVENT_MOUSEMOVE)
7083 ptrPGE->olc_UpdateMouse(e->targetX, e->targetY);
7084
7085
7086 //Mouse button press
7087 if (e->button == 0) // left click
7088 {
7089 if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN)
7090 ptrPGE->olc_UpdateMouseState(0, true);
7091 else if (eventType == EMSCRIPTEN_EVENT_MOUSEUP)
7092 ptrPGE->olc_UpdateMouseState(0, false);
7093 }
7094
7095 if (e->button == 2) // right click
7096 {
7097 if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN)
7098 ptrPGE->olc_UpdateMouseState(1, true);
7099 else if (eventType == EMSCRIPTEN_EVENT_MOUSEUP)
7100 ptrPGE->olc_UpdateMouseState(1, false);
7101
7102 }
7103
7104 if (e->button == 1) // middle click
7105 {
7106 if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN)
7107 ptrPGE->olc_UpdateMouseState(2, true);
7108 else if (eventType == EMSCRIPTEN_EVENT_MOUSEUP)
7109 ptrPGE->olc_UpdateMouseState(2, false);
7110
7111 //at the moment only middle mouse needs to consume events.
7112 return EM_TRUE;
7113 }
7114
7115 return EM_FALSE;
7116 }
7117
7118
7119 virtual olc::rcode SetWindowTitle(const std::string& s) override
7120 { emscripten_set_window_title(s.c_str()); return olc::OK; }
7121
7122 virtual olc::rcode StartSystemEventLoop() override
7123 { return olc::OK; }
7124
7125 virtual olc::rcode HandleSystemEvent() override
7126 { return olc::OK; }
7127
7128 static void MainLoop()
7129 {
7131 if (!ptrPGE->olc_IsRunning())
7132 {
7133 if (ptrPGE->OnUserDestroy())
7134 {
7135 emscripten_cancel_main_loop();
7136 platform->ApplicationCleanUp();
7137 }
7138 else
7139 {
7140 ptrPGE->olc_Reanimate();
7141 }
7142 }
7143 }
7144 };
7145
7146 //Emscripten needs a special Start function
7147 //Much of this is usually done in EngineThread, but that isn't used here
7149 {
7150 if (platform->ApplicationStartUp() != olc::OK) return olc::FAIL;
7151
7152 // Construct the window
7153 if (platform->CreateWindowPane({ 30,30 }, vWindowSize, bFullScreen) != olc::OK) return olc::FAIL;
7154 olc_UpdateWindowSize(vWindowSize.x, vWindowSize.y);
7155
7156 // Some implementations may form an event loop here
7157 if (platform->ThreadStartUp() == olc::FAIL) return olc::FAIL;
7158
7159 // Do engine context specific initialisation
7161
7162 // Consider the "thread" started
7163 bAtomActive = true;
7164
7165 // Create user resources as part of this thread
7166 for (auto& ext : vExtensions) ext->OnBeforeUserCreate();
7167 if (!OnUserCreate()) bAtomActive = false;
7168 for (auto& ext : vExtensions) ext->OnAfterUserCreate();
7169
7170 platform->StartSystemEventLoop();
7171
7172 //This causes a heap memory corruption in Emscripten for some reason
7173 //Platform_Emscripten::bActiveRef = &bAtomActive;
7174 emscripten_set_main_loop(&Platform_Emscripten::MainLoop, 0, 1);
7175
7176 // Wait for thread to be exited
7177 if (platform->ApplicationCleanUp() != olc::OK) return olc::FAIL;
7178 return olc::OK;
7179 }
7180}
7181
7182extern "C"
7183{
7184 EMSCRIPTEN_KEEPALIVE inline void olc_PGE_UpdateWindowSize(int width, int height)
7185 {
7186 emscripten_set_canvas_element_size("#canvas", width, height);
7187 // Thanks slavka
7188 ((olc::Platform_Emscripten*)olc::platform.get())->UpdateWindowSize(width, height);
7189 }
7190}
7191
7192#endif
7193// O------------------------------------------------------------------------------O
7194// | END PLATFORM: Emscripten |
7195// O------------------------------------------------------------------------------O
7196#pragma endregion
7197
7198
7199#endif // Headless
7200
7201// O------------------------------------------------------------------------------O
7202// | olcPixelGameEngine Auto-Configuration |
7203// O------------------------------------------------------------------------------O
7204#pragma region pge_config
7205namespace olc
7206{
7208 {
7209
7210//#if !defined(OLC_PGE_HEADLESS)
7211
7212 olc::Sprite::loader = nullptr;
7213
7214#if defined(OLC_IMAGE_GDI)
7215 olc::Sprite::loader = std::make_unique<olc::ImageLoader_GDIPlus>();
7216#endif
7217
7218#if defined(OLC_IMAGE_LIBPNG)
7219 olc::Sprite::loader = std::make_unique<olc::ImageLoader_LibPNG>();
7220#endif
7221
7222#if defined(OLC_IMAGE_STB)
7223 olc::Sprite::loader = std::make_unique<olc::ImageLoader_STB>();
7224#endif
7225
7226#if defined(OLC_IMAGE_CUSTOM_EX)
7227 olc::Sprite::loader = std::make_unique<OLC_IMAGE_CUSTOM_EX>();
7228#endif
7229
7230
7231#if defined(OLC_PLATFORM_HEADLESS)
7232 platform = std::make_unique<olc::Platform_Headless>();
7233#endif
7234
7235#if defined(OLC_PLATFORM_WINAPI)
7236 platform = std::make_unique<olc::Platform_Windows>();
7237#endif
7238
7239#if defined(OLC_PLATFORM_X11)
7240 platform = std::make_unique<olc::Platform_Linux>();
7241#endif
7242
7243#if defined(OLC_PLATFORM_GLUT)
7244 platform = std::make_unique<olc::Platform_GLUT>();
7245#endif
7246
7247#if defined(OLC_PLATFORM_EMSCRIPTEN)
7248 platform = std::make_unique<olc::Platform_Emscripten>();
7249#endif
7250
7251#if defined(OLC_PLATFORM_CUSTOM_EX)
7252 platform = std::make_unique<OLC_PLATFORM_CUSTOM_EX>();
7253#endif
7254
7255#if defined(OLC_GFX_HEADLESS)
7256 renderer = std::make_unique<olc::Renderer_Headless>();
7257#endif
7258
7259#if defined(OLC_GFX_OPENGL10)
7260 renderer = std::make_unique<olc::Renderer_OGL10>();
7261#endif
7262
7263#if defined(OLC_GFX_OPENGL33)
7264 renderer = std::make_unique<olc::Renderer_OGL33>();
7265#endif
7266
7267#if defined(OLC_GFX_OPENGLES2)
7268 renderer = std::make_unique<olc::Renderer_OGLES2>();
7269#endif
7270
7271#if defined(OLC_GFX_DIRECTX10)
7272 renderer = std::make_unique<olc::Renderer_DX10>();
7273#endif
7274
7275#if defined(OLC_GFX_DIRECTX11)
7276 renderer = std::make_unique<olc::Renderer_DX11>();
7277#endif
7278
7279#if defined(OLC_GFX_CUSTOM_EX)
7280 renderer = std::make_unique<OLC_RENDERER_CUSTOM_EX>();
7281#endif
7282
7283 // Associate components with PGE instance
7284 platform->ptrPGE = this;
7285 renderer->ptrPGE = this;
7286//#else
7287// olc::Sprite::loader = nullptr;
7288// platform = nullptr;
7289// renderer = nullptr;
7290//#endif
7291 }
7292}
7293
7294#pragma endregion
7295
7296#endif // End OLC_PGE_APPLICATION
7297
7298// O------------------------------------------------------------------------------O
7299// | END OF OLC_PGE_APPLICATION |
7300// O------------------------------------------------------------------------------O
7301
Definition olcPixelGameEngine.h:1089
void UpdateSprite()
Decal(olc::Sprite *spr, bool filter=false, bool clamp=true)
virtual ~Decal()
int32_t id
Definition olcPixelGameEngine.h:1098
olc::Sprite * sprite
Definition olcPixelGameEngine.h:1099
void Update()
Decal(const uint32_t nExistingTextureResource, olc::Sprite *spr)
olc::vf2d vUVScale
Definition olcPixelGameEngine.h:1100
Definition olcPixelGameEngine.h:1034
virtual ~ImageLoader()=default
ImageLoader()=default
virtual olc::rcode LoadImageResource(olc::Sprite *spr, const std::string &sImageFile, olc::ResourcePack *pack)=0
virtual olc::rcode SaveImageResource(olc::Sprite *spr, const std::string &sImageFile)=0
Definition olcPixelGameEngine.h:1615
static PixelGameEngine * pge
Definition olcPixelGameEngine.h:1627
virtual void OnAfterUserCreate()
virtual void OnAfterUserUpdate(float fElapsedTime)
virtual void OnBeforeUserCreate()
virtual bool OnBeforeUserUpdate(float &fElapsedTime)
PGEX(bool bHook=false)
Definition olcPixelGameEngine.h:1225
void DrawCircle(const olc::vi2d &pos, int32_t radius, Pixel p=olc::WHITE, uint8_t mask=0xFF)
void FillRectDecal(const olc::vf2d &pos, const olc::vf2d &size, const olc::Pixel col=olc::WHITE)
std::string sAppName
Definition olcPixelGameEngine.h:1488
void FillTriangleDecal(const olc::vf2d &p0, const olc::vf2d &p1, const olc::vf2d &p2, const olc::Pixel col=olc::WHITE)
void FillTriangle(const olc::vi2d &pos1, const olc::vi2d &pos2, const olc::vi2d &pos3, Pixel p=olc::WHITE)
const olc::vi2d & GetWindowSize() const
void SetDecalStructure(const olc::DecalStructure &structure)
void DrawPolygonDecal(olc::Decal *decal, const std::vector< olc::vf2d > &pos, const std::vector< olc::vf2d > &uv, const std::vector< olc::Pixel > &tint)
void SetLayerOffset(uint8_t layer, const olc::vf2d &offset)
bool ClipLineToScreen(olc::vi2d &in_p1, olc::vi2d &in_p2)
void GradientFillRectDecal(const olc::vf2d &pos, const olc::vf2d &size, const olc::Pixel colTL, const olc::Pixel colBL, const olc::Pixel colBR, const olc::Pixel colTR)
void DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p=olc::WHITE, uint32_t pattern=0xFFFFFFFF)
void DrawStringProp(const olc::vi2d &pos, const std::string &sText, Pixel col=olc::WHITE, uint32_t scale=1)
void FillCircle(const olc::vi2d &pos, int32_t radius, Pixel p=olc::WHITE)
void DrawPolygonDecal(olc::Decal *decal, const std::vector< olc::vf2d > &pos, const std::vector< float > &depth, const std::vector< olc::vf2d > &uv, const std::vector< olc::Pixel > &colours, const olc::Pixel tint)
void DrawPartialDecal(const olc::vf2d &pos, const olc::vf2d &size, olc::Decal *decal, const olc::vf2d &source_pos, const olc::vf2d &source_size, const olc::Pixel &tint=olc::WHITE)
void DrawStringProp(int32_t x, int32_t y, const std::string &sText, Pixel col=olc::WHITE, uint32_t scale=1)
void EnableLayer(uint8_t layer, bool b)
void olc_DropFiles(int32_t x, int32_t y, const std::vector< std::string > &vFiles)
void DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p=olc::WHITE)
std::vector< LayerDesc > & GetLayers()
void DrawExplicitDecal(olc::Decal *decal, const olc::vf2d *pos, const olc::vf2d *uv, const olc::Pixel *col, uint32_t elements=4)
HWButton GetKey(Key k) const
void SetDecalMode(const olc::DecalMode &mode)
void DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p=olc::WHITE)
void DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p=olc::WHITE, uint8_t mask=0xFF)
int32_t GetMouseX() const
const olc::vi2d & GetDroppedFilesPoint() const
int32_t TextEntryGetCursor() const
virtual bool OnConsoleCommand(const std::string &sCommand)
void SetLayerScale(uint8_t layer, float x, float y)
void DrawPolygonDecal(olc::Decal *decal, const std::vector< olc::vf2d > &pos, const std::vector< olc::vf2d > &uv, const olc::Pixel tint=olc::WHITE)
void SetLayerCustomRenderFunction(uint8_t layer, std::function< void()> f)
virtual ~PixelGameEngine()
int32_t GetDrawTargetWidth() const
void DrawRectDecal(const olc::vf2d &pos, const olc::vf2d &size, const olc::Pixel col=olc::WHITE)
void FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p=olc::WHITE)
void pgex_Register(olc::PGEX *pgex)
int32_t GetDrawTargetHeight() const
void olc_UpdateWindowSize(int32_t x, int32_t y)
olc::Sprite * GetDrawTarget() const
void DrawWarpedDecal(olc::Decal *decal, const std::array< olc::vf2d, 4 > &pos, const olc::Pixel &tint=olc::WHITE)
void TextEntryEnable(const bool bEnable, const std::string &sText="")
void olc_UpdateMouseState(int32_t button, bool state)
void DrawPartialWarpedDecal(olc::Decal *decal, const olc::vf2d *pos, const olc::vf2d &source_pos, const olc::vf2d &source_size, const olc::Pixel &tint=olc::WHITE)
const olc::vi2d & GetScreenSize() const
void DrawDecal(const olc::vf2d &pos, olc::Decal *decal, const olc::vf2d &scale={ 1.0f, 1.0f }, const olc::Pixel &tint=olc::WHITE)
void DrawSprite(int32_t x, int32_t y, Sprite *sprite, uint32_t scale=1, uint8_t flip=olc::Sprite::NONE)
std::stringstream & ConsoleOut()
void olc_UpdateKeyState(int32_t key, bool state)
void DrawWarpedDecal(olc::Decal *decal, const olc::vf2d(&pos)[4], const olc::Pixel &tint=olc::WHITE)
void DrawStringDecal(const olc::vf2d &pos, const std::string &sText, const Pixel col=olc::WHITE, const olc::vf2d &scale={ 1.0f, 1.0f })
virtual bool OnUserCreate()
void FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p=olc::WHITE)
void olc_UpdateMouse(int32_t x, int32_t y)
virtual void OnTextEntryComplete(const std::string &sText)
void DrawPolygonDecal(olc::Decal *decal, const std::vector< olc::vf2d > &pos, const std::vector< float > &depth, const std::vector< olc::vf2d > &uv, const olc::Pixel tint=olc::WHITE)
void SetDrawTarget(Sprite *target)
void olc_UpdateKeyFocus(bool state)
olc::rcode SetWindowSize(const olc::vi2d &vPos, const olc::vi2d &vSize)
void DrawStringPropDecal(const olc::vf2d &pos, const std::string &sText, const Pixel col=olc::WHITE, const olc::vf2d &scale={ 1.0f, 1.0f })
void DrawPartialWarpedDecal(olc::Decal *decal, const olc::vf2d(&pos)[4], const olc::vf2d &source_pos, const olc::vf2d &source_size, const olc::Pixel &tint=olc::WHITE)
virtual void olc_ConfigureSystem()
void SetLayerTint(uint8_t layer, const olc::Pixel &tint)
const olc::vi2d & GetWindowMouse() const
void ConsoleShow(const olc::Key &keyExit, bool bSuspendTime=true)
const olc::vi2d & GetMousePos() const
uint32_t GetFPS() const
void DrawPartialDecal(const olc::vf2d &pos, olc::Decal *decal, const olc::vf2d &source_pos, const olc::vf2d &source_size, const olc::vf2d &scale={ 1.0f, 1.0f }, const olc::Pixel &tint=olc::WHITE)
int32_t GetMouseY() const
olc::rcode Start()
bool IsFocused() const
const olc::vi2d & GetScreenPixelSize() const
const std::vector< std::string > & GetDroppedFiles() const
void GradientTriangleDecal(const olc::vf2d &p0, const olc::vf2d &p1, const olc::vf2d &p2, const olc::Pixel c0, const olc::Pixel c1, const olc::Pixel c2)
virtual bool Draw(int32_t x, int32_t y, Pixel p=olc::WHITE)
int32_t GetMouseWheel() const
void SetPixelMode(std::function< olc::Pixel(const int x, const int y, const olc::Pixel &pSource, const olc::Pixel &pDest)> pixelMode)
bool IsConsoleShowing() const
void SetLayerOffset(uint8_t layer, float x, float y)
void DrawLineDecal(const olc::vf2d &pos1, const olc::vf2d &pos2, Pixel p=olc::WHITE)
olc::rcode ShowWindowFrame(const bool bShowFrame)
void olc_UpdateMouseWheel(int32_t delta)
int32_t ScreenWidth() const
void DrawRotatedStringDecal(const olc::vf2d &pos, const std::string &sText, const float fAngle, const olc::vf2d &center={ 0.0f, 0.0f }, const olc::Pixel col=olc::WHITE, const olc::vf2d &scale={ 1.0f, 1.0f })
olc::vi2d GetTextSize(const std::string &s)
olc::rcode Construct(int32_t screen_w, int32_t screen_h, int32_t pixel_w, int32_t pixel_h, bool full_screen=false, bool vsync=false, bool cohesion=false, bool realwindow=false)
void DrawPartialWarpedDecal(olc::Decal *decal, const std::array< olc::vf2d, 4 > &pos, const olc::vf2d &source_pos, const olc::vf2d &source_size, const olc::Pixel &tint=olc::WHITE)
void DrawPartialRotatedDecal(const olc::vf2d &pos, olc::Decal *decal, const float fAngle, const olc::vf2d &center, const olc::vf2d &source_pos, const olc::vf2d &source_size, const olc::vf2d &scale={ 1.0f, 1.0f }, const olc::Pixel &tint=olc::WHITE)
void DrawTriangle(const olc::vi2d &pos1, const olc::vi2d &pos2, const olc::vi2d &pos3, Pixel p=olc::WHITE)
void SetPixelBlend(float fBlend)
olc::vi2d GetTextSizeProp(const std::string &s)
void olc_UpdateMouseFocus(bool state)
void DrawPartialSprite(int32_t x, int32_t y, Sprite *sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale=1, uint8_t flip=olc::Sprite::NONE)
std::string TextEntryGetString() const
void adv_FlushLayer(const size_t nLayerID)
void DrawRotatedDecal(const olc::vf2d &pos, olc::Decal *decal, const float fAngle, const olc::vf2d &center={ 0.0f, 0.0f }, const olc::vf2d &scale={ 1.0f, 1.0f }, const olc::Pixel &tint=olc::WHITE)
void EnablePixelTransfer(const bool bEnable=true)
bool IsTextEntryEnabled() const
int32_t ScreenHeight() const
void SetScreenSize(int w, int h)
HWButton GetMouse(uint32_t b) const
void DrawLine(const olc::vi2d &pos1, const olc::vi2d &pos2, Pixel p=olc::WHITE, uint32_t pattern=0xFFFFFFFF)
void DrawString(int32_t x, int32_t y, const std::string &sText, Pixel col=olc::WHITE, uint32_t scale=1)
void DrawPolygonDecal(olc::Decal *decal, const std::vector< olc::vf2d > &pos, const std::vector< olc::vf2d > &uv, const std::vector< olc::Pixel > &colours, const olc::Pixel tint)
void DrawRect(const olc::vi2d &pos, const olc::vi2d &size, Pixel p=olc::WHITE)
const olc::vi2d & GetWindowPos() const
void SetDrawTarget(uint8_t layer, bool bDirty=true)
void FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p=olc::WHITE)
Pixel::Mode GetPixelMode()
virtual bool OnUserDestroy()
bool Draw(const olc::vi2d &pos, Pixel p=olc::WHITE)
static const std::map< size_t, uint8_t > & GetKeyMap()
Definition olcPixelGameEngine.h:1266
void adv_FlushLayerDecals(const size_t nLayerID)
void adv_ManualRenderEnable(const bool bEnable)
void DrawSprite(const olc::vi2d &pos, Sprite *sprite, uint32_t scale=1, uint8_t flip=olc::Sprite::NONE)
olc::Sprite * GetFontSprite()
void FillTexturedTriangle(std::vector< olc::vf2d > vPoints, std::vector< olc::vf2d > vTex, std::vector< olc::Pixel > vColour, olc::Sprite *sprTex)
void DrawString(const olc::vi2d &pos, const std::string &sText, Pixel col=olc::WHITE, uint32_t scale=1)
uint32_t CreateLayer()
void FillRect(const olc::vi2d &pos, const olc::vi2d &size, Pixel p=olc::WHITE)
void SetPixelMode(Pixel::Mode m)
void ConsoleCaptureStdOut(const bool bCapture)
void FillTexturedPolygon(const std::vector< olc::vf2d > &vPoints, const std::vector< olc::vf2d > &vTex, const std::vector< olc::Pixel > &vColour, olc::Sprite *sprTex, olc::DecalStructure structure=olc::DecalStructure::LIST)
void DrawWarpedDecal(olc::Decal *decal, const olc::vf2d *pos, const olc::Pixel &tint=olc::WHITE)
void Clear(Pixel p)
void DrawPartialSprite(const olc::vi2d &pos, Sprite *sprite, const olc::vi2d &sourcepos, const olc::vi2d &size, uint32_t scale=1, uint8_t flip=olc::Sprite::NONE)
void ClearBuffer(Pixel p, bool bDepth=true)
const olc::vi2d & GetPixelSize() const
float GetElapsedTime() const
void SetLayerScale(uint8_t layer, const olc::vf2d &scale)
virtual bool OnUserUpdate(float fElapsedTime)
void olc_UpdateWindowPos(int32_t x, int32_t y)
void adv_HardwareClip(const bool bScale, const olc::vi2d &viewPos, const olc::vi2d &viewSize, const bool bClear=false)
void DrawRotatedStringPropDecal(const olc::vf2d &pos, const std::string &sText, const float fAngle, const olc::vf2d &center={ 0.0f, 0.0f }, const olc::Pixel col=olc::WHITE, const olc::vf2d &scale={ 1.0f, 1.0f })
Definition olcPixelGameEngine.h:1197
virtual olc::rcode ThreadCleanUp()=0
virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d &vViewPos, const olc::vi2d &vViewSize)=0
virtual ~Platform()=default
static olc::PixelGameEngine * ptrPGE
Definition olcPixelGameEngine.h:1211
virtual olc::rcode SetWindowSize(const olc::vi2d &vWindowPos, const olc::vi2d &vWindowSize)=0
virtual olc::rcode CreateWindowPane(const olc::vi2d &vWindowPos, olc::vi2d &vWindowSize, bool bFullScreen)=0
virtual olc::rcode ApplicationStartUp()=0
virtual olc::rcode SetWindowTitle(const std::string &s)=0
virtual olc::rcode HandleSystemEvent()=0
virtual olc::rcode ShowWindowFrame(const bool bShowFrame=true)=0
virtual olc::rcode ThreadStartUp()=0
virtual olc::rcode ApplicationCleanUp()=0
virtual olc::rcode StartSystemEventLoop()=0
Definition olcPixelGameEngine.h:1125
Renderable & operator=(Renderable &&r)=default
Renderable(const Renderable &)=delete
void Create(uint32_t width, uint32_t height, bool filter=false, bool clamp=true)
Renderable(Renderable &&r)=default
olc::rcode Load(const std::string &sFile, ResourcePack *pack=nullptr, bool filter=false, bool clamp=true)
olc::Sprite * Sprite() const
olc::Decal * Decal() const
Renderable()=default
Definition olcPixelGameEngine.h:1175
virtual void PrepareDrawing()=0
virtual void ApplyTexture(uint32_t id)=0
virtual void UpdateTexture(uint32_t id, olc::Sprite *spr)=0
virtual olc::rcode CreateDevice(std::vector< void * > params, bool bFullScreen, bool bVSYNC)=0
virtual olc::rcode DestroyDevice()=0
virtual void DrawLayerQuad(const olc::vf2d &offset, const olc::vf2d &scale, const olc::Pixel tint)=0
virtual void DisplayFrame()=0
virtual void PrepareDevice()=0
virtual ~Renderer()=default
static olc::PixelGameEngine * ptrPGE
Definition olcPixelGameEngine.h:1193
virtual void ClearBuffer(olc::Pixel p, bool bDepth)=0
virtual void ReadTexture(uint32_t id, olc::Sprite *spr)=0
virtual void UpdateViewport(const olc::vi2d &pos, const olc::vi2d &size)=0
virtual void DrawDecal(const olc::DecalInstance &decal)=0
virtual uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered=false, const bool clamp=true)=0
virtual void SetDecalMode(const olc::DecalMode &mode)=0
virtual uint32_t DeleteTexture(const uint32_t id)=0
Definition olcPixelGameEngine.h:1015
bool LoadPack(const std::string &sFile, const std::string &sKey)
bool AddFile(const std::string &sFile)
ResourceBuffer GetFileBuffer(const std::string &sFile)
bool SavePack(const std::string &sFile, const std::string &sKey)
Definition olcPixelGameEngine.h:1047
static std::unique_ptr< olc::ImageLoader > loader
Definition olcPixelGameEngine.h:1082
Pixel SampleBL(const olc::vf2d &uv) const
Pixel GetPixel(const olc::vi2d &a) const
bool SetPixel(int32_t x, int32_t y, Pixel p)
olc::Sprite * Duplicate(const olc::vi2d &vPos, const olc::vi2d &vSize)
Sprite(int32_t w, int32_t h)
olc::Sprite * Duplicate()
void SetSize(int32_t w, int32_t h)
Sprite(const olc::Sprite &)=delete
Pixel SampleBL(float u, float v) const
Pixel * GetData()
Mode
Definition olcPixelGameEngine.h:1061
@ NORMAL
Definition olcPixelGameEngine.h:1061
@ PERIODIC
Definition olcPixelGameEngine.h:1061
@ CLAMP
Definition olcPixelGameEngine.h:1061
void SetSampleMode(olc::Sprite::Mode mode=olc::Sprite::Mode::NORMAL)
Pixel GetPixel(int32_t x, int32_t y) const
Pixel Sample(float x, float y) const
int32_t height
Definition olcPixelGameEngine.h:1060
Pixel Sample(const olc::vf2d &uv) const
Mode modeSample
Definition olcPixelGameEngine.h:1080
olc::vi2d Size() const
Flip
Definition olcPixelGameEngine.h:1062
@ HORIZ
Definition olcPixelGameEngine.h:1062
@ NONE
Definition olcPixelGameEngine.h:1062
@ VERT
Definition olcPixelGameEngine.h:1062
Sprite(const std::string &sImageFile, olc::ResourcePack *pack=nullptr)
std::vector< olc::Pixel > pColData
Definition olcPixelGameEngine.h:1079
olc::rcode LoadFromFile(const std::string &sImageFile, olc::ResourcePack *pack=nullptr)
bool SetPixel(const olc::vi2d &a, Pixel p)
int32_t width
Definition olcPixelGameEngine.h:1059
Definition olcPixelGameEngine.h:593
Pixel PixelF(float red, float green, float blue, float alpha=1.0f)
constexpr bool operator<(const v_2d< TL > &lhs, const v_2d< TR > &rhs)
Definition olcPixelGameEngine.h:872
v_2d< float > vf2d
Definition olcPixelGameEngine.h:894
constexpr uint32_t nDefaultPixel
Definition olcPixelGameEngine.h:914
constexpr auto operator/=(v_2d< TL > &lhs, const TR &rhs)
Definition olcPixelGameEngine.h:791
static const Pixel VERY_DARK_YELLOW(64, 64, 0)
static const Pixel VERY_DARK_MAGENTA(64, 0, 64)
static const Pixel BLACK(0, 0, 0)
constexpr auto operator/(const TL &lhs, const v_2d< TR > &rhs)
Definition olcPixelGameEngine.h:773
DecalStructure
Definition olcPixelGameEngine.h:1114
Pixel PixelLerp(const olc::Pixel &p1, const olc::Pixel &p2, float t)
static const Pixel VERY_DARK_GREEN(0, 64, 0)
constexpr auto operator*(const TL &lhs, const v_2d< TR > &rhs)
Definition olcPixelGameEngine.h:747
static const Pixel GREEN(0, 255, 0)
static const Pixel DARK_YELLOW(128, 128, 0)
rcode
Definition olcPixelGameEngine.h:917
@ OK
Definition olcPixelGameEngine.h:917
@ FAIL
Definition olcPixelGameEngine.h:917
@ NO_FILE
Definition olcPixelGameEngine.h:917
static const Pixel CYAN(0, 255, 255)
static const Pixel VERY_DARK_BLUE(0, 0, 64)
constexpr auto operator-=(v_2d< TL > &lhs, const TR &rhs)
Definition olcPixelGameEngine.h:864
constexpr std::ostream & operator<<(std::ostream &os, const v_2d< T > &rhs)
Definition olcPixelGameEngine.h:885
constexpr auto operator+=(v_2d< TL > &lhs, const TR &rhs)
Definition olcPixelGameEngine.h:824
constexpr auto operator+(const v_2d< T > &lhs)
Definition olcPixelGameEngine.h:799
v_2d< uint32_t > vu2d
Definition olcPixelGameEngine.h:893
constexpr uint8_t nTabSizeInSpaces
Definition olcPixelGameEngine.h:915
v_2d< double > vd2d
Definition olcPixelGameEngine.h:895
static const Pixel YELLOW(255, 255, 0)
static const Pixel DARK_GREY(128, 128, 128)
v_2d< int32_t > vi2d
Definition olcPixelGameEngine.h:892
static const Pixel DARK_RED(128, 0, 0)
static const Pixel VERY_DARK_RED(64, 0, 0)
constexpr size_t OLC_MAX_VERTS
Definition olcPixelGameEngine.h:916
constexpr auto operator*=(v_2d< TL > &lhs, const TR &rhs)
Definition olcPixelGameEngine.h:765
constexpr auto operator-(const v_2d< T > &lhs)
Definition olcPixelGameEngine.h:839
static const Pixel VERY_DARK_GREY(64, 64, 64)
static const Pixel DARK_CYAN(0, 128, 128)
Key
Definition olcPixelGameEngine.h:972
@ S
Definition olcPixelGameEngine.h:974
@ NP5
Definition olcPixelGameEngine.h:980
@ PGUP
Definition olcPixelGameEngine.h:978
@ PAUSE
Definition olcPixelGameEngine.h:979
@ F6
Definition olcPixelGameEngine.h:976
@ K
Definition olcPixelGameEngine.h:974
@ NP0
Definition olcPixelGameEngine.h:980
@ V
Definition olcPixelGameEngine.h:974
@ F1
Definition olcPixelGameEngine.h:976
@ G
Definition olcPixelGameEngine.h:974
@ PERIOD
Definition olcPixelGameEngine.h:981
@ F2
Definition olcPixelGameEngine.h:976
@ H
Definition olcPixelGameEngine.h:974
@ X
Definition olcPixelGameEngine.h:974
@ HOME
Definition olcPixelGameEngine.h:978
@ P
Definition olcPixelGameEngine.h:974
@ UP
Definition olcPixelGameEngine.h:977
@ NP_DECIMAL
Definition olcPixelGameEngine.h:981
@ K0
Definition olcPixelGameEngine.h:975
@ F9
Definition olcPixelGameEngine.h:976
@ ENTER
Definition olcPixelGameEngine.h:979
@ K1
Definition olcPixelGameEngine.h:975
@ K5
Definition olcPixelGameEngine.h:975
@ ENUM_END
Definition olcPixelGameEngine.h:984
@ BACK
Definition olcPixelGameEngine.h:979
@ OEM_1
Definition olcPixelGameEngine.h:983
@ F4
Definition olcPixelGameEngine.h:976
@ OEM_7
Definition olcPixelGameEngine.h:983
@ A
Definition olcPixelGameEngine.h:974
@ NP4
Definition olcPixelGameEngine.h:980
@ SCROLL
Definition olcPixelGameEngine.h:979
@ NP8
Definition olcPixelGameEngine.h:980
@ J
Definition olcPixelGameEngine.h:974
@ MINUS
Definition olcPixelGameEngine.h:982
@ SHIFT
Definition olcPixelGameEngine.h:978
@ L
Definition olcPixelGameEngine.h:974
@ LEFT
Definition olcPixelGameEngine.h:977
@ RETURN
Definition olcPixelGameEngine.h:979
@ DOWN
Definition olcPixelGameEngine.h:977
@ CAPS_LOCK
Definition olcPixelGameEngine.h:984
@ END
Definition olcPixelGameEngine.h:978
@ NP9
Definition olcPixelGameEngine.h:980
@ NONE
Definition olcPixelGameEngine.h:973
@ F3
Definition olcPixelGameEngine.h:976
@ RIGHT
Definition olcPixelGameEngine.h:977
@ DEL
Definition olcPixelGameEngine.h:978
@ F
Definition olcPixelGameEngine.h:974
@ Y
Definition olcPixelGameEngine.h:974
@ U
Definition olcPixelGameEngine.h:974
@ K8
Definition olcPixelGameEngine.h:975
@ INS
Definition olcPixelGameEngine.h:978
@ Q
Definition olcPixelGameEngine.h:974
@ D
Definition olcPixelGameEngine.h:974
@ R
Definition olcPixelGameEngine.h:974
@ Z
Definition olcPixelGameEngine.h:974
@ NP2
Definition olcPixelGameEngine.h:980
@ O
Definition olcPixelGameEngine.h:974
@ K6
Definition olcPixelGameEngine.h:975
@ K7
Definition olcPixelGameEngine.h:975
@ B
Definition olcPixelGameEngine.h:974
@ SPACE
Definition olcPixelGameEngine.h:978
@ K9
Definition olcPixelGameEngine.h:975
@ T
Definition olcPixelGameEngine.h:974
@ NP1
Definition olcPixelGameEngine.h:980
@ F12
Definition olcPixelGameEngine.h:976
@ OEM_4
Definition olcPixelGameEngine.h:983
@ EQUALS
Definition olcPixelGameEngine.h:982
@ C
Definition olcPixelGameEngine.h:974
@ NP3
Definition olcPixelGameEngine.h:980
@ K4
Definition olcPixelGameEngine.h:975
@ NP_SUB
Definition olcPixelGameEngine.h:981
@ PGDN
Definition olcPixelGameEngine.h:978
@ K2
Definition olcPixelGameEngine.h:975
@ OEM_8
Definition olcPixelGameEngine.h:983
@ N
Definition olcPixelGameEngine.h:974
@ F5
Definition olcPixelGameEngine.h:976
@ F8
Definition olcPixelGameEngine.h:976
@ K3
Definition olcPixelGameEngine.h:975
@ F11
Definition olcPixelGameEngine.h:976
@ OEM_3
Definition olcPixelGameEngine.h:983
@ F10
Definition olcPixelGameEngine.h:976
@ W
Definition olcPixelGameEngine.h:974
@ I
Definition olcPixelGameEngine.h:974
@ ESCAPE
Definition olcPixelGameEngine.h:979
@ F7
Definition olcPixelGameEngine.h:976
@ E
Definition olcPixelGameEngine.h:974
@ OEM_2
Definition olcPixelGameEngine.h:983
@ NP6
Definition olcPixelGameEngine.h:980
@ OEM_5
Definition olcPixelGameEngine.h:983
@ NP_MUL
Definition olcPixelGameEngine.h:981
@ COMMA
Definition olcPixelGameEngine.h:982
@ CTRL
Definition olcPixelGameEngine.h:978
@ NP_DIV
Definition olcPixelGameEngine.h:981
@ TAB
Definition olcPixelGameEngine.h:978
@ NP_ADD
Definition olcPixelGameEngine.h:981
@ OEM_6
Definition olcPixelGameEngine.h:983
@ M
Definition olcPixelGameEngine.h:974
@ NP7
Definition olcPixelGameEngine.h:980
static const Pixel DARK_MAGENTA(128, 0, 128)
constexpr uint8_t nMouseButtons
Definition olcPixelGameEngine.h:912
static const Pixel DARK_GREEN(0, 128, 0)
static const Pixel BLUE(0, 0, 255)
static const Pixel DARK_BLUE(0, 0, 128)
static const Pixel BLANK(0, 0, 0, 0)
static const Pixel RED(255, 0, 0)
static const Pixel MAGENTA(255, 0, 255)
constexpr uint8_t nDefaultAlpha
Definition olcPixelGameEngine.h:913
static const Pixel WHITE(255, 255, 255)
DecalMode
Definition olcPixelGameEngine.h:1104
static const Pixel VERY_DARK_CYAN(0, 64, 64)
constexpr bool operator>(const v_2d< TL > &lhs, const v_2d< TR > &rhs)
Definition olcPixelGameEngine.h:878
#define UNUSED(x)
Definition olcPixelGameEngine.h:461
#define olcT(s)
Definition olcPixelGameEngine.h:458
Definition olcPixelGameEngine.h:1148
olc::DecalStructure structure
Definition olcPixelGameEngine.h:1156
std::vector< olc::Pixel > tint
Definition olcPixelGameEngine.h:1154
std::vector< float > z
Definition olcPixelGameEngine.h:1153
std::vector< float > w
Definition olcPixelGameEngine.h:1152
bool depth
Definition olcPixelGameEngine.h:1158
olc::DecalMode mode
Definition olcPixelGameEngine.h:1155
std::vector< olc::vf2d > uv
Definition olcPixelGameEngine.h:1151
std::vector< olc::vf2d > pos
Definition olcPixelGameEngine.h:1150
uint32_t points
Definition olcPixelGameEngine.h:1157
olc::Decal * decal
Definition olcPixelGameEngine.h:1149
Definition olcPixelGameEngine.h:998
bool bPressed
Definition olcPixelGameEngine.h:999
bool bReleased
Definition olcPixelGameEngine.h:1000
bool bHeld
Definition olcPixelGameEngine.h:1001
Definition olcPixelGameEngine.h:1162
olc::vf2d vOffset
Definition olcPixelGameEngine.h:1163
std::function< void()> funcHook
Definition olcPixelGameEngine.h:1171
bool bUpdate
Definition olcPixelGameEngine.h:1166
olc::Renderable pDrawTarget
Definition olcPixelGameEngine.h:1167
uint32_t nResID
Definition olcPixelGameEngine.h:1168
olc::vf2d vScale
Definition olcPixelGameEngine.h:1164
std::vector< DecalInstance > vecDecalInstance
Definition olcPixelGameEngine.h:1169
bool bShow
Definition olcPixelGameEngine.h:1165
olc::Pixel tint
Definition olcPixelGameEngine.h:1170
Definition olcPixelGameEngine.h:924
Pixel & operator-=(const Pixel &p)
uint8_t g
Definition olcPixelGameEngine.h:928
Pixel operator*(const float i) const
Pixel operator-(const Pixel &p) const
Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha=nDefaultAlpha)
uint8_t a
Definition olcPixelGameEngine.h:928
bool operator==(const Pixel &p) const
Pixel & operator=(const Pixel &v)=default
Pixel operator/(const float i) const
uint8_t b
Definition olcPixelGameEngine.h:928
Pixel inv() const
uint8_t r
Definition olcPixelGameEngine.h:928
uint32_t n
Definition olcPixelGameEngine.h:927
Pixel & operator+=(const Pixel &p)
Pixel & operator*=(const float i)
Pixel operator+(const Pixel &p) const
Pixel(uint32_t p)
Pixel & operator/=(const float i)
Mode
Definition olcPixelGameEngine.h:931
@ MASK
Definition olcPixelGameEngine.h:931
@ ALPHA
Definition olcPixelGameEngine.h:931
@ NORMAL
Definition olcPixelGameEngine.h:931
@ CUSTOM
Definition olcPixelGameEngine.h:931
bool operator!=(const Pixel &p) const
Definition olcPixelGameEngine.h:1009
std::vector< char > vMemory
Definition olcPixelGameEngine.h:1011
ResourceBuffer(std::ifstream &ifs, uint32_t offset, uint32_t size)
Definition olcPixelGameEngine.h:600
constexpr v_2d clamp(const v_2d &v1, const v_2d &v2) const
Definition olcPixelGameEngine.h:702
T x
Definition olcPixelGameEngine.h:604
constexpr auto cross(const v_2d &rhs) const
Definition olcPixelGameEngine.h:684
T y
Definition olcPixelGameEngine.h:606
constexpr v_2d & operator=(const v_2d &v)=default
constexpr v_2d lerp(const v_2d &v1, const double t) const
Definition olcPixelGameEngine.h:708
constexpr auto dot(const v_2d &rhs) const
Definition olcPixelGameEngine.h:678
constexpr T mag2() const
Definition olcPixelGameEngine.h:635
v_2d norm() const
Definition olcPixelGameEngine.h:641
constexpr bool operator!=(const v_2d &rhs) const
Definition olcPixelGameEngine.h:720
std::string str() const
Definition olcPixelGameEngine.h:726
constexpr auto area() const
Definition olcPixelGameEngine.h:623
constexpr v_2d polar() const
Definition olcPixelGameEngine.h:696
constexpr v_2d(T _x, T _y)
Definition olcPixelGameEngine.h:612
constexpr v_2d()=default
constexpr v_2d min(const v_2d &v) const
Definition olcPixelGameEngine.h:672
constexpr v_2d(const v_2d &v)=default
constexpr bool operator==(const v_2d &rhs) const
Definition olcPixelGameEngine.h:714
constexpr v_2d max(const v_2d &v) const
Definition olcPixelGameEngine.h:666
constexpr v_2d ceil() const
Definition olcPixelGameEngine.h:660
constexpr v_2d reflect(const v_2d &n) const
Definition olcPixelGameEngine.h:732
constexpr v_2d perp() const
Definition olcPixelGameEngine.h:648
constexpr v_2d floor() const
Definition olcPixelGameEngine.h:654
constexpr v_2d cart() const
Definition olcPixelGameEngine.h:690
auto mag() const
Definition olcPixelGameEngine.h:629