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