Command to draw a rectangular area of an image

BlitzMax Forums/BlitzMax Programming/Command to draw a rectangular area of an image

_Skully(Posted 2009) [#1]
Is there a command to draw a rectangular area of an image?

DrawImageRect appears to draw from 0,0 to a width and height but there doesnt seem to be a way to offset the upper left corner of the image. What I am effectively looking for is:

DrawImageRect (Img:TImage,ScreenX:Int,ScreenY:Int,X:Int,Y:Int,Width:Int,Height:Int)


Zeke(Posted 2009) [#2]



_Skully(Posted 2009) [#3]
Sweet, thanks!

Gives me some incite as well

Cheers


GfK(Posted 2009) [#4]
Circumstances permitting, you can also use LoadImage(PixmapWindow()) to achieve the same effect.


_Skully(Posted 2009) [#5]
I'm needing this for parallax effects in various map regions

I'll have to see which is faster.

Cheers.


_Skully(Posted 2009) [#6]
GfK,

I tested both methods... Zeke's is massively faster

This is the code I used to test it...

Function DrawImageArea2(image:TImage,x:Int,y:Int,ix:Int,iy:Int,width:Int,height:Int)
	Local img:TImage=LoadImage(PixmapWindow(image.pixmaps[0],ix,iy,width,height))
	DrawImage(img,x,y)
End Function




_Skully(Posted 2009) [#7]
Zeke,

I changed the Pow2Size to use shl

	Function Pow2Size:Int(n:Int)
		Local ry:Int = 1

		While ry < n
			ry=ry Shl 1
		Wend
		
		Return ry
	End Function


Its likely faster but I couldn't see a difference... shl's are usually the fastest form of multiplication.

Thanks for the help!

Cheers


MGE(Posted 2009) [#8]
"I tested both methods... Zeke's is massively faster.."

I've been there and done that many times over. Your mileage will vary. On XP machines and certain drivers, it's faster. On some newer boxes it's actually slower. Plus you'll end up having problems with artifacting so you'll need to place 1 or 2 blank pixels around each tile, sprite, etc, again...depending on driver/gpu, things will vary.

Just wait till you start coding tile maps using a projection matrix. You'll start seeing faint artifacting lines between your tiles, etc, etc. Very frustrating. To cure that you'll need to pick a fixed resolution closest to your game res and center the display. This is also frustrating since so many developers consider defaulting to the desktop res the normal thing to do now days.

In the end I just used the drawimage with the frame parameter. Easy and seemed to solve a few of the problems above. ;)


Arowx(Posted 2009) [#9]
How about using the setViewPort() to restrict the size of the image to an area on the screen then DrawImage() with an offset to ensure the right section of the image is shown?

Or would that be a lot slower?


GfK(Posted 2009) [#10]
How about using the setViewPort() to restrict the size of the image to an area on the screen then DrawImage() with an offset to ensure the right section of the image is shown?

Or would that be a lot slower?
SetViewport doesn't work on some hardware.


_Skully(Posted 2009) [#11]
if you want to see how well Zekes works check TileMax... the whole thing is being drawn with that routine and I'm seeing some nice returns FPS wise.


TaskMaster(Posted 2009) [#12]
Hmmm, I am getting a strange occurrence when using this code. The image being drawn by the DrawImageArea function is larger than the image drawn by the plain drawimage function or the drawimagerect function. And the colors don't come out the same. Can anyone test this and see if they get the same results. Use any image you want...

Here is the code I used:



Edit: the funny thing is, the DrawImageArea function draws the image at its actual size, the built in function are drawing a little small.

Edit 2: Interesting, it has something to do with the image width and height not being a power of 2. The DrawImageArea Function corrects for this, the built in functions do not, and end up scaling the picture down by the percentage of their size difference from power of 2.

This actually seems like a bug to me.

Edit 3: OK, the colors are right, it just seemed not right do to the scaling... But, the built in function are scaling the images if they are not sized to a power of 2, so this really does seem like an inherent bug in BlitzMax.


MoriartyL(Posted 2009) [#13]
When I try using this function, I get the error message:

"Compile Error

Duplicate identifier 'frame'"



It's on the line "Local frame:TGLImageFrame = TGLImageFrame (image.frame(frame))".


_Skully(Posted 2009) [#14]
Ya I got that too... I use superstrict

	Function DrawImageArea(image:TImage, x#, y#, dw#, dh#, l#, t#, w#, h#, frame:Int=0)
		Rem
			image: handle of the image you want to draw
			x , y: Position at which you want to draw the imagerect
			dw,dh: Drawing height and width of the image part you want do draw.
			l,t: top left position on the image you want to start drawing (in pixels)
			w,h: width and height of the imagerect you want to draw
		End Rem

		Local origin_x#,origin_y#
		GetOrigin (origin_x , origin_y)
		
		Local tw:Int = Pow2Size(image.width)
		Local th:Int = Pow2Size(image.height)
		Local l1#	= l + w
		Local h1#	= t + h
		Local x0#=-image.handle_x
		Local y0#=-image.handle_y
		
		If l1 > image.width
			l1 = image.width
		EndIf
		 
		If h1 > image.height
			h1 = image.height
		EndIf
	
		If TGLImageFrame (image.frame(frame))
			Local frame1:TGLImageFrame 	= TGLImageFrame (image.frame(frame))
											
			frame1.u0 = l / tw
			frame1.v0 = t / th
			frame1.u1 = l1 / tw
			frame1.v1 = h1 / th
			frame1.Draw x0,y0,x0+dw,y0+dh,x+origin_x,y+origin_y
			
			frame1.u0	= 0
			frame1.v0	= 0
			frame1.u1	= 1
			frame1.v1	= 1
		Else
			Local frame2:TD3D7ImageFrame	= TD3D7ImageFrame(image.frame(frame))
			frame2.setUV (l/tw, t/th, l1 / tw, h1 / th)
			frame2.Draw x0,y0,x0+dw,y0+dh,x+origin_x,y+origin_y
			frame2.setUV (0,0,1,1)
		EndIf
		
		Function Pow2Size:Int(n:Int)
			Local ry:Int = 1
	
			While ry < n
				ry=ry Shl 1
			Wend
			
			Return ry
		End Function
	End Function



MoriartyL(Posted 2009) [#15]
Thanks a lot, that works.


MoriartyL(Posted 2009) [#16]
Once this function is used, the standard DrawImage function stops working correctly for whatever image was used!

I have an image that fills the whole screen. Once the program uses DrawImageArea on it, it no longer fills the screen. A standard DrawImage draws the image at a fraction of its actual size, while scale is 1,1.

This seems obvious, but I'll say it anyway. I can't use a function that's going to break the rest of my code.


MoriartyL(Posted 2009) [#17]
And just to be clear: I need for this function to work, because it's the only way to do what I need to do without using viewports, which only work on specific graphics cards.