diff --git a/README.md b/README.md index 0a48168..8cf2827 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## Outline -TurtleGUI requires SDL2, SDL_image and SDL_ttf. It also requires Image and BoundingBox from [Tortuga](https://github.com/Ratstail91/Tortuga). +TurtleGUI requires SDL2, SDL_image and SDL_ttf. Other than that, it should be a self contained package. ## Copyright diff --git a/bounding_box.hpp b/bounding_box.hpp new file mode 100644 index 0000000..06747b0 --- /dev/null +++ b/bounding_box.hpp @@ -0,0 +1,75 @@ +/* Copyright: (c) Kayne Ruse 2013-2016 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include +#include + +class BoundingBox { +public: + //This is explicitly a POD + int x, y; + int w, h; + + BoundingBox() = default; + BoundingBox(int i, int j): x(i), y(j), w(0), h(0) {}; + BoundingBox(int i, int j, int k, int l): x(i), y(j), w(k), h(l) {}; + ~BoundingBox() = default; + BoundingBox& operator=(BoundingBox const&) = default; + + int Size() { + return std::max(w*h,0); + } + + bool CheckOverlap(BoundingBox rhs) { + return !( + x >= rhs.x + rhs.w || + y >= rhs.y + rhs.h || + rhs.x >= x + w || + rhs.y >= y + h); + } + + BoundingBox CalcOverlap(BoundingBox rhs) { + if (!CheckOverlap(rhs)) { + return {0, 0, 0, 0}; + } + BoundingBox ret; + ret.x = std::max(x, rhs.x); + ret.y = std::max(y, rhs.y); + ret.w = std::min(x+w, rhs.x+rhs.w) - ret.x; + ret.h = std::min(y+h, rhs.y+rhs.h) - ret.y; + return ret; + } +}; + +//This is explicitly a POD +static_assert(std::is_pod::value, "BoundingBox is not a POD"); + +#include "vector2.hpp" + +//operators +inline BoundingBox operator+(BoundingBox b, Vector2 v) { + return {b.x + (int)v.x, b.y + (int)v.y, b.w, b.h}; +} +inline BoundingBox operator+(Vector2 v, BoundingBox b) { + return b + v; +} diff --git a/image.cpp b/image.cpp new file mode 100644 index 0000000..7eadeaf --- /dev/null +++ b/image.cpp @@ -0,0 +1,211 @@ +/* Copyright: (c) Kayne Ruse 2013-2016 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#include "image.hpp" + +#include "SDL2/SDL_image.h" + +#include +#include + +Image& Image::operator=(Image const& rhs) { + //don't screw yourself + if (this == &rhs) { + return *this; + } + + Free(); + + //Copy the other Image's stuff + texture = rhs.texture; + clip = rhs.clip; + local = false; +} + +Image& Image::operator=(Image&& rhs) { + //don't screw yourself + if (this == &rhs) { + return *this; + } + + Free(); + + //Steal the other Image's stuff + texture = rhs.texture; + clip = rhs.clip; + local = rhs.local; + + rhs.texture = nullptr; + rhs.clip = {0, 0, 0, 0}; + rhs.local = false; +} + +SDL_Texture* Image::Load(SDL_Renderer* renderer, std::string fname) { + Free(); + + //load the file into a surface + SDL_Surface* surface = IMG_Load(fname.c_str()); + if (!surface) { + std::ostringstream msg; + msg << "Failed to load an image file: " << fname; + msg << "; " << IMG_GetError(); + throw(std::runtime_error(msg.str())); + } + + //create a texture from this surface + texture = SDL_CreateTextureFromSurface(renderer, surface); + if (!texture) { + std::ostringstream msg; + msg << "Failed to convert a newly loaded image file: " << fname; + msg << "; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + + //set the metadata + clip.x = 0; + clip.y = 0; + if (SDL_QueryTexture(texture, nullptr, nullptr, &clip.w, &clip.h)) { + std::ostringstream msg; + msg << "Failed to record metadata for a newly loaded image file: " << fname; + msg << "; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + local = true; + + //free the surface & return + SDL_FreeSurface(surface); + return texture; +} + +SDL_Texture* Image::Create(SDL_Renderer* renderer, Uint16 w, Uint16 h, SDL_Color blank) { + Free(); + + //make the texture + texture = SDL_CreateTexture(renderer, + SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_TARGET, + w, h); + + //check + if (!texture) { + std::ostringstream msg; + msg << "Failed to create a texture; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + + //set the metadata + clip.x = 0; + clip.y = 0; + if (SDL_QueryTexture(texture, nullptr, nullptr, &clip.w, &clip.h)) { + std::ostringstream msg; + msg << "Failed to record metadata for a newly created image"; + msg << "; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + local = true; + + //blank (black) texture + SDL_SetRenderTarget(renderer, texture); + SDL_SetRenderDrawColor(renderer, blank.r, blank.g, blank.b, blank.a); + SDL_RenderFillRect(renderer, nullptr); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + SDL_SetRenderTarget(renderer, nullptr); + + return texture; +} + +SDL_Texture* Image::CopyTexture(SDL_Renderer* renderer, SDL_Texture* ptr) { + Free(); + int w = 0, h = 0; + + //get the info + SDL_QueryTexture(ptr, nullptr, nullptr, &w, &h); + + //create a texture of (w, h) size (also sets the metadata) + Create(renderer, w, h); + + //copy the argument texture to the local texture + SDL_SetRenderTarget(renderer, texture); + SDL_RenderCopy(renderer, ptr, nullptr, nullptr); + SDL_SetRenderTarget(renderer, nullptr); + + //return the local texture + return texture; +} + +SDL_Texture* Image::SetTexture(SDL_Texture* ptr) { + Free(); + + texture = ptr; + + //set the metadata + clip.x = 0; + clip.y = 0; + if (SDL_QueryTexture(texture, nullptr, nullptr, &clip.w, &clip.h)) { + std::ostringstream msg; + msg << "Failed to record metadata for a newly set image"; + msg << "; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + local = false; + + return texture; +} + +SDL_Texture* Image::GetTexture() const { + return texture; +} + +void Image::Free() { + if (local) { + SDL_DestroyTexture(texture); + local = false; + } + texture = nullptr; + clip = {0, 0, 0, 0}; +} + +void Image::DrawTo(SDL_Renderer* const renderer, Sint16 x, Sint16 y, double scaleX, double scaleY) { + if (!texture) { + throw(std::logic_error("No image texture to draw")); + } + SDL_Rect sclip = clip; + SDL_Rect dclip = {x, y, Uint16(clip.w * scaleX), Uint16(clip.h * scaleY)}; + SDL_RenderCopy(renderer, texture, &sclip, &dclip); +} + +void Image::SetAlpha(Uint8 a) { + if (SDL_SetTextureAlphaMod(texture, a)) { + std::ostringstream msg; + msg << "Failed to set alpha; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } +} + +Uint8 Image::GetAlpha() { + Uint8 ret = 0; + if (SDL_GetTextureAlphaMod(texture, &ret)) { + std::ostringstream msg; + msg << "Failed to get alpha; " << SDL_GetError(); + throw(std::runtime_error(msg.str())); + } + return ret; +} \ No newline at end of file diff --git a/image.hpp b/image.hpp new file mode 100644 index 0000000..b4e62f8 --- /dev/null +++ b/image.hpp @@ -0,0 +1,73 @@ +/* Copyright: (c) Kayne Ruse 2013-2016 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include "SDL2/SDL.h" + +#include + +class Image { +public: + Image() = default; + Image(Image const& rhs) { *this = rhs; } + Image(Image&& rhs) { *this = std::move(rhs); } + Image(SDL_Renderer* r, std::string fname) { Load(r, fname); } + Image(SDL_Renderer* r, Uint16 w, Uint16 h) { Create(r, w, h); } + Image(SDL_Texture* p) { SetTexture(p); } + virtual ~Image() { Free(); } + + Image& operator=(Image const&); + Image& operator=(Image&&); + + SDL_Texture* Load(SDL_Renderer* renderer, std::string fname); + SDL_Texture* Create(SDL_Renderer* renderer, Uint16 w, Uint16 h, SDL_Color blank = {0, 0, 0, 255}); + SDL_Texture* CopyTexture(SDL_Renderer* renderer, SDL_Texture* ptr); + SDL_Texture* SetTexture(SDL_Texture*); + SDL_Texture* GetTexture() const; + virtual void Free(); + + void DrawTo(SDL_Renderer* const, Sint16 x, Sint16 y, double scaleX = 1.0, double scaleY = 1.0); + + void SetAlpha(Uint8 a); + Uint8 GetAlpha(); + + //Clip handlers + SDL_Rect SetClip(SDL_Rect r) { return clip = r; } + SDL_Rect GetClip() const { return clip; } + + Sint16 SetClipX(Sint16 x) { return clip.x = x; } + Sint16 SetClipY(Sint16 y) { return clip.y = y; } + Uint16 SetClipW(Uint16 w) { return clip.w = w; } + Uint16 SetClipH(Uint16 h) { return clip.h = h; } + + Sint16 GetClipX() const { return clip.x; } + Sint16 GetClipY() const { return clip.y; } + Uint16 GetClipW() const { return clip.w; } + Uint16 GetClipH() const { return clip.h; } + + bool GetLocal() const { return local; } + +protected: + SDL_Texture* texture = nullptr; + SDL_Rect clip = {0, 0, 0, 0}; + bool local = false; +}; \ No newline at end of file diff --git a/makefile b/makefile index ca46ad5..0dc99a2 100644 --- a/makefile +++ b/makefile @@ -1,5 +1,5 @@ #config -INCLUDES+=. .. +INCLUDES+=. LIBS+= CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) diff --git a/vector2.hpp b/vector2.hpp new file mode 100644 index 0000000..ad0b17f --- /dev/null +++ b/vector2.hpp @@ -0,0 +1,111 @@ +/* Copyright: (c) Kayne Ruse 2013-2016 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#pragma once + +#include +#include +#include + +class Vector2 { +public: + double x, y; + + Vector2() = default; + Vector2(double i, double j): x(i), y(j) {}; + ~Vector2() = default; + Vector2& operator=(Vector2 const&) = default; + + double Length() const { + return sqrt(x*x+y*y); + } + double SquaredLength() const { + return x*x+y*y; + } + void Normalize() { + double l = Length(); + if (l == 0) + throw(std::domain_error("Divide by zero")); + x /= l; + y /= l; + } + + //Arithmetic operators + Vector2 operator+(Vector2 v) const { + Vector2 ret; + ret.x = x + v.x; + ret.y = y + v.y; + return ret; + } + Vector2 operator-(Vector2 v) const { + Vector2 ret; + ret.x = x - v.x; + ret.y = y - v.y; + return ret; + } + Vector2 operator*(Vector2 v) const { + Vector2 ret; + ret.x = x * v.x; + ret.y = y * v.y; + return ret; + } + Vector2 operator*(double d) const { + Vector2 ret; + ret.x = x * d; + ret.y = y * d; + return ret; + } + + Vector2 operator/(Vector2 v) { + if (!v.x || !v.y) + throw(std::domain_error("Divide by zero")); + Vector2 ret; + ret.x = x / v.x; + ret.y = y / v.y; + return ret; + } + Vector2 operator/(double d) { + if (!d) + throw(std::domain_error("Divide by zero")); + Vector2 ret; + ret.x = x / d; + ret.y = y / d; + return ret; + } + + //unary operators + Vector2 operator-() { return {-x, -y}; } + + //comparison operators + bool operator==(Vector2 v) { return (x == v.x && y == v.y); } + bool operator!=(Vector2 v) { return (x != v.x || y != v.y); } + + //member templates (curry the above operators) + template Vector2 operator+=(T t) { return *this = *this + t; } + template Vector2 operator-=(T t) { return *this = *this - t; } + template Vector2 operator*=(T t) { return *this = *this * t; } + template Vector2 operator/=(T t) { return *this = *this / t; } + template bool operator==(T t) { return (x == t && y == t); } + template bool operator!=(T t) { return (x != t || y != t); } +}; + +//This is explicitly a POD +static_assert(std::is_pod::value, "Vector2 is not a POD");