-
Notifications
You must be signed in to change notification settings - Fork 0
/
rudl_video_surface.c
1549 lines (1317 loc) · 46.7 KB
/
rudl_video_surface.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
RUDL - a C library wrapping SDL for use in Ruby.
Copyright (C) 2001, 2002, 2003 Danny van Bruggen
$Log: rudl_video_surface.c,v $
Revision 1.38 2004/10/23 19:54:22 rennex
Fixed docs
Revision 1.37 2004/08/21 23:25:31 tsuihark
Fixed little documentation typo
Revision 1.36 2004/08/04 23:03:47 tsuihark
Updated all documentation to Dokumentat format.
Revision 1.35 2004/01/21 22:02:14 tsuihark
Converted to Dokumentat format.
Revision 1.34 2004/01/06 18:01:39 tsuihark
Removed a few warnings
Revision 1.33 2003/12/30 01:02:41 rennex
Added mirror_x.
Fixed segfault when calling set_palette(0, nil).
Added (set_)palette prototypes before Surface.new
Revision 1.32 2003/12/29 20:46:36 rennex
Added mirror_y for now.
Changed previous ALLOC_N to ALLOCA_N.
Revision 1.31 2003/12/29 20:15:04 tsuihark
Changed malloc to ALLOC_N to prevent memory leaks
Revision 1.30 2003/12/26 22:41:14 rennex
Combined Surface#get and Surface#[] into one method
Revision 1.29 2003/12/16 01:04:15 rennex
Added target coordinate for scale2x and reorganized that code a little
Revision 1.28 2003/12/09 15:09:01 rennex
Added Scale2x support for 24-bit surfaces
Revision 1.27 2003/12/09 14:22:17 rennex
Added Scale2x support for 8-bit and 16-bit surfaces.
Made set_colorkey(nil) and set_alpha(nil) work.
Made Surface.new copy the palette if a 8-bit surface was given.
Revision 1.26 2003/12/09 01:38:54 rennex
Added the scale2x method (currently only for 32bit surfaces)
Revision 1.25 2003/11/28 22:24:58 rennex
Fixed bugs that caused errors on Linux.
Revision 1.24 2003/10/26 15:29:32 tsuihark
Did stuff
Revision 1.23 2003/10/19 11:26:13 tsuihark
Added VideoExposeEvent and removed an odd bug in rudl_video_surface.c
Revision 1.22 2003/10/01 21:26:01 tsuihark
Some 16 bit + alpha stuff
Revision 1.21 2003/09/29 12:43:21 rennex
Moved SDL_LockSurface after the coordinate check in internal_(nonlocking_)get
*/
#include "rudl_events.h"
#include "rudl_video.h"
#ifdef HAVE_SDL_IMAGE_H
#include "SDL_image.h"
#endif
///////////////////////////////// SURFACE
/**
@file Surface
@class Surface
A @Surface is a two dimensional array of pixels with some information about those pixels.
This might not seem like much, but it is just about the most important class in RUDL.
*/
// SUPPORT:
ID id_shared_surface_reference;
__inline__ VALUE createSurfaceObject(SDL_Surface* surface)
{
return Data_Wrap_Struct(classSurface, 0, SDL_FreeSurface, surface);
}
__inline__ SDL_Surface* retrieveSurfacePointer(VALUE self)
{
SDL_Surface* surface;
Data_Get_Struct(self, SDL_Surface, surface);
return surface;
}
__inline__ void setMasksFromBPP(Uint32 bpp, bool alphaWanted, Uint32* Rmask, Uint32* Gmask, Uint32* Bmask, Uint32* Amask)
{
*Amask = 0;
if(alphaWanted && (bpp==32||bpp==16)){
switch(bpp){
case 16: *Rmask=0xF<<12; *Gmask=0xF<<8; *Bmask=0xF<<4; *Amask=0xF;break;
case 32: *Rmask = 0xFF << 24; *Gmask = 0xFF << 16; *Bmask = 0xFF << 8; *Amask=0xFF; break;
}
}else{
switch(bpp){
case 8: *Rmask = 0xFF >> 6 << 5; *Gmask = 0xFF >> 5 << 2; *Bmask = 0xFF >> 6; break;
case 12: *Rmask = 0xFF >> 4 << 8; *Gmask = 0xFF >> 4 << 4; *Bmask = 0xFF >> 4; break;
case 15: *Rmask = 0xFF >> 3 << 10; *Gmask = 0xFF >> 3 << 5; *Bmask = 0xFF >> 3; break;
case 16: *Rmask = 0xFF >> 3 << 11; *Gmask = 0xFF >> 2 << 5; *Bmask = 0xFF >> 3; break;
case 24:
case 32: *Rmask = 0xFF << 16; *Gmask = 0xFF << 8; *Bmask = 0xFF; break;
default: SDL_RAISE_S("no standard masks exist for given bitdepth");
}
}
}
/* declare the functions here, so we can use them in Surface.new */
static VALUE surface_palette(VALUE self);
static VALUE surface_set_palette(VALUE self, VALUE firstValue, VALUE colors);
// METHODS:
/**
@section Initializers
@method new( size ) => Surface
@method new( size, surface ) => Surface
@method new( size, flags ) => Surface
@method new( size, flags, surface ) => Surface
@method new( size, flags, depth ) => Surface
@method new( size, flags, depth, masks ) => Surface
All these methods create a new @Surface with @size = [w, h].
If only @size is supplied, the rest of the arguments will be set to reasonable values.
If a surface is supplied, it is used to copy the values from that aren't given.
@flags is, according to SDL's documentation:
<ul>
<li>SWSURFACE:
SDL will create the surface in system memory.
This improves the performance of pixel level access,
however you may not be able to take advantage of some types of hardware blitting.
<li>HWSURFACE:
SDL will attempt to create the surface in video memory.
This will allow SDL to take advantage of Video->Video blits (which are often accelerated).
<li>SRCCOLORKEY:
This flag turns on colourkeying for blits from this surface.
If HWSURFACE is also specified and colourkeyed blits are hardware-accelerated,
then SDL will attempt to place the surface in video memory.
Use @Surface#set_colorkey to set or clear this flag after surface creation.
<li>SRCALPHA:
This flag turns on alpha-blending for blits from this surface.
If HWSURFACE is also specified and alpha-blending blits are hardware-accelerated,
then the surface will be placed in video memory if possible.
Use @Surface#set_alpha to set or clear this flag after surface creation.
For a 32 bitdepth surface, an alpha mask will automatically be added,
in other cases, you will have to specify a mask.
</ul>
@depth is bitdepth, like 8, 15, 16, 24 or 32.
@masks describes the format for the pixels and is an array of [R, G, B, A]
containing 32 bit values with bits set where the colorcomponent should be stored.
For example: [0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF] describes a 32 bit color
with red in the highest values and an alpha channel. If it is not specified, the following
defaults are used:
<pre>
........ ........ ........ .RRGGGBB (8bpp)
........ ........ ....RRRR GGGGBBBB (12bpp)
........ ........ .RRRRRGG GGGBBBBB (15bpp)
........ ........ RRRRRGGG GGGBBBBB (16bpp)
........ RRRRRRRR GGGGGGGG BBBBBBBB (24 bpp)
........ RRRRRRRR GGGGGGGG BBBBBBBB (32 bpp)
RRRRRRRR GGGGGGGG BBBBBBBB AAAAAAAA (32 bpp, SRCALPHA set)
</pre>
Normally this shouldn't have to be of interest.
*/
VALUE surface_new(int argc, VALUE* argv, VALUE self)
{
Uint32 flags = 0;
Uint16 width, height;
short bpp = 0;
Uint32 Rmask, Gmask, Bmask, Amask;
VALUE tmp;
bool wildGuess = false;
VALUE sizeObject, surfaceOrFlagsObject, surfaceOrDepthObject, masksObject;
SDL_PixelFormat* pix = NULL;
SDL_Surface* oldsurface = NULL;
VALUE oldsurfaceobj = 0, newsurfaceobj;
initVideo();
rb_scan_args(argc, argv, "13", &sizeObject, &surfaceOrFlagsObject, &surfaceOrDepthObject, &masksObject);
PARAMETER2COORD(sizeObject, &width, &height);
if(argc>1){
if(rb_obj_is_kind_of(surfaceOrFlagsObject, classSurface)){ // got surface on pos 1
oldsurfaceobj = surfaceOrFlagsObject;
oldsurface = retrieveSurfacePointer(oldsurfaceobj);
pix = oldsurface->format;
flags = oldsurface->flags;
}else{
flags = PARAMETER2FLAGS(surfaceOrFlagsObject);
if(argc>2){ // got surface on pos 2, or depth
if(rb_obj_is_kind_of(surfaceOrDepthObject, classSurface)){ // got Surface on pos 2
RUDL_VERIFY(argc == 3, "masks are taken from surface");
oldsurfaceobj = surfaceOrDepthObject;
oldsurface = retrieveSurfacePointer(oldsurfaceobj);
pix = oldsurface->format;
}else{ // got depth
bpp = NUM2Sint16(surfaceOrDepthObject);
if(argc == 4){ // got masks
Check_Type(masksObject, T_ARRAY);
RUDL_VERIFY(RARRAY(masksObject)->len==4, "Need 4 elements in masks array");
tmp = rb_ary_entry(masksObject, 0); Rmask = NUM2UINT(tmp);
tmp = rb_ary_entry(masksObject, 1); Gmask = NUM2UINT(tmp);
tmp = rb_ary_entry(masksObject, 2); Bmask = NUM2UINT(tmp);
tmp = rb_ary_entry(masksObject, 3); Amask = NUM2UINT(tmp);
}else{ // no masks
setMasksFromBPP(bpp, (flags&SDL_SRCALPHA)>0, &Rmask, &Gmask, &Bmask, &Amask);
}
}
}else{
wildGuess = true; // only size and flags given
}
}
}else{ // only size given... Guess a bit:
wildGuess = true;
}
if(wildGuess){
if(SDL_GetVideoSurface()){
pix = SDL_GetVideoSurface()->format;
}else{
pix = SDL_GetVideoInfo()->vfmt;
}
}
if(pix){
bpp = pix->BitsPerPixel;
Rmask = pix->Rmask;
Gmask = pix->Gmask;
Bmask = pix->Bmask;
Amask = pix->Amask;
}
newsurfaceobj = createSurfaceObject(SDL_CreateRGBSurface(flags, width, height, bpp, Rmask, Gmask, Bmask, Amask));
/* paletted (8-bit) surface given to copy values from? then copy the palette */
if(oldsurface && oldsurface->format->BytesPerPixel == 1){
surface_set_palette(newsurfaceobj, INT2FIX(0), surface_palette(oldsurfaceobj));
}
return newsurfaceobj;
}
/**
@method load_new( filename ) => Surface
This creates a @Surface with an image in it,
loaded from disk from @filename by using load_new.
The file should be in a supported file format.
If the SDL_image library was found during RUDL's installation,
it will load the following formats:
BMP, PNM, XPM, XCF, PCX, GIF, JPEG, TIFF, PNG, TGA and LBM.
If the SDL_image library was not found, only simple BMP loading is supported.
Simple means: not all BMP files can be loaded.
*/
static VALUE surface_load_new(VALUE self, VALUE filename)
{
SDL_Surface* surface=NULL;
initVideo();
#ifdef HAVE_SDL_IMAGE_H
surface=IMG_Load(STR2CSTR(filename));
#else
surface=SDL_LoadBMP(STR2CSTR(filename));
#endif
if(!surface) SDL_RAISE;
return createSurfaceObject(surface);
}
/**
@method String.to_surface => Surface
This creates a @Surface with an image in it,
loaded by treating @String as the image data when using @to_surface.
The @string should be in a supported file format,
just like the file for @load_new should be.
*/
static VALUE string_to_surface(VALUE self)
{
SDL_RWops* rwops=NULL;
SDL_Surface* surface=NULL;
initVideo();
rwops=SDL_RWFromMem(RSTRING(self)->ptr, RSTRING(self)->len);
#ifdef HAVE_SDL_IMAGE_H
surface=IMG_Load_RW(rwops, 0);
#else
surface=SDL_LoadBMP_RW(rwops, 0);
#endif
SDL_FreeRW(rwops);
if(!surface) SDL_RAISE;
return createSurfaceObject(surface);
}
static VALUE surface_destroy(VALUE self);
void dont_free(void*_)
{
DEBUG_S("dont_free");
}
/**
@method shared_new( surface ) => Surface
This method is two things:
<ol>
<li>a way to share the same bunch of data (width, height, bpp, pixeldata) between two Surface objects.
Please don't use it this way if there isn't a very good reason for it.
<li>a way to import foreign objects that wrap an SDL_Surface*.
If that doesn't mean anything to you, please ignore this point.
It takes the pointer from the foreign object and creates a new Surface that wraps it.
</ol>
Garbage collection problems should be prevented by giving the new surface
a reference to @surface
Note that if the original surface is destroyed by a call to @Surface.destroy,
the shared ones will be invalidated too!
*/
static VALUE surface_shared_new(VALUE self, VALUE other)
{
VALUE new_surface=createSurfaceObject(DATA_PTR(other));
rb_ivar_set(new_surface, id_shared_surface_reference, other);
RDATA(new_surface)->dfree=dont_free;
return new_surface;
}
/**
@section Methods
@method share( other_surface ) => self
Like @Surface.shared_new, but this works on an existing surface.
It will destroy this surface, then make it share @other_surface 's data.
*/
static VALUE surface_share(VALUE self, VALUE other)
{
if(DATA_PTR(self)!=DATA_PTR(other)){
surface_destroy(self);
DATA_PTR(self)=DATA_PTR(other);
RDATA(self)->dfree=dont_free;
rb_ivar_set(self, id_shared_surface_reference, other);
}
return self;
}
/**
@method immodest_export( other_surface ) => self
Like Surface.share, but this works the other way around.
It will destroy the @other_surface then make it share the data in itself
and setting a reference on @other_surface back to @self.
It's called immodest because it interferes with another object, bluntly
assuming it contains a SDL_Surface pointer and changing it to something
else...
*/
static VALUE surface_immodest_export(VALUE self, VALUE other)
{
if(DATA_PTR(self)!=DATA_PTR(other)){
surface_destroy(other);
DATA_PTR(other)=DATA_PTR(self);
RDATA(other)->dfree=dont_free;
rb_ivar_set(other, id_shared_surface_reference, self);
}
return self;
}
/**
@method destroy => nil
Frees memory used by this surface.
The surface is no longer useable after this call.
*/
static VALUE surface_destroy(VALUE self)
{
if(RDATA(self)->dfree!=dont_free){
GET_SURFACE;
SDL_FreeSurface(surface);
DATA_PTR(self)=NULL;
}else{
rb_ivar_set(self, id_shared_surface_reference, Qnil);
DATA_PTR(self)=NULL;
}
return Qnil;
}
/**
@method blit( source, coordinate ) => Array
@method blit( source, coordinate, sourceRect ) => Array
This method blits (copies, pastes, draws) @source onto the surface it is called on.
@coordinate is the position [x, y] where @source will end up in the destination surface.
@sourcerect is the area in the @source bitmap that you want blitted.
Not supplying it will blit the whole @source.
Returns the rectangle array ([x,y,w,h]) in the surface that was changed.
*/
static VALUE surface_blit(int argc, VALUE* argv, VALUE self)
{
SDL_Surface* src;
SDL_Surface* dest=retrieveSurfacePointer(self);
int result;
SDL_Rect src_rect, dest_rect;
VALUE sourceSurfaceObject, coordinateObject, sourceRectObject;
rb_scan_args(argc, argv, "21", &sourceSurfaceObject, &coordinateObject, &sourceRectObject);
src=retrieveSurfacePointer(sourceSurfaceObject);
PARAMETER2COORD(coordinateObject, &dest_rect.x, &dest_rect.y);
if(argc==3){
PARAMETER2CRECT(sourceRectObject, &src_rect);
result=SDL_BlitSurface(src, &src_rect, dest, &dest_rect);
}else{
result=SDL_BlitSurface(src, NULL, dest, &dest_rect);
}
switch(result){
case -1:SDL_RAISE;return Qnil;break;
case -2:rb_raise(classSurfacesLostException, "all surfaces lost their contents - reload graphics");return Qnil;break;
}
return new_rect_from_SDL_Rect(&dest_rect);
}
/**
@method convert => Surface
@method convert! => self
Creates a new version of the surface in the current display's format,
making it faster to blit.
*/
/**
@method convert_alpha => Surface
@method convert_alpha! => self
Like @convert, creates a new version of the surface in the current display's format,
making it faster to blit.
The alpha version optimizes for fast alpha blitting.
*/
static VALUE surface_convert(VALUE self)
{
GET_SURFACE;
surface=SDL_DisplayFormat(surface);
if(surface){
return createSurfaceObject(surface);
}else{
SDL_RAISE;
return Qnil;
}
}
static VALUE surface_convert_alpha(VALUE self)
{
GET_SURFACE;
surface=SDL_DisplayFormatAlpha(surface);
if(surface){
return createSurfaceObject(surface);
}else{
SDL_RAISE;
return Qnil;
}
}
static VALUE surface_convert_(VALUE self)
{
SDL_Surface* new_surface;
GET_SURFACE;
new_surface=SDL_DisplayFormat(surface);
if(new_surface){
SDL_FreeSurface(surface);
DATA_PTR(self)=new_surface;
return self;
}else{
SDL_RAISE;
return Qnil;
}
}
static VALUE surface_convert_alpha_(VALUE self)
{
SDL_Surface* new_surface;
GET_SURFACE;
new_surface=SDL_DisplayFormatAlpha(surface);
if(new_surface){
SDL_FreeSurface(surface);
DATA_PTR(self)=new_surface;
return self;
}else{
SDL_RAISE;
return Qnil;
}
}
/**
@section Locking
These methods control the locking of surfaces.
If you ever encounter a locking error,
you might try these out.
Locking errors are expected when trying to access video hardware.
Keep a @Surface locked for as short a time as possible.
*/
/**
@method lock => self
Locks the surface.
*/
static VALUE surface_lock(VALUE self)
{
if(SDL_LockSurface(retrieveSurfacePointer(self)) == -1) SDL_RAISE;
return self;
}
/**
@method must_lock => boolean
Returns true when a surface needs locking for pixel access.
*/
static VALUE surface_must_lock(VALUE self)
{
return INT2BOOL(SDL_MUSTLOCK(retrieveSurfacePointer(self)));
}
/**
@method unlock => self
Unlocks a surface that was locked with @lock and returns self.
*/
static VALUE surface_unlock(VALUE self)
{
SDL_UnlockSurface(retrieveSurfacePointer(self));
return self;
}
/**
@method locked? => boolean
Returns true when the surface is locked.
*/
static VALUE surface_locked_(VALUE self)
{
return INT2BOOL(retrieveSurfacePointer(self)->locked);
}
/**
@section Methods
@method save_bmp( filename ) => self
This is the only method in RUDL which stores surface data.
Pass @save_bmp the @filename and the surface data will be saved to that file.
*/
static VALUE surface_save_bmp(VALUE self, VALUE filename)
{
if(SDL_SaveBMP(retrieveSurfacePointer(self), STR2CSTR(filename))==-1) SDL_RAISE;
return self;
}
/**
@section Size methods
These methods return the size of the surface.
*/
/**
@method size => Array[w,h]
*/
static VALUE surface_size(VALUE self)
{
SDL_Surface* surface=retrieveSurfacePointer(self);
return rb_ary_new3(2, UINT2NUM(surface->w), UINT2NUM(surface->h));
}
/**
@method rect => Array[0, 0, w, h]
*/
static VALUE surface_rect(VALUE self)
{
SDL_Rect rect;
SDL_Surface* surface=retrieveSurfacePointer(self);
rect.x=0;
rect.y=0;
rect.w=surface->w;
rect.h=surface->h;
return new_rect_from_SDL_Rect(&rect);
}
/**
@method w => Number
Returns width in pixels.
*/
static VALUE surface_w(VALUE self)
{
return UINT2NUM(retrieveSurfacePointer(self)->w);
}
/**
@method h => Number
Returns height in pixels.
*/
static VALUE surface_h(VALUE self)
{
return UINT2NUM(retrieveSurfacePointer(self)->h);
}
/**
@section Colorkey methods
These methods control the color that will be completely transparent (it will not be copied
to the destination surface.)
*/
/**
@method colorkey => Array[R,G,B]
@method unset_colorkey => self
@method set_colorkey( color ) => self
@method set_colorkey( color, flags ) => self
The only flag for @flags is <code>RLEACCEL</code> which will encode the bitmap in a more efficient way for blitting,
by skipping the transparent pixels.
set_colorkey(nil) removes the color key, same as @unset_colorkey .
*/
static VALUE surface_set_colorkey(int argc, VALUE* argv, VALUE self)
{
SDL_Surface* surface = retrieveSurfacePointer(self);
Uint32 flags = 0, color = 0;
VALUE colorObject, flagsObject;
switch (rb_scan_args(argc, argv, "11", &colorObject, &flagsObject)) {
case 2:
flags = PARAMETER2FLAGS(flagsObject);
case 1:
if (colorObject == Qnil) {
flags = 0;
} else {
flags |= SDL_SRCCOLORKEY;
color = VALUE2COLOR(colorObject, surface->format);
}
}
if (SDL_SetColorKey(surface, flags, color) == -1) SDL_RAISE;
return self;
}
static VALUE surface_unset_colorkey(VALUE self)
{
if (SDL_SetColorKey(retrieveSurfacePointer(self), 0, 0) == -1) SDL_RAISE;
return self;
}
static VALUE surface_colorkey(VALUE self)
{
SDL_Surface* surface=retrieveSurfacePointer(self);
if(!(surface->flags&SDL_SRCCOLORKEY)){
return Qnil;
}
return COLOR2VALUE(surface->format->colorkey, surface);
}
/**
@section Drawing
@method fill( color ) => self
@method fill( color, rect ) => self
Fills rectangle @rect in the surface with @color.
*/
static VALUE surface_fill(int argc, VALUE* argv, VALUE self)
{
SDL_Rect rectangle;
SDL_Surface* surface=retrieveSurfacePointer(self);
VALUE rect, color;
switch(rb_scan_args(argc, argv, "11", &color, &rect)){
case 1:
SDL_FillRect(surface, NULL, VALUE2COLOR(color, surface->format));
break;
case 2:
PARAMETER2CRECT(rect, &rectangle);
SDL_FillRect(surface, &rectangle, VALUE2COLOR(color, surface->format));
break;
}
return self;
}
/**
@section Information
@method pitch
The surface pitch is the number of bytes used in each scanline.
This function should rarely needed, mainly for any special-case debugging.
*/
static VALUE surface_pitch(VALUE self)
{
GET_SURFACE;
return UINT2NUM(surface->pitch);
}
/**
@method bitsize
Returns the number of bits used to represent each pixel.
This value may not exactly fill the number of bytes used per pixel.
For example a 15 bit Surface still requires a full 2 bytes.
*/
static VALUE surface_bitsize(VALUE self)
{
return UINT2NUM(retrieveSurfacePointer(self)->format->BitsPerPixel);
}
/**
@method bytesize
Returns the number of bytes used to store each pixel.
*/
static VALUE surface_bytesize(VALUE self)
{
return UINT2NUM(retrieveSurfacePointer(self)->format->BytesPerPixel);
}
/**
@method flags
Returns the current state flags for the surface.
*/
static VALUE surface_flags(VALUE self)
{
return UINT2NUM(retrieveSurfacePointer(self)->flags);
}
/**
@method losses => Array[redloss, greenloss, blueloss, alphaloss]
Returns the bitloss for each color plane.
The loss is the number of bits removed for each colorplane from a full 8 bits of
resolution. A value of 8 usually indicates that colorplane is not used
(like the alpha plane)
*/
static VALUE surface_losses(VALUE self)
{
SDL_Surface* surface=retrieveSurfacePointer(self);
return rb_ary_new3(4,
UINT2NUM(surface->format->Rloss),
UINT2NUM(surface->format->Gloss),
UINT2NUM(surface->format->Bloss),
UINT2NUM(surface->format->Aloss));
}
/**
@method shifts => Array[redshift, greenshift, blueshift, alphashift]
Returns the bitshifts used for each color plane.
The shift is determine how many bits left-shifted a colorplane value is in a
mapped color value.
*/
static VALUE surface_shifts(VALUE self)
{
SDL_Surface* surface=retrieveSurfacePointer(self);
return rb_ary_new3(4,
UINT2NUM(surface->format->Rshift),
UINT2NUM(surface->format->Gshift),
UINT2NUM(surface->format->Bshift),
UINT2NUM(surface->format->Ashift));
}
/**
@method masks => Array[redmask, greenmask, bluemask, alphamask]
Returns the bitmasks for each color plane.
The bitmask is used to isolate each colorplane value from a mapped color value.
A value of zero means that colorplane is not used (like alpha)
*/
static VALUE surface_masks(VALUE self)
{
SDL_Surface* surface=retrieveSurfacePointer(self);
return rb_ary_new3(4,
UINT2NUM(surface->format->Rmask),
UINT2NUM(surface->format->Gmask),
UINT2NUM(surface->format->Bmask),
UINT2NUM(surface->format->Amask));
}
/**
@section Palette manipulation
@method palette => Array[[R,G,B], [R,G,B],....]
@method set_palette( first, colors ) => self
These methods return or set the 256 color palette that is part of 8 bit @Surface s.
@first is the first color to change.
@colors and the return value of @palette are arrays of colors like
[[50,80,120], [255,255,0]]
=end */
static VALUE surface_palette(VALUE self)
{
SDL_Surface* surface = retrieveSurfacePointer(self);
SDL_Palette* pal = surface->format->palette;
int i;
VALUE retval;
VALUE color;
if(!pal) return Qnil;
retval=rb_ary_new2(256);
for(i=0; i<256; i++){
color=rb_ary_new3(3,
UINT2NUM(pal->colors[i].r),
UINT2NUM(pal->colors[i].g),
UINT2NUM(pal->colors[i].b));
rb_ary_push(retval, color);
}
return retval;
}
static VALUE surface_set_palette(VALUE self, VALUE firstValue, VALUE colors)
{
SDL_Surface* surface = retrieveSurfacePointer(self);
SDL_Palette* pal = surface->format->palette;
int first=NUM2INT(firstValue);
int amount;
int i;
SDL_Color newPal[256];
VALUE color;
VALUE tmp;
RUDL_VERIFY(rb_obj_is_kind_of(colors, rb_cArray), "Need array of colors");
amount=RARRAY(colors)->len;
if (!pal) return Qfalse;
if (first+amount>256) amount=256-first;
for (i=0; i<amount; i++) {
color=rb_ary_entry(colors, i);
tmp=rb_ary_entry(color, 0); newPal[i].r=NUM2Uint8(tmp);
tmp=rb_ary_entry(color, 1); newPal[i].g=NUM2Uint8(tmp);
tmp=rb_ary_entry(color, 2); newPal[i].b=NUM2Uint8(tmp);
}
if (SDL_SetColors(surface, newPal, first, amount)==0) SDL_RAISE;
return self;
}
/**
@section Alpha methods
Gets or sets the overall transparency for the @Surface.
An alpha of 0 is fully transparent, an alpha of 255 is fully opaque.
If your surface has a pixel alpha channel, it will override the overall surface transparency.
You'll need to change the actual pixel transparency to make changes.
If your image also has pixel alpha values and will be used repeatedly, you
will probably want to pass the <code>RLEACCEL</code> flag to the call.
This will take a short time to compile your surface, and increase the blitting speed.
Note that the per-surface alpha value of 128 is considered a special case and is
optimised, so it's much faster than other per-surface values.
*/
/**
@method alpha
@method unset_alpha
@method set_alpha( alpha )
@method set_alpha( alpha, flags )
@set_alpha(nil) removes the per-surface alpha, same as @unset_alpha.
*/
static VALUE surface_set_alpha(int argc, VALUE* argv, VALUE self)
{
SDL_Surface* surface = retrieveSurfacePointer(self);
Uint32 flags = SDL_SRCALPHA;
Uint8 alpha = 0;
VALUE alphaObject, flagsObject;
switch (rb_scan_args(argc, argv, "11", &alphaObject, &flagsObject)) {
case 2:
flags = PARAMETER2FLAGS(flagsObject);
}
if (alphaObject == Qnil) {
flags = alpha = 0;
} else {
alpha = (Uint8) NUM2UINT(alphaObject);
}
if (SDL_SetAlpha(surface, flags, alpha) == -1) SDL_RAISE;
return self;
}
static VALUE surface_unset_alpha(VALUE self)
{
if (SDL_SetAlpha(retrieveSurfacePointer(self), 0, 0) == -1) SDL_RAISE;
return self;
}
static VALUE surface_alpha(VALUE self)
{
SDL_Surface* surface = retrieveSurfacePointer(self);
if(surface->flags & SDL_SRCALPHA){
return UINT2NUM(surface->format->alpha);
}
return Qnil;
}
/**
@section Clipping
@method clip
@method unset_clip
@method clip=( rect )
Retrieves, removes or sets the clipping rectangle for surfaces that are
blitted to this surface.
*/
static VALUE surface_unset_clip(VALUE self)
{
SDL_SetClipRect(retrieveSurfacePointer(self), NULL);
return self;
}
static VALUE surface_clip_(VALUE self, VALUE rectObject)
{
SDL_Rect rect;
PARAMETER2CRECT(rectObject, &rect);
SDL_SetClipRect(retrieveSurfacePointer(self), &rect);
return self;
}
static VALUE surface_clip(VALUE self)
{
return new_rect_from_SDL_Rect(&(retrieveSurfacePointer(self)->clip_rect));
}
/**
@section Drawing
@method get( x, y )
@method get( coordinate )
These methods read single pixels on a surface.
@get or @[] get the color of a pixel.
The coordinate can be given as an [x,y] array or two separate numbers.
@get is an alias for @[].
These methods require the surface to be locked if necessary.
@[]= and @[] are the only methods in RUDL that take separate x and y coordinates.
See also: @Surface.plot, @Surface.[]=
*/
/**
@method [ x, y ]
@method [ coordinate ]
See @get
*/
__inline__ Uint32 internal_get(SDL_Surface* surface, Sint16 x, Sint16 y)
{
SDL_PixelFormat* format = surface->format;
Uint8* pixels;
Uint32 color;
Uint8* pix;
if(x < 0 || x >= surface->w || y < 0 || y >= surface->h){
return 0;
}
SDL_LockSurface(surface);
pixels = (Uint8*)surface->pixels;
RUDL_ASSERT(format->BytesPerPixel>=1, "Color depth too small for surface (<1)");
RUDL_ASSERT(format->BytesPerPixel<=4, "Color depth too large for surface (>4)");
switch(format->BytesPerPixel){
case 1:
color = (Uint32)*((Uint8*)pixels + y * surface->pitch + x);
break;
case 2:
color = (Uint32)*((Uint16*)(pixels + y * surface->pitch) + x);
break;
case 3:
pix = ((Uint8*)(pixels + y * surface->pitch) + x * 3);
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
color = (pix[0]) + (pix[1]<<8) + (pix[2]<<16);
#else
color = (pix[2]) + (pix[1]<<8) + (pix[0]<<16);
#endif
break;
default: /*case 4:*/
color = *((Uint32*)(pixels + y * surface->pitch) + x);
break;
}
SDL_UnlockSurface(surface);
return color;
}
__inline__ Uint32 internal_nonlocking_get(SDL_Surface* surface, Sint16 x, Sint16 y)
{
SDL_PixelFormat* format = surface->format;
Uint8* pixels;
Uint32 color;
Uint8* pix;
if(x < 0 || x >= surface->w || y < 0 || y >= surface->h){
return 0;
}