PageRenderTime 16ms CodeModel.GetById 10ms app.highlight 2ms RepoModel.GetById 1ms app.codeStats 0ms

/src/SDLx/LayerManager.xs

http://github.com/PerlGameDev/SDL
Unknown | 370 lines | 327 code | 43 blank | 0 comment | 0 complexity | 7b43620b2d63404299396abe34556eff MD5 | raw file
  1#include "EXTERN.h"
  2#include "perl.h"
  3#include "XSUB.h"
  4#include "ppport.h"
  5#include "helper.h"
  6
  7#ifndef aTHX_
  8#define aTHX_
  9#endif
 10
 11#include <SDL.h>
 12#include "SDLx/LayerManager.h"
 13
 14int _get_pixel( SDL_Surface *surface, int x, int y )
 15{
 16    int value  = 0;
 17    int offset = x + surface->w * y;
 18    switch(surface->format->BytesPerPixel)
 19    {
 20        case 1:  value = ((Uint8  *)surface->pixels)[offset];
 21                 break;
 22        case 2:  value = ((Uint16 *)surface->pixels)[offset];
 23                 break;
 24        case 3:  value = ((Uint32)((Uint8 *)surface->pixels)[offset * surface->format->BytesPerPixel]     <<  0)
 25                       + ((Uint32)((Uint8 *)surface->pixels)[offset * surface->format->BytesPerPixel + 1] <<  8)
 26                       + ((Uint32)((Uint8 *)surface->pixels)[offset * surface->format->BytesPerPixel + 2] << 16);
 27                 break;
 28        case 4:  value = ((Uint32 *)surface->pixels)[offset];
 29                 break;
 30    }
 31
 32    return value;
 33}
 34
 35MODULE = SDLx::LayerManager    PACKAGE = SDLx::LayerManager    PREFIX = lmx_
 36
 37SDLx_LayerManager *
 38lmx_new( CLASS, ... )
 39    char* CLASS
 40    CODE:
 41        RETVAL           = (SDLx_LayerManager *)safemalloc( sizeof(SDLx_LayerManager) );
 42        RETVAL->layers   = newAV();
 43        RETVAL->saveshot = (SDL_Surface *)safemalloc( sizeof(SDL_Surface) );
 44        RETVAL->saved    = 0;
 45    OUTPUT:
 46        RETVAL
 47
 48void 
 49lmx_add( manager, bag )
 50    SDLx_LayerManager *manager
 51    SV* bag 
 52    CODE:
 53        if( sv_isobject(bag) && (SvTYPE(SvRV(bag)) == SVt_PVMG) )
 54        {
 55            SDLx_Layer *layer = (SDLx_Layer *)bag2obj(bag);
 56            layer->index      = av_len( manager->layers ) + 1;
 57            layer->manager    = manager;
 58            layer->touched    = 1;
 59            av_push( manager->layers, bag);
 60            SvREFCNT_inc(bag);
 61        }
 62
 63AV *
 64lmx_layers( manager )
 65    SDLx_LayerManager *manager
 66    CODE:
 67        RETVAL = manager->layers;
 68    OUTPUT:
 69        RETVAL
 70
 71
 72SV *
 73lmx_layer( manager, index )
 74    SDLx_LayerManager *manager
 75    int index
 76    PREINIT:
 77        char* CLASS = "SDLx::Layer";
 78    CODE:
 79        if(index >= 0 && index < av_len( manager->layers ) + 1)
 80        {
 81             RETVAL = *av_fetch( manager->layers, index, 0 ) ;
 82             SvREFCNT_inc(RETVAL);
 83        }
 84        else
 85            XSRETURN_UNDEF;
 86    OUTPUT:
 87        RETVAL
 88
 89int
 90lmx_length( manager )
 91    SDLx_LayerManager *manager
 92    CODE:
 93        RETVAL = av_len( manager->layers ) + 1;
 94    OUTPUT:
 95        RETVAL
 96
 97AV *
 98lmx_blit( manager, dest )
 99    SDLx_LayerManager *manager
100    SDL_Surface       *dest
101    CODE:
102        manager->dest       = dest;
103        RETVAL              = newAV();
104        int index           = 0;
105        int length          = av_len( manager->layers ) + 1;
106        int attached_layers = 0;
107        int did_something   = 0;
108        
109        while(index < length)
110        {
111            SDLx_Layer *layer = (SDLx_Layer *)bag2obj(*av_fetch(manager->layers, index, 0));
112            
113            if(layer->attached == 0)
114            {
115                if(layer->touched || manager->saved == 0)
116                {
117                    SDL_Rect *rect = (SDL_Rect *)safemalloc( sizeof(SDL_Rect) );
118                    rect->x        = layer->pos->x;
119                    rect->y        = layer->pos->y;
120                    rect->w        = layer->clip->w;
121                    rect->h        = layer->clip->h;
122                    layer->touched = 0;
123                    SDL_BlitSurface(layer->surface, layer->clip, dest, rect);
124                    av_push(RETVAL, _sv_ref( rect, sizeof(SDL_Rect *), sizeof(SDL_Rect), "SDL::Rect" ));
125                    did_something  = 1;
126                }
127            }
128            else
129                attached_layers = 1;
130            index++;
131        }
132        
133        if(manager->saved == 0)
134        {
135            manager->saveshot = SDL_ConvertSurface(dest, dest->format, dest->flags);
136            manager->saved    = 1;
137        }
138        
139        if((manager->saved && did_something) || attached_layers)
140        {
141            SDL_BlitSurface(manager->saveshot, NULL, dest, NULL);
142        }
143        
144        if(attached_layers)
145        {
146            int x, y;
147            SDL_GetMouseState(&x, &y);
148            index = 0;
149            while(index < length)
150            {
151                SDLx_Layer *layer = (SDLx_Layer *)bag2obj(*av_fetch(manager->layers, index, 0));
152
153                if(layer->attached == 1 || layer->attached == 2)
154                {
155                    if(layer->attached == 1)
156                    {
157                        layer->pos->x  = x + layer->attached_rel->x;
158                        layer->pos->y  = y + layer->attached_rel->y;
159                    }
160
161                    SDL_Rect *rect    = (SDL_Rect *)safemalloc( sizeof(SDL_Rect) );
162                    rect->x           = layer->pos->x;
163                    rect->y           = layer->pos->y;
164                    rect->w           = layer->clip->w;
165                    rect->h           = layer->clip->h;
166
167                    SDL_BlitSurface(layer->surface, layer->clip, dest, rect);
168                    av_push(RETVAL, _sv_ref( rect, sizeof(SDL_Rect *), sizeof(SDL_Rect), "SDL::Rect" ));
169                }
170
171                index++;
172            }
173        }
174    OUTPUT:
175        RETVAL
176
177SV *
178lmx_by_position( manager, x, y )
179    SDLx_LayerManager* manager
180    int x
181    int y
182    CODE:
183        int i;
184        SV *match = NULL;
185        for( i = av_len( manager->layers ); i >= 0 && match == NULL; i-- )
186        {
187            SV          *bag   = *av_fetch(manager->layers, i, 0);
188            SDLx_Layer  *layer = (SDLx_Layer *)bag2obj(bag);
189            SDL_Rect    *clip  = layer->clip;
190            SDL_Rect    *pos   = layer->pos;
191            SDL_Surface *surf  = layer->surface;
192            if (   pos->x <= x && x <= pos->x + clip->w
193                && pos->y <= y && y <= pos->y + clip->h)
194            {
195                Uint8 r, g, b, a;
196                Uint32 pixel = _get_pixel(surf, x - pos->x, y - pos->y);
197                SDL_GetRGBA( pixel, surf->format, &r, &g, &b, &a );
198
199                if(a > 0)
200                    match = bag;
201            }
202        }
203
204        if(match != NULL)
205        {
206            RETVAL = match;
207            SvREFCNT_inc(RETVAL);
208        }
209        else
210            XSRETURN_UNDEF;
211    OUTPUT:
212        RETVAL
213
214AV *
215lmx_ahead( manager, index )
216    SDLx_LayerManager *manager
217    int               index
218    CODE:
219        SDLx_Layer *layer = (SDLx_Layer *)bag2obj(*av_fetch(manager->layers, index, 0));
220        RETVAL            = layers_ahead( layer );
221    OUTPUT:
222        RETVAL
223
224AV *
225lmx_behind( manager, index )
226    SDLx_LayerManager *manager
227    int               index
228    CODE:
229        SDLx_Layer *layer = (SDLx_Layer *)bag2obj(*av_fetch(manager->layers, index, 0));
230        RETVAL            = layers_behind( layer );
231    OUTPUT:
232        RETVAL
233
234void
235lmx_attach( manager, ... )
236    SDLx_LayerManager *manager
237    CODE:
238        manager->saved = 0;
239        int x = -1;
240        int y = -1;
241        
242        if(SvIOK(ST(items - 1)))
243        {
244            y = SvIV(ST(items - 1));
245            items--;
246        }
247        
248        if(SvIOK(ST(items - 1)))
249        {
250            x = SvIV(ST(items - 1));
251            items--;
252        }
253        
254        if(-1 == x || -1 == y)
255            SDL_GetMouseState(&x, &y);
256
257        int i;
258        for( i = 1; i < items; i++ )
259        {
260            SDLx_Layer *layer      = (SDLx_Layer *)bag2obj(ST(i));
261            layer->attached        = 1;
262            layer->attached_pos->x = layer->pos->x;
263            layer->attached_pos->y = layer->pos->y;
264            layer->attached_rel->x = layer->pos->x - x;
265            layer->attached_rel->y = layer->pos->y - y;
266        }
267
268AV *
269lmx_detach_xy( manager, x = -1, y = -1 )
270    SDLx_LayerManager *manager
271    int x
272    int y
273    CODE:
274        RETVAL = newAV();
275        int index  = 0;
276        int length = av_len( manager->layers ) + 1;
277        int lower_x;
278        int lower_y;
279        int offset_x = 0;
280        int offset_y = 0;
281        while(index < length)
282        {
283            SDLx_Layer *layer = (SDLx_Layer *)bag2obj(*av_fetch(manager->layers, index, 0));
284            
285            if(layer->attached == 1)
286            {
287                if(av_len(RETVAL) == -1)
288                {
289                    lower_x  = layer->attached_pos->x;
290                    lower_y  = layer->attached_pos->y;
291                    offset_x = layer->attached_pos->x - x;
292                    offset_y = layer->attached_pos->y - y;
293                    av_push(RETVAL, newSViv(layer->attached_pos->x));
294                    av_push(RETVAL, newSViv(layer->attached_pos->y));
295                }
296                
297                layer->attached = 0;
298                layer->touched  = 1;
299                layer->pos->x   = layer->attached_pos->x - offset_x;
300                layer->pos->y   = layer->attached_pos->y - offset_y;
301            }
302            
303            index++;
304        }
305        manager->saved = 0;
306    OUTPUT:
307        RETVAL
308
309void
310lmx_detach_back( manager )
311    SDLx_LayerManager *manager
312    CODE:
313        int index  = 0;
314        int length = av_len( manager->layers ) + 1;
315        while(index < length)
316        {
317            SDLx_Layer *layer = (SDLx_Layer *)bag2obj(*av_fetch(manager->layers, index, 0));
318            
319            if(layer->attached == 1)
320            {
321                layer->attached = 0;
322                layer->touched  = 1;
323                layer->pos->x   = layer->attached_pos->x;
324                layer->pos->y   = layer->attached_pos->y;
325            }
326            
327            index++;
328        }
329        manager->saved = 0;
330
331AV *
332lmx_foreground( manager, ... )
333    SDLx_LayerManager *manager
334    CODE:
335        RETVAL = newAV();
336        int x;
337        for(x = 1; x < items; x++)
338        {
339            SDLx_Layer        *layer   = (SDLx_Layer *)bag2obj(ST(x));
340            SDLx_LayerManager *manager = layer->manager;
341            int index                  = layer->index; /* we cant trust its value */
342            int i;
343            
344            SV *fetched;
345            for(i = 0; i <= av_len(manager->layers); i++)
346            {
347                fetched = *av_fetch(manager->layers, i, 0);
348                if(fetched == ST(x)) /* what bag do we have? => finding the right layer index */
349                {
350                    index = i;
351                    break;
352                }
353            }
354
355            for(i = index; i < av_len(manager->layers); i++)
356            {
357                AvARRAY(manager->layers)[i] = AvARRAY(manager->layers)[i + 1];
358            }
359            
360            AvARRAY(manager->layers)[i] = fetched;
361            manager->saved = 0;
362        }
363    OUTPUT:
364        RETVAL
365
366void
367lmx_DESTROY( manager )
368    SDLx_LayerManager *manager
369    CODE:
370        safefree(manager);