1 /*
2  * SDmm - a C++ wrapper for SDL and related libraries
3  * Copyright � 2001 David Hedbor <david@hedbor.org>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  */
20 
21 
22 #ifndef SDLMM_BASESURFACE_H
23 #define SDLMM_BASESURFACE_H
24 #include "sdlmm_config.h"
25 #include "sdlmm_spoint.h"
26 #include "sdlmm_srect.h"
27 #include "sdlmm_color.h"
28 #include "sdlmm_pixelformat.h"
29 #include <string>
30 
31 namespace SDLmm {
32   //! An abstract base class for graphical surfaces
33   /*!
34 
35     Surfaces represent areas of "graphical" memory, memory that can be
36     drawn to. The video framebuffer is returned as a VideoSurface by
37     SetVideoMode() and GetVideoSurface(). Ordinary (non-framebuffer
38     surfaces) are represented by a Surface. The clipping rectangle
39     returned by clip_rect() can be set with SetClipRect() method.
40 
41     \author David Hedbor <david@hedbor.org>
42   */
43   class DECLSPEC BaseSurface {
44 
45   protected:
46     //! The actual SDL_Surface allocated for this BaseSurface.
47     SDL_Surface *me;
SetSurface(SDL_Surface * surface)48     virtual void SetSurface(SDL_Surface *surface) {
49       if(me) {
50         SDL_FreeSurface(me);
51       }
52       me = surface;
53     }
54 
55     //! Constructor from an SDL_Surface*
56     /*!
57       This creates a new BaseSurface object from an existing
58       SDL_Surface. Note that ownership of the SDL_Surface is passed
59       on to the BaseSurface. It's very important not to free the original
60       surface since that will cause a problem when the object is
61       destructed (SDL_Surface storage freed twice). Use with caution.
62     */
BaseSurface(SDL_Surface * surface)63     explicit BaseSurface(SDL_Surface *surface)
64       : me(surface) {
65     }
66 
BaseSurface(const BaseSurface & other)67     BaseSurface(const BaseSurface& other)
68       : me(other.me) {
69     }
70 
71     BaseSurface &operator=(const BaseSurface& other) {
72       if(this != &other)
73         SetSurface(other.me);
74       return *this;
75     }
76 
77   public:
78 
79     //! The destructor.
~BaseSurface()80     virtual ~BaseSurface() {
81       if(me) {
82         SDL_FreeSurface(me);
83       }
84     }
85 
GetSurface()86     SDL_Surface *GetSurface() {
87       ASSERT(me);
88       return me;
89     }
90 
GetSurface()91     const SDL_Surface *GetSurface() const {
92       ASSERT(me);
93       return me;
94     }
95 
96     //! Lock the surface to allow direct access to the surface pixels.
97     //! Returns true if lock succeeded, false otherwise.
98     bool Lock();
99 
100     //! Unlock the surface.
101     void Unlock();
102 
103     //! \name Informational methods
104     //@{
105     //! Returns true if this surface is initialized, false otherwise.
106     /*! \warning Using an uninitialzied surface can cause many problems. */
valid()107     bool valid() const { return me != 0; }
108 
109     //! Returns the surface flags.
flags()110     Uint32 flags() const { return GetSurface()->flags; }
111 
112     //! Returns the pixel format.
GetPixelFormat()113     const PixelFormat GetPixelFormat() const { return PixelFormat(GetSurface()->format); }
GetPixelFormat()114     PixelFormat GetPixelFormat() { return PixelFormat(GetSurface()->format); }
115 
116     //! Returns the width of the surface.
w()117     int w() const { return GetSurface()->w; }
118 
119     //! Returns the height of the surface.
h()120     int h() const { return GetSurface()->h; }
121 
122     //! Returns the scanline length in bytes
pitch()123     Uint16 pitch() const { return GetSurface()->pitch; }
124 
125     //! Returns the surface clip rectangle
clip_rect()126     const SRect clip_rect() const { return SRect(GetSurface()->clip_rect); }
127 
128     //! Returns the pixel data, which can be used for low-level manipulation.
129     /*!
130       \warning You can only modify this surface when the surface is locked.
131     */
pixels()132     void *pixels() { return GetSurface()->pixels; }
133 
134     //! Returns the pixel data, which can be used for low-level manipulation.
135     /*!
136       \warning You can only modify this surface when the surface is locked.
137     */
pixels()138     const void *pixels() const { return GetSurface()->pixels; }
139 
140     //! Returns the hardware-specific surface info.
hwdata()141     struct private_hwdata *hwdata() const { return GetSurface()->hwdata; }
142     //@}
143 
144     //! Set the pixel to the color
145     /*!
146       \warning You can only use this function when the surface is locked.
147     */
148     void SetPixel(int x, int y, Color color);
149 
150     //! Set the pixel to the color
151     /*!
152       \warning You can only use this function when the surface is locked
153       and when the bytes per pixel is 1.
154     */
155     void SetPixel1(int x, int y, Color color);
156 
157     //! Set the pixel to the color
158     /*!
159       \warning You can only use this function when the surface is locked
160       and when the bytes per pixel is 2.
161     */
162     void SetPixel2(int x, int y, Color color);
163 
164     //! Set the pixel to the color
165     /*!
166       \warning You can only use this function when the surface is locked
167       and when the bytes per pixel is 3.
168     */
169     void SetPixel3(int x, int y, Color color);
170 
171     //! Set the pixel to the color
172     /*!
173       \warning You can only use this function when the surface is locked
174       and when the bytes per pixel is 4.
175     */
176     void SetPixel4(int x, int y, Color color);
177 
178     //! Set the pixel to the color
179     /*!
180       \warning You can only use this function when the surface is locked.
181     */
SetPixel(const SRect & point,Color color)182     void SetPixel(const SRect& point, Color color) { SetPixel(point.x, point.y, color); }
183 
184     //! Get the color of the pixel
185     /*!
186       \warning You can only use this function when the surface is locked.
187     */
188     Color GetPixel(int x, int y) const;
189 
190     //! Get the color of the pixel
191     /*!
192       \warning You can only use this function when the surface is locked.
193     */
GetPixel(const SRect & point)194     Color GetPixel(const SRect& point) const { return GetPixel(point.x, point.y); }
195 
196     //! Sets the color key (transparent pixel) in a blittable surface
197     //! and enables or disables RLE blit acceleration.
198     /*!
199       RLE acceleration can substantially speed up blitting of images
200       with large horizontal runs of transparent pixels (i.e., pixels
201       that match the \a key value). The key must be of the same pixel
202       format as the surface, MapRGB() is often useful for obtaining an
203       acceptable value.
204 
205       \returns Returns true for success, false if there was an error.
206       \param flag If */
207     bool SetColorKey(Uint32 flag, Color key);
208 
209     //! Adjust the alpha properties of this surface
210     /*!
211 
212     SetAlpha is used for setting the surface alpha value and / or
213     enabling and disabling alpha blending.
214 
215     \param flag used to specify whether alpha blending should be
216     used (SDL_SRCALPHA) and whether the surface should use RLE
217     acceleration for blitting (SDL_RLEACCEL). \a flag can be an OR'd
218     combination of these two options, one of these options or 0. If
219     SDL_SRCALPHA is not passed as a flag then all alpha information
220     is ignored when blitting the surface.
221 
222     \param alpha the per-surface alpha value; a surface need not
223     have an alpha channel to use per-surface alpha and blitting can
224     still be accelerated with SDL_RLEACCEL.
225 
226     \note The per-surface alpha value of 128 is considered a special
227     case and is optimised, so it's much faster than other
228     per-surface values.
229 
230     \returns true for success or false if there was an error.
231     */
232     bool SetAlpha(Uint32 flag, Uint8 alpha);
233 
234     //! \name Clipping Methods
235     //@{
236     //! Resets the clipping rectangle for the surface.
237     /*!
238       This functions resets the clipping to the full size of the surface.
239       \sa GetClipRect, SetClipRect, Blit
240     */
241     void ResetClipRect();
242 
243     //! Sets the clipping rectangle for the surface.
244     /*!
245       Sets the clipping rectangle for a surface. When this surface is
246       the destination of a blit, only the area within the clip
247       rectangle will be drawn into.
248 
249       \param rect The rectangle pointed to by rect will be clipped to
250       the edges of the surface so that the clip rectangle for a
251       surface can never fall outside the edges of the surface.
252 
253       \sa GetClipRect, ResetClipRect, Blit
254     */
255     void SetClipRect(const SDL_Rect& rect);
256 
257     //! Gets the clipping rectangle for the surface.
258     /*!
259       Gets the clipping rectangle for a surface. When this surface is
260       the destination of a blit, only the area within the clip
261       rectangle is drawn into.
262 
263       \param rect reference to a rectangle which will be filled with
264       the clipping rectangle of this surface.
265       \sa SetClipRect, ResetClipRect, Blit
266     */
267     void GetClipRect(SDL_Rect& rect) const;
268     //@}
269 
270     //! \name Blitting / Filling
271     //@{
272     //! Fast blit the entire source surface onto this surface.
273     /*!
274       The source surface will be blitted to this surface. If the
275       source area is larger than the destination, clipping will
276       occur. No scaling will be performed. Blitting should not be used
277       on a locked surface. The entire surface will be copied to this
278       surface using this function.
279 
280       \return If the blit is successful, it returns 0, otherwise it
281       returns -1. If either of the surfaces were in video memory,
282       and the blit returns -2, the video memory was lost. It should
283       be reloaded with artwork and re-blitted.
284 
285       \param src the surface to blit from.
286     */
287     int Blit(const BaseSurface& src);
288 
289     //! Fast blit the entire source surface onto this surface at the
290     //! specified coordinates.
291     /*!
292       The source surface will be blitted to this surface. If the
293       source area is larger than the destination, clipping will
294       occur. No scaling will be performed. Blitting should not be used
295       on a locked surface. The entire surface will be copied to this
296       surface using this function. The final blit rectangle is saved
297       in \a dstrect after all clipping is performed.
298 
299       \return If the blit is successful, it returns 0, otherwise it
300       returns -1. If either of the surfaces were in video memory,
301       and the blit returns -2, the video memory was lost. It should
302       be reloaded with artwork and re-blitted.
303 
304       \param src the surface to blit from.
305       \param dstrect the destination coordinates. Only the position
306       is used (i.e width and height are ignored). The width and height are
307       set upon returning.
308     */
309     int Blit(const BaseSurface& src, SDL_Rect& dstrect);
310 
311     //! Fast blit the entire source surface onto this surface at the
312     //! specified coordinates.
313     /*!
314       The source surface will be blitted to this surface. If the
315       source area is larger than the destination, clipping will
316       occur. No scaling will be performed. Blitting should not be used
317       on a locked surface. The entire surface will be copied to this
318       surface using this function. The final blit rectangle is saved
319       in \a dstrect after all clipping is performed.
320 
321       \return If the blit is successful, it returns 0, otherwise it
322       returns -1. If either of the surfaces were in video memory,
323       and the blit returns -2, the video memory was lost. It should
324       be reloaded with artwork and re-blitted.
325 
326       \param src the surface to blit from.
327       \param dstpoint the destination coordinates.
328       \param dstrect the final position and size is set upon returning.
329     */
Blit(const BaseSurface & src,const SPoint & dstpoint,SDL_Rect & dstrect)330     int Blit(const BaseSurface& src, const SPoint& dstpoint, SDL_Rect& dstrect) { dstrect.x = dstpoint.x; dstrect.y = dstpoint.y; return Blit(src, dstrect); }
331 
332     //! Fast blit the entire source surface onto this surface at the
333     //! specified coordinates.
334     /*!
335       The source surface will be blitted to this surface. If the
336       source area is larger than the destination, clipping will
337       occur. No scaling will be performed. Blitting should not be used
338       on a locked surface. The entire surface will be copied to this
339       surface using this function.
340 
341       \return If the blit is successful, it returns 0, otherwise it
342       returns -1. If either of the surfaces were in video memory,
343       and the blit returns -2, the video memory was lost. It should
344       be reloaded with artwork and re-blitted.
345 
346       \param src the surface to blit from.
347       \param dstpoint the destination coordinates.
348     */
349     int Blit(const BaseSurface& src, const SPoint& dstpoint);
350 
351     //! Fast blit the specified area part of the source surface onto
352     //! this surface at the specified coordinates.
353     /*!
354       The choosen rectangle of the source surface will be blitted to
355       this surface. If the source area is larger than the destination,
356       clipping will occur. No scaling will be performed. Blitting
357       should not be used on a locked surface. The entire surface will
358       be copied to this surface using this function. The final blit
359       rectangle is saved in \a dstrect after all clipping is performed
360       (\a srcrect is not modified).
361 
362       \return If the blit is successful, it returns 0, otherwise it
363       returns -1. If either of the surfaces were in video memory,
364       and the blit returns -2, the video memory was lost. It should
365       be reloaded with artwork and re-blitted.
366 
367       \param src the surface to blit from.
368       \param srcrect the rectangular area to copy from the source
369       surface.
370       \param dstrect the destination coordinates. Only the position
371       is used (i.e width and height are ignored). The width and height are
372       set upon returning.
373     */
374     int Blit(const BaseSurface& src, const SDL_Rect& srcrect, SDL_Rect& dstrect);
375 
376     //! Fast blit the specified area part of the source surface onto
377     //! this surface at the specified coordinates.
378     /*!
379       The choosen rectangle of the source surface will be blitted to
380       this surface. If the source area is larger than the destination,
381       clipping will occur. No scaling will be performed. Blitting
382       should not be used on a locked surface. The entire surface will
383       be copied to this surface using this function. The final blit
384       rectangle is saved in \a dstrect after all clipping is performed
385       (\a srcrect is not modified).
386 
387       \return If the blit is successful, it returns 0, otherwise it
388       returns -1. If either of the surfaces were in video memory,
389       and the blit returns -2, the video memory was lost. It should
390       be reloaded with artwork and re-blitted.
391 
392       \param src the surface to blit from.
393       \param srcrect the rectangular area to copy from the source
394       surface.
395       \param dstpoint the destination coordinates.
396       \param dstrect the final position and size is set upon returning.
397     */
Blit(const BaseSurface & src,const SDL_Rect & srcrect,const SPoint & dstpoint,SDL_Rect & dstrect)398     int Blit(const BaseSurface& src, const SDL_Rect& srcrect, const SPoint& dstpoint, SDL_Rect& dstrect) { dstrect.x = dstpoint.x; dstrect.y = dstpoint.y; return Blit(src, srcrect, dstrect); }
399 
400     //! Fast blit the specified area part of the source surface onto
401     //! this surface at the specified coordinates.
402     /*!
403       The choosen rectangle of the source surface will be blitted to
404       this surface. If the source area is larger than the destination,
405       clipping will occur. No scaling will be performed. Blitting
406       should not be used on a locked surface. The entire surface will
407       be copied to this surface using this function.
408 
409       \return If the blit is successful, it returns 0, otherwise it
410       returns -1. If either of the surfaces were in video memory,
411       and the blit returns -2, the video memory was lost. It should
412       be reloaded with artwork and re-blitted.
413 
414       \param src the surface to blit from.
415       \param srcrect the rectangular area to copy from the source
416       surface.
417       \param dstpoint the destination coordinates.
418     */
419     int Blit(const BaseSurface& src, const SDL_Rect& srcrect, const SPoint& dstpoint);
420 
421     //! Fast fill the surface with the specified color
422     /*!
423       If a clipping rectangle has been set using SetClipRect(), only the
424       area within that rectangle will be filled.
425       \returns Returns true for success, false if there was an error.
426       \param color the color to fill with, generated by MapRGB() or MapRGBA().
427     */
428     bool Fill(Color color);
429 
430     //! Fast fill the surface with the specified color
431     /*!
432       If a clipping rectangle has been set using SetClipRect(), only the
433       area within that rectangle will be filled.
434       \returns Returns true for success, false if there was an error.
435       \param r, g, b the red, green and blue color values.
436     */
Fill(Uint8 r,Uint8 g,Uint8 b)437     bool Fill(Uint8 r, Uint8 g, Uint8 b) { return Fill(GetPixelFormat().MapRGB(r, g, b)); }
438 
439     //! Fast fill the surface with the specified color
440     /*!
441       If a clipping rectangle has been set using SetClipRect(), only the
442       area within that rectangle will be filled.
443       \returns Returns true for success, false if there was an error.
444       \param r, g, b the red, green and blue color values.
445       \param a the alpha value
446     */
Fill(Uint8 r,Uint8 g,Uint8 b,Uint8 a)447     bool Fill(Uint8 r, Uint8 g, Uint8 b, Uint8 a) { return Fill(GetPixelFormat().MapRGBA(r, g, b, a)); }
448 
449     //! Performs a fast fill of the given rectangle with the specified color
450     /*!
451       If a clipping rectangle has been set using SetClipRect(), the area
452       filled will be the intersection of the clipping rectangle and
453       \a dstrect.
454       \returns Returns true for success, false if there was an error.
455       \param dstrect the rectangle to fill, upon returning it contains the
456         clipped rectangle that was actually filled.
457       \param color the color to fill with, generated by MapRGB() or MapRGBA().
458     */
459     bool FillRect(SDL_Rect& dstrect, Color color);
460 
461     //! Performs a fast fill of the given rectangle with the specified color
462     /*!
463       If a clipping rectangle has been set using SetClipRect(), the area
464       filled will be the intersection of the clipping rectangle and
465       \a dstrect.
466       \returns Returns true for success, false if there was an error.
467       \param dstrect the rectangle to fill, upon returning it contains the
468         clipped rectangle that was actually filled.
469       \param r, g, b the red, green and blue color values.
470     */
FillRect(SDL_Rect & dstrect,Uint8 r,Uint8 g,Uint8 b)471     bool FillRect(SDL_Rect& dstrect, Uint8 r, Uint8 g, Uint8 b) { return FillRect(dstrect, GetPixelFormat().MapRGB(r, g, b)); }
472 
473     //! Performs a fast fill of the given rectangle with the specified color
474     /*!
475       If a clipping rectangle has been set using SetClipRect(), the area
476       filled will be the intersection of the clipping rectangle and
477       \a dstrect.
478       \returns Returns true for success, false if there was an error.
479       \param dstrect the rectangle to fill, upon returning it contains the
480         clipped rectangle that was actually filled.
481       \param r, g, b the red, green and blue color values.
482       \param a the alpha value
483     */
FillRect(SDL_Rect & dstrect,Uint8 r,Uint8 g,Uint8 b,Uint8 a)484     bool FillRect(SDL_Rect& dstrect, Uint8 r, Uint8 g, Uint8 b, Uint8 a) { return FillRect(dstrect, GetPixelFormat().MapRGBA(r, g, b, a)); }
485 
486     //@}
487 
488     //! Convert the surface to the display format.
489     /*!
490       This function converts the surface to the pixel format and
491       colors of the video framebuffer, making it suitable for fast
492       blitting onto the display surface.
493 
494       If you want to take advantage of hardware colorkey or alpha blit
495       acceleration, you should set the colorkey and alpha value before
496       calling this function.
497 
498       \returns The functions returns true if the conversion
499       succeeded or false otherwise. If the conversion failed, the
500       BaseSurface object will not have changed.
501 
502       \note Please note that this function doesn't return a new,
503       modified object like the SDL_DisplayFormat() function does. Thus
504       there is no need to manually free the old surface.
505 
506       \sa SetDisplayFormatAlpha(), SetAlpha(), SetColorKey()
507     */
508     virtual bool SetDisplayFormat() = 0;
509 
510     //! Convert the surface to the display format.
511     /*!
512       This function converts the surface to the pixel format and
513       colors of the video framebuffer plus an alpha channel, making it
514       suitable for fast blitting onto the display surface.
515 
516       If you want to take advantage of hardware colorkey or alpha blit
517       acceleration, you should set the colorkey and alpha value before
518       calling this function.
519 
520       \returns The functions returns true if the conversion
521       succeeded or false otherwise. If the conversion failed, the
522       BaseSurface object will not have changed.
523 
524       \note Please note that this function doesn't return a new,
525       modified object like the SDL_DisplayFormatAlpha() function
526       does. Thus there is no need to manually free the old surface.
527 
528       \sa SetDisplayFormat(), SetAlpha(), SetColorKey()
529     */
530     virtual bool SetDisplayFormatAlpha() = 0;
531 
532     //! Save a BaseSurface object as a Windows bitmap file
533     /*!
534       \param file the file name to save to.
535       \returns True if the loading succeeded, false otherwise.
536     */
537     bool SaveBMP(const char *file) const;
538 
539     //! Save a BaseSurface object as a Windows bitmap file
540     /*!
541       \param file the file name to save to.
542       \returns True if the loading succeeded, false otherwise.
543     */
SaveBMP(const std::string & file)544     bool SaveBMP(const std::string& file) const { return SaveBMP(file.c_str()); }
545 
546   };
547 }
548 
549 #endif // SDLMM_BASESURFACE_H
550