Page 1 of 2

DrawTiledImage(ImageID, X, Y, Width, Height)

Posted: Thu Aug 27, 2009 11:03 am
by eesau
A function to draw an image tiled on the output would be useful.

Posted: Thu Aug 27, 2009 11:59 am
by Seymour Clufley
But you could code that in seconds...!

Posted: Thu Aug 27, 2009 12:10 pm
by eesau
I know, and I have! I still think that a native solution would be better than my own version.

Posted: Thu Aug 27, 2009 12:16 pm
by Kaeru Gaman
I don't think so.
it would not be faster, and having the same tile all over is just a special case.

Posted: Thu Aug 27, 2009 12:19 pm
by eesau
Please feel free to post your versions of this to tips & tricks then, since the solution I came up with wasn't very good. Hence the feature request.

I don't think it's a special case either, I use it all the time. Maybe that just makes *me* the special case though :)

Posted: Thu Aug 27, 2009 12:42 pm
by Kaeru Gaman
I would do it that way:

Code: Select all

Procedure DrawTiledImage(ImageNr, X, Y, Width, Height)
  Protected n.l, t.l
  Protected w.l = ImageWidth(ImageNr)
  Protected h.l = ImageHeight(ImageNr)
  For t=1 To Height
    For n=1 To Width
      DrawImage( ImageID(ImageNr), X + n*w, Y + t*h )
    Next
  Next
EndProcedure

Posted: Thu Aug 27, 2009 1:34 pm
by Seymour Clufley
I haven't tested this, but:

Code: Select all

Procedure DrawTiledImage(img, bx, by, dWidth, dHeight) 
  If Not dWidth : dWidth=OutputWidth() : EndIf
  If Not dHeight : dHeight=OutputHeight() : EndIF
  tw = ImageWidth(img) 
  th = ImageHeight(img) 
  dy = by
  Repeat
      dx=bx
      Repeat
          DrawImage(ImageID(img),dx,dy)
          dx+tw
      Until dx+tw>dWidth
      dy+th
Until dy+th>dHeight
EndProcedure

Posted: Thu Aug 27, 2009 1:37 pm
by eesau
Thanks, but those are not right. The width and height should be pixels, not times the image should be tiled.

Posted: Thu Aug 27, 2009 1:39 pm
by Seymour Clufley
In my code, the width and height are pixels.

Posted: Thu Aug 27, 2009 1:44 pm
by eesau
Seymour Clufley wrote:In my code, the width and height are pixels.
They are, but say if the width is 10 pixels wider than the width of the image to be drawn, it doesn't draw those 10 pixels. The X, Y, Width and Height parameters define the area that should be fully filled with the tiled image.

Posted: Thu Aug 27, 2009 1:52 pm
by Kaeru Gaman
I have a code ready, but not yet tested... do you want to see it anyways?

Posted: Thu Aug 27, 2009 1:53 pm
by eesau
Sure, why not :)

Posted: Thu Aug 27, 2009 1:53 pm
by Kaeru Gaman
my idea was to create a tiled big image in advance to spare this time while drawing the tiled area.

Code: Select all

;******************************************************
;***
;*** CreateTiledImage( ImageNr.i, TileNr.i, Width.l, Height.l, Depth.l, LeftX.l = 0, TopY.l = 0, TileWidth.l = 0, TileHeight.l = 0 )
;***
;******************************************************
;***
;*** ImageNr.i      - Number of the Image to create (can be #PB_Any)
;*** TileNr.i       - Number of the Image giving the Tile (must be valid)
;*** Width.l        - Width of the Image to create
;*** Height.l       - Height of the Image to create
;*** Depth.l        - Depth of the Image to create (optional)
;*** LeftX.l        - Number of Pixels to X-shift into the first Row of Tiles (optional)
;*** TopY.l         - Number of Pixels to Y-shift into the first Line of Tiles (optional)
;*** TileWidth.l    - Resize Tile to this Width (optional)
;*** TileHeight.l   - Resize Tile to this Height (optional)
;***
;******************************************************
;***
;*** Creates a new Image wich is Tiled with the given Image.
;***
;*** ReturnValue    - analogue to CreateImage()
;***
;******************************************************
;***
;*** by Kaeru Gaman, 2009-08-27
;*** PureBasic Ver. 4.40
;***
;******************************************************

Procedure CreateTiledImage( ImageNr.i, TileNr.i, Width.l, Height.l, Depth.l = 32, LeftX.l = 0, TopY.l = 0, TileWidth.l = 0, TileHeight.l = 0 )
  Protected RetVal.i
  Protected.l n,t, Rows, Lines
  RetVal =  CreateImage( ImageNr, Width, Height, Depth )
  If RetVal And TileNr
    If ImageNr = #PB_Any
      ImageNr = RetVal
    EndIf
    If TileWidth = 0
      TileWidth = ImageWidth( TileNr )
    EndIf
    If TileHeight = 0
      TileHeight = ImageHeight( TileNr )
    EndIf
    Rows = Int( ( Width + LeftX - 1 ) / TileWidth + 1 )
    Lines = Int( ( Height + TopY - 1 ) / TileHeight + 1 )
    StartDrawing( ImageOutput( ImageNr ) )
      For t=1 To Lines
        For n=1 To Rows
          DrawImage( ImageID( TileNr ), n * TileWidth - LeftX, t * TileHeight - TopY, TileWidth, TileHeight )
        Next
      Next
    StopDrawing()
  EndIf
  ProcedureReturn RetVal
EndProcedure
please test it intensively and give feedback. ;)

Posted: Thu Aug 27, 2009 1:59 pm
by eesau
For reference, here's my current implementation. Probably not very efficient, because of the GrabImages. Can be used inside a StartDrawing()/StopDrawing() -block, which is important.

Code: Select all

Procedure ImageDrawTiled ( Image , X , Y , Width , Height )

	Protected TimesX = Width / ImageWidth ( Image )
	Protected TimesY = Height / ImageHeight ( Image )
	Protected LeftX = Width % ImageWidth ( Image )
	Protected LeftY = Height % ImageHeight ( Image )

	Protected CounterX
	Protected CounterY
	Protected Temporary
	
	For CounterX = 0 To TimesX - 1
	
		For CounterY = 0 To TimesY - 1
		
			DrawImage ( ImageID ( Image ) , X + CounterX * ImageWidth ( Image ) , Y + CounterY * ImageHeight ( Image ) )
					
		Next
		
	Next
	
	If LeftX
	
		Temporary = GrabImage ( Image , #PB_Any , 0 , 0 , LeftX , ImageHeight ( Image ) )
		
		If Temporary
						
			For CounterY = 0 To TimesY - 1
			
				DrawImage ( ImageID ( Temporary ) , X + CounterX * ImageWidth ( Image ) , Y + CounterY * ImageHeight ( Image ) )
			
			Next		
		
			FreeImage ( Temporary )
		
		EndIf
		
	EndIf
	
	If LeftY
	
		Temporary = GrabImage ( Image , #PB_Any , 0 , 0 , ImageWidth ( Image ) , LeftY )
		
		If Temporary
						
			For CounterX = 0 To TimesX - 1
			
				DrawImage ( ImageID ( Temporary ) , X + CounterX * ImageWidth ( Image ) , Y + CounterY * ImageHeight ( Image ) )
			
			Next		
		
			FreeImage ( Temporary )
		
		EndIf	
	
	EndIf
	
	If LeftX And LeftY
	
		Temporary = GrabImage ( Image , #PB_Any , 0 , 0 , LeftX , LeftY )
	
		If Temporary

			DrawImage ( ImageID ( Temporary ) , X + CounterX * ImageWidth ( Image ) , Y + CounterY * ImageHeight ( Image ) )
		
			FreeImage ( Temporary )
		
		EndIf
			
	EndIf
		
EndProcedure

Posted: Thu Aug 27, 2009 2:16 pm
by Kaeru Gaman
I chose the 'Create'-approach, because it simplyfies the clipping extremely.
plus, if you need the same tilefield more than once, you only need to create it once.
disadvantage is that it has it's own start/stop-drawing.