X-Git-Url: http://git.localhorst.tv/?p=space.git;a=blobdiff_plain;f=src%2Fgraphics%2FCanvas.cpp;fp=src%2Fgraphics%2FCanvas.cpp;h=45997c6b3d3ad92cac6b5c38e6ff29ec570b3b71;hp=0000000000000000000000000000000000000000;hb=61c2d30a60d586cbe63885885c6a373c7713af1e;hpb=08d0e47634e1632c96ebe3308535a86f5e625b40 diff --git a/src/graphics/Canvas.cpp b/src/graphics/Canvas.cpp new file mode 100644 index 0000000..45997c6 --- /dev/null +++ b/src/graphics/Canvas.cpp @@ -0,0 +1,227 @@ +#include "Canvas.h" + +#include +#include +#include +#include + +using std::runtime_error; + + +namespace space { + +Canvas::Canvas(SDL_Window *win, int index, Uint32 flags) +: canv(SDL_CreateRenderer(win, index, flags)) { + if (!canv) { + throw runtime_error(std::string("create canvas: ") + SDL_GetError()); + } +} + +Canvas::~Canvas() { + if (canv) SDL_DestroyRenderer(canv); +} + +Canvas::Canvas(Canvas &&other) +: canv(other.canv) { + other.canv = nullptr; +} + +Canvas &Canvas::operator =(Canvas &&other) { + std::swap(canv, other.canv); + return *this; +} + + +void Canvas::Present() { + SDL_RenderPresent(canv); +} + + +Vector Canvas::Size() const { + assert(canv); + Vector size; + SDL_GetRendererOutputSize(canv, &size.x, &size.y); + return size; +} + + +void Canvas::SetColor(Color c) { + SDL_SetRenderDrawColor(canv, c.r, c.g, c.b, c.a); +} + + +void Canvas::Fill() { + SDL_RenderClear(canv); +} + +void Canvas::Outline() { + SDL_RenderDrawRect(canv, nullptr); +} + + +void Canvas::Line(Vector from, Vector to) { + SDL_RenderDrawLine(canv, from.x, from.y, to.x, to.y); +} + +void Canvas::FillRect(Vector pos, Vector size) { + SDL_Rect destRect; + destRect.x = pos.x; + destRect.y = pos.y; + destRect.w = size.x; + destRect.h = size.y; + SDL_RenderFillRect(canv, &destRect); +} + +void Canvas::OutlineRect(Vector pos, Vector size) { + SDL_Rect destRect; + destRect.x = pos.x; + destRect.y = pos.y; + destRect.w = size.x; + destRect.h = size.y; + SDL_RenderDrawRect(canv, &destRect); +} + + +void Canvas::Dot(Vector pos) { + SDL_RenderDrawPoint(canv, pos.x, pos.y); +} + +void Canvas::Cross(Vector pos, int extent) { + Line( + Vector(pos.x - extent, pos.y), + Vector(pos.x + extent, pos.y)); + Line( + Vector(pos.x, pos.y - extent), + Vector(pos.x, pos.y + extent)); +} + + +namespace { + +template +void GridImpl( + Canvas &canv, + Vector pos, + Vector size, + Vector step) { + Vector from(pos); + Vector to(pos + size); + Vector clip(canv.Size()); + + if (from.x > clip.x || from.y > clip.y || to.x < 0 || to.y < 0) { + return; + } + if (step.x <= 1 || step.y <= 1) { + canv.FillRect(pos, size); + return; + } + + if (from.x < -step.x) { + int skip = from.x / -step.x; + from.x += skip * step.x; + } + if (from.y < -step.y) { + int skip = from.y / -step.y; + from.y += skip * step.y; + } + if (to.x > clip.x + step.x) { + int skip = (to.x - clip.x) / step.x; + to.x -= skip * step.x; + } + if (to.y > clip.y + step.y) { + int skip = (to.y - clip.y) / step.y; + to.y -= skip * step.y; + } + + int width = to.x - from.x; + int height = to.y - from.y; + + for (Vector pos(from); pos.x <= to.x; pos.x += step.x) { + canv.Line(pos, Vector(pos.x, pos.y + height)); + } + for (Vector pos(from); pos.y <= to.y; pos.y += step.y) { + canv.Line(pos, Vector(pos.x + width, pos.y)); + } +} + +template +void Grid2Impl( + Canvas &canv, + Vector pos, + Vector size, + Vector step, + Vector n, + Color c1, + Color c2) { + Vector from(pos); + Vector to(pos + size); + Vector clip(canv.Size()); + + if (from.x > clip.x || from.y > clip.y || to.x < 0 || to.y < 0) { + return; + } + if (step.x <= 1 || step.y <= 1) { + canv.SetColor(c1); + canv.FillRect(pos, size); + canv.SetColor(c2); + GridImpl(canv, pos, size, step); + return; + } + + Vector i(0, 0); + + if (from.x < -step.x) { + int skip = from.x / -step.x; + from.x += skip * step.x; + i.x += skip; + } + if (from.y < -step.y) { + int skip = from.y / -step.y; + from.y += skip * step.y; + i.y += skip; + } + if (to.x > clip.x + step.x) { + int skip = (to.x - clip.x) / step.x; + to.x -= skip * step.x; + } + if (to.y > clip.y + step.y) { + int skip = (to.y - clip.y) / step.y; + to.y -= skip * step.y; + } + + int width = to.x - from.x; + int height = to.y - from.y; + + for (Vector pos(from); pos.x <= to.x; pos.x += step.x) { + canv.SetColor((i.x++ % n.x) ? c1 : c2); + canv.Line(pos, Vector(pos.x, pos.y + height)); + } + for (Vector pos(from); pos.y <= to.y; pos.y += step.y) { + canv.SetColor((i.y++ % n.y) ? c1 : c2); + canv.Line(pos, Vector(pos.x + width, pos.y)); + } +} + +} + +void Canvas::Grid(Vector pos, Vector size, Vector step) { + GridImpl(*this, pos, size, step); +} + +void Canvas::Grid(Vector pos, Vector size, Vector step) { + GridImpl(*this, pos, size, step); +} + +void Canvas::Grid2( + Vector pos, Vector size, Vector step, + Vector n, Color c1, Color c2) { + Grid2Impl(*this, pos, size, step, n, c1, c2); +} + +void Canvas::Grid2( + Vector pos, Vector size, Vector step, + Vector n, Color c1, Color c2) { + Grid2Impl(*this, pos, size, step, n, c1, c2); +} + +}