Version 1.14

+ Static GDI initialiser for windows
+ 2D vector type
+ Sampling texels Accurately
+ Normalised mouse position
+ Pre-cache mouse position before frame update
+ Mouse wheel access
pull/113/head
Javidx9 6 years ago committed by GitHub
parent 35acfcd278
commit b3f124affd
  1. 392
      olcPixelGameEngine.h

@ -2,83 +2,73 @@
olcPixelGameEngine.h olcPixelGameEngine.h
+-------------------------------------------------------------+ +-------------------------------------------------------------+
| OneLoneCoder Pixel Game Engine v1.13 | | OneLoneCoder Pixel Game Engine v1.14 |
| "Like the command prompt console one, but not..." - javidx9 | | "Like the command prompt console one, but not..." - javidx9 |
+-------------------------------------------------------------+ +-------------------------------------------------------------+
What is this? What is this?
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
The olcConsoleGameEngine has been a surprsing and wonderful The olcConsoleGameEngine has been a surprising and wonderful success for me,
success for me, and I'm delighted how people have reacted so and I'm delighted how people have reacted so positively towards it, so thanks
positively towards it, so thanks for that. for that.
However, there are limitations that I simply cannot avoid. However, there are limitations that I simply cannot avoid. Firstly, I need to
Firstly, I need to maintain several different versions of maintain several different versions of it to accommodate users on Windows7,
it to accommodate users on Windows7, 8, 10, Linux, Mac, 8, 10, Linux, Mac, Visual Studio & Code::Blocks. Secondly, this year I've been
Visual Studio & Code::Blocks. Secondly, this year I've been pushing the console to the limits of its graphical capabilities and the effect
pushing the console to the limits of its graphical capabilities is becoming underwhelming. The engine itself is not slow at all, but the process
and the effect is becoming underwhelming. The engine itself that Windows uses to draw the command prompt to the screen is, and worse still,
is not slow at all, but the process that Windows uses to it's dynamic based upon the variation of character colours and glyphs. Sadly
draw the command prompt to the screen is, and worse still, I have no control over this, and recent videos that are extremely graphical
it's dynamic based upon the variation of character colours (for a command prompt :P ) have been dipping to unacceptable framerates. As
and glyphs. Sadly I have no control over this, and recent the channel has been popular with aspiring game developers, I'm concerned that
videos that are extremely graphical (for a command prompt :P ) the visual appeal of the command prompt is perhaps limited to us oldies, and I
have been dipping to unacceptable framerates. As the channel dont want to alienate younger learners. Finally, I'd like to demonstrate many
has been popular with aspiring game developers, I'm concerned more algorithms and image processing that exist in the graphical domain, for
that the visual appeal of the command prompt is perhaps which the console is insufficient.
limited to us oldies, and I dont want to alienate younger
learners. Finally, I'd like to demonstrate many more For this reason, I have created olcPixelGameEngine! The look and feel to the
algorithms and image processing that exist in the graphical programmer is almost identical, so all of my existing code from the videos is
domain, for which the console is insufficient. easily portable, and the programmer uses this file in exactly the same way. But
I've decided that rather than just build a command prompt emulator, that I
For this reason, I have created olcPixelGameEngine! The look would at least harness some modern(ish) portable technologies.
and feel to the programmer is almost identical, so all of my
existing code from the videos is easily portable, and the As a result, the olcPixelGameEngine supports 32-bit colour, is written in a
programmer uses this file in exactly the same way. But I've cross-platform style, uses modern(ish) C++ conventions and most importantly,
decided that rather than just build a command prompt emulator, renders much much faster. I will use this version when my applications are
that I would at least harness some modern(ish) portable predominantly graphics based, but use the console version when they are
technologies. predominantly text based - Don't worry, loads more command prompt silliness to
come yet, but evolution is important!!
As a result, the olcPixelGameEngine supports 32-bit colour, is
written in a cross-platform style, uses modern(ish) C++
conventions and most importantly, renders much much faster. I
will use this version when my applications are predominantly
graphics based, but use the console version when they are
predominantly text based - Don't worry, loads more command
prompt silliness to come yet, but evolution is important!!
License (OLC-3) License (OLC-3)
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
Copyright 2018 - 2019 OneLoneCoder.com Copyright 2018 - 2019 OneLoneCoder.com
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without modification,
modification, are permitted provided that the following conditions are permitted provided that the following conditions are met:
are met:
1. Redistributions or derivations of source code must retain the above copyright
1. Redistributions or derivations of source code must retain the above notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
2. Redistributions or derivative works in binary form must reproduce copyright notice. This list of conditions and the following disclaimer must be
the above copyright notice. This list of conditions and the following reproduced in the documentation and/or other materials provided with the distribution.
disclaimer must be reproduced in the documentation and/or other
materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
3. Neither the name of the copyright holder nor the names of its prior written permission.
contributors may be used to endorse or promote products derived
from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY SUCH DAMAGE.
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Links Links
~~~~~ ~~~~~
@ -116,17 +106,25 @@
in your build options, and add to your linker the following libraries: in your build options, and add to your linker the following libraries:
user32 gdi32 opengl32 gdiplus user32 gdi32 opengl32 gdiplus
Ports
~~~~~
olc::PixelGameEngine has been ported and tested with varying degrees of
success to: WinXP, Win7, Win8, Win10, Various Linux, Rapberry Pi,
Chromebook, Playstation Portable (PSP) and Nintendo Switch. If you are
interested in the details of these ports, come and visit the Discord!
Thanks Thanks
~~~~~~ ~~~~~~
I'd like to extend thanks to Eremiell, slavka, gurkanctn, Phantim, I'd like to extend thanks to Eremiell, slavka, gurkanctn, Phantim,
JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice
Ralakus, Gorbit99, raoul & MagetzUb for advice, ideas and testing, and I'd like Ralakus, Gorbit99, raoul, joshinils & MagetzUb for advice, ideas and
to extend my appreciation to the 23K YouTube followers and 1.5K Discord server testing, and I'd like to extend my appreciation to the 36K YouTube followers
members who give me the motivation to keep going with all this :D and 2.3K Discord server members who give me the motivation to keep
going with all this :D
Special thanks to those who bring gifts! Special thanks to those who bring gifts!
GnarGnarHead.......Domina GnarGnarHead.......Domina
Gorbit99...........Bastion Gorbit99...........Bastion, Ori & The Blind Forest
Special thanks to my Patreons too - I wont name you on here, but I've Special thanks to my Patreons too - I wont name you on here, but I've
certainly enjoyed my tea and flapjacks :D certainly enjoyed my tea and flapjacks :D
@ -221,6 +219,7 @@
#include <fstream> #include <fstream>
#include <map> #include <map>
#include <functional> #include <functional>
#include <algorithm>
#undef min #undef min
#undef max #undef max
@ -264,17 +263,56 @@ namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace
NO_FILE = -1, NO_FILE = -1,
}; };
//==================================================================================
template <class T>
struct v2d_generic
{
T x = 0;
T y = 0;
inline v2d_generic() : x(0), y(0) { }
inline v2d_generic(T _x, T _y) : x(_x), y(_y) { }
inline v2d_generic(const v2d_generic& v) : x(v.x), y(v.y){ }
inline T mag() { return sqrt(x * x + y * y); }
inline v2d_generic norm() { T r = 1 / mag(); return v2d_generic(x*r, y*r); }
inline v2d_generic perp() { return v2d_generic(-y, x); }
inline T dot(const v2d_generic& rhs) { return this->x * rhs.x + this->y * rhs.y; }
inline T cross(const v2d_generic& rhs) { return this->x * rhs.y - this->y * rhs.x; }
inline v2d_generic operator + (const v2d_generic& rhs) { return v2d_generic(this->x + rhs.x, this->y + rhs.y);}
inline v2d_generic operator - (const v2d_generic& rhs) { return v2d_generic(this->x - rhs.x, this->y - rhs.y);}
inline v2d_generic operator * (const T& rhs) { return v2d_generic(this->x * rhs, this->y * rhs); }
inline v2d_generic operator / (const T& rhs) { return v2d_generic(this->x / rhs, this->y / rhs); }
inline v2d_generic& operator += (const v2d_generic& rhs) { this->x += rhs.x; this->y += rhs.y; return *this; }
inline v2d_generic& operator -= (const v2d_generic& rhs) { this->x -= rhs.x; this->y -= rhs.y; return *this; }
inline v2d_generic& operator *= (const T& rhs) { this->x *= rhs; this->y *= rhs; return *this; }
inline v2d_generic& operator /= (const T& rhs) { this->x /= rhs; this->y /= rhs; return *this; }
inline T& operator [] (std::size_t i) { return *((T*)this + i); /* <-- D'oh :( */ }
};
template<class T> inline v2d_generic<T> operator * (const float& lhs, const v2d_generic<T>& rhs) { return v2d_generic<T>(lhs * rhs.x, lhs * rhs.y); }
template<class T> inline v2d_generic<T> operator * (const double& lhs, const v2d_generic<T>& rhs){ return v2d_generic<T>(lhs * rhs.x, lhs * rhs.y); }
template<class T> inline v2d_generic<T> operator * (const int& lhs, const v2d_generic<T>& rhs) { return v2d_generic<T>(lhs * rhs.x, lhs * rhs.y); }
template<class T> inline v2d_generic<T> operator / (const float& lhs, const v2d_generic<T>& rhs) { return v2d_generic<T>(lhs / rhs.x, lhs / rhs.y); }
template<class T> inline v2d_generic<T> operator / (const double& lhs, const v2d_generic<T>& rhs){ return v2d_generic<T>(lhs / rhs.x, lhs / rhs.y); }
template<class T> inline v2d_generic<T> operator / (const int& lhs, const v2d_generic<T>& rhs) { return v2d_generic<T>(lhs / rhs.x, lhs / rhs.y); }
typedef v2d_generic<int> vi2d;
typedef v2d_generic<float> vf2d;
typedef v2d_generic<double> vd2d;
//============================================================= //=============================================================
struct HWButton struct HWButton
{ {
bool bPressed = false; // Set once during the frame the event occurs bool bPressed = false; // Set once during the frame the event occurs
bool bReleased = false; // Set once during the frame the event occurs bool bReleased = false; // Set once during the frame the event occurs
bool bHeld = false; // Set tru for all frames between pressed and released events bool bHeld = false; // Set true for all frames between pressed and released events
}; };
//============================================================= //=============================================================
class ResourcePack class ResourcePack
{ {
public: public:
@ -325,7 +363,7 @@ namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace
public: public:
void SetSampleMode(olc::Sprite::Mode mode = olc::Sprite::Mode::NORMAL); void SetSampleMode(olc::Sprite::Mode mode = olc::Sprite::Mode::NORMAL);
Pixel GetPixel(int32_t x, int32_t y); Pixel GetPixel(int32_t x, int32_t y);
void SetPixel(int32_t x, int32_t y, Pixel p); bool SetPixel(int32_t x, int32_t y, Pixel p);
Pixel Sample(float x, float y); Pixel Sample(float x, float y);
Pixel SampleBL(float u, float v); Pixel SampleBL(float u, float v);
@ -346,6 +384,7 @@ namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace
enum Key enum Key
{ {
NONE,
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, 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,
K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, K0, K1, K2, K3, K4, K5, K6, K7, K8, K9,
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
@ -387,6 +426,8 @@ namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace
int32_t GetMouseX(); int32_t GetMouseX();
// Get Mouse Y coordinate in "pixel" space // Get Mouse Y coordinate in "pixel" space
int32_t GetMouseY(); int32_t GetMouseY();
// Get Mouse Wheel Delta
int32_t GetMouseWheel();
public: // Utility public: // Utility
// Returns the width of the screen in "pixels" // Returns the width of the screen in "pixels"
@ -418,7 +459,7 @@ namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace
void SetSubPixelOffset(float ox, float oy); void SetSubPixelOffset(float ox, float oy);
// Draws a single Pixel // Draws a single Pixel
virtual void Draw(int32_t x, int32_t y, Pixel p = olc::WHITE); virtual bool Draw(int32_t x, int32_t y, Pixel p = olc::WHITE);
// Draws a line from (x1,y1) to (x2,y2) // Draws a line from (x1,y1) to (x2,y2)
void DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p = olc::WHITE); void DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p = olc::WHITE);
// Draws a circle located at (x,y) with radius // Draws a circle located at (x,y) with radius
@ -443,6 +484,8 @@ namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace
// Clears entire draw target to Pixel // Clears entire draw target to Pixel
void Clear(Pixel p); void Clear(Pixel p);
void EnableFullScreen(bool bFullScreen, bool bMaintainAspect = true);
public: // Branding public: // Branding
std::string sAppName; std::string sAppName;
@ -455,8 +498,14 @@ namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace
uint32_t nScreenHeight = 240; uint32_t nScreenHeight = 240;
uint32_t nPixelWidth = 4; uint32_t nPixelWidth = 4;
uint32_t nPixelHeight = 4; uint32_t nPixelHeight = 4;
int32_t nMousePosX = 0; int32_t nMousePosX = 0;
int32_t nMousePosY = 0; int32_t nMousePosY = 0;
int32_t nMouseWheelDelta = 0;
int32_t nMousePosXcache = 0;
int32_t nMousePosYcache = 0;
int32_t nMouseWheelDeltaCache = 0;
int32_t nWindowWidth = 0;
int32_t nWindowHeight = 0;
float fPixelX = 1.0f; float fPixelX = 1.0f;
float fPixelY = 1.0f; float fPixelY = 1.0f;
float fSubPixelOffsetX = 0.0f; float fSubPixelOffsetX = 0.0f;
@ -494,9 +543,12 @@ namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace
// Common initialisation functions // Common initialisation functions
void olc_UpdateMouse(int32_t x, int32_t y); void olc_UpdateMouse(int32_t x, int32_t y);
void olc_UpdateMouseWheel(int32_t delta);
void olc_UpdateWindowSize(int32_t x, int32_t y);
bool olc_OpenGLCreate(); bool olc_OpenGLCreate();
void olc_ConstructFontSheet(); void olc_ConstructFontSheet();
#ifdef _WIN32 #ifdef _WIN32
// Windows specific window handling // Windows specific window handling
HWND olc_hWnd = nullptr; HWND olc_hWnd = nullptr;
@ -541,14 +593,6 @@ namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace
to including this file must have OLC_PGE_APPLICATION defined before it. This prevents to including this file must have OLC_PGE_APPLICATION defined before it. This prevents
the definitions being duplicated. the definitions being duplicated.
Consider the following project structure:
Class1.h - Includes olcPixelGameEngine.h, overrides olc::PixelGameEngine
Class1.cpp - #define OLC_PGE_APPLICATION #include "Class1.h"
Class2.h - Includes Class1.h, which includes olcPixelGameEngine.h
Class2.cpp - #define OLC_PGE_APPLICATION #include "Class2.h"
main.cpp - Includes Class1.h and Class2.h
If all else fails, create a file called "olcPixelGameEngine.cpp" with the following If all else fails, create a file called "olcPixelGameEngine.cpp" with the following
two lines. Then you can just #include "olcPixelGameEngine.h" as normal without worrying two lines. Then you can just #include "olcPixelGameEngine.h" as normal without worrying
about defining things. Dont forget to include that cpp file as part of your build! about defining things. Dont forget to include that cpp file as part of your build!
@ -812,7 +856,7 @@ namespace olc
} }
} }
void Sprite::SetPixel(int32_t x, int32_t y, Pixel p) bool Sprite::SetPixel(int32_t x, int32_t y, Pixel p)
{ {
#ifdef OLC_DBG_OVERDRAW #ifdef OLC_DBG_OVERDRAW
@ -820,13 +864,18 @@ namespace olc
#endif #endif
if (x >= 0 && x < width && y >= 0 && y < height) if (x >= 0 && x < width && y >= 0 && y < height)
{
pColData[y*width + x] = p; pColData[y*width + x] = p;
return true;
}
else
return false;
} }
Pixel Sprite::Sample(float x, float y) Pixel Sprite::Sample(float x, float y)
{ {
int32_t sx = (int32_t)((x * (float)width) - 0.5f); int32_t sx = std::min((int32_t)((x * (float)width)), width - 1);
int32_t sy = (int32_t)((y * (float)height) - 0.5f); int32_t sy = std::min((int32_t)((y * (float)height)), height - 1);
return GetPixel(sx, sy); return GetPixel(sx, sy);
} }
@ -834,17 +883,17 @@ namespace olc
{ {
u = u * width - 0.5f; u = u * width - 0.5f;
v = v * height - 0.5f; v = v * height - 0.5f;
int x = (int)u; int x = (int)floor(u); // cast to int rounds toward zero, not downward
int y = (int)v; int y = (int)floor(v); // Thanks @joshinils
float u_ratio = u - x; float u_ratio = u - x;
float v_ratio = v - y; float v_ratio = v - y;
float u_opposite = 1 - u_ratio; float u_opposite = 1 - u_ratio;
float v_opposite = 1 - v_ratio; float v_opposite = 1 - v_ratio;
olc::Pixel p1 = GetPixel(x, y); olc::Pixel p1 = GetPixel(std::max(x, 0), std::max(y, 0));
olc::Pixel p2 = GetPixel(x+1, y); olc::Pixel p2 = GetPixel(std::min(x + 1, (int)width - 1), std::max(y, 0));
olc::Pixel p3 = GetPixel(x, y+1); olc::Pixel p3 = GetPixel(std::max(x, 0), std::min(y + 1, (int)height - 1));
olc::Pixel p4 = GetPixel(x+1, y+1); olc::Pixel p4 = GetPixel(std::min(x + 1, (int)width - 1), std::min(y + 1, (int)height - 1));
return olc::Pixel( return olc::Pixel(
(uint8_t)((p1.r * u_opposite + p2.r * u_ratio) * v_opposite + (p3.r * u_opposite + p4.r * u_ratio) * v_ratio), (uint8_t)((p1.r * u_opposite + p2.r * u_ratio) * v_opposite + (p3.r * u_opposite + p4.r * u_ratio) * v_ratio),
@ -1036,15 +1085,15 @@ namespace olc
return olc::FAIL; return olc::FAIL;
// Load libraries required for PNG file interaction // Load libraries required for PNG file interaction
#ifdef _WIN32 //#ifdef _WIN32
// Windows use GDI+ // // Windows use GDI+
Gdiplus::GdiplusStartupInput startupInput; // Gdiplus::GdiplusStartupInput startupInput;
ULONG_PTR token; // ULONG_PTR token;
Gdiplus::GdiplusStartup(&token, &startupInput, NULL); // Gdiplus::GdiplusStartup(&token, &startupInput, NULL);
#else //#else
// Linux use libpng // // Linux use libpng
//
#endif //#endif
// Start the thread // Start the thread
bAtomActive = true; bAtomActive = true;
std::thread t = std::thread(&PixelGameEngine::EngineThread, this); std::thread t = std::thread(&PixelGameEngine::EngineThread, this);
@ -1118,6 +1167,11 @@ namespace olc
return nMousePosY; return nMousePosY;
} }
int32_t PixelGameEngine::GetMouseWheel()
{
return nMouseWheelDelta;
}
int32_t PixelGameEngine::ScreenWidth() int32_t PixelGameEngine::ScreenWidth()
{ {
return nScreenWidth; return nScreenWidth;
@ -1128,22 +1182,20 @@ namespace olc
return nScreenHeight; return nScreenHeight;
} }
void PixelGameEngine::Draw(int32_t x, int32_t y, Pixel p) bool PixelGameEngine::Draw(int32_t x, int32_t y, Pixel p)
{ {
if (!pDrawTarget) return; if (!pDrawTarget) return false;
if (nPixelMode == Pixel::NORMAL) if (nPixelMode == Pixel::NORMAL)
{ {
pDrawTarget->SetPixel(x, y, p); return pDrawTarget->SetPixel(x, y, p);
return;
} }
if (nPixelMode == Pixel::MASK) if (nPixelMode == Pixel::MASK)
{ {
if(p.a == 255) if(p.a == 255)
pDrawTarget->SetPixel(x, y, p); return pDrawTarget->SetPixel(x, y, p);
return;
} }
if (nPixelMode == Pixel::ALPHA) if (nPixelMode == Pixel::ALPHA)
@ -1154,15 +1206,15 @@ namespace olc
float r = a * (float)p.r + c * (float)d.r; float r = a * (float)p.r + c * (float)d.r;
float g = a * (float)p.g + c * (float)d.g; float g = a * (float)p.g + c * (float)d.g;
float b = a * (float)p.b + c * (float)d.b; float b = a * (float)p.b + c * (float)d.b;
pDrawTarget->SetPixel(x, y, Pixel((uint8_t)r, (uint8_t)g, (uint8_t)b)); return pDrawTarget->SetPixel(x, y, Pixel((uint8_t)r, (uint8_t)g, (uint8_t)b));
return;
} }
if (nPixelMode == Pixel::CUSTOM) if (nPixelMode == Pixel::CUSTOM)
{ {
pDrawTarget->SetPixel(x, y, funcPixelMode(x, y, p, pDrawTarget->GetPixel(x, y))); return pDrawTarget->SetPixel(x, y, funcPixelMode(x, y, p, pDrawTarget->GetPixel(x, y)));
return;
} }
return false;
} }
void PixelGameEngine::SetSubPixelOffset(float ox, float oy) void PixelGameEngine::SetSubPixelOffset(float ox, float oy)
@ -1598,22 +1650,47 @@ namespace olc
{ return true; } { return true; }
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
void PixelGameEngine::EnableFullScreen(bool bFullScreen, bool bMaintainAspect)
{
if(bFullScreen)
{
// Go full Screen
}
else
{
// Go back to window
}
}
void PixelGameEngine::olc_UpdateWindowSize(int32_t x, int32_t y)
{
nWindowWidth = x;
nWindowHeight = y;
}
void PixelGameEngine::olc_UpdateMouseWheel(int32_t delta)
{
nMouseWheelDeltaCache += delta;
}
void PixelGameEngine::olc_UpdateMouse(int32_t x, int32_t y) void PixelGameEngine::olc_UpdateMouse(int32_t x, int32_t y)
{ {
// Mouse coords come in screen space // Mouse coords come in screen space
// But leave in pixel space // But leave in pixel space
nMousePosX = x / (int32_t)nPixelWidth; nMousePosXcache = (int32_t)(((float)x / (float)nWindowWidth) * (float)nScreenWidth);
nMousePosY = y / (int32_t)nPixelHeight; nMousePosYcache = (int32_t)(((float)y / (float)nWindowHeight) * (float)nScreenHeight);
if (nMousePosX >= (int32_t)nScreenWidth) if (nMousePosXcache >= (int32_t)nScreenWidth)
nMousePosX = nScreenWidth - 1; nMousePosXcache = nScreenWidth - 1;
if (nMousePosY >= (int32_t)nScreenHeight) if (nMousePosYcache >= (int32_t)nScreenHeight)
nMousePosY = nScreenHeight - 1; nMousePosYcache = nScreenHeight - 1;
if (nMousePosX < 0) if (nMousePosXcache < 0)
nMousePosX = 0; nMousePosXcache = 0;
if (nMousePosY < 0) if (nMousePosYcache < 0)
nMousePosY = 0; nMousePosYcache = 0;
} }
void PixelGameEngine::EngineThread() void PixelGameEngine::EngineThread()
@ -1666,6 +1743,12 @@ namespace olc
XGetWindowAttributes(olc_Display, olc_Window, &gwa); XGetWindowAttributes(olc_Display, olc_Window, &gwa);
glViewport(0, 0, gwa.width, gwa.height); glViewport(0, 0, gwa.width, gwa.height);
} }
else if (xev.type == ConfigureNotify)
{
XConfigureEvent xce = xev.xconfigure;
nWindowWidth = xce.width;
nWindowHeight = xce.height;
}
else if (xev.type == KeyPress) else if (xev.type == KeyPress)
{ {
KeySym sym = XLookupKeysym(&xev.xkey, 0); KeySym sym = XLookupKeysym(&xev.xkey, 0);
@ -1678,11 +1761,25 @@ namespace olc
} }
else if (xev.type == ButtonPress) else if (xev.type == ButtonPress)
{ {
pMouseNewState[xev.xbutton.button-1] = true; switch (xev.xbutton.button)
{
case 1: pMouseNewState[0] = true; break;
case 2: pMouseNewState[2] = true; break;
case 3: pMouseNewState[1] = true; break;
case 4: olc_UpdateMouseWheel(120); break;
case 5: olc_UpdateMouseWheel(-120); break;
default: break;
}
} }
else if (xev.type == ButtonRelease) else if (xev.type == ButtonRelease)
{ {
pMouseNewState[xev.xbutton.button-1] = false; switch (xev.xbutton.button)
{
case 1: pMouseNewState[0] = false; break;
case 2: pMouseNewState[2] = false; break;
case 3: pMouseNewState[1] = false; break;
default: break;
}
} }
else if (xev.type == MotionNotify) else if (xev.type == MotionNotify)
{ {
@ -1749,6 +1846,14 @@ namespace olc
pMouseOldState[i] = pMouseNewState[i]; pMouseOldState[i] = pMouseNewState[i];
} }
// Cache mouse coordinates so they remain
// consistent during frame
nMousePosX = nMousePosXcache;
nMousePosY = nMousePosYcache;
nMouseWheelDelta = nMouseWheelDeltaCache;
nMouseWheelDeltaCache = 0;
#ifdef OLC_DBG_OVERDRAW #ifdef OLC_DBG_OVERDRAW
olc::Sprite::nOverdrawCount = 0; olc::Sprite::nOverdrawCount = 0;
#endif #endif
@ -1823,6 +1928,21 @@ namespace olc
} }
#ifdef _WIN32
// Thanks @MaGetzUb for this, which allows sprites to be defined
// at construction, by initialising the GDI subsystem
static class GDIPlusStartup
{
public:
GDIPlusStartup()
{
Gdiplus::GdiplusStartupInput startupInput;
ULONG_PTR token;
Gdiplus::GdiplusStartup(&token, &startupInput, NULL);
};
} gdistartup;
#endif
void PixelGameEngine::olc_ConstructFontSheet() void PixelGameEngine::olc_ConstructFontSheet()
{ {
@ -1904,6 +2024,7 @@ namespace olc
#endif #endif
// Create Keyboard Mapping // Create Keyboard Mapping
mapKeys[0x00] = Key::NONE;
mapKeys[0x41] = Key::A; mapKeys[0x42] = Key::B; mapKeys[0x43] = Key::C; mapKeys[0x44] = Key::D; mapKeys[0x45] = Key::E; mapKeys[0x41] = Key::A; mapKeys[0x42] = Key::B; mapKeys[0x43] = Key::C; mapKeys[0x44] = Key::D; mapKeys[0x45] = Key::E;
mapKeys[0x46] = Key::F; mapKeys[0x47] = Key::G; mapKeys[0x48] = Key::H; mapKeys[0x49] = Key::I; mapKeys[0x4A] = Key::J; mapKeys[0x46] = Key::F; mapKeys[0x47] = Key::G; mapKeys[0x48] = Key::H; mapKeys[0x49] = Key::I; mapKeys[0x4A] = Key::J;
mapKeys[0x4B] = Key::K; mapKeys[0x4C] = Key::L; mapKeys[0x4D] = Key::M; mapKeys[0x4E] = Key::N; mapKeys[0x4F] = Key::O; mapKeys[0x4B] = Key::K; mapKeys[0x4C] = Key::L; mapKeys[0x4D] = Key::M; mapKeys[0x4E] = Key::N; mapKeys[0x4F] = Key::O;
@ -1955,7 +2076,7 @@ namespace olc
// Remove Frame cap // Remove Frame cap
wglSwapInterval = (wglSwapInterval_t*)wglGetProcAddress("wglSwapIntervalEXT"); wglSwapInterval = (wglSwapInterval_t*)wglGetProcAddress("wglSwapIntervalEXT");
wglSwapInterval(0); if (wglSwapInterval) wglSwapInterval(0);
return true; return true;
} }
@ -1975,11 +2096,21 @@ namespace olc
sge->olc_UpdateMouse(ix, iy); sge->olc_UpdateMouse(ix, iy);
return 0; return 0;
} }
case WM_MOUSELEAVE: sge->bHasMouseFocus = false; case WM_SIZE:
{
sge->olc_UpdateWindowSize(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF);
return 0;
}
case WM_MOUSEWHEEL:
{
sge->olc_UpdateMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
return 0;
}
case WM_MOUSELEAVE: sge->bHasMouseFocus = false; return 0;
case WM_SETFOCUS: sge->bHasInputFocus = true; return 0; case WM_SETFOCUS: sge->bHasInputFocus = true; return 0;
case WM_KILLFOCUS: sge->bHasInputFocus = false; return 0; case WM_KILLFOCUS: sge->bHasInputFocus = false; return 0;
case WM_KEYDOWN: sge->pKeyNewState[mapKeys[(uint16_t)wParam]] = true; return 0; case WM_KEYDOWN: sge->pKeyNewState[mapKeys[wParam]] = true; return 0;
case WM_KEYUP: sge->pKeyNewState[mapKeys[(uint16_t)wParam]] = false; return 0; case WM_KEYUP: sge->pKeyNewState[mapKeys[wParam]] = false; return 0;
case WM_LBUTTONDOWN:sge->pMouseNewState[0] = true; return 0; case WM_LBUTTONDOWN:sge->pMouseNewState[0] = true; return 0;
case WM_LBUTTONUP: sge->pMouseNewState[0] = false; return 0; case WM_LBUTTONUP: sge->pMouseNewState[0] = false; return 0;
case WM_RBUTTONDOWN:sge->pMouseNewState[1] = true; return 0; case WM_RBUTTONDOWN:sge->pMouseNewState[1] = true; return 0;
@ -2008,7 +2139,7 @@ namespace olc
olc_SetWindowAttribs.colormap = olc_ColourMap; olc_SetWindowAttribs.colormap = olc_ColourMap;
// Register which events we are interested in receiving // Register which events we are interested in receiving
olc_SetWindowAttribs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask; olc_SetWindowAttribs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | StructureNotifyMask;
// Create the window // Create the window
olc_Window = XCreateWindow(olc_Display, olc_WindowRoot, 30, 30, nScreenWidth * nPixelWidth, nScreenHeight * nPixelHeight, 0, olc_VisualInfo->depth, InputOutput, olc_VisualInfo->visual, CWColormap | CWEventMask, &olc_SetWindowAttribs); olc_Window = XCreateWindow(olc_Display, olc_WindowRoot, 30, 30, nScreenWidth * nPixelWidth, nScreenHeight * nPixelHeight, 0, olc_VisualInfo->depth, InputOutput, olc_VisualInfo->visual, CWColormap | CWEventMask, &olc_SetWindowAttribs);
@ -2020,6 +2151,7 @@ namespace olc
XStoreName(olc_Display, olc_Window, "OneLoneCoder.com - Pixel Game Engine"); XStoreName(olc_Display, olc_Window, "OneLoneCoder.com - Pixel Game Engine");
// Create Keyboard Mapping // Create Keyboard Mapping
mapKeys[0x00] = Key::NONE;
mapKeys[0x61] = Key::A; mapKeys[0x62] = Key::B; mapKeys[0x63] = Key::C; mapKeys[0x64] = Key::D; mapKeys[0x65] = Key::E; mapKeys[0x61] = Key::A; mapKeys[0x62] = Key::B; mapKeys[0x63] = Key::C; mapKeys[0x64] = Key::D; mapKeys[0x65] = Key::E;
mapKeys[0x66] = Key::F; mapKeys[0x67] = Key::G; mapKeys[0x68] = Key::H; mapKeys[0x69] = Key::I; mapKeys[0x6A] = Key::J; mapKeys[0x66] = Key::F; mapKeys[0x67] = Key::G; mapKeys[0x68] = Key::H; mapKeys[0x69] = Key::I; mapKeys[0x6A] = Key::J;
mapKeys[0x6B] = Key::K; mapKeys[0x6C] = Key::L; mapKeys[0x6D] = Key::M; mapKeys[0x6E] = Key::N; mapKeys[0x6F] = Key::O; mapKeys[0x6B] = Key::K; mapKeys[0x6C] = Key::L; mapKeys[0x6D] = Key::M; mapKeys[0x6E] = Key::N; mapKeys[0x6F] = Key::O;

Loading…
Cancel
Save