PDA

View Full Version : Spot the mistake...



savage
14-11-2006, 08:42 PM
I'm trying to compile a game on MacOS X, but at run-time I keep getting an "arithmetic error" AV on code that works perfectly fine on Win32 and Linux

The code is as follows...

procedure SDL_SubSurface( SrcSurface : PSDL_Surface; SrcRect : PSDL_Rect;
DestSurface : PSDL_Surface; DestRect : PSDL_Rect );
var
R, G, B, Pixel1, Pixel2, TransparentColor : Cardinal;
Src, Dest : TSDL_Rect;
Diff : integer;
SrcAddr, DestAddr : cardinal;
_ebx, _esi, _edi, _esp : cardinal;
WorkX, WorkY : word;
SrcMod, DestMod : cardinal;
Bits : cardinal;
begin
if ( SrcSurface = nil ) or ( DestSurface = nil ) then
exit; // Remove this to make it faster
if ( SrcSurface.Format.BitsPerPixel <DestSurface> y + h then
begin
smallint( Src.h ) := y + h - Dest.y;
smallint( Dest.h ) := y + h - Dest.y;
if smallint( Dest.h ) < 1 then
exit;
end;
// Source's left side is less than the dest.clip
if Dest.x < x then
begin
Diff := x - Dest.x;
Src.x := Src.x + Diff;
smallint( Src.w ) := smallint( Src.w ) - Diff;
Dest.x := x;
smallint( Dest.w ) := smallint( Dest.w ) - Diff;
if smallint( Dest.w ) < 1 then
exit;
end;
// Source's Top side is less than the dest.clip
if Dest.y < y then
begin
Diff := y - Dest.y;
Src.y := Src.y + Diff;
smallint( Src.h ) := smallint( Src.h ) - Diff;
Dest.y := y;
smallint( Dest.h ) := smallint( Dest.h ) - Diff;
if smallint( Dest.h ) < 1 then
exit;
end;
end;
with SrcSurface^ do
begin
SrcAddr := cardinal( Pixels ) + UInt32( Src.y ) * Pitch + UInt32( Src.x ) *
Format.BytesPerPixel;
SrcMod := Pitch - Src.w * Format.BytesPerPixel;
TransparentColor := Format.colorkey;
end;
with DestSurface^ do
begin
DestAddr := cardinal( Pixels ) + UInt32( Dest.y ) * Pitch + UInt32( Dest.x ) *
Format.BytesPerPixel;
DestMod := Pitch - Dest.w * Format.BytesPerPixel;
Bits := DestSurface.Format.BitsPerPixel;
end;
SDL_LockSurface( SrcSurface );
SDL_LockSurface( DestSurface );
WorkY := Src.h;
case bits of
8 :
begin
repeat
WorkX := Src.w;
repeat
Pixel1 := PUInt8( SrcAddr )^;
if ( Pixel1 <> TransparentColor ) and ( Pixel1 <0> 0 then
begin
R := (Pixel2 and $E0) - (Pixel1 and $E0);
G := (Pixel2 and $1C) - (Pixel1 and $1C);
B := (Pixel2 and $03) - (Pixel1 and $03);
if R > $E0 then
R := 0;
if G > $1C then
G := 0;
if B > $03 then
B := 0;
PUInt8( DestAddr )^ := R or G or B;
end;
end;
inc( SrcAddr );
inc( DestAddr );
dec( WorkX );
until WorkX = 0;
inc( SrcAddr, SrcMod );
inc( DestAddr, DestMod );
dec( WorkY );
until WorkY = 0;
end;
15 :
begin
repeat
WorkX := Src.w;
repeat
Pixel1 := PUInt16( SrcAddr )^;
if ( Pixel1 <> TransparentColor ) and ( Pixel1 <0> 0 then
begin
R := (Pixel2 and $7C00) - (Pixel1 and $7C00);
G := (Pixel2 and $03E0) - (Pixel1 and $03E0);
B := (Pixel2 and $001F) - (Pixel1 and $001F);
if R > $7C00 then
R := 0;
if G > $03E0 then
G := 0;
if B > $001F then
B := 0;
PUInt16( DestAddr )^ := R or G or B;
end;
end;
inc( SrcAddr, 2 );
inc( DestAddr, 2 );
dec( WorkX );
until WorkX = 0;
inc( SrcAddr, SrcMod );
inc( DestAddr, DestMod );
dec( WorkY );
until WorkY = 0;
end;
16 :
begin
repeat
WorkX := Src.w;
repeat
Pixel1 := PUInt16( SrcAddr )^;
if ( Pixel1 <> TransparentColor ) and ( Pixel1 <0> 0 then
begin
R := (Pixel2 and $F800) - (Pixel1 and $F800);
G := (Pixel2 and $07E0) - (Pixel1 and $07E0);
B := (Pixel2 and $001F) - (Pixel1 and $001F);
if R > $F800 then
R := 0;
if G > $07E0 then
G := 0;
if B > $001F then
B := 0;
PUInt16( DestAddr )^ := R or G or B;
end;
end;
inc( SrcAddr, 2 );
inc( DestAddr, 2 );
dec( WorkX );
until WorkX = 0;
inc( SrcAddr, SrcMod );
inc( DestAddr, DestMod );
dec( WorkY );
until WorkY = 0;
end;
24 :
begin
repeat
WorkX := Src.w;
repeat
Pixel1 := PUInt32( SrcAddr )^ and $00FFFFFF;
if ( Pixel1 <> TransparentColor ) and ( Pixel1 <0> 0 then
begin
R := (Pixel2 and $FF0000) - (Pixel1 and $FF0000);
G := (Pixel2 and $00FF00) - (Pixel1 and $00FF00);
B := (Pixel2 and $0000FF) - (Pixel1 and $0000FF);
if R > $FF0000 then
R := 0;
if G > $00FF00 then
G := 0;
if B > $0000FF then
B := 0;
PUInt32( DestAddr )^ := (PUInt32( DestAddr )^ and $FF000000)or ( R or G or B );
end;
end;
inc( SrcAddr, 3 );
inc( DestAddr, 3 );
dec( WorkX );
until WorkX = 0;
inc( SrcAddr, SrcMod );
inc( DestAddr, DestMod );
dec( WorkY );
until WorkY = 0;
end;
32 :
begin
repeat
WorkX := Src.w;
repeat
Pixel1 := PUInt32( SrcAddr )^;
if ( Pixel1 <> TransparentColor ) and ( Pixel1 <0> 0 then
begin
R := (Pixel2 and $FF0000) - (Pixel1 and $FF0000);
G := (Pixel2 and $00FF00) - (Pixel1 and $00FF00);
B := (Pixel2 and $0000FF) - (Pixel1 and $0000FF);
if R > $FF0000 then
R := 0;
if G > $00FF00 then
G := 0;
if B > $0000FF then
B := 0;
PUInt32( DestAddr )^ := R or G or B;
end
else
PUInt32( DestAddr )^ := Pixel2;
end;
inc( SrcAddr, 4 );
inc( DestAddr, 4 );
dec( WorkX );
until WorkX = 0;
inc( SrcAddr, SrcMod );
inc( DestAddr, DestMod );
dec( WorkY );
until WorkY = 0;
end;
end;
SDL_UnlockSurface( SrcSurface );
SDL_UnlockSurface( DestSurface );
end;


the lines from the code above that cause the crashes, regardless of surface depth are...

R := (Pixel2 and $FF0000) - (Pixel1 and $FF0000);
G := (Pixel2 and $00FF00) - (Pixel1 and $00FF00);
B := (Pixel2 and $0000FF) - (Pixel1 and $0000FF);

and the other similar code blocks.

I can't see why these lines would cause an AV on MacOS X, but not on Win32 or Linux all of which use the FreePascal compiler. Any ideas?

technomage
14-11-2006, 09:44 PM
Dom

Is this a PPC Mac or an Intel mac?If it's PPC that remember that the High and Low bytes are swapped over,so the masks would not work.

so

$FF0000

would need to be

$0000FF

Just a thought

Dean

savage
14-11-2006, 10:00 PM
It's an Intel Mac, but I'm not sure if MacOS X being based on FreeBSD would make any endian difference.

technomage
14-11-2006, 11:32 PM
Endian is down to the hardware I think. I'm sure you could test the theory in a small app.