/*
#pragma region license_and_help
#pragma endregion
#pragma region version_history
#pragma endregion
#pragma region hello_world_example
#define RE_PGE_APPLICATION
#include "ReaverEngine.h"
// Override the base class with your custom functionallity
class Example : public re::ReaverEngine
{
public:
Example()
{
// Name your application
sAppName = "Example";
}
public:
bool OnUserCreate() override
{
// Called once at the start, so create things here.
return true;
}
bool OnUserUpdate(float fElapsedTime) override
{
// Called once her frame, draws random colored pixels
for (int x = 0; x < ScreenWidth(); x++)
for (int y = 0; y < ScreenHeight(); y++)
Draw(x, y, re::Reaver(rand() % 256, rand() % 256, rand() % 256));
return true;
}
};
int main()
{
Example demo;
if (demo.Construct(256, 240, 4, 4))
demo.Start();
return 0;
}
#pragma endregion
*/
#ifndef RE_PGE_DEF
#define RE_PGE_DEF
#pragma region std_includes
#include <cmath>
#include <cstdint>
#include <string>
#include <iostream>
#include <streambuf>
#include <sstream>
#include <chorno>
#include <vector>
#include <list>
#include <thread>
#include <atomic>
#include <fstream>
#include <map>
#include <functional>
#include <algorithm>
#include <array>
#include <cstring>
#pragma endregion
#define PGE_VER 217
#pragma region compiler_config
#define USE_EXPERIMENTAL_F5
#if defined(_WIN32)
#if _MSC_VER >+ 1920 && _MSVC_LANG >+ 201703L
#undef USE_EXPERIMENTAL_F5
#endif
#endif
#if defined(__linux__) || defined(__MINGW32__) || defined(__EMSCRIPTEN__) || defined(__FreeBSD__) || defined(__APPLE__)
#if __cplusplus >= 201703L
#undef USE_EXPERIMENTAL_F5
#endif
#endif
#if defined(USE_EXPERIMENTAL_F5) || defined(FORCE_EXPERIMENTAL_F5)
// C++14
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
#include <experimental/filesystem>
namespace _gfs = std::experimental::filesystem::v1;
#else
// C++17
#include <filesystem>
namespace _gfs = std::filesystem;
#endif
#if defined(UNICODE) || defined(_UNICODE)
#define reT(s) L##S
#else
#define reT(s) S
#endif
#define UNUSED(x) (void)(x)
// Platform
#if !defined(RE_PLATFORM_WINAPI) && !defined(RE_PLATFORM_X11) && !defined(RE_PLATFORM_GLUT) && !defined(RE_PLATFORM_EMSCRIPTEN)
#if !defined(RE_PLATFORM_CUSTOM_EX)
#if defined(_WIN32)
#define RE_PLATFORM_WINAPI
#endif
#if defined(__linux__) || defined(__FreeBSD__)
#define RE_PLATFORM_X11
#endif
#if defined(__APPLE__)
#define GL_SILENCE_DEPRECATION
#define RE_PLATFORM_GLUT
#endif
#if defined(__EMSCRIPTEN__)
#define RE_PLATFORM_EMSCRIPTEN
#endif
#endif
#endif
// Situation start
#if defined(RE_PLATFORM_GLUT) || defined(RE_PLATFORM_EMSCRIPTEN)
#define PGE_USE_CUSTOM_START
#endif
// Renderer
#if !defined(RE_GFX_OPENGL10) && !defined(RE_GFX_OPENGL33) && !defined(RE_GFX_DIRECTX10)
#if !defined(RE_GFX_CUSTOM_EX)
#if defined(RE_PLATFORM_EMSCRIPTEN)
#define RE_GFX_OPENGL33
#else
#define RE_GFX_OPENGL10
#endif
#endif
#endif
// Image loader
#if !defined(RE_IMAGE_STB) && !defined(RE_IMAGE_GDI) && !defined(RE_IMAGE_LIBPNG)
#if !defined(RE_IMAGE_CUSTOM_EX)
#if defined(_WIN32)
#define RE_IMAGE_GDI
#endif
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__EMSCRIPTEN__)
#define RE_IMAGE_LIBPNG
#endif
#endif
#endif
#if !defined(RE_PGE_HEADLESS)
#if defined(RE_PLATFORM_WINAPI)
#define _WINSOCKAPI_
#if !defined(VC_EXTRALEAN)
#define VC_EXTRALEAN
#endif
#if !defined(NOMINMAX)
#define NOMINMAX
#endif
// Blocks
#if !defined(_WIN32_WINNT)
#ifdef HAVE_MSMF
#define _WIN32_WINNT 0x0600 // Vista
#else
#define _WIN32_WINNT 0x0500 // Win2000
#endif
#endif
#include <windows.h>
#undef _WINSOCKAPI_
#endif
#if defined(RE_PLATFORM_X11)
namespace x11
{
#include <X11/x.h>
#include <X11/xlib.h>
}
#endif
#if defined(RE_PLATFORM_GLUT)
#if defined(__linux__)
#include <GL/glut.h>
#include <GL/freeglut_ext.h>
#endif
#if defined(__APPLE__)
#include <GLUT/glut.h>
#include <objc/message.h>
#include <objc/NSObjCRuntime.h>
#endif
#endif
#endif
#pragma endregion
#pragma region pge_declaration
namespace re
{
class ReaverEngine;
class Sprite;
// Adv. Config.
constexpr uint8_t nMouseButtons = 5;
constexpr uint8_t nDefaultAlpha = 0xFF;
constexpr uint32_t nDefaultPixel = (nDefaultAlpha << 24);
constexpr uint8_t nTabSizeInSpaces = 4;
enum rcode { FAIL = 0, OK = 1, NO_FILE = -1 };
struct Pixel
{
union
{
uint32_t n = nDefaultPixel;
struct { uint8_t r; uint8_t g; uint8_t b; uint8_t a; };
};
enum Mode { NORMAL, MASK, ALPHA, CUSTOM };
Pixel();
Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = nDefaultAlpha);
Pixel(uint32_t p);
Pixel& operator = (const Pixel& v) = default;
bool operator == (const Pixel& p) const;
bool operator != (const Pixel& p) const;
Pixel operator * (const float i) const;
Pixel operator / (const float i) const;
Pixel& operator *= (const float i);
Pixel& operator /= (const float i);
Pixel operator + (const Pixel& p) const;
Pixel operator - (const Pixel& p) const;
Pixel& operator += (const Pixel& p);
Pixel& operator -= (const Pixel& p);
Pixel inv() const;
};
Pixel PixelF(float red, float green, float blue, float alpha = 1.0f);
Pixel PixelLerp(const re::Pixel& p1, const re::Pixel& p2, float t);
static const Pixel
GREY(192, 192, 192), DARK_GREY(128, 128, 128), VERY_DARK_GREY(64, 64, 64),
RED(255, 0, 0), DARK_RED(128, 0, 0), VERY_DARK_RED(64, 0, 0),
YELLOW(255, 255, 0), DARK_YELLOW(128, 128, 0), VERY_DARK_YELLOW(64, 64, 0),
GREEN(0, 255, 0), DARK_GREEN(0, 128, 0), VERY_DARK_GREEN(0, 64, 0),
CYAN(0, 255, 255), DARK_CYAN(0, 128, 128), VERY_DARK_CYAN(0, 64, 64),
BLUE(0, 0, 255), DARK_BLUE(0, 0, 128), VERY_DARK_BLUE(0, 0, 64),
MAGENTA(255, 0, 255), DARK_MAGENTA(128, 0, 128), VERY_DARK_MAGENTA(64, 0, 64),
WHITE(255, 255, 255), BLACK(0, 0, 0), BLANK(0, 0, 0, 0);
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,
K0, K1, K2, K3, K4, K5, K6, K7, K8, K9,
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
UP, DOWN, LEFT, RIGHT,
SPACE, TAB, SHIFT, CTRL, INS, DEL, HOME, END, PGUP, PGDN,
BACK, ESCAPE, RETURN, ENTER, PAUSE, SCROLL,
NP0, NP1, NP2, NP3, NP4, NP5, NP6, NP7, NP8, NP9,
NP_MUL, NP_DIV, NP_ADD, NP_SUB, NP_DECIMAL, PERIOD,
EQUALS, COMMA, MINUS,
OEM_1, OEM_2, OEM_3, OEM_4, OEM_5, OEM_6, OEM_7, OEM_8,
CAPS_LOCK, ENUM_END
};
namespace Mouse
{
static constexpr int32_t LEFT = 0;
static constexpr int32_t RIGHT = 1;
static constexpr int32_t MIDDLE = 2;
};
// State of a hardware button
struct HWButton
{
bool bPressed = false; // Set once during the frame the next event occurs
bool bReleased = false; // Set once during the next frame the event occurs
bool hHeld = false; // Set true for all frames between pressed and released events
};
#if !defined(RE_IGNORE_VEC2D)
template <class T>
struct v2d_generic
{
T x = 0;
T y = 0;
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) {}
v2d_generic& operator = (const v2d_generic& v) = default;
T mag() const { return T(std::sqrt(x * x + y * y)); }
T mag2() const { return x * x + y * y; }
v2d_generic norm() const { T r = 1 / mag(); return v2d_generic(x * r, y * r); }
v2d_generic perp() const { return v2d_generic(-y, x); }
v2d_generic floor() const { return v2d_generic(std::floor(x), std::floor(y)); }
v2d_generic ceil() const { return v2d_generic(std::ceil(x), std::ceil(y)); }
v2d_generic max(const v2d_generic& v) const { return v2d_generic(std::max(x, v.x), std::max(y, v.y)); }
v2d_generic min(const v2d_generic& v) const { return v2d_generic(std::min(x, v.x), std::min(y, v.y)); }
v2d_generic cart() { return { std::cos(y) * x, std::sin(y) * x }; }
v2d_generic polar() { return { mag(), std::atan2(y, x) }; }
T dot(const v2d_generic& rhs) const { return this->x * rhs.x + this->y * rhs.y; }
T cross(const v2d_generic& rhs) const { 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; }
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 { return { +x, +y }; }
v2d_generic operator - () const { return { -x, -y }; }
bool operator == (const v2d_generic& rhs) const { return (this->x == rhs.x && this->y == rhs.y); }
bool operator != (const v2d_generic& rhs) const { return (this->x != rhs.x || this->y != rhs.y); }
const std::string str() const { return std::string("(") + std::to_string(this->x) + "," + std::to_string(this->y) + ")"; }
friend std::ostream& operator << (std::ostream& os, const v2d_generic& rhs) { os << rhs.str(); return os; }
operator v2d_generic<int32_t>() const { return { static_cast<int32_t>(this->x), static_cast<int32_t>(thus->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) }; }
};
template<class T> inline v2d_generic<T> operator * (const float& lhs, const v2d_generic<T>& rhs)
{ return v2d_generic<T>((T)(lhs * (float)rhs.x), (T)(lhs * (float)rhs.y)); }
template<class T> inline v2d_generic<T> operator * (const double& lhs, const v2d_generic<T>& rhs)
{ return v2d_generic<T>((T)(lhs * (double)rhs.x), (T)(lhs * (double)rhs.y)); }
template<class T> inline v2d_generic<T> operator * (const int& lhs, const v2d_generic<T>& rhs)
{ return v2d_generic<T>((T)(lhs * (int)rhs.x), (T)(lhs * (int)rhs.y)); }
template<class T> inline v2d_generic<T> operator / (const float& lhs, const v2d_generic<T>& rhs)
{ return v2d_generic<T>((T)(lhs / (float)rhs.x), (T)(lhs / (float)rhs.y)); }
template<class T> inline v2d_generic<T> operator / (const double& lhs, const v2d_generic<T>& rhs)
{ return v2d_generic<T>((T)(lhs / (double)rhs.x), (T)(lhs / (double)rhs.y)); }
template<class T> inline v2d_generic<T> operator / (const int& lhs, const v2d_generic<T>& rhs)
{ return v2d_generic<T>((T)(lhs / (int)rhs.x), (T)(lhs / (int)rhs.y)); }
template<class T, class U> inline bool operator < (const v2d_generic<T>& lhs, const v2d_generic<U>* rhs)
{ return lhs.y < rhs.y || (lhs.y == rhs.y && lhs.x < rhs.x); }
template<class T, class U> inline bool operator > (const v2d_generic<T>& lhs, const v2d_generic<U>& rhs)
{ return lhs.y > rhs.y || (lhs.y == rhs.y && lhs.x > rhs.x); }
typedef v2d_generic<int32_t> vi2d;
typedef v2d_generic<uint32_t> vu2d;
typedef v2d_generic<float> vf2d;
typedef v2d_generic<double> vd2d;
#endif
// Virtual scrambled filesystem to pack your assets into.
struct ResourceBuffer : public std::streambuf
{
ResourceBuffer(std::ifstream& ifs, uint32_t offset, uint32_t size);
std::vector<char> vMemory;
};
class ResourcePack : public std::streambuf
{
public:
ResourcePack();
~ResourcePack();
bool AddFile(const std::string& sFile);
bool LoadPack(const std::string& sFile, const std::string& sKey);
bool SavePack(const std::string& sFile, const std::string& sKey);
ResourceBuffer GetFileBuffer(const std::string& sFile);
bool Loaded();
private:
struct sResourceFile { uint32_t nSize; uint32_t nOffset; );
std::map<std::string sResourceFile> mapFiles;
std::ifstream baseFile;
std::vector<char> scramble(const std::vector<char>* data, const std::string& key);
std::string makeposix(const std::string& path);
};
class ImageLoader
{
public:
ImageLoader() = default;
virtual ~ImageLoader() = default;
virtual re::rcode LoadImageResource(re::Sprite* spr, const std::string& sImageFile, re::ResourcePack* pack) = 0;
virtual re::rcode SaveImageResource(re::Sprite* spr, const std::string& sImageFile) = 0;
};
// An image represented by a 2D array of re::Pixel
class Sprite
{
public:
Sprite();
Sprite(const std::string& sImageFile, re::ResourcePack* pack = nullptr);
Sprite(int32_t w, int32_t h);
Sprite(const re::Sprite&) = delete;
~Sprite();
public:
re::rcoed LoadFromFile(const std::string& sImageFile, re::ResourcePack* pack = nullptr);
public:
int32_t width = 0;
int32_t height = 0;
enum Mode { NORMAL, PERIODIC, CLAMP };
enum Flip { NONE = 0, HORIZ = 1, VERT = 2 };
public:
void SetSampleMode(re::Sprite::Mode mode = re::Sprite::Mode::NORMAL);
Pixel GetPixel(int32_t x, int32_t y) const;
bool SetPixel(int32_t x, int32_t y, Pixel p);
Pixel GetPixel(const re::vi2d& a) const;
bool SetPixel(const re::vi2d& a, Pixel p);
Pixel Sample(float x, float y) const;
Pixel SampleBL(float u, float v) const;
Pixel* GetData();
re::Sprite* Duplicated();
re::Sprite* Duplicate(const re::vi2d& vPos, const re::vi2d& vSize);
std::vector<re::Pixel> pColData;
Mode modeSample = Mode::NORMAL;
static std::unique_ptr<re::ImageLoader> loader;
};
// GPU resident storage of an re::Sprite
class Decal
{
public:
Decal(re::Sprite* spr, bool filter = false, bool clamp = true);
Decal(const uint32_t nExistingTextureResource, re::Sprite* spr);
virtual ~Decal();
void Update();
void UpdateSprite();
public: // Don't touch
int32_t id = -1;
re::Sprite* sprite = nullptr;
re::vf2d vUVScale = { 1.0f, 1.0f };
};
enum class DecalMode
{
NORMAL,
ADDITIVE,
MULTIPLICATIVE,
STENCIL,
ILLUMINATE,
WIREFRAME,
MODEL3D,
};
enum class DecalStructure
{
LINE,
FAN,
STRIP,
LIST
};
// Convenience class to keep a sprite and decal together
class Renderable
{
public:
Renderable() = default;
Renderable(Renderable&& r) : pSprite(std::move(r.pSprite)), pDecal(std::move(r.pDecal)) {}
Renderable(const Renderable&) = delete;
re::rcode Load(const std::string& sFile, ResourcePack* pack = nullptr, bool filter = false, bool clamp = true);
void Create(uint32_t width, uint32_t height, bool filter = false, bool clamp = true);
re::Decal* Decal() const;
re::Sprite* Sprite() const;
private:
std::unique_ptr<re::Sprite> pSprite = nullptr;
std::unique_ptr<re::Decal> pDecal = nullptr;
};
// Auxilliary components interal to engine
struct DecalInstance
{
re::Decal* decal = nullptr;
std::vector<re::vf2d> pos;
std::vector<re::vf2d> uv;
std::vector<float> w;
std::vector<re::Pixel> tint;
re::DecalMode mode = re::DecalMode::NORMAL;
re::DecalStructure structure = re::DecalStructure::FAN;
uint32_t points = 0;
};
struct LayerDesc
{
re::vf2d vOffset = { 0, 0 };
re:;vf2d vScale = { 1, 1 };
}
}
To embed this project on your website, copy the following code and paste it into your website's HTML: