8 using std::runtime_error;
13 Canvas::Canvas(SDL_Window *win, int index, Uint32 flags)
14 : canv(SDL_CreateRenderer(win, index, flags)) {
16 throw runtime_error(std::string("create canvas: ") + SDL_GetError());
21 if (canv) SDL_DestroyRenderer(canv);
24 Canvas::Canvas(Canvas &&other)
29 Canvas &Canvas::operator =(Canvas &&other) {
30 std::swap(canv, other.canv);
35 void Canvas::Present() {
36 SDL_RenderPresent(canv);
40 Vector<int> Canvas::Size() const {
43 SDL_GetRendererOutputSize(canv, &size.x, &size.y);
48 Texture Canvas::CreateStaticTexture(Vector<int> size) {
49 return Texture(canv, Color::Format, SDL_TEXTUREACCESS_STATIC, size);
52 Texture Canvas::LoadTexture(const char *file) {
53 return Texture(canv, file);
57 void Canvas::Copy(Texture &tex, Vector<int> to) {
61 void Canvas::Copy(Texture &tex, Rect<int> clip, Vector<int> to) {
62 tex.Copy(canv, clip, to);
66 void Canvas::SetColor(Color c) {
67 SDL_SetRenderDrawColor(canv, c.r, c.g, c.b, c.a);
72 SDL_RenderClear(canv);
75 void Canvas::Outline() {
76 SDL_RenderDrawRect(canv, nullptr);
80 void Canvas::Line(Vector<int> from, Vector<int> to) {
81 SDL_RenderDrawLine(canv, from.x, from.y, to.x, to.y);
84 void Canvas::FillRect(Rect<int> rect) {
85 SDL_RenderFillRect(canv, &rect);
88 void Canvas::OutlineRect(Rect<int> rect) {
89 SDL_RenderDrawRect(canv, &rect);
92 void Canvas::OutlineRectRot(Rect<float> rect, Vector<float> origin, float rot) {
93 const Vector<float> topLeft(rect.x, rect.y);
94 const Vector<float> topRight(rect.x + rect.w - 1, rect.y);
95 const Vector<float> botLeft(rect.x, rect.y + rect.h - 1);
96 const Vector<float> botRight(rect.x + rect.w - 1, rect.y + rect.h - 1);
99 Rotate(topLeft - origin, rot) + origin,
100 Rotate(topRight - origin, rot) + origin,
101 Rotate(botRight - origin, rot) + origin,
102 Rotate(botLeft - origin, rot) + origin
107 void Canvas::Dot(Vector<int> pos) {
108 SDL_RenderDrawPoint(canv, pos.x, pos.y);
111 void Canvas::Cross(Vector<int> pos, int extent) {
113 Vector<int>(pos.x - extent, pos.y),
114 Vector<int>(pos.x + extent, pos.y));
116 Vector<int>(pos.x, pos.y - extent),
117 Vector<int>(pos.x, pos.y + extent));
120 void Canvas::Arrow(Vector<int> from, Vector<int> to) {
122 Vector<float> delta(to - from);
123 delta = delta / Length(delta);
125 Line(to, to + Vector<int>(Rotate90(delta) * 5.0f - (delta * 5.0f)));
126 Line(to, to + Vector<int>(Rotate270(delta) * 5.0f - (delta * 5.0f)));
129 void Canvas::Triangle(Vector<int> v1, Vector<int> v2, Vector<int> v3) {
130 SDL_Point points[4] = { v1, v2, v3, v1 };
131 SDL_RenderDrawLines(canv, points, 4);
134 void Canvas::Quad(Vector<int> v1, Vector<int> v2, Vector<int> v3, Vector<int> v4) {
135 SDL_Point points[5] = { v1, v2, v3, v4, v1 };
136 SDL_RenderDrawLines(canv, points, 5);
142 template<class Scalar>
147 Vector<Scalar> step) {
148 Vector<int> from(pos);
149 Vector<int> to(pos + size);
150 Vector<int> clip(canv.Size());
152 if (from.x > clip.x || from.y > clip.y || to.x < 0 || to.y < 0) {
155 if (step.x <= 1 || step.y <= 1) {
156 canv.FillRect(pos, size);
160 if (from.x < -step.x) {
161 int skip = from.x / -step.x;
162 from.x += skip * step.x;
164 if (from.y < -step.y) {
165 int skip = from.y / -step.y;
166 from.y += skip * step.y;
168 if (to.x > clip.x + step.x) {
169 int skip = (to.x - clip.x) / step.x;
170 to.x -= skip * step.x;
172 if (to.y > clip.y + step.y) {
173 int skip = (to.y - clip.y) / step.y;
174 to.y -= skip * step.y;
177 int width = to.x - from.x;
178 int height = to.y - from.y;
180 for (Vector<Scalar> pos(from); pos.x <= to.x; pos.x += step.x) {
181 canv.Line(pos, Vector<int>(pos.x, pos.y + height));
183 for (Vector<Scalar> pos(from); pos.y <= to.y; pos.y += step.y) {
184 canv.Line(pos, Vector<int>(pos.x + width, pos.y));
188 template<class Scalar>
197 Vector<int> from(pos);
198 Vector<int> to(pos + size);
199 Vector<int> clip(canv.Size());
201 if (from.x > clip.x || from.y > clip.y || to.x < 0 || to.y < 0) {
204 if (step.x <= 1 || step.y <= 1) {
206 canv.FillRect(pos, size);
208 GridImpl(canv, pos, size, step * Vector<Scalar>(n));
214 if (from.x < -step.x) {
215 int skip = from.x / -step.x;
216 from.x += skip * step.x;
219 if (from.y < -step.y) {
220 int skip = from.y / -step.y;
221 from.y += skip * step.y;
224 if (to.x > clip.x + step.x) {
225 int skip = (to.x - clip.x) / step.x;
226 to.x -= skip * step.x;
228 if (to.y > clip.y + step.y) {
229 int skip = (to.y - clip.y) / step.y;
230 to.y -= skip * step.y;
233 int width = to.x - from.x;
234 int height = to.y - from.y;
236 for (Vector<Scalar> pos(from); pos.x <= to.x; pos.x += step.x) {
237 canv.SetColor((i.x++ % n.x) ? c1 : c2);
238 canv.Line(pos, Vector<int>(pos.x, pos.y + height));
240 for (Vector<Scalar> pos(from); pos.y <= to.y; pos.y += step.y) {
241 canv.SetColor((i.y++ % n.y) ? c1 : c2);
242 canv.Line(pos, Vector<int>(pos.x + width, pos.y));
248 void Canvas::Grid(Vector<int> pos, Vector<int> size, Vector<int> step) {
249 GridImpl(*this, pos, size, step);
252 void Canvas::Grid(Vector<int> pos, Vector<int> size, Vector<float> step) {
253 GridImpl(*this, pos, size, step);
257 Vector<int> pos, Vector<int> size, Vector<int> step,
258 Vector<int> n, Color c1, Color c2) {
259 Grid2Impl(*this, pos, size, step, n, c1, c2);
263 Vector<int> pos, Vector<int> size, Vector<float> step,
264 Vector<int> n, Color c1, Color c2) {
265 Grid2Impl(*this, pos, size, step, n, c1, c2);