1 /////////////////////////////////////////
2 //
3 // OpenLieroX
4 //
5 // Auxiliary Software class library
6 //
7 // based on the work of JasonB
8 // enhanced by Dark Charlie and Albert Zeyer
9 //
10 // code under LGPL
11 //
12 /////////////////////////////////////////
13
14
15 // Graphics primitives
16 // Created 12/11/01
17 // By Jason Boettcher
18
19
20 #ifndef __GFXPRIMITIVES_H__
21 #define __GFXPRIMITIVES_H__
22
23 #include <SDL.h>
24 #include <SDL_image.h>
25 #include <string>
26 #include <assert.h>
27
28 #include "Color.h"
29 #include "SmartPointer.h"
30 #include "Debug.h"
31 #include "CVec.h"
32
33
34 //
35 // Misc routines, defines and variables
36 //
37
38 // Flags used for screen and new surfaces
39 extern int iSurfaceFormat;
40
41 // Like in SDL_video.c in SDL_DisplayFormatAlpha
42 #define ALPHASURFACE_RMASK 0x00ff0000
43 #define ALPHASURFACE_GMASK 0x0000ff00
44 #define ALPHASURFACE_BMASK 0x000000ff
45 #define ALPHASURFACE_AMASK 0xff000000
46
47 // Gradient direction
48 enum GradientDirection {
49 grdHorizontal,
50 grdVertical
51 };
52
53
54
55 void DumpPixelFormat(const SDL_PixelFormat* format);
56 bool PixelFormatEqual(const SDL_PixelFormat* fm1, const SDL_PixelFormat* fm2);
57 bool IsCorrectSurfaceFormat(const SDL_PixelFormat* format);
58
59
60 /////////////////////
61 // Locking and unlocking routines, must be called before doing anything with pixels
LockSurface(SDL_Surface * bmp)62 inline bool LockSurface(SDL_Surface * bmp) {
63 if (SDL_MUSTLOCK(bmp))
64 return SDL_LockSurface(bmp) != -1;
65 return true;
66 }
LockSurface(const SmartPointer<SDL_Surface> & bmp)67 inline bool LockSurface(const SmartPointer<SDL_Surface> & bmp) {
68 return LockSurface(bmp.get());
69 }
70
UnlockSurface(SDL_Surface * bmp)71 inline void UnlockSurface(SDL_Surface * bmp) {
72 if (SDL_MUSTLOCK(bmp))
73 SDL_UnlockSurface(bmp);
74 }
UnlockSurface(const SmartPointer<SDL_Surface> & bmp)75 inline void UnlockSurface(const SmartPointer<SDL_Surface> & bmp) {
76 UnlockSurface(bmp.get());
77 }
78
79 #define LOCK_OR_QUIT(bmp) { if(!LockSurface(bmp)) return; }
80 #define LOCK_OR_FAIL(bmp) { if(!LockSurface(bmp)) return false; }
81
82
83 ////////////////////
84 // Returns number of bytes the surface takes in memory
GetSurfaceMemorySize(SDL_Surface * surf)85 inline size_t GetSurfaceMemorySize(SDL_Surface *surf) {
86 if (surf)
87 return sizeof(SDL_Surface) + sizeof(SDL_PixelFormat) + surf->w * surf->h * surf->format->BytesPerPixel;
88 else
89 return 0;
90 }
91
92 //
93 // Clipping routines
94 //
95
96 /////////////////////
97 // Clip the line to the surface
98 bool ClipLine(SDL_Surface * dst, int * x1, int * y1, int * x2, int * y2);
ClipLine(const SmartPointer<SDL_Surface> & bmp,int * x1,int * y1,int * x2,int * y2)99 inline bool ClipLine(const SmartPointer<SDL_Surface> & bmp, int * x1, int * y1, int * x2, int * y2){
100 return ClipLine(bmp.get(), x1, y1, x2, y2);
101 }
102
103 class SDLRectBasic : public SDL_Rect {
104 public:
105 typedef Sint16 Type;
106 typedef Uint16 TypeS;
107
SDLRectBasic()108 SDLRectBasic() { this->SDL_Rect::x = this->SDL_Rect::y = this->SDL_Rect::w = this->SDL_Rect::h = 0; }
SDLRectBasic(const SDL_Rect & r)109 SDLRectBasic(const SDL_Rect & r): SDL_Rect(r) {}
SDLRectBasic(Type _x,Type _y,TypeS _w,TypeS _h)110 SDLRectBasic(Type _x, Type _y, TypeS _w, TypeS _h) { SDL_Rect::x = _x; SDL_Rect::y = _y; SDL_Rect::w = _w; SDL_Rect::h = _h; }
x()111 Type& x() { return this->SDL_Rect::x; }
y()112 Type& y() { return this->SDL_Rect::y; }
width()113 TypeS& width() { return this->SDL_Rect::w; }
height()114 TypeS& height() { return this->SDL_Rect::h; }
115
x()116 Type x() const { return this->SDL_Rect::x; }
y()117 Type y() const { return this->SDL_Rect::y; }
width()118 TypeS width() const { return this->SDL_Rect::w; }
height()119 TypeS height() const { return this->SDL_Rect::h; }
120 };
121
122 template<typename _Type, typename _TypeS>
123 class RefRectBasic {
124 public:
125 typedef _Type Type;
126 typedef _TypeS TypeS;
127 private:
128 Type *m_x, *m_y;
129 TypeS *m_w, *m_h;
130 public:
RefRectBasic()131 RefRectBasic() : m_x(NULL), m_y(NULL), m_w(NULL), m_h(NULL) {
132 // HINT: never use this constructor directly; it's only there to avoid some possible compiler-warnings
133 assert(false);
134 }
RefRectBasic(Type & x_,Type & y_,TypeS & w_,TypeS & h_)135 RefRectBasic(Type& x_, Type& y_, TypeS& w_, TypeS& h_)
136 : m_x(&x_), m_y(&y_), m_w(&w_), m_h(&h_) {}
137
x()138 Type& x() { return *m_x; }
y()139 Type& y() { return *m_y; }
width()140 TypeS& width() { return *m_w; }
height()141 TypeS& height() { return *m_h; }
142
x()143 Type x() const { return *m_x; }
y()144 Type y() const { return *m_y; }
width()145 TypeS width() const { return *m_w; }
height()146 TypeS height() const { return *m_h; }
147 };
148
149
150 // _RectBasic has to provide the following public members:
151 // typedef ... Type; // type for x,y
152 // typedef ... TypeS; // type for w,h
153 // Type x();
154 // Type y();
155 // TypeS width();
156 // TypeS height();
157 // and the above as const
158 template<typename _RectBasic>
159 class OLXRect : public _RectBasic {
160 public:
161
OLXRect(const _RectBasic & r)162 OLXRect(const _RectBasic & r): _RectBasic(r) {}
163
OLXRect(typename _RectBasic::Type x,typename _RectBasic::Type y,typename _RectBasic::TypeS w,typename _RectBasic::TypeS h)164 OLXRect(typename _RectBasic::Type x, typename _RectBasic::Type y, typename _RectBasic::TypeS w, typename _RectBasic::TypeS h): _RectBasic(x, y, w, h) {}
165
166 class GetX2 {
167 protected:
168 const _RectBasic* base;
169 public:
GetX2(const _RectBasic * b)170 GetX2(const _RectBasic* b) : base(b) {}
Type()171 operator typename _RectBasic::Type () const
172 { return base->x() + base->width(); }
173 };
174 class AssignX2 : public GetX2 {
175 private:
176 _RectBasic* base;
177 public:
AssignX2(_RectBasic * b)178 AssignX2(_RectBasic* b) : GetX2(b), base(b) {}
179 AssignX2& operator=(const typename _RectBasic::Type& v)
180 { base->width() = v - base->x(); return *this; }
181 };
182
x2()183 AssignX2 x2() { return AssignX2(this); }
x2()184 GetX2 x2() const { return GetX2(this); }
185
186 class GetY2 {
187 protected:
188 const _RectBasic* base;
189 public:
GetY2(const _RectBasic * b)190 GetY2(const _RectBasic* b) : base(b) {}
Type()191 operator typename _RectBasic::Type () const
192 { return base->y() + base->height(); }
193 };
194 class AssignY2 : public GetY2 {
195 private:
196 _RectBasic* base;
197 public:
AssignY2(_RectBasic * b)198 AssignY2(_RectBasic* b) : GetY2(b), base(b) {}
199 AssignY2& operator=(const typename _RectBasic::Type& v)
200 { base->height() = v - base->y(); return *this; }
201 };
y2()202 AssignY2 y2() { return AssignY2(this); }
y2()203 GetY2 y2() const { return GetY2(this); }
204
205 template<typename _ClipRect>
clipWith(const _ClipRect & clip)206 bool clipWith(const _ClipRect& clip) {
207 // Horizontal
208 {
209 typename OLXRect::Type orig_x2 = this->OLXRect::x2();
210 this->OLXRect::x() = MAX( (typename OLXRect::Type)this->OLXRect::x(), (typename OLXRect::Type)clip.x() );
211 this->OLXRect::x2() = MIN( orig_x2, (typename OLXRect::Type)clip.x2() );
212 this->OLXRect::x2() = MAX( this->OLXRect::x(), (typename OLXRect::Type)this->OLXRect::x2() );
213 }
214
215 // Vertical
216 {
217 typename OLXRect::Type orig_y2 = this->OLXRect::y2();
218 this->OLXRect::y() = MAX( (typename OLXRect::Type)this->OLXRect::y(), (typename OLXRect::Type)clip.y() );
219 this->OLXRect::y2() = MIN( orig_y2, (typename OLXRect::Type)clip.y2() );
220 this->OLXRect::y2() = MAX( this->OLXRect::y(), (typename OLXRect::Type)this->OLXRect::y2() );
221 }
222
223 return (this->OLXRect::width() && this->OLXRect::height());
224 }
225 };
226
227
228 typedef OLXRect<SDLRectBasic> SDLRect; // Use this for creating clipping rects from SDL
229
230 template<typename _Type, typename _TypeS, typename _ClipRect>
ClipRefRectWith(_Type & x,_Type & y,_TypeS & w,_TypeS & h,const _ClipRect & clip)231 bool ClipRefRectWith(_Type& x, _Type& y, _TypeS& w, _TypeS& h, const _ClipRect& clip) {
232 RefRectBasic<_Type, _TypeS> refrect = RefRectBasic<_Type, _TypeS>(x, y, w, h);
233 return ((OLXRect<RefRectBasic<_Type, _TypeS> >&) refrect).clipWith(clip);
234 }
235
236 template<typename _ClipRect>
ClipRefRectWith(SDL_Rect & rect,const _ClipRect & clip)237 bool ClipRefRectWith(SDL_Rect& rect, const _ClipRect& clip) {
238 RefRectBasic<Sint16,Uint16> refrect(rect.x, rect.y, rect.w, rect.h);
239 return OLXRect< RefRectBasic<Sint16,Uint16> >(refrect).clipWith(clip);
240 }
241
242
243
244 /////////////////////////
245 // Performs one side (horizontal or vertical) clip
246 // c - x or y; d - width or height
247 template<typename T1, typename T2>
_OneSideClip(T1 & c,T2 & d,const T1 clip_c,const T2 clip_d)248 bool _OneSideClip(T1& c, T2& d, const T1 clip_c, const T2 clip_d) {
249 if (c < clip_c) {
250 d += c - clip_c;
251 c = clip_c;
252 if (d <= 0) {
253 d = 0;
254 return false;
255 }
256 }
257
258 if (c + d >= clip_c + clip_d) {
259 if (c >= clip_c + clip_d) {
260 d = 0;
261 return false;
262 }
263
264 d = clip_c + clip_d - c;
265 }
266
267 return true;
268 }
269
270 template<typename T1, typename T2, typename T3, typename T4>
OneSideClip(T1 & c,T2 & d,const T3 clip_c,const T4 clip_d)271 bool OneSideClip(T1& c, T2& d, const T3 clip_c, const T4 clip_d) {
272 return _OneSideClip(c, d, (T1)clip_c, (T2)clip_d);
273 }
274
275 ////////////////
276 // Create a SDL rect
MakeRect(int x,int y,int w,int h)277 inline SDL_Rect MakeRect(int x, int y, int w, int h)
278 {
279 SDL_Rect r = {(SDLRect::Type) x, (SDLRect::Type) y, (SDLRect::TypeS) w, (SDLRect::TypeS) h};
280 return r;
281 }
282
283 ////////////////
284 // Returns true if the given point is in the given rect
PointInRect(int x,int y,const SDL_Rect & r)285 inline bool PointInRect(int x, int y, const SDL_Rect& r)
286 {
287 return (r.x <= x) && (x <= (r.x + r.w)) &&
288 (r.y <= y) && (y <= (r.y + r.h));
289 }
290
291 //////////////////////
292 // Returns true if rect1 contains rect2
ContainsRect(const SDL_Rect & rect1,const SDL_Rect & rect2)293 inline bool ContainsRect(const SDL_Rect& rect1, const SDL_Rect& rect2)
294 {
295 return (rect1.x <= rect2.x) && (rect1.x + rect1.w >= rect2.x + rect2.w) &&
296 (rect1.y <= rect2.y) && (rect1.y + rect1.h >= rect2.y + rect2.h);
297 }
298
299 //
300 // Image loading and saving
301 //
302
303 //////////////////
304 // Load an image
305 SmartPointer<SDL_Surface> LoadGameImage(const std::string& _filename, bool withalpha = false);
306
307 /////////////////
308 // Loads an image and quits with error if could not load
309 #define LOAD_IMAGE(bmp,name) { if (!Load_Image(bmp,name)) return false; }
310 #define LOAD_IMAGE_WITHALPHA(bmp,name) { if (!Load_Image_WithAlpha(bmp,name)) return false; }
311 #define LOAD_IMAGE_WITHALPHA2(bmp,name1,name2) { if (!Load_Image_WithAlpha(bmp,name1) && !Load_Image_WithAlpha(bmp,name2)) return false; }
312 #define LOAD_IMAGE_WITHALPHA__OR(bmp,name,img) { if (!Load_Image_WithAlpha(bmp,name) && ((bmp = (img)).get() == NULL)) return false; }
313
314 /////////////////
315 // Gets the colorkey from the surface
316 #define COLORKEY(bmp) ((bmp)->format->colorkey)
317
318
319 /////////////////////
320 // Load an image, without alpha channel
Load_Image(SmartPointer<SDL_Surface> & bmp,const std::string & name)321 inline bool Load_Image(SmartPointer<SDL_Surface>& bmp, const std::string& name) {
322 bmp = LoadGameImage(name);
323 if (bmp.get() == NULL) {
324 warnings << "could not load alpha-image " << name << endl;
325 return false;
326 }
327 return true;
328 }
329
330 ////////////////////
331 // Load an image with alpha channel
Load_Image_WithAlpha(SmartPointer<SDL_Surface> & bmp,const std::string & name)332 inline bool Load_Image_WithAlpha(SmartPointer<SDL_Surface>& bmp, const std::string& name) {
333 bmp = LoadGameImage(name, true);
334 if (bmp.get() == NULL) {
335 warnings << "could not load image " << name << endl;
336 return false;
337 }
338 return true;
339 }
340
341 ///////////////////
342 // Save surface in the specified format
343 bool SaveSurface(SDL_Surface * image, const std::string& FileName, int Format, const std::string& Data);
SaveSurface(const SmartPointer<SDL_Surface> & image,const std::string & FileName,int Format,const std::string & Data)344 inline bool SaveSurface(const SmartPointer<SDL_Surface> & image, const std::string& FileName, int Format, const std::string& Data){
345 return SaveSurface(image.get(), FileName, Format, Data);
346 }
347
348 //
349 // Surface stuff
350 //
351
352 //////////////////
353 // Creates a buffer with the same details as the screen
354 SmartPointer<SDL_Surface> gfxCreateSurface(int width, int height, bool forceSoftware = false);
355
356
357 ///////////////////
358 // Creates an ARGB 32bit surface if screen supports no alpha or a surface like screen
359 SmartPointer<SDL_Surface> gfxCreateSurfaceAlpha(int width, int height, bool forceSoftware = false);
360
361 ////////////////////
362 // Destroys a surface
363 // Now with SmartPointer usage everywhere this function is forbidden!
364 /*
365 inline void gfxFreeSurface(const SmartPointer<SDL_Surface> & surf) {
366 if (surf == NULL)
367 return;
368
369 #ifdef DEBUG_SMARTPTR
370 printf("gfxFreeSurface() %p\n", surf.get() );
371 #endif
372 SDL_FreeSurface(surf);
373 //surf = NULL; // That's a hack that won't fix anything
374 }
375 */
376
377 //
378 // Image drawing
379 //
380
381 ///////////////
382 // Copies one surface to another (not blitting, so the alpha values are kept!)
383 void CopySurface(SDL_Surface * dst, SDL_Surface * src, int sx, int sy, int dx, int dy, int w, int h);
CopySurface(SDL_Surface * dst,const SmartPointer<SDL_Surface> & src,int sx,int sy,int dx,int dy,int w,int h)384 inline void CopySurface(SDL_Surface * dst, const SmartPointer<SDL_Surface> & src, int sx, int sy, int dx, int dy, int w, int h){
385 CopySurface(dst, src.get(), sx, sy, dx, dy, w, h);
386 }
387
388 //////////////
389 // Draw the image with a huge amount of options
390 void DrawImageAdv(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, SDL_Rect& rDest, SDL_Rect& rSrc);
391
DrawImageAdv(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,SDL_Rect & rDest,SDL_Rect & rSrc)392 inline void DrawImageAdv(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, SDL_Rect& rDest, SDL_Rect& rSrc) {
393 DrawImageAdv(bmpDest, bmpSrc.get(), rDest, rSrc);
394 }
395
396 //////////////
397 // Draw the image with a huge amount of options
DrawImageAdv(SDL_Surface * bmpDest,SDL_Surface * bmpSrc,int sx,int sy,int dx,int dy,int w,int h)398 inline void DrawImageAdv(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int sx, int sy, int dx, int dy, int w, int h) {
399 SDL_Rect r1 = { (SDLRect::Type) dx, (SDLRect::Type) dy, 0, 0 };
400 SDL_Rect r2 = { (SDLRect::Type) sx, (SDLRect::Type) sy, (SDLRect::TypeS) w, (SDLRect::TypeS) h };
401 DrawImageAdv( bmpDest, bmpSrc, r1, r2);
402 }
DrawImageAdv(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int dx,int dy,int w,int h)403 inline void DrawImageAdv(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int sx, int sy, int dx, int dy, int w, int h) {
404 DrawImageAdv(bmpDest, bmpSrc.get(), sx, sy, dx, dy, w, h);
405 }
406
407
408 ///////////////
409 // Draw the image, with more options
DrawImageEx(SDL_Surface * bmpDest,SDL_Surface * bmpSrc,int x,int y,int w,int h)410 inline void DrawImageEx(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int x, int y, int w, int h) {
411 DrawImageAdv(bmpDest, bmpSrc, 0, 0, x, y, w, h);
412 }
DrawImageEx(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int x,int y,int w,int h)413 inline void DrawImageEx(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int x, int y, int w, int h) {
414 DrawImageEx(bmpDest, bmpSrc.get(), x, y, w, h);
415 }
416
417 ///////////////
418 // Simply draw the image
DrawImage(SDL_Surface * bmpDest,SDL_Surface * bmpSrc,SDL_Rect & rDest)419 inline void DrawImage(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, SDL_Rect& rDest) {
420 if(!bmpDest) {
421 errors << "DrawImage: bmpDest not set" << endl;
422 return;
423 }
424 if(!bmpSrc) {
425 errors << "DrawImage: bmpSrc not set" << endl;
426 return;
427 }
428 SDL_BlitSurface(bmpSrc, NULL, bmpDest, &rDest);
429 }
DrawImage(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,SDL_Rect & rDest)430 inline void DrawImage(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, SDL_Rect& rDest) {
431 DrawImage(bmpDest, bmpSrc.get(), rDest);
432 }
433
434 ///////////////
435 // Simply draw the image
DrawImage(SDL_Surface * bmpDest,SDL_Surface * bmpSrc,int x,int y)436 inline void DrawImage(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int x, int y) {
437 SDL_Rect r = { (SDLRect::Type) x, (SDLRect::Type) y, (SDLRect::TypeS) bmpSrc->w, (SDLRect::TypeS) bmpSrc->h };
438 DrawImage( bmpDest, bmpSrc, r);
439 }
DrawImage(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int x,int y)440 inline void DrawImage(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int x, int y) {
441 DrawImage(bmpDest, bmpSrc.get(), x, y);
442 }
443
444 ///////////////
445 // Draws image mirror flipped
446 // WARNING: passing invalid source x/y/w/h causes a segfault
447 void DrawImageAdv_Mirror(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int sx, int sy, int dx, int dy, int w, int h);
DrawImageAdv_Mirror(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int dx,int dy,int w,int h)448 inline void DrawImageAdv_Mirror(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int sx, int sy, int dx, int dy, int w, int h) {
449 DrawImageAdv_Mirror(bmpDest, bmpSrc.get(), sx, sy, dx, dy, w, h);
450 }
451
452 void DrawImageAdv_MirrorVertical(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int sx, int sy, int dx, int dy, int w, int h);
DrawImageAdv_MirrorVertical(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int dx,int dy,int w,int h)453 inline void DrawImageAdv_MirrorVertical(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int sx, int sy, int dx, int dy, int w, int h) {
454 DrawImageAdv_MirrorVertical(bmpDest, bmpSrc.get(), sx, sy, dx, dy, w, h);
455 }
456
457 ////////////////
458 // Draws the image doubly stretched (fast)
459 void DrawImageStretch2(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int sx, int sy, int dx, int dy, int w, int h);
DrawImageStretch2(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int dx,int dy,int w,int h)460 inline void DrawImageStretch2(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int sx, int sy, int dx, int dy, int w, int h) {
461 DrawImageStretch2(bmpDest, bmpSrc.get(), sx, sy, dx, dy, w, h);
462 }
463
464 /////////////////
465 // Draws the image doubly stretched while checking for colorkey
466 void DrawImageStretch2Key(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int sx, int sy, int dx, int dy, int w, int h);
DrawImageStretch2Key(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int dx,int dy,int w,int h)467 inline void DrawImageStretch2Key(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int sx, int sy, int dx, int dy, int w, int h) {
468 DrawImageStretch2Key(bmpDest, bmpSrc.get(), sx, sy, dx, dy, w, h);
469 }
470
471 /////////////////
472 // Draws image doubly stretched, mirrored and checking for colorkey
473 // WARNING: passing invalid source x/y/w/h causes a segfault
474 void DrawImageStretchMirrorKey(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int sx, int sy, int dx, int dy, int w, int h);
DrawImageStretchMirrorKey(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int dx,int dy,int w,int h)475 inline void DrawImageStretchMirrorKey(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int sx, int sy, int dx, int dy, int w, int h) {
476 DrawImageStretchMirrorKey(bmpDest, bmpSrc.get(), sx, sy, dx, dy, w, h);
477 }
478
GetCopiedImage(SDL_Surface * bmpSrc)479 inline SmartPointer<SDL_Surface> GetCopiedImage(SDL_Surface* bmpSrc) {
480 SmartPointer<SDL_Surface> result = SDL_CreateRGBSurface(
481 bmpSrc->flags,
482 bmpSrc->w, bmpSrc->h,
483 bmpSrc->format->BitsPerPixel,
484 bmpSrc->format->Rmask,
485 bmpSrc->format->Gmask,
486 bmpSrc->format->Bmask,
487 bmpSrc->format->Amask);
488 if (result.get() == NULL) return NULL;
489 CopySurface(result.get(), bmpSrc, 0, 0, 0, 0, bmpSrc->w, bmpSrc->h);
490 return result;
491 }
GetCopiedImage(const SmartPointer<SDL_Surface> & bmpSrc)492 inline SmartPointer<SDL_Surface> GetCopiedImage(const SmartPointer<SDL_Surface> & bmpSrc) {
493 return GetCopiedImage(bmpSrc.get());
494 }
495
496 /////////////////
497 // Creates a new surface of the same size and draws the image mirror flipped onto it
GetMirroredImage(SDL_Surface * bmpSrc)498 inline SmartPointer<SDL_Surface> GetMirroredImage(SDL_Surface* bmpSrc) {
499 SmartPointer<SDL_Surface> result = SDL_CreateRGBSurface(
500 bmpSrc->flags,
501 bmpSrc->w, bmpSrc->h,
502 bmpSrc->format->BitsPerPixel,
503 bmpSrc->format->Rmask,
504 bmpSrc->format->Gmask,
505 bmpSrc->format->Bmask,
506 bmpSrc->format->Amask);
507 if (result.get() == NULL) return NULL;
508 DrawImageAdv_Mirror(result.get(), bmpSrc, 0, 0, 0, 0, bmpSrc->w, bmpSrc->h);
509 return result;
510 }
GetMirroredImage(const SmartPointer<SDL_Surface> & bmpSrc)511 inline SmartPointer<SDL_Surface> GetMirroredImage(const SmartPointer<SDL_Surface> & bmpSrc) {
512 return GetMirroredImage(bmpSrc.get());
513 }
514
515 /////////////////
516 // Draws a sprite doubly stretched but not so advanced
DrawImageStretch(SDL_Surface * bmpDest,SDL_Surface * bmpSrc,int dx,int dy)517 inline void DrawImageStretch(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int dx, int dy) {
518 DrawImageStretch2(bmpDest,bmpSrc,0,0,dx,dy,bmpSrc->w,bmpSrc->h);
519 }
DrawImageStretch(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int dx,int dy)520 inline void DrawImageStretch(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int dx, int dy) {
521 DrawImageStretch(bmpDest, bmpSrc.get(), dx, dy);
522 }
523
524 /////////////////
525 // Draws a sprite doubly stretched, with a colour key and not so advanced
DrawImageStretchKey(SDL_Surface * bmpDest,SDL_Surface * bmpSrc,int dx,int dy)526 inline void DrawImageStretchKey(SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int dx, int dy) {
527 DrawImageStretch2Key(bmpDest, bmpSrc, 0, 0, dx, dy, bmpSrc->w, bmpSrc->h);
528 }
DrawImageStretchKey(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int dx,int dy)529 inline void DrawImageStretchKey(SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int dx, int dy) {
530 DrawImageStretchKey(bmpDest, bmpSrc.get(), dx, dy);
531 }
532
533 /////////////////
534 // Draws the image resized according to ratios
535 void DrawImageResizedAdv( SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int sx, int sy, int dx, int dy, int sw, int sh, float xratio, float yratio);
536 void DrawImageResizedAdv( SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int sx, int sy, int dx, int dy, int sw, int sh, int dw, int dh);
DrawImageResizedAdv(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int dx,int dy,int sw,int sh,float xratio,float yratio)537 inline void DrawImageResizedAdv( SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int sx, int sy, int dx, int dy, int sw, int sh, float xratio, float yratio) {
538 DrawImageResizedAdv( bmpDest, bmpSrc.get(), sx, sy, dx, dy, sw, sh, xratio, yratio);
539 }
DrawImageResizedAdv(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int dx,int dy,int sw,int sh,int dw,int dh)540 inline void DrawImageResizedAdv( SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int sx, int sy, int dx, int dy, int sw, int sh, int dw, int dh) {
541 DrawImageResizedAdv( bmpDest, bmpSrc.get(), sx, sy, dx, dy, sw, sh, dw, dh);
542 }
543
544 /////////////////
545 // Draws the image nicely resampled, blur says how much the result should be blurred
546 void DrawImageResampledAdv( SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int sx, int sy, int dx, int dy, int sw, int sh, float xratio, float yratio);
547 void DrawImageResampledAdv( SDL_Surface * bmpDest, SDL_Surface * bmpSrc, int sx, int sy, int dx, int dy, int sw, int sh, int dw, int dh);
DrawImageResampledAdv(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int dx,int dy,int sw,int sh,float xratio,float yratio)548 inline void DrawImageResampledAdv( SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int sx, int sy, int dx, int dy, int sw, int sh, float xratio, float yratio) {
549 DrawImageResampledAdv( bmpDest, bmpSrc.get(), sx, sy, dx, dy, sw, sh, xratio, yratio );
550 }
DrawImageResampledAdv(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int dx,int dy,int sw,int sh,int dw,int dh)551 inline void DrawImageResampledAdv( SDL_Surface * bmpDest, const SmartPointer<SDL_Surface> & bmpSrc, int sx, int sy, int dx, int dy, int sw, int sh, int dw, int dh) {
552 DrawImageResampledAdv( bmpDest, bmpSrc.get(), sx, sy, dx, dy, sw, sh, dw, dh );
553 }
554
555 //////////////////
556 // Draws the image in double size using the scale2x algorithm
557 void DrawImageScale2x(SDL_Surface* bmpDest, SDL_Surface* bmpSrc, int sx, int sy, int dx, int dy, int w, int h);
DrawImageScale2x(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int dx,int dy,int w,int h)558 inline void DrawImageScale2x(SDL_Surface* bmpDest, const SmartPointer<SDL_Surface>& bmpSrc, int sx, int sy, int dx, int dy, int w, int h) {
559 DrawImageScale2x(bmpDest, bmpSrc.get(), sx, sy, dx, dy, w, h);
560 }
561
562 void DrawImageScaleHalf(SDL_Surface* bmpDest, SDL_Surface* bmpSrc);
563
564 ///////////////////
565 // Tiles the source image onto the dest image
566 void DrawImageTiled(SDL_Surface *bmpDest, SDL_Surface *bmpSrc, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh);
567 void DrawImageTiledX(SDL_Surface *bmpDest, SDL_Surface *bmpSrc, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh);
568 void DrawImageTiledY(SDL_Surface *bmpDest, SDL_Surface *bmpSrc, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh);
569
DrawImageTiled(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int sw,int sh,int dx,int dy,int dw,int dh)570 inline void DrawImageTiled(SDL_Surface *bmpDest, const SmartPointer<SDL_Surface>& bmpSrc, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh) {
571 DrawImageTiled(bmpDest, bmpSrc.get(), sx, sy, sw, sh, dx, dy, dw, dh);
572 }
DrawImageTiledX(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int sw,int sh,int dx,int dy,int dw,int dh)573 inline void DrawImageTiledX(SDL_Surface *bmpDest, const SmartPointer<SDL_Surface>& bmpSrc, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh) {
574 DrawImageTiledX(bmpDest, bmpSrc.get(), sx, sy, sw, sh, dx, dy, dw, dh);
575 }
576
DrawImageTiledY(SDL_Surface * bmpDest,const SmartPointer<SDL_Surface> & bmpSrc,int sx,int sy,int sw,int sh,int dx,int dy,int dw,int dh)577 inline void DrawImageTiledY(SDL_Surface *bmpDest, const SmartPointer<SDL_Surface>& bmpSrc, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh) {
578 DrawImageTiledX(bmpDest, bmpSrc.get(), sx, sy, sw, sh, dx, dy, dw, dh);
579 }
580
581 SmartPointer<SDL_Surface> GenerateShadowSurface(SDL_Surface *object, unsigned char opacity = 96);
582
583 //
584 // Pixel and color routines
585 //
586
587
588 ////////////////////
589 // Get address of a pixel
GetPixelAddr(const SDL_Surface * surf,int x,int y)590 inline Uint8 *GetPixelAddr(const SDL_Surface *surf, int x, int y) {
591 return (Uint8 *)surf->pixels + y * surf->pitch + x * surf->format->BytesPerPixel;
592 }
593
594 /////////////////
595 // Put pixel to a specified address
596 // WARNING: passing an invalid adress will cause a segfault
597 // NOTE: destination surface must be locked before calling this
PutPixelToAddr(Uint8 * p,Uint32 color,short bpp)598 inline void PutPixelToAddr(Uint8* p, Uint32 color, short bpp) {
599 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
600 memcpy(p, (Uint8*)&color + 4 - bpp, bpp);
601 #else
602 memcpy(p, &color, bpp);
603 #endif
604 }
605
606 //////////////
607 // Pixel drawing
608 // WARNING: passing invalid coordinates will cause a segfault
609 // NOTE: bmpDest must be locked before calling this
PutPixel(SDL_Surface * bmpDest,int x,int y,Uint32 color)610 inline void PutPixel(SDL_Surface * bmpDest, int x, int y, Uint32 color) {
611 PutPixelToAddr(
612 (Uint8*)bmpDest->pixels + y * bmpDest->pitch + x * bmpDest->format->BytesPerPixel,
613 color,
614 bmpDest->format->BytesPerPixel);
615 }
616
617 ////////////////
618 // Get a pixel from an 8bit address
619 // WARNING: passing invalid adress will cause a segfault
620 // NOTE: the surface must be locked before calling this
GetPixelFromAddr(Uint8 * p,short bpp)621 inline Uint32 GetPixelFromAddr(Uint8* p, short bpp) {
622 Uint32 result;
623 result = 0;
624 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
625 memcpy((Uint8*)&result + 4 - bpp, p, bpp);
626 #else
627 memcpy(&result, p, bpp);
628 #endif
629 return result;
630 }
631
632 ////////////////
633 // Get a pixel from the surface
634 // WARNING: passing invalid coordinates will cause a segfault
635 // NOTE: bmpSrc must be locked before calling this
636 // This function doesn't have "const SmartPointer<SDL_Surface> &" interface because it will slow it down
GetPixel(SDL_Surface * bmpSrc,int x,int y)637 inline Uint32 GetPixel(SDL_Surface * bmpSrc, int x, int y) {
638 return GetPixelFromAddr(
639 (Uint8*)bmpSrc->pixels + y * bmpSrc->pitch + x * bmpSrc->format->BytesPerPixel,
640 bmpSrc->format->BytesPerPixel);
641 }
642
643 ////////////////
644 // Copy pixel from one surface to another, both surfaces must have same format
645 // WARNING: doesn't do clipping
646 // NOTE: dst must be locked before calling this
647 // This function doesn't have "const SmartPointer<SDL_Surface> &" interface because it will slow it down
CopyPixel_SameFormat(SDL_Surface * dst,SDL_Surface * src,int dx,int dy,int sx,int sy)648 inline void CopyPixel_SameFormat(
649 SDL_Surface * dst, SDL_Surface * src,
650 int dx, int dy, int sx, int sy) {
651 memcpy(
652 (Uint8*)dst->pixels + dy * dst->pitch + dx * dst->format->BytesPerPixel,
653 (Uint8*)src->pixels + sy * src->pitch + sx * dst->format->BytesPerPixel,
654 dst->format->BytesPerPixel);
655 }
656
657 ////////////////
658 // Copy pixel from one surface to another, the coordinate on both surfaces is the same
659 // WARNING: doesn't do clipping
660 // WARNING: surfaces must have same format
661 // NOTE: dst must be locked before calling his
662 // This function doesn't have "const SmartPointer<SDL_Surface> &" interface because it will slow it down
CopyPixel_SameFormat(SDL_Surface * dst,SDL_Surface * src,int x,int y)663 inline void CopyPixel_SameFormat(
664 SDL_Surface * dst, SDL_Surface * src, int x, int y) {
665 CopyPixel_SameFormat(dst, src, x, y, x, y);
666 }
667
668
669 ////////////////
670 // Put pixel alpha blended with the background
671 // WARNING: passing invalid coordinates will cause a segfault
672 // NOTE: dst must be locked before calling this
673 void PutPixelA(SDL_Surface * bmpDest, int x, int y, Uint32 colour, Uint8 a);
674
675
676 ////////////////
677 // Extract 4 colour components from a packed int
GetColour4(Uint32 pixel,SDL_PixelFormat * format,Uint8 * r,Uint8 * g,Uint8 * b,Uint8 * a)678 inline void GetColour4(Uint32 pixel, SDL_PixelFormat* format, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a) {
679 SDL_GetRGBA(pixel, format, r, g, b, a);
680 }
681
682 ///////////////
683 // Extract 3 colour components from a packed int
GetColour3(Uint32 pixel,SDL_PixelFormat * format,Uint8 * r,Uint8 * g,Uint8 * b)684 inline void GetColour3(Uint32 pixel, SDL_PixelFormat* format, Uint8 *r, Uint8 *g, Uint8 *b) {
685 SDL_GetRGB(pixel, format, r, g, b);
686 }
687
688 ////////////////
689 // Returns true if the color is considered as (partly) transparent on the surface
IsTransparent(SDL_Surface * surf,Uint32 color)690 inline bool IsTransparent(SDL_Surface * surf, Uint32 color) {
691 if((surf->flags & SDL_SRCALPHA) && ((color & surf->format->Amask) != surf->format->Amask))
692 return true;
693
694 // TODO: should this check be done, if SDL_SRCALPHA was set? SDL/OpenGL possibly will ignore it
695 if((surf->flags & SDL_SRCCOLORKEY) && (EqualRGB(color, COLORKEY(surf), surf->format)))
696 return true;
697
698 return false;
699 }
700
701
702
703
704 //
705 // Solid drawing
706 //
707
708
709 ///////////////////
710 // Draw horizontal line
711 void DrawHLine(SDL_Surface * bmpDest, int x, int x2, int y, Color colour);
712
713 ///////////////////
714 // Draw vertical line
715 void DrawVLine(SDL_Surface * bmpDest, int y, int y2, int x, Color colour);
716
717 ///////////////////
718 // Draw a line
719 void DrawLine(SDL_Surface * dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Color color);
720
721 //////////////////
722 // Draw the line nicely antialiased
723 void AntiAliasedLine(SDL_Surface * dst, int x1, int y1, int x2, int y2, Color color, void (*proc)(SDL_Surface *, int, int, Uint32, Uint8));
724
725 /////////////////////
726 // Draws a filled rectangle
727 void DrawRectFill(SDL_Surface * bmpDest, int x, int y, int x2, int y2, Color color);
728
729 ////////////////////
730 // Very fast routine for drawing 2x2 rects
731 void DrawRectFill2x2(SDL_Surface *bmpDest, int x, int y, Color color);
732 void DrawRectFill2x2_NoClip(SDL_Surface *bmpDest, int x, int y, Color color);
733
734 // x,y is center
735 void DrawCircleFilled(SDL_Surface* bmpDest, int x, int y, int rx, int ry, Color color);
736
737 // draws a cross ("X")
738 void DrawCross(SDL_Surface* bmpDest, int x, int y, int w, int h, Color c);
739
740 // draw a simple loading animation
741 enum LoadingAniType { LAT_CIRCLES, LAT_CAKE };
742 void DrawLoadingAni(SDL_Surface* bmpDest, int x, int y, int rx, int ry, Color fg, Color bg, LoadingAniType type);
743
744 struct ScopedBackgroundLoadingAni {
745 struct Data; Data* data;
746 ScopedBackgroundLoadingAni(int x, int y, int rx, int ry, Color fg, Color bg, LoadingAniType type = LAT_CIRCLES);
747 ~ScopedBackgroundLoadingAni();
748 };
749
750
751 /////////////////////
752 // Draws a simple linear gradient
753 void DrawLinearGradient(SDL_Surface *bmpDest, int x, int y, int w, int h, Color cl1, Color cl2, GradientDirection dir);
754
755 ////////////////////
756 // Fills the surface with specified colour
FillSurface(SDL_Surface * dst,Color colour)757 inline void FillSurface(SDL_Surface * dst, Color colour) {
758 if (dst->clip_rect.w > 0 && dst->clip_rect.h > 0)
759 SDL_FillRect(dst, NULL, colour.get(dst->format));
760 }
761
FillSurface(SDL_Surface * dst,Uint32 colour)762 inline void FillSurface(SDL_Surface * dst, Uint32 colour) {
763 if (dst->clip_rect.w > 0 && dst->clip_rect.h > 0)
764 SDL_FillRect(dst, NULL, colour);
765 }
766
767 ////////////////////
768 // Fills the whole surface with a transparent color
FillSurfaceTransparent(SDL_Surface * dst)769 inline void FillSurfaceTransparent(SDL_Surface * dst) {
770 // check alpha first as it has priority (if set, colorkey is ignored)
771 if (dst->flags & SDL_SRCALPHA)
772 FillSurface(dst, SDL_MapRGBA(dst->format, 255, 0, 255, SDL_ALPHA_TRANSPARENT));
773 else if (dst->flags & SDL_SRCCOLORKEY)
774 FillSurface(dst, COLORKEY(dst));
775 else
776 warnings("There's no possibility to make this surface transparent!\n");
777 }
778
779
780 ////////////////////
781 // Draws a rectangle
DrawRect(SDL_Surface * bmpDest,int x,int y,int x2,int y2,Color colour)782 inline void DrawRect(SDL_Surface * bmpDest, int x, int y, int x2, int y2, Color colour) {
783 DrawHLine(bmpDest, x, x2, y, colour);
784 DrawHLine(bmpDest, x, x2, y2, colour);
785 DrawVLine(bmpDest, y, y2, x, colour);
786 DrawVLine(bmpDest, y, y2, x2, colour);
787 }
788
789 ///////////////////
790 // Draws a rectangle with transparency
DrawRectFillA(SDL_Surface * bmpDest,int x,int y,int x2,int y2,Uint32 color,Uint8 alpha)791 inline void DrawRectFillA(SDL_Surface * bmpDest, int x, int y, int x2, int y2, Uint32 color, Uint8 alpha) {
792 Color col(bmpDest->format, color); col.a = alpha;
793 DrawRectFill(bmpDest, x, y, x2, y2, col);
794 }
795
DrawRectFillA(SDL_Surface * bmpDest,int x,int y,int x2,int y2,Color color,Uint8 alpha)796 inline void DrawRectFillA(SDL_Surface * bmpDest, int x, int y, int x2, int y2, Color color, Uint8 alpha) {
797 color.a = alpha;
798 DrawRectFill(bmpDest, x, y, x2, y2, color);
799 }
800
801 //////////////////
802 // Draw a triangle
DrawTriangle(SDL_Surface * bmpDest,int x1,int y1,int x2,int y2,int x3,int y3,Color colour)803 inline void DrawTriangle(SDL_Surface * bmpDest, int x1, int y1, int x2, int y2, int x3, int y3, Color colour) {
804 DrawLine(bmpDest, x1, y1, x2, y2, colour);
805 DrawLine(bmpDest, x2, y2, x3, y3, colour);
806 DrawLine(bmpDest, x3, y3, x1, y1, colour);
807 }
808
809
810
811 //
812 // Special lines (rope, laser sight, beam)
813 //
814
815 void DrawRope(SDL_Surface * bmp, int x1, int y1, int x2, int y2, Color color);
816 void DrawBeam(SDL_Surface * bmp, int x1, int y1, int x2, int y2, Color color);
817 void DrawLaserSight(SDL_Surface * bmp, int x1, int y1, int x2, int y2, Color color);
818
819
820 //
821 // Colorkey handling
822 //
823
824 // sets alpha in a safe way for both non-alpha-surfaces and alpha-surfaces
825 // for non-alpha surfaces, it uses SDL_SetAlpha
826 // for real alphablended surfaces, that means this multiplies a/255 to each a-value
827 void SetPerSurfaceAlpha(SDL_Surface * dst, Uint8 a);
828
829 // set colorkey for both alpha-blended and non-alpha surfaces
830 // for non-alpha surfaces, SDL_SetAlpha is used
831 // for alpha surfaces, it applies to every pixel
832 void SetColorKey(SDL_Surface * dst, Uint8 r, Uint8 g, Uint8 b);
833
834 //////////////////
835 // Set's the game's default color key (pink) to the surface
836 // Works for both alpha and nonalpha surfaces
837 void SetColorKey(SDL_Surface * dst);
838
839 //////////////////
840 // Resets the alpha-channel and the colorkey
841 void ResetAlpha(SDL_Surface * dst);
842
843
844 struct ScopedSurfaceClip {
845 SDL_Rect oldclip;
846 SDL_Surface* surf;
847
ScopedSurfaceClipScopedSurfaceClip848 ScopedSurfaceClip(SDL_Surface* s, const SDL_Rect& rect) {
849 surf = s;
850 SDL_GetClipRect(s, &oldclip);
851 SDL_SetClipRect(s, &rect);
852 }
~ScopedSurfaceClipScopedSurfaceClip853 ~ScopedSurfaceClip() {
854 SDL_SetClipRect(surf, &oldclip);
855 }
856 };
857
858
859
860 #endif // __GFXPRIMITIVES_H__
861