Results 1 to 5 of 5

Thread: Alpha Transparency for Simba (No Plugins)

  1. #1
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default Alpha Transparency for Simba (No Plugins)

    I wrote a class for Simba to allow Bitmaps with the alpha channel. All you have to do is change SMART to also use it.

    To do this, I opened Client.java and replaced: BufferedImage.TYPE_INT_RGB with BufferedImage.TYPE_INT_ARGB and recompiled Smart. All you need is the new SMART.jar. NOTE: You can also draw transparent images on the browser or any window as well..


    Next, I wrote the following class to load images manually:

    Simba Code:
    type
      TBitmap32 = record
        Pixels: array of byte;
        W, H: Integer;
      end;


    Procedure TBitmap32.Init(W, H: Integer);
    Begin
      Self.W := W;
      Self.H := H;
      SetLength(Pixels, ((Self.W * $20 + $1F) div $20) * $4 * Self.H);
    End;

    Procedure TBitmap32.Init(Path: String); overload;
    type PInt = ^Integer;
    var
      Stream: TFileStream;
      Header: array[0..53] of byte;
      Offset, Size: Integer;
    Begin
      try
        Stream.Init(Path, $0000);
        Stream.Read(Header, sizeof(Header));
        If ((Header[0] = $42) and (Header[1] = $4D) and (Header[28] = $20)) Then
        begin
          Self.W := PInt(@Header[18])^;
          Self.H := PInt(@Header[22])^;
          Offset := PInt(@header[10])^;
          Size := ((Self.W * Header[28] + $1F) div $20) * $4 * Self.H;
          Stream.Seek(Offset, soBeginning);
          SetLength(Self.Pixels, Size);
          Stream.Read(Self.Pixels[0], Size);
          Self.Flip();
        end;
      finally
        Stream.Free;
      end;
    End;

    Procedure TBitmap32.Save(Path: String);
    type PInt = ^Integer;
    var
      Stream: TFileStream;
      I, Size: Integer;
    Begin
      try
        Self.Flip();
        Stream.Init(Path, $FF00);
        Size := ((Self.W * $20 + $1F) div $20) * $4 * Self.H;
        Stream.WriteWord($4D42);
        {$IFNDEF BHEXTENDED}
        Stream.WriteDWord(Size + $7A);
        {$ELSE}
        Stream.WriteDWord(Size + $8A);
        {$ENDIF}
        Stream.WriteDWord($0);
        {$IFNDEF BHEXTENDED}
        Stream.WriteDWord($7A);
        Stream.WriteDWord($6C);
        {$ELSE}
        Stream.WriteDWord($8A);
        Stream.WriteDWord($7C);
        {$ENDIF}
        Stream.WriteDWord(Self.W);
        Stream.WriteDWord(Self.H);
        Stream.WriteWord($1);
        Stream.WriteWord($20);
        Stream.WriteDWord($3);
        Stream.WriteDWord(Size);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($FF0000);
        Stream.WriteDWord($FF00);
        Stream.WriteDWord($FF);
        Stream.WriteDWord($FF000000);
        Stream.WriteDWord($73524742);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        {$IFDEF BHEXTENDED}
        Stream.WriteDWord($4);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        Stream.WriteDWord($0);
        {$ENDIF}
        Stream.WriteBuffer(Self.Pixels[0], Size);
      finally
        Stream.Free;
      end;
    End;

    Procedure TBitmap32.Flip();
    var
      I, J: Integer;
      Ptr: ^PtrUInt;
    Begin
      Ptr := @Self.Pixels[0];
      For I := 0 To (Self.H div 2) - 1 do
        For J := 0 To Self.W - 1 Do
          Swap(Ptr[(Self.H - I - 1) * Self.W + J]^, Ptr[I * Self.W + J]^);
    End;

    Function TBitmap32.GetMufasaBitmap(): TMufasaBitmap;
    Begin
      Result.Init(Client.GetMBitmaps);
      Result.SetPersistentMemory(PtrUInt(@Self.Pixels[0]), Self.W, Self.H);
    End;

    Function TBitmap32.Copy(): TBitmap32;
    Begin
      Result.W := Self.W;
      Result.H := Self.H;
      Result.Pixels := Self.Pixels;
    End;

    Function TBitmap32.GetPixel(X, Y: Integer): TColor;
    type
      TColour32 = Union Colour: Integer; RGB: TRGB32; end;
    var
      Ptr: ^TColour32;
    Begin
      Ptr := @Self.Pixels[0];
      Result := Ptr[Y * Self.W + X]^.Colour;
      Result := (Result and $FF000000) or ((Result and $FF0000) shr 16) or (Result and $00FF00) or ((Result and $0000FF) shl 16);
    End;

    Procedure TBitmap32.SetPixel(X, Y: Integer; Colour: TColor);
    type
      TColour32 = Union Colour: Integer; RGB: TRGB32; end;
      PColour32 = ^TColour32;
    var
      Ptr: ^TColour32;
    Begin
      Ptr := @Self.Pixels[0];
      Colour := (Colour and $FF000000) or ((Colour and $FF0000) shr 16) or (Colour and $00FF00) or ((Colour and $0000FF) shl 16);
      Ptr[Y * Self.W + X]^.Colour := Colour;
    End;

    Procedure TBitmap32.GetPixel(X, Y: Integer; var R, G, B, A: Byte) overload;
    type
      TColour32 = Union Colour: Integer; RGB: TRGB32; end;
      PColour32 = ^TColour32;
    var
      Ptr: ^TColour32;
    Begin
      Ptr := @Self.Pixels[0];
      R := Ptr[Y * Self.W + X]^.RGB.R;
      G := Ptr[Y * Self.W + X]^.RGB.G;
      B := Ptr[Y * Self.W + X]^.RGB.B;
      A := Ptr[Y * Self.W + X]^.RGB.A;
    End;

    Procedure TBitmap32.SetPixel(X, Y: Integer; R, G, B, A: Byte) overload;
    type
      TColour32 = Union Colour: Integer; RGB: TRGB32; end;
      PColour32 = ^TColour32;
    var
      Ptr: ^TColour32;
    Begin
      Ptr := @Self.Pixels[0];
      Ptr[Y * Self.W + X]^.RGB.R := R;
      Ptr[Y * Self.W + X]^.RGB.G := G;
      Ptr[Y * Self.W + X]^.RGB.B := B;
      Ptr[Y * Self.W + X]^.RGB.A := A;
    End;

    Procedure TBitmap32.FromString(const Data: String);
    type PInt = ^Integer;
    var
      Str: String;
      I: Integer;
      O: Integer;
    Begin
      If (Data[1] = 'm') Then
      begin
        O := sizeof(Integer) * 2;
        Str := DecompressString(Base64Decode(Copy(Data, 2, Length(Data) - 1)));
        SetLength(Self.Pixels, Length(Str));

        Self.W := PInt(@Str[1])^;
        Self.H := PInt(@Str[5])^;

        For I := O + 1 To Length(Str) Do
          Self.Pixels[I - 1] := Byte(Str[I]);
      end;
    End;

    Function TBitmap32.ToString(): String;
    type PInt = ^Integer;
    var
      Str: String;
      I: Integer;
      O: Integer;
    Begin
      O := sizeof(Integer) * 2;
      SetLength(Str, Length(Self.Pixels) + O);

      PInt(@Str[1])^ := Self.W;
      PInt(@Str[5])^ := Self.H;

      For I := O + 1 To Length(Self.Pixels) Do
        Str[I] := AnsiChar(Self.Pixels[I - 1]);
      Result := 'm' + Base64Encode(CompressString(Str));
    End;

    Function ToString(var Bmp: TBitmap32): String; override;
    begin
      Result := Bmp.ToString();
    end;


    //Just a test function.. Not part of the API.
    Procedure SetAlphas(var Bmp: TBitmap32; ADiv: Integer);
    var
      I, J: Integer;
      R, G, B, A: Byte;
    Begin
      For I := 0 To Bmp.H - 1 Do
        For J := 0 To Bmp.W - 1 Do
        Begin
          Bmp.GetPixel(J, I, R, G, B, A);
          Bmp.SetPixel(J, I, R, G, B, A div ADiv);
        End;
    End;

    var
      Smart: TSmart;
      TBmp: TBitmap32;
      TMBmp: TMufasaBitmap;
    begin
      ClearDebug();
      Smart.Create(800, 600);
      Smart.Graphics().Clear();

      TBmp.Init('C:/Users/Brandon/Desktop/Small.bmp');
      SetAlphas(TBmp, 100);

      TMBmp := TBmp.GetMufasaBitmap();
      Smart.Graphics().DrawBitmap(TMBmp.getIndex(), Point(175, 100));
      TMBmp.Free();
    end.


    Example Results:








    Saving Bitmaps to disk (You can see that it has a transparent background):

    and it's a BITMAP.. Not a PNG.

    Properties:



    Photoviewer shows the background as transparent as well..



    You can use this site to convert a PNG to a 32-bit bitmap (I use my own program to convert): http://www.picresize.com/

    OR pray that someone adds Alpha support to Simba.. Enjoy.


    NOTES:

    The code above does not require explicit memory allocation. This means that if something crashes, you don't have a leak. You never have to free anything either because there's nothing to free. The only time freeing of anything is required is if you convert to TMufasaBitmap. That's when you free the resulting TMufasaBitmap. NOT the bitmap belonging to this API.

    I also doubt TMufasaBitmap would need freeing as it doesn't allocate memory for bitmap pointers. But who knows.. There's also a ToString and FromString function to allow you to store and create bitmaps to/from strings.
    Last edited by Brandon; 02-02-2015 at 10:17 PM.
    I am Ggzz..
    Hackintosher

  2. #2
    Join Date
    Dec 2010
    Posts
    483
    Mentioned
    30 Post(s)
    Quoted
    328 Post(s)

    Default

    Sweet! Thanks for the share!

  3. #3
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by the bank View Post
    Sweet! Thanks for the share!

    Glad you like it.

    In case anyone needs to figure out conversions between 32-bit and 24-bit colours.. Quick lesson in bit-masking:

    Simba Code:
    //Because Simba's TRGB32 struct is actually BGRA and NOT RGBA.. Lol.. It's named badly.
    type
      TRGBA = packed record
        R, G, B, A: Byte;
      end;

    //Just to "show" another conversion between RGBA and Integer.
    type
      TColour32 = Union Colour: Integer; RGB: TRGBA; end;
      PColour32 = ^TColour32;


    //Not needed. Only used to print colours in a recognisable format.
    Function RGBAToBGRA(var Colour: Integer): Integer;
    begin
      Result := (Colour and $FF000000) or ((Colour and $FF0000) shr 16) or (Colour and $00FF00) or ((Colour and $0000FF) shl 16);
    end;


    var
      A, B: Integer;
    begin
      A := $FFFF0000;       //Red with Full Alpha channel.
      A := A xor $FF000000; //Mask out the alpha channel.
      writeln(TColour32(RGBAToBGRA(A)));


      A := $FF00FF00;        //Green with Full Alpha channel.
      A := A xor $FF000000;  //Mask out the alpha channel.
      writeln(TColour32(RGBAToBGRA(A)));


      A := $FF0000FF;       //Blue with Full Alpha channel.
      A := A xor $FF000000; //Mask out the alpha channel.
      writeln(TColour32(RGBAToBGRA(A)));


      writeln('');
      //-----------------------------------------------------------//


      A := $00FF0000;       //Red without Full Alpha channel.
      A := A or $FF000000;  //Add full alpha channel.
      writeln(TColour32(RGBAToBGRA(A)));


      A := $0000FF00;       //Green without Full Alpha channel.
      A := A or $FF000000;  //Add full alpha channel.
      writeln(TColour32(RGBAToBGRA(A)));


      A := $000000FF;       //Blue without Full Alpha channel.
      A := A or $FF000000;  //Add full alpha channel.
      writeln(TColour32(RGBAToBGRA(A)));


      writeln('');
      //----------------------------------------------------------//



      A := $00FF0000;        //Red without alpha channel.
      A := A or $80000000;   //Add half alpha channel.
      writeln(TColour32(RGBAToBGRA(A)));

      A := $80FF0000;        //Red with Half alpha channel.
      A := A or $FF000000 xor $FF000000;   //Mask out alpha channel. Does not matter if it's half or not.
      writeln(TColour32(RGBAToBGRA(A)));


      A := $80FF0000;        //Red with Half alpha channel.
      A := A and $00FFFFFF;   //Mask out alpha channel. Does not matter if it's half or not. Same as the above or + xor.
      writeln(TColour32(RGBAToBGRA(A)));

      //etc..
    end.

    Progress Report:
    {COLOUR = 255, RGB = {R = 255, G = 0, B = 0, A = 0}}
    {COLOUR = 65280, RGB = {R = 0, G = 255, B = 0, A = 0}}
    {COLOUR = 16711680, RGB = {R = 0, G = 0, B = 255, A = 0}}
    
    {COLOUR = -16776961, RGB = {R = 255, G = 0, B = 0, A = 255}}
    {COLOUR = -16711936, RGB = {R = 0, G = 255, B = 0, A = 255}}
    {COLOUR = -65536, RGB = {R = 0, G = 0, B = 255, A = 255}}
    
    {COLOUR = -2147483393, RGB = {R = 255, G = 0, B = 0, A = 128}}
    {COLOUR = 255, RGB = {R = 255, G = 0, B = 0, A = 0}}
    
    {COLOUR = -2147483393, RGB = {R = 255, G = 0, B = 0, A = 128}}
    {COLOUR = 255, RGB = {R = 255, G = 0, B = 0, A = 0}}


    Without masking, you could always just cast the colour to a TRGB32 and remove the alpha channel that way as well.. In the above examples, I used masking. You do not need the BGRAToRGBA or TColour32 when you do masking.

    Something Simba really should have been doing.. That way, you can compare 32-bit colours with 24-bit colours without the alpha channel getting in the way..


    TLDR:

    To add the alpha channel: Colour := Colour or $XX000000; Where XX is between 0 and $FF aka 255 inclusive.

    To remove the alpha channel: Colour := Colour and $00FFFFFF.
    Last edited by Brandon; 02-02-2015 at 07:16 PM.
    I am Ggzz..
    Hackintosher

  4. #4
    Join Date
    Sep 2010
    Posts
    5,762
    Mentioned
    136 Post(s)
    Quoted
    2739 Post(s)

    Default

    Nice, and how are you calling flip inside of Init and Save without a forwarded procedure?

  5. #5
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Robert View Post
    Nice, and how are you calling flip inside of Init and Save without a forwarded procedure?
    Because Flip is a member function belonging to the record/class TBitmap32. If you fully qualify it by using "self (dot) FunctionName", the lookup will be fine. If you just do "FunctionName", it will not find it unless it's forwarded or declared before init & save. It must be fully qualified with the self pointer/reference to avoid forwarding or pre-declaration.


    TLDR: Self.Flip() vs. Flip(); Self.FunctionName() vs. FunctionName();
    Last edited by Brandon; 02-02-2015 at 06:36 PM.
    I am Ggzz..
    Hackintosher

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •