olcPixelGameEngine v2.28
The official distribution of olcPixelGameEngine, a tool used in javidx9's YouTube videos and projects
Loading...
Searching...
No Matches
olcPGEX_Graphics2D.h
Go to the documentation of this file.
1/*
2 olcPGEX_Graphics2D.h
3
4 +-------------------------------------------------------------+
5 | OneLoneCoder Pixel Game Engine Extension |
6 | Advanced 2D Rendering - v0.5 |
7 +-------------------------------------------------------------+
8
9 What is this?
10 ~~~~~~~~~~~~~
11 This is an extension to the olcPixelGameEngine, which provides
12 advanced olc::Sprite manipulation and drawing routines. To use
13 it, simply include this header file.
14
15 License (OLC-3)
16 ~~~~~~~~~~~~~~~
17
18 Copyright 2018 - 2019 OneLoneCoder.com
19
20 Redistribution and use in source and binary forms, with or without
21 modification, are permitted provided that the following conditions
22 are met:
23
24 1. Redistributions or derivations of source code must retain the above
25 copyright notice, this list of conditions and the following disclaimer.
26
27 2. Redistributions or derivative works in binary form must reproduce
28 the above copyright notice. This list of conditions and the following
29 disclaimer must be reproduced in the documentation and/or other
30 materials provided with the distribution.
31
32 3. Neither the name of the copyright holder nor the names of its
33 contributors may be used to endorse or promote products derived
34 from this software without specific prior written permission.
35
36 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
37 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
38 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
39 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
40 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
43 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
45 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
46 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47
48 Links
49 ~~~~~
50 YouTube: https://www.youtube.com/javidx9
51 Discord: https://discord.gg/WhwHUMV
52 Twitter: https://www.twitter.com/javidx9
53 Twitch: https://www.twitch.tv/javidx9
54 GitHub: https://www.github.com/onelonecoder
55 Homepage: https://www.onelonecoder.com
56
57 Author
58 ~~~~~~
59 David Barr, aka javidx9, ©OneLoneCoder 2019
60*/
61
62/*
63 Matrices stored as [Column][Row] (i.e. x, y)
64
65 |C0R0 C1R0 C2R0| | x | | x'|
66 |C0R1 C1R1 C2R1| * | y | = | y'|
67 |C0R2 C1R2 C2R2| |1.0| | - |
68*/
69
70
71
72#ifndef OLC_PGEX_GFX2D
73#define OLC_PGEX_GFX2D
74
75#include <algorithm>
76
77#include "olcPixelGameEngine.h"
78
79#undef min
80#undef max
81
82namespace olc
83{
84 // Container class for Advanced 2D Drawing functions
85 class GFX2D : public olc::PGEX
86 {
87 // A representation of an affine transform, used to rotate, scale, offset & shear space
88 public:
90 {
91 public:
93
94 public:
95 // Set this transformation to unity
96 void Reset();
97 // Append a rotation of fTheta radians to this transform
98 void Rotate(float fTheta);
99 // Append a translation (ox, oy) to this transform
100 void Translate(float ox, float oy);
101 // Append a scaling operation (sx, sy) to this transform
102 void Scale(float sx, float sy);
103 // Append a shear operation (sx, sy) to this transform
104 void Shear(float sx, float sy);
105
106 void Perspective(float ox, float oy);
107 // Calculate the Forward Transformation of the coordinate (in_x, in_y) -> (out_x, out_y)
108 void Forward(float in_x, float in_y, float &out_x, float &out_y);
109 // Calculate the Inverse Transformation of the coordinate (in_x, in_y) -> (out_x, out_y)
110 void Backward(float in_x, float in_y, float &out_x, float &out_y);
111 // Regenerate the Inverse Transformation
112 void Invert();
113
114 private:
115 void Multiply();
116 float matrix[4][3][3];
117 int nTargetMatrix;
118 int nSourceMatrix;
119 bool bDirty;
120 };
121
122 public:
123 // Draws a sprite with the transform applied
124 static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform);
125 };
126}
127
128
129#ifdef OLC_PGEX_GRAPHICS2D
130#undef OLC_PGEX_GRAPHICS2D
131
132namespace olc
133{
135 {
136 if (sprite == nullptr)
137 return;
138
139 // Work out bounding rectangle of sprite
140 float ex, ey;
141 float sx, sy;
142 float px, py;
143
144 transform.Forward(0.0f, 0.0f, sx, sy);
145 px = sx; py = sy;
146 sx = std::min(sx, px); sy = std::min(sy, py);
147 ex = std::max(ex, px); ey = std::max(ey, py);
148
149 transform.Forward((float)sprite->width, (float)sprite->height, px, py);
150 sx = std::min(sx, px); sy = std::min(sy, py);
151 ex = std::max(ex, px); ey = std::max(ey, py);
152
153 transform.Forward(0.0f, (float)sprite->height, px, py);
154 sx = std::min(sx, px); sy = std::min(sy, py);
155 ex = std::max(ex, px); ey = std::max(ey, py);
156
157 transform.Forward((float)sprite->width, 0.0f, px, py);
158 sx = std::min(sx, px); sy = std::min(sy, py);
159 ex = std::max(ex, px); ey = std::max(ey, py);
160
161 // Perform inversion of transform if required
162 transform.Invert();
163
164 if (ex < sx)
165 std::swap(ex, sx);
166 if (ey < sy)
167 std::swap(ey, sy);
168
169 // Iterate through render space, and sample Sprite from suitable texel location
170 for (float i = sx; i < ex; i++)
171 {
172 for (float j = sy; j < ey; j++)
173 {
174 float ox, oy;
175 transform.Backward(i, j, ox, oy);
176 pge->Draw((int32_t)i, (int32_t)j, sprite->GetPixel((int32_t)(ox+0.5f), (int32_t)(oy+0.5f)));
177 }
178 }
179 }
180
182 {
183 Reset();
184 }
185
187 {
188 nTargetMatrix = 0;
189 nSourceMatrix = 1;
190 bDirty = true;
191
192 // Columns Then Rows
193
194 // Matrices 0 & 1 are used as swaps in Transform accumulation
195 matrix[0][0][0] = 1.0f; matrix[0][1][0] = 0.0f; matrix[0][2][0] = 0.0f;
196 matrix[0][0][1] = 0.0f; matrix[0][1][1] = 1.0f; matrix[0][2][1] = 0.0f;
197 matrix[0][0][2] = 0.0f; matrix[0][1][2] = 0.0f; matrix[0][2][2] = 1.0f;
198
199 matrix[1][0][0] = 1.0f; matrix[1][1][0] = 0.0f; matrix[1][2][0] = 0.0f;
200 matrix[1][0][1] = 0.0f; matrix[1][1][1] = 1.0f; matrix[1][2][1] = 0.0f;
201 matrix[1][0][2] = 0.0f; matrix[1][1][2] = 0.0f; matrix[1][2][2] = 1.0f;
202
203 // Matrix 2 is a cache matrix to hold the immediate transform operation
204 // Matrix 3 is a cache matrix to hold the inverted transform
205 }
206
207 void olc::GFX2D::Transform2D::Multiply()
208 {
209 for (int c = 0; c < 3; c++)
210 {
211 for (int r = 0; r < 3; r++)
212 {
213 matrix[nTargetMatrix][c][r] = matrix[2][0][r] * matrix[nSourceMatrix][c][0] +
214 matrix[2][1][r] * matrix[nSourceMatrix][c][1] +
215 matrix[2][2][r] * matrix[nSourceMatrix][c][2];
216 }
217 }
218
219 std::swap(nTargetMatrix, nSourceMatrix);
220 bDirty = true; // Any transform multiply dirties the inversion
221 }
222
223 void olc::GFX2D::Transform2D::Rotate(float fTheta)
224 {
225 // Construct Rotation Matrix
226 matrix[2][0][0] = cosf(fTheta); matrix[2][1][0] = sinf(fTheta); matrix[2][2][0] = 0.0f;
227 matrix[2][0][1] = -sinf(fTheta); matrix[2][1][1] = cosf(fTheta); matrix[2][2][1] = 0.0f;
228 matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
229 Multiply();
230 }
231
232 void olc::GFX2D::Transform2D::Scale(float sx, float sy)
233 {
234 // Construct Scale Matrix
235 matrix[2][0][0] = sx; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f;
236 matrix[2][0][1] = 0.0f; matrix[2][1][1] = sy; matrix[2][2][1] = 0.0f;
237 matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
238 Multiply();
239 }
240
241 void olc::GFX2D::Transform2D::Shear(float sx, float sy)
242 {
243 // Construct Shear Matrix
244 matrix[2][0][0] = 1.0f; matrix[2][1][0] = sx; matrix[2][2][0] = 0.0f;
245 matrix[2][0][1] = sy; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f;
246 matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
247 Multiply();
248 }
249
250 void olc::GFX2D::Transform2D::Translate(float ox, float oy)
251 {
252 // Construct Translate Matrix
253 matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = ox;
254 matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = oy;
255 matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
256 Multiply();
257 }
258
259 void olc::GFX2D::Transform2D::Perspective(float ox, float oy)
260 {
261 // Construct Translate Matrix
262 matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f;
263 matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f;
264 matrix[2][0][2] = ox; matrix[2][1][2] = oy; matrix[2][2][2] = 1.0f;
265 Multiply();
266 }
267
268 void olc::GFX2D::Transform2D::Forward(float in_x, float in_y, float &out_x, float &out_y)
269 {
270 out_x = in_x * matrix[nSourceMatrix][0][0] + in_y * matrix[nSourceMatrix][1][0] + matrix[nSourceMatrix][2][0];
271 out_y = in_x * matrix[nSourceMatrix][0][1] + in_y * matrix[nSourceMatrix][1][1] + matrix[nSourceMatrix][2][1];
272 float out_z = in_x * matrix[nSourceMatrix][0][2] + in_y * matrix[nSourceMatrix][1][2] + matrix[nSourceMatrix][2][2];
273 if (out_z != 0)
274 {
275 out_x /= out_z;
276 out_y /= out_z;
277 }
278 }
279
280 void olc::GFX2D::Transform2D::Backward(float in_x, float in_y, float &out_x, float &out_y)
281 {
282 out_x = in_x * matrix[3][0][0] + in_y * matrix[3][1][0] + matrix[3][2][0];
283 out_y = in_x * matrix[3][0][1] + in_y * matrix[3][1][1] + matrix[3][2][1];
284 float out_z = in_x * matrix[3][0][2] + in_y * matrix[3][1][2] + matrix[3][2][2];
285 if (out_z != 0)
286 {
287 out_x /= out_z;
288 out_y /= out_z;
289 }
290 }
291
293 {
294 if (bDirty) // Obviously costly so only do if needed
295 {
296 float det = matrix[nSourceMatrix][0][0] * (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) -
297 matrix[nSourceMatrix][1][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2]) +
298 matrix[nSourceMatrix][2][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][0][2]);
299
300 float idet = 1.0f / det;
301 matrix[3][0][0] = (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) * idet;
302 matrix[3][1][0] = (matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][2]) * idet;
303 matrix[3][2][0] = (matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][1] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][1]) * idet;
304 matrix[3][0][1] = (matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2]) * idet;
305 matrix[3][1][1] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][0][2]) * idet;
306 matrix[3][2][1] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][1]) * idet;
307 matrix[3][0][2] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][1]) * idet;
308 matrix[3][1][2] = (matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][2]) * idet;
309 matrix[3][2][2] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][1] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][0]) * idet;
310 bDirty = false;
311 }
312 }
313}
314
315#endif
316#endif
Definition olcPGEX_Graphics2D.h:90
void Translate(float ox, float oy)
void Rotate(float fTheta)
void Shear(float sx, float sy)
void Backward(float in_x, float in_y, float &out_x, float &out_y)
void Perspective(float ox, float oy)
void Scale(float sx, float sy)
void Forward(float in_x, float in_y, float &out_x, float &out_y)
Definition olcPGEX_Graphics2D.h:86
static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform)
Definition olcPixelGameEngine.h:1615
static PixelGameEngine * pge
Definition olcPixelGameEngine.h:1627
virtual bool Draw(int32_t x, int32_t y, Pixel p=olc::WHITE)
Definition olcPixelGameEngine.h:1047
Pixel GetPixel(int32_t x, int32_t y) const
int32_t height
Definition olcPixelGameEngine.h:1060
int32_t width
Definition olcPixelGameEngine.h:1059
Definition olcPixelGameEngine.h:593