PDA

View Full Version : JEDI-SDL/S2DL Testing for transparent?



jdarling
11-09-2006, 05:29 PM
Its me again Margaret... Well ok, thats more how I feel every time I ask a question :). Anyways, to the point. I'm working on some pixel perfect collision stuff using S2DL and JEDI-SDL. I have the code working to tell me the overlap rectangle of the two surfaces. No problem. The problem is, how do I tell if the Alpha or color of the pixels is the transparent one? Looking into SDLImage I can see how to setup the transparent color, but not how to get it back. I can find the methods (in SDL.pas) to getRGBA, but not how to use the SDLImage in conjunction with it.

Anyone care to post up some sample code showing how exactly I can tell if a pixel is (either by Alpha or Color) transparent on the surface?

Thanks in advance,

savage
12-09-2006, 10:33 AM
KiCHY's Sprite SDL engine has an example of pixel perfect collision. Look for the demo under the SDLSprites directory.

cairnswm
12-09-2006, 10:58 AM
SDL uses an SDL_surface to store its data. As far as I understand S2DL uses a OpenGL texture to store its data. Not sure if a normal SDL call will work against the OpenGL texture.

As far as I know the next version of SDL will be fully OpenGL and then it should be the same calee.

jdarling
12-09-2006, 01:18 PM
KiCHY's Sprite SDL engine has an example of pixel perfect collision. Look for the demo under the SDLSprites directory.

Hmm... I obviously don't have the latest and greatest of the Beta source. Can you shoot up a link, as the version I have only has a 3D folder in the Demos folder. I know that the link for download is some place on the site, but honestly I can't remember were I got it from :)

savage
12-09-2006, 01:41 PM
It should be under /SDLSpriteEngine/Demos/CollisionTest/ if I'm not mistaken. If not you can have a look here - http://jedi-sdl.cvs.sourceforge.net/jedi-sdl/JEDI-SDLv1.0/SDLSpriteEngine/Demos/

jdarling
12-09-2006, 05:28 PM
Looking at the samples in the SpriteEngine folder all I see is Rect based collision samples :(.

jdarling
12-09-2006, 06:44 PM
I found a project called SDL_Collide that implements quite a bit of what I've been looking for. After translating it from C to Pascal it seems to work. In case anyone else is interested I'm going to paste it at the end of this message. Once I get the actual collision code complete I might even be nice enough to paste it in.

Info on SDL_Collide: http://gpwiki.org/index.php/SDL:Tutorials:Collision_Detection_between_2_SDL_Su rfaces

Translated from: http://gpwiki.org/index.php/Files:Sdl_collide.zip
unit SDLCollide;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils, sdl;

function SDL_CollideTransparentPixelTest(Surface : PSDL_Surface; X, Y : Integer) : Boolean;
function SDL_CollidePixel( Surface1 : PSDL_Surface; AtX1, AtY1 : Integer;
Surface2 : PSDL_Surface; AtX2, AtY2 : Integer) : Boolean;
function SDL_CollideBoundingBox( Surface1 : PSDL_Surface; AtX1, AtY1 : Integer;
Surface2 : PSDL_Surface; AtX2, AtY2 : Integer) : Boolean; overload;
function SDL_CollideBoundingBox(R1, R2 : PSDL_Rect) : Boolean; overload;
function SDL_CollideBoundingCircle(x1, y1, r1, x2, y2, r2, offset : Integer) : Boolean; overload;
function SDL_CollideBoundingCircle( Surface1 : PSDL_Surface; AtX1, AtY1 : Integer;
Surface2 : PSDL_Surface; AtX2, AtY2 : Integer;
offset : Integer) : Boolean; overload;

implementation

type
TPixelArray = Array[0..64000] of UInt8;
TPixelFormat = Array[0..2] of UInt8;

function SDL_COLLIDE_MAX(A, B : UInt32) : UInt32;
begin
if A > B then
result := A
else
result := B;
end;

function SDL_COLLIDE_MIN(A, B : UInt32) : UInt32;
begin
if A < B then
result := A
else
result := B;
end;

function SDL_CollideTransparentPixelTest(Surface : PSDL_Surface; X, Y : Integer) : Boolean;
var
bits : Pointer;
bpp, r, g, b : Uint8;
PixelColor : UInt32;
begin
If Surface = Nil then
Exit;
bpp := Surface^.Format^.BytesPerPixel;
bits := @(TPixelArray(Surface^.Pixels^)[(Y * Surface^.pitch) + (X * bpp)]);

case bpp of
1:
begin
PixelColor := PUint8( bits )^;
end;
2:
begin
PixelColor := PUint16( bits )^;
end;
3:
begin
r := TPixelFormat(bits^)[(Surface^.Format^.Rshift div 8)];
g := TPixelFormat(bits^)[(Surface^.Format^.Gshift div 8)];
b := TPixelFormat(bits^)[(Surface^.Format^.Bshift div 8)];

PixelColor := 0;
PixelColor := PixelColor or ((r shl Surface^.Format^.Rshift ));
PixelColor := PixelColor or ((r shl Surface^.Format^.Gshift ));
PixelColor := PixelColor or ((r shl Surface^.Format^.Bshift ));
end;
4:
begin
PixelColor := PUint32( bits )^;
end;
end;
result := PixelColor = Surface^.Format^.ColorKey;
end;

function SDL_CollidePixel( Surface1 : PSDL_Surface; AtX1, AtY1 : Integer;
Surface2 : PSDL_Surface; AtX2, AtY2 : Integer) : Boolean;
var
inter_x0, inter_x1, inter_y0, inter_y1,
x, y,
ax1, ay1, bx1, by1 : UInt32;
begin
ax1 := AtX1 + Surface1^.w -1;
ay1 := AtY1 + Surface1^.h -1;
bx1 := AtX2 + Surface2^.w -1;
bx1 := AtY2 + Surface2^.h -1;

if (bx1<AtX1) or (ax1<AtX2) then
begin
result := false;
exit;
end;
if (by1<AtY1) or (ay1 < AtY2) then
begin
result := false;
exit;
end;
inter_x0 := SDL_COLLIDE_MAX(AtX1, AtX2);
inter_X1 := SDL_COLLIDE_MIN(ax1, bx1);
inter_y0 := SDL_COLLIDE_MAX(AtY1, AtY2);
inter_y1 := SDL_COLLIDE_MIN(ay1, by1);
for y := inter_y0 to inter_y1 do
for x := inter_x0 to inter_x1 do
if (SDL_CollideTransparentPixelTest(Surface1, x-AtX1, y-AtY1) and
SDL_CollideTransparentPixelTest(Surface2, x-AtX2, y-AtY2)) then
begin
result := true;
exit;
end;
result := false;
end;

function SDL_CollideBoundingBox( Surface1 : PSDL_Surface; AtX1, AtY1 : Integer;
Surface2 : PSDL_Surface; AtX2, AtY2 : Integer) : Boolean;
begin
result := (AtX2 + Surface2^.w < AtX1) or
(AtX2 > AtX1 + Surface1^.w) or
(AtY2 + Surface2^.h < AtY1) or
(AtY2 > AtY1 + Surface1^.h);

result := not result;
end;

function SDL_CollideBoundingBox(R1, R2 : PSDL_Rect) : Boolean;
begin
result := (R2^.X + R2^.W < R1^.X) or
(R2^.X > R1^.X + R1^.W) or
(R2^.Y + R2^.H < R1^.Y) or
(R2^.Y > R1^.Y + R1^.H);
result := not result;
end;

function SDL_CollideBoundingCircle(x1, y1, r1, x2, y2, r2, offset : Integer) : Boolean;
var
xdiff, ydiff, dcentre_sq, r_sum_sq : Integer;
begin
xdiff := X2-X1;
ydiff := Y2-Y1;
dcentre_sq := (ydiff*ydiff)+(xdiff*xdiff);
r_sum_sq := r1 + r2;
r_sum_sq := r_sum_sq * r_sum_sq;
result := dcentre_sq - r_sum_sq <= (offset*offset);
end;

function SDL_CollideBoundingCircle( Surface1 : PSDL_Surface; AtX1, AtY1 : Integer;
Surface2 : PSDL_Surface; AtX2, AtY2 : Integer;
offset : Integer) : Boolean;
var
r1, r2 : Integer;
begin
r1 := (Surface1^.w + Surface1^.h) div 4;
r2 := (Surface2^.w + Surface2^.h) div 4;
AtX1 := AtX1 + Surface1^.w div 2;
AtY1 := AtY1 + Surface1^.h div 2;
AtX2 := AtX2 + Surface2^.w div 2;
AtY2 := AtY2 + Surface2^.h div 2;
result := SDL_CollideBoundingCircle(AtX1, AtY1, R1, AtX2, AtY2, R2, offset);
end;

end.

jdarling
12-09-2006, 09:26 PM
As a side note, the SDL_CollideTransparentPixelTest doesn't test for alpha transparency of a particular pixel. Thus it only works with color keyed images. Anyone have an idea on how to get it to look for an Alpha value on a pixel below a threashold so that it will consider the pixel as transparent?