• Welcome to Vampyre Imaging Library Forum. Please login or sign up.
 

Can I draw a circle onto a TSingleImage or TImgData?

Started by sofakng, 30 August 2007, 00:15:15

Previous topic - Next topic

sofakng

First of all, this library is very impressive!!

I have three quick questions:

1) Let's say I have an image and want to change only the alpha values of an ellipse-shape inside my image.  How can I do that?

2) The library seems to support many DirectX (D3D) functions.  Is there any to update an existing D3D texture?  For example, I want to have a HUGE (5000x3000) TSingleImage/TImgData and then create smaller D3D textures from it.  If my TSingleImage/TImgData changes, I want to update the appropriate the D3D texture.

3) How can I take a small piece of a TSingleImage/TImgData and make a D3D texture out of it?  (let's say I want to take a 50x50 quad from the center of my TSingleImage/TImgData).

Thanks for your help!

Galfar

I'll start from the last:

3) Simplest way would be to create new smaller image and copy piece of the original image
onto it. Then you can create D3D texture out of the smaller one.

var
  OrigImage, SmallImage: TSingleImage;
  Texture: IDirect3DTexture9;
  D3DDevice: IDirect3DDevice9;

.... init D3D ....
.... create orig image, say 1024x1024 pixels ....
SmallImage := TSingleImage.CreateFromParams(256, 256, OrigImage.Format); // create small image
OrigImage.CopyTo(512, 512, SmallImage.Width, SmallImage.Height, SmallImage, 0, 0); // copy from orig to small
CreateD3DTextureFromImage(SmallImage.ImageDataPointer^, D3DDevice, Texture); // create texture from small image


2) There is no Imaging function for this now but I'll add one in the future. Meanwhile you can use regular D3D texture updates using IDirect3DTexture9.LockRect method.

var
  Image: TSingleImage;
  Texture: IDirect3DTexture9;
  Rect: TD3DLockedRect;
  PixelPtr, DestPtr: Pointer;
  X, Y, I, LineBytes, TextureSize: Integer;  // say TextureSize is 128, [X, Y] is source position in image

  .... create your texture and image ....
  Texture.LockRect(0, Rect, nil, 0);  // lock texture
 
  LineBytes := Image.FormatInfo.GetPixelsSize(Image.FormatInfo.Format, TextureSize, 1);
 
  for I := 0 to TextureSize - 1 do
  begin
    Move(Image.PixelPointers[X, Y + I]^,                           // move pixels from image to texture
        PByteArray(Rect.pBits)[I * Rect.Pitch], LineBytes);
  end;

  Texture.UnlockRect(0);  // unlock texture

Note that this will work only for non DXTC formats (PixelPointers doesn't work for them).

1) Do you need it working for all data formats or just for one like A8R8G8B8? And do you need it filled or just outlined?

sofakng

Thanks for your help!!

Quote from: Galfar on 31 August 2007, 20:16:24
1) Do you need it working for all data formats or just for one like A8R8G8B8? And do you need it filled or just outlined?


I just need it to work for A8R8G8B8.  (If I load a PNG or JPG, I can convert whatever format it's currently in to A8R8G8B8)

Basically all I'm doing in my program is creating A8R8G8B8 textures to be converted into D3D textures so all I need is A8R8G8B8 support, I think.

Also, I'd like to be able to draw alpha squares and rectangles if possible.  (eg. change only the alpha values in an A8R8G8B8 image in a square, rectangle, or circle/ellipse shape)

Thanks!!!

Galfar

Here is code for ellipse that changes alpha of A8R8G8B8 image:

procedure DrawPixelAlpha(Canvas: TImagingCanvas; X, Y: Integer; Alpha: Byte);
var
  ColRec: TColor32Rec;
begin
  ColRec.Color := Canvas.Pixels32[X, Y];
  ColRec.A := Alpha;
  Canvas.Pixels32[X, Y] := ColRec.Color;
end;

procedure DrawAlphaEllipse(Canvas: TImagingCanvas; const Rect: TRect; Alpha: Byte; Fill: Boolean);
var
RadX, RadY, DeltaX, DeltaY, R, RX, RY: LongInt;
X1, X2, Y1, Y2, Bpp, OldY, I: LongInt;
Color: PColor32Rec;
begin
  X1 := Rect.Left;
  X2 := Rect.Right;
  Y1 := Rect.Top;
  Y2 := Rect.Bottom;

  SwapMin(X1, X2);
  SwapMin(Y1, Y2);

  RadX := (X2 - X1) div 2;
  RadY := (Y2 - Y1) div 2;

  Y1 := Y1 + RadY;
  Y2 := Y1;
  OldY := Y1;

  DeltaX := (RadX * RadX);
  DeltaY := (RadY * RadY);
  R  := RadX * RadY * RadY;
  RX := R;
  RY := 0;

  if Fill then
  begin
    for I := X1 to X2 do
      DrawPixelAlpha(Canvas, I, Y1, Alpha);
  end;

  DrawPixelAlpha(Canvas, X1, Y1, Alpha);
  DrawPixelAlpha(Canvas, X2, Y1, Alpha);

  while RadX > 0 do
  begin
    if R > 0 then
    begin
      Inc(Y1);
      Dec(Y2);
      Inc(RY, DeltaX);
      Dec(R, RY);
    end;
    if R <= 0 then
    begin
      Dec(RadX);
      Inc(X1);
      Dec(X2);
      Dec(RX, DeltaY);
      Inc(R, RX);
    end;

    if (OldY <> Y1) and Fill then
    begin
      for I := X1 to X2 do
        DrawPixelAlpha(Canvas, I, Y1, Alpha);
      for I := X1 to X2 do
        DrawPixelAlpha(Canvas, I, Y2, Alpha);
    end;
    OldY := Y1;

    DrawPixelAlpha(Canvas, X1, Y1, Alpha);
    DrawPixelAlpha(Canvas, X2, Y1, Alpha);
    DrawPixelAlpha(Canvas, X1, Y2, Alpha);
    DrawPixelAlpha(Canvas, X2, Y2, Alpha);
  end;
end;

Here is how to use it to draw alpha ellipses and squares/rectangles (filled):

// draw ellipse
DrawAlphaEllipse(Canvas, Rect(16, 64, 240, 192), 55, True);
// draw square
for I := 128 to 255 do
  for J := 128 to 255 do
    DrawPixelAlpha(Canvas, I, J, 200);

Resulting image is attached to this post.



sofakng

That's perfect, thank you!

The circle in your image looks a bit white though...

Did you change the RGB values as well as the alpha?

Galfar

That is just how some browsers display PNGs with alpha. Try to open it in some
image editor (that supports PNGs with alpha).

Quick Reply

With Quick-Reply you can write a post when viewing a topic without loading a new page. You can still use bulletin board code and smileys as you would in a normal post.

Name:
Email:

Shortcuts: ALT+S save/post or ALT+P preview

SMF spam blocked by CleanTalk