A Quick Question About GrabImage

Blitz3D Forums/Blitz3D Beginners Area/A Quick Question About GrabImage

Newbie31(Posted 2013) [#1]
Heyo, I've just started looking at the grabimage command, and am having a little trouble. I'm trying to load 2 images one background and one foreground and when the mouse passes over an area it displays the background image. I know it can be done cause years ago I created such and effect, but I forgot exactly what I did.

This is what my current code looks like and it kind of works but it not updating correctly, I was wondering if the problem might be a graphics card issue?




Kryzon(Posted 2013) [#2]
[bbcode]
While Not KeyHit( 1 )

;DRAW IMAGES
DrawImage gfx_bg,0,0 ;Draws The Background Image
DrawImage gfx_fg,0,0 ;Draws The Foreground Image

;Draw Image Grab
gfxgrab = CreateImage(300,300) ;**********[/bbcode]You have a creation function inside a loop, that's very dangerous. If you let your program running, it'll eventually crash due to lack of available memory.
Every single loop cycle you're creating a new 'gfxgrab' image, and this isn't necessary.

You see, when you create an image, you can replace its content and the image wil still be usable by Blitz. Since you want a dynamic image (one that changes its content throughout the program), you can do it with just a single image.

About the GrabImage(). According to its documentation (something you can always consult when you're having trouble with a specific command), this function "allows you to grab a portion of the current drawing buffer".
Since the current drawing buffer is the BackBuffer, whenever you call GrabImage it will capture whatever's drawn there. And if you follow your program's flow...
[bbcode]
;DRAW IMAGES
DrawImage gfx_bg,0,0 ;Draws The Background Image
DrawImage gfx_fg,0,0 ;Draws The Foreground Image

;Draw Image Grab
GrabImage gfxgrab,MouseX()+10,MouseY()+10[/bbcode]... you're drawing both backgrounds first, then grabbing. You're going to end up capturing the foreground (which just overwrote the background).

If you want to capture only the background image, you should change the order to:




Newbie31(Posted 2013) [#3]
Heyo, me again.

I was wondering if there is a way to change the shape of the image buffer to a circle. I thought maybe could be done with alpha channels(masks) in the created image but I didn't have any luck with that. Can it be done?


Kryzon(Posted 2013) [#4]
All images start with a color mask of [0,0,0]. That's black.
If you plot any black pixels on the buffer of an image masked with that same black, they'll be transparent.

All image buffers are rectangular. If you use masking in a smart way you can make it look like you have a circular buffer.

To do this:

1) Create a 300x300 image that'll be your "dynamic image".

2) Create another 300x300 image that'll be your "stencil image". Fill it with black and then paint a white, filled circle perfectly inscribed in the image.

3) Create another 300x300 image that'll be your "dynamic masked result image".

-----
4) Now, per render cycle, grab a piece of the BackBuffer to your "dynamic image" as discussed in the previous posts.

5) Plot on the "dynamic masked result image" the bitwise AND comparison results between the pixel values you read from the "dynamic" and the "stencil" images.

What will happen is this: if the pixel value you read from the stencil image is black (so it's part of the background, outside of the white filled circle) it's going to make the bitwise AND result in 0, giving you a black pixel.
If the pixel value you read from the stencil image is white (inside the circle), it's going to make the bitwise AND result in whatever pixel color you picked from the dynamic image.

In the end, the "dynamic masked result image" will have a black background and a circular section of the dynamic image overlayed on it.
When you draw it with DrawImage, it'll have a circular shape because of masking.


Kryzon(Posted 2013) [#5]
The above is a more intuitive way, using comparisons.
But you can use another more mathematical way, specific for this, so it's cheaper on memory and CPU.

These two steps every loop cycle:

1) Grab your "dynamic image" from the BackBuffer like usual.

2) Process the image with the following function:
;Only admits SQUARE images, where width and height are equal.

Function CircularMask( image )
	Local width = ImageWidth(image)-1
	Local height = width
	Local halfWidth# = width/2.0
	
	LockBuffer ImageBuffer(image)
		For X = 0 To width
			For Y = 0 To height
			
				;Pythagorean theorem without the square root.
				;If the pixel is distanced from the center of the image by more 
				;than the image's "radius" (half its width or height), it's 
				;outside of what should be visible.
				If ( Abs((X-halfWidth) * (X-halfWidth)) + Abs((Y-halfWidth) * (Y-halfWidth)) ) > (halfWidth*halfWidth) Then WritePixelFast X,Y,0,ImageBuffer(image)
			
			Next
		Next	
	UnlockBuffer ImageBuffer(image)
End Function

What it does is compare the distance of each pixel against the center of the square image.
If it's bigger than the image's inscribed circle's "radius" (half the width or half the height), then the pixel is outside the circle and is colored black.


Addi(Posted 2013) [#6]
You can also use this Code:

;Bild runden =)
Function MaskImgRound(Pic, MX, MY, DX, DY, R = 0, G = 0, B = 0)
	
	Local CC = 255*$1000000+R*$10000+G*100+B
	Local ColorCode = 0
	
	;ImageBuffer einstellen um auf dem Bild malen zu können	
	SetBuffer ImageBuffer(Pic)	
		
	;Auf dem geladenen Bild and MX und MY (Kreismittelpunkt) ein Kreis mit DX/2 und DY/2 als Radius 
	Color R, G, B
	Oval MX-(DX/2), MY-(DY/2), DX, DY, 0
	
	;Buffer für ReadPixelFast und WritePixelFast sperren
	LockBuffer ImageBuffer(Pic)
	
	;Alle Pixel auserhalb des Kreis werden unsichtbar gemacht
	For Y=0 To ImageHeight(Pic)-1
		For X = 0 To MX
			ColorCode = ReadPixelFast(X,Y)	
			
			If ColorCode = CC Then Exit
			WritePixelFast X, Y, CC	
		Next
		
		For X = ImageWidth(Pic)-1 To MX Step -1
			ColorCode = ReadPixelFast(X,Y)	
									
			If ColorCode = CC Then Exit
			WritePixelFast X, Y, CC
		Next
	Next
	
	;Bild maskieren
	MaskImage Pic,R,G,B
	
	;Buffer freigeben und den BackBuffer setzen
	UnlockBuffer ImageBuffer(Pic)
	SetBuffer BackBuffer()
End Function


Pararmeter:
pic = handle of the pic you want to shape
mx = the x-position of the middle point of the circle
my = the y-position of the middle point of the circle
dx = the width of the circle
dy = the height of the circle
r, g, b = the rgb values for MaskImage

Example:
https://dl.dropbox.com/u/48089972/MaskImgRound.rar

Problem:
If the circle goes out of the picture

Edit:
This function works for each picture


Newbie31(Posted 2013) [#7]
Heyo, I'm back again.

I tried that "Function CircularMask( image )", and that works but it seems to have problems with refreshing(kind of flickers between the 2 images, and there seems to be a little displacement when moving). I've had problems like this before, I always assumed it was a lack in processing power problem.

Also I haven't had much practice with drawing into image that is created in blitz, I usually just draw in paint. Could you recommend any tutorials I should look at regarding this?


Kryzon(Posted 2013) [#8]
You need to share your exact code so we can see if there's anything wrong. Especially because that CircularMask() function is quite fast and shouldn't be flickering.

If you want to learn about the 2D part of Blitz3D (originally a standalone product itself, called Blitz Basic), there's no better place for that than the archived BlitzCoder tutorials. It's how I learned most of what I know:

http://web.archive.org/web/20050102090428/http://www.blitzcoder.com/

Everything there should be of use to you. One of those tutorials in particular is "How to create a simple image editor in Blitz2D", and while it doesn't explain to the fullest detail how the Front\Back\ImageBuffer() functions work, it does make use of them.
You need to ally those articles with the habit of consulting the documentation for any doubts you have about the language.
If you can, prefer to use the online documentation you can find here, in the official website. It includes a few user comments about the commands and functions, and some times it's very valuable info.


Newbie31(Posted 2014) [#9]
Heyo,

I have been going over some of my older code and I found this Imagegrab tests that the people here helped me with. I've learned a little bit more since then so I figured I'd give dynamic and stencil images a shot like kryzon suggested. It took me a while me a few tries to figure it out and get it working but I've accounted a problem, it is really slow at updating.

I was wondering if some of the guru's could have a looksy' and tell me how I could make it work faster. Thanks.



Complete files(156kbytes) : http://www.sendspace.com/file/8azgxh


fox95871(Posted 2014) [#10]
I'm not a guru, but I think in general the 2d commands are considered to be relatively slow. It's just one of the downsides of a language that's otherwise very good. But considering the new Direct x update, maybe a fix for this might be down the road too? I heard Blitz3d's coming back from the dead, afterall. Anyway, try doing the same thing with fullscreen animated image planes. I've found you can work around a lot of the 2d slowness with simulated 2d.