1 /*
2  *  This file is part of Dune Legacy.
3  *
4  *  Dune Legacy is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Dune Legacy is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Dune Legacy.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef DRAWINGRECTHELPER_H
19 #define DRAWINGRECTHELPER_H
20 
21 #include <SDL.h>
22 
23 extern SDL_Renderer* renderer;
24 
25 enum class HAlign {
26     Left,
27     Center,
28     Right,
29 };
30 
31 enum class VAlign {
32     Top,
33     Center,
34     Bottom,
35 };
36 
37 /**
38     Returns the width of this surface
39     \param  pSurface    the surface to consider
40     \return the width of pSurface
41 */
getWidth(SDL_Surface * pSurface)42 inline int getWidth(SDL_Surface *pSurface) {
43     return pSurface->w;
44 }
45 
46 /**
47     Returns the height of this surface
48     \param  pSurface    the surface to consider
49     \return the height of pSurface
50 */
getHeight(SDL_Surface * pSurface)51 inline int getHeight(SDL_Surface *pSurface) {
52     return pSurface->h;
53 }
54 
55 /**
56     Returns the width of this texture
57     \param  pTexture    the surface to consider
58     \return the width of pTexture
59 */
getWidth(SDL_Texture * pTexture)60 inline int getWidth(SDL_Texture *pTexture) {
61     int w;
62     SDL_QueryTexture(pTexture, nullptr, nullptr, &w, nullptr);
63     return w;
64 }
65 
66 /**
67     Returns the height of this texture
68     \param  pTexture    the surface to consider
69     \return the height of pTexture
70 */
getHeight(SDL_Texture * pTexture)71 inline int getHeight(SDL_Texture *pTexture) {
72     int h;
73     SDL_QueryTexture(pTexture, nullptr, nullptr, nullptr, &h);
74     return h;
75 }
76 
77 /**
78     Calculates the source rect for drawing the sprite at (row, col) in pSurface.
79     \param  pSurface    the surface to calculate the rect for
80     \param  col         the zero-based column index of the sprite
81     \param  numCols     the number of sprites per row in pSurface
82     \param  row         the zero-based row index of the sprite (default is 0)
83     \param  numRows     the number of sprites per column in pSurface (default is 1)
84     \return the rectangle for drawing the specified sprite from pSurface when passed to SDL_BlitSurface
85 */
86 inline SDL_Rect calcSpriteSourceRect(SDL_Surface *pSurface, int col, int numCols, int row = 0, int numRows = 1) {
87     SDL_Rect rect = { col * (pSurface->w/numCols), row * (pSurface->h/numRows), pSurface->w/numCols, pSurface->h/numRows };
88     return rect;
89 }
90 
91 /**
92     Calculates the source rect for drawing the sprite at (row, col) in pTexture.
93     \param  pTexture    the texture to calculate the rect for
94     \param  col         the zero-based column index of the sprite
95     \param  numCols     the number of sprites per row in pTexture
96     \param  row         the zero-based row index of the sprite (default is 0)
97     \param  numRows     the number of sprites per column in pTexture (default is 1)
98     \return the rectangle for drawing the specified sprite from pTexture when passed to SDL_RenderCopy
99 */
100 inline SDL_Rect calcSpriteSourceRect(SDL_Texture *pTexture, int col, int numCols, int row = 0, int numRows = 1) {
101     int w;
102     int h;
103     SDL_QueryTexture(pTexture, nullptr, nullptr, &w, &h);
104     SDL_Rect rect = { col * (w/numCols), row * (h/numRows), w/numCols, h/numRows };
105     return rect;
106 }
107 
108 /**
109     Calculates the drawing rectangle for drawing a sprite from pSurface at (x,y). The parameters halign and valign determine which coordinate in the sprite
110     is drawn at (x,y), e.g. if they are HAlign::Right and VAlign::Bottom the bottom right corner of the sprite is drawn at position (x,y)
111     \param  pSurface    the surface to calculate the rect for
112     \param  x           the x-coordinate
113     \param  y           the y-coordinate
114     \param  numCols     the number of sprites in each column
115     \param  numRows     the number of sprites in each row (default is 1)
116     \param  halign      the horizontal alignment of pSurface (default is HAlign::Left)
117     \param  valign      the vertical alignment of pSurface (default is VAlign::Top)
118     \return the rectangle for drawing pSurface at the specified position when passed to SDL_BlitSurface
119 */
120 inline SDL_Rect calcSpriteDrawingRect(SDL_Surface* pSurface, int x, int y, int numCols, int numRows = 1, HAlign halign = HAlign::Left, VAlign valign = VAlign::Top) {
121     SDL_Rect rect = { x, y, pSurface->w/numCols, pSurface->h/numRows };
122 
123     switch(halign) {
124         case HAlign::Left:      /*nothing*/         break;
125         case HAlign::Center:    rect.x -= rect.w/2; break;
126         case HAlign::Right:     rect.x -= rect.w-1; break;
127     }
128 
129     switch(valign) {
130         case VAlign::Top:       /*nothing*/         break;
131         case VAlign::Center:    rect.y -= rect.h/2; break;
132         case VAlign::Bottom:    rect.y -= rect.h-1; break;
133     }
134 
135     return rect;
136 }
137 
138 /**
139     Calculates the drawing rectangle for drawing a sprite from pTexture at (x,y). The parameters halign and valign determine which coordinate in the sprite
140     is drawn at (x,y), e.g. if they are HAlign::Right and VAlign::Bottom the bottom right corner of the sprite is drawn at position (x,y)
141     \param  pTexture    the texture to calculate the rect for
142     \param  x           the x-coordinate
143     \param  y           the y-coordinate
144     \param  numCols     the number of sprites in each column
145     \param  numRows     the number of sprites in each row (default is 1)
146     \param  halign      the horizontal alignment of pTexture (default is HAlign::Left)
147     \param  valign      the vertical alignment of pTexture (default is VAlign::Top)
148     \return the rectangle for drawing pTexture at the specified position when passed to SDL_RenderCopy
149 */
150 inline SDL_Rect calcSpriteDrawingRect(SDL_Texture* pTexture, int x, int y, int numCols, int numRows = 1, HAlign halign = HAlign::Left, VAlign valign = VAlign::Top) {
151     SDL_Rect rect = { x, y, 0, 0 };
152     SDL_QueryTexture(pTexture, nullptr, nullptr, &rect.w, &rect.h);
153 
154     rect.w /= numCols;
155     rect.h /= numRows;
156 
157     switch(halign) {
158         case HAlign::Left:      /*nothing*/         break;
159         case HAlign::Center:    rect.x -= rect.w/2; break;
160         case HAlign::Right:     rect.x -= rect.w-1; break;
161     }
162 
163     switch(valign) {
164         case VAlign::Top:       /*nothing*/         break;
165         case VAlign::Center:    rect.y -= rect.h/2; break;
166         case VAlign::Bottom:    rect.y -= rect.h-1; break;
167     }
168 
169     return rect;
170 }
171 
172 /**
173     Calculates the drawing rectangle for drawing pSurface at (x,y). The parameters halign and valign determine which coordinate in pSurface
174     is drawn at (x,y), e.g. if they are HAlign::Right and VAlign::Bottom the bottom right corner of pSurface is drawn at position (x,y)
175     \param  pSurface    the surface to calculate the rect for
176     \param  x           the x-coordinate
177     \param  y           the y-coordinate
178     \param  halign      the horizontal alignment of pSurface (default is HAlign::Left)
179     \param  valign      the vertical alignment of pSurface (default is VAlign::Top)
180     \return the rectangle for drawing pSurface at the specified position when passed to SDL_BlitSurface
181 */
182 inline SDL_Rect calcDrawingRect(SDL_Surface* pSurface, int x, int y, HAlign halign = HAlign::Left, VAlign valign = VAlign::Top) {
183     return calcSpriteDrawingRect(pSurface, x, y, 1, 1, halign, valign);
184 }
185 
186 /**
187     Calculates the drawing rectangle for drawing pTexture at (x,y). The parameters halign and valign determine which coordinate in pTexture
188     is drawn at (x,y), e.g. if they are HAlign::Right and VAlign::Bottom the bottom right corner of pTexture is drawn at position (x,y)
189     \param  pTexture    the texture to calculate the rect for
190     \param  x           the x-coordinate
191     \param  y           the y-coordinate
192     \param  halign      the horizontal alignment of pTexture (default is HAlign::Left)
193     \param  valign      the vertical alignment of pTexture (default is VAlign::Top)
194     \return the rectangle for drawing pTexture at the specified position when passed to SDL_RenderCopy
195 */
196 inline SDL_Rect calcDrawingRect(SDL_Texture* pTexture, int x, int y, HAlign halign = HAlign::Left, VAlign valign = VAlign::Top) {
197     return calcSpriteDrawingRect(pTexture, x, y, 1, 1, halign, valign);
198 }
199 
200 /**
201     Returns size of the rendering target.
202     \return the rectangle describing the size (w,h) of the rendering target (x and y are always zero)
203 */
getRendererSize()204 inline SDL_Rect getRendererSize() {
205     SDL_Rect rect = {0, 0, 0, 0};
206     SDL_RenderGetLogicalSize(renderer, &rect.w, &rect.h);
207     if(rect.w == 0 || rect.h == 0) {
208         SDL_GetRendererOutputSize(renderer, &rect.w, &rect.h);
209     }
210     return rect;
211 }
212 
213 /**
214     Returns the width of the rendering target.
215     \return the width of the rendering target
216 */
getRendererWidth()217 inline int getRendererWidth() {
218     return getRendererSize().w;
219 }
220 
221 /**
222     Returns the height of the rendering target.
223     \return the height of the rendering target
224 */
getRendererHeight()225 inline int getRendererHeight() {
226     return getRendererSize().h;
227 }
228 
229 /**
230     Calculates the drawing rectangle for drawing pSurface at the edge or in the center of rect.
231     The parameters halign and valign determine at which edge pSurface is drawn, e.g. HAlign::Left and VAlign::Top draws pSurface in the
232     top left corner.
233     \param  pSurface    the surface to calculate the rect for
234     \param  rect        the rect to center around
235     \param  halign      the horizontal alignment of pSurface (default is HAlign::Center)
236     \param  valign      the vertical alignment of pSurface (default is VAlign::Center)
237     \return the rectangle for drawing pSurface at the specified position when passed to SDL_BlitSurface
238 */
239 inline SDL_Rect calcAlignedDrawingRect(SDL_Surface* pSurface, const SDL_Rect& rect, HAlign halign = HAlign::Center, VAlign valign = VAlign::Center) {
240     int x = 0;
241     int y = 0;
242 
243     switch(halign) {
244         case HAlign::Left:      x = 0;          break;
245         case HAlign::Center:    x = rect.w/2;   break;
246         case HAlign::Right:     x = rect.w-1;   break;
247     }
248 
249     switch(valign) {
250         case VAlign::Top:       y = 0;          break;
251         case VAlign::Center:    y = rect.h/2;   break;
252         case VAlign::Bottom:    y = rect.h-1;   break;
253     }
254 
255     return calcDrawingRect(pSurface, x, y, halign, valign);
256 }
257 
258 /**
259     Calculates the drawing rectangle for drawing pSurface at the edge or in the center of the current rendering target (usually the screen).
260     The parameters halign and valign determine at which edge pSurface is drawn, e.g. HAlign::Left and VAlign::Top draws pSurface in the
261     top left corner.
262     \param  pSurface    the surface to calculate the rect for
263     \param  halign      the horizontal alignment of pSurface (default is HAlign::Center)
264     \param  valign      the vertical alignment of pSurface (default is VAlign::Center)
265     \return the rectangle for drawing pSurface at the specified position when passed to SDL_BlitSurface
266 */
267 inline SDL_Rect calcAlignedDrawingRect(SDL_Surface* pSurface, HAlign halign = HAlign::Center, VAlign valign = VAlign::Center) {
268     return calcAlignedDrawingRect(pSurface, getRendererSize(), halign, valign);
269 }
270 
271 /**
272     Calculates the drawing rectangle for drawing pSurface at the edge or in the center of pBaseSurface.
273     The parameters halign and valign determine at which edge pSurface is drawn, e.g. HAlign::Left and VAlign::Top draws pSurface in the
274     top left corner.
275     \param  pSurface        the surface to calculate the rect for
276     \param  pBaseSurface    the rect to center around
277     \param  halign          the horizontal alignment of pSurface (default is HAlign::Center)
278     \param  valign          the vertical alignment of pSurface (default is VAlign::Center)
279     \return the rectangle for drawing pSurface at the specified position when passed to SDL_BlitSurface
280 */
281 inline SDL_Rect calcAlignedDrawingRect(SDL_Surface* pSurface, SDL_Surface* pBaseSurface, HAlign halign = HAlign::Center, VAlign valign = VAlign::Center) {
282     SDL_Rect rect = {0, 0, pBaseSurface->w, pBaseSurface->h};
283     return calcAlignedDrawingRect(pSurface, rect, halign, valign);
284 }
285 
286 /**
287     Calculates the drawing rectangle for drawing pTexture at the edge or in the center of rect.
288     The parameters halign and valign determine at which edge pTexture is drawn, e.g. HAlign::Left and VAlign::Top draws pTexture in the
289     top left corner.
290     \param  pTexture    the texture to calculate the rect for
291     \param  rect        the rect to center around
292     \param  halign      the horizontal alignment of pTexture (default is HAlign::Center)
293     \param  valign      the vertical alignment of pTexture (default is VAlign::Center)
294     \return the rectangle for drawing pTexture at the specified position when passed to SDL_RenderCopy
295 */
296 inline SDL_Rect calcAlignedDrawingRect(SDL_Texture* pTexture, const SDL_Rect& rect, HAlign halign = HAlign::Center, VAlign valign = VAlign::Center) {
297     int x = 0;
298     int y = 0;
299 
300     switch(halign) {
301         case HAlign::Left:      x = 0;          break;
302         case HAlign::Center:    x = rect.w/2;   break;
303         case HAlign::Right:     x = rect.w-1;   break;
304     }
305 
306     switch(valign) {
307         case VAlign::Top:       y = 0;          break;
308         case VAlign::Center:    y = rect.h/2;   break;
309         case VAlign::Bottom:    y = rect.h-1;   break;
310     }
311 
312     return calcDrawingRect(pTexture, x, y, halign, valign);
313 }
314 
315 /**
316     Calculates the drawing rectangle for drawing pTexture at the edge or in the center of the current rendering target (usually the screen).
317     The parameters halign and valign determine at which edge pTexture is drawn, e.g. HAlign::Left and VAlign::Top draws pTexture in the
318     top left corner.
319     \param  pTexture    the texture to calculate the rect for
320     \param  halign      the horizontal alignment of pTexture (default is HAlign::Center)
321     \param  valign      the vertical alignment of pTexture (default is VAlign::Center)
322     \return the rectangle for drawing pTexture at the specified position when passed to SDL_RenderCopy
323 */
324 inline SDL_Rect calcAlignedDrawingRect(SDL_Texture* pTexture, HAlign halign = HAlign::Center, VAlign valign = VAlign::Center) {
325     return calcAlignedDrawingRect(pTexture, getRendererSize(), halign, valign);
326 }
327 
328 
329 #endif // DRAWINGRECTHELPER_H
330