1 #include "ppport.h"
2 #include <SDL.h>
3 #include "helper.h"
4 
5 /* SV input should be a mortal SV */
create_mortal_rect(SV * rect)6 SV *create_mortal_rect( SV *rect )
7 {
8     SV *retval = NULL;
9 
10     if( !SvOK(rect) )
11     {
12         /* create a new zero sized rectangle */
13         SDL_Rect* r = safemalloc( sizeof(SDL_Rect) );
14         r->x        = 0;
15         r->y        = 0;
16         r->w        = 0;
17         r->h        = 0;
18         retval      = obj2bag( sizeof( SDL_Rect *), (void *)(r), "SDL::Rect" );
19         sv_2mortal(retval) ;
20     }
21     else if( sv_derived_from(rect, "ARRAY") )
22     {
23         /* create a new rectangle from the array */
24         SDL_Rect* r      = safemalloc( sizeof(SDL_Rect) );
25         AV* recta        = (AV*)SvRV(rect);
26         int len          = av_len(recta);
27         int i;
28         int ra[4];
29         for(i = 0; i < 4; i++)
30         {
31             SV* iv = i > len ? NULL : AvARRAY(recta)[i];
32             ra[i]  = ( iv == NULL || !SvOK( iv ) || iv == &PL_sv_undef )
33                    ? 0
34                    : SvIV( iv );
35         }
36 
37         r->x   = ra[0]; r->y = ra[1]; r->w = ra[2]; r->h= ra[3];
38         retval = obj2bag( sizeof( SDL_Rect *), (void *)(r), "SDL::Rect" );
39         sv_2mortal(retval) ;
40     }
41     else if( sv_isobject(rect) && sv_derived_from(rect, "SDL::Rect") )
42     {
43         /* we already had a good mortal rect . Just pass it along */
44         retval = rect;
45     }
46     else
47         croak("Rect must be number or arrayref or SDL::Rect or undef");
48 
49     return retval;
50 }
51 
assert_surface(SV * surface)52 void assert_surface( SV *surface )
53 {
54     if( sv_isobject(surface) && sv_derived_from(surface, "SDL::Surface"))
55         return;
56 
57     croak("Surface must be SDL::Surface or SDLx::Surface");
58     /* does not return */
59 }
60 
_color_format(SV * color)61 char *_color_format( SV *color )
62 {
63     char *retval = NULL;
64     if( !SvOK(color) || SvIOK(color) )
65         retval = "number";
66     else if( sv_derived_from(color, "ARRAY") )
67         retval = "arrayref";
68     else if( sv_isobject(color) && sv_derived_from(color, "SDL::Color") )
69         retval = "SDL::Color";
70     else
71         croak("Color must be number or arrayref or SDL::Color");
72 
73     return retval;
74 }
75 
_color_number(SV * color,SV * alpha)76 SV *_color_number( SV *color, SV *alpha )
77 {
78     int          c      = SvIV(color);
79     int          a      = SvIV(alpha);
80     unsigned int retval = SvUV(color);
81 
82     if( !SvOK(color) || color < 0 )
83     {
84         if( color < 0 )
85             warn("Color was a negative number");
86         retval = a == 1
87                ? 0x000000FF
88                : 0;
89     }
90     else
91     {
92         if( a == 1 && (c > 0xFFFFFFFF) )
93         {
94             warn("Color was number greater than maximum expected: 0xFFFFFFFF");
95             retval = 0xFFFFFFFF;
96         }
97         else if ( a != 1 && ( c > 0xFFFFFF) )
98         {
99             warn("Color was number greater than maximum expected: 0xFFFFFF");
100             retval = 0xFFFFFF;
101         }
102     }
103 
104     return newSVuv(retval);
105 }
106 
107 /* returns a new mortal AV* */
_color_arrayref(AV * color,SV * alpha)108 AV *_color_arrayref( AV *color, SV *alpha )
109 {
110     AV *retval = (AV*)sv_2mortal((SV*)newAV());
111     int length = SvTRUE(alpha) ? 4 : 3;
112     int i      = 0;
113     for(i = 0; i < length; i++)
114     {
115         if( av_len(color) < i || !SvOK(AvARRAY(color)[i]) )
116             av_push(retval, newSVuv(i == 3 ? 0xFF : 0));
117         else
118         {
119             int c = SvIV(AvARRAY(color)[i]);
120             if( c > 0xFF )
121             {
122                 warn("Number in color arrayref was greater than maximum expected: 0xFF");
123                 av_push(retval, newSVuv(0xFF));
124             }
125             else if( c < 0 )
126             {
127                 warn("Number in color arrayref was negative");
128                 av_push(retval, newSVuv(0));
129             }
130             else
131                 av_push(retval, newSVuv(c));
132         }
133     }
134 
135     return retval;
136 }
137 
138 /* returns a mortal AV* */
__list_rgb(SV * color)139 AV* __list_rgb( SV* color )
140 {
141     char *format = _color_format(color);
142     AV* RETVAL ;
143     if ( 0 == strcmp("number", format) )
144     {
145         RETVAL              = (AV*)sv_2mortal( (SV *) newAV() );
146         unsigned int _color = SvUV(sv_2mortal(_color_number(color, newSVuv(0))));
147         av_push(RETVAL, newSVuv(_color >> 16 & 0xFF));
148         av_push(RETVAL, newSVuv(_color >>  8 & 0xFF));
149         av_push(RETVAL, newSVuv(_color       & 0xFF));
150     }
151     else if ( 0 == strcmp("arrayref", format) )
152     {
153         /* _color_arrayref returns a mortal AV* */
154         RETVAL = _color_arrayref((AV *)SvRV(color), sv_2mortal(newSVuv(0)));
155     }
156     else if ( 0 == strcmp("SDL::Color", format) )
157     {
158         RETVAL            = (AV*)sv_2mortal((SV *) newAV() );
159         SDL_Color *_color = (SDL_Color *)bag2obj(color);
160         av_push(RETVAL, newSVuv(_color->r));
161         av_push(RETVAL, newSVuv(_color->g));
162         av_push(RETVAL, newSVuv(_color->b));
163     }
164     else
165     {
166         RETVAL = (AV*)sv_2mortal((SV *) newAV() );
167         av_push(RETVAL, newSVuv(0));
168         av_push(RETVAL, newSVuv(0));
169         av_push(RETVAL, newSVuv(0));
170     }
171 
172     return RETVAL;
173 }
174 
__list_rgba(SV * color)175 AV* __list_rgba( SV* color )
176 {
177     char *format = _color_format(color);
178     AV* RETVAL ;
179     if ( 0 == strcmp("number", format) )
180     {
181         RETVAL              = (AV*)sv_2mortal((SV *) newAV() );
182         unsigned int _color = SvUV(sv_2mortal(_color_number(color, sv_2mortal(newSVuv(1)))));
183         av_push(RETVAL, newSVuv(_color >> 24 & 0xFF));
184         av_push(RETVAL, newSVuv(_color >> 16 & 0xFF));
185         av_push(RETVAL, newSVuv(_color >>  8 & 0xFF));
186         av_push(RETVAL, newSVuv(_color       & 0xFF));
187     }
188     else if ( 0 == strcmp("arrayref", format) )
189     {
190         RETVAL = _color_arrayref((AV *)SvRV(color), sv_2mortal(newSVuv(1)));
191     }
192     else if ( 0 == strcmp("SDL::Color", format) )
193     {
194         RETVAL            = (AV*)sv_2mortal((SV *) newAV() );
195         SDL_Color *_color = (SDL_Color*)bag2obj(color);
196         av_push(RETVAL, newSVuv(_color->r));
197         av_push(RETVAL, newSVuv(_color->g));
198         av_push(RETVAL, newSVuv(_color->b));
199         av_push(RETVAL, newSVuv(0xFF));
200     }
201     else
202     {
203         RETVAL = (AV*)sv_2mortal((SV *) newAV() );
204         av_push(RETVAL, newSVuv(0));
205         av_push(RETVAL, newSVuv(0));
206         av_push(RETVAL, newSVuv(0));
207         av_push(RETVAL, newSVuv(0xFF));
208     }
209 
210     return RETVAL;
211 }
212 
213 
__map_rgb(SV * color,SDL_PixelFormat * format)214 unsigned int __map_rgb( SV* color, SDL_PixelFormat* format )
215 {
216     Uint8 r, g, b;
217     AV* a = __list_rgb( color );
218     r     = SvUV(*av_fetch(a, 0, 0));
219     g     = SvUV(*av_fetch(a, 1, 0));
220     b     = SvUV(*av_fetch(a, 2, 0));
221 
222     return SDL_MapRGB( format, r, g, b );
223 }
224 
__map_rgba(SV * color,SDL_PixelFormat * format)225 unsigned int __map_rgba( SV* color, SDL_PixelFormat* format )
226 {
227     int r, g, b, a;
228     AV* ar = __list_rgba( color );
229     r      = SvUV(*av_fetch(ar, 0, 0));
230     g      = SvUV(*av_fetch(ar, 1, 0));
231     b      = SvUV(*av_fetch(ar, 2, 0));
232     a      = SvUV(*av_fetch(ar, 3, 0));
233 
234     return SDL_MapRGBA( format, r, g, b, a );
235 }
236