drawImage - Tiled?

A quick and possibly dumb question, is there a way to draw a image which is repeated/tiled in an area? If not, I will create my own code and share here. :wink:

Wk

Graphics::setTiledImageFill

Oh man, I need to learn how to do better searchesā€¦ :oops:

Thanks Jules.

Wk

Actually, thereā€™s nothing like this in the online manual. I couldnā€™t find it in Juce files either. I will check if thereā€™s a newer Juce version, it could be that. :wink: (Iā€™m using 1.50)

Wk

Strange, thereā€™s no newer version, so it seems Iā€™m using the latest.

I did find ā€œImageBrushā€ which seems to be what Iā€™m looking:

[code]/**
A Brush that fills areas with tiled repetitions of an image.

@see Brush, Graphics::setBrush, SolidColourBrush, GradientBrush

*/
class JUCE_API ImageBrush : public Brush[/code]

Wk

http://www.rawmaterialsoftware.com/juce/api/classImageBrush.html

Thanks, its what I mentioned above, Iā€™m already using it. 8)

g.setBrush(backBrush); g.fillRect(0,0,getWidth(),getHeight());

Wk

Hereā€™s the code I created to draw a skinable square. It used 9 Images.

[code] if (Background[0] != 0)
{
if (backBrush[0] == 0)
{
backBrush[0] = new ImageBrush(Background[1],0,0,1.0f);
backBrush[1] = new ImageBrush(Background[3],0,0,1.0f);
backBrush[2] = new ImageBrush(Background[4],0,0,1.0f);
backBrush[3] = new ImageBrush(Background[5],getWidth()-Background[5]->getWidth(),0,1.0f);
backBrush[4] = new ImageBrush(Background[7],0,getHeight()-Background[7]->getHeight(),1.0f);
}

	g.setBrush(backBrush[2]);	// Middle ///
	g.fillRect(0,0,getWidth(),getHeight());

	g.setBrush(backBrush[0]);	// Top Middle //
	g.fillRect(0,0,getWidth(),Background[1]->getHeight());
	
	g.setBrush(backBrush[4]);	// Bottom Middle //
	g.fillRect(0,getHeight()-Background[7]->getHeight(),getWidth(),Background[7]->getHeight());

	g.setBrush(backBrush[1]);	// Left Middle //
	g.fillRect(0,Background[0]->getHeight(),Background[3]->getWidth(),getHeight()-Background[0]->getHeight()-Background[6]->getHeight());
	
	g.setBrush(backBrush[3]);	// Right Middle //
	g.fillRect(getWidth()-Background[5]->getWidth(),Background[2]->getHeight(),Background[5]->getWidth(),getHeight()-Background[2]->getHeight()-Background[8]->getHeight());

	g.drawImageAt(Background[0],0,0);
	g.drawImageAt(Background[2],getWidth()-Background[2]->getWidth(),0);
	g.drawImageAt(Background[6],0,getHeight()-Background[6]->getHeight());
	g.drawImageAt(Background[8],getWidth()-Background[8]->getWidth(),getHeight()-Background[8]->getHeight());
}[/code]

It uses Image Background[9] which are: TopLeft,TopMid,TopRight,MidLeft,MidMid,MidRight,BottLeft,BottMid,BottRight.

The Brush are:

ImageBrush* backBrush[5];

Wk

If thereā€™s a resize, just delete all backBrush variables and repaint, thatā€™s all. Seems to be working hereā€¦

Wk

Ah, yes, sorry - Iā€™m in the middle of changing all the graphics context filling stuff, so donā€™t get carried away with ImageBrushes, as theyā€™re going to be deprecated at some point in the future.

The new Graphics::setTiledImageFill method isnā€™t in the online docs yet, but is there in the headers if youā€™ve got the latest code. It does basically the same thing, but will allow more efficient rendering than is possible by using the abstract Brush classes.

Thanks Jules. I just downloaded the latest version and I see it now in the header files. (I didnā€™t know how to download the daily/weekly files)

But now I wonder, the setBrush works correctly like I need, while setTiledImageFill doesnā€™t.

I want to create my own Background image which can be resized, so with any window size it will look correctly thanks to the 9 images as Iā€™m using above.

Now, with setTiledImageFill, from what I understood, I only got to use One picture for the entire background, is that correct?

So, am I right to say that only Brushes would do the correct thing in this case? I do worry that you will deprecate it, since it works perfectly for what Iā€™m doing. But I understand, just need to find another way to do what I have in mind. :wink:

Wk

ā€¦no, they have exactly the same capability. Youā€™d just call setTiledImageFill instead of setBrush. It actually makes for more readable code, and avoids having to worry about deleting your brush objects (though in your example thatā€™s clearly not a worry for you, as you seem to just be leaking them!)

Oh, ok, I understand now, I will try it out. Thanks Jules. 8)

Wk

Yeah, it works perfectly. Thanks again.

Hereā€™s the new code. Maybe I will try to create a Macro for this, as its very handy. :wink:

[code]void FileTreeMain::paint (Graphics& g)
{
if (Background[0] != 0)
{
g.setTiledImageFill(*Background[4],0,0,1.0f); // Middle ///
g.fillRect(0,0,getWidth(),getHeight());

	g.setTiledImageFill(*Background[1],0,0,1.0f);	// Top Middle //
	g.fillRect(0,0,getWidth(),Background[1]->getHeight());
	
	g.setTiledImageFill(*Background[7],0,getHeight()-Background[7]->getHeight(),1.0f);	// Bottom Middle //
	g.fillRect(0,getHeight()-Background[7]->getHeight(),getWidth(),Background[7]->getHeight());

	g.setTiledImageFill(*Background[3],0,0,1.0f);	// Left Middle //
	g.fillRect(0,Background[0]->getHeight(),Background[3]->getWidth(),getHeight()-Background[0]->getHeight()-Background[6]->getHeight());
	
	g.setTiledImageFill(*Background[5],getWidth()-Background[5]->getWidth(),0,1.0f);	// Right Middle //
	g.fillRect(getWidth()-Background[5]->getWidth(),Background[2]->getHeight(),Background[5]->getWidth(),getHeight()-Background[2]->getHeight()-Background[8]->getHeight());

	g.drawImageAt(Background[0],0,0);
	g.drawImageAt(Background[2],getWidth()-Background[2]->getWidth(),0);
	g.drawImageAt(Background[6],0,getHeight()-Background[6]->getHeight());
	g.drawImageAt(Background[8],getWidth()-Background[8]->getWidth(),getHeight()-Background[8]->getHeight());
}

}[/code]

Wk

And hereā€™s the Macro.

// IMAGE must be "Image* image[9]" Nine Pictures in the following order: // (TopLeft,TopMid,TopRight,MidLeft,MidMid,MidRight,BottomLeft,BottomMid,BottomRight) #define skinDrawSquare(IMAGE,X,Y,WIDTH,HEIGHT); \ \ g.setTiledImageFill(*IMAGE[4],X,Y,1.0f); \ g.fillRect(X,Y,WIDTH,HEIGHT); \ \ g.setTiledImageFill(*IMAGE[1],X,Y,1.0f); \ g.fillRect(X,Y,WIDTH,IMAGE[1]->getHeight()); \ \ g.setTiledImageFill(*IMAGE[7],X,Y+HEIGHT-IMAGE[7]->getHeight(),1.0f); \ g.fillRect(X,Y+HEIGHT-IMAGE[7]->getHeight(),WIDTH,IMAGE[7]->getHeight()); \ \ g.setTiledImageFill(*IMAGE[3],X,Y,1.0f); \ g.fillRect(X,Y+IMAGE[0]->getHeight(),IMAGE[3]->getWidth(),HEIGHT-IMAGE[0]->getHeight()-IMAGE[6]->getHeight()); \ \ g.setTiledImageFill(*IMAGE[5],X+WIDTH-IMAGE[5]->getWidth(),Y,1.0f); \ g.fillRect(X+WIDTH-IMAGE[5]->getWidth(),Y+IMAGE[2]->getHeight(),IMAGE[5]->getWidth(),HEIGHT-IMAGE[2]->getHeight()-IMAGE[8]->getHeight()); \ \ g.drawImageAt(IMAGE[0],X,Y); \ g.drawImageAt(IMAGE[2],X+WIDTH-IMAGE[2]->getWidth(),Y); \ g.drawImageAt(IMAGE[6],X,Y+HEIGHT-IMAGE[6]->getHeight()); \ g.drawImageAt(IMAGE[8],X+WIDTH-IMAGE[8]->getWidth(),Y+HEIGHT-IMAGE[8]->getHeight());

And hereā€™s an example of usage:

void FileTreeMain::paint (Graphics& g) { if (Background[0] != 0) { skinDrawSquare(Background,0,0,getWidth(),getHeight()); } }

Where Background is Image* Background[9];

Wk

Hereā€™s a Macro that will draw Transparent images, with an Opacity option:

[code]/*
Image* buttonIMAGE[9];

Starting from the Top-Left Corner. Its best that all images have the same size, or relative sizes.
0  1  2

3  4  5

6  7  8

*/
#define skinDrawSquare(IMAGE,X,Y,WIDTH,HEIGHT,OPACITY);

g.setTiledImageFill(*IMAGE[4],X+IMAGE[3]->getWidth(),Y+IMAGE[1]->getHeight(),OPACITY);
g.fillRect(X+IMAGE[3]->getWidth(),Y+IMAGE[1]->getHeight(),WIDTH-IMAGE[3]->getWidth()-IMAGE[5]->getWidth(),HEIGHT-IMAGE[1]->getHeight()-IMAGE[7]->getHeight());

g.setTiledImageFill(*IMAGE[1],X+IMAGE[0]->getWidth(),Y,OPACITY);
g.fillRect(X+IMAGE[0]->getWidth(),Y,WIDTH-IMAGE[0]->getWidth()-IMAGE[2]->getWidth(),IMAGE[1]->getHeight());

g.setTiledImageFill(*IMAGE[7],X+IMAGE[6]->getWidth(),Y+HEIGHT-IMAGE[7]->getHeight(),OPACITY);
g.fillRect(X+IMAGE[6]->getWidth(),Y+HEIGHT-IMAGE[7]->getHeight(),WIDTH-IMAGE[6]->getWidth()-IMAGE[8]->getWidth(),IMAGE[7]->getHeight());

g.setTiledImageFill(*IMAGE[3],X,Y+IMAGE[0]->getHeight(),OPACITY);
g.fillRect(X,Y+IMAGE[0]->getHeight(),IMAGE[3]->getWidth(),HEIGHT-IMAGE[0]->getHeight()-IMAGE[6]->getHeight());

g.setTiledImageFill(*IMAGE[5],X+WIDTH-IMAGE[5]->getWidth(),Y,OPACITY);
g.fillRect(X+WIDTH-IMAGE[5]->getWidth(),Y+IMAGE[2]->getHeight(),IMAGE[5]->getWidth(),HEIGHT-IMAGE[2]->getHeight()-IMAGE[8]->getHeight());

g.setTiledImageFill(*IMAGE[0],X,Y,OPACITY);
g.fillRect(X,Y,IMAGE[0]->getWidth(),IMAGE[0]->getHeight());

g.setTiledImageFill(*IMAGE[2],X+WIDTH-IMAGE[2]->getWidth(),Y,OPACITY);
g.fillRect(X+WIDTH-IMAGE[2]->getWidth(),Y,IMAGE[2]->getWidth(),IMAGE[2]->getHeight());

g.setTiledImageFill(*IMAGE[6],X,Y+HEIGHT-IMAGE[6]->getHeight(),OPACITY);
g.fillRect(X,Y+HEIGHT-IMAGE[6]->getHeight(),IMAGE[6]->getWidth(),IMAGE[6]->getHeight());

g.setTiledImageFill(*IMAGE[8],X+WIDTH-IMAGE[8]->getWidth(),Y+HEIGHT-IMAGE[8]->getHeight(),OPACITY);
g.fillRect(X+WIDTH-IMAGE[8]->getWidth(),Y+HEIGHT-IMAGE[8]->getHeight(),IMAGE[8]->getWidth(),IMAGE[8]->getHeight());[/code]

out of curiosity, why a macro and not a static C function ?

Ah, good question. Its just that I donā€™t know how I would do a static function for that. Iā€™m pretty sure I could figure it out. :wink: Maybe someone could show to me how to do that? :mrgreen: Iā€™m still learning, every day. :oops:

Wk

Or a class that holds the images and has a ā€œdraw (Graphics& g)ā€ method?