diff --git a/common/image.cpp b/common/image.cpp new file mode 100644 index 0000000..474b76d --- /dev/null +++ b/common/image.cpp @@ -0,0 +1,145 @@ +/* Copyright: (c) Kayne Ruse 2013 + * + * 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 +#include + +Image& Image::operator=(Image const& rhs) { + //don't screw yourself + if (this == &rhs) { + return *this; + } + + FreeSurface(); + + //Copy the other Image's stuff + surface = rhs.surface; + clip = rhs.clip; + local = false; +} + +Image& Image::operator=(Image&& rhs) { + //don't screw yourself + if (this == &rhs) { + return *this; + } + + FreeSurface(); + + //Steal the other Image's stuff + surface = rhs.surface; + clip = rhs.clip; + local = rhs.local; + + rhs.surface = nullptr; + rhs.clip = {0, 0, 0, 0}; + rhs.local = false; +} + +SDL_Surface* Image::LoadSurface(std::string fname) { + FreeSurface(); + SDL_Surface* p = SDL_LoadBMP(fname.c_str()); + if (!p) { + std::ostringstream os; + os << "Failed to load file: " << fname; + throw(std::runtime_error(os.str())); + } + surface = p; + clip = {0, 0, (Uint16)surface->w, (Uint16)surface->h}; + local = true; + SetTransparentColor(255, 0, 255); //default + return surface; +} + +SDL_Surface* Image::CreateSurface(Uint16 w, Uint16 h) { + FreeSurface(); + Uint32 rmask, gmask, bmask, amask; +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + rmask = 0xff000000; + gmask = 0x00ff0000; + bmask = 0x0000ff00; + amask = 0x000000ff; +#else + rmask = 0x000000ff; + gmask = 0x0000ff00; + bmask = 0x00ff0000; + amask = 0xff000000; +#endif + SDL_Surface* p = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, rmask, gmask, bmask, amask); + if (!p) { + throw(std::runtime_error("Failed to create Image surface")); + } + surface = p; + clip = {0, 0, (Uint16)surface->w, (Uint16)surface->h}; + local = true; + SetTransparentColor(255, 0, 255); //default + return surface; +} + +SDL_Surface* Image::SetSurface(SDL_Surface* p) { + FreeSurface(); + if (!p) { + throw(std::invalid_argument("No surface pointer provided")); + } + surface = p; + clip = {0, 0, (Uint16)surface->w, (Uint16)surface->h}; + local = false; + return surface; +} + +void Image::FreeSurface() { + if (local) { + SDL_FreeSurface(surface); + local = false; + } + surface = nullptr; + clip = {0, 0, 0, 0}; +} + +void Image::DrawTo(SDL_Surface* dest, Sint16 x, Sint16 y) { + if (!surface) { + throw(std::logic_error("No image surface to draw")); + } + SDL_Rect sclip = clip, dclip = {x,y}; + SDL_BlitSurface(surface, &sclip, dest, &dclip); +} + +void Image::SetTransparentColor(Uint8 r, Uint8 g, Uint8 b) { + if (!surface) { + throw(std::logic_error("Failed to set the transparent color")); + } + if (!local) { + throw(std::logic_error("Cannot set the transparent color of a non-local surface")); + } + SDL_SetColorKey(surface, SDL_SRCCOLORKEY, SDL_MapRGB(surface->format, r, g, b)); +} + +void Image::ClearTransparentColor() { + if (!surface) { + throw(std::logic_error("Failed to clear the transparent color")); + } + if (!local) { + throw(std::logic_error("Cannot clear the transparent color of a non-local surface")); + } + SDL_SetColorKey(surface, 0, 0); +} diff --git a/common/image.hpp b/common/image.hpp new file mode 100644 index 0000000..eb684bb --- /dev/null +++ b/common/image.hpp @@ -0,0 +1,73 @@ +/* Copyright: (c) Kayne Ruse 2013 + * + * 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. +*/ +#ifndef IMAGE_HPP_ +#define IMAGE_HPP_ + +#include "SDL/SDL.h" +#include + +class Image { +public: + Image() = default; + Image(Image const& rhs) { *this = rhs; } + Image(Image&& rhs) { *this = std::move(rhs); } + Image(std::string fname) { LoadSurface(fname); } + Image(Uint16 w, Uint16 h) { CreateSurface(w, h); } + Image(SDL_Surface* p) { SetSurface(p); } + ~Image() { FreeSurface(); } + + Image& operator=(Image const&); + Image& operator=(Image&&); + + SDL_Surface* LoadSurface(std::string fname); + SDL_Surface* CreateSurface(Uint16 w, Uint16 h); + SDL_Surface* SetSurface(SDL_Surface*); + SDL_Surface* GetSurface() const { return surface; } + void FreeSurface(); + + void DrawTo(SDL_Surface* const, Sint16 x, Sint16 y); + + //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; } + + void SetTransparentColor(Uint8 r, Uint8 g, Uint8 b); + void ClearTransparentColor(); +protected: + SDL_Surface* surface = nullptr; + SDL_Rect clip = {0, 0, 0, 0}; + bool local = false; +}; + +#endif diff --git a/editor/region.cpp b/editor/region.cpp index d02f505..ec320f5 100644 --- a/editor/region.cpp +++ b/editor/region.cpp @@ -25,6 +25,7 @@ #include static int snap(int base, int x) { + //snap to a grid if (x < 0) { x++; return x - x % base - base; @@ -46,8 +47,9 @@ Region::Region(int i, int j, int k, int l): } } -bool Region::NewTile(Tile const& tile) { - if (!InBounds(tile.x, tile.y)) { +bool Region::NewTileR(Tile const& tile) { + //return 1 for overwrite, 0 for insert + if (!InBoundsR(tile.x, tile.y)) { throw(std::runtime_error("New tile location out of bounds")); } @@ -56,11 +58,10 @@ bool Region::NewTile(Tile const& tile) { return ret; } -Tile Region::GetTile(int x, int y, int tw, int th, int minDepth) { - /* This method is used to find a tile that covers (x, y). - * This method returns the first tile above minDepth. - * Since Region & Tile do not save the tile's size, tw & th are the size of the tiles. - */ +Tile Region::GetTileR(int tx, int ty, int tw, int th, int minDepth) { + //find the first tile at this location, with the specified minimum depth + //since neither the Region or Tile classes store the tile sizes, + //this function takes the sizes as arguments std::set::iterator ptr = tiles.begin(); while(ptr != tiles.end()) { //skip the tiles that are too deep @@ -71,7 +72,7 @@ Tile Region::GetTile(int x, int y, int tw, int th, int minDepth) { } while(ptr != tiles.end()) { //find the first tile here - if ((ptr->x <= x) && (ptr->y <= y) && (ptr->x + tw > x) && (ptr->y + th > y)) { + if ((ptr->x <= tx) && (ptr->y <= ty) && (ptr->x + tw > tx) && (ptr->y + th > ty)) { break; } ptr++; @@ -79,20 +80,16 @@ Tile Region::GetTile(int x, int y, int tw, int th, int minDepth) { if (ptr != tiles.end()) { return *ptr; } - return {0,0,0,-1}; + return {0,0,0,-1}; //value = -1 is a crappy error code } -bool Region::DeleteTile(Tile const& tile) { - if (!InBounds(tile.x, tile.y)) { +bool Region::DeleteTileR(Tile const& tile) { + if (!InBoundsR(tile.x, tile.y)) { throw(std::runtime_error("Deleted tile location out of bounds")); } return tiles.erase(tile); } -bool Region::InBounds(int x, int y) { - return (x > this->x) && (y > this->y) && (x < this->x + this->width) && (y < this->y + this->height); -} - bool operator<(Region const& lhs, Region const& rhs) { //sort by y -> x if (lhs.y == rhs.y) { diff --git a/editor/region.hpp b/editor/region.hpp index 964f5f3..5897577 100644 --- a/editor/region.hpp +++ b/editor/region.hpp @@ -26,22 +26,57 @@ #include +/* A single section of the map. + * This class stores the tiles relative to it's own position, but + * there are functions for referencing the tiles' absolute position. + * These functions simply wrap the normal functions. + * + * TODO: This class needs to be thoroughly tested. +*/ class Region { public: Region() = delete; Region(int x, int y, int width, int height); ~Region() = default; - bool NewTile(Tile const&); + //create and insert a new tile, overwriting an existing tile at that location + bool NewTileR(Tile const& tile); + bool NewTileA(Tile const& tile) { + return NewTileR({tile.x - x, tile.y - y, tile.depth, tile.value}); + } - Tile GetTile(int x, int y, int tw, int th, int minDepth); + //find the first tile at this location, with the specified minimum depth + //since neither the Region or Tile classes store the tile sizes, + //this function takes the sizes as arguments + Tile GetTileR(int tx, int ty, int tw, int th, int minDepth); + Tile GetTileA(int tx, int ty, int tw, int th, int minDepth) { + return GetTileR(tx - x, ty - y, tw, th, minDepth); + } - bool DeleteTile(int x, int y, int tw, int th, int minDepth) { return DeleteTile(GetTile(x, y, tw, th, minDepth)); } - bool DeleteTile(Tile const&); + //wrap the other delete functions + bool DeleteTileR(int tx, int ty, int tw, int th, int minDepth) { + return DeleteTileR(GetTileR(tx, ty, tw, th, minDepth)); + } + bool DeleteTileA(int tx, int ty, int tw, int th, int minDepth) { + //explicitly skip one function call by adjusting from A to R + return DeleteTileR(GetTileR(tx - x, ty - y, tw, th, minDepth)); + } - bool InBounds(int x, int y); + //delete the specified tile + bool DeleteTileR(Tile const& tile); + bool DeleteTileA(Tile const& tile) { + return DeleteTileR({tile.x - x, tile.y - y, tile.depth, tile.value}); + } - //accessors & mutators + //find if the specified location exists within the region's bounds + bool InBoundsR(int i, int j) { + return (i >= 0) && (j >= 0) && (i < width) && (j < height); + } + bool InBoundsA(int i, int j) { + return InBoundsR(i - x, j - y); + } + + //Raw accessors & mutators int GetX() const { return x; } int GetY() const { return y; } int GetWidth() const { return width; } @@ -49,6 +84,7 @@ public: std::set* GetTiles() { return &tiles; } + //sorting the regions by the locations friend bool operator<(Region const& lhs, Region const& rhs); friend bool operator>(Region const& lhs, Region const& rhs); friend bool operator==(Region const& lhs, Region const& rhs); diff --git a/editor/tile.hpp b/editor/tile.hpp index 7a597ad..a07d393 100644 --- a/editor/tile.hpp +++ b/editor/tile.hpp @@ -28,9 +28,7 @@ struct Tile { int value; Tile() = default; - Tile(int i, int j, int k, int l) : x(i), y(j), depth(k), value(l) { - // - } + Tile(int i, int j, int k, int l) : x(i), y(j), depth(k), value(l) {} friend bool operator<(Tile const& lhs, Tile const& rhs); friend bool operator>(Tile const& lhs, Tile const& rhs);