Draw only a part of an image?

BlitzMax Forums/BlitzMax Programming/Draw only a part of an image?

Grisu(Posted 2008) [#1]
Hi there!

What would be a fast way to draw only a part of a larger image that is already loaded into memory (as Image Handle)?

No Blending / Alpha required!

Grisu


MGE(Posted 2008) [#2]
Use LoadAnimImage:TImage( url:Object,cell_width,cell_height,first_cell,cell_count,flags=-1 ) to create tiles from the image then use drawimage to draw the section you want with the frame parameter.


Warpy(Posted 2008) [#3]
SetViewport looks like what you want.


GfK(Posted 2008) [#4]
SetViewport is unreliable on some hardware.

Try this (you'll have to use LockImage on myBigImage to use it as a pixmap).
mySmallImage:tImage = LoadImage(PixmapWindow(myBigImage,x,y,width,height))



Grisu(Posted 2008) [#5]
Thanks guys!


Grey Alien(Posted 2008) [#6]
This should be faster. I use it for my games

' -----------------------------------------------------------------------------
' ccDrawImageArea: Draws part of an image.
' (by Ian Duff)
' -----------------------------------------------------------------------------
Function ccDrawImageArea(image:TImage, x#, y#, rx#, ry#, rw#, rh#, theframe%=0)
 'Note that this code works fine in DirectX or OpenGL on PCs - it autodetects (Grey Alien).
 'Warning: make sure that none of your images have pixels right on the edge otherwise
 'when drawing clipped, they may leave smear in the clipped area! (Grey Alien).
  Local origin_x#, origin_y# ; GetOrigin (origin_x, origin_y)
  Local tw% = ccDrawImageAreaPow2Size(image.width)
  Local th% = ccDrawImageAreaPow2Size(image.height)
  Local rw1#  = rx + rw
  Local rh1#  = ry + rh
  Local x0# = -image.handle_x, x1# = x0 + rw
  Local y0# = -image.handle_y, y1# = y0 + rh
  
  If rw1 > image.width
    x1 = x0 + rw + image.width - rw1
    rw1 = image.width
  EndIf
   
  If rh1 > image.height
    y1 = y0 + rh + image.height - rh1
    rh1 = image.height
  EndIf
?Win32
  If TD3D7ImageFrame(image.frame(theframe))
    Local frame:TD3D7ImageFrame = TD3D7ImageFrame(image.frame(theframe))
    
    frame.setUV(rx / tw, ry / th, rw1 / tw, rh1 / th)
	frame.Draw x0, y0, x1, y1, x + origin_x, y + origin_y
    frame.setUV(0, 0, image.width / Float(tw), image.height / Float(th))
  Else
?
    Local frameA:TGLImageFrame = TGLImageFrame (image.frame(theframe))
    'Protect against frameA being null due to alt+tab. (Grey Alien)
	If frameA<>Null Then
	    frameA.u0 = rx / tw
	    frameA.v0 = ry / th
	    frameA.u1 = rw1 / tw
	    frameA.v1 = rh1 / th
	    
	    frameA.Draw x0, y0, x1, y1, x + origin_x, y + origin_y
	    
	    frameA.u0 = 0
	    frameA.v0 = 0
	    frameA.u1 = image.width / Float(tw)
	    frameA.v1 = image.height / Float(th)
	EndIf
?Win32
  EndIf
?
  
  Function ccDrawImageAreaPow2Size%(n%)
    Local ry% = 1
    
    While ry < n
      ry :* 2
    Wend
    
    Return ry
  End Function
End Function




MGE(Posted 2008) [#7]
"This should be faster." - Only on outdated gpu's. I didn't see a real "worth it" increase on newer gpu's.


Grey Alien(Posted 2008) [#8]
I thought it was faster than this:

mySmallImage:tImage = LoadImage(PixmapWindow(myBigImage,x,y,width,height)) 
Because it worked directly in VRAM.


MGE(Posted 2008) [#9]
ahh.. I see... ok.


jtfrench(Posted 2008) [#10]
@ Grey Alien

This looks pretty cool. I've been searching the forums for a while for a single surface blitting example that also included the conditional compilation as to avoid the "TD3D7ImageFrame indentifier not found" error (yeah, i could've written it myself...but thanks!)

Would you say this workaround is on par with the TAnimImage class that Indiepath made?

-Jason


jtfrench(Posted 2010) [#11]
Looks like this function may have to be updated for the new TGLImageFrame.draw method parameters.


Oddball(Posted 2010) [#12]
Take a look at DrawSubImageRect which was added to Max2D in v1.36.


jtfrench(Posted 2010) [#13]
Yup. I guess I'm just going to go with that. I'm not sure which is faster (Grey Alien approach, or DrawSubImageRect) but DrawSubImageRect is at least supported.