]> git.localhorst.tv Git - space.git/blob - src/graphics/Canvas.cpp
move to SDL2
[space.git] / src / graphics / Canvas.cpp
1 #include "Canvas.h"
2
3 #include <algorithm>
4 #include <cassert>
5 #include <stdexcept>
6 #include <string>
7
8 using std::runtime_error;
9
10
11 namespace space {
12
13 Canvas::Canvas(SDL_Window *win, int index, Uint32 flags)
14 : canv(SDL_CreateRenderer(win, index, flags)) {
15         if (!canv) {
16                 throw runtime_error(std::string("create canvas: ") + SDL_GetError());
17         }
18 }
19
20 Canvas::~Canvas() {
21         if (canv) SDL_DestroyRenderer(canv);
22 }
23
24 Canvas::Canvas(Canvas &&other)
25 : canv(other.canv) {
26         other.canv = nullptr;
27 }
28
29 Canvas &Canvas::operator =(Canvas &&other) {
30         std::swap(canv, other.canv);
31         return *this;
32 }
33
34
35 void Canvas::Present() {
36         SDL_RenderPresent(canv);
37 }
38
39
40 Vector<int> Canvas::Size() const {
41         assert(canv);
42         Vector<int> size;
43         SDL_GetRendererOutputSize(canv, &size.x, &size.y);
44         return size;
45 }
46
47
48 void Canvas::SetColor(Color c) {
49         SDL_SetRenderDrawColor(canv, c.r, c.g, c.b, c.a);
50 }
51
52
53 void Canvas::Fill() {
54         SDL_RenderClear(canv);
55 }
56
57 void Canvas::Outline() {
58         SDL_RenderDrawRect(canv, nullptr);
59 }
60
61
62 void Canvas::Line(Vector<int> from, Vector<int> to) {
63         SDL_RenderDrawLine(canv, from.x, from.y, to.x, to.y);
64 }
65
66 void Canvas::FillRect(Vector<int> pos, Vector<int> size) {
67         SDL_Rect destRect;
68         destRect.x = pos.x;
69         destRect.y = pos.y;
70         destRect.w = size.x;
71         destRect.h = size.y;
72         SDL_RenderFillRect(canv, &destRect);
73 }
74
75 void Canvas::OutlineRect(Vector<int> pos, Vector<int> size) {
76         SDL_Rect destRect;
77         destRect.x = pos.x;
78         destRect.y = pos.y;
79         destRect.w = size.x;
80         destRect.h = size.y;
81         SDL_RenderDrawRect(canv, &destRect);
82 }
83
84
85 void Canvas::Dot(Vector<int> pos) {
86         SDL_RenderDrawPoint(canv, pos.x, pos.y);
87 }
88
89 void Canvas::Cross(Vector<int> pos, int extent) {
90         Line(
91                 Vector<int>(pos.x - extent, pos.y),
92                 Vector<int>(pos.x + extent, pos.y));
93         Line(
94                 Vector<int>(pos.x, pos.y - extent),
95                 Vector<int>(pos.x, pos.y + extent));
96 }
97
98
99 namespace {
100
101 template<class Scalar>
102 void GridImpl(
103                 Canvas &canv,
104                 Vector<int> pos,
105                 Vector<int> size,
106                 Vector<Scalar> step) {
107         Vector<int> from(pos);
108         Vector<int> to(pos + size);
109         Vector<int> clip(canv.Size());
110
111         if (from.x > clip.x || from.y > clip.y || to.x < 0 || to.y < 0) {
112                 return;
113         }
114         if (step.x <= 1 || step.y <= 1) {
115                 canv.FillRect(pos, size);
116                 return;
117         }
118
119         if (from.x < -step.x) {
120                 int skip = from.x / -step.x;
121                 from.x += skip * step.x;
122         }
123         if (from.y < -step.y) {
124                 int skip = from.y / -step.y;
125                 from.y += skip * step.y;
126         }
127         if (to.x > clip.x + step.x) {
128                 int skip = (to.x - clip.x) / step.x;
129                 to.x -= skip * step.x;
130         }
131         if (to.y > clip.y + step.y) {
132                 int skip = (to.y - clip.y) / step.y;
133                 to.y -= skip * step.y;
134         }
135
136         int width = to.x - from.x;
137         int height = to.y - from.y;
138
139         for (Vector<Scalar> pos(from); pos.x <= to.x; pos.x += step.x) {
140                 canv.Line(pos, Vector<int>(pos.x, pos.y + height));
141         }
142         for (Vector<Scalar> pos(from); pos.y <= to.y; pos.y += step.y) {
143                 canv.Line(pos, Vector<int>(pos.x + width, pos.y));
144         }
145 }
146
147 template<class Scalar>
148 void Grid2Impl(
149                 Canvas &canv,
150                 Vector<int> pos,
151                 Vector<int> size,
152                 Vector<Scalar> step,
153                 Vector<int> n,
154                 Color c1,
155                 Color c2) {
156         Vector<int> from(pos);
157         Vector<int> to(pos + size);
158         Vector<int> clip(canv.Size());
159
160         if (from.x > clip.x || from.y > clip.y || to.x < 0 || to.y < 0) {
161                 return;
162         }
163         if (step.x <= 1 || step.y <= 1) {
164                 canv.SetColor(c1);
165                 canv.FillRect(pos, size);
166                 canv.SetColor(c2);
167                 GridImpl(canv, pos, size, step);
168                 return;
169         }
170
171         Vector<int> i(0, 0);
172
173         if (from.x < -step.x) {
174                 int skip = from.x / -step.x;
175                 from.x += skip * step.x;
176                 i.x += skip;
177         }
178         if (from.y < -step.y) {
179                 int skip = from.y / -step.y;
180                 from.y += skip * step.y;
181                 i.y += skip;
182         }
183         if (to.x > clip.x + step.x) {
184                 int skip = (to.x - clip.x) / step.x;
185                 to.x -= skip * step.x;
186         }
187         if (to.y > clip.y + step.y) {
188                 int skip = (to.y - clip.y) / step.y;
189                 to.y -= skip * step.y;
190         }
191
192         int width = to.x - from.x;
193         int height = to.y - from.y;
194
195         for (Vector<Scalar> pos(from); pos.x <= to.x; pos.x += step.x) {
196                 canv.SetColor((i.x++ % n.x) ? c1 : c2);
197                 canv.Line(pos, Vector<int>(pos.x, pos.y + height));
198         }
199         for (Vector<Scalar> pos(from); pos.y <= to.y; pos.y += step.y) {
200                 canv.SetColor((i.y++ % n.y) ? c1 : c2);
201                 canv.Line(pos, Vector<int>(pos.x + width, pos.y));
202         }
203 }
204
205 }
206
207 void Canvas::Grid(Vector<int> pos, Vector<int> size, Vector<int> step) {
208         GridImpl(*this, pos, size, step);
209 }
210
211 void Canvas::Grid(Vector<int> pos, Vector<int> size, Vector<float> step) {
212         GridImpl(*this, pos, size, step);
213 }
214
215 void Canvas::Grid2(
216                 Vector<int> pos, Vector<int> size, Vector<int> step,
217                 Vector<int> n, Color c1, Color c2) {
218         Grid2Impl(*this, pos, size, step, n, c1, c2);
219 }
220
221 void Canvas::Grid2(
222                 Vector<int> pos, Vector<int> size, Vector<float> step,
223                 Vector<int> n, Color c1, Color c2) {
224         Grid2Impl(*this, pos, size, step, n, c1, c2);
225 }
226
227 }