]> git.localhorst.tv Git - gworm.git/blob - src/graphics/Canvas.cpp
added texture support
[gworm.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 gworm {
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 Texture Canvas::CreateStaticTexture(Vector<int> size) {
49         return Texture(canv, Color::Format, SDL_TEXTUREACCESS_STATIC, size);
50 }
51
52
53 void Canvas::Copy(Texture &tex, Vector<int> to) {
54         tex.Copy(canv, to);
55 }
56
57
58 void Canvas::SetColor(Color c) {
59         SDL_SetRenderDrawColor(canv, c.r, c.g, c.b, c.a);
60 }
61
62
63 void Canvas::Fill() {
64         SDL_RenderClear(canv);
65 }
66
67 void Canvas::Outline() {
68         SDL_RenderDrawRect(canv, nullptr);
69 }
70
71
72 void Canvas::Line(Vector<int> from, Vector<int> to) {
73         SDL_RenderDrawLine(canv, from.x, from.y, to.x, to.y);
74 }
75
76 void Canvas::FillRect(Vector<int> pos, Vector<int> size) {
77         SDL_Rect destRect;
78         destRect.x = pos.x;
79         destRect.y = pos.y;
80         destRect.w = size.x;
81         destRect.h = size.y;
82         SDL_RenderFillRect(canv, &destRect);
83 }
84
85 void Canvas::OutlineRect(Vector<int> pos, Vector<int> size) {
86         SDL_Rect destRect;
87         destRect.x = pos.x;
88         destRect.y = pos.y;
89         destRect.w = size.x;
90         destRect.h = size.y;
91         SDL_RenderDrawRect(canv, &destRect);
92 }
93
94
95 void Canvas::Dot(Vector<int> pos) {
96         SDL_RenderDrawPoint(canv, pos.x, pos.y);
97 }
98
99 void Canvas::Cross(Vector<int> pos, int extent) {
100         Line(
101                 Vector<int>(pos.x - extent, pos.y),
102                 Vector<int>(pos.x + extent, pos.y));
103         Line(
104                 Vector<int>(pos.x, pos.y - extent),
105                 Vector<int>(pos.x, pos.y + extent));
106 }
107
108 void Canvas::Arrow(Vector<int> from, Vector<int> to) {
109         Line(from, to);
110         Vector<float> delta(to - from);
111         delta = delta / Length(delta);
112
113         Line(to, to + Vector<int>(Rotate90(delta) * 5.0f - (delta * 5.0f)));
114         Line(to, to + Vector<int>(Rotate270(delta) * 5.0f - (delta * 5.0f)));
115 }
116
117 void Canvas::Triangle(Vector<int> v1, Vector<int> v2, Vector<int> v3) {
118         SDL_Point points[4] = { v1, v2, v3, v1 };
119         SDL_RenderDrawLines(canv, points, 4);
120 }
121
122 void Canvas::Quad(Vector<int> v1, Vector<int> v2, Vector<int> v3, Vector<int> v4) {
123         SDL_Point points[5] = { v1, v2, v3, v4, v1 };
124         SDL_RenderDrawLines(canv, points, 5);
125 }
126
127
128 namespace {
129
130 template<class Scalar>
131 void GridImpl(
132                 Canvas &canv,
133                 Vector<int> pos,
134                 Vector<int> size,
135                 Vector<Scalar> step) {
136         Vector<int> from(pos);
137         Vector<int> to(pos + size);
138         Vector<int> clip(canv.Size());
139
140         if (from.x > clip.x || from.y > clip.y || to.x < 0 || to.y < 0) {
141                 return;
142         }
143         if (step.x <= 1 || step.y <= 1) {
144                 canv.FillRect(pos, size);
145                 return;
146         }
147
148         if (from.x < -step.x) {
149                 int skip = from.x / -step.x;
150                 from.x += skip * step.x;
151         }
152         if (from.y < -step.y) {
153                 int skip = from.y / -step.y;
154                 from.y += skip * step.y;
155         }
156         if (to.x > clip.x + step.x) {
157                 int skip = (to.x - clip.x) / step.x;
158                 to.x -= skip * step.x;
159         }
160         if (to.y > clip.y + step.y) {
161                 int skip = (to.y - clip.y) / step.y;
162                 to.y -= skip * step.y;
163         }
164
165         int width = to.x - from.x;
166         int height = to.y - from.y;
167
168         for (Vector<Scalar> pos(from); pos.x <= to.x; pos.x += step.x) {
169                 canv.Line(pos, Vector<int>(pos.x, pos.y + height));
170         }
171         for (Vector<Scalar> pos(from); pos.y <= to.y; pos.y += step.y) {
172                 canv.Line(pos, Vector<int>(pos.x + width, pos.y));
173         }
174 }
175
176 template<class Scalar>
177 void Grid2Impl(
178                 Canvas &canv,
179                 Vector<int> pos,
180                 Vector<int> size,
181                 Vector<Scalar> step,
182                 Vector<int> n,
183                 Color c1,
184                 Color c2) {
185         Vector<int> from(pos);
186         Vector<int> to(pos + size);
187         Vector<int> clip(canv.Size());
188
189         if (from.x > clip.x || from.y > clip.y || to.x < 0 || to.y < 0) {
190                 return;
191         }
192         if (step.x <= 1 || step.y <= 1) {
193                 canv.SetColor(c1);
194                 canv.FillRect(pos, size);
195                 canv.SetColor(c2);
196                 GridImpl(canv, pos, size, step * Vector<Scalar>(n));
197                 return;
198         }
199
200         Vector<int> i(0, 0);
201
202         if (from.x < -step.x) {
203                 int skip = from.x / -step.x;
204                 from.x += skip * step.x;
205                 i.x += skip;
206         }
207         if (from.y < -step.y) {
208                 int skip = from.y / -step.y;
209                 from.y += skip * step.y;
210                 i.y += skip;
211         }
212         if (to.x > clip.x + step.x) {
213                 int skip = (to.x - clip.x) / step.x;
214                 to.x -= skip * step.x;
215         }
216         if (to.y > clip.y + step.y) {
217                 int skip = (to.y - clip.y) / step.y;
218                 to.y -= skip * step.y;
219         }
220
221         int width = to.x - from.x;
222         int height = to.y - from.y;
223
224         for (Vector<Scalar> pos(from); pos.x <= to.x; pos.x += step.x) {
225                 canv.SetColor((i.x++ % n.x) ? c1 : c2);
226                 canv.Line(pos, Vector<int>(pos.x, pos.y + height));
227         }
228         for (Vector<Scalar> pos(from); pos.y <= to.y; pos.y += step.y) {
229                 canv.SetColor((i.y++ % n.y) ? c1 : c2);
230                 canv.Line(pos, Vector<int>(pos.x + width, pos.y));
231         }
232 }
233
234 }
235
236 void Canvas::Grid(Vector<int> pos, Vector<int> size, Vector<int> step) {
237         GridImpl(*this, pos, size, step);
238 }
239
240 void Canvas::Grid(Vector<int> pos, Vector<int> size, Vector<float> step) {
241         GridImpl(*this, pos, size, step);
242 }
243
244 void Canvas::Grid2(
245                 Vector<int> pos, Vector<int> size, Vector<int> step,
246                 Vector<int> n, Color c1, Color c2) {
247         Grid2Impl(*this, pos, size, step, n, c1, c2);
248 }
249
250 void Canvas::Grid2(
251                 Vector<int> pos, Vector<int> size, Vector<float> step,
252                 Vector<int> n, Color c1, Color c2) {
253         Grid2Impl(*this, pos, size, step, n, c1, c2);
254 }
255
256 }