Added olc::PixelGameEngine v2.06

A bunch more drawing routines, some PRs partially absorbed, more PGEX integration
pull/135/head v2.06
Javidx9 5 years ago committed by GitHub
parent 09080544cb
commit 60407bce45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 419
      olcPixelGameEngine.h

@ -2,7 +2,7 @@
olcPixelGameEngine.h
+-------------------------------------------------------------+
| OneLoneCoder Pixel Game Engine v2.05 |
| OneLoneCoder Pixel Game Engine v2.06 |
| "What do you need? Pixels... Lots of Pixels..." - javidx9 |
+-------------------------------------------------------------+
@ -108,13 +108,13 @@
Thanks
~~~~~~
I'd like to extend thanks to Eremiell, slavka, gurkanctn, Phantim, IProgramInCPP
JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice
JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice, dandistine
Ralakus, Gorbit99, raoul, joshinils, benedani, Moros1138, SaladinAkara & MagetzUb
for advice, ideas and testing, and I'd like to extend my appreciation to the
144K YouTube followers, 70+ Patreons and 6K Discord server members who give me
164K YouTube followers, 70+ Patreons and 8K Discord server members who give me
the motivation to keep going with all this :D
Significant Contributors: @MaGetzUb, @slavka, @Dragoneye & @Gorbit99
Significant Contributors: @Moros1138, @SaladinAkara, @MaGetzUb, @slavka, @Dragoneye & @Gorbit99
Special thanks to those who bring gifts!
GnarGnarHead.......Domina
@ -122,6 +122,7 @@
Marti Morta........Gris
Danicron...........Terraria
SaladinAkara.......Aseprite
AlterEgo...........Final Fantasy XII - The Zodiac Age
Special thanks to my Patreons too - I wont name you on here, but I've
certainly enjoyed my tea and flapjacks :D
@ -135,6 +136,16 @@
2.03: Added FreeBSD flags, Added DrawStringDecal()
2.04: Windows Full-Screen bug fixed
2.05: Added DrawPartialWarpedDecal(), Added DrawPartialRotatedDecal()
2.06: +GetTextSize() - returns area occupied by multiline string
+GetWindowSize() - returns actual window size
+GetElapsedTime() - returns last calculated fElapsedTime
+GetWindowMouse() - returns actual mouse location in window
+DrawExplicitDecal() - bow-chikka-bow-bow
+DrawPartialDecal(pos, size) - draws a partial decal to dpecified area
+FillRectDecal() - draws a flat shaded rectangle as a decal
+GradientFillRectDecal() - draws a rectangle, with unique colour corners
+Modified DrawCircle() & FillCircle() - Thanks IanM-Matrix1 (#PR121)
+Gone someway to appeasing pedants
*/
//////////////////////////////////////////////////////////////////////////////////////////
@ -226,7 +237,7 @@ int main()
#endif
#endif
#if defined(USE_EXPERIMENTAL_FS)
#if defined(USE_EXPERIMENTAL_FS) || defined(FORCE_EXPERIMENTAL_FS)
// C++14
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
#include <experimental/filesystem>
@ -326,28 +337,28 @@ namespace olc
{
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 std::sqrt(x * x + y * y); }
inline T mag2() { return 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) const { return v2d_generic(this->x + rhs.x, this->y + rhs.y);}
inline v2d_generic operator - (const v2d_generic& rhs) const { return v2d_generic(this->x - rhs.x, this->y - rhs.y);}
inline v2d_generic operator * (const T& rhs) const { return v2d_generic(this->x * rhs, this->y * rhs); }
inline v2d_generic operator * (const v2d_generic& rhs) const { return v2d_generic(this->x * rhs.x, this->y * rhs.y);}
inline v2d_generic operator / (const T& rhs) const { return v2d_generic(this->x / rhs, this->y / rhs); }
inline v2d_generic operator / (const v2d_generic& rhs) const { return v2d_generic(this->x / rhs.x, this->y / rhs.y);}
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 operator v2d_generic<int32_t>() const { return { static_cast<int32_t>(this->x), static_cast<int32_t>(this->y) }; }
inline operator v2d_generic<float>() const { return { static_cast<float>(this->x), static_cast<float>(this->y) }; }
inline operator v2d_generic<double>() const { return { static_cast<double>(this->x), static_cast<double>(this->y) }; }
v2d_generic() : x(0), y(0) { }
v2d_generic(T _x, T _y) : x(_x), y(_y) { }
v2d_generic(const v2d_generic& v) : x(v.x), y(v.y){ }
T mag() { return std::sqrt(x * x + y * y); }
T mag2() { return x * x + y * y; }
v2d_generic norm() { T r = 1 / mag(); return v2d_generic(x*r, y*r); }
v2d_generic perp() { return v2d_generic(-y, x); }
T dot(const v2d_generic& rhs) { return this->x * rhs.x + this->y * rhs.y; }
T cross(const v2d_generic& rhs) { return this->x * rhs.y - this->y * rhs.x; }
v2d_generic operator + (const v2d_generic& rhs) const { return v2d_generic(this->x + rhs.x, this->y + rhs.y);}
v2d_generic operator - (const v2d_generic& rhs) const { return v2d_generic(this->x - rhs.x, this->y - rhs.y);}
v2d_generic operator * (const T& rhs) const { return v2d_generic(this->x * rhs, this->y * rhs); }
v2d_generic operator * (const v2d_generic& rhs) const { return v2d_generic(this->x * rhs.x, this->y * rhs.y);}
v2d_generic operator / (const T& rhs) const { return v2d_generic(this->x / rhs, this->y / rhs); }
v2d_generic operator / (const v2d_generic& rhs) const { return v2d_generic(this->x / rhs.x, this->y / rhs.y);}
v2d_generic& operator += (const v2d_generic& rhs) { this->x += rhs.x; this->y += rhs.y; return *this; }
v2d_generic& operator -= (const v2d_generic& rhs) { this->x -= rhs.x; this->y -= rhs.y; return *this; }
v2d_generic& operator *= (const T& rhs) { this->x *= rhs; this->y *= rhs; return *this; }
v2d_generic& operator /= (const T& rhs) { this->x /= rhs; this->y /= rhs; return *this; }
operator v2d_generic<int32_t>() const { return { static_cast<int32_t>(this->x), static_cast<int32_t>(this->y) }; }
operator v2d_generic<float>() const { return { static_cast<float>(this->x), static_cast<float>(this->y) }; }
operator v2d_generic<double>() const { return { static_cast<double>(this->x), static_cast<double>(this->y) }; }
};
// Note: joshinils has some good suggestions here, but they are complicated to implement at this moment,
@ -438,12 +449,12 @@ namespace olc
public:
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) const;
bool SetPixel(int32_t x, int32_t y, Pixel p);
Pixel GetPixel(const olc::vi2d& a);
Pixel GetPixel(const olc::vi2d& a) const;
bool SetPixel(const olc::vi2d& a, Pixel p);
Pixel Sample(float x, float y);
Pixel SampleBL(float u, float v);
Pixel Sample(float x, float y) const;
Pixel SampleBL(float u, float v) const;
Pixel* GetData();
Pixel *pColData = nullptr;
Mode modeSample = Mode::NORMAL;
@ -465,6 +476,24 @@ namespace olc
olc::vf2d vUVScale = { 1.0f, 1.0f };
};
// O------------------------------------------------------------------------------O
// | olc::Renderable - Convenience class to keep a sprite and decal together |
// O------------------------------------------------------------------------------O
class Renderable
{
public:
Renderable() = default;
olc::rcode Load(const std::string& sFile, ResourcePack* pack = nullptr);
void Create(uint32_t width, uint32_t height);
olc::Decal* Decal() const;
olc::Sprite* Sprite() const;
private:
std::unique_ptr<olc::Sprite> pSprite = nullptr;
std::unique_ptr<olc::Decal> pDecal = nullptr;
};
// O------------------------------------------------------------------------------O
// | Auxilliary components internal to engine |
// O------------------------------------------------------------------------------O
@ -475,7 +504,15 @@ namespace olc
olc::vf2d pos[4] = {{ 0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}};
olc::vf2d uv[4] = {{ 0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f}};
float w[4] = { 1, 1, 1, 1 };
olc::Pixel tint;
olc::Pixel tint[4] = { olc::WHITE, olc::WHITE, olc::WHITE, olc::WHITE };;
};
struct DecalTriangleInstance
{
olc::vf2d points[3];
olc::vf2d texture[3];
olc::Pixel colours[3];
olc::Decal* decal = nullptr;
};
struct LayerDesc
@ -563,12 +600,14 @@ namespace olc
int32_t GetMouseY();
// Get Mouse Wheel Delta
int32_t GetMouseWheel();
// Get the ouse in window space
const olc::vi2d& GetWindowMouse() const;
public: // Utility
// Returns the width of the screen in "pixels"
const int32_t ScreenWidth();
int32_t ScreenWidth();
// Returns the height of the screen in "pixels"
const int32_t ScreenHeight();
int32_t ScreenHeight();
// Returns the width of the currently selected drawing target in "pixels"
int32_t GetDrawTargetWidth();
// Returns the height of the currently selected drawing target in "pixels"
@ -582,6 +621,10 @@ namespace olc
void SetDrawTarget(Sprite *target);
// Gets the current Frames Per Second
uint32_t GetFPS();
// Gets last update of elapsed time
const float GetElapsedTime() const;
// Gets Actual Window size
const olc::vi2d& GetWindowSize() const;
public: // CONFIGURATION ROUTINES
// Layer targeting functions
@ -644,28 +687,40 @@ namespace olc
// selected area is (ox,oy) to (ox+w,oy+h)
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);
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);
// Decal Quad functions
// Draws a whole decal, with optional scale and tinting
void DrawDecal(const olc::vf2d& pos, olc::Decal *decal, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE);
// Draws a region of a decal, with optional scale and tinting
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);
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);
// Draws fully user controlled 4 vertices, pos(pixels), uv(pixels), colours
void DrawExplicitDecal(olc::Decal* decal, const olc::vf2d *pos, const olc::vf2d *uv, const olc::Pixel *col);
// Draws a decal with 4 arbitrary points, warping the texture to look "correct"
void DrawWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::Pixel& tint = olc::WHITE);
void DrawWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::Pixel& tint = olc::WHITE);
void DrawWarpedDecal(olc::Decal* decal, const std::array<olc::vf2d, 4>& pos, const olc::Pixel& tint = olc::WHITE);
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 DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f });
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);
// As above, but you can specify a region of a decal source sprite
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);
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);
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);
// Draws a decal rotated to specified angle, wit point of rotation offset
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 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);
// Draws a multiline string as a decal, with tiniting and scaling
void DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f });
// Draws a single shaded filled rectangle as a decal
void FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::WHITE);
// Draws a corner shaded rectangle as a decal
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);
// Draws a single line of text
void DrawString(int32_t x, int32_t y, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
void DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col = olc::WHITE, uint32_t scale = 1);
olc::vi2d GetTextSize(const std::string& s);
// Clears entire draw target to Pixel
void Clear(Pixel p);
// Clears the rendering back buffer
@ -685,6 +740,7 @@ namespace olc
olc::vi2d vMousePos = { 0, 0 };
int32_t nMouseWheelDelta = 0;
olc::vi2d vMousePosCache = { 0, 0 };
olc::vi2d vMouseWindowPos = { 0, 0 };
int32_t nMouseWheelDeltaCache = 0;
olc::vi2d vWindowSize = { 0, 0 };
olc::vi2d vViewPos = { 0, 0 };
@ -695,6 +751,7 @@ namespace olc
bool bHasMouseFocus = false;
bool bEnableVSYNC = false;
float fFrameTimer = 1.0f;
float fLastElapsed = 0.0f;
int nFrameCount = 0;
Sprite* fontSprite = nullptr;
Decal* fontDecal = nullptr;
@ -744,6 +801,8 @@ namespace olc
// NOTE: Items Here are to be deprecated, I have left them in for now
// in case you are using them, but they will be removed.
// olc::vf2d vSubPixelOffset = { 0.0f, 0.0f };
friend class PGEX;
};
@ -897,13 +956,13 @@ namespace olc
void Sprite::SetSampleMode(olc::Sprite::Mode mode)
{ modeSample = mode; }
Pixel Sprite::GetPixel(const olc::vi2d& a)
Pixel Sprite::GetPixel(const olc::vi2d& a) const
{ return GetPixel(a.x, a.y); }
bool Sprite::SetPixel(const olc::vi2d& a, Pixel p)
{ return SetPixel(a.x, a.y, p); }
Pixel Sprite::GetPixel(int32_t x, int32_t y)
Pixel Sprite::GetPixel(int32_t x, int32_t y) const
{
if (modeSample == olc::Sprite::Mode::NORMAL)
{
@ -929,14 +988,14 @@ namespace olc
return false;
}
Pixel Sprite::Sample(float x, float y)
Pixel Sprite::Sample(float x, float y) const
{
int32_t sx = std::min((int32_t)((x * (float)width)), width - 1);
int32_t sy = std::min((int32_t)((y * (float)height)), height - 1);
return GetPixel(sx, sy);
}
Pixel Sprite::SampleBL(float u, float v)
Pixel Sprite::SampleBL(float u, float v) const
{
u = u * width - 0.5f;
v = v * height - 0.5f;
@ -991,7 +1050,33 @@ namespace olc
}
}
void Renderable::Create(uint32_t width, uint32_t height)
{
pSprite = std::make_unique<olc::Sprite>(width, height);
pDecal = std::make_unique<olc::Decal>(pSprite.get());
}
olc::rcode Renderable::Load(const std::string& sFile, ResourcePack *pack)
{
pSprite = std::make_unique<olc::Sprite>();
if (pSprite->LoadFromFile(sFile, pack))
{
pDecal = std::make_unique<olc::Decal>(pSprite.get());
return olc::rcode::OK;
}
else
{
pSprite.release();
pSprite = nullptr;
return olc::rcode::NO_FILE;
}
}
olc::Decal* Renderable::Decal() const
{ return pDecal.get(); }
olc::Sprite* Renderable::Sprite() const
{ return pSprite.get(); }
// O------------------------------------------------------------------------------O
// | olc::ResourcePack IMPLEMENTATION |
@ -1346,12 +1431,32 @@ namespace olc
int32_t PixelGameEngine::GetMouseWheel()
{ return nMouseWheelDelta; }
const int32_t PixelGameEngine::ScreenWidth()
int32_t PixelGameEngine::ScreenWidth()
{ return vScreenSize.x; }
const int32_t PixelGameEngine::ScreenHeight()
int32_t PixelGameEngine::ScreenHeight()
{ return vScreenSize.y; }
const float PixelGameEngine::GetElapsedTime() const
{ return fLastElapsed; }
const olc::vi2d& PixelGameEngine::GetWindowSize() const
{ return vWindowSize; }
const olc::vi2d& PixelGameEngine::GetWindowMouse() const
{ return vMouseWindowPos; }
bool PixelGameEngine::Draw(const olc::vi2d& pos, Pixel p)
{ return Draw(pos.x, pos.y, p); }
@ -1474,54 +1579,81 @@ namespace olc
{ DrawCircle(pos.x, pos.y, radius, p, mask);}
void PixelGameEngine::DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p, uint8_t mask)
{
int x0 = 0;
int y0 = radius;
int d = 3 - 2 * radius;
if (!radius) return;
{ // Thanks to IanM-Matrix1 #PR121
if (radius < 0 || x < -radius || y < -radius || x - GetDrawTargetWidth() > radius || y - GetDrawTargetHeight() > radius)
return;
while (y0 >= x0) // only formulate 1/8 of circle
if (radius > 0)
{
if (mask & 0x01) Draw(x + x0, y - y0, p);
if (mask & 0x02) Draw(x + y0, y - x0, p);
if (mask & 0x04) Draw(x + y0, y + x0, p);
if (mask & 0x08) Draw(x + x0, y + y0, p);
if (mask & 0x10) Draw(x - x0, y + y0, p);
if (mask & 0x20) Draw(x - y0, y + x0, p);
if (mask & 0x40) Draw(x - y0, y - x0, p);
if (mask & 0x80) Draw(x - x0, y - y0, p);
if (d < 0) d += 4 * x0++ + 6;
else d += 4 * (x0++ - y0--) + 10;
int x0 = 0;
int y0 = radius;
int d = 3 - 2 * radius;
while (y0 >= x0) // only formulate 1/8 of circle
{
// Draw even octants
if (mask & 0x01) Draw(x + x0, y - y0, p);// Q6 - upper right right
if (mask & 0x04) Draw(x + y0, y + x0, p);// Q4 - lower lower right
if (mask & 0x10) Draw(x - x0, y + y0, p);// Q2 - lower left left
if (mask & 0x40) Draw(x - y0, y - x0, p);// Q0 - upper upper left
if (x0 != 0 && x0 != y0)
{
if (mask & 0x02) Draw(x + y0, y - x0, p);// Q7 - upper upper right
if (mask & 0x08) Draw(x + x0, y + y0, p);// Q5 - lower right right
if (mask & 0x20) Draw(x - y0, y + x0, p);// Q3 - lower lower left
if (mask & 0x80) Draw(x - x0, y - y0, p);// Q1 - upper left left
}
if (d < 0)
d += 4 * x0++ + 6;
else
d += 4 * (x0++ - y0--) + 10;
}
}
else
Draw(x, y, p);
}
void PixelGameEngine::FillCircle(const olc::vi2d& pos, int32_t radius, Pixel p)
{ FillCircle(pos.x, pos.y, radius, p); }
void PixelGameEngine::FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p)
{
// Taken from wikipedia
int x0 = 0;
int y0 = radius;
int d = 3 - 2 * radius;
if (!radius) return;
{ // Thanks to IanM-Matrix1 #PR121
if (radius < 0 || x < -radius || y < -radius || x - GetDrawTargetWidth() > radius || y - GetDrawTargetHeight() > radius)
return;
auto drawline = [&](int sx, int ex, int ny)
if (radius > 0)
{
for (int i = sx; i <= ex; i++)
Draw(i, ny, p);
};
int x0 = 0;
int y0 = radius;
int d = 3 - 2 * radius;
while (y0 >= x0)
{
// Modified to draw scan-lines instead of edges
drawline(x - x0, x + x0, y - y0);
drawline(x - y0, x + y0, y - x0);
drawline(x - x0, x + x0, y + y0);
drawline(x - y0, x + y0, y + x0);
if (d < 0) d += 4 * x0++ + 6;
else d += 4 * (x0++ - y0--) + 10;
auto drawline = [&](int sx, int ex, int y)
{
for (int x = sx; x <= ex; x++)
Draw(x, y, p);
};
while (y0 >= x0)
{
drawline(x - y0, x + y0, y - x0);
if (x0 > 0) drawline(x - y0, x + y0, y + x0);
if (d < 0)
d += 4 * x0++ + 6;
else
{
if (x0 != y0)
{
drawline(x - x0, x + x0, y - y0);
drawline(x - x0, x + x0, y + y0);
}
d += 4 * (x0++ - y0--) + 10;
}
}
}
else
Draw(x, y, p);
}
void PixelGameEngine::DrawRect(const olc::vi2d& pos, const olc::vi2d& size, Pixel p)
@ -1806,7 +1938,35 @@ namespace olc
vScreenSpacePos.y - (2.0f * source_size.y * vInvScreenSize.y) * scale.y
};
DecalInstance di; di.decal = decal; di.tint = tint;
DecalInstance di; di.decal = decal; di.tint[0] = tint;
di.pos[0] = { vScreenSpacePos.x, vScreenSpacePos.y };
di.pos[1] = { vScreenSpacePos.x, vScreenSpaceDim.y };
di.pos[2] = { vScreenSpaceDim.x, vScreenSpaceDim.y };
di.pos[3] = { vScreenSpaceDim.x, vScreenSpacePos.y };
olc::vf2d uvtl = source_pos * decal->vUVScale;
olc::vf2d uvbr = uvtl + (source_size * decal->vUVScale);
di.uv[0] = { uvtl.x, uvtl.y }; di.uv[1] = { uvtl.x, uvbr.y };
di.uv[2] = { uvbr.x, uvbr.y }; di.uv[3] = { uvbr.x, uvtl.y };
vLayers[nTargetLayer].vecDecalInstance.push_back(di);
}
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)
{
olc::vf2d vScreenSpacePos =
{
(pos.x * vInvScreenSize.x) * 2.0f - 1.0f,
((pos.y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f
};
olc::vf2d vScreenSpaceDim =
{
vScreenSpacePos.x + (2.0f * size.x * vInvScreenSize.x),
vScreenSpacePos.y - (2.0f * size.y * vInvScreenSize.y)
};
DecalInstance di; di.decal = decal; di.tint[0] = tint;
di.pos[0] = { vScreenSpacePos.x, vScreenSpacePos.y };
di.pos[1] = { vScreenSpacePos.x, vScreenSpaceDim.y };
@ -1820,6 +1980,7 @@ namespace olc
vLayers[nTargetLayer].vecDecalInstance.push_back(di);
}
void PixelGameEngine::DrawDecal(const olc::vf2d& pos, olc::Decal *decal, const olc::vf2d& scale, const olc::Pixel& tint)
{
olc::vf2d vScreenSpacePos =
@ -1836,7 +1997,7 @@ namespace olc
DecalInstance di;
di.decal = decal;
di.tint = tint;
di.tint[0] = tint;
di.pos[0] = { vScreenSpacePos.x, vScreenSpacePos.y };
di.pos[1] = { vScreenSpacePos.x, vScreenSpaceDim.y };
di.pos[2] = { vScreenSpaceDim.x, vScreenSpaceDim.y };
@ -1848,7 +2009,7 @@ namespace olc
{
DecalInstance di;
di.decal = decal;
di.tint = tint;
di.tint[0] = tint;
di.pos[0] = (olc::vf2d(0.0f, 0.0f) - center) * scale;
di.pos[1] = (olc::vf2d(0.0f, float(decal->sprite->height)) - center) * scale;
di.pos[2] = (olc::vf2d(float(decal->sprite->width), float(decal->sprite->height)) - center) * scale;
@ -1863,11 +2024,40 @@ namespace olc
vLayers[nTargetLayer].vecDecalInstance.push_back(di);
}
void PixelGameEngine::DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col)
{
DecalInstance di;
for (int i = 0; i < 4; i++)
{
di.pos[i] = { (pos[i].x * vInvScreenSize.x) * 2.0f - 1.0f, ((pos[i].y * vInvScreenSize.y) * 2.0f - 1.0f) * -1.0f };
di.uv[i] = uv[i];
di.tint[i] = col[i];
}
vLayers[nTargetLayer].vecDecalInstance.push_back(di);
}
void PixelGameEngine::FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col)
{
std::array<olc::vf2d, 4> points = { { {pos}, {pos.x, pos.y + size.y}, {pos + size}, {pos.x + size.x, pos.y} } };
std::array<olc::vf2d, 4> uvs = { {{0,0},{0,0},{0,0},{0,0}} };
std::array<olc::Pixel, 4> cols = { {col, col, col, col} };
DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data());
}
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)
{
std::array<olc::vf2d, 4> points = { { {pos}, {pos.x, pos.y + size.y}, {pos + size}, {pos.x + size.x, pos.y} } };
std::array<olc::vf2d, 4> uvs = { {{0,0},{0,0},{0,0},{0,0}} };
std::array<olc::Pixel, 4> cols = { {colTL, colBL, colBR, colTR} };
DrawExplicitDecal(nullptr, points.data(), uvs.data(), cols.data());
}
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)
{
DecalInstance di;
di.decal = decal;
di.tint = tint;
di.tint[0] = tint;
di.pos[0] = (olc::vf2d(0.0f, 0.0f) - center) * scale;
di.pos[1] = (olc::vf2d(0.0f, source_size.y) - center) * scale;
di.pos[2] = (olc::vf2d(source_size.x, source_size.y) - center) * scale;
@ -1892,7 +2082,7 @@ namespace olc
{
DecalInstance di;
di.decal = decal;
di.tint = tint;
di.tint[0] = tint;
olc::vf2d center;
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));
if (rd != 0)
@ -1923,7 +2113,7 @@ namespace olc
// http://www.reedbeta.com/blog/quadrilateral-interpolation-part-1/
DecalInstance di;
di.decal = decal;
di.tint = tint;
di.tint[0] = tint;
olc::vf2d center;
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));
if (rd != 0)
@ -1974,6 +2164,20 @@ namespace olc
}
}
olc::vi2d PixelGameEngine::GetTextSize(const std::string& s)
{
olc::vi2d size = { 0,1 };
olc::vi2d pos = { 0,1 };
for (auto c : s)
{
if (c == '\n') { pos.y++; pos.x = 0; }
else pos.x++;
size.x = std::max(size.x, pos.x);
size.y = std::max(size.y, pos.y);
}
return size * 8;
}
void PixelGameEngine::DrawString(const olc::vi2d& pos, const std::string& sText, Pixel col, uint32_t scale)
{ DrawString(pos.x, pos.y, sText, col, scale); }
@ -2082,7 +2286,8 @@ namespace olc
{
// Mouse coords come in screen space
// But leave in pixel space
bHasMouseFocus = true;
vMouseWindowPos = { x, y };
// Full Screen mode may have a weird viewport we must clamp to
x -= vViewPos.x;
y -= vViewPos.y;
@ -2165,6 +2370,7 @@ namespace olc
// Our time per frame coefficient
float fElapsedTime = elapsedTime.count();
fLastElapsed = fElapsedTime;
// Some platforms will need to check for events
platform->HandleSystemEvent();
@ -2282,7 +2488,7 @@ namespace olc
fontSprite = new olc::Sprite(128, 48);
int px = 0, py = 0;
for (int b = 0; b < 1024; b += 4)
for (size_t b = 0; b < 1024; b += 4)
{
uint32_t sym1 = (uint32_t)data[b + 0] - 48;
uint32_t sym2 = (uint32_t)data[b + 1] - 48;
@ -2467,14 +2673,31 @@ namespace olc
void DrawDecalQuad(const olc::DecalInstance& decal) override
{
glBindTexture(GL_TEXTURE_2D, decal.decal->id);
glBegin(GL_QUADS);
glColor4ub(decal.tint.r, decal.tint.g, decal.tint.b, decal.tint.a);
glTexCoord4f(decal.uv[0].x, decal.uv[0].y, 0.0f, decal.w[0]); glVertex2f(decal.pos[0].x, decal.pos[0].y);
glTexCoord4f(decal.uv[1].x, decal.uv[1].y, 0.0f, decal.w[1]); glVertex2f(decal.pos[1].x, decal.pos[1].y);
glTexCoord4f(decal.uv[2].x, decal.uv[2].y, 0.0f, decal.w[2]); glVertex2f(decal.pos[2].x, decal.pos[2].y);
glTexCoord4f(decal.uv[3].x, decal.uv[3].y, 0.0f, decal.w[3]); glVertex2f(decal.pos[3].x, decal.pos[3].y);
glEnd();
if (decal.decal == nullptr)
{
glBindTexture(GL_TEXTURE_2D, 0);
glBegin(GL_QUADS);
glColor4ub(decal.tint[0].r, decal.tint[0].g, decal.tint[0].b, decal.tint[0].a);
glTexCoord4f(decal.uv[0].x, decal.uv[0].y, 0.0f, decal.w[0]); glVertex2f(decal.pos[0].x, decal.pos[0].y);
glColor4ub(decal.tint[1].r, decal.tint[1].g, decal.tint[1].b, decal.tint[1].a);
glTexCoord4f(decal.uv[1].x, decal.uv[1].y, 0.0f, decal.w[1]); glVertex2f(decal.pos[1].x, decal.pos[1].y);
glColor4ub(decal.tint[2].r, decal.tint[2].g, decal.tint[2].b, decal.tint[2].a);
glTexCoord4f(decal.uv[2].x, decal.uv[2].y, 0.0f, decal.w[2]); glVertex2f(decal.pos[2].x, decal.pos[2].y);
glColor4ub(decal.tint[3].r, decal.tint[3].g, decal.tint[3].b, decal.tint[3].a);
glTexCoord4f(decal.uv[3].x, decal.uv[3].y, 0.0f, decal.w[3]); glVertex2f(decal.pos[3].x, decal.pos[3].y);
glEnd();
}
else
{
glBindTexture(GL_TEXTURE_2D, decal.decal->id);
glBegin(GL_QUADS);
glColor4ub(decal.tint[0].r, decal.tint[0].g, decal.tint[0].b, decal.tint[0].a);
glTexCoord4f(decal.uv[0].x, decal.uv[0].y, 0.0f, decal.w[0]); glVertex2f(decal.pos[0].x, decal.pos[0].y);
glTexCoord4f(decal.uv[1].x, decal.uv[1].y, 0.0f, decal.w[1]); glVertex2f(decal.pos[1].x, decal.pos[1].y);
glTexCoord4f(decal.uv[2].x, decal.uv[2].y, 0.0f, decal.w[2]); glVertex2f(decal.pos[2].x, decal.pos[2].y);
glTexCoord4f(decal.uv[3].x, decal.uv[3].y, 0.0f, decal.w[3]); glVertex2f(decal.pos[3].x, decal.pos[3].y);
glEnd();
}
}
uint32_t CreateTexture(const uint32_t width, const uint32_t height) override

Loading…
Cancel
Save